Should wakeUpNoMoreInformation() be sent to ALL channels?


(JJG) #1

On a Fibaro FGK-101, a battery operated multi-channels device, I send 2 commands each time the device wakes up, every 30mn :

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
        def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
        result << response("delay 1200")
        result << response(zwave.batteryV1.batteryGet())
        result << response("delay 1200")
        result << response(zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint: 2, destinationEndPoint: 2, commandClass:0x31 /*Sensor Multilevel Get*/, command:4))
        result << response("delay 5000")
    // should wakeUpNoMoreInformation() be sent to all EndPoints ???
        result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
        return result
}

But what I do not understand is that the Dashboard trace then shows “theDevice is now inactive” +++7 MINUTES+++ after the device woke up, and I sent my 2 commands followed by wakeUpNoMoreInformation().
First, I thought that once waken up, a battery operated device would listen only for a few SECONDS, not MINUTES.
And second, it looks like my ending wakeUpNoMoreInformation() is ineffective at putting it to sleep again.

So I modified my last wakeUpNoMoreInformation() command, replacing it by :

    result << response(zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint: 2, destinationEndPoint: 2, commandClass:0x84, command:8/*Wake Up No More Information*/))
    result << response("delay 1200")
    result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())

and the 7 minutes too late sleep anomaly seems to have disappeared.

So my question is : could anyone confirm that the wakeUpNoMoreInformation() command is to be sent to ALL channels, when a multichannel device wakes up ?

UPDATE : in the above “SEEMS to have disappeared” was the key word : for whatever reason, the “theDevice is now inactive” message does not always appear in the Log, but the problem is still there most of the time : the Device goes to sleep 7mn too late, even when a wakeUpNoMoreInformation() command is sent to all channels.
Any suggestion welcomed…


(Duncan) #2

You can ignore the active and inactive state for pretty much all Z-Wave devices. The system that drives was designed for the SmartThings ZigBee devices, so it assumes a device will check in every 5 minutes. The server guys never get around to fixing it for Z-Wave devices, even though I ask and ask ; )

You are right to send wakeUpNoMoreInformation unencapsulated as (I assume) the WakeUpNotification was not multiChannel encapsulated. Z-Wave devices don’t send any notification when they go back to sleep (that would just take more battery) so we don’t know for sure whether they did or not, but as long as you send the wakeUpNoMoreInformation you’re okay. It definitely isn’t staying awake for 7 minutes.

Another strategy would be to send the wakeUpNoMoreInformation from the SensorMultilevelReport handler so it’s sent as soon as possible instead of using the delay 5000 which could leave it awake longer than necessary.

(PS. I don’t always see these posts so if you have technical Z-Wave questions in the future feel free to “@” me)


(JJG) #3

Thanks a lot for your answer. I knew at some point the “Zigbee-oriented-design” would creep in… :wink:
Actually, my problem is not so much that 7 mn “false” pseudo-Zigbee inactive detection.
AFAIU, it has no effective consequence, except a spurious warning that I can just ignore.
And by the way, I do not send any WakeUpNotification (my battery-operated device is asleep most of the time), the Z-Wave device spontaneously wakes up at regular intervals, with the period set by : wakeUpIntervalSet(seconds:60*30, nodeid:zwaveHubNodeId))

My problem is instead that the response(“delay xxxx”) commands seem to be TOTALLY INEFFECTIVE :
ALL the commands I send within the response will answer immediately (when they answer) ALL TOGETHER, at the exact same time; whatever xxxx value is, it behaves just like if it was 0.
And THAT unfortunately has dire consequences : the response() behavior is totally erratic, sometimes I get all the answers for all the commands I sent, sometimes I get (part of) the answers at the next wake-up, 1 hour late !!! (and likely with 1 hour late obsolete values).

I opened a ticket on that one (Support request #64312 ), it is supposed to have been forwarded to development.
I am afraid I won’t be able to achieve a stable behavior for my Z-Wave custom handler until that one is properly corrected.


(Duncan) #4

I looked into it and you’re right. Putting a delay in the response() helper doesn’t work properly. I’ll make a ticket for that.

You can do it this way, however, to make sure the system treats your response commands as a command block:

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
        def event = createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
        def cmds = []
        cmds << zwave.batteryV1.batteryGet().format()
        cmds << "delay 1200"
        cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint: 2, destinationEndPoint: 2, commandClass:0x31 /*Sensor Multilevel Get*/, command:4).format()
        cmds << "delay 5000"
        cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
        return [event, response(cmds)]
}

