Zigbee2MQTT - Control Alarmo via keypad

This blueprint allows you to control Alarmo from a zigbee keypad. For arming/disarming you can enter a code on the keypad, it is sent to Alarmo and validated. The current status of the alarm can be seen from the keypad.

This blueprint is a modified version of Zigbee2MQTT - Sync Keypad and Alarm Control Panel States by @AndrejDelany. Credits for this blueprint should go to him!
The main difference of this blueprint is that the pin code is not checked within the automation, but validated by Alarmo (this also means that multiple pins can be used).

Compatibility
The blueprint is designed for the Linkind ZS130000078. You can buy this keypad for around €50 on Amazon. It comes in a set with 2 door contacts, motion sensor and a siren (note that the siren is not compattible with Zigbee2MQTT).

Other keypads in Zigbee2MQTT may be compatible as well (or can be made compatible with some changes), but are untested. Post a message in this forum if you want to test your keypad with this blueprint.

Functionality
The keypad is battery powered and will normally sleep. It can only wake up by moving your hand in front of it (it has a built-in motion detector). The keypad will return to sleep in 8 seconds after it woke up.

The keypad has three buttons for controlling the states Disarmed / Armed Home / Armed Away.

After waking up the keypad, you can read the current state of the alarm as follows:

  • Alarm is disarmed: Disarmed button is solid green
  • Alarm is enabled in armed home: Home button is solid green
  • Alarm is enabled in armed away: Away button is solid green
  • Exit delay is active: Away button is blinking green
  • Entry delay is active: Home button is blinking green
  • Alarm is triggered: no buttons are green

To switch between states, press any of the 3 buttons (except the button which is already green). Next enter a PIN and press the checkmark to confirm. The following results can occur:

  • Command was successful: long beep and the state will be updated
  • Wrong PIN has been entered: 3 beeps and the number keys will flash.
  • Command not allowed due to blocking sensors (Home / Away modes): 4 short beeps and exclamation mark icon becomes red
  • Command not allowed in case of disarming when alarm is already disarmed: 3 beeps and the number keys will flash.
  • Other (communication error or similar): communication icon will blink green for 5 seconds, then becomes red, followed by 3 beeps.

Limitations / known issues

  • Pin code is mandatory for both arming and disarming. If you set up Alarmo not to require a pin code for arming, you can simply enter a random pin (can even be 1 digit) and confirm it. It will be accepted.
  • The keypad will not give audio feedback during exit/entry delay or triggered state. The state can only be seen via the button colours after waking up the keypad.
  • The SOS button is currently not implemented (there is also no SOS behaviour in Alarmo yet).
  • After installing the blueprint the keypad does not know the initial state. You need to change the state of Alarmo (without the keypad) to send the initial state.
  • For using this blueprint properly, you need to have Alarmo v1.9.1 (or newer) installed and have the arm modes ‘Away’ and ‘Home’ configured (it’s preferred to have other arm modes disabled since the keypad cannot display/control them).

Code
Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

blueprint:
  name: Alarmo Keypad Sync
  description: Keypad sync with Alarmo
  domain: automation

  input:
    state_topic:
      name: MQTT State Topic of your Zigbee2MQTT Keypad
      description: "The State Topic is composed of your Zigbee2MQTT base_topic (see your Z2M Addon Configuration) and the Friendly Name of your keypad in Z2M. Example: zigbee2mqtt/Keypad"
      selector:
        text:
    set_topic:
      name: MQTT Set Topic of your Zigbee2MQTT Keypad
      description: "This is the same as your State Topic, with the addition of /set. Example: zigbee2mqtt/Keypad/set"
      selector:
        text:
    entity:
      name: Alarmo entity
      description: "An alarm control panel entity from alarmo."
      selector:
        entity:
          domain: alarm_control_panel
          integration: alarmo

trigger:
  - platform: state
    entity_id: !input entity
    to: disarmed
    id: to_state_disarmed
  - platform: state
    entity_id: !input entity
    to: armed_home
    id: to_state_armed_home
  - platform: state
    entity_id: !input entity
    to: armed_away
    id: to_state_armed_away
  - platform: state
    entity_id: !input entity
    to: arming
    id: to_state_arming
  - platform: state
    entity_id: !input entity
    to: pending
    id: to_state_pending
  - platform: state
    entity_id: !input entity
    to: triggered
    id: to_state_triggered
  - platform: mqtt
    topic: !input state_topic
    id: keypad_command
  - platform: event
    event_type: alarmo_failed_to_arm
    id: event_arm_failure
  - platform: event
    event_type: alarmo_command_success
    id: event_command_success
