Comparing Device Objects [Solved]

Posted on
Sat Mar 17, 2018 7:39 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Comparing Device Objects [Solved]

I think I might be code-blind. I'm working with something based on subscribeToChanges() and trying to isolate on what's actually changed between origDev and newDev. In starting to work on a way to compare the two objects, I came across a result that I find perplexing.

Code: Select all
dev1 = indigo.devices[1149686816]
dev2 = indigo.devices[1149686816]
indigo.server.log(str(dev1 == dev2))
Log:
Code: Select all
Mar 17, 2018, 8:31:34 PM
   Script                          False

I would think they would be equal......but how to tell the difference between the two?

I started down a path of converting the device instances to Unicode and then parsing the string, but is there an easier way? What I want is only the changes:
Code: Select all
# prop or state: (old, new)
brightness: (42, 100)
onState: (False, True)
Last edited by DaveL17 on Tue Mar 20, 2018 6:19 am, 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
Sat Mar 17, 2018 7:50 pm
Colorado4Wheeler offline
User avatar
Posts: 2794
Joined: Jul 20, 2009
Location: Colorado

Re: Comparing Device Objects

Code: Select all
if old.onState == new.onState:
   ...


How I check for changes is iterate through all the attributes and states. So for states:
Code: Select all
for key, val in old.states.iteritems():
  if key in new.states and new.states[key] != old.states[key]:
   ....


Edit: I forgot to tack on .iteritems() to that iteration.

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
Sat Mar 17, 2018 8:31 pm
FlyingDiver offline
User avatar
Posts: 7189
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Comparing Device Objects

DaveL17 wrote:
I think I might be code-blind. I'm working with something based on subscribeToChanges() and trying to isolate on what's actually changed between origDev and newDev. In starting to work on a way to compare the two objects, I came across a result that I find perplexing.

Code: Select all
dev1 = indigo.devices[1149686816]
dev2 = indigo.devices[1149686816]
indigo.server.log(str(dev1 == dev2))
Log:
Code: Select all
Mar 17, 2018, 8:31:34 PM
   Script                          False

I would think they would be equal......but how to tell the difference between the two?


They're not equal because your Python code is getting a copy of the actual device info on the server. Not a pointer to it. So each copy is distinct. And you're comparing the device object pointers, not the contents.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Sun Mar 18, 2018 5:41 am
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Comparing Device Objects

Colorado4Wheeler wrote:
Code: Select all
if old.onState == new.onState:
   ...


How I check for changes is iterate through all the attributes and states. So for states:
Code: Select all
for key, val in old.states.iteritems():
  if key in new.states and new.states[key] != old.states[key]:
   ....


Edit: I forgot to tack on .iteritems() to that iteration.

Thanks. I should've been more clear (told you I was code blind)...

I realize I can compare them element by element, I was hoping there was a more straightforward way of doing the comparison. I don't know, like with a dictionary comprehension or something:
Code: Select all
dev1 = {'k1': 'v1', 'k2': 'v2'}
dev2 = {'k1': 'v1', 'k2': 'v3'}

d = {k: (dev1[k], dev2[k]) for k in dev1.keys() if dev1[k] != dev2[k]}

indigo.server.log(str(d))

Result:
Code: Select all
{'k2': ('v2', 'v3')}

But that won't work for device objects. How about indigo.listOfChanges(origDev, newDev)? :)

FlyingDiver wrote:
And you're comparing the device object pointers, not the contents.

That's the bit I find perplexing. Why isn't it comparing the contents? If I compare two dictionaries with the same contents, they will come back as equal. In one case it's comparing the pointers and in the other case it's comparing the values.

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

[My Plugins] - [My Forums]

Posted on
Sun Mar 18, 2018 6:54 am
FlyingDiver offline
User avatar
Posts: 7189
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Comparing Device Objects

DaveL17 wrote:
FlyingDiver wrote:
And you're comparing the device object pointers, not the contents.

That's the bit I find perplexing. Why isn't it comparing the contents? If I compare two dictionaries with the same contents, they will come back as equal. In one case it's comparing the pointers and in the other case it's comparing the values.


I believe that's because the dictionary data type implements the __cmp__ function which is designed to do a deep compare. The Indigo device data type does not.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Sun Mar 18, 2018 7:16 am
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Comparing Device Objects

