parnic / node-screenlogic

Pentair ScreenLogic Javascript library using Node.JS
https://www.npmjs.com/package/node-screenlogic
MIT License
52 stars 14 forks source link
automation easytouch node node-js node-module nodejs nodejs-modules pentair pool screenlogic swim swimming swimming-pool

node-screenlogic

This is a Node.JS module for interfacing with Pentair ScreenLogic systems over your local network or remotely through the Pentair dispatcher. Local connections require a Pentair ScreenLogic device on the same network (a network which supports UDP broadcasts).

Tested with a Pentair ScreenLogic system on firmware versions 5.2 Build 736.0 Rel, 5.2 Build 738.0 Rel

See the Wiki for information on migrating from v1 to v2.

Table of Contents:

Usage

See example.ts for an example of interfacing with the library. Broadly, import the library with

import * as Screenlogic from "./index";

Individual named imports can also be used. Then for local connections create a new ScreenLogic unit finder with

let finder = new ScreenLogic.FindUnits();
let localUnit = await finder.searchAsync();
return Promise.resolve(localUnit);

If you prefer to use an event-based approach, you can hook the serverFound event with:

.on('serverFound', function(server) { })
await finder.searchAsync();

and call it via searchAsync(). This performs a UDP broadcast on 255.255.255.255, port 1444, so ensure your network supports UDP broadcasts and the device is on the same subnet.

Alternatively, to find a unit remotely, create a new ScreenLogic remote login with

let gateway = new ScreenLogic.RemoteLogin(systemName);  // systemName in the format "Pentair: xx-xx-xx"
let unit = await gateway.connectAsync();
if (!unit || !unit.gatewayFound || unit.ipAddr === '') {
  logger.error(`Screenlogic: No unit found called ${systemName}`);
  return;
}
await gateway.closeAsync();

and call it via connectAsync(). This opens a TCP connection to screenlogicserver.pentair.com, port 500.

When a local or remote server is found, create and connect to a new UnitConnection with

let client = ScreenLogic.screenlogic;
client.init(systemName, ipAddr, port, password);  // ipAddr and password as strings; port as integer
await client.connectAsync();

where password is the remote login password.

Once you've connected with connectAsync(), there are a number of methods available and corresponding events for when they've completed successfully. See screenlogic API reference.

All communication with a ScreenLogic unit is done via TCP, so responses will come back in the order they were requested.

Notes

Contributions welcome. There are lots of available messages supported by ScreenLogic that the app doesn't support yet, but can be added pretty easily as needed.

Packet format

All ScreenLogic packets are sent with an 8-byte header. The first 2 bytes are a little-endian-encoded sender ID (which is normally specified when making the original request). The second 2 bytes are a little-endian-encoded message ID. The final 4 bytes are a little-endian-encoded length of the data payload on the packet. The data payload is handled per-message.

API Reference

Pull requests to document undocumented properties are most welcome.

FindUnits

constructor()

Examples:

import * as Screenlogic from 'node-screenlogic';
/*or
const ScreenLogic = require('node-screenlogic');
*/
var finder = new ScreenLogic.FindUnits();

search()

Issues one UDP broadcast search for available units. Since this is a stateless UDP query, the connection will not automatically be closed, so you may need to issue another search if the first one doesn't work, if your network connection is not established, etc. There is no automatic timeout built in to this command. This call does not return any found units directly, but does emit the serverFound message which contains each LocalUnit object that is found:

searchAsync(searchTimeMs?)

Issues one UDP broadcast search for available units. This is a stateless UDP query, but the connection will automatically be closed, so you may need to issue another search if the first one doesn't work, if your network connection is not established, etc. There is a 5s timeout built in to this command, and no retry mechanism.

Optionally accepts a number of milliseconds to wait for units; defaults to 5000 if not specified. Returns a LocalUnit[] array with each object containing:

This async call will also emit the serverFound message.

close()

Closes the socket. Only needed for search(). searchAsync() will close the socket itself.

Events

Examples:

let finder = new ScreenLogic.FindUnits();
let localUnit = await finder.searchAsync();
// or hook the event if you don't assign the function to a variable
finder.on('serverFound', function(server) {
  // server object will contain connection information
})

