Trigger an attribute write in a custom device type

I’m working on a custom device lets say it is a color LED. My custom device type uses the color control and sets the LED’s color everything works great. When I reboot my color LED its default color is white and it is out of sync with what the color control thinks its color is. I want to set my recently rebooted color LED to the current color in the color control. My color LED sends a custom command to my device type letting it know it has been rebooted. I’m able to detect the custom command in my parse method. I then use the command:

cClr.hex = device.currentState(“color”)?.value

to get the current color and then I pass it to the following setColor method:

def setColor(value) {
log.trace"setColor = ${value}"
def cx = value.hex
cx = cx.substring(1, cx.length()) // Remove # from front of hex value.hex string
def cmds = []
cmds << “st wattr 0x${device.deviceNetworkId} 0x38 0x0008 0x400 0x23 {${cx}}” // Send new RGB Color value write attribute 0x0400
cmds
}

The setColor method creates an array of cmds and I can’t figure out how to execute them?? What am I missing? I know I’m over looking something obvious.

Thanks

Just a wild guess, but what about sendEvent( ... )?

1 Like

Yep that was the first thing i tried. Here is the error:

Is it my syntax? The error talks about an onEvent and setParent option?

What did your sendEvent look like? It should be the same as using the device type to set the color, I think.

Here is the custom Device type:

In the parseOnOff method look for this command:

sendEvent(setColor(cClr))

The value I send is based on the return of the setColor method.

See I wonder if this is just not going to work because I’m triggering the event from the ZigBee device not from my iPhone. Usually the setColor method is called as a result of me selecting a color from the color control on my iPhone. But in this case I’m calling it from the parse method??

Have you tried just doing that sendEvent from within the device type? It shouldn’t matter where the event came from, the device type should process it the same way. You might want to put in isStateChange: true as well.

sendEvent(name: setColor, value: cClr, isStateChange: true)

I’m not at all sure about that, just guessing. I had a completely unrelated device type, and that’s how I set attribute values.

1 Like

Well your getting me a lot closer and your example makes sense. When I call it this way i no longer get an error but the method doesn’t get called?? I tried it with the isStateChange: true and with out it.

It’s something about the interaction with the tile definition. Perhaps experiment by sending switch events, to see if you can get those to work. I’m not familiar with the new multi-attribute tile stuff, and I suspect your problem is a nit about how to address it.

I have tried sending the on() event same thing happens. It executes the

sendEvent(name: on, isStateChange: true)

No errors but just doesn’t call it.

To be clear all these commands work just fine if I call them from the iPhone by tapping on the color value, level value etc… What I’m trying to do now is call them from within the parse method.

I guess I could write a SmartApp that listens for the “justBooted” event and then calls all these commands.

That’s not right. It would be

sendEvent(name: switch, value: on, …

I tried that syntax same thing fires event no error and doesn’t call my “on” method.

Doesn’t

sendEvent(name: “switch”, value: “on”)

just set the switch attribute equal to the string “on”?

I want to call this method called on:

// Commands
def on() {
log.info “on cmd sent”
“st cmd 0x${device.deviceNetworkId} 1 6 1 {}”
}

Shouldn’t the command be something like device.switch.on() something like that?

Unfortunately, you can’t call a command from parse(). At least that was what I was told (see below quote). Parse is meant to create events, but events themselves don’t take action on a device, only change information displayed to the user in the devicetype. I think you’ll need a SmartApp to initiate the action.

I am not sure why you are trying to trigger commands from the parse method. The parse method does not expect the return to be a command.

Ummm… Isn’t the Command in scope of the Device Handler?

Just:

def parse... { 
... 
   on() 
...
}

?

I guess my statement was misleading. By command, I mean sending out a command, such as a Zigbee command, to the device. You can call methods and return values, but it won’t trigger an action to the device.

If the on() command simply creates an ‘on’ event, you’re all good; but if you actually want it to turn on the device by sending a command out, it won’t do it. It will be ignored.

Sure… But why the heck would you have an on() method in your Device Handler that doesn’t actually have the code in it to physically affect the device approximately??

I’m not saying you would. Only that calling on() from your parse() method won’t physically affect the device because ST will ignore any outgoing commands to the actual device.

Not correct (I think).
If we have (pseudo code)

def on() {
   zigbeeSend( address, "on" );
}

Then on() should be callable and functioning anywhere in the scope of the Device Handler Instance, including inside its parse() method.

NB: I understand the theoretical architecture of SmartThings a lot, but have much less practical coding experience than other folks here. But that knowledge of the theory has often led to eureka moments and further education in both directions.

I think it should be too, but it doesn’t work and the quote I posted is from ST. Testing that I believe @rpress did showed that the same is true for the updated() method. I can only attest to Zigbee commands because that’s what I’ve worked with, but they simply don’t fire.

It might be a way to prevent loops within a devicetype.

(One exception seems to be for the Enroll Response for Zigbee sensors, which is triggered by a request from the device.)

OK. Well… this is definitely worth me confirming with a test device and some log.debug, etc., commands to confirm.

Indeed, it is certainly understandable that this would be the behavior, even if frustrating … while inside parse(), the communication layer is in “receive” mode (or something), and thus “sending” is prohibited or impossible. Though that could vary by RF protocol.

If this is the case, then I, personally, would first want to understand the bigger “problem we’re trying to solve” before trying to hack around the restriction.

In other words, trying to hack the restriction by using sendEvent() or some other clever coding, could be a waste of time, when we really ought to be putting some eyes on the actual end-result requirements first.