15 Commits

Author SHA1 Message Date
4cfffdd9df Drop support for nodejs 10.x, add 14.x and 16.x
Update package.json version
2021-10-13 14:14:41 -05:00
ba6dac4399 Update changelog, dependencies 2021-10-13 14:12:05 -05:00
f406bccb5d Update coolSetPoint documentation per user findings
Closes #57
2021-09-06 23:09:44 -05:00
a5d207d3aa Add support for setting the current system date/time
#56
2021-09-06 23:02:02 -05:00
f271554d89 Add DateTime writing support to SLMessages
There may be some value in providing a read version of this as well, but
it is comprised of so many properties that I'm leaving that out for now.
If it becomes a need in the future, it will be straightforward to add.
2021-09-06 23:01:42 -05:00
37d40b3386 Add support for retrieving the current system date/time
#56
2021-09-06 23:00:51 -05:00
6f1ee3c13f Add info about add/remove client function events 2021-09-06 22:56:16 -05:00
0b990bbc28 Add links to time conversion functions 2021-09-06 21:51:50 -05:00
2aa14cc114 Fix SLGetScheduleData documentation 2021-09-06 21:51:50 -05:00
bef8e6a379 Bump glob-parent from 5.1.1 to 5.1.2
Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.1 to 5.1.2.
- [Release notes](https://github.com/gulpjs/glob-parent/releases)
- [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.1...v5.1.2)

---
updated-dependencies:
- dependency-name: glob-parent
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-11 07:23:37 -05:00
5bbbfb6f41 Bump lodash from 4.17.20 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-10 22:26:51 -05:00
fa43b3c03e Bump y18n from 4.0.0 to 4.0.1
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-31 14:36:05 -05:00
789f75f4a6 Add missing break 2020-12-12 21:14:41 -06:00
1ea8548991 Add handling/documentation for the scheduleChanged event
See discussion on #44 for more info
2020-12-12 21:12:15 -06:00
542d2f3e94 Disabled scheduled CodeQL runs 2020-11-28 19:44:23 -06:00
12 changed files with 603 additions and 576 deletions

View File

@ -11,8 +11,6 @@ on:
pull_request:
# The branches below must be a subset of the branches above
branches: [main]
schedule:
- cron: '0 8 * * 3'
jobs:
analyze:

View File

@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
node-version: [10.x, 12.x]
node-version: [12.x, 14.x, 16.x]
steps:
- uses: actions/checkout@v2

View File

@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## v1.7.0 - 2021-10-13
### Added
* Added handling/documentation for the scheduleChanged event (#44).
* Added support for getting and setting the system date/time.
### Fixed
* Documentation updates for `SLGetScheduleData`, more linkage for easy navigation, `addClient`/`removeClient` methods, clarified `coolSetPoint` for spas.
## v1.6.1 - 2020-11-23
### Added

View File

@ -33,6 +33,8 @@ Tested with a Pentair ScreenLogic system on firmware versions 5.2 Build 736.0 Re
* [SLCancelDelay](#slcanceldelay)
* [SLAddClient](#sladdclient)
* [SLRemoveClient](#slremoveclient)
* [SLGetSystemTime](#slgetsystemtime)
* [SLSetSystemTime](#slsetsystemtime)
## Usage
@ -256,15 +258,15 @@ Retrieves a list of schedule events of the specified type. See [`SLGetScheduleDa
#### addNewScheduleEvent(scheduleType, senderId)
Adds a new event to the specified schedule type. See [`SLAddNewScheduleEvent`](#sladdnewscheduleevent) documentation for argument values. Emits the `addNewScheduleEvent` event when response is acknowledged. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
Adds a new event to the specified schedule type. See [`SLAddNewScheduleEvent`](#sladdnewscheduleevent) documentation for argument values. Emits either the `addNewScheduleEvent` or `scheduleChanged` event when response is acknowledged (listen for both). `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
#### deleteScheduleEventById(scheduleId, senderId)
Deletes a scheduled event with specified id. See [`SLDeleteScheduleEventById`](#sldeletescheduleeventbyid) documentation for argument values. Emits the `deleteScheduleById` event when response is acknowledged. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
Deletes a scheduled event with specified id. See [`SLDeleteScheduleEventById`](#sldeletescheduleeventbyid) documentation for argument values. Emits the `deleteScheduleById` or `scheduleChanged` event when response is acknowledged (listen for both). `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
#### setScheduleEventById(scheduleId, circuitId, startTime, stopTime, dayMask, flags, heatCmd, heatSetPoint, senderId)
Configures a schedule event. See [`SLSetScheduleEventById`](#slsetscheduleeventbyid) documentation for argument values. Emits the `setScheduleEventById` event when response is acknowledged. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
Configures a schedule event. See [`SLSetScheduleEventById`](#slsetscheduleeventbyid) documentation for argument values. Emits the `setScheduleEventById` or `scheduleChanged` event when response is acknowledged (listen for both). `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
#### setCircuitRuntimebyId(circuitId, runTime, senderId)
@ -284,11 +286,19 @@ Cancels any delays on the system. See [`SLCancelDelay`](#slcanceldelay) document
#### addClient(clientId, senderId)
Registers to receive updates from controller when something changes. Takes a random number `clientId` to identify the client. Emits the `poolStatus` event when something changes on the controller. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
Registers to receive updates from controller when something changes. Takes a random number `clientId` to identify the client. Emits the `poolStatus` event when something changes on the controller, and the `addClient` event when the request to add a client is acknowledged. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
#### removeClient(clientId, senderId)
No longer receive `poolStatus` messages from controller. Takes a random number `clientId` that should match a previously registered client with `addClient`. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
No longer receive `poolStatus` messages from controller. Emits the `removeClient` event when the request to remove a client is acknowledged. Takes a random number `clientId` that should match a previously registered client with `addClient`. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
#### getSystemTime(senderId)
Retrieves the current time the system is set to. Emits the `getSystemTime` event when response is received. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
#### setSystemTime(date, adjustForDST, senderId)
Sets the current date and time of the ScreenLogic system. 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. `senderId` is an optional 16-bit integer and will be present as the `senderId` field on the returned message.
### Events
@ -307,10 +317,15 @@ No longer receive `poolStatus` messages from controller. Takes a random number `
* `addNewScheduleEvent` - Indicates that a response to `addNewScheduleEvent()` has been received which contains the created `scheduleId` to be used later for setting up the properties. Event handler receives a [`SLAddNewScheduleEvent`](#sladdnewscheduleevent) object.
* `deleteScheduleById` - Indicates that a response to `deleteScheduleById()` has been received. Event handler receives a [`SLDeleteScheduleEventById`](#sldeletescheduleeventbyid) object.
* `setScheduleEventById` - Indicates that a response to `setScheduleEventById()` has been received. Event handler receives a [`SLSetScheduleEventById`](#slsetscheduleeventbyid) 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.
* `setCircuitRuntimeById` - Indicates that a response to `setCircuitRuntimeById()` has been received. Event handler receives a [`SLSetCircuitRuntimeById`](#slsetcircuitruntimebyid) object.
* `getPumpStatus` - Indicates that a response to `getPumpStatus()` has been received. Event handler receives a [`SLGetPumpStatus`](#slgetpumpstatus) object.
* `setPumpFlow` - Indicates that a response to `setPumpFlow()` has been received. Event handler receives a [`SLSetPumpFlow`](#slsetpumpflow) object.
* `cancelDelay` - Indicates that a response to `cancelDelay()` has been received. Event handler receives a [`SLCancelDelay`](#slcanceldelay) object.
* `addClient` - Indicates that a response to `addClient()` has been received. Event handler receives a [`SLAddClient`](#sladdclient) object.
* `removeClient` - Indicates that a response to `removeClient()` has been received. Event handler receives a [`SLRemoveClient`](#slremoveclient) object.
* `getSystemTime` - Indicates that a response to `getSystemTime()` has been received. Event handler receives a [`SLGetSystemTime`](#slgetsystemtime) object.
* `setSystemTime` - Indicates that a response to `setSystemTime()` has been received. Event handler receives a [`SLSetSystemTime`](#slsetsystemtime) object if the request was valid, or `null` if the request was invalid (input parameters were not of the required types).
* `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.
* `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.
* `error` - Indicates that an unhandled error was caught (such as the connection timing out)
@ -412,7 +427,7 @@ Returns a bool indicating whether the pool is currently active or not.
* `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)
* `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)
@ -657,7 +672,24 @@ Passed as an argument to the emitted `getScheduleData` event. Retrieves a list o
#### Properties
* `scheduleType` - 0 indicates regular scheduled events, 1 indicates a run-once event
* `eventCount` - the number of `events` returned
* `events` - array containing:
* `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](#decodetimetime))
* `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](#decodetimetime))
* `dayMask` - 7-bit mask that determines which days the schedule is active for, MSB is always 0, valid numbers 1-127 (see [conversion functions](#decodedaymaskmask))
* `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:
* ScreenLogic.HEAT_MODE_OFF
* ScreenLogic.HEAT_MODE_SOLAR
* ScreenLogic.HEAT_MODE_SOLARPREFERRED
* ScreenLogic.HEAT_MODE_HEATPUMP
* ScreenLogic.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()`](#decodedaymaskmask) for convenience
### SLSetScheduleEventById
@ -667,10 +699,10 @@ Passed as an argument to the emitted `setScheduleEventById` event. Configures an
* `scheduleId` - id of a schedule previously created, see [`SLAddNewScheduleEvent`](#sladdnewscheduleevent)
* `circuitId` - id of the circuit to which this event applies
* `startTime` - the start time of the event, specified as minutes since midnight
* `startTime` - the start time of the event, specified as minutes since midnight (see [conversion functions](#encodetimetime))
* example: 6:00am would be 360
* example: 6:15am would be 375
* `stopTime` - the stop time of the event, specified as minutes since midnight
* `stopTime` - the stop time of the event, specified as minutes since midnight (see [conversion functions](#encodetimetime))
* `dayMask`
* 7-bit mask that determines which days the schedule is active for, MSB is always 0, valid numbers 1-127
* `flags`
@ -740,3 +772,24 @@ Passed as an argument to the emitted `addClient` event.
### SLRemoveClient
Passed as an argument to the emitted `removeClient` event.
### SLGetSystemTime
Contains information about the system's current time and date. Passed as an argument to the emitted `getSystemTime` event.
#### Properties
* `year` - short representing current system year
* `month` - short representing current system month (where 1 is January, 2 is February, etc.)
* `day` - short representing current system day of the month
* `dayOfWeek` - short representing current system day of the week (where 0 is Monday and 6 is Sunday)
* `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
* `date` - `Date` instance representing the current system datetime (convenience, constructed from the above properties)
### SLSetSystemTime
Passed as an argument to the emitted `setSystemTime` event.

View File

@ -297,6 +297,28 @@ class UnitConnection extends EventEmitter {
this.client.write(new messages.SLRemoveClient(clientId, senderId).toBuffer());
}
getSystemTime(senderId) {
debugUnit('[%d] sending get system time query...', senderId || 0);
this.client.write(new messages.SLGetSystemTime(null, senderId).toBuffer());
}
setSystemTime(date, shouldAdjustForDST, senderId) {
if (!(date instanceof Date)) {
debugUnit('setSystemTime() must receive valid Date object for the date argument');
this.emit('setSystemTime', null);
return;
}
if (typeof shouldAdjustForDST !== 'boolean') {
debugUnit('setSystemTime() must receive a boolean for the shouldAdjustForDST argument');
this.emit('setSystemTime', null);
return;
}
debugUnit('[%d] sending set system time command...', senderId || 0);
this.client.write(new messages.SLSetSystemTime(null, date, shouldAdjustForDST, senderId).toBuffer());
}
onClientMessage(msg) {
debugUnit('received message of length %d', msg.length);
if (msg.length < 4) {
@ -402,6 +424,18 @@ class UnitConnection extends EventEmitter {
debugUnit(" it's async pool status");
this.emit('poolStatus', new messages.SLPoolStatusMessage(msg));
break;
case messages.SLGetSystemTime.getResponseId():
debugUnit(" it's system time");
this.emit('getSystemTime', new messages.SLGetSystemTime(msg));
break;
case messages.SLSetSystemTime.getResponseId():
debugUnit(" it's a set system time ack");
this.emit('setSystemTime', new messages.SLSetSystemTime(msg));
break;
case 12501:
debugUnit(" it's a schedule changed notification");
this.emit('scheduleChanged');
break;
case 13:
debugUnit(" it's a login failure.");
this.emit('loginFailed');

View File

@ -0,0 +1,37 @@
'use strict';
const SLMessage = require('./SLMessage.js').SLMessage;
const MSG_ID = 8110;
exports.SLGetSystemTime = class SLGetSystemTime extends SLMessage {
constructor(buf, senderId) {
if (buf) {
var size = buf.readInt32LE(4) + 8;
super(buf, MSG_ID, size);
} else {
super(senderId, MSG_ID);
}
}
decode() {
super.decode();
this.year = this.readUInt16LE();
this.month = this.readUInt16LE();
this.dayOfWeek = this.readUInt16LE();
this.day = this.readUInt16LE();
this.hour = this.readUInt16LE();
this.minute = this.readUInt16LE();
this.second = this.readUInt16LE();
this.millisecond = this.readUInt16LE();
var adjustForDST = this.readInt32LE();
this.adjustForDST = adjustForDST === 1;
this.date = new Date(this.year, this.month - 1, this.day, this.hour, this.minute, this.second);
}
static getResponseId() {
return MSG_ID + 1;
}
};

View File

@ -150,6 +150,21 @@ exports.SLMessage = class SLMessage extends SmartBuffer {
return 0;
}
writeSLDateTime(date) {
this.writeInt16LE(date.getFullYear());
this.writeInt16LE(date.getMonth() + 1);
var dayOfWeek = date.getDay() - 1;
if (dayOfWeek < 0) {
dayOfWeek = 6;
}
this.writeInt16LE(dayOfWeek);
this.writeInt16LE(date.getDate());
this.writeInt16LE(date.getHours());
this.writeInt16LE(date.getMinutes());
this.writeInt16LE(date.getSeconds());
this.writeInt16LE(date.getMilliseconds());
}
static slackForAlignment(val) {
return (4 - val % 4) % 4;
}

View File

@ -0,0 +1,28 @@
'use strict';
const SLMessage = require('./SLMessage.js').SLMessage;
const MSG_ID = 8112;
exports.SLSetSystemTime = class SLSetSystemTime extends SLMessage {
constructor(buf, date, shouldAdjustForDST, senderId) {
if (buf) {
var size = buf.readInt32LE(4) + 8;
super(buf, MSG_ID, size);
} else {
super(senderId, MSG_ID);
this.date = date;
this.shouldAdjustForDST = shouldAdjustForDST;
}
}
encode() {
this.writeSLDateTime(this.date);
this.writeInt32LE(this.shouldAdjustForDST ? 1 : 0);
}
static getResponseId() {
return MSG_ID + 1;
}
};

View File

@ -25,3 +25,5 @@ exports.SLSetPumpFlow = require('./SLSetPumpFlow.js').SLSetPumpFlow;
exports.SLCancelDelay = require('./SLCancelDelay.js').SLCancelDelay;
exports.SLAddClient = require('./SLAddClient.js').SLAddClient;
exports.SLRemoveClient = require('./SLRemoveClient.js').SLRemoveClient;
exports.SLGetSystemTime = require('./SLGetSystemTime.js').SLGetSystemTime;
exports.SLSetSystemTime = require('./SLSetSystemTime.js').SLSetSystemTime;

950
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
"name": "node-screenlogic",
"description": "Tool for connecting to Pentair ScreenLogic systems on the local network",
"version": "1.6.1",
"version": "1.7.0",
"main": "index.js",
"license": "MIT",
"repository": "https://github.com/parnic/node-screenlogic.git",
@ -12,13 +12,13 @@
"swimmingpool"
],
"dependencies": {
"debug": "^4.3.1",
"smart-buffer": "~4.1.0"
"debug": "^4.3.2",
"smart-buffer": "^4.2.0"
},
"devDependencies": {
"eslint": "^7.14.0",
"eslint": "^8.0.0",
"eslint-config-strongloop": "^2.1.0",
"mocha": "^8.2.1"
"mocha": "^9.1.2"
},
"scripts": {
"test": "mocha test/*.spec.js",

View File

@ -172,4 +172,21 @@ describe('SLMessage utilities', function() {
assert.strictEqual(decodedMsg.dataLength, decodedMsg.readOffset - 8);
}
});
it('encodes Date as SLTime', function() {
let msg = new SLMessage();
let date = new Date(2021, 8, 6, 22, 8, 5);
msg.writeSLDateTime(date);
let decodedMsg = new SLMessage(msg.toBuffer());
assert.equal(decodedMsg.readUInt16LE(), 2021);
// javascript Date() month is 0-based, ScreenLogic month matches the calendar
assert.equal(decodedMsg.readUInt16LE(), 9);
// ScreenLogic day-of-week starts with Monday as 0
assert.equal(decodedMsg.readUInt16LE(), 0);
assert.equal(decodedMsg.readUInt16LE(), 6);
assert.equal(decodedMsg.readUInt16LE(), 22);
assert.equal(decodedMsg.readUInt16LE(), 8);
assert.equal(decodedMsg.readUInt16LE(), 5);
assert.equal(decodedMsg.readUInt16LE(), 0);
});
});