Embedded Python to determine the calling deviceID

Posted on
Fri Aug 27, 2021 2:53 pm
jay (support) offline
Site Admin
User avatar
Posts: 18199
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Embedded Python to determine the calling deviceID

kw123 wrote:
Code: Select all
for scanDevice in indigo.devices:
   indigo.server.log ( str( scanDevice.id ), scanDevice.name )
   try:
      deviceState = str( scanDevice.onState )
   except:
      indigo.server.log ( "In the except section" )
   
   indigo.server.log ( str(scanDevice.onState ) )


will always execute: indigo.server.log ( str(scanDevice.onState ) )


Ding, ding, ding, ding!

I will disagree with Karl - the more Pythonic way is to use try/except. But either approach works.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Fri Aug 27, 2021 3:05 pm
kw123 offline
User avatar
Posts: 8333
Joined: May 12, 2013
Location: Dallas, TX

Re: Embedded Python to determine the calling deviceID

Why?
I thought using error traps takes more resources than an if

Karl

I know
try:
will also catch all other errors


Sent from my iPhone using Tapatalk

Posted on
Fri Aug 27, 2021 3:31 pm
jay (support) offline
Site Admin
User avatar
Posts: 18199
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Embedded Python to determine the calling deviceID

kw123 wrote:
Why?
I thought using error traps takes more resources than an if


Well, it really depends on what test(s) are happening, but in terms of performance it's negligible. More importantly, Python's general philosophy (as expressed by Guido, the original developer) is EAFP (easier to ask forgiveness than permission). Therefore, as I stated, it's more Pythonic. :)

kw123 wrote:
I know
try:
will also catch all other errors


except by itself will catch all errors, though you can catch explicit errors if you want. Catching all errors is often times a better result if your script can continue to process regardless of whether an error occurred or not.

It really depends on what the goal of the construct is, how often things will fail vs succeed, etc. In his case, I suspect that putting all the logic inside the try section and just pass on the exceptions would be the most efficient pattern for what he's doing.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Fri Aug 27, 2021 5:43 pm
jjpmir04 offline
Posts: 15
Joined: Aug 25, 2021

Re: Embedded Python to determine the calling deviceID

Great, thank you, I will check that tonight...
Here is where I am with the code suggestion from Karl to capture the exception. Also some best practices on the function getattr(dev, "onState", None)
. Current results are shared here. Next thing is to correct my errors of stuffing int into strings.

Code: Select all
for dev in indigo.devices:
   try:
      alarmHasonState = getattr(dev, "onState", None)
      indigo.server.log( "Staying in the try path " + int( dev.id ) + " " + str( dev.name )  )
      if alarmHasonState is not None:
         indigo.server.log( "Staying in the if true path " + int( dev.id ) + " This could be the truth path " +  str( dev.name ) +          indigo.server.log( "Truth Path to " + dev.id + " " + dev.name + " being the activated device ******  " + str(dev.onState ) )  )
      else:
         indigo.server.log( "Moving to the if-then-else false path " + int( dev.id ) + " " +  str( dev.name ) )
   except:
         indigo.server.log( "Moving to the if except path" + int( dev.id ) +  " " + str( dev.name ) )


Getting really close...under an actual water leak detected, I received the following log entries.


Aug 27, 2021 at 4:46:57 PM
Z-Wave Debug RCVD requestAlarmSensorStatus: 01 0F 00 04 00 06 09 71 05 00 00 00 FF 05 02 00 17
Z-Wave Debug . . requestAlarmSensorStatus: node 006, endpoint None, cmdClass 71, type 0, value 0, classSubKey 710000
Z-Wave Debug . . requestAlarmSensorStatus: typeExt 5, valueExt 2, classSubKeyExt 7100000502
Z-Wave Debug . . requestAlarmSensorStatus: defnStatusByte 255
Z-Wave received "006 - Leak Sensor" status update is on
Trigger Water Leak Sensor Activated
Trigger Water Leak Sensor Activated Siren
006 - Humidity 1384093992
Script None
006 - Leak Sensor 1873696535
Script True
006 - Tamper 316739640
Script False
006 - Temperature 77470459
Script None
Z-Wave Debug SENT soundSwitchTonePlay: 01 0E 00 13 08 07 60 0D 01 07 79 08 15 25 25 E2
007 - Z-Wave Repeater (ZW189) 1219598056
Script In the except section
Script Error embedded script: 'Device' object has no attribute 'onState'
Script Error Exception Traceback (most recent call shown last):