FlyingDiver wrote:
I believe that's because the dictionary data type implements the __cmp__ function which is designed to do a deep compare. The Indigo device data type does not.

I see I need to do a bit more studying. :)

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

[My Plugins] - [My Forums]

Posted on
Sun Mar 18, 2018 7:23 am
FlyingDiver offline
User avatar
Posts: 7189
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Comparing Device Objects

https://docs.python.org/2/reference/dat ... ct.__cmp__

object.__cmp__(self, other)
Called by comparison operations if rich comparison (see above) is not defined. Should return a negative integer if self < other, zero if self == other, a positive integer if self > other. If no __cmp__(), __eq__() or __ne__() operation is defined, class instances are compared by object identity (“address”)

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Sun Mar 18, 2018 7:29 am
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Comparing Device Objects

Thanks!

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

[My Plugins] - [My Forums]

Posted on
Sun Mar 18, 2018 1:51 pm
matt (support) offline
Site Admin
User avatar
Posts: 21411
Joined: Jan 27, 2003
Location: Texas

Re: Comparing Device Objects

We probably should implement (internally) the __cmp__ method for Indigo objects. But in the mean time I think what you want to do is this:

indigo.server.log(str(dev1.id == dev2.id))

As internally Indigo forces all objects to have a unique ID which is not mutable (and doesn't change as python instances of the objects are created).

Image

Posted on
Sun Mar 18, 2018 2:10 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Comparing Device Objects

Thanks Matt -- I'm looking to compare the 'origDev' and 'newDev' objects that are sent to def deviceUpdated(self, origDev, newDev) for changes. I'm looking to identify what about the device has changed without iterating through all the props and states. Maybe that's the only way to do it...

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

[My Plugins] - [My Forums]

Posted on
Sun Mar 18, 2018 4:56 pm
matt (support) offline
Site Admin
User avatar
Posts: 21411
Joined: Jan 27, 2003
Location: Texas

Re: Comparing Device Objects

Ah yes, my suggestion won't help with that at all. I think even if we implemented the __cmp__ method that wouldn't help with what you are after though, since you want a list of exactly what has changed. Here is roughly how the SQL Logger plugin handles it:

changeDict = { key:val for key, val in newDev.states.iteritems() if key not in origDev.states or val != origDev.states[key] }

Although I don't believe that handles the case of a state being deleted (it does handle them being added). That is pretty much an edge case though, as in general plugins should never delete a state since it will potentially break Triggers, Conditionals, etc., that reference it.

Image

Posted on
Mon Mar 19, 2018 6:03 am
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Comparing Device Objects

Thanks Matt. This works great for device states, but I was also looking for a way to detect changes to device props. But after a few tests, it doesn't look like deviceUpdated() is called when a device's props change. Does that sound right?

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

[My Plugins] - [My Forums]

Posted on
Mon Mar 19, 2018 6:25 am
matt (support) offline
Site Admin
User avatar
Posts: 21411
Joined: Jan 27, 2003
Location: Texas

Re: Comparing Device Objects

deviceUpdated() is called when the properties (or anything else: name, states, etc.) change. I'm not sure why it isn't in your case/example, but definitely is routinely (we have plugins that rely on it).

Image

Posted on
Mon Mar 19, 2018 7:17 am
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Comparing Device Objects

All I can come up with is this error:

Code: Select all
   Script Error                    embedded script: developer is too stupid to live
   Script Error                    Exception Traceback (most recent call shown last):

     embedded script, line 123, at top level
PEBKACError: developer is too stupid to live

It is, of course, called. So I guess my question is this: Is there an iterator I can call to grab all the device's props for inspection? I haven't been able to land on one that seems to work. May also be a result of the above error.

If I need to call the props from an internal list, I can do that, too.

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

[My Plugins] - [My Forums]

Posted on
Mon Mar 19, 2018 8:59 am
Colorado4Wheeler offline
User avatar
Posts: 2794
Joined: Jul 20, 2009
Location: Colorado

Re: Comparing Device Objects

You missed a critical 'Except' in that trap....

Code: Select all
Except:
  "He writes good plugins that a lot of people use and that makes up for anything he thinks are dumb mistakes"


:lol:

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

Who is online

Users browsing this forum: No registered users and 2 guests