Whenever on and off keywords are specified in app configuration, ControllerX won't work as expected.
I experienced this bug while working on a custom light controller with an IKEA E1743 configured with the z2m integration, which exposes on and off actions for the controller, but this issue is related to every use of the on and off keywords in yaml configuration.
I discovered this is due to the fact that, according to YAML specification, on and off are interpreted as True and False respectively.
One of the possible solutions is to always specify these 2 values wrapped in single quotes ('on' and 'off'). Therefore they will be treated as strings and won't evaluate to boolean values.
z2mThis is an example of a faulty configuration. Observe on and off keys and values not wrapped in single quotes.
example_app:
module: controllerx
class: CustomLightController
controller: sensor.mycontroller
integration: z2m
light: light.mylight
mapping:
brightness_up: hold_brightness_up
brightness_down: hold_brightness_down
brightness_stop: release
on: on
off: off
The solution is to wrap on and off keywords in single quotes.
example_app:
module: controllerx
class: CustomLightController
controller: sensor.mycontroller
integration: z2m
light: light.mylight
mapping:
brightness_up: hold_brightness_up
brightness_down: hold_brightness_down
brightness_stop: release
'on': 'on'
'off': 'off'
This issue could be solved by asking users to always wrap these values when writing the configuration (adding an entry in the docs), or doing some sort of pre-processing whenever on or off are expected to be passed to ControllerX but True or False are received instead.
on and off are interpreted as boolean values in YAML, I don't think there's anything to be done here.
I'm not sure you need the quotes around the mapping keys, only the values: 'on': 'on' could become on: 'on' (to be tested though)
Here's the reference as to what will be interpreted as a boolean if not quoted in YAML: https://yaml.org/type/bool.html
Hi @Crocmagnon,
For testing purposes I edited the Controller Class as follows:
async def handle_action(self, action_key):
# edit: log actions_mapping
print(self.actions_mapping)
if action_key in self.actions_mapping:
previous_call_time = self.action_times[action_key]
now = time.time() * 1000
self.action_times[action_key] = now
if now - previous_call_time > self.action_delta:
self.log(
f"馃幃 Button event triggered: `{action_key}`",
level="INFO",
ascii_encode=False,
)
await self.call_action(action_key)
This way every time a valid action is received the entire actions mapping is logged.
With the following configuration for ControllerX:
example_app:
module: controllerx
class: CustomLightController
controller: sensor.mycontroller
integration: z2m
light: light.mylight
mapping:
brightness_up: on_full_brightness
brightness_down: on_min_brightness
brightness_stop: release
on: 'on'
off: 'off'
I get the following in AppDaemon log:
{
'brightness_up': (<bound method action.<locals>._action_impl of <core.custom_controller.CustomLightController object at 0x75614a00>>, 'brightness'),
'brightness_down': (<bound method action.<locals>._action_impl of <core.custom_controller.CustomLightController object at 0x75614a00>>, 'brightness'),
'brightness_stop': <bound method action.<locals>._action_impl of <core.custom_controller.CustomLightController object at 0x75614a00>>,
True: <bound method action.<locals>._action_impl of <core.custom_controller.CustomLightController object at 0x75614a00>>,
False: <bound method action.<locals>._action_impl of <core.custom_controller.CustomLightController object at 0x75614a00>>
}
So it seems also mapping keys without quotes evaluate to boolean values.
While doing a little research I came across this StackOverflow question where the asker has the same problem we are experiencing here:
He's using PyYAML as a parser, which is YAML 1.1 conformant.
The package is also used by AppDaemon and has the behaviour you pointed out for boolean interpretation. :+1:
So it seems also mapping keys without quotes evaluate to boolean values.
Thanks for testing that! I learned something 馃檪
As @Crocmagnon is saying. This is not something from ControllerX. This is a "problem" on the library that parses the yaml that Home Assistant and AppDaemon uses. So there is no development that can be further made on this. However, I will add a note on the documentation to advertise about this.
Thank you for you guys pointing this out.
Thanks for testing that! I learned something
You're welcome @Crocmagnon, I didn't know about this detail in yaml 1.1 specification so it was something new (and unexpected) for me too :smiley:
As @Crocmagnon is saying. This is not something from ControllerX. This is a "problem" on the library that parses the yaml that Home Assistant and AppDaemon uses. So there is no development that can be further made on this. However, I will add a note on the documentation to advertise about this.
Thank you for you guys pointing this out.
You're welcome @xaviml, mine was a suggestion to avoid users having to wrap these keywords when using them in configuration, but adding a note to the docs is probably the best way without dealing with re-parsing the actions mapping just for this specific purpose.
As always, thank you for putting so much effort on this project and sharing your work with the Home Assistant community :rocket:
I added a note in the configuration page and in the device pages (like this one).
This issue can be closed now.
Most helpful comment
As @Crocmagnon is saying. This is not something from ControllerX. This is a "problem" on the library that parses the yaml that Home Assistant and AppDaemon uses. So there is no development that can be further made on this. However, I will add a note on the documentation to advertise about this.
Thank you for you guys pointing this out.