Starting out with Python

Posted on
Mon Mar 06, 2017 5:34 pm
Colly offline
Posts: 535
Joined: Jan 16, 2016
Location: Ireland

Starting out with Python

Hi All,

I'd like to experiment with Python and have the following requirement - to be clear I have absolutely no experience with same. I have a beam sensor at my driveway entrance which is connected to a Fibaro Universal Sensor (which works very reliably so far). I can easily activate certain devices to trigger on the beam being broken, what I'm struggling with is how I can brighten my "Sitting Room" light (if on) for say 5 seconds to signify that someone has arrived and then return to it's previous value. What is the easiest way to do this? Thanks in advance for your help.

Colly

Posted on
Mon Mar 06, 2017 7:33 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Starting out with Python

Here's a simple Python script to get you started:
Code: Select all
# Get current brightness
dev = indigo.devices[243868511]
light_level = int(dev.states['brightnessLevel'])

# Set the level to 100%
indigo.dimmer.setBrightness(dev, value=100)

# Set the level back after 5 seconds
indigo.dimmer.setBrightness(dev, value=light_level, delay=5)

Python is pretty easy to understand on the face until you start to get deep into it.

This script should be pretty easy to understand, but feel free to ask any questions. You'll need to replace the device number with the ID of your device. One thing that may be an issue that we may need to work on is -- what happens if the light is already on at 100 percent? We can address it no problem, but I didn't want to make the script more complex than you needed.

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

[My Plugins] - [My Forums]

Posted on
Wed Mar 08, 2017 3:49 pm
Colly offline
Posts: 535
Joined: Jan 16, 2016
Location: Ireland

Re: Starting out with Python

Thanks Dave,

I've tried that and it works great. You've highlighted one issue if the light is @ 100% which we can come back to - it rarely is. Another issue is when the light is off it brightens to 100% and back off, however the next time the light is turned on it reverts to 100% brightness rather than the previous dimmed value. What's the best way to deal with this?

Posted on
Wed Mar 08, 2017 4:38 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Starting out with Python

I'm glad that we're making progress! I want to understand better the issue that you're facing now. Please let me know if I have this right.

By some other means, you turn the light on -- let's say to 50%, and later turn it off. Your previous dim level is now 50%.

Your script runs. It reads the brightness level at 0%, brightens the light to 100% for 5 seconds, and then sets it back to 0%. Now the previous brightness level is 100%

The next time you turn on the light, it goes to 100% instead of the desired 50%.

Is that right?

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

[My Plugins] - [My Forums]

Posted on
Wed Mar 08, 2017 4:44 pm
Colly offline
Posts: 535
Joined: Jan 16, 2016
Location: Ireland

Re: Starting out with Python

Correct and right! :D That's exactly the situation.

Posted on
Wed Mar 08, 2017 5:16 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Starting out with Python

Okay, got it. Somebody should correct me in case I'm thinking about this the wrong way (it's been a long day. :D) IIRC, the last brightness level is maintained within the device but not within Indigo. That is, you can tell Indigo to turn the light on to a specific level, but if you simply tell it to turn on, it will go to the last brightness level (which in this case is 100% once the script has run--I think this also varies by device). We may have to modify the script to do something like the following.

See if the light is off. If it is, set a flag.
If it was off, turn it on (it will brighten to the 50% you want to retain for later)
Save that value to memory within the script
Brighten the light to 100% for 5 seconds.
Brighten the light to the last level (50%)
If the light was off when we started, turn it off again.

If I'm thinking about this right, you'll finish with your original 50%. Does that make sense? The trip from 50% to 100% (and back after 5 seconds) *should be* almost seamless.

I'm not at a place to test this, but it should work. Hopefully, someone will pipe up with a better idea, but if not, I'll try this out later tonight and see what happens.

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

[My Plugins] - [My Forums]

Posted on
Wed Mar 08, 2017 8:57 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Starting out with Python

Okay, this works for me but it might rely on something that's device specific so YMMV.

I did a small bit of digging, and it turns out there's an Indigo setting (at least for my test device) that does store the default brightness. So if we read that value, as well as whether the light was on or off, we can come really close to what you want--something that's at least serviceable--but there may be room for more improvement.

Code: Select all
from time import sleep

device_id = 243868511
dev = indigo.devices[device_id]

# Determine if the device was off
was_off = False
if not dev.onState:
    was_off = True

# Get the default brightness
light_level = int(dev.defaultBrightness)

# Set the level to 100%
indigo.dimmer.setBrightness(dev, value=100)

# Set the level back after 5 seconds
sleep(5)
indigo.dimmer.setBrightness(dev, value=light_level)

if was_off:
    indigo.device.turnOff(device_id)

I've tested this against a dimmer device and it works pretty well. If you need me to explain any of the new stuff beyond the comments I've added, I'm happy to do that. By the way, the reason I decided to use sleep over Indigo's built-in delay is that the 'turnOff' command was processed before the delay had finished.

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

[My Plugins] - [My Forums]

Posted on
Thu Mar 09, 2017 4:00 pm
Colly offline
Posts: 535
Joined: Jan 16, 2016
Location: Ireland

