Kane610 / deconz

Python library wrapping deconz rest api for home-assistant
MIT License
47 stars 16 forks source link

Support events for Philips Tap Dial Switch #359

Open sjafferali opened 1 year ago

sjafferali commented 1 year ago

The new philips tap dial switch does not emit an event on deconz_event in home assistant when the dial is rotated. The buttons on the switch do however emit events.

Support was added in deconz for this switch in https://github.com/dresden-elektronik/deconz-rest-plugin/issues/6160 .

I opened an issue in https://github.com/home-assistant/core/issues/76427, but was directed to resubmit here.

Kane610 commented 1 year ago

Sorry, I've been busy and will keep busy until next week. I haven't forgotten this.

Kane610 commented 1 year ago

I've bought a tap switch myself, just need to get a deconz 2.18 instance running

Kane610 commented 1 year ago

Would you mind sharing your thoughts on how you would like it working?

sjafferali commented 1 year ago

Thanks @Kane610 .

I am not intimately familiar with the implementation, but querying the rest API shows the tab dial state.

{
    "config": {
        "battery": 43,
        "on": true,
        "reachable": true
    },
    "etag": "XXXXXXXXXXXXXXXXXXXXXXXXX",
    "lastannounced": "2022-08-23T20:04:23Z",
    "lastseen": "2022-08-23T20:24Z",
    "manufacturername": "Signify Netherlands B.V.",
    "modelid": "RDM002",
    "name": "RelativeRotary 16",
    "state": {
        "expectedeventduration": 400,
        "expectedrotation": 317,
        "lastupdated": "2022-08-23T14:55:31.188",
        "rotaryevent": 2
    },
    "swversion": "2.59.19",
    "type": "ZHARelativeRotary",
    "uniqueid": "XXXXXXXXXXXXXXXX"
}

If we could emit a deconz_event in home-assistant with these state updates, similar to the buttons on the switch, that should be sufficient for automation purposes.

There was also a similar issue for this switch in the home-assistant repo, that was recently resolved, which may be helpful. https://github.com/home-assistant/core/issues/75082.

Mincka commented 1 year ago

Is it possible to get the number of steps, like the event is retrieved here? It was implemented like this in the HA Hue integration. It looks like it makes its usage for dimming very easy. Thanks!

Kane610 commented 1 year ago

Is it possible to get the number of steps, like the event is retrieved here? It was implemented like this in the HA Hue integration. It looks like it makes its usage for dimming very easy. Thanks!

I will need to investigate it closer ones support is released

krusemedia commented 1 year ago

Any news on this? Can we help?

Kane610 commented 1 year ago

Nope sorry, I've refrained from upgrading to 2.18 due to what seem to be a memory leak in the system. I really want to progress on it :)

krusemedia commented 1 year ago

Does the problem still persist with v2.18.2 ?

Kane610 commented 1 year ago

Does the problem still persist with v2.18.2 ?

I've asked the devs and await more details

chris-nite commented 1 year ago

I'm also desperately awaiting support for dial movements in deconz. Right now i'm on 2.18.2 and so far, deconz still won't emit any events (or exposes them via API), when the dial is turned. All the other button-functions work as expected. Are there any news about this? Thanks in advance for your support and best regards.

Kane610 commented 1 year ago

I have been fully occupied with other things but plan on upgrading to 2.19.1 so I can get started.

The more suggestions about how you want it exposed the better for me when I get started. I won't promise it but I would like to get the support in with 2022.12 release

Mincka commented 1 year ago

I think it depends on the exact meaning of expectedrotation (see this post).

A Hue event looks like this:

"relative_rotary": {
              "last_event": {
                "action": "start",
                "rotation": {
                  "direction": "clock_wise",
                  "duration": 400,
                  "steps": 15
                }
              }
            }

I don't know how the expectedrotation and the steps are linked. I observed that one rotation click equals to 15 steps. I count 66 clicks for a 360° rotation. But it seems possible to get values that are not multiples of 15 for expectedrotations or steps. Maybe if you compare both for a single step, you will understand how they are related. In the end, I think the goal would be to get the same presentation than the one of the Hue API, maybe with even more precision if possible.

The steps give the rotation amount between two updates that are done every 400ms. This means that even when I move the dial quite fast, I can get the total amount and catch up with my automations (increase brightness / volume by x steps, open/close cover for position+x steps, seek forward in music/video for x seconds as steps...).

Sadly, there's a pending bug in the Hue integration that ignores identical events to it doesn't make the dial play very well for now. Hopefully, once we have it in Deconz Rest API, it will be perfect. 😄

Kane610 commented 1 year ago

PR is up, I haven't upgraded deCONZ yet so I can't verify it myself, please try it out at the latest during the 2022.12 beta.

Kane610 commented 1 year ago

Event will initially contain

Event new movement/ repeat movement Expected rotation positive/negative for angle and direction Event duration

Kane610 commented 1 year ago

PR has been merged, please try it out

sjafferali commented 1 year ago

