Can a child make a parent send out z-wave commands (in a composite device)?

I have a working device handler for a multi-button scene controller. Basically, it has 5 boolean states for whether the buttons/lights on the device are off/on. I'm trying to convert this into a composite device, with 5 child devices that are very similar to virtual switches. That will vastly simplify building Rule Machine or other integrations, because I can just attach automations to the individual child switches.

Here's how far I've gotten:

  • I've created a driver for the child devices that behaves just like a virtual switch
  • I have a configure command on the parent device that will create the 5 child devices
  • I can successfully send state from parent to child. For example, if I press a button on the physical device, a z-wave message comes to the parent, it gets parsed, and the parent calls on() or off() on the correct child. I can then see the virtual switches get updated to match what the lights on the physical device look like.

Here's my problem: I'm trying to do a two-way binding. If another automation turns one of the virtual switches on or off, I want that child device to tell the parent to send a z-wave message out to the physical device, so that it can update its indicators.

I have code in the parent that can do this, but it isn't working if triggered by the child. So, on the parent, I have a method like:

def IndicatorSet(index, onOrOff)

It does a little logic and then ends up calling:

delayBetween([
zwave.indicatorV1.indicatorSet(value: onOrOff).format(),
zwave.indicatorV1.indicatorGet().format(),
],300)

This works just fine if you call it from the device page of the parent.

However, in the child device, I have code like this (to try to send events back to the parent, so they can be sent to the physical device):

def on() {
log.debug "${device.displayName} on"
sendEvent(name: "switch", value: "on", isStateChange: true)

def parent = getParent()
if (parent) {
def childsIndex = device.deviceNetworkId[device.deviceNetworkId.size() - 1] as Integer
parent.IndicatorSet(childsIndex, 1)
}
}

If I watch my logs, I can see that parent.IndicatorSet gets called, gets executed, and gets to the point of the delayBetween command. But then nothing happens. No z-wave messages get sent to the physical device.

Is it possible for a child to make a parent send out z-wave commands? When a child calls a method on a parent, is that executed in the "device context" of the parent or the child? Thanks for any help!

Well, I have an answer for my final question about "device context" when a child calls a method on a parent.

I put this code in the on method of the child driver:

log.debug "CHILD.ON DEVICE LABEL: ${device.label}"

And I put this code in the IndicatorSet method of the parent driver:

log.debug "INDICATORSET DEVICE LABEL: ${device.label}"

When I trigger an on() on the child, I see this in the logs:

INDICATORSET DEVICE LABEL: Keypad
CHILD.ON DEVICE LABEL: Keypad (Switch 5)
Keypad (Switch 5) on

So it looks like the method on the parent executes with "device" being the parent. Still don't know how to make that device send out z-wave commands though.

1 Like

I may have it! It seems the child must call a method on the parent that is ALSO defined as a command in the metadata. At least, a quick test seems to indicate that. Now to do full development on it...

1 Like

All zwave commands are sent and received by the parent, the parent being the actual device that joined.
You create child device in the normal way.
The child does not send or receive any zwave commands.
In the child you define a method, let's just say on for ease.
The on method calls a method in the parent, parent.childOn(), in the parent you create the method childOn(), this method doesn't need to be in the meta data.
In this method you return your zwave commands.
The response if any will be returned in the parent parse method.
Within this parse you then need to send the result back to the child.
Get a reference to the child, then call some method, just like you would from any app.
You could also send the result back to the child's parse method if you want.

2 Likes

FYI, this code is unnecessary. Every child device intrinsically has a parent device called “parent” that you can just use.