Package: screenlogicpy
screenlogicpyscreenlogicpyis an interface for Pentair ScreenLogic connected pool controllers over IP via python using asyncio.InstallationThescreenlogicpypackage can be installed from PyPI usingpip.$pipinstallscreenlogicpyLibrary usageChanged in v0.5.0: The screenlogicpy library has moved over to using asyncio for all network I/O. Relevant methods now require theasync/awaitsyntax.New in v0.8.0: Support for Python 3.8 and 3.9 is being phased out across future releases. Version 0.8.x will be the last versions to support Python 3.8.New in v0.9.0: Support for Python 3.8 has been removed. Support for Python 3.9 is being phased out across future releases. Version 0.9.x will be the last versions to support Python 3.9.New in v0.10.0: Support for Python 3.9 has been deprecated. Additionally, support for Python 3.10 is being phased out across future releases. Versions 0.10.x will be the last versions to support Python 3.10.TheScreenLogicGatewayclass is the primary interface.fromscreenlogicpyimportScreenLogicGatewaygateway=ScreenLogicGateway()Changed in v0.5.0: Instantiating the gateway no longer automatically connects to the protocol adapter or performs an initial update.Changed in v0.7.0: Passing adapter connection info when instantiating the gateway is deprecated and will be removed in a future release. Connection info should be passed toasync_connect()instead.Changed in v0.8.0: Support for passing connection info to gateway constructor is fully deprecated and has been removed. Ability to specify client id used for push subscriptions, and to specify maximum number of times to retry a request has replaced it.Connecting to a ScreenLogic Protocol AdapterOnce instantiated, useasync_connect()to connect and login to the ScreenLogic protocol adapter, and gather the pool configuration.If disconnected, this method may be called without any parameters to reconnect with the previous connection info, or with new parameters to connect to a different host.awaitgateway.async_connect("192.168.x.x")New in v0.5.0.Changed in v0.7.0:async_connect()now accepts adapter connection info. This supports handling ip changes to the protocol adapter.Changed in v0.10.0:async_connect()no longer returns aboolindicating success. If the action is unsuccessful, an exception indicating the failure mode is raised.Polling the pool stateOnce connected, all available state information can be polled with theasync_update()coroutine.awaitgateway.async_update()This update consists of sending requests for:Current pool statusDetailed information foreachconfigured pumpDetailed pool chemistry informationStatus and settings for any configured salt chlorine generatorsThe controller's current date and time, and auto DST settingsWarning:This method is not rate-limited. The calling application is responsible for maintaining reasonable intervals between updates. The ScreenLogic protocol adapter may respond with an error message if too many requests are made too quickly.Changed in v0.5.0: This method is now an async coroutine and no longer disconnects from the protocol adapter after polling the data.Changed in v0.10.0: Now includes polling for information regarding the controller's date and time settings.Subscribing to pool state updatesThe preferred method for retrieving updated pool data is to subscribe to updates pushed to the gateway by the ScreenLogic system. This reduces network traffic compared to polling, and improves responsiveness to state changes.To enable push updates, subscribe to a particular message code usinggateway.async_subscribe_client(callback, message_code), passing a callback method to be called when that message is received, and themessage codeto subscribe to. This function returns a callback that can be called to unsubscribe that particular subscription.The gateway'sClientManagerwill automatically handle subscribing and unsubscribing as a client to the ScreenLogic protocol adapter upon the first callback subscription and last unsub respectively.fromscreenlogicpy.constimportCODEdefstatus_updated():# Do something with the updated dataunsub_method=awaitgateway.async_subscribe_client(status_updated,CODE.STATUS_CHANGED)Example in./examples/async_client.pyMultiple callbacks can be subscribed to a single message code. Additionally, a single global callback may be subscribed to multiple message codes.Note:Each combination of callback and code will result in a separate unique unsub callback. The calling application is responsible for managing and unsubing all subscribed callbacks as needed.Pushed dataWhile the ScreenLogic system does support some push updates, not all state information for all equipment available via push. The two main state update messages that can be subscribed to are:General status update containingAir and water temperature and heater statesBasic status indicators such as Freeze mode and active delaysCircuit statesBasic chemistry informationIntelliChem controller status update containingDetailed chemistry informationThe status of any pumps or salt chlorine generators is not included in any push updates. To supplement this, the different data sets can now be requested individually.New in v0.7.0.Polling specific dataTo update a specific set of data, you can use any of the following methods:# Updates the basic status of the pool controller. *Same as pushed dataawaitgateway.async_get_status()# Updates the state of all configured pumpsawaitgateway.async_get_pumps()# Updates the detailed chemistry information from a IntelliChem controller. *Same as pushed dataawaitgateway.async_get_chemistry()# Updates the state of any configured salt chlorine generatorsawaitgateway.async_get_scg()# Updates the current pool controller time and Daylight Saving Time adjustments settingawaitgateway.async_get_datetime()Push subscriptions and polling of all or specific data can be used on their own or at the same time.Warning:Some expected data keys may not be present until a full update has been performed. It is recommended that an initial fullasync_update()be preformed to ensure the gateway's datadictis fully primed.New in v0.7.0.Using the dataTheScreenLogicGatewayclass caches all data from the ScreenLogic protocol adapter as a singledictobject for continued reference by the consuming application. This includes any data processed via push or polling. The consuming application may get this data at anytime with theget_data()method.data=gateway.get_data()get_data()now supports specifying a path directly to the data desired. A path can be any length. By default, if the data path is not found,get_data()will returnNone, similar todict.get(). Alternativelystrict=Truekeyword argument can be added to force theScreenLogicGatewayto raise aKeyErrorexception if the path is not found.The majority of data points normally available to the end-user via the official apps are presented asdictobjects containing "name" and "value" keys/pairs. Additional keys may be present depending on the type of data.For example, let's consider the following scenario:gateway._data={"controller":{"sensor":{"air_temperature":{"name":"Air Temperature","value":57,"unit":"Â°F","device_type":"temperature","state_type":"measurement",},}}}data_path=("controller","sensor","air_temperature")temperature_sensor=gateway.get_data(*data_path)Here,temperature_sensorwould be adictof all key/value pairs under the "air_temperature" key.TheScreenLogicGatewayalso provides shortcut methodsget_name()andget_value()to get the "name" or "value" values respectively from the specified data path.# sensor_value = 57sensor_value=gateway.get_value(*data_path)# sensor_name = "Air Temperature"sensor_name=gateway.get_name(*data_path)To get other values directly, useget_data()with the full key path:# sensor_unit = "Â°F"sensor_unit=gateway.get_data("controller","sensor","air_temperature","unit")New in v0.9.0.DisconnectingWhen done, useasync_disconnect()to unsubscribe from push updates and close the connection to the protocol adapter.awaitgateway.async_disconnect()New in v0.5.0.Gateway DiscoveryThediscoverymodule'sasync_discover()function can be used to get a list of all discovered ScreenLogic protocol adapters on the local network. Each protocol adapter is represented as adictobject that can then be directly used to instanciate aScreenLogicGatewayclass.Note:Gateway discovery is limited to discovering ScreenLogic protocol adapters on the same subnet.hosts=awaitdiscovery.async_discover()Changed in v0.5.0: This method is now an async coroutine.Example in./examples/async_discovery.pyBasic Implementation ExamplefromscreenlogicpyimportScreenLogicGateway,discoveryhosts=awaitdiscovery.async_discover()iflen(hosts)>0:gateway=ScreenLogicGateway(**hosts[0])ifawaitgateway.async_connect():awaitgateway.async_update()awaitgateway.async_disconnect()data=gateway.get_data()else:print("No gateways found")Full example in./examples/gateway.pyPerforming actionsThe following actions can be performed with methods on theScreenLogicGatewayobject:Set a specific circuit to on or offSet a heating mode for a specific body of water (spa/pool)Set a target heating temperature for a specific body of water (spa/pool)Select various color-enabled lighting optionsSet chlorinator output levels and super-chlorination valuesSetting IntelliChem chemistry valuesSetting the pool controller's system date and timeIf the action is unsuccessful, an exception will be raised indicating the failure mode.Note:The methods do not confirm the requested action is now in effect on the pool controller.Changed in v0.10.0: Actions no longer return aboolindicating success. If the action is unsuccessful, an exception is raised indicating the failure mode.Turning a circuit ON or OFFA circuit can be requested to be turned on or off with theasync_set_circuit()method.async_set_circuittakes two required arguments,circuitIDwhich is the id number of the circuit as anint, andcircuitStatewhich represents the desired new state of the circuit, as anint. SeeStatebelow.awaitgateway.async_set_circuit(circuitID,circuitState)Changed in v0.5.0: This method is now an async coroutine.Changed in v0.10.0: No longer returns aboolindicating success. If the action is unsuccessful, an exception is raised indicating the failure mode.Setting a heating modeThe desired heating mode can be set per body of water (pool or spa) withasync_set_heat_mode().async_set_heat_modetakes two required arguments,bodyas anintrepresenting thebody of water, andmodeas anintof the desiredheating mode.awaitgateway.async_set_heat_mode(body,mode)Changed in v0.5.0: This method is now an async coroutine.Changed in v0.10.0: No longer returns aboolindicating success. If the action is unsuccessful, an exception is raised indicating the failure mode.Setting a target temperatureThe target heating temperature can be set per body of water (pool or spa) withasync_set_heat_temp().async_set_heat_temptakes two required arguments,bodyas anintrepresenting thebody of water, andtempas anintof the desired target temperature.awaitgateway.async_set_heat_temp(body,temp)Changed in v0.5.0: This method is now an async coroutine.Changed in v0.10.0: No longer returns aboolindicating success. If the action is unsuccessful, an exception is raised indicating the failure mode.Setting light colors or showsColors or color-shows can be set for compatible color-enable lighting withasync_set_color_lights().async_set_color_lightstakes one required argument,light_commandas anintrepresenting the desiredcommand/show/colorawaitgateway.async_set_color_lights(light_command)Changed in v0.5.0: This method is now an async coroutine.Changed in v0.10.0: No longer returns aboolindicating success. If the action is unsuccessful, an exception is raised indicating the failure mode.Setting chlorinator output levels, super chlorinationChlorinator output levels can be set withasync_set_scg_config().async_set_scg_configtakes up to four keyword arguments,pool_setpoint,spa_setpoint,super_chlorinate, andsuper_chlor_timer. All areintwithsuper_chlorinaterepresenting an ON or OFF state. SeeStatebelow.awaitgateway.async_set_scg_config(pool_setpoint=pool_output,spa_setpoint=spa_output)New in v0.5.0.Changed in v0.10.0:Addedsuper_chlorinate, andsuper_chlor_timerparameters to control super chlorination functions.Now accepts keyword arguments only. This allows the caller to specify only the value(s) they want to update, retaining all other existing values.No longer returns aboolindicating success. If the action is unsuccessful, an exception is raised indicating the failure mode.Setting IntelliChem chemistry valuesChemistry values used in the IntelliChem system can be set withasync_set_chem_data().async_set_chem_datatakes up to six keyword arguments,ph_setpoint,orp_setpoint,calcium_hardness,total_alkalinity,cyanuric_acid, andsalt_tds_ppm.ph_setpointis afloatand the rest areint.awaitgateway.async_set_chem_data(ph_setpoint=ph,orp_setpoint=orp,calcium_hardness=cal,total_alkalinity=alk,cyanuric_acid=cya,salt_tds_ppm=salt)New in v0.6.0.Changed in v0.10.0:Addedcalcium_hardness,total_alkalinity,cyanuric_acid, andsalt_tds_ppmparameters.Now accepts keyword arguments only. This allows the caller to specify only the value(s) they want to update, retaining all other existing values.No longer returns aboolindicating success. If the action is unsuccessful, an exception is raised indicating the failure mode.Setting controller date and timeThe system date and time in the pool controller can be set withasync_set_date_time(). Method takes up to two keyword arguments,date_timeas a pythondatetimeobject andauto_dstas anintrepresenting an ON or OFF state. SeeStatebelow.awaitgateway.async_set_date_time(date_time=datetime.now(),auto_dst=set_dst)New in v0.10.0.Handling unsolicited messagesWith the move to asyncio,screenlogicpycan now handle unsolicited messages from the ScreenLogic protocol adapter (messages that are not a direct response to a request from screenlogicpy).
To do so, you need to tell theScreenLogicGatewaywhat message code to listen for and what to do when it is received. You can register a handler withregister_message_handler(). This method takes the message code to wait for, the async coroutine to schedule when a message is received, and any parameters you want to pass to your handler. Your handler coroutine needs to accept the bytes message itself, and any additional parameters you specified.Notes:Currently theScreenLogicGatewaymust be connected to the protocol adapter before registering a handler.Registering a handler in this way does not subscribe the gateway to push state updates from the ScreenLogic system.Example:WEATHER_UPDATE_CODE=9806WEATHER_REQUEST_CODE=9807asyncdefweather_request(message:bytes,data:dict):result=awaitgateway.async_send_message(WEATHER_REQUEST_CODE)decode_weather(result,data)print(data)gateway.register_async_message_handler(WEATHER_UPDATE_CODE,weather_request,data)Remove the handler with:gateway.remove_async_message_handler(WEATHER_UPDATE_CODE)Example in./examples/async_listen.pyNew in v0.7.0.Debug InformationA debug function is available in theScreenLogicGatewayclass:get_debug. This will return a dict with the raw bytes for the last response for each request the gateway performs during an update. This can be useful for debugging the actual responses from the protocol adapter.Note:Currently only includes polled data.last_responses=gateway.get_debug()New in v0.5.5.Command lineScreenlogicpy can also be used via the command line. The primary design is for the command line output to be consumed/parsed by other applications and thus by default is not very human-readable. For more human-friendly output, specify the-v, --verboseoption.Basic usage$screenlogicpyWithout any arguments, screenlogicpy will attempt to discover a gateway on the LAN, and display a human readable "dashboard" of the current state of their pool.$screenlogicpy
Discovered'Pentair: XX-XX-XX'at192.168.XX.XX:80
EasyTouch28**************************
Pooltemperatureislast58Â°F
PoolHeatSetPoint:86Â°F
PoolHeat:Off
PoolHeatMode:Off
--------------------------
Spatemperatureislast97Â°F
SpaHeatSetPoint:97Â°F
SpaHeat:Off
SpaHeatMode:Heater
--------------------------
**************************IDSTATENAME
--------------------------500OffSpa501OffWaterfall502OffPoolLight503OffSpaLight504OffCleaner505OnPoolLow506OffYardLight507OffAux6508OffPoolHigh510OffFeature1511OffFeature2512OffFeature3513OffFeature4514OffFeature5515OffFeature6516OffFeature7517OffFeature8519OffAuxEx
**************************Argument usagescreenlogicpy [-h] [-v] [-i IP] [-p PORT] {discover,export,get,set} ...Optional arguments-h, --helpArgparsehelpcommand. Available at any stage of positional commands.-v, --verboseTells screenlogicpy to be a little more verbose in it's output. Friendlier for humans.-i, --ipscreenlogicpy-ixxx.xxx.xxx.xxxSpecify the IP address of the ScreenLogic protocol adapter to connect to.Note:If the IP address is not specified, screenlogicpy will attempt to discover ScreenLogic protocol adapters on the local network, and connect to the first one that responds. This is generally fine if you only have one ScreenLogic protocol adapter. Discovery is limited to finding protocol adapters on the same subnet as the host runningscreenlogicpy.-p, --portscreenlogicpy-ixxx.xxx.xxx.xxx-pxxSpecify the port of the ScreenLogic protocol adapter to connect to. Needs to be used in conjunction with-i, --ipoption.Positional argumentsdiscoverscreenlogicpydiscoverAttempts to discover ScreenLogic protocol adapters on the local network via UDP broadcast. Returns[ip address]:[port]of each discovered ScreenLogic protocol adapter, one per line.Note:Discovery is limited to finding protocol adapters on the same subnet as the host runningscreenlogicpy.exportscreenlogicpyexportExports a response collection saved as a JSON file that can be used for debugging/testing purposes. A response collection includes each controller response with both the originalbytesdata along with a decodeddictof that data, and all data merged into a completedictas it would be in theScreenLogicGateway. JSON file is named for "slpy[libversion]_[adapter-firmware]_[controller-model]_[equipment-flags].json".getscreenlogicpyget{circuit,c,heat-mode,hm,heat-temp,ht,heat-state,hs,current-temp,t,json,j}The get option is use with additional options to return the current state of the additional option specified.getcircuit, cscreenlogicpygetcircuitCIRCUIT_NUMReturns 1 for on and 0 for offgetheat-mode, hmscreenlogicpygetheat-modeBODYReturns the current heating mode for the specified body of water.Note:BODYcan be anintorstringrepresenting thebody of water.getheat-temp, htscreenlogicpygetheat-tempBODYReturns the current target heating temperature for the specified body of water.Note:BODYcan be anintorstringrepresenting thebody of water.getheat-state, hsscreenlogicpygetheat-stateBODYReturns the current state of the heater for the specified body of water. The current state will match the heat mode when heating is active, otherwise will be 0 (off).Note:BODYcan be anintorstringrepresenting thebody of water.getcurrent-temp, tscreenlogicpygetcurrent-tempBODYReturns the current temperature for the specified body of water. This is actually the last-known temperature from when that body of water was active (Pool or Spa)Note:BODYcan be anintorstringrepresenting thebody of water.getdate-time, dtscreenlogicpygetdate-time[--formatFORMAT]Returns the pool controller's internal date and time in ISO 8601 format. Use the optional argument to specify a format string.get date-time--format, -fSpecify a format string for the returneddatetimeto be formatted with.getauto-dst, dstscreenlogicpygetauto-dstReturns the value of the pool controller's "Adjust for Daylight Savings Time" setting.getjson, jscreenlogicpygetjsonReturns a json dump of all data cached in the datadict.setscreenlogicpyset{circuit,c,color-lights,cl,heat-mode,hm,heat-temp,ht,salt-generator,scg,super-chlorinate,sc,chemistry-setpoint,cs,chemistry-value,cv,date-time,dt}...Allsetcommands work like their correspondinggetcommands, but take an additional argument or arguments for the desired setting.setcircuit, cscreenlogicpysetcircuitCIRCUIT_NUMSTATESets the specified circuit to the specified circuit state.Note:STATEcan be anintorstringrepresenting the desiredstate.setheat-mode, hmscreenlogicpysetheat-modeBODYMODESets the desired heating mode for the specified body of water.Note:BODYcan be anintorstringrepresenting thebody of water.MODEcan be anintorstringrepresenting the desiredheat modesetheat-temp, htscreenlogicpysetheat-tempBODYTEMPSets the desired target heating temperature for the specified body of water.Note:BODYcan be anintorstringrepresenting thebody of water.TEMPis anintrepresenting the desired target temperature.setcolor-lights, clscreenlogicpysetcolor-lights[colormode]Sets a color mode for all color-capable lights configured on the pool controller.Note:[color mode]can be either theintorstringrepresentation of acolor mode.New in v0.3.0.setsalt-generator, scgscreenlogicpysetsalt-generator[--poolPOOL_PCT][--spaSPA_PCT]Sets the chlorinator output levels for the pool and/or spa via two optional arguments:set salt-generator-p, --poolSpecify the output level for the pool as anintbetween0-100.set salt-generator-s, --spaSpecify the output level for the spa as anintbetween0-100.Note:Pentair treats spa output level as a percentage of the pool's output level.New in v0.5.0.Changed in v0.10.0:Pool and spa arguments are now optional. Users may specify one or the other, or both.setsuper-chlorinate, scscreenlogicpysetsuper-chlorinate[--stateON_OFF][--timeHOURS]Enables or disables super chlorination for the specified amount of time via two option arguments:set super-chlorinate-s, --stateSpecify a new state for super chlorination as anintorstringrepresenting the desiredstate.set super-chlorinate-t, --timeSpecify the number of hours to run super chlorination for as anintbetween1-72.New in v0.10.0.setchemistry-setpoint, csscreenlogicpysetchemistry-setpoint[--phPH][--orpORP]Sets the pH and/or ORP set points for the IntelliChem system via two optional arguments:set chemistry-setpoint-p, --phSpecify the target pH value for Intellichem to maintain as afloatbetween7.2-7.6.set chemistry-setpoint-o, --orpSpecify the target ORP value for Intellichem to maintain as anintbetween400-800.Note:chemistry-setpointreplaces the previous chem-data.New in v0.10.0.setchemistry-value, cvscreenlogicpysetchemistry-value[--calcium-hardnessCALCIUM][--total-alkalinityTA][--cyanuric-acidCYA][--total-dissolved-solidsTDS]Sets values used in the calculation of Saturation Index in the IntelliChem system via four optional arguments:set chemistry-value-ch, --calcium-hardnessSpecify the calcium hardness value for Saturation Index calculation as anintbetween25-800.set chemistry-value-ta, --total-alkalinitySpecify the total alkalinity value for Saturation Index calculation as anintbetween25-800.set chemistry-value-cya, --cyanuric-acidSpecify the cyanuric acid value for Saturation Index calculation as anintbetween0-201.set chemistry-value-tds, --total-dissolved-solidsSpecify the total dissolved solids value for Saturation Index calculation as anintbetween500-6500.New in v0.10.0.setdate-time, dtscreenlogicpysetdate-time[--date-timeISO_8601][--auto-dstON_OFF]Sets the date and time on the pool controller (used in schedules), and the "Adjust for DST" setting via optional arguments:set date-time-dt, --date-timeSpecify a date and time with an ISO 8601 formattedstring.Note:stringmust not contain spaces. Use the 'T' character between the date and the time (2023-11-12T16:24:00).set date-time-dst, --auto-dstEnable or disable automatic adjustment of system time for Daylight Saving Time as anintorstringrepresenting the desiredstate.New in v0.10.0.ReferenceStateintstringName0offOff1onOnBodyintstringName0poolPool1spaSpaHeat ModesintstringNameDescription0offOffHeating is off1solarSolarHeating will use solar heat to achieve the desired temperature set point.2solar_preferredSolar PreferredHeating will use solar if available to achieve the desired temperature set point, otherwise it will use the heater.3heaterHeaterHeating will use the heater to achieve the desired temperature set point.4dont_changeDon't ChangeDon't change the heating mode based on circuit or function changes.Color ModesintstringNameDescription0all_offAll OffTurns all light circuits off.1all_onAll OnTurns all light circuits on to their last mode.2color_setColor SetSets light circuits to their pre-set colors as set in the pool controller.3color_syncColor SyncSynchronize all IntelliBrite, SAm, SAL, or FIBERworks color changing lights and synchronize their colors.4color_swimColor SwimCycles through white, magenta, blue and green colors. (Emulates Pentair SAm color changing light.)5partyPartyRapid color changing building the energy and excitement.6romanceRomanceSlow color transitions creating a mesmerizing and calming effect.7caribbeanCaribbeanTransitions between a variety of blues and greens.8americanAmericanPatriotic red, white and blue transitions.9sunsetSunsetDramatic transitions of orange, red and magenta tones.10royalRoyalRicher, deeper, color tones.11saveSave ColorSave the exact colors that are being displayed.12recallRecall ColorRecall the saved colors.13blueBlueFixed color: Blue14greenGreenFixed color: Green15redRedFixed color: Red16whiteWhiteFixed color: White17magentaMagentaFixed color: Magenta18thumperThumperToggles the solenoid thumper on MagicStream laminars.19next_modeNext ModeCycle to the next color mode.20resetResetReset light modes.21holdHoldHold light transitions.Supported Subscribable Messagesscreenlogicpyincludes functionality to automatically decode these messages and update its data accordingly. Other message codes can be subscribed to, but the consuming application will need to implement any processing of the incoming message.fromscreenlogicpy.constimportCODEMessage CodeImported CONSTDescription12500CODE.STATUS_CHANGEDSent when basic status changes. Air/water temp, heater state, circuit state, basic chemistry (if available).12504CODE.COLOR_UPDATESent repeatedly during a color lights color mode transition.12505CODE.CHEMISTRY_CHANGEDSent when a change occurs to the state of an attached IntelliChem controller.AcknowledgementsInspired byhttps://github.com/keithpjolley/soipipThe protocol and codes are documented fairly well here:https://github.com/ceisenach/screenlogic_over_ip