[GUIDE] Writing Z-Wave Drivers for S2

Thank you. That was helpful and easy to follow.

One more question . . .

  • If you use Supervise without S2 -- i.e., for a non-secure node, you have to be careful about what is supervised (commands can be supervised, certain "gets" can't be, etc.).

  • If you supervise only for S2 added nodes, do you need to use the same caution? Or, since you are supervising the "secure" packet rather than the underlining payload, can you just supervise everything without being concerned about what is in the secure payload?

Correct.. not everything should be supervised..

Yes

1 Like

3.7.2 Compatibility considerations
This command class is used as an integrated part of the Security 2 Command Class but may also be used for non-secure applications.

The Supervision Command Class MAY be used for solitary commands such as Set, Remove and unsolicited Report commands.

The Supervision Command Class MUST NOT be used for session-like command flows such as Get<->Report command exchanges or firmware update.

The Supervision Get Command MAY carry multiple commands grouped with the Multi Command encapsulation command.

So it looks like my GE Enbrighten drivers do this correctly - that's good.

I did notice, though, that my zwave.supervisionV1.supervisionReport command does not have a ".format()" on it. Mine's working, so I guess I'll leave it alone.

I admit I never know when to/not to use .format() for sure anyway...

1 Like

It will work like that.. But you are passing the class on to zwaveSecureEncap.. .format() before passes a string (slightly less resource intensive) ..

1 Like

Do nodes have a "timeout" allowing the same sessionID to be used twice in a row for different commands?

Specific issue - on Hub restart, you don't know the last sessionID seen by a node (unless you save it to state which seems like extra work), so there's a 1 in 64 chance you'll use a sessionID last used by the node. Will this result in a failure if you happen to do that, or does the z-wave standard / sdk cause the node to "reset" after a while so that re-using the last sessionID after a reboot will still work. Yes, I realize its a relatively rare failure scenario, but just wondering if its already accounted for.

I would say this would be a pretty unlikely scenario .. But you could initialize with a random to reduce this possibility

Agreed. Its unlikely (1 in 64) and only for the first command.

I had thought about random, but realized that can clash too. The way I currently address this is I use an Initialize routine where, during driver startup, it reads the devices current attributes and send that to the device twice (on two sequential sessionIDs). This both ensures the device is at the value that Hubitat thinks it is (just in case a device was turned on / off or something else happened to it during the reboot), and, by sending twice, it ensures the sessionID that is used will work (if the first attempt clashes with a prior sessionID, the second succeeds; if the first is fine, the second will be too, but no harm). I suspect this is as good a method as any.

Anyway, thanks for the info. you provided this morning. It helped to clear up a few misunderstandings that I had about this feature.

Out of curiosity... Would this mean that the Z-wave trafic is doubled? Can this become a problem on a mesh with many devices, especially if many drivers do the same thing?

I'd say the increase in traffic is miniscule compared to the available bandwidth and the time period over which startup occurs. I'm doing this with about 75 devices right now and it isn't noticeable. The reason it isn't a problem is it only happens on a hub reboot and it is only done once. Assuming each driver takes 1 second to start up (and some of mine take longer), you're talking about each driver adding only a couple of short command / acknowledgement sequences on a channel that can handle many commands per second during a period where performance isn't a significant issue.

1 Like

Awesome post. Love the indepth explanation.

Time to update my drivers with proper s2 encapsulation.

2 Likes

Question - I noticed the inclusion of the supervisionCheck function which seems to perform a retransmission if you don't get a "success" response. I don't have anything like this in my code since I thought it was the job of the SDK to perform the application-level retransmission and the driver doesn't have to worry about it. Did I get this wrong - i.e., Is this another misunderstanding I have and do I need to do this (or are you being extra cautious)?

I do do something that I guess is a bit on the flip-side of this which is, if I get a "failure" code back in return to a supervision message, I put the command code (cmd.CMD) into a failure table (which is stored @Field static based on the manufacturer / deviceType / deviceID code of the device so any failure of a similar device is marked for all similar devices ) and never try to supervise that same command again for the same device type (I had found some devices seemed to always respond with a "failure" even when they were supposed to succeed, so I made it so my code "learns" this and adapts). I'm revisiting all this based on your sample (checking to make sure my "failures" weren't coding problems).

The SDK doesn’t perform this application layer re-transmit. The SDK already got it’s ACK and has cleared this packet out of it’s queue..

1 Like

yep, I had that wrong. Thanks for clarifying.

1 Like

Anytime

1 Like

Forgive my intrusion (my only experience w/"ACK" is below, and I'm not a SW engineer)...

image

When will this thread and it's excellent/useful info be moved into the fully accessible/non-beta part of the forum so all developers have access to it? I'm not sure why it's in the 2.2.7 beta section (Security Encapsulation is new in 2.2.7?) but that's above my pay grade.

From the responses of the developers to this info, seems like the more developers see this, the better for them and their drivers and for HE/HE users. :slight_smile:

It will be moved out to public soon..

2 Likes

It’s public now.

3 Likes

Ok.. Just noticed a couple of places in the example code is using a method of mine to simplify things.. sendToDevice ..

This just packages the commands into a HubAction or HubMultiAction and sends it out immediately:

void sendToDevice(List<String> cmds, Long delay = 300) {
    sendHubCommand(new hubitat.device.HubMultiAction(commands(cmds, delay), hubitat.device.Protocol.ZWAVE))
}

void sendToDevice(String cmd, Long delay = 300) {
    sendHubCommand(new hubitat.device.HubAction(zwaveSecureEncap(cmd), hubitat.device.Protocol.ZWAVE))
}

List<String> commands(List<String> cmds, Long delay = 300) {
    return delayBetween(cmds.collect { zwaveSecureEncap(it) }, delay)
}