@vldmit/leap-client 1.7.9 → 1.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +2 -2
- package/lib/index.js.map +3 -3
- package/package.json +1 -1
package/lib/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/Connection/Association.ts", "../src/Connection/Connection.ts", "../src/Response/Parser.ts", "../src/Response/ResponseHeader.ts", "../src/Response/ResponseStatus.ts", "../src/Response/Response.ts", "../src/Response/ExceptionDetail.ts", "../src/Connection/Socket.ts", "../src/Connection/Context.ts", "../src/Connection/Discovery.ts", "../src/Client.ts", "../src/Devices/Processor/ProcessorController.ts", "../src/Devices/Devices.ts", "../src/Devices/Contact/ContactController.ts", "../src/Devices/Common.ts", "../src/Devices/Dimmer/DimmerController.ts", "../src/Devices/Fan/FanController.ts", "../src/Devices/Keypad/KeypadController.ts", "../src/Devices/Remote/RemoteController.ts", "../src/Devices/Remote/ButtonMap.ts", "../src/Devices/Remote/TriggerController.ts", "../src/Devices/Occupancy/OccupancyController.ts", "../src/Devices/Shade/ShadeController.ts", "../src/Devices/Strip/StripController.ts", "../src/Devices/Switch/SwitchController.ts", "../src/Devices/Timeclock/TimeclockController.ts", "../src/Devices/Unknown/UnknownController.ts", "../src/Connection/MetadataProbe.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Publishes devices, states and actions to an event emitter using the Lutron\n * LEAP protocol.\n *\n * @remarks\n * This will autopmatically discover processors. You will need to press the\n * pairing button on your processor or bridge.\n *\n * @packageDocumentation\n */\n\nimport { Association } from \"./Connection/Association\";\nimport { Context } from \"./Connection/Context\";\nimport { Discovery } from \"./Connection/Discovery\";\nimport { Client } from \"./Client\";\n\nexport { Contact } from \"./Devices/Contact/Contact\";\nexport { ContactState } from \"./Devices/Contact/ContactState\";\nexport { Dimmer } from \"./Devices/Dimmer/Dimmer\";\nexport { DimmerState } from \"./Devices/Dimmer/DimmerState\";\nexport { Fan } from \"./Devices/Fan/Fan\";\nexport { FanState } from \"./Devices/Fan/FanState\";\nexport { Keypad } from \"./Devices/Keypad/Keypad\";\nexport { KeypadState } from \"./Devices/Keypad/KeypadState\";\nexport { Occupancy } from \"./Devices/Occupancy/Occupancy\";\nexport { OccupancyState } from \"./Devices/Occupancy/OccupancyState\";\nexport { Remote } from \"./Devices/Remote/Remote\";\nexport { Shade } from \"./Devices/Shade/Shade\";\nexport { ShadeState } from \"./Devices/Shade/ShadeState\";\nexport { Strip } from \"./Devices/Strip/Strip\";\nexport { StripState } from \"./Devices/Strip/StripState\";\nexport { Switch } from \"./Devices/Switch/Switch\";\nexport { SwitchState } from \"./Devices/Switch/SwitchState\";\nexport { Timeclock } from \"./Devices/Timeclock/Timeclock\";\nexport { TimeclockState } from \"./Devices/Timeclock/TimeclockState\";\nexport { Unknown } from \"./Devices/Unknown/Unknown\";\n\n/**\n * Establishes a connection to all paired devices.\n *\n * @param refresh (optional) Setting this to true will not load devices from\n * cache.\n *\n * @returns A reference to the location with all processors.\n * @public\n */\nexport function connect(refresh?: boolean): Client {\n return new Client(refresh);\n}\n\n/**\n * Starts listening for pairing commands from processors.\n * @public\n */\nexport function pair(): Promise<void> {\n return new Promise((resolve, reject) => {\n const discovery = new Discovery();\n const context = new Context();\n\n discovery.on(\"Discovered\", (processor) => {\n if (context.get(processor.id) == null) {\n const association = new Association(processor);\n\n association\n .authenticate()\n .then((certificate) => {\n context.set(processor, certificate);\n\n resolve();\n })\n .catch((error) => reject(error))\n .finally(() => discovery.stop());\n }\n });\n\n discovery.search();\n });\n}\n\nexport { Client };\n", "import { pki } from \"node-forge\";\nimport { HostAddressFamily } from \"@mkellsy/hap-device\";\n\nimport { Certificate } from \"../Response/Certificate\";\nimport { CertificateRequest } from \"../Response/CertificateRequest\";\nimport { Connection } from \"./Connection\";\nimport { ProcessorAddress } from \"../Response/ProcessorAddress\";\n\n/**\n * Defines the logic for pairing a processor to this device.\n * @private\n */\nexport class Association {\n private connection: Connection;\n\n /**\n * Creates an association to a processor (pairing).\n *\n * @param processor The processor to pair.\n */\n constructor(processor: ProcessorAddress) {\n const ip =\n processor.addresses.find((address) => {\n return address.family === HostAddressFamily.IPv4;\n }) || processor.addresses[0];\n\n this.connection = new Connection(ip.address);\n }\n\n /**\n * Authenticate with the processor. This listens for when the pairing\n * button is pressed on the physical processor.\n *\n * @returns An authentication certificate.\n */\n public async authenticate(): Promise<Certificate> {\n return new Promise((resolve, reject) => {\n this.connection\n .connect()\n .then(() => {\n this.createCertificateRequest(\"mkellsy-mqtt-lutron\")\n .then((request) => {\n this.connection\n .authenticate(request)\n .then((certificate) => resolve(certificate))\n .catch((error) => reject(error));\n })\n .catch((error) => reject(error));\n })\n .catch((error) => reject(error));\n });\n }\n\n /*\n * Creates a certificate reqquest.\n */\n private createCertificateRequest(name: string): Promise<CertificateRequest> {\n return new Promise((resolve, reject) => {\n pki.rsa.generateKeyPair({ bits: 2048 }, (error, keys) => {\n if (error == null) {\n const request = pki.createCertificationRequest();\n\n request.publicKey = keys.publicKey;\n request.setSubject([{ name: \"commonName\", value: name }]);\n request.sign(keys.privateKey);\n\n return resolve({\n key: keys.privateKey,\n cert: pki.certificationRequestToPem(request),\n });\n }\n\n return reject(new Error(\"Error generating RSA keys\"));\n });\n });\n }\n}\n", "import fs from \"fs\";\nimport path from \"path\";\nimport net from \"net\";\n\nimport { BSON } from \"bson\";\nimport { get as getLogger } from \"js-logger\";\nimport { pki } from \"node-forge\";\nimport { v4 } from \"uuid\";\n\nimport { Authentication } from \"../Response/Authentication\";\nimport { Parser } from \"../Response/Parser\";\nimport { Certificate } from \"../Response/Certificate\";\nimport { CertificateRequest } from \"../Response/CertificateRequest\";\nimport { ExceptionDetail } from \"../Response/ExceptionDetail\";\nimport { InflightMessage } from \"../Response/InflightMessage\";\nimport { Message } from \"../Response/Message\";\nimport { PhysicalAccess } from \"../Response/PhysicalAccess\";\nimport { Response } from \"../Response/Response\";\nimport { RequestType } from \"../Response/RequestType\";\nimport { Socket } from \"./Socket\";\nimport { Subscription } from \"../Response/Subscription\";\n\nconst log = getLogger(\"Connection\");\n\nconst SOCKET_PORT = 8083;\nconst SECURE_SOCKET_PORT = 8081;\nconst REACHABLE_TIMEOUT = 1_000;\n\n/**\n * Connects to a device with the provided secure host.\n * @private\n */\nexport class Connection extends Parser<{\n Connect: (protocol: string) => void;\n Disconnect: () => void;\n Response: (response: Response) => void;\n Message: (response: Response) => void;\n Error: (error: Error) => void;\n}> {\n private socket?: Socket;\n private secure: boolean = false;\n private teardown: boolean = false;\n\n private host: string;\n private certificate: Certificate;\n\n private requests: Map<string, InflightMessage> = new Map();\n private subscriptions: Map<string, Subscription> = new Map();\n\n /**\n * Creates a new connection to a device.\n *\n * ```js\n * const connection = new Connection(\"192.168.1.1\", { ca, key, cert });\n * ```\n *\n * @param host The ip address of the device.\n * @param certificate Authentication certificate.\n */\n constructor(host: string, certificate?: Certificate) {\n super();\n\n this.host = host;\n this.secure = certificate != null;\n\n this.certificate = {\n ca: \"\",\n cert: \"\",\n key: \"\",\n ...(certificate != null ? certificate : this.authorityCertificate()),\n };\n }\n\n /**\n * Detects if a host is reachable.\n *\n * @param host Address of the device.\n *\n * @returns True if the device is rechable, false if not.\n */\n public static reachable(host: string): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = new net.Socket();\n\n const response = (success: boolean) => {\n socket.destroy();\n\n resolve(success);\n };\n\n socket.setTimeout(REACHABLE_TIMEOUT);\n\n socket.once(\"error\", () => response(false));\n socket.once(\"timeout\", () => response(false));\n\n socket.connect(SOCKET_PORT, host, () => response(true));\n });\n }\n\n /**\n * Asyncronously connects to a device.\n *\n * ```js\n * await connection.connect();\n * ```\n */\n public connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.teardown = false;\n this.socket = undefined;\n\n const port = this.secure ? SECURE_SOCKET_PORT : SOCKET_PORT;\n const subscriptions = [...this.subscriptions.values()];\n const socket = new Socket(this.host, port, this.certificate);\n\n log.info(`connect ${this.host}:${port} secure=${this.secure} pendingSubscriptions=${subscriptions.length}`);\n\n socket.on(\"Data\", this.onSocketData);\n socket.on(\"Error\", this.onSocketError);\n socket.on(\"Disconnect\", this.onSocketDisconnect);\n\n socket\n .connect()\n .then((protocol) => {\n log.info(\n `socket up ${this.host}:${port} protocol=${protocol}; physicalAccess secure=${this.secure}`,\n );\n\n this.physicalAccess(this.secure)\n .then(() => {\n const waits: Promise<void>[] = [];\n\n this.subscriptions.clear();\n this.socket = socket;\n\n if (this.secure) {\n for (const subscription of subscriptions) {\n /* istanbul ignore next */\n waits.push(this.subscribe(subscription.url, subscription.listener));\n }\n }\n\n Promise.all(waits)\n .then(() => {\n log.info(`emit Connect ${this.host} protocol=${protocol}`);\n this.emit(\"Connect\", protocol);\n\n resolve();\n })\n .catch((error) => {\n log.error(\n `resubscribe failed ${this.host}: ${error instanceof Error ? error.message : String(error)}`,\n );\n reject(error);\n });\n })\n .catch((error) => {\n log.error(\n `physicalAccess failed ${this.host}: ${error instanceof Error ? error.message : String(error)}`,\n );\n reject(error);\n });\n })\n .catch((error) => {\n log.error(\n `socket connect failed ${this.host}:${port}: ${error instanceof Error ? error.message : String(error)}`,\n );\n reject(error);\n });\n });\n }\n\n /**\n * Disconnects from a device.\n *\n * ```js\n * connection.disconnect();\n * ```\n */\n public disconnect() {\n this.teardown = true;\n\n if (this.secure) this.drainRequests();\n\n this.subscriptions.clear();\n this.socket?.disconnect();\n }\n\n /**\n * Fetches a record from the device. Not this only works for a secure\n * connections.\n *\n * ```js\n * const record = await connection.read<Zone>(\"/zone/123456\");\n * ```\n *\n * @param url The url of the record, this is typically a device address.\n *\n * @returns A payload or rejects. The payload is typed per call.\n */\n public read<T>(url: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const tag = v4();\n\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n this.sendRequest(tag, \"ReadRequest\", url)\n .then((response) => {\n const body = response.Body as T;\n const bodyType = response.Header?.MessageBodyType;\n\n if (body == null) {\n log.info(`read ${url} -> empty body status=${response.Header?.StatusCode || \"?\"}`);\n return reject(new Error(`${url} no body`));\n }\n\n // ExceptionDetail is unwrapped by Response.parse() to the Message string,\n // so instanceof ExceptionDetail only works for manually constructed bodies.\n if (bodyType === \"ExceptionDetail\" || response.Body instanceof ExceptionDetail) {\n const message =\n response.Body instanceof ExceptionDetail\n ? response.Body.Message\n : typeof response.Body === \"string\"\n ? response.Body\n : \"Unknown exception\";\n\n log.info(`read ${url} -> exception: ${message}`);\n return reject(new Error(message));\n }\n\n const kind = Array.isArray(body)\n ? `array(${(body as unknown[]).length})`\n : typeof body === \"object\"\n ? `object(${Object.keys(body as object)\n .slice(0, 12)\n .join(\",\")})`\n : typeof body;\n\n log.debug(`read ${url} -> ok ${kind}`);\n\n return resolve(response.Body as T);\n })\n .catch((error) => {\n log.info(`read ${url} -> fail: ${error instanceof Error ? error.message : String(error)}`);\n reject(error);\n });\n });\n }\n\n /**\n * This sends an authentication request. This only works for non-secure\n * connections.\n *\n * ```js\n * const certificate = await connection.authenticate(csr);\n * ```\n *\n * @param csr Sends a certificate request, typically created with open ssl.\n *\n * @returns An authentication certificate or rejects if failed.\n */\n public authenticate(csr: CertificateRequest): Promise<Certificate> {\n return new Promise((resolve, reject) => {\n if (this.secure) return reject(new Error(\"Only available for physical connections\"));\n\n const message = {\n Header: {\n RequestType: \"Execute\",\n Url: \"/pair\",\n ClientTag: \"get-cert\",\n },\n Body: {\n CommandType: \"CSR\",\n Parameters: {\n CSR: csr.cert,\n DisplayName: \"get_lutron_cert.py\",\n DeviceUID: \"000000000000\",\n Role: \"Admin\",\n },\n },\n };\n\n /*\n * Real clocks are required for proper socket testing, this\n * requires a fake clock or unit test timeout extention. Excluding\n * this to speedup build times.\n */\n\n /* istanbul ignore next */\n const timeout = setTimeout(() => reject(new Error(\"Authentication timeout exceeded\")), 5_000);\n\n this.once(\"Message\", (response: Response) => {\n clearTimeout(timeout);\n\n resolve({\n ca: (response.Body as Authentication).SigningResult.RootCertificate,\n cert: (response.Body as Authentication).SigningResult.Certificate,\n key: pki.privateKeyToPem(csr.key),\n });\n });\n\n /* istanbul ignore next */\n this.socket?.write(message);\n });\n }\n\n /**\n * Sends a commend to update a device. This only works for secure\n * connections.\n *\n * ```js\n * await connection.update(\"/zone/123456\", state);\n * ```\n *\n * @param url A command url typically the href of a device.\n * @param body An object of values to update.\n *\n * @returns Returns a status paylod. The type is set per call.\n */\n public update<T>(url: string, body: Record<string, unknown>): Promise<T> {\n return new Promise((resolve, reject) => {\n const tag = v4();\n\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n this.sendRequest(tag, \"UpdateRequest\", url, body)\n .then((response) => {\n if (response.Body instanceof ExceptionDetail) {\n return reject(new Error(response.Body.Message));\n }\n\n return resolve(response.Body as T);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Sends a known command to the device. This only works for secure\n * connections.\n *\n * ```js\n * await connection.command(\"/zone/123456\", command);\n * ```\n *\n * @param url A command url typically the href of a device.\n * @param command A known command object.\n */\n public command(url: string, command: Record<string, unknown>): Promise<void> {\n return new Promise((resolve, reject) => {\n const tag = v4();\n\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n this.sendRequest(tag, \"CreateRequest\", url, command)\n .then(() => resolve())\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Subscribes to a record on the device. This will bind a listener to that\n * record that will get called every time the record changes. This is\n * helpful for keeping track of the status of an area, zone, or device.\n * This only works for secure connections.\n *\n * ```js\n * connection.subscribe(\"/zone/123456/status\", (response) => { });\n * ```\n *\n * @param url Url to subscribe to.\n * @param listener Callback to run when the record updates.\n */\n public subscribe<T>(url: string, listener: (response: T) => void): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n const tag = v4();\n\n this.sendRequest(tag, \"SubscribeRequest\", url)\n .then((response: Response) => {\n if (response.Header.StatusCode != null && response.Header.StatusCode.isSuccessful()) {\n this.subscriptions.set(tag, {\n url,\n listener,\n callback: (response: Response) => listener(response.Body as T),\n });\n }\n\n resolve();\n })\n .catch((error) => reject(error));\n });\n }\n\n /*\n * Clears any ongoing commands. This will cancel all incomplete and failed\n * connections.\n */\n private drainRequests(): void {\n /*\n * Draining requests is incredibly difficult to test. This requires\n * very randon chunks that depend on network conditions. Testing this\n * functionallity is best suited for the buffered responce object.\n */\n\n /* istanbul ignore next */\n for (const tag of this.requests.keys()) {\n const request = this.requests.get(tag)!;\n\n clearTimeout(request.timeout);\n }\n\n this.requests.clear();\n }\n\n /*\n * Internally sends read, update, and command requests.\n */\n private sendRequest(\n tag: string,\n requestType: RequestType,\n url: string,\n body?: Record<string, unknown>,\n ): Promise<Response> {\n return new Promise((resolve, reject) => {\n /*\n * Testing tag reuse is difficult when mocking payloads. Tagged\n * payloads are transparent past this stage, and unit tests are\n * unable to pause the fulfillment.\n */\n\n /* istanbul ignore next */\n if (this.requests.has(tag)) {\n const request = this.requests.get(tag)!;\n\n request.reject(new Error(`tag \"${tag}\" reused`));\n\n clearTimeout(request.timeout);\n\n this.requests.delete(tag);\n }\n\n const message: Message = {\n CommuniqueType: requestType,\n Header: {\n ClientTag: tag!,\n Url: url,\n },\n Body: body,\n };\n\n /* istanbul ignore next */\n if (this.socket == null) return reject(new Error(\"Connection not established\"));\n\n this.socket\n .write(message)\n .then(() => {\n this.requests.set(tag!, {\n message,\n resolve,\n reject,\n timeout: setTimeout(\n /* istanbul ignore next */\n () => {\n // Reject on timeout \u2014 never resolve with a fake ExceptionDetail body.\n // Response.parse() unwraps { Message: \"...\" } to a bare string, which\n // used to be treated as a successful read and permanently cached.\n this.requests.delete(tag!);\n reject(new Error(\"Request timeout\"));\n },\n 15_000,\n ),\n });\n })\n .catch((error) => reject(error));\n });\n }\n\n /*\n * Listener for taged responses from the device.\n */\n private onResponse = (response: Response): void => {\n const tag = response.Header.ClientTag;\n\n if (tag == null) {\n this.emit(\"Message\", response);\n\n return;\n }\n\n const request = this.requests.get(tag)!;\n\n if (request != null) {\n clearTimeout(request.timeout);\n\n this.requests.delete(tag);\n request.resolve(response);\n }\n\n const subscription = this.subscriptions.get(tag);\n\n if (subscription == null) return;\n\n subscription.callback(response);\n };\n\n /*\n * Handles all data recieved from a device.\n */\n private onSocketData = (data: Buffer): void => {\n if (this.secure) {\n this.parse(data, this.onResponse);\n } else {\n this.emit(\"Message\", JSON.parse(data.toString()));\n }\n };\n\n /*\n * Listener for any socket disconnects. This will teardown the failed\n * connection and will attempt to reconnect, unless a discrete disconnect\n * is invoked.\n */\n private onSocketDisconnect = (): void => {\n if (!this.teardown) this.emit(\"Disconnect\");\n };\n\n /*\n * Listener for any error from the socket.\n */\n private onSocketError = (error: Error): void => {\n this.emit(\"Error\", error);\n };\n\n /*\n * Loads a saved device certificate. Certificates are created when a\n * processor is paired with this device.\n */\n private authorityCertificate(): Certificate | null {\n const filename = path.resolve(__dirname, \"../authority\");\n\n if (fs.existsSync(filename)) {\n const bytes = fs.readFileSync(filename);\n\n if (bytes == null) return null;\n\n const certificate = BSON.deserialize(bytes) as Certificate;\n\n certificate.ca = Buffer.from(certificate.ca, \"base64\").toString(\"utf8\");\n certificate.key = Buffer.from(certificate.key, \"base64\").toString(\"utf8\");\n certificate.cert = Buffer.from(certificate.cert, \"base64\").toString(\"utf8\");\n\n return certificate;\n }\n\n return null;\n }\n\n /*\n * For non-secure connections, this will wait for a processor to enter\n * pairing mode. This requires a button press on the physical processor.\n */\n private physicalAccess(secure: boolean): Promise<void> {\n return new Promise((resolve, reject) => {\n if (secure) return resolve();\n\n /*\n * Testing processor errors and physical button press timeout is\n * not feasible for unit tests. This functionallity is best tested\n * manually with access to the processor.\n */\n\n /* istanbul ignore next */\n const timeout = setTimeout(() => reject(new Error(\"Physical timeout exceeded\")), 60_000);\n\n this.once(\"Message\", (response: Response) => {\n /* istanbul ignore else */\n if ((response.Body as PhysicalAccess).Status.Permissions.includes(\"PhysicalAccess\")) {\n clearTimeout(timeout);\n\n return resolve();\n }\n\n /* istanbul ignore next */\n return reject(new Error(\"Unknown pairing error\"));\n });\n });\n }\n}\n", "import { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { Response } from \"./Response\";\n\n/**\n * Enables response buffering.\n * @private\n */\nexport class Parser<MAP extends { [key: string]: (...args: any[]) => void }> extends EventEmitter<MAP> {\n private buffer: string = \"\";\n\n /**\n * Parses a raw response, and returns via a callback.\n *\n * @param data Raw socket buffer.\n * @param callback Listener for complete response.\n */\n public parse(data: Buffer, callback: (response: Response) => void): void {\n const response = this.buffer + data.toString();\n const lines: string[] = response.split(/\\r?\\n/);\n\n if (lines.length - 1 === 0) {\n this.buffer = response;\n\n return;\n }\n\n this.buffer = lines[lines.length - 1] || \"\";\n\n for (const line of lines.slice(0, lines.length - 1)) {\n callback(Response.parse(line));\n }\n }\n}\n", "import { MessageType } from \"./MessageType\";\nimport { ResponseStatus } from \"./ResponseStatus\";\n\n/**\n * Creates a response header object.\n * @private\n */\nexport class ResponseHeader {\n public StatusCode?: ResponseStatus;\n public Url?: string;\n public MessageBodyType?: MessageType;\n public ClientTag?: string;\n}\n", "/**\n * Creates a response status object.\n * @private\n */\nexport class ResponseStatus {\n /**\n * Status message\n */\n public message?: string;\n\n /**\n * Status code\n */\n public code?: number;\n\n /**\n * Creates a response status object.\n *\n * @param message Complete response.\n * @param code Response code from the message.\n */\n constructor(message?: string, code?: number) {\n this.message = message;\n this.code = code;\n }\n\n /**\n * Creates a response status object from a string.\n *\n * @param value Status string.\n *\n * @returns A response status object.\n */\n static fromString(value?: string): ResponseStatus {\n const parts = value?.split(\" \", 2);\n\n if (parts == null || parts.length === 1) {\n return new ResponseStatus(value);\n }\n\n const code = parseInt(parts[0], 10);\n\n if (Number.isNaN(code)) {\n return new ResponseStatus(value);\n }\n\n return new ResponseStatus(parts[1], code);\n }\n\n /**\n * Is the status successful.\n *\n * @returns True if successful, false if not.\n */\n public isSuccessful(): boolean {\n return this.code !== undefined && this.code >= 200 && this.code < 300;\n }\n}\n", "import * as Body from \"./BodyType\";\n\nimport { RequestType } from \"./RequestType\";\nimport { MessageType } from \"./MessageType\";\nimport { ResponseHeader } from \"./ResponseHeader\";\nimport { ResponseStatus } from \"./ResponseStatus\";\n\n/**\n * Defines a processor response.\n * @private\n */\nexport class Response {\n public CommuniqueType?: RequestType;\n public Body?: Body.BodyType;\n public Header: ResponseHeader;\n\n /**\n * Creates a new response object.\n */\n constructor() {\n this.Header = new ResponseHeader();\n }\n\n /**\n * Parses complete responses to a response object.\n *\n * @param value The assembled response.\n *\n * @returns Returns a response object.\n */\n static parse(value: string): Response {\n const payload = JSON.parse(value);\n\n const status =\n payload.Header.StatusCode == null ? undefined : ResponseStatus.fromString(payload.Header.StatusCode);\n\n const header: ResponseHeader = Object.assign({}, payload.Header, {\n StatusCode: status,\n MessageBodyType: payload.Header.MessageBodyType as MessageType,\n });\n\n if (header.MessageBodyType == null) {\n return Object.assign(new Response(), { Header: header });\n }\n\n const key = Object.keys(payload.Body || {})[0];\n const body = key != null ? payload.Body[key] || undefined : undefined;\n\n return Object.assign(new Response(), payload, { Header: header, Body: body });\n }\n}\n", "/**\n * Exception response.\n * @private\n */\nexport class ExceptionDetail {\n /**\n * Responce message.\n */\n Message = \"\";\n}\n", "import { EventEmitter } from \"@mkellsy/event-emitter\";\nimport { get as getLogger } from \"js-logger\";\nimport { connect, createSecureContext, TLSSocket } from \"tls\";\n\nimport { Certificate } from \"../Response/Certificate\";\nimport { Message } from \"../Response/Message\";\n\nconst log = getLogger(\"Socket\");\n\nconst KEEPALIVE_INITIAL_DELAY = 10_000;\nconst INACTIVITY_TIMEOUT = 30_000;\n\n/**\n * Creates a connections underlying socket.\n * @private\n */\nexport class Socket extends EventEmitter<{\n Error: (error: Error) => void;\n Data: (data: Buffer) => void;\n Disconnect: () => void;\n}> {\n private connection?: TLSSocket;\n\n private readonly host: string;\n private readonly port: number;\n private readonly certificate: Certificate;\n\n /**\n * Creates a socket.\n *\n * @param host The IP address of the device.\n * @param port The port the device listenes on.\n * @param certificate An authentication certificate.\n */\n constructor(host: string, port: number, certificate: Certificate) {\n super();\n\n this.host = host;\n this.port = port;\n this.certificate = certificate;\n }\n\n /**\n * Establishes a connection to the device.\n *\n * @returns A connection protocol.\n */\n public connect(): Promise<string> {\n return new Promise((resolve, reject) => {\n log.info(`TLS connect ${this.host}:${this.port}`);\n\n const connection = connect(this.port, this.host, {\n secureContext: createSecureContext(this.certificate),\n secureProtocol: \"TLS_method\",\n rejectUnauthorized: false,\n });\n\n connection.once(\"secureConnect\", (): void => {\n this.connection = connection;\n\n this.connection.off(\"error\", reject);\n\n this.connection.on(\"timeout\", this.onSocketTimeout);\n this.connection.on(\"error\", this.onSocketError);\n this.connection.on(\"close\", this.onSocketClose);\n this.connection.on(\"data\", this.onSocketData);\n\n this.connection.setKeepAlive(true, KEEPALIVE_INITIAL_DELAY);\n this.connection.setTimeout(INACTIVITY_TIMEOUT);\n\n const protocol = this.connection.getProtocol() || \"Unknown\";\n\n log.info(`TLS secureConnect ${this.host}:${this.port} protocol=${protocol}`);\n resolve(protocol);\n });\n\n connection.once(\"error\", (error) => {\n log.error(`TLS connect error ${this.host}:${this.port}: ${error.message}`);\n reject(error);\n });\n });\n }\n\n /**\n * Disconnects from a device.\n */\n public disconnect(): void {\n this.connection?.end();\n this.connection?.destroy();\n }\n\n /**\n * Writes a message to the connection.\n *\n * @param message A message to write.\n */\n public write(message: Message): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.connection == null) return reject(new Error(\"connection not established\"));\n\n this.connection.write(`${JSON.stringify(message)}\\n`, (error) => {\n if (error != null) return reject(error);\n\n return resolve();\n });\n });\n }\n\n /*\n * Listens for data from the socket.\n */\n private onSocketData = (data: Buffer): void => {\n this.emit(\"Data\", data);\n };\n\n /*\n * Listens for socket timeouts.\n */\n private onSocketTimeout = (): void => {\n log.warn(`TLS inactivity timeout ${this.host}:${this.port} (${INACTIVITY_TIMEOUT}ms)`);\n this.emit(\"Error\", new Error(\"connect ETIMEDOUT\"));\n };\n\n /*\n * Listenes for discrete disconects from the socket.\n */\n private onSocketClose = (): void => {\n log.info(`TLS close ${this.host}:${this.port}`);\n this.emit(\"Disconnect\");\n };\n\n /*\n * Listenes for any errors from the socket. This will filter out any socket\n */\n private onSocketError = (error: Error): void => {\n log.error(`TLS error ${this.host}:${this.port}: ${error.message}`);\n this.emit(\"Error\", error);\n };\n}\n", "import fs from \"fs\";\nimport path from \"path\";\nimport os from \"os\";\n\nimport { BSON } from \"bson\";\nimport { get as getLogger } from \"js-logger\";\n\nimport { Certificate } from \"../Response/Certificate\";\nimport { ProcessorAddress } from \"../Response/ProcessorAddress\";\n\nconst log = getLogger(\"Context\");\n\n/**\n * Defines an authentication context and state for a processor.\n * @private\n */\nexport class Context {\n private context: Record<string, Certificate> = {};\n\n /**\n * Create an authentication context, and load any cached certificates. This\n * ensures that processors can be paired with device, and authentication\n * only happens once.\n */\n constructor() {\n try {\n const context = this.open<Record<string, Certificate>>(\"pairing\") || {};\n const keys = Object.keys(context);\n\n for (let i = 0; i < keys.length; i++) {\n context[keys[i]] = this.decrypt(context[keys[i]])!;\n }\n\n this.context = context;\n\n const processors = this.processors;\n\n log.info(`pairing loaded: ${processors.length} processor(s) [${processors.join(\", \") || \"none\"}]`);\n } catch (error) {\n log.error(\n `failed to load pairing from ~/.leap/pairing: ${error instanceof Error ? error.message : String(error)}`,\n );\n this.context = {};\n }\n }\n\n /**\n * A list of processor ids currently paired.\n *\n * @returns A string array of processor ids.\n */\n public get processors(): string[] {\n return Object.keys(this.context).filter((key) => key !== \"authority\");\n }\n\n /**\n * Check to see if the context has a processor paired.\n *\n * @param id The processor id to check.\n *\n * @returns True if paired, false if not.\n */\n public has(id: string): boolean {\n return this.context[id] != null;\n }\n\n /**\n * Fetches the authentication certificate for a processor.\n *\n * @param id The processor id to fetch.\n *\n * @returns An authentication certificate or undefined if it doesn't exist.\n */\n public get(id: string): Certificate | undefined {\n return this.context[id];\n }\n\n /**\n * Adds a processor authentication certificate to the context.\n *\n * @param processor The processor address object to add.\n * @param context The authentication certificate to associate.\n */\n public set(processor: ProcessorAddress, context: Certificate): void {\n this.context[processor.id] = { ...context };\n this.save(\"pairing\", this.context);\n }\n\n /*\n * Decrypts an authentication certificate.\n */\n private decrypt(context: Certificate | null): Certificate | null {\n if (context == null) return null;\n\n context.ca = Buffer.from(context.ca, \"base64\").toString(\"utf8\");\n context.key = Buffer.from(context.key, \"base64\").toString(\"utf8\");\n context.cert = Buffer.from(context.cert, \"base64\").toString(\"utf8\");\n\n return context;\n }\n\n /*\n * Encrypts a certificate for storage. This ensures security at rest.\n */\n private encrypt(context: Certificate | null): Certificate | null {\n if (context == null) return null;\n\n context.ca = Buffer.from(context.ca).toString(\"base64\");\n context.key = Buffer.from(context.key).toString(\"base64\");\n context.cert = Buffer.from(context.cert).toString(\"base64\");\n\n return context;\n }\n\n /*\n * Opens the context storage and loads paired processors.\n */\n private open<T>(filename: string): T | null {\n const directory = path.join(os.homedir(), \".leap\");\n const filePath = path.join(directory, filename);\n\n if (!fs.existsSync(directory)) fs.mkdirSync(directory);\n\n if (fs.existsSync(filePath)) {\n const bytes = fs.readFileSync(filePath);\n const size = bytes != null && typeof (bytes as Buffer).length === \"number\" ? (bytes as Buffer).length : 0;\n\n log.info(`opened ${filePath} (${size} bytes)`);\n\n return BSON.deserialize(bytes) as T;\n }\n\n log.warn(`missing pairing file: ${filePath}`);\n\n return null;\n }\n\n /*\n * Saves the context to storage.\n */\n private save(filename: string, context: Record<string, Certificate>): void {\n const directory = path.join(os.homedir(), \".leap\");\n\n if (!fs.existsSync(directory)) fs.mkdirSync(directory);\n\n const clear = { ...context };\n const keys = Object.keys(clear);\n\n for (let i = 0; i < keys.length; i++) {\n clear[keys[i]] = this.encrypt(clear[keys[i]])!;\n }\n\n fs.writeFileSync(path.join(directory, filename), BSON.serialize(clear));\n }\n}\n", "import os from \"os\";\nimport path from \"path\";\nimport equals from \"deep-equal\";\n\nimport Cache from \"flat-cache\";\nimport { get as getLogger } from \"js-logger\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\nimport { MDNSService, MDNSServiceDiscovery, Protocol } from \"tinkerhub-mdns\";\nimport { HostAddress, HostAddressFamily } from \"@mkellsy/hap-device\";\n\nimport { ProcessorAddress } from \"../Response/ProcessorAddress\";\n\nconst log = getLogger(\"Discovery\");\n\n/**\n * Creates and searches the network for devices.\n * @private\n */\nexport class Discovery extends EventEmitter<{\n Discovered: (processor: ProcessorAddress) => void;\n Failed: (error: Error) => void;\n}> {\n private cache: Cache.Cache;\n private cached: ProcessorAddress[];\n private discovery?: MDNSServiceDiscovery;\n\n /**\n * Creates a mDNS discovery object used to search the network for devices.\n *\n * ```js\n * const discovery = new Discovery();\n *\n * discovery.on(\"Discovered\", (device: ProcessorAddress) => { });\n * discovery.search()\n * ```\n */\n constructor() {\n super();\n\n this.cache = Cache.load(\"discovery\", path.join(os.homedir(), \".leap\"));\n this.cached = this.cache.getKey(\"/hosts\") || [];\n\n this.cache.setKey(\"/hosts\", this.cached);\n this.cache.save(true);\n }\n\n /**\n * Starts searching the network for devices.\n */\n public search(): void {\n this.stop();\n\n log.info(`search start: ${this.cached.length} cached host(s)`);\n\n for (let i = 0; i < this.cached.length; i++) {\n const host = this.cached[i];\n const addrs = (host.addresses || []).map((a) => a.address).join(\",\");\n\n log.info(`emit cached host id=${host.id} type=${host.type} addresses=[${addrs}]`);\n this.emit(\"Discovered\", host);\n }\n\n this.discovery = new MDNSServiceDiscovery({ type: \"lutron\", protocol: Protocol.TCP });\n this.discovery.onAvailable(this.onAvailable);\n log.info(\"mDNS browse started for _lutron._tcp\");\n }\n\n /**\n * Stops searching the network.\n */\n public stop(): void {\n this.discovery?.destroy();\n }\n\n /*\n * Parses a service once discovered. If it fits the criteria, this will\n * emit a discovered event.\n */\n private onAvailable = (service: MDNSService): void => {\n const systype = service.data.get(\"systype\");\n\n if (!this.isProcessorService(service)) {\n log.debug(`mDNS ignore service id=${service.id} systype=${String(systype)}`);\n return;\n }\n\n let host: ProcessorAddress;\n\n try {\n host = this.parseProcessorAddress(service);\n } catch (error) {\n log.error(\n `mDNS parse failed for service id=${service.id}: ${error instanceof Error ? error.message : String(error)}`,\n );\n return;\n }\n\n const addrs = (host.addresses || []).map((a) => a.address).join(\",\");\n const cached = this.isProcessorCached(host);\n\n log.info(`mDNS processor id=${host.id} type=${host.type} addresses=[${addrs}] cached=${cached}`);\n\n if (!cached) this.emit(\"Discovered\", host);\n\n this.cacheProcessor(host);\n };\n\n /*\n * Determines if a processor host is currently cached.\n */\n private isProcessorCached(host: ProcessorAddress): boolean {\n return this.cached.find((entry) => equals(entry, host)) != null;\n }\n\n /*\n * Determines if a MDNS service is a processor.\n */\n private isProcessorService(service: MDNSService): boolean {\n const type = service.data.get(\"systype\");\n\n if (type == null || typeof type === \"boolean\") return false;\n\n return true;\n }\n\n /*\n * Saves a processor host to disk cache.\n */\n private cacheProcessor(host: ProcessorAddress): void {\n const index = this.cached.findIndex((entry) => entry.id === host.id);\n\n if (index >= 0) {\n this.cached[index] = host;\n } else {\n this.cached.push(host);\n }\n\n this.cache.setKey(\"/hosts\", this.cached);\n this.cache.save();\n }\n\n /*\n * Transforms a MDNS service to a processor host.\n */\n private parseProcessorAddress(service: MDNSService): ProcessorAddress {\n const target = (this.discovery as any).serviceData.get(service.id).SRV._record.target;\n const addresses: HostAddress[] = [];\n\n for (let i = 0; i < service.addresses?.length; i++) {\n addresses.push({\n address: service.addresses[i].host,\n family: /^([\\da-f]{1,4}:){7}[\\da-f]{1,4}$/i.test(service.addresses[i].host)\n ? HostAddressFamily.IPv6\n : HostAddressFamily.IPv4,\n });\n }\n\n return {\n id: target.match(/[Ll]utron-(?<id>\\w+)\\.local/)!.groups!.id.toUpperCase(),\n type: String(service.data.get(\"systype\")),\n addresses,\n };\n }\n}\n", "import { get as getLogger } from \"js-logger\";\n\nimport Colors from \"colors\";\n\nimport {\n Action,\n Address,\n AreaStatus,\n Button,\n Device,\n DeviceType,\n DeviceState,\n HostAddressFamily,\n TimeclockStatus,\n ZoneStatus,\n} from \"@mkellsy/hap-device\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { AreaAddress } from \"./Response/AreaAddress\";\nimport { Connection } from \"./Connection/Connection\";\nimport { Context } from \"./Connection/Context\";\nimport { ControlStation } from \"./Response/ControlStation\";\nimport { DeviceAddress } from \"./Response/DeviceAddress\";\nimport { Discovery } from \"./Connection/Discovery\";\nimport { Processor } from \"./Devices/Processor/Processor\";\nimport { ProcessorController } from \"./Devices/Processor/ProcessorController\";\nimport { ProcessorAddress } from \"./Response/ProcessorAddress\";\n\nimport { createDevice, isAddressable, parseDeviceType } from \"./Devices/Devices\";\nimport { probeProcessorMetadata } from \"./Connection/MetadataProbe\";\n\nconst log = getLogger(\"Client\");\n\nconst RETRY_BACKOFF_DURATION = 5_000;\n\n/**\n * Creates an object that represents a single location, with a single network.\n * @public\n */\nexport class Client extends EventEmitter<{\n Action: (device: Device, button: Button, action: Action) => void;\n Available: (devices: Device[]) => void;\n Message: (response: Response) => void;\n Update: (device: Device, state: DeviceState) => void;\n}> {\n private context: Context;\n private refresh: boolean;\n\n private discovery: Discovery;\n private discovered: Map<string, Processor> = new Map();\n private areaPaths: Map<string, string> = new Map();\n\n /**\n * Creates a location object and starts mDNS discovery.\n *\n * ```js\n * const location = new Client();\n *\n * location.on(\"Avaliable\", (devices: Device[]) => { });\n * ```\n *\n * @param refresh If true, this will ignore any cache and reload.\n */\n constructor(refresh?: boolean) {\n super(Infinity);\n\n this.context = new Context();\n this.discovery = new Discovery();\n this.refresh = refresh === true;\n\n const paired = this.context?.processors ?? [];\n\n log.info(`Client start refresh=${this.refresh} paired=[${paired.join(\", \") || \"none\"}]`);\n\n this.discovery.on(\"Discovered\", this.onDiscovered).search();\n }\n\n /**\n * A list of processors in this location.\n *\n * @returns A string array of processor ids.\n */\n public get processors(): string[] {\n return [...this.discovered.keys()];\n }\n\n /**\n * Fetch a processor from this location.\n *\n * @param id The processor id to fetch.\n *\n * @returns A processor object or undefined if it doesn't exist.\n */\n public processor(id: string): Processor | undefined {\n return this.discovered.get(id);\n }\n\n /**\n * Closes all connections for a location and stops searching.\n */\n public close(): void {\n this.discovery.stop();\n\n for (const processor of this.discovered.values()) {\n processor.disconnect();\n }\n\n this.discovered.clear();\n }\n\n /*\n * Builds \"House / Floor / Room\" paths for every area href.\n */\n private rebuildAreaPaths(areas: AreaAddress[]): void {\n const byHref = new Map(areas.map((area) => [area.href, area]));\n this.areaPaths.clear();\n\n for (const area of areas) {\n const names: string[] = [];\n let current: string | undefined = area.href;\n const seen = new Set<string>();\n\n while (current != null && !seen.has(current)) {\n seen.add(current);\n const node = byHref.get(current);\n\n if (node == null) break;\n\n names.unshift(node.Name);\n current = node.Parent?.href;\n }\n\n this.areaPaths.set(area.href, names.join(\" / \") || area.Name);\n }\n }\n\n /*\n * Annotates an area with its full hierarchy path for device constructors.\n */\n private withAreaPath(area: AreaAddress): AreaAddress & { Path: string } {\n return {\n ...area,\n Path: this.areaPaths.get(area.href) || area.Name,\n };\n }\n\n /*\n * Discovers all available zones on this processor. In other systems this\n * is the device.\n */\n private discoverZones(processor: Processor, area: AreaAddress): Promise<void> {\n return new Promise((resolve) => {\n if (!area.IsLeaf) return resolve();\n\n const areaWithPath = this.withAreaPath(area);\n\n processor\n .zones(area)\n .then((zones) => {\n for (const zone of zones) {\n const device = createDevice(processor, areaWithPath, zone)\n .on(\"Update\", this.onDeviceUpdate)\n .on(\"Action\", this.onDeviceAction);\n\n processor.devices.set(zone.href, device);\n }\n\n resolve();\n })\n .catch(() => resolve());\n });\n }\n\n /*\n * Discovers all available timeclocks. Timeclocks are schedules, and\n * sometimes are used as vurtual switches.\n */\n private discoverTimeclocks(processor: Processor): Promise<void> {\n return new Promise((resolve) => {\n processor\n .timeclocks()\n .then((timeclocks) => {\n for (const timeclock of timeclocks) {\n const device = createDevice(\n processor,\n {\n href: timeclock.href,\n Name: timeclock.Name,\n ControlType: \"Timeclock\",\n Parent: timeclock.Parent,\n IsLeaf: true,\n AssociatedZones: [],\n AssociatedControlStations: [],\n AssociatedOccupancyGroups: [],\n Path: timeclock.Name,\n } as AreaAddress & { Path: string },\n { ...timeclock, ControlType: \"Timeclock\" },\n ).on(\"Update\", this.onDeviceUpdate);\n\n processor.devices.set(timeclock.href, device);\n }\n\n resolve();\n })\n .catch(() => resolve());\n });\n }\n\n /*\n * Discovers all keypads and remotes. These are ganged devices.\n */\n private discoverControls(processor: Processor, area: AreaAddress): Promise<void> {\n return new Promise((resolve) => {\n if (!area.IsLeaf) return resolve();\n\n const areaWithPath = this.withAreaPath(area);\n\n processor\n .controls(area)\n .then(async (controls) => {\n if (controls == null || controls.length === 0) {\n return resolve();\n }\n\n // Wait for every control station \u2014 previously resolved after the first,\n // which dropped later Picos in multi-station rooms.\n await Promise.all(\n controls.map(async (control) => {\n const positions = await this.discoverPositions(processor, control);\n\n for (const position of positions) {\n const type = parseDeviceType(position.DeviceType);\n\n const address =\n type === DeviceType.Occupancy\n ? `/occupancy/${area.href?.split(\"/\")[2]}`\n : position.href;\n\n const device = createDevice(processor, areaWithPath, {\n ...position,\n Name: `${area.Name} ${control.Name} ${position.Name}`,\n })\n .on(\"Update\", this.onDeviceUpdate)\n .on(\"Action\", this.onDeviceAction);\n\n processor.devices.set(address, device);\n }\n }),\n );\n\n resolve();\n })\n .catch(() => resolve());\n });\n }\n\n /*\n * Discovers individual positions in a control station. Represents a single\n * keypad or remote in a gang.\n */\n private discoverPositions(processor: Processor, control: ControlStation): Promise<DeviceAddress[]> {\n return new Promise((resolve) => {\n if (control.AssociatedGangedDevices == null) return resolve([]);\n\n const waits: Promise<DeviceAddress>[] = [];\n\n for (const gangedDevice of control.AssociatedGangedDevices) {\n waits.push(processor.device(gangedDevice.Device));\n }\n\n // allSettled so one timed-out device does not drop the whole gang.\n Promise.allSettled(waits)\n .then((results) => {\n const positions: DeviceAddress[] = [];\n\n for (const result of results) {\n if (result.status === \"rejected\") {\n log.warn(\n `control station ${control.Name || control.href}: device fetch failed: ${\n result.reason instanceof Error ? result.reason.message : String(result.reason)\n }`,\n );\n continue;\n }\n\n if (isAddressable(result.value)) {\n positions.push(result.value);\n } else {\n const value = result.value as DeviceAddress | null;\n log.info(\n `skipping non-addressable ${control.Name || \"?\"} ` +\n `type=${value?.DeviceType || typeof value} ` +\n `state=${value?.AddressedState || \"?\"} href=${value?.href || \"?\"}`,\n );\n }\n }\n\n resolve(positions);\n })\n .catch(() => resolve([]));\n });\n }\n\n /*\n * Creates a connection when mDNS finds a processor.\n */\n private onDiscovered = (host: ProcessorAddress): void => {\n this.discovered.delete(host.id);\n\n const addrs = (host.addresses || []).map((a) => `${a.family}:${a.address}`).join(\", \");\n\n log.info(`Discovered host id=${host.id} type=${host.type} addresses=[${addrs}]`);\n\n if (!this.context.has(host.id)) {\n log.warn(\n `skipping host id=${host.id}: not in pairing (paired=[${this.context.processors.join(\", \") || \"none\"}])`,\n );\n return;\n }\n\n const ip = host.addresses.find((address) => address.family === HostAddressFamily.IPv4) || host.addresses[0];\n\n if (ip == null) {\n log.error(`host id=${host.id} has no addresses`);\n return;\n }\n\n log.info(`connecting to processor id=${host.id} at ${ip.address}`);\n\n const processor = new ProcessorController(host.id, new Connection(ip.address, this.context.get(host.id)));\n\n this.discovered.set(host.id, processor);\n\n processor.log.info(`Processor ${Colors.green(ip.address)}`);\n\n processor\n .on(\"Disconnect\", () => {\n log.warn(`processor ${host.id} disconnected; retry in ${RETRY_BACKOFF_DURATION}ms`);\n setTimeout(() => this.onDiscovered(host), RETRY_BACKOFF_DURATION);\n })\n .on(\"Connect\", () => {\n log.info(`processor ${host.id} Connect event \u2014 loading system/project/areas (refresh=${this.refresh})`);\n\n if (this.refresh) processor.clear();\n\n // RESET RETRIES\n\n Promise.all([processor.system(), processor.project(), processor.areas()])\n .then(([system, project, areas]) => {\n const version = system?.FirmwareImage.Firmware.DisplayName;\n const type = system?.DeviceType;\n const waits: Promise<void>[] = [];\n\n this.rebuildAreaPaths(areas);\n\n log.info(\n `processor ${host.id} system loaded firmware=${version || \"Unknown\"} type=${type} areas=${areas?.length ?? 0}`,\n );\n\n processor.log.info(`Firmware ${Colors.green(version || \"Unknown\")}`);\n processor.log.info(project.ProductType);\n\n processor\n .subscribe<ZoneStatus[]>({ href: \"/zone/status\" }, (statuses: ZoneStatus[]): void => {\n for (const status of statuses) {\n const device = processor.devices.get(status.Zone.href);\n\n if (device != null) device.update(status);\n }\n })\n .then(() => log.info(`processor ${host.id} subscribed /zone/status`))\n .catch((error) => this.onProcessorError(host, error));\n\n processor\n .subscribe<AreaStatus[]>({ href: \"/area/status\" }, (statuses: AreaStatus[]): void => {\n for (const status of statuses) {\n const occupancy = processor.devices.get(`/occupancy/${status.href?.split(\"/\")[2]}`);\n\n if (occupancy != null && status.OccupancyStatus != null) occupancy.update(status);\n }\n })\n .then(() => log.info(`processor ${host.id} subscribed /area/status`))\n .catch((error) => this.onProcessorError(host, error));\n\n if (type === \"RadioRa3Processor\") {\n processor\n .subscribe<TimeclockStatus[]>(\n { href: \"/timeclock/status\" },\n (statuses: TimeclockStatus[]): void => {\n for (const status of statuses) {\n const device = processor.devices.get(\n (status as TimeclockStatus & { Timeclock: Address }).Timeclock.href,\n );\n\n if (device != null) device.update(status);\n }\n },\n )\n .then(() => log.info(`processor ${host.id} subscribed /timeclock/status`))\n .catch((error) => this.onProcessorError(host, error));\n }\n\n for (const area of areas) {\n waits.push(\n new Promise((resolve) => {\n this.discoverZones(processor, area).then(() => resolve());\n }),\n );\n\n waits.push(\n new Promise((resolve) => {\n this.discoverControls(processor, area).then(() => resolve());\n }),\n );\n }\n\n if (type === \"RadioRa3Processor\") {\n waits.push(\n new Promise((resolve) => {\n this.discoverTimeclocks(processor).then(() => resolve());\n }),\n );\n }\n\n log.info(`processor ${host.id} discovering devices (${waits.length} wait tasks)`);\n\n Promise.all(waits).then(async () => {\n const devices = [...processor.devices.values()];\n\n // Remotes/keypads load buttons asynchronously; wait so HomeKit\n // accessories are built with StatelessProgrammableSwitch services.\n await Promise.all(\n devices.map(async (device) => {\n const ready = (device as Device & { ready?: Promise<void> }).ready;\n\n if (ready != null) {\n try {\n await ready;\n } catch (error) {\n log.warn(\n `device ${device.name} button init failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n }\n }),\n );\n\n const count = devices.length;\n\n log.info(`processor ${host.id} discovery complete: ${count} devices; loading statuses`);\n\n processor\n .statuses(type)\n .then((statuses) => {\n for (const status of statuses) {\n const zone = processor.devices.get(\n ((status as ZoneStatus).Zone || {}).href || \"\",\n );\n\n const occupancy = processor.devices.get(\n `/occupancy/${(status.href || \"\").split(\"/\")[2]}`,\n );\n\n if (zone != null) zone.update(status as ZoneStatus);\n\n if (occupancy != null && (status as AreaStatus).OccupancyStatus != null) {\n occupancy.update(status as AreaStatus);\n }\n }\n\n log.info(`processor ${host.id} applied ${statuses.length} status record(s)`);\n })\n .catch((error) => {\n log.error(\n `processor ${host.id} statuses failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n });\n\n processor.log.info(`discovered ${Colors.green(count.toString())} devices`);\n\n // One-shot protocol inventory: area/group hierarchy + extra LEAP URLs.\n probeProcessorMetadata(processor, areas).catch((error) => {\n log.error(\n `metadata probe failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n });\n\n log.info(`processor ${host.id} emitting Available with ${count} devices`);\n this.emit(\"Available\", devices);\n });\n })\n .catch((error) => this.onProcessorError(host, error));\n })\n .on(\"Error\", (error: Error) => this.onProcessorError(host, error));\n\n processor.connect().catch((error) => this.onProcessorError(host, error));\n };\n\n /*\n * When a device updates, this will emit an update event.\n */\n private onDeviceUpdate = (device: Device, state: DeviceState): void => {\n this.emit(\"Update\", device, state);\n };\n\n /*\n * When a control station emits an action, this will emit an action event.\n * This is when a button is pressed on a keypad or remote.\n */\n private onDeviceAction = (device: Device, button: Button, action: Action): void => {\n this.emit(\"Action\", device, button, action);\n };\n\n private onProcessorError = (host: ProcessorAddress, error: Error): void => {\n const message = error?.message != null ? error.message : String(error);\n\n if (message.match(/ENOTFOUND|ENETUNREACH|EHOSTUNREACH|ECONNRESET|EPIPE|ECONNREFUSED|ETIMEDOUT/g) != null) {\n log.warn(`processor ${host.id} network error: ${message}; retry in ${RETRY_BACKOFF_DURATION}ms`);\n setTimeout(() => this.onDiscovered(host), RETRY_BACKOFF_DURATION);\n\n return;\n }\n\n log.error(Colors.red(`processor ${host.id} error: ${message}`));\n };\n}\n", "import { ILogger, get as getLogger } from \"js-logger\";\n\nimport { Device } from \"@mkellsy/hap-device\";\n\nimport Cache from \"flat-cache\";\nimport Colors from \"colors\";\n\nimport os from \"os\";\nimport path from \"path\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { Address } from \"../../Response/Address\";\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { AreaStatus } from \"../../Response/AreaStatus\";\nimport { ButtonGroupExpanded } from \"../../Response/ButtonGroupExpanded\";\nimport { Connection } from \"../../Connection/Connection\";\nimport { ControlStation } from \"../../Response/ControlStation\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { PingResponse } from \"../../Response/PingResponse\";\nimport { Processor } from \"./Processor\";\nimport { Project } from \"../../Response/Project\";\nimport { Response } from \"../../Response/Response\";\nimport { TimeclockAddress } from \"../../Response/TimeclockAddress\";\nimport { TimeclockStatus } from \"../../Response/TimeclockStatus\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\nimport { ZoneStatus } from \"../../Response/ZoneStatus\";\n\nconst HEARTBEAT_DURATION = 20_000;\n\n/**\n * Defines a LEAP processor. This could be a Caseta Smart Bridge, RA2/RA3\n * Processor, or a Homeworks Processor.\n * @public\n */\nexport class ProcessorController\n extends EventEmitter<{\n Message: (response: Response) => void;\n Connect: (connection: Connection) => void;\n Disconnect: () => void;\n Error: (error: Error) => void;\n }>\n implements Processor\n{\n private uuid: string;\n private connection: Connection;\n private logger: ILogger;\n\n private cache: Cache.Cache;\n private discovered: Map<string, Device> = new Map();\n private heartbeatTimeout?: NodeJS.Timeout;\n\n /**\n * Creates a LEAP processor.\n *\n * @param id The processor UUID.\n * @param connection A reference to the connection to the processor.\n */\n constructor(id: string, connection: Connection) {\n super();\n\n this.uuid = id;\n this.logger = getLogger(`Processor ${Colors.dim(this.id)}`);\n this.connection = connection;\n this.cache = Cache.load(id, path.join(os.homedir(), \".leap\"));\n\n this.connection.on(\"Connect\", this.onConnect);\n this.connection.on(\"Message\", this.onMessage);\n this.connection.on(\"Error\", this.onError);\n\n this.connection.once(\"Disconnect\", this.onDisconnect);\n }\n\n /**\n * The processor's unique identifier.\n *\n * @returns The processor id.\n */\n public get id(): string {\n return this.uuid;\n }\n\n /**\n * A logger for the processor. This will automatically print the\n * processor id.\n *\n * @returns A reference to the logger assigned to this processor.\n */\n public get log(): ILogger {\n return this.logger;\n }\n\n /**\n * A device map for all devices found on this processor.\n *\n * @returns A device map by device id.\n */\n public get devices(): Map<string, Device> {\n return this.discovered;\n }\n\n /**\n * Connects to a processor.\n */\n public connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.logger.info(\"connect() starting\");\n\n this.connection\n .connect()\n .then(() => {\n this.logger.info(\"connect() socket/session ready; starting heartbeat\");\n this.startHeartbeat();\n\n resolve();\n })\n .catch((error) => {\n this.logger.error(`connect() failed: ${error instanceof Error ? error.message : String(error)}`);\n reject(error);\n });\n });\n }\n\n /**\n * Disconnects from a processor.\n */\n public disconnect(): void {\n this.stopHeartbeat();\n this.connection.disconnect();\n }\n\n /**\n * Clears the processor's device cache.\n */\n public clear(): void {\n for (const key of this.cache.keys()) {\n this.cache.removeKey(key);\n }\n\n this.cache.removeCacheFile();\n this.cache.save();\n }\n\n /**\n * True when a cache entry looks like a real LEAP payload (object/array),\n * not a poisoned error string such as \"Request timeout\".\n */\n private isValidCacheEntry(value: unknown): boolean {\n return value != null && typeof value === \"object\";\n }\n\n /**\n * Drops a bad cache entry so the next read hits the processor.\n */\n private dropCacheKey(key: string): void {\n this.cache.removeKey(key);\n this.cache.save(true);\n }\n\n /**\n * Pings the processor, useful for keeping the connection alive.\n *\n * @returns A ping response.\n */\n public ping(): Promise<PingResponse> {\n return this.read<PingResponse>(\"/server/1/status/ping\");\n }\n\n /**\n * Sends a read command to the processor.\n *\n * @param url The url to read.\n * @returns A response object.\n */\n public read<PAYLOAD = any>(url: string): Promise<PAYLOAD> {\n return this.connection.read<PAYLOAD>(url);\n }\n\n /**\n * Fetches the project information assigned to this processor.\n *\n * @returns A project object.\n */\n public project(): Promise<Project> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/project\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<Project>(\"/project\")\n .then((response) => {\n this.cache.setKey(\"/project\", response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches the processor's system information.\n *\n * @returns The processor as a device, or undefined if the processor\n * doesn't support this.\n */\n public system(): Promise<DeviceAddress | undefined> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/device?where=IsThisDevice:true\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<DeviceAddress[]>(\"/device?where=IsThisDevice:true\")\n .then((response) => {\n if (response[0] != null) {\n this.cache.setKey(\"/device?where=IsThisDevice:true\", response[0]);\n this.cache.save(true);\n\n return resolve(response[0]);\n }\n\n reject(new Error(\"No system device found\"));\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available areas. This represents floors, rooms, and suites.\n *\n * @returns An array of area objects.\n */\n public areas(): Promise<AreaAddress[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/area\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<AreaAddress[]>(\"/area\")\n .then((response) => {\n this.cache.setKey(\"/area\", response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available timeclocks.\n *\n * @returns An array of timeclock objects.\n */\n public timeclocks(): Promise<TimeclockAddress[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/timeclock\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<TimeclockAddress[]>(\"/timeclock\")\n .then((response) => {\n this.cache.setKey(\"/timeclock\", response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available zones in an area. Zones represent a light and control.\n * In other systems this is the device.\n *\n * @param address The area to fetch zones.\n *\n * @returns An array of zone objects.\n */\n public zones(address: Address): Promise<ZoneAddress[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(`${address.href}/associatedzone`);\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<ZoneAddress[]>(`${address.href}/associatedzone`)\n .then((response) => {\n this.cache.setKey(`${address.href}/associatedzone`, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches multiple status objects from an area or zone. Typically used to\n * fetch sensor states from an area.\n *\n * @param address Address of an area or zone.\n *\n * @returns A zone status object.\n */\n public status(address: Address): Promise<ZoneStatus> {\n return this.read<ZoneStatus>(`${address.href}/status`);\n }\n\n public statuses(type?: string): Promise<(ZoneStatus | AreaStatus | TimeclockStatus)[]> {\n return new Promise((resolve, reject) => {\n const waits: Promise<(ZoneStatus | AreaStatus | TimeclockStatus)[]>[] = [];\n\n waits.push(this.read<ZoneStatus[]>(\"/zone/status\"));\n waits.push(this.read<AreaStatus[]>(\"/area/status\"));\n\n if (type === \"RadioRa3Processor\") waits.push(this.read<TimeclockStatus[]>(\"/timeclock/status\"));\n\n Promise.all(waits)\n .then(([zones, areas, timeclocks]) => resolve([...zones, ...areas, ...(timeclocks || [])]))\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available control stations of an area or zone. A control station\n * represents a group of keypads or remotes.\n *\n * @param address The address of an area or zone.\n *\n * @returns An array of control station objects.\n */\n public controls(address: Address): Promise<ControlStation[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(`${address.href}/associatedcontrolstation`);\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<ControlStation[]>(`${address.href}/associatedcontrolstation`)\n .then((response) => {\n this.cache.setKey(`${address.href}/associatedcontrolstation`, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches a single device in a group. This represents a single keypad or\n * Pico remote.\n *\n * @param address An address of a group position.\n *\n * @returns A device object.\n */\n public device(address: Address): Promise<DeviceAddress> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(address.href);\n\n if (this.isValidCacheEntry(cached) && typeof (cached as DeviceAddress).DeviceType === \"string\") {\n return resolve(cached as DeviceAddress);\n }\n\n if (cached != null) {\n this.logger.warn(\n `dropping invalid cache for ${address.href}: ${typeof cached === \"string\" ? cached : typeof cached}`,\n );\n this.dropCacheKey(address.href);\n }\n\n this.connection\n .read<DeviceAddress>(address.href)\n .then((response) => {\n if (!this.isValidCacheEntry(response) || typeof response.DeviceType !== \"string\") {\n return reject(new Error(`invalid device payload for ${address.href}`));\n }\n\n this.cache.setKey(address.href, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available buttons on a device.\n *\n * @param address An address or a device.\n *\n * @returns An array of button group objects.\n */\n public buttons(address: Address): Promise<ButtonGroupExpanded[]> {\n return new Promise((resolve, reject) => {\n const key = `${address.href}/buttongroup/expanded`;\n const cached = this.cache.getKey(key);\n\n if (this.isValidCacheEntry(cached) && Array.isArray(cached)) {\n return resolve(cached as ButtonGroupExpanded[]);\n }\n\n if (cached != null) {\n this.logger.warn(\n `dropping invalid cache for ${key}: ${typeof cached === \"string\" ? cached : typeof cached}`,\n );\n this.dropCacheKey(key);\n }\n\n this.connection\n .read<ButtonGroupExpanded[]>(`${address.href}/buttongroup/expanded`)\n .then((response) => {\n if (!Array.isArray(response)) {\n return reject(new Error(`invalid button group payload for ${address.href}`));\n }\n\n this.cache.setKey(key, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Sends an updatre command to the processor.\n *\n * @param address The address of the record.\n * @param field The field to update.\n * @param value The value to set.\n */\n public update(address: Address, field: string, value: object): Promise<void> {\n return this.connection.update(`${address.href}/${field}`, value as Record<string, unknown>);\n }\n\n /**\n * Sends a structured command to the processor.\n *\n * @param address The address of the zone or device.\n * @param command The structured command object.\n */\n public command(address: Address, command: object): Promise<void> {\n return this.connection.command(`${address.href}/commandprocessor`, { Command: command });\n }\n\n /**\n * Subscribes to record updates. This will call the listener every time the\n * record is updated.\n *\n * @param address The assress of the record.\n * @param listener The callback to call on updates.\n */\n public subscribe<T>(address: Address, listener: (response: T) => void): Promise<void> {\n return this.connection.subscribe<T>(address.href, listener);\n }\n\n /*\n * Listener for the processor's connection status.\n */\n private onConnect = (): void => {\n this.log.info(\"connected\");\n this.emit(\"Connect\", this.connection);\n };\n\n /*\n * Listener for when the processor sends a message.\n */\n private onMessage = (response: Response): void => {\n this.log.debug(\"message\");\n this.emit(\"Message\", response);\n };\n\n /*\n * Listener for when the connection is dropped.\n */\n private onDisconnect = (): void => {\n this.log.info(\"disconnected\");\n this.emit(\"Disconnect\");\n };\n\n /*\n * Listener for when there is an error in the connection.\n */\n private onError = (error: Error): void => {\n this.logger.error(`connection error: ${error?.message != null ? error.message : String(error)}`);\n this.emit(\"Error\", error);\n };\n\n /*\n * Starts the ping heartbeat with the processor.\n */\n private startHeartbeat(): void {\n this.stopHeartbeat();\n\n this.ping()\n .then(() => {\n this.logger.debug(\"heartbeat ping ok\");\n })\n .catch((error) => {\n this.logger.warn(`heartbeat ping failed: ${error instanceof Error ? error.message : String(error)}`);\n })\n .finally(() => {\n this.heartbeatTimeout = setTimeout(() => this.startHeartbeat(), HEARTBEAT_DURATION);\n });\n }\n\n /*\n * Stops the ping heartbeat.\n */\n private stopHeartbeat(): void {\n clearTimeout(this.heartbeatTimeout);\n\n this.heartbeatTimeout = undefined;\n }\n}\n", "import { Device, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../Response/AreaAddress\";\nimport { ContactController } from \"./Contact/ContactController\";\nimport { DeviceAddress } from \"../Response/DeviceAddress\";\nimport { DimmerController } from \"./Dimmer/DimmerController\";\nimport { FanController } from \"./Fan/FanController\";\nimport { KeypadController } from \"./Keypad/KeypadController\";\nimport { Processor } from \"./Processor/Processor\";\nimport { RemoteController } from \"./Remote/RemoteController\";\nimport { OccupancyController } from \"./Occupancy/OccupancyController\";\nimport { ShadeController } from \"./Shade/ShadeController\";\nimport { StripController } from \"./Strip/StripController\";\nimport { SwitchController } from \"./Switch/SwitchController\";\nimport { TimeclockController } from \"./Timeclock/TimeclockController\";\nimport { TimeclockAddress } from \"../Response/TimeclockAddress\";\nimport { UnknownController } from \"./Unknown/UnknownController\";\nimport { ZoneAddress } from \"../Response/ZoneAddress\";\n\n/**\n * Creates a device by type. This is a device factory.\n *\n * @param processor A reference to the processor.\n * @param area A reference to the area.\n * @param definition Device definition, this is either an area, zone or device.\n *\n * @returns A common device object. Casting will be needed to access extended\n * capibilities.\n * @private\n */\nexport function createDevice(processor: Processor, area: AreaAddress, definition: unknown): Device {\n const type = parseDeviceType((definition as ZoneAddress).ControlType || (definition as DeviceAddress).DeviceType);\n\n switch (type) {\n case DeviceType.Contact:\n return new ContactController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Dimmer:\n return new DimmerController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Fan:\n return new FanController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Keypad:\n return new KeypadController(processor, area, definition as DeviceAddress);\n\n case DeviceType.Occupancy:\n return new OccupancyController(processor, area, {\n href: `/occupancy/${area.href?.split(\"/\")[2]}`,\n Name: (definition as ZoneAddress).Name,\n } as DeviceAddress);\n\n case DeviceType.Remote:\n return new RemoteController(processor, area, definition as DeviceAddress);\n\n case DeviceType.Shade:\n return new ShadeController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Strip:\n return new StripController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Switch:\n return new SwitchController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Timeclock:\n return new TimeclockController(processor, area, definition as TimeclockAddress);\n\n default:\n return new UnknownController(processor, area, definition as ZoneAddress);\n }\n}\n\n/**\n * Parses a string to a standard device type enum value.\n *\n * @param value A string device type from the processor.\n *\n * @returns A standard device type from the device type enum.\n * @private\n */\nexport function parseDeviceType(value: string): DeviceType {\n switch (value) {\n case \"Switched\":\n case \"PowPakSwitch\":\n case \"OutdoorPlugInSwitch\":\n return DeviceType.Switch;\n\n case \"Dimmed\":\n case \"PlugInDimmer\":\n return DeviceType.Dimmer;\n\n case \"Shade\":\n return DeviceType.Shade;\n\n case \"Timeclock\":\n return DeviceType.Timeclock;\n\n case \"WhiteTune\":\n return DeviceType.Strip;\n\n case \"FanSpeed\":\n return DeviceType.Fan;\n\n case \"Pico2Button\":\n case \"Pico2ButtonRaiseLower\":\n case \"Pico3Button\":\n case \"Pico4Button\":\n case \"Pico3ButtonRaiseLower\":\n case \"Pico4Button2Group\":\n case \"Pico4ButtonScene\":\n case \"Pico4ButtonZone\":\n case \"PaddleSwitchPico\":\n return DeviceType.Remote;\n\n case \"SunnataDimmer\":\n case \"SunnataSwitch\":\n case \"SunnataKeypad\":\n case \"SunnataHybridKeypad\":\n return DeviceType.Keypad;\n\n case \"RPSCeilingMountedOccupancySensor\":\n return DeviceType.Occupancy;\n\n case \"CCO\":\n return DeviceType.Contact;\n\n default:\n return DeviceType.Unknown;\n }\n}\n\n/**\n * Determines if the device is addressable. Basically can we program actions\n * for it.\n *\n * @param device A reference to the device.\n *\n * @returns True is addressable, false if not.\n * @private\n */\nexport function isAddressable(device: DeviceAddress): boolean {\n // Guard against poisoned cache entries (e.g. the string \"Request timeout\").\n if (device == null || typeof device !== \"object\") {\n return false;\n }\n\n if (device.AddressedState !== \"Addressed\") {\n return false;\n }\n\n switch (device.DeviceType) {\n case \"Pico2Button\":\n case \"Pico2ButtonRaiseLower\":\n case \"Pico3Button\":\n case \"Pico4Button\":\n case \"Pico3ButtonRaiseLower\":\n case \"Pico4Button2Group\":\n case \"Pico4ButtonScene\":\n case \"Pico4ButtonZone\":\n case \"PaddleSwitchPico\":\n return true;\n\n case \"SunnataKeypad\":\n case \"SunnataHybridKeypad\":\n return true;\n\n case \"RPSCeilingMountedOccupancySensor\":\n return true;\n\n default:\n return false;\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Contact } from \"./Contact\";\nimport { ContactState } from \"./ContactState\";\nimport { Processor } from \"../Processor/Processor\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a CCO device.\n * @public\n */\nexport class ContactController extends Common<ContactState> implements Contact {\n /**\n * Creates a CCO device.\n *\n * ```js\n * const cco = new Contact(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Contact, processor, area, zone, { state: \"Open\" });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"Open\", \"Closed\"] });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * cco.update({ CCOLevel: \"Closed\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.CCOLevel != null) this.state.state = status.CCOLevel;\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * cco.set({ state: \"Closed\" });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: ContactState): Promise<void> {\n return this.processor.command(this.address, {\n CommandType: \"GoToCCOLevel\",\n CCOLevelParameters: { CCOLevel: status.state },\n });\n }\n}\n", "import { ILogger, get as getLogger } from \"js-logger\";\n\nimport { Action, Address, Area, Button, Capability, Device, DeviceState, DeviceType } from \"@mkellsy/hap-device\";\n\nimport Colors from \"colors\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\nimport { Processor } from \"./Processor/Processor\";\n\n/**\n * Defines common functionallity for a device.\n * @private\n */\nexport abstract class Common<STATE extends DeviceState> extends EventEmitter<{\n Action: (device: Device, button: Button, action: Action) => void;\n Update: (device: Device, state: STATE) => void;\n}> {\n protected processor: Processor;\n protected state: STATE;\n protected initialized: boolean = false;\n protected fields: Map<string, Capability> = new Map();\n\n /**\n * Resolves when async device setup (e.g. button enumeration) is finished.\n * Defaults to already-resolved; remotes/keypads override.\n */\n public ready: Promise<void> = Promise.resolve();\n\n private logger: ILogger;\n\n private deviceName: string;\n private deviceAddress: string;\n private deviceArea: Area;\n private deviceAreaPath: string;\n private deviceType: DeviceType;\n\n /**\n * Creates a base device object.\n *\n * ```\n * class Fan extends Common {\n * constructor(id: string, connection: Connection, name: string) {\n * super(DeviceType.Fan, connection, { id, name, \"Fan\" });\n *\n * // Device specific code\n * }\n * }\n * ```\n *\n * @param type The device type.\n * @param processor The current processor for this device.\n * @param area The area the device belongs to. May include Path (full hierarchy).\n * @param definition Device address definition.\n * @param state The device's initial state.\n */\n constructor(\n type: DeviceType,\n processor: Processor,\n area: Area & { Path?: string },\n definition: { href: string; Name: string },\n state: STATE,\n ) {\n super();\n\n this.processor = processor;\n this.deviceAddress = definition.href;\n this.deviceName = definition.Name;\n this.deviceArea = area;\n this.deviceAreaPath = area.Path || area.Name || \"\";\n this.deviceType = type;\n\n this.logger = getLogger(`Device ${Colors.dim(this.id)}`);\n this.state = state;\n }\n\n /**\n * The device's manufacturer.\n *\n * @returns The manufacturer.\n */\n public get manufacturer(): string {\n return \"Lutron Electronics Co., Inc\";\n }\n\n /**\n * The device's unique identifier.\n *\n * @returns The device id.\n */\n public get id(): string {\n return `LEAP-${this.processor.id}-${DeviceType[this.deviceType].toUpperCase()}-${this.deviceAddress?.split(\"/\")[2]}`;\n }\n\n /**\n * The device's configured name.\n *\n * @returns The device's configured name.\n */\n public get name(): string {\n return this.deviceName;\n }\n\n /**\n * The device's configured room.\n *\n * @returns The device's configured room.\n */\n public get room(): string {\n return this.area.Name;\n }\n\n /**\n * Full area hierarchy path (e.g. \"House / Upper Floor / Kitchen\").\n * Falls back to the leaf room name when path was not provided.\n */\n public get areaPath(): string {\n return this.deviceAreaPath || this.room;\n }\n\n /**\n * The devices capibilities. This is a map of the fields that can be set\n * or read.\n *\n * @returns The device's capabilities.\n */\n public get capabilities(): { [key: string]: Capability } {\n return Object.fromEntries(this.fields);\n }\n\n /**\n * A logger for the device. This will automatically print the devices name,\n * room and id.\n *\n * @returns A reference to the logger assigned to this device.\n */\n public get log(): ILogger {\n return this.logger;\n }\n\n /**\n * The href address of the device.\n *\n * @returns The device's href address.\n */\n public get address(): Address {\n return { href: this.deviceAddress };\n }\n\n /**\n * The device type.\n *\n * @returns The device type.\n */\n public get type(): DeviceType {\n return this.deviceType;\n }\n\n /**\n * The area the device is in.\n *\n * @returns The device's area.\n */\n public get area(): Area {\n return this.deviceArea;\n }\n\n /**\n * The current state of the device.\n *\n * @returns The device's state.\n */\n public get status(): STATE {\n return this.state;\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Dimmer } from \"./Dimmer\";\nimport { DimmerState } from \"./DimmerState\";\nimport { Processor } from \"../Processor/Processor\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a dimmable light device.\n * @public\n */\nexport class DimmerController extends Common<DimmerState> implements Dimmer {\n /**\n * Creates a dimmable light device.\n *\n * ```js\n * const dimmer = new Dimmer(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Dimmer, processor, area, zone, { state: \"Off\", level: 0 });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n this.fields.set(\"level\", { type: \"Integer\", min: 0, max: 100 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * dimmer.update({ Level: 100 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.Level != null) {\n this.state.state = status.Level > 0 ? \"On\" : \"Off\";\n this.state.level = status.Level;\n }\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * dimmer.set({ state: \"On\", level: 50 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: DimmerState): Promise<void> {\n return this.processor.command(this.address, {\n CommandType: \"GoToLevel\",\n Parameter: [{ Type: \"Level\", Value: status.state === \"Off\" ? 0 : status.level }],\n });\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Fan } from \"./Fan\";\nimport { FanState } from \"./FanState\";\nimport { Processor } from \"../Processor/Processor\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a fan device.\n * @public\n */\nexport class FanController extends Common<FanState> implements Fan {\n /**\n * Creates a fan device.\n *\n * ```js\n * const fan = new Fan(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Fan, processor, area, zone, { state: \"Off\", speed: 0 });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n this.fields.set(\"speed\", { type: \"Integer\", min: 0, max: 7 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * fan.update({ SwitchedLevel: \"On\", FanSpeed: 7 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n const speed = this.parseFanSpeed(status.FanSpeed as unknown as string);\n\n this.state = {\n ...previous,\n state: speed > 0 ? \"On\" : \"Off\",\n speed,\n };\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * fan.set({ state: \"On\", speed: 3 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: FanState): Promise<void> {\n const speed = status.state === \"Off\" ? \"Off\" : this.lookupFanSpeed(status.speed);\n\n return this.processor.command(this.address, {\n CommandType: \"GoToFanSpeed\",\n FanSpeedParameters: [{ FanSpeed: speed }],\n });\n }\n\n /*\n * Converts a 7 speed setting to a 4 speed string value.\n */\n private lookupFanSpeed(value: number): string {\n switch (value) {\n case 1:\n return \"Low\";\n\n case 2:\n case 3:\n return \"Medium\";\n\n case 4:\n case 5:\n return \"MediumHigh\";\n\n case 6:\n case 7:\n return \"High\";\n\n default:\n return \"Off\";\n }\n }\n\n /*\n * Converts a 4 speed string speed to a numeric 7 speed value.\n */\n private parseFanSpeed(value: string): number {\n switch (value) {\n case \"Low\":\n return 1;\n\n case \"Medium\":\n return 3;\n\n case \"MediumHigh\":\n return 5;\n\n case \"High\":\n return 7;\n\n default:\n return 0;\n }\n }\n}\n", "import Colors from \"colors\";\n\nimport { Button, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { ButtonStatus } from \"../../Response/ButtonStatus\";\nimport { Common } from \"../Common\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { Keypad } from \"./Keypad\";\nimport { KeypadState } from \"./KeypadState\";\nimport { Processor } from \"../Processor/Processor\";\n\n/**\n * Defines a keypad device.\n * @public\n */\nexport class KeypadController extends Common<KeypadState> implements Keypad {\n public readonly buttons: Button[] = [];\n\n /**\n * Creates a keypad device.\n *\n * ```js\n * const keypad = new Keypad(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device A refrence to this device.\n */\n constructor(processor: Processor, area: AreaAddress, device: DeviceAddress) {\n super(DeviceType.Keypad, processor, area, device, {\n led: { href: \"/unknown\" },\n state: \"Off\",\n });\n\n if (device.DeviceType === \"SunnataKeypad\" || device.DeviceType === \"SunnataHybridKeypad\") {\n this.ready = this.processor\n .buttons(this.address)\n .then(async (groups) => {\n if (!Array.isArray(groups)) {\n throw new Error(`button groups not an array for ${device.DeviceType} ${this.address.href}`);\n }\n\n for (let i = 0; i < groups.length; i++) {\n for (let j = 0; j < groups[i].Buttons?.length; j++) {\n const button = groups[i].Buttons[j];\n const id = `LEAP-${this.processor.id}-BUTTON-${button.href.split(\"/\")[2]}`;\n\n const definition: Button = {\n id,\n index: button.ButtonNumber,\n name: (button.Engraving || {}).Text || button.Name,\n led: button.AssociatedLED,\n };\n\n this.buttons.push(definition);\n\n try {\n await this.processor.subscribe<ButtonStatus>(\n { href: `${button.href}/status/event` },\n (status: ButtonStatus): void => {\n const action = status.ButtonEvent.EventType;\n\n if (action !== \"Press\") return;\n\n this.emit(\"Action\", this, definition, \"Press\");\n\n setTimeout(() => this.emit(\"Action\", this, definition, \"Release\"), 100);\n },\n );\n } catch (error) {\n this.log.error(Colors.red(error instanceof Error ? error.message : String(error)));\n }\n }\n }\n\n this.log.info(\n `keypad buttons ready count=${this.buttons.length} type=${device.DeviceType} href=${this.address.href}`,\n );\n })\n .catch((error: Error) => {\n this.log.error(Colors.red(error.message));\n throw error;\n });\n }\n }\n\n /**\n * Recieves a state response from the processor (not supported).\n */\n public update(): void {\n this.initialized = true;\n }\n\n /**\n * Controls this LEDs on this device.\n *\n * ```js\n * keypad.set({ state: { href: \"/led/123456\" }, state: \"On\" });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: KeypadState): Promise<void> {\n return this.processor.update(status.led, \"status\", {\n LEDStatus: { State: status.state === \"On\" ? \"On\" : \"Off\" },\n });\n }\n}\n", "import Colors from \"colors\";\n\nimport { Button, DeviceState, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { ButtonMap } from \"./ButtonMap\";\nimport { ButtonStatus } from \"../../Response/ButtonStatus\";\nimport { Common } from \"../Common\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Remote } from \"./Remote\";\nimport { Trigger } from \"./Trigger\";\nimport { TriggerController } from \"./TriggerController\";\n\n/**\n * Defines a Pico remote device.\n * @public\n */\nexport class RemoteController extends Common<DeviceState> implements Remote {\n public readonly buttons: Button[] = [];\n\n private triggers: Map<string, Trigger> = new Map();\n\n /**\n * Creates a Pico remote device.\n *\n * ```js\n * const remote = new Remote(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device A refrence to this device.\n */\n constructor(processor: Processor, area: AreaAddress, device: DeviceAddress) {\n super(DeviceType.Remote, processor, area, device, { state: \"Unknown\" });\n\n this.ready = this.processor\n .buttons(this.address)\n .then(async (groups) => {\n if (!Array.isArray(groups)) {\n throw new Error(`button groups not an array for ${device.DeviceType} ${this.address.href}`);\n }\n\n const map = ButtonMap.get(device.DeviceType);\n\n if (map == null) {\n this.log.warn(`no ButtonMap for DeviceType=${device.DeviceType}; buttons will be unmapped`);\n }\n\n for (let i = 0; i < groups.length; i++) {\n for (let j = 0; j < groups[i].Buttons?.length; j++) {\n const button = groups[i].Buttons[j];\n const mapped = map?.get(button.ButtonNumber);\n const index = (mapped?.[0] as number | undefined) ?? button.ButtonNumber + 1;\n const raiseLower = (mapped?.[1] as boolean | undefined) ?? false;\n\n const trigger = new TriggerController(this.processor, button, index, { raiseLower });\n\n trigger.on(\"Press\", (button): void => {\n this.emit(\"Action\", this, button, \"Press\");\n\n setTimeout(() => this.emit(\"Action\", this, button, \"Release\"), 100);\n });\n\n trigger.on(\"DoublePress\", (button): void => {\n this.emit(\"Action\", this, button, \"DoublePress\");\n\n setTimeout(() => this.emit(\"Action\", this, button, \"Release\"), 100);\n });\n\n trigger.on(\"LongPress\", (button): void => {\n this.emit(\"Action\", this, button, \"LongPress\");\n\n setTimeout(() => this.emit(\"Action\", this, button, \"Release\"), 100);\n });\n\n this.triggers.set(button.href, trigger);\n this.buttons.push(trigger.definition);\n\n try {\n await this.processor.subscribe<ButtonStatus>(\n { href: `${button.href}/status/event` },\n (status: ButtonStatus): void => this.triggers.get(button.href)!.update(status),\n );\n } catch (error) {\n this.log.error(Colors.red(error instanceof Error ? error.message : String(error)));\n }\n }\n }\n\n this.log.info(\n `remote buttons ready count=${this.buttons.length} type=${device.DeviceType} href=${this.address.href}`,\n );\n })\n .catch((error: Error) => {\n this.log.error(Colors.red(error.message));\n throw error;\n });\n }\n\n /**\n * Recieves a state response from the processor (not supported).\n */\n public update(): void {\n this.initialized = true;\n }\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "/**\n * Maps button index from the processor to a standard sequence index. It also\n * determines if the button is a raise or lower button.\n * @private\n */\nexport const ButtonMap = new Map<string, Map<number, (number | boolean)[]>>([\n [\n \"Pico2Button\",\n new Map([\n [0, [1, false]],\n [2, [2, false]],\n ]),\n ],\n [\n \"Pico2ButtonRaiseLower\",\n new Map([\n [0, [1, false]],\n [2, [4, false]],\n [3, [2, true]],\n [4, [3, true]],\n ]),\n ],\n [\n \"Pico3Button\",\n new Map([\n [0, [1, false]],\n [1, [2, false]],\n [2, [3, false]],\n ]),\n ],\n [\n \"Pico3ButtonRaiseLower\",\n new Map([\n [0, [1, false]],\n [1, [3, false]],\n [2, [5, false]],\n [3, [2, true]],\n [4, [4, true]],\n ]),\n ],\n [\n \"Pico4Button2Group\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n [\n \"Pico4ButtonScene\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n [\n \"Pico4ButtonZone\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n [\n \"PaddleSwitchPico\",\n new Map([\n [0, [1, false]],\n [2, [2, false]],\n ]),\n ],\n [\n \"Pico4Button\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n]);\n", "import { Button, TriggerOptions, TriggerState } from \"@mkellsy/hap-device\";\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { ButtonAddress } from \"../../Response/ButtonAddress\";\nimport { ButtonStatus } from \"../../Response/ButtonStatus\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Trigger } from \"./Trigger\";\n\n/**\n * Defines a button tracker. This enables single, double and long presses on\n * remotes.\n * @public\n */\nexport class TriggerController\n extends EventEmitter<{\n Press: (button: Button) => void;\n DoublePress: (button: Button) => void;\n LongPress: (button: Button) => void;\n }>\n implements Trigger\n{\n private processor: Processor;\n private action: ButtonAddress;\n private options: TriggerOptions;\n\n private timer?: NodeJS.Timeout;\n private state: TriggerState = TriggerState.Idle;\n private button: Button;\n private index: number;\n\n /**\n * Creates a button tracker.\n *\n * @param processor A refrence to the processor.\n * @param button A reference to the individual button.\n * @param index An index of the button on the device.\n * @param options Button options like click speed, raise or lower.\n */\n constructor(processor: Processor, button: ButtonAddress, index: number, options?: Partial<TriggerOptions>) {\n super();\n\n this.index = index;\n this.processor = processor;\n this.action = button;\n\n this.options = {\n doubleClickSpeed: 300,\n clickSpeed: 450,\n raiseLower: false,\n ...options,\n };\n\n this.button = {\n id: this.id,\n index: this.index,\n name: (this.action.Engraving || {}).Text || this.action.Name,\n };\n\n if (this.options.raiseLower === true) this.button.raiseLower = true;\n }\n\n /**\n * The button id.\n *\n * @returns A string of the button id.\n */\n public get id(): string {\n return `LEAP-${this.processor.id}-BUTTON-${this.action.href.split(\"/\")[2]}`;\n }\n\n /**\n * The definition of the button.\n *\n * @returns A button object.\n */\n public get definition(): Button {\n return this.button;\n }\n\n /**\n * Resets the button state to idle.\n */\n public reset(): void {\n this.state = TriggerState.Idle;\n\n if (this.timer) clearTimeout(this.timer);\n\n this.timer = undefined;\n }\n\n /**\n * Updates the button state and tracks single, double or long presses.\n *\n * @param status The current button status.\n */\n public update(status: ButtonStatus): void {\n const longPressTimeoutHandler = () => {\n this.reset();\n\n /*\n * Testing this edge case is not reliable in unit tests. This\n * prevents false positives.\n */\n\n /* istanbul ignore next */\n if (this.options.clickSpeed === 0) return;\n\n this.emit(\"LongPress\", this.button);\n };\n\n const doublePressTimeoutHandler = () => {\n this.reset();\n this.emit(\"Press\", this.button);\n };\n\n switch (this.state) {\n case TriggerState.Idle: {\n if (status.ButtonEvent.EventType === \"Press\" && this.options.clickSpeed > 0) {\n this.state = TriggerState.Down;\n this.timer = setTimeout(longPressTimeoutHandler, this.options.clickSpeed);\n\n return;\n }\n\n if (status.ButtonEvent.EventType === \"Press\") {\n this.state = TriggerState.Down;\n\n doublePressTimeoutHandler();\n\n return;\n }\n\n break;\n }\n\n case TriggerState.Down: {\n if (status.ButtonEvent.EventType === \"Release\") {\n this.state = TriggerState.Up;\n\n /*\n * Getting the unit tests to trigger this edge case is\n * un-reliable. This prevents false positives.\n */\n\n /* istanbul ignore else */\n if (this.timer) clearTimeout(this.timer);\n\n if (this.options.doubleClickSpeed > 0) {\n this.timer = setTimeout(\n doublePressTimeoutHandler,\n this.options.doubleClickSpeed + (this.options.raiseLower ? 250 : 0),\n );\n }\n\n return;\n }\n\n this.reset();\n\n break;\n }\n\n case TriggerState.Up: {\n if (status.ButtonEvent.EventType === \"Press\" && this.timer) {\n this.reset();\n\n if (this.options.doubleClickSpeed === 0) return;\n\n this.emit(\"DoublePress\", this.button);\n\n return;\n }\n\n this.reset();\n\n break;\n }\n }\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { AreaStatus, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { Occupancy } from \"./Occupancy\";\nimport { OccupancyState } from \"./OccupancyState\";\nimport { Processor } from \"../Processor/Processor\";\n\n/**\n * Defines a occupancy sensor device.\n * @public\n */\nexport class OccupancyController extends Common<OccupancyState> implements Occupancy {\n /**\n * Creates a occupancy sensor device.\n *\n * ```js\n * const sensor = new Occupancy(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device The refrence to this device.\n */\n constructor(processor: Processor, area: AreaAddress, device: DeviceAddress) {\n super(DeviceType.Occupancy, processor, area, device, { state: \"Unoccupied\" });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * sensor.update({ OccupancyStatus: \"Occupied\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: AreaStatus): void {\n const previous = { ...this.status };\n\n if (status.OccupancyStatus != null) {\n this.state.state = status.OccupancyStatus === \"Occupied\" ? \"Occupied\" : \"Unoccupied\";\n }\n\n if (!equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Shade } from \"./Shade\";\nimport { ShadeState } from \"./ShadeState\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a window shade device.\n * @public\n */\nexport class ShadeController extends Common<ShadeState> implements Shade {\n /**\n * Creates a window shade device.\n *\n * ```js\n * const shade = new Shade(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Shade, processor, area, zone, {\n state: \"Closed\",\n level: 0,\n tilt: 0,\n });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"Open\", \"Closed\"] });\n this.fields.set(\"level\", { type: \"Integer\", min: 0, max: 100 });\n this.fields.set(\"tilt\", { type: \"Integer\", min: 0, max: 100 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * shade.update({ Level: 100 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.Level != null) {\n this.state.state = status.Level > 0 ? \"Open\" : \"Closed\";\n this.state.level = status.Level;\n }\n\n if (status.Tilt != null) this.state.tilt = status.Tilt;\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * shade.set({ state: \"Open\", level: 50, tilt: 50 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: ShadeState): Promise<void> {\n const waits: Promise<void>[] = [];\n\n waits.push(\n this.processor.command(this.address, {\n CommandType: \"GoToLevel\",\n Parameter: [{ Type: \"Level\", Value: status.state === \"Closed\" ? 0 : status.level }],\n }),\n );\n\n if (status.tilt != null || status.state === \"Closed\") {\n waits.push(\n this.processor.command(this.address, {\n CommandType: \"TiltParameters\",\n TiltParameters: { Tilt: status.state === \"Closed\" ? 0 : status.tilt },\n }),\n );\n }\n\n return Promise.all(waits) as unknown as Promise<void>;\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Strip } from \"./Strip\";\nimport { StripState } from \"./StripState\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a LED strip device.\n * @public\n */\nexport class StripController extends Common<StripState> implements Strip {\n /**\n * Creates a LED strip device.\n *\n * ```js\n * const strip = new Strip(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Strip, processor, area, zone, {\n state: \"Off\",\n level: 0,\n luminance: 1800,\n });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n this.fields.set(\"level\", { type: \"Integer\", min: 0, max: 100 });\n this.fields.set(\"luminance\", { type: \"Integer\", min: 1800, max: 3000 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * strip.update({ Level: 100 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.Level != null) {\n this.state.state = status.Level > 0 ? \"On\" : \"Off\";\n this.state.level = status.Level;\n }\n\n if (\n status.ColorTuningStatus != null &&\n status.ColorTuningStatus.WhiteTuningLevel != null &&\n status.ColorTuningStatus.WhiteTuningLevel.Kelvin != null\n ) {\n this.state.luminance = status.ColorTuningStatus.WhiteTuningLevel.Kelvin;\n }\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * strip.set({ state: \"On\", level: 50, luminance: 3000 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: StripState): Promise<void> {\n if (status.state === \"Off\") {\n return this.processor.command(this.address, {\n CommandType: \"GoToWhiteTuningLevel\",\n WhiteTuningLevelParameters: { Level: 0 },\n });\n }\n\n return this.processor.command(this.address, {\n CommandType: \"GoToWhiteTuningLevel\",\n WhiteTuningLevelParameters: {\n Level: status.level,\n WhiteTuningLevel: { Kelvin: status.luminance },\n },\n });\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Switch } from \"./Switch\";\nimport { SwitchState } from \"./SwitchState\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a on/off switch device.\n * @public\n */\nexport class SwitchController extends Common<SwitchState> implements Switch {\n /**\n * Creates a on/off switch device.\n *\n * ```js\n * const switch = new Switch(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Switch, processor, area, zone, { state: \"Off\" });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * switch.update({ SwitchedLevel: \"On\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n this.state = {\n ...previous,\n state: status.SwitchedLevel || \"Unknown\",\n };\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * switch.set({ state: \"On\" });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: SwitchState): Promise<void> {\n return this.processor.command(this.address, {\n CommandType: \"GoToLevel\",\n Parameter: [{ Type: \"Level\", Value: status.state === \"On\" ? 100 : 0 }],\n });\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, TimeclockStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Timeclock } from \"./Timeclock\";\nimport { TimeclockAddress } from \"../../Response/TimeclockAddress\";\nimport { TimeclockState } from \"./TimeclockState\";\n\n/**\n * Defines a timeclock device.\n * @public\n */\nexport class TimeclockController extends Common<TimeclockState> implements Timeclock {\n /**\n * Creates a timeclock device.\n *\n * ```js\n * const timeclock = new Timeclock(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device The reference to the device.\n */\n constructor(processor: Processor, area: AreaAddress, device: TimeclockAddress) {\n super(DeviceType.Timeclock, processor, area, device, { state: \"Off\" });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * timeclock.update({ EnabledState: \"Enabled\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: TimeclockStatus): void {\n const previous = { ...this.status };\n\n this.state = {\n ...previous,\n state: status.EnabledState === \"Enabled\" ? \"On\" : \"Off\",\n };\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "import { DeviceState, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Unknown } from \"./Unknown\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines an unknown device.\n * @public\n */\nexport class UnknownController extends Common<DeviceState> implements Unknown {\n /**\n * Creates a placeholder for an unknown device.\n *\n * ```js\n * const unknown = new Unknown(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Unknown, processor, area, zone, { state: \"Unknown\" });\n }\n\n /**\n * Recieves a state response from the processor (not supported).\n */\n public update(): void {}\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "import { Device } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../Response/AreaAddress\";\nimport { Processor } from \"../Devices/Processor/Processor\";\n\n// Use console so Homebridge child-bridge logs capture this even if js-logger\n// is not wired (esbuild can isolate logger instances).\nconst log = {\n info: (message: string) => console.log(`[LEAP][MetaProbe] ${message}`),\n warn: (message: string) => console.warn(`[LEAP][MetaProbe] ${message}`),\n};\n\n/**\n * Candidate LEAP URLs that may expose grouping / catalog metadata.\n * Many will 404 or reject; that is expected and still useful signal.\n */\nconst PROBE_URLS: string[] = [\n \"/area\",\n \"/zone\",\n \"/device\",\n \"/controlstation\",\n \"/occupancygroup\",\n \"/group\",\n \"/areagroup\",\n \"/zonegroup\",\n \"/loadgroup\",\n \"/devicegroup\",\n \"/virtualbutton\",\n \"/preset\",\n \"/area/status\",\n \"/zone/status\",\n \"/server/1/status/ping\",\n \"/project\",\n \"/clientsetting\",\n \"/link\",\n \"/button\",\n \"/buttongroup\",\n \"/timeclock\",\n];\n\nfunction summarizeBody(body: unknown): string {\n if (body == null) return \"null\";\n\n if (Array.isArray(body)) {\n const first = body[0] as Record<string, unknown> | undefined;\n const keys = first != null && typeof first === \"object\" ? Object.keys(first).join(\",\") : \"\";\n\n return `array(len=${body.length}${keys ? ` sampleKeys=${keys}` : \"\"})`;\n }\n\n if (typeof body === \"object\") {\n const record = body as Record<string, unknown>;\n const keys = Object.keys(record);\n\n return `object(keys=${keys.slice(0, 20).join(\",\")}${keys.length > 20 ? \",...\" : \"\"})`;\n }\n\n if (typeof body === \"string\") {\n return `string(len=${body.length} preview=${JSON.stringify(body.slice(0, 200))})`;\n }\n\n return `${typeof body}:${String(body).slice(0, 120)}`;\n}\n\nfunction areaPath(areas: AreaAddress[], href: string | undefined): string {\n if (href == null) return \"\";\n\n const byHref = new Map(areas.map((a) => [a.href, a]));\n const names: string[] = [];\n let current: string | undefined = href;\n const seen = new Set<string>();\n\n while (current != null && !seen.has(current)) {\n seen.add(current);\n const area = byHref.get(current);\n\n if (area == null) break;\n\n names.unshift(area.Name);\n current = area.Parent?.href;\n }\n\n return names.join(\" / \");\n}\n\n/**\n * Live LEAP metadata probe: dumps area hierarchy, zone/device associations,\n * and tries extra endpoints that might correspond to \"groups\" in other apps.\n * @private\n */\nexport async function probeProcessorMetadata(processor: Processor, areas: AreaAddress[]): Promise<void> {\n log.info(`===== LEAP metadata probe start processor=${processor.id} areas=${areas.length} =====`);\n\n // Area tree (rooms / floors). UniFi Connect \"groups\" often map to this.\n for (const area of areas) {\n log.info(\n `AREA href=${area.href} name=${JSON.stringify(area.Name)} leaf=${area.IsLeaf} ` +\n `parent=${area.Parent?.href || \"none\"} path=${JSON.stringify(areaPath(areas, area.href))} ` +\n `keys=${Object.keys(area).join(\",\")}`,\n );\n }\n\n // Zones + control stations already fetched for leaf areas (cache-backed).\n for (const area of areas.filter((a) => a.IsLeaf)) {\n const path = areaPath(areas, area.href);\n\n try {\n const zones = await processor.zones(area);\n\n for (const zone of zones) {\n log.info(\n `ZONE area=${JSON.stringify(path)} name=${JSON.stringify(zone.Name)} ` +\n `href=${zone.href} control=${zone.ControlType} ` +\n `category=${zone.Category?.Type || \"\"} isLight=${zone.Category?.IsLight ?? \"?\"} ` +\n `assocArea=${zone.AssociatedArea?.href || \"\"} ` +\n `device=${zone.Device?.href || \"\"} keys=${Object.keys(zone).join(\",\")}`,\n );\n }\n } catch (error) {\n log.warn(`ZONE list failed for ${area.href}: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n try {\n const stations = await processor.controls(area);\n\n for (const station of stations) {\n const ganged = (station.AssociatedGangedDevices || [])\n .map((g) => `${g.Device?.DeviceType || \"?\"}@${g.Device?.href || \"?\"}`)\n .join(\",\");\n\n log.info(\n `STATION area=${JSON.stringify(path)} name=${JSON.stringify(station.Name)} ` +\n `href=${station.href} ganged=[${ganged}] keys=${Object.keys(station).join(\",\")}`,\n );\n }\n } catch (error) {\n log.warn(`STATION list failed for ${area.href}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // Live raw reads of candidate catalog endpoints (bypass high-level helpers).\n for (const url of PROBE_URLS) {\n try {\n const body = await processor.read(url);\n\n log.info(`PROBE ok url=${url} body=${summarizeBody(body)}`);\n\n // For small arrays/objects, dump a compact JSON sample.\n if (Array.isArray(body) && body.length > 0 && body.length <= 5) {\n log.info(`PROBE sample url=${url} ${JSON.stringify(body).slice(0, 1500)}`);\n } else if (Array.isArray(body) && body.length > 5) {\n log.info(`PROBE sample url=${url} first=${JSON.stringify(body[0]).slice(0, 800)}`);\n } else if (body != null && typeof body === \"object\" && !Array.isArray(body)) {\n log.info(`PROBE sample url=${url} ${JSON.stringify(body).slice(0, 1200)}`);\n }\n } catch (error) {\n log.info(`PROBE fail url=${url}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // Devices currently discovered by the client with room metadata.\n for (const device of processor.devices.values()) {\n const area = device.area as AreaAddress | undefined;\n const withPath = device as Device & { areaPath?: string };\n const path = typeof withPath.areaPath === \"string\" ? withPath.areaPath : areaPath(areas, area?.href);\n\n log.info(\n `DEVICE type=${device.type} name=${JSON.stringify(device.name)} room=${JSON.stringify(device.room)} ` +\n `areaPath=${JSON.stringify(path)} id=${device.id} href=${device.address?.href || \"\"} ` +\n `areaHref=${area?.href || \"\"} areaParent=${area?.Parent?.href || \"\"}`,\n );\n }\n\n log.info(`===== LEAP metadata probe done processor=${processor.id} =====`);\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["src_exports", "__export", "Client", "connect", "pair", "__toCommonJS", "import_node_forge", "import_hap_device", "import_fs", "import_path", "import_net", "import_bson", "import_js_logger", "import_node_forge", "import_uuid", "import_event_emitter", "ResponseHeader", "ResponseStatus", "_ResponseStatus", "message", "code", "value", "parts", "Response", "_Response", "ResponseHeader", "value", "payload", "status", "ResponseStatus", "header", "key", "body", "Parser", "data", "callback", "response", "lines", "line", "Response", "ExceptionDetail", "import_event_emitter", "import_js_logger", "import_tls", "log", "getLogger", "KEEPALIVE_INITIAL_DELAY", "INACTIVITY_TIMEOUT", "Socket", "host", "port", "certificate", "data", "error", "resolve", "reject", "connection", "protocol", "_a", "_b", "message", "log", "getLogger", "SOCKET_PORT", "SECURE_SOCKET_PORT", "REACHABLE_TIMEOUT", "Connection", "Parser", "host", "certificate", "response", "tag", "request", "subscription", "data", "error", "__spreadValues", "resolve", "socket", "net", "success", "reject", "port", "subscriptions", "Socket", "protocol", "waits", "_a", "url", "_b", "body", "bodyType", "ExceptionDetail", "message", "kind", "csr", "timeout", "command", "listener", "requestType", "filename", "path", "fs", "bytes", "secure", "Association", "processor", "ip", "address", "Connection", "__async", "resolve", "reject", "request", "certificate", "error", "name", "keys", "import_fs", "import_path", "import_os", "import_bson", "import_js_logger", "log", "getLogger", "Context", "context", "keys", "i", "processors", "error", "key", "id", "processor", "__spreadValues", "filename", "directory", "path", "os", "filePath", "fs", "bytes", "size", "clear", "import_os", "import_path", "import_deep_equal", "import_flat_cache", "import_js_logger", "import_event_emitter", "import_tinkerhub_mdns", "import_hap_device", "log", "getLogger", "Discovery", "service", "systype", "host", "error", "addrs", "a", "cached", "Cache", "path", "os", "i", "_a", "entry", "equals", "type", "index", "target", "addresses", "import_js_logger", "import_colors", "import_hap_device", "import_event_emitter", "import_js_logger", "import_flat_cache", "import_colors", "import_os", "import_path", "import_event_emitter", "HEARTBEAT_DURATION", "ProcessorController", "id", "connection", "response", "error", "getLogger", "Colors", "Cache", "path", "os", "resolve", "reject", "key", "value", "url", "cached", "address", "type", "waits", "zones", "areas", "timeclocks", "field", "command", "listener", "import_hap_device", "import_deep_equal", "import_hap_device", "import_js_logger", "import_hap_device", "import_colors", "import_event_emitter", "Common", "type", "processor", "area", "definition", "state", "getLogger", "Colors", "_a", "ContactController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "DimmerController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "FanController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "speed", "__spreadProps", "equals", "value", "import_colors", "import_hap_device", "KeypadController", "Common", "processor", "area", "device", "groups", "__async", "_a", "i", "j", "button", "definition", "status", "error", "Colors", "import_colors", "import_hap_device", "ButtonMap", "import_hap_device", "import_event_emitter", "TriggerController", "processor", "button", "index", "options", "__spreadValues", "status", "longPressTimeoutHandler", "doublePressTimeoutHandler", "RemoteController", "Common", "processor", "area", "device", "groups", "__async", "_a", "_b", "_c", "map", "ButtonMap", "i", "j", "button", "mapped", "index", "raiseLower", "trigger", "TriggerController", "status", "error", "Colors", "import_deep_equal", "import_hap_device", "OccupancyController", "Common", "processor", "area", "device", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "ShadeController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "waits", "import_deep_equal", "import_hap_device", "StripController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "SwitchController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "__spreadProps", "equals", "import_deep_equal", "import_hap_device", "TimeclockController", "Common", "processor", "area", "device", "status", "previous", "__spreadValues", "__spreadProps", "equals", "import_hap_device", "UnknownController", "Common", "processor", "area", "zone", "createDevice", "processor", "area", "definition", "_a", "parseDeviceType", "ContactController", "DimmerController", "FanController", "KeypadController", "OccupancyController", "RemoteController", "ShadeController", "StripController", "SwitchController", "TimeclockController", "UnknownController", "value", "isAddressable", "device", "log", "message", "PROBE_URLS", "summarizeBody", "body", "first", "keys", "areaPath", "areas", "href", "_a", "byHref", "a", "names", "current", "seen", "area", "probeProcessorMetadata", "processor", "__async", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "path", "zones", "zone", "error", "stations", "station", "ganged", "g", "url", "device", "withPath", "log", "getLogger", "RETRY_BACKOFF_DURATION", "Client", "refresh", "_a", "_b", "host", "addrs", "a", "ip", "address", "processor", "ProcessorController", "Connection", "Colors", "system", "project", "areas", "version", "type", "waits", "statuses", "status", "device", "error", "occupancy", "area", "resolve", "__async", "devices", "ready", "count", "zone", "probeProcessorMetadata", "state", "button", "action", "message", "Context", "Discovery", "paired", "id", "byHref", "names", "current", "seen", "node", "__spreadProps", "__spreadValues", "areaWithPath", "zones", "createDevice", "timeclocks", "timeclock", "controls", "control", "positions", "position", "parseDeviceType", "gangedDevice", "results", "result", "isAddressable", "value", "connect", "refresh", "Client", "pair", "resolve", "reject", "discovery", "Discovery", "context", "Context", "processor", "Association", "certificate", "error"]
|
|
4
|
+
"sourcesContent": ["/**\n * Publishes devices, states and actions to an event emitter using the Lutron\n * LEAP protocol.\n *\n * @remarks\n * This will autopmatically discover processors. You will need to press the\n * pairing button on your processor or bridge.\n *\n * @packageDocumentation\n */\n\nimport { Association } from \"./Connection/Association\";\nimport { Context } from \"./Connection/Context\";\nimport { Discovery } from \"./Connection/Discovery\";\nimport { Client } from \"./Client\";\n\nexport { Contact } from \"./Devices/Contact/Contact\";\nexport { ContactState } from \"./Devices/Contact/ContactState\";\nexport { Dimmer } from \"./Devices/Dimmer/Dimmer\";\nexport { DimmerState } from \"./Devices/Dimmer/DimmerState\";\nexport { Fan } from \"./Devices/Fan/Fan\";\nexport { FanState } from \"./Devices/Fan/FanState\";\nexport { Keypad } from \"./Devices/Keypad/Keypad\";\nexport { KeypadState } from \"./Devices/Keypad/KeypadState\";\nexport { Occupancy } from \"./Devices/Occupancy/Occupancy\";\nexport { OccupancyState } from \"./Devices/Occupancy/OccupancyState\";\nexport { Remote } from \"./Devices/Remote/Remote\";\nexport { Shade } from \"./Devices/Shade/Shade\";\nexport { ShadeState } from \"./Devices/Shade/ShadeState\";\nexport { Strip } from \"./Devices/Strip/Strip\";\nexport { StripState } from \"./Devices/Strip/StripState\";\nexport { Switch } from \"./Devices/Switch/Switch\";\nexport { SwitchState } from \"./Devices/Switch/SwitchState\";\nexport { Timeclock } from \"./Devices/Timeclock/Timeclock\";\nexport { TimeclockState } from \"./Devices/Timeclock/TimeclockState\";\nexport { Unknown } from \"./Devices/Unknown/Unknown\";\n\n/**\n * Establishes a connection to all paired devices.\n *\n * @param refresh (optional) Setting this to true will not load devices from\n * cache.\n *\n * @returns A reference to the location with all processors.\n * @public\n */\nexport function connect(refresh?: boolean): Client {\n return new Client(refresh);\n}\n\n/**\n * Starts listening for pairing commands from processors.\n * @public\n */\nexport function pair(): Promise<void> {\n return new Promise((resolve, reject) => {\n const discovery = new Discovery();\n const context = new Context();\n\n discovery.on(\"Discovered\", (processor) => {\n if (context.get(processor.id) == null) {\n const association = new Association(processor);\n\n association\n .authenticate()\n .then((certificate) => {\n context.set(processor, certificate);\n\n resolve();\n })\n .catch((error) => reject(error))\n .finally(() => discovery.stop());\n }\n });\n\n discovery.search();\n });\n}\n\nexport { Client };\n", "import { pki } from \"node-forge\";\nimport { HostAddressFamily } from \"@mkellsy/hap-device\";\n\nimport { Certificate } from \"../Response/Certificate\";\nimport { CertificateRequest } from \"../Response/CertificateRequest\";\nimport { Connection } from \"./Connection\";\nimport { ProcessorAddress } from \"../Response/ProcessorAddress\";\n\n/**\n * Defines the logic for pairing a processor to this device.\n * @private\n */\nexport class Association {\n private connection: Connection;\n\n /**\n * Creates an association to a processor (pairing).\n *\n * @param processor The processor to pair.\n */\n constructor(processor: ProcessorAddress) {\n const ip =\n processor.addresses.find((address) => {\n return address.family === HostAddressFamily.IPv4;\n }) || processor.addresses[0];\n\n this.connection = new Connection(ip.address);\n }\n\n /**\n * Authenticate with the processor. This listens for when the pairing\n * button is pressed on the physical processor.\n *\n * @returns An authentication certificate.\n */\n public async authenticate(): Promise<Certificate> {\n return new Promise((resolve, reject) => {\n this.connection\n .connect()\n .then(() => {\n this.createCertificateRequest(\"mkellsy-mqtt-lutron\")\n .then((request) => {\n this.connection\n .authenticate(request)\n .then((certificate) => resolve(certificate))\n .catch((error) => reject(error));\n })\n .catch((error) => reject(error));\n })\n .catch((error) => reject(error));\n });\n }\n\n /*\n * Creates a certificate reqquest.\n */\n private createCertificateRequest(name: string): Promise<CertificateRequest> {\n return new Promise((resolve, reject) => {\n pki.rsa.generateKeyPair({ bits: 2048 }, (error, keys) => {\n if (error == null) {\n const request = pki.createCertificationRequest();\n\n request.publicKey = keys.publicKey;\n request.setSubject([{ name: \"commonName\", value: name }]);\n request.sign(keys.privateKey);\n\n return resolve({\n key: keys.privateKey,\n cert: pki.certificationRequestToPem(request),\n });\n }\n\n return reject(new Error(\"Error generating RSA keys\"));\n });\n });\n }\n}\n", "import fs from \"fs\";\nimport path from \"path\";\nimport net from \"net\";\n\nimport { BSON } from \"bson\";\nimport { get as getLogger } from \"js-logger\";\nimport { pki } from \"node-forge\";\nimport { v4 } from \"uuid\";\n\nimport { Authentication } from \"../Response/Authentication\";\nimport { Parser } from \"../Response/Parser\";\nimport { Certificate } from \"../Response/Certificate\";\nimport { CertificateRequest } from \"../Response/CertificateRequest\";\nimport { ExceptionDetail } from \"../Response/ExceptionDetail\";\nimport { InflightMessage } from \"../Response/InflightMessage\";\nimport { Message } from \"../Response/Message\";\nimport { PhysicalAccess } from \"../Response/PhysicalAccess\";\nimport { Response } from \"../Response/Response\";\nimport { RequestType } from \"../Response/RequestType\";\nimport { Socket } from \"./Socket\";\nimport { Subscription } from \"../Response/Subscription\";\n\nconst log = getLogger(\"Connection\");\n\nconst SOCKET_PORT = 8083;\nconst SECURE_SOCKET_PORT = 8081;\nconst REACHABLE_TIMEOUT = 1_000;\n\n/**\n * Connects to a device with the provided secure host.\n * @private\n */\nexport class Connection extends Parser<{\n Connect: (protocol: string) => void;\n Disconnect: () => void;\n Response: (response: Response) => void;\n Message: (response: Response) => void;\n Error: (error: Error) => void;\n}> {\n private socket?: Socket;\n private secure: boolean = false;\n private teardown: boolean = false;\n\n private host: string;\n private certificate: Certificate;\n\n private requests: Map<string, InflightMessage> = new Map();\n private subscriptions: Map<string, Subscription> = new Map();\n\n /**\n * Creates a new connection to a device.\n *\n * ```js\n * const connection = new Connection(\"192.168.1.1\", { ca, key, cert });\n * ```\n *\n * @param host The ip address of the device.\n * @param certificate Authentication certificate.\n */\n constructor(host: string, certificate?: Certificate) {\n super();\n\n this.host = host;\n this.secure = certificate != null;\n\n this.certificate = {\n ca: \"\",\n cert: \"\",\n key: \"\",\n ...(certificate != null ? certificate : this.authorityCertificate()),\n };\n }\n\n /**\n * Detects if a host is reachable.\n *\n * @param host Address of the device.\n *\n * @returns True if the device is rechable, false if not.\n */\n public static reachable(host: string): Promise<boolean> {\n return new Promise((resolve) => {\n const socket = new net.Socket();\n\n const response = (success: boolean) => {\n socket.destroy();\n\n resolve(success);\n };\n\n socket.setTimeout(REACHABLE_TIMEOUT);\n\n socket.once(\"error\", () => response(false));\n socket.once(\"timeout\", () => response(false));\n\n socket.connect(SOCKET_PORT, host, () => response(true));\n });\n }\n\n /**\n * Asyncronously connects to a device.\n *\n * ```js\n * await connection.connect();\n * ```\n */\n public connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.teardown = false;\n this.socket = undefined;\n\n const port = this.secure ? SECURE_SOCKET_PORT : SOCKET_PORT;\n const subscriptions = [...this.subscriptions.values()];\n const socket = new Socket(this.host, port, this.certificate);\n\n log.info(`connect ${this.host}:${port} secure=${this.secure} pendingSubscriptions=${subscriptions.length}`);\n\n socket.on(\"Data\", this.onSocketData);\n socket.on(\"Error\", this.onSocketError);\n socket.on(\"Disconnect\", this.onSocketDisconnect);\n\n socket\n .connect()\n .then((protocol) => {\n log.info(\n `socket up ${this.host}:${port} protocol=${protocol}; physicalAccess secure=${this.secure}`,\n );\n\n this.physicalAccess(this.secure)\n .then(() => {\n const waits: Promise<void>[] = [];\n\n this.subscriptions.clear();\n this.socket = socket;\n\n if (this.secure) {\n for (const subscription of subscriptions) {\n /* istanbul ignore next */\n waits.push(this.subscribe(subscription.url, subscription.listener));\n }\n }\n\n Promise.all(waits)\n .then(() => {\n log.info(`emit Connect ${this.host} protocol=${protocol}`);\n this.emit(\"Connect\", protocol);\n\n resolve();\n })\n .catch((error) => {\n log.error(\n `resubscribe failed ${this.host}: ${error instanceof Error ? error.message : String(error)}`,\n );\n reject(error);\n });\n })\n .catch((error) => {\n log.error(\n `physicalAccess failed ${this.host}: ${error instanceof Error ? error.message : String(error)}`,\n );\n reject(error);\n });\n })\n .catch((error) => {\n log.error(\n `socket connect failed ${this.host}:${port}: ${error instanceof Error ? error.message : String(error)}`,\n );\n reject(error);\n });\n });\n }\n\n /**\n * Disconnects from a device.\n *\n * ```js\n * connection.disconnect();\n * ```\n */\n public disconnect() {\n this.teardown = true;\n\n if (this.secure) this.drainRequests();\n\n this.subscriptions.clear();\n this.socket?.disconnect();\n }\n\n /**\n * Fetches a record from the device. Not this only works for a secure\n * connections.\n *\n * ```js\n * const record = await connection.read<Zone>(\"/zone/123456\");\n * ```\n *\n * @param url The url of the record, this is typically a device address.\n *\n * @returns A payload or rejects. The payload is typed per call.\n */\n public read<T>(url: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const tag = v4();\n\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n this.sendRequest(tag, \"ReadRequest\", url)\n .then((response) => {\n const body = response.Body as T;\n const bodyType = response.Header?.MessageBodyType;\n\n if (body == null) {\n log.info(`read ${url} -> empty body status=${response.Header?.StatusCode || \"?\"}`);\n return reject(new Error(`${url} no body`));\n }\n\n // ExceptionDetail is unwrapped by Response.parse() to the Message string,\n // so instanceof ExceptionDetail only works for manually constructed bodies.\n if (bodyType === \"ExceptionDetail\" || response.Body instanceof ExceptionDetail) {\n const message =\n response.Body instanceof ExceptionDetail\n ? response.Body.Message\n : typeof response.Body === \"string\"\n ? response.Body\n : \"Unknown exception\";\n\n log.info(`read ${url} -> exception: ${message}`);\n return reject(new Error(message));\n }\n\n const kind = Array.isArray(body)\n ? `array(${(body as unknown[]).length})`\n : typeof body === \"object\"\n ? `object(${Object.keys(body as object)\n .slice(0, 12)\n .join(\",\")})`\n : typeof body;\n\n log.debug(`read ${url} -> ok ${kind}`);\n\n return resolve(response.Body as T);\n })\n .catch((error) => {\n log.info(`read ${url} -> fail: ${error instanceof Error ? error.message : String(error)}`);\n reject(error);\n });\n });\n }\n\n /**\n * This sends an authentication request. This only works for non-secure\n * connections.\n *\n * ```js\n * const certificate = await connection.authenticate(csr);\n * ```\n *\n * @param csr Sends a certificate request, typically created with open ssl.\n *\n * @returns An authentication certificate or rejects if failed.\n */\n public authenticate(csr: CertificateRequest): Promise<Certificate> {\n return new Promise((resolve, reject) => {\n if (this.secure) return reject(new Error(\"Only available for physical connections\"));\n\n const message = {\n Header: {\n RequestType: \"Execute\",\n Url: \"/pair\",\n ClientTag: \"get-cert\",\n },\n Body: {\n CommandType: \"CSR\",\n Parameters: {\n CSR: csr.cert,\n DisplayName: \"get_lutron_cert.py\",\n DeviceUID: \"000000000000\",\n Role: \"Admin\",\n },\n },\n };\n\n /*\n * Real clocks are required for proper socket testing, this\n * requires a fake clock or unit test timeout extention. Excluding\n * this to speedup build times.\n */\n\n /* istanbul ignore next */\n const timeout = setTimeout(() => reject(new Error(\"Authentication timeout exceeded\")), 5_000);\n\n this.once(\"Message\", (response: Response) => {\n clearTimeout(timeout);\n\n resolve({\n ca: (response.Body as Authentication).SigningResult.RootCertificate,\n cert: (response.Body as Authentication).SigningResult.Certificate,\n key: pki.privateKeyToPem(csr.key),\n });\n });\n\n /* istanbul ignore next */\n this.socket?.write(message);\n });\n }\n\n /**\n * Sends a commend to update a device. This only works for secure\n * connections.\n *\n * ```js\n * await connection.update(\"/zone/123456\", state);\n * ```\n *\n * @param url A command url typically the href of a device.\n * @param body An object of values to update.\n *\n * @returns Returns a status paylod. The type is set per call.\n */\n public update<T>(url: string, body: Record<string, unknown>): Promise<T> {\n return new Promise((resolve, reject) => {\n const tag = v4();\n\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n this.sendRequest(tag, \"UpdateRequest\", url, body)\n .then((response) => {\n if (response.Body instanceof ExceptionDetail) {\n return reject(new Error(response.Body.Message));\n }\n\n return resolve(response.Body as T);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Sends a known command to the device. This only works for secure\n * connections.\n *\n * ```js\n * await connection.command(\"/zone/123456\", command);\n * ```\n *\n * @param url A command url typically the href of a device.\n * @param command A known command object.\n */\n public command(url: string, command: Record<string, unknown>): Promise<void> {\n return new Promise((resolve, reject) => {\n const tag = v4();\n\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n this.sendRequest(tag, \"CreateRequest\", url, command)\n .then(() => resolve())\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Subscribes to a record on the device. This will bind a listener to that\n * record that will get called every time the record changes. This is\n * helpful for keeping track of the status of an area, zone, or device.\n * This only works for secure connections.\n *\n * ```js\n * connection.subscribe(\"/zone/123456/status\", (response) => { });\n * ```\n *\n * @param url Url to subscribe to.\n * @param listener Callback to run when the record updates.\n */\n public subscribe<T>(url: string, listener: (response: T) => void): Promise<void> {\n return new Promise((resolve, reject) => {\n if (!this.secure) return reject(new Error(\"Only available for secure connections\"));\n\n const tag = v4();\n\n this.sendRequest(tag, \"SubscribeRequest\", url)\n .then((response: Response) => {\n if (response.Header.StatusCode != null && response.Header.StatusCode.isSuccessful()) {\n this.subscriptions.set(tag, {\n url,\n listener,\n callback: (response: Response) => listener(response.Body as T),\n });\n }\n\n resolve();\n })\n .catch((error) => reject(error));\n });\n }\n\n /*\n * Clears any ongoing commands. This will cancel all incomplete and failed\n * connections.\n */\n private drainRequests(): void {\n /*\n * Draining requests is incredibly difficult to test. This requires\n * very randon chunks that depend on network conditions. Testing this\n * functionallity is best suited for the buffered responce object.\n */\n\n /* istanbul ignore next */\n for (const tag of this.requests.keys()) {\n const request = this.requests.get(tag)!;\n\n clearTimeout(request.timeout);\n }\n\n this.requests.clear();\n }\n\n /*\n * Internally sends read, update, and command requests.\n */\n private sendRequest(\n tag: string,\n requestType: RequestType,\n url: string,\n body?: Record<string, unknown>,\n ): Promise<Response> {\n return new Promise((resolve, reject) => {\n /*\n * Testing tag reuse is difficult when mocking payloads. Tagged\n * payloads are transparent past this stage, and unit tests are\n * unable to pause the fulfillment.\n */\n\n /* istanbul ignore next */\n if (this.requests.has(tag)) {\n const request = this.requests.get(tag)!;\n\n request.reject(new Error(`tag \"${tag}\" reused`));\n\n clearTimeout(request.timeout);\n\n this.requests.delete(tag);\n }\n\n const message: Message = {\n CommuniqueType: requestType,\n Header: {\n ClientTag: tag!,\n Url: url,\n },\n Body: body,\n };\n\n /* istanbul ignore next */\n if (this.socket == null) return reject(new Error(\"Connection not established\"));\n\n this.socket\n .write(message)\n .then(() => {\n this.requests.set(tag!, {\n message,\n resolve,\n reject,\n timeout: setTimeout(\n /* istanbul ignore next */\n () => {\n // Reject on timeout \u2014 never resolve with a fake ExceptionDetail body.\n // Response.parse() unwraps { Message: \"...\" } to a bare string, which\n // used to be treated as a successful read and permanently cached.\n this.requests.delete(tag!);\n reject(new Error(\"Request timeout\"));\n },\n 15_000,\n ),\n });\n })\n .catch((error) => reject(error));\n });\n }\n\n /*\n * Listener for taged responses from the device.\n */\n private onResponse = (response: Response): void => {\n const tag = response.Header.ClientTag;\n\n if (tag == null) {\n this.emit(\"Message\", response);\n\n return;\n }\n\n const request = this.requests.get(tag)!;\n\n if (request != null) {\n clearTimeout(request.timeout);\n\n this.requests.delete(tag);\n request.resolve(response);\n }\n\n const subscription = this.subscriptions.get(tag);\n\n if (subscription == null) return;\n\n subscription.callback(response);\n };\n\n /*\n * Handles all data recieved from a device.\n */\n private onSocketData = (data: Buffer): void => {\n if (this.secure) {\n this.parse(data, this.onResponse);\n } else {\n this.emit(\"Message\", JSON.parse(data.toString()));\n }\n };\n\n /*\n * Listener for any socket disconnects. This will teardown the failed\n * connection and will attempt to reconnect, unless a discrete disconnect\n * is invoked.\n */\n private onSocketDisconnect = (): void => {\n if (!this.teardown) this.emit(\"Disconnect\");\n };\n\n /*\n * Listener for any error from the socket.\n */\n private onSocketError = (error: Error): void => {\n this.emit(\"Error\", error);\n };\n\n /*\n * Loads a saved device certificate. Certificates are created when a\n * processor is paired with this device.\n */\n private authorityCertificate(): Certificate | null {\n const filename = path.resolve(__dirname, \"../authority\");\n\n if (fs.existsSync(filename)) {\n const bytes = fs.readFileSync(filename);\n\n if (bytes == null) return null;\n\n const certificate = BSON.deserialize(bytes) as Certificate;\n\n certificate.ca = Buffer.from(certificate.ca, \"base64\").toString(\"utf8\");\n certificate.key = Buffer.from(certificate.key, \"base64\").toString(\"utf8\");\n certificate.cert = Buffer.from(certificate.cert, \"base64\").toString(\"utf8\");\n\n return certificate;\n }\n\n return null;\n }\n\n /*\n * For non-secure connections, this will wait for a processor to enter\n * pairing mode. This requires a button press on the physical processor.\n */\n private physicalAccess(secure: boolean): Promise<void> {\n return new Promise((resolve, reject) => {\n if (secure) return resolve();\n\n /*\n * Testing processor errors and physical button press timeout is\n * not feasible for unit tests. This functionallity is best tested\n * manually with access to the processor.\n */\n\n /* istanbul ignore next */\n const timeout = setTimeout(() => reject(new Error(\"Physical timeout exceeded\")), 60_000);\n\n this.once(\"Message\", (response: Response) => {\n /* istanbul ignore else */\n if ((response.Body as PhysicalAccess).Status.Permissions.includes(\"PhysicalAccess\")) {\n clearTimeout(timeout);\n\n return resolve();\n }\n\n /* istanbul ignore next */\n return reject(new Error(\"Unknown pairing error\"));\n });\n });\n }\n}\n", "import { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { Response } from \"./Response\";\n\n/**\n * Enables response buffering.\n * @private\n */\nexport class Parser<MAP extends { [key: string]: (...args: any[]) => void }> extends EventEmitter<MAP> {\n private buffer: string = \"\";\n\n /**\n * Parses a raw response, and returns via a callback.\n *\n * @param data Raw socket buffer.\n * @param callback Listener for complete response.\n */\n public parse(data: Buffer, callback: (response: Response) => void): void {\n const response = this.buffer + data.toString();\n const lines: string[] = response.split(/\\r?\\n/);\n\n if (lines.length - 1 === 0) {\n this.buffer = response;\n\n return;\n }\n\n this.buffer = lines[lines.length - 1] || \"\";\n\n for (const line of lines.slice(0, lines.length - 1)) {\n callback(Response.parse(line));\n }\n }\n}\n", "import { MessageType } from \"./MessageType\";\nimport { ResponseStatus } from \"./ResponseStatus\";\n\n/**\n * Creates a response header object.\n * @private\n */\nexport class ResponseHeader {\n public StatusCode?: ResponseStatus;\n public Url?: string;\n public MessageBodyType?: MessageType;\n public ClientTag?: string;\n}\n", "/**\n * Creates a response status object.\n * @private\n */\nexport class ResponseStatus {\n /**\n * Status message\n */\n public message?: string;\n\n /**\n * Status code\n */\n public code?: number;\n\n /**\n * Creates a response status object.\n *\n * @param message Complete response.\n * @param code Response code from the message.\n */\n constructor(message?: string, code?: number) {\n this.message = message;\n this.code = code;\n }\n\n /**\n * Creates a response status object from a string.\n *\n * @param value Status string.\n *\n * @returns A response status object.\n */\n static fromString(value?: string): ResponseStatus {\n const parts = value?.split(\" \", 2);\n\n if (parts == null || parts.length === 1) {\n return new ResponseStatus(value);\n }\n\n const code = parseInt(parts[0], 10);\n\n if (Number.isNaN(code)) {\n return new ResponseStatus(value);\n }\n\n return new ResponseStatus(parts[1], code);\n }\n\n /**\n * Is the status successful.\n *\n * @returns True if successful, false if not.\n */\n public isSuccessful(): boolean {\n return this.code !== undefined && this.code >= 200 && this.code < 300;\n }\n}\n", "import * as Body from \"./BodyType\";\n\nimport { RequestType } from \"./RequestType\";\nimport { MessageType } from \"./MessageType\";\nimport { ResponseHeader } from \"./ResponseHeader\";\nimport { ResponseStatus } from \"./ResponseStatus\";\n\n/**\n * Defines a processor response.\n * @private\n */\nexport class Response {\n public CommuniqueType?: RequestType;\n public Body?: Body.BodyType;\n public Header: ResponseHeader;\n\n /**\n * Creates a new response object.\n */\n constructor() {\n this.Header = new ResponseHeader();\n }\n\n /**\n * Parses complete responses to a response object.\n *\n * @param value The assembled response.\n *\n * @returns Returns a response object.\n */\n static parse(value: string): Response {\n const payload = JSON.parse(value);\n\n const status =\n payload.Header.StatusCode == null ? undefined : ResponseStatus.fromString(payload.Header.StatusCode);\n\n const header: ResponseHeader = Object.assign({}, payload.Header, {\n StatusCode: status,\n MessageBodyType: payload.Header.MessageBodyType as MessageType,\n });\n\n if (header.MessageBodyType == null) {\n return Object.assign(new Response(), { Header: header });\n }\n\n const key = Object.keys(payload.Body || {})[0];\n const body = key != null ? payload.Body[key] || undefined : undefined;\n\n return Object.assign(new Response(), payload, { Header: header, Body: body });\n }\n}\n", "/**\n * Exception response.\n * @private\n */\nexport class ExceptionDetail {\n /**\n * Responce message.\n */\n Message = \"\";\n}\n", "import { EventEmitter } from \"@mkellsy/event-emitter\";\nimport { get as getLogger } from \"js-logger\";\nimport { connect, createSecureContext, TLSSocket } from \"tls\";\n\nimport { Certificate } from \"../Response/Certificate\";\nimport { Message } from \"../Response/Message\";\n\nconst log = getLogger(\"Socket\");\n\nconst KEEPALIVE_INITIAL_DELAY = 10_000;\nconst INACTIVITY_TIMEOUT = 30_000;\n\n/**\n * Creates a connections underlying socket.\n * @private\n */\nexport class Socket extends EventEmitter<{\n Error: (error: Error) => void;\n Data: (data: Buffer) => void;\n Disconnect: () => void;\n}> {\n private connection?: TLSSocket;\n\n private readonly host: string;\n private readonly port: number;\n private readonly certificate: Certificate;\n\n /**\n * Creates a socket.\n *\n * @param host The IP address of the device.\n * @param port The port the device listenes on.\n * @param certificate An authentication certificate.\n */\n constructor(host: string, port: number, certificate: Certificate) {\n super();\n\n this.host = host;\n this.port = port;\n this.certificate = certificate;\n }\n\n /**\n * Establishes a connection to the device.\n *\n * @returns A connection protocol.\n */\n public connect(): Promise<string> {\n return new Promise((resolve, reject) => {\n log.info(`TLS connect ${this.host}:${this.port}`);\n\n const connection = connect(this.port, this.host, {\n secureContext: createSecureContext(this.certificate),\n secureProtocol: \"TLS_method\",\n rejectUnauthorized: false,\n });\n\n connection.once(\"secureConnect\", (): void => {\n this.connection = connection;\n\n this.connection.off(\"error\", reject);\n\n this.connection.on(\"timeout\", this.onSocketTimeout);\n this.connection.on(\"error\", this.onSocketError);\n this.connection.on(\"close\", this.onSocketClose);\n this.connection.on(\"data\", this.onSocketData);\n\n this.connection.setKeepAlive(true, KEEPALIVE_INITIAL_DELAY);\n this.connection.setTimeout(INACTIVITY_TIMEOUT);\n\n const protocol = this.connection.getProtocol() || \"Unknown\";\n\n log.info(`TLS secureConnect ${this.host}:${this.port} protocol=${protocol}`);\n resolve(protocol);\n });\n\n connection.once(\"error\", (error) => {\n log.error(`TLS connect error ${this.host}:${this.port}: ${error.message}`);\n reject(error);\n });\n });\n }\n\n /**\n * Disconnects from a device.\n */\n public disconnect(): void {\n this.connection?.end();\n this.connection?.destroy();\n }\n\n /**\n * Writes a message to the connection.\n *\n * @param message A message to write.\n */\n public write(message: Message): Promise<void> {\n return new Promise((resolve, reject) => {\n if (this.connection == null) return reject(new Error(\"connection not established\"));\n\n this.connection.write(`${JSON.stringify(message)}\\n`, (error) => {\n if (error != null) return reject(error);\n\n return resolve();\n });\n });\n }\n\n /*\n * Listens for data from the socket.\n */\n private onSocketData = (data: Buffer): void => {\n this.emit(\"Data\", data);\n };\n\n /*\n * Listens for socket timeouts.\n */\n private onSocketTimeout = (): void => {\n log.warn(`TLS inactivity timeout ${this.host}:${this.port} (${INACTIVITY_TIMEOUT}ms)`);\n this.emit(\"Error\", new Error(\"connect ETIMEDOUT\"));\n };\n\n /*\n * Listenes for discrete disconects from the socket.\n */\n private onSocketClose = (): void => {\n log.info(`TLS close ${this.host}:${this.port}`);\n this.emit(\"Disconnect\");\n };\n\n /*\n * Listenes for any errors from the socket. This will filter out any socket\n */\n private onSocketError = (error: Error): void => {\n log.error(`TLS error ${this.host}:${this.port}: ${error.message}`);\n this.emit(\"Error\", error);\n };\n}\n", "import fs from \"fs\";\nimport path from \"path\";\nimport os from \"os\";\n\nimport { BSON } from \"bson\";\nimport { get as getLogger } from \"js-logger\";\n\nimport { Certificate } from \"../Response/Certificate\";\nimport { ProcessorAddress } from \"../Response/ProcessorAddress\";\n\nconst log = getLogger(\"Context\");\n\n/**\n * Defines an authentication context and state for a processor.\n * @private\n */\nexport class Context {\n private context: Record<string, Certificate> = {};\n\n /**\n * Create an authentication context, and load any cached certificates. This\n * ensures that processors can be paired with device, and authentication\n * only happens once.\n */\n constructor() {\n try {\n const context = this.open<Record<string, Certificate>>(\"pairing\") || {};\n const keys = Object.keys(context);\n\n for (let i = 0; i < keys.length; i++) {\n context[keys[i]] = this.decrypt(context[keys[i]])!;\n }\n\n this.context = context;\n\n const processors = this.processors;\n\n log.info(`pairing loaded: ${processors.length} processor(s) [${processors.join(\", \") || \"none\"}]`);\n } catch (error) {\n log.error(\n `failed to load pairing from ~/.leap/pairing: ${error instanceof Error ? error.message : String(error)}`,\n );\n this.context = {};\n }\n }\n\n /**\n * A list of processor ids currently paired.\n *\n * @returns A string array of processor ids.\n */\n public get processors(): string[] {\n return Object.keys(this.context).filter((key) => key !== \"authority\");\n }\n\n /**\n * Check to see if the context has a processor paired.\n *\n * @param id The processor id to check.\n *\n * @returns True if paired, false if not.\n */\n public has(id: string): boolean {\n return this.context[id] != null;\n }\n\n /**\n * Fetches the authentication certificate for a processor.\n *\n * @param id The processor id to fetch.\n *\n * @returns An authentication certificate or undefined if it doesn't exist.\n */\n public get(id: string): Certificate | undefined {\n return this.context[id];\n }\n\n /**\n * Adds a processor authentication certificate to the context.\n *\n * @param processor The processor address object to add.\n * @param context The authentication certificate to associate.\n */\n public set(processor: ProcessorAddress, context: Certificate): void {\n this.context[processor.id] = { ...context };\n this.save(\"pairing\", this.context);\n }\n\n /*\n * Decrypts an authentication certificate.\n */\n private decrypt(context: Certificate | null): Certificate | null {\n if (context == null) return null;\n\n context.ca = Buffer.from(context.ca, \"base64\").toString(\"utf8\");\n context.key = Buffer.from(context.key, \"base64\").toString(\"utf8\");\n context.cert = Buffer.from(context.cert, \"base64\").toString(\"utf8\");\n\n return context;\n }\n\n /*\n * Encrypts a certificate for storage. This ensures security at rest.\n */\n private encrypt(context: Certificate | null): Certificate | null {\n if (context == null) return null;\n\n context.ca = Buffer.from(context.ca).toString(\"base64\");\n context.key = Buffer.from(context.key).toString(\"base64\");\n context.cert = Buffer.from(context.cert).toString(\"base64\");\n\n return context;\n }\n\n /*\n * Opens the context storage and loads paired processors.\n */\n private open<T>(filename: string): T | null {\n const directory = path.join(os.homedir(), \".leap\");\n const filePath = path.join(directory, filename);\n\n if (!fs.existsSync(directory)) fs.mkdirSync(directory);\n\n if (fs.existsSync(filePath)) {\n const bytes = fs.readFileSync(filePath);\n const size = bytes != null && typeof (bytes as Buffer).length === \"number\" ? (bytes as Buffer).length : 0;\n\n log.info(`opened ${filePath} (${size} bytes)`);\n\n return BSON.deserialize(bytes) as T;\n }\n\n log.warn(`missing pairing file: ${filePath}`);\n\n return null;\n }\n\n /*\n * Saves the context to storage.\n */\n private save(filename: string, context: Record<string, Certificate>): void {\n const directory = path.join(os.homedir(), \".leap\");\n\n if (!fs.existsSync(directory)) fs.mkdirSync(directory);\n\n const clear = { ...context };\n const keys = Object.keys(clear);\n\n for (let i = 0; i < keys.length; i++) {\n clear[keys[i]] = this.encrypt(clear[keys[i]])!;\n }\n\n fs.writeFileSync(path.join(directory, filename), BSON.serialize(clear));\n }\n}\n", "import os from \"os\";\nimport path from \"path\";\nimport equals from \"deep-equal\";\n\nimport Cache from \"flat-cache\";\nimport { get as getLogger } from \"js-logger\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\nimport { MDNSService, MDNSServiceDiscovery, Protocol } from \"tinkerhub-mdns\";\nimport { HostAddress, HostAddressFamily } from \"@mkellsy/hap-device\";\n\nimport { ProcessorAddress } from \"../Response/ProcessorAddress\";\n\nconst log = getLogger(\"Discovery\");\n\n/**\n * Creates and searches the network for devices.\n * @private\n */\nexport class Discovery extends EventEmitter<{\n Discovered: (processor: ProcessorAddress) => void;\n Failed: (error: Error) => void;\n}> {\n private cache: Cache.Cache;\n private cached: ProcessorAddress[];\n private discovery?: MDNSServiceDiscovery;\n\n /**\n * Creates a mDNS discovery object used to search the network for devices.\n *\n * ```js\n * const discovery = new Discovery();\n *\n * discovery.on(\"Discovered\", (device: ProcessorAddress) => { });\n * discovery.search()\n * ```\n */\n constructor() {\n super();\n\n this.cache = Cache.load(\"discovery\", path.join(os.homedir(), \".leap\"));\n this.cached = this.cache.getKey(\"/hosts\") || [];\n\n this.cache.setKey(\"/hosts\", this.cached);\n this.cache.save(true);\n }\n\n /**\n * Starts searching the network for devices.\n */\n public search(): void {\n this.stop();\n\n log.info(`search start: ${this.cached.length} cached host(s)`);\n\n for (let i = 0; i < this.cached.length; i++) {\n const host = this.cached[i];\n const addrs = (host.addresses || []).map((a) => a.address).join(\",\");\n\n log.info(`emit cached host id=${host.id} type=${host.type} addresses=[${addrs}]`);\n this.emit(\"Discovered\", host);\n }\n\n this.discovery = new MDNSServiceDiscovery({ type: \"lutron\", protocol: Protocol.TCP });\n this.discovery.onAvailable(this.onAvailable);\n log.info(\"mDNS browse started for _lutron._tcp\");\n }\n\n /**\n * Stops searching the network.\n */\n public stop(): void {\n this.discovery?.destroy();\n }\n\n /*\n * Parses a service once discovered. If it fits the criteria, this will\n * emit a discovered event.\n */\n private onAvailable = (service: MDNSService): void => {\n const systype = service.data.get(\"systype\");\n\n if (!this.isProcessorService(service)) {\n log.debug(`mDNS ignore service id=${service.id} systype=${String(systype)}`);\n return;\n }\n\n let host: ProcessorAddress;\n\n try {\n host = this.parseProcessorAddress(service);\n } catch (error) {\n log.error(\n `mDNS parse failed for service id=${service.id}: ${error instanceof Error ? error.message : String(error)}`,\n );\n return;\n }\n\n const addrs = (host.addresses || []).map((a) => a.address).join(\",\");\n const cached = this.isProcessorCached(host);\n\n log.info(`mDNS processor id=${host.id} type=${host.type} addresses=[${addrs}] cached=${cached}`);\n\n if (!cached) this.emit(\"Discovered\", host);\n\n this.cacheProcessor(host);\n };\n\n /*\n * Determines if a processor host is currently cached.\n */\n private isProcessorCached(host: ProcessorAddress): boolean {\n return this.cached.find((entry) => equals(entry, host)) != null;\n }\n\n /*\n * Determines if a MDNS service is a processor.\n */\n private isProcessorService(service: MDNSService): boolean {\n const type = service.data.get(\"systype\");\n\n if (type == null || typeof type === \"boolean\") return false;\n\n return true;\n }\n\n /*\n * Saves a processor host to disk cache.\n */\n private cacheProcessor(host: ProcessorAddress): void {\n const index = this.cached.findIndex((entry) => entry.id === host.id);\n\n if (index >= 0) {\n this.cached[index] = host;\n } else {\n this.cached.push(host);\n }\n\n this.cache.setKey(\"/hosts\", this.cached);\n this.cache.save();\n }\n\n /*\n * Transforms a MDNS service to a processor host.\n */\n private parseProcessorAddress(service: MDNSService): ProcessorAddress {\n const target = (this.discovery as any).serviceData.get(service.id).SRV._record.target;\n const addresses: HostAddress[] = [];\n\n for (let i = 0; i < service.addresses?.length; i++) {\n addresses.push({\n address: service.addresses[i].host,\n family: /^([\\da-f]{1,4}:){7}[\\da-f]{1,4}$/i.test(service.addresses[i].host)\n ? HostAddressFamily.IPv6\n : HostAddressFamily.IPv4,\n });\n }\n\n return {\n id: target.match(/[Ll]utron-(?<id>\\w+)\\.local/)!.groups!.id.toUpperCase(),\n type: String(service.data.get(\"systype\")),\n addresses,\n };\n }\n}\n", "import { get as getLogger } from \"js-logger\";\n\nimport Colors from \"colors\";\n\nimport {\n Action,\n Address,\n AreaStatus,\n Button,\n Device,\n DeviceType,\n DeviceState,\n HostAddressFamily,\n TimeclockStatus,\n ZoneStatus,\n} from \"@mkellsy/hap-device\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { AreaAddress } from \"./Response/AreaAddress\";\nimport { Connection } from \"./Connection/Connection\";\nimport { Context } from \"./Connection/Context\";\nimport { ControlStation } from \"./Response/ControlStation\";\nimport { DeviceAddress } from \"./Response/DeviceAddress\";\nimport { Discovery } from \"./Connection/Discovery\";\nimport { Processor } from \"./Devices/Processor/Processor\";\nimport { ProcessorController } from \"./Devices/Processor/ProcessorController\";\nimport { ProcessorAddress } from \"./Response/ProcessorAddress\";\n\nimport { createDevice, isAddressable, parseDeviceType } from \"./Devices/Devices\";\nimport { probeProcessorMetadata } from \"./Connection/MetadataProbe\";\n\nconst log = getLogger(\"Client\");\n\nconst RETRY_BACKOFF_DURATION = 5_000;\n\n/**\n * Creates an object that represents a single location, with a single network.\n * @public\n */\nexport class Client extends EventEmitter<{\n Action: (device: Device, button: Button, action: Action) => void;\n Available: (devices: Device[]) => void;\n Message: (response: Response) => void;\n Update: (device: Device, state: DeviceState) => void;\n}> {\n private context: Context;\n private refresh: boolean;\n\n private discovery: Discovery;\n private discovered: Map<string, Processor> = new Map();\n private areaPaths: Map<string, string> = new Map();\n\n /**\n * Creates a location object and starts mDNS discovery.\n *\n * ```js\n * const location = new Client();\n *\n * location.on(\"Avaliable\", (devices: Device[]) => { });\n * ```\n *\n * @param refresh If true, this will ignore any cache and reload.\n */\n constructor(refresh?: boolean) {\n super(Infinity);\n\n this.context = new Context();\n this.discovery = new Discovery();\n this.refresh = refresh === true;\n\n const paired = this.context?.processors ?? [];\n\n log.info(`Client start refresh=${this.refresh} paired=[${paired.join(\", \") || \"none\"}]`);\n\n this.discovery.on(\"Discovered\", this.onDiscovered).search();\n }\n\n /**\n * A list of processors in this location.\n *\n * @returns A string array of processor ids.\n */\n public get processors(): string[] {\n return [...this.discovered.keys()];\n }\n\n /**\n * Fetch a processor from this location.\n *\n * @param id The processor id to fetch.\n *\n * @returns A processor object or undefined if it doesn't exist.\n */\n public processor(id: string): Processor | undefined {\n return this.discovered.get(id);\n }\n\n /**\n * Closes all connections for a location and stops searching.\n */\n public close(): void {\n this.discovery.stop();\n\n for (const processor of this.discovered.values()) {\n processor.disconnect();\n }\n\n this.discovered.clear();\n }\n\n /*\n * Builds \"House / Floor / Room\" paths for every area href.\n */\n private rebuildAreaPaths(areas: AreaAddress[]): void {\n const byHref = new Map(areas.map((area) => [area.href, area]));\n this.areaPaths.clear();\n\n for (const area of areas) {\n const names: string[] = [];\n let current: string | undefined = area.href;\n const seen = new Set<string>();\n\n while (current != null && !seen.has(current)) {\n seen.add(current);\n const node = byHref.get(current);\n\n if (node == null) break;\n\n names.unshift(node.Name);\n current = node.Parent?.href;\n }\n\n this.areaPaths.set(area.href, names.join(\" / \") || area.Name);\n }\n }\n\n /*\n * Annotates an area with its full hierarchy path for device constructors.\n */\n private withAreaPath(area: AreaAddress): AreaAddress & { Path: string } {\n return {\n ...area,\n Path: this.areaPaths.get(area.href) || area.Name,\n };\n }\n\n /*\n * Discovers all available zones on this processor. In other systems this\n * is the device.\n */\n private discoverZones(processor: Processor, area: AreaAddress): Promise<void> {\n return new Promise((resolve) => {\n if (!area.IsLeaf) return resolve();\n\n const areaWithPath = this.withAreaPath(area);\n\n processor\n .zones(area)\n .then((zones) => {\n for (const zone of zones) {\n const device = createDevice(processor, areaWithPath, zone)\n .on(\"Update\", this.onDeviceUpdate)\n .on(\"Action\", this.onDeviceAction);\n\n processor.devices.set(zone.href, device);\n }\n\n resolve();\n })\n .catch(() => resolve());\n });\n }\n\n /*\n * Discovers all available timeclocks. Timeclocks are schedules, and\n * sometimes are used as vurtual switches.\n */\n private discoverTimeclocks(processor: Processor): Promise<void> {\n return new Promise((resolve) => {\n processor\n .timeclocks()\n .then((timeclocks) => {\n for (const timeclock of timeclocks) {\n const device = createDevice(\n processor,\n {\n href: timeclock.href,\n Name: timeclock.Name,\n ControlType: \"Timeclock\",\n Parent: timeclock.Parent,\n IsLeaf: true,\n AssociatedZones: [],\n AssociatedControlStations: [],\n AssociatedOccupancyGroups: [],\n Path: timeclock.Name,\n } as AreaAddress & { Path: string },\n { ...timeclock, ControlType: \"Timeclock\" },\n ).on(\"Update\", this.onDeviceUpdate);\n\n processor.devices.set(timeclock.href, device);\n }\n\n resolve();\n })\n .catch(() => resolve());\n });\n }\n\n /*\n * Discovers all keypads and remotes. These are ganged devices.\n */\n private discoverControls(processor: Processor, area: AreaAddress): Promise<void> {\n return new Promise((resolve) => {\n if (!area.IsLeaf) return resolve();\n\n const areaWithPath = this.withAreaPath(area);\n\n processor\n .controls(area)\n .then(async (controls) => {\n if (controls == null || controls.length === 0) {\n return resolve();\n }\n\n // Wait for every control station \u2014 previously resolved after the first,\n // which dropped later Picos in multi-station rooms.\n await Promise.all(\n controls.map(async (control) => {\n const positions = await this.discoverPositions(processor, control);\n\n for (const position of positions) {\n const type = parseDeviceType(position.DeviceType);\n\n const address =\n type === DeviceType.Occupancy\n ? `/occupancy/${area.href?.split(\"/\")[2]}`\n : position.href;\n\n const device = createDevice(processor, areaWithPath, {\n ...position,\n Name: `${area.Name} ${control.Name} ${position.Name}`,\n })\n .on(\"Update\", this.onDeviceUpdate)\n .on(\"Action\", this.onDeviceAction);\n\n processor.devices.set(address, device);\n }\n }),\n );\n\n resolve();\n })\n .catch(() => resolve());\n });\n }\n\n /*\n * Discovers individual positions in a control station. Represents a single\n * keypad or remote in a gang.\n */\n private discoverPositions(processor: Processor, control: ControlStation): Promise<DeviceAddress[]> {\n return new Promise((resolve) => {\n if (control.AssociatedGangedDevices == null) return resolve([]);\n\n const waits: Promise<DeviceAddress>[] = [];\n\n for (const gangedDevice of control.AssociatedGangedDevices) {\n waits.push(processor.device(gangedDevice.Device));\n }\n\n // allSettled so one timed-out device does not drop the whole gang.\n Promise.allSettled(waits)\n .then((results) => {\n const positions: DeviceAddress[] = [];\n\n for (const result of results) {\n if (result.status === \"rejected\") {\n log.warn(\n `control station ${control.Name || control.href}: device fetch failed: ${\n result.reason instanceof Error ? result.reason.message : String(result.reason)\n }`,\n );\n continue;\n }\n\n if (isAddressable(result.value)) {\n positions.push(result.value);\n } else {\n const value = result.value as DeviceAddress | null;\n log.info(\n `skipping non-addressable ${control.Name || \"?\"} ` +\n `type=${value?.DeviceType || typeof value} ` +\n `state=${value?.AddressedState || \"?\"} href=${value?.href || \"?\"}`,\n );\n }\n }\n\n resolve(positions);\n })\n .catch(() => resolve([]));\n });\n }\n\n /*\n * Creates a connection when mDNS finds a processor.\n */\n private onDiscovered = (host: ProcessorAddress): void => {\n this.discovered.delete(host.id);\n\n const addrs = (host.addresses || []).map((a) => `${a.family}:${a.address}`).join(\", \");\n\n log.info(`Discovered host id=${host.id} type=${host.type} addresses=[${addrs}]`);\n\n if (!this.context.has(host.id)) {\n log.warn(\n `skipping host id=${host.id}: not in pairing (paired=[${this.context.processors.join(\", \") || \"none\"}])`,\n );\n return;\n }\n\n const ip = host.addresses.find((address) => address.family === HostAddressFamily.IPv4) || host.addresses[0];\n\n if (ip == null) {\n log.error(`host id=${host.id} has no addresses`);\n return;\n }\n\n log.info(`connecting to processor id=${host.id} at ${ip.address}`);\n\n const processor = new ProcessorController(host.id, new Connection(ip.address, this.context.get(host.id)));\n\n this.discovered.set(host.id, processor);\n\n processor.log.info(`Processor ${Colors.green(ip.address)}`);\n\n processor\n .on(\"Disconnect\", () => {\n log.warn(`processor ${host.id} disconnected; retry in ${RETRY_BACKOFF_DURATION}ms`);\n setTimeout(() => this.onDiscovered(host), RETRY_BACKOFF_DURATION);\n })\n .on(\"Connect\", () => {\n log.info(`processor ${host.id} Connect event \u2014 loading system/project/areas (refresh=${this.refresh})`);\n\n if (this.refresh) processor.clear();\n\n // RESET RETRIES\n\n Promise.all([processor.system(), processor.project(), processor.areas()])\n .then(([system, project, areas]) => {\n const version = system?.FirmwareImage.Firmware.DisplayName;\n const type = system?.DeviceType;\n const waits: Promise<void>[] = [];\n\n this.rebuildAreaPaths(areas);\n\n log.info(\n `processor ${host.id} system loaded firmware=${version || \"Unknown\"} type=${type} areas=${areas?.length ?? 0}`,\n );\n\n processor.log.info(`Firmware ${Colors.green(version || \"Unknown\")}`);\n processor.log.info(project.ProductType);\n\n processor\n .subscribe<ZoneStatus[]>({ href: \"/zone/status\" }, (statuses: ZoneStatus[]): void => {\n for (const status of statuses) {\n const device = processor.devices.get(status.Zone.href);\n\n if (device != null) device.update(status);\n }\n })\n .then(() => log.info(`processor ${host.id} subscribed /zone/status`))\n .catch((error) => this.onProcessorError(host, error));\n\n processor\n .subscribe<AreaStatus[]>({ href: \"/area/status\" }, (statuses: AreaStatus[]): void => {\n for (const status of statuses) {\n const occupancy = processor.devices.get(`/occupancy/${status.href?.split(\"/\")[2]}`);\n\n if (occupancy != null && status.OccupancyStatus != null) occupancy.update(status);\n }\n })\n .then(() => log.info(`processor ${host.id} subscribed /area/status`))\n .catch((error) => this.onProcessorError(host, error));\n\n if (type === \"RadioRa3Processor\") {\n processor\n .subscribe<TimeclockStatus[]>(\n { href: \"/timeclock/status\" },\n (statuses: TimeclockStatus[]): void => {\n for (const status of statuses) {\n const device = processor.devices.get(\n (status as TimeclockStatus & { Timeclock: Address }).Timeclock.href,\n );\n\n if (device != null) device.update(status);\n }\n },\n )\n .then(() => log.info(`processor ${host.id} subscribed /timeclock/status`))\n .catch((error) => this.onProcessorError(host, error));\n }\n\n for (const area of areas) {\n waits.push(\n new Promise((resolve) => {\n this.discoverZones(processor, area).then(() => resolve());\n }),\n );\n\n waits.push(\n new Promise((resolve) => {\n this.discoverControls(processor, area).then(() => resolve());\n }),\n );\n }\n\n if (type === \"RadioRa3Processor\") {\n waits.push(\n new Promise((resolve) => {\n this.discoverTimeclocks(processor).then(() => resolve());\n }),\n );\n }\n\n log.info(`processor ${host.id} discovering devices (${waits.length} wait tasks)`);\n\n Promise.all(waits).then(async () => {\n const devices = [...processor.devices.values()];\n\n // Remotes/keypads load buttons asynchronously; wait so HomeKit\n // accessories are built with StatelessProgrammableSwitch services.\n await Promise.all(\n devices.map(async (device) => {\n const ready = (device as Device & { ready?: Promise<void> }).ready;\n\n if (ready != null) {\n try {\n await ready;\n } catch (error) {\n log.warn(\n `device ${device.name} button init failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n }\n }),\n );\n\n const count = devices.length;\n\n log.info(`processor ${host.id} discovery complete: ${count} devices; loading statuses`);\n\n processor\n .statuses(type)\n .then((statuses) => {\n for (const status of statuses) {\n const zone = processor.devices.get(\n ((status as ZoneStatus).Zone || {}).href || \"\",\n );\n\n const occupancy = processor.devices.get(\n `/occupancy/${(status.href || \"\").split(\"/\")[2]}`,\n );\n\n if (zone != null) zone.update(status as ZoneStatus);\n\n if (occupancy != null && (status as AreaStatus).OccupancyStatus != null) {\n occupancy.update(status as AreaStatus);\n }\n }\n\n log.info(`processor ${host.id} applied ${statuses.length} status record(s)`);\n })\n .catch((error) => {\n log.error(\n `processor ${host.id} statuses failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n });\n\n processor.log.info(`discovered ${Colors.green(count.toString())} devices`);\n\n // One-shot protocol inventory: area/group hierarchy + extra LEAP URLs.\n probeProcessorMetadata(processor, areas).catch((error) => {\n log.error(\n `metadata probe failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n });\n\n log.info(`processor ${host.id} emitting Available with ${count} devices`);\n this.emit(\"Available\", devices);\n });\n })\n .catch((error) => this.onProcessorError(host, error));\n })\n .on(\"Error\", (error: Error) => this.onProcessorError(host, error));\n\n processor.connect().catch((error) => this.onProcessorError(host, error));\n };\n\n /*\n * When a device updates, this will emit an update event.\n */\n private onDeviceUpdate = (device: Device, state: DeviceState): void => {\n this.emit(\"Update\", device, state);\n };\n\n /*\n * When a control station emits an action, this will emit an action event.\n * This is when a button is pressed on a keypad or remote.\n */\n private onDeviceAction = (device: Device, button: Button, action: Action): void => {\n this.emit(\"Action\", device, button, action);\n };\n\n private onProcessorError = (host: ProcessorAddress, error: Error): void => {\n const message = error?.message != null ? error.message : String(error);\n\n if (message.match(/ENOTFOUND|ENETUNREACH|EHOSTUNREACH|ECONNRESET|EPIPE|ECONNREFUSED|ETIMEDOUT/g) != null) {\n log.warn(`processor ${host.id} network error: ${message}; retry in ${RETRY_BACKOFF_DURATION}ms`);\n setTimeout(() => this.onDiscovered(host), RETRY_BACKOFF_DURATION);\n\n return;\n }\n\n log.error(Colors.red(`processor ${host.id} error: ${message}`));\n };\n}\n", "import { ILogger, get as getLogger } from \"js-logger\";\n\nimport { Device } from \"@mkellsy/hap-device\";\n\nimport Cache from \"flat-cache\";\nimport Colors from \"colors\";\n\nimport os from \"os\";\nimport path from \"path\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { Address } from \"../../Response/Address\";\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { AreaStatus } from \"../../Response/AreaStatus\";\nimport { ButtonGroupExpanded } from \"../../Response/ButtonGroupExpanded\";\nimport { Connection } from \"../../Connection/Connection\";\nimport { ControlStation } from \"../../Response/ControlStation\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { PingResponse } from \"../../Response/PingResponse\";\nimport { Processor } from \"./Processor\";\nimport { Project } from \"../../Response/Project\";\nimport { Response } from \"../../Response/Response\";\nimport { TimeclockAddress } from \"../../Response/TimeclockAddress\";\nimport { TimeclockStatus } from \"../../Response/TimeclockStatus\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\nimport { ZoneStatus } from \"../../Response/ZoneStatus\";\n\nconst HEARTBEAT_DURATION = 20_000;\n\n/**\n * Defines a LEAP processor. This could be a Caseta Smart Bridge, RA2/RA3\n * Processor, or a Homeworks Processor.\n * @public\n */\nexport class ProcessorController\n extends EventEmitter<{\n Message: (response: Response) => void;\n Connect: (connection: Connection) => void;\n Disconnect: () => void;\n Error: (error: Error) => void;\n }>\n implements Processor\n{\n private uuid: string;\n private connection: Connection;\n private logger: ILogger;\n\n private cache: Cache.Cache;\n private discovered: Map<string, Device> = new Map();\n private heartbeatTimeout?: NodeJS.Timeout;\n\n /**\n * Creates a LEAP processor.\n *\n * @param id The processor UUID.\n * @param connection A reference to the connection to the processor.\n */\n constructor(id: string, connection: Connection) {\n super();\n\n this.uuid = id;\n this.logger = getLogger(`Processor ${Colors.dim(this.id)}`);\n this.connection = connection;\n this.cache = Cache.load(id, path.join(os.homedir(), \".leap\"));\n\n this.connection.on(\"Connect\", this.onConnect);\n this.connection.on(\"Message\", this.onMessage);\n this.connection.on(\"Error\", this.onError);\n\n this.connection.once(\"Disconnect\", this.onDisconnect);\n }\n\n /**\n * The processor's unique identifier.\n *\n * @returns The processor id.\n */\n public get id(): string {\n return this.uuid;\n }\n\n /**\n * A logger for the processor. This will automatically print the\n * processor id.\n *\n * @returns A reference to the logger assigned to this processor.\n */\n public get log(): ILogger {\n return this.logger;\n }\n\n /**\n * A device map for all devices found on this processor.\n *\n * @returns A device map by device id.\n */\n public get devices(): Map<string, Device> {\n return this.discovered;\n }\n\n /**\n * Connects to a processor.\n */\n public connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.logger.info(\"connect() starting\");\n\n this.connection\n .connect()\n .then(() => {\n this.logger.info(\"connect() socket/session ready; starting heartbeat\");\n this.startHeartbeat();\n\n resolve();\n })\n .catch((error) => {\n this.logger.error(`connect() failed: ${error instanceof Error ? error.message : String(error)}`);\n reject(error);\n });\n });\n }\n\n /**\n * Disconnects from a processor.\n */\n public disconnect(): void {\n this.stopHeartbeat();\n this.connection.disconnect();\n }\n\n /**\n * Clears the processor's device cache.\n */\n public clear(): void {\n for (const key of this.cache.keys()) {\n this.cache.removeKey(key);\n }\n\n this.cache.removeCacheFile();\n this.cache.save();\n }\n\n /**\n * True when a cache entry looks like a real LEAP payload (object/array),\n * not a poisoned error string such as \"Request timeout\".\n */\n private isValidCacheEntry(value: unknown): boolean {\n return value != null && typeof value === \"object\";\n }\n\n /**\n * Drops a bad cache entry so the next read hits the processor.\n */\n private dropCacheKey(key: string): void {\n this.cache.removeKey(key);\n this.cache.save(true);\n }\n\n /**\n * Pings the processor, useful for keeping the connection alive.\n *\n * @returns A ping response.\n */\n public ping(): Promise<PingResponse> {\n return this.read<PingResponse>(\"/server/1/status/ping\");\n }\n\n /**\n * Sends a read command to the processor.\n *\n * @param url The url to read.\n * @returns A response object.\n */\n public read<PAYLOAD = any>(url: string): Promise<PAYLOAD> {\n return this.connection.read<PAYLOAD>(url);\n }\n\n /**\n * Fetches the project information assigned to this processor.\n *\n * @returns A project object.\n */\n public project(): Promise<Project> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/project\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<Project>(\"/project\")\n .then((response) => {\n this.cache.setKey(\"/project\", response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches the processor's system information.\n *\n * @returns The processor as a device, or undefined if the processor\n * doesn't support this.\n */\n public system(): Promise<DeviceAddress | undefined> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/device?where=IsThisDevice:true\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<DeviceAddress[]>(\"/device?where=IsThisDevice:true\")\n .then((response) => {\n if (response[0] != null) {\n this.cache.setKey(\"/device?where=IsThisDevice:true\", response[0]);\n this.cache.save(true);\n\n return resolve(response[0]);\n }\n\n reject(new Error(\"No system device found\"));\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available areas. This represents floors, rooms, and suites.\n *\n * @returns An array of area objects.\n */\n public areas(): Promise<AreaAddress[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/area\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<AreaAddress[]>(\"/area\")\n .then((response) => {\n this.cache.setKey(\"/area\", response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available timeclocks.\n *\n * @returns An array of timeclock objects.\n */\n public timeclocks(): Promise<TimeclockAddress[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(\"/timeclock\");\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<TimeclockAddress[]>(\"/timeclock\")\n .then((response) => {\n this.cache.setKey(\"/timeclock\", response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available zones in an area. Zones represent a light and control.\n * In other systems this is the device.\n *\n * @param address The area to fetch zones.\n *\n * @returns An array of zone objects.\n */\n public zones(address: Address): Promise<ZoneAddress[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(`${address.href}/associatedzone`);\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<ZoneAddress[]>(`${address.href}/associatedzone`)\n .then((response) => {\n this.cache.setKey(`${address.href}/associatedzone`, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches multiple status objects from an area or zone. Typically used to\n * fetch sensor states from an area.\n *\n * @param address Address of an area or zone.\n *\n * @returns A zone status object.\n */\n public status(address: Address): Promise<ZoneStatus> {\n return this.read<ZoneStatus>(`${address.href}/status`);\n }\n\n public statuses(type?: string): Promise<(ZoneStatus | AreaStatus | TimeclockStatus)[]> {\n return new Promise((resolve, reject) => {\n const waits: Promise<(ZoneStatus | AreaStatus | TimeclockStatus)[]>[] = [];\n\n waits.push(this.read<ZoneStatus[]>(\"/zone/status\"));\n waits.push(this.read<AreaStatus[]>(\"/area/status\"));\n\n if (type === \"RadioRa3Processor\") waits.push(this.read<TimeclockStatus[]>(\"/timeclock/status\"));\n\n Promise.all(waits)\n .then(([zones, areas, timeclocks]) => resolve([...zones, ...areas, ...(timeclocks || [])]))\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available control stations of an area or zone. A control station\n * represents a group of keypads or remotes.\n *\n * @param address The address of an area or zone.\n *\n * @returns An array of control station objects.\n */\n public controls(address: Address): Promise<ControlStation[]> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(`${address.href}/associatedcontrolstation`);\n\n if (cached != null) return resolve(cached);\n\n this.connection\n .read<ControlStation[]>(`${address.href}/associatedcontrolstation`)\n .then((response) => {\n this.cache.setKey(`${address.href}/associatedcontrolstation`, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches a single device in a group. This represents a single keypad or\n * Pico remote.\n *\n * @param address An address of a group position.\n *\n * @returns A device object.\n */\n public device(address: Address): Promise<DeviceAddress> {\n return new Promise((resolve, reject) => {\n const cached = this.cache.getKey(address.href);\n\n if (this.isValidCacheEntry(cached) && typeof (cached as DeviceAddress).DeviceType === \"string\") {\n return resolve(cached as DeviceAddress);\n }\n\n if (cached != null) {\n this.logger.warn(\n `dropping invalid cache for ${address.href}: ${typeof cached === \"string\" ? cached : typeof cached}`,\n );\n this.dropCacheKey(address.href);\n }\n\n this.connection\n .read<DeviceAddress>(address.href)\n .then((response) => {\n if (!this.isValidCacheEntry(response) || typeof response.DeviceType !== \"string\") {\n return reject(new Error(`invalid device payload for ${address.href}`));\n }\n\n this.cache.setKey(address.href, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Fetches available buttons on a device.\n *\n * @param address An address or a device.\n *\n * @returns An array of button group objects.\n */\n public buttons(address: Address): Promise<ButtonGroupExpanded[]> {\n return new Promise((resolve, reject) => {\n const key = `${address.href}/buttongroup/expanded`;\n const cached = this.cache.getKey(key);\n\n if (this.isValidCacheEntry(cached) && Array.isArray(cached)) {\n return resolve(cached as ButtonGroupExpanded[]);\n }\n\n if (cached != null) {\n this.logger.warn(\n `dropping invalid cache for ${key}: ${typeof cached === \"string\" ? cached : typeof cached}`,\n );\n this.dropCacheKey(key);\n }\n\n this.connection\n .read<ButtonGroupExpanded[]>(`${address.href}/buttongroup/expanded`)\n .then((response) => {\n if (!Array.isArray(response)) {\n return reject(new Error(`invalid button group payload for ${address.href}`));\n }\n\n this.cache.setKey(key, response);\n this.cache.save(true);\n\n resolve(response);\n })\n .catch((error) => reject(error));\n });\n }\n\n /**\n * Sends an updatre command to the processor.\n *\n * @param address The address of the record.\n * @param field The field to update.\n * @param value The value to set.\n */\n public update(address: Address, field: string, value: object): Promise<void> {\n return this.connection.update(`${address.href}/${field}`, value as Record<string, unknown>);\n }\n\n /**\n * Sends a structured command to the processor.\n *\n * @param address The address of the zone or device.\n * @param command The structured command object.\n */\n public command(address: Address, command: object): Promise<void> {\n return this.connection.command(`${address.href}/commandprocessor`, { Command: command });\n }\n\n /**\n * Subscribes to record updates. This will call the listener every time the\n * record is updated.\n *\n * @param address The assress of the record.\n * @param listener The callback to call on updates.\n */\n public subscribe<T>(address: Address, listener: (response: T) => void): Promise<void> {\n return this.connection.subscribe<T>(address.href, listener);\n }\n\n /*\n * Listener for the processor's connection status.\n */\n private onConnect = (): void => {\n this.log.info(\"connected\");\n this.emit(\"Connect\", this.connection);\n };\n\n /*\n * Listener for when the processor sends a message.\n */\n private onMessage = (response: Response): void => {\n this.log.debug(\"message\");\n this.emit(\"Message\", response);\n };\n\n /*\n * Listener for when the connection is dropped.\n */\n private onDisconnect = (): void => {\n this.log.info(\"disconnected\");\n this.emit(\"Disconnect\");\n };\n\n /*\n * Listener for when there is an error in the connection.\n */\n private onError = (error: Error): void => {\n this.logger.error(`connection error: ${error?.message != null ? error.message : String(error)}`);\n this.emit(\"Error\", error);\n };\n\n /*\n * Starts the ping heartbeat with the processor.\n */\n private startHeartbeat(): void {\n this.stopHeartbeat();\n\n this.ping()\n .then(() => {\n this.logger.debug(\"heartbeat ping ok\");\n })\n .catch((error) => {\n this.logger.warn(`heartbeat ping failed: ${error instanceof Error ? error.message : String(error)}`);\n })\n .finally(() => {\n this.heartbeatTimeout = setTimeout(() => this.startHeartbeat(), HEARTBEAT_DURATION);\n });\n }\n\n /*\n * Stops the ping heartbeat.\n */\n private stopHeartbeat(): void {\n clearTimeout(this.heartbeatTimeout);\n\n this.heartbeatTimeout = undefined;\n }\n}\n", "import { Device, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../Response/AreaAddress\";\nimport { ContactController } from \"./Contact/ContactController\";\nimport { DeviceAddress } from \"../Response/DeviceAddress\";\nimport { DimmerController } from \"./Dimmer/DimmerController\";\nimport { FanController } from \"./Fan/FanController\";\nimport { KeypadController } from \"./Keypad/KeypadController\";\nimport { Processor } from \"./Processor/Processor\";\nimport { RemoteController } from \"./Remote/RemoteController\";\nimport { OccupancyController } from \"./Occupancy/OccupancyController\";\nimport { ShadeController } from \"./Shade/ShadeController\";\nimport { StripController } from \"./Strip/StripController\";\nimport { SwitchController } from \"./Switch/SwitchController\";\nimport { TimeclockController } from \"./Timeclock/TimeclockController\";\nimport { TimeclockAddress } from \"../Response/TimeclockAddress\";\nimport { UnknownController } from \"./Unknown/UnknownController\";\nimport { ZoneAddress } from \"../Response/ZoneAddress\";\n\n/**\n * Creates a device by type. This is a device factory.\n *\n * @param processor A reference to the processor.\n * @param area A reference to the area.\n * @param definition Device definition, this is either an area, zone or device.\n *\n * @returns A common device object. Casting will be needed to access extended\n * capibilities.\n * @private\n */\nexport function createDevice(processor: Processor, area: AreaAddress, definition: unknown): Device {\n const type = parseDeviceType((definition as ZoneAddress).ControlType || (definition as DeviceAddress).DeviceType);\n\n switch (type) {\n case DeviceType.Contact:\n return new ContactController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Dimmer:\n return new DimmerController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Fan:\n return new FanController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Keypad:\n return new KeypadController(processor, area, definition as DeviceAddress);\n\n case DeviceType.Occupancy:\n return new OccupancyController(processor, area, {\n href: `/occupancy/${area.href?.split(\"/\")[2]}`,\n Name: (definition as ZoneAddress).Name,\n } as DeviceAddress);\n\n case DeviceType.Remote:\n return new RemoteController(processor, area, definition as DeviceAddress);\n\n case DeviceType.Shade:\n return new ShadeController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Strip:\n return new StripController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Switch:\n return new SwitchController(processor, area, definition as ZoneAddress);\n\n case DeviceType.Timeclock:\n return new TimeclockController(processor, area, definition as TimeclockAddress);\n\n default:\n return new UnknownController(processor, area, definition as ZoneAddress);\n }\n}\n\n/**\n * Parses a string to a standard device type enum value.\n *\n * @param value A string device type from the processor.\n *\n * @returns A standard device type from the device type enum.\n * @private\n */\nexport function parseDeviceType(value: string): DeviceType {\n switch (value) {\n case \"Switched\":\n case \"PowPakSwitch\":\n case \"OutdoorPlugInSwitch\":\n return DeviceType.Switch;\n\n case \"Dimmed\":\n case \"PlugInDimmer\":\n return DeviceType.Dimmer;\n\n case \"Shade\":\n return DeviceType.Shade;\n\n case \"Timeclock\":\n return DeviceType.Timeclock;\n\n case \"WhiteTune\":\n return DeviceType.Strip;\n\n case \"FanSpeed\":\n return DeviceType.Fan;\n\n case \"Pico2Button\":\n case \"Pico2ButtonRaiseLower\":\n case \"Pico3Button\":\n case \"Pico4Button\":\n case \"Pico3ButtonRaiseLower\":\n case \"Pico4Button2Group\":\n case \"Pico4ButtonScene\":\n case \"Pico4ButtonZone\":\n case \"PaddleSwitchPico\":\n return DeviceType.Remote;\n\n case \"SunnataDimmer\":\n case \"SunnataSwitch\":\n case \"SunnataKeypad\":\n case \"SunnataHybridKeypad\":\n return DeviceType.Keypad;\n\n case \"RPSCeilingMountedOccupancySensor\":\n return DeviceType.Occupancy;\n\n case \"CCO\":\n return DeviceType.Contact;\n\n default:\n return DeviceType.Unknown;\n }\n}\n\n/**\n * Determines if the device is addressable. Basically can we program actions\n * for it.\n *\n * @param device A reference to the device.\n *\n * @returns True is addressable, false if not.\n * @private\n */\nexport function isAddressable(device: DeviceAddress): boolean {\n // Guard against poisoned cache entries (e.g. the string \"Request timeout\").\n if (device == null || typeof device !== \"object\") {\n return false;\n }\n\n if (device.AddressedState !== \"Addressed\") {\n return false;\n }\n\n switch (device.DeviceType) {\n case \"Pico2Button\":\n case \"Pico2ButtonRaiseLower\":\n case \"Pico3Button\":\n case \"Pico4Button\":\n case \"Pico3ButtonRaiseLower\":\n case \"Pico4Button2Group\":\n case \"Pico4ButtonScene\":\n case \"Pico4ButtonZone\":\n case \"PaddleSwitchPico\":\n return true;\n\n case \"SunnataKeypad\":\n case \"SunnataHybridKeypad\":\n return true;\n\n case \"RPSCeilingMountedOccupancySensor\":\n return true;\n\n default:\n return false;\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Contact } from \"./Contact\";\nimport { ContactState } from \"./ContactState\";\nimport { Processor } from \"../Processor/Processor\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a CCO device.\n * @public\n */\nexport class ContactController extends Common<ContactState> implements Contact {\n /**\n * Creates a CCO device.\n *\n * ```js\n * const cco = new Contact(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Contact, processor, area, zone, { state: \"Open\" });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"Open\", \"Closed\"] });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * cco.update({ CCOLevel: \"Closed\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.CCOLevel != null) this.state.state = status.CCOLevel;\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * cco.set({ state: \"Closed\" });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: ContactState): Promise<void> {\n return this.processor.command(this.address, {\n CommandType: \"GoToCCOLevel\",\n CCOLevelParameters: { CCOLevel: status.state },\n });\n }\n}\n", "import { ILogger, get as getLogger } from \"js-logger\";\n\nimport { Action, Address, Area, Button, Capability, Device, DeviceState, DeviceType } from \"@mkellsy/hap-device\";\n\nimport Colors from \"colors\";\n\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\nimport { Processor } from \"./Processor/Processor\";\n\n/**\n * Defines common functionallity for a device.\n * @private\n */\nexport abstract class Common<STATE extends DeviceState> extends EventEmitter<{\n Action: (device: Device, button: Button, action: Action) => void;\n Update: (device: Device, state: STATE) => void;\n}> {\n protected processor: Processor;\n protected state: STATE;\n protected initialized: boolean = false;\n protected fields: Map<string, Capability> = new Map();\n\n /**\n * Resolves when async device setup (e.g. button enumeration) is finished.\n * Defaults to already-resolved; remotes/keypads override.\n */\n public ready: Promise<void> = Promise.resolve();\n\n private logger: ILogger;\n\n private deviceName: string;\n private deviceAddress: string;\n private deviceArea: Area;\n private deviceAreaPath: string;\n private deviceType: DeviceType;\n\n /**\n * Creates a base device object.\n *\n * ```\n * class Fan extends Common {\n * constructor(id: string, connection: Connection, name: string) {\n * super(DeviceType.Fan, connection, { id, name, \"Fan\" });\n *\n * // Device specific code\n * }\n * }\n * ```\n *\n * @param type The device type.\n * @param processor The current processor for this device.\n * @param area The area the device belongs to. May include Path (full hierarchy).\n * @param definition Device address definition.\n * @param state The device's initial state.\n */\n constructor(\n type: DeviceType,\n processor: Processor,\n area: Area & { Path?: string },\n definition: { href: string; Name: string },\n state: STATE,\n ) {\n super();\n\n this.processor = processor;\n this.deviceAddress = definition.href;\n this.deviceName = definition.Name;\n this.deviceArea = area;\n this.deviceAreaPath = area.Path || area.Name || \"\";\n this.deviceType = type;\n\n this.logger = getLogger(`Device ${Colors.dim(this.id)}`);\n this.state = state;\n }\n\n /**\n * The device's manufacturer.\n *\n * @returns The manufacturer.\n */\n public get manufacturer(): string {\n return \"Lutron Electronics Co., Inc\";\n }\n\n /**\n * The device's unique identifier.\n *\n * @returns The device id.\n */\n public get id(): string {\n return `LEAP-${this.processor.id}-${DeviceType[this.deviceType].toUpperCase()}-${this.deviceAddress?.split(\"/\")[2]}`;\n }\n\n /**\n * The device's configured name.\n *\n * @returns The device's configured name.\n */\n public get name(): string {\n return this.deviceName;\n }\n\n /**\n * The device's configured room.\n *\n * @returns The device's configured room.\n */\n public get room(): string {\n return this.area.Name;\n }\n\n /**\n * Full area hierarchy path (e.g. \"House / Upper Floor / Kitchen\").\n * Falls back to the leaf room name when path was not provided.\n */\n public get areaPath(): string {\n return this.deviceAreaPath || this.room;\n }\n\n /**\n * The devices capibilities. This is a map of the fields that can be set\n * or read.\n *\n * @returns The device's capabilities.\n */\n public get capabilities(): { [key: string]: Capability } {\n return Object.fromEntries(this.fields);\n }\n\n /**\n * A logger for the device. This will automatically print the devices name,\n * room and id.\n *\n * @returns A reference to the logger assigned to this device.\n */\n public get log(): ILogger {\n return this.logger;\n }\n\n /**\n * The href address of the device.\n *\n * @returns The device's href address.\n */\n public get address(): Address {\n return { href: this.deviceAddress };\n }\n\n /**\n * The device type.\n *\n * @returns The device type.\n */\n public get type(): DeviceType {\n return this.deviceType;\n }\n\n /**\n * The area the device is in.\n *\n * @returns The device's area.\n */\n public get area(): Area {\n return this.deviceArea;\n }\n\n /**\n * The current state of the device.\n *\n * @returns The device's state.\n */\n public get status(): STATE {\n return this.state;\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Dimmer } from \"./Dimmer\";\nimport { DimmerState } from \"./DimmerState\";\nimport { Processor } from \"../Processor/Processor\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a dimmable light device.\n * @public\n */\nexport class DimmerController extends Common<DimmerState> implements Dimmer {\n /**\n * Creates a dimmable light device.\n *\n * ```js\n * const dimmer = new Dimmer(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Dimmer, processor, area, zone, { state: \"Off\", level: 0 });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n this.fields.set(\"level\", { type: \"Integer\", min: 0, max: 100 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * dimmer.update({ Level: 100 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.Level != null) {\n this.state.state = status.Level > 0 ? \"On\" : \"Off\";\n this.state.level = status.Level;\n }\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * dimmer.set({ state: \"On\", level: 50 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: DimmerState): Promise<void> {\n return this.processor.command(this.address, {\n CommandType: \"GoToLevel\",\n Parameter: [{ Type: \"Level\", Value: status.state === \"Off\" ? 0 : status.level }],\n });\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Fan } from \"./Fan\";\nimport { FanState } from \"./FanState\";\nimport { Processor } from \"../Processor/Processor\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a fan device.\n * @public\n */\nexport class FanController extends Common<FanState> implements Fan {\n /**\n * Creates a fan device.\n *\n * ```js\n * const fan = new Fan(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Fan, processor, area, zone, { state: \"Off\", speed: 0 });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n this.fields.set(\"speed\", { type: \"Integer\", min: 0, max: 7 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * fan.update({ SwitchedLevel: \"On\", FanSpeed: 7 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n const speed = this.parseFanSpeed(status.FanSpeed as unknown as string);\n\n this.state = {\n ...previous,\n state: speed > 0 ? \"On\" : \"Off\",\n speed,\n };\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * fan.set({ state: \"On\", speed: 3 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: FanState): Promise<void> {\n const speed = status.state === \"Off\" ? \"Off\" : this.lookupFanSpeed(status.speed);\n\n return this.processor.command(this.address, {\n CommandType: \"GoToFanSpeed\",\n FanSpeedParameters: [{ FanSpeed: speed }],\n });\n }\n\n /*\n * Converts a 7 speed setting to a 4 speed string value.\n */\n private lookupFanSpeed(value: number): string {\n switch (value) {\n case 1:\n return \"Low\";\n\n case 2:\n case 3:\n return \"Medium\";\n\n case 4:\n case 5:\n return \"MediumHigh\";\n\n case 6:\n case 7:\n return \"High\";\n\n default:\n return \"Off\";\n }\n }\n\n /*\n * Converts a 4 speed string speed to a numeric 7 speed value.\n */\n private parseFanSpeed(value: string): number {\n switch (value) {\n case \"Low\":\n return 1;\n\n case \"Medium\":\n return 3;\n\n case \"MediumHigh\":\n return 5;\n\n case \"High\":\n return 7;\n\n default:\n return 0;\n }\n }\n}\n", "import Colors from \"colors\";\n\nimport { Button, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { ButtonStatus } from \"../../Response/ButtonStatus\";\nimport { Common } from \"../Common\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { Keypad } from \"./Keypad\";\nimport { KeypadState } from \"./KeypadState\";\nimport { Processor } from \"../Processor/Processor\";\n\n/**\n * Defines a keypad device.\n * @public\n */\nexport class KeypadController extends Common<KeypadState> implements Keypad {\n public readonly buttons: Button[] = [];\n\n /**\n * Creates a keypad device.\n *\n * ```js\n * const keypad = new Keypad(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device A refrence to this device.\n */\n constructor(processor: Processor, area: AreaAddress, device: DeviceAddress) {\n super(DeviceType.Keypad, processor, area, device, {\n led: { href: \"/unknown\" },\n state: \"Off\",\n });\n\n if (device.DeviceType === \"SunnataKeypad\" || device.DeviceType === \"SunnataHybridKeypad\") {\n this.ready = this.processor\n .buttons(this.address)\n .then(async (groups) => {\n if (!Array.isArray(groups)) {\n throw new Error(`button groups not an array for ${device.DeviceType} ${this.address.href}`);\n }\n\n for (let i = 0; i < groups.length; i++) {\n for (let j = 0; j < groups[i].Buttons?.length; j++) {\n const button = groups[i].Buttons[j];\n const id = `LEAP-${this.processor.id}-BUTTON-${button.href.split(\"/\")[2]}`;\n\n const definition: Button = {\n id,\n index: button.ButtonNumber,\n name: (button.Engraving || {}).Text || button.Name,\n led: button.AssociatedLED,\n };\n\n this.buttons.push(definition);\n\n try {\n await this.processor.subscribe<ButtonStatus>(\n { href: `${button.href}/status/event` },\n (status: ButtonStatus): void => {\n const action = status.ButtonEvent.EventType;\n\n if (action !== \"Press\") return;\n\n this.emit(\"Action\", this, definition, \"Press\");\n\n setTimeout(() => this.emit(\"Action\", this, definition, \"Release\"), 100);\n },\n );\n } catch (error) {\n this.log.error(Colors.red(error instanceof Error ? error.message : String(error)));\n }\n }\n }\n\n this.log.info(\n `keypad buttons ready count=${this.buttons.length} type=${device.DeviceType} href=${this.address.href}`,\n );\n })\n .catch((error: Error) => {\n this.log.error(Colors.red(error.message));\n throw error;\n });\n }\n }\n\n /**\n * Recieves a state response from the processor (not supported).\n */\n public update(): void {\n this.initialized = true;\n }\n\n /**\n * Controls this LEDs on this device.\n *\n * ```js\n * keypad.set({ state: { href: \"/led/123456\" }, state: \"On\" });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: KeypadState): Promise<void> {\n return this.processor.update(status.led, \"status\", {\n LEDStatus: { State: status.state === \"On\" ? \"On\" : \"Off\" },\n });\n }\n}\n", "import Colors from \"colors\";\n\nimport { Button, DeviceState, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { ButtonMap } from \"./ButtonMap\";\nimport { ButtonStatus } from \"../../Response/ButtonStatus\";\nimport { Common } from \"../Common\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Remote } from \"./Remote\";\nimport { Trigger } from \"./Trigger\";\nimport { TriggerController } from \"./TriggerController\";\n\n/**\n * Defines a Pico remote device.\n * @public\n */\nexport class RemoteController extends Common<DeviceState> implements Remote {\n public readonly buttons: Button[] = [];\n\n private triggers: Map<string, Trigger> = new Map();\n\n /**\n * Creates a Pico remote device.\n *\n * ```js\n * const remote = new Remote(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device A refrence to this device.\n */\n constructor(processor: Processor, area: AreaAddress, device: DeviceAddress) {\n super(DeviceType.Remote, processor, area, device, { state: \"Unknown\" });\n\n this.ready = this.processor\n .buttons(this.address)\n .then(async (groups) => {\n if (!Array.isArray(groups)) {\n throw new Error(`button groups not an array for ${device.DeviceType} ${this.address.href}`);\n }\n\n const map = ButtonMap.get(device.DeviceType);\n\n if (map == null) {\n this.log.warn(`no ButtonMap for DeviceType=${device.DeviceType}; buttons will be unmapped`);\n }\n\n for (let i = 0; i < groups.length; i++) {\n for (let j = 0; j < groups[i].Buttons?.length; j++) {\n const button = groups[i].Buttons[j];\n const mapped = map?.get(button.ButtonNumber);\n const index = (mapped?.[0] as number | undefined) ?? button.ButtonNumber + 1;\n const raiseLower = (mapped?.[1] as boolean | undefined) ?? false;\n\n const trigger = new TriggerController(this.processor, button, index, { raiseLower });\n\n if (raiseLower) {\n // Raw press/release \u2014 real finger timing for volume ramp consumers.\n trigger.on(\"Press\", (btn): void => {\n this.emit(\"Action\", this, btn, \"Press\");\n });\n\n trigger.on(\"Release\", (btn): void => {\n this.emit(\"Action\", this, btn, \"Release\");\n });\n } else {\n trigger.on(\"Press\", (btn): void => {\n this.emit(\"Action\", this, btn, \"Press\");\n\n setTimeout(() => this.emit(\"Action\", this, btn, \"Release\"), 100);\n });\n\n trigger.on(\"DoublePress\", (btn): void => {\n this.emit(\"Action\", this, btn, \"DoublePress\");\n\n setTimeout(() => this.emit(\"Action\", this, btn, \"Release\"), 100);\n });\n\n trigger.on(\"LongPress\", (btn): void => {\n this.emit(\"Action\", this, btn, \"LongPress\");\n\n setTimeout(() => this.emit(\"Action\", this, btn, \"Release\"), 100);\n });\n }\n\n this.triggers.set(button.href, trigger);\n this.buttons.push(trigger.definition);\n\n try {\n await this.processor.subscribe<ButtonStatus>(\n { href: `${button.href}/status/event` },\n (status: ButtonStatus): void => this.triggers.get(button.href)!.update(status),\n );\n } catch (error) {\n this.log.error(Colors.red(error instanceof Error ? error.message : String(error)));\n }\n }\n }\n\n this.log.info(\n `remote buttons ready count=${this.buttons.length} type=${device.DeviceType} href=${this.address.href}`,\n );\n })\n .catch((error: Error) => {\n this.log.error(Colors.red(error.message));\n throw error;\n });\n }\n\n /**\n * Recieves a state response from the processor (not supported).\n */\n public update(): void {\n this.initialized = true;\n }\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "/**\n * Maps button index from the processor to a standard sequence index. It also\n * determines if the button is a raise or lower button.\n * @private\n */\nexport const ButtonMap = new Map<string, Map<number, (number | boolean)[]>>([\n [\n \"Pico2Button\",\n new Map([\n [0, [1, false]],\n [2, [2, false]],\n ]),\n ],\n [\n \"Pico2ButtonRaiseLower\",\n new Map([\n [0, [1, false]],\n [2, [4, false]],\n [3, [2, true]],\n [4, [3, true]],\n ]),\n ],\n [\n \"Pico3Button\",\n new Map([\n [0, [1, false]],\n [1, [2, false]],\n [2, [3, false]],\n ]),\n ],\n [\n \"Pico3ButtonRaiseLower\",\n new Map([\n [0, [1, false]],\n [1, [3, false]],\n [2, [5, false]],\n [3, [2, true]],\n [4, [4, true]],\n ]),\n ],\n [\n \"Pico4Button2Group\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n [\n \"Pico4ButtonScene\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n [\n \"Pico4ButtonZone\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n [\n \"PaddleSwitchPico\",\n new Map([\n [0, [1, false]],\n [2, [2, false]],\n ]),\n ],\n [\n \"Pico4Button\",\n new Map([\n [1, [1, false]],\n [2, [2, false]],\n [3, [3, false]],\n [4, [4, false]],\n ]),\n ],\n]);\n", "import { Button, TriggerOptions, TriggerState } from \"@mkellsy/hap-device\";\nimport { EventEmitter } from \"@mkellsy/event-emitter\";\n\nimport { ButtonAddress } from \"../../Response/ButtonAddress\";\nimport { ButtonStatus } from \"../../Response/ButtonStatus\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Trigger } from \"./Trigger\";\n\n/**\n * Defines a button tracker. This enables single, double and long presses on\n * remotes. When `raiseLower` is true, LEAP Press/Release are forwarded raw\n * (no double/long classification) so consumers can implement hold-to-ramp.\n * @public\n */\nexport class TriggerController\n extends EventEmitter<{\n Press: (button: Button) => void;\n DoublePress: (button: Button) => void;\n LongPress: (button: Button) => void;\n Release: (button: Button) => void;\n }>\n implements Trigger\n{\n private processor: Processor;\n private action: ButtonAddress;\n private options: TriggerOptions;\n\n private timer?: NodeJS.Timeout;\n private state: TriggerState = TriggerState.Idle;\n private button: Button;\n private index: number;\n\n /**\n * Creates a button tracker.\n *\n * @param processor A refrence to the processor.\n * @param button A reference to the individual button.\n * @param index An index of the button on the device.\n * @param options Button options like click speed, raise or lower.\n */\n constructor(processor: Processor, button: ButtonAddress, index: number, options?: Partial<TriggerOptions>) {\n super();\n\n this.index = index;\n this.processor = processor;\n this.action = button;\n\n this.options = {\n doubleClickSpeed: 300,\n clickSpeed: 450,\n raiseLower: false,\n ...options,\n };\n\n this.button = {\n id: this.id,\n index: this.index,\n name: (this.action.Engraving || {}).Text || this.action.Name,\n };\n\n if (this.options.raiseLower === true) this.button.raiseLower = true;\n }\n\n /**\n * The button id.\n *\n * @returns A string of the button id.\n */\n public get id(): string {\n return `LEAP-${this.processor.id}-BUTTON-${this.action.href.split(\"/\")[2]}`;\n }\n\n /**\n * The definition of the button.\n *\n * @returns A button object.\n */\n public get definition(): Button {\n return this.button;\n }\n\n /**\n * Resets the button state to idle.\n */\n public reset(): void {\n this.state = TriggerState.Idle;\n\n if (this.timer) clearTimeout(this.timer);\n\n this.timer = undefined;\n }\n\n /**\n * Updates the button state and tracks single, double or long presses.\n * Raise/lower buttons pass through raw Press/Release only.\n *\n * @param status The current button status.\n */\n public update(status: ButtonStatus): void {\n // Volume raise/lower: faithful finger-down / finger-up for hold-to-ramp.\n if (this.options.raiseLower === true) {\n const event = status.ButtonEvent?.EventType;\n\n if (event === \"Press\") {\n this.emit(\"Press\", this.button);\n } else if (event === \"Release\") {\n this.emit(\"Release\", this.button);\n }\n\n return;\n }\n\n const longPressTimeoutHandler = () => {\n this.reset();\n\n /*\n * Testing this edge case is not reliable in unit tests. This\n * prevents false positives.\n */\n\n /* istanbul ignore next */\n if (this.options.clickSpeed === 0) return;\n\n this.emit(\"LongPress\", this.button);\n };\n\n const doublePressTimeoutHandler = () => {\n this.reset();\n this.emit(\"Press\", this.button);\n };\n\n switch (this.state) {\n case TriggerState.Idle: {\n if (status.ButtonEvent.EventType === \"Press\" && this.options.clickSpeed > 0) {\n this.state = TriggerState.Down;\n this.timer = setTimeout(longPressTimeoutHandler, this.options.clickSpeed);\n\n return;\n }\n\n if (status.ButtonEvent.EventType === \"Press\") {\n this.state = TriggerState.Down;\n\n doublePressTimeoutHandler();\n\n return;\n }\n\n break;\n }\n\n case TriggerState.Down: {\n if (status.ButtonEvent.EventType === \"Release\") {\n this.state = TriggerState.Up;\n\n /*\n * Getting the unit tests to trigger this edge case is\n * un-reliable. This prevents false positives.\n */\n\n /* istanbul ignore else */\n if (this.timer) clearTimeout(this.timer);\n\n if (this.options.doubleClickSpeed > 0) {\n this.timer = setTimeout(\n doublePressTimeoutHandler,\n this.options.doubleClickSpeed + (this.options.raiseLower ? 250 : 0),\n );\n }\n\n return;\n }\n\n this.reset();\n\n break;\n }\n\n case TriggerState.Up: {\n if (status.ButtonEvent.EventType === \"Press\" && this.timer) {\n this.reset();\n\n if (this.options.doubleClickSpeed === 0) return;\n\n this.emit(\"DoublePress\", this.button);\n\n return;\n }\n\n this.reset();\n\n break;\n }\n }\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { AreaStatus, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { DeviceAddress } from \"../../Response/DeviceAddress\";\nimport { Occupancy } from \"./Occupancy\";\nimport { OccupancyState } from \"./OccupancyState\";\nimport { Processor } from \"../Processor/Processor\";\n\n/**\n * Defines a occupancy sensor device.\n * @public\n */\nexport class OccupancyController extends Common<OccupancyState> implements Occupancy {\n /**\n * Creates a occupancy sensor device.\n *\n * ```js\n * const sensor = new Occupancy(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device The refrence to this device.\n */\n constructor(processor: Processor, area: AreaAddress, device: DeviceAddress) {\n super(DeviceType.Occupancy, processor, area, device, { state: \"Unoccupied\" });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * sensor.update({ OccupancyStatus: \"Occupied\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: AreaStatus): void {\n const previous = { ...this.status };\n\n if (status.OccupancyStatus != null) {\n this.state.state = status.OccupancyStatus === \"Occupied\" ? \"Occupied\" : \"Unoccupied\";\n }\n\n if (!equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Shade } from \"./Shade\";\nimport { ShadeState } from \"./ShadeState\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a window shade device.\n * @public\n */\nexport class ShadeController extends Common<ShadeState> implements Shade {\n /**\n * Creates a window shade device.\n *\n * ```js\n * const shade = new Shade(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Shade, processor, area, zone, {\n state: \"Closed\",\n level: 0,\n tilt: 0,\n });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"Open\", \"Closed\"] });\n this.fields.set(\"level\", { type: \"Integer\", min: 0, max: 100 });\n this.fields.set(\"tilt\", { type: \"Integer\", min: 0, max: 100 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * shade.update({ Level: 100 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.Level != null) {\n this.state.state = status.Level > 0 ? \"Open\" : \"Closed\";\n this.state.level = status.Level;\n }\n\n if (status.Tilt != null) this.state.tilt = status.Tilt;\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * shade.set({ state: \"Open\", level: 50, tilt: 50 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: ShadeState): Promise<void> {\n const waits: Promise<void>[] = [];\n\n waits.push(\n this.processor.command(this.address, {\n CommandType: \"GoToLevel\",\n Parameter: [{ Type: \"Level\", Value: status.state === \"Closed\" ? 0 : status.level }],\n }),\n );\n\n if (status.tilt != null || status.state === \"Closed\") {\n waits.push(\n this.processor.command(this.address, {\n CommandType: \"TiltParameters\",\n TiltParameters: { Tilt: status.state === \"Closed\" ? 0 : status.tilt },\n }),\n );\n }\n\n return Promise.all(waits) as unknown as Promise<void>;\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Strip } from \"./Strip\";\nimport { StripState } from \"./StripState\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a LED strip device.\n * @public\n */\nexport class StripController extends Common<StripState> implements Strip {\n /**\n * Creates a LED strip device.\n *\n * ```js\n * const strip = new Strip(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Strip, processor, area, zone, {\n state: \"Off\",\n level: 0,\n luminance: 1800,\n });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n this.fields.set(\"level\", { type: \"Integer\", min: 0, max: 100 });\n this.fields.set(\"luminance\", { type: \"Integer\", min: 1800, max: 3000 });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * strip.update({ Level: 100 });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n if (status.Level != null) {\n this.state.state = status.Level > 0 ? \"On\" : \"Off\";\n this.state.level = status.Level;\n }\n\n if (\n status.ColorTuningStatus != null &&\n status.ColorTuningStatus.WhiteTuningLevel != null &&\n status.ColorTuningStatus.WhiteTuningLevel.Kelvin != null\n ) {\n this.state.luminance = status.ColorTuningStatus.WhiteTuningLevel.Kelvin;\n }\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * strip.set({ state: \"On\", level: 50, luminance: 3000 });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: StripState): Promise<void> {\n if (status.state === \"Off\") {\n return this.processor.command(this.address, {\n CommandType: \"GoToWhiteTuningLevel\",\n WhiteTuningLevelParameters: { Level: 0 },\n });\n }\n\n return this.processor.command(this.address, {\n CommandType: \"GoToWhiteTuningLevel\",\n WhiteTuningLevelParameters: {\n Level: status.level,\n WhiteTuningLevel: { Kelvin: status.luminance },\n },\n });\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, ZoneStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Switch } from \"./Switch\";\nimport { SwitchState } from \"./SwitchState\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines a on/off switch device.\n * @public\n */\nexport class SwitchController extends Common<SwitchState> implements Switch {\n /**\n * Creates a on/off switch device.\n *\n * ```js\n * const switch = new Switch(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Switch, processor, area, zone, { state: \"Off\" });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * switch.update({ SwitchedLevel: \"On\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: ZoneStatus): void {\n const previous = { ...this.status };\n\n this.state = {\n ...previous,\n state: status.SwitchedLevel || \"Unknown\",\n };\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device.\n *\n * ```js\n * switch.set({ state: \"On\" });\n * ```\n *\n * @param status Desired device state.\n */\n public set(status: SwitchState): Promise<void> {\n return this.processor.command(this.address, {\n CommandType: \"GoToLevel\",\n Parameter: [{ Type: \"Level\", Value: status.state === \"On\" ? 100 : 0 }],\n });\n }\n}\n", "import equals from \"deep-equal\";\n\nimport { DeviceType, TimeclockStatus } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Timeclock } from \"./Timeclock\";\nimport { TimeclockAddress } from \"../../Response/TimeclockAddress\";\nimport { TimeclockState } from \"./TimeclockState\";\n\n/**\n * Defines a timeclock device.\n * @public\n */\nexport class TimeclockController extends Common<TimeclockState> implements Timeclock {\n /**\n * Creates a timeclock device.\n *\n * ```js\n * const timeclock = new Timeclock(processor, area, device);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param device The reference to the device.\n */\n constructor(processor: Processor, area: AreaAddress, device: TimeclockAddress) {\n super(DeviceType.Timeclock, processor, area, device, { state: \"Off\" });\n\n this.fields.set(\"state\", { type: \"String\", values: [\"On\", \"Off\"] });\n }\n\n /**\n * Recieves a state response from the connection and updates the device\n * state.\n *\n * ```js\n * timeclock.update({ EnabledState: \"Enabled\" });\n * ```\n *\n * @param status The current device state.\n */\n public update(status: TimeclockStatus): void {\n const previous = { ...this.status };\n\n this.state = {\n ...previous,\n state: status.EnabledState === \"Enabled\" ? \"On\" : \"Off\",\n };\n\n if (this.initialized && !equals(this.state, previous)) this.emit(\"Update\", this, this.state);\n\n this.initialized = true;\n }\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "import { DeviceState, DeviceType } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../../Response/AreaAddress\";\nimport { Common } from \"../Common\";\nimport { Processor } from \"../Processor/Processor\";\nimport { Unknown } from \"./Unknown\";\nimport { ZoneAddress } from \"../../Response/ZoneAddress\";\n\n/**\n * Defines an unknown device.\n * @public\n */\nexport class UnknownController extends Common<DeviceState> implements Unknown {\n /**\n * Creates a placeholder for an unknown device.\n *\n * ```js\n * const unknown = new Unknown(processor, area, zone);\n * ```\n *\n * @param processor The processor this device belongs to.\n * @param area The area this device is in.\n * @param zone The zone assigned to this device.\n */\n constructor(processor: Processor, area: AreaAddress, zone: ZoneAddress) {\n super(DeviceType.Unknown, processor, area, zone, { state: \"Unknown\" });\n }\n\n /**\n * Recieves a state response from the processor (not supported).\n */\n public update(): void {}\n\n /**\n * Controls this device (not supported).\n */\n public set = (): Promise<void> => Promise.resolve();\n}\n", "import { Device } from \"@mkellsy/hap-device\";\n\nimport { AreaAddress } from \"../Response/AreaAddress\";\nimport { Processor } from \"../Devices/Processor/Processor\";\n\n// Use console so Homebridge child-bridge logs capture this even if js-logger\n// is not wired (esbuild can isolate logger instances).\nconst log = {\n info: (message: string) => console.log(`[LEAP][MetaProbe] ${message}`),\n warn: (message: string) => console.warn(`[LEAP][MetaProbe] ${message}`),\n};\n\n/**\n * Candidate LEAP URLs that may expose grouping / catalog metadata.\n * Many will 404 or reject; that is expected and still useful signal.\n */\nconst PROBE_URLS: string[] = [\n \"/area\",\n \"/zone\",\n \"/device\",\n \"/controlstation\",\n \"/occupancygroup\",\n \"/group\",\n \"/areagroup\",\n \"/zonegroup\",\n \"/loadgroup\",\n \"/devicegroup\",\n \"/virtualbutton\",\n \"/preset\",\n \"/area/status\",\n \"/zone/status\",\n \"/server/1/status/ping\",\n \"/project\",\n \"/clientsetting\",\n \"/link\",\n \"/button\",\n \"/buttongroup\",\n \"/timeclock\",\n];\n\nfunction summarizeBody(body: unknown): string {\n if (body == null) return \"null\";\n\n if (Array.isArray(body)) {\n const first = body[0] as Record<string, unknown> | undefined;\n const keys = first != null && typeof first === \"object\" ? Object.keys(first).join(\",\") : \"\";\n\n return `array(len=${body.length}${keys ? ` sampleKeys=${keys}` : \"\"})`;\n }\n\n if (typeof body === \"object\") {\n const record = body as Record<string, unknown>;\n const keys = Object.keys(record);\n\n return `object(keys=${keys.slice(0, 20).join(\",\")}${keys.length > 20 ? \",...\" : \"\"})`;\n }\n\n if (typeof body === \"string\") {\n return `string(len=${body.length} preview=${JSON.stringify(body.slice(0, 200))})`;\n }\n\n return `${typeof body}:${String(body).slice(0, 120)}`;\n}\n\nfunction areaPath(areas: AreaAddress[], href: string | undefined): string {\n if (href == null) return \"\";\n\n const byHref = new Map(areas.map((a) => [a.href, a]));\n const names: string[] = [];\n let current: string | undefined = href;\n const seen = new Set<string>();\n\n while (current != null && !seen.has(current)) {\n seen.add(current);\n const area = byHref.get(current);\n\n if (area == null) break;\n\n names.unshift(area.Name);\n current = area.Parent?.href;\n }\n\n return names.join(\" / \");\n}\n\n/**\n * Live LEAP metadata probe: dumps area hierarchy, zone/device associations,\n * and tries extra endpoints that might correspond to \"groups\" in other apps.\n * @private\n */\nexport async function probeProcessorMetadata(processor: Processor, areas: AreaAddress[]): Promise<void> {\n log.info(`===== LEAP metadata probe start processor=${processor.id} areas=${areas.length} =====`);\n\n // Area tree (rooms / floors). UniFi Connect \"groups\" often map to this.\n for (const area of areas) {\n log.info(\n `AREA href=${area.href} name=${JSON.stringify(area.Name)} leaf=${area.IsLeaf} ` +\n `parent=${area.Parent?.href || \"none\"} path=${JSON.stringify(areaPath(areas, area.href))} ` +\n `keys=${Object.keys(area).join(\",\")}`,\n );\n }\n\n // Zones + control stations already fetched for leaf areas (cache-backed).\n for (const area of areas.filter((a) => a.IsLeaf)) {\n const path = areaPath(areas, area.href);\n\n try {\n const zones = await processor.zones(area);\n\n for (const zone of zones) {\n log.info(\n `ZONE area=${JSON.stringify(path)} name=${JSON.stringify(zone.Name)} ` +\n `href=${zone.href} control=${zone.ControlType} ` +\n `category=${zone.Category?.Type || \"\"} isLight=${zone.Category?.IsLight ?? \"?\"} ` +\n `assocArea=${zone.AssociatedArea?.href || \"\"} ` +\n `device=${zone.Device?.href || \"\"} keys=${Object.keys(zone).join(\",\")}`,\n );\n }\n } catch (error) {\n log.warn(`ZONE list failed for ${area.href}: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n try {\n const stations = await processor.controls(area);\n\n for (const station of stations) {\n const ganged = (station.AssociatedGangedDevices || [])\n .map((g) => `${g.Device?.DeviceType || \"?\"}@${g.Device?.href || \"?\"}`)\n .join(\",\");\n\n log.info(\n `STATION area=${JSON.stringify(path)} name=${JSON.stringify(station.Name)} ` +\n `href=${station.href} ganged=[${ganged}] keys=${Object.keys(station).join(\",\")}`,\n );\n }\n } catch (error) {\n log.warn(`STATION list failed for ${area.href}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // Live raw reads of candidate catalog endpoints (bypass high-level helpers).\n for (const url of PROBE_URLS) {\n try {\n const body = await processor.read(url);\n\n log.info(`PROBE ok url=${url} body=${summarizeBody(body)}`);\n\n // For small arrays/objects, dump a compact JSON sample.\n if (Array.isArray(body) && body.length > 0 && body.length <= 5) {\n log.info(`PROBE sample url=${url} ${JSON.stringify(body).slice(0, 1500)}`);\n } else if (Array.isArray(body) && body.length > 5) {\n log.info(`PROBE sample url=${url} first=${JSON.stringify(body[0]).slice(0, 800)}`);\n } else if (body != null && typeof body === \"object\" && !Array.isArray(body)) {\n log.info(`PROBE sample url=${url} ${JSON.stringify(body).slice(0, 1200)}`);\n }\n } catch (error) {\n log.info(`PROBE fail url=${url}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // Devices currently discovered by the client with room metadata.\n for (const device of processor.devices.values()) {\n const area = device.area as AreaAddress | undefined;\n const withPath = device as Device & { areaPath?: string };\n const path = typeof withPath.areaPath === \"string\" ? withPath.areaPath : areaPath(areas, area?.href);\n\n log.info(\n `DEVICE type=${device.type} name=${JSON.stringify(device.name)} room=${JSON.stringify(device.room)} ` +\n `areaPath=${JSON.stringify(path)} id=${device.id} href=${device.address?.href || \"\"} ` +\n `areaHref=${area?.href || \"\"} areaParent=${area?.Parent?.href || \"\"}`,\n );\n }\n\n log.info(`===== LEAP metadata probe done processor=${processor.id} =====`);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["src_exports", "__export", "Client", "connect", "pair", "__toCommonJS", "import_node_forge", "import_hap_device", "import_fs", "import_path", "import_net", "import_bson", "import_js_logger", "import_node_forge", "import_uuid", "import_event_emitter", "ResponseHeader", "ResponseStatus", "_ResponseStatus", "message", "code", "value", "parts", "Response", "_Response", "ResponseHeader", "value", "payload", "status", "ResponseStatus", "header", "key", "body", "Parser", "data", "callback", "response", "lines", "line", "Response", "ExceptionDetail", "import_event_emitter", "import_js_logger", "import_tls", "log", "getLogger", "KEEPALIVE_INITIAL_DELAY", "INACTIVITY_TIMEOUT", "Socket", "host", "port", "certificate", "data", "error", "resolve", "reject", "connection", "protocol", "_a", "_b", "message", "log", "getLogger", "SOCKET_PORT", "SECURE_SOCKET_PORT", "REACHABLE_TIMEOUT", "Connection", "Parser", "host", "certificate", "response", "tag", "request", "subscription", "data", "error", "__spreadValues", "resolve", "socket", "net", "success", "reject", "port", "subscriptions", "Socket", "protocol", "waits", "_a", "url", "_b", "body", "bodyType", "ExceptionDetail", "message", "kind", "csr", "timeout", "command", "listener", "requestType", "filename", "path", "fs", "bytes", "secure", "Association", "processor", "ip", "address", "Connection", "__async", "resolve", "reject", "request", "certificate", "error", "name", "keys", "import_fs", "import_path", "import_os", "import_bson", "import_js_logger", "log", "getLogger", "Context", "context", "keys", "i", "processors", "error", "key", "id", "processor", "__spreadValues", "filename", "directory", "path", "os", "filePath", "fs", "bytes", "size", "clear", "import_os", "import_path", "import_deep_equal", "import_flat_cache", "import_js_logger", "import_event_emitter", "import_tinkerhub_mdns", "import_hap_device", "log", "getLogger", "Discovery", "service", "systype", "host", "error", "addrs", "a", "cached", "Cache", "path", "os", "i", "_a", "entry", "equals", "type", "index", "target", "addresses", "import_js_logger", "import_colors", "import_hap_device", "import_event_emitter", "import_js_logger", "import_flat_cache", "import_colors", "import_os", "import_path", "import_event_emitter", "HEARTBEAT_DURATION", "ProcessorController", "id", "connection", "response", "error", "getLogger", "Colors", "Cache", "path", "os", "resolve", "reject", "key", "value", "url", "cached", "address", "type", "waits", "zones", "areas", "timeclocks", "field", "command", "listener", "import_hap_device", "import_deep_equal", "import_hap_device", "import_js_logger", "import_hap_device", "import_colors", "import_event_emitter", "Common", "type", "processor", "area", "definition", "state", "getLogger", "Colors", "_a", "ContactController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "DimmerController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "FanController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "speed", "__spreadProps", "equals", "value", "import_colors", "import_hap_device", "KeypadController", "Common", "processor", "area", "device", "groups", "__async", "_a", "i", "j", "button", "definition", "status", "error", "Colors", "import_colors", "import_hap_device", "ButtonMap", "import_hap_device", "import_event_emitter", "TriggerController", "processor", "button", "index", "options", "__spreadValues", "status", "_a", "event", "longPressTimeoutHandler", "doublePressTimeoutHandler", "RemoteController", "Common", "processor", "area", "device", "groups", "__async", "_a", "_b", "_c", "map", "ButtonMap", "i", "j", "button", "mapped", "index", "raiseLower", "trigger", "TriggerController", "btn", "status", "error", "Colors", "import_deep_equal", "import_hap_device", "OccupancyController", "Common", "processor", "area", "device", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "ShadeController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "waits", "import_deep_equal", "import_hap_device", "StripController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "equals", "import_deep_equal", "import_hap_device", "SwitchController", "Common", "processor", "area", "zone", "status", "previous", "__spreadValues", "__spreadProps", "equals", "import_deep_equal", "import_hap_device", "TimeclockController", "Common", "processor", "area", "device", "status", "previous", "__spreadValues", "__spreadProps", "equals", "import_hap_device", "UnknownController", "Common", "processor", "area", "zone", "createDevice", "processor", "area", "definition", "_a", "parseDeviceType", "ContactController", "DimmerController", "FanController", "KeypadController", "OccupancyController", "RemoteController", "ShadeController", "StripController", "SwitchController", "TimeclockController", "UnknownController", "value", "isAddressable", "device", "log", "message", "PROBE_URLS", "summarizeBody", "body", "first", "keys", "areaPath", "areas", "href", "_a", "byHref", "a", "names", "current", "seen", "area", "probeProcessorMetadata", "processor", "__async", "_b", "_c", "_d", "_e", "_f", "_g", "_h", "path", "zones", "zone", "error", "stations", "station", "ganged", "g", "url", "device", "withPath", "log", "getLogger", "RETRY_BACKOFF_DURATION", "Client", "refresh", "_a", "_b", "host", "addrs", "a", "ip", "address", "processor", "ProcessorController", "Connection", "Colors", "system", "project", "areas", "version", "type", "waits", "statuses", "status", "device", "error", "occupancy", "area", "resolve", "__async", "devices", "ready", "count", "zone", "probeProcessorMetadata", "state", "button", "action", "message", "Context", "Discovery", "paired", "id", "byHref", "names", "current", "seen", "node", "__spreadProps", "__spreadValues", "areaWithPath", "zones", "createDevice", "timeclocks", "timeclock", "controls", "control", "positions", "position", "parseDeviceType", "gangedDevice", "results", "result", "isAddressable", "value", "connect", "refresh", "Client", "pair", "resolve", "reject", "discovery", "Discovery", "context", "Context", "processor", "Association", "certificate", "error"]
|
|
7
7
|
}
|