Conversion of complicated AS to Python

Posted on
Thu Oct 11, 2018 6:23 pm
SMUSEBY offline
Posts: 511
Joined: Sep 16, 2009
Location: California

Conversion of complicated AS to Python

I tried to learn Python on-line, and was a miserable failure. I have several AS's that I need to convert, and by submitting a complicated one, I'm hoping I can use the Python version to educate me so I can work on others.
My script performs the following:
1) turns on my espresso machine
2) calculates time of day when machine will be ready
3) when warmed up, it turns on two lamp to indicate ready
4) it calculates an Auto Off time based on the cost of electricity (from variables)
A lot of the code is dealing with time arithmetic - e.g., adding 15 minutes to 50 minutes, results in 1 Hr and 5 Min. I'm guessing there is an easier way to do that.
I attempted to assist by documenting the script with comments.
Thank you, in advance, for helping the code challenged user.
Bob
Code: Select all
set theHour to (do shell script "date +%H") as integer
set theMinute to (do shell script "date +%M") as integer
tell application "IndigoServer"
   --gather variables
   disable time date action "espMachOff"
   set hseVacant to the value of variable "hseVacant" as boolean
   set espMachHot to the value of variable "espMachHot" as string
   set espMachWarmupTime to the value of variable "espMachWarmupTime"
   set coldSeason to the value of variable "coldSeason" as boolean
   set espMachAvailH to the value of variable "espMachAvailH"
   set espMachAvailM to the value of variable "espMachAvailM"
   set espMachAvailH_PEAK to the value of variable "espMachAvailH_PEAK"
   set espMachAvailM_PEAK to the value of variable "espMachAvailM_PEAK"
   set espMachON_AM to the value of variable "espMachON_AM" as boolean
   set pgeSched to the value of variable "pgeSched"
   set espMachOffHour to the value of variable "espMachOffHour"
   set espMachOffMin to the value of variable "espMachOffMin"
   if not hseVacant then
      --turn on appliance if the house is vacant
      turn on "kEspressoMachine"
      log "Espresso Machine Turned On" using type "espMachineON.scpt"
      log theHour using type "Hour on - espMachineON.scpt"
      log theMinute using type "Minute on - espMachineON.scpt"
      
      --calculate time when machine will be ready:   
      set hotMin to theMinute + espMachWarmupTime
      set hotHour to theHour
      if hotMin ≥ 60 then
         set hotMin to hotMin - 60
         set hotHour to theHour + 1
         if hotHour > 23 then
            set hotHour to hotHour - 24
         end if
      end if
      if hotHour < 10 then
         set hotHour to hotHour as string
         set hotHour to "0" & hotHour
      else
         set hotHour to hotHour as string
      end if
      if hotMin < 10 then
         set hotMin to hotMin as string
         set hotMin to "0" & hotMin
      else
         set hotMin to hotMin as string
      end if
      log hotHour using type "esp mach ready as of (hours)"
      log hotMin using type "esp mach ready as of (minutes)"
      --modify variables      
      set the value of variable "espMachHot" to "ON - will be ready as of " & hotHour & ":" & hotMin as string
      set the value of variable "espTime" to the value of variable "espMachHot" --used by ctrl page
      --light up various keypad buttons
      send insteon group instnTurnOn using index 148 --kKpl#3 btn#8
      --Using light bulbs to indicate status, turn off "nOffLamp", kTell in warmup mode (white)
      execute group "espMachWarmingUP lamp"
      turn off "nOffRmDeskLamp"
      
      --calculate time when machine will be turned off:   
      --delay ((espMachWarmupTime * 60) - 60)
      if not espMachON_AM then
         if pgeSched ≠ "$.33" then
            --for when PGE is selling off peak power
            set offHour to hotHour + espMachAvailH
            set offMin to hotMin + espMachAvailM
            if offMin ≥ 60 then
               set offMin to offMin - 60
               set offHour to offHour + 1
               if offMin < 10 then
                  set offMin to "0" & offMin as string
               end if
            end if
            --set offMin to offMin as string
            --for when PGE is selling peak power
         else if pgeSched = "$.33" then
            set offHour to hotHour + espMachAvailH_PEAK
            set offMin to hotMin + espMachAvailM_PEAK
            
            if offMin ≥ 60 then
               set offMin to offMin - 60
               set offHour to offHour + 1
               if offMin < 10 then
                  set offMin to "0" & offMin as string
               end if
            end if
            set offMin to offMin as string
         end if
         if offHour > 24 then
            set offHour to offHour - 24
         end if
         if offHour < 10 then
            set offHour to offHour as string
            set offHour to "0" & offHour
         else
            set offHour to offHour as string
            log offHour using type "esp mach will turn off (hours)"
            log offMin using type "esp mach will turn off (minutes)"
         end if
      else
         --special case - turns off in morning at 11am
         set offHour to "11" as string
         set offMin to "00" as string
      end if
      
      execute group "kEspMachREADY" in (espMachWarmupTime * 60)
      set the value of variable "espMachOff" to offHour & ":" & offMin as string
      log offHour using type "Off H, espMachineON.scpt"
      log offMin using type "Off M, espMachineON.scpt"
      
      enable time date action "espMachOff"
      set offSec to "00" as string
      set offTime to offHour & ":" & offMin & ":" & offSec
      set the value of variable "espMachOffHour" to offHour as number
      set the value of variable "espMachOffMin" to offMin
      log offTime
      set the time trigger type of time date action "espMachOff" to absolute
      set the date trigger type of time date action "espMachOff" to everyDay
      set the absolute trigger time of time date action "espMachOff" to date offTime
      --get properties of time date action "espMachOff"
   end if
