TD22057 / insteon-mqtt

Python Insteon PLM <-> MQTT bridge
GNU General Public License v3.0
99 stars 43 forks source link

6 Button Keypad in HA not working as expected #418

Closed roopesh closed 3 years ago

roopesh commented 3 years ago

When trying to control button 1 (Load) of the six button keypad from the Home Assistant UI, it's sending insteon/<address>/set/1 ON which doesn't do anything. That is the expected behavior for the other buttons but not the load. For the load insteon/command/<address> {"cmd": "on"} needs to be sent.

I think the discovery message for the six button keypad needs to be updated... at the same time, could buttons 2 and 9 be removed?

roopesh commented 3 years ago

I went through the guidance here (https://github.com/TD22057/insteon-mqtt/blob/master/docs/discovery.md#six-button-keypadlinc) and added a new discovery class. However I keep getting an error on restart:

mqtt: 
  kpl_six: 
    btn_on_off_payload: 
    - must be of dict type
    btn_on_off_topic: 
    - must be of dict type
    btn_scene_payload: 
    - must be of dict type
    btn_scene_topic: 
    - must be of dict type
    btn_state_payload: 
    - must be of dict type
    btn_state_topic: 
    - must be of dict type
    dimmer_level_payload: 
    - must be of dict type
    dimmer_level_topic: 
    - must be of dict type
    dimmer_state_payload: 
    - must be of dict type
    dimmer_state_topic: 
    - must be of dict type

I have tried renaming all the topic/payload variables (and updating them in the associated discovery entities) and the error just changes to the new name. I've checked my syntax:

mqtt:
  kpl_six:
    btn_state_topic: 'insteon/{{address}}/state/{{button}}'
    btn_state_payload: '{{on_str.upper()}}'
    dimmer_state_topic: 'insteon/{{address}}/state/1'
    dimmer_state_payload: '{ "state" : "{{on_str.upper()}}", "brightness" : {{level_255}} }'
    btn_on_off_topic: 'insteon/{{address}}/set/{{button}}'
    btn_on_off_payload: '{ "cmd" : "{{value.lower()}}" }'
    dimmer_level_topic: 'insteon/command/{{address}}'
    dimmer_level_payload: >
        '{ "cmd" : "{{json.state.lower()}}"
         {% if json.brightness is defined %}
             , "level" : {{json.brightness}}
         {% endif %}
         {% if json.transition is defined %}
             , "transition" : {{json.transition}}
         {% endif %} }'
    btn_scene_topic: 'insteon/{{address}}/scene/{{button}}'
    btn_scene_payload: >
            '{ "cmd" : "{{json.cmd.lower()}}"
              {% if json.brightness is defined %}
                  , "level" : {{json.brightness}}
              {% endif %}
            }'
    discovery_entities:
      - component: 'light'
        config: |-
          {
            "uniq_id": "{{address}}_1",
            "name": "{{name_user_case}} btn 1",
            "device": {{device_info_template}},
            "brightness": {{is_dimmable|lower()}},
            "cmd_t": "{%- if is_dimmable -%}
                        {{dimmer_level_topic}}
                      {%- else -%}
                        {{btn_on_off_topic_1}}
                      {%- endif -%}",
            "schema": "json",
            "stat_t": "{%- if is_dimmable -%}
                        {{dimmer_state_topic}}
                      {%- else -%}
                        {{btn_state_topic_1}}
                      {%- endif -%}"
          }
      - component: 'switch'  
        config: |-
          {
            "uniq_id": "{{address}}_3",
            "name": "{{name_user_case}} btn 3",
            "device": {{device_info_template}},
            "cmd_t": "{{btn_on_off_topic_3}}",
            "stat_t": "{{btn_on_off_topic_3}}"
          }
      - component: 'switch'
        config: |-
          {
            "uniq_id": "{{address}}_4",
            "name": "{{name_user_case}} btn 4",
            "device": {{device_info_template}},
            "cmd_t": "{{btn_on_off_topic_4}}",
            "stat_t": "{{btn_on_off_topic_4}}"
          }
      - component: 'switch'
        config: |-
          {
            "uniq_id": "{{address}}_5",
            "name": "{{name_user_case}} btn 5",
            "device": {{device_info_template}},
            "cmd_t": "{{btn_on_off_topic_5}}",
            "stat_t": "{{btn_on_off_topic_5}}"
          }
      - component: 'switch'
        config: |-
          {
            "uniq_id": "{{address}}_6",
            "name": "{{name_user_case}} btn 6",
            "device": {{device_info_template}},
            "cmd_t": "{{btn_on_off_topic_6}}",
            "stat_t": "{{btn_on_off_topic_6}}"
          }

I've done yaml validations, too. Any ideas why I keep getting the same error?