Re: Starting out with Python

Dave - works perfectly. OK so lets go with the Dummies Guide to help me and hopefully some others in understanding. I apologise in advance for the stupid questions I'll no doubt ask.
from time import sleep
I assume you are importing the last known value here. What does "from time" mean and why is it needed? Could it not just be "import sleep"?
was_off = False
if not dev.onState:
was_off = True

So as you state we are determining if the dev was off - "was_off = False". I'm failing to understand how you can just insert this text (which makes sense of course) and then how it actually determines the state of the device. I hope this makes sense, it's probably stupid question No 1.. In the previous action it seems clear - "import sleep", but for this part it just looks like a statement. :oops:
Next
light_level = int(dev.defaultBrightness)
I understand this piece - how do you or more importantly do I determine that the device actually stores "default brightness" or other values? It's obvious my device does because the script works.
Let's stop here for now on the "Python for DUMMIES" tutorial
I'm guessing these questions to you are like the questions my 4 year old daughter asks of me. :D

Posted on
Thu Mar 09, 2017 5:39 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Starting out with Python

No! Never feel bad about asking questions or trying to learn. When I came to Indigo, I didn't know what Python was. I'll just say that I'm proof that even a trained monkey can learn this stuff. :D

For your first question,
Code: Select all
from time import sleep

This is importing a Python module called 'time'. We could've just imported the whole thing ('import time') but sleep was the only part we needed. 'Sleep' is a part of the time module that tells the script to pause for the number of seconds specified. There are other functions in time, but we didn't need them here. This is a good place to introduce you to the Python Docs. Follow that link, poke around, and then go here for more information about 'sleep' and the other functions in 'time'. Don't get bogged down with it all now; just marvel at the number of things you can do if you wanted to. If we had instead imported the whole time module, we would've referred to our sleep command like this:
Code: Select all
time.sleep(5)

There are many, many modules built in to the base installation of Python. whenever you see a statement like the one above, the convention is:
Code: Select all
module_name.function_name(parameters)

But enough of that for now.

For your second question,
Code: Select all
was_off = False
if not dev.onState:
    was_off = True

This employs some simple logic that Python is exceedingly good at. These types of commands are very common. The first one creates a local variable called 'was_off" and sets it initially to the boolean value False. True and False are reserved words that connote just that--True or False. So we start out assuming that the light is initially off. Next, 'dev.onState' is a state value that Indigo maintains that's related to whether the light is on or off, but it does that by setting its own value to True or False. So the statement, 'if not dev.onState' means "If the device (dev) onState is not True". Meaning that the next line (which is indented underneath it) will only run if that is the current condition. I know it gets a little hairy at first, but what we have is if the light onState is False, set the value of 'was_off' to True. Otherwise, just blow right on by. So if the light was in fact off, the value of our variable 'was_off' is now True. Which is *ahem* True. The light was indeed off. 'Truthiness' is an important concept in Python.

For the third question,
it's a little bit complicated, but you can handle it. :D

We can inspect the attributes of any Indigo device (or variable, or action, or trigger, ...) with variations on the following short script:
Code: Select all
dev = indigo.devices[445253253]
indigo.server.log(unicode(dev))

Just substitute the device ID of your light for the one above and then have a gander at all the information that Indigo maintains just for one light. Now on to the rest of your question. It's a little tricky depending on what you're looking to inspect because Indigo has some of these types of inspections built in, but here's one way to determine whether a device supports 'defaultBrightness':
Code: Select all
dev = indigo.devices[445253253]

try:
    prop = str(dev.defaultBrightness)
except:
    prop = "Not Supported"

indigo.server.log(unicode(prop))

The script will try to set the variable 'prop' to the value of dev.defaultBrightness, and if dev.defaultBrightness doesn't exist, Python will throw an Exception. When it does, we 'trap' the exception (because we expect it to happen with some devices) and return "Not supported".

That's enough for now. If you want to learn Python, there are many good tutorials and videos online. That, with help from the folks here, is how I learned. Oh--and trial and error--LOTS of error. :D I started with Google's YouTube videos.

Please feel free to ask more questions if you have them.
Dave

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

[My Plugins] - [My Forums]

Posted on
Thu Mar 09, 2017 6:04 pm
jay (support) offline
Site Admin
User avatar
Posts: 18199
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Starting out with Python

Nice tutorial Dave. Another way to determine if a device has a given property is to ask it:

Code: Select all
hasattr(dev, "defaultBrightness")

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Fri Mar 10, 2017 1:49 pm
Professor Falken offline
User avatar
Posts: 289
Joined: Mar 29, 2015

Re: Starting out with Python

That's enough for now. If you want to learn Python, there are many good tutorials and videos online. That, with help from the folks here, is how I learned. Oh--and trial and error--LOTS of error. :D I started with Google's YouTube videos.


Dave,

Thanks for the Python course links. I think I may jump in and see if I can learn some Python scripting. My AppleScripts are sorta held together with duct tape and zip ties, and it sounds like Apple is inching ever closer to not supporting it at all in the future.

Posted on
Fri Mar 10, 2017 2:39 pm
DaveL17 offline
User avatar
Posts: 6741
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Starting out with Python