end tell

Posted on
Thu Oct 11, 2018 9:05 pm
jay (support) offline
Site Admin
User avatar
Posts: 18212
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Conversion of complicated AS to Python

I started doing a conversion, then I realized that you were adjusting a schedule at the end of the script, which isn't supported in Python yet. However, I suspect there's a way to do this without doing that, but I have a couple of questions:

1) When exactly is this script run? Once a day? What time?
2) What are the exact actions that the schedule named "espMachOff" perform?
3) It appears that if espMachOn_AM is "false", then the schedule always turns off at 11:00am, but the name of the variable implies that when in this config it turns on in PM, which means it's on all night long? Please clarify that logic.

There may be more questions, but those should be a good start. The time calculations are significantly easier in Python. To whit, this part of the AppleScript:

Code: Select all
      --calculate time when machine will be ready:   
      set hotMin to theMinute + espMachWarmupTime
      set hotHour to theHour
      if hotMin ≥ 60 then
         set hotMin to hotMin - 60
         set hotHour to theHour + 1
         if hotHour > 23 then
            set hotHour to hotHour - 24
         end if
      end if
      if hotHour < 10 then
         set hotHour to hotHour as string
         set hotHour to "0" & hotHour
      else
         set hotHour to hotHour as string
      end if
      if hotMin < 10 then
         set hotMin to hotMin as string
         set hotMin to "0" & hotMin
      else
         set hotMin to hotMin as string
      end if


turns into this:

Code: Select all
willBeHotAt = datetime.today() + timedelta(minutes=espMachWarmupTime)


and this:

Code: Select all
      if not espMachON_AM then
         if pgeSched ≠ "$.33" then
            --for when PGE is selling off peak power
            set offHour to hotHour + espMachAvailH
            set offMin to hotMin + espMachAvailM
            if offMin ≥ 60 then
               set offMin to offMin - 60
               set offHour to offHour + 1
               if offMin < 10 then
                  set offMin to "0" & offMin as string
               end if
            end if
            --set offMin to offMin as string
            --for when PGE is selling peak power
         else if pgeSched = "$.33" then
            set offHour to hotHour + espMachAvailH_PEAK
            set offMin to hotMin + espMachAvailM_PEAK
           
            if offMin ≥ 60 then
               set offMin to offMin - 60
               set offHour to offHour + 1
               if offMin < 10 then
                  set offMin to "0" & offMin as string
               end if
            end if
            set offMin to offMin as string
         end if
         if offHour > 24 then
            set offHour to offHour - 24
         end if
         if offHour < 10 then
            set offHour to offHour as string
            set offHour to "0" & offHour
         else
            set offHour to offHour as string
            log offHour using type "esp mach will turn off (hours)"
            log offMin using type "esp mach will turn off (minutes)"
         end if
      else
         --special case - turns off in morning at 11am
         set offHour to "11" as string
         set offMin to "00" as string
      end if


turns into this (assuming the AM/PM thing above is true):

Code: Select all
    if not espMachON_AM:
        if pgeSched != "$.33":
            turnOffTime = willBeHotAt + timedelta(hours=espMachAvailH, minutes=espMachAvailM)
        else:
            turnOffTime = willBeHotAt + timedelta(hours=espMachAvailH_PEAK, minutes=espMachAvailM_PEAK)
    else:
        # special case - turns off tomorrow morning at 11am (assumption here about am/pm)
        tomorrow = datetime.today() + timedelta(days=1)
        turnOffTime = datetime(tomorrow.year, tomorrow.month, tomorrow.day, 11, 0, 0)

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Thu Oct 11, 2018 9:30 pm
SMUSEBY offline
Posts: 511
Joined: Sep 16, 2009
Location: California