There are other problems with delay though, so I’d still recommend only sending the first request from the wakeup handler and then sending the next one from that response’s handler, etc. So you would just send the multilevel get and then you’d send the battery get from the multilevel report handler and then the wakeUpNoMore from the battery report handler.


(JJG) #5

Thanks duncan for confirming the delay() bug.
The workaround you suggest should work, but with the inconvenience of making “spaghetti” code in my handler, somewhat harder to read and modify, .
You say that “there are other problems with delay” : does that mean that the likeliness of a quick correction is low ?


(Duncan) #6

Well the response(cmds) code I suggested should work as the workaround. The spaghetti method is more of an optimization to improve battery life by putting the device back to sleep as quickly as possible.


(JJG) #7

Sorry Duncan, I read your post too fast and thought somehow the wakeUpNoMoreInformation() optimization was also part of the workaround.
I have now implemented your workaround and it works great, with the “delay 1200” now effective and commands properly spaced, and 100% reliable response() (well… almost, see below).
Thanks ! :slight_smile:

Except…
…it works great only for SensorAlarmReport notifications, with 100% reliability, but for BasicSet notifications, the 2nd part “response(cmds)” seems to be totally ignored (or differed) 9 times out of 10.
The commands sent to the sensor seem to be stacked, but not executed; and somewhat randomly, later on, I get (all ? most of ??) the responses corresponding to the stacked commands.
I don’t understand why since I execute EXACTLY the same code in both cases.
Are responses to ___Set notifications processed in a different way of ___Report ones ?


(Duncan) #8

I can’t think of any way the platform would distinguish between Set and Report type commands. Maybe the device isn’t staying awake after sending the BasicSet? I’m not sure what the context is here.


(JJG) #9

Yes, that was my idea too, that any BasicSet notification would somehow have the device sending it go back to to sleep faster than for a SensorAlarmReport notification or WakeUpNotification.
I am not familiar with the details of the Z-Wave specifications : is there a minimum delay that ANY command sent, including BasicSet, should wait after for a response() ? May be 1200 ms is larger than this delay ??


(Duncan) #10

A sleepy device only has to stay awake after sending a WakeUpNotification. You can’t usually respond to any other command.


(JJG) #11

Thanks for the explanation Duncan, it explains fully what I observe : response() works following WakeUpNotification, and not following BasicSet notifications.

Except that…
…in “SmartThings Documentation Documentation, Release 1.0 - August 21, 2014”, p66, there is an example of usage of response() following an AssociationReport;
…in my case, response() worked perfectly following SensorAlarmReport notifications too !

It is thus a bit tough for the handler’s developer to “guess” after what notifications response() will work, and after which ones it will not.
Ah well…


(Duncan) #12

Well a device wouldn’t send an AssociationReport to the hub on its own, it would be a response to an AssociationGet sent when the handler knew that the device was awake. That would be the spaghetti method I mentioned earlier.

Also remember this only applies to sleepy devices; most devices you can send commands any time. It’s not whether response() works to send a message, it’s whether the device is listening to receive it, which we don’t control.


(JJG) #13

Not to belabor the point, but although your argument is certainly right for any xxxReport notification from the Device, it still does not explain why two different unsolicited/ spontaneous/ asynchronous notifications, SensorAlarmReport and BasicSet, behave differently, the first waiting for a response(), the second not.
I am not a Z-Wave licensee, so I do not have the Z-Wave specification, but may be it is one “gray area”, as such exist in any specification, and it just happens that the Fibaro FGK-101 is not so consistent in its behavior ?.
Ah well…

Thanks for all your explanations anyway, it is now much clearer to me what exactly I do not understand… :wink:


(Cyril Peponnet) #14

Hi @duncan,

Could be related.

What is wrong with this ?

dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug === Parsed 'zw device: 20, command: 5601, payload: 84 07 CC 39 ' to [[['descriptionText':Fibaro Motion Sensor woke up, 'isStateChange':false, 'displayed':false, 'linkText':'Fibaro Motion Sensor'], physicalgraph.device.HubMultiAction@721fa91e]]
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug physicalgraph.device.HubMultiAction@721fa91e
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug [700401010A, delay 1000, 700501, delay 1000, 7004020110, delay 1000, 700502, delay 1000, 7004040103, delay 1000, 700504]
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug [700401010A, 700501, 7004020110, 700502, 7004040103, 700504]
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug Parameter 4 will be updated to 3
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug Parameter 2 will be updated to 16
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug Parameter 1 will be updated to 10
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug %%%% Device Fibaro Motion Sensor woke up
dd9986bf-2d14-4293-b1ab-9948674f39f5 11:11:46 PM PDT: debug ==> New Zwave Event: zw device: 20, command: 5601, payload: 84 07 CC 39

