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 00000000..84c4a363 Binary files /dev/null and b/docs/assets/img/ZS230002.jpeg differ diff --git a/docs/controllers/ZS230002.md b/docs/controllers/ZS230002.md new file mode 100644 index 00000000..16af163e --- /dev/null +++ b/docs/controllers/ZS230002.md @@ -0,0 +1,5 @@ +--- +layout: controller +title: ZS230002 (Linkind) +device: ZS230002 +--- diff --git a/tests/integ_tests/linkind_ZS23000278_z2m/brightness_from_controller_test.yaml b/tests/integ_tests/linkind_ZS23000278_z2m/brightness_from_controller_test.yaml new file mode 100644 index 00000000..b485af75 --- /dev/null +++ b/tests/integ_tests/linkind_ZS23000278_z2m/brightness_from_controller_test.yaml @@ -0,0 +1,9 @@ +entity_state: "on" +fired_actions: ["brightness_move_to_level"] +extra: + action_level: 42 +expected_calls: + - service: light/turn_on + data: + entity_id: light.my_light + brightness: 42 diff --git a/tests/integ_tests/linkind_ZS23000278_z2m/config.yaml b/tests/integ_tests/linkind_ZS23000278_z2m/config.yaml new file mode 100644 index 00000000..44675e34 --- /dev/null +++ b/tests/integ_tests/linkind_ZS23000278_z2m/config.yaml @@ -0,0 +1,9 @@ +example_app: + module: controllerx + class: ZS23000278LightController + integration: + name: z2m + listen_to: mqtt + controller: my_controller + light: light.my_light + \ No newline at end of file diff --git a/tests/integ_tests/muller_licht_deconz/xy_color_from_controller_test.yaml b/tests/integ_tests/muller_licht_deconz/xy_color_from_controller_test.yaml index 052ba637..733d4c84 100644 --- a/tests/integ_tests/muller_licht_deconz/xy_color_from_controller_test.yaml +++ b/tests/integ_tests/muller_licht_deconz/xy_color_from_controller_test.yaml @@ -7,4 +7,3 @@ expected_calls: data: entity_id: light.my_light xy_color: !!python/tuple [0.12, 0.08] -expected_calls_count: 1 diff --git a/tests/integ_tests/muller_licht_z2m/xy_color_from_controller_test.yaml.disabled b/tests/integ_tests/muller_licht_z2m/xy_color_from_controller_test.yaml similarity index 90% rename from tests/integ_tests/muller_licht_z2m/xy_color_from_controller_test.yaml.disabled rename to tests/integ_tests/muller_licht_z2m/xy_color_from_controller_test.yaml index 2c46dd84..5a8a9537 100644 --- a/tests/integ_tests/muller_licht_z2m/xy_color_from_controller_test.yaml.disabled +++ b/tests/integ_tests/muller_licht_z2m/xy_color_from_controller_test.yaml @@ -8,4 +8,3 @@ expected_calls: data: entity_id: light.my_light xy_color: !!python/tuple [0.12, 0.08] -expected_calls_count: 1