Synchronize Ring Alarm Keypad v2 with Alarmo

A few weeks ago, I posted instructions for pairing the Ring Alarm Keypad v2 with Home Assistant using ZWaveJS2MQTT. A few folks asked for a Blueprint for the automations necessary to synchronize the keypad with an alarm_control_panel. I’ve finally got that in a state I like, so here it is.

Note that this Blueprint specifically requires Alarmo, since it uses some events that as far as I know are Alarmo-specific. If you want to integrate with a different alarm_control_panel implementation, it should be mostly portable.

This automation handles all of the keypad behaviors except for the three emergency buttons. I may put together a separate Blueprint to tie those in with Noonlight, but that seemed like not a great idea as a default requirement.

This is my first time putting together a Blueprint, so I’m happy to take suggestions if there’s better ways to do something.

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

blueprint:
  name: Ring Keypad Automations
  description: Automations to use the Ring Keypad with an Alarm Panel integration.  See https://github.com/ImSorryButWho/HomeAssistantNotes/blob/main/RingKeypadV2.md for more information.
  domain: automation
  input:
    keypad:
      name: Keypad Device
      description: The device entry for the Ring keypad
      selector:
        device:
          manufacturer: Ring
          integration: zwave_js
    alarm:
      name: Alarm Control Panel entity
      description: The Alarm Control Panel to synchronize the keypad with
      selector:
        entity:
          domain: alarm_control_panel
          integration: alarmo
    selected_action_police:
      name: Selected Action Police
      description: Select the action for Police Button
      default: []
      selector:
        action:
    selected_action_fire:
      name: Selected Action Fire
      description: Select the action for Fire Button
      default: []
      selector:
        action:
    selected_action_medical:
      name: Selected Action Medical
      description: Select the action for Medical Button
      default: []
      selector:
        action:
variables:
  alarm: !input alarm
mode: parallel
max: 10
trigger:
  - platform: event
    event_type: "zwave_js_notification"
    event_data:
      command_class: 111
      device_id: !input keypad
      event_type: 2
    id: code_entered
  - platform: event
    event_type: "zwave_js_notification"
    event_data:
      command_class: 111
      device_id: !input keypad
      event_type: 3
    id: keypad_disarm
  - platform: event
    event_type: "zwave_js_notification"
    event_data:
      command_class: 111
      device_id: !input keypad
      event_type: 5
    id: keypad_arm_away
  - platform: event
    event_type: "zwave_js_notification"
    event_data:
      command_class: 111
      device_id: !input keypad
      event_type: 6
    id: keypad_arm_home
  - platform: event
    event_type: zwave_js_notification
    event_data:
      command_class: 111
      device_id: !input 'keypad'
      event_type: 16
    id: keypad_fire
  - platform: event
    event_type: zwave_js_notification
    event_data:
      command_class: 111
      device_id: !input 'keypad'
      event_type: 17
    id: keypad_police
  - platform: event
    event_type: zwave_js_notification
    event_data:
      command_class: 111
      device_id: !input 'keypad'
      event_type: 19
    id: keypad_medical
  - platform: event
    event_type: "alarmo_failed_to_arm"
    event_data:
      reason: "invalid_code"
    id: invalid_code
  - platform: event
    event_type: "alarmo_failed_to_arm"
    event_data:
      reason: "open_sensors"
    id: need_bypass
  - platform: state
    entity_id: !input alarm
    to: disarmed
    id: alarm_disarmed
  - platform: state
    entity_id: !input alarm
    to: arming
    id: alarm_arming
  - platform: state
    entity_id: !input alarm
    to: armed_away
    id: alarm_armed_away
  - platform: state
    entity_id: !input alarm
    to: armed_home
    id: alarm_armed_home
  - platform: state
    entity_id: !input alarm
    to: pending
    id: alarm_pending
  - platform: state
    entity_id: !input alarm
    to: triggered
    id: alarm_triggered
condition:
  condition: not
  conditions:
    - condition: template
      value_template: "{{ ('from_state' in trigger) and (trigger.from_state.state == 'unknown') }}"
action:
  choose:
    - conditions:
        - condition: trigger
          id:
            - code_entered
            - keypad_disarm
      sequence:
        - service: alarmo.disarm
          data:
            entity_id: !input alarm
            code: >
              {% if trigger.event.data.event_data != none %}
                {{ trigger.event.data.event_data }}
              {% endif %}
    - conditions:
        - condition: and
          conditions:
            - condition: or
              conditions:
                - condition: trigger
                  id: keypad_arm_away
                - condition: trigger
                  id: keypad_arm_home
            - condition: state
              entity_id: !input alarm
              state: disarmed
      sequence:
        - service: alarmo.arm
          data:
            entity_id: !input alarm
            mode: '{{ trigger.id.split("_")[2] }}'
            force: false
            code: >
              {% if trigger.event.data.event_data != none %}
                {{ trigger.event.data.event_data }}
              {% endif %}
        - wait_for_trigger:
            - platform: event
              event_type: zwave_js_notification
              event_data:
                command_class: 111
                device_id: !input keypad
                event_type: 2
                event_data: null
          timeout: '5'
          continue_on_timeout: false
        - service: alarmo.arm
          data:
            entity_id: !input alarm
            mode: '{{ trigger.id.split("_")[2] }}'
            force: true
            code: >
              {% if trigger.event.data.event_data != none %}
                {{ trigger.event.data.event_data }}
              {% endif %}
    - conditions:
        - condition: trigger
          id:
            - invalid_code
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "9"
            property_key: "1"
            value: 100
    - conditions:
        - condition: trigger
          id: need_bypass
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "16"
            property_key: "1"
            value: 100
    - conditions:
        - condition: trigger
          id: alarm_disarmed
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "2"
            property_key: "1"
            value: 100
    - conditions:
        - condition: trigger
          id: alarm_armed_away
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "11"
            property_key: "1"
            value: 100
    - conditions:
        - condition: trigger
          id: alarm_armed_home
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "10"
            property_key: "1"
            value: 100
    - conditions:
        - condition: trigger
          id: alarm_arming
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "18"
            property_key: "7"
            value: "{{ state_attr(alarm, 'delay') }}"
    - conditions:
        - condition: trigger
          id: alarm_pending
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "17"
            property_key: "7"
            value: "{{ state_attr(alarm, 'delay') }}"
    - conditions:
        - condition: trigger
          id: alarm_triggered
      sequence:
        - service: zwave_js.set_value
          target:
            device_id: !input keypad
          data:
            command_class: "135"
            endpoint: "0"
            property: "13"
            property_key: "1"
            value: 100
    - conditions:
      - condition: trigger
        id: keypad_fire
      sequence: !input selected_action_fire
    - conditions:
      - condition: trigger
        id: keypad_police
      sequence: !input selected_action_police
    - conditions:
      - condition: trigger
        id: keypad_medical
      sequence: !input selected_action_medical