condition: []

action:
  - choose:
      - conditions:
          - condition: trigger
            id: to_state_disarmed
        sequence:
          - service: mqtt.publish
            data_template:
              topic: !input set_topic
              payload: |-
                {
                  "arm_mode": 
                  {
                    "mode": "disarm"
                  }
                }
      - conditions:
          - condition: trigger
            id: to_state_armed_home
        sequence:
          - service: mqtt.publish
            data_template:
              topic: !input set_topic
              payload: |-
                {
                  "arm_mode": 
                  {
                    "mode": "arm_day_zones"
                  }
                }
      - conditions:
          - condition: trigger
            id: to_state_armed_away
        sequence:
          - service: mqtt.publish
            data_template:
              topic: !input set_topic
              payload: |-
                {
                  "arm_mode": 
                  {
                    "mode": "arm_all_zones"
                  }
                }
      - conditions:
          - condition: trigger
            id: to_state_arming
        sequence:
          - service: mqtt.publish
            data_template:
              topic: !input set_topic
              payload: |-
                {
                  "arm_mode": 
                  {
                    "mode": "exit_delay"
                  }
                }
      - conditions:
          - condition: trigger
            id: to_state_pending
        sequence:
          - service: mqtt.publish
            data_template:
              topic: !input set_topic
              payload: |-
                {
                  "arm_mode": 
                  {
                    "mode": "entry_delay"
                  }
                }
      - conditions:
          - condition: trigger
            id: to_state_triggered
        sequence:
          - service: mqtt.publish
            data_template:
              topic: !input set_topic
              payload: |-
                {
                  "arm_mode": 
                  {
                    "mode": "in_alarm"
                  }
                }
      - conditions:
          - condition: trigger
            id: keypad_command
        sequence:
          - choose:
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.payload_json.action == "disarm"  }}'
                sequence:
                  - service: alarmo.disarm
                    data:
                      entity_id: !input entity
                      code: "{{ trigger.payload_json.action_code }}"
                      context_id: "{{ trigger.payload_json.action_transaction }}"
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.payload_json.action == "arm_all_zones"  }}'
                sequence:
                  - service: alarmo.arm
                    data:
                      entity_id: !input entity
                      mode: away
                      code: "{{ trigger.payload_json.action_code }}"
                      context_id: "{{ trigger.payload_json.action_transaction }}"
              - conditions:
                  - condition: template
                    value_template: '{{ trigger.payload_json.action == "arm_day_zones"  }}'
                sequence:
                  - service: alarmo.arm
                    data:
                      entity_id: !input entity
                      mode: home
                      code: "{{ trigger.payload_json.action_code }}"
                      context_id: "{{ trigger.payload_json.action_transaction }}"
      - conditions:
          - condition: trigger
            id: event_arm_failure
        sequence:
          - choose:
              - conditions:
                  - condition: template
                    value_template: "{{ trigger.event.data.reason == 'invalid_code' }}"
                sequence:
                  - service: mqtt.publish
                    data_template:
                      topic: !input set_topic
                      payload: |-
                        {
                          "arm_mode": 
                          {
                            "transaction": {{ trigger.event.data.context_id }},
                            "mode": "invalid_code"
                          }
                        }
              - conditions:
                  - condition: template
                    value_template: "{{ trigger.event.data.reason == 'open_sensors' }}"
                sequence:
                  - service: mqtt.publish
                    data_template:
                      topic: !input set_topic
                      payload: |-
                        {
                          "arm_mode": 
                          {
                            "transaction": {{ trigger.event.data.context_id }},
                            "mode": "not_ready"
                          }
                        }
              - conditions:
                  - condition: template
                    value_template: "{{ trigger.event.data.reason == 'not_allowed' }}"
                  - condition: template
                    value_template: "{{ trigger.event.data.command|lower == 'disarm' }}"
                sequence:
                  - service: mqtt.publish
                    data_template:
                      topic: !input set_topic
                      payload: |-
                        {
                          "arm_mode": 
                          {
                            "transaction": {{ trigger.event.data.context_id }},
                            "mode": "already_disarmed"
                          }
                        }
      - conditions:
          - condition: trigger
            id: event_command_success
        sequence:
          - choose:
              - conditions:
                  - condition: template
                    value_template: "{{ trigger.event.data.action == 'arm' }}"
                  - condition: template
                    value_template: "{{ trigger.event.data.context_id != null }}"
                  - condition: template
                    value_template: "{{ trigger.event.data.mode == 'away' }}"
                sequence:
                  - service: mqtt.publish
                    data_template:
                      topic: !input set_topic
                      payload: |-
                        {
                          "arm_mode": 
                          {
                            "transaction": {{ trigger.event.data.context_id }},
                            "mode": "arm_all_zones"
                          }
                        }
              - conditions:
                  - condition: template
                    value_template: "{{ trigger.event.data.action == 'arm' }}"
                  - condition: template
                    value_template: "{{ trigger.event.data.context_id != null }}"
                  - condition: template
                    value_template: "{{ trigger.event.data.mode == 'home' }}"
                sequence:
                  - service: mqtt.publish
                    data_template:
                      topic: !input set_topic
                      payload: |-
                        {
                          "arm_mode": 
                          {
                            "transaction": {{ trigger.event.data.context_id }},
                            "mode": "arm_day_zones"
                          }
                        }
              - conditions:
                  - condition: template
                    value_template: "{{ trigger.event.data.action == 'disarm' }}"
                  - condition: template
                    value_template: "{{ trigger.event.data.context_id != null }}"
                sequence:
                  - service: mqtt.publish
                    data_template:
                      topic: !input set_topic
                      payload: |-
                        {
                          "arm_mode": 
                          {
                            "transaction": {{ trigger.event.data.context_id }},
                            "mode": "disarm"
                          }
                        }
