Skip to content

Commit

Permalink
Merge pull request #1 from AlexxIT/master
Browse files Browse the repository at this point in the history
merge
  • Loading branch information
nesror authored Jul 22, 2023
2 parents 490f71c + 2f6956f commit f7f7bed
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 14 deletions.
1 change: 1 addition & 0 deletions custom_components/xiaomi_gateway3/core/converters/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@
BATTERY_LOW = {1: False, 2: True}
SWITCH_MODE = {1: "250 ms", 2: "500 ms", 3: "750 ms", 4: "1 sec"}
INVERSE = {0: True, 1: False}
INVERSE_BOOL = {False: True, True: False}
96 changes: 89 additions & 7 deletions custom_components/xiaomi_gateway3/core/converters/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,7 @@
EventConv("motion", mi="2.e.1008", value=True),
Converter("battery", mi="3.p.1003"),
],
},{
}, {
# https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:remote-control:0000A021:huca-wx8:1
12382: ["H+", "Wireless Button", "huca-wx8"],
"spec": [
Expand Down Expand Up @@ -1533,8 +1533,10 @@
10371: ["PTX", "Mesh Multifunction Wireless Switch", "090615.remote.mlsw0a"],
"spec": [
MiBeacon, BLEAction, Button, # don't know is it BLE or Mesh
EventConv("action", mi="2.e.1", value="click"),
EventConv("action", mi="3.e.2", value="hold"),
EventConv("action", mi="2.e.1", value="button_1_single"),
EventConv("action", mi="2.e.2", value="button_2_single"),
EventConv("action", mi="3.e.2", value="button_1_hold"),
EventConv("action", mi="3.e.3", value="button_2_hold"),
]
}, {
# https://home.miot-spec.com/spec/090615.remote.btsw1
Expand Down Expand Up @@ -1862,7 +1864,7 @@
Converter("switch", "switch", mi="2.p.1"), # bool
Converter("battery", "sensor", mi="3.p.1"), # percentage 0-100
Converter("supply", "sensor", mi="4.p.1"), # percentage 0-100
Converter("led", "switch", mi="9.p.1", enabled=False), # bool
MapConv("led", "switch", mi="9.p.1", map=INVERSE_BOOL, enabled=False), # bool
MapConv("power_mode", "select", mi="2.p.2", map={
0: "auto", 1: "battery", 2: "usb"
}, enabled=False)
Expand Down Expand Up @@ -1895,10 +1897,10 @@
Converter("mode", "switch", mi="2.p.2"), # int8
MathConv("chip_temperature", "sensor", mi="2.p.3", round=2,
enabled=False), # float
MathConv("energy", "sensor", mi="3.p.1", multiply=0.001, round=2),
MathConv("energy", "sensor", mi="3.p.1", multiply=0.1, round=2),
MathConv("power", "sensor", mi="3.p.2", round=2), # float
MathConv("voltage", "sensor", mi="3.p.3"), # float
MathConv("current", "sensor", mi="3.p.4"), # float
MathConv("voltage", "sensor", mi="3.p.3", multiply=0.001, round=2), # float
MathConv("current", "sensor", mi="3.p.4", multiply=0.001, round=2), # float
]
}, {
3129: ["Xiaomi", "Smart Curtain Motor", "MJSGCLBL01LM"],
Expand Down Expand Up @@ -1938,6 +1940,7 @@
],
}, {
11332: ["PTX", "Mesh Double Wall Switch", "090615.switch.aksk2"],
12471: ["PTX", "Mesh Double Wall Switch (no N)", "090615.switch.aksk2"],
"spec": [
Converter("channel_1", "switch", mi="2.p.1"),
Converter("channel_2", "switch", mi="3.p.1"),
Expand Down Expand Up @@ -2166,6 +2169,46 @@

Converter("compatible_mode", "switch", mi="7.p.4"),
],
}, {
# https://home.miot-spec.com/s/5045
2428: ["Linptech", "Lingpu Single Wall Switch", "linp.switch.q3s1"],
"spec": [
Converter("channel_1", "switch", mi="2.p.1"),
Converter("action", "sensor", enabled=False),

ButtonMIConv("button_1", mi="7.e.1", value=1),

Converter("led", "switch", mi="5.p.1"),
],
}, {
# https://home.miot-spec.com/s/5045
2429: ["Linptech", "Lingpu Double Wall Switch", "linp.switch.q3s2"],
"spec": [
Converter("channel_1", "switch", mi="2.p.1"),
Converter("channel_2", "switch", mi="3.p.1"),

Converter("action", "sensor", enabled=False),

ButtonMIConv("button_1", mi="7.e.1", value=1),
ButtonMIConv("button_2", mi="7.e.2", value=1),

Converter("led", "switch", mi="5.p.1"),
],
}, {
2274: ["Linptech", "Lingpu Triple Wall Switch", "linp.switch.q3s3"],
"spec": [
Converter("channel_1", "switch", mi="2.p.1"),
Converter("channel_2", "switch", mi="3.p.1"),
Converter("channel_3", "switch", mi="4.p.1"),

Converter("action", "sensor", enabled=False),

ButtonMIConv("button_1", mi="7.e.1", value=1),
ButtonMIConv("button_2", mi="7.e.2", value=1),
ButtonMIConv("button_3", mi="7.e.3", value=1),

Converter("led", "switch", mi="5.p.1"),
],
}, {
# https://home.miot-spec.com/spec/chuangmi.switch.mesh
1350: ["Chuangmi", "Single Wall Switch K1-A (with N)", "chuangmi.switch.mesh"],
Expand All @@ -2191,6 +2234,16 @@
Action,
ButtonMIConv("button", mi="3.e.1", value=1),
]
}, {
10939: ["Linptech", "Sliding Window Driver WD1", "WD1"],
"spec": [
MapConv("motor", "cover", mi="2.p.1", map={
0: "stop", 1: "open", 2: "close"
}),
Converter("target_position", mi="2.p.3"),
CurtainPosConv("position", mi="2.p.2", parent="motor"),
Converter("battery", "sensor", mi="3.p.1"),
],
}, {
# https://home.miot-spec.com/spec/yeelink.curtain.crc1
10813: ["Yeelink", "Curtain Motor C1", "YCCBCI008"],
Expand All @@ -2203,6 +2256,23 @@
0: "default", 1: "doublmode", 2: "leftmode", 3: "rightmode"
}, enabled=False),
]
}, {
4722: ["Xiaomi", "Curtain Motor", "MJZNCL02LM"],
"spec": [
MapConv("motor", "cover", mi="2.p.1", map={
0: "stop", 1: "open", 2: "close"
}),
Converter("target_position", mi="2.p.2"),
CurtainPosConv("position", mi="2.p.6", parent="motor"),
MapConv("run_state", mi="2.p.3", parent="motor", map={
0: "stop", 1: "opening", 2: "closing", 3: "busy"
}),
Converter("battery", "sensor", mi="5.p.1"), # percent
Converter("motor_reverse", "switch", mi="2.p.5", enabled=False),
MapConv("battery_charging", "binary_sensor", mi="5.p.2", map={
1: True, 2: False, 3: False,
}, enabled=False),
],
}, {
# https://home.miot-spec.com/spec/giot.light.v5ssm
11724: ["GranwinIoT", "Mesh Light V5", "giot.light.v5ssm"],
Expand Down Expand Up @@ -2255,6 +2325,18 @@
# Converter("fill_light_switch", "switch", mi="3.p.21"),
# MathConv("min_bri_factory", "number", mi="3.p.16", min=1, max=500),
]
}, {
# https://home.miot-spec.com/spec/opple.light.barelp
3661: ["Opple", "Bare Light Panel", "opple.light.barelp"],
"spec": [
Converter("light", "light", mi="2.p.1"),
BrightnessConv("brightness", mi="2.p.2", parent="light", max=100),
ColorTempKelvin("color_temp", mi="2.p.3", parent="light", mink=3000, maxk=5700),
MapConv("mode", "select", mi="2.p.4", map={
0: "Reception", 1: "Entertainment", 2: "Cinema", 3: "Night", 4: "Wakeup", 5: "Sleep",
6: "Sunset", 7: "None", 8: "Invert"
}),
],
}, {
"default": "mesh", # default Mesh device
"spec": [
Expand Down
5 changes: 5 additions & 0 deletions custom_components/xiaomi_gateway3/core/converters/silabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ def decode(data: dict):
"ieee": args[1],
"nwk": args[2],
}
elif hdr.command_id == ZDOCmd.Mgmt_Lqi_req:
# https://docs.silabs.com/zigbee/6.5/af_v2/group-zdo
return {"command": cmd, "start_index": args[0]}
elif hdr.command_id == ZDOCmd.Mgmt_Lqi_rsp:
return {"command": cmd}
else:
raise NotImplemented

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ class ZXiaomiBrightnessConv(Converter):
"""

def decode(self, device: "XDevice", payload: dict, value: Any):
payload[self.attr] = value / 100.0 * 255.0
payload[self.attr] = max (0, min(255, round(value / 100.0 * 255.0)))

def encode(self, device: "XDevice", payload: dict, value: Any):
# brightness and transition in seconds
Expand Down
4 changes: 3 additions & 1 deletion custom_components/xiaomi_gateway3/core/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,11 @@ def update(self, value: dict):

if self.lazy_setup:
for attr in self.lazy_setup & attrs:
self.lazy_setup.remove(attr)
conv = next(c for c in self.converters if c.attr == attr)
gateway = self.gateways[0]
if conv.domain not in gateway.setups:
return
self.lazy_setup.remove(attr)
gateway.setups[conv.domain](gateway, self, conv)

for entity in self.entities.values():
Expand Down
3 changes: 2 additions & 1 deletion custom_components/xiaomi_gateway3/core/ezsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ async def read_firmware(host: str) -> Optional[str]:
# noinspection PyProtectedMember
await asyncio.wait_for(ezsp._probe(), timeout=10)
_, _, version = await ezsp.get_board_info()
except asyncio.TimeoutError:
except Exception as e:
_LOGGER.debug(f"{host} [FWUP] Read firmware error: {e}")
return None
finally:
ezsp.close()
Expand Down
6 changes: 4 additions & 2 deletions custom_components/xiaomi_gateway3/core/shell/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ async def check_bin(self, filename: str, md5: str, url: str) -> int:
if md5 in await self.exec(cmd):
return OK

# if there is an old version of the file
await self.exec("killall " + filename)
# better not to kill busybox :)
if filename != "busybox":
# if there is an old version of the file
await self.exec("killall " + filename)

raw = await download(url)
await self.write_file(filepath, raw)
Expand Down
2 changes: 1 addition & 1 deletion custom_components/xiaomi_gateway3/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"requirements": [
"zigpy>=0.44.1"
],
"version": "3.3.1",
"version": "3.3.2",
"iot_class": "local_push"
}
2 changes: 1 addition & 1 deletion custom_components/xiaomi_gateway3/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def available(self):
@callback
def async_update_available(self):
super().async_update_available()
self._attr_extra_state_attributes["available"] = self.available
self._attr_extra_state_attributes["available"] = self._attr_available

async def async_added_to_hass(self):
await super().async_added_to_hass()
Expand Down
16 changes: 16 additions & 0 deletions tests/test_conv_ble.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from homeassistant.components.sensor import DOMAIN

from custom_components.xiaomi_gateway3.core.device import XDevice, BLE
from custom_components.xiaomi_gateway3.core.gateway.base import GatewayBase

assert DOMAIN # fix circular import

Expand Down Expand Up @@ -296,3 +297,18 @@ def test_10249():
]
)
assert p == {"action": "doorbell", "timestamp": 1681029598}


def test_lazy_setup():
device = XDevice(BLE, 9538, DID, MAC)
assert device.info.name == "Xiaomi TH Clock Pro"
device.setup_converters()

gw = GatewayBase()
gw.options = {}
gw.setups = {}
gw.add_device(device.did, device)

# https://github.com/AlexxIT/XiaomiGateway3/issues/1095
payload = device.decode("mibeacon", {"eid": 18435, "edata": "64"})
device.update(payload)

0 comments on commit f7f7bed

Please sign in to comment.