diff --git a/apps/hue_dimmer_switch_deconz/hue_dimmer_switch_deconz.py b/apps/hue_dimmer_switch_deconz/hue_dimmer_switch_deconz.py index 9dcf188..88da3ca 100755 --- a/apps/hue_dimmer_switch_deconz/hue_dimmer_switch_deconz.py +++ b/apps/hue_dimmer_switch_deconz/hue_dimmer_switch_deconz.py @@ -1,14 +1,200 @@ -"""Define automations for Hue Dimmer switches""" +"""Define automations for DeCONZ lights and remote controls.""" from appdaemon.plugins.hass.hassapi import Hass -class HueDimmerSwitch(Hass): +class SwitchBase(Hass): + """Define a base class from which other classes inherit from.""" + + def initialize(self) -> None: + """Initialize.""" + #self.set_namespace("hass") + + # configure entities + self.entities = self.args["entities"] + self.lights = self.entities["lights"] + + # get the advanced button config + self.button_config = self.args.get("button_config", {}) + + def get_light_type(self, light: str) -> str: + """Get the DeCONZ light type of the given light.""" + if self.get_state(light, attribute="is_deconz_group"): + return "/action" + else: + return "/state" + + def dim_light(self, direction: str) -> None: + """In-/decrease brightness of light through service call to deCONZ.""" + if direction == "up": + bri_inc = 254 + else: + bri_inc = -254 + for light in self.lights: + self.call_service( + "deconz/configure", + field=self.get_light_type(light), + entity=light, + data={"bri_inc": bri_inc, "transitiontime": 50}, + ) + + def stop_dim_light(self) -> None: + """Stop dimming of light through service call to deCONZ.""" + for light in self.lights: + self.call_service( + "deconz/configure", + field=self.get_light_type(light), + entity=light, + data={"bri_inc": 0}, + ) + + def action(self, button_config: dict) -> None: + """Call the respective service based on the passed button config.""" + action_type = button_config["action_type"] + entity = button_config["entity"] + parameters = button_config.get("parameters", {}) + + self.call_service( + f"{action_type.replace('.','/')}", entity_id=entity, **parameters + ) + + +class XiaomiWXKG11LM2016(SwitchBase): + """Define a Aqara Wirless Switch 2016 version base feature""" + + def initialize(self) -> None: + """Configure""" + super().initialize() + self.switch_id = self.entities["remote_event_id"] + self.button_map = { + 1002: "short_press", + 1004: "double_press", + 1005: "triple_press", + 1006: "quadruple_press", + } + + # take action when button is pressed + self.listen_event(self.button_pressed_cb, "deconz_event", id=self.switch_id) + + def button_pressed_cb(self, event_name: str, data: dict, kwargs: dict) -> None: + """Take action when button is pressed.""" + button_code = data["event"] + button_name = self.button_map[button_code] + + if button_name in self.button_config: + self.action(self.button_config[button_name]) + else: + self.log(f"Button '{button_name}' not configured. No action.") + + +class TradfriE1743(SwitchBase): + """Define a Tradfri E1743 base feature""" + + def initialize(self) -> None: + """Configure""" + super().initialize() + self.switch_id = self.entities["remote_event_id"] + self.button_map = { + 1002: "short_press_on", + 1001: "long_press_on", + 1003: "long_press_on_release", + 2002: "short_press_off", + 2001: "long_press_off", + 2003: "long_press_off_release", + } + + if "short_press_on" not in self.button_config: + self.button_config["short_press_on"] = { + "action_type": "light.turn_on", + "entity": self.lights, + "parameters": {"brightness": 255}, + } + + if "short_press_off" not in self.button_config: + self.button_config["short_press_off"] = { + "action_type": "light.turn_off", + "entity": self.lights, + "parameters": {}, + } + + # take action when button is pressed + self.listen_event(self.button_pressed_cb, "deconz_event", id=self.switch_id) + + def button_pressed_cb(self, event_name: str, data: dict, kwargs: dict) -> None: + """Take action when button is pressed.""" + button_code = data["event"] + button_name = self.button_map[button_code] + + if button_name == "long_press_on": + self.dim_light("up") + elif button_name == "long_press_off": + self.dim_light("down") + elif button_name in ["long_press_on_release", "long_press_off_release"]: + self.stop_dim_light() + elif button_name in self.button_config: + self.action(self.button_config[button_name]) + else: + self.log(f"Button '{button_name}' not configured. No action.") + + +class TradfriE1810(SwitchBase): + """Define a Tradfri E1810 base feature""" + + def initialize(self) -> None: + """Configure""" + super().initialize() + self.switch_id = self.entities["remote_event_id"] + self.button_map = { + 1002: "short_press_center", + 2002: "short_press_up", + 2001: "long_press_up", + 2003: "long_press_up_release", + 3002: "short_press_down", + 3001: "long_press_down", + 3003: "long_press_down_release", + 4002: "short_press_left", + 4001: "long_press_left", + 4003: "long_press_left_release", + 5002: "short_press_right", + 5001: "long_press_right", + 5003: "long_press_right_release", + } + + if "short_press_center" not in self.button_config: + self.button_config["short_press_center"] = { + "action_type": "light.toggle", + "entity": self.lights, + "parameters": {}, + } + + # take action when button is pressed + self.listen_event(self.button_pressed_cb, "deconz_event", id=self.switch_id) + + def button_pressed_cb(self, event_name: str, data: dict, kwargs: dict) -> None: + """Take action when button is pressed.""" + button_code = data["event"] + button_name = self.button_map[button_code] + + if button_name == "long_press_up": + self.dim_light("up") + elif button_name == "long_press_down": + self.dim_light("down") + elif button_name in ["long_press_up_release", "long_press_down_release"]: + self.stop_dim_light() + elif button_name in self.button_config: + self.action(self.button_config[button_name]) + else: + self.log(f"Button '{button_name}' not configured. No action.") + + +class HueDimmerSwitch(SwitchBase): """Define a Hue Dimmer Switch base feature""" def initialize(self) -> None: """Configure""" + super().initialize() + self.switch_id = self.entities["remote_event_id"] self.button_map = { 1000: "short_press_on", 1002: "short_press_on_release", @@ -27,43 +213,26 @@ def initialize(self) -> None: 4001: "long_press_off", 4003: "long_press_off_release", } - # configure entities - entities = self.args["entities"] - self.light = entities["light"] - self.switch = entities["switch"] - - # get the advanced button config - self.button_config = self.args.get("advanced", {}) if "short_press_on_release" not in self.button_config: self.button_config["short_press_on_release"] = { - "action_type": "turn_on", - "entity": self.light, - "parameters": {"brightness": 255} + "action_type": "light.turn_on", + "entity": self.lights, + "parameters": {"brightness": 255}, } if "short_press_off_release" not in self.button_config: self.button_config["short_press_off_release"] = { - "action_type": "turn_off", - "entity": self.light, + "action_type": "light.turn_off", + "entity": self.lights, "parameters": {}, } - # check if the light is a deconz group or single bulb - if self.get_state(self.light, attribute="is_deconz_group"): - self.deconz_field = "/action" - else: - self.deconz_field = "/state" - # take action when button is pressed - self.listen_event( - self.button_pressed_cb, - "deconz_event", - id=self.switch - ) + self.listen_event(self.button_pressed_cb, "deconz_event", id=self.switch_id) def button_pressed_cb(self, event_name: str, data: dict, kwargs: dict) -> None: - """Take action when button is pressed on dimmer switch.""" + """Take action when button is pressed.""" button_code = data["event"] button_name = self.button_map[button_code] @@ -75,38 +244,67 @@ def button_pressed_cb(self, event_name: str, data: dict, kwargs: dict) -> None: self.stop_dim_light() elif button_name in self.button_config: self.action(self.button_config[button_name]) - - def dim_light(self, direction: str) -> None: - """In-/decrease brightness of light through service call to deCONZ.""" - if direction == "up": - bri_inc = 254 else: - bri_inc = -254 + self.log(f"Button '{button_name}' not configured. No action.") - self.call_service( - "deconz/configure", - field=self.deconz_field, - entity=self.light, - data={"bri_inc": bri_inc, "transitiontime": 50} - ) - def stop_dim_light(self) -> None: - """Stop dimming of light through service call to deCONZ.""" - self.call_service( - "deconz/configure", - field=self.deconz_field, - entity=self.light, - data={"bri_inc": 0} - ) +class KNXSwitch(SwitchBase): + """Define a KNX Switch base feature""" - def action(self, button_config: dict) -> None: - """Call the respective service based on the passed button config.""" - action_type = button_config["action_type"] - entity = button_config["entity"] - parameters = button_config.get("parameters", {}) + def initialize(self) -> None: + """Configure""" + super().initialize() + self.on_off_address = self.args["knx_address"]["on_off"] + self.dimming_address = self.args["knx_address"]["dimming"] - self.call_service( - f"{entity.split('.')[0]}/{action_type}", - entity_id=entity, - **parameters - ) + if "short_press_on" not in self.button_config: + self.button_config["short_press_on"] = { + "action_type": "light.turn_on", + "entity": self.lights, + "parameters": {"brightness": 255}, + } + + if "short_press_off" not in self.button_config: + self.button_config["short_press_off"] = { + "action_type": "light.turn_off", + "entity": self.lights, + "parameters": {}, + } + + # take action when button is pressed + self.listen_event(self.button_pressed_cb, "knx_event") + + def button_pressed_cb(self, event_name: str, data: dict, kwargs: dict) -> None: + """Take action when button is pressed.""" + button_name = self.get_button_name(data) + self.log(button_name) + + if button_name == "long_press_on": + self.dim_light("up") + elif button_name == "long_press_off": + self.dim_light("down") + elif button_name == "long_press_release": + self.stop_dim_light() + elif button_name in self.button_config: + self.action(self.button_config[button_name]) + else: + self.log(f"Button '{button_name}' not configured. No action.") + + def get_button_name(self, event_data: dict) -> str: + """Get the name of the button pressed from the event data.""" + address = event_data["address"] + data = event_data["data"] + + if address in [self.on_off_address, self.dimming_address]: + if address == self.on_off_address and data == [1]: + return "short_press_on" + elif address == self.on_off_address and data == [0]: + return "short_press_off" + elif address == self.dimming_address and data == [9]: + return "long_press_on" + elif address == self.dimming_address and data == [0]: + return "long_press_release" + elif address == self.dimming_address and data == [1]: + return "long_press_off" + else: + return f"Address {address}, Data {data}" diff --git a/readme.md b/readme.md index 64e0403..accf7af 100755 --- a/readme.md +++ b/readme.md @@ -29,6 +29,8 @@ dimmer_bedroom: switch: dimmer_switch_bedroom light: light.bedroom ``` +Add this configuration to your AppDaemon configuration file, e.g. `/config/appdaemon/apps/apps.yaml`. + #### Configuration key | optional | type | default | description -- | -- | -- | -- | --