RemoteLogin

constructor(systemName)

Argument is the name of a system to connect to in "Pentair: xx-xx-xx" format.

Example:

let gateway = new ScreenLogic.RemoteLogin(systemName);  // systemName in the format "Pentair: xx-xx-xx"
let unit = await gateway.connectAsync();
if (!unit || !unit.gatewayFound || unit.ipAddr === '') {
  logger.error(`Screenlogic: No unit found called ${systemName}`);
  return;
}
await gateway.closeAsync();
// or use the emit if you don't assign the function to a variable

connectAsync()

Connects to the dispatcher service and searches for the unit passed to its constructor.

closeAsync()

Closes the connection and removes all listeners.

Events

UnitConnection

Module

screenlogic is an exported module that maintains state and connection for a given unit. Parameters are initialized with the init and connections are made with the connectAsync functions.

Examples:

let client = ScreenLogic.screenlogic;
client.init(systemName, unit.ipAddr, unit.port, password);
await client.connectAsync();

init(systemName, address, port, password, senderId?)

Takes the parameters (systemName, address, port, password, senderId?)

systemName is a string. Port is an integer. Address is an IPv4 address of the server as a string. Password is optional; should be the 4-digit password in string form, e.g. '1234'.

senderId can be set once (or it defaults to 0) and will be present as the senderId field on the returned message.

Examples:

client.init('Pentair: 00-00-00', '10.0.0.85', 80, '1234', senderId?);

initUnit(localUnit)

Helper method for init. Takes a LocalUnit remote login object and passes the appropriate values to init.

connectAsync()

Connects to the server after init parameters are set.

Examples:

await client.connectAsync();

closeAsync()

Closes the connection and removes all listeners.

addClientAsync(clientId?, senderid?)

Registers to receive updates from controller when something changes. Takes a random number clientId (if passed, or will be randomly assigned) to identify the client. Resolves/emits the addClient event when the request to add a client is acknowledged. As long as this client is connected, various events will be emitted when something changes on the controller, such as equipmentState or chemicalData.

getVersionAsync(senderId?)

Requests the system version string from the connected unit. Resolves/emits the version event when the response comes back.

pingServerAsync(senderId?)

Sends a ping to the server to keep the connection alive. Resolves/emits the pong event when the response comes back.

reconnectAsync()

Will be automatically called if node-screenlogic detects an error in communications, but can also be called manually to re-establish communications.

removeClientAsync(clientId)

No longer receive update messages from controller. Resolves/emits the removeClient event when the request to remove a client is acknowledged. clientId must match a client previously registered via addClientAsync().

status()

Returns an object with the socket state:

Body

bodies.setCoolSetPointAsync(bodyId, temperature, senderId?)

Sets the cooling setpoint for any body. Emits the coolSetPointChanged event when response is acknowledged. Resolves with BoolData.

Parameters:

bodies.setHeatModeAsync(bodyId, heatMode, senderId?)

Sets the preferred heat mode. See SLSetHeatModeMessage documentation for argument values. Emits the heatModeChanged event when response is acknowledged. Resolves with BoolData.

bodies.setSetPointAsync(bodyId, temperature, senderId?)

Sets the heating setpoint for any body. Emits the setPointChanged event when response is acknowledged. Resolves with BoolData.

Parameters:

Chemistry

chem.getChemHistoryDataAsync(fromTime?, toTime?, senderId?)

Requests chemical history data from the connected unit. This is information about the pH and ORP readings over time and when pH and ORP feeds were turned on and off. fromTime is the time (as a Javascript Date object) that you want to get events from and toTime is the time (as a Javascript Date object) that you want to get events until. If omitted, data will be resolved for the past 24 hours. Emits the getChemHistoryDataPending event when the request to get data is confirmed, then the getChemHistoryData event when the chemical history data is actually ready to be handled. Resolves with SLChemHistory.

chem.getChemicalDataAsync(senderId?)

Requests chemical data from the connected unit (may require an IntelliChem or similar). Emits the chemicalData event when the response comes back. Resolves with SLChemData.

Chlorinator

