Device valuesDict Passed on Callback Method [SOLVED]

Posted on
Thu Jan 25, 2018 8:29 am
DaveL17 offline
User avatar
Posts: 6751
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Device valuesDict Passed on Callback Method [SOLVED]

I have a device config with two menu controls that use callbacks. While developing, I added a line to log the valuesDict that's passed to the callbacks to inspect the contents. When the device is first created, the valuesDict passed to both callbacks only contains 1 of about 20 props. I expect that this is due to the fact that valuesDict is still being created at the time the callback is called. However, when I populate the first menu item 'thing' within the device config dialog, I get a TypeError:
Code: Select all
Error in plugin execution UiAction:

Traceback (most recent call last):
  File "plugin.py", line 2591, in deviceStateGenerator
TypeError: string indices must be integers

On this line:
Code: Select all
id = valuesDict['thing']

I have confirmed that valuesDict['thing'] at that stage contains the expected value (an Indigo ID number for a device or variable). If I trap the TypeError and simply ignore it, the rest of the flow works as expected.
Code: Select all
            <Field id="thing" type="menu" defaultValue="None">
                <Label>Source:</Label>
                <List class="self" filter="" method="listGenerator" dynamicReload="true"/>
                <CallbackMethod>deviceStateGenerator</CallbackMethod>
            </Field>

            <Field id="thingState" type="menu" defaultValue="None">
                <Label>Text to chart:</Label>
                <List class="self" filter="" method="deviceStateGenerator" dynamicReload="true"/>
            </Field>

Code: Select all
    def deviceStateGenerator(self, filter="", valuesDict=None, typeId="", targetId=0):

        indigo.server.log(u"deviceStateGenerator: {0}".format(valuesDict))

        try:
            id = valuesDict['thing']
            return self.Fogbert.generatorStateOrValue(id)
        except KeyError:
            return [("Select a Source Above", "Select a Source Above")]
        except TypeError:
            pass


The valuesDict key appears to exist and have a valid value, so why the TypeError? Clearly, there's something I'm not seeing.
Last edited by DaveL17 on Thu Jan 25, 2018 5:41 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 Jan 25, 2018 10:01 am
matt (support) offline
Site Admin
User avatar
Posts: 21416
Joined: Jan 27, 2003
Location: Texas

Re: Device valuesDict Passed on Callback Method

Odd. In the failure case what is the log result of your indigo.server.log line?

The error is hinting that valuesDict isn't a dict but is a string. Try adding this to see if that is the case:

indigo.server.log(u"valuesDict type: %s" % type(valuesDict))

Image

Posted on
Thu Jan 25, 2018 10:05 am
matt (support) offline
Site Admin
User avatar
Posts: 21416
Joined: Jan 27, 2003
Location: Texas

Re: Device valuesDict Passed on Callback Method

I think the problem is the signature for your callback method isn't correct. You are using the callback for constructing a menu, whereas that refresh callback should look like this:

def deviceStateGenerator(self, valuesDict, typeId="", devId=0):

Image

Posted on
Thu Jan 25, 2018 12:04 pm
DaveL17 offline
User avatar
Posts: 6751
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Device valuesDict Passed on Callback Method

matt (support) wrote:
Odd. In the failure case what is the log result of your indigo.server.log line?

The error is hinting that valuesDict isn't a dict but is a string. Try adding this to see if that is the case:

indigo.server.log(u"valuesDict type: %s" % type(valuesDict))

Thanks Matt. indigo.server.log(u"deviceStateGenerator: {0}".format(type(valuesDict))) gives me:
Code: Select all
deviceStateGenerator: <type 'unicode'>

I think the problem is the signature for your callback method isn't correct. You are using the callback for constructing a menu, whereas that refresh callback should look like this:

def deviceStateGenerator(self, valuesDict, typeId="", devId=0):

When I use that signature, I get an error that I'm not receiving enough arguments.
Code: Select all
Error in plugin execution GetUiDynamicList:

Traceback (most recent call last):
TypeError: deviceStateGenerator() takes at most 4 arguments (5 given)


But I think you might be on to something. I'm calling deviceStateGenerator() both as a control callback and as a source for a dynamic list. I need to do some more testing, but I suspect that the two signatures are different. I'll report back when I have a chance to test that.

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

[My Plugins] - [My Forums]

Posted on
Thu Jan 25, 2018 12:18 pm
kw123 offline
User avatar
Posts: 8360
Joined: May 12, 2013
Location: Dallas, TX

Re: Device valuesDict Passed on Callback Method

I use these 2 and they always work
Code: Select all
    def filterxxx(self, filter="", valuesDict=None, typeId="", devId=""):

Code: Select all
    def CALLBACKxxx(self, valuesDict=None, typeId="", devId=0):


filter does not offer values dict, I have left it in .

Karl
Last edited by kw123 on Thu Jan 25, 2018 12:20 pm, edited 1 time in total.

