[ANSWERED] Add Custom Device State Dynamically

Posted on
Wed Nov 19, 2014 4:58 pm
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

[ANSWERED] Add Custom Device State Dynamically

If there's a way to do this, I haven't been able to find it. What I would like to do is to add a new device state to a custom device. I know that it's possible to add to pluginProps thusly:

Code: Select all
newProps = dev.pluginProps
newProps['propName'] = value
dev.replacePluginPropsOnServer(newProps)
and what I am looking for is something akin to:

Code: Select all
newStates = dev.pluginStates
newState['stateName'] = value
dev.replacePluginStatesOnServer(newStates)
Is it possible to create device states on the fly? Of course, this would only be for devices that my plugin owns.

Thanks in advance,
Dave
Last edited by DaveL17 on Sat Nov 22, 2014 12:47 pm, edited 1 time in total.

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Thu Nov 20, 2014 10:57 am
jay (support) offline
Site Admin
User avatar
Posts: 18200
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Add Custom Device State Dynamically

Check out the stateListOrDisplayStateIdChanged() method in the Device Class Instance Methods doc for details.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Thu Nov 20, 2014 7:58 pm
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Add Custom Device State Dynamically

Thanks Jay. I'm either not understanding the docs or I didn't explain my question clearly enough. It's my understanding from the documentation that stateListOrDisplayStateIdChanged() when called will reach out to details.xml and add any states to the device dict that aren't already there.

What I want to do is:
- pull a copy of the states dict from the device itself (dev.states),
- add a state/value pair to it, and
- write the updated states dict back to the device

all through code. I don't want to use devices.xml in the operation. I can add pluginProps to the device with code, and I wanted to be able to the same thing with states. Is this possible?

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Thu Nov 20, 2014 10:07 pm
jay (support) offline
Site Admin
User avatar
Posts: 18200
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Add Custom Device State Dynamically

Reread the description - specifically about the getDeviceStateList() method. The default version of that method in the base class just returns what's in Devices.xml. However, you may override it and return whatever you want - including new fields. The method must return all state fields - so you'll need to return them all (both old states and new states).

The default implementation:

Code: Select all
   def getDeviceStateList(self, dev):
      if dev.deviceTypeId in self.devicesTypeDict:
         return self.devicesTypeDict[dev.deviceTypeId][u"States"]
      return None


self.devicesTypeDict is a dictionary of your device types. The key is the deviceTypeId. The value is the device type definition dictionary. The "States" key in that dictionary will return the states list. Modify that list to include the new state.

If you're wanting to add a state to a single device instance - that's not really something that can be done effectively. Unlike an instance's properties, which are quite dynamic, a device's state list is less so: states should be consistent across instances of the same device type. Doing otherwise is going to cause confusion for the user.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Fri Nov 21, 2014 5:08 am
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Add Custom Device State Dynamically

Thanks Jay very much. I am going to shoot you a message offline to explain a little more about what I'm trying to accomplish. It may be that I'm heading down a rabbit hole here.

Dave

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Fri Nov 21, 2014 11:50 am
matt (support) offline
Site Admin
User avatar
Posts: 21411
Joined: Jan 27, 2003
Location: Texas

Re: Add Custom Device State Dynamically

Hi Dave,

What you want to do is something like this:
Code: Select all
   def getDeviceStateList(self, dev):
      stateList = indigo.PluginBase.getDeviceStateList(self, dev)
      if stateList is not None:
         # Add any dynamic states onto the device based on the node's characteristics.
         if dev-supports-something:
            someNumState = self.getDeviceStateDictForNumberType(u"someNumState", u"Some Level Label", u"Some Level Label")
            someStringState = self.getDeviceStateDictForStringType(u"someStringState", u"Some Level Label", u"Some Level Label")
            someOnOffBoolState = self.getDeviceStateDictForBoolOnOffType(u"someOnOffBoolState", u"Some Level Label", u"Some Level Label")
            someYesNoBoolState = self.getDeviceStateDictForBoolYesNoType(u"someYesNoBoolState", u"Some Level Label", u"Some Level Label")
            someOneZeroBoolState = self.getDeviceStateDictForBoolOneZeroType(u"someOneZeroBoolState", u"Some Level Label", u"Some Level Label")
            someTrueFalseBoolState = self.getDeviceStateDictForBoolTrueFalseType(u"someTrueFalseBoolState", u"Some Level Label", u"Some Level Label")
            stateList.append(someNumState)
            stateList.append(someStringState)
            stateList.append(someOnOffBoolState)
            stateList.append(someYesNoBoolState)
            stateList.append(someOneZeroBoolState)
            stateList.append(someTrueFalseBoolState)
      return stateList