embedded script, line 17, at top level
AttributeError: 'Device' object has no attribute 'onState'

Posted on
Fri Aug 27, 2021 6:09 pm
jay (support) offline
Site Admin
User avatar
Posts: 18199
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Embedded Python to determine the calling deviceID

You've still got extraneous stuff in your script, some of which won't actually work (I think you may have a copy/paste error). Here is the script for you with comments to describe what's going on:

Code: Select all
for dev in indigo.devices:
    try:
        # Attempt to use dev.onState. If it doesn't exist, it will fall through to the except block
        # This line will print the id, name, and onState value. it substitutes items in the format
        # functions parameter list for the curly brackets
        indigo.server.log(u"id: {}, name: {}, onState: {}".format(dev.id, dev.name, dev.onState))
        # Do whatever else you want to do here for devices with an onState
    except:
        # We get here if there is no onState, or if any other exception is raised. I think
        # you don't actually want to do anything, so we'll just pass, which means do nothing
        pass


Try this script exactly as-is before trying to modify it just to make sure that it's working without any errors.

Here's what I get when I run it in the interactive shell:

Code: Select all
   Interactive Shell               id: 1217906765, name: 010 - Smart Fan Control (14287), onState: False
   Interactive Shell               id: 1198679701, name: 016 - Plug-In Appliance Module (ZL-PA-100), onState: True
   Interactive Shell               id: 854505717, name: 017 - Door/Window Sensor, onState: True
   Interactive Shell               id: 138804565, name: 033 - Aeotec Motion Sensor DSB05, onState: False
   Interactive Shell               id: 1670388240, name: 033 - Humidity, onState: None
   Interactive Shell               id: 563953359, name: 033 - Illuminance, onState: None
   Interactive Shell               id: 1062951901, name: 033 - Temperature, onState: None
   Interactive Shell               id: 1054394084, name: 037 - Humidity, onState: None
   Interactive Shell               id: 1423396960, name: 037 - Illuminance, onState: None
   Interactive Shell               id: 1174438877, name: 037 - Motion Sensor, onState: False
   Interactive Shell               id: 843639454, name: 037 - Tamper, onState: False
   Interactive Shell               id: 353759082, name: 037 - Temperature, onState: None
   Interactive Shell               id: 11221236, name: 038 - Lamp Module (AD130), onState: True
   Interactive Shell               id: 1619832111, name: automatic door, onState: False
   Interactive Shell               id: 1635226612, name: bestätigt für explicaría por qué está léger problème sûr  c'è, onState: False
   Interactive Shell               id: 770310484, name: Device Group, onState: False
   Interactive Shell               id: 1748999492, name: FanLinc - Fan, onState: True
   Interactive Shell               id: 1239593452, name: FanLinc - Light, onState: True
   Interactive Shell               id: 1832515689, name: Fortrezz Siren, onState: False
   Interactive Shell               id: 747983, name: Fortrezz Strobe, onState: False
   Interactive Shell               id: 1578082226, name: Generic X10 Appliance Module, onState: False
   Interactive Shell               id: 388029976, name: Hue Bulb, onState: False
   Interactive Shell               id: 1508839119, name: Insteon Dimmer, onState: False
   Interactive Shell               id: 1709062776, name: Insteon Door Sensor, onState: False
   Interactive Shell               id: 712384195, name: Insteon Motion Sensor, onState: False
   Interactive Shell               id: 409229455, name: Insteon Motion Sensor 2, onState: True
   Interactive Shell               id: 222549294, name: Insteon On/Off, onState: False
   Interactive Shell               id: 70182328, name: Insteon Window Sensor, onState: False
   Interactive Shell               id: 382287804, name: Kasa Plug, onState: True
   Interactive Shell               id: 498764526, name: KeypadLinc, onState: False
   Interactive Shell               id: 892416427, name: office outlet, onState: False
   Interactive Shell               id: 1777351472, name: Office Siren, onState: False
   Interactive Shell               id: 1139412655, name: Outdoor Appliance Module (45604), onState: False
   Interactive Shell               id: 1685264189, name: Simple Virtual On/Off, onState: False
   Interactive Shell               id: 54647685, name: Virtual On/Off Device w/ Manual State, onState: False
   Interactive Shell               id: 1759169776, name: Virtual On/Off Device w/ Var Status, onState: False

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Sat Aug 28, 2021 8:32 am
jjpmir04 offline
Posts: 15
Joined: Aug 25, 2021

Re: Embedded Python to determine the calling deviceID

I really appreciate the help and guidance.

Here are the results

