How do I calculate elapsed time?

Posted on
Sat Jul 04, 2020 10:10 pm
gmusser offline
Posts: 290
Joined: Feb 12, 2005
Location: New Jersey

How do I calculate elapsed time?

My old AppleScripts stored time as an integer representing the number of seconds elapsed since 1970, which made time calculations trivial. I'm having trouble porting these to Python. I looked at the delta-time calculation in the Indigo scripting tutorial, but I’m not grasping the data structure used to store time and how it should be manipulated. For instance, consider this code fragment:
Code: Select all
timeDelta = datetime.now() - lamp.lastChanged
if not lamp.onState and timeDelta.seconds > 60:

I presume that "lamp" is what in C would be a struct, but then what is "timeDelta"? It looks like a struct, too, but (a) how can you subtract two numbers and get a struct? and (b) ".seconds" looks like a call to a conversion function rather than accessing one element of a structure. Python sure does use a lot of periods. (Clearly it would help if I sat down and learned the language properly!)

Anyway, here is my attempt at Pythonizing my AppleScript. The first script, triggered when my boiler turns on, logs the time. The second, triggered when the boiler turns off, logs the time, calculates the run time, and resets the relevant Indigo variable. I tried substituting the datetime.now() function for indigo.server.getTime(), but the result was the same.

Thanks for your help!

Code: Select all
import os

# set up log file name
data_path = os.path.expanduser('~') + "/Documents/BoilerData-TEST.txt"

try:

    # open log file
    with open(data_path, 'a+') as outfile:

        # set Indigo variable to current time
        now = indigo.server.getTime()
        indigo.variable.updateValue(79472523, value=unicode(now))
       
        # write the boiler startup time to the log file     
        decimal = (now.hour * 3600.0 + now.minute * 60.0 + now.second) / (3600.0*24.0)
        outfile.write((u"{0:%m/%d/%Y}\t{1}\ton\r".format(now, decimal)))

except Exception as err:
    indigo.server.log("boiler monitor error: {0}".format(err))


Code: Select all
import os

# set up log file name
data_path = os.path.expanduser('~') + "/Documents/BoilerData-TEST.txt"

try:

    # open log file
    with open(data_path, 'a+') as outfile:

        # write the boiler shutdown time to the log file     
        now = indigo.server.getTime()
        decimal = (now.hour * 3600.0 + now.minute * 60.0 + now.second) / (3600.0*24.0)
        outfile.write((u"{0:%m/%d/%Y}\t{1}\toff".format(now, decimal)))

        # if we can calculate an elapsed time, do so
        startup = indigo.variables[79472523].getValue(int)
        if startup > 0:
                elapsed = now - startup
               
                # write elapsed time (in seconds) to the log file
                outfile.write((u"\t{0}\r".format(elapsed)))
               
                # reset variable to indicate the boiler is now off
                indigo.variable.updateValue(79472523, value=unicode(0))
                               
        else:
                outfile.write((u"\r"))

except Exception as err:
    indigo.server.log("boiler monitor error: {0}".format(err))

Posted on
Sun Jul 05, 2020 4:41 am
DaveL17 offline
User avatar
Posts: 6742
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: How do I calculate elapsed time?

I don't know what a struct is, but in Python pretty much everything is an object. Dates and times (in Python: datetime) are datetime objects which have a lot of properties. If you print out a datetime object, the print function formats it into a standard POSIX time value:
Code: Select all
import datetime

now = datetime.datetime.now()
print(u"{0}".format(now))

>>> 2020-07-05 05:28:50.901691

Taking the difference between two time values results in a timedelta object.
Code: Select all
import datetime
from time import sleep

now = datetime.datetime.now()
print(u"{0}".format(now))
sleep(5)
then = datetime.datetime.now()
print(u"{0}".format(then))
diff = then - now
print(u"{0}".format(diff.seconds))

>>> 2020-07-05 05:31:02.896778
>>> 2020-07-05 05:31:07.903543
>>> 5

The timedelta object is still a datetime object, and has properties too.

In your example, 'lamp' is an Indigo device object (and has properties like 'onState'). For your second question, you're not subtracting two numbers and getting a struct, you're performing math on two objects and getting a new object. IMO, converting time to decimals is an unnecessary step.

