diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d83e90d88b..cb700fb337 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,20 +1,42 @@ -## Initial Contribution Guidelines - WIP +# Initial Contribution Guidelines - WIP -- Capture the SimpleDescriptor log entries for each endpoint on the device. These can be found in the HA logs after joining a device and they look like this: ``. This information can also be obtained from the zigbee.db if you want to take the time to query the tables and reconstitute the log entry. I find it easier to just remove and rejoin the device. ZHA entity ids are stable for the most part so it *shouldn't* disrupt anything you have configured. These need to match what the device reports EXACTLY or zigpy will not match them when a device joins and the handler will not be used for the device. +- All code is formatted with black. The check format script that runs in CI will ensure that code meets this requirement and that it is correctly formatted with black. Instructions for installing black in many editors can be found here: + +- Capture the SimpleDescriptor log entries for each endpoint on the device. These can be found in the HA logs after joining a device and they look like this: ``. This information can also be obtained from the zigbee.db if you want to take the time to query the tables and reconstitute the log entry. I find it easier to just remove and rejoin the device. ZHA entity ids are stable for the most part so it _shouldn't_ disrupt anything you have configured. These need to match what the device reports EXACTLY or zigpy will not match them when a device joins and the handler will not be used for the device. - Create a device class extending CustomDevice or a derivitave of it -- Use an existing handler as a guide. signature and replacement dicts are required. Include the SimpleDescriptor entry for each endpoint in the signature dict above the definition of the endpoint in this format: +- All custom cluster definitions must extend CustomCluster + +- Use an existing handler as a guide. signature and replacement dicts are required. Include the SimpleDescriptor entry for each endpoint in the signature dict above the definition of the endpoint in this format: + + ```yaml + # + ``` + +- Use constants for all attribute values referencing the appropriate labels from Zigpy / HA as necessary + +- how `device_automation_triggers` work: + + Device automation triggers are essentially representations of the events that the devices fire in HA. They allow users to use actions in the UI instead of using the raw events. Ex: For the Hue remote - the on button fires this event: + + `` + + and the action defined for this is: + + `(SHORT_PRESS, TURN_ON): {COMMAND: COMMAND_ON}` + + The first part `(SHORT_PRESS, TURN_ON)` corresponds to the txt the user will see in the UI: - ```yaml + image - # + The second part is the event data. You only need to supply enough of the event data to uniquely match the event which in this case is just the command for this event fired by this device: `{COMMAND: COMMAND_ON}` - ``` + If you look at another example for the same device: -- manufacturer and model are required on EVERY replacement endpoint definition and they NEED to match what the device reports to HA. + `(SHORT_PRESS, DIM_UP): {COMMAND: COMMAND_STEP, CLUSTER_ID: 8, ENDPOINT_ID: 1, ARGS: [0, 30, 9],}` -- Use constants for all attribute values referencing the appropriate labels from Zigpy / HA as necessary \ No newline at end of file + you can see a pattern that illustrates how to match a more complex event. In this case the step command is used for the dim up and dim down buttons so we need to match more of the event data to uniquely match the event. diff --git a/Contributors.md b/Contributors.md index 5be554caa1..42735ae90e 100644 --- a/Contributors.md +++ b/Contributors.md @@ -1,18 +1,20 @@ # Contributors -- [David F. Mulcahey] (https://github.com/dmulcahey) -- [roblandry] (https://github.com/roblandry) -- [presslab-us] (https://github.com/presslab-us) -- [Alexei Chetroi] (https://github.com/Adminiuga) -- [Abílio Costa] (https://github.com/abmantis) -- [Andreas Setterlind] (https://github.com/Gamester17) -- [prairiesnpr] (https://github.com/prairiesnpr) -- [Daniel Lashua] (https://github.com/dlashua) -- [bballwiz5] (https://github.com/bballwiz5) -- [Ross Patterson] (https://github.com/rpatterson) -- [Marc Egli] (https://github.com/frog32) -- [Dinko Bajric] (https://github.com/dbajric) -- [brg468] (https://github.com/brg468) -- [James Riley] (https://github.com/Thalagyrt) -- [Shulyaka] (https://github.com/Shulyaka) -- [Nemesis24] (https://github.com/Nemesis24) + +- [David F. Mulcahey](https://github.com/dmulcahey) +- [roblandry](https://github.com/roblandry) +- [presslab-us](https://github.com/presslab-us) +- [Alexei Chetroi](https://github.com/Adminiuga) +- [Abílio Costa](https://github.com/abmantis) +- [Andreas Setterlind](https://github.com/Gamester17) +- [prairiesnpr](https://github.com/prairiesnpr) +- [Daniel Lashua](https://github.com/dlashua) +- [bballwiz5](https://github.com/bballwiz5) +- [Ross Patterson](https://github.com/rpatterson) +- [Marc Egli](https://github.com/frog32) +- [Dinko Bajric](https://github.com/dbajric) +- [brg468](https://github.com/brg468) +- [James Riley](https://github.com/Thalagyrt) +- [Shulyaka](https://github.com/Shulyaka) +- [Nemesis24](https://github.com/Nemesis24) - [Andy Zickler](https://github.com/andyzickler) +- [Piotr Majkrzak](https://github.com/majkrzak) diff --git a/README.md b/README.md index 00c60f1765..dcd3c5166b 100644 --- a/README.md +++ b/README.md @@ -127,8 +127,25 @@ Please refer to [xbee.md](xbee.md) for details on configuration and usage exampl - All supported devices report battery level -### Thanks +# Thanks - Special thanks to damarco for the majority of the device tracker code - Special thanks to Yoda-x for the Xioami attribute parsing code - Special thanks to damarco and Adminiuga for allowing me to bounce ideas off of them and for listening to me ramble + +# Related projects + +### Zigpy +**[zigpy](https://github.com/zigpy/zigpy)** is **[Zigbee protocol stack](https://en.wikipedia.org/wiki/Zigbee)** integration project to implement the **[Zigbee Home Automation](https://www.zigbee.org/)** standard as a Python 3 library. Zigbee Home Automation integration with zigpy allows you to connect one of many off-the-shelf Zigbee adapters using one of the available Zigbee radio library modules compatible with zigpy to control Zigbee based devices. There is currently support for controlling Zigbee device types such as binary sensors (e.g., motion and door sensors), sensors (e.g., temperature sensors), lightbulbs, switches, locks, fans, covers (blinds, marquees, and more). A working implementation of zigpy exist in **[Home Assistant](https://www.home-assistant.io)** (Python based open source home automation software) as part of its **[ZHA component](https://www.home-assistant.io/components/zha/)** + +### ZHA Map +[zha-map](https://github.com/zha-ng/zha-map) project allow building a Zigbee network topology map for ZHA component in Home Assistant. + +### zha-network-visualization-card +[zha-network-visualization-card](https://github.com/dmulcahey/zha-network-visualization-card) is a custom Lovelace element for visualizing the Zigbee network map for ZHA component in Home Assistant. + +### ZHA Network Card +[zha-network-card](https://github.com/dmulcahey/zha-network-card) is a custom Lovelace card that displays ZHA network and device information in Home Assistant + +### zigpy-deconz-parser +[zigpy-deconz-parser](https://github.com/zha-ng/zigpy-deconz-parser) project can parse Home Assistant ZHA component debug log using `zigpy-deconz` library if you have ConBee or RaspBee hardware. diff --git a/setup.py b/setup.py index e33db2495c..56eeddd6cb 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import find_packages, setup -VERSION = "0.0.32" +VERSION = "0.0.33" def readme(): diff --git a/zhaquirks/centralite/3460L.py b/zhaquirks/centralite/3460L.py index eb6afa4e49..0ded4cc5bd 100755 --- a/zhaquirks/centralite/3460L.py +++ b/zhaquirks/centralite/3460L.py @@ -15,12 +15,18 @@ from zhaquirks import PowerConfigurationCluster from zhaquirks.centralite import CENTRALITE from zhaquirks.const import ( + BUTTON_1, + COMMAND, + COMMAND_OFF, + COMMAND_ON, DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SHORT_PRESS, + SHORT_RELEASE, ) DIAGNOSTICS_CLUSTER_ID = 0x0B05 # decimal = 2821 @@ -85,3 +91,8 @@ class CentraLite3460L(CustomDevice): } } } + + device_automation_triggers = { + (SHORT_PRESS, BUTTON_1): {COMMAND: COMMAND_ON}, + (SHORT_RELEASE, BUTTON_1): {COMMAND: COMMAND_OFF}, + } diff --git a/zhaquirks/const.py b/zhaquirks/const.py index 37e5af933a..2faefe6da1 100644 --- a/zhaquirks/const.py +++ b/zhaquirks/const.py @@ -69,6 +69,8 @@ RIGHT = "right" SHAKEN = "device_shaken" SHORT_PRESS = "remote_button_short_press" +SKIP_CONFIGURATION = "skip_configuration" +SHORT_RELEASE = "remote_button_short_release" TRIPLE_PRESS = "remote_button_triple_press" TURN_OFF = "turn_off" TURN_ON = "turn_on" diff --git a/zhaquirks/ikea/__init__.py b/zhaquirks/ikea/__init__.py index 9cdc7517e2..8ebe29a319 100644 --- a/zhaquirks/ikea/__init__.py +++ b/zhaquirks/ikea/__init__.py @@ -19,7 +19,13 @@ async def bind(self): _LOGGER.warning("Aborting - unable to locate required coordinator device.") return group_list = await self.get_group_identifiers(0) - group_record = group_list[2] - group_id = group_record[0].group_id + try: + group_record = group_list[2] + group_id = group_record[0].group_id + except IndexError: + _LOGGER.warning( + "unable to locate required group info - falling back to group 0x0000." + ) + group_id = 0x0000 status = await coordinator.add_to_group(group_id) return [status] diff --git a/zhaquirks/ikea/motionzha.py b/zhaquirks/ikea/motionzha.py index 7ebd33e7f2..6122c38b64 100644 --- a/zhaquirks/ikea/motionzha.py +++ b/zhaquirks/ikea/motionzha.py @@ -1,6 +1,6 @@ """Device handler for IKEA of Sweden TRADFRI remote control.""" from zigpy.profiles import zha -from zigpy.quirks import CustomCluster, CustomDevice +from zigpy.quirks import CustomDevice from zigpy.zcl.clusters.general import ( Alarms, Basic, @@ -29,20 +29,6 @@ DIAGNOSTICS_CLUSTER_ID = 0x0B05 # decimal = 2821 -class LightLinkClusterNew(CustomCluster, LightLink): - """Ikea LightLink cluster.""" - - async def bind(self): - """Bind LightLink cluster to coordinator.""" - application = self._endpoint.device.application - try: - coordinator = application.get_device(application.ieee) - except KeyError: - return - status = await coordinator.add_to_group(0x0000) - return [status] - - class IkeaTradfriMotion(CustomDevice): """Custom device representing IKEA of Sweden TRADFRI remote control.""" @@ -145,7 +131,7 @@ class IkeaTradfriMotionE1745(CustomDevice): Identify.cluster_id, Alarms.cluster_id, PollControl.cluster_id, - LightLinkClusterNew, + LightLinkCluster, IKEA_CLUSTER_ID, ], OUTPUT_CLUSTERS: [ diff --git a/zhaquirks/ikea/twobtnremote.py b/zhaquirks/ikea/twobtnremote.py index eaa4ad0e1e..acd9e4a2c8 100644 --- a/zhaquirks/ikea/twobtnremote.py +++ b/zhaquirks/ikea/twobtnremote.py @@ -1,6 +1,6 @@ """Device handler for IKEA of Sweden TRADFRI remote control.""" from zigpy.profiles import zha, zll -from zigpy.quirks import CustomCluster, CustomDevice +from zigpy.quirks import CustomDevice from zigpy.zcl.clusters.closures import WindowCovering from zigpy.zcl.clusters.general import ( Alarms, @@ -15,7 +15,7 @@ ) from zigpy.zcl.clusters.lightlink import LightLink -from . import IKEA +from . import IKEA, LightLinkCluster from .. import DoublingPowerConfigurationCluster from ..const import ( ARGS, @@ -43,20 +43,6 @@ IKEA_CLUSTER_ID = 0xFC7C # decimal = 64636 -class LightLinkCluster(CustomCluster, LightLink): - """Ikea LightLink cluster.""" - - async def bind(self): - """Bind LightLink cluster to coordinator.""" - application = self._endpoint.device.application - try: - coordinator = application.get_device(application.ieee) - except KeyError: - return - status = await coordinator.add_to_group(0x0000) - return [status] - - class IkeaTradfriRemote2Btn(CustomDevice): """Custom device representing IKEA of Sweden TRADFRI remote control.""" diff --git a/zhaquirks/konke/__init__.py b/zhaquirks/konke/__init__.py new file mode 100644 index 0000000000..8e71e1dbc6 --- /dev/null +++ b/zhaquirks/konke/__init__.py @@ -0,0 +1,70 @@ +"""Konke sensors.""" + +import asyncio + +from zigpy.quirks import CustomCluster +from zigpy.zcl.clusters.measurement import OccupancySensing +from zigpy.zcl.clusters.security import IasZone + +from .. import LocalDataCluster +from ..const import CLUSTER_COMMAND, OFF, ON, ZONE_STATE + +KONKE = "Konke" +OCCUPANCY_STATE = 0 +OCCUPANCY_EVENT = "occupancy_event" +MOTION_TYPE = 0x000D +ZONE_TYPE = 0x0001 + +MOTION_TIME = 60 +OCCUPANCY_TIME = 600 + + +class OccupancyCluster(LocalDataCluster, OccupancySensing): + """Occupancy cluster.""" + + cluster_id = OccupancySensing.cluster_id + + def __init__(self, *args, **kwargs): + """Init.""" + super().__init__(*args, **kwargs) + self._timer_handle = None + self.endpoint.device.occupancy_bus.add_listener(self) + + def occupancy_event(self): + """Occupancy event.""" + self._update_attribute(OCCUPANCY_STATE, ON) + + if self._timer_handle: + self._timer_handle.cancel() + + loop = asyncio.get_event_loop() + self._timer_handle = loop.call_later(OCCUPANCY_TIME, self._turn_off) + + def _turn_off(self): + self._timer_handle = None + self._update_attribute(OCCUPANCY_STATE, OFF) + + +class MotionCluster(CustomCluster, IasZone): + """Motion cluster.""" + + cluster_id = IasZone.cluster_id + + def __init__(self, *args, **kwargs): + """Init.""" + super().__init__(*args, **kwargs) + self._timer_handle = None + + def handle_cluster_request(self, tsn, command_id, args): + """Handle the cluster command.""" + if command_id == 0: + if self._timer_handle: + self._timer_handle.cancel() + loop = asyncio.get_event_loop() + self._timer_handle = loop.call_later(MOTION_TIME, self._turn_off) + self.endpoint.device.occupancy_bus.listener_event(OCCUPANCY_EVENT) + + def _turn_off(self): + self._timer_handle = None + self.listener_event(CLUSTER_COMMAND, 999, 0, [0, 0, 0, 0]) + self._update_attribute(ZONE_STATE, OFF) diff --git a/zhaquirks/konke/motion.py b/zhaquirks/konke/motion.py new file mode 100644 index 0000000000..c74638f537 --- /dev/null +++ b/zhaquirks/konke/motion.py @@ -0,0 +1,70 @@ +"""Konke motion sensor.""" + +from zigpy.profiles import zha +from zigpy.quirks import CustomDevice +from zigpy.zcl.clusters.general import Basic, Identify, PowerConfiguration +from zigpy.zcl.clusters.security import IasZone + +from . import KONKE, MotionCluster, OccupancyCluster +from .. import Bus +from ..const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + MODELS_INFO, + OUTPUT_CLUSTERS, + PROFILE_ID, +) + +KONKE_CLUSTER_ID = 0xFCC0 + + +class KonkeMotion(CustomDevice): + """Custom device representing konke motion sensors.""" + + def __init__(self, *args, **kwargs): + """Init.""" + self.occupancy_bus = Bus() + super().__init__(*args, **kwargs) + + signature = { + # + MODELS_INFO: [ + (KONKE, "3AFE28010402000D"), + (KONKE, "3AFE14010402000D"), + (KONKE, "3AFE27010402000D"), + ], + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.IAS_ZONE, + INPUT_CLUSTERS: [ + Basic.cluster_id, + PowerConfiguration.cluster_id, + Identify.cluster_id, + IasZone.cluster_id, + KONKE_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [Identify.cluster_id, KONKE_CLUSTER_ID], + } + }, + } + + replacement = { + ENDPOINTS: { + 1: { + INPUT_CLUSTERS: [ + Basic.cluster_id, + PowerConfiguration.cluster_id, + Identify.cluster_id, + OccupancyCluster, + MotionCluster, + KONKE_CLUSTER_ID, + ], + OUTPUT_CLUSTERS: [Identify.cluster_id, KONKE_CLUSTER_ID], + } + } + } diff --git a/zhaquirks/philips/rom001.py b/zhaquirks/philips/rom001.py new file mode 100644 index 0000000000..d517c0c86b --- /dev/null +++ b/zhaquirks/philips/rom001.py @@ -0,0 +1,95 @@ +"""Phillips ROM001 device.""" +from zigpy.profiles import zha +from zigpy.quirks import CustomDevice +from zigpy.zcl.clusters.general import ( + Basic, + Groups, + Identify, + LevelControl, + OnOff, + Ota, + PowerConfiguration, + Scenes, +) +from zigpy.zcl.clusters.lightlink import LightLink + +from ..const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + OUTPUT_CLUSTERS, + PROFILE_ID, + SHORT_PRESS, + TURN_ON, + TURN_OFF, + COMMAND, + COMMAND_ON, + COMMAND_OFF_WITH_EFFECT, +) + +DEVICE_SPECIFIC_UNKNOWN = 64512 + + +class PhilipsROM001(CustomDevice): + """Phillips ROM001 device.""" + + signature = { + # + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.NON_COLOR_SCENE_CONTROLLER, + INPUT_CLUSTERS: [ + Basic.cluster_id, + PowerConfiguration.cluster_id, + Identify.cluster_id, + DEVICE_SPECIFIC_UNKNOWN, + LightLink.cluster_id, + ], + OUTPUT_CLUSTERS: [ + Ota.cluster_id, + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + OnOff.cluster_id, + LevelControl.cluster_id, + Scenes.cluster_id, + LightLink.cluster_id, + ], + } + } + } + + replacement = { + ENDPOINTS: { + 1: { + PROFILE_ID: zha.PROFILE_ID, + DEVICE_TYPE: zha.DeviceType.NON_COLOR_SCENE_CONTROLLER, + INPUT_CLUSTERS: [ + Basic.cluster_id, + PowerConfiguration.cluster_id, + Identify.cluster_id, + DEVICE_SPECIFIC_UNKNOWN, + LightLink.cluster_id, + ], + OUTPUT_CLUSTERS: [ + Ota.cluster_id, + Basic.cluster_id, + Identify.cluster_id, + Groups.cluster_id, + OnOff.cluster_id, + LevelControl.cluster_id, + Scenes.cluster_id, + LightLink.cluster_id, + ], + } + } + } + + device_automation_triggers = { + (SHORT_PRESS, TURN_ON): {COMMAND: COMMAND_ON}, + (SHORT_PRESS, TURN_OFF): {COMMAND: COMMAND_OFF_WITH_EFFECT}, + } diff --git a/zhaquirks/xiaomi/aqara/cube.py b/zhaquirks/xiaomi/aqara/cube.py index 4892689cc0..89facbad45 100644 --- a/zhaquirks/xiaomi/aqara/cube.py +++ b/zhaquirks/xiaomi/aqara/cube.py @@ -11,7 +11,6 @@ Scenes, ) -from .. import LUMI, BasicCluster, PowerConfigurationCluster, XiaomiCustomDevice from ... import CustomCluster from ...const import ( ARGS, @@ -23,10 +22,12 @@ OUTPUT_CLUSTERS, PROFILE_ID, SHAKEN, + SKIP_CONFIGURATION, TURN_ON, VALUE, ZHA_SEND_EVENT, ) +from .. import LUMI, BasicCluster, PowerConfigurationCluster, XiaomiCustomDevice ACTIVATED_FACE = "activated_face" DESCRIPTION = "description" @@ -276,6 +277,7 @@ def _update_attribute(self, attrid, value): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: XIAOMI_SENSORS_REPLACEMENT, @@ -314,7 +316,7 @@ def _update_attribute(self, attrid, value): AnalogInput.cluster_id, ], }, - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/aqara/cube_aqgl01.py b/zhaquirks/xiaomi/aqara/cube_aqgl01.py index 95bdd3abab..9d4930dea6 100644 --- a/zhaquirks/xiaomi/aqara/cube_aqgl01.py +++ b/zhaquirks/xiaomi/aqara/cube_aqgl01.py @@ -23,6 +23,7 @@ OUTPUT_CLUSTERS, PROFILE_ID, SHAKEN, + SKIP_CONFIGURATION, TURN_ON, VALUE, ZHA_SEND_EVENT, @@ -276,6 +277,7 @@ def _update_attribute(self, attrid, value): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: XIAOMI_SENSORS_REPLACEMENT, @@ -314,7 +316,7 @@ def _update_attribute(self, attrid, value): AnalogInput.cluster_id, ], }, - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/aqara/magnet_aq2.py b/zhaquirks/xiaomi/aqara/magnet_aq2.py index 13709f776e..c9ae8d3130 100644 --- a/zhaquirks/xiaomi/aqara/magnet_aq2.py +++ b/zhaquirks/xiaomi/aqara/magnet_aq2.py @@ -12,6 +12,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) OPEN_CLOSE_DEVICE_TYPE = 0x5F01 @@ -53,6 +54,7 @@ def __init__(self, *args, **kwargs): }, } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { INPUT_CLUSTERS: [ @@ -68,5 +70,5 @@ def __init__(self, *args, **kwargs): XIAOMI_CLUSTER_ID, ], } - } + }, } diff --git a/zhaquirks/xiaomi/aqara/motion_aq2.py b/zhaquirks/xiaomi/aqara/motion_aq2.py index 3f92fd4400..d707f5c48d 100644 --- a/zhaquirks/xiaomi/aqara/motion_aq2.py +++ b/zhaquirks/xiaomi/aqara/motion_aq2.py @@ -22,6 +22,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) XIAOMI_CLUSTER_ID = 0xFFFF @@ -61,6 +62,7 @@ def __init__(self, *args, **kwargs): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { INPUT_CLUSTERS: [ @@ -74,5 +76,5 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [Basic.cluster_id, Ota.cluster_id], } - } + }, } diff --git a/zhaquirks/xiaomi/aqara/motion_aq2b.py b/zhaquirks/xiaomi/aqara/motion_aq2b.py index d2199b0c8a..08fcea33a6 100644 --- a/zhaquirks/xiaomi/aqara/motion_aq2b.py +++ b/zhaquirks/xiaomi/aqara/motion_aq2b.py @@ -14,6 +14,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) XIAOMI_CLUSTER_ID = 0xFFFF @@ -50,6 +51,7 @@ def __init__(self, *args, **kwargs): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { INPUT_CLUSTERS: [ @@ -61,5 +63,5 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [Basic.cluster_id, Ota.cluster_id], } - } + }, } diff --git a/zhaquirks/xiaomi/aqara/plug.py b/zhaquirks/xiaomi/aqara/plug.py index f11a530538..6a8e5c93ba 100644 --- a/zhaquirks/xiaomi/aqara/plug.py +++ b/zhaquirks/xiaomi/aqara/plug.py @@ -18,6 +18,13 @@ ) from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement +from .. import ( + LUMI, + POWER_REPORTED, + BasicCluster, + ElectricalMeasurementCluster, + XiaomiCustomDevice, +) from ... import Bus, CustomCluster from ...const import ( DEVICE_TYPE, @@ -26,13 +33,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, -) -from .. import ( - LUMI, - POWER_REPORTED, - BasicCluster, - ElectricalMeasurementCluster, - XiaomiCustomDevice, + SKIP_CONFIGURATION, ) _LOGGER = logging.getLogger(__name__) @@ -121,6 +122,7 @@ def __init__(self, *args, **kwargs): }, } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, @@ -157,5 +159,5 @@ def __init__(self, *args, **kwargs): INPUT_CLUSTERS: [BinaryInput.cluster_id], OUTPUT_CLUSTERS: [BinaryInput.cluster_id, Groups.cluster_id], }, - } + }, } diff --git a/zhaquirks/xiaomi/aqara/relay.py b/zhaquirks/xiaomi/aqara/relay.py index af8c17f913..8ce47ddad3 100644 --- a/zhaquirks/xiaomi/aqara/relay.py +++ b/zhaquirks/xiaomi/aqara/relay.py @@ -17,6 +17,13 @@ ) from zigpy.zcl.clusters.homeautomation import ElectricalMeasurement +from .. import ( + LUMI, + POWER_REPORTED, + BasicCluster, + ElectricalMeasurementCluster, + XiaomiCustomDevice, +) from ... import Bus, CustomCluster from ...const import ( DEVICE_TYPE, @@ -25,13 +32,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, -) -from .. import ( - LUMI, - POWER_REPORTED, - BasicCluster, - ElectricalMeasurementCluster, - XiaomiCustomDevice, + SKIP_CONFIGURATION, ) _LOGGER = logging.getLogger(__name__) @@ -106,6 +107,7 @@ def __init__(self, *args, **kwargs): }, } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { PROFILE_ID: zha.PROFILE_ID, @@ -136,5 +138,5 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [], }, - } + }, } diff --git a/zhaquirks/xiaomi/aqara/remote_b186acn01.py b/zhaquirks/xiaomi/aqara/remote_b186acn01.py index 1a204f1055..0eb5ac458f 100644 --- a/zhaquirks/xiaomi/aqara/remote_b186acn01.py +++ b/zhaquirks/xiaomi/aqara/remote_b186acn01.py @@ -27,6 +27,7 @@ PRESS_TYPE, PROFILE_ID, SHORT_PRESS, + SKIP_CONFIGURATION, VALUE, ZHA_SEND_EVENT, ) @@ -136,6 +137,7 @@ def _update_attribute(self, attrid, value): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: XIAOMI_DEVICE_TYPE, @@ -178,7 +180,7 @@ def _update_attribute(self, attrid, value): MultistateInputCluster, ], }, - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/aqara/remote_b286acn01.py b/zhaquirks/xiaomi/aqara/remote_b286acn01.py index 0c3e413864..accc3c23df 100644 --- a/zhaquirks/xiaomi/aqara/remote_b286acn01.py +++ b/zhaquirks/xiaomi/aqara/remote_b286acn01.py @@ -31,6 +31,7 @@ PRESS_TYPE, PROFILE_ID, SHORT_PRESS, + SKIP_CONFIGURATION, VALUE, ZHA_SEND_EVENT, ) @@ -149,6 +150,7 @@ def _update_attribute(self, attrid, value): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: XIAOMI_DEVICE_TYPE, @@ -191,7 +193,7 @@ def _update_attribute(self, attrid, value): MultistateInputCluster, ], }, - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/aqara/sensor_swit.py b/zhaquirks/xiaomi/aqara/sensor_swit.py index 0ff0c1d4e6..eccf3fb7ce 100644 --- a/zhaquirks/xiaomi/aqara/sensor_swit.py +++ b/zhaquirks/xiaomi/aqara/sensor_swit.py @@ -24,6 +24,7 @@ PROFILE_ID, SHAKEN, SHORT_PRESS, + SKIP_CONFIGURATION, VALUE, ZHA_SEND_EVENT, ) @@ -94,6 +95,7 @@ def _update_attribute(self, attrid, value): }, } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL, @@ -104,7 +106,7 @@ def _update_attribute(self, attrid, value): ], OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id], } - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/aqara/sensor_switch_aq3.py b/zhaquirks/xiaomi/aqara/sensor_switch_aq3.py index 6bc02a4543..39e9187762 100644 --- a/zhaquirks/xiaomi/aqara/sensor_switch_aq3.py +++ b/zhaquirks/xiaomi/aqara/sensor_switch_aq3.py @@ -2,7 +2,7 @@ import logging from zigpy.profiles import zha -from zigpy.zcl.clusters.general import Basic, MultistateInput, OnOff, Identify +from zigpy.zcl.clusters.general import Basic, Identify, MultistateInput, OnOff from .. import LUMI, BasicCluster, PowerConfigurationCluster, XiaomiCustomDevice from ... import CustomCluster @@ -24,6 +24,7 @@ PROFILE_ID, SHAKEN, SHORT_PRESS, + SKIP_CONFIGURATION, VALUE, ZHA_SEND_EVENT, ) @@ -98,6 +99,7 @@ class SwitchAQ3(XiaomiCustomDevice): }, } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL, @@ -108,7 +110,7 @@ class SwitchAQ3(XiaomiCustomDevice): ], OUTPUT_CLUSTERS: [Basic.cluster_id, OnOff.cluster_id], } - } + }, } device_automation_triggers = { @@ -143,6 +145,7 @@ class SwitchAQ3B(XiaomiCustomDevice): }, } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL, @@ -153,7 +156,7 @@ class SwitchAQ3B(XiaomiCustomDevice): ], OUTPUT_CLUSTERS: [Basic.cluster_id], } - } + }, } device_automation_triggers = SwitchAQ3.device_automation_triggers diff --git a/zhaquirks/xiaomi/aqara/switch_aq2.py b/zhaquirks/xiaomi/aqara/switch_aq2.py index 6cb8842532..87dd2c3956 100644 --- a/zhaquirks/xiaomi/aqara/switch_aq2.py +++ b/zhaquirks/xiaomi/aqara/switch_aq2.py @@ -22,6 +22,7 @@ OUTPUT_CLUSTERS, PROFILE_ID, SHORT_PRESS, + SKIP_CONFIGURATION, TRIPLE_PRESS, UNKNOWN, VALUE, @@ -58,6 +59,7 @@ class SwitchAQ2(XiaomiCustomDevice): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL, @@ -73,7 +75,7 @@ class SwitchAQ2(XiaomiCustomDevice): OnOff.cluster_id, ], } - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/aqara/vibration_aq1.py b/zhaquirks/xiaomi/aqara/vibration_aq1.py index 24904249ae..beb1dfef8e 100644 --- a/zhaquirks/xiaomi/aqara/vibration_aq1.py +++ b/zhaquirks/xiaomi/aqara/vibration_aq1.py @@ -31,6 +31,7 @@ MOTION_EVENT, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, UNKNOWN, ZHA_SEND_EVENT, ) @@ -186,6 +187,7 @@ def _turn_off(self): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.DOOR_LOCK, @@ -215,7 +217,7 @@ def _turn_off(self): MultistateInput.cluster_id, ], }, - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/aqara/weather.py b/zhaquirks/xiaomi/aqara/weather.py index 8bdff84d19..b6e58e39b2 100644 --- a/zhaquirks/xiaomi/aqara/weather.py +++ b/zhaquirks/xiaomi/aqara/weather.py @@ -22,6 +22,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) TEMPERATURE_HUMIDITY_DEVICE_TYPE = 0x5F01 @@ -68,6 +69,7 @@ def __init__(self, *args, **kwargs): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { INPUT_CLUSTERS: [ @@ -85,5 +87,5 @@ def __init__(self, *args, **kwargs): XIAOMI_CLUSTER_ID, ], } - } + }, } diff --git a/zhaquirks/xiaomi/aqara/wleak_aq1.py b/zhaquirks/xiaomi/aqara/wleak_aq1.py index 8d1f8aaa28..c8f67fe673 100644 --- a/zhaquirks/xiaomi/aqara/wleak_aq1.py +++ b/zhaquirks/xiaomi/aqara/wleak_aq1.py @@ -11,6 +11,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) from .. import LUMI, BasicCluster, PowerConfigurationCluster, XiaomiCustomDevice @@ -51,6 +52,7 @@ class LeakAQ1(XiaomiCustomDevice): }, } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { INPUT_CLUSTERS: [ @@ -61,5 +63,5 @@ class LeakAQ1(XiaomiCustomDevice): ], OUTPUT_CLUSTERS: [Ota.cluster_id], } - } + }, } diff --git a/zhaquirks/xiaomi/mija/motion.py b/zhaquirks/xiaomi/mija/motion.py index a509bd8e14..afd9580f7c 100644 --- a/zhaquirks/xiaomi/mija/motion.py +++ b/zhaquirks/xiaomi/mija/motion.py @@ -28,6 +28,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) XIAOMI_CLUSTER_ID = 0xFFFF @@ -74,6 +75,7 @@ def __init__(self, *args, **kwargs): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.OCCUPANCY_SENSOR, @@ -93,5 +95,5 @@ def __init__(self, *args, **kwargs): Ota.cluster_id, ], } - } + }, } diff --git a/zhaquirks/xiaomi/mija/sensor_ht.py b/zhaquirks/xiaomi/mija/sensor_ht.py index 67f4366533..242285695f 100644 --- a/zhaquirks/xiaomi/mija/sensor_ht.py +++ b/zhaquirks/xiaomi/mija/sensor_ht.py @@ -27,6 +27,7 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) TEMPERATURE_HUMIDITY_DEVICE_TYPE = 0x5F01 @@ -107,6 +108,7 @@ def __init__(self, *args, **kwargs): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: TEMPERATURE_HUMIDITY_DEVICE_TYPE2, @@ -153,5 +155,5 @@ def __init__(self, *args, **kwargs): AnalogInput.cluster_id, ], }, - } + }, } diff --git a/zhaquirks/xiaomi/mija/sensor_magnet.py b/zhaquirks/xiaomi/mija/sensor_magnet.py index 7bf6526025..2b8b6b31ce 100644 --- a/zhaquirks/xiaomi/mija/sensor_magnet.py +++ b/zhaquirks/xiaomi/mija/sensor_magnet.py @@ -11,7 +11,6 @@ Scenes, ) -from .. import LUMI, BasicCluster, PowerConfigurationCluster, XiaomiCustomDevice from ...const import ( DEVICE_TYPE, ENDPOINTS, @@ -19,7 +18,9 @@ MODELS_INFO, OUTPUT_CLUSTERS, PROFILE_ID, + SKIP_CONFIGURATION, ) +from .. import LUMI, BasicCluster, PowerConfigurationCluster, XiaomiCustomDevice OPEN_CLOSE_DEVICE_TYPE = 0x5F01 XIAOMI_CLUSTER_ID = 0xFFFF @@ -65,6 +66,7 @@ def __init__(self, *args, **kwargs): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.ON_OFF_SENSOR, @@ -85,5 +87,5 @@ def __init__(self, *args, **kwargs): Ota.cluster_id, ], } - } + }, } diff --git a/zhaquirks/xiaomi/mija/sensor_switch.py b/zhaquirks/xiaomi/mija/sensor_switch.py index ae73dd5ccf..dcd1800a20 100644 --- a/zhaquirks/xiaomi/mija/sensor_switch.py +++ b/zhaquirks/xiaomi/mija/sensor_switch.py @@ -34,6 +34,7 @@ QUADRUPLE_PRESS, QUINTUPLE_PRESS, SHORT_PRESS, + SKIP_CONFIGURATION, TRIPLE_PRESS, UNKNOWN, ZHA_SEND_EVENT, @@ -129,6 +130,7 @@ def _update_attribute(self, attrid, value): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { DEVICE_TYPE: zha.DeviceType.REMOTE_CONTROL, @@ -146,7 +148,7 @@ def _update_attribute(self, attrid, value): Ota.cluster_id, ], } - } + }, } device_automation_triggers = { diff --git a/zhaquirks/xiaomi/mija/smoke.py b/zhaquirks/xiaomi/mija/smoke.py index 4f3a4fced4..81f9d67a8b 100644 --- a/zhaquirks/xiaomi/mija/smoke.py +++ b/zhaquirks/xiaomi/mija/smoke.py @@ -27,7 +27,14 @@ from .. import BasicCluster, PowerConfigurationCluster, XiaomiCustomDevice from ... import CustomCluster -from ...const import DEVICE_TYPE, ENDPOINTS, INPUT_CLUSTERS, OUTPUT_CLUSTERS, PROFILE_ID +from ...const import ( + DEVICE_TYPE, + ENDPOINTS, + INPUT_CLUSTERS, + OUTPUT_CLUSTERS, + PROFILE_ID, + SKIP_CONFIGURATION, +) IAS_ZONE = 0x0402 @@ -75,6 +82,7 @@ def __init__(self, *args, **kwargs): } replacement = { + SKIP_CONFIGURATION: True, ENDPOINTS: { 1: { INPUT_CLUSTERS: [ @@ -87,5 +95,5 @@ def __init__(self, *args, **kwargs): ], OUTPUT_CLUSTERS: [Ota.cluster_id], } - } + }, }