11 Commits

Author SHA1 Message Date
03022f9220 Updated version for release 2018-04-23 23:44:43 -05:00
8329bb22d7 Added changelog 2018-04-23 23:44:28 -05:00
2d382dda65 Documented setCircuitState 2018-04-23 23:41:33 -05:00
1f83be8e10 Fixed error
On my RPi3 I'm seeing a failure to find units because send() is demanding a Buffer or String. Uint8Array works for me in every other environment I've tried, but something about the RPi wants this to be a buffer. Having it as a buffer also works in other environments, thankfully.
2018-04-23 23:21:01 -05:00
e1c775b8a8 Added ability to set circuit state
This allows for, for example, turning on a water feature or changing pool/spa active status.
2018-04-16 19:49:01 -05:00
562a9993aa Updated example
Close the finder when we've found a unit.
Request and handle each piece of data in sequence instead of requesting it all at once and then closing when the last expected message comes through. This is potentially slightly slower, but much clearer and 'safer'.
2018-04-02 17:09:06 -05:00
973f01ae37 Added keywords for easier searching 2018-04-02 17:08:13 -05:00
9e11d830d6 Minor improvements/clarifications 2018-04-02 17:08:00 -05:00
b8cf9a1801 Increased version for release 2018-03-31 16:27:11 -05:00
a25b0ff3b2 Added example of direct connection 2018-03-31 11:24:47 -05:00
7907430e95 Added ability to connect by address and port 2018-03-31 11:24:37 -05:00
7 changed files with 119 additions and 26 deletions

View File