I just tried this out. Works perfectly. Thanks a ton @Kane610 !

Kane610 commented 1 year ago

Awesome! Thanks for the quick feedback @sjafferali

Mincka commented 1 year ago

I just tried this out. Works perfectly. Thanks a ton @Kane610 !

How did you try it? With a dev release of HA? I tried to put the latest dev of the deconz folder in my custom_components folder but it does not seem to override the native version. I saw this method here but maybe it's deprecated.

Otherwise, I just need to be a little bit patient and wait the beta release tonight.

Edit: Ok, maybe I should try to read the logs first...

2022-11-30 14:03:18.941 WARNING (SyncWorker_0) [homeassistant.loader] We found a custom integration deconz which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you experience issues with Home Assistant
2022-11-30 14:03:18.942 ERROR (SyncWorker_0) [homeassistant.loader] The custom integration 'deconz' does not have a version key in the manifest file and was blocked from loading. See https://developers.home-assistant.io/blog/2021/01/29/custom-integration-changes#versions for more details
Mincka commented 1 year ago

I can also confirm I get the deconz_relative_rotary_event in HA. Thank you @Kane610 👍

My first feedback is that it seems complicated to use the rotation property while the dial is sending repeat events.

If I continuously rotate the dial (without more than 400ms between the clicks), the sequence will look like this (chronological order):

event_type: deconz_relative_rotary_event
data:
  id: relativerotary_150
  unique_id: xxx
  device_id: xxx
  event: new
  rotation: 15
  duration: 400
origin: LOCAL
time_fired: "2022-11-30T13:29:51.906267+00:00"

event_type: deconz_relative_rotary_event
data:
  id: relativerotary_150
  unique_id: xxx
  device_id: xxx
  event: repeat
  rotation: 90
  duration: 400
origin: LOCAL
time_fired: "2022-11-30T13:29:52.332120+00:00"

event_type: deconz_relative_rotary_event
data:
  id: relativerotary_150
  unique_id: xxx
  device_id: xxx
  event: repeat
  rotation: 150
  duration: 400
origin: LOCAL
time_fired: "2022-11-30T13:29:52.736521+00:00"

While the dial send repeat events, it tracks the total rotation of the dial. It's ok if you consider that you need to wait for the total rotation before triggering an action. But I think it would be even better to get the distance that can calculated between events sent every 400ms.

My goal is to dynamically adjust a volume or a brightness while rotating the dial. For this, I think I would need to calculate the difference with the previous value of the rotation event. In the case above, I get the new event, I set the volume to current + rotation0. Then, I get repeat event and I set the volume to current + (rotation1 - rotation0), then the last repeat event and I set the volume to current + (rotation2 - rotation1).

I think it could be great to have an additional property called steps for instance, that would be the difference between a rotation property of a repeat event and the previous new or repeat event.

See my previous post and the log example here: https://github.com/home-assistant/core/issues/78621

In this implementation, the "steps" property is the rotation value between the start and the new event, or between two 400ms events.

My idea would give this output:

event_type: deconz_relative_rotary_event
data:
  id: relativerotary_150
  unique_id: xxx
  device_id: xxx
  event: new
  rotation: 15
  duration: 400
  steps: 15

event_type: deconz_relative_rotary_event
data:
  id: relativerotary_150
  unique_id: xxx
  device_id: xxx
  event: repeat
  rotation: 90
  duration: 400
  steps: 75

event_type: deconz_relative_rotary_event
data:
  id: relativerotary_150
  unique_id: xxx
  device_id: xxx
  event: repeat
  rotation: 150
  duration: 400
  steps: 60

If that's not possible, I can try to use the event trigger on new events and wait_for_trigger in a loop to track the subsequent repeat events and do the maths inside.

Kane610 commented 1 year ago

@Mincka thanks for the feedback. It sounds reasonable to do something like what you suggest. I just wanted to get some support out with this release and giving the basics was better than waiting another release :)

Mincka commented 1 year ago

Great! In the meantime, I implemented it with an automation and an input_number helper and it works really great. I use the helper to store the last rotation value and I send, as a new augmented event, either the value of the new event, or the difference between the two latest rotations in case of repeat.

For a light, I chose to divise by 2 the number of dial steps (1 click = 15), so it means that a click increase/decrease the light by 8 light steps (from 0 to 255). You go from 0 to 100% of brightness with 1/2 of the dial rotation, in my case that's good, but I think it also works if you use the steps directly. It's fine enough for a light.

alias: Tap Dial with Steps
description: >-
  Refire the tap dial event with the number of steps since the last received
  event
