Zipato keypad - resolved

Hi,

Has anyone written a driver for the Zipato wt-rfid z-wave keypad?

https://www.amazon.fr/dp/B00KMU55TY/ref=cm_sw_r_cp_taa_v5h4CbH27RKQG

I have seen a smartthings device handler so might have to work on porting that.

A quick search of the forum shows that @mike.maxwell was working on this just about a year ago. Any update Mike? Never saw a resolution in the thread I saw but it was VERY long so I might have missed it.

It's still sitting in its box...

1 Like

This is the sole device I have on ST that stops me unplugging it. We don’t have many keypad options in the EU, so would be very cool to have this working.

I attempted porting the ST driver but without success :disappointed_relieved:

1 Like

I'll have a go this week. I'll let you know how I get on

3 Likes

OK,

So, I have found the problem but I don't know what the solution is... The difference between Smartthings and Hubitat is the amount of data that is being received on a parse.

The driver compares the .user field obtained from the parse with with a stored value but as this field does not exist the driver crashes out.

The parse handler is the same on both Smartthings and hubitat and the raw data received by hubitat from the device is the same but hubitat doesn't decode all of the data which is the cause of the problem

Parse Handler:

def parse(String description) {
debug ("Parsing - $String - $description")
def result = null
def versions =  [ 0x70: 1, 0x63: 1, 0x72: 2, 0x25: 1, 0x84: 1, 0x86: 1, 0x71: 2, 0x85: 2, 0x80:1  ]
def cmd = zwave.parse(description, versions)
debug ("NOW Parsing - $cmd")
  if (cmd) {
    result = zwaveEvent(cmd)
         
} else {
    log.error "Non-parsed event: ${description}"
}
return result

}

Smartthings output
String = class java.lang.String
description = zw device: 07, command: 6303, payload: 00 00 8F 9B 48 28 85 50 01 04 00 00"