Re: Conversion of complicated AS to Python

1) When exactly is this script run? Once a day? What time?
Script runs when I push a button with a keypad or with iOS. I also turn the machine on every morning with a simple schedule at 630 and it turns of at 9am.

2) What are the exact actions that the schedule named "espMachOff" perform?
Below is the script for Off:
Code: Select all
tell application "IndigoServer"
   turn off "kEspressoMachine"
   -- toggle "kTelLamp"
   set tod to the value of variable "isDaylight" as boolean
   set espMachOff to the value of variable "espMachOff"
   set espTime to the value of variable "espTime"
   set ambLt to the value of variable "zzambientLight" as integer
   set espTime to the value of variable "espTime" as string
   if ambLt > 400 then --checks ambient light value (from Phidgets), and proceeds
      delay 1
      turn off "kTelLamp"
      delay 1
      turn off "nOffRmDeskLamp"
   else
      turn on "kTelLamp"
      turn on "nOffRmDeskLamp"
      execute group "0 hue Normal kTelLamp"
   end if
end tell
tell current application
   set espMachOff to time string of (current date)
end tell
tell application "IndigoServer"
   set AppleScript's text item delimiters to ":"
   set espOffMM to word 2 of espMachOff as integer
   set espOffHH to word 1 of espMachOff as integer
   if espOffMM < 10 then
      set espOffMM to "0" & espOffMM as string
   end if
   set espTime to espOffHH & espOffMM as string
   set AppleScript's text item delimiters to ""
end tell
tell application "IndigoServer"
   --send insteon group instnTurnOff using index 58
   send insteon group instnTurnOff using index 148
   set the value of variable "espMachON_AM" to "false"
   set the value of variable "espTime" to "OFF - as of " & espTime
   disable time date action "espMachOff"
   if tod and ambLt > 700 then
      turn off "kStoveSinks(load)"
   end if
end tell


3) It appears that if espMachOn_AM is "false", then the schedule always turns off at 11:00am, but the name of the variable implies that when in this config it turns on in PM, which means it's on all night long? Please clarify that logic.
Schedule turns on Espresso Machine (if house is occupied) at 630am (when rates are low), and off at 9am. I think this variable is a leftover from earlier logic and can be ignored. This is the only reference I can find to it in the event log:
2018-10-08 03:43:01.123 SQL Logger Error exception trying to create table variable_history_656408003 ("espMachON_AM").
No clue what that means, but it looks like detritus.

This is really nice of you to do this. I 'learned' AS this way, and stumbled around; hopefully I can do the same with Python. What you've done so far is certainly a lot neater.
Bob

Posted on
Fri Oct 12, 2018 10:59 am
jay (support) offline
Site Admin
User avatar
Posts: 18212
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Conversion of complicated AS to Python

