Command Delay simulation

@bravenel this error is bring thrown:

app:2802019-12-02 03:29:20.313 pm errorgroovy.lang.MissingMethodException: No signature of method: groovy.json.internal.LazyMap.setLevel() is applicable for argument types: (java.lang.Integer, java.lang.Integer) values: [0, 3] on line 4991 (runDeviceCmd)

here is the code based on your example … indicated with <<<<< line 4991 where the error is thrown at:

private deviceCmdDelay(dev, command, delayMS, param1 = null, param2 = null)		{
	if (param2 != null)
    	runInMillis(delayMS, runDeviceCmd, [data: [dev: dev, cmd: command, param1: param1, param2: param2]])
	else if (param1 != null)
		runInMillis(delayMS, runDeviceCmd, [data: [dev: dev, cmd: command, param1: param1]])
	else
		runInMillis(delayMS, runDeviceCmd, [data: [dev: dev, cmd: command]])
}

def runDeviceCmd(data)		{
    def dev = data.dev
    def cmd = data.cmd
	def p1 = data?.param1
	def p2 = data?.param2
	if (p2 != null)
		dev."$cmd"(p1, p2)   <<<<<
	else if (p1 != null)
		dev."$cmd"(p1)
	else
		dev."$cmd"()
} 

here is the call to deviceCmdDelay:

