Child DTHs not firing zwave events

I’m trying to make a device that controls four relays (as basic switches). I’m setting it up as a parent device (controlling relay #1) and three child devices (controlling relays #2 - #4).

The parent device calls the on() and off() methods, and the returned list of zwave commands do get sent out to the device. For example:

// called from on()
def on1() {
	log.debug "on1()"
    delayBetween([
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:1, parameter:[255]).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
    ], 1000)
}

However, on/off command sent from the children don’t get sent, even though they’re properly getting handed to the parent (and the parent is turning the dni to a channel number), the zwave commands do not get sent out:

def childOn(String id) {
	log.debug("childOn($id)")
    int channel = zwaveChannelFromChildDNI(id)
    log.debug("  Looks like that's channel $channel")
    // This does not get sent
    delayBetween([
        zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:channel, commandClass:37, command:1, parameter:[255]).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:channel, commandClass:37, command:2).format()
    ], 1000)
}

The method does get executed and correctly determines the channel:

[fd539bbb-61ee-41c7-901c-271682a24ea5] 11:16:37 AM: debug Looks like that’s channel 4
[fd539bbb-61ee-41c7-901c-271682a24ea5] 11:16:37 AM: debug childOn(2A-ep4)

I was able to get something working by using code from someone else’s child-device example:

def childOn(String id) {
	log.debug("childOn($id)")
    int channel = zwaveChannelFromChildDNI(id)
    log.debug("  Looks like that's channel $channel")
    def cmds = []
    // "command()" calls .format() (and possibly wraps in security encapsulation) on the command objects
    // "encap()" wraps the command in a multi-channel encapsulation
    cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0xFF), channel)))
    cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channel)))
    sendHubCommand(cmds)
 }

But this doesn’t have a delay between messages, and I’d also just like to know why the childOn() doesn’t work, but on() does.

I’ve tried using “Switch Child Device” from “erocm123” and “Child Switch” from “smartthings” both giving the same effect. Anybody have any idea how we’re supposed to emit zwave commands from child devices?

You have probably noticed that if you want to update attributes as a result of processing in the parse() method, you will often return an attribute map that is typically created by createEvent(). ST takes this return value and uses it to do a sendEvent(). However if you want to send an event outside of that flow you have to call sendEvent() yourself.

There is an analogous flow going on for hub commands, such as Zigbee or Z-Wave commands or hubActions. When you are calling on() you are typically calling it in the context of a capability command, whether called from the app UI or from an app. When you do that, ST will use any return value as a hub command to be sent to the hub. In the absence of an explicit return statement, Groovy uses the value of the last statement executed as the return value. If you make the last statement of either your on() or on1() method a log statement you should find it no longer works.

You will also find the on() only works when called as a command. If, for example, you called it from a timer like runIn(), it wouldn’t be being used as a command, it would just be any old method. So the hub commands wouldn’t get run and you would need to do the job manually.

So I’d be checking firstly for any extra statements after parent.childOn() in the child devices, and then accepting that doing it yourself with sendHubCommand() may be necessary (I’ve only used hubActions in this way and they get sent for you).

Well, the erocm123 one looks like this:

void on() {
	log.debug("childOn")
	log.debug("childOn called for $device");
	parent.childOn(device.deviceNetworkId)
}

I just realized that the return type is void, and I just tried changing it to “def”, to let the type-inferencer figure it out, but that didn’t solve it. I have no way of knowing what the built-in smartthings one does.

If I’m stuck doing it with sendHubCommand(), how does one inject delays?