From 6ac5df64751b69cec2442e1a8b332842193e1f01 Mon Sep 17 00:00:00 2001 From: Ernst Klamer Date: Sun, 25 Feb 2024 17:30:43 +0100 Subject: [PATCH] Add PTX wireless switch --- .../ble_monitor/ble_parser/xiaomi.py | 39 +++++++++++++++++- custom_components/ble_monitor/const.py | 2 + custom_components/ble_monitor/manifest.json | 2 +- .../ble_monitor/test/test_xiaomi_parser.py | 27 ++++++++++++ .../{K9B-1BTN.md => Xiaomi_K9B-1BTN.md} | 0 .../{K9B-2BTN.md => Xiaomi_K9B-2BTN.md} | 0 .../{K9B-3BTN.md => Xiaomi_K9B-3BTN.md} | 0 .../{K9BB-1BTN.md => Xiaomi_K9BB-1BTN.md} | 0 .../{LYWSD02.md => Xiaomi_LYWSD02.md} | 0 .../{LYWSD02MMC.md => Xiaomi_LYWSD02MMC.md} | 0 .../{LYWSD03MMC.md => Xiaomi_LYWSD03MMC.md} | 0 .../{LYWSDCGQ.md => Xiaomi_LYWSDCGQ.md} | 0 .../{MCCGQ02HL.md => Xiaomi_MCCGQ02HL.md} | 0 .../{MHO-C303.md => Xiaomi_MHO-C303.md} | 0 .../{MHO-C401.md => Xiaomi_MHO-C401.md} | 0 .../{MJWSD05MMC.md => Xiaomi_MJWSD05MMC.md} | 0 .../{MJYD02YL.md => Xiaomi_MJYD02YL.md} | 0 .../{MJZNMSQ01YD.md => Xiaomi_MJZNMSQ01YD.md} | 0 .../{MUE4094RT.md => Xiaomi_MUE4094RT.md} | 0 docs/_devices/Xiaomi_PTX.md | 20 +++++++++ docs/_devices/{RS1BB.md => Xiaomi_RS1BB.md} | 0 .../{RTCGQ02LM.md => Xiaomi_RTCGQ02LM.md} | 0 docs/_devices/{WX08ZM.md => Xiaomi_WX08ZM.md} | 0 .../{XMMF01JQD.md => Xiaomi_XMMF01JQD.md} | 0 ...C04HM.md => Xiaomi_XMTZC01HM_XMTZC04HM.md} | 0 ...> Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md} | 0 .../{XMWSDJ04MMC.md => Xiaomi_XMWSDJ04MMC.md} | 0 docs/_devices/Xiaomi_XMWXKG01LM.md | 20 +++++++++ .../{XMWXKG01YL.md => Xiaomi_XMWXKG01YL.md} | 0 .../{XMZNMS04LM.md => Xiaomi_XMZNMS04LM.md} | 0 .../{XMZNMS08LM.md => Xiaomi_XMZNMS08LM.md} | 0 .../{XMZNMST02YD.md => Xiaomi_XMZNMST02YD.md} | 0 .../{YLAI003.md => Xiaomi_YLAI003.md} | 0 ...LKG08YL.md => Xiaomi_YLKG07YL_YLKG08YL.md} | 0 ...01YL-BHFRC.md => Xiaomi_YLYB01YL-BHFRC.md} | 0 ...01YL-FANCL.md => Xiaomi_YLYK01YL-FANCL.md} | 0 ...YL-VENFAN.md => Xiaomi_YLYK01YL-VENFAN.md} | 0 .../{YLYK01YL.md => Xiaomi_YLYK01YL.md} | 0 .../{YM-K1501.md => Xiaomi_YM-K1501.md} | 0 .../{ZNMS16LM.md => Xiaomi_ZNMS16LM.md} | 0 .../{ZNMS17LM.md => Xiaomi_ZNMS17LM.md} | 0 docs/assets/images/PTX.png | Bin 0 -> 6209 bytes 42 files changed, 108 insertions(+), 2 deletions(-) rename docs/_devices/{K9B-1BTN.md => Xiaomi_K9B-1BTN.md} (100%) rename docs/_devices/{K9B-2BTN.md => Xiaomi_K9B-2BTN.md} (100%) rename docs/_devices/{K9B-3BTN.md => Xiaomi_K9B-3BTN.md} (100%) rename docs/_devices/{K9BB-1BTN.md => Xiaomi_K9BB-1BTN.md} (100%) rename docs/_devices/{LYWSD02.md => Xiaomi_LYWSD02.md} (100%) rename docs/_devices/{LYWSD02MMC.md => Xiaomi_LYWSD02MMC.md} (100%) rename docs/_devices/{LYWSD03MMC.md => Xiaomi_LYWSD03MMC.md} (100%) rename docs/_devices/{LYWSDCGQ.md => Xiaomi_LYWSDCGQ.md} (100%) rename docs/_devices/{MCCGQ02HL.md => Xiaomi_MCCGQ02HL.md} (100%) rename docs/_devices/{MHO-C303.md => Xiaomi_MHO-C303.md} (100%) rename docs/_devices/{MHO-C401.md => Xiaomi_MHO-C401.md} (100%) rename docs/_devices/{MJWSD05MMC.md => Xiaomi_MJWSD05MMC.md} (100%) rename docs/_devices/{MJYD02YL.md => Xiaomi_MJYD02YL.md} (100%) rename docs/_devices/{MJZNMSQ01YD.md => Xiaomi_MJZNMSQ01YD.md} (100%) rename docs/_devices/{MUE4094RT.md => Xiaomi_MUE4094RT.md} (100%) create mode 100644 docs/_devices/Xiaomi_PTX.md rename docs/_devices/{RS1BB.md => Xiaomi_RS1BB.md} (100%) rename docs/_devices/{RTCGQ02LM.md => Xiaomi_RTCGQ02LM.md} (100%) rename docs/_devices/{WX08ZM.md => Xiaomi_WX08ZM.md} (100%) rename docs/_devices/{XMMF01JQD.md => Xiaomi_XMMF01JQD.md} (100%) rename docs/_devices/{XMTZC01HM_XMTZC04HM.md => Xiaomi_XMTZC01HM_XMTZC04HM.md} (100%) rename docs/_devices/{XMTZC02HM_XMTZC05HM_NUN4049CN.md => Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md} (100%) rename docs/_devices/{XMWSDJ04MMC.md => Xiaomi_XMWSDJ04MMC.md} (100%) create mode 100644 docs/_devices/Xiaomi_XMWXKG01LM.md rename docs/_devices/{XMWXKG01YL.md => Xiaomi_XMWXKG01YL.md} (100%) rename docs/_devices/{XMZNMS04LM.md => Xiaomi_XMZNMS04LM.md} (100%) rename docs/_devices/{XMZNMS08LM.md => Xiaomi_XMZNMS08LM.md} (100%) rename docs/_devices/{XMZNMST02YD.md => Xiaomi_XMZNMST02YD.md} (100%) rename docs/_devices/{YLAI003.md => Xiaomi_YLAI003.md} (100%) rename docs/_devices/{YLKG07YL_YLKG08YL.md => Xiaomi_YLKG07YL_YLKG08YL.md} (100%) rename docs/_devices/{YLYB01YL-BHFRC.md => Xiaomi_YLYB01YL-BHFRC.md} (100%) rename docs/_devices/{YLYK01YL-FANCL.md => Xiaomi_YLYK01YL-FANCL.md} (100%) rename docs/_devices/{YLYK01YL-VENFAN.md => Xiaomi_YLYK01YL-VENFAN.md} (100%) rename docs/_devices/{YLYK01YL.md => Xiaomi_YLYK01YL.md} (100%) rename docs/_devices/{YM-K1501.md => Xiaomi_YM-K1501.md} (100%) rename docs/_devices/{ZNMS16LM.md => Xiaomi_ZNMS16LM.md} (100%) rename docs/_devices/{ZNMS17LM.md => Xiaomi_ZNMS17LM.md} (100%) create mode 100644 docs/assets/images/PTX.png diff --git a/custom_components/ble_monitor/ble_parser/xiaomi.py b/custom_components/ble_monitor/ble_parser/xiaomi.py index d257f82a8..a8f3284ae 100755 --- a/custom_components/ble_monitor/ble_parser/xiaomi.py +++ b/custom_components/ble_monitor/ble_parser/xiaomi.py @@ -75,6 +75,7 @@ 0x18E3: "ZX1", 0x11C2: "SV40", 0x3F0F: "RS1BB", + 0x38BB: "PTX", } # Structured objects for data conversions @@ -769,6 +770,30 @@ def obj4a08(xobj): return {"motion": 1, "motion timer": 1, "illuminance": illu} +def obj4a0c(xobj): + """Single click PTX""" + return { + "one btn switch": "toggle", + "button switch": "single press", + } + + +def obj4a0d(xobj): + """Double click PTX""" + return { + "one btn switch": "toggle", + "button switch": "double press", + } + + +def obj4a0e(xobj): + """Long click PTX""" + return { + "one btn switch": "toggle", + "button switch": "long press", + } + + def obj4a0f(xobj): """Door/window broken open""" dev_forced = xobj[0] @@ -852,6 +877,12 @@ def obj4c14(xobj): return {"mode": mode} +def obj4e01(xobj): + """Low Battery""" + low_batt = xobj[0] + return {"low battery": low_batt} + + def obj4e0c(xobj, device_type): """Click""" if device_type == "XMWXKG01YL": @@ -1065,6 +1096,9 @@ def obj5a16(xobj): 0x4818: obj4818, 0x4a01: obj4a01, 0x4a08: obj4a08, + 0x4a0c: obj4a0c, + 0x4a0d: obj4a0d, + 0x4a0e: obj4a0e, 0x4a0f: obj4a0f, 0x4a12: obj4a12, 0x4a13: obj4a13, @@ -1074,6 +1108,7 @@ def obj5a16(xobj): 0x4c03: obj4c03, 0x4c08: obj4c08, 0x4c14: obj4c14, + 0x4e01: obj4e01, 0x4e0c: obj4e0c, 0x4e0d: obj4e0d, 0x4e0e: obj4e0e, @@ -1267,7 +1302,9 @@ def parse_xiaomi(self, data: bytes, mac: str): _LOGGER.debug("Invalid payload data length, payload: %s", payload.hex()) break dobject = payload[payload_start + 3:next_start] - if dobject and obj_length != 0 or hex(obj_typecode) in ["0x4e0c", "0x4e0d", "0x4e0e"]: + if dobject and obj_length != 0 or hex(obj_typecode) in [ + "0x4a0c", "0x4a0d", "0x4a0e", "0x4e0c", "0x4e0d", "0x4e0e" + ]: resfunc = xiaomi_dataobject_dict.get(obj_typecode, None) if resfunc: if hex(obj_typecode) in ["0x8", "0x100e", "0x1001", "0xf", "0xb", "0x4e0c", "0x4e0d", "0x4e0e"]: diff --git a/custom_components/ble_monitor/const.py b/custom_components/ble_monitor/const.py index 7418b2591..9baa83e27 100755 --- a/custom_components/ble_monitor/const.py +++ b/custom_components/ble_monitor/const.py @@ -1674,6 +1674,7 @@ class BLEMonitorBinarySensorEntityDescription( 'HS1BB(MI)' : [["illuminance", "battery", "rssi"], [], ["motion"]], 'XMWXKG01YL' : [["rssi"], ["two btn switch left", "two btn switch right"], []], 'XMWXKG01LM' : [["battery", "rssi"], ["one btn switch"], []], + 'PTX' : [["battery", "rssi"], ["one btn switch"], []], 'YLAI003' : [["rssi", "battery"], ["button"], []], 'YLYK01YL' : [["rssi"], ["remote"], ["remote single press", "remote long press"]], 'YLYK01YL-FANCL' : [["rssi"], ["fan remote"], []], @@ -1812,6 +1813,7 @@ class BLEMonitorBinarySensorEntityDescription( 'HS1BB(MI)' : 'Linptech', 'XMWXKG01YL' : 'Xiaomi', 'XMWXKG01LM' : 'Xiaomi', + 'PTX' : 'Xiaomi', 'SV40' : 'Lockin', 'SU001-T' : 'Petoneer', 'ATC' : 'ATC', diff --git a/custom_components/ble_monitor/manifest.json b/custom_components/ble_monitor/manifest.json index 6a1497482..4b3396463 100644 --- a/custom_components/ble_monitor/manifest.json +++ b/custom_components/ble_monitor/manifest.json @@ -14,5 +14,5 @@ "btsocket>=0.2.0", "pyric>=0.1.6.3" ], - "version": "12.9.2" + "version": "12.9.3" } diff --git a/custom_components/ble_monitor/test/test_xiaomi_parser.py b/custom_components/ble_monitor/test/test_xiaomi_parser.py index bf0c86e57..622478ddb 100644 --- a/custom_components/ble_monitor/test/test_xiaomi_parser.py +++ b/custom_components/ble_monitor/test/test_xiaomi_parser.py @@ -1037,3 +1037,30 @@ def test_XMWXKG01LM_long_click(self): assert sensor_msg["one btn switch"] == "toggle" assert sensor_msg["button switch"] == "long press" assert sensor_msg["rssi"] == -64 + + def test_Xiaomi_PTX(self): + """Test Xiaomi parser for PTX BLE wireless switch.""" + self.aeskeys = {} + data_string = "043E2802010000adb9a538c1a41c020106181695fe5859bb3804adb9a538c1a4dc10b50400002c122fb6CC" + data = bytes(bytearray.fromhex(data_string)) + + aeskey = "a74510b40386d35ae6227a7451efc76e" + + is_ext_packet = True if data[3] == 0x0D else False + mac = (data[8 if is_ext_packet else 7:14 if is_ext_packet else 13])[::-1] + mac_address = mac.hex() + p_mac = bytes.fromhex(mac_address.replace(":", "").lower()) + p_key = bytes.fromhex(aeskey.lower()) + self.aeskeys[p_mac] = p_key + # pylint: disable=unused-variable + ble_parser = BleParser(aeskeys=self.aeskeys) + sensor_msg, tracker_msg = ble_parser.parse_raw_data(data) + + assert sensor_msg["firmware"] == "Xiaomi (MiBeacon V5 encrypted)" + assert sensor_msg["type"] == "PTX" + assert sensor_msg["mac"] == "A4C138A5B9AD" + assert sensor_msg["packet"] == 4 + assert sensor_msg["data"] + assert sensor_msg["one btn switch"] == "toggle" + assert sensor_msg["button switch"] == "single press" + assert sensor_msg["rssi"] == -52 diff --git a/docs/_devices/K9B-1BTN.md b/docs/_devices/Xiaomi_K9B-1BTN.md similarity index 100% rename from docs/_devices/K9B-1BTN.md rename to docs/_devices/Xiaomi_K9B-1BTN.md diff --git a/docs/_devices/K9B-2BTN.md b/docs/_devices/Xiaomi_K9B-2BTN.md similarity index 100% rename from docs/_devices/K9B-2BTN.md rename to docs/_devices/Xiaomi_K9B-2BTN.md diff --git a/docs/_devices/K9B-3BTN.md b/docs/_devices/Xiaomi_K9B-3BTN.md similarity index 100% rename from docs/_devices/K9B-3BTN.md rename to docs/_devices/Xiaomi_K9B-3BTN.md diff --git a/docs/_devices/K9BB-1BTN.md b/docs/_devices/Xiaomi_K9BB-1BTN.md similarity index 100% rename from docs/_devices/K9BB-1BTN.md rename to docs/_devices/Xiaomi_K9BB-1BTN.md diff --git a/docs/_devices/LYWSD02.md b/docs/_devices/Xiaomi_LYWSD02.md similarity index 100% rename from docs/_devices/LYWSD02.md rename to docs/_devices/Xiaomi_LYWSD02.md diff --git a/docs/_devices/LYWSD02MMC.md b/docs/_devices/Xiaomi_LYWSD02MMC.md similarity index 100% rename from docs/_devices/LYWSD02MMC.md rename to docs/_devices/Xiaomi_LYWSD02MMC.md diff --git a/docs/_devices/LYWSD03MMC.md b/docs/_devices/Xiaomi_LYWSD03MMC.md similarity index 100% rename from docs/_devices/LYWSD03MMC.md rename to docs/_devices/Xiaomi_LYWSD03MMC.md diff --git a/docs/_devices/LYWSDCGQ.md b/docs/_devices/Xiaomi_LYWSDCGQ.md similarity index 100% rename from docs/_devices/LYWSDCGQ.md rename to docs/_devices/Xiaomi_LYWSDCGQ.md diff --git a/docs/_devices/MCCGQ02HL.md b/docs/_devices/Xiaomi_MCCGQ02HL.md similarity index 100% rename from docs/_devices/MCCGQ02HL.md rename to docs/_devices/Xiaomi_MCCGQ02HL.md diff --git a/docs/_devices/MHO-C303.md b/docs/_devices/Xiaomi_MHO-C303.md similarity index 100% rename from docs/_devices/MHO-C303.md rename to docs/_devices/Xiaomi_MHO-C303.md diff --git a/docs/_devices/MHO-C401.md b/docs/_devices/Xiaomi_MHO-C401.md similarity index 100% rename from docs/_devices/MHO-C401.md rename to docs/_devices/Xiaomi_MHO-C401.md diff --git a/docs/_devices/MJWSD05MMC.md b/docs/_devices/Xiaomi_MJWSD05MMC.md similarity index 100% rename from docs/_devices/MJWSD05MMC.md rename to docs/_devices/Xiaomi_MJWSD05MMC.md diff --git a/docs/_devices/MJYD02YL.md b/docs/_devices/Xiaomi_MJYD02YL.md similarity index 100% rename from docs/_devices/MJYD02YL.md rename to docs/_devices/Xiaomi_MJYD02YL.md diff --git a/docs/_devices/MJZNMSQ01YD.md b/docs/_devices/Xiaomi_MJZNMSQ01YD.md similarity index 100% rename from docs/_devices/MJZNMSQ01YD.md rename to docs/_devices/Xiaomi_MJZNMSQ01YD.md diff --git a/docs/_devices/MUE4094RT.md b/docs/_devices/Xiaomi_MUE4094RT.md similarity index 100% rename from docs/_devices/MUE4094RT.md rename to docs/_devices/Xiaomi_MUE4094RT.md diff --git a/docs/_devices/Xiaomi_PTX.md b/docs/_devices/Xiaomi_PTX.md new file mode 100644 index 000000000..87c753d9b --- /dev/null +++ b/docs/_devices/Xiaomi_PTX.md @@ -0,0 +1,20 @@ +--- +manufacturer: Xiaomi +name: BLE wireless switch +model: PTX +image: PTX.png +physical_description: +broadcasted_properties: + - one btn switch + - battery + - rssi +broadcasted_property_notes: + - property: one btn switch + note: returns 'single press', 'double press' or 'long press' +broadcast_rate: +active_scan: false +encryption_key: Yes +custom_firmware: false +notes: + - The switch sensor state will return to `no press` after the time set with the [reset_timer](configuration_params#reset_timer) option. It is advised to change the reset time to 1 second (default = 35 seconds). +--- diff --git a/docs/_devices/RS1BB.md b/docs/_devices/Xiaomi_RS1BB.md similarity index 100% rename from docs/_devices/RS1BB.md rename to docs/_devices/Xiaomi_RS1BB.md diff --git a/docs/_devices/RTCGQ02LM.md b/docs/_devices/Xiaomi_RTCGQ02LM.md similarity index 100% rename from docs/_devices/RTCGQ02LM.md rename to docs/_devices/Xiaomi_RTCGQ02LM.md diff --git a/docs/_devices/WX08ZM.md b/docs/_devices/Xiaomi_WX08ZM.md similarity index 100% rename from docs/_devices/WX08ZM.md rename to docs/_devices/Xiaomi_WX08ZM.md diff --git a/docs/_devices/XMMF01JQD.md b/docs/_devices/Xiaomi_XMMF01JQD.md similarity index 100% rename from docs/_devices/XMMF01JQD.md rename to docs/_devices/Xiaomi_XMMF01JQD.md diff --git a/docs/_devices/XMTZC01HM_XMTZC04HM.md b/docs/_devices/Xiaomi_XMTZC01HM_XMTZC04HM.md similarity index 100% rename from docs/_devices/XMTZC01HM_XMTZC04HM.md rename to docs/_devices/Xiaomi_XMTZC01HM_XMTZC04HM.md diff --git a/docs/_devices/XMTZC02HM_XMTZC05HM_NUN4049CN.md b/docs/_devices/Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md similarity index 100% rename from docs/_devices/XMTZC02HM_XMTZC05HM_NUN4049CN.md rename to docs/_devices/Xiaomi_XMTZC02HM_XMTZC05HM_NUN4049CN.md diff --git a/docs/_devices/XMWSDJ04MMC.md b/docs/_devices/Xiaomi_XMWSDJ04MMC.md similarity index 100% rename from docs/_devices/XMWSDJ04MMC.md rename to docs/_devices/Xiaomi_XMWSDJ04MMC.md diff --git a/docs/_devices/Xiaomi_XMWXKG01LM.md b/docs/_devices/Xiaomi_XMWXKG01LM.md new file mode 100644 index 000000000..bc0e207c6 --- /dev/null +++ b/docs/_devices/Xiaomi_XMWXKG01LM.md @@ -0,0 +1,20 @@ +--- +manufacturer: Xiaomi +name: Mijia wireless switch +model: XMWXKG01LM +image: XMWXKG01LM.png +physical_description: round switch +broadcasted_properties: + - one btn switch + - battery + - rssi +broadcasted_property_notes: + - property: one btn switch + note: returns 'single press', 'double press' or 'long press' +broadcast_rate: +active_scan: false +encryption_key: Yes +custom_firmware: false +notes: + - The switch sensor state will return to `no press` after the time set with the [reset_timer](configuration_params#reset_timer) option. It is advised to change the reset time to 1 second (default = 35 seconds). +--- diff --git a/docs/_devices/XMWXKG01YL.md b/docs/_devices/Xiaomi_XMWXKG01YL.md similarity index 100% rename from docs/_devices/XMWXKG01YL.md rename to docs/_devices/Xiaomi_XMWXKG01YL.md diff --git a/docs/_devices/XMZNMS04LM.md b/docs/_devices/Xiaomi_XMZNMS04LM.md similarity index 100% rename from docs/_devices/XMZNMS04LM.md rename to docs/_devices/Xiaomi_XMZNMS04LM.md diff --git a/docs/_devices/XMZNMS08LM.md b/docs/_devices/Xiaomi_XMZNMS08LM.md similarity index 100% rename from docs/_devices/XMZNMS08LM.md rename to docs/_devices/Xiaomi_XMZNMS08LM.md diff --git a/docs/_devices/XMZNMST02YD.md b/docs/_devices/Xiaomi_XMZNMST02YD.md similarity index 100% rename from docs/_devices/XMZNMST02YD.md rename to docs/_devices/Xiaomi_XMZNMST02YD.md diff --git a/docs/_devices/YLAI003.md b/docs/_devices/Xiaomi_YLAI003.md similarity index 100% rename from docs/_devices/YLAI003.md rename to docs/_devices/Xiaomi_YLAI003.md diff --git a/docs/_devices/YLKG07YL_YLKG08YL.md b/docs/_devices/Xiaomi_YLKG07YL_YLKG08YL.md similarity index 100% rename from docs/_devices/YLKG07YL_YLKG08YL.md rename to docs/_devices/Xiaomi_YLKG07YL_YLKG08YL.md diff --git a/docs/_devices/YLYB01YL-BHFRC.md b/docs/_devices/Xiaomi_YLYB01YL-BHFRC.md similarity index 100% rename from docs/_devices/YLYB01YL-BHFRC.md rename to docs/_devices/Xiaomi_YLYB01YL-BHFRC.md diff --git a/docs/_devices/YLYK01YL-FANCL.md b/docs/_devices/Xiaomi_YLYK01YL-FANCL.md similarity index 100% rename from docs/_devices/YLYK01YL-FANCL.md rename to docs/_devices/Xiaomi_YLYK01YL-FANCL.md diff --git a/docs/_devices/YLYK01YL-VENFAN.md b/docs/_devices/Xiaomi_YLYK01YL-VENFAN.md similarity index 100% rename from docs/_devices/YLYK01YL-VENFAN.md rename to docs/_devices/Xiaomi_YLYK01YL-VENFAN.md diff --git a/docs/_devices/YLYK01YL.md b/docs/_devices/Xiaomi_YLYK01YL.md similarity index 100% rename from docs/_devices/YLYK01YL.md rename to docs/_devices/Xiaomi_YLYK01YL.md diff --git a/docs/_devices/YM-K1501.md b/docs/_devices/Xiaomi_YM-K1501.md similarity index 100% rename from docs/_devices/YM-K1501.md rename to docs/_devices/Xiaomi_YM-K1501.md diff --git a/docs/_devices/ZNMS16LM.md b/docs/_devices/Xiaomi_ZNMS16LM.md similarity index 100% rename from docs/_devices/ZNMS16LM.md rename to docs/_devices/Xiaomi_ZNMS16LM.md diff --git a/docs/_devices/ZNMS17LM.md b/docs/_devices/Xiaomi_ZNMS17LM.md similarity index 100% rename from docs/_devices/ZNMS17LM.md rename to docs/_devices/Xiaomi_ZNMS17LM.md diff --git a/docs/assets/images/PTX.png b/docs/assets/images/PTX.png new file mode 100644 index 0000000000000000000000000000000000000000..9c7e60fca203d4c7a0844f5df3b870fbc781c6ae GIT binary patch literal 6209 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 rB6`IE&n}#L{QUpzr`yCH9|