chlor.getIntellichlorConfigAsync(senderId?)

Requests salt cell status/configuration from the connected unit (requires an IntelliChlor or compatible salt cell). Emits the intellichlorConfig event when the response comes back. Resolves with SLIntellichlorData.

chlor.setIntellichlorIsActiveAsync(isActive, senderId?)

Tells the OCP if a chlorinator is present. isActive is a boolean. Emits the intellichlorIsActive event. Resolves with BoolData.

chlor.setIntellichlorOutputAsync(poolOutput, spaOutput, senderId?)

Sets the salt cell's output levels. See SLSetIntellichlorConfigMessage documentation for argument values. Emits the setIntellichlorConfig event when response is acknowledged. Resolves with BoolData.

Circuit

circuits.sendLightCommandAsync(command, senderId?)

Sends a lighting command. See SLLightControlMessage documentation for argument values. Emits the sentLightCommand event when response is acknowledged. Resolves with BoolData.

EasyTouch/Intellitouch only have a single light group and individual lights cannot be address. Pentair's Intellicenter offers this capability.

circuits.setCircuitAsync(circuitId, nameIndex, circuitFunction, circuitInterface, freeze, colorPos, senderId?)

Parameters:

Sets the configuration for a specific circuit. Emits the circuit event when completed. Resolves with BoolData.

circuits.setCircuitRuntimebyIdAsync(circuitId, runTime, senderId?)

Configures default run-time of a circuit, usually referred to as the 'egg timer'. This also applies to 'run-once' programs as this will set the length of the program. See SLSetCircuitRuntimeById documentation for argument values. Emits the setCircuitRuntimeById event when response is acknowledged. Resolves with BoolData.

circuits.setCircuitStateAsync(circuitId, circuitState, senderId?)

Activates or deactivates a circuit. See SLSetCircuitStateMessage documentation for argument values. Emits the circuitStateChanged event when response is acknowledged. Resolves with BoolData.

Equipment

equipment.cancelDelayAsync(senderId?)

Cancels any delays on the system. Resolves as a BoolData and emits the cancelDelay event when response is acknowledged.

equipment.getCircuitDefinitionsAsync(senderId?)

Returns an array of objects that represent the different circuit functions that a circuit can be assigned. Emits the circuitDefinitions event which resolves to a SLCircuitNamesData object.

equipment.getCircuitNamesAsync(size?, senderId?)

Returns an array of objects with circuit names and IDs. Internally, this calls equipment.getNCircuitNames() for the count of circuits and equipment.getCircuitNames(index, count) to retrieve the array from the server. Emits the circuitNames event which resolves with a SLCircuitNamesData object.

equipment.getControllerConfigAsync(senderId?)

Requests controller configuration from the connected unit. Emits the controllerConfig event when the response comes back. Resolves with EquipmentConfigurationMessage.

equipment.getCustomNamesAsync(senderId?)

Requests all custom names from the OCP. An array of 20 names will be returned, but some OCP's only support 10. Emits the getCustomNames event. Resolves with SLGetCustomNamesData.

equipment.getEquipmentConfigurationAsync(senderId?)

Resolves/emits the equipmentConfiguration event when the response comes back. This is the basic configuration of what equipment is installed on the controller. Resolves with SLEquipmentConfigurationData.

equipment.getEquipmentStateAsync(senderid?)

Emits the equipmentState event when the response comes back. This is the current state of all equipment in the system. Resolves with SLEquipmentStateMessage.

equipment.getHistoryDataAsync(fromTime?, toTime?, senderId?)

Requests history data from the connected unit. This is information like what various temperature sensors (air, water) read over time, changes in heat setpoints, and when various circuits (pool, spa, solar, heater, and lights) were turned on and off. fromTime is the time (as a Javascript Date object) that you want to get events from and toTime is the time (as a Javascript Date object) that you want to get events until. Will default to the last 24 hours if fromTime/toTime are not provided. Resolves/emits the getHistoryDataPending event when the request to get data is confirmed, then the getHistoryData event when the history data is actually ready to be handled. Resolves with SLHistoryData.

equipment.getSystemTimeAsync(senderid?)

