[QUESTION] PTM215X Multifunction Button
Closed this issue · 12 comments
Question
Hello,
I've used your plug in for AppDaemon successfully for a few months. However, I was just now getting around to trying to duplicate a functionality I had previously with the Hue app. I didn't succeed, so I figure I'd ask if you thought this feature was possible, and if so, any ideas on how.
I'm currently using a RunLessWire HUE switch (PTM215XController). This switch can either be configured as a standard decora switch (1 paddle), or converted to control 2 sets of lights (2 narrow paddles). When paired with the HUE app, this switch allows control of a single or double set of lights, where a single press of the top turns on the light, a single press of the bottom turns off the light, and a hold with either increase or decrease the brightness. I've now moved most of my Hue bulbs to Z2M.
The PTM215X is already supported by your plug-in. There are 4 buttons, and several different events. However, in the application I'm trying to achieve, I'd like to use a "pair" of the buttons (say 1 and 2, OR 3 and 4). Using the 1-2 pair as an example, I'd like a single tap of button 1 (press_1) to turn the light on, and a single tap of button 2 (press_2) to turn the light off. I can achieve this successfully. However, the next part I want is that a press-and-hold of button1 should do an "ramp" type increase of the brightness, while a press-and-hold of button2 should do a "ramp" type decrease of the brightness. Right now, I can take the "other" pair (say buttons3/4) and implement the brightness ramp. Unfortunately, this configuration implies that I can only control the on-off and brightness for a single set of lights. Also, when I use the additional pair, I see two behaviors. A press and release gives a step increment/decrement, and a hold gives the "gradual" ramp up/down. I'd like to sacrifice the step increment/decrement, and replace that with the on/off.
I tried to add a merge mapping with the action "click" and attribute "on", and the action: "hold" being the brightness, but it seemed to ignore the "on" and implement the step and ramp brightness.
Hopefully, the question is clear.
Thanks,
Sean
Additional information
- Devices involved:
- Model: [ eg. IKEA 1744 ] as [ Light | Media Player | Controller ]
- ...
- Integration: Choose from
z2m | deconz | zha
- AppDaemon version: [ eg. v4.0.1 ]
- ControllerX version: [ eg. v2.2.1 ]
- HACS version (if installed from there): [ eg. v0.21.5 ]
- Home Assistant Core version: [ eg. v0.105.4 ]
AppDaemon app configuration
(optional) Insert your appdaemon app configuration here (apps.yaml content).
Insert only the configuration relative to the controllerx app you're asking the question for.
Logs
(optional) Add relevant AppDaemon / Home Assistant logs which could help answering the question.
Additional Context
Add any other context or screenshots about the question here.
Hi @SeanNazareth ,
Thank you for your detailed explanation of your question. I see that this controller does not support hold actions for Zigbee2MQTT
. This is because at the time this controller was added, those actions did not exist.
Could you please send the Zigbee2MQTT logs of this controller when buttons 1,2,3,4 are held? Also, does zigbee2MQTT provide a release event?
If there are hold and release action, I will update this controller as well as letting you know how the mapping
can be used as you tried.
Regards,
Xavi M.
Hi @SeanNazareth ,
Is there a description somewhere of how to collect them?
Assuming you are using the Zigbee2MQTT addon from HA, I recommend you opening the addon and going to the "log" tab. In there, if you hold the button and then release, you should be able to see the commands that are fired. You can also try just clicking. Once you have those logs, please send those to me. They will look like something like:
Zigbee2MQTT:info 2023-01-25 23:45:12: MQTT publish: topic 'zigbee2mqtt/office_controller', payload '{"action":"on","battery":100,"linkquality":255,"update":{"installed_version":65572,"latest_version":581,"state":"idle"},"update_available":false}'
Zigbee2MQTT:info 2023-01-25 23:45:12: MQTT publish: topic 'zigbee2mqtt/office_controller', payload '{"action":"","battery":100,"linkquality":255,"update":{"installed_version":65572,"latest_version":581,"state":"idle"},"update_available":false}'
Zigbee2MQTT:info 2023-01-25 23:45:12: MQTT publish: topic 'zigbee2mqtt/office_controller/action', payload 'on'
ControllerX is able to manage presses and hold actions. However, the controllers (devices) need to have the capatibility to send those events. Otherwise, ControllerX will not know if there has been a hold action or not. This is an example of using this controller with z2m and a custom mapping:
example_app:
module: controllerx
class: PTM215XLightController
integration: z2m
controller: sensor.my_controller_action
light: light.my_entity_id
mapping:
press_1: "on" # This is already part of the default mapping
press_2: "off" # This is already part of the default mapping
press_3: "on"
press_4: "off"
When you have time, please provide logs and the configuration you have tried.
Regards,
Xavi M.
Hi @SeanNazareth ,
There seems to be a limitation from the controller. You can see that even you are doing 3 actions (click, hold and release), there are only 2 events in the logs: press_3
and release_3
. This means that the click and hold action fire the same event (press_X
). Unfortunately, you cannot achieve what you want with this controller on Zigbee2MQTT. I can see that deCONZ integration supports the 3 actions (click, hold and release).
However, you still have options:
- Use click + multiple click
- Use hold + multiple click
Multiple click is the only way to differentiate clicks and holds. I would recommend you going with a solution like the following:
example_app:
module: controllerx
class: PTM215XLightController
integration: z2m
controller: sensor.my_controller_action
light: light.my_entity_id
mapping:
press_1$2: "on"
press_1: hold_brightness_up
release_1: release
press_2$2: "off"
press_2: hold_brightness_down
release_2: release
This mapping will:
- Turn on light when pressing button 1 twice.
- Birght the light up when holding button 1.
- Turn off light when pressing button 2 twice.
- Dim the light down when holding button 2.
You can read more about multiple clicks here. Note that you can add the mutplie_click_delay
(as shown in the link shared) to loosen the delay to recognize the multi clicks.
P.S.: I see you said: "With regard to my mapping, here's an example...", but then you copied the same message I left you, so I do not see your mapping example.
Regards,
Xavi M.
Hi @SeanNazareth,
Let me answer your questions one by one.
I don't quite understand why you say what I want isn't doable. Your controller detects the "hold" condition, and specify a hold attribute as separate from the "press". Is there some requirement that both the "press" and "hold" operations use the same "attribute? I do understand that the z2m integration only provides press and release events, but somehow, you must detect a "lack" of release over a specific interval to be a "hold" in this case. Specifically, if one paddle is brightness attribute, you currently can simulate a "press" as an incremental bright/dim, and a "hold" as a ramp bright/dim. Are you processing the first "press" based on the press event, and then subsequently a hold because of the "missing or delayed" release? Or do you have some timer that fires some delay after the press to trigger and process the press event? Since you simulate the hold detection for the brightness function, it isn't clear why we couldn't do what I want. Maybe the implementation is that "press" and the "hold" have to both issue the same command, but the simulated "hold" just repeats the "press" command with some frequency?
When I said in my previous comment that is not doable is because if ControllerX receives a press_1
event, it cannot not if it is a hold or a click. It will know that is a hold once a release
event has been received, but in that moment it would be too late to start doing the hold
action. However, if the release
is always triggered (no matter if it is clicked or hold), then it would be possible to set some capability to trigger a click event if the release and the press event are together in time, and trigger a hold event otherwise. I see in the logs you sent that the release
is always sent, so it would be doable for your use case. However, it is a capability that ControllerX does not support. FYI, it is not normal that a controller supports a release
event, but not a hold
one. In general all devices support 3 distinct events for click, hold and release. This is why this is not supported by ControllerX, because it is a specific use case from this specific controller. I will give it a think to add support for this feature, but I would not wait for it since I cannot commit to it.
- I think I understand the mapping vs merge_mapping in that the latter (merge_mapping) lets you just "override" a few of the settings while keeping the defaults for the unmodified presses, while "mapping" requires you to define the operation of all the features/events you want to use. I got really confused last night because I had forgotten this, and tried your "mapping" technique, but found that the "ramp" wouldn't stop. While I'm only reading your email this morning, I think I didn't define the "release" operation so it couldn't detect the release wouldn't know when to stop the ramp. But is there something else I should know about mapping vs merge_mapping? I didn't troubleshoot, but when I was trying the mapping method for on/off, my controlled lights (hue) lost the ramp on/ramp off feature when you turned them on/off. This ramp on/off seems to be automatic with the merge_mapping. Losing the ramp is very jarring as compared to a standard incandescent bulb. Only after restoring the merge_mapping on/off did that feature come back.
All you need to know about the mapping
and merge_mapping
can be found in this section of the documentation: https://xaviml.github.io/controllerx/advanced/.
- I had tried the multiple presses similar as you mention as an option to solve my issue, but I had tried this with the merge_mapping attribute, and I couldn't get it to work. Is that expected? Do I need to use the "mapping" option to make this work? While the multipress may be an option, it's kind of confusing to use as mentioned. 99% of the time, I want the users to do an on/off. Ramp dim/brignt would be rare. Most users wouldn't know (or remember) to do a double press. Worse, after doing single press or press-and-hold (the incremental or ramp function) would leave the light at a random brightness setting, the subsequent double-press on/off will keep using that same setting instead of resetting it. Is there any way to reverse whether the dim/bright is on the double-press or the single press? Can you assign a hold version to the double-press?
It should not matter if you use mapping
or merge_mapping
. The only difference between the 2 is that mapping
allows you to define your own mapping by completely overwriting all the default mappings for that controller. Then, merge_mapping
allows you to only overwrite the events you specify in the configuration, the rest will still be using the default mapping for that controller. My recommendation (if confused) is to use the mapping
option so you do not get any surprises. Especially for your controller which is a controller whose default mapping does not make much sense. Default mappings make sense for controllers which have a defined purpose, like:
- https://xaviml.github.io/controllerx/controllers/E1810/
- https://xaviml.github.io/controllerx/controllers/HueDimmer/
You can reverse the behaviour of the double press, by just inverting the actions:
office_dimmer:
module: controllerx
class: PTM215XLightController
controller: sensor.officeswitch_action
integration: z2m
light: light.office_lights
merge_mapping:
press_1: "on"
press_1$2:
action: hold
attribute: brightness
direction: up
mode: stop
steps: 10
press_2: "off"
press_2$2:
action: hold
attribute: brightness
direction: down
mode: stop
steps: 10
Important note: if you use the words on
and off
, make sure to wrap them up with ". E.g.: "on"
, "off"
.
- I do have an option for what I need, that could work... but I'd only like to do this as a last resort. This particular controller has a press_1/press_2 that corresponds to 1 paddle, press_3/press_4 that corresponds to the 2nd paddle, and a press_1_and_press_3/press_2_and_press_4 that corresponds to both paddles pressed at the same time and the same direction. I could use that one for the rare brightness feature. But, I was really hoping to duplicate the press on/off and hold_for_dim feature I can do with a single paddle with the same switch and the hue hub.
That is correct, those events (press_1_and_3
and press_2_and_4
) can be used for the brighten/dim the light. You could use the hold_brightness_toggle
predefined action to brighten up/down the light. Each time the button is hold, it will alternate the direction of the brightness:
office_dimmer:
module: controllerx
class: PTM215XLightController
controller: sensor.officeswitch_action
integration: z2m
light: light.office_lights
merge_mapping:
press_1: "on"
press_1_and_3:
action: hold
attribute: brightness
direction: toggle
mode: stop
steps: 10
press_3: "off"
- When we do the "on", is there a way to pass an attribute to turn the light on to a specific brightness setting instead of the "last"? And set a specific ramp rate?
You can set the light to a spcific brightness with the on
or toggle
action:
office_dimmer:
module: controllerx
class: PTM215XLightController
controller: sensor.officeswitch_action
integration: z2m
light: light.office_lights
merge_mapping:
press_1:
action: "on"
attributes:
brightness: 128
You can pass any attribute that the light supports. You can see an example here.
Regarding the "ramp" rate, you can configure it through this attributes:
automatic_steps
: Number of steps to go from min to max when smoothing. If the value is 2 with one click you will set the light to 50% and with another one to 100%. The higher, the slower the ramp will be.delay
: Delay in milliseconds that takes between sending the instructions to the light (for the smooth functionality). Note that if leaving to 0, you might get uncommon behavior. The higher, the slower the ramp will be.
In general the automatic_steps
is enough to tweak, but delay
can be used to sent the commands faster.
I hope I answered all your questions.
Regards,
Xavi M.
Thank you so much for your response. Let me try these out today.
Here are a few follow up questions..
-
I think I mostly understand you comments on why the "Hold" and the "click" shouldn't work. What I don't quite understand is why it works if the "click" corresponds to brightness increment/decrement, then the "hold" also works as a hold ramp increment/decrement. Is it because both the press and the hold both issue the same command, i.e. inc/dec brightness, but the "hold" just keeps repeating that command?
-
with regard to the "multi"-press operation, Does the controller issue the "single" press operation on the first press of a multi-press event, and "then" issue the intended multi-press operation? Or does the system delay until it can detect whether the operation is a multi-press, and then issue only the multi-press operation? I guess I can try this, but it might be helpful to others if this is specified in the description.
For example you provided for me, if press_1 is "on", and press_1$2 is hold increment with brightness attribute, press_2 is "off", and press_2$2 is hold decrement with brightness attribute, if the light is currently in state on, would we expect the first press of the double-click brightness decrement to turn off the light? Or would it work logically.
- Is there any way to implement a "stateful" operation.... as described below?
Define state variable "state"
state=0. (i.e. on-off mode)
state=1 (i.e. brightness mode)
In state=0: press_1="on", press_2="off"
In state=1: press_1/press_2 have click/hold for brightness
Use press_1_and_press_3 to toggle state (if 0, make 1, if 1 make 0)
- Is there a good way to "debug" or "see" what the controllerx plug is seeing and doing?
Thanks.
Hi @SeanNazareth ,
Please, find my answers below,
I think I mostly understand you comments on why the "Hold" and the "click" shouldn't work. What I don't quite understand is why it works if the "click" corresponds to brightness increment/decrement, then the "hold" also works as a hold ramp increment/decrement. Is it because both the press and the hold both issue the same command, i.e. inc/dec brightness, but the "hold" just keeps repeating that command?
That is correct. The click
just sends one command to HA to change thr brightness. The hold
keep sending command to HA to change the brightness gradually. Then, it stops either when:
- A
release
command is triggered. - The brightness reaches its maximum/minimum level.
- It reaches the
max_loops
(set to 50 by default).
with regard to the "multi"-press operation, Does the controller issue the "single" press operation on the first press of a multi-press event, and "then" issue the intended multi-press operation? Or does the system delay until it can detect whether the operation is a multi-press, and then issue only the multi-press operation? I guess I can try this, but it might be helpful to others if this is specified in the description.
ControllerX records in the initialization which commands need multiple clicks by checking which commands have the $
. For those, the clicks will always be delayed by the mutliple_click_delay
(500ms) by default since it needs to detect if there will be any more clicks or not. The multiple-click functionality is a virtualization since the multiple clicks do not come from the controller, but ControllerX is the one registering them. You can read more about this functionality here. So, if the command has multiple click registered, then the clicks will be issued after the mutlitple_click_delay
is passed. This is barely noticeable when the mutliple_click_delay
is set to the default value (500ms), this is why it is not specified in the wiki since it is a technicality on how it works. I will, however, add it, so tech people understand how it works.
For example you provided for me, if press_1 is "on", and press_1$2 is hold increment with brightness attribute, press_2 is "off", and press_2$2 is hold decrement with brightness attribute, if the light is currently in state on, would we expect the first press of the double-click brightness decrement to turn off the light? Or would it work logically.
For that configuration to work correctly, you would need to do a double-click, but maintain the button until the brightness is set to the right level. The first press of the double-click would not do anything if the second click is triggered within the 500ms (mutlitple_click_delay
). If no second click is registered, then the action from press_1
/press_2
would be issued.
Is there any way to implement a "stateful" operation.... as described below?
Define state variable "state"
state=0. (i.e. on-off mode)
state=1 (i.e. brightness mode)
In state=0: press_1="on", press_2="off"
In state=1: press_1/press_2 have click/hold for brightness
ControllerX does not register this type of state. However, it can be done together with input_select
(from HA) and constrain_input_select
(from AppDaemon). First, you need to create an input_select
on HA like the following (you can do it on the UI):
input_select:
controller_state:
options:
- state_0
- state_1
Then, you just need to create 2 ControllerX apps:
office_dimmer_0:
module: controllerx
class: PTM215XLightController
controller: sensor.officeswitch_action
integration: z2m
light: light.office_lights
mapping:
press_1: "on"
press_2: "off"
press_1_and_3:
service: input_select.select_next
entity_id: input_select.controller_state
constrain_input_select: input_select.controller_state,state_0
office_dimmer_1:
module: controllerx
class: PTM215XLightController
controller: sensor.officeswitch_action
integration: z2m
light: light.office_lights
mapping:
press_1: hold_brightness_up
release_1: release
press_2: hold_brightness_down
release_2: release
press_1_and_3:
service: input_select.select_next
entity_id: input_select.controller_state
constrain_input_select: input_select.controller_state,state_1
I get this question quite a lot, so I will try to create an article in the documentation to give an example like this. This feature is not a ControllerX feature, but an AppDaemon one. However, I do think it would be nice to have an article to guide user through this.
Is there a good way to "debug" or "see" what the controllerx plug is seeing and doing?
Yes, you can check the AppDaemon logs. You will see in there the ControllerX logs (e.g. which event was triggered, which action was issued, etc). In addition, you can see extra logs if you add log_level: DEBUG
at the same level as module
or class
in the AppDaemon app (ControllerX config).
Regards,
Xavi M.
Hi @SeanNazareth ,
I have added the following to the documentation:
- A section at the end of the multple-click page explaining the technical details about how it works: https://controllerx.netlify.app/controllerx/advanced/multiple-clicks/
- A new page that goes through an easy example of a stateful controller: https://controllerx.netlify.app/controllerx/advanced/stateful-controllers/
Note that the link is from the development documentation. These changes will be released to the main documentation site once a new ControllerX version is released.
Regards,
Xavi M.
Thanks so much for your help and explanations. I think this clarifies things. I didn't get a chance to work on this today, but I'll try to do it later this evening or tomorrow. I suspect I'll be able to do what I want given this info. I really like the idea of the constrained input option.
I think I'll have to play around with things to figure out how to set up the state variable in HA. I think you described the concept well, but I'm not yet quite sure how to do that. But at least you've given me a good direction. I'll verify the other options as well... just for completeness.
Thanks again,
Sean
Glad to help. Let me know if you have anymore questions.