... integrate the Ring Keypad v1 (not v2)

Posted on
Thu Dec 03, 2020 2:18 pm
jay (support) offline
Site Admin
User avatar
Posts: 18219
Joined: Mar 19, 2008
Location: Austin, Texas

... integrate the Ring Keypad v1 (not v2)

Overview

I recently purchased both a v1 and v2 Ring Keypad to see if we could integrate them more closely with Indigo. First and foremost, the v2 keypad won't work reliably with Indigo because it seems to only support S2 Z-Wave security which Indigo doesn't yet support (it's a HUGE undertaking, which even other open source solutions have yet to do, but it is on our to do list for some future version).

I was fully intending to add direct support for the v1 keypad; unfortunately, now it seems to be unavailable (I guess I got lucky in getting one of the last ones), so it seems inappropriate to spend any significant time on it given that you can't easily buy one. In lieu of official support, I've put together this tutorial on how you can use the v1 keypad with Indigo's match raw packet event type.

How the v1 Keypad works

The v1 keypad works by sending packets to Indigo at various times when buttons are pressed. When you press a number key, it adds that key to a list. The keypad will continue to add numeric key presses to this list until one of several things happens:

  1. You stop pressing buttons and the timeout of 5 seconds (user adjustable via a config param) is up without pressing anything else.
  2. You press one of the non-numeric keys (Away, Disarm, Home, ✔️, and X).
  3. You press 8 numeric keys.

When the timeout period expires or you press the Away, Disarm, Home, ✔️, and X keys, the keypad will immediately send a message to Indigo indicating that the button has been pressed along with anything in its numeric key list. If you press one of those buttons without pressing any numeric keys first, it will just send an empty list (see below for details). If you enter 8 keys, it will immediately send a message formatted to look like 8 keys were pressed followed by the timeout period (like #1 above). Note that it's sent immediately following the 8th key press, so any other key you press after that starts the process over.

Each of these scenarios are cases you can catch using the Match Raw Packet event type in Indigo, allowing you complete flexibility in setting up your own codes to trigger any action(s) Indigo can perform. Neat, huh?

Z-Wave Packet Description

The complex part of this solution is how to construct the match bytes for use in the Match Raw Packet event type. Let's look at an example, then explain what each bytes are important and how to match those. If you press:

Code: Select all
1-2-3-4-5-6-✔️


the messages you'll get from the keypad look something like this:

Code: Select all
   Z-Wave Debug                    RCVD nonceFetch: node 027
   Z-Wave Debug                    SENT nonceReport: 01 11 00 13 1B 0A 98 80 26 92 6C E5 4D B3 68 2C 25 F5 A3
   Z-Wave Debug                    RCVD nonceReport: 01 05 00 13 F5 00 1C (node ACK)
   Z-Wave Debug                    . .  nonceReport: requeuing 1 unsolicited packets
   Z-Wave Debug                    RCVD encryptedPacket: 00 6F 01 01 02 00 00 (decrypted)
   Z-Wave Debug                    RCVD requestReply1: 01 0C 00 04 00 1B 06 6F 01 01 02 00 00 FF (hex)
   Z-Wave Debug                    RCVD nonceFetch: node 027
   Z-Wave Debug                    SENT nonceReport: 01 11 00 13 1B 0A 98 80 26 92 6C E5 4D B3 68 2C 25 F6 A0
   Z-Wave Debug                    RCVD nonceReport: 01 05 00 13 F6 00 1F (node ACK)
   Z-Wave Debug                    RCVD encryptedPacket: 00 6F 01 02 02 02 06 31 32 33 34 35 36 (decrypted)
   Z-Wave Debug                    RCVD requestReply1: 01 12 00 04 00 1B 0C 6F 01 02 02 02 06 31 32 33 34 35 36 FF (hex)


This is what you would see (with the Z-Wave debugging config option turned on) in the Event Log window. You only care about that last line, and more specifically the list of hexadecimal bytes:

Code: Select all
01 12 00 04 00 1B 0C 6F 01 02 02 02 06 31 32 33 34 35 36 FF


If you look closely, you'll notice pretty quickly a pattern:

Code: Select all
31 32 33 34 35 36


That looks suspiciously like the numbers you pressed (1 2 3 4 5 6). It is, in fact, the list of numbers you pressed directly before you pressed the ✔️ key - just added to 30 hexadecimal (usually written as 0x30). Further, if you look at the byte directly before it, you'll see that it's 0x06, which is the count of numbers that follow. This is the main pattern that you'll want to keep in mind as you construct your match bytes string.

Here is a summary of the full byte string and what's important:

  • bytes 1-9: will always be: 01 ? 00 04 00 1B ? 6F 01 (the second and seventh bytes seem to vary, but it's not relevant to our matching logic)
  • byte 10: sequence or something (also not relevant to our matching logic)
  • byte 11: always: 02
  • byte 12: 01=Timeout, 02=✔️(Checkmark), 03=Disarm, 05=Away, 06=Home, 19=X(Cancel)
  • byte 13: count of bytes directly following - corresponding to the number of numeric keys pressed
  • byte 14-22: (list of digits pressed up to 8) 30=0, 39=9
  • last byte: always FF

Given this summary, you can now fully decipher the byte list above, because the 12th byte is 0x02 - which represents the ✔️ key. There are 2 places where the data varies, but we don't care about those, so this is how you'd construct your match bytes (note the use of the 0x00 hexadecimal notation):

Code: Select all
0x01 ? 0x00 0x04 0x00 0x1B ? 0x6F 0x01 ? 0x02 0x02 0x06 0x31 0x32 0x33 0x34 0x35 0x36 0xFF


The ? in the second and seventh locations will just ignore anything in those locations because they aren't relevant. Also, byte 10 should also match anything using the ? because it's not part of our matching logic. Byte 12 is 0x02, which will match the sequence end key if it's the ✔️ key. Byte 13 is 0x06, because the next 6 bytes will represent the numeric keys pressed.

Here's another example. If I press:

Code: Select all
1-0-9-7


and just wait for the timeout (default of 5 seconds), this is what I'll see in the debug log:

Code: Select all
   Z-Wave Debug                    RCVD nonceFetch: node 027
   Z-Wave Debug                    SENT nonceReport: 01 11 00 13 1B 0A 98 80 54 C8 3A 75 9A 36 2A D5 25 FE AF
   Z-Wave Debug                    RCVD nonceReport: 01 05 00 13 FE 00 17 (node ACK)
   Z-Wave Debug                    RCVD encryptedPacket: 00 6F 01 01 02 00 00 (decrypted)
   Z-Wave Debug                    RCVD requestReply1: 01 0C 00 04 00 1B 06 6F 01 01 02 00 00 FF (hex)
   Z-Wave Debug                    RCVD nonceFetch: node 027
   Z-Wave Debug                    SENT nonceReport: 01 11 00 13 1B 0A 98 80 17 75 D1 6B 29 8C 7D 3B 25 FF 15
   Z-Wave Debug                    RCVD nonceReport: 01 05 00 13 FF 00 16 (node ACK)
   Z-Wave Debug                    RCVD encryptedPacket: 00 6F 01 02 02 01 04 31 30 39 37 (decrypted)
   Z-Wave Debug                    RCVD requestReply1: 01 10 00 04 00 1B 0A 6F 01 02 02 01 04 31 30 39 37 FF (hex)


Again, the only line I'm interested in is the last line, and the bytes in it:

Code: Select all
 01 10 00 04 00 1B 0A 6F 01 02 02 01 04 31 30 39 37 FF
                                  T   4  1  0  9  7


The T byte is 0x01 which represents the timeout ending sequence, followed by the count of numbers pressed (0x04), followed by each digit added to 0x30 hexadecimal. So, your match bytes would be:

Code: Select all
0x01 ? 0x00 0x04 0x00 0x1B ? 0x6F 0x01 ? 0x02 0x01 0x04 0x34 0x30 0x39 0x37 0xFF


Another example. If you want to match the code 1097 followed by ANY sequence end (timeout, any non-numeric key), you would use this match bytes string:

Code: Select all
0x01 ? 0x00 0x04 0x00 0x1B ? 0x6F 0x01 ? 0x02 ? 0x04 0x34 0x30 0x39 0x37 0xFF


Notice the ? in the 12th byte position - that means match any value, so it will match any of the possible sequence ending scenarios.

If you just want to catch any of the non-numeric keys (Away, Disarm, Home, ✔️, and X) without any digits, you can use the general pattern described above, but for the number of numeric keys you specify 0x00 directly followed by the end byte 0xFF. So, if you just want to catch a Home button press by itself:

Code: Select all
0x01 ? 0x00 0x04 0x00 0x1B ? 0x6F 0x01 ? 0x02 0x06 0x00 0xFF


0x06 is the Home key, followed by 0x00 since there are not digits, followed by the end byte of 0xFF.

That's it! You can now catch codes and keypresses from your keypad to fire Indigo Events. Use this in conjunction with the Homegrown Security System wiki article to build your own alarm system in Indigo.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Mon Dec 07, 2020 6:35 pm
Dual offline
Posts: 257
Joined: Feb 05, 2019

Re: ... integrate the Ring Keypad v1 (not v2)

Jay thanks so much for your work. I have been building my own PIN using a 0 second timeout receiving each number press separately. I suspected it would work as you determined and it has been on my ToDo list for a couple of years to experiment and figure out what you have learned. Now I don't have to do it ... thanks to you. :)

To execute the built in indications use the raw command ... screenshot attached of typical command. Also list of payloads for each command below.

[*] 0x87 0x01 0x01 speaks "home and armed" and HOME button lights up red
[*] 0x87 0x01 0x02 speaks "away and armed" and AWAY button lights up red
[*] 0x87 0x01 0x03 speaks "disarmed" and DISARM button lights up blue
[*]0x87 0x01 0x04 turns on the siren and the RING flashes red
[*]0x87 0x01 0x05 speaks "sensors require bypass" and flashes the checkmark white and turns on the yellow warning light
[*]0x87 0x01 0x06 makes a heartbeat noise and the ring flashes red in a CCW motion
[*]0x87 0x01 0x07 makes a heartbeat noise and the ring flashes red in a CW motion
[*]0x87 0x01 0x08 makes a chime noise and the ring flashes red

That's as much as I figured out through my experimentation.
Attachments
Screen Shot 2020-12-07 at 5.11.25 PM.png
Screen Shot 2020-12-07 at 5.11.25 PM.png (294.9 KiB) Viewed 2775 times

Posted on
Mon Dec 07, 2020 7:45 pm
jay (support) offline
Site Admin
User avatar
Posts: 18219
Joined: Mar 19, 2008
Location: Austin, Texas

Re: ... integrate the Ring Keypad v1 (not v2)

Great information, thanks!

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Wed Dec 09, 2020 8:23 pm
whmoorejr offline
User avatar
Posts: 762
Joined: Jan 15, 2013
Location: Houston, TX

Re: ... integrate the Ring Keypad v1 (not v2)

My keypad showed up finally and I've begun tinkering and finally have something to contribute to the topic instead of just being a sponge.

Using match raw packets, I was able to get proximity on and proximity off.

Firstly, I checked parameters 4, 11, 13, 14 which I set as follows:
4 (proximity timeout) 5 (seconds)
11 (Light Sensor) 5 <- default I think.
13 (proximity on) 1 = on
14 (proximity distance) = 100 <- default. (still have to be right in front of it to register)

Raw packets
Proximity On: 0x01 0x10 0x00 0x04 0x00 0x31 0x0A 0x71 0x05 0x00 0x00 0x00 0xFF 0x07 0x08 0x00 0x01 0xFF
Proximity Off: 0x01 0x10 0x00 0x04 0x00 0x31 0x0A 0x71 0x05 0x00 0x00 0x00 0xFF 0x07 0x00 0x00 0x01 0xFF

What I used for trigger (threw a bunch of ?? in there in a guessing pattern)
On: 0x01 ? 0x00 0x04 0x00 ? ? ? ? ? ? ? ? 0x07 0x00 0x00 0x01 0xFF
Off: 0x01 ? 0x00 0x04 0x00 ? ? ? ? ? ? ? ? 0x07 0x08 0x00 0x01 0xFF

Side note: The proximity thing works fine, as long as the keypad is unplugged. Once I plug it into a USB, no more proximity detection.

Edit: I don't think this is actually the proximity packets. I don't think proximity sends any raw zwave packets, I think the device's proximity behavior is an internal function of the device.... but I think that function (which acts to illuminate the keypad) changes the power mode of the device when the device is unplugged. I think it's the power mode change that is sending the raw packets. That would explain why the proximity illuminates the keypad regardless of power source, but only sends traffic when unplugged.

Next up, working on some python bits to compare entered numbers to a list of user pins. I'll probably be back on the forum in a day to ask for help on that. :lol:

Bill
My Plugin: My People

Posted on
Thu Dec 10, 2020 10:32 am
jay (support) offline
Site Admin
User avatar
Posts: 18219
Joined: Mar 19, 2008
Location: Austin, Texas

Re: ... integrate the Ring Keypad v1 (not v2)

Great information! Thanks.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Fri Jan 15, 2021 7:35 pm
Dual offline
Posts: 257
Joined: Feb 05, 2019

Re: ... integrate the Ring Keypad v1 (not v2)

whmoorejr wrote:
Next up, working on some python bits to compare entered numbers to a list of user pins. I'll probably be back on the forum in a day to ask for help on that. :lol:


I am about to try doing this. Did you have success? Can you share your python code?

Cheers

John

Posted on
Fri Jan 15, 2021 9:15 pm
whmoorejr offline
User avatar
Posts: 762
Joined: Jan 15, 2013
Location: Houston, TX

Re: ... integrate the Ring Keypad v1 (not v2)

Dual wrote:
Did you have success? Can you share your python code?

Cheers

John


I did figure it out. I have a few versions depending on how you are doing it.
If you want to build the PINs from variables, you can do it this way:
Code: Select all
# Users
Bill = indigo.variables[699977664].value # "User01_Bill"
User2 = indigo.variables[669277461].value # "User02"
Vikki = indigo.variables[380866193].value # "User03_Vikki"
Anna = indigo.variables[190982521].value # "User04_Anna"
Ashley = indigo.variables[717167343].value # "User05_Ashley"
OneTime1 = indigo.variables[141646497].value # "User20_OneTime1"
# Add 20 more lines

# Build PW List
PWLIST = (Bill, User2, Vikki, Anna, Ashley, OneTime1)

# Receive and check the input variable
PWInput = indigo.variables[777599449].value # "PWInput"

if PWInput in PWLIST:
   indigo.variable.updateValue(748482965, value="Success")

else:
   indigo.variable.updateValue(748482965, value="Fail")

If you have your PIN codes saved in a CSV file, you can do it this way:
Code: Select all
import csv

# Default failure indicator to be written to the variable
login_name = "fail"
with open('/Users/williammoore/Desktop/PinList.csv', 'r') as csvfile:
   csv_reader = csv.reader(csvfile)
   password = indigo.variables[777599449].value # "PWInput"
   for column in csv_reader (You can thank Jay for helping me out with this one):
      # You had prints which would be eaten - this will write to the Indigo log
      indigo.server.log(column[0],column[1])
      indigo.server.log(password)
      if column[1] == password:
         # When you find the first match, set the login_name to the correct Value
         # and break out of the for loop since you don't need to go further
         login_name = column[0]
         break
# Update the variable with the login name or "fail" if it hasn't changed
indigo.variable.updateValue(748482965, value=login_name)


And of course I have one written that works with My People plugin:
Which looks like this:
Code: Select all
import logging
login_name = "PIN fail" # if you change this, don't forget to update the if login_name == "PIN fail" below
password = indigo.variables[777599449].value # "PWInput"
theMessage = "Unsuccessful PIN Entry Attempt with PIN: " + password

for dev in indigo.devices.iter(filter="com.whmoorejr.my-people"):
   MyPin = dev.states["userPinNumber"]
   if MyPin == password:
      login_name = dev.states["friendlyName"]
      theMessage = "PIN Code Accepted, " + login_name + " is here."
#      indigo.server.log(login_name + " can have soup!") # log a success PIN message
#      indigo.actionGroup.execute(12345678) # run a success PIN action

if login_name == "PIN fail":
   indigo.server.log("No Soup For You!", level=logging.WARNING) # log a failure message
#   indigo.actionGroup.execute(87654321) # run a failure PIN action

indigo.variable.updateValue(748482965, value=login_name)  # update variable with name of user with matching pin or "PIN Fail"
indigo.server.log(theMessage) # log the result of the script

Bill
My Plugin: My People

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 1 guest