Retrieves the current time the system is set to. Emits the getSystemTime event when response is received. Resolves with SLSystemTimeData.

equipment.getWeatherForecastAsync(senderId?)

Requests the system version string from the connected unit. Emits the weatherForecast event when the response comes back. Resolves with SLWeatherForecastData.

equipment.setCustomNameAsync(idx, name, senderId?)

Sets an individual custom name on the OCP. idx is the index of the custom name, name is the custom name to be set, senderId is the optional unique identifier. Emits the setCustomName event. Resolves with BoolData.

equipment.setEquipmentConfigurationAsync(data, senderId?)

This method allows you to set the configuration of the controller. data is in the format of SLEquipmentConfigurationData but will take any individual component, or all components. Emits the setEquipmentConfiguration event which resolves with SLSetEquipmentConfigurationData.

equipment.setSystemTimeAsync(date, adjustForDST, senderid?)

Sets the current date and time of the ScreenLogic system. Resolves/emits the setSystemTime event when request is acknowledged. date must be a Date instance holding the date/time to set, and adjustForDST must be a boolean indicating whether the system should adjust for daylight saving time or not. Resolves with SLSystemTimeData.

Pump

pump.getPumpStatusAsync(pumpId, senderId?)

Gets information about the specified pump (1 based index). See SLPumpStatusData documentation for argument values. Resolves/emits the getPumpStatus event when response is acknowledged.

pump.setPumpSpeedAsync(pumpId, circuitId, speed, isRPMs?, senderId?)

Parameters:

Sets speed (rpm) or flow (gpm) setting for a pump/circuit combination. Emits the setPumpSpeed event when response is acknowledged. Resolves with BoolData.

Schedule

schedule.addNewScheduleEventAsync(scheduleType, senderId?)

Parameters:

Adds a new event to the specified schedule type. Emits either the addNewScheduleEvent, with NumberData, or scheduleChanged event when response is acknowledged (listen for both).

schedule.deleteScheduleEventByIdAsync(scheduleId, senderId?)

Parameters:

Deletes a scheduled event with specified id. Resolves/emits the deleteScheduleEventById, with BoolData, or scheduleChanged event when response is acknowledged (listen for both).

schedule.getScheduleDataAsync(scheduleType, senderId?)

Parameters:

Retrieves a list of schedule events of the specified type. Emits the getScheduleData event when response is acknowledged. Resolves with an SLScheduleData array.

schedule.setScheduleEventByIdAsync(scheduleId, circuitId, startTime, stopTime, dayMask, flags, heatCmd, heatSetPoint, senderId?)

Configures a schedule event. See SLSetScheduleEventById documentation for argument values. Resolves/emits the setScheduleEventById or scheduleChanged event when response is acknowledged (listen for both). Resolves with BoolData.

Events

Properties

All messages

Information about features common to all the below SL Message types.

decodeTime(time)

Interprets a time integer recorded as minutes past midnight and returns the ScreenLogic string representation of it in 24-hour time.

encodeTime(time)

Interprets the string representing 24-hour time and returns an integer of minutes past midnight.

decodeDayMask(mask)

Converts a day mask from, for example, SLGetScheduleData's events[idx].days property into a DAY_VALUES array for ease of use.

encodeDayMask(days)

Converts an array of DAY_VALUES keys (['Mon', 'Tue'], etc.) into a mask used by, for example, SLGetScheduleData's events[idx].days property.

getDayValue(dayName)

Returns the value of a given DAY_VALUES day name.

DAY_VALUES is defined as the following map for simplicity of checking whether a specific day is set in a mask:

const DAY_VALUES = {
  Mon: 0x1,
  Tue: 0x2,
  Wed: 0x4,
  Thu: 0x8,
  Fri: 0x10,
  Sat: 0x20,
  Sun: 0x40,
};

Properties

BoolData

Generic response type that holds the sender id of the request and a boolean value.

Properties

NumberData

Generic response type that holds the sender id of the request and a number value.

Properties

SLAddClient

Passed as an argument to the emitted addClient event.

SLCancelDelay

Passed as an argument to the emitted cancelDelay event.

SLChemData

Passed as an argument to the emitted chemicalData event handler.