Code: Select all
for dev in indigo.devices:
    try:
        # Attempt to use dev.onState. If it doesn't exist, it will fall through to the except block
        # This line will print the id, name, and onState value. it substitutes items in the format
        # functions parameter list for the curly brackets
        indigo.server.log(u"id: {}, name: {}, onState: {}".format(dev.id, dev.name, dev.onState))
        # Do whatever else you want to do here for devices with an onState
        if dev.onState == True:
         indigo.server.log( "Found Device: " + dev.name + "Break loop")
         break
    except:
        # We get here if there is no onState, or if any other exception is raised. I think
        # you don't actually want to do anything, so we'll just pass, which means do nothing
        indigo.server.log( "in the exception processing" )
        pass

# indigo.server.log(u"id: {}, name: {}, onState: {}".format(dev.id, dev.name, dev.onState))
# Do whatever else you want to do here for devices with an onState


Code will run in the embedded script editor:
Aug 28, 2021 at 9:23:42 AM
Script id: 1384093992, name: 006 - Humidity, onState: None
Script id: 1873696535, name: 006 - Leak Sensor, onState: False
Script id: 316739640, name: 006 - Tamper, onState: False
Script id: 77470459, name: 006 - Temperature, onState: None
Script in the exception processing
Script id: 553374040, name: 008 - Button 1, onState: False
Script id: 47791506, name: 008 - Button 2, onState: False
Script id: 93060902, name: 008 - Button 3, onState: False
Script id: 1451990799, name: 008 - Security Siren, onState: False
Script id: 1209823218, name: 008 - Tamper Alert, onState: False
Script in the exception processing
Script in the exception processing

But when a real alarm is triggered, I get the following...

Aug 28, 2021 at 9:24:12 AM
Z-Wave Debug RCVD requestAlarmSensorStatus: 01 0F 00 04 00 06 09 71 05 00 00 00 FF 05 02 00 12
Z-Wave Debug . . requestAlarmSensorStatus: node 006, endpoint None, cmdClass 71, type 0, value 0, classSubKey 710000
Z-Wave Debug . . requestAlarmSensorStatus: typeExt 5, valueExt 2, classSubKeyExt 7100000502
Z-Wave Debug . . requestAlarmSensorStatus: defnStatusByte 255
Z-Wave received "006 - Leak Sensor" status update is on
Trigger Water Leak Sensor Activated
Trigger Water Leak Sensor Activated Siren
006 - Humidity 1384093992
Script None
006 - Leak Sensor 1873696535
Script True
006 - Tamper 316739640
Script False
006 - Temperature 77470459
Script None
007 - Z-Wave Repeater (ZW189) 1219598056
Script In the except section
Script Error embedded script: 'Device' object has no attribute 'onState'
Script Error Exception Traceback (most recent call shown last):

embedded script, line 17, at top level
AttributeError: 'Device' object has no attribute 'onState'

Posted on
Sat Aug 28, 2021 8:39 am
kw123 offline
User avatar
Posts: 8333
Joined: May 12, 2013
Location: Dallas, TX

Re: Embedded Python to determine the calling deviceID

the log out put can not be created by the posted script.

line 17 has a # in front so it should not be executed.

I believe you have a simple misunderstanding of
Code: Select all
try:
       normal code for whatever you want to do
except:
       error activity
and here a new section begins w or w/o error in the preceding try/except


if an error occurs in the try: section the except section get executed and the the script CONTINUES with the following lines
if the line 17 does not have the # inform that would explain the log output.

so you need to put ALL active code into the try: section , only the error handling into the except:

Then when except section is done a new live begins any error there is not covered by the previous try: / except:

Karl

and the pass in the except section does not do anything, can be dropped.. only if there is no line after except the pass makes sense

Posted on
Sat Aug 28, 2021 8:54 am
jjpmir04 offline
Posts: 15
Joined: Aug 25, 2021

Re: Embedded Python to determine the calling deviceID

UPDATE:

When running with the embedded editor open with the script - you get the results just shared.

When the embedded editor is closed, I get the following successful results:

Thank you to everyone, I really appreciate it. I'm sorry to consume so much of your time. I've been a programmer forever but python is new to me.

with best regards,

Jim Prete

