Code Monkey home page Code Monkey logo

node-screenlogic's Introduction

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:

  • address - ip address string
  • type - integer
  • port - integer, the port to connect to
  • gatewayType - integer
  • gatewaySubtype - integer
  • gatewayName - the gateway/unit name as a string

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:

  • address - ip address string
  • type - integer
  • port - integer, the port to connect to
  • gatewayType - integer
  • gatewaySubtype - integer
  • gatewayName - the gateway/unit name as a string

This async call will also emit the serverFound message.

close()

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

Events

  • close - Indicates that close() has been called on the finder.
  • error - Indicates that an unhandled error was caught (such as the connection timing out).
  • serverFound - Indicates that a ScreenLogic unit has been found. Event handler receives a UnitConnection object. The async call is a wrapper for this event.

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

  • close - Indicates that the connection to the remote login server has been closed. Event handler receives a bool indicating whether there was a transmission error.
  • end - Indicates the socket has terminated.
  • error - Indicates that an unhandled error was caught (such as the connection timing out).
  • timeout - Indicates the socket timed out.
  • clientError - Indicates an error with the client on the other end of the socket.
  • gatewayFound - Indicates that the search for the named unit has completed (may or may not be successful). Event handler receives a SLReceiveGatewayDataMessage argument. The async function is a promise that wraps this event.

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:

  • destroyed - boolean indicating if the socket has been destroyed
  • connecting - boolean indicating if the socket is in a connecting state
  • timeout - optional boolean indicating if the socket timed out
  • readyState - string

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:

  • bodyId - integer indicating the type of body to set the setpoint of. The pool is body 0 and the spa is body 1.
  • temperature - integer indicating the desired setpoint. This is presumably in whatever units your system is set to (celsius or fahrenheit).

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:

  • bodyId - integer indicating the type of body to set the setpoint of. The pool is body 0 and the spa is body 1.
  • temperature - integer indicating the desired setpoint. This is presumably in whatever units your system is set to (celsius or fahrenheit).

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:

  • circuitId - 1 based index of circuit id's
  • nameIndex - 1 based index of the name id (built-in or custom)
  • circuitFunction - Number from getCircuitDefinitionsAsync
  • circuitInterface - 0 = pool; 1 = spa; 2 = features; 4 = lights; 5 = hide
  • freeze - boolean. Turn this circuit on with freeze protection.
  • colorPos - Number. Only applicable for Intellibrite.

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:

  • pumpId - id of pump to get information about, first pump is 0
  • circuitId - index of circuit for which to change the set point (id of the pump as returned by SLPumpStatusData)
  • speed - the value for which to set the pump/circuit combo
  • isRPMs - optional (will be inferred). boolean, true for RPMs, false for GPMs

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:

  • scheduleType - 0 indicates recurring scheduled events, 1 indicates a run-once event

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:

  • scheduleType - 0 indicates recurring scheduled events, 1 indicates a run-once event

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:

  • scheduleType - 0 indicates recurring scheduled events, 1 indicates a run-once event

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

  • addClient - Indicates that a response to addClientAsync() has been received. Event handler receives a SLAddClient object.
  • addNewScheduleEvent - Indicates that a response to addNewScheduleEventAsync() has been received which contains the created scheduleId to be used later for setting up the properties. Event handler receives a NumberData object.
  • badParameter - Indicates that a bad parameter has been supplied to a function. This can be triggered, for example, by sending the wrong controller ID to a set function.
  • cancelDelay - Indicates that a response to cancelDelayAsync() has been received. Event handler receives a BoolData.
  • chemicalData - Indicates that a response to getChemicalDataAsync() has been received. Event handler receives a SLChemData object.
  • circuitStateChanged - Indicates that a response to setCircuitStateAsync() has been received. Event handler receives a SLSetCircuitStateMessage object.
  • close - Indicates that the connection to the unit has been closed. Event handler receives a bool indicating whether there was a transmission error.
  • controllerConfig - Indicates that a response to getControllerConfigAsync() has been received. Event handler receives a EquipmentConfigurationMessage object.
  • coolSetPointChanged - Indicates that a response to setCoolSetPointAsync() has been received. Event handler receives a BoolData object.
  • deleteScheduleById - Indicates that a response to deleteScheduleByIdAsync() has been received. Event handler receives a SLDeleteScheduleEventById object.
  • error - Indicates that an unhandled error was caught (such as the connection timing out)
  • equipmentConfiguration - Indicates a response to getEquipmentConfigurationAsync(). Receives a SLEquipmentConfigurationData object.
  • equipmentState - Indicates that a response to getEquipmentStateAsync() has been received. Event handler receives a SLEquipmentStateMessage object.
  • getChemHistoryData - Indicates that chemical history data for the requested timeframe is ready. Event handler receives a SLGetChemHistoryData object.
  • getChemHistoryDataPending - Indicates that the getChemHistoryDataAsync() request has been received and is being processed.
  • getHistoryData - Indicates that history data for the requested timeframe is ready. Event handler receives a SLHistoryData object.
  • getHistoryDataPending - Indicates that the getHistoryDataAsync() request has been received and is being processed.
  • getPumpStatus - Indicates that a response to getPumpStatusAsync() has been received. Event handler receives a SLPumpStatusData object.
  • getScheduleData - Indicates that a response to getScheduleDataAsync() has been received. Event handler receives a SLGetScheduleData object.
  • getSystemTime - Indicates that a response to getSystemTimeAsync() has been received. Event handler receives a SLSystemTimeData object.
  • heatModeChanged - Indicates that a response to setHeatModeAsync() has been received. Event handler receives a SLSetHeatModeMessage object.
  • intellichlorConfig - Indicates that a response to getIntellichlorConfigAsync() has been received. Event handler receives a SLIntellichlorConfigMessage object.
  • loggedIn - Indicates that a connection to the server has been established and the login process completed. get methods can be called once this event has been emitted.
  • loginFailed - Indicates that a remote login attempt via supplying a system address and password to UnitConnection has failed likely due to the incorrect password being used.
  • pong - Indicates that a response to pingServerAsync() has been received. Event handler receives a SLPingServerMessage object.
  • removeClient - Indicates that a response to removeClientAsync() has been received. Event handler receives a SLRemoveClient object.
  • scheduleChanged - Indicates that a response to adding, deleting, or setting a schedule has been received. Event handler receives nothing. This seems to be arbitrarily returned sometimes instead of a normal ack by the system.
  • sentLightCommand - Indicates that a response to sendLightCommandAsync() has been received. Event handler receives a SLLightControlMessage object.
  • setCircuitRuntimeById - Indicates that a response to setCircuitRuntimeByIdAsync() has been received. Event handler receives a SLSetCircuitRuntimeById object.
  • setEquipmentConfiguration - Indicates that the last call to setEquipmentConfigurationAsync() has been applied. Event handler receives a SLSetEquipmentConfigurationData object.
  • setEquipmentConfigurationAck - Indicates that the request to setEquipmentConfigurationAsync() has been received. Event handler receives a BoolData object.
  • setIntellichlorConfig - Indicates that a response to setIntellichlorOutputAsync() has been received. Event handler receives a SLSetIntellichlorConfigMessage object.
  • setPumpSpeed - Indicates that a response to setPumpFlowAsync() has been received. Event handler receives a BoolData object.
  • setPointChanged - Indicates that a response to setSetPointAsync() has been received. Event handler receives a SLSetHeatSetPointMessage object.
  • setScheduleEventById - Indicates that a response to setScheduleEventByIdAsync() has been received. Event handler receives a SLSetScheduleEventById object.
  • setSystemTime - Indicates that a response to setSystemTimeAsync() has been received. Event handler receives a BoolData object if the request was valid, or null/rejected promise if the request was invalid (input parameters were not of the required types).
  • unknownCommand - Indicates that an unknown command was issued to ScreenLogic (should not be possible to trigger when using the supplied UnitConnection methods).
  • version - Indicates that a response to getVersionAsync() has been received. Event handler receives a SLVersionMessage object.

Properties

  • address - string representing the IPv4 address of the found server
  • type - integer representing the type of server found (will always be 2)
  • port - short representing the port to use for TCP connections to this server
  • gatewayType - byte
  • gatewaySubtype - byte
  • gatewayName - string representing the server's name. Will be in the format Pentair: xx-xx-xx

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

  • senderId - an integer matching whatever was passed as the senderId argument when making the initial request (default 0)
  • action - an integer indicating the ScreenLogic ID for this message

BoolData

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

Properties

  • senderId - the sender id from the matching request
  • val - boolean value

NumberData

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

