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

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;

157
esm/dns.js Normal file
View File

@ -0,0 +1,157 @@
export const TypeTxt = 16;
export const TypePtr = 12;
export const TypeSrv = 33;
export const TypeA = 1;
export class Question {
name = "";
type = 0;
class = 0;
endOffset = 0;
}
export class Record {
type = 0;
ttlSeconds = 0;
name = "";
endOffset = -1;
}
export class PtrRecord extends Record {
domain = "";
}
export class TxtRecord extends Record {
text = "";
}
export class SrvRecord extends Record {
priority = 0;
weight = 0;
port = 0;
target = "";
}
export class ARecord extends Record {
address = 0;
get addressStr() {
return ipToString(this.address);
}
}
export 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;
}
export 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;
}
export 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 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 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 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 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
esm/dns.js.map Normal file

File diff suppressed because one or more lines are too long

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;
}

192
esm/finder.js Normal file
View File

@ -0,0 +1,192 @@
import { createSocket } from "dgram";
import { EventEmitter } from "events";
import debug from "debug";
import { ARecord, GetDNSAnswer, GetDNSQuestion, ipToString, PtrRecord, SrvRecord, TypePtr, } from "./dns.js";
const debugFind = debug("ic:find");
/**
* Contains connection information for an IntelliCenter controller.
*/
export class UnitInfo {
name;
hostname;
port;
address;
get addressStr() {
return ipToString(this.address);
}
constructor(_name, _hostname, _port, _address) {
this.name = _name;
this.hostname = _hostname;
this.port = _port;
this.address = _address;
}
}
/**
* 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 class FindUnits extends 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(TypePtr, offset); // type
this.message.writeUInt16BE(1, offset); // class: IN
this.finder = 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 = 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 = 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 SrvRecord);
const a = records.find((r) => r instanceof 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 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();
}
}
//# sourceMappingURL=finder.js.map

1
esm/finder.js.map Normal file

File diff suppressed because one or more lines are too long

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 };

4
esm/index.js Normal file
View File

@ -0,0 +1,4 @@
import { FindUnits } from "./finder.js";
import { Unit } from "./unit.js";
export { FindUnits, Unit };
//# sourceMappingURL=index.js.map

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

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC"}

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;

View File

@ -0,0 +1,27 @@
import { GetRequest, ICRequestObj } 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 function GetBodyStatus() {
const req = GetRequest();
req.command = "GetParamList";
req.condition = "OBJTYP = BODY";
req.objectList = [];
const reqObj = new 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":"AAAA,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,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"}

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;

View File

@ -0,0 +1,30 @@
import { GetRequest, ICRequestObj } 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 function GetChemicalStatus() {
const req = GetRequest();
req.command = "GetParamList";
req.condition = "OBJTYP = CHEM";
req.objectList = [];
const reqObj = new 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":"AAAA,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,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"}

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;

View File

@ -0,0 +1,37 @@
import { GetRequest, ICRequestObj } 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 function GetCircuitStatus() {
const req = GetRequest();
req.command = "GetParamList";
req.condition = "OBJTYP = CIRCUIT";
req.objectList = [];
const reqObj = new 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":"AAAA,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,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"}

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;

View File

@ -0,0 +1,22 @@
import { GetRequest } 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 function GetSystemConfiguration() {
const req = 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":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,cAAc,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,GAAG,GAAG,UAAU,EAAE,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"}

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;

View File

@ -0,0 +1,22 @@
import { GetRequest, ICRequestObj } 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 function GetHeaters() {
const req = GetRequest();
req.command = "GetParamList";
req.condition = "OBJTYP = HEATER";
req.objectList = [];
const reqObj = new 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":"AAAA,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,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"}

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, };

13
esm/messages/messages.js Normal file
View File

@ -0,0 +1,13 @@
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, };
//# sourceMappingURL=messages.js.map

View File

@ -0,0 +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,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;

32
esm/messages/notify.js Normal file
View File

@ -0,0 +1,32 @@
import { GetRequest, ICRequestObj } 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 function SubscribeToUpdates(objnam, keys) {
const req = GetRequest();
req.command = "RequestParamList";
req.objectList = [];
let ks;
if (Array.isArray(keys)) {
ks = keys;
}
else {
ks = [keys];
}
const reqObj = new 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":"AAAA,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAOnE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAc,EACd,IAAuB;IAEvB,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,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"}

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;
}

129
esm/messages/param.js Normal file
View File

@ -0,0 +1,129 @@
export 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;
}
//# 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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"}

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

@ -0,0 +1,15 @@
import { ICParam } from "./param.js";
export declare class ICRequestObj {
objnam: string;
keys: string[];
params?: ICParam;
}
export declare class ICRequest {
condition?: string;
objectList?: ICRequestObj[];
queryName?: string;
arguments?: string[] | string;
command: string;
messageID: string;
}
export declare function GetRequest(): ICRequest;

20
esm/messages/request.js Normal file
View File

@ -0,0 +1,20 @@
import { v4 as uuidv4 } from "uuid";
export class ICRequestObj {
objnam = "";
keys = [];
params;
}
export class ICRequest {
condition;
objectList;
queryName;
arguments;
command = "";
messageID = "";
}
export function GetRequest() {
const req = new ICRequest();
req.messageID = uuidv4();
return req;
}
//# sourceMappingURL=request.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"request.js","sourceRoot":"","sources":["../../messages/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAGpC,MAAM,OAAO,YAAY;IAChB,MAAM,GAAG,EAAE,CAAC;IACZ,IAAI,GAAa,EAAE,CAAC;IACpB,MAAM,CAAW;CACzB;AAED,MAAM,OAAO,SAAS;IACb,SAAS,CAAU;IACnB,UAAU,CAAkB;IAC5B,SAAS,CAAU;IACnB,SAAS,CAAqB;IAC9B,OAAO,GAAG,EAAE,CAAC;IACb,SAAS,GAAG,EAAE,CAAC;CACvB;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,IAAI,SAAS,EAAE,CAAC;IAC5B,GAAG,CAAC,SAAS,GAAG,MAAM,EAAE,CAAC;IACzB,OAAO,GAAG,CAAC;AACb,CAAC"}

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

@ -0,0 +1,15 @@
import { ICParam } from "./param.js";
export declare class ICResponseObj {
objnam: string;
params?: ICParam;
}
export declare class ICResponse {
command: string;
messageID: string;
response: string;
objectList?: ICResponseObj[];
queryName?: string;
answer?: ICResponseObj[];
timeSince?: string;
timeNow?: string;
}

15
esm/messages/response.js Normal file
View File

@ -0,0 +1,15 @@
export class ICResponseObj {
objnam = "";
params;
}
export class ICResponse {
command = "";
messageID = "";
response = "";
objectList;
queryName;
answer;
timeSince;
timeNow;
}
//# sourceMappingURL=response.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"response.js","sourceRoot":"","sources":["../../messages/response.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,aAAa;IACjB,MAAM,GAAG,EAAE,CAAC;IACZ,MAAM,CAAW;CACzB;AAED,MAAM,OAAO,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"}

9
esm/messages/schedule.d.ts vendored Normal file
View File

@ -0,0 +1,9 @@
import { ICRequest } from "./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
*/
export declare function GetSchedule(): ICRequest;

