From a00d56816c9f11f52600c675470ef42a195339fd Mon Sep 17 00:00:00 2001 From: Xavier Moreno Date: Mon, 23 Aug 2021 22:47:11 +0200 Subject: [PATCH] feat(device): add Z2M support for ZS230002 (Linkind) related to #347 @kloodhu --- apps/controllerx/controllerx.py | 1 + apps/controllerx/cx_const.py | 1 + .../cx_core/type/light_controller.py | 15 +++++++++ apps/controllerx/cx_devices/linkind.py | 20 +++++++++++ docs/_data/controllers/ZS230002.yml | 31 ++++++++++++++++++ docs/assets/img/ZS230002.jpeg | Bin 0 -> 6704 bytes docs/controllers/ZS230002.md | 5 +++ .../brightness_from_controller_test.yaml | 9 +++++ .../linkind_ZS23000278_z2m/config.yaml | 9 +++++ .../xy_color_from_controller_test.yaml | 1 - ...led => xy_color_from_controller_test.yaml} | 1 - 11 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 apps/controllerx/cx_devices/linkind.py create mode 100644 docs/_data/controllers/ZS230002.yml create mode 100644 docs/assets/img/ZS230002.jpeg create mode 100644 docs/controllers/ZS230002.md create mode 100644 tests/integ_tests/linkind_ZS23000278_z2m/brightness_from_controller_test.yaml create mode 100644 tests/integ_tests/linkind_ZS23000278_z2m/config.yaml rename tests/integ_tests/muller_licht_z2m/{xy_color_from_controller_test.yaml.disabled => xy_color_from_controller_test.yaml} (90%) diff --git a/apps/controllerx/controllerx.py b/apps/controllerx/controllerx.py index 503cee8e..2bb41c5e 100644 --- a/apps/controllerx/controllerx.py +++ b/apps/controllerx/controllerx.py @@ -19,6 +19,7 @@ from cx_devices.aurora import * from cx_devices.ikea import * from cx_devices.legrand import * +from cx_devices.linkind import * from cx_devices.livarno import * from cx_devices.lutron import * from cx_devices.muller_licht import * diff --git a/apps/controllerx/cx_const.py b/apps/controllerx/cx_const.py index 72a510a5..000ebeab 100644 --- a/apps/controllerx/cx_const.py +++ b/apps/controllerx/cx_const.py @@ -61,6 +61,7 @@ class Light: HOLD_XY_COLOR_TOGGLE = "hold_xycolor_toggle" XYCOLOR_FROM_CONTROLLER = "xycolor_from_controller" COLORTEMP_FROM_CONTROLLER = "colortemp_from_controller" + BRIGHTNESS_FROM_CONTROLLER = "brightness_from_controller" class MediaPlayer: diff --git a/apps/controllerx/cx_core/type/light_controller.py b/apps/controllerx/cx_core/type/light_controller.py index 83d1b531..b58bffd2 100644 --- a/apps/controllerx/cx_core/type/light_controller.py +++ b/apps/controllerx/cx_core/type/light_controller.py @@ -390,6 +390,7 @@ def get_predefined_actions_mapping(self) -> PredefinedActionsMapping: ), Light.XYCOLOR_FROM_CONTROLLER: self.xycolor_from_controller, Light.COLORTEMP_FROM_CONTROLLER: self.colortemp_from_controller, + Light.BRIGHTNESS_FROM_CONTROLLER: self.brightness_from_controller, } async def check_remove_transition(self, on_from_user: bool) -> bool: @@ -523,6 +524,20 @@ async def colortemp_from_controller(self, extra: Optional[EventData]) -> None: return await self._on(color_temp=extra["action_color_temperature"]) + @action + async def brightness_from_controller(self, extra: Optional[EventData]) -> None: + if extra is None: + self.log("No event data present", level="WARNING") + return + if isinstance(self.integration, Z2MIntegration): + if "action_level" not in extra: + self.log( + "`action_level` is not present in the MQTT payload", + level="WARNING", + ) + return + await self._on(brightness=extra["action_level"]) + @property async def supported_color_modes(self) -> Set[str]: if self._supported_color_modes is None or self.update_supported_features: diff --git a/apps/controllerx/cx_devices/linkind.py b/apps/controllerx/cx_devices/linkind.py new file mode 100644 index 00000000..34397714 --- /dev/null +++ b/apps/controllerx/cx_devices/linkind.py @@ -0,0 +1,20 @@ +from cx_const import DefaultActionsMapping, Light +from cx_core import LightController + + +class ZS23000278LightController(LightController): + def get_z2m_actions_mapping(self) -> DefaultActionsMapping: + return { + "on": Light.ON, + "off": Light.OFF, + "brightness_step_up": Light.CLICK_BRIGHTNESS_UP, + "brightness_step_down": Light.CLICK_BRIGHTNESS_DOWN, + "brightness_move_to_level": Light.BRIGHTNESS_FROM_CONTROLLER, + "brightness_move_up": Light.HOLD_BRIGHTNESS_UP, + "brightness_move_down": Light.HOLD_BRIGHTNESS_DOWN, + "brightness_stop": Light.RELEASE, + "color_temperature_move": Light.COLORTEMP_FROM_CONTROLLER, + "color_temperature_move_up": Light.CLICK_COLOR_TEMP_UP, + "color_temperature_move_down": Light.CLICK_COLOR_TEMP_DOWN, + "color_move": Light.XYCOLOR_FROM_CONTROLLER, + } diff --git a/docs/_data/controllers/ZS230002.yml b/docs/_data/controllers/ZS230002.yml new file mode 100644 index 00000000..04e7fe95 --- /dev/null +++ b/docs/_data/controllers/ZS230002.yml @@ -0,0 +1,31 @@ +name: ZS230002 (Linkind) +device_support: + - type: Light + domain: light + controller: ZS23000278LightController + delay: 350 + mapping: + - "Click on/off → Toggle" + - "Click arrow up in dim mode → Brighten up (1 step)" + - "Click arrow down in dim mode → Dim down (1 step)" + - "Hold arrow up in dim mode → Brighten up" + - "Hold arrow down in dim mode → Dim down" + - "Click arrow up in color temp mode → Color temp up (1 step)" + - "Click arrow down in color temp mode → Color temp down (1 step)" + +integrations: + - name: Zigbee2MQTT + codename: z2m + actions: + - '"on" → Click on/off' + - '"off" → Click on/off' + - "brightness_step_up → Click arrow up in dim mode" + - "brightness_step_down → Click arrow down in dim mode" + - "brightness_move_to_level → " + - "brightness_move_up → Hold arrow up in dim mode" + - "brightness_move_down → Hold arrow down in dim mode" + - "brightness_stop → Release arrow up/down" + - "color_temperature_move → " + - "color_temperature_move_up → Click arrow up in color temp mode" + - "color_temperature_move_down → Click arrow down in color temp mode" + - "color_move → " diff --git a/docs/assets/img/ZS230002.jpeg b/docs/assets/img/ZS230002.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..84c4a36380491dc584827143f03a646c575fd07a GIT binary patch literal 6704 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