krkeegan commented 3 years ago

You missed a key when writing your new class

mqtt:
  kpl_six:
    discovery_entities:
       ....
roopesh commented 3 years ago

Thanks @krkeegan. However discovery_entities is in my class definition. How can I debug what specifically is missing or mis-defined?

krkeegan commented 3 years ago

Apologies, I only saw the first lines. What I should say is you can only have discovery_entities in that definition. you need to drop:

    btn_state_topic: 'insteon/{{address}}/state/{{button}}'
    btn_state_payload: '{{on_str.upper()}}'
    dimmer_state_topic: 'insteon/{{address}}/state/1'
    dimmer_state_payload: '{ "state" : "{{on_str.upper()}}", "brightness" : {{level_255}} }'
    btn_on_off_topic: 'insteon/{{address}}/set/{{button}}'
    btn_on_off_payload: '{ "cmd" : "{{value.lower()}}" }'
    dimmer_level_topic: 'insteon/command/{{address}}'
    dimmer_level_payload: >
        '{ "cmd" : "{{json.state.lower()}}"
         {% if json.brightness is defined %}
             , "level" : {{json.brightness}}
         {% endif %}
         {% if json.transition is defined %}
             , "transition" : {{json.transition}}
         {% endif %} }'
    btn_scene_topic: 'insteon/{{address}}/scene/{{button}}'
    btn_scene_payload: >
            '{ "cmd" : "{{json.cmd.lower()}}"
              {% if json.brightness is defined %}
                  , "level" : {{json.brightness}}
              {% endif %}
            }'
roopesh commented 3 years ago

Oh! So where do those definitions come from? In order to fix the original issue here I was thinking to redefine the dimmer_level_payload configuration.

krkeegan commented 3 years ago

The only place to change topic and payload templates is:

mqtt:
  keypad_linc:
    dimmer_level_payload: ...

Does that make sense?

roopesh commented 3 years ago

OK @krkeegan, I think I've narrowed this down further. Basically, I can't seem to have Button 1 and Button 3+ on/off work from HA discovered entities. There may be multiple things going on, so I'll just share my findings.

The topics and payloads to button 1 and 3 need to be different. Here's what works (at the command line using mosquitto):

mosquitto_pub -t 'insteon/52.29.9d/set/3' -m '{"state":"on"}' 
mosquitto_pub -t 'insteon/command/52.29.9d' -m '{"cmd":"on"}'

which result in states being generated:

insteon/52.29.9d/state/1 { "state" : "ON", "brightness" : 255 }
insteon/52.29.9d/state/3 ON

Using the discovered HA entities, the following corresponding on messages get sent:

insteon/52.29.9d/set/1 {"state": "ON"}
insteon/52.29.9d/set/3 ON

But only the button 3 state changes (published)

insteon/52.29.9d/state/3 ON

Button 1 has an error:

2021-05-22 08:01:34.359 DEBUG Mqtt: Received PUBLISH (d0, q0, r0, m0), 'insteon/52.29.9d/set/1', ...  (15 bytes)
2021-05-22 08:01:34.359 INFO KeypadLincDimmer: KeypadLinc message insteon/52.29.9d/set/1 b'{"state": "ON"}'
2021-05-22 08:01:34.360 DEBUG MsgTemplate: Input template render: '{ "cmd" : "on"

   }'
2021-05-22 08:01:34.361 INFO KeypadLincDimmer: KeypadLinc input command: {'cmd': 'on'}
2021-05-22 08:01:34.361 DEBUG SetTopic: SetTopic message insteon/52.29.9d/set/1 b'{"state": "ON"}'
2021-05-22 08:01:34.362 DEBUG MsgTemplate: Input template render: '{ "cmd" : "{"state": "on"}" }'
2021-05-22 08:01:34.362 ERROR MsgTemplate: Invalid JSON message { "cmd" : "{"state": "on"}" } from template { "cmd" : "{{value.lower()}}" }
2021-05-22 08:01:34.362 INFO SetTopic: SetTopic input command: None
2021-05-22 08:01:34.362 ERROR SetTopic: Invalid SetTopic command: None
Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/insteon_mqtt/mqtt/topic/SetTopic.py", line 131, in _input_set
    is_on, mode, transition = util.parse_on_off(data)
  File "/usr/lib/python3.8/site-packages/insteon_mqtt/mqtt/util.py", line 37, in parse_on_off
    cmd = data.get('cmd').lower()
AttributeError: 'NoneType' object has no attribute 'get'

Button 3 is fine:

