From 3262ac428bea821a0cbfe3a0e203a09f6faff512 Mon Sep 17 00:00:00 2001 From: Parnic Date: Fri, 30 Mar 2018 19:59:17 -0500 Subject: [PATCH] Added chem data Added salt cell config Added system version Tweaked pool status to pre-adjust values Chem data uses big endian encoding for most of its values (but not all) while everything else (so far) has used little endian. Chem data also encodes bits like whether there's a system error or not inside other pieces of data like salt levels. There are also bytes in the returned data that I don't know the significance of just yet. Pool status was tweaked such that asking for pH is corrected down to its proper float representation (e.g. 7.60) instead of the integer representation that is sent by the system (760). Same for water balance/saturation. Salt now returns the proper value (scaled up by 50) instead of the value sent over by the system, which I guess is the maximum precision the system can provide. --- index.js | 26 ++++++++++++++++ messages/SLChemDataMessage.js | 48 +++++++++++++++++++++++++++++ messages/SLPoolStatusMessage.js | 6 ++-- messages/SLSaltCellConfigMessage.js | 27 ++++++++++++++++ messages/SLVersionMessage.js | 19 ++++++++++++ messages/index.js | 3 ++ test.js | 16 ++++++++-- 7 files changed, 140 insertions(+), 5 deletions(-) create mode 100755 messages/SLChemDataMessage.js create mode 100755 messages/SLSaltCellConfigMessage.js create mode 100755 messages/SLVersionMessage.js diff --git a/index.js b/index.js index 29e5868..1e54c8d 100644 --- a/index.js +++ b/index.js @@ -104,6 +104,21 @@ class UnitConnection extends EventEmitter { this.client.write(new messages.SLControllerConfigMessage().toBuffer()); } + getChemicalData() { + console.log('sending chemical data query...'); + this.client.write(new messages.SLChemDataMessage().toBuffer()); + } + + getSaltCellConfig() { + console.log('sending salt cell config query...'); + this.client.write(new messages.SLSaltCellConfigMessage().toBuffer()); + } + + getVersion() { + console.log('sending version query...'); + this.client.write(new messages.SLVersionMessage().toBuffer()); + } + onClientMessage(msg) { console.log('received message of length ' + msg.length); var msgType = msg.readInt16LE(2); @@ -119,6 +134,17 @@ class UnitConnection extends EventEmitter { } else if (msgType === 12533) { console.log(" it's controller configuration"); this.emit('controllerConfig', new messages.SLControllerConfigMessage(msg)); + } else if (msgType === 12593) { + console.log(" it's chem data"); + this.emit('chemicalData', new messages.SLChemDataMessage(msg)); + } else if (msgType === 12573) { + console.log(" it's salt cell config"); + this.emit('saltCellConfig', new messages.SLSaltCellConfigMessage(msg)); + } else if (msgType === 8121) { + console.log(" it's version"); + this.emit('version', new messages.SLVersionMessage(msg)); + } else { + console.log(" it's unknown. type: " + msgType); } } } diff --git a/messages/SLChemDataMessage.js b/messages/SLChemDataMessage.js new file mode 100755 index 0000000..9ed57d4 --- /dev/null +++ b/messages/SLChemDataMessage.js @@ -0,0 +1,48 @@ +const SLMessage = require('./SLMessage.js').SLMessage; + +exports.SLChemDataMessage = class SLChemDataMessage extends SLMessage { + constructor(buf) { + super(0, 12592); + if (!buf) { + this.writeInt32LE(0); // controller index + } else { + this._wroteSize = true; + this.writeBuffer(buf, 0); + + this.decode(); + } + } + + decode() { + super.decode(); + + let sentinel = this.readInt32LE(); + if (sentinel === 42) { + this.isValid = true; + this._readOffset++; + this.pH = this.readUInt16BE() / 100; + this.orp = this.readUInt16BE(); + this.pHSetPoint = this.readUInt16BE() / 100; + this.orpSetPoint = this.readUInt16BE(); + this._readOffset += 12; + this.pHTankLevel = this.readUInt8(); + this.orpTankLevel = this.readUInt8(); + this.saturation = this.readUInt8(); + if ((this.saturation & 128) !== 0) { + this.saturation = -(256 - this.saturation); + } + this.saturation /= 100; + this.calcium = this.readUInt16BE(); + this.cyanuricAcid = this.readUInt16BE(); + this.alkalinity = this.readUInt16BE(); + let salt = this.readUInt16LE(); + this.saltPPM = salt * 50; + this.temperature = this.readUInt8(); + this._readOffset += 2; + let balance = this.readUInt8(); + this.corrosive = (balance & 1) !== 0; + this.scaling = (balance & 2) !== 0; + this.error = (salt & 128) !== 0; + } + } +} diff --git a/messages/SLPoolStatusMessage.js b/messages/SLPoolStatusMessage.js index 0d2d6f3..6c8d69b 100755 --- a/messages/SLPoolStatusMessage.js +++ b/messages/SLPoolStatusMessage.js @@ -59,10 +59,10 @@ exports.SLPoolStatusMessage = class SLPoolStatusMessage extends SLMessage { } } - this.pH = this.readInt32LE(); + this.pH = this.readInt32LE() / 100; this.orp = this.readInt32LE(); - this.saturation = this.readInt32LE(); - this.saltPPM = this.readInt32LE(); + this.saturation = this.readInt32LE() / 100; + this.saltPPM = this.readInt32LE() * 50; this.pHTank = this.readInt32LE(); this.orpTank = this.readInt32LE(); this.alarms = this.readInt32LE(); diff --git a/messages/SLSaltCellConfigMessage.js b/messages/SLSaltCellConfigMessage.js new file mode 100755 index 0000000..b542f31 --- /dev/null +++ b/messages/SLSaltCellConfigMessage.js @@ -0,0 +1,27 @@ +const SLMessage = require('./SLMessage.js').SLMessage; + +exports.SLSaltCellConfigMessage = class SLSaltCellConfigMessage extends SLMessage { + constructor(buf) { + super(0, 12572); + if (!buf) { + this.writeInt32LE(0); // controller index + } else { + this._wroteSize = true; + this.writeBuffer(buf, 0); + + this.decode(); + } + } + + decode() { + super.decode(); + + this.installed = this.readInt32LE() === 1; + this.status = this.readInt32LE(); + this.level1 = this.readInt32LE(); + this.level2 = this.readInt32LE(); + this.salt = this.readInt32LE() * 50; + this.flags = this.readInt32LE(); + this.superChlorTimer = this.readInt32LE(); + } +} diff --git a/messages/SLVersionMessage.js b/messages/SLVersionMessage.js new file mode 100755 index 0000000..35c58de --- /dev/null +++ b/messages/SLVersionMessage.js @@ -0,0 +1,19 @@ +const SLMessage = require('./SLMessage.js').SLMessage; + +exports.SLVersionMessage = class SLVersionMessage extends SLMessage { + constructor(buf) { + super(0, 8120); + if (buf) { + this._wroteSize = true; + this.writeBuffer(buf, 0); + + this.decode(); + } + } + + decode() { + super.decode(); + + this.version = this.readSLString(); + } +} diff --git a/messages/index.js b/messages/index.js index abe6af3..d7d7377 100755 --- a/messages/index.js +++ b/messages/index.js @@ -2,3 +2,6 @@ exports.SLPoolStatusMessage = require("./SLPoolStatusMessage.js").SLPoolStatusMe exports.SLControllerConfigMessage = require("./SLControllerConfigMessage.js").SLControllerConfigMessage; exports.SLChallengeMessage = require("./SLChallengeMessage.js").SLChallengeMessage; exports.SLLoginMessage = require("./SLLoginMessage.js").SLLoginMessage; +exports.SLChemDataMessage = require("./SLChemDataMessage.js").SLChemDataMessage; +exports.SLSaltCellConfigMessage = require("./SLSaltCellConfigMessage.js").SLSaltCellConfigMessage; +exports.SLVersionMessage = require("./SLVersionMessage.js").SLVersionMessage; diff --git a/test.js b/test.js index b228978..a024230 100755 --- a/test.js +++ b/test.js @@ -4,17 +4,29 @@ var finder = new ScreenLogic.FindUnits(); finder.on('serverFound', function(server) { var client = new ScreenLogic.UnitConnection(server); client.on('loggedIn', function() { + this.getVersion(); this.getPoolStatus(); + this.getChemicalData(); + this.getSaltCellConfig(); this.getControllerConfig(); }).on('poolStatus', function(status) { console.log(" pool ok=" + status.ok); console.log(" air temp=" + status.airTemp); - console.log(" salt ppm=" + status.saltPPM * 50); - console.log(" pH=" + status.pH / 100); + console.log(" salt ppm=" + status.saltPPM); + console.log(" pH=" + status.pH); + console.log(" saturation=" + status.saturation); }).on('controllerConfig', function(config) { console.log(" controller is in celsius=" + config.degC); client.close(); finder.close(); + }).on('chemicalData', function(chemData) { + console.log(" calcium=" + chemData.calcium); + console.log(" cyanuric acid=" + chemData.cyanuricAcid); + console.log(" alkalinity=" + chemData.alkalinity); + }).on('saltCellConfig', function(saltCellConfig) { + console.log(" salt cell installed=" + saltCellConfig.installed); + }).on('version', function(version) { + console.log(" version=" + version.version); }); client.connect();