mode: parallel
max: 10

14 Likes

Wow! This works very very good. I’m using it with a Xfinity XHK1-UE

Maybe the easiest blueprint I’ve ever seen, 3 things to fill and done. Thank you for your work. Keep up the good stuff!

Thank you for making this, makes it so much easier to integrate the keypad. Had a a bit of a fight to get the device functioning but suddenly it worked.

It would be awesome if you could add support for the SOS button, maybe just the option to link an action to it.

1 Like

@neliss " * Other (communication error or similar): communication icon will blink green for 5 seconds, then becomes red, followed by 3 beeps."

So this is happening to me when trying to set a pin for the first time on the linkind keypad. How do I resolve?

For this blueprint to work correctly, you should initially tell the linkind keypad which state the alarm is in.
What I did is arm + disarm the alarm once, via the HA entity directly (or via alarmo-card).
Afterwards the linkind keypad showed the correct state (the icon with LED) and commands are handled correctly.
Note that you don’t set (store) the pin on the keypad, but in Alarmo.

I can’t disable or enable alarm of the keypad via HA. The thing is literally not showing me what all you guys see. Very frustrating to get this keypad working.

This is what I see in entities. No option to arm or disarm in there.

Install Alarmo first. This will create the alarm_control_panel entity you will be controlling via the keypad. Please read the description carefully.

I am using this blueprint and it is amazing. The only difference is my keypad Universal Electronics Inc XHK1-UE control via MQTT | Zigbee2MQTT also has an arm_night_zones button. I am trying to tweak the blueprint to make this work as well but its a bit over my head. Any guidance would be greatly appreciated!

EDIT: I did figure out how to add the armed night mode to the blueprint and have it working on my end. If you would like me to share the changes, I am happy to. I don’t want to hijack your great work and make a new one.

Did you end up publishing your blueprint?

I did not but it is working great. I will put it up when I get home tonight.

That would be awesome!

Perhaps we can add your improvements to this blueprint?
I would prefer if we can provide a ‘one fits all’ solution to the user.
What is contained by this blueprint so far is based on what my own linkind keypad supports.

I have the same keypad, the xfinity. It gets the state from alarmo (the led and keypads change color) but nothing seems to happen when I use the pin on the keypad (the alarm state never updates). Any advice?

Sounds good to me. Ill post it up. I am using it with multiple keypads now. I do need a separate automation for each keypad. I suppose it would be amazing if there was 1 automation which could control as many keypads as possible, but thats a bit over my head.

