Page 1 of 1

Python script works from command line, but not Indigo

PostPosted: Mon Jan 29, 2018 5:29 pm
by blysik
Hi,

I've got a python cli script for turning my spa on. If I execute it from the command line, it works no problem.

Adding it as a Server side shell script action, I get:

Action Group Spa on
Action Collection Error Script /Users/home/bin/spa_on.py exited abnormally with a return code of: 1


Is there any way to get better debugging on this?

Re: Python script works from command line, but not Indigo

PostPosted: Mon Jan 29, 2018 5:32 pm
by blysik
Here's what running it form the command line looks like:

$ ./spa_on.py
Initializing...
/Library/Python/2.7/site-packages/selenium/webdriver/phantomjs/webdriver.py:49: UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead
warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
Logging in to iAqualink...
Successfully logged into iAqualink.
Hot tub turned on.

Re: Python script works from command line, but not Indigo

PostPosted: Mon Jan 29, 2018 6:11 pm
by jay (support)
What is the first line of the script?

Better yet, if it's not huge just post the full script.

Re: Python script works from command line, but not Indigo

PostPosted: Mon Jan 29, 2018 6:31 pm
by blysik
Code: Select all
#!/usr/bin/python

### AQUALINK LOGIN
### IMPORTANT!
### Set the login information to your iAqualink Zodiac pool systems account here.
AQUA_USERNAME = 'XXXXX'
AQUA_PASSWORD = 'ZZZZZ'

# System
import os
import time
import threading

# Selenium Interactions
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium import common

# Selenium Timing
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# BROWSER INTERACTION
AQUA_URL = 'https://iaqualink.zodiacpoolsystems.com/start/mobile/?actionID=AlzZVnPMfHDU5&lang=en'
AQUA_TOGGLE_ON = 'https://iaqualink.zodiacpoolsystems.com/files/images/aux_0_1.png'
AQUA_TOGGLE_OFF = 'https://iaqualink.zodiacpoolsystems.com/files/images/aux_0_0.png'
AQUA_TOGGLE_ALTERNATE = 'https://iaqualink.zodiacpoolsystems.com/files/images/aux_0_3.png'

def newBrowser():
    new_browser = None

    try:
        new_browser = webdriver.PhantomJS()
        return new_browser

    except:
        print ('CRITICAL ERROR: phantomj found\n'
               'Please download phantomjs')

    finally:
        return new_browser

def openAqua(browser):
    browser.get(AQUA_URL)
    if 'iAquaLink Email Address:' in browser.page_source:
        assert 'Sign In' in browser.page_source
        print ('Logging in to iAqualink...')
        userID = browser.find_element_by_id('userID')
        userPassword = browser.find_element_by_id('userPassword')
        userID.clear()
        userID.send_keys(AQUA_USERNAME)
        userPassword.clear()
        userPassword.send_keys(AQUA_PASSWORD)
        userPassword.send_keys(Keys.RETURN)

        try:
            WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.ID, "spa_pump_state")))
            return browser

        except common.exceptions.TimeoutException:
            print ('CRITICAL: iAqualink login information is incorrect.')
            quit()

# When an event is triggered, check the status of BROWSER, the global browser variable for PhantomJS
# If not logged in, instantiate a new Aqua browser and update BROWSER accordingly.
global BROWSER
print ("Initializing...")
BROWSER = openAqua(newBrowser())
print ("Successfully logged into iAqualink.")

def refreshBROWSER():
    global BROWSER
    BROWSER.refresh()
    if "iAquaLink Email Address:" in BROWSER.page_source:
        print ("Logging into a new BROWSER.")
        BROWSER.quit()
        BROWSER = openAqua(newBrowser())

# BROWSER FUNCTIONALITY