Properties

  • senderId - the sender id from the matching request
  • val - number value

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

  • isValid - boolean indicating whether we got a valid response back or not
  • pH - float indicating the current pH level
  • orp - short indicating the current ORP level
  • pHSetPoint - float indicating the desired pH level
  • orpSetPoint - short indicating the desired ORP level
  • pHTankLevel - byte indicating how full the pH tank is. I believe this operates on a 0-6 scale
  • orpTankLevel - byte indicating how full the ORP tank is
  • saturation - float indicating water balance/LSI saturation
  • calcium - short indicating the calcium level (manually set)
  • cyanuricAcid - short indicating the CYA level (manually set)
  • alkalinity - short indicating the alkalinity level (manually set)
  • saltPPM - integer representing the salt level in parts-per-million
  • temperature - byte indicating the current water temperature
  • corrosive - boolean indicating whether the water balance is corrosive or not
  • scaling - boolean indicating whether the water balance is scaling or not
  • error - boolean indicating whether there's currently an error in the chem system or not
  • balance - bitmask containing the composite data that is broken out to corrosive, scaling, and error - generally you should prefer to use those properties instead

SLCircuitNamesData

Properties

  • circuits - an array of circuit ids to names
    • id - number indicating the id of the circuit
    • circuitName - string indicating the circuit's name

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

  • controllerId - integer indicating the id of the controller
  • minSetPoint - array (size 2) indicating the minimum setpoint available for the pool (index 0) or spa (index 1)
  • maxSetPoint - array (size 2) indicating the maximum setpoint available for the pool (index 0) or spa (index 1)
  • degC - boolean indicating whether the system is using the centigrade scale for temperatures or not
  • controllerType - byte that can be passed to static methods to interpret what type of controller this is
  • circuitCount - integer indicating the size of the circuitArray
  • circuitArray - array holding circuit data
    • circuitId - number
    • name - string
    • nameIndex - number
    • function - number
    • interface - number
    • freeze - number
    • colorSet - number
    • colorPos - number
    • colorStagger - number
    • deviceId - number
    • eggTimer - number
  • hwType - byte passed to static methods to determine more info about the hardware
  • controllerData - byte
  • equipment - object containing booleans that provide additional data about available equipment
    • POOL_SOLARPRESENT - boolean indicating if solar is present
    • POOL_SOLARHEATPUMP - boolean indicating if a solar heat pump is present
    • POOL_CHLORPRESENT - boolean indicating if a chlorinator is present
    • POOL_IBRITEPRESENT - boolean indicating if IntelliBrite is present
    • POOL_IFLOWPRESENT0 - boolean indicating if IntelliFlow pumps are present
    • POOL_IFLOWPRESENT1 - boolean indicating if IntelliFlow pumps are present
    • POOL_IFLOWPRESENT2 - boolean indicating if IntelliFlow pumps are present
    • POOL_IFLOWPRESENT3 - boolean indicating if IntelliFlow pumps are present
    • POOL_IFLOWPRESENT4 - boolean indicating if IntelliFlow pumps are present
    • POOL_IFLOWPRESENT5 - boolean indicating if IntelliFlow pumps are present
    • POOL_IFLOWPRESENT6 - boolean indicating if IntelliFlow pumps are present
    • POOL_IFLOWPRESENT7 - boolean indicating if IntelliFlow pumps are present
    • POOL_NO_SPECIAL_LIGHTS - boolean indicating if there are no special lights present
    • POOL_HEATPUMPHASCOOL - boolean indicating if the heat pump has a cooling feature
    • POOL_MAGICSTREAMPRESENT - boolean indicating if MagicStream deck jets are present
    • POOL_ICHEMPRESENT - boolean indicating if an IntelliChem is present
  • genCircuitName - string indicating the circuit name
  • interfaceTabFlags - integer
  • colorCount - integer indicating the size of the colorArray array
  • colorArray - array holding light color information
    • name - string indicating the light name
    • color - object containing color data
      • r - byte indicating red value from 0-255
      • g - byte indicating green value from 0-255
      • b - byte indicating blue value from 0-255
  • pumpCircCount - integer indicating the size of the pumpCircArray array
  • pumpCircArray - array of numbers indicating ids of pump circuits
  • showAlarms - integer

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.

  • controllerType - byte that can be passed to EquipmentConfigurationMessage static methods to interpret what type of controller this is
  • hwType - byte passed to EquipmentConfigurationMessage static methods to determine more info about the hardware
  • expansionsCount - number
  • version - number
  • pumps - Pump[]
    • id - number
    • type - number
    • pentairType - PumpTypes
    • name - string
    • address - number
    • circuits - PumpCircuit[]
    • primingSpeed - number
    • primingTime - number
    • minSpeed - number
    • maxSpeed - number
    • speedStepSize - number
    • backgroundCircuit - number
    • filterSize - number
    • turnovers - number
    • manualFilterGPM - number
    • minFlow - number
    • maxFlow - number
    • flowStepSize - number
    • maxSystemTime - number
    • maxPressureIncrease - number
    • backwashFlow - number
    • backwashTime - number
    • rinseTime - number
    • vacuumFlow - number
    • vacuumTime - number
  • heaterConfig - HeaterConfig
    • body1SolarPresent - boolean
    • body2SolarPresent - boolean
    • thermaFloCoolPresent - boolean
    • solarHeatPumpPresent - boolean
    • thermaFloPresent - boolean
    • units - number
  • valves - Valves[]
    • loadCenterIndex - number
    • valveIndex - number
    • valveName - string
    • loadCenterName - string
    • deviceId - number
    • sCircuit - string
  • delays - Delays
    • poolPumpOnDuringHeaterCooldown - boolean
    • spaPumpOnDuringHeaterCooldown - boolean
    • pumpOffDuringValveAction - boolean
  • misc - Misc
    • intelliChem - boolean
    • manualHeat - boolean
  • remotes - SLRemoteData
    • fourButton - number[]
    • tenButton - number[][]
    • quickTouch - number[]
  • highSpeedCircuits - number[]
  • lights - Lights
    • allOnAllOff - number[]
  • spaFlow - SpaFlow
    • isActive - boolean
    • pumpId - number
    • stepSize - number
  • numPumps - number
  • rawData - rawData
    • versionData - number[]
    • highSpeedCircuitData - number[]
    • valveData - number[]
    • remoteData - number[]
    • heaterConfigData - number[]
    • delayData - number[]
    • macroData - number[]
    • miscData - number[]
    • lightData - number[]
    • pumpData - number[]
    • sgData - number[]
    • spaFlowData - number[]

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

  • phPoints - array of objects containing the pH reading over time. Each object contains a time key containing a Javascript Date object, and a pH key containing the pH reading as a float.
  • orpPoints - array of objects containing the ORP reading over time. Each object contains a time key containing a Javascript Date object, and an orp key containing the ORP reading as an integer.
  • phRuns - array of objects containing the pH feed on/off times. Each object contains an on key containing a Javascript Date object for when the feed turned on, and an off key containing a Javascript Date object for when the feed turned off.
  • orpRuns - array of objects containing the ORP feed on/off times. Each object contains an on key containing a Javascript Date object for when the feed turned on, and an off key containing a Javascript Date object for when the feed turned off.

SLGetCustomNamesData

Passed as an argument to the emitted setCustomNames event.