// switches is list of devices to turn off collected from all switches specified in app settings
for (def switch : switches)
   if (switch.hasCommand("setLevel")
       deviceCmdDelay(switch, 'setLevel', delay, 0, 3)

what am i doing wrong?

thank you

I don't know. How about putting some log.debug in to see what it looks like just prior to the error?

added this:

log.debug "dev: $dev | cmd: $cmd | p1: $p1 | p2: $p2"

gets this output … looks odd …

[app:280](http://192.168.1.44/logs#app280)2019-12-02 04:01:41.655 pm [debug](http://192.168.1.44/installedapp/configure/280)dev: [currentStates:[[floatValue:6535.0, jsonValue:6535, value:6535, dataType:NUMBER, unit:null, date:2019-12-02T17:48:18+0000, stringValue:6535, id:null, numberValue:6535, doubleValue:6535.0, name:colorTemperature], [value:on, dataType:ENUM, unit:null, date:2019-12-02T07:18:08+0000, stringValue:on, id:null, name:switch], [floatValue:49.0, jsonValue:49, value:49, dataType:NUMBER, unit:null, date:2019-12-03T00:01:32+0000, stringValue:49, id:null, numberValue:49, doubleValue:49.0, name:level], [value:Polar, dataType:STRING, unit:null, date:2019-12-02T17:48:18+0000, stringValue:Polar, id:null, name:colorName]], driverId:193, isComponent:false, zigbeeId:B0CE18140301ABC0, hub:[updateTime:null, zigbeeId:000D6F000AFF715D, locationId:1, id:1, dataSorted:[hardwareID:000D], hardwareID:000D, createTime:2018-02-21T10:03:28+0000, localSrvPortTCP:39501, name:home, firmwareVersionString:2.1.6.118, type:PHYSICAL, localIP:192.168.1.44, uptime:2661, version:1, data:[hardwareID:000D, zigbeeEui:000D6F000AFF715D, zigbeeChannel:0x14 (20), zigbeePanID:B8FD, localSrvPortTCP:39501, localIP:192.168.1.44], zigbeeEui:000D6F000AFF715D, batteryInUse:false, lastActivityTime:null], id:761, supportedCommands:[[arguments:null, parameters:null, id:8, version:1, name:configure], [arguments:null, parameters:null, id:2, version:1, name:off], [arguments:null, parameters:null, id:127, version:1, name:off], [arguments:null, parameters:null, id:1, version:1, name:on], [arguments:null, parameters:null, id:126, version:1, name:on], [arguments:null, parameters:null, id:13, version:1, name:refresh], [arguments:[NUMBER], parameters:[[name:Color temperature*, description:Color temperature in degrees Kelvin, type:NUMBER, constraints:[NUMBER]]], id:83, version:1, name:setColorTemperature], [arguments:[NUMBER, NUMBER], parameters:[[name:Level*, description:Level to set (0 to 100), type:NUMBER, constraints:[NUMBER]], [name:Duration, description:Transition duration in seconds, type:NUMBER, constraints:[NUMBER]]], id:10, version:1, name:setLevel], [arguments:[ENUM], parameters:[[name:Direction*, description:Direction for level change request, type:ENUM, constraints:[up, down]]], id:1641, version:1, name:startLevelChange], [arguments:null, parameters:null, id:1642, version:1, name:stopLevelChange]], lanId:null, endpointId:01, controllerType:ZGB, displayAsChild:true, name:Generic Zigbee CT Bulb (dev), capabilities:[[commands:[[arguments:null, parameters:null, id:1, version:null, name:on], [arguments:null, parameters:null, id:2, version:null, name:off]], id:4, version:null, attributes:[[dataType:null, values:null, id:4, version:null, possibleValues:null, name:switch]], name:Switch, reference:null], [commands:[[arguments:null, parameters:null, id:8, version:null, name:configure]], id:12, version:null, attributes:[], name:Configuration, reference:null], [commands:[[arguments:null, parameters:null, id:10, version:null, name:setLevel]], id:15, version:null, attributes:[[dataType:null, values:null, id:12, version:null, possibleValues:null, name:level]], name:SwitchLevel, reference:null], [commands:[[arguments:null, parameters:null, id:13, version:null, name:refresh]], id:18, version:null, attributes:[], name:Refresh, reference:null], [commands:[], id:35, version:null, attributes:[], name:Actuator, reference:null], [commands:[[arguments:null, parameters:null, id:83, version:null, name:setColorTemperature]], id:53, version:null, attributes:[[dataType:null, values:null, id:70, version:null, possibleValues:null, name:colorTemperature], [dataType:null, values:null, id:11571, version:null, possibleValues:null, name:colorName]], name:ColorTemperature, reference:null], [commands:[[arguments:null, parameters:null, id:126, version:null, name:on], [arguments:null, parameters:null, id:127, version:null, name:off]], id:80, version:null, attributes:[[dataType:null, values:null, id:104, version:null, possibleValues:null, name:switch]], name:Light, reference:null], [commands:[[arguments:null, parameters:null, id:1641, version:null, name:startLevelChange], [arguments:null, parameters:null, id:1642, version:null, name:stopLevelChange]], id:89, version:null, attributes:[], name:ChangeLevel, reference:null]], device:[currentStates:[level:[floatValue:49.0, jsonValue:49, value:49, dataType:NUMBER, unit:null, date:2019-12-03T00:01:32+0000, stringValue:49, id:null, numberValue:49, doubleValue:49.0, name:level]], locationName:home, updateTime:2018-07-13T03:55:00+0000, hubName:home, isComponent:false, zigbeeId:B0CE18140301ABC0, deviceTypeName:Generic Zigbee CT Bulb (dev), hub:[updateTime:null, zigbeeId:000D6F000AFF715D, locationId:1, id:1, dataSorted:[hardwareID:000D], hardwareID:000D, createTime:2018-02-21T10:03:28+0000, localSrvPortTCP:39501, name:home, firmwareVersionString:2.1.6.118, type:PHYSICAL, localIP:192.168.1.44, uptime:2661, version:1, data:[hardwareID:000D, zigbeeEui:000D6F000AFF715D, zigbeeChannel:0x14 (20), zigbeePanID:B8FD, localSrvPortTCP:39501, localIP:192.168.1.44], zigbeeEui:000D6F000AFF715D, batteryInUse:false, lastActivityTime:null], locationId:1, id:761, displayAttributes:null, groupId:null, currentStatesSorted:[level:[floatValue:49.0, jsonValue:49, value:49, dataType:NUMBER, unit:null, date:2019-12-03T00:01:32+0000, stringValue:49, id:null, numberValue:49, doubleValue:49.0, name:level]], lanId:null, hubId:1, endpointId:01, createTime:2018-07-13T03:54:00+0000, controllerType:ZGB, displayAsChild:true, name:Generic Zigbee CT Bulb (dev), parentAppId:null, disabled:false, status:ACTIVE, groupName:null, version:3, driverType:sys, label:dW OF LI 3, data:[application:01, model:Z01-A19NAE26, manufacturer:sengled], deviceNetworkId:1A66, deviceTypeId:193, lastActivityTime:2019-12-03T00:01:32+0000, parentDeviceId:null, displayName:dW OF LI 3], idAsLong:761, parentAppId:null, disabled:false, status:ACTIVE, typeName:Generic Zigbee CT Bulb (dev), driverType:sys, label:dW OF LI 3, data:[application:01, model:Z01-A19NAE26, manufacturer:sengled], supportedAttributes:[[dataType:STRING, values:null, id:11571, version:1, possibleValues:null, name:colorName], [dataType:STRING, values:null, id:14109, version:1, possibleValues:null, name:colorName], [dataType:NUMBER, values:null, id:70, version:1, possibleValues:null, name:colorTemperature], [dataType:NUMBER, values:null, id:12, version:1, possibleValues:null, name:level], [dataType:ENUM, values:[on, off], id:4, version:1, possibleValues:[on, off], name:switch], [dataType:ENUM, values:[on, off], id:104, version:1, possibleValues:[on, off], name:switch]], deviceNetworkId:1A66, lastActivity:2019-12-03T00:01:32+0000, parentDeviceId:null, displayName:dW OF LI 3] | cmd: setLevel | p1: 0 | p2: 3

You must use screenshots, not copy/paste. That's some sort of map, such as a full device wrapper.

It's been 8 months, so I don't recall the post I made, or if it is right or not.

added another log.debug right before runInMillis is called:

log.debug "dev: $dev | cmd: $command | p1: $param1 | p2: $param2"
runInMillis(delayMS, runDeviceCmd, [data: [dev: dev, cmd: command, param1: param1, param2: param2]])

here is the output:

app:2802019-12-02 04:11:07.321 pm debugdev: dW OF LI 1 | cmd: setLevel | p1: 0 | p2: 3

looks like runDeviceCmd is being sent a map with all device attributes even though deviceCmdDelay specified a device wrapper in scheduling the call to runDeviceCmd via runInMillis.

You don't want to pass a device wrapper into a run in...

right. i was trying to follow the example here:

really just trying to figure out how to use device.command with delay on HE.

thanks!

I have a related question. and I apologize if I'm using the wrong terms. Remember...I'm totally self taught for anyting code related. So please be patient with me.

Do you mean only if they are selected from an input and are the only "memeber" of that input? So, the input is only a single device?

To put it another way...If i have a multi-device input and I have found the correct one from the set and assigned it to a variable, can that be passed to another method or no? Do i have to pass off the way to find the device to the method that will execute the command on said device?

For example, if I do this:

def device = myDevices.find {it.deviceId == event.deviceId}

That will pull the matching device out of myDevices. Can I use runIn to pass "device" to another method as part of the data map? Or will it be lost when I try to do that? So far I can't tell if it's the way I'm setting it up or if it's just not supposed to work. So, thought I'd ask before pulling my hair out any further.

Thanks a bunch!!!!

Yes, as long as myDevices came from an input selection.

Well, myDevices in this case would have been the input selection of multiple devices. Okay, I'll have to take a closer look and see what I was doing wrong. Maybe it's how I was setting up the mapped data. Thanks Bruce.

Okay Bruce, I must be doing something wrong. I am finding the device out of the input myDevices...that is working perfectly.

def device = myDevices.find{it.label == name}
log.debug device.label
device.on()
runIn(time, turnOff, [data:device])

So, the device turns on correctly. But then I try to do this:

def turnOff(device){
    device.off()
}

And that gives me this error:

I thought you said I could pass a device variable off to another method as long as it was part of an input. Did i miss-understand you? Or was I not stating my question clearly?

Basically, I have gone through the steps necessary to identify which device i need to use. Do i have to do that again in the method called to by runIn? To be clear, device is not an input but it is part of the multi-device input of myDevices. It probably is a lot clearer what I'm asking now that I've given you an example.

I also tried to save the device is a state variable....boy, that doesn't work And talk about a total mess!! Learned that one the hard way. :smiley:

Thank you!

As you've helped me before, I will try to return the favor. Judging from the error message, the device is stored as a json object when scheduling with runIn. A possible approach would be to pass the device id or network id instead of the whole device object, and in the turnOff function retrieve the device from myDevices using the ID.

Yes, I know that. If you read the conversation that Bruce and I were having above, I asked if that was the only method. He said I can just pass the device. When I tried it, I couldn't get it to work so I was asking him what I was doing wrong, since he said it was possible.

@bravenel, nothing huh? You said I could pass a device variable to another method with runIn but it doesn't appear to be working. Please let me know what I am doing wrong. Thanks.

There was no mentioning of doing it this way, but anyway, he wasn’t answering, but no worries, disregard my post if it’s of no help.

I don't think you can serialize a device object and use it later. IThat could be a potential security issue if that was allowed.

This should work.. You're just passing the name as a string and looking up the device on the call to off.

def device = myDevices.find{it.label == name}
log.debug device.label
device.on()
runIn(time, turnOff, [data:name])


def turnOff(name){
    def device = myDevices.find{it.label == name}. // Assuming myDevices is a preference
    device.off()
}

I know that and that's what I thought was required. That's what I'm doing in the first method. But after what Bruce said, I thought it would work differently. Do you read what he said the same way? I don't really care one way or the other, I just want some acknowledgement that it won't work so I can stop digging. Ya know what I mean? Someone in authority tells you something, I tend to believe them. After all, Bruce has forgotten more about this stuff than I've ever known. I hold no illusions about that. That's what makes it so frustrating. How can those of us trying to learn this stuff supposed to learn if they don't correct themselves? :man_shrugging: Since I'm seeing that it doesn't work either I will just move the identifying "system" to the called method as well.

Do you mean because the person could remove the device from the app between the first and second methods but the device would be persistent if that's what was passed? (Again, trying to confirm for my own edification, not questioning your reasoning.) From experience I knew this wasn't working but this makes a lot of sense WHY this SHOULDN'T work. After all, you don't know what type of length of time you might use in a runIn...it could be months from now.

Thanks!

This is all so out of context it's hard for me to know what you're doing. What is myDevices?

This works:

preferences {
    section {
    	input "switches", "capability.switch", title: "Select Switches", multiple: true
    }
}

def updated() {
	def dev = switches.find{it.label = "Bar Overhead"}
	sub(dev)
}

def sub(dev) {
	dev.off()
}

Yes bruce...but my question was regards to runIn. Not calling the method directly.

You can't pass a device wrapper to runIn, nor can you put one in state.