2021-05-22 07:58:09.284 DEBUG Mqtt: Received PUBLISH (d0, q0, r0, m0), 'insteon/command/52.29.9d', ...  (12 bytes)
2021-05-22 07:58:09.284 INFO Mqtt: MQTT message insteon/command/52.29.9d b'{"cmd":"on"}'
2021-05-22 07:58:09.284 UI Mqtt: Commanding keypad_linc device 52.29.9d (office fan) cmd=on
2021-05-22 07:58:09.285 INFO ResponderBase: Device 52.29.9d grp: 1 cmd: on normal
2021-05-22 07:58:09.285 DEBUG MsgHistory: Average hops 0.0, using 0
2021-05-22 07:58:09.285 INFO Protocol: Write message to modem: Std: 52.29.9d, Type.DIRECT mh:0 hl:0, 11 ff 
2021-05-22 07:58:09.285 DEBUG Protocol: Write bytes to modem: 026252299d0011ff
2021-05-22 07:58:09.285 DEBUG Serial: Wrote 8 bytes to serial /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AM00O14D-if00-port0
2021-05-22 07:58:09.309 INFO Protocol: Read 0x62: Std: 52.29.9d, Type.DIRECT mh:0 hl:0, 11 ff ack: True
2021-05-22 07:58:09.310 DEBUG Protocol: Passing msg to write handler: StandardCmd handler
2021-05-22 07:58:09.310 DEBUG StandardCmd: 52.29.9d got PLM ACK
2021-05-22 07:58:09.470 INFO Protocol: Read 0x50: Std: 52.29.9d->53.c2.d9 Type.DIRECT_ACK mh:0 hl:0 cmd: 11 ff
2021-05-22 07:58:09.470 DEBUG Protocol: Setting next write time: 07:58:09.470
2021-05-22 07:58:09.470 DEBUG MsgHistory: Received 0 hops, total 0 for 11 entries
2021-05-22 07:58:09.470 DEBUG Protocol: Passing msg to write handler: StandardCmd handler
2021-05-22 07:58:09.471 DEBUG ResponderBase: Device 52.29.9d ACK: Std: 52.29.9d->53.c2.d9 Type.DIRECT_ACK mh:0 hl:0 cmd: 11 ff
2021-05-22 07:58:09.471 INFO Base: Setting device 52.29.9d (office fan) on True level 255 normal command
2021-05-22 07:58:09.471 INFO StateTopic: MQTT received state 52.29.9d (office fan) on: {'is_on': True, 'level': 255, 'mode': <Mode.NORMAL: 'normal'>, 'button': 1, 'reason': 'command'}
2021-05-22 07:58:09.471 DEBUG Mqtt: Sending PUBLISH (d0, q0, r1, m41), 'b'insteon/52.29.9d/state/1'', ... (38 bytes)
2021-05-22 07:58:09.472 DEBUG Mqtt: MQTT publish insteon/52.29.9d/state/1 { "state" : "ON", "brightness" : 255 } qos=0 ret=1
2021-05-22 07:58:09.472 UI Mqtt: Device state updated to on=True
2021-05-22 07:58:09.472 DEBUG Protocol: Write handler finished
2021-05-22 07:58:09.473 DEBUG Mqtt: MQTT writing
2021-05-22 07:58:48.530 DEBUG Mqtt: Received PUBLISH (d0, q0, r0, m0), 'insteon/52.29.9d/set/3', ...  (2 bytes)
2021-05-22 07:58:48.530 DEBUG SetTopic: SetTopic message insteon/52.29.9d/set/3 b'ON'
2021-05-22 07:58:48.531 DEBUG MsgTemplate: Input template render: '{ "cmd" : "on" }'
2021-05-22 07:58:48.532 INFO SetTopic: SetTopic input command: {'cmd': 'on'}
2021-05-22 07:58:48.532 INFO KeypadLinc: KeypadLinc setting LED 3 to True
2021-05-22 07:58:48.533 DEBUG MsgHistory: Average hops 0.0, using 0
2021-05-22 07:58:48.533 INFO Protocol: Write message to modem: Ext: 52.29.9d, Type.DIRECT ext mh:0 hl:0, 2e 00 01 09 c5 00 00 00 00 00 00 00 00 00 00 00 
2021-05-22 07:58:48.534 DEBUG Protocol: Write bytes to modem: 026252299d102e000109c50000000000000000000003
2021-05-22 07:58:48.534 DEBUG Serial: Wrote 22 bytes to serial /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AM00O14D-if00-port0
2021-05-22 07:58:48.562 INFO Protocol: Read 0x62: Ext: 52.29.9d, Type.DIRECT ext mh:0 hl:0, 2e 00 ack: True 01 09 c5 00 00 00 00 00 00 00 00 00 00 03 
2021-05-22 07:58:48.562 DEBUG Protocol: Passing msg to write handler: StandardCmd handler
2021-05-22 07:58:48.562 DEBUG StandardCmd: 52.29.9d got PLM ACK
2021-05-22 07:58:48.769 INFO Protocol: Read 0x50: Std: 52.29.9d->53.c2.d9 Type.DIRECT_ACK mh:0 hl:0 cmd: 2e 00
2021-05-22 07:58:48.770 DEBUG Protocol: Setting next write time: 07:58:48.769
2021-05-22 07:58:48.770 DEBUG MsgHistory: Received 0 hops, total 0 for 11 entries
2021-05-22 07:58:48.770 DEBUG Protocol: Passing msg to write handler: StandardCmd handler
2021-05-22 07:58:48.771 DEBUG KeypadLinc: KeypadLinc LED 52.29.9d group 3 ACK: Std: 52.29.9d->53.c2.d9 Type.DIRECT_ACK mh:0 hl:0 cmd: 2e 00
2021-05-22 07:58:48.771 UI KeypadLinc: KeypadLinc 52.29.9d LED's changed to 11000101
2021-05-22 07:58:48.771 INFO Base: Setting device 52.29.9d (office fan) on None level 255 normal command
2021-05-22 07:58:48.771 INFO StateTopic: MQTT received state 52.29.9d (office fan) on: {'is_on': None, 'level': 255, 'mode': <Mode.NORMAL: 'normal'>, 'button': 3, 'reason': 'command'}
2021-05-22 07:58:48.772 DEBUG Mqtt: Sending PUBLISH (d0, q0, r1, m42), 'b'insteon/52.29.9d/state/3'', ... (2 bytes)
2021-05-22 07:58:48.773 DEBUG Mqtt: MQTT publish insteon/52.29.9d/state/3 ON qos=0 ret=1
2021-05-22 07:58:48.774 DEBUG Protocol: Write handler finished
2021-05-22 07:58:48.774 DEBUG Mqtt: MQTT writing