If you want to work with POSIX dates that are stored as strings, Python has a way to handle that. Take a look at 'datetime.strptime' and 'datetime.strftime'. Oh, and the seconds since epoch (1/1/70) is also something that Python can handle easily.

https://docs.python.org/2.7/library/time.html
Last edited by DaveL17 on Sun Jul 05, 2020 4:45 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
Sun Jul 05, 2020 4:42 am
DaveL17 offline
User avatar
Posts: 6742
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: How do I calculate elapsed time?

p.s. datetime.now and indigo.server.getTime are the same thing. Indigo is providing a convenience method so you can just get the time from the server instead of importing datetime.

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

[My Plugins] - [My Forums]

Posted on
Sun Jul 05, 2020 10:11 am
gmusser offline
Posts: 290
Joined: Feb 12, 2005
Location: New Jersey

Re: How do I calculate elapsed time?

Thanks for clarifying. On the looking at the documentation, I see that the Unix timestamp (seconds elapsed since 1970) is available as the element ".timestamp". That avoids the need to use strptime and strftime to convert to and from strings. The site https://www.programiz.com/python-progra ... p-datetime provides this code fragment:
Code: Select all
from datetime import datetime
now = datetime.now()
timestamp = datetime.timestamp(now)

But when I use that code in my script, Indigo returns the error "type object 'datetime.datetime' has no attribute 'timestamp'". This, even though I just copied and pasted the above code. Here is the full script as it now stands:
Code: Select all
import os
from datetime import datetime

# set up log file name
data_path = os.path.expanduser('~') + "/Documents/BoilerData-TEST.txt"

try:
    # open log file
    with open(data_path, 'a+') as outfile:

        # set Indigo variable to current time
        now = datetime.now()
        timestamp = datetime.timestamp(now)
        indigo.variable.updateValue(79472523, value=unicode(timestamp))
       
        # write the boiler startup time to the log file as mm/dd/yyyy with time as fraction of a day     
        decimal = (now.hour * 3600.0 + now.minute * 60.0 + now.second) / (3600.0*24.0)
        outfile.write((u"{0:%m/%d/%Y}\t{1}\ton\r".format(now, decimal)))

except Exception as err:
    indigo.server.log("boiler monitor error: {0}".format(err))

Posted on
Sun Jul 05, 2020 12:14 pm
DaveL17 offline
User avatar
Posts: 6742
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: How do I calculate elapsed time?

datetime.timestamp() was introduced in Python 3--it's not available in Python 2.7. Be careful when Googling answers to Python questions because this will sting you every time. In my opinion, you don't need the timestamp at all. You can store the start time as a POSIX time just as easily and you'll still be able to do the math you need to do.

Code: Select all
import datetime as dt
from time import sleep

start_time = dt.datetime.now()
indigo.variable.updateValue(1612110734, dt.datetime.strftime(start_time, '%Y-%m-%d %H:%M:%S.%f'))

sleep(5)

stored_time = indigo.variables[1612110734].value
old_time = dt.datetime.strptime(stored_time, '%Y-%m-%d %H:%M:%S.%f')

now = dt.datetime.now()
diff = now - old_time

indigo.server.log(u"{0}".format(diff))

>>> 0:00:05.007182

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

[My Plugins] - [My Forums]

Posted on
Sun Jul 05, 2020 3:49 pm
ELWOOD offline
Posts: 225
Joined: Feb 11, 2007
Location: Ramsey, NJ

Re: How do I calculate elapsed time?

Have you looked at the "Timed Devices" plugin. One of the timer devices "Running Timer" will track on time of any device. I use it to keep track of my HVAC system, The plugin gives total on time for the heating and air-conditioning and I use a short script to calculate total cost per day, week, month and a total for the year.

Elwood

Posted on
Sun Jul 05, 2020 6:56 pm
gmusser offline
Posts: 290
Joined: Feb 12, 2005
Location: New Jersey

Re: How do I calculate elapsed time?

@DaveL17 - thanks so much. With a bit more tweaking, I got the script to work.
@Elwood - I hadn't seen that; will take a look.

Posted on
Sun Jul 05, 2020 7:01 pm
DaveL17 offline
User avatar
Posts: 6742
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: How do I calculate elapsed time?

Glad you found something that works for you.

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