def checkElementToggle(element):
    imgSrc = element.get_attribute("src")
    if imgSrc == AQUA_TOGGLE_ON or imgSrc == AQUA_TOGGLE_ALTERNATE:
        return True
    elif imgSrc == AQUA_TOGGLE_OFF:
        return False
    else:
        print ("Error: Unknown state derived from element " + element.get_attribute("id") + " in checkElementToggle.")

def goToHome(browser=BROWSER):
    if "Spa Mode" not in browser.page_source:
        homeButton = browser.find_element_by_link_text("Home")
        homeButton.click()
    WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.ID, "spa_pump_state")))
    WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.ID, "pool_pump_state")))
    WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.ID, "spa_heater_state")))
    WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.ID, "pool_heater_state")))

def goToDevices(browser=BROWSER):
    if "Jet Pump" not in browser.page_source:
        devicesButton = browser.find_element_by_link_text("Devices")
        devicesButton.click()
    WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.ID, "aux_1")))
    WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.ID, "aux_2")))
    WebDriverWait(browser, 10).until(EC.visibility_of_element_located((By.ID, "aux_3")))


# DEVICE INTERACTIONS
# Returns:
#   0 == No toggle(s) needed
#   1 == Toggle(s) completed
def hotTubOn(browser=BROWSER):
    goToHome(browser)
    spaButton = browser.find_element_by_id("spa_pump_state")
    heatButton = browser.find_element_by_id("spa_heater_state")
    if checkElementToggle(spaButton) is True:
        if checkElementToggle(heatButton) is True:
            return 0
        else:
            heatButton.click()
            print ("Hot tub was already on, but the heater is now on.")
            return 1
    else:
        spaButton.click()
        if checkElementToggle(heatButton) is False:
            heatButton.click()
        print ("Hot tub turned on.")
        return 1

def hotTubOff(browser=BROWSER):
    bubblesOff(browser)
    goToHome(browser)
    spaButton = browser.find_element_by_id("spa_pump_state")
    heatButton = browser.find_element_by_id("spa_heater_state")
    if checkElementToggle(spaButton) is False:
        return 0
    else:
        spaButton.click()
        if checkElementToggle(heatButton) is True:
            heatButton.click()
        print ("Hot tub turned off.")
        return 1

def poolOn(browser=BROWSER):
    hotTubOff(browser)
    goToHome(browser)
    poolButton = browser.find_element_by_id("pool_pump_state")
    if checkElementToggle(poolButton) is True:
        return 0
    else:
        poolButton.click()
        print ("Pool turned on.")
        return 1

def poolOff(browser=BROWSER):
    goToHome(browser)
    poolButton = browser.find_element_by_id("pool_pump_state")
    if checkElementToggle(poolButton) is False:
        return 0
    else:
        poolButton.click()
        print ("Pool turned off.")
        return 1

hotTubOn()

Re: Python script works from command line, but not Indigo

PostPosted: Tue Jan 30, 2018 1:10 pm
by blysik
Turns out that try, except, finally logic was hiding the error. Removing that showed:

Code: Select all
   Script Error                    Exception Traceback (most recent call shown last):

     spa_on.py, line 69, at top level
     spa_on.py, line 34, in newBrowser
     File "/Library/Python/2.7/site-packages/selenium/webdriver/phantomjs/webdriver.py", line 56, in __init__
       self.service.start()
     File "/Library/Python/2.7/site-packages/selenium/webdriver/common/service.py", line 83, in start
       os.path.basename(self.path), self.start_error_message)
WebDriverException: Message: 'phantomjs' executable needs to be in PATH.


So I just had to change the webdriver line like so:

Code: Select all
new_browser = webdriver.PhantomJS('/usr/local/bin/phantomjs')


And now it works.

Re: Python script works from command line, but not Indigo

PostPosted: Tue May 23, 2023 8:48 pm
by hamw
I’m getting an iAqualink. There are a few other users who have posted in other threads here regarding MQTT etc.…

How is your a script-based approach working? Were you able to come up with a plug-in? Or at least a series of executable actions maybe? Will it work with 2022.2?