Oddly, if I use dimming, Button 1 will get published as

insteon/52.29.9d/set/1 {"state": "ON", "brightness": 128}

and the state will change:

insteon/52.29.9d/state/1 { "state" : "ON", "brightness" : 128 }

Now, if I change btn_on_off_payload to '{ "cmd" : "{{json.state.lower()}}" }', Button 1 on/off works great (including dimming) but Button 3+ no longer work.

2021-05-22 08:08:15.932 DEBUG Mqtt: Received PUBLISH (d0, q0, r0, m0), 'insteon/52.29.9d/set/3', ...  (2 bytes)
2021-05-22 08:08:15.932 DEBUG SetTopic: SetTopic message insteon/52.29.9d/set/3 b'ON'
2021-05-22 08:08:15.935 ERROR MsgTemplate: Error rendering payload: 'None' has no attribute 'state'
2021-05-22 08:08:15.936 ERROR MsgTemplate: Template was: 
{ "cmd" : "{{json.state.lower()}}" }
2021-05-22 08:08:15.936 ERROR MsgTemplate: Data passed was: {'value': 'ON', 'json': None}
2021-05-22 08:08:15.936 DEBUG MsgTemplate: Input template render: 'None'
2021-05-22 08:08:15.936 INFO SetTopic: SetTopic input command: None
2021-05-22 08:08:15.936 ERROR SetTopic: Invalid SetTopic command: None
Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/insteon_mqtt/mqtt/topic/SetTopic.py", line 131, in _input_set
    is_on, mode, transition = util.parse_on_off(data)
  File "/usr/lib/python3.8/site-packages/insteon_mqtt/mqtt/util.py", line 37, in parse_on_off
    cmd = data.get('cmd').lower()
AttributeError: 'NoneType' object has no attribute 'get'

I'm totally ok trying to fix this myself if you can point me in the direction... I can't figure out how to disentangle Button 1 and Button 3+ payloads.

Thanks!

krkeegan commented 3 years ago

Thank you, all of your data was very helpful.

The code around the dimmer for keypad_lincs is a little messy. I will look into cleaning that up.

In the meantime, I think if you change the following, it should just work:

mqtt:
  keypad_linc:
    btn_on_off_payload: >-
      { "cmd" : {%- if json is defined and json -%}
                  "{{json.state.lower()}}"
                {%- else -%}
                  "{{value.lower()}}"
                {%- endif -%}}

Let me know if that solves the issue.

All of these commands should then work:

insteon/52.29.9d/set/1 {"state": "ON"}
insteon/52.29.9d/set/3 {"state": "ON"}
insteon/52.29.9d/set/3 ON

Also check to make sure that dimming still works:

insteon/52.29.9d/set/1 {"state": "ON", "brightness": 128}

It should.

roopesh commented 3 years ago

That resolved it! Thank you!