Note the getDeviceStateDictFor*Type() methods are just helper functions defined by the base plugin class that return the appropriately keyed dict() that stateList wants.

You then have to call stateListOrDisplayStateIdChanged() whenever you want to dynamically update the states list. That will force getDeviceStateList() to be called. So getDeviceStateList() will have to look at internal properties/settings to figure out how it wants to build the stateList, then it returns that. Note getDeviceStateList() always needs to work correctly – it is called when Trigger or Control Page UI is shown, and when objects are first created. It is okay if it changes behavior at runtime (which is what you want to happen when you call stateListOrDisplayStateIdChanged()), but the device will need to have enough information (stored in its properties) such that anytime getDeviceStateList() is called the correct stateList is returned. Otherwise the Trigger and Control Page UI won't show all the correct possible Device State Changed states in the popup.

Sorry if thisn't clear (I realize it is a bit convoluted). But basically getDeviceStateList() is what defines the stateList (by returning it), and it can be called at anytime, and if you need it called dynamically (because you are changing the state list), then you can tell the IndigoServer that via the stateListOrDisplayStateIdChanged() method.

Image

Posted on
Sat Nov 22, 2014 7:26 am
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Add Custom Device State Dynamically

Hot diggity, This works great! I worked with the code while I was on a plane last night and almost paid your hometown Airline a bunch of money for WiFi just to say thanks.

Anyway, thanks guys. I have much coding to do.
Dave

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Sat Nov 22, 2014 9:57 am
matt (support) offline
Site Admin
User avatar
Posts: 21411
Joined: Jan 27, 2003
Location: Texas

Re: Add Custom Device State Dynamically

Hi Dave,

Great, I'm glad that is going to work for you. I'm interested to see the plugin you are creating once it is available.

Image

Posted on
Sat Nov 22, 2014 10:40 am
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Add Custom Device State Dynamically

Absolutely. It will involve some fairly complex logic, so I might be a while.

Complex logic is not something that I'm usually associated with. :wink:

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Wed Nov 26, 2014 6:18 am
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: [ANSWERED] Add Custom Device State Dynamically

I have the plugin working with multiple devices, each with their own custom states. Thanks for the pointers. For simplicity in the initial rounds, I decided to string everything. This works great:

Code: Select all
def getDeviceStateList(self, dev):

   stateList = indigo.PluginBase.getDeviceStateList(self, dev)      
   
   if stateList is not None:
      
      for key in self.xmlDict.iterkeys():
         dynamicState1 = self.getDeviceStateDictForStringType(key, key, key)
         stateList.append(dynamicState1)

   return stateList
However, for Trigger and Control Page UI stuff, Indigo reaches out again to getDeviceStateList() just as you said it would, and there's the rub. It returns the last stateList generated--not necessarily the one appropriate to dev. For example, I have three plugin devices (A, B, and C). When I create a trigger for device A, I get the trigger labels for device C.

Am I missing something obvious?

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Wed Nov 26, 2014 8:54 am
matt (support) offline
Site Admin
User avatar
Posts: 21411
Joined: Jan 27, 2003
Location: Texas

Re: [ANSWERED] Add Custom Device State Dynamically

The device instance is passed in as an argument, so you'll need to use that (or a property inside that) to determine what state list should be returned.

Image

Posted on
Thu Nov 27, 2014 5:58 am
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: [ANSWERED] Add Custom Device State Dynamically

Thanks Matt.

And just to be sure that I understand, in this instance the stateList would need to be recreated when called from Trigger and Control Page UI because getDeviceStateList() wants to go to devices.xml, right?

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Thu Nov 27, 2014 9:31 am
jay (support) offline
Site Admin
User avatar
Posts: 18200
Joined: Mar 19, 2008
Location: Austin, Texas

Re: [ANSWERED] Add Custom Device State Dynamically

Right - every time that method is called it must return the complete state list for the given device instance.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Thu Nov 27, 2014 9:33 am
DaveL17 offline
User avatar
Posts: 6744
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: [ANSWERED] Add Custom Device State Dynamically

Thanks Jay (and Matt) -- Happy Thanksgiving!
Dave

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Mon Apr 16, 2018 3:48 pm
howartp offline
Posts: 4559
Joined: Jan 09, 2014
Location: West Yorkshire, UK

Re: [ANSWERED] Add Custom Device State Dynamically

A tad late, but also my thanks - I've just come searching for exactly this, and it works a treat!

Peter

Who is online

Users browsing this forum: No registered users and 2 guests