@ -91,6 +91,15 @@ finder.on('serverFound', function(server) {
})
```
### constructor(port, address)
Port is an integer. Address is an IPv4 address of the server as a string.
Examples:
```javascript
var client = new ScreenLogic.UnitConnection(80, '10.0.0.85')
```
### connect()
Connects to the server passed to its constructor.
@ -125,14 +134,19 @@ Requests salt cell status/configuration from the connected unit (requires an Int
Requests controller configuration from the connected unit. Emits the `controllerConfig` event when the response comes back.
### setCircuitState(controllerId, circuitId, circuitState)
Activates or deactivates a circuit. See [`SLSetCircuitStateMessage`](#slsetcircuitstatemessage) documentation for argument values. Emits the `circuitStateChanged` event when response is acknowledged.
### Events
* `loggedIn`
* `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.
* `version` - Indicates that a response to `getVersion()` has been received. Event handler receives a [`SLVersionMessage`](#slversionmessage) object.
* `poolStatus` - Indicates that a response to `getPoolStatus()` has been received. Event handler receives a [`SLPoolStatusMessage`](#slpoolstatusmessage) object.
* `chemicalData` - Indicates that a response to `getChemicalData()` has been received. Event handler receives a [`SLChemDataMessage`](#slchemdatamessage) object.
* `saltCellConfig` - Indicates that a response to `getSaltCellConfig()` has been received. Event handler receives a [`SLSaltCellConfigMessage`](#slsaltcellconfigmessage) object.
* `controllerConfig` - Indicates that a response to `getControllerConfig()` has been received. Event handler receives a [`SLControllerConfigMessage`](#slcontrollerconfigmessage) object.
* `circuitStateChanged` - Indicates that a response to `setCircuitState()` has been received. Event handler receives a [`SLSetCircuitStateMessage`](#slsetcircuitstatemessage) object.
### Properties
@ -184,11 +198,11 @@ Returns a bool indicating whether the pool is currently active or not.
* `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 (spa/pool) (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 (spa/pool)
* `setPoint` - array of size 0-2 holding the heating set point for each body as an integer (spa/pool) (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 (spa/pool) (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 (spa/pool)
* `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) (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)
@ -248,8 +262,8 @@ Passed as an argument to the emitted `controllerConfig` event handler.
### Properties
* `controllerId` - integer indicating the controller's ID
* `minSetPoint` - array (size 2) indicating the minimum setpoint available for the pool or spa
* `maxSetPoint` - array (size 2) indicating the maximum setpoint available for the pool or spa
* `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
* `hwType` - byte
@ -274,3 +288,24 @@ Passed as an argument to the emitted `controllerConfig` event handler.
* `pumpCircArray` - array (size 8) holding data about pumps attached to the system
* `interfaceTabFlags` - integer
* `showAlarms` - integer
## SLSetCircuitStateMessage
Passed as an argument to the emitted `circuitStateChanged`. The passed version is empty, however, since the response is just an acknowledgement of receipt of the set command.
### Properties
* `controllerId` - integer indicating the ID of the controller to send this command to.
* Note that while `SLControllerConfigMessage` includes a controllerId, this ID, in my experience, should always be 0.
* `circuitId` - integer indicating the ID of the circuit to set the state of.
* This ID can be retrieved from `SLControllerConfigMessage`'s `bodyArray` property.
* `circuitState` - integer indicating whether to switch the circuit on (`1`) or off (`0`).
# Changelog
## v1.0.1
* Added direct connection support.
## v1.1.0
* Added ability to set circuit state.
* Fixed FindUnits.sendServerBroadcast() failing in certain environments.

View File

@ -2,14 +2,23 @@ const ScreenLogic = require('./index');
var finder = new ScreenLogic.FindUnits();
finder.on('serverFound', function(server) {
var client = new ScreenLogic.UnitConnection(server);
finder.close();
connect(new ScreenLogic.UnitConnection(server));
});
finder.search();
// use this instead of the above `finder` logic if you want to use a direct connection
//connect(new ScreenLogic.UnitConnection(80, '10.0.0.85'));
function connect(client) {
client.on('loggedIn', function() {
this.getVersion();
}).on('version', function(version) {
this.getPoolStatus();
this.getChemicalData();
this.getSaltCellConfig();
this.getControllerConfig();
console.log(" version=" + version.version);
}).on('poolStatus', function(status) {
this.getChemicalData();
console.log(" pool ok=" + status.ok);
console.log(" air temp=" + status.airTemp);
console.log(" salt ppm=" + status.saltPPM);
@ -17,21 +26,18 @@ finder.on('serverFound', function(server) {
console.log(" saturation=" + status.saturation);
console.log(" spa active=" + status.isSpaActive());
console.log(" pool active=" + status.isPoolActive());
}).on('controllerConfig', function(config) {
console.log(" controller is in celsius=" + config.degC);
client.close();
finder.close();
}).on('chemicalData', function(chemData) {
this.getSaltCellConfig();
console.log(" calcium=" + chemData.calcium);
console.log(" cyanuric acid=" + chemData.cyanuricAcid);
console.log(" alkalinity=" + chemData.alkalinity);
}).on('saltCellConfig', function(saltCellConfig) {
this.getControllerConfig();
console.log(" salt cell installed=" + saltCellConfig.installed);
}).on('version', function(version) {
console.log(" version=" + version.version);
}).on('controllerConfig', function(config) {
console.log(" controller is in celsius=" + config.degC);
client.close();
});
client.connect();
});
finder.search();
}

View File

@ -44,7 +44,7 @@ class FindUnits extends EventEmitter {
}
sendServerBroadcast() {
var message = new Uint8Array(8);
var message = Buffer.alloc(8);
message[0] = 1;
this.finder.send(message, 0, message.length, 1444, "255.255.255.255");
//console.log("Looking for ScreenLogic hosts...");
@ -56,9 +56,15 @@ class FindUnits extends EventEmitter {
}
class UnitConnection extends EventEmitter {
constructor(server) {
constructor(server, address) {
super();
this.server = server;
if (typeof server === 'object') {
this.serverPort = server.port;
this.serverAddress = server.address;
} else {
this.serverPort = server;
this.serverAddress = address;
}
this.client = new net.Socket();
var _this = this;
@ -76,7 +82,7 @@ class UnitConnection extends EventEmitter {
connect() {
//console.log("connecting...");
var _this = this;
this.client.connect(this.server.port, this.server.address, function() {
this.client.connect(this.serverPort, this.serverAddress, function() {
_this.onConnected();
});
}
@ -121,6 +127,10 @@ class UnitConnection extends EventEmitter {
this.client.write(new messages.SLVersionMessage().toBuffer());
}
setCircuitState(controllerId, circuitId, circuitState) {
this.client.write(new messages.SLSetCircuitStateMessage(controllerId, circuitId, circuitState).toBuffer());
}
onClientMessage(msg) {
//console.log('received message of length ' + msg.length);
if (msg.length < 4) {
@ -157,6 +167,10 @@ class UnitConnection extends EventEmitter {
//console.log(" it's version");
this.emit('version', new messages.SLVersionMessage(msg));
break;
case messages.SLSetCircuitStateMessage.getResponseId():
//console.log(" it's circuit toggle ack");
this.emit('circuitStateChanged', new messages.SLSetCircuitStateMessage());
break;
default:
//console.log(" it's unknown. type: " + msgType);
break;

6
messages/SLMessage.js Executable file → Normal file
View File

@ -10,6 +10,8 @@ exports.SLMessage = class SLMessage extends SmartBuffer {
}
toBuffer() {
this.encode();
if (this._wroteSize === false) {
this.insertInt32LE(this.length - 4, 4);
this._wroteSize = true;
@ -54,4 +56,8 @@ exports.SLMessage = class SLMessage extends SmartBuffer {
this.messageId = this.readUInt16LE();
this.dataLength = this.readInt32LE();
}
encode() {
}
}

View File

@ -0,0 +1,25 @@
const SLMessage = require('./SLMessage.js').SLMessage;
const MSG_ID = 12530;
exports.SLSetCircuitStateMessage = class SLSetCircuitStateMessage extends SLMessage {
constructor(controllerId, circuitId, circuitState) {
super(0, MSG_ID);
this.controllerId = controllerId;
this.circuitId = circuitId;
this.circuitState = circuitState;
}
encode() {
this.writeInt32LE(this.controllerId || 0);
this.writeInt32LE(this.circuitId || 0);
this.writeInt32LE(this.circuitState || 0);
super.encode();
}
static getResponseId() {
return MSG_ID + 1;
}
}

1
messages/index.js Executable file → Normal file
View File

@ -5,3 +5,4 @@ exports.SLLoginMessage = require("./SLLoginMessage.js").SLLoginMessage;
exports.SLChemDataMessage = require("./SLChemDataMessage.js").SLChemDataMessage;
exports.SLSaltCellConfigMessage = require("./SLSaltCellConfigMessage.js").SLSaltCellConfigMessage;
exports.SLVersionMessage = require("./SLVersionMessage.js").SLVersionMessage;
exports.SLSetCircuitStateMessage = require("./SLSetCircuitStateMessage.js").SLSetCircuitStateMessage;

View File

@ -1,11 +1,17 @@
{
"name": "node-screenlogic",
"description": "Tool for connecting to Pentair ScreenLogic systems on the local network",
"version": "1.0.0",
"version": "1.1.0",
"main": "index.js",
"license": "MIT",
"repository": "https://github.com/parnic/node-screenlogic.git",
"main": "index.js",
"keywords": [
"pentair",
"pool",
"screenlogic",
"swimmingpool"
],
"dependencies": {
"smart-buffer": "~4.0.1"
}