Z-Wave received "006 - Leak Sensor" status update is on
Trigger Water Leak Sensor Activated
Trigger Water Leak Sensor Activated Siren
Z-Wave Debug SENT soundSwitchTonePlay: 01 0E 00 13 08 07 60 0D 01 07 79 08 15 25 41 86
Script Device id: 1384093992
Script id: 1384093992, name: 006 - Humidity, onState: None
Script Device id: 1873696535
Script id: 1873696535, name: 006 - Leak Sensor, onState: True
Script Found Device: 006 - Leak SensorBreak loop
Email+ sending email 'ALARM - The RHC Association - Leak ALARM - Leak Detected in Unit: HH31' to 'james.prete@icloud.com, james@prete.net' using Indigo Notifications

Posted on
Sat Aug 28, 2021 9:32 am
kw123 offline
User avatar
Posts: 8333
Joined: May 12, 2013
Location: Dallas, TX

Re: Embedded Python to determine the calling deviceID

when you have the script editor open it makes a copy you then change.
So if you execute it outside the editor and inside you will get different results as you execute different scripts

Only after closing the editor the new script gets saved.

Karl

ps there is no save button in the editor (has been on the list for improvements for some time :( )

Posted on
Sat Aug 28, 2021 10:10 am
jay (support) offline
Site Admin
User avatar
Posts: 18199
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Embedded Python to determine the calling deviceID

Please run the script first EXACTLY as I posted without changes, otherwise we will continue to run in circles.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Sat Aug 28, 2021 12:05 pm
jjpmir04 offline
Posts: 15
Joined: Aug 25, 2021

Re: Embedded Python to determine the calling deviceID

Sorry about that Jay, I was impatient to get to the next issue and I was jumping ahead.

Thank you very much for your help, it was much appreciated.

Now, I will convert the tamper, battery level, temperature sensors to this logic and I'm hopeful that this will facilitate scaling the implementation of the network. Good news is that only the tamper sensor relies on a onState property to determine what fired.

I just completed a HomeAssistant (on a pi3B) build-out at the same time I am implementing indigo for a much larger network. Going back and forth is quite jarring.

Really nice community here on indigo domotics. Very helpful and friendly.

with best regards,

Jim Prete

Posted on
Mon Aug 30, 2021 7:58 am
jjpmir04 offline
Posts: 15
Joined: Aug 25, 2021

Re: Embedded Python to determine the calling deviceID

Thanks again for all the help...
Here is the working code to assist anyone in the future.

Code: Select all
#Loop to find the calling device
#this variable will allow me to test at the end if the loop to see if the effort was succesful
deviceID = int(0)
#Loop through all device
for dev in indigo.devices:
    #indigo.server.log( "Device id: " + str( dev.id ) )
    #Check if the found device is a range extender - they are difficult to coax properties from
    if "Repeater" in dev.name:
      indigo.server.log( "Ignore Repeater devices" )
      #found the text Repeater so stop this object from passing through the rest of this loop
      pass
    #This try statement will allow me to catch exceptions generated by attempting to access properties that do not exist on an object
    try:
        # Attempt to access property onState for this object.
        # If it doesn't exist, it will fall through to the except block
        alarmHasonState = getattr(dev, "onState", None)
        # This line will print the id, name, and onState value. it substitutes items in the format
        # functions parameter list for the curly brackets
        # indigo.server.log(u"id: {}, name: {}, onState: {}".format(dev.id, dev.name, dev.onState))
        # The object has the property onState but now test that the onState property is True
        if dev.onState == True:
            # Print out various values during debug phase
            #indigo.server.log(u"id: {}, name: {}, onState: {}".format(dev.id, dev.name, dev.onState))
            #indigo.server.log( "Found Device: " + dev.name + "Break loop")
           #Save the retrieved deviceID to process the remaining portion of this script
            deviceID = dev.id
            #Breakout of this loop since we found the device object we are looking for.
            break
    except:
        # We get here if there is no onState, or if any other exception is raised. I think
        # you don't actually want to do anything, so we'll just pass, which means do nothing
        # indigo.server.log( "in the exception processing" )
        pass
#First thing to do is check whether we got here by finding a device object or by exhausting the list of objects
if deviceID == 0:
    indigo.server.log("No Device found with onState property set to True" )
    indigo.server.log("This is really bad... report it to supplier of this software" )
    # Send email to developer
    indigo.server.sendEmailTo( "james.prete@icloud.com", subject = "ALARM - The " +
    "Leak Monitoring Software" +
    " is showing a BUG - SOFTWARE ALARM - Broken Logic in LEAK ALARM handling detected ",
    body =
    "SOFTWARE ALARM - Leak Sensor processing failed" + "-Check Log File- Call Developer ASAP"  )
    sys.exit()


Who is online

Users browsing this forum: No registered users and 7 guests