Simpler way to define similar automations and reuse code?

I’ll provide you the test file and instructions tomorrow, need to :sleeping:

All good! I was already asleep anyway :slight_smile:

Sorry for only coming back now, some other things popped up on my to-do list :slight_smile:

I didn’t release anything new yet as I need more feedback from testers on some things.

Put this into wireless_remote.py and put the file into the appdaemon apps folder.

"""Define automations for DeCONZ/ZHA remotes."""
from appdaemon.plugins.hass.hassapi import Hass


class SwitchBase(Hass):
    """Define a base feature for all switches."""

    def initialize(self) -> None:
        """Initialize."""
        self.lights = self.args["lights"]
        self.event_type = self.args["event_type"]
        self.event_id = self.args.get("event_id")

        self.button_config = self.args.get("button_config", {})

    def dim_light(self, direction: str) -> None:
        """Start dimming of light."""
        if direction == "up":
            bri_inc = 254
        else:
            bri_inc = -254
        for light in self.lights:
            if self.is_deconz_light(light):
                self.call_service(
                    "deconz/configure",
                    field=self.get_deconz_field(light),
                    entity=light,
                    data={"bri_inc": bri_inc, "transitiontime": 50},
                )
            else:
                self.log("Dimming not supported yet for non-deconz lights")

    def stop_dim_light(self) -> None:
        """Stop dimming of light."""
        for light in self.lights:
            if self.is_deconz_light(light):
                self.call_service(
                    "deconz/configure",
                    field=self.get_deconz_field(light),
                    entity=light,
                    data={"bri_inc": 0},
                )
            else:
                self.log("Dimming not supported yet for non-deconz lights")

    def is_deconz_light(self, light: str) -> bool:
        """Return true if the light is a deconz light."""
        return self.get_state(light, attribute="is_deconz_group") is not None

    def get_deconz_field(self, light: str) -> str:
        """Return the DeCONZ light type of the given light."""
        if self.get_state(light, attribute="is_deconz_group"):
            return "/action"
        else:
            return "/state"

    def action(self, button_config: dict) -> None:
        """Call the respective service based on the passed button config."""
        service = button_config["service"]
        entity_id = button_config["entity_id"]
        data = button_config.get("data", {})

        self.call_service(f"{service.replace('.','/')}", entity_id=entity_id, **data)


class XiaomiWXKG01LM(SwitchBase):
    """Define a Mi round smart wireless switch base feature"""

    def initialize(self) -> None:
        """Configure"""
        super().initialize()
        self.button_map = {
            1000: "short_press",
            1002: "short_press_release",
            1001: "long_press",
            1003: "long_press_release",
            1004: "double_press",
            1005: "triple_press",
            1006: "quadruple_press",
            1010: "many_press",
        }

        # take action when button is pressed
        self.listen_event(
            self.button_pressed_cb,
            self.event_type,
            id=self.event_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.")

And put this into apps.yaml

xiaomi_remote_study_room:
  module: wireless_remote
  class: XiaomiWXKG01LM
  event_type: deconz_event
  event_id: study_button #id that identifies the remote, you can see this in the events, it took the one from your code
  button_config:
    short_press_release:
      service: light.turn_on
      entity_id: 
        - light.study_ceiling
      data:
        brightness: 150
    double_press:
      service: light.turn_off
      entity_id: 
        - light.study_ceiling

This configuration will turn on light.study_ceiling at 150 brightness when the button is released after a short press and turn off light.study_ceiling when you do a double press. You can configure the other buttons in the same manner. The names of the button presses are:

  • short_press
  • short_press_release
  • long_press
  • long_press_release
  • double_press
  • triple_press
  • quadruple_press
  • many_press

I would love to get some feedback, as you are the first one testing it with this switch.

Does any of the remote send a continuous event on holding the button or just one event at the beginning of the “hold” period?

Do you require smooth dimming of lights as well or just assigning different button presses to different service calls?

I complete forgot to send you the events! Sorry about that!

The Ikea dimmer sends continuous events. The Sylvania and the Hue dimmer don’t (I think, I need to test it again). As for smooth dimming? Doesn’t matter to me as I usually use remotes for on/off and voice to set to various levels.

This is the hold event from the Ikea dimmer:

{
    "event_type": "zha_event",
    "data": {
        "unique_id": "cc:cc:cc:ff:fe:99:12:49:1:0x0008",
        "device_ieee": "cc:cc:cc:ff:fe:99:12:49",
        "endpoint_id": 1,
        "cluster_id": 8,
        "command": "stop",
        "args": []
    },
    "origin": "LOCAL",
    "time_fired": "2020-02-02T15:37:17.393168+00:00",
    "context": {
        "id": "83e0a17834184401b335d55370236542",
        "parent_id": null,
        "user_id": null
    }
}

{
    "event_type": "zha_event",
    "data": {
        "unique_id": "cc:cc:cc:ff:fe:99:12:49:1:0x0008",
        "device_ieee": "cc:cc:cc:ff:fe:99:12:49",
        "endpoint_id": 1,
        "cluster_id": 8,
        "command": "move_with_on_off",
        "args": [
            0,
            83
        ]
    },
    "origin": "LOCAL",
    "time_fired": "2020-02-02T15:37:13.853017+00:00",
    "context": {
        "id": "06b8b5fcba6a4d2ba3cac43ab1c6888d",
        "parent_id": null,
        "user_id": null
    }
}

[edit] Yeah, holding the dim up/down on the Hue remote generates separate events unlike the Ikea dimmer (which does a start and then stop at the end of the hold).

Ok, I see now that unfortunately the zha_events are completely different from the deconz_events.

So you need to provide me the whole set of button presses :sweat_smile:

if you remove event_id and make it event_data with kwargs, you can make this more generic. You might need another configuration attribute that maps important event data to your listeners.

Thanks for the suggestion. I’m already working on making it more generic, but first I need to understand the mapping of the zha events. Also I’m not sure whether I want to continue this project or not as the app provided by @xaviml is way more advanced, dimming works for non-deconz lights as well, and it already has support for ZigBee2MQTT and probably soon for ZHA as well.

Hi all,

I recently released the code to support ZHA. It’s still in a pre-release (dev branch), but you can download from HACS marking “Show beta” . You can bind the following controllers for ZHA for the moment:

  • E1810 (for a light and media player)
  • E1743
  • E1744 (symfonisk controller for light and media player)

As @Burningstone says this appdaemon app integrates with z2m and deconz as well. However, I could not integrate the Hue Dimmer due to not be properly implemented in the zha. It sends the click action as well as the hold one and it does not have an action for the release of the on/off buttons. If someone has a question, don’t hesitate to ask me or open a issue in the repository: https://github.com/xaviml/controllerx

1 Like

@123 Can you elaborate on this? I have not used scripts on HA yet.

I suggest reviewing the documentation for Scripts.

The relevant section for this discussion is titled: Passing variables to scripts