You bet. The ones from Khan Academy are good too.
https://youtu.be/husPzLE6sZc?list=PLJR1V_NHIKrCkswPMULzQFHpYa57ZFGbs

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

[My Plugins] - [My Forums]

Posted on
Thu Apr 20, 2017 8:14 pm
BlaineM offline
Posts: 36
Joined: Jan 13, 2012

Re: Starting out with Python

DaveL17 wrote:
Code: Select all
indigo.server.log(unicode(prop))

I've got a question related to the above code.

I'm attempting to test the state of a Phidgets device (from berkinet's plugin). In particular, I'm able to successfully do the following to turn on a digital output (or off using turnOff):
indigo.device.turnOn("do_device_name") # where device is a Phidgets digital output

What I'm not able to do is test the state of a digital input by using code similar to this (I get an error saying the attribute onState is not defined):
Code: Select all
dev = indigo.devices["di_device_name"] # where device is a Phidgets digital input
if dev.onState == on: # not sure about the boolean value I'm testing against, but it never got there before throwing an error on the undefined attribute
    do something


OK, so the device doesn't support onState. Reading through this thread, I figured I'd just see what the device's properties are and I then subsequently put them in the log file using the quoted code and got this:

2017-04-19 19:33:29.578 Script address : P-SBC3 - Veg Garden |di 1
batteryLevel : None
buttonGroupCount : 0
configured : True
description :
deviceTypeId : phDiIfKit
displayStateId : onOffState
displayStateImageSel : PowerOff
displayStateValRaw : False
displayStateValUi : off
enabled : True
energyAccumBaseTime : None
energyAccumTimeDelta : None
energyAccumTotal : None
energyCurLevel : None
errorState :
folderId : 0
globalProps : MetaProps : (dict)
com.perceptiveautomation.indigoplugin.Phidgets : (dict)
address : P-SBC3 - Veg Garden |di 1 (string)
buttonFlagDi : false (bool)
phDiIfKitId : 580018001 (string)
phDiIfKitInput : 1 (string)
phDiIfKitModel : phDiIfKit (string)
phDiIfKitSerial : 491507 (string)
id : 1567846833
lastChanged : 2017-04-19 14:22:51
lastSuccessfulComm : 2017-04-19 14:22:51
model : InterfaceKit Digital Input
name : 3-Way Valve Position - Veg Garden to Street Drain
ownerProps : com.perceptiveautomation.indigoplugin.Phidgets : (dict)
address : P-SBC3 - Veg Garden |di 1 (string)
buttonFlagDi : false (bool)
phDiIfKitId : 580018001 (string)
phDiIfKitInput : 1 (string)
phDiIfKitModel : phDiIfKit (string)
phDiIfKitSerial : 491507 (string)
pluginId : com.perceptiveautomation.indigoplugin.Phidgets
pluginProps : emptyDict : (dict)
protocol : Plugin
remoteDisplay : True
states : States : (dict)
lastUpdate : 2017-04-19 14:22:51 (string)
onOffState : off (on/off bool)
subModel :
supportsAllLightsOnOff : False
supportsAllOff : False
supportsStatusRequest : False
version : None

Now, based on my limited knowledge, I'd expect that I could use onOffState (instead of onState), but it also ends up being undefined. Am I doing something wrong or is this a limitation of the plugin? If the latter, how else can I test the state of the device within a Python script? Clearly Indigo can see the state of the on/off attribute since I can use the attribute to fire a trigger, so I would think I can test against it too. Any tips are greatly appreciated.

Thanks,
Blaine

Posted on
Thu Apr 20, 2017 8:36 pm
kw123 offline
User avatar
Posts: 8333
Joined: May 12, 2013
Location: Dallas, TX

Re: Starting out with Python

try:
Code: Select all
dev.states["onOffState"]
for
states : States : (dict)
lastUpdate : 2017-04-19 14:22:51 (string)
onOffState : off (on/off bool)


for props:
Code: Select all
props=dev.pluginProps
props["xxxx"]
or
Code: Select all
dev.pluginProps["xxxx"]
pluginProps : emptyDict : (dict) this one is empty

this are dicts inside the device... = one level deeper than dev.xxx

hope that helps
Karl

Posted on
Thu Apr 20, 2017 9:04 pm
BlaineM offline
Posts: 36
Joined: Jan 13, 2012

Re: Starting out with Python

kw123 wrote:
try:
Code: Select all
dev.states["onOffState"]
for
states : States : (dict)
lastUpdate : 2017-04-19 14:22:51 (string)
onOffState : off (on/off bool)


for props:
Code: Select all
props=dev.pluginProps
props["xxxx"]
or
Code: Select all
dev.pluginProps["xxxx"]
pluginProps : emptyDict : (dict) this one is empty

this are dicts inside the device... = one level deeper than dev.xxx

hope that helps
Karl

That was the ticket! This helps me in other ways than just solving my particular issue. I believe it's tied to the enumerated types I read about earlier, but I'll go back for further review before I commit to that conclusion.

Thanks for the quick reply.

--Blaine

Who is online

Users browsing this forum: No registered users and 3 guests