Posted on
Thu Jan 25, 2018 12:19 pm
DaveL17 offline
User avatar
Posts: 6751
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Device valuesDict Passed on Callback Method

Winner, winner, chicken dinner.

First trip through:
Code: Select all
filter:
valuesDict: UiValuesDict : (dict)
typeId: DEVICE TYPE
targetId: DEVICE ID

That's the result of building the dynamic lists.

After the first control is populated:
Code: Select all
filter: UiValuesDict : (dict)
valuesDict: DEVICE TYPE
typeId: DEVICE ID
targetId: 0

That's the result of the control callback.

As Jeff Spicoli said, "My brother has an awesome set of tools. We can fix this." Thanks for putting me back on the path Matt.

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

[My Plugins] - [My Forums]

Posted on
Thu Jan 25, 2018 12:21 pm
DaveL17 offline
User avatar
Posts: 6751
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Device valuesDict Passed on Callback Method

kw123 wrote:
I use these 2 and they always work

Karl

Thanks Karl.

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

[My Plugins] - [My Forums]

Posted on
Thu Jan 25, 2018 5:50 pm
DaveL17 offline
User avatar
Posts: 6751
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Device valuesDict Passed on Callback Method [SOLVED]

That was exactly the issue. I was using the same plugin method to both generate a dynamic list *and* as a callback to force another dynamic control to refresh. I created a new method called _dummyCallback() for use by the control's <CallbackMethod> which solved my problem.
Code: Select all
    def _dummyCallback(self, valuesDict=None, typeId="", targetId=0):
        pass

For the future:

As Karl states above, the signature for a dynamic control (where dynamicReload=True) is:
Code: Select all
    def METHOD_NAME(self, filter="", valuesDict=None, typeId="", targetId=0):

Whereas the signature for a control's <CallbackMethod> is:
Code: Select all
    def METHOD_NAME(self, valuesDict=None, typeId="", targetId=0):

Most importantly, they shouldn't be used interchangeably. :D

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

[My Plugins] - [My Forums]

Posted on
Thu Jan 25, 2018 6:21 pm
Colorado4Wheeler offline
User avatar
Posts: 2794
Joined: Jul 20, 2009
Location: Colorado

Re: Device valuesDict Passed on Callback Method [SOLVED]

I always use a stock callback for form fields needing to do something or force a list refresh called 'formFieldChanged', then I spur off of that into specific actions when I need them:

Code: Select all
   #
   # A form field changed, update defaults
   #
   def formFieldChanged (self, valuesDict, typeId, devId):
      try:   
         if typeId == "Server":
            return self.serverFormFieldChanged (valuesDict, typeId, devId)
         
      except Exception as e:
         self.logger.error (ext.getException(e))   


I do this in all of my plugins and it makes it easy for me to always remember that my dynamic stuff happens there in every plugin. I actually do a similar thing for dynamically reloading lists and menus although I've really done a lot in that area so it would be too complicated to explain here but the idea is that every single plugin calls the same 'getCustomList' method and I make extensive use of the filters to tell the plugin exactly what list I want back and from where, this way I don't have to create as much code.

My Modest Contributions to Indigo:

HomeKit Bridge | Device Extensions | Security Manager | LCD Creator | Room-O-Matic | Smart Dimmer | Scene Toggle | Powermiser | Homebridge Buddy

Check Them Out Here

Posted on
Thu Jan 25, 2018 7:28 pm
DaveL17 offline
User avatar
Posts: 6751
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Device valuesDict Passed on Callback Method [SOLVED]

Colorado4Wheeler wrote:
I do this in all of my plugins and it makes it easy for me to always remember that my dynamic stuff happens there in every plugin.

[snip]

this way I don't have to create as much code.

Yeah, I'm moving that direction too. In fact, Adam has given me some great examples for me to steal and I think I'll snoop around your plugins too.

Nice avatar by the way. :D

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

[My Plugins] - [My Forums]

Posted on
Thu Jan 25, 2018 7:34 pm
Colorado4Wheeler offline
User avatar
Posts: 2794
Joined: Jul 20, 2009
Location: Colorado

Re: Device valuesDict Passed on Callback Method [SOLVED]

LOL, thank Jay, he inspired my avatar :lol:

If you dive into mine let me know and I’ll answer as much as I can. I’ve made mine quite modular, passing all Indigo functions to a processor library that decides what goes where and when.

My Modest Contributions to Indigo:

HomeKit Bridge | Device Extensions | Security Manager | LCD Creator | Room-O-Matic | Smart Dimmer | Scene Toggle | Powermiser | Homebridge Buddy

Check Them Out Here

Posted on
Thu Jan 25, 2018 7:42 pm
DaveL17 offline
User avatar
Posts: 6751
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Device valuesDict Passed on Callback Method [SOLVED]

Thanks for the offer.

I love the idea of standardizing as much as possible across plugins.

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

[My Plugins] - [My Forums]

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 2 guests

cron