blueprint:
  name: Alarmo Keypad Sync - JD Rev
  description: Keypad sync with Alarmo - JD Rev
  domain: automation
  input:
    state_topic:
      name: MQTT State Topic of your Zigbee2MQTT Keypad
      description: 'The State Topic is composed of your Zigbee2MQTT base_topic (see
        your Z2M Addon Configuration) and the Friendly Name of your keypad in Z2M.
        Example: zigbee2mqtt/Keypad'
      selector:
        text: {}
    set_topic:
      name: MQTT Set Topic of your Zigbee2MQTT Keypad
      description: 'This is the same as your State Topic, with the addition of /set.
        Example: zigbee2mqtt/Keypad/set'
      selector:
        text: {}
    entity:
      name: Alarmo entity
      description: An alarm control panel entity from alarmo.
      selector:
        entity:
          domain: alarm_control_panel
          integration: alarmo
          multiple: false

trigger:
- platform: state
  entity_id: !input entity
  to: disarmed
  id: to_state_armed_night
- platform: state
  entity_id: !input entity
  to: disarmed
  id: to_state_disarmed
- platform: state
  entity_id: !input entity
  to: armed_home
  id: to_state_armed_home
- platform: state
  entity_id: !input entity
  to: armed_away
  id: to_state_armed_away
- platform: state
  entity_id: !input entity
  to: arming
  id: to_state_arming
- platform: state
  entity_id: !input entity
  to: pending
  id: to_state_pending
- platform: state
  entity_id: !input entity
  to: triggered
  id: to_state_triggered
- platform: mqtt
  topic: !input state_topic
  id: keypad_command
- platform: event
  event_type: alarmo_failed_to_arm
  id: event_arm_failure
- platform: event
  event_type: alarmo_command_success
  id: event_command_success