My cmds sent as response from a wake up seems to never been handled…

This is the part of the code:

def parse(String description)
{
    log.debug "==> New Zwave Event: ${description}"

    def result = []

    switch(description) {
        case ~/Err.*/:
            log.error "Error: $description"
        break
        default:
            def cmd = zwave.parse(description, [0x72: 2, 0x31: 2, 0x30: 1, 0x84: 1, 0x9C: 1, 0x70: 2, 0x80: 1, 0x86: 1, 0x7A: 1, 0x56: 1])
            if (cmd) {
                result << zwaveEvent(cmd)
            }
        break
    }

    log.debug "=== Parsed '${description}' to ${result.inspect()}"
    if ( result[0] != null ) { result }
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
    log.debug "%%%% Device ${device.displayName} woke up"
    def cmds = sync_properties()
    log.debug cmds
    def delay = delayBetween(cmds, 1000)
    log .debug delay
    def result = response(delay)
    log.debug result
    return [createEvent([descriptionText: "${device.displayName} woke up", isStateChange: false]), result]
}

def sync_properties()
{
    def currentProperties = device.currentValue("currentProperties") ? parseJson(device.currentValue("currentProperties")) : [:]
    def cmds = []
    settings.each
    {
        if (! currentProperties."${it.key}" || currentProperties."${it.key}" == null)
        {
            cmds << zwave.configurationV1.configurationGet(parameterNumber: it.key.toInteger()).format()
        }
    }

    if (device.currentValue("needUpdate") == "YES") { cmds.addAll(update_needed_settings()) }
    return cmds
}

def update_needed_settings()
{
    def cmds = []
    def currentProperties = device.currentValue("currentProperties") ? parseJson(device.currentValue("currentProperties")) : [:]
    def configuration = parseXml(configuration_model())
    def isUpdateNeeded = "NO"
    configuration.Value.each
    {
        if (currentProperties."${it.@index}" == null)
        {
            isUpdateNeeded = "YES"
        }
        else if (settings."${it.@index}" != null && cmd2Integer(currentProperties."${it.@index}") != settings."${it.@index}".toInteger())
        {
            log.debug "Parameter ${it.@index} will be updated to " + settings."${it.@index}"
            isUpdateNeeded = "YES"
            switch(it.@type)
            {
                case ["byte", "list"]:
                    cmds << zwave.configurationV1.configurationSet(configurationValue: [(settings."${it.@index}").toInteger()], parameterNumber: it.@index.toInteger(), size: 1).format()
                break
                case "short":
                    def short valueLow   = settings."${it.@index}" & 0xFF
                    def short valueHight = (settings."${it.@index}" >> 8) & 0xFF
                    def value = [valueHigh, valueLow]
                    cmds << zwave.configurationV1.configurationSet(configurationValue: value, parameterNumber: it.@index.toInteger(), size: 2).format()
                break
            }
            cmds << zwave.configurationV1.configurationGet(parameterNumber: it.@index.toInteger()).format()
        }
    }
    sendEvent(name:"needUpdate", value: isUpdateNeeded, displayed:false, isStateChange: true)

    return cmds
}

I can’t figure out why it’s not working properly or I missed something obvious here.

Thanks :slight_smile:


(Cyril Peponnet) #15

Well sounds the following is fixing it.

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
    log.debug "%%%% Device ${device.displayName} woke up"
    def commands = sync_properties()
    return [createEvent([descriptionText: "${device.displayName} woke up", isStateChange: false]), response(delayBetween(commands, 1000))]
}

to

def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
{
    log.debug "%%%% Device ${device.displayName} woke up"
    def commands = sync_properties()
    sendEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
    // Adding No More infomration needed at the end
    commands << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
    response(delayBetween(commands, 1000))
}

Not sure to well understand why (maybe parse return cannot be a mix of event and commands…). But seems to work


(Duncan) #16

Ah, that’s probably because in your parse you are doing result << zwaveEvent(cmd) which treats the return value of zwaveEvent as a single item to add to the list, leading to a doubly nested array. I bet if you try result += zwaveEvent(cmd) to append to the result it will work with returning both an event and HubMultiAction.


(Cyril Peponnet) #17

Oh you’re right it makes sense ! I will try that. is += same as addAll ?