Split into commonjs and ESM outputs

This allows require() and import to work for even better compatibility between CJS and ESM consumers.

I dislike that this kills our ability for top-level awaits in example.ts, but seeing as how my primary use case for this library is a commonjs module, I think this is a fair trade-off.

Also changed "messages" to not encapsulate its export under the name "messages" to remove some repetition in importing "messages" and still needing to do "messages." to get the methods out. Now it's simple to import each message by name or group them under something like "messages" as desired on a per-library-user basis.

Refs:
* https://www.kravchyk.com/typescript-npm-package-json-exports/
* https://arethetypeswrong.github.io/
* https://evertpot.com/universal-commonjs-esm-typescript-packages/
This commit is contained in:
2025-01-05 15:17:47 -06:00
parent 861fec9565
commit c445a844ee
133 changed files with 1872 additions and 185 deletions

View File

@ -38,28 +38,40 @@ jobs:
id: lint
run: npm run lint
# This will fail the workflow if the `dist/` directory is different than
# expected.
# This will fail the workflow if either of the output directories are different
# than expected.
- name: Compare Directories
id: diff
run: |
if [ ! -d dist/ ]; then
echo "Expected dist/ directory does not exist. See status below:"
if [ ! -d cjs/ ]; then
echo "Expected cjs/ directory does not exist. See status below:"
ls -la ./
exit 1
fi
if [ "$(git diff --ignore-space-at-eol --text dist/ | wc -l)" -gt "0" ]; then
if [ "$(git diff --ignore-space-at-eol --text cjs/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff --ignore-space-at-eol --text dist/
git diff --ignore-space-at-eol --text cjs/
exit 1
fi
if [ ! -d esm/ ]; then
echo "Expected esm/ directory does not exist. See status below:"
ls -la ./
exit 1
fi
if [ "$(git diff --ignore-space-at-eol --text esm/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff --ignore-space-at-eol --text esm/
exit 1
fi
# If `dist/` was different than expected, upload the expected version as a
# If outdir was different than expected, upload the expected version as a
# workflow artifact.
- if: ${{ failure() && steps.diff.outcome == 'failure' }}
name: Upload Artifact
id: upload
uses: actions/upload-artifact@v4
with:
name: dist-${{ matrix.node-version }}-diff
path: dist/
name: outdir-${{ matrix.node-version }}-diff
path: |
cjs/
esm/

View File

@ -1,3 +1,4 @@
/.github/
/dist/
/cjs/
/esm/
/connection-logs/

View File

169
cjs/dns.js Normal file
View File

@ -0,0 +1,169 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ARecord = exports.SrvRecord = exports.TxtRecord = exports.PtrRecord = exports.Record = exports.Question = exports.TypeA = exports.TypeSrv = exports.TypePtr = exports.TypeTxt = void 0;
exports.ipToString = ipToString;
exports.GetDNSQuestion = GetDNSQuestion;
exports.GetDNSAnswer = GetDNSAnswer;
exports.TypeTxt = 16;
exports.TypePtr = 12;
exports.TypeSrv = 33;
exports.TypeA = 1;
class Question {
name = "";
type = 0;
class = 0;
endOffset = 0;
}
exports.Question = Question;
class Record {
type = 0;
ttlSeconds = 0;
name = "";
endOffset = -1;
}
exports.Record = Record;
class PtrRecord extends Record {
domain = "";
}
exports.PtrRecord = PtrRecord;
class TxtRecord extends Record {
text = "";
}
exports.TxtRecord = TxtRecord;
class SrvRecord extends Record {
priority = 0;
weight = 0;
port = 0;
target = "";
}
exports.SrvRecord = SrvRecord;
class ARecord extends Record {
address = 0;
get addressStr() {
return ipToString(this.address);
}
}
exports.ARecord = ARecord;
function ipToString(ip) {
const o1 = (ip >> 24) & 0xff;
const o2 = (ip >> 16) & 0xff;
const o3 = (ip >> 8) & 0xff;
const o4 = (ip >> 0) & 0xff;
const addressStr = `${o1.toString()}.${o2.toString()}.${o3.toString()}.${o4.toString()}`;
return addressStr;
}
class dnsAnswerParseResult {
name = "";
endOffset = 0;
}
function parseDnsName(msg, startOffset) {
const result = new dnsAnswerParseResult();
let offset = startOffset;
while (offset < msg.length) {
const nextByte = msg.readUInt8(offset);
if (nextByte === 0) {
offset++;
break;
}
const pointerMask = (1 << 6) | (1 << 7);
if ((nextByte & pointerMask) === pointerMask) {
offset++;
const pointerOffset = msg.readUInt8(offset);
offset++;
const nestedResult = parseDnsName(msg, pointerOffset);
if (result.name.length > 0 && nestedResult.name.length > 0) {
result.name += ".";
}
result.name += nestedResult.name;
break;
}
offset++;
const segment = msg.toString("ascii", offset, offset + nextByte);
offset += nextByte;
if (result.name.length > 0 && segment.length > 0) {
result.name += ".";
}
result.name += segment;
}
result.endOffset = offset;
return result;
}
function GetDNSQuestion(msg, startOffset) {
let offset = startOffset;
const parsedResult = parseDnsName(msg, offset);
offset = parsedResult.endOffset;
const type = msg.readUInt16BE(offset);
offset += 2;
const cls = msg.readUInt16BE(offset);
offset += 2;
const ret = new Question();
ret.name = parsedResult.name;
ret.type = type;
ret.class = cls;
ret.endOffset = offset;
return ret;
}
function GetDNSAnswer(msg, startOffset) {
let offset = startOffset;
const parsedResult = parseDnsName(msg, offset);
offset = parsedResult.endOffset;
const type = msg.readUInt16BE(offset);
offset += 2;
offset += 2; // don't care about "class" of answer
const ttlSeconds = msg.readUInt32BE(offset);
offset += 4;
const rDataLength = msg.readUInt16BE(offset);
offset += 2;
switch (type) {
case exports.TypePtr: {
const domainResult = parseDnsName(msg, offset);
const ret = new PtrRecord();
ret.type = type;
ret.ttlSeconds = ttlSeconds;
ret.name = parsedResult.name;
ret.endOffset = offset + rDataLength;
ret.domain = domainResult.name;
return ret;
}
case exports.TypeTxt: {
const textResult = parseDnsName(msg, offset);
const ret = new TxtRecord();
ret.type = type;
ret.ttlSeconds = ttlSeconds;
ret.name = parsedResult.name;
ret.endOffset = offset + rDataLength;
ret.text = textResult.name;
return ret;
}
case exports.TypeSrv: {
const priority = msg.readUInt16BE(offset);
const weight = msg.readUInt16BE(offset + 2);
const port = msg.readUInt16BE(offset + 4);
const targetResult = parseDnsName(msg, offset + 6);
const ret = new SrvRecord();
ret.type = type;
ret.ttlSeconds = ttlSeconds;
ret.name = parsedResult.name;
ret.endOffset = offset + rDataLength;
ret.priority = priority;
ret.weight = weight;
ret.port = port;
ret.target = targetResult.name;
return ret;
}
case exports.TypeA: {
const address = msg.readUInt32BE(offset);
const ret = new ARecord();
ret.type = type;
ret.ttlSeconds = ttlSeconds;
ret.name = parsedResult.name;
ret.endOffset = offset + rDataLength;
ret.address = address;
return ret;
}
default:
break;
}
return undefined;
}
//# sourceMappingURL=dns.js.map

1
cjs/dns.js.map Normal file

File diff suppressed because one or more lines are too long

102
cjs/example.js Normal file
View File

@ -0,0 +1,102 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const index_js_1 = require("./index.js");
const messages = __importStar(require("./messages/messages.js"));
const example = async () => {
console.log("searching...");
const f = new index_js_1.FindUnits();
const units = await f.searchAsync(1000);
f.close();
console.log("Discovered units:", units);
if (units.length === 0) {
throw new Error("no IntelliCenter units found, exiting.");
}
if (units.length > 1) {
throw new Error(`found more than one IntelliCenter unit, unsure which one to use. ${JSON.stringify(units)}`);
}
const endpoint = units[0].addressStr;
const port = units[0].port;
// const endpoint = "10.0.0.41";
// const port = 6680;
console.log("connecting to intellicenter device at", endpoint, "port", port);
const unit = new index_js_1.Unit(endpoint, port);
await unit.connect();
console.log("connected");
unit.on("notify", (msg) => {
console.log("received notify:", msg);
});
console.log("subscribing for updates...");
let resp = await unit.send(messages.SubscribeToUpdates("B1202", "LOTMP"));
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get System Info request...");
resp = await unit.send(messages.GetSystemInformation());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get System Config request...");
resp = await unit.send(messages.GetSystemConfiguration());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Body Status request...");
resp = await unit.send(messages.GetBodyStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Chemical Status request...");
resp = await unit.send(messages.GetChemicalStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Heaters request...");
resp = await unit.send(messages.GetHeaters());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Schedule request...");
resp = await unit.send(messages.GetSchedule());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Circuit Status request...");
resp = await unit.send(messages.GetCircuitStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("sending Set Setpoint request...");
// resp = await unit.send(messages.SetSetpoint("B1202", 97));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("turning off pool...");
// resp = await unit.send(messages.SetObjectStatus("B1101", false));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("turning off water feature...");
// resp = await unit.send(messages.SetObjectStatus("C0003", false));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("sending Set Heatmode request...");
// resp = await unit.send(messages.SetHeatMode("B1202", true));
// console.log("got response:", JSON.stringify(resp, null, 2));
unit.close();
};
example().catch((e) => {
throw e;
});
//# sourceMappingURL=example.js.map

1
cjs/example.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"example.js","sourceRoot":"","sources":["../example.ts"],"names":[],"mappings":"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"}

View File

200
cjs/finder.js Normal file
View File

@ -0,0 +1,200 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FindUnits = exports.UnitInfo = void 0;
const dgram_1 = require("dgram");
const events_1 = require("events");
const debug_1 = __importDefault(require("debug"));
const dns_js_1 = require("./dns.js");
const debugFind = (0, debug_1.default)("ic:find");
/**
* Contains connection information for an IntelliCenter controller.
*/
class UnitInfo {
name;
hostname;
port;
address;
get addressStr() {
return (0, dns_js_1.ipToString)(this.address);
}
constructor(_name, _hostname, _port, _address) {
this.name = _name;
this.hostname = _hostname;
this.port = _port;
this.address = _address;
}
}
exports.UnitInfo = UnitInfo;
/**
* Broadcasts mDNS packets to the local network to identify any Pentair IntelliCenter controllers connected to it.
*
* Available events:
*
* * `"close"` - fired when the search socket has closed
* * `"error"` - fired when an unrecoverable error has occurred in the search socket
* * `"serverFound"` - fired immediately when an IntelliCenter unit has been located; receives a {@linkcode UnitInfo} argument
*/
class FindUnits extends events_1.EventEmitter {
broadcastInterface;
/**
* Creates a new finder.
*
* @param broadcastInterface the address of the interface to send the broadcast to. If not specified, will use system selection. Only necessary if you have more than one network adapter/interface and want to search on a specific one.
*/
constructor(broadcastInterface) {
super();
this.broadcastInterface = broadcastInterface;
// construct mDNS packet to ping for intellicenter controllers
this.message = Buffer.alloc(34);
let offset = 0;
offset = this.message.writeUInt16BE(0, offset); // transaction id
offset = this.message.writeUInt16BE(0, offset); // flags: 0x0 (standard query)
offset = this.message.writeUInt16BE(1, offset); // asking 1 question
offset = this.message.writeUInt16BE(0, offset); // answer rr
offset = this.message.writeUInt16BE(0, offset); // authority rr
offset = this.message.writeUInt16BE(0, offset); // additional rr
offset = this.message.writeUInt8("_http".length, offset);
offset += this.message.write("_http", offset);
offset = this.message.writeUInt8("_tcp".length, offset);
offset += this.message.write("_tcp", offset);
offset = this.message.writeUInt8("local".length, offset);
offset += this.message.write("local", offset);
offset = this.message.writeUInt8(0, offset); // no more strings
offset = this.message.writeUInt16BE(dns_js_1.TypePtr, offset); // type
this.message.writeUInt16BE(1, offset); // class: IN
this.finder = (0, dgram_1.createSocket)("udp4");
this.finder
.on("listening", () => {
if (this.broadcastInterface) {
this.finder.setMulticastInterface(this.broadcastInterface);
}
this.finder.setBroadcast(true);
this.finder.setMulticastTTL(128);
if (!this.bound) {
this.bound = true;
this.sendServerBroadcast();
}
})
.on("message", (msg) => {
this.foundServer(msg);
})
.on("close", () => {
debugFind("Finder socket closed.");
this.emit("close");
})
.on("error", (e) => {
debugFind("Finder socket error: %O", e);
this.emit("error", e);
});
}
finder;
bound = false;
message;
units = [];
/**
* Begins a search and returns immediately. Must close the finder with close() when done with all searches.
* Subscribe to the `"serverFound"` event to receive connected unit information.
*/
search() {
if (!this.bound) {
this.finder.bind();
}
else {
this.sendServerBroadcast();
}
}
/**
* Searches for the given amount of time. Must close the finder with close() when done with all searches.
*
* @param searchTimeMs the number of milliseconds to search before giving up and returning found results (default: 5000)
* @returns Promise resolving to a list of discovered {@linkcode UnitInfo}, if any.
*/
async searchAsync(searchTimeMs) {
const p = new Promise((resolve) => {
setTimeout(() => {
if (this.units.length === 0) {
debugFind("No units found searching locally.");
}
this.removeAllListeners();
resolve(this.units);
}, searchTimeMs ?? 5000);
this.on("serverFound", (unit) => {
debugFind(" found: %o", unit);
this.units.push(unit);
});
this.search();
});
return p;
}
foundServer(msg) {
let flags = 0;
if (msg.length > 4) {
flags = msg.readUInt16BE(2);
const answerBit = 1 << 15;
if ((flags & answerBit) === 0) {
// received query, don't process as answer
return;
}
}
let nextAnswerOffset = 12;
let questions = 0;
if (msg.length >= 6) {
questions = msg.readUInt16BE(4);
let nextQuestionOffset = 12;
for (let i = 0; i < questions; i++) {
const parsed = (0, dns_js_1.GetDNSQuestion)(msg, nextQuestionOffset);
nextQuestionOffset = parsed.endOffset;
}
nextAnswerOffset = nextQuestionOffset;
}
let answers = 0;
if (msg.length >= 8) {
answers = msg.readUInt16BE(6);
}
const records = [];
if (answers > 0) {
for (let i = 0; i < answers; i++) {
if (msg.length <= nextAnswerOffset) {
console.error(`while inspecting dns answers, expected message length > ${nextAnswerOffset.toString()} but it was ${msg.length.toString()}`);
break;
}
const answer = (0, dns_js_1.GetDNSAnswer)(msg, nextAnswerOffset);
if (!answer) {
break;
}
records.push(answer);
nextAnswerOffset = answer.endOffset;
}
}
if (records.find((r) => r.name.startsWith("Pentair -i"))) {
const srv = records.find((r) => r instanceof dns_js_1.SrvRecord);
const a = records.find((r) => r instanceof dns_js_1.ARecord);
if (!srv || !a) {
return;
}
const unit = new UnitInfo(srv.name, a.name, srv.port, a.address);
this.emit("serverFound", unit);
}
else {
debugFind(" found something that wasn't an IntelliCenter unit: %s", records
.filter((r) => r instanceof dns_js_1.PtrRecord)
.map((r) => r.domain)
.join(", "));
}
}
sendServerBroadcast() {
this.finder.send(this.message, 0, this.message.length, 5353, "224.0.0.251");
debugFind("Looking for IntelliCenter hosts...");
}
/**
* Closes the finder socket.
*/
close() {
this.finder.close();
}
}
exports.FindUnits = FindUnits;
//# sourceMappingURL=finder.js.map

1
cjs/finder.js.map Normal file

File diff suppressed because one or more lines are too long

View File

8
cjs/index.js Normal file
View File

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Unit = exports.FindUnits = void 0;
const finder_js_1 = require("./finder.js");
Object.defineProperty(exports, "FindUnits", { enumerable: true, get: function () { return finder_js_1.FindUnits; } });
const unit_js_1 = require("./unit.js");
Object.defineProperty(exports, "Unit", { enumerable: true, get: function () { return unit_js_1.Unit; } });
//# sourceMappingURL=index.js.map

1
cjs/index.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,2CAAwC;AAG/B,0FAHA,qBAAS,OAGA;AAFlB,uCAAiC;AAEb,qFAFX,cAAI,OAEW"}

View File

@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetBodyStatus = GetBodyStatus;
const request_js_1 = require("./request.js");
/**
* Requests the status of bodies known to this controller.
*
* The response contains the list of bodies in the `params` field. Each body has
* an `objnam` that should be used to reference that body for future requests.
* When `params`.`STATUS` is `"OFF"`, use `params`.`LSTTMP` to get the temperature
* of the body the last time it was on, or `params`.`TEMP` to get the temperature
* if the `STATUS` is `"ON"`. `LSTTMP` seems to always be accurate, however, whether
* the body is currently on or off.
*
* @returns the object used to issue this request
*/
function GetBodyStatus() {
const req = (0, request_js_1.GetRequest)();
req.command = "GetParamList";
req.condition = "OBJTYP = BODY";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = "ALL";
reqObj.keys = [
"OBJTYP: SUBTYP: SNAME: LISTORD: FILTER: LOTMP: TEMP: HITMP: HTSRC: PRIM: SEC: ACT1: ACT2: ACT3: ACT4: CIRCUIT: SPEED: BOOST: SELECT: STATUS: HTMODE : LSTTMP : HEATER : VOL : MANUAL : HNAME : MODE",
];
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=body-status.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"body-status.js","sourceRoot":"","sources":["../../messages/body-status.ts"],"names":[],"mappings":";;AAcA,sCAcC;AA5BD,6CAAmE;AAEnE;;;;;;;;;;;GAWG;AACH,SAAgB,aAAa;IAC3B,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,SAAS,GAAG,eAAe,CAAC;IAChC,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,MAAM,CAAC,IAAI,GAAG;QACZ,qMAAqM;KACtM,CAAC;IACF,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetChemicalStatus = GetChemicalStatus;
const request_js_1 = require("./request.js");
/**
* Requests the status of chemical controllers known to this controller.
*
* The response contains the list of chemical controllers available in the `objectList` array.
* For example, an IntelliChem may be one of the entries with `objnam` = `"CHM01"`, `params`.`OBJTYP`
* = `"CHEM"`, `params`.`SUBTYP` = `"ICHEM"` while an IntelliChlor salt cell may be `objnam` = `"CHR01"`,
* `params`.`OBJTYP` = `"CHEM"`, `params`.`SUBTYP` = `"ICHLOR"`. IntelliChlor knows the `"SALT"` level
* while IntelliChem knows the `"PH"` values (PHTNK, PHSET, PHVAL), `"ORP"` values (ORPTNK, ORPSET, ORPVAL),
* `"ALK"` (alkalinity), `"CALC"` (calcium hardness), and `"CYACID"` (cyanuric acid).
*
* pH and ORP Set and Val are in their respective units and orders of magnitude (e.g. 7.6, 750) while the TNK
* levels seem to be on a scale of 1-7 (so "7" would be 100% full).
*
* @returns the object used to issue this request
*/
function GetChemicalStatus() {
const req = (0, request_js_1.GetRequest)();
req.command = "GetParamList";
req.condition = "OBJTYP = CHEM";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = "ALL";
reqObj.keys = [
"OBJTYP: SUBTYP: SNAME: LISTORD : BODY: PHVAL: ORPVAL: SINDEX : PRIM: SEC : PHTNK : ORPTNK : ALK : CALC : CYACID : SUPER : SALT: COMUART: PHSET: ORPSET: TIMOUT : QUALTY ",
];
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=chem-status.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"chem-status.js","sourceRoot":"","sources":["../../messages/chem-status.ts"],"names":[],"mappings":";;AAiBA,8CAcC;AA/BD,6CAAmE;AAEnE;;;;;;;;;;;;;;GAcG;AACH,SAAgB,iBAAiB;IAC/B,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,SAAS,GAAG,eAAe,CAAC;IAChC,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,MAAM,CAAC,IAAI,GAAG;QACZ,0KAA0K;KAC3K,CAAC;IACF,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetCircuitStatus = GetCircuitStatus;
const request_js_1 = require("./request.js");
/**
* Requests the list of circuits known to this controller.
*
* The response contains an `objectList` populated with circuit information.
*
* @returns the object used to issue this request
*/
function GetCircuitStatus() {
const req = (0, request_js_1.GetRequest)();
req.command = "GetParamList";
req.condition = "OBJTYP = CIRCUIT";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = "ALL";
reqObj.keys = [
"OBJNAM",
"OBJTYP",
"SUBTYP",
"STATUS",
"BODY",
"SNAME",
"HNAME",
"FREEZE",
"DNTSTP",
"HNAME",
"TIME",
"FEATR",
"USAGE",
"LIMIT",
"USE",
"SHOMNU",
];
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=circuit-status.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"circuit-status.js","sourceRoot":"","sources":["../../messages/circuit-status.ts"],"names":[],"mappings":";;AASA,4CA6BC;AAtCD,6CAAmE;AAEnE;;;;;;GAMG;AACH,SAAgB,gBAAgB;IAC9B,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,SAAS,GAAG,kBAAkB,CAAC;IACnC,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,MAAM,CAAC,IAAI,GAAG;QACZ,QAAQ;QACR,QAAQ;QACR,QAAQ;QACR,QAAQ;QACR,MAAM;QACN,OAAO;QACP,OAAO;QACP,QAAQ;QACR,QAAQ;QACR,OAAO;QACP,MAAM;QACN,OAAO;QACP,OAAO;QACP,OAAO;QACP,KAAK;QACL,QAAQ;KACT,CAAC;IACF,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetSystemConfiguration = GetSystemConfiguration;
const request_js_1 = require("./request.js");
/**
* Requests the configuration of bodies and circuits available to this controller.
*
* The response contains the list of bodies and circuits under the `answer` field.
* Each object has an `objnam` that should be used to reference that object for future requests,
* and `params`.`SNAME` is the user-entered friendly name that can be displayed for the object.
* `params`.`OBJTYP` will be either BODY or CIRCUIT depending on the object it's describing.
*
* Some objects, such as the Pool body, will have the `params`.`OBJLIST` array populated with
* a series of attached objects such as a chlorinator device.
*
* @returns the object used to issue this request
*/
function GetSystemConfiguration() {
const req = (0, request_js_1.GetRequest)();
req.command = "GetQuery";
req.queryName = "GetConfiguration";
req.arguments = "";
return req;
}
//# sourceMappingURL=configuration.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"configuration.js","sourceRoot":"","sources":["../../messages/configuration.ts"],"names":[],"mappings":";;AAeA,wDAOC;AAtBD,6CAAqD;AAErD;;;;;;;;;;;;GAYG;AACH,SAAgB,sBAAsB;IACpC,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,UAAU,CAAC;IACzB,GAAG,CAAC,SAAS,GAAG,kBAAkB,CAAC;IACnC,GAAG,CAAC,SAAS,GAAG,EAAE,CAAC;IAEnB,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetHeaters = GetHeaters;
const request_js_1 = require("./request.js");
/**
* Requests the list of heaters known to this controller.
*
* The response contains an `objectList` populated with heater information.
*
* @returns the object used to issue this request
*/
function GetHeaters() {
const req = (0, request_js_1.GetRequest)();
req.command = "GetParamList";
req.condition = "OBJTYP = HEATER";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = "ALL";
reqObj.keys = [
"OBJTYP: SUBTYP: SNAME: LISTORD: STATUS: PERMIT: TIMOUT: READY: HTMODE : SHOMNU : COOL : COMUART : BODY : HNAME : START : STOP : HEATING : BOOST : TIME : DLY : MODE",
];
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=get-heater.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"get-heater.js","sourceRoot":"","sources":["../../messages/get-heater.ts"],"names":[],"mappings":";;AASA,gCAcC;AAvBD,6CAAmE;AAEnE;;;;;;GAMG;AACH,SAAgB,UAAU;IACxB,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,SAAS,GAAG,iBAAiB,CAAC;IAClC,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,MAAM,CAAC,IAAI,GAAG;QACZ,qKAAqK;KACtK,CAAC;IACF,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -9,16 +9,4 @@ import { SetHeatMode } from "./set-heater.js";
import { SetObjectStatus } from "./set-object-status.js";
import { SetSetpoint } from "./setpoint.js";
import { GetSystemInformation } from "./system-info.js";
export declare const messages: {
GetBodyStatus: typeof GetBodyStatus;
GetChemicalStatus: typeof GetChemicalStatus;
GetCircuitStatus: typeof GetCircuitStatus;
GetHeaters: typeof GetHeaters;
GetSchedule: typeof GetSchedule;
GetSystemConfiguration: typeof GetSystemConfiguration;
GetSystemInformation: typeof GetSystemInformation;
SetHeatMode: typeof SetHeatMode;
SetObjectStatus: typeof SetObjectStatus;
SetSetpoint: typeof SetSetpoint;
SubscribeToUpdates: typeof SubscribeToUpdates;
};
export { GetBodyStatus, GetChemicalStatus, GetCircuitStatus, GetHeaters, GetSchedule, GetSystemConfiguration, GetSystemInformation, SetHeatMode, SetObjectStatus, SetSetpoint, SubscribeToUpdates, };

26
cjs/messages/messages.js Normal file
View File

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubscribeToUpdates = exports.SetSetpoint = exports.SetObjectStatus = exports.SetHeatMode = exports.GetSystemInformation = exports.GetSystemConfiguration = exports.GetSchedule = exports.GetHeaters = exports.GetCircuitStatus = exports.GetChemicalStatus = exports.GetBodyStatus = void 0;
const body_status_js_1 = require("./body-status.js");
Object.defineProperty(exports, "GetBodyStatus", { enumerable: true, get: function () { return body_status_js_1.GetBodyStatus; } });
const chem_status_js_1 = require("./chem-status.js");
Object.defineProperty(exports, "GetChemicalStatus", { enumerable: true, get: function () { return chem_status_js_1.GetChemicalStatus; } });
const circuit_status_js_1 = require("./circuit-status.js");
Object.defineProperty(exports, "GetCircuitStatus", { enumerable: true, get: function () { return circuit_status_js_1.GetCircuitStatus; } });
const configuration_js_1 = require("./configuration.js");
Object.defineProperty(exports, "GetSystemConfiguration", { enumerable: true, get: function () { return configuration_js_1.GetSystemConfiguration; } });
const get_heater_js_1 = require("./get-heater.js");
Object.defineProperty(exports, "GetHeaters", { enumerable: true, get: function () { return get_heater_js_1.GetHeaters; } });
const notify_js_1 = require("./notify.js");
Object.defineProperty(exports, "SubscribeToUpdates", { enumerable: true, get: function () { return notify_js_1.SubscribeToUpdates; } });
const schedule_js_1 = require("./schedule.js");
Object.defineProperty(exports, "GetSchedule", { enumerable: true, get: function () { return schedule_js_1.GetSchedule; } });
const set_heater_js_1 = require("./set-heater.js");
Object.defineProperty(exports, "SetHeatMode", { enumerable: true, get: function () { return set_heater_js_1.SetHeatMode; } });
const set_object_status_js_1 = require("./set-object-status.js");
Object.defineProperty(exports, "SetObjectStatus", { enumerable: true, get: function () { return set_object_status_js_1.SetObjectStatus; } });
const setpoint_js_1 = require("./setpoint.js");
Object.defineProperty(exports, "SetSetpoint", { enumerable: true, get: function () { return setpoint_js_1.SetSetpoint; } });
const system_info_js_1 = require("./system-info.js");
Object.defineProperty(exports, "GetSystemInformation", { enumerable: true, get: function () { return system_info_js_1.GetSystemInformation; } });
//# sourceMappingURL=messages.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../messages/messages.ts"],"names":[],"mappings":";;;AAAA,qDAAiD;AAa/C,8FAbO,8BAAa,OAaP;AAZf,qDAAqD;AAanD,kGAbO,kCAAiB,OAaP;AAZnB,2DAAuD;AAarD,iGAbO,oCAAgB,OAaP;AAZlB,yDAA4D;AAe1D,uGAfO,yCAAsB,OAeP;AAdxB,mDAA6C;AAY3C,2FAZO,0BAAU,OAYP;AAXZ,2CAAiD;AAkB/C,mGAlBO,8BAAkB,OAkBP;AAjBpB,+CAA4C;AAW1C,4FAXO,yBAAW,OAWP;AAVb,mDAA8C;AAa5C,4FAbO,2BAAW,OAaP;AAZb,iEAAyD;AAavD,gGAbO,sCAAe,OAaP;AAZjB,+CAA4C;AAa1C,4FAbO,yBAAW,OAaP;AAZb,qDAAwD;AAStD,qGATO,qCAAoB,OASP"}

35
cjs/messages/notify.js Normal file
View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubscribeToUpdates = SubscribeToUpdates;
const request_js_1 = require("./request.js");
/**
* Requests to subscribe for updates to the given keys.
*
* Keys and objnam should be given matching an objnam known to the controller and a key for that object.
* {@linkcode ICParam} fields are the known list of keys available to subscribe to.
*
* The response contains an acknowledgement of success or failure. When the given keys change, the `Unit` will
* emit a `"notify"` event with an {@linkcode ICResponse} payload for the new values.
*
* @param objnam the name of the object to subscribe to updates on
* @param keys the key or list of keys to subscribe to updates on this object for
* @returns the object used to issue this request
*/
function SubscribeToUpdates(objnam, keys) {
const req = (0, request_js_1.GetRequest)();
req.command = "RequestParamList";
req.objectList = [];
let ks;
if (Array.isArray(keys)) {
ks = keys;
}
else {
ks = [keys];
}
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = objnam;
reqObj.keys = ks;
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=notify.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"notify.js","sourceRoot":"","sources":["../../messages/notify.ts"],"names":[],"mappings":";;AAoBA,gDAqBC;AAzCD,6CAAmE;AAOnE;;;;;;;;;;;;GAYG;AACH,SAAgB,kBAAkB,CAChC,MAAc,EACd,IAAuB;IAEvB,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,kBAAkB,CAAC;IACjC,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,IAAI,EAAY,CAAC;IACjB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,EAAE,GAAG,IAAI,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;IACjB,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

133
cjs/messages/param.js Normal file
View File

@ -0,0 +1,133 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ICParam = void 0;
class ICParam {
// "": "PROGRESS";
ABSMAX;
ABSMIN;
ACT;
ACT1;
ACT2;
ACT3;
ACT4;
ADDRESS;
ALK;
AVAIL;
BADGE;
BODY;
BOOST;
CALC;
CALIB;
CHILD;
CIRCUIT;
CITY;
CLK24A;
COMUART;
COOL;
COOLING;
COUNT;
COUNTRY;
CYACID;
DAY; // list of characters for each day. MTWRFAU: M=Monday, T=Tuesday, W=Wednesday, R=Thursday, F=Friday, A=Saturday, U=Sunday. could be empty to mean "no days assigned"
DLSTIM;
DLY;
DNTSTP;
EMAIL;
EMAIL2;
ENABLE;
FEATR;
FILTER;
FREEZE;
GPM;
GROUP;
HEATER; // name of a heater circuit, e.g. "H0001". "00000" means unset/none. also seen to contain the string "HOLD" in some contexts such as when retrieving scheduling information.
HEATING;
HITMP; // high temperature threshold in whatever units the system is set to. "78" means 78 degrees fahrenheit for a system in F, "30" means 30 degrees celsius for a system in C
HNAME;
HTMODE;
HTSRC;
IN;
LIMIT;
LISTORD; // sorting order. "2", "3", "4", etc.
LOCX;
LOCY;
LOTMP;
LSTTMP;
MANHT;
MANOVR;
MANUAL;
MAX;
MAXF;
MIN;
MINF;
MODE; // seems to be a number, e.g. "0"
NAME;
OBJLIST;
OBJNAM;
OBJTYP;
OFFSET;
ORPSET;
ORPTNK;
ORPVAL;
PARENT;
PARTY;
PASSWRD;
PERMIT;
PHONE;
PHONE2;
PHSET;
PHTNK;
PHVAL;
PRIM;
PRIMFLO;
PRIMTIM;
PRIOR;
PROBE;
PROPNAME;
PWR;
QUALTY;
READY;
RLY;
RPM;
SALT;
SEC;
SELECT;
SERVICE;
SETTMP;
SETTMPNC;
SHARE;
SHOMNU;
SINDEX;
SINGLE;
SNAME; // friendly name for a circuit, e.g. "Pool"
SOURCE;
SMTSRT; // stringified 16-bit bitfield, maybe? "65535"
SPEED;
SRIS;
SSET;
START; // seems to be very context-sensitive start value. sometimes a hint for how to interpret the TIME field ("ABSTIM"), other times as a single number ("6", in Heater response), and others as perhaps a date (in format "MM,DD,YY" where leading 0s are replaced with spaces, e.g. "12,30,24" vs " 1, 6,25")
STATE;
STATIC;
STATUS;
STOP; // seems to be very context-sensitive stop value. sometimes a hint for how to interpret the TIME field ("ABSTIM"), other times as a single number ("3", in Heater response), and others as perhaps a date (in format "MM,DD,YY" where leading 0s are replaced with spaces, e.g. "12,30,24" vs " 1, 6,25")
SUBTYP;
SUPER;
SWIM;
SYNC;
SYSTIM;
TEMP;
TIME; // start time in "hh,mm,ss" format (24hr)
TIMOUT; // seems to sometimes be end time in "hh,mm,ss" format (24hr), i guess that means "timeout" as in "time that this runs out" or something; other times a duration as number of seconds, e.g. "86400"
TIMZON; // timezone offset from UTC, e.g. "-6"
UPDATE; // seems to be a date in "MM/DD/YY" format
USAGE;
USE;
VACFLO; // vacation...flow?
VACTIM; // vacation time?
VALVE;
VER;
VOL;
ZIP;
}
exports.ICParam = ICParam;
//# sourceMappingURL=param.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"param.js","sourceRoot":"","sources":["../../messages/param.ts"],"names":[],"mappings":"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"}

26
cjs/messages/request.js Normal file
View File

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ICRequest = exports.ICRequestObj = void 0;
exports.GetRequest = GetRequest;
const uuid_1 = require("uuid");
class ICRequestObj {
objnam = "";
keys = [];
params;
}
exports.ICRequestObj = ICRequestObj;
class ICRequest {
condition;
objectList;
queryName;
arguments;
command = "";
messageID = "";
}
exports.ICRequest = ICRequest;
function GetRequest() {
const req = new ICRequest();
req.messageID = (0, uuid_1.v4)();
return req;
}
//# sourceMappingURL=request.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../messages/request.ts"],"names":[],"mappings":";;;AAkBA,gCAIC;AAtBD,+BAAoC;AAGpC,MAAa,YAAY;IAChB,MAAM,GAAG,EAAE,CAAC;IACZ,IAAI,GAAa,EAAE,CAAC;IACpB,MAAM,CAAW;CACzB;AAJD,oCAIC;AAED,MAAa,SAAS;IACb,SAAS,CAAU;IACnB,UAAU,CAAkB;IAC5B,SAAS,CAAU;IACnB,SAAS,CAAqB;IAC9B,OAAO,GAAG,EAAE,CAAC;IACb,SAAS,GAAG,EAAE,CAAC;CACvB;AAPD,8BAOC;AAED,SAAgB,UAAU;IACxB,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;IAC5B,GAAG,CAAC,SAAS,GAAG,IAAA,SAAM,GAAE,CAAC;IACzB,OAAO,GAAG,CAAC;AACb,CAAC"}

20
cjs/messages/response.js Normal file
View File

@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ICResponse = exports.ICResponseObj = void 0;
class ICResponseObj {
objnam = "";
params;
}
exports.ICResponseObj = ICResponseObj;
class ICResponse {
command = "";
messageID = "";
response = "";
objectList;
queryName;
answer;
timeSince;
timeNow;
}
exports.ICResponse = ICResponse;
//# sourceMappingURL=response.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../messages/response.ts"],"names":[],"mappings":";;;AAEA,MAAa,aAAa;IACjB,MAAM,GAAG,EAAE,CAAC;IACZ,MAAM,CAAW;CACzB;AAHD,sCAGC;AAED,MAAa,UAAU;IACd,OAAO,GAAG,EAAE,CAAC;IACb,SAAS,GAAG,EAAE,CAAC;IACf,QAAQ,GAAG,EAAE,CAAC;IACd,UAAU,CAAmB;IAC7B,SAAS,CAAU;IACnB,MAAM,CAAmB;IACzB,SAAS,CAAU;IACnB,OAAO,CAAU;CACzB;AATD,gCASC"}

25
cjs/messages/schedule.js Normal file
View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetSchedule = GetSchedule;
const request_js_1 = require("./request.js");
/**
* Requests the list of schedules set on this controller.
*
* The response contains an `objectList` populated with schedule information.
*
* @returns the object used to issue this request
*/
function GetSchedule() {
const req = (0, request_js_1.GetRequest)();
req.command = "GetParamList";
req.condition = "OBJTYP=SCHED";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = "ALL";
reqObj.keys = [
"OBJNAM : OBJTYP : LISTORD : CIRCUIT : SNAME : DAY : SINGLE : START : TIME : STOP : TIMOUT : GROUP : HEATER : COOLING : LOTMP : SMTSRT : STATUS : DNTSTP : ACT : MODE : AVAIL: VACFLO : VACTIM : UPDATE",
];
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=schedule.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../messages/schedule.ts"],"names":[],"mappings":";;AASA,kCAcC;AAvBD,6CAAmE;AAEnE;;;;;;GAMG;AACH,SAAgB,WAAW;IACzB,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,SAAS,GAAG,cAAc,CAAC;IAC/B,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,MAAM,CAAC,IAAI,GAAG;QACZ,wMAAwM;KACzM,CAAC;IACF,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -0,0 +1,30 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SetHeatMode = SetHeatMode;
const param_js_1 = require("./param.js");
const request_js_1 = require("./request.js");
/**
* Requests to turn a body's heater on or off.
*
* This is very WIP. For my pool and my heater configuration, the MODE needs to be 11 to enable my
* heater and 1 to disable all heaters. I have a feeling 11 is unique to my system's configuration,
* but I can't yet determine how to know what 11 maps to in order to make this more generic.
*
* Note that this doesn't necessarily start heating the body by itself - if the body's pump is
* currently off, enabling the heater will not turn it on. If the pump/body is on, then this will
* enable the heater and no further action is required.
*
* @returns the object used to issue this request
*/
function SetHeatMode(bodyObjnam, enabled) {
const req = (0, request_js_1.GetRequest)();
req.command = "SetParamList";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = bodyObjnam;
reqObj.params = new param_js_1.ICParam();
reqObj.params.MODE = enabled ? "11" : "1";
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=set-heater.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"set-heater.js","sourceRoot":"","sources":["../../messages/set-heater.ts"],"names":[],"mappings":";;AAgBA,kCAYC;AA5BD,yCAAqC;AACrC,6CAAmE;AAEnE;;;;;;;;;;;;GAYG;AACH,SAAgB,WAAW,CAAC,UAAkB,EAAE,OAAgB;IAC9D,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3B,MAAM,CAAC,MAAM,GAAG,IAAI,kBAAO,EAAE,CAAC;IAC9B,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1C,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SetObjectStatus = SetObjectStatus;
const param_js_1 = require("./param.js");
const request_js_1 = require("./request.js");
/**
* Requests to change the status of objects known to this controller.
*
* Turns one or more objects on or off. Use the `objnam` of the circuit to be set.
*
* @returns the object used to issue this request
*/
function SetObjectStatus(object, status) {
const req = (0, request_js_1.GetRequest)();
req.command = "SetParamList";
req.objectList = [];
let objects;
if (Array.isArray(object)) {
objects = object;
}
else {
objects = [object];
}
for (const i of objects) {
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = i;
reqObj.params = new param_js_1.ICParam();
reqObj.params.STATUS = status ? "ON" : "OFF";
req.objectList.push(reqObj);
}
return req;
}
//# sourceMappingURL=set-object-status.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"set-object-status.js","sourceRoot":"","sources":["../../messages/set-object-status.ts"],"names":[],"mappings":";;AAUA,0CAwBC;AAlCD,yCAAqC;AACrC,6CAAmE;AAEnE;;;;;;GAMG;AACH,SAAgB,eAAe,CAC7B,MAAyB,EACzB,MAAe;IAEf,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,IAAI,OAAiB,CAAC;IACtB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAClB,MAAM,CAAC,MAAM,GAAG,IAAI,kBAAO,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;QAC7C,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}

26
cjs/messages/setpoint.js Normal file
View File

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SetSetpoint = SetSetpoint;
const param_js_1 = require("./param.js");
const request_js_1 = require("./request.js");
/**
* Requests to change the setpoint of a temperature circuit.
*
* Use the `objnam` of the circuit to be set and give the temperature in the same units that the
* controller is set to (so, give a number in Celsius if the system is in Celsius or Fahrenheit
* if the system is in Fahrenheit).
*
* @returns the object used to issue this request
*/
function SetSetpoint(objnam, setpoint) {
const req = (0, request_js_1.GetRequest)();
req.command = "SetParamList";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = objnam;
reqObj.params = new param_js_1.ICParam();
reqObj.params.LOTMP = setpoint.toString();
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=setpoint.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"setpoint.js","sourceRoot":"","sources":["../../messages/setpoint.ts"],"names":[],"mappings":";;AAYA,kCAYC;AAxBD,yCAAqC;AACrC,6CAAmE;AAEnE;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,MAAc,EAAE,QAAgB;IAC1D,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,MAAM,GAAG,IAAI,kBAAO,EAAE,CAAC;IAC9B,MAAM,CAAC,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAC1C,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

View File

@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetSystemInformation = GetSystemInformation;
const request_js_1 = require("./request.js");
/**
* Requests information about this controller such as owner, address, etc.
*
* @returns the object used to issue this request
*/
function GetSystemInformation() {
const req = (0, request_js_1.GetRequest)();
req.command = "GETPARAMLIST";
req.condition = "";
req.objectList = [];
const reqObj = new request_js_1.ICRequestObj();
reqObj.objnam = "_5451";
reqObj.keys = [
"VER",
"MODE",
"ZIP",
"TIMZON",
"PROPNAME",
"NAME",
"ADDRESS",
"CITY",
"STATE",
"PHONE",
"PHONE2",
"EMAIL",
"EMAIL2",
"COUNTRY",
"PHONE",
"LOCX",
"LOCY",
"AVAIL",
"SERVICE",
"UPDATE",
"PROGRESS",
"IN",
"VALVE",
"HEATING",
];
req.objectList.push(reqObj);
return req;
}
//# sourceMappingURL=system-info.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"system-info.js","sourceRoot":"","sources":["../../messages/system-info.ts"],"names":[],"mappings":";;AAOA,oDAqCC;AA5CD,6CAAmE;AAEnE;;;;GAIG;AACH,SAAgB,oBAAoB;IAClC,MAAM,GAAG,GAAG,IAAA,uBAAU,GAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,SAAS,GAAG,EAAE,CAAC;IACnB,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,yBAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC;IACxB,MAAM,CAAC,IAAI,GAAG;QACZ,KAAK;QACL,MAAM;QACN,KAAK;QACL,QAAQ;QACR,UAAU;QACV,MAAM;QACN,SAAS;QACT,MAAM;QACN,OAAO;QACP,OAAO;QACP,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,SAAS;QACT,OAAO;QACP,MAAM;QACN,MAAM;QACN,OAAO;QACP,SAAS;QACT,QAAQ;QACR,UAAU;QACV,IAAI;QACJ,OAAO;QACP,SAAS;KACV,CAAC;IACF,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,GAAG,CAAC;AACb,CAAC"}

1
cjs/package.json Normal file
View File

@ -0,0 +1 @@
{"type": "commonjs"}

View File

144
cjs/unit.js Normal file
View File

@ -0,0 +1,144 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Unit = void 0;
const events_1 = require("events");
const ws_1 = require("ws");
const debug_1 = __importDefault(require("debug"));
const debugUnit = (0, debug_1.default)("ic:unit");
/**
* Contains methods to connect to and communicate with an IntelliCenter controller.
*
* Call `connect` to connect to the unit.
* Use `send` to send a message.
* Subscribe to events to process socket conditions, notify updates, and message responses (if not `await`ing the response)
*
* Available events:
*
* * `"response-{messageID}"` - fired once per message sent with `send()` where {messageID} is the ID specified in the {@linkcode ICRequest} given to `send()`
* * `"notify"` - fired when an update is available to a property previously subscribed to via a {@linkcode SubscribeToUpdates} request
* * `"close"` - fired any time the client is closed by any means (timeout, by request, error, etc.)
* * `"open"` - fired when the socket connects to the unit successfully
* * `"error"` - fired when the socket encounters an unrecoverable error and will close
* * `"timeout"` - fired when the socket has not received a ping response within the allowed threshold and will close
* * `"connected"` - fired when a connection has completed successfully
*/
class Unit extends events_1.EventEmitter {
endpoint;
port;
client;
pingTimeout;
pingTimer;
pingInterval = 60000;
constructor(endpoint, port = 6680) {
super();
this.endpoint = endpoint;
this.port = port;
this.endpoint = endpoint;
this.port = port;
}
/**
* Connects to the specified unit and maintains a connection to it until `close()` is called.
*/
async connect() {
if (this.client) {
throw new Error("can't open a client that is already open");
}
debugUnit(`connecting to ws://${this.endpoint}:${this.port.toString()}`);
this.client = new ws_1.WebSocket(`ws://${this.endpoint}:${this.port.toString()}`);
const { heartbeat, onClientMessage, socketCleanup } = this;
this.client.on("error", (evt) => {
// todo: emit event so we can reconnect? auto reconnect?
debugUnit("error in websocket: $o", evt);
this.emit("error");
socketCleanup();
});
this.client.on("open", () => {
this.emit("open");
heartbeat();
});
this.client.on("ping", heartbeat);
this.client.on("pong", heartbeat);
this.client.on("close", socketCleanup);
this.client.on("message", onClientMessage);
this.pingTimer = setInterval(() => {
debugUnit("sending ping");
this.client?.ping();
}, this.pingInterval);
await new Promise((resolve, reject) => {
this.client?.once("error", reject);
this.client?.once("open", resolve);
});
debugUnit("connected");
this.emit("connected");
}
/**
* Closes the connection to the unit.
*/
close() {
if (!this.client) {
return;
}
debugUnit("closing connection by request");
this.emit("close");
this.client.close();
}
socketCleanup = () => {
debugUnit("socket cleanup");
this.client?.removeAllListeners();
this.client = undefined;
if (this.pingTimeout) {
clearTimeout(this.pingTimeout);
this.pingTimeout = undefined;
}
if (this.pingTimer) {
clearInterval(this.pingTimer);
this.pingTimer = undefined;
}
};
heartbeat = () => {
debugUnit("received heartbeat");
clearTimeout(this.pingTimeout);
this.pingTimeout = setTimeout(() => {
debugUnit("terminating connection due to heartbeat timeout");
this.emit("timeout");
this.client?.terminate();
this.socketCleanup();
}, this.pingInterval + 5000);
};
onClientMessage = (msg) => {
debugUnit("message received, length %d", msg.length);
const respObj = JSON.parse(msg.toString());
if (respObj.command.toLowerCase() === "notifylist") {
debugUnit(" it's a subscription confirmation or update");
this.emit(`notify`, respObj);
}
this.emit(`response-${respObj.messageID}`, respObj);
};
/**
* Sends a request to the unit.
*
* @param request an message from {@linkcode messages} to send to the unit.
* @returns a promise that resolves into the {@linkcode ICResponse} with information about the request.
*/
async send(request) {
if (!this.client) {
return await new Promise(() => {
throw new Error("client not connected");
});
}
const payload = JSON.stringify(request);
debugUnit("sending message of length %d with id %s", payload.length, request.messageID);
this.client.send(payload);
return await new Promise((resolve) => {
this.once(`response-${request.messageID}`, (resp) => {
debugUnit(" returning response to message %s", request.messageID);
resolve(resp);
});
});
}
}
exports.Unit = Unit;
//# sourceMappingURL=unit.js.map

1
cjs/unit.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"unit.js","sourceRoot":"","sources":["../unit.ts"],"names":[],"mappings":"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"}

63
dist/example.js vendored
View File

@ -1,63 +0,0 @@
"use strict";
import { FindUnits, Unit } from "./index.js";
import { messages } from "./messages/messages.js";
console.log("searching...");
const f = new FindUnits();
const units = await f.searchAsync(1000);
f.close();
console.log("Discovered units:", units);
if (units.length === 0) {
throw new Error("no IntelliCenter units found, exiting.");
}
if (units.length > 1) {
throw new Error(`found more than one IntelliCenter unit, unsure which one to use. ${JSON.stringify(units)}`);
}
const endpoint = units[0].addressStr;
const port = units[0].port;
// const endpoint = "10.0.0.41";
// const port = 6680;
console.log("connecting to intellicenter device at", endpoint, "port", port);
const unit = new Unit(endpoint, port);
await unit.connect();
console.log("connected");
unit.on("notify", (msg) => {
console.log("received notify:", msg);
});
console.log("subscribing for updates...");
let resp = await unit.send(messages.SubscribeToUpdates("B1202", "LOTMP"));
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get System Info request...");
resp = await unit.send(messages.GetSystemInformation());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get System Config request...");
resp = await unit.send(messages.GetSystemConfiguration());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Body Status request...");
resp = await unit.send(messages.GetBodyStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Chemical Status request...");
resp = await unit.send(messages.GetChemicalStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Heaters request...");
resp = await unit.send(messages.GetHeaters());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Schedule request...");
resp = await unit.send(messages.GetSchedule());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Circuit Status request...");
resp = await unit.send(messages.GetCircuitStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("sending Set Setpoint request...");
// resp = await unit.send(messages.SetSetpoint("B1202", 97));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("turning off pool...");
// resp = await unit.send(messages.SetObjectStatus("B1101", false));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("turning off water feature...");
// resp = await unit.send(messages.SetObjectStatus("C0003", false));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("sending Set Heatmode request...");
// resp = await unit.send(messages.SetHeatMode("B1202", true));
// console.log("got response:", JSON.stringify(resp, null, 2));
unit.close();
//# sourceMappingURL=example.js.map

1
dist/example.js.map vendored
View File

@ -1 +0,0 @@
{"version":3,"file":"example.js","sourceRoot":"","sources":["../example.ts"],"names":[],"mappings":"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"}

View File

@ -14,6 +14,6 @@ export default tseslint.config(
},
},
{
ignores: ["dist/**", "eslint.config.mjs"],
ignores: ["cjs/**", "esm/**", "eslint.config.mjs"],
},
);

35
esm/dns.d.ts vendored Normal file
View File

@ -0,0 +1,35 @@
export declare const TypeTxt = 16;
export declare const TypePtr = 12;
export declare const TypeSrv = 33;
export declare const TypeA = 1;
export declare class Question {
name: string;
type: number;
class: number;
endOffset: number;
}
export declare abstract class Record {
type: number;
ttlSeconds: number;
name: string;
endOffset: number;
}
export declare class PtrRecord extends Record {
domain: string;
}
export declare class TxtRecord extends Record {
text: string;
}
export declare class SrvRecord extends Record {
priority: number;
weight: number;
port: number;
target: string;
}
export declare class ARecord extends Record {
address: number;
get addressStr(): string;
}
export declare function ipToString(ip: number): string;
export declare function GetDNSQuestion(msg: Buffer, startOffset: number): Question;
export declare function GetDNSAnswer(msg: Buffer, startOffset: number): Record | undefined;

1
esm/example.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

68
esm/example.js Normal file
View File

@ -0,0 +1,68 @@
"use strict";
import { FindUnits, Unit } from "./index.js";
import * as messages from "./messages/messages.js";
const example = async () => {
console.log("searching...");
const f = new FindUnits();
const units = await f.searchAsync(1000);
f.close();
console.log("Discovered units:", units);
if (units.length === 0) {
throw new Error("no IntelliCenter units found, exiting.");
}
if (units.length > 1) {
throw new Error(`found more than one IntelliCenter unit, unsure which one to use. ${JSON.stringify(units)}`);
}
const endpoint = units[0].addressStr;
const port = units[0].port;
// const endpoint = "10.0.0.41";
// const port = 6680;
console.log("connecting to intellicenter device at", endpoint, "port", port);
const unit = new Unit(endpoint, port);
await unit.connect();
console.log("connected");
unit.on("notify", (msg) => {
console.log("received notify:", msg);
});
console.log("subscribing for updates...");
let resp = await unit.send(messages.SubscribeToUpdates("B1202", "LOTMP"));
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get System Info request...");
resp = await unit.send(messages.GetSystemInformation());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get System Config request...");
resp = await unit.send(messages.GetSystemConfiguration());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Body Status request...");
resp = await unit.send(messages.GetBodyStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Chemical Status request...");
resp = await unit.send(messages.GetChemicalStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Heaters request...");
resp = await unit.send(messages.GetHeaters());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Schedule request...");
resp = await unit.send(messages.GetSchedule());
console.log("got response:", JSON.stringify(resp, null, 2));
console.log("sending Get Circuit Status request...");
resp = await unit.send(messages.GetCircuitStatus());
console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("sending Set Setpoint request...");
// resp = await unit.send(messages.SetSetpoint("B1202", 97));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("turning off pool...");
// resp = await unit.send(messages.SetObjectStatus("B1101", false));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("turning off water feature...");
// resp = await unit.send(messages.SetObjectStatus("C0003", false));
// console.log("got response:", JSON.stringify(resp, null, 2));
// console.log("sending Set Heatmode request...");
// resp = await unit.send(messages.SetHeatMode("B1202", true));
// console.log("got response:", JSON.stringify(resp, null, 2));
unit.close();
};
example().catch((e) => {
throw e;
});
//# sourceMappingURL=example.js.map

1
esm/example.js.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"example.js","sourceRoot":"","sources":["../example.ts"],"names":[],"mappings":"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"}

52
esm/finder.d.ts vendored Normal file
View File

@ -0,0 +1,52 @@
import { EventEmitter } from "events";
/**
* Contains connection information for an IntelliCenter controller.
*/
export declare class UnitInfo {
name: string;
hostname: string;
port: number;
address: number;
get addressStr(): string;
constructor(_name: string, _hostname: string, _port: number, _address: number);
}
/**
* Broadcasts mDNS packets to the local network to identify any Pentair IntelliCenter controllers connected to it.
*
* Available events:
*
* * `"close"` - fired when the search socket has closed
* * `"error"` - fired when an unrecoverable error has occurred in the search socket
* * `"serverFound"` - fired immediately when an IntelliCenter unit has been located; receives a {@linkcode UnitInfo} argument
*/
export declare class FindUnits extends EventEmitter {
broadcastInterface?: string | undefined;
/**
* Creates a new finder.
*
* @param broadcastInterface the address of the interface to send the broadcast to. If not specified, will use system selection. Only necessary if you have more than one network adapter/interface and want to search on a specific one.
*/
constructor(broadcastInterface?: string | undefined);
private finder;
private bound;
private message;
private units;
/**
* Begins a search and returns immediately. Must close the finder with close() when done with all searches.
* Subscribe to the `"serverFound"` event to receive connected unit information.
*/
search(): void;
/**
* Searches for the given amount of time. Must close the finder with close() when done with all searches.
*
* @param searchTimeMs the number of milliseconds to search before giving up and returning found results (default: 5000)
* @returns Promise resolving to a list of discovered {@linkcode UnitInfo}, if any.
*/
searchAsync(searchTimeMs?: number): Promise<UnitInfo[]>;
private foundServer;
private sendServerBroadcast;
/**
* Closes the finder socket.
*/
close(): void;
}

3
esm/index.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import { FindUnits } from "./finder.js";
import { Unit } from "./unit.js";
export { FindUnits, Unit };

14
esm/messages/body-status.d.ts vendored Normal file
View File

@ -0,0 +1,14 @@
import { ICRequest } from "./request.js";
/**
* Requests the status of bodies known to this controller.
*
* The response contains the list of bodies in the `params` field. Each body has
* an `objnam` that should be used to reference that body for future requests.
* When `params`.`STATUS` is `"OFF"`, use `params`.`LSTTMP` to get the temperature
* of the body the last time it was on, or `params`.`TEMP` to get the temperature
* if the `STATUS` is `"ON"`. `LSTTMP` seems to always be accurate, however, whether
* the body is currently on or off.
*
* @returns the object used to issue this request
*/
export declare function GetBodyStatus(): ICRequest;

17
esm/messages/chem-status.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import { ICRequest } from "./request.js";
/**
* Requests the status of chemical controllers known to this controller.
*
* The response contains the list of chemical controllers available in the `objectList` array.
* For example, an IntelliChem may be one of the entries with `objnam` = `"CHM01"`, `params`.`OBJTYP`
* = `"CHEM"`, `params`.`SUBTYP` = `"ICHEM"` while an IntelliChlor salt cell may be `objnam` = `"CHR01"`,
* `params`.`OBJTYP` = `"CHEM"`, `params`.`SUBTYP` = `"ICHLOR"`. IntelliChlor knows the `"SALT"` level
* while IntelliChem knows the `"PH"` values (PHTNK, PHSET, PHVAL), `"ORP"` values (ORPTNK, ORPSET, ORPVAL),
* `"ALK"` (alkalinity), `"CALC"` (calcium hardness), and `"CYACID"` (cyanuric acid).
*
* pH and ORP Set and Val are in their respective units and orders of magnitude (e.g. 7.6, 750) while the TNK
* levels seem to be on a scale of 1-7 (so "7" would be 100% full).
*
* @returns the object used to issue this request
*/
export declare function GetChemicalStatus(): ICRequest;

9
esm/messages/circuit-status.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
import { ICRequest } from "./request.js";
/**
* Requests the list of circuits known to this controller.
*
* The response contains an `objectList` populated with circuit information.
*
* @returns the object used to issue this request
*/
export declare function GetCircuitStatus(): ICRequest;

15
esm/messages/configuration.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
import { ICRequest } from "./request.js";
/**
* Requests the configuration of bodies and circuits available to this controller.
*
* The response contains the list of bodies and circuits under the `answer` field.
* Each object has an `objnam` that should be used to reference that object for future requests,
* and `params`.`SNAME` is the user-entered friendly name that can be displayed for the object.
* `params`.`OBJTYP` will be either BODY or CIRCUIT depending on the object it's describing.
*
* Some objects, such as the Pool body, will have the `params`.`OBJLIST` array populated with
* a series of attached objects such as a chlorinator device.
*
* @returns the object used to issue this request
*/
export declare function GetSystemConfiguration(): ICRequest;

9
esm/messages/get-heater.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
import { ICRequest } from "./request.js";
/**
* Requests the list of heaters known to this controller.
*
* The response contains an `objectList` populated with heater information.
*
* @returns the object used to issue this request
*/
export declare function GetHeaters(): ICRequest;

12
esm/messages/messages.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
import { GetBodyStatus } from "./body-status.js";
import { GetChemicalStatus } from "./chem-status.js";
import { GetCircuitStatus } from "./circuit-status.js";
import { GetSystemConfiguration } from "./configuration.js";
import { GetHeaters } from "./get-heater.js";
import { SubscribeToUpdates } from "./notify.js";
import { GetSchedule } from "./schedule.js";
import { SetHeatMode } from "./set-heater.js";
import { SetObjectStatus } from "./set-object-status.js";
import { SetSetpoint } from "./setpoint.js";
import { GetSystemInformation } from "./system-info.js";
export { GetBodyStatus, GetChemicalStatus, GetCircuitStatus, GetHeaters, GetSchedule, GetSystemConfiguration, GetSystemInformation, SetHeatMode, SetObjectStatus, SetSetpoint, SubscribeToUpdates, };

View File

@ -9,17 +9,5 @@ import { SetHeatMode } from "./set-heater.js";
import { SetObjectStatus } from "./set-object-status.js";
import { SetSetpoint } from "./setpoint.js";
import { GetSystemInformation } from "./system-info.js";
export const messages = {
GetBodyStatus,
GetChemicalStatus,
GetCircuitStatus,
GetHeaters,
GetSchedule,
GetSystemConfiguration,
GetSystemInformation,
SetHeatMode,
SetObjectStatus,
SetSetpoint,
SubscribeToUpdates,
};
export { GetBodyStatus, GetChemicalStatus, GetCircuitStatus, GetHeaters, GetSchedule, GetSystemConfiguration, GetSystemInformation, SetHeatMode, SetObjectStatus, SetSetpoint, SubscribeToUpdates, };
//# sourceMappingURL=messages.js.map

View File

@ -1 +1 @@
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../messages/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,aAAa;IACb,iBAAiB;IACjB,gBAAgB;IAChB,UAAU;IACV,WAAW;IACX,sBAAsB;IACtB,oBAAoB;IACpB,WAAW;IACX,eAAe;IACf,WAAW;IACX,kBAAkB;CACnB,CAAC"}
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../messages/messages.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,WAAW,EACX,eAAe,EACf,WAAW,EACX,kBAAkB,GACnB,CAAC"}

15
esm/messages/notify.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
import { ICRequest } from "./request.js";
/**
* Requests to subscribe for updates to the given keys.
*
* Keys and objnam should be given matching an objnam known to the controller and a key for that object.
* {@linkcode ICParam} fields are the known list of keys available to subscribe to.
*
* The response contains an acknowledgement of success or failure. When the given keys change, the `Unit` will
* emit a `"notify"` event with an {@linkcode ICResponse} payload for the new values.
*
* @param objnam the name of the object to subscribe to updates on
* @param keys the key or list of keys to subscribe to updates on this object for
* @returns the object used to issue this request
*/
export declare function SubscribeToUpdates(objnam: string, keys: string | string[]): ICRequest;

127
esm/messages/param.d.ts vendored Normal file
View File

@ -0,0 +1,127 @@
export declare class ICParam {
ABSMAX?: string;
ABSMIN?: string;
ACT?: string;
ACT1?: string;
ACT2?: string;
ACT3?: string;
ACT4?: string;
ADDRESS?: string;
ALK?: string;
AVAIL?: "AVAIL" | "ON" | "OFF";
BADGE?: string;
BODY?: string;
BOOST?: string;
CALC?: string;
CALIB?: string;
CHILD?: string;
CIRCUIT?: string;
CITY?: string;
CLK24A?: string;
COMUART?: string;
COOL?: string;
COOLING?: string;
COUNT?: string;
COUNTRY?: string;
CYACID?: string;
DAY?: string;
DLSTIM?: "DLSTIM" | "ON" | "OFF";
DLY?: string;
DNTSTP?: string;
EMAIL?: string;
EMAIL2?: string;
ENABLE?: "ENABLE" | "ON" | "OFF";
FEATR?: string;
FILTER?: string;
FREEZE?: string;
GPM?: string;
GROUP?: string;
HEATER?: string;
HEATING?: "HEATING" | "ON" | "OFF";
HITMP?: string;
HNAME?: string;
HTMODE?: string;
HTSRC?: string;
IN?: string;
LIMIT?: string;
LISTORD?: string;
LOCX?: string;
LOCY?: string;
LOTMP?: string;
LSTTMP?: string;
MANHT?: "MANHT" | "ON" | "OFF";
MANOVR?: "MANOVR" | "ON" | "OFF";
MANUAL?: string;
MAX?: string;
MAXF?: string;
MIN?: string;
MINF?: string;
MODE?: string;
NAME?: string;
OBJLIST?: ICParam[];
OBJNAM?: string;
OBJTYP?: string;
OFFSET?: string;
ORPSET?: string;
ORPTNK?: string;
ORPVAL?: string;
PARENT?: string;
PARTY?: string;
PASSWRD?: string;
PERMIT?: string;
PHONE?: string;
PHONE2?: string;
PHSET?: string;
PHTNK?: string;
PHVAL?: string;
PRIM?: string;
PRIMFLO?: string;
PRIMTIM?: string;
PRIOR?: string;
PROBE?: string;
PROPNAME?: string;
PWR?: string;
QUALTY?: string;
READY?: string;
RLY?: string;
RPM?: string;
SALT?: string;
SEC?: string;
SELECT?: string;
SERVICE?: "SERVICE" | "AUTO" | "TIMEOUT";
SETTMP?: string;
SETTMPNC?: string;
SHARE?: string;
SHOMNU?: string;
SINDEX?: string;
SINGLE?: "SINGLE" | "ON" | "OFF";
SNAME?: string;
SOURCE?: string;
SMTSRT?: string;
SPEED?: string;
SRIS?: string;
SSET?: string;
START?: string;
STATE?: string;
STATIC?: string;
STATUS?: "STATUS" | "ON" | "OFF";
STOP?: string;
SUBTYP?: string;
SUPER?: "SUPER" | "ON" | "OFF";
SWIM?: string;
SYNC?: string;
SYSTIM?: string;
TEMP?: string;
TIME?: string;
TIMOUT?: string;
TIMZON?: string;
UPDATE?: string;
USAGE?: string;
USE?: string;
VACFLO?: "VACFLO" | "ON" | "OFF";
VACTIM?: "VACTIM" | "ON" | "OFF";
VALVE?: "VALVE" | "ON" | "OFF";
VER?: string;
VOL?: string;
ZIP?: string;
}

Some files were not shown because too many files have changed in this diff Show More