After zwave.parse(description, versions) command:
UserCodeReport(userIdStatus: 0, userIdentifier: 7, code: , user: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

Hubitat Output
String = class java.lang.String
description = zw device: 07, command: 6303, payload: 00 00 8F 9B 48 28 85 50 01 04 00 00 B1 00 , isMulticast: false

After zwave.parse(description, versions) command:
UserCodeReport(userIdentifier:0, userIdStatus:0, userCode:null)

So you can see that the user code data is not available on hubitat which is why we can not get this keypad to work.

I will send this topic to hubitat support, hopefully they can find a solution

For the time being I will have to use smartthings to interface with the keypad. @Royski : How do you pass the "home" / "away" status from smartthings to hubitat? is there a way of sending directly from Hub to Hub?

1 Like

Thats a great find!! Hopefully someone can help on this.

I'm using hubConnect between my two HE hubs and ST.
Works extremely well.

You dont have to pass the Home / Away though, you can just pass the RFID device as a switch. Then use rules in HE to switch the mode/HSM etc.

Not sure what the issue is here, but I don't think ST is parsing this correctly.

the first byte in the payload is the user Identifier, aka slot
the second byte is the id status
for the status byte, 00 = not set, 01 = occupied
per the zwave spec when the status is 00, the next 4 bytes are all supposed to be set to 00, clearly the device isn't doing that...
It looks like ST has mapped the Z-Wave device ID into the userIdentifier attribute for some reason...
The userIdentifier is clearly 00, which we parse correctly, the status is 00 which we parse correctly, when we get a userIdentifier code of 00 we don't even look at whatever follows since per spec it's supposed to be 4 bytes of 00...

So Zipato has tacked on extra bytes onto this payload, and I'm sure they have some meaning, but what that Is I have no idea.

Hi @mike.maxwell,

I have spent a bit of time looking at how the Zipato works and why this parsing is important.

So when you use a new RFID in the reader it sends to the hub the following data:
zw device: 08, command: 6303, payload: 00 00 8F 9B 48 28 85 50 01 04 00 00
this needs to be parsed as UserCodeReport(userIdStatus: 0, userIdentifier: 0, code: ›H(
P, user: [143, 155, 72, 40, 133, 80, 1, 4, 0, 0])
so: hex to Dec
8F - 143
9B - 155
48 - 72
28 - 40
85 - 133
50 - 80
01 - 1
04 - 4
00 - 0
00 - 0

When the same RFID is used again, the Zipato recognised the key number as being allocated to a user and allows the operation of the "home" "Away" buttons.

The problem that we have is that the parse decoding on hubitat is not giving enough information. I am far from an expert on this. I am trying to port the ST driver and I can see where it is falling over. To enable the driver to work: the decoding of the parse information needs contain all the information that it does in ST, I can move it around etc if the formatting is a bit different but more than that is beyond me

1 Like

All done! - Nearly (sorry)

It is now saving keyfob keys and looking them up when a kew fob is applied but... "It is not saving the keyfob code correctly"

the line of code that sends the key codes to the Zipato is

requests << zwave.userCodeV1.userCodeSet(userIdentifier: userNumber, userIdStatus: UserCodeSet.USER_ID_STATUS_OCCUPIED, userCode: state.lastUnrecognisedCode).format()

But, when sending [143, 155, 72, 40, 133, 80, 1, 4, 0, 0] the device stores this as the hex value for the ascii characters, eg 5b 31 34 33. 5B = 091 decimal which is the ascii code for [ 31 is the ascii code for 1 etc etc. When you use the keyfog the device reads the 8F 9B etc hex value of 143 155 etc and compares it to 5B 31 etc and therefore does not recognise the fob.

The guy who programmed the ST version had the same problem which is why he commented out the command and replaced it with the following code:

495        def cmd = [
496        	0x63, // USER_CODE command class
497            0x01, // USER_CODE SET command
498            userNumber,
509            UserCodeSet.USER_ID_STATUS_OCCUPIED]
500        cmd += state.lastUnrecognisedCode
501        cmd = cmd.collect { String.format("%02x", it).toUpperCase() }.join('')
502        requests << cmd

This code works in ST but not in HE which crashes out with the following error

error java.util.IllegalFormatConversionException: x != java.util.ArrayList on line 501

Does anyone know what needs to be done to correct the above code? Once that is done then the driver should work.

The full code is available on my github page:

1 Like

Yeah getting the same here. Just un-paired from ST and re-paired on HE.
Fantastic that you've got this far though!! :smiley:

Let's hope that someone can help with the last little bit. My groovy knowledge is pretty basic, been learning as I go along.

1 Like

You've done far better than I could! Hats off :+1:

1 Like

Does this help at all?

https://sharkysoft.com/archive/printf/docs/javadocs/lava/clib/stdio/doc-files/specification.htm

For our locks we use the following to add a user code to a lock:
zwave.userCodeV1.userCodeSet(userIdentifier:codeNumber, userIdStatus:1, userCode:code).format()
where codeNumber is an Integer and
code is a String representation of the pin code, IE pin code 1234 -> "1234"
So assuming that state.lastUnrecognisedCode is the actual pin code, IE 1234, then state.lastUnrecognisedCode.toString() should do it.

Similarly, zwaveEvent(hubitat.zwave.commands.usercodev1.UserCodeReport cmd)
Returns the stored code from the device in cmd.userCode as a string

Hi Mike,

The device stores the code for each registerd key fob in hex 10 hex pairs ie F2 3B 47... etc etc. When you use a key Fob the device compares the code with its list of activated keys, and activates the home away controls. When it is an unknown key fob the devices gives the HE the unknown key fob code as a decimal array. If HE wants to add the unknown key fob then the code is sent back to the device telling it to assign it. This last step is my problem as I can't get the code back into the device as a list of hex values.

ah I see, the ST driver is creating a command from scratch, to do this in Hubitat you will want to return a hex string, not an array of hex bytes...
In other words what you want to create would be "630101<8F9B...whatever...>"

1 Like

OK,

I have a version that can work but it is a bit manual, I'm sure @mike.maxwell can give me the answer :slight_smile:

So, the code to set a new keyfob is:

	     def cmd = [
    	0x63, // USER_CODE command class
        0x01, // USER_CODE SET command
        userNumber,
        UserCodeSet.USER_ID_STATUS_OCCUPIED]
    cmd += newCode
    cmd = cmd.collect { String.format("%02x", it).toUpperCase() }.join('')
    requests << cmd

newCode is set by a little handler that convers the array to a hex string.

def convertCode (code) {
debug "Converting code $code"
//code = "256"
def newCode = "0x"
def indexStart = 0
def indexEnd = code.indexOf(',')
for (int i = 0; i < 10; i++){
	
	def byteDec = code[indexStart+1..indexEnd-1] as int
	
	codeByte = Integer.toHexString(byteDec) 
	if (byteDec < 15) {newCode = "$newCode" + "0"}
	newCode = "$newCode" + "$codeByte"
	
	indexStart = indexEnd + 1
	indexEnd = code.indexOf(',',indexEnd +1)
}

So if I write:

	def newCode = convertCode (state.lastUnrecognisedCode)
	debug "newCode = $newCode"

then the logger says "newCode = 0x8f153e0c720001040000" so all should be find? but no. the command doesn't work

if I hardcode the "newCode" as follows

	def newCode = 0x8f153e0c720001040000  // (note, no quotation marks)

then the command works and the keyfob is registered and the Zipato works !!! But I have to edit the driver to hardcode the hex value of each fob that I want to register!

I would like to know how I am supposed to tell hubitat to treat newCode as hex (i've tried as hex or as byte etc but come up with nothing)

I'm sure the answer is a one liner but I don't know what that line is!

I have updated my driver on github

1 Like

change this to newCode = ""

sorry,

Don't quite follow.

the def is currenty

 def newCode = convertCode (state.lastUnrecognisedCode)
debug "newCode = $newCode"

and "convertCode" is what gets the hex string together