trigger:
  - platform: event
    event_type: deconz_relative_rotary_event
    event_data:
      event: new
    id: new
  - platform: event
    event_type: deconz_relative_rotary_event
    event_data:
      event: repeat
    id: repeat
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: new
        sequence:
          - event: deconz_relative_rotary_event_with_steps
            event_data:
              id: "{{ trigger.event.data.id }}"
              unique_id: "{{ trigger.event.data.unique_id }}"
              device_id: "{{ trigger.event.data.device_id }}"
              event: "{{ trigger.event.data.event }}"
              rotation: "{{ trigger.event.data.rotation }}"
              duration: "{{ trigger.event.data.duration }}"
              steps: "{{ trigger.event.data.rotation }}"
      - conditions:
          - condition: trigger
            id: repeat
        sequence:
          - event: deconz_relative_rotary_event_with_steps
            event_data:
              id: "{{ trigger.event.data.id }}"
              unique_id: "{{ trigger.event.data.unique_id }}"
              device_id: "{{ trigger.event.data.device_id }}"
              event: "{{ trigger.event.data.event }}"
              rotation: "{{ trigger.event.data.rotation }}"
              duration: "{{ trigger.event.data.duration }}"
              steps: >-
                {{ trigger.event.data.rotation -
                states("input_number.tap_dial_1_last_rotation") | int }}
  - service: input_number.set_value
    target:
      entity_id: input_number.tap_dial_1_last_rotation
    data:
      value: "{{ trigger.event.data.rotation }}"
mode: queued
max: 10
description: "Increment / Decrement the light based on the number of steps of the Hue Tap Dial"
mode: single
trigger:
  - platform: event
    event_type: deconz_relative_rotary_event_with_steps
    event_data:
      unique_id: xxx
condition: []
action:
  - service: light.turn_on
    data:
      brightness_step: "{{ (trigger.event.data.steps / 2) | round }}"
    target:
      entity_id: light.bureau_julien_grande_lampe
TUNER88 commented 1 year ago

Any updates on this topic? I still do not see the rotary events in the logbook (only regular press events). Using Home Assistant 2023.1.7

How can I debug it?

Screenshot 2023-01-26 at 20 47 35
Kane610 commented 1 year ago

The logbook is not updated to show extra details like that.

You can use the event interface in home assistant to subscribe to Deconz events and see the payloads

TUNER88 commented 1 year ago

@Kane610 ah, ok, great, now I can see them, thanks 👍

Kane610 commented 1 year ago

@Kane610 ah, ok, great, now I can see them, thanks 👍

Awesome! Gave me a scare there for a sec! :)

Mincka commented 1 year ago

It still works great here with my automation to get steps but hopefully we can have them available directly the event. It would not be a breaking change and it would be useful to cover progressive and dynamic increase / decrease of value.

rEs-84 commented 1 year ago

description: "Increment / Decrement the light based on the number of steps of the Hue Tap Dial" mode: single trigger:

  • platform: event event_type: deconz_relative_rotary_event_with_steps event_data: unique_id: xxx condition: [] action:
  • service: light.turn_on data: brightness_step: "{{ (trigger.event.data.steps / 2) | round }}" target: entity_id: light.bureau_julien_grande_lampe

Hi, this appears to work (until a better way to handle the events is kindly created). This does turn on my hue lights when rotating right, turns off when rotating left.

However to incrementally make them light or darker, it seems to take quite the rotation for it to be used. and that doesn't seem fully consistent (not quite worked that out).

Are you using your automations or was that just a proof of concept?

Mincka commented 1 year ago

I use it with a Shelly DImmer 2 and it works great. As I said, you need to tweak it for your case, especially this part.

For a light, I chose to divise by 2 the number of dial steps (1 click = 15) brightness_step: "{{ (trigger.event.data.steps / 2) | round }}"

Observe how the brightness value changes for each click. Try to remove / 2 if you think it's too slow.

DrBlokmeister commented 1 month ago

After two weeks of struggling with my tap dial switch and posting issues on both the Deconz and the Home Assistant github, I finally found this thread.

I was wondering why the decision was made to not throw deconz_events but to instead throw a very specific deconz event? Won't it be simpler to just use deconz_event for everything and maybe add an additional key inside data like action_type: rotation?

Also, are you aware that if you have the Phoscon device page open and selected the specific tap dial switch, then suddenly standard deconz_events are sent? These are the 500X and 600X events that are standard for other switches.

Edit

I learned a bit more and found out that it's not so easy as it first seemed to me. However, there are things that I would appreciate to be improved.

The event data is seen below:

event_type: deconz_relative_rotary_event
data:
  id: hue_tap_dial_switch
  unique_id: 00:17:88:01:0d:d0:26:e0
  device_id: 479e093dd93fc09f8af97957ae5201b8
  event: repeat
  rotation: -347
  duration: 400
origin: LOCAL
time_fired: "2024-06-14T20:27:53.600235+00:00"
context:
  id: 01J0C6YTW0X9KDXHYGE8ER9GCZ
  parent_id: null
  user_id: null

The device_id is correct in my case. However, the id is not, which should be babyroom_tap_dial, which is correct for the button presses. Additionally, the rotation events do not show up in the Home Assistant log book on the device page: image

Do you know if these are things that are reasonably easily implementable? And if so, should these be on the Home Assistant or on the Deconz side?

Note: I've also asked this question here: https://github.com/dresden-elektronik/deconz-rest-plugin/issues/7804