From b186561d242daabccbf8ab1500d2a3c47b37cd03 Mon Sep 17 00:00:00 2001 From: Parnic Date: Thu, 2 Jan 2025 17:03:28 -0600 Subject: [PATCH] Finish Finder implementation This can correctly find and return IntelliCenter units on the local network now. Cleaned up a bunch of Finder code and added back in "debug" module logging. Fixed up types in Dns module so we can use instanceof --- dist/dns.d.ts | 23 ++---- dist/dns.js | 121 +++++++++++++++++-------------- dist/dns.js.map | 2 +- dist/finder.d.ts | 27 +++++-- dist/finder.js | 138 ++++++++++++++++------------------- dist/finder.js.map | 2 +- dist/index.js | 18 +++-- dist/index.js.map | 2 +- dns.ts | 158 ++++++++++++++++++++-------------------- finder.ts | 176 ++++++++++++++++++++++----------------------- index.ts | 22 ++++-- package-lock.json | 49 ++++++++++--- package.json | 3 + 13 files changed, 401 insertions(+), 340 deletions(-) diff --git a/dist/dns.d.ts b/dist/dns.d.ts index 2c07ec0..c7a3467 100644 --- a/dist/dns.d.ts +++ b/dist/dns.d.ts @@ -1,40 +1,31 @@ -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; - constructor(_name: string, _type: number, _cls: number, _endOffset: number); } -export interface Record { - interface: string | undefined; +export declare abstract class Record { type: number; ttlSeconds: number; name: string; endOffset: number; } -export interface PtrRecord extends Record { - interface: "ptr"; +export declare class PtrRecord extends Record { domain: string; } -export interface TxtRecord extends Record { - interface: "txt"; +export declare class TxtRecord extends Record { text: string; } -export interface SrvRecord extends Record { - interface: "srv"; +export declare class SrvRecord extends Record { priority: number; weight: number; port: number; target: string; } -export interface ARecord extends Record { - interface: "a"; +export declare class ARecord extends Record { address: number; - addressStr: string; + 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; diff --git a/dist/dns.js b/dist/dns.js index 9a9010a..b1a9960 100644 --- a/dist/dns.js +++ b/dist/dns.js @@ -1,19 +1,45 @@ -export const TypeTxt = 16; -export const TypePtr = 12; -export const TypeSrv = 33; -export const TypeA = 1; +const TypeTxt = 16; +const TypePtr = 12; +const TypeSrv = 33; +const TypeA = 1; export class Question { name = ""; type = 0; class = 0; endOffset = 0; - constructor(_name, _type, _cls, _endOffset) { - this.name = _name; - this.type = _type; - this.class = _cls; - this.endOffset = _endOffset; +} +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; @@ -58,7 +84,12 @@ export function GetDNSQuestion(msg, startOffset) { offset += 2; const cls = msg.readUInt16BE(offset); offset += 2; - return new Question(parsedResult.name, type, cls, offset); + 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; @@ -74,26 +105,22 @@ export function GetDNSAnswer(msg, startOffset) { switch (type) { case TypePtr: { const domainResult = parseDnsName(msg, offset); - const ret = { - interface: "ptr", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - domain: domainResult.name, - }; + 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 = { - interface: "txt", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - text: textResult.name, - }; + 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: { @@ -101,35 +128,25 @@ export function GetDNSAnswer(msg, startOffset) { const weight = msg.readUInt16BE(offset + 2); const port = msg.readUInt16BE(offset + 4); const targetResult = parseDnsName(msg, offset + 6); - const ret = { - interface: "srv", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - priority: priority, - weight: weight, - port: port, - target: targetResult.name, - }; + 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 o1 = msg.readUInt8(offset); - const o2 = msg.readUInt8(offset + 1); - const o3 = msg.readUInt8(offset + 2); - const o4 = msg.readUInt8(offset + 3); - const address = (o1 << 24) | (o2 << 16) | (o3 << 8) | (o4 << 0); - const addressStr = `${o1.toString()}.${o2.toString()}.${o3.toString()}.${o4.toString()}`; - const ret = { - interface: "a", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - address: address, - addressStr: addressStr, - }; + 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: diff --git a/dist/dns.js.map b/dist/dns.js.map index ffa3190..3fed62d 100644 --- a/dist/dns.js.map +++ b/dist/dns.js.map @@ -1 +1 @@ -{"version":3,"file":"dns.js","sourceRoot":"","sources":["../dns.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,CAAC;AAC1B,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,CAAC;AAC1B,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,CAAC;AAC1B,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC;AAEvB,MAAM,OAAO,QAAQ;IACZ,IAAI,GAAG,EAAE,CAAC;IACV,IAAI,GAAG,CAAC,CAAC;IACT,KAAK,GAAG,CAAC,CAAC;IACV,SAAS,GAAG,CAAC,CAAC;IAErB,YAAY,KAAa,EAAE,KAAa,EAAE,IAAY,EAAE,UAAkB;QACxE,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC;IAC9B,CAAC;CACF;AAkCD,MAAM,oBAAoB;IACjB,IAAI,GAAG,EAAE,CAAC;IACV,SAAS,GAAG,CAAC,CAAC;CACtB;AAED,SAAS,YAAY,CAAC,GAAW,EAAE,WAAmB;IACpD,MAAM,MAAM,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC1C,IAAI,MAAM,GAAG,WAAW,CAAC;IAEzB,OAAO,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACnB,MAAM,EAAE,CAAC;YACT,MAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,KAAK,WAAW,EAAE,CAAC;YAC7C,MAAM,EAAE,CAAC;YACT,MAAM,aAAa,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,EAAE,CAAC;YACT,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YACtD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3D,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC;YACrB,CAAC;YACD,MAAM,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC;YACjC,MAAM;QACR,CAAC;QAED,MAAM,EAAE,CAAC;QACT,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC;QACjE,MAAM,IAAI,QAAQ,CAAC;QACnB,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC;QACrB,CAAC;QACD,MAAM,CAAC,IAAI,IAAI,OAAO,CAAC;IACzB,CAAC;IAED,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC;IAC1B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,WAAmB;IAC7D,IAAI,MAAM,GAAG,WAAW,CAAC;IACzB,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC;IAChC,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,IAAI,CAAC,CAAC;IACZ,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,IAAI,CAAC,CAAC;IACZ,OAAO,IAAI,QAAQ,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,GAAW,EACX,WAAmB;IAEnB,IAAI,MAAM,GAAG,WAAW,CAAC;IACzB,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC/C,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC;IAEhC,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,IAAI,CAAC,CAAC;IACZ,MAAM,IAAI,CAAC,CAAC,CAAC,qCAAqC;IAClD,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,IAAI,CAAC,CAAC;IACZ,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,IAAI,CAAC,CAAC;IAEZ,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC/C,MAAM,GAAG,GAAc;gBACrB,SAAS,EAAE,KAAK;gBAChB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,UAAU;gBACtB,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,SAAS,EAAE,MAAM,GAAG,WAAW;gBAC/B,MAAM,EAAE,YAAY,CAAC,IAAI;aAC1B,CAAC;YACF,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC7C,MAAM,GAAG,GAAc;gBACrB,SAAS,EAAE,KAAK;gBAChB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,UAAU;gBACtB,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,SAAS,EAAE,MAAM,GAAG,WAAW;gBAC/B,IAAI,EAAE,UAAU,CAAC,IAAI;aACtB,CAAC;YACF,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC1C,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;YAEnD,MAAM,GAAG,GAAc;gBACrB,SAAS,EAAE,KAAK;gBAChB,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,UAAU;gBACtB,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,SAAS,EAAE,MAAM,GAAG,WAAW;gBAC/B,QAAQ,EAAE,QAAQ;gBAClB,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,IAAI;gBACV,MAAM,EAAE,YAAY,CAAC,IAAI;aAC1B,CAAC;YACF,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACjC,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrC,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrC,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YAChE,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YAEzF,MAAM,GAAG,GAAY;gBACnB,SAAS,EAAE,GAAG;gBACd,IAAI,EAAE,IAAI;gBACV,UAAU,EAAE,UAAU;gBACtB,IAAI,EAAE,YAAY,CAAC,IAAI;gBACvB,SAAS,EAAE,MAAM,GAAG,WAAW;gBAC/B,OAAO,EAAE,OAAO;gBAChB,UAAU,EAAE,UAAU;aACvB,CAAC;YACF,OAAO,GAAG,CAAC;QACb,CAAC;QAED;YACE,MAAM;IACV,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"} \ No newline at end of file +{"version":3,"file":"dns.js","sourceRoot":"","sources":["../dns.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/finder.d.ts b/dist/finder.d.ts index b5043cc..f0b5f1d 100644 --- a/dist/finder.d.ts +++ b/dist/finder.d.ts @@ -1,13 +1,32 @@ -import * as dgram from "dgram"; import { EventEmitter } from "events"; +export declare class UnitInfo { + name: string; + hostname: string; + port: number; + address: number; + get addressStr(): string; + constructor(_name: string, _hostname: string, _port: number, _address: number); +} export declare class FindUnits extends EventEmitter { constructor(); 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. + */ search(): void; - searchAsync(searchTimeMs?: number): Promise; - foundServer(msg: Buffer, remote: dgram.RemoteInfo): void; - sendServerBroadcast(): 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 units, if any. + */ + searchAsync(searchTimeMs?: number): Promise; + private foundServer; + private sendServerBroadcast; + /** + * Closes the finder socket. + */ close(): void; } diff --git a/dist/finder.js b/dist/finder.js index bf90559..2d98a5e 100644 --- a/dist/finder.js +++ b/dist/finder.js @@ -1,35 +1,28 @@ -import * as dgram from "dgram"; +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import { createSocket } from "dgram"; import { EventEmitter } from "events"; -import { setTimeout as setTimeoutSync } from "timers"; -import os from "os"; -import { GetDNSAnswer, GetDNSQuestion } from "./dns.js"; +import debug from "debug"; +import { ARecord, GetDNSAnswer, GetDNSQuestion, ipToString, PtrRecord, SrvRecord, } from "./dns.js"; +const debugFind = debug("ic:find"); +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; + } +} export class FindUnits extends EventEmitter { constructor() { super(); - const infs = os.networkInterfaces(); - const localIps = []; - let localIp = "127.0.0.1"; - Object.keys(infs).forEach((key) => { - infs[key]?.forEach((iface) => { - if (iface.internal) { - return; - } - if (iface.family !== "IPv4") { - return; - } - localIps.push(iface.address); - }); - }); - if (localIps.length === 0) { - console.error(`no local interfaces found, can't search for controllers.`); - // todo: emit error - } - else { - localIp = localIps[0]; - } - if (localIps.length > 1) { - console.log(`found ${localIps.length.toString()} local IPs, using the first one for SSDP search (${localIp})`); - } // construct mDNS packet to ping for intellicenter controllers this.message = Buffer.alloc(34); let offset = 0; @@ -48,7 +41,7 @@ export class FindUnits extends EventEmitter { offset = this.message.writeUInt8(0, offset); // no more strings offset = this.message.writeUInt16BE(0x000c, offset); // type: ptr this.message.writeUInt16BE(1, offset); // class: IN - this.finder = dgram.createSocket("udp4"); + this.finder = createSocket("udp4"); this.finder .on("listening", () => { this.finder.setBroadcast(true); @@ -58,23 +51,25 @@ export class FindUnits extends EventEmitter { this.sendServerBroadcast(); } }) - .on("message", (msg, remote) => { - this.foundServer(msg, remote); + .on("message", (msg) => { + this.foundServer(msg); }) .on("close", () => { - // debugFind("closed"); - console.log("closed"); + debugFind("Finder socket closed."); this.emit("close"); }) .on("error", (e) => { - // debugFind("error: %O", e); - console.log("errored"); + 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. + */ search() { if (!this.bound) { this.finder.bind(); @@ -83,27 +78,29 @@ export class FindUnits extends EventEmitter { 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 units, if any. + */ async searchAsync(searchTimeMs) { const p = new Promise((resolve) => { - // debugFind("IntelliCenter finder searching for local units..."); - setTimeoutSync(() => { - // if (units.length === 0) { - // debugFind("No units found searching locally."); - // } + setTimeout(() => { + if (this.units.length === 0) { + debugFind("No units found searching locally."); + } this.removeAllListeners(); - resolve(0); + resolve(this.units); }, searchTimeMs ?? 5000); - this.on("serverFound", () => { - // debugFind(`IntelliCenter found unit ${JSON.stringify(unit)}`); - console.log("found"); - // units.push(unit); + this.on("serverFound", (unit) => { + debugFind(" found: %o", unit); + this.units.push(unit); }); this.search(); }); - return Promise.resolve(p); + return p; } - foundServer(msg, remote) { - // debugFind("found something"); + foundServer(msg) { let flags = 0; if (msg.length > 4) { flags = msg.readUInt16BE(2); @@ -128,6 +125,7 @@ export class FindUnits extends EventEmitter { if (msg.length >= 8) { answers = msg.readUInt16BE(6); } + const records = []; if (answers > 0) { for (let i = 0; i < answers; i++) { if (msg.length <= nextAnswerOffset) { @@ -138,45 +136,33 @@ export class FindUnits extends EventEmitter { if (!answer) { break; } + records.push(answer); nextAnswerOffset = answer.endOffset; - if (answer.interface === "a") { - console.log("a record:", answer); - } } } - const str = msg.toString(); - console.log(str); - if (msg.length >= 40) { - const server = { - address: remote.address, - type: msg.readInt32LE(0), - port: msg.readInt16LE(8), - gatewayType: msg.readUInt8(10), - gatewaySubtype: msg.readUInt8(11), - gatewayName: msg.toString("utf8", 12, 29), - }; - // debugFind( - // " type: " + - // server.type + - // ", host: " + - // server.address + - // ":" + - // server.port + - // ", identified as " + - // server.gatewayName, - // ); - if (server.type === 2) { - this.emit("serverFound", server); + 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(" unexpected message"); + 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..."); + debugFind("Looking for IntelliCenter hosts..."); } + /** + * Closes the finder socket. + */ close() { this.finder.close(); } diff --git a/dist/finder.js.map b/dist/finder.js.map index 0a9206c..efa3ab9 100644 --- a/dist/finder.js.map +++ b/dist/finder.js.map @@ -1 +1 @@ -{"version":3,"file":"finder.js","sourceRoot":"","sources":["../finder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,OAAO,SAAU,SAAQ,YAAY;IACzC;QACE,KAAK,EAAE,CAAC;QAER,MAAM,IAAI,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,OAAO,GAAG,WAAW,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAChC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC3B,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnB,OAAO;gBACT,CAAC;gBACD,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;oBAC5B,OAAO;gBACT,CAAC;gBACD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;YAC1E,mBAAmB;QACrB,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CACT,SAAS,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,oDAAoD,OAAO,GAAG,CAClG,CAAC;QACJ,CAAC;QAED,8DAA8D;QAC9D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,iBAAiB;QACjE,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,8BAA8B;QAC9E,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,oBAAoB;QACpE,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY;QAC5D,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,eAAe;QAC/D,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,gBAAgB;QAChE,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACxD,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzD,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,kBAAkB;QAC/D,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY;QACjE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY;QAEnD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM;aACR,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;YACpB,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAEjC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;gBAClB,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,CAAC;QACH,CAAC,CAAC;aACD,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAC7B,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC,CAAC;aACD,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAChB,uBAAuB;YACvB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC,CAAC;aACD,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;YACjB,6BAA6B;YAC7B,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,MAAM,CAAS;IACf,KAAK,GAAG,KAAK,CAAC;IACd,OAAO,CAAS;IAExB,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,YAAqB;QAC5C,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAChC,kEAAkE;YAClE,cAAc,CAAC,GAAG,EAAE;gBAClB,8BAA8B;gBAC9B,sDAAsD;gBACtD,MAAM;gBAEN,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC1B,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,CAAC,EAAE,YAAY,IAAI,IAAI,CAAC,CAAC;YAEzB,IAAI,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;gBAC1B,mEAAmE;gBACnE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACrB,sBAAsB;YACxB,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAkB,CAAC;IAC7C,CAAC;IAED,WAAW,CAAC,GAAW,EAAE,MAAwB;QAC/C,gCAAgC;QAEhC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC5B,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9B,0CAA0C;gBAC1C,OAAO;YACT,CAAC;QACH,CAAC;QAED,IAAI,gBAAgB,GAAG,EAAE,CAAC;QAE1B,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACpB,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAChC,IAAI,kBAAkB,GAAG,EAAE,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;gBACnC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;gBACvD,kBAAkB,GAAG,MAAM,CAAC,SAAS,CAAC;YACxC,CAAC;YAED,gBAAgB,GAAG,kBAAkB,CAAC;QACxC,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,IAAI,GAAG,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;oBACnC,OAAO,CAAC,KAAK,CACX,2DAA2D,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,CAC7H,CAAC;oBACF,MAAM;gBACR,CAAC;gBAED,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;gBACnD,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM;gBACR,CAAC;gBAED,gBAAgB,GAAG,MAAM,CAAC,SAAS,CAAC;gBACpC,IAAI,MAAM,CAAC,SAAS,KAAK,GAAG,EAAE,CAAC;oBAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEjB,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG;gBACb,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;gBACxB,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;gBACxB,WAAW,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC9B,cAAc,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjC,WAAW,EAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;aAC1C,CAAC;YAEF,eAAe;YACf,mBAAmB;YACnB,sBAAsB;YACtB,qBAAqB;YACrB,yBAAyB;YACzB,cAAc;YACd,sBAAsB;YACtB,6BAA6B;YAC7B,4BAA4B;YAC5B,OAAO;YAEP,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,uCAAuC;QACzC,CAAC;IACH,CAAC;IAED,mBAAmB;QACjB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;QAC5E,mDAAmD;IACrD,CAAC;IAEM,KAAK;QACV,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF"} \ No newline at end of file +{"version":3,"file":"finder.js","sourceRoot":"","sources":["../finder.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js index 40f31f8..bc709d6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4,12 +4,20 @@ import { v4 as uuidv4 } from "uuid"; import { FindUnits } from "./finder.js"; console.log("searching..."); const f = new FindUnits(); -await f.searchAsync(5000); -// temp. replace with the IP of your device -const endpoint = "10.0.0.41"; +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; let pingTimeout; -console.log("connecting to intellicenter device at", endpoint); -const client = new WebSocket(`ws://${endpoint}:6680`); +console.log("connecting to intellicenter device at", endpoint, "port", port); +const client = new WebSocket(`ws://${endpoint}:${port.toString()}`); const heartbeat = () => { clearTimeout(pingTimeout); pingTimeout = setTimeout(() => { diff --git a/dist/index.js.map b/dist/index.js.map index f284be0..d7bfce0 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAC5B,MAAM,CAAC,GAAG,IAAI,SAAS,EAAE,CAAC;AAC1B,MAAM,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;AAE1B,2CAA2C;AAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC;AAE7B,IAAI,WAA0C,CAAC;AAE/C,OAAO,CAAC,GAAG,CAAC,uCAAuC,EAAE,QAAQ,CAAC,CAAC;AAC/D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,QAAQ,OAAO,CAAC,CAAC;AAEtD,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,YAAY,CAAC,WAAW,CAAC,CAAC;IAE1B,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE;QAC5B,MAAM,CAAC,SAAS,EAAE,CAAC;IACrB,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;AAClC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAC7B,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;IACtB,YAAY,CAAC,WAAW,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAW,EAAE,EAAE;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,8DAA8D;IAC1G,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AACH,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IACpC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC/B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;IACX,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG;QACV,SAAS,EAAE,EAAE;QACb,UAAU,EAAE;YACV;gBACE,MAAM,EAAE,OAAO;gBACf,IAAI,EAAE;oBACJ,KAAK;oBACL,MAAM;oBACN,KAAK;oBACL,QAAQ;oBACR,UAAU;oBACV,MAAM;oBACN,SAAS;oBACT,MAAM;oBACN,OAAO;oBACP,OAAO;oBACP,QAAQ;oBACR,OAAO;oBACP,QAAQ;oBACR,SAAS;oBACT,OAAO;oBACP,MAAM;oBACN,MAAM;oBACN,OAAO;oBACP,SAAS;oBACT,QAAQ;oBACR,UAAU;oBACV,IAAI;oBACJ,OAAO;oBACP,SAAS;iBACV;aACF;SACF;QACD,OAAO,EAAE,cAAc;QACvB,SAAS,EAAE,MAAM,EAAE;KACpB,CAAC;IACF,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dns.ts b/dns.ts index 188aa07..314a79e 100644 --- a/dns.ts +++ b/dns.ts @@ -1,52 +1,52 @@ -export const TypeTxt = 16; -export const TypePtr = 12; -export const TypeSrv = 33; -export const TypeA = 1; +const TypeTxt = 16; +const TypePtr = 12; +const TypeSrv = 33; +const TypeA = 1; export class Question { public name = ""; public type = 0; public class = 0; public endOffset = 0; +} - constructor(_name: string, _type: number, _cls: number, _endOffset: number) { - this.name = _name; - this.type = _type; - this.class = _cls; - this.endOffset = _endOffset; +export abstract class Record { + public type = 0; + public ttlSeconds = 0; + public name = ""; + public endOffset = -1; +} + +export class PtrRecord extends Record { + public domain = ""; +} + +export class TxtRecord extends Record { + public text = ""; +} + +export class SrvRecord extends Record { + public priority = 0; + public weight = 0; + public port = 0; + public target = ""; +} + +export class ARecord extends Record { + public address = 0; + + public get addressStr(): string { + return ipToString(this.address); } } -export interface Record { - interface: string | undefined; - type: number; - ttlSeconds: number; - name: string; - endOffset: number; -} - -export interface PtrRecord extends Record { - interface: "ptr"; - domain: string; -} - -export interface TxtRecord extends Record { - interface: "txt"; - text: string; -} - -export interface SrvRecord extends Record { - interface: "srv"; - priority: number; - weight: number; - port: number; - target: string; -} - -export interface ARecord extends Record { - interface: "a"; - address: number; - addressStr: string; +export function ipToString(ip: number): string { + 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 { @@ -99,7 +99,13 @@ export function GetDNSQuestion(msg: Buffer, startOffset: number): Question { offset += 2; const cls = msg.readUInt16BE(offset); offset += 2; - return new Question(parsedResult.name, type, cls, offset); + + const ret = new Question(); + ret.name = parsedResult.name; + ret.type = type; + ret.class = cls; + ret.endOffset = offset; + return ret; } export function GetDNSAnswer( @@ -121,27 +127,25 @@ export function GetDNSAnswer( switch (type) { case TypePtr: { const domainResult = parseDnsName(msg, offset); - const ret: PtrRecord = { - interface: "ptr", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - domain: domainResult.name, - }; + + 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: TxtRecord = { - interface: "txt", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - text: textResult.name, - }; + + const ret = new TxtRecord(); + ret.type = type; + ret.ttlSeconds = ttlSeconds; + ret.name = parsedResult.name; + ret.endOffset = offset + rDataLength; + ret.text = textResult.name; return ret; } @@ -151,37 +155,27 @@ export function GetDNSAnswer( const port = msg.readUInt16BE(offset + 4); const targetResult = parseDnsName(msg, offset + 6); - const ret: SrvRecord = { - interface: "srv", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - priority: priority, - weight: weight, - port: port, - target: targetResult.name, - }; + 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 o1 = msg.readUInt8(offset); - const o2 = msg.readUInt8(offset + 1); - const o3 = msg.readUInt8(offset + 2); - const o4 = msg.readUInt8(offset + 3); - const address = (o1 << 24) | (o2 << 16) | (o3 << 8) | (o4 << 0); - const addressStr = `${o1.toString()}.${o2.toString()}.${o3.toString()}.${o4.toString()}`; + const address = msg.readUInt32BE(offset); - const ret: ARecord = { - interface: "a", - type: type, - ttlSeconds: ttlSeconds, - name: parsedResult.name, - endOffset: offset + rDataLength, - address: address, - addressStr: addressStr, - }; + const ret = new ARecord(); + ret.type = type; + ret.ttlSeconds = ttlSeconds; + ret.name = parsedResult.name; + ret.endOffset = offset + rDataLength; + ret.address = address; return ret; } diff --git a/finder.ts b/finder.ts index bedbe54..f6f451c 100644 --- a/finder.ts +++ b/finder.ts @@ -1,41 +1,48 @@ -import * as dgram from "dgram"; -import { Socket } from "dgram"; +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import { createSocket, Socket } from "dgram"; import { EventEmitter } from "events"; -import { setTimeout as setTimeoutSync } from "timers"; -import os from "os"; -import { GetDNSAnswer, GetDNSQuestion } from "./dns.js"; +import debug from "debug"; + +import { + ARecord, + GetDNSAnswer, + GetDNSQuestion, + ipToString, + PtrRecord, + Record, + SrvRecord, +} from "./dns.js"; + +const debugFind = debug("ic:find"); + +export class UnitInfo { + public name: string; + public hostname: string; + public port: number; + public address: number; + + public get addressStr(): string { + return ipToString(this.address); + } + + public constructor( + _name: string, + _hostname: string, + _port: number, + _address: number, + ) { + this.name = _name; + this.hostname = _hostname; + this.port = _port; + this.address = _address; + } +} export class FindUnits extends EventEmitter { constructor() { super(); - const infs = os.networkInterfaces(); - const localIps: string[] = []; - let localIp = "127.0.0.1"; - Object.keys(infs).forEach((key) => { - infs[key]?.forEach((iface) => { - if (iface.internal) { - return; - } - if (iface.family !== "IPv4") { - return; - } - localIps.push(iface.address); - }); - }); - if (localIps.length === 0) { - console.error(`no local interfaces found, can't search for controllers.`); - // todo: emit error - } else { - localIp = localIps[0]; - } - - if (localIps.length > 1) { - console.log( - `found ${localIps.length.toString()} local IPs, using the first one for SSDP search (${localIp})`, - ); - } - // construct mDNS packet to ping for intellicenter controllers this.message = Buffer.alloc(34); let offset = 0; @@ -55,7 +62,7 @@ export class FindUnits extends EventEmitter { offset = this.message.writeUInt16BE(0x000c, offset); // type: ptr this.message.writeUInt16BE(1, offset); // class: IN - this.finder = dgram.createSocket("udp4"); + this.finder = createSocket("udp4"); this.finder .on("listening", () => { this.finder.setBroadcast(true); @@ -66,17 +73,15 @@ export class FindUnits extends EventEmitter { this.sendServerBroadcast(); } }) - .on("message", (msg, remote) => { - this.foundServer(msg, remote); + .on("message", (msg) => { + this.foundServer(msg); }) .on("close", () => { - // debugFind("closed"); - console.log("closed"); + debugFind("Finder socket closed."); this.emit("close"); }) .on("error", (e) => { - // debugFind("error: %O", e); - console.log("errored"); + debugFind("Finder socket error: %O", e); this.emit("error", e); }); } @@ -84,8 +89,12 @@ export class FindUnits extends EventEmitter { private finder: Socket; private bound = false; private message: Buffer; + private units: UnitInfo[] = []; - search() { + /** + * Begins a search and returns immediately. Must close the finder with close() when done with all searches. + */ + public search() { if (!this.bound) { this.finder.bind(); } else { @@ -93,33 +102,34 @@ export class FindUnits extends EventEmitter { } } - public async searchAsync(searchTimeMs?: number): Promise { - const p = new Promise((resolve) => { - // debugFind("IntelliCenter finder searching for local units..."); - setTimeoutSync(() => { - // if (units.length === 0) { - // debugFind("No units found searching locally."); - // } + /** + * 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 units, if any. + */ + public async searchAsync(searchTimeMs?: number): Promise { + const p = new Promise((resolve) => { + setTimeout(() => { + if (this.units.length === 0) { + debugFind("No units found searching locally."); + } this.removeAllListeners(); - resolve(0); + resolve(this.units); }, searchTimeMs ?? 5000); - this.on("serverFound", () => { - // debugFind(`IntelliCenter found unit ${JSON.stringify(unit)}`); - console.log("found"); - // units.push(unit); + this.on("serverFound", (unit: UnitInfo) => { + debugFind(" found: %o", unit); + this.units.push(unit); }); this.search(); }); - return Promise.resolve(p) as Promise; + return p; } - foundServer(msg: Buffer, remote: dgram.RemoteInfo) { - // debugFind("found something"); - + private foundServer(msg: Buffer) { let flags = 0; if (msg.length > 4) { flags = msg.readUInt16BE(2); @@ -149,6 +159,7 @@ export class FindUnits extends EventEmitter { answers = msg.readUInt16BE(6); } + const records: Record[] = []; if (answers > 0) { for (let i = 0; i < answers; i++) { if (msg.length <= nextAnswerOffset) { @@ -163,50 +174,39 @@ export class FindUnits extends EventEmitter { break; } + records.push(answer); nextAnswerOffset = answer.endOffset; - if (answer.interface === "a") { - console.log("a record:", answer); - } } } - const str = msg.toString(); - console.log(str); - - if (msg.length >= 40) { - const server = { - address: remote.address, - type: msg.readInt32LE(0), - port: msg.readInt16LE(8), - gatewayType: msg.readUInt8(10), - gatewaySubtype: msg.readUInt8(11), - gatewayName: msg.toString("utf8", 12, 29), - }; - - // debugFind( - // " type: " + - // server.type + - // ", host: " + - // server.address + - // ":" + - // server.port + - // ", identified as " + - // server.gatewayName, - // ); - - if (server.type === 2) { - this.emit("serverFound", server); + 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(" unexpected message"); + debugFind( + " found something that wasn't an IntelliCenter unit: %s", + records + .filter((r) => r instanceof PtrRecord) + .map((r) => r.domain) + .join(", "), + ); } } - sendServerBroadcast() { + private sendServerBroadcast() { this.finder.send(this.message, 0, this.message.length, 5353, "224.0.0.251"); - // debugFind("Looking for IntelliCenter hosts..."); + debugFind("Looking for IntelliCenter hosts..."); } + /** + * Closes the finder socket. + */ public close() { this.finder.close(); } diff --git a/index.ts b/index.ts index e84db64..9f41f1a 100644 --- a/index.ts +++ b/index.ts @@ -6,15 +6,27 @@ import { FindUnits } from "./finder.js"; console.log("searching..."); const f = new FindUnits(); -await f.searchAsync(5000); +const units = await f.searchAsync(1000); +f.close(); +console.log("Discovered units:", units); -// temp. replace with the IP of your device -const endpoint = "10.0.0.41"; +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; let pingTimeout: ReturnType; -console.log("connecting to intellicenter device at", endpoint); -const client = new WebSocket(`ws://${endpoint}:6680`); +console.log("connecting to intellicenter device at", endpoint, "port", port); +const client = new WebSocket(`ws://${endpoint}:${port.toString()}`); const heartbeat = () => { clearTimeout(pingTimeout); diff --git a/package-lock.json b/package-lock.json index d2dbe1a..eb93e00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,17 @@ "version": "0.0.1", "license": "MIT", "dependencies": { + "debug": "^4.4.0", "uuid": "^11.0.3", "ws": "^8.18.0" }, "devDependencies": { "@eslint/js": "^9.17.0", + "@types/debug": "^4.1.12", "@types/ws": "^8.5.13", "eslint": "^9.17.0", "prettier": "3.4.2", + "supports-color": "^10.0.0", "typescript": "^5.7.2", "typescript-eslint": "^8.19.0" }, @@ -255,6 +258,16 @@ "node": ">= 8" } }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -269,6 +282,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.10.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", @@ -630,6 +650,19 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -676,7 +709,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1231,7 +1263,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/natural-compare": { @@ -1501,16 +1532,16 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.0.0.tgz", + "integrity": "sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==", "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/to-regex-range": { diff --git a/package.json b/package.json index 31f6f58..cd94be5 100644 --- a/package.json +++ b/package.json @@ -30,14 +30,17 @@ "lint": "eslint . && prettier . --check" }, "dependencies": { + "debug": "^4.4.0", "uuid": "^11.0.3", "ws": "^8.18.0" }, "devDependencies": { "@eslint/js": "^9.17.0", + "@types/debug": "^4.1.12", "@types/ws": "^8.5.13", "eslint": "^9.17.0", "prettier": "3.4.2", + "supports-color": "^10.0.0", "typescript": "^5.7.2", "typescript-eslint": "^8.19.0" },