condition: []
action:
- choose:
  - conditions:
    - condition: trigger
      id: to_state_disarmed
    sequence:
    - service: mqtt.publish
      data_template:
        topic: !input set_topic
        payload: "{\n  \"arm_mode\": \n  {\n    \"mode\": \"disarm\"\n  }\n}"
  - conditions:
    - condition: trigger
      id: to_state_armed_home
    sequence:
    - service: mqtt.publish
      data_template:
        topic: !input set_topic
        payload: "{\n  \"arm_mode\": \n  {\n    \"mode\": \"arm_day_zones\"\n  }\n}"
  - conditions:
    - condition: trigger
      id: to_state_armed_night
    sequence:
    - service: mqtt.publish
      data_template:
        topic: !input set_topic
        payload: "{\n  \"arm_mode\": \n  {\n    \"mode\": \"arm_night_zones\"\n  }\n}"		
  - conditions:
    - condition: trigger
      id: to_state_armed_away
    sequence:
    - service: mqtt.publish
      data_template:
        topic: !input set_topic
        payload: "{\n  \"arm_mode\": \n  {\n    \"mode\": \"arm_all_zones\"\n  }\n}"
  - conditions:
    - condition: trigger
      id: to_state_arming
    sequence:
    - service: mqtt.publish
      data_template:
        topic: !input set_topic
        payload: "{\n  \"arm_mode\": \n  {\n    \"mode\": \"exit_delay\"\n  }\n}"
  - conditions:
    - condition: trigger
      id: to_state_pending
    sequence:
    - service: mqtt.publish
      data_template:
        topic: !input set_topic
        payload: "{\n  \"arm_mode\": \n  {\n    \"mode\": \"entry_delay\"\n  }\n}"
  - conditions:
    - condition: trigger
      id: to_state_triggered
    sequence:
    - service: mqtt.publish
      data_template:
        topic: !input set_topic
        payload: "{\n  \"arm_mode\": \n  {\n    \"mode\": \"in_alarm\"\n  }\n}"
  - conditions:
    - condition: trigger
      id: keypad_command
    sequence:
    - choose:
      - conditions:
        - condition: template
          value_template: '{{ trigger.payload_json.action == "disarm"  }}'
        sequence:
        - service: alarmo.disarm
          data:
            entity_id: !input entity
            code: '{{ trigger.payload_json.action_code }}'
            context_id: '{{ trigger.payload_json.action_transaction }}'
      - conditions:
        - condition: template
          value_template: '{{ trigger.payload_json.action == "arm_all_zones"  }}'
        sequence:
        - service: alarmo.arm
          data:
            entity_id: !input entity
            mode: away
            code: '{{ trigger.payload_json.action_code }}'
            context_id: '{{ trigger.payload_json.action_transaction }}'
      - conditions:
        - condition: template
          value_template: '{{ trigger.payload_json.action == "arm_day_zones"  }}'
        sequence:
        - service: alarmo.arm
          data:
            entity_id: !input entity
            mode: home
            code: '{{ trigger.payload_json.action_code }}'
            context_id: '{{ trigger.payload_json.action_transaction }}'
      - conditions:
        - condition: template
          value_template: '{{ trigger.payload_json.action == "arm_night_zones"  }}'
        sequence:
        - service: alarmo.arm
          data:
            entity_id: !input entity
            mode: home
            code: '{{ trigger.payload_json.action_code }}'
            context_id: '{{ trigger.payload_json.action_transaction }}'
  - conditions:
    - condition: trigger
      id: event_arm_failure
    sequence:
    - choose:
      - conditions:
        - condition: template
          value_template: '{{ trigger.event.data.reason == ''invalid_code'' }}'
        sequence:
        - service: mqtt.publish
          data_template:
            topic: !input set_topic
            payload: "{\n  \"arm_mode\": \n  {\n    \"transaction\": {{ trigger.event.data.context_id
              }},\n    \"mode\": \"invalid_code\"\n  }\n}"
      - conditions:
        - condition: template
          value_template: '{{ trigger.event.data.reason == ''open_sensors'' }}'
        sequence:
        - service: mqtt.publish
          data_template:
            topic: !input set_topic
            payload: "{\n  \"arm_mode\": \n  {\n    \"transaction\": {{ trigger.event.data.context_id
              }},\n    \"mode\": \"not_ready\"\n  }\n}"
      - conditions:
        - condition: template
          value_template: '{{ trigger.event.data.reason == ''not_allowed'' }}'
        - condition: template
          value_template: '{{ trigger.event.data.command|lower == ''disarm'' }}'
        sequence:
        - service: mqtt.publish
          data_template:
            topic: !input set_topic
            payload: "{\n  \"arm_mode\": \n  {\n    \"transaction\": {{ trigger.event.data.context_id
              }},\n    \"mode\": \"already_disarmed\"\n  }\n}"
  - conditions:
    - condition: trigger
      id: event_command_success
    sequence:
    - choose:
      - conditions:
        - condition: template
          value_template: '{{ trigger.event.data.action == ''arm'' }}'
        - condition: template
          value_template: '{{ trigger.event.data.context_id != null }}'
        - condition: template
          value_template: '{{ trigger.event.data.mode == ''away'' }}'
        sequence:
        - service: mqtt.publish
          data_template:
            topic: !input set_topic
            payload: "{\n  \"arm_mode\": \n  {\n    \"transaction\": {{ trigger.event.data.context_id
              }},\n    \"mode\": \"arm_all_zones\"\n  }\n}"
      - conditions:
        - condition: template
          value_template: '{{ trigger.event.data.action == ''arm'' }}'
        - condition: template
          value_template: '{{ trigger.event.data.context_id != null }}'
        - condition: template
          value_template: '{{ trigger.event.data.mode == ''home'' }}'
        sequence:
        - service: mqtt.publish
          data_template:
            topic: !input set_topic
            payload: "{\n  \"arm_mode\": \n  {\n    \"transaction\": {{ trigger.event.data.context_id
              }},\n    \"mode\": \"arm_day_zones\"\n  }\n}"
      - conditions:
        - condition: template
          value_template: '{{ trigger.event.data.action == ''arm'' }}'
        - condition: template
          value_template: '{{ trigger.event.data.context_id != null }}'
        - condition: template
          value_template: '{{ trigger.event.data.mode == ''home'' }}'
        sequence:
        - service: mqtt.publish
          data_template:
            topic: !input set_topic
            payload: "{\n  \"arm_mode\": \n  {\n    \"transaction\": {{ trigger.event.data.context_id
              }},\n    \"mode\": \"arm_night_zones\"\n  }\n}"
      - conditions:
        - condition: template
          value_template: '{{ trigger.event.data.action == ''disarm'' }}'
        - condition: template
          value_template: '{{ trigger.event.data.context_id != null }}'
        sequence:
        - service: mqtt.publish
          data_template:
            topic: !input set_topic
            payload: "{\n  \"arm_mode\": \n  {\n    \"transaction\": {{ trigger.event.data.context_id
              }},\n    \"mode\": \"disarm\"\n  }\n}"
mode: parallel
max: 10

Thanks for posting it!

For me, disarm works with just the code. Arming requires me to hit the arming mode button and than any 4 digits trigger it to be set. Would be nice if the button alone did it, but it seems to be a hardware related limitation that a code is required to send the arm command.

Hmmm. That’s what I’ve been trying. Thanks for the advice I appreciate the feedback. I’ll have to do more debugging.

Have you checked the logs in zigbee2mqtt?