22
esm/messages/schedule.js Normal file
View File

@ -0,0 +1,22 @@
import { GetRequest, ICRequestObj } from "./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
*/
export function GetSchedule() {
const req = GetRequest();
req.command = "GetParamList";
req.condition = "OBJTYP=SCHED";
req.objectList = [];
const reqObj = new 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":"AAAA,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,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"}

15
esm/messages/set-heater.d.ts vendored Normal file
View File

@ -0,0 +1,15 @@
import { ICRequest } from "./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
*/
export declare function SetHeatMode(bodyObjnam: string, enabled: boolean): ICRequest;

View File

@ -0,0 +1,27 @@
import { ICParam } from "./param.js";
import { GetRequest, ICRequestObj } from "./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
*/
export function SetHeatMode(bodyObjnam, enabled) {
const req = GetRequest();
req.command = "SetParamList";
req.objectList = [];
const reqObj = new ICRequestObj();
reqObj.objnam = bodyObjnam;
reqObj.params = new 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":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,UAAkB,EAAE,OAAgB;IAC9D,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3B,MAAM,CAAC,MAAM,GAAG,IAAI,OAAO,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"}

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

@ -0,0 +1,9 @@
import { ICRequest } from "./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
*/
export declare function SetObjectStatus(object: string | string[], status: boolean): ICRequest;

View File

@ -0,0 +1,30 @@
import { ICParam } from "./param.js";
import { GetRequest, ICRequestObj } from "./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
*/
export function SetObjectStatus(object, status) {
const req = 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 ICRequestObj();
reqObj.objnam = i;
reqObj.params = new 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":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAyB,EACzB,MAAe;IAEf,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAClB,MAAM,CAAC,MAAM,GAAG,IAAI,OAAO,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"}

11
esm/messages/setpoint.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
import { ICRequest } from "./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
*/
export declare function SetSetpoint(objnam: string, setpoint: number): ICRequest;

23
esm/messages/setpoint.js Normal file
View File

@ -0,0 +1,23 @@
import { ICParam } from "./param.js";
import { GetRequest, ICRequestObj } from "./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
*/
export function SetSetpoint(objnam, setpoint) {
const req = GetRequest();
req.command = "SetParamList";
req.objectList = [];
const reqObj = new ICRequestObj();
reqObj.objnam = objnam;
reqObj.params = new 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":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,QAAgB;IAC1D,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,GAAG,CAAC,OAAO,GAAG,cAAc,CAAC;IAC7B,GAAG,CAAC,UAAU,GAAG,EAAE,CAAC;IAEpB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,MAAM,GAAG,IAAI,OAAO,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"}

7
esm/messages/system-info.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import { ICRequest } from "./request.js";
/**
* Requests information about this controller such as owner, address, etc.
*
* @returns the object used to issue this request
*/
export declare function GetSystemInformation(): ICRequest;

View File

@ -0,0 +1,43 @@
import { GetRequest, ICRequestObj } from "./request.js";
/**
* Requests information about this controller such as owner, address, etc.
*
* @returns the object used to issue this request
*/
export function GetSystemInformation() {
const req = GetRequest();
req.command = "GETPARAMLIST";
req.condition = "";
req.objectList = [];
const reqObj = new 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":"AAAA,OAAO,EAAE,UAAU,EAAa,YAAY,EAAE,MAAM,cAAc,CAAC;AAEnE;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,GAAG,GAAG,UAAU,EAAE,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,YAAY,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
esm/package.json Normal file
View File

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

47
esm/unit.d.ts vendored Normal file
View File

@ -0,0 +1,47 @@
import { EventEmitter } from "events";
import { ICRequest } from "./messages/request.js";
import { ICResponse } from "./messages/response.js";
/**
* 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
*/
export declare class Unit extends EventEmitter {
endpoint: string;
port: number;
private client?;
private pingTimeout?;
private pingTimer?;
private pingInterval;
constructor(endpoint: string, port?: number);
/**
* Connects to the specified unit and maintains a connection to it until `close()` is called.
*/
connect(): Promise<void>;
/**
* Closes the connection to the unit.
*/
close(): void;
private socketCleanup;
private heartbeat;
private onClientMessage;
/**
* 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.
*/
send(request: ICRequest): Promise<ICResponse>;
}

137
esm/unit.js Normal file
View File

@ -0,0 +1,137 @@
import { EventEmitter } from "events";
import { WebSocket } from "ws";
import debug from "debug";
const debugUnit = debug("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
*/
export class Unit extends 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 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);
});
});
}
}
//# sourceMappingURL=unit.js.map

1
esm/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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"}