Added decoding of messages
Also moved things out to their own files and setup require()s to bring it all together.
This commit is contained in:
75
index.js
75
index.js
@ -1,45 +1,7 @@
|
|||||||
var dgram = require('dgram');
|
var dgram = require('dgram');
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
const SmartBuffer = require('smart-buffer').SmartBuffer;
|
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
const messages = require('./messages');
|
||||||
class SLMessage extends SmartBuffer {
|
|
||||||
constructor(senderId, messageId) {
|
|
||||||
super();
|
|
||||||
this.writeUInt16LE(senderId);
|
|
||||||
this.writeUInt16LE(messageId);
|
|
||||||
|
|
||||||
this._wroteSize = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
toBuffer() {
|
|
||||||
if (this._wroteSize === false) {
|
|
||||||
this.insertInt32LE(this.length - 4, 4);
|
|
||||||
this._wroteSize = true;
|
|
||||||
} else {
|
|
||||||
this.writeInt32LE(this.length - 8, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.toBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
writeSLString(str) {
|
|
||||||
this.writeInt32LE(str.length);
|
|
||||||
this.writeString(str);
|
|
||||||
this.skip(4 - (str.length % 4));
|
|
||||||
}
|
|
||||||
|
|
||||||
writeSLBuffer(buf) {
|
|
||||||
this.writeInt32LE(buf.length);
|
|
||||||
this.writeBuffer(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
skip(num) {
|
|
||||||
if (num > 0) {
|
|
||||||
this.writeBuffer(Buffer.alloc(num));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FindUnits extends EventEmitter {
|
class FindUnits extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -124,44 +86,22 @@ class UnitConnection extends EventEmitter {
|
|||||||
this.client.write('CONNECTSERVERHOST\r\n\r\n');
|
this.client.write('CONNECTSERVERHOST\r\n\r\n');
|
||||||
|
|
||||||
console.log('sending challenge message...');
|
console.log('sending challenge message...');
|
||||||
var buf = new SLMessage(0, 14);
|
this.client.write(new messages.SLChallengeMessage().toBuffer());
|
||||||
this.client.write(buf.toBuffer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
login() {
|
login() {
|
||||||
console.log('sending login message...');
|
console.log('sending login message...');
|
||||||
var buf = new SLMessage(0, 27);
|
this.client.write(new messages.SLLoginMessage().toBuffer());
|
||||||
buf.writeInt32LE(348); // schema
|
|
||||||
buf.writeInt32LE(0); // connection type
|
|
||||||
buf.writeSLString('ScreenLogicConnect library'); // version
|
|
||||||
buf.writeSLBuffer(Buffer.alloc(16)); // encoded password. empty/unused for local connections
|
|
||||||
buf.writeInt32LE(2); // procID
|
|
||||||
this.client.write(buf.toBuffer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getPoolStatus() {
|
getPoolStatus() {
|
||||||
console.log('sending pool status query...');
|
console.log('sending pool status query...');
|
||||||
var buf = new SLMessage(0, 12526);
|
this.client.write(new messages.SLPoolStatusMessage().toBuffer());
|
||||||
buf.writeInt32LE(0);
|
|
||||||
this.client.write(buf.toBuffer());
|
|
||||||
}
|
|
||||||
|
|
||||||
parsePoolStatus(msg) {
|
|
||||||
// todo: actually parse the message
|
|
||||||
this.emit('poolStatus', {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getControllerConfig() {
|
getControllerConfig() {
|
||||||
console.log('sending controller config query...');
|
console.log('sending controller config query...');
|
||||||
var buf = new SLMessage(0, 12532);
|
this.client.write(new messages.SLControllerConfigMessage().toBuffer());
|
||||||
buf.writeInt32LE(0);
|
|
||||||
buf.writeInt32LE(0);
|
|
||||||
this.client.write(buf.toBuffer());
|
|
||||||
}
|
|
||||||
|
|
||||||
parseControllerConfig(msg) {
|
|
||||||
// todo: actually parse the message
|
|
||||||
this.emit('controllerConfig', {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onClientMessage(msg) {
|
onClientMessage(msg) {
|
||||||
@ -175,10 +115,10 @@ class UnitConnection extends EventEmitter {
|
|||||||
this.emit('loggedIn');
|
this.emit('loggedIn');
|
||||||
} else if (msgType === 12527) {
|
} else if (msgType === 12527) {
|
||||||
console.log(" it's pool status");
|
console.log(" it's pool status");
|
||||||
this.parsePoolStatus(msg);
|
this.emit('poolStatus', new messages.SLPoolStatusMessage(msg));
|
||||||
} else if (msgType === 12533) {
|
} else if (msgType === 12533) {
|
||||||
console.log(" it's controller configuration");
|
console.log(" it's controller configuration");
|
||||||
this.parseControllerConfig(msg);
|
this.emit('controllerConfig', new messages.SLControllerConfigMessage(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,6 +131,5 @@ for (const value of buf.values()) {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
FindUnits,
|
FindUnits,
|
||||||
SLMessage,
|
|
||||||
UnitConnection
|
UnitConnection
|
||||||
}
|
}
|
||||||
|
7
messages/SLChallengeMessage.js
Executable file
7
messages/SLChallengeMessage.js
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||||
|
|
||||||
|
exports.SLChallengeMessage = class SLChallengeMessage extends SLMessage {
|
||||||
|
constructor() {
|
||||||
|
super(0, 14);
|
||||||
|
}
|
||||||
|
}
|
78
messages/SLControllerConfigMessage.js
Executable file
78
messages/SLControllerConfigMessage.js
Executable file
@ -0,0 +1,78 @@
|
|||||||
|
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||||
|
|
||||||
|
exports.SLControllerConfigMessage = class SLControllerConfigMessage extends SLMessage {
|
||||||
|
constructor(buf) {
|
||||||
|
super(0, 12532);
|
||||||
|
if (!buf) {
|
||||||
|
this.writeInt32LE(0);
|
||||||
|
this.writeInt32LE(0);
|
||||||
|
} else {
|
||||||
|
this._wroteSize = true;
|
||||||
|
this.writeBuffer(buf, 0);
|
||||||
|
|
||||||
|
this.decode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decode() {
|
||||||
|
super.decode();
|
||||||
|
|
||||||
|
this.controllerId = this.readInt32LE();
|
||||||
|
|
||||||
|
this.minSetPoint = new Array(2);
|
||||||
|
this.maxSetPoint = new Array(2);
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
this.minSetPoint[i] = this.readUInt8();
|
||||||
|
this.maxSetPoint[i] = this.readUInt8();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.degC = this.readUInt8();
|
||||||
|
this.controllerType = this.readUInt8();
|
||||||
|
this.hwType = this.readUInt8();
|
||||||
|
this.controllerData = this.readUInt8();
|
||||||
|
this.equipFlags = this.readInt32LE();
|
||||||
|
this.genCircuitName = this.readSLString();
|
||||||
|
|
||||||
|
let circuitCount = this.readInt32LE();
|
||||||
|
this.bodyArray = new Array(circuitCount);
|
||||||
|
for (let i = 0; i < circuitCount; i++) {
|
||||||
|
this.bodyArray[i] = {
|
||||||
|
circuitId: this.readInt32LE(),
|
||||||
|
name: this.readSLString(),
|
||||||
|
nameIndex: this.readUInt8(),
|
||||||
|
function: this.readUInt8(),
|
||||||
|
interface: this.readUInt8(),
|
||||||
|
flags: this.readUInt8(),
|
||||||
|
colorSet: this.readUInt8(),
|
||||||
|
colorPos: this.readUInt8(),
|
||||||
|
colorStagger: this.readUInt8(),
|
||||||
|
deviceId: this.readUInt8(),
|
||||||
|
dfaultRt: this.readUInt16LE(),
|
||||||
|
pad1: this.readUInt8(),
|
||||||
|
pad2: this.readUInt8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let colorCount = this.readInt32LE();
|
||||||
|
this.colorArray = new Array(colorCount);
|
||||||
|
for (let i = 0; i < colorCount; i++) {
|
||||||
|
this.colorArray[i] = {
|
||||||
|
name: this.readSLString(),
|
||||||
|
color: {
|
||||||
|
r: this.readInt32LE() & 0xFF,
|
||||||
|
g: this.readInt32LE() & 0xFF,
|
||||||
|
b: this.readInt32LE() & 0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pumpCircCount = 8;
|
||||||
|
this.pumpCircArray = new Array(pumpCircCount);
|
||||||
|
for (let i = 0; i < pumpCircCount; i++) {
|
||||||
|
this.pumpCircArray[i] = this.readUInt8();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.interfaceTabFlags = this.readInt32LE();
|
||||||
|
this.showAlarms = this.readInt32LE();
|
||||||
|
}
|
||||||
|
}
|
12
messages/SLLoginMessage.js
Executable file
12
messages/SLLoginMessage.js
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||||
|
|
||||||
|
exports.SLLoginMessage = class SLLoginMessage extends SLMessage {
|
||||||
|
constructor() {
|
||||||
|
super(0, 27);
|
||||||
|
this.writeInt32LE(348); // schema
|
||||||
|
this.writeInt32LE(0); // connection type
|
||||||
|
this.writeSLString('node-screenlogic'); // version
|
||||||
|
this.writeSLBuffer(Buffer.alloc(16)); // encoded password. empty/unused for local connections
|
||||||
|
this.writeInt32LE(2); // procID
|
||||||
|
}
|
||||||
|
}
|
57
messages/SLMessage.js
Executable file
57
messages/SLMessage.js
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
const SmartBuffer = require('smart-buffer').SmartBuffer;
|
||||||
|
|
||||||
|
exports.SLMessage = class SLMessage extends SmartBuffer {
|
||||||
|
constructor(senderId, messageId) {
|
||||||
|
super();
|
||||||
|
this.writeUInt16LE(senderId);
|
||||||
|
this.writeUInt16LE(messageId);
|
||||||
|
|
||||||
|
this._wroteSize = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
toBuffer() {
|
||||||
|
if (this._wroteSize === false) {
|
||||||
|
this.insertInt32LE(this.length - 4, 4);
|
||||||
|
this._wroteSize = true;
|
||||||
|
} else {
|
||||||
|
this.writeInt32LE(this.length - 8, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.toBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSLString(str) {
|
||||||
|
this.writeInt32LE(str.length);
|
||||||
|
this.writeString(str);
|
||||||
|
if (str.length % 4 != 0) {
|
||||||
|
this.skipWrite(4 - (str.length % 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readSLString() {
|
||||||
|
var len = this.readInt32LE();
|
||||||
|
var str = this.readString(len);
|
||||||
|
if (len % 4 != 0) {
|
||||||
|
this.readOffset += 4 - (len % 4);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSLBuffer(buf) {
|
||||||
|
this.writeInt32LE(buf.length);
|
||||||
|
this.writeBuffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipWrite(num) {
|
||||||
|
if (num > 0) {
|
||||||
|
this.writeBuffer(Buffer.alloc(num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decode() {
|
||||||
|
this.readOffset = 0;
|
||||||
|
this.senderId = this.readUInt16LE();
|
||||||
|
this.messageId = this.readUInt16LE();
|
||||||
|
this.dataLength = this.readInt32LE();
|
||||||
|
}
|
||||||
|
}
|
70
messages/SLPoolStatusMessage.js
Executable file
70
messages/SLPoolStatusMessage.js
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
const SLMessage = require('./SLMessage.js').SLMessage;
|
||||||
|
|
||||||
|
exports.SLPoolStatusMessage = class SLPoolStatusMessage extends SLMessage {
|
||||||
|
constructor(buf) {
|
||||||
|
super(0, 12526);
|
||||||
|
if (!buf) {
|
||||||
|
this.writeInt32LE(0);
|
||||||
|
} else {
|
||||||
|
this._wroteSize = true;
|
||||||
|
this.writeBuffer(buf, 0);
|
||||||
|
|
||||||
|
this.decode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decode() {
|
||||||
|
super.decode();
|
||||||
|
|
||||||
|
this.ok = this.readInt32LE();
|
||||||
|
this.freezeMode = this.readUInt8();
|
||||||
|
this.remotes = this.readUInt8();
|
||||||
|
this.poolDelay = this.readUInt8();
|
||||||
|
this.spaDelay = this.readUInt8();
|
||||||
|
this.cleanerDelay = this.readUInt8();
|
||||||
|
this.readOffset += 3;
|
||||||
|
this.airTemp = this.readInt32LE();
|
||||||
|
|
||||||
|
let bodiesCount = this.readInt32LE();
|
||||||
|
if (bodiesCount > 2) {
|
||||||
|
bodiesCount = 2;
|
||||||
|
}
|
||||||
|
this.currentTemp = new Array(bodiesCount);
|
||||||
|
this.heatStatus = new Array(bodiesCount);
|
||||||
|
this.setPoint = new Array(bodiesCount);
|
||||||
|
this.coolSetPoint = new Array(bodiesCount);
|
||||||
|
this.heatMode = new Array(bodiesCount);
|
||||||
|
for (let i = 0; i < bodiesCount; i++) {
|
||||||
|
let bodyType = this.readInt32LE();
|
||||||
|
if (bodyType < 0 || bodyType >= 2) {
|
||||||
|
bodyType = 0;
|
||||||
|
}
|
||||||
|
this.currentTemp[bodyType] = this.readInt32LE();
|
||||||
|
this.heatStatus[bodyType] = this.readInt32LE();
|
||||||
|
this.setPoint[bodyType] = this.readInt32LE();
|
||||||
|
this.coolSetPoint[bodyType] = this.readInt32LE();
|
||||||
|
this.heatMode[bodyType] = this.readInt32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
let circuitCount = this.readInt32LE();
|
||||||
|
this.circuitArray = new Array(circuitCount);
|
||||||
|
for (let i = 0; i < circuitCount; i++) {
|
||||||
|
this.circuitArray[i] = {
|
||||||
|
id: this.readInt32LE(),
|
||||||
|
state: this.readInt32LE(),
|
||||||
|
colorSet: this.readUInt8(),
|
||||||
|
colorPos: this.readUInt8(),
|
||||||
|
colorStagger: this.readUInt8(),
|
||||||
|
delay: this.readUInt8()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pH = this.readInt32LE();
|
||||||
|
this.orp = this.readInt32LE();
|
||||||
|
this.saturation = this.readInt32LE();
|
||||||
|
this.saltPPM = this.readInt32LE();
|
||||||
|
this.pHTank = this.readInt32LE();
|
||||||
|
this.orpTank = this.readInt32LE();
|
||||||
|
this.alarms = this.readInt32LE();
|
||||||
|
}
|
||||||
|
}
|
4
messages/index.js
Executable file
4
messages/index.js
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
exports.SLPoolStatusMessage = require("./SLPoolStatusMessage.js").SLPoolStatusMessage;
|
||||||
|
exports.SLControllerConfigMessage = require("./SLControllerConfigMessage.js").SLControllerConfigMessage;
|
||||||
|
exports.SLChallengeMessage = require("./SLChallengeMessage.js").SLChallengeMessage;
|
||||||
|
exports.SLLoginMessage = require("./SLLoginMessage.js").SLLoginMessage;
|
@ -5,6 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/parnic/ScreenLogicConnect-NodeJS.git",
|
"repository": "https://github.com/parnic/ScreenLogicConnect-NodeJS.git",
|
||||||
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"smart-buffer": "~4.0.1"
|
"smart-buffer": "~4.0.1"
|
||||||
}
|
}
|
||||||
|
5
test.js
5
test.js
@ -7,7 +7,12 @@ finder.on('serverFound', function(server) {
|
|||||||
this.getPoolStatus();
|
this.getPoolStatus();
|
||||||
this.getControllerConfig();
|
this.getControllerConfig();
|
||||||
}).on('poolStatus', function(status) {
|
}).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);
|
||||||
}).on('controllerConfig', function(config) {
|
}).on('controllerConfig', function(config) {
|
||||||
|
console.log(" controller is in celsius=" + config.degC);
|
||||||
client.close();
|
client.close();
|
||||||
finder.close();
|
finder.close();
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user