Properties

  • names - array of strings containing all custom names

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.

  • gatewayFound - boolean indicating whether a unit was found
  • licenseOK - boolean indicating if the license is valid (I've never seen this be false)
  • ipAddr - string containing the ipv4 address to remotely connect to this unit
  • port - number containing the port to connect to the unit
  • portOpen - boolean indicating whether or not the port is open and able to be connected to
  • relayOn - boolean indicating whether the relay is on (unsure what exactly this indicates; it's always been false in my tests)

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

  • airTemps - array of objects containing the air temperature over time. Each object contains a time key containing a Javascript Date object, and a temp key containing the temperature as an integer.
  • poolTemps - array of objects containing the pool temperature over time. Each object contains a time key containing a Javascript Date object, and a temp key containing the temperature as an integer.
  • poolSetPointTemps - array of objects containing the pool setpoint over time. Each object contains a time key containing a Javascript Date object, and a temp key containing the temperature as an integer.
  • spaTemps - array of objects containing the spa temperature over time. Each object contains a time key containing a Javascript Date object, and a temp key containing the temperature as an integer.
  • spaSetPointTemps - array of objects containing the spa setpoint over time. Each object contains a time key containing a Javascript Date object, and a temp key containing the temperature as an integer.
  • poolRuns - array of objects containing the pool on/off times over time. Each object contains an on key containing a Javascript Date object for when the circuit turned on, and an off key containing a Javascript Date object for when the circuit turned off.
  • spaRuns - array of objects containing the spa on/off times over time. Each object contains an on key containing a Javascript Date object for when the circuit turned on, and an off key containing a Javascript Date object for when the circuit turned off.
  • solarRuns - array of objects containing the solar on/off times over time. Each object contains an on key containing a Javascript Date object for when the circuit turned on, and an off key containing a Javascript Date object for when the circuit turned off.
  • heaterRuns - array of objects containing the heater on/off times over time. Each object contains an on key containing a Javascript Date object for when the circuit turned on, and an off key containing a Javascript Date object for when the circuit turned off.
  • lightRuns - array of objects containing the light on/off times over time. Each object contains an on key containing a Javascript Date object for when the circuit turned on, and an off key containing a Javascript Date object for when the circuit turned off.

SLPumpStatusData

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

Properties

  • pumpId - id of pump to get information about, first pump is 1

Return Values

  • isRunning - boolean that says if pump is running
  • pumpType - 0 if not installed or one of the IntelliFlo constants:
    • PumpTypes.PUMP_TYPE_INTELLIFLOVF
    • PumpTypes.PUMP_TYPE_INTELLIFLOVS
    • PumpTypes.PUMP_TYPE_INTELLIFLOVSF
  • pumpWatts - current Watts usage of the pump
  • pumpRPMs - current RPMs of the pump
  • pumpGPMs - current GPMs of the pump
  • pumpCircuits - Array of 8 items each containing
    • circuitId - Circuit Id (CircuitId matched data returned by EquipmentConfigurationMessage's getCircuitByDeviceIdAsync())
    • speed - the set point for this pump/circuit combo (in either RPMs or GPMs depending on the value of isRPMs)
    • isRPMs - boolean indicating if the set point is in RPMs (false means it's in GPMs)
  • pumpUnknown1 - unknown data; always 0
  • pumpUnknown2 - unknown data; always 255

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

  • data - array of schedule datum
    • scheduleId - the associated scheduleId
    • circuitId - the circuit this schedule affects
    • startTime - the start time of the event, specified as a string in 24-hour time, so, for example, 6:00AM would be '0600' (see conversion functions)
    • stopTime - the stop time of the event, specified as a string in 24-hour time, so, for example, 6:00AM would be '0600' (see conversion functions)
    • dayMask - 7-bit mask that determines which days the schedule is active for, MSB is always 0, valid numbers 1-127 (see conversion functions)
    • flags
      • bit 0 is the schedule type, if 0 then regular event, if 1 its a run-once
      • bit 1 indicates whether heat setPoint should be changed
    • heatCmd - integer indicating the desired heater mode. Valid values are:
      • HeatModes.HEAT_MODE_OFF
      • HeatModes.HEAT_MODE_SOLAR
      • HeatModes.HEAT_MODE_SOLARPREFERRED
      • HeatModes.HEAT_MODE_HEATPUMP
      • HeatModes.HEAT_MODE_DONTCHANGE
    • heatSetPoint - the temperature set point if heat is to be changed (ignored if bit 1 of flags is 0)
    • days - which days this schedule is active for; this is just the dayMask property run through decodeDayMask)` for convenience

SLSetEquipmentConfigurationData

Properties

  • pumps - Pump[]
    • id - number
    • type - number
    • pentairType - PumpTypes
    • name - string
    • address - number
    • circuits - PumpCircuit[]
    • primingSpeed - number
    • primingTime - number
    • minSpeed - number
    • maxSpeed - number
    • speedStepSize - number
    • backgroundCircuit - number
    • filterSize - number
    • turnovers - number
    • manualFilterGPM - number
    • minFlow - number
    • maxFlow - number
    • flowStepSize - number
    • maxSystemTime - number
    • maxPressureIncrease - number
    • backwashFlow - number
    • backwashTime - number
    • rinseTime - number
    • vacuumFlow - number
    • vacuumTime - number
  • heaterConfig - HeaterConfig
    • body1SolarPresent - boolean
    • body2SolarPresent - boolean
    • thermaFloCoolPresent - boolean
    • solarHeatPumpPresent - boolean
    • thermaFloPresent - boolean
    • units - number
  • valves - Valves[]
    • loadCenterIndex - number
    • valveIndex - number
    • valveName - string
    • loadCenterName - string
    • deviceId - number
    • sCircuit - string
  • delays - Delays
    • poolPumpOnDuringHeaterCooldown - boolean
    • spaPumpOnDuringHeaterCooldown - boolean
    • pumpOffDuringValveAction - boolean
  • misc - Misc
    • intelliChem - boolean
    • manualHeat - boolean
  • remotes - SLRemoteData
    • fourButton - number[]
    • tenButton - number[][]
    • quickTouch - number[]
  • highSpeedCircuits - number[]
  • lights - Lights
    • allOnAllOff - number[]
  • numPumps - number

SLSystemTimeData

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

Properties

  • date - Date instance representing the current system datetime (preferred, the other properties are derived from this one and provided for backward compatibility purposes)
  • year - short representing current system year
  • month - short representing current system month (where 1 is January, 2 is February, etc.)
  • dayOfWeek - short representing current system day of the week (where 1 is Sunday and 7 is Saturday)
  • day - short representing current system day of the month
  • hour - short representing current system hour (24-hour time where 0 is midnight, 13 is 1PM, etc.)
  • minute - short representing current system minute
  • second - short representing current system second
  • millisecond - short representing current system millisecond
  • adjustForDST - bool indicating whether the system should adjust for daylight saving time or not

SLLightControlMessage

Passed as an argument to sentLightCommandAsync.

Properties

  • controllerId - integer indicating the ID of the controller to send this command to.
    • Note that while SLControllerConfig includes a controllerId, this ID, in my experience, should always be 0.
  • command - integer indicating which command to send to the lights. Valid values are:
    • LightCommands.LIGHT_CMD_LIGHTS_OFF
    • LightCommands.LIGHT_CMD_LIGHTS_ON
    • LightCommands.LIGHT_CMD_COLOR_SET
    • LightCommands.LIGHT_CMD_COLOR_SYNC
    • LightCommands.LIGHT_CMD_COLOR_SWIM
    • LightCommands.LIGHT_CMD_COLOR_MODE_PARTY
    • LightCommands.LIGHT_CMD_COLOR_MODE_ROMANCE
    • LightCommands.LIGHT_CMD_COLOR_MODE_CARIBBEAN
    • LightCommands.LIGHT_CMD_COLOR_MODE_AMERICAN
    • LightCommands.LIGHT_CMD_COLOR_MODE_SUNSET
    • LightCommands.LIGHT_CMD_COLOR_MODE_ROYAL
    • LightCommands.LIGHT_CMD_COLOR_SET_SAVE
    • LightCommands.LIGHT_CMD_COLOR_SET_RECALL
    • LightCommands.LIGHT_CMD_COLOR_BLUE
    • LightCommands.LIGHT_CMD_COLOR_GREEN
    • LightCommands.LIGHT_CMD_COLOR_RED
    • LightCommands.LIGHT_CMD_COLOR_WHITE
    • LightCommands.LIGHT_CMD_COLOR_PURPLE

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

  • ok - can be interpreted with isDevice... methods.
  • freezeMode - byte representing whether the device is in freeze mode or not.
  • remotes - byte
  • poolDelay - byte
  • spaDelay - byte
  • cleanerDelay - byte
  • airTemp - integer representing the current temperature (check controller config to see if it's in celsius or fahrenheit)
  • currentTemp - array of size 0-2 indicating current temperature of each body as an integer (pool: 0, spa: 1) (check controller config to see if it's in celsius or fahrenheit)
  • heatStatus - array of size 0-2 indicating whether heat is active or not for each body as an integer (pool: 0, spa: 1)
  • setPoint - array of size 0-2 holding the heating set point for each body as an integer (pool: 0, spa: 1) (check controller config to see if it's in celsius or fahrenheit)
  • coolSetPoint - array of size 0-2 holding the cooling set point for each body as an integer (pool: 0, spa: 1; the spa seems to always track air temperature for this, however) (check controller config to see if it's in celsius or fahrenheit)
  • heatMode - array of size 0-2 indicating whether heating is enabled or not for each body as an integer (pool: 0, spa: 1)
  • circuitArray - array holding all circuits in the system
    • id - integer representing the circuit's ID (spa is 500, pool is 505)
    • state - integer indicating whether the circuit is on or not (0/1)
    • colorSet - byte
    • colorPos - byte
    • colorStagger - byte
    • delay - byte
  • pH - float indicating the current pH level (e.g.: 7.62)
  • orp - integer indicating the current ORP value if available (e.g.: 650)
  • saturation - float indicating the water balance/saturation level (e.g.: -0.13)
  • saltPPM - integer indicating the salt level in parts-per-million (e.g.: 3000)
  • pHTank - integer indicating the fill level of the pH tank (e.g.: 4)
  • orpTank - integer indicating the fill level of the ORP tank
  • alarms - integer indicating how many alarms are currently active

SLRemoveClient

Passed as an argument to the emitted removeClient event.

SLIntellichlorData

Passed as an argument to the emitted intellichlorConfig event handler.

Properties

  • installed - boolean indicating whether a salt cell is installed or not
  • status - integer bitmask
  • poolSetpoint - integer indicating the output level of the salt cell for the pool. Valid setpoints are 40-104F or 4-40C.
  • spaSetpoint - integer indicating the output level of the salt cell for the spa. Valid setpoints are 40-104F or 4-40C.
  • salt - integer indicating salt level in parts-per-million
  • flags - integer bitmask
  • superChlorTimer - integer

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

  • circuitId - id of the circuit to which this event applies to
  • runTime - integer specifying the run time in minutes

SLSetCircuitStateMessage

Passed as an argument to the emitted circuitStateChanged event.

Properties

  • circuitId - integer indicating the ID of the circuit to set the state of.
    • This ID can be retrieved from SLControllerConfigData's circuitArray property.
  • circuitState - integer indicating whether to switch the circuit on (1) or off (0).

SLSetHeatModeMessage

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

Properties

  • controllerId - integer indicating the ID of the controller to send this command to.
    • Note that while SLControllerConfig includes a controllerId, this ID, in my experience, should always be 0.
  • bodyType - integer indicating the type of body to set the setpoint of. The pool is body 0 and the spa is body 1.
  • heatMode - integer indicating the desired heater mode. Valid values are:
    • HeatModes.HEAT_MODE_OFF
    • HeatModes.HEAT_MODE_SOLAR
    • HeatModes.HEAT_MODE_SOLARPREFERRED
    • HeatModes.HEAT_MODE_HEATPUMP
    • HeatModes.HEAT_MODE_DONTCHANGE

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

  • controllerId - integer indicating the ID of the controller to send this command to.
    • Note that while SLControllerConfig includes a controllerId, this ID, in my experience, should always be 0.
  • poolOutput - integer indicating the output level of the salt cell for the pool. I believe this operates on a 0-100 scale.
  • spaOutput - integer indicating the output level of the salt cell for the spa. I believe this operates on a 0-100 scale.

SLSetScheduleEventById

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

Properties

  • scheduleId - id of a schedule previously created, see scheduleaddNewScheduleEventAsync()`
  • circuitId - id of the circuit to which this event applies
  • startTime - the start time of the event, specified as minutes since midnight (see conversion functions)
    • example: 6:00am would be 360
    • example: 6:15am would be 375
  • stopTime - the stop time of the event, specified as minutes since midnight (see conversion functions)
  • dayMask
    • 7-bit mask that determines which days the schedule is active for, MSB is always 0, valid numbers 1-127
  • flags
    • bit 0 is the schedule type, if 0 then regular event, if 1 its a run-once
    • bit 1 indicates whether heat setPoint should be changed
  • heatCmd - integer indicating the desired heater mode. Valid values are:
    • HeatModes.HEAT_MODE_OFF
    • HeatModes.HEAT_MODE_SOLAR
    • HeatModes.HEAT_MODE_SOLARPREFERRED
    • HeatModes.HEAT_MODE_HEATPUMP
    • HeatModes.HEAT_MODE_DONTCHANGE
  • heatSetPoint - the temperature set point if heat is to be changed (ignored if bit 1 of flags is 0)

SLSetSystemTime

Passed as an argument to the emitted setSystemTime event.

SLVersionMessage

Passed as an argument to the emitted version event handler.

Properties

  • version - a string representing the system's version

SLWeatherForecastData

Properties

  • version - number
  • zip - string
  • lastUpdate - Date
  • lastRequest - Date
  • dateText - string
  • text - string
  • currentTemperature - number
  • humidity - number
  • wind - string
  • pressure - number
  • dewPoint - number
  • windChill - number
  • visibility - number
  • dayData - SLWeatherForecastDayData[]
    • dayTime - Date
    • highTemp - number
    • lowTemp - number
    • text - string
  • sunrise - number
  • sunset - number

node-screenlogic's People

Contributors

bshep avatar dependabot[bot] avatar gjbadros avatar mikemucc avatar parnic avatar schemers avatar tagyoureit avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-screenlogic's Issues

getPumpStatus returns the same values regardless of pumpID passed

When I call getPumpStatus(pumpID) I get the same values coming back regardless of the pumpID I use. It is possible I am doing something wrong. Here is my example:

function connect(client) {
client.on('loggedIn', function() {
this.getVersion();
}).on('version', function(version) {
this.getSaltCellConfig();
}).on('saltCellConfig', function(saltCellConfig) {
this.getPumpStatus(0);
console.log('pentair/saltcellstatus/state,' + saltCellConfig.status);
console.log('pentair/saltcelllevel1/state,' + saltCellConfig.level1);
console.log('pentair/saltcelllevel2/state,' + saltCellConfig.level2);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(2);
console.log('pentair/pump/0/watts/state,' + status.pumpWatts);
console.log('pentair/pump/0/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/0/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(3);
console.log('pentair/pump/2/watts/state,' + status.pumpWatts);
console.log('pentair/pump/2/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/2/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(4);
console.log('pentair/pump/3/watts/state,' + status.pumpWatts);
console.log('pentair/pump/3/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/3/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(5);
console.log('pentair/pump/4/watts/state,' + status.pumpWatts);
console.log('pentair/pump/4/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/4/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(6);
console.log('pentair/pump/5/watts/state,' + status.pumpWatts);
console.log('pentair/pump/5/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/5/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(7);
console.log('pentair/pump/6/watts/state,' + status.pumpWatts);
console.log('pentair/pump/6/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/6/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(1);
console.log('pentair/pump/7/watts/state,' + status.pumpWatts);
console.log('pentair/pump/7/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/7/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
this.getPumpStatus(8);
console.log('pentair/pump/1/watts/state,' + status.pumpWatts);
console.log('pentair/pump/1/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/1/gpm/state,' + status.pumpGPMs);
}).on('getPumpStatus', function(status) {
console.log('pentair/pump/8/watts/state,' + status.pumpWatts);
console.log('pentair/pump/8/rpm/state,' + status.pumpRPMs);
console.log('pentair/pump/8/gpm/state,' + status.pumpGPMs);
client.close();
});

Also, how many pumps does ScreenLogic support? Is there any way to see how many pumps are installed with pumpIDs or do we just need to iterate through them to get details?

addClient disconnecting

Thanks for this library, it's great! I'm using the addClient() function to subscribe to updates from the controller which works fine, but it seems to disconnect after about 20 minutes or so and stop receiving updates. Also if I try to send commands to the controller after that, it gives me an error that says "this socket has been ended by the other party". Can anyone else confirm this? Is there some autoreconnect procedure? I want to have a persistent 24/7 connection to the controller.

FEATURE: Set Timeout

Hey, really love the work here.

I'm writing an Alexa skill that controls various features and find that some are slower than others to respond with state confirmation. Would be super rad if we could set a config on the constructor to set a timeout vs. the default 2300ms.

CoolSetpoint on Spa tracks outdoor air temp?

I noticed today that the cool setpoint for a spa body (the data that comes back in SLPoolStatusMessage.js) seems to track along with the air temperature reading. At first I thought I had a bug somewhere parsing the data or updating my UI but when I look at the actual data coming back from the controller it matches what I see.

It probably makes sense in some way as a cool setpoint for a spa doesn't seem very useful but I thought I'd ask as I didn't see any reference to it in the code or docs that the controller would send back the air temp in the cool setpoint value for a spa. The pool setpoints (heat and cool) seem reasonable and I don't see them change as the air temp does.

Talking to screen logic

Hey there,
I'm not sure if you want to have discussions like this over GitHub issues or else where but let me know if this should be some where else.

I recently had a new pool installed that has a pentair screen logic, intellibrite( lights ), intellichem and I also have my backyard lights wired into a relay.

I'd love to be able to talk to the system to both read and change state ( turning off water features, turn on lights, turn on the high speed circuit...ect)

Ideally I would be able to integrate into into my home automation (https://www.home-assistant.io/).

So questions:

  1. I see that I can read a bunch of data but am I able to turn on circuits?

Unable to set salt level for pool or spa individually

The setSaltCellOutput function sets the pool and spa levels so you can't just send one level. Would it be possible to either create distinct functions for pool and spa or add the ability to pass null values to the existing function like this:

exports.SLSetSaltCellConfigMessage = class SLSetSaltCellConfigMessage extends SLMessage {
  constructor(controllerIndex, poolOutput, spaOutput) {
    super(0, MSG_ID);
    this.controllerIndex = controllerIndex;
    if(poolOutput != null){
      this.poolOutput = poolOutput;
    }
    if(spaOutput != null){
      this.spaOutput = spaOutput;
    }
  }
  encode() {
    this.writeInt32LE(this.controllerIndex || 0);
    this.writeInt32LE(this.poolOutput || 0);
    this.writeInt32LE(this.spaOutput || 0);
    this.writeInt32LE(0);
    this.writeInt32LE(0);
    super.encode();
  }
  static getResponseId() {
    return MSG_ID + 1;
  }
};

I'm not sure how the messages are sent to SL so this might not be possible, but it would make sense to allow just setting one at a time.

Integration with nodejs-poolController

Hey @parnic! This is long overdue, but I'm finally at a place where I can integrate direct Screenlogic control into nodejs-poolController. I've been wanting to dig into this for quite a while.

To that end, I've gone through and converted all of your code to Typescript + Promises. It still supports the events, too. I've published this up to my repo at https://github.com/tagyoureit/node-screenlogic/tree/typescript. I've changed quite a bit (event names, data structure, return values, etc etc). I can keep this as a separate repo if that makes more sense. I haven't updated the docs yet but the example.ts shows how to use all of the methods.

First question is whether or not you are ok with moving to Typescript + Promises or you would rather keep the plain 'ole Javascript.

Second question is do you have any bandwidth to flush out more of the commands?

I'll also be able to help debugging/decoding many of the other aspects as I've got in-depth knowledge of how the RS485 packets work.

I've got a short list of items that I've compiled so far, but haven't gone through everything to validate it yet. Need to put it through a fine tooth comb.

  1. Equipment config - I see you have a separate thread on this... will try to dig into what I can find.
  2. Do you know how often a ping needs to be sent to keep a connection to the server?
  3. What's the difference between the clientId and senderId?
  4. I'm getting bad parameters trying to run the following: set circuit state, set circuit run time, delete schedule by id, set schedule
  5. 12504 is async message that the intellibrite is changing colors (~16s)
  6. I have not yet tested the local connection; I'm currently working remotely and also need to replace a fried chip on my transceiver

Heater/thermostat support?

Thank you for creating this! I've got everything working including spa and pool temp display, but I seem to not be able to turn the heater on/off or adjust the pool or spa temperature.

Uncaught Exception crashing node-red

This is the only information I can find in the logs:

9 May 07:31:47 - [red] Uncaught Exception:
9 May 07:31:47 - Error: read ECONNRESET at TCP.onStreamRead (internal/stream_base_commons.js:209:20)

This occurs 30 seconds after node-red starts. I have node-red auto starting on failure. So, this puts it into a cycle of start/die in 30 seconds/restart/die in 30 seconds... for ever.

Below is the node-red function on start code. Other than the fatal crash, everything appears to be working normally:


node.status({fill:'yellow',shape:'dot',text:'Loading'});

const systemName = 'Pentair: xx-xx-xx;
const password = '';

var screenLogic = global.get('screenlogic');
var remote = new screenLogic.RemoteLogin(systemName);

var pool = {};

remote.on('gatewayFound', function(unit) {
  if (unit && unit.gatewayFound) {
    var client = new screenLogic.UnitConnection(unit.port, unit.ipAddr, password);
    client.on('loggedIn', function() {
        pool.systemName = remote.systemName;
        pool.ip = unit.ipAddr;
        pool.port = unit.port;
        node.status({fill:'green',shape:'dot',text:'connected, getting version'});
        this.getVersion();
    }).on('version', function(version) {
        pool.version = version.version;
        node.status({fill:'green',shape:'dot',text:'connected, getting status'});
        this.getPoolStatus();
    }).on('poolStatus', function(status) {
        pool.status = status;
        pool.isOk = status.ok==1?"ok":"fault";
        pool.airTemp = status.airTemp;
        pool.waterTemp = status.currentTemp[0];
        pool.running = status.isPoolActive();
        pool.lightState = status.circuitArray[0].state==1?true:false;
        pool.highspeedState = status.circuitArray[1].state==1?true:false;
        node.status({fill:'green',shape:'dot',text:'connected, getting configuration'});
        this.getControllerConfig();
    }).on('controllerConfig', function(config) {
        node.status({fill:'green',shape:'dot',text: (pool.running?'running':'off') + ' ' + pool.waterTemp + pool.degreesUnit});
        pool.config=config;
        pool.degreesUnit = config.degC?"C":"F";
        pool.lightName = config.bodyArray[0].name;
        pool.highspeedName = config.bodyArray[1].name;
        pool.client = client;
        pool.remote = remote;
        node.status({fill:'green',shape:'dot',text:'connected, saving pool'});
        flow.set("pool", pool);
    }).on('loginFailed', function() {
        node.status({fill:'red',shape:'dot',text:'could not log in'});
        client.close();
    });
    client.connect();
  } else {
    node.status({fill:'red',shape:'dot',text:'no unit found by that name'});
    remote.close();
  }
 });

remote.connect();

return;

getNumPumps() returns number of available pump slots, not actual number of pumps

As always, thanks for this work!

On my system I have one filter pump configured in the controller and it has pump circulation settings for the pool and spa set for it. If you call getNumPumps() you (at least I) get 8 back always as the result. Looking at the data coming back from the controller and adding a phantom 2nd pump to see how the data changed, I believe I see where the issue is. Currently the code in getNumPumps() loops through the 45 byte record for each pump record and checks the 3rd byte in the array to see if it's non-zero. For me this value is always 2 no matter what I do so every record in the list (all 8) are seen as a pump and the counter incremented.

Looking at the data, particularly the first 3 bytes of each 45 byte record, I get the following for the first record (where my IntelliFlo VSF pump is):

0x40, 0x0,0x2

For all the remaining records where I have no pump, each one starts with:

0x0,0xF,0x2

When I created my phantom pump, only byte 0 changed, depending on what pump type I chose in SLConfig. Byte 1 and 2 didn't change from 0xF and 0x2. Not sure what byte 1 represents but given it's 0 for my real pump and 0xF for the phantom one, it's probably some sort of status about the pump that the controller can't get from my fake pump.

Byte 0 took the following values:
0 = None selected in SLConfig for pump type
0x6 = IntelliFlo VF
0x40 = IntelliFlo VSF
0x80 = IntelliFlo VS

So I think the code in getNumPumps should be looking at byte 0 rather than byte 2 for whether there's a pump there (unless it is really intended to return the number of potential slots vs. actual pumps). The values for the various pump models shown above don't seem to match the values returned by the GetPumpStatus msg but my VSF reports 3 so I think that mapping is accurate otherwise. The values above for pump type track repeatedly to what is set in SLConfig.

Can anyone confirm that they get 8 pumps from getNumPumps()? I don't see a way to get rid of the unused pump slots so I assume that the controller just always has 8 slots no matter how many pumps you may actually have and you have to see if a pump is actually set for that slot before counting it.

Is UDP Broadcast the same as mdns/dns service discovery?

Hello still kinda new to node and networking. I'm working on something where I can search do dns service discovery and I can find local devices on my network by searching for _http._tcp. But im not sure how to search via dns service discovery for screenlogic. any pointers?

Set pump speeds

Creating a new issue so we don't pollute the other thread.

When I get back the pump status the data is this:

Pump 0: 
{"pumpCircuits":
[
{"circuitId":1,"speed":5,"isRPMs":true},
{"circuitId":6,"speed":2000,"isRPMs":true},
{"circuitId":7,"speed":2500,"isRPMs":true},
{"circuitId":8,"speed":3250,"isRPMs":true},
{"circuitId":18,"speed":1320,"isRPMs":true},
{"circuitId":0,"speed":1000,"isRPMs":true},
{"circuitId":0,"speed":1000,"isRPMs":true},
{"circuitId":0,"speed":1000,"isRPMs":true}
],
"pumpType":2,
"isRunning":true,
"pumpWatts":506,
"pumpRPMs":2000,
"pumpUnknown1":0,
"pumpGPMs":255,
"pumpUnknown2":255}

I tried both (in your original code):

  • this.setPumpFlow(0,5,1010,true); (for the 5th index in the array)
  • this.setPumpFlow(0,18,1010,true); (for the circuit id of 18)

Neither worked. What am I missing here?

And a follow on item- looks like in order to change the pump, or circuit itself, I'll need to call 12568 and update the entire pool config. Does that sound correct?

Basic question from a novice: Truncated example.js output

when I first used this example function months ago I saw the full result to console. Now when I run the example I see only the result of the first get equipment config only. What am I missing? I dont see in example anything that would prevent the subsequent functions to display their data to console.

C:\Users\Chris\Desktop\node_screenlogic\node_modules\node-screenlogic>node example
version = 1180
secondaries = 0
pump 1 type=0, pump 2 type=2
pump 1 pool rpm=2000
pump 2 waterfall rpm=0
num pumps=7

C:\Users\Chris\Desktop\node_screenlogic\node_modules\node-screenlogic>

Get current light color for pool/spa lights

I checked the SLControllerConfigMessage in bodyArray and colorArray, and I checked the SLPoolStatusMessage in circuit array. Am I missing something?

Also as a side question, is it possible to target specific group of lights, for example pool lights, or spa lights when doing sendLightCommand?

Server crashes out

Firstly, thank you so much for this code. I have set everything up and I am assuming that I run example.js? When i run it, it does connect to my unit but then exits with: controller is in celsius=false because of the client.close(). How do I keep this running? If I comment out that line, it runs for a little while and then crashes after a few seconds with:
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
Emitted 'error' event at:
at emitErrorNT (internal/streams/destroy.js:91:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
at process._tickCallback (internal/process/next_tick.js:63:19)

Question: Polling vs Listening for an event on poolStatus changes

Parnic, thank you for this piece of work. It's great. I'm using node-screenlogic + google to learn node.js (and programming in general) so apologies in advance if I'm missing the obvious.

I'm treating my pool (via node-screenlogic) as a series of sensors and publish their status in JSON format via mqtt.js. I'm also using mqtt to change the state of various components (pumps, spa temp, lights, etc.).

Currently, I'm polling the poolStatus and controllerConfig via setInterval to refresh and publish status. It's working, but it doesn't feel like the most efficient or stable approach.

Also note, most of my code is based on your example.js, node.js official docs and various node.js tutorials I've found via Google... so my approach is definitely a victim of the last tutorial I read.

Questions:

  • In this case is polling a valid strategy?
  • If not, Is there a status change event that I could listen for vs polling?
  • If so, do you happen to have additional code examples that might lead me down an appropriate path?

Eventually, I'd like to contribute a MQTT emitter to the project.

Thanks,
pgregg

History messages

Anybody got any luck/experience with history messsages?

From what I figured out looking at the android apps comms:
Sending a 12534 type requests history events.
Format is:
Int32(0), DateTime(start), DateTime(end)
with DateTime encoded as:
Uint16(year), Uint16(month), Uint16(Day of week, can be ignored/0), Uint16(day), Uint16(hour), Uint16(minute), Uint32?(seconds)

It'll come back with an empty 12535.

It then send a (very long) message 12502 with the format:

Uint32(Number of events)
for (event in number events):
DateTime(event timestamp)
Uint32(Outside Temperature)

So basically so far I've been able to get the outside temperature read out, but I have no clue how to figure out when the pump/heater/light was on. Anyone any idea?

any ideas on how to set setPoint (for spa heater)?

I assume I need the equivalent of setCircuitState. Here's the function I'm using to turn the spa on (circuit ID 500) and then call getPoolState() to publish status to my network.

Thoughts?

    function connect(client) {
      client.on('loggedIn', function() {
        this.setCircuitState(0, 500, 1);
        console.log('Spa turned on')
        client.close();
        wait(500).then( getPoolState())
        .then(console.log('called getPoolState'))
      });
  
      client.connect();

Homebridge Compatibility

Hello parnic!

Not really an issue but was wondering if you were looking into creating a homebridge version of this so that Pumps can be controlled through Apple's HomeKit?

Thanks for your awesome work so far!

SLSetHeatSetPoint not parsing API response

Hi!

I'm using setSetPoint to set the temperature, and it's working fine -- but the emitted event doesn't parse the response from ScreenLogic so there's no way to programmatically verify the temperature was set correctly.

It looks like the messageId is different -- looking at the code SLSetHeatSetPoint expects message ID 12528, but the response I'm getting has 12529:

{"length":8,"_encoding":"utf8","_writeOffset":8,"_readOffset":8,"_buff":{"type":"Buffer","data":[0,0,241,48,0,0,0,0]},"_wroteSize":true,"senderId":0,"messageId":12529,"dataLength":0}

Is this just a matter of changing the messageId to get this parsed properly?

Differentiate the callback event for getScheduleData(0) vs (1)

I'd like to see a the calls for getScheduleData(0) to have a different callback event name than getScheduleData(1). If I call both of those functions sequentially, I never actually get the egg timer data.

Or, make getScheduleData() = getScheduleData(0) and getEggTimers() = getScheduleData(1) and give it a different callback event name.

Get Circuit State (on, off, etc.)

We are trying to get the circuit state of something like the waterfalls so we know if they are on or off. We read all the documentation and couldn't figure out how to do this. Did we miss something or is this impossible?

We tried getCircuitByDeviceId(), but it said the function is not defined.
We also tried looking at ...}).on('controllerConfig', function (config) { config.bodyArray[<index of circuit>]..., but it didn't give us the information we need.

Timeout / Parameter Failure on setCircuitAsync

Hello and thanks so much for putting this library together! Really amazing work!

I am attempting to turn a circuit on and getting a timeout: (I used getAllCircuitNamesAsync to look up the circuitId)

client.circuits.setCircuitStateAsync(72, 1)

The timeout error result I think might be a red herring though as I see the following in the debug logs:

  sl:unit [0] sending set circuit state command: controllerId: 0, circuitId: 72, circuitState: 1... +0ms
  sl:unit received 31 message of length 8 +9ms
  sl:unit   it is a parameter failure. +0ms

I've tried multiple circuits with the same result. I've also tried using both the local and remote connection approaches but this does not appear to make a difference. I am however able to successfully turn the pool light on and off using sendLightCommandAsync so I know that at some level things are working.

I checked the version of my equipment using getVersionAsync:

POOL: 5.2 Build 736.0 Rel

This isn't the latest version of the firmware but it is a version listed in this project's notes as one of the tested versions. Having said that I am wondering if maybe this version is only partially supported? I'd update my firmware but I am on a Mac and the screenlogic firmware updater unfortunately doesnt work on any remotely recent version of the Mac OS.

Any ideas what might be going on?

Lights Command questions

In the README it lists a bunch of light commands, but says that the command takes an Integer. Is this the correct mapping?

Edit: Correct Integers per below.

Number Meaning
0 ScreenLogic.LIGHT_CMD_LIGHTS_OFF
1 ScreenLogic.LIGHT_CMD_LIGHTS_ON
2 ScreenLogic.LIGHT_CMD_COLOR_SET
3 ScreenLogic.LIGHT_CMD_COLOR_SYNC
4 ScreenLogic.LIGHT_CMD_COLOR_SWIM
5 ScreenLogic.LIGHT_CMD_COLOR_MODE_PARTY
6 ScreenLogic.LIGHT_CMD_COLOR_MODE_ROMANCE
7 ScreenLogic.LIGHT_CMD_COLOR_MODE_CARIBBEAN
8 ScreenLogic.LIGHT_CMD_COLOR_MODE_AMERICAN
9 ScreenLogic.LIGHT_CMD_COLOR_MODE_SUNSET
10 ScreenLogic.LIGHT_CMD_COLOR_MODE_ROYAL
11 ScreenLogic.LIGHT_CMD_COLOR_SET_SAVE
12 ScreenLogic.LIGHT_CMD_COLOR_SET_RECALL
13 ScreenLogic.LIGHT_CMD_COLOR_BLUE
14 ScreenLogic.LIGHT_CMD_COLOR_GREEN
16 ScreenLogic.LIGHT_CMD_COLOR_RED
17 ScreenLogic.LIGHT_CMD_COLOR_WHITE
18 ScreenLogic.LIGHT_CMD_COLOR_PURPLE

Schedule Editing

I'm really interested in being able to configure the schedule remotely, i wonder if i can help by providing some packet captures?

I have PC app and wireshark available but i'm not sure what to look for.

RS-485?

Parnic,

Are you able to see what messages the RS-485 bus is sending/receiving? For example, I'm really interested in the ControllerConfigMessage and how it translates to a request/response on the serial bus. Let me know if you can see that side of the communications.

It's great you're making progress and I'm trying to understand how (or if) it makes sense to utilize this networking approach in my app.

Tag

Set Control for the Salt Cell Output

First I want to say I love this Library! totally awesome.

Per our previous postings...

I would like to make a feature request for Set Control for the Salt Cell Output.

User Story: I have both an IntelliChem and an IntelliChlor. I have noticed that the IntelliChem control for my SaltCell isn't very intelligent. It's set up so that if the SaltCell can't keep up with the Chlorine output then it adds Chlorine from the tank. The issue is that it doesn't just attempt to increase the Setting on the Salt Cell first. The problem is that I don't find out that the salt cell is set too low until I get an error that my ORP Tank is empty... I am feeding ORP Stats into an AI now using your library (Awesome)! and I would like that system to be able to control my SaltCell based on the results.

Thanks so much for hearing me out and I am happy to know that it's not just me having this issue.

(Some) equipFlags meanings

Not so much an issue, but interesting findings that I thought anybody working on this would find useful.

I'm in the middle of creating a UI in Angular, and needed the ability to programmatically determine the heater/cooler configuration so I did a little research with my EasyTouch/ScreenLogic II today to figure out what equipFlags really means.

Here are the results:

24: No Solar (Heat Pump Present) - Baseline
25: Solar Present (+1)
27: Solar Is Heat Pump (+2)
27: UltraTemp or ThermaFlo (Turns on Solar & Solar Is Heat Pump)
28: Chlorinator Present (+4)
29: Chlorinator + Solar 
31: Chlorinator + Solar is Heat Pump

--- Cooling Present
8219: Has Cooling (+8192 (Turns on Solar Present (+1), Solar Is HP (+2), UltraTemp or ThermaFlo))
8223: Has Cooling + Chlorinator Present (Turns on Solar Present, Solar Is HP, UltraTemp or ThermaFlo)

--- IntelliChem Present
32792: IntelliChem Present (+32768)
32793: IC + Solar
32795: IC + Solar + Solar Is heatpump
32796: IntelliChem + Chlorinator
32797: IntelliChem + Chlorinator + Solar
32799 : IntelliChem + Chlorinator + Solar + Solar is HP
40991 : IntelliChem + Chlorinator + Solar + Cooling

Binary Representations:

Setting Binary Notes
Heater 0000000000011000 Baseline
+ Solar 0000000000011001
+ Solar + Solar is HP 0000000000011011
+ Chlorinator 0000000000011100
+ Chlorinator + Solar 0000000000011101
+ Ch + So + SoisHP 0000000000011111
+ Cooling (+ So + SoisHP) 00100000011011
+ Cooling + Ch 00100000011111
IntelliChem + Ch + Cooling + Solar 1010000000011111

Testing Needed for SLGetPumpStatus / SLSetPumpFlow

@mikemucc and @parnic

I implemented the above messages, but need feedback from someone with more than one VS pump as I have no way to know for sure how to set/request data for other pumps, i made an educated guess based on the other messages.

you can checkout my branch:
https://github.com/bshep/node-screenlogic/tree/pump_info

you can use this example file to test:
https://gist.github.com/bshep/0f900eabe699d141bd4a33d60907037f

edit the line 51:

this.getPumpStatus(0);

to request other pumps ( it may not work if i guessed wrong )

Please also test ( this WILL change your settings so make sure you have some way of setting them back if something fails):

setPumpFlow(pumpId, circuitId, setPoint, isRPMs)

I've tested with 'pumpId = 0' and it works perfectly

Once more testing has been done I will submit a PR to have it merged.

Unknown message 8300

When adding, setting, or deleting a schedule, I often get an 8300 response, but not the ack I expected.

2020-07-01T00:00:48.721Z sl:unit sending set schedule event command for scheduleId: 702, circuitId: 505, startTime: 420, stopTime: 1080, dayMask: 32, flags: 0, heatCmd: 0, heatSetPoint: 0...
2020-07-01T00:00:48.854Z sl:unit received message of length 12
2020-07-01T00:00:48.854Z sl:unit   it's an unknown type: 8300

The message buffer for 8300 is always the same

{
  "type": "Buffer",
  "data": [
    255,
    127,
    108,
    32,
    4,
    0,
    0,
    0,
    1,
    0,
    0,
    0
  ]
}

When I get 8300, I do not usually receive the response I expect (eg. delete ack, set ack, add ack)

2020-07-01T15:48:26.382Z sl:unit sending delete schedule event command for scheduleId: 702...
2020-07-01T15:48:26.489Z sl:unit received message of length 12
2020-07-01T15:48:26.490Z sl:unit   it's an unknown type: 8300

Occasionally I receive both 8300 and the response I expect

2020-07-01T15:48:26.382Z sl:unit sending delete schedule event command for scheduleId: 702...
2020-07-01T15:48:26.489Z sl:unit received message of length 12
2020-07-01T15:48:26.490Z sl:unit   it's an unknown type: 8300
2020-07-01T15:48:26.494Z sl:unit received message of length 8
2020-07-01T15:48:26.494Z sl:unit   it's a delete schedule event ack 12547

Sometimes I receive 8300 multiple times for one operation

2020-07-01T15:48:26.382Z sl:unit sending delete schedule event command for scheduleId: 702...
2020-07-01T15:48:26.489Z sl:unit received message of length 12
2020-07-01T15:48:26.490Z sl:unit   it's an unknown type: 8300
2020-07-01T15:48:26.493Z sl:unit received message of length 12
2020-07-01T15:48:26.494Z sl:unit   it's an unknown type: 8300

The operation always works, when I check getScheduleData, the schedule has been added/deleted/set, even though I didn't get a response.

Any ideal what message 8300 might be? Any suggestions for how I can figure out what it means, and why I'm seeing this behaviour?

Thanks!

Issue with Buffer Changes.

Hey Parnic! Hope you are well.
I saw that you added SLEquipmentConfigurationMessage and so I cloned down the latest to my test server to see if I can help make heads or tails of the arrays. That said... I also picked up, of course, the buffer changes you made a few weeks ago.

I am getting some errors that the functions aren't declared. I tried to follow through your code to see if I could find them but I am just not that familiar with it yet. This is what I am seeing...

/usr/lib/node_modules/node-screenlogic/messages/SLGetGatewayDataMessage.js:11
size = buf.readInt32LE(4) + 8;
^

TypeError: buf.readInt32LE is not a function
at new SLGetGatewayDataMessage (/usr/lib/node_modules/node-screenlogic/messages/SLGetGatewayDataMessage.js:11:18)
at RemoteLogin.onConnected (/usr/lib/node_modules/node-screenlogic/index.js:87:23)
at Socket. (/usr/lib/node_modules/node-screenlogic/index.js:80:13)
at Object.onceWrapper (events.js:299:28)
at Socket.emit (events.js:215:7)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1115:10)

feature request: Access "history" data

I would really like to access the data that shows up in "history" on the pentair screen logic app. Pool temp, spa temp, outdoor temp and heater running time. It also shows pool mode and spa mode.

maybe its easier if I monitor those myself continuously, but curious if it is easy to pull from the device. Also not sure how much data it stores.

thanks.

Socket reads only first chunk (1024 bytes).

Hello.
When I am runing this.getPoolStatus(); I get error: Attempted to read beyond the bounds of the managed data.

Error: Attempted to read beyond the bounds of the managed data.
smartbuffer.js:957
at SLControllerConfigMessage.ensureReadable (d:\node-screenlogic-master\node_modules\smart-buffer\build\smartbuffer.js:957:19)
at SLControllerConfigMessage._readNumberValue (d:\node-screenlogic-master\node_modules\smart-buffer\build\smartbuffer.js:1025:14)
at SLControllerConfigMessage.readInt32LE (d:\node-screenlogic-master\node_modules\smart-buffer\build\smartbuffer.js:145:21)
at SLControllerConfigMessage.decode (d:\node-screenlogic-master\messages\SLControllerConfigMessage.js:65:19)
at new SLControllerConfigMessage (d:\node-screenlogic-master\messages\SLControllerConfigMessage.js:17:12)
at UnitConnection.onClientMessage (d:\node-screenlogic-master\index.js:219:39)
at Socket. (d:\node-screenlogic-master\index.js:131:15)
at Socket.emit (events.js:182:13)
at addChunk (_stream_readable.js:283:12)
at readableAddChunk (_stream_readable.js:264:11)

I investigated this problem. Data send in two chunks, but app don't wait second chunk.

My fix for UnitConnection class:

var buffer = Buffer.from("", 'binary');
this.client.on('data', function(msg) {
buffer = Buffer.concat([buffer, msg]);
if (msg.length!=1024) {
_this.onClientMessage(buffer);
buffer = Buffer.from("", 'binary');
}
}).on('close', function(had_error) {
// console.log('unit connection closed');
});

received message of length 1196

Schedule Create/Delete is a very long operation (15-20 seconds)

TL;DR version: it looks like it's taking between 15-20 seconds for the Create New Schedule ID/Delete Schedule ID calls to successfully complete. I believe that this may be the reason I'm not seeing the ACKs on Create/Delete Schedule.

The Long Version:
I'm now keeping a Set() object with the IDs of all of the Schedule Events (daily & run once) that exist on the system so I can quickly check to see if it exists (and return a 404 if somebody tries to Update or Delete an event ID that doesn't exist). I update this set every time I poll the ScreenLogic for new data. That polling frequency is currently 5 seconds.

So I end up with an object that looks kinda like this:
{ 700, 701, 702, 703, 704 }

So, from the perspective my my REST API:

  1. Start up the API. The API does its initial data load and logs all of the Schedule Event IDs that currently exist on the system (console.log() the Set() object that is schedules.eventIds).
  2. I call the "create New Schedule Event" endpoint.
  3. I watch the API logs make the call back to the ScreenLogic to create a new Schedule Event
  4. My API Polls the ScreenLogic Device immediately after making the CreateSchedule call (Lets cal this T=0)
    3a. During that poll, the API prints all of the current Schedule Event IDs on the system again. This is currently still the same as in step 0.
  5. 5 seconds later, the API polls again (Call this T=+5 seconds). The set of Schedule Event IDs on the system hasn't changed.
  6. Repeat Step 4 (Call this T+10)
  7. Repeat Step 4 (T+15)
  8. API Polls (T+20). Now the Schedule IDs on the system has incremented by 1 (i.e. the new schedule has actually been created).

So the apparent behavior is that a Create or Delete schedule event takes between 15 and 20 seconds to complete (at least on my system, the backend of which is an EasyTouch). This could be a result of my hardware, maybe the EasyTouch is a little slower than some of the other systems, who knows.

So I thought I remembered @bshep adding a keepalive value to the client. Could this be related to the behavior I'm seeing?

I could modify that line in my local cache to something like this.client.setKeepAlive(true, 25 * 1000); and see if it affects the behavior I'm seeing (if you think that would have any affect).

Calling getPumpStatus() is timing out.

Hi Parnic, I have created a REST webservice using your Library and I love it!

Recently, I have been asked to expand to capture more Pump info and I noticed you added Pump Functions to the library.

I created a copy of example.js and added the get getPumpStatus(). It seems to be timing out on that one function.

Any ideas?

}).on('saltCellConfig', function(saltCellConfig) { this.getControllerConfig(); console.log(' salt cell installed=' + saltCellConfig.installed); //Adding Pump }).on('pumpStatus', function(pumpStatus) { this.getPumpStatus(0); console.log(' Pump Status =' + pumpStatus.isRunning); //Pump End }).on('controllerConfig', function(config) { console.log(' controller is in celsius=' + config.degC); client.close();

The requested platform "ScreenLogic" was not registered by any plugin v2.0.1

Hi, I just stumbled across this great plugin and tried to get it setup in HOOBS. I have several other plugins working with HOOBS, however the ScreenLogic plugin fails with this message:

6/24/2020, 9:23:02 AM Loaded plugin "homebridge-screenlogic".
6/24/2020, 9:23:02 AM The requested platform "ScreenLogic" was not registered by any plugin.
6/24/2020, 9:23:02 AM Your config.json is requesting the platform "ScreenLogic" which has not been published by any installed plugins.

My config:
{
"platform": "ScreenLogic",
"plugin_map": {
"plugin_name": "homebridge-screenlogic"
},
"hidePoolTemperatureSensor": false,
"hideSpaTemperatureSensor": false,
"hideAirTemperatureSensor": false,
"hidePoolThermostat": false,
"hideSpaThermostat": false,
"statusPollingSeconds": 60
}

HOOBS 3.2.6 (up to date)
Node 12.16.2

Any ideas?

Heat Status Code 1 Meaning?

I'm actually trying to wrap your code into a polling REST API using express.js.

Right now I'm just working on getting the status of the pool and I'm working through the heater status options.

I was able to figure out what the heater mode codes are from that PDF published by Carson Eisenach, but I'm not sure what the heat status codes are.

From my own observations I've been able to glean the following:
0 = off
2 = on (gas heater)

Would you perchance know what does a heat status code 1 mean?

If I were going to guess, I'd guess it means "Solar On", since the lower non-zero codes for heat mode refer to Solar, but I figured I'd ask the expert.

Decoding SLEquipmentConfigurationMessage

@mikemucc @bshep @tomblevins
Figured I'd go ahead and make an issue for decoding this thing so nobody's duplicating work.

As a reminder, most of this is coming from decompiling the slconfig app with jadx + experimentation.

  • versionDataArray can be turned into a version integer like so: (this.versionDataArray[0] * 1000) + (this.versionDataArray[1])
  • controllerData's top 2 bits indicate how many "slave" devices there are (which I'm calling "secondary" devices): (this.controllerData & 0x11000000) >> 6. don't know about the rest of the bits (my controller returns a value of 2 for this)
  • flowDataArray is where I've found the most interesting info so far. This contains information for up to 8 pumps worth of flow data. 45 bits are reserved for each pump and 24 of those contain data for the up-to-8 circuits that each pump supports. I've decoded a given pump's bits like this so far (values are from my equipment):
0:128 128 if pump exists, 0 if no pump, i think
1:0  priming time (in minutes, 0-10)
2:2  pump type (0 = none, 1 = IntelliFloVF, 2 = IntelliFloVS, 3 = IntelliFloVSF)
3:0  ? (maybe "background filtering"? this option is grayed out for me in slconfig)
4:11 circuit id (for me this is my "floor cleaner" circuit)
5:12 circuit val upper 8 bits
6:6  circuit id (for me this is "pool")
7:10 circuit val upper 8 bits
8:1  circuit id (for me this is "spa")
9:11 circuit val upper 8 bits
10:0 circuit id
11:3 circuit val upper 8 bits
12:0 circuit id
13:3 circuit val upper 8 bits
14:0 circuit id
15:3 circuit val upper 8 bits
16:0 circuit id
17:3 circuit val upper 8 bits
18:0 circuit id
19:3 circuit val upper 8 bits
20:3 priming RPM upper 8 bits
21:28 circuit 1 (4) val lower 8 bits
22:90 circuit 2 (6) val lower 8 bits
23:184 circuit 3 (8) val lower 8 bits
24:232 circuit 4 (10) val lower 8 bits
25:232 circuit 5 (12) val lower 8 bits
26:232 circuit 6 (14) val lower 8 bits
27:232 circuit 7 (16) val lower 8 bits
28:232 circuit 8 (18) val lower 8 bits
29:232 priming RPM lower 8 bits
30:0 unused?
31:0 unused?
32:0 unused?
33:0 unused?
34:0 unused?
35:0 unused?
36:0 unused?
37:0 unused?
38:0 unused?
39:0 unused?
40:0 unused?
41:0 unused?
42:0 unused?
43:0 unused?
44:0 unused?

Circuit id's are decoded via SLControllerConfigMessage's bodyArray array, deviceId property.
The circuit and priming rpms are really strange with the upper and lower bits separated in the array. Valid values for RPMs is 400 - 3450 with the default value being 1000 (upper 8 bits = 3, lower 8 bits = 232).

I'm having trouble reconciling this information with what I'm seeing in the SLConfig code, though. PageIntelliFloPriming and PageIntelliFloFiltering are both doing things with the flow data array, but the indices they're using don't match up quite right with what I'm seeing from my equipment. Still working on all this.

Can you tell if a scheduled event is running or not?

Thanks so much for this project. Super useful.

In the ScreenLogic app when you look at the scheduled events (at least on the iOS version), it highlights jobs in green when they are running. Any idea if this running state is queried from the controller or is the app just being smart and looking at the current time and the state of the circuit and assuming the schedule is the reason for it being active? The reason I ask is I notice the onboard clock can get off over time and the time window drift because of it so assuming both controller and my code are on the same time isn't a great assumption. I'm assuming that the controller has a way to query this info for the app but I'm not seeing it in the code/doc.

Related question, is there a way to get the current time on the controller to determine if it is reasonably in synch?

Thanks!!

ECONNREFUSED on connect

First of all, this library is great! I've been working on a little smart dashboard for various things at our house and have had this plumbed in for a while now going back to last year when we had our pool put in. Things have been working with little issue until earlier this week and now I'm having a tough time getting connectivity to the pump. Base connection attempts are erroring out with the below:

Error: connect ECONNREFUSED 127.0.0.1
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1145:16) {
  errno: -111,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1'
}

We still have connectivity via the mobile apps but I'm a little stumped as to what has changed. I verified that the credentials are still the same so just curious if you've got any insight or if anyone else may have experienced this.

Thanks!

Unit is found but remote connection is hanging?

Hi!

Having a weird issue -- the unit is found, but the network connection fails.

const ScreenLogic = require("node-screenlogic");

const username = ".......";
const password = ".......";

const rl = new ScreenLogic.RemoteLogin(username);

rl.on('gatewayFound', function(unit) {
    console.log('Found unit');
    console.log(JSON.stringify(unit));
    const unitConnection = new ScreenLogic.UnitConnection(unit.port, unit.ipAddr, password);
    console.log('trying to connect');
    try {
        unitConnection.on('connected', function() {
            console.log('connected');
            unitConnection.getPoolStatus((status) => {
                console.log(status);
            });
        });
        unitConnection.on('error', function(error) {
            console.log(error);
        });
        unitConnection.connect();
    
    } catch (error) {
        console.log(error);
    }
});

rl.connect();

The Unit data is sent back properly, the port is open.
The connection to the unit itself fails after a few moments:

Error: read ECONNRESET at TCP.onStreamRead (node:internal/stream_base_commons:217:20) { errno: -54, code: 'ECONNRESET', syscall: 'read' }

Any ideas how to debug this?

Can't get example to run

Forgive this simple question as I've never used node.js before, but how do I run the example? I've downloaded the package as a zip file, expanded it, and edited example.js to use my systemName and password. But trying to run the example:

node-screenlogic$ node example.js 
/Users/colin/node.js/node-screenlogic/index.js:21
var remote = new ScreenLogic.RemoteLogin(systemName);
             ^

TypeError: ScreenLogic.RemoteLogin is not a constructor
    at Object.<anonymous> (/Users/colin/node.js/node-screenlogic/index.js:21:14)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.<anonymous> (/Users/colin/node.js/node-screenlogic/example.js:3:21)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
node-screenlogic$ 
node-screenlogic$ node -v
v10.15.3
node-screenlogic$

How to cancel the default pool delays?

Love the API! Is there an API I can use to cancel the default pool delays? My controller automatically runs the pool and spa for 2 mins on my system after turning off the spa.

Can Intellibrite "save" and "recall" functionality from the mobile app be leveraged to store and set custom light colors?

@parnic @WhiteFire356 @bshep The iPhone app allows you to "save" the current color and hit the "recall" button to change all lights to that color. I use this to set the right color of blue that my wife likes as it fades through the various shades and hues. (pain in the ass to get it right) I assume it saves the RBG hex code for the current color value somewhere and loads it when the "recall" button is pressed.

It seems this would be a great was to create a custom color pallet of hex values (outside of pentair) and then pass in the desired RBG hex using whatever the "recall" feature uses.

Is this viable?

It would also be awesome if there was a way to dim the lights.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.