Hmmm. Bob, I think we need to step back here, ignore the scripts (which seem to perhaps have stuff that is no longer relevant, etc) and just outline EXACTLY what you want this solution to do without any technical details of how something is done. You have a bit of a start in your first post, but there are a lot of details missing (some of the questions I asked helped, but there's a lot still missing). So let's try to flesh that out.

For example, one scenario (called a use case) might be:

Scheduled Coffee Run
  1. At X in the morning, I want my coffee maker to come on.
  2. It takes Y minutes to warm up. When it's warmed up, I want light A and B to come on.
  3. I calculate when to automatically turn it off by using the following formula: [DESCRIBE FORMULA]
  4. At the calculated time, I want these things to be done: [LIST STUFF TO DO]

Another one might be:

On-demand Coffee Run
[here you do the same thing - out line actions that you take, what you want to happen, and the details around that]

When I say detail, I'm not talking technical implementation details, but the detail in english of what the use case should do/address.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Thu Oct 25, 2018 7:00 pm
SMUSEBY offline
Posts: 511
Joined: Sep 16, 2009
Location: California

Re: Conversion of complicated AS to Python

Sorry for the delay in responding - I was out-of-town.
I like the way you think - hopefully, and can respond in a useful way:

Scheduled Coffee Run
- At 0635 (M-F), 0700 (SS), IF house occupied=true AND bypass variable=false, turn on coffee machine & turn on lamp
- It takes 35 minutes to warm up. When it's warmed up, I want light A to turn red (Hue) - I do this by executing an action group..
- At 0930, coffee machine turns off (done now with a schedule - it would be neater to be part of this script - and would demonstrate how to create an ad hoc schedule)

On demand Coffee Run
- Turn on coffee machine (test that house is vacant as I don't trust Insteon) and lamp
- At machine ready time (35 minutes), turn lamp red (Hue) by executing an action group
- Calculate Off time (would like to use variables for ready time, peak time, off peak time)
- if Rate Schedule is not Peak Rate, turn off in 120 minutes from ready time (note - I change the rate variable with schedules)
- if Rate Schedule is Peak Rate, turn off in 60 minutes from ready time
- at Off time,
- turn off Coffee Machine
- turn off lamp if it is light outside (I test a Phidgets ambient light level)
- if it is dark outside, I turn the lamp back to white from red

I think that's it. I picked this script for its complexity, hopefully finding models for other, less complicated scripts. But to be honest, there will be other questions.
Thank you again for your assistance.
Bob

Posted on
Tue Oct 30, 2018 6:05 pm
jay (support) offline
Site Admin
User avatar
Posts: 18212
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Conversion of complicated AS to Python

Honestly I wouldn't attempt this whole thing in a script because the script would become quite cumbersome and hard to maintain (IMO), much as your AppleScript has become. Rather, I'd implement much of the logic in Indigo-native objects (Timers, Schedules, Triggers, Action Groups) and only use scripts where necessary.

Here's the parts I would create for these two scenarios:

Code: Select all
On Demand Coffee Auto Off (Timers & Pesters plugin, Timer device)
   Initial amount: 160 minutes

Coffee Maker Ready (Action Group)
   Turn on light A to Red

Start Coffee Maker (Action Group)
   turn on coffee maker
   turn on lamp
   execute action Coffee Maker Ready (with a delay of 0:35:00)

M-F Coffee (Schedule)
   at 6:35am
   conditions
      house_occupied = true
      bypass_variable = false
   actions
      execute action Start Coffee Maker
      turn off coffee maker (with a delay of 2:55:00)

S-S Coffee (Schedule)
   at 7:00am
   conditions
      house_occupied = true
      bypass_variable = false (not sure if you want this one)
   actions
      execute action Start Coffee Maker
      turn off coffee maker (with a delay of 2:30:00)

Auto Off On Demand Coffee (Trigger)
   Type: Timers and Pesters Event
   Event: Timer Expired
   Timer: On Demand Coffee Auto Off
   actions
      turn off coffee maker
      execute script (check Phidgets device and do whatever)

On Demand Coffee Run (Action Group)
   execute action Start Coffee Maker
   execute action Coffee Maker Ready (with a delay of 0:35:00)
   execute script (see script #2 below)


Script #1:

Code: Select all
# Script #1 - checks phidgets device for light and does the right things
# Not sure how you check the phidgets, so you'll have to fill in that logic here
is_dark = True # you need to set is_dark appropriately here
if is_dark:
    indigo.actionGroup.execute(123) # ID of Coffee Maker Ready action group
else:
    indigo.device.turnOff(456) # ID of device to turn off if it's light outside


Script #2:

Code: Select all
# Script #2 - sets the timer to the appropriate run time then starts it
#
# Get the rate variable and the auto off timer
rate_schedule = indigo.variables[123] # ID of Peak Rate variable
auto_off_timer_id = 456 # ID of "On Demand Coffee Auto Off" Timer
# Default the auto-off to 120 minutes
minutes_to_off = 120
# But if it's peak rate, make it 60 minutes
if rate_schedule.value == "Peak Rate":
    minutes_to_off = 60
# Set the timer value
tId = "com.perceptiveautomation.indigoplugin.timersandpesters"
timerPlugin = indigo.server.getPlugin(tId)
if timerPlugin.isEnabled():
    timerPlugin.executeAction(
        "setTimerStartValue",
        deviceId=auto_off_timer_id,
        props={'amount':str(minutes_to_off), 'amountType':'minutes'}
    )
    # Start the timer
    timerPlugin.executeAction("startTimer", deviceId=auto_off_timer_id)


Not tested, but it should be quite close.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Tue Oct 30, 2018 6:09 pm
SMUSEBY offline
Posts: 511
Joined: Sep 16, 2009
Location: California

Re: Conversion of complicated AS to Python

I now have some homework. I hope to learn a lot from the scripts you wrote for me.
Thank you,
Bob

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 4 guests