Properties

SLCircuitNamesData

Properties

EquipmentConfigurationMessage

Passed as an argument to the emitted controllerConfig event handler.

static isEasyTouch(controllerType)

Returns a bool indicating whether the system is an EasyTouch system or not. (Helper method for interpreting the value in controllerType.)

static isIntelliTouch(controllerType)

Returns a bool indicating whether the system is an IntelliTouch system or not. (Helper method for interpreting the value in controllerType.)

static isEasyTouchLite(controllerType)

Returns a bool indicating whether the system is an EasyTouch Lite system or not. (Helper method for interpreting the value in controllerType and hwType.)

static isDualBody(controllerType)

Returns a bool indicating whether the system is dual-body or not. (Helper method for interpreting the value in controllerType.)

static isChem2(controllerType)

Returns a bool indicating whether the system is a Chem2 system or not. (Helper method for interpreting the value in controllerType and hwType.)

Properties

SLDeleteScheduleEventById

Passed as an argument to the emitted deleteScheduleEventById event. Deletes a scheduled event with specified id.

SLEquipmentConfigurationData

This is largely undocumented at this time, but we are making progress toward figuring it out.

SLGetChemHistoryData

Passed as an argument to the emitted getChemHistoryData event. Contains information about the remote unit's pH and ORP readings over time as well as pH and ORP feed on/off times.

Properties

SLGetCustomNamesData

Passed as an argument to the emitted setCustomNames event.

Properties

SLReceiveGatewayDataMessage

Passed as an argument to the emitted gatewayFound event. Contains information about the remote unit's status and access properties.

Properties

Note: these properties are available on the object acquired by calling .get() on the given message.

SLHistoryData

Passed as an argument to the emitted getHistoryData event. Contains information about the remote unit's temperature and circuit on/off times over time.

Properties

SLPumpStatusData

Passed as an argument to the emitted getPumpStatus event. Gets information about the specified pump.

Properties

Return Values

SLScheduleData

Passed as an argument to the emitted getScheduleData event. Retrieves a list of schedule events of the specified type, either 0 for regular events or 1 for one-time events.

Properties

SLSetEquipmentConfigurationData

Properties

SLSystemTimeData

Contains information about the system's current time and date. Passed as a return object/ an argument to the emitted getSystemTimeAsync event.

Properties

SLLightControlMessage

Passed as an argument to sendLightCommandAsync.

Properties

SLPingServerMessage

Passed as an argument to the emitted pong event handler.

SLEquipmentStateMessage

Passed as an argument to the emitted equipmentState event handler.

isDeviceReady()

Returns a bool indicating whether the device is in a normal operating state.

isDeviceSync()

Returns a bool.

isDeviceServiceMode()

Returns a bool indicating whether the device is in service mode or not.

isSpaActive()

Returns a bool indicating whether the spa is currently active or not.

isPoolActive()

Returns a bool indicating whether the pool is currently active or not.

Properties

SLRemoveClient

Passed as an argument to the emitted removeClient event.

SLIntellichlorData

Passed as an argument to the emitted intellichlorConfig event handler.

Properties

SLSetCircuitRuntimeById

Passed as an argument to the emitted setCircuitRuntimebyId event. Configures default run-time of a circuit, usually referred to as the 'egg timer'. This also applies to 'run-once' programs as this will set the length of the program.

Properties

SLSetCircuitStateMessage

Passed as an argument to the emitted circuitStateChanged event.

Properties

SLSetHeatModeMessage

Passed as an argument, returned to the emitted heatModeChanged event. Valid values depend on installed equipment.

Properties

SLSetHeatSetPointMessage

Passed as an argument to the emitted setPointChanged event. Receives a BoolData object.

SLSetIntellichlorConfigMessage

Passed as an argument to the emitted setIntellichlorConfig event.

Properties

SLSetScheduleEventById

Passed as an argument to the emitted setScheduleEventById event. Configures an event with properties as described below.

Properties

SLSetSystemTime

Passed as an argument to the emitted setSystemTime event.

SLVersionMessage

Passed as an argument to the emitted version event handler.

Properties

SLWeatherForecastData

Properties