6 Likes

This is great, thank you! A few suggestions/requests:

  • Add a trigger for a code entry timeout based on property ‘0’ which sends the keypad error tone similar to for an invalid code entry.
  • Possibly add the same error tone for fire, medical, and police.
  • Add ‘manufacturer: Ring’ to your device selector and it will only show the Ring keypads.

Great suggestions, thanks! I added the manufacturer restriction, which makes it a lot nicer.

I tried the timeout suggestion, and unfortunately the keypad doesn’t seem to work like you’d expect. If you enter a code, let it time out, then send the command to play an error, it doesn’t actually play it until you press another button. I’m not sure what’s going on in its internal state machine, but the delayed feedback seems probably more confusing than helpful.

Similarly, I don’t think errors for the emergency buttons are a good idea here. I like the idea of error feedback, and might try it in a separate blueprint. But if someone does wire up something useful to them, I don’t want it to both do whatever they’ve wired up and signal an error.

I think the timeout error is if you don’t enter a complete code.

Another thing I noticed… I setup Alarmo to require a pin for arming as well. Looks like you have only set this up to pass the code for disarming.

Sorry for all the posts, but I also noticed another item. It would be good if you could arm to away mode if the alarmo state is armed_home. As it is the way you have it setup, you can only arm to either home or away if alarmo is disarmed.

Okay, updated to pass an arming code if one is provided, and to allow arming away from armed home.

Note that it looks like Alarmo doesn’t give you an exit delay if you arm to away from home, which probably isn’t want you want. That one you’ll have to take up with the Alarmo developers.

Thanks for putting this together! I was just working to convert my ring keypad over from smartthings last night and was stuck on a few items, so this helps immensely.

I don’t use a passcode with the Alamro keypad, just the ring keypad. Just a use case to consider. I’ll have to figure out how to modify so I can verify the ring input against a variable code.

1 Like

Thanks. Looks good!

I have 3 keypads. I noticed only one of them exposes a motion sensor. I see that it is running firmware 1.18, while the other two without the motion sensor are on firmware 1.8. Looks like firmware can only be updated through the Ring app through a base station. Can anyone confirm this?

I noticed on HA restarts, Alarmo must change its state and this causes the keypad to make arm/disarm announcements on restart. Can you think of a clean way to avoid this? Perhaps an option for an input boolean that be set on at HA start which prevents the announcements from running?

I haven’t noticed that in my setup. Maybe the most straightforward way to handle this would be to disable this automation on home assistant stop, and re-enable it at some point after startup? Something like:

automation:
  - name: "Disable alarm keypad sync on shutdown"
    trigger: 
      platform: homeassistant
      event: shutdown
    action: 
      service: automation.turn_off
      entity_id: automation.ring_keypad_automations
    mode: single
  - name: "Enable keypad sync after startup"
    trigger:
      platform: homeassistant
      event: start
    action:
      sequence:
        - delay: 30
        - service: automation.turn_on
          entity_id: automation.ring_keypad_automations
    mode: single

Or, actually, another thought: is the alarm_control_panel state showing as “unknown” on startup for you? We could condition the whole automation on the trigger not being a state transition from unknown.

Yes it is “Unknown” during my nightly restart for backups. Here’s a snapshot.

Okay, updated to include what I think should be the right condition. Sorry, this case I can’t test - let me know if it doesn’t stop it. It at least doesn’t break normal operation.

Thanks. I’ll test it tonight.

You should also consider adding a source URL to the blueprint code. This will likely be what HA requires in a future update to automatically update blueprints.

So… dumb question, but where is that documented? I don’t see that option in the blueprint schema.

@ImSorryButWho Thanks so much for this! I’ve been struggling with how to get this all setup as well and this should definitely help the WAF!

1 Like

First off this blueprint is great! Thanks so much for the work.

I noticed the three mode buttons do not light up when first changing modes, here is an example

When arming home the status light will be turned off until the keypad goes to sleep and wakes up again it will then be red (or blue). This happens with all modes; disarmed, armed home, and armed away. You can cover the motion sensor after a mode change, wait for keypad to sleep then uncover and it will be the correct status color.

Never used the Ring keypad before integrating with Home Assistant, not sure if this is by design or not.

Thank you!