isy-nodejs 1.0.1-alpha.27 → 1.0.1-alpha.28
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/dist/cjs/CodeGeneration/EnumFactory.js +6 -6
- package/dist/cjs/CodeGeneration/EnumFactory.js.map +1 -1
- package/dist/cjs/CodeGeneration/NodeClassFactory.js +7 -7
- package/dist/cjs/CodeGeneration/NodeClassFactory.js.map +1 -1
- package/dist/cjs/Devices/ISYDeviceNode.js.map +1 -1
- package/dist/cjs/Devices/Insteon/InsteonDevice.js.map +1 -1
- package/dist/cjs/Devices/Insteon/InsteonDeviceFactory.js +12 -8
- package/dist/cjs/Devices/Insteon/InsteonDeviceFactory.js.map +1 -1
- package/dist/cjs/Devices/Insteon/InsteonKeypadDevice.js +2 -2
- package/dist/cjs/Devices/Insteon/InsteonKeypadDevice.js.map +1 -1
- package/dist/cjs/Devices/Insteon/KeypadButton.js +52 -0
- package/dist/cjs/Devices/Insteon/KeypadButton.js.map +1 -0
- package/dist/cjs/Devices/NodeFactory.js +5 -4
- package/dist/cjs/Devices/NodeFactory.js.map +1 -1
- package/dist/cjs/Devices/index.js.map +1 -1
- package/dist/cjs/ISY.js +220 -213
- package/dist/cjs/ISY.js.map +1 -1
- package/dist/cjs/ISYNode.js +3 -3
- package/dist/cjs/ISYNode.js.map +1 -1
- package/dist/cjs/ISYScene.js.map +1 -1
- package/dist/cjs/Matter/Behaviors/ISYBridgedDeviceBehavior.js.map +1 -1
- package/dist/cjs/Matter/Behaviors/ISYClusterBehavior.js.map +1 -1
- package/dist/cjs/Matter/Bridge/Server.js +4 -4
- package/dist/cjs/Matter/Bridge/Server.js.map +1 -1
- package/dist/cjs/Model/ClusterMap.js +2 -2
- package/dist/cjs/Model/ClusterMap.js.map +1 -1
- package/dist/cjs/Model/NodeInfo.js +3 -3
- package/dist/cjs/Model/NodeInfo.js.map +1 -1
- package/dist/cjs/Utils.js.map +1 -1
- package/dist/cjs/types/CodeGeneration/EnumFactory.d.ts +1 -1
- package/dist/cjs/types/CodeGeneration/EnumFactory.d.ts.map +1 -1
- package/dist/cjs/types/CodeGeneration/NodeClassFactory.d.ts +1 -1
- package/dist/cjs/types/CodeGeneration/NodeClassFactory.d.ts.map +1 -1
- package/dist/cjs/types/Devices/EndpointFor.d.ts +1 -1
- package/dist/cjs/types/Devices/ISYDeviceNode.d.ts +2 -1
- package/dist/cjs/types/Devices/ISYDeviceNode.d.ts.map +1 -1
- package/dist/cjs/types/Devices/Insteon/InsteonDevice.d.ts +8 -7
- package/dist/cjs/types/Devices/Insteon/InsteonDevice.d.ts.map +1 -1
- package/dist/cjs/types/Devices/Insteon/InsteonDeviceFactory.d.ts +2 -1
- package/dist/cjs/types/Devices/Insteon/InsteonDeviceFactory.d.ts.map +1 -1
- package/dist/cjs/types/Devices/Insteon/InsteonFanDevice.d.ts.map +1 -1
- package/dist/cjs/types/Devices/Insteon/InsteonKeypadDevice.d.ts +4 -4
- package/dist/cjs/types/Devices/Insteon/InsteonKeypadDevice.d.ts.map +1 -1
- package/dist/cjs/types/Devices/Insteon/InsteonRelayDevice.d.ts.map +1 -1
- package/dist/cjs/types/Devices/Insteon/KeypadButton.d.ts +63 -0
- package/dist/cjs/types/Devices/Insteon/KeypadButton.d.ts.map +1 -0
- package/dist/cjs/types/Devices/NodeFactory.d.ts +2 -1
- package/dist/cjs/types/Devices/NodeFactory.d.ts.map +1 -1
- package/dist/cjs/types/Devices/index.d.ts +1 -1
- package/dist/cjs/types/Devices/index.d.ts.map +1 -1
- package/dist/cjs/types/ISY.d.ts +13 -28
- package/dist/cjs/types/ISY.d.ts.map +1 -1
- package/dist/cjs/types/ISYDevice.d.ts +1 -1
- package/dist/cjs/types/ISYDevice.d.ts.map +1 -1
- package/dist/cjs/types/ISYNode.d.ts +4 -2
- package/dist/cjs/types/ISYNode.d.ts.map +1 -1
- package/dist/cjs/types/Matter/Behaviors/ISYBridgedDeviceBehavior.d.ts +1 -1
- package/dist/cjs/types/Matter/Behaviors/ISYBridgedDeviceBehavior.d.ts.map +1 -1
- package/dist/cjs/types/Matter/Behaviors/ISYClusterBehavior.d.ts.map +1 -1
- package/dist/cjs/types/Matter/Bridge/Server.d.ts.map +1 -1
- package/dist/cjs/types/Model/ClusterMap.d.ts +1 -1
- package/dist/cjs/types/Model/ClusterMap.d.ts.map +1 -1
- package/dist/cjs/types/Model/EnumDefinition.d.ts +1 -1
- package/dist/cjs/types/Model/NodeInfo.d.ts +2 -2
- package/dist/cjs/types/Model/NodeInfo.d.ts.map +1 -1
- package/dist/cjs/types/Utils.d.ts +8 -1
- package/dist/cjs/types/Utils.d.ts.map +1 -1
- package/dist/esm/CodeGeneration/EnumFactory.js +1 -1
- package/dist/esm/CodeGeneration/EnumFactory.js.map +1 -1
- package/dist/esm/CodeGeneration/NodeClassFactory.js +1 -1
- package/dist/esm/CodeGeneration/NodeClassFactory.js.map +1 -1
- package/dist/esm/Devices/ISYDeviceNode.js.map +1 -1
- package/dist/esm/Devices/Insteon/InsteonDevice.js.map +1 -1
- package/dist/esm/Devices/Insteon/InsteonDeviceFactory.js +5 -1
- package/dist/esm/Devices/Insteon/InsteonDeviceFactory.js.map +1 -1
- package/dist/esm/Devices/Insteon/InsteonKeypadDevice.js +2 -2
- package/dist/esm/Devices/Insteon/InsteonKeypadDevice.js.map +1 -1
- package/dist/esm/Devices/Insteon/KeypadButton.js +48 -0
- package/dist/esm/Devices/Insteon/KeypadButton.js.map +1 -0
- package/dist/esm/Devices/NodeFactory.js +2 -1
- package/dist/esm/Devices/NodeFactory.js.map +1 -1
- package/dist/esm/Devices/index.js.map +1 -1
- package/dist/esm/ISY.js +220 -183
- package/dist/esm/ISY.js.map +1 -1
- package/dist/esm/ISYNode.js +2 -2
- package/dist/esm/ISYNode.js.map +1 -1
- package/dist/esm/ISYScene.js.map +1 -1
- package/dist/esm/Matter/Behaviors/ISYBridgedDeviceBehavior.js.map +1 -1
- package/dist/esm/Matter/Behaviors/ISYClusterBehavior.js.map +1 -1
- package/dist/esm/Matter/Bridge/Server.js +5 -5
- package/dist/esm/Matter/Bridge/Server.js.map +1 -1
- package/dist/esm/Model/ClusterMap.js +2 -2
- package/dist/esm/Model/ClusterMap.js.map +1 -1
- package/dist/esm/Model/NodeInfo.js +1 -1
- package/dist/esm/Model/NodeInfo.js.map +1 -1
- package/dist/esm/Utils.js.map +1 -1
- package/dist/esm/types/CodeGeneration/EnumFactory.d.ts +1 -1
- package/dist/esm/types/CodeGeneration/EnumFactory.d.ts.map +1 -1
- package/dist/esm/types/CodeGeneration/NodeClassFactory.d.ts +1 -1
- package/dist/esm/types/CodeGeneration/NodeClassFactory.d.ts.map +1 -1
- package/dist/esm/types/Devices/EndpointFor.d.ts +1 -1
- package/dist/esm/types/Devices/ISYDeviceNode.d.ts +2 -1
- package/dist/esm/types/Devices/ISYDeviceNode.d.ts.map +1 -1
- package/dist/esm/types/Devices/Insteon/InsteonDevice.d.ts +8 -7
- package/dist/esm/types/Devices/Insteon/InsteonDevice.d.ts.map +1 -1
- package/dist/esm/types/Devices/Insteon/InsteonDeviceFactory.d.ts +2 -1
- package/dist/esm/types/Devices/Insteon/InsteonDeviceFactory.d.ts.map +1 -1
- package/dist/esm/types/Devices/Insteon/InsteonFanDevice.d.ts.map +1 -1
- package/dist/esm/types/Devices/Insteon/InsteonKeypadDevice.d.ts +4 -4
- package/dist/esm/types/Devices/Insteon/InsteonKeypadDevice.d.ts.map +1 -1
- package/dist/esm/types/Devices/Insteon/InsteonRelayDevice.d.ts.map +1 -1
- package/dist/esm/types/Devices/Insteon/KeypadButton.d.ts +63 -0
- package/dist/esm/types/Devices/Insteon/KeypadButton.d.ts.map +1 -0
- package/dist/esm/types/Devices/NodeFactory.d.ts +2 -1
- package/dist/esm/types/Devices/NodeFactory.d.ts.map +1 -1
- package/dist/esm/types/Devices/index.d.ts +1 -1
- package/dist/esm/types/Devices/index.d.ts.map +1 -1
- package/dist/esm/types/ISY.d.ts +13 -28
- package/dist/esm/types/ISY.d.ts.map +1 -1
- package/dist/esm/types/ISYDevice.d.ts +1 -1
- package/dist/esm/types/ISYDevice.d.ts.map +1 -1
- package/dist/esm/types/ISYNode.d.ts +4 -2
- package/dist/esm/types/ISYNode.d.ts.map +1 -1
- package/dist/esm/types/Matter/Behaviors/ISYBridgedDeviceBehavior.d.ts +1 -1
- package/dist/esm/types/Matter/Behaviors/ISYBridgedDeviceBehavior.d.ts.map +1 -1
- package/dist/esm/types/Matter/Behaviors/ISYClusterBehavior.d.ts.map +1 -1
- package/dist/esm/types/Matter/Bridge/Server.d.ts.map +1 -1
- package/dist/esm/types/Model/ClusterMap.d.ts +1 -1
- package/dist/esm/types/Model/ClusterMap.d.ts.map +1 -1
- package/dist/esm/types/Model/NodeInfo.d.ts +2 -2
- package/dist/esm/types/Model/NodeInfo.d.ts.map +1 -1
- package/dist/esm/types/Utils.d.ts +8 -1
- package/dist/esm/types/Utils.d.ts.map +1 -1
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/CodeGeneration/EnumFactory.ts +2 -1
- package/src/CodeGeneration/NodeClassFactory.ts +2 -1
- package/src/Definitions/Global/Events.ts +2 -2
- package/src/Devices/ISYDeviceNode.ts +2 -1
- package/src/Devices/ISYMultiNodeDevice.ts +1 -1
- package/src/Devices/Insteon/InsteonDevice.ts +3 -2
- package/src/Devices/Insteon/InsteonDeviceFactory.ts +7 -2
- package/src/Devices/Insteon/InsteonFanDevice.ts +1 -1
- package/src/Devices/Insteon/InsteonKeypadDevice.ts +5 -5
- package/src/Devices/Insteon/InsteonRelayDevice.ts +1 -1
- package/src/Devices/Insteon/{Generated/KeypadButton.ts → KeypadButton.ts} +20 -20
- package/src/Devices/NodeFactory.ts +3 -2
- package/src/Devices/ZWave/ZWaveDimmerSwitchDevice.ts +1 -1
- package/src/Devices/index.ts +2 -2
- package/src/ISY.ts +249 -228
- package/src/ISYDevice.ts +3 -2
- package/src/ISYNode.ts +7 -5
- package/src/ISYScene.ts +1 -1
- package/src/Matter/Behaviors/ISYBridgedDeviceBehavior.ts +4 -2
- package/src/Matter/Behaviors/ISYClusterBehavior.ts +2 -12
- package/src/Matter/Bridge/Server.ts +8 -6
- package/src/Model/ClusterMap.ts +4 -3
- package/src/Model/NodeInfo.ts +4 -3
- package/src/Utils.ts +13 -6
package/src/ISY.ts
CHANGED
|
@@ -4,34 +4,15 @@ import { writeFile } from 'fs';
|
|
|
4
4
|
import { Parser, type ParserOptions } from 'xml2js';
|
|
5
5
|
import { parseBooleans, parseNumbers } from 'xml2js/lib/processors.js';
|
|
6
6
|
|
|
7
|
-
import axios from 'axios';
|
|
7
|
+
import axios, { type AxiosRequestConfig } from 'axios';
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
|
-
import { format, Logger, loggers } from 'winston';
|
|
10
|
-
import { Category } from './Definitions/Global/Categories.js';
|
|
11
|
-
import { Family } from './Definitions/Global/Families.js';
|
|
9
|
+
import { format, Logger, loggers, type LeveledLogMethod } from 'winston';
|
|
12
10
|
import { DeviceFactory } from './Devices/DeviceFactory.js';
|
|
13
11
|
import { ELKAlarmPanelDevice } from './Devices/Elk/ElkAlarmPanelDevice.js';
|
|
14
12
|
import { ElkAlarmSensorDevice } from './Devices/Elk/ElkAlarmSensorDevice.js';
|
|
15
|
-
import { InsteonBaseDevice } from './Devices/Insteon/InsteonBaseDevice.js';
|
|
16
|
-
import { InsteonOutletDevice } from './Devices/Insteon/InsteonDevice.js';
|
|
17
|
-
import { InsteonDimmableDevice } from './Devices/Insteon/InsteonDimmableDevice.js';
|
|
18
|
-
import { InsteonDimmerOutletDevice } from './Devices/Insteon/InsteonDimmerOutletDevice.js';
|
|
19
|
-
import { InsteonDimmerSwitchDevice } from './Devices/Insteon/InsteonDimmerSwitchDevice.js';
|
|
20
|
-
import { InsteonDoorWindowSensorDevice } from './Devices/Insteon/InsteonDoorWindowSensorDevice.js';
|
|
21
|
-
import { InsteonFanDevice, InsteonFanMotorDevice } from './Devices/Insteon/InsteonFanDevice.js';
|
|
22
|
-
import { InsteonKeypadButtonDevice } from './Devices/Insteon/InsteonKeypadDevice.js';
|
|
23
|
-
import { InsteonKeypadDimmerDevice } from './Devices/Insteon/InsteonKeypadDimmerDevice.js';
|
|
24
|
-
import { InsteonKeypadRelayDevice } from './Devices/Insteon/InsteonKeypadRelayDevice.js';
|
|
25
|
-
import { InsteonLeakSensorDevice } from './Devices/Insteon/InsteonLeakSensorDevice.js';
|
|
26
|
-
import { InsteonLockDevice } from './Devices/Insteon/InsteonLockDevice.js';
|
|
27
|
-
import { InsteonMotionSensorDevice } from './Devices/Insteon/InsteonMotionSensorDevice.js';
|
|
28
|
-
import { InsteonOnOffOutletDevice } from './Devices/Insteon/InsteonOnOffOutletDevice.js';
|
|
29
|
-
import { InsteonRelayDevice } from './Devices/Insteon/InsteonRelayDevice.js';
|
|
30
|
-
import { InsteonSmokeSensorDevice } from './Devices/Insteon/InsteonSmokeSensorDevice.js';
|
|
31
|
-
import { InsteonThermostatDevice } from './Devices/Insteon/InsteonThermostatDevice.js';
|
|
32
13
|
import { ISYDeviceNode } from './Devices/ISYDeviceNode.js';
|
|
33
14
|
import { EventType } from './Events/EventType.js';
|
|
34
|
-
import {
|
|
15
|
+
import { VariableType } from './ISYConstants.js';
|
|
35
16
|
import { type ISYDevice } from './ISYDevice.js';
|
|
36
17
|
import { ISYNode } from './ISYNode.js';
|
|
37
18
|
import { ISYScene } from './ISYScene.js';
|
|
@@ -46,39 +27,54 @@ import { NodeFactory } from './Devices/NodeFactory.js';
|
|
|
46
27
|
import type { Config } from './Model/Config.js';
|
|
47
28
|
import { findPackageJson } from './Utils.js';
|
|
48
29
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
ISYNode
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
30
|
+
|
|
31
|
+
class ISYError extends Error {
|
|
32
|
+
constructor(message: string)
|
|
33
|
+
constructor(error: Error)
|
|
34
|
+
constructor(messageOrError: string | Error) {
|
|
35
|
+
if(messageOrError instanceof Error) {
|
|
36
|
+
super(messageOrError.message);
|
|
37
|
+
this.stack = messageOrError.stack;
|
|
38
|
+
this.cause = messageOrError;
|
|
39
|
+
this.name = 'ISYError';
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
else if(typeof messageOrError === 'string') {
|
|
43
|
+
super(messageOrError);
|
|
44
|
+
this.name = 'ISYError';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
class ISYNodeError extends ISYError {
|
|
52
|
+
|
|
53
|
+
constructor(message: string, node: ISYNode)
|
|
54
|
+
constructor(error:Error, node: ISYNode)
|
|
55
|
+
constructor(messageOrError: string | Error, node: ISYNode)
|
|
56
|
+
{
|
|
57
|
+
super(messageOrError as any);
|
|
58
|
+
this.name = 'ISYNodeError';
|
|
59
|
+
this.node = node;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
node: ISYNode;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type InitStep = 'config' | 'loadNodes' | 'readFolders' | 'readDevices' | 'readScenes' | 'variables' | 'websocket' | 'refreshStatuses' | 'initialize';
|
|
66
|
+
|
|
67
|
+
class ISYInitializationError extends ISYError {
|
|
68
|
+
|
|
69
|
+
step: InitStep;
|
|
70
|
+
constructor(message: string, step: InitStep);
|
|
71
|
+
constructor(error: Error, step: InitStep);
|
|
72
|
+
constructor(messageOrError: string | Error, step: InitStep) {
|
|
73
|
+
super(messageOrError as any);
|
|
74
|
+
this.name = 'ISYInitializationError';
|
|
75
|
+
this.step = step;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
82
78
|
|
|
83
79
|
const defaultParserOptions: ParserOptions = {
|
|
84
80
|
explicitArray: false,
|
|
@@ -132,6 +128,8 @@ interface ISYConfig {
|
|
|
132
128
|
protocol: 'http' | 'https';
|
|
133
129
|
username: string;
|
|
134
130
|
|
|
131
|
+
socketPath?: string;
|
|
132
|
+
|
|
135
133
|
// #endregion Properties (8)
|
|
136
134
|
}
|
|
137
135
|
|
|
@@ -139,6 +137,7 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
139
137
|
// #region Properties (30)
|
|
140
138
|
|
|
141
139
|
public readonly credentials: { username: string; password: string };
|
|
140
|
+
|
|
142
141
|
public readonly deviceList: Map<string, ISYDevice<any, any, any, any>> = new Map();
|
|
143
142
|
public readonly deviceMap: Map<string, string[]> = new Map();
|
|
144
143
|
public readonly displayNameFormat: string;
|
|
@@ -173,6 +172,21 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
173
172
|
|
|
174
173
|
public apiVersion: string;
|
|
175
174
|
|
|
175
|
+
socketPath: string;
|
|
176
|
+
|
|
177
|
+
public get axiosOptions(): AxiosRequestConfig
|
|
178
|
+
{
|
|
179
|
+
return {
|
|
180
|
+
baseURL: `${this.protocol}://${this.host}:${this.port}`,
|
|
181
|
+
auth: {
|
|
182
|
+
username: this.credentials.username,
|
|
183
|
+
password: this.credentials.password
|
|
184
|
+
},
|
|
185
|
+
socketPath: this.socketPath,
|
|
186
|
+
validateStatus: (status) => status >= 200 && status < 300,
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
}
|
|
176
190
|
// #endregion Properties (30)
|
|
177
191
|
|
|
178
192
|
// #region Constructors (1)
|
|
@@ -185,6 +199,7 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
185
199
|
this.displayNameFormat = config.displayNameFormat ?? '${location ?? folder} ${spokenName ?? name}';
|
|
186
200
|
this.host = config.host;
|
|
187
201
|
this.port = config.port;
|
|
202
|
+
|
|
188
203
|
this.credentials = {
|
|
189
204
|
username: config.username,
|
|
190
205
|
password: config.password
|
|
@@ -362,68 +377,80 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
362
377
|
});
|
|
363
378
|
}
|
|
364
379
|
|
|
365
|
-
public async initialize(): Promise<
|
|
380
|
+
public async initialize(): Promise<boolean> {
|
|
366
381
|
const that = this;
|
|
367
382
|
try {
|
|
368
383
|
this.apiVersion = (await findPackageJson()).version;
|
|
384
|
+
} catch (e) {
|
|
385
|
+
this.logger.error(`Unable to read package.json: ${e.message}`);
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
369
388
|
await this.loadConfig();
|
|
370
389
|
await this.loadNodes();
|
|
371
390
|
await this.loadVariables(VariableType.Integer);
|
|
372
391
|
await this.loadVariables(VariableType.State);
|
|
373
392
|
await this.refreshStatuses();
|
|
374
393
|
await this.#finishInitialize(true);
|
|
394
|
+
return true;
|
|
375
395
|
} catch (e) {
|
|
376
|
-
|
|
396
|
+
if (e instanceof ISYInitializationError) {
|
|
397
|
+
this.logger.error(`Error initializing ISY during (${e.step}): ${e.message}`);
|
|
398
|
+
} else {
|
|
399
|
+
this.logger.error(`Error initializing ISY: ${e.message}`);
|
|
400
|
+
}
|
|
401
|
+
throw e;
|
|
377
402
|
} finally {
|
|
378
403
|
if (this.nodesLoaded !== true) {
|
|
379
404
|
that.#finishInitialize(false);
|
|
380
405
|
}
|
|
381
406
|
}
|
|
382
|
-
return Promise.resolve(true);
|
|
383
407
|
}
|
|
384
408
|
|
|
385
|
-
public initializeWebSocket() {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
409
|
+
public async initializeWebSocket() {
|
|
410
|
+
try {
|
|
411
|
+
const that = this;
|
|
412
|
+
const auth = `Basic ${Buffer.from(`${this.credentials.username}:${this.credentials.password}`).toString('base64')}`;
|
|
413
|
+
this.logger.info(`Opening webSocket: ${this.wsprotocol}://${this.address}/rest/subscribe`);
|
|
414
|
+
if (this.webSocket) {
|
|
415
|
+
try {
|
|
416
|
+
this.webSocket.close();
|
|
417
|
+
} catch (e) {
|
|
418
|
+
this.logger.warn(`Error closing existing websocket: ${e.message}`);
|
|
419
|
+
}
|
|
394
420
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
ping: 10
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
this.lastActivity = new Date();
|
|
405
|
-
|
|
406
|
-
this.webSocket
|
|
407
|
-
.on('message', (event: any) => {
|
|
408
|
-
that.logger.silly(`Received message: ${JSON.stringify(event.data, null, 2)}`);
|
|
409
|
-
that.handleWebSocketMessage(event);
|
|
410
|
-
})
|
|
411
|
-
.on('error', (err: any, response: any) => {
|
|
412
|
-
that.logger.warn(`Websocket subscription error: ${JSON.stringify(err.message)}`);
|
|
413
|
-
/// throw new Error('Error calling ISY' + err);
|
|
414
|
-
})
|
|
415
|
-
.on('fail', (data: string, response: any) => {
|
|
416
|
-
that.logger.warn(`Websocket subscription failure: ${data}`);
|
|
417
|
-
throw new Error('Failed calling ISY');
|
|
418
|
-
})
|
|
419
|
-
.on('abort', () => {
|
|
420
|
-
that.logger.warn('Websocket subscription aborted.');
|
|
421
|
-
throw new Error('Call to ISY was aborted');
|
|
422
|
-
})
|
|
423
|
-
.on('timeout', (ms: string) => {
|
|
424
|
-
that.logger.warn(`Websocket subscription timed out after ${ms} milliseconds.`);
|
|
425
|
-
throw new Error('Timeout contacting ISY');
|
|
421
|
+
this.webSocket = new WebSocket.Client(`${this.wsprotocol}://${this.address}/rest/subscribe`, ['ISYSUB'], {
|
|
422
|
+
headers: {
|
|
423
|
+
Origin: 'com.universal-devices.websockets.isy',
|
|
424
|
+
Authorization: auth
|
|
425
|
+
},
|
|
426
|
+
ping: 10
|
|
426
427
|
});
|
|
428
|
+
|
|
429
|
+
this.lastActivity = new Date();
|
|
430
|
+
|
|
431
|
+
this.webSocket
|
|
432
|
+
.on('message', (event: any) => {
|
|
433
|
+
that.logger.silly(`Received message: ${Utils.logStringify(event.data, 1)}`);
|
|
434
|
+
that.handleWebSocketMessage(event);
|
|
435
|
+
})
|
|
436
|
+
.on('error', (err: any, response: any) => {
|
|
437
|
+
that.logger.warn(`Websocket subscription error: ${Utils.logStringify(err, 1)}`);
|
|
438
|
+
})
|
|
439
|
+
.on('fail', (data: string, response: any) => {
|
|
440
|
+
that.logger.warn(`Websocket subscription failure: ${data}`);
|
|
441
|
+
throw new Error('Websocket subscription failure');
|
|
442
|
+
})
|
|
443
|
+
.on('abort', () => {
|
|
444
|
+
that.logger.warn('Websocket subscription aborted.');
|
|
445
|
+
throw new Error('Websocket subscription aborted.');
|
|
446
|
+
})
|
|
447
|
+
.on('timeout', (ms: string) => {
|
|
448
|
+
that.logger.warn(`Websocket subscription timed out after ${ms} milliseconds.`);
|
|
449
|
+
throw new Error('Timeout contacting ISY');
|
|
450
|
+
});
|
|
451
|
+
} catch (e) {
|
|
452
|
+
throw new ISYInitializationError(e, 'websocket');
|
|
453
|
+
}
|
|
427
454
|
}
|
|
428
455
|
|
|
429
456
|
public async loadConfig(): Promise<any> {
|
|
@@ -452,27 +479,31 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
452
479
|
}
|
|
453
480
|
return configuration;
|
|
454
481
|
} catch (e) {
|
|
455
|
-
|
|
456
|
-
throw Error(`Error Loading Config: ${(e as Error).message}`);
|
|
482
|
+
throw new ISYInitializationError(e, 'config');
|
|
457
483
|
}
|
|
458
484
|
}
|
|
459
485
|
|
|
460
486
|
public async loadNodes(): Promise<any> {
|
|
461
487
|
try {
|
|
488
|
+
this.logger.info('Loading ISY Nodes');
|
|
462
489
|
const result = await this.sendRequest('nodes');
|
|
463
490
|
if (this.isDebugEnabled) writeFile(this.storagePath + '/ISYNodesDump.json', JSON.stringify(result), this.logger.error);
|
|
464
|
-
|
|
465
|
-
await this.#
|
|
466
|
-
await this.#
|
|
467
|
-
await this.#readSceneNodes(result).catch((p) => this.logger.error('Error Loading Scenes', p));
|
|
491
|
+
await this.#readFolderNodes(result);
|
|
492
|
+
await this.#readDeviceNodes(result);
|
|
493
|
+
await this.#readSceneNodes(result);
|
|
468
494
|
return result;
|
|
469
495
|
} catch (e) {
|
|
470
|
-
|
|
496
|
+
if (e instanceof ISYInitializationError) {
|
|
497
|
+
throw e;
|
|
498
|
+
} else {
|
|
499
|
+
throw new ISYInitializationError(e, 'loadNodes');
|
|
500
|
+
}
|
|
471
501
|
}
|
|
472
502
|
}
|
|
473
503
|
|
|
474
504
|
public async loadVariables(type: VariableType): Promise<any> {
|
|
475
505
|
const that = this;
|
|
506
|
+
this.logger.info(`Loading ISY Variables of type: ${type}`);
|
|
476
507
|
return this.sendRequest(`vars/definitions/${type}`)
|
|
477
508
|
.then((result) => that.#createVariables(type, result))
|
|
478
509
|
.then(() => that.sendRequest(`vars/get/${type}`))
|
|
@@ -502,40 +533,11 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
502
533
|
if (that.isDebugEnabled) {
|
|
503
534
|
writeFile(that.storagePath + '/ISYStatusDump.json', JSON.stringify(result), this.logger.error);
|
|
504
535
|
}
|
|
505
|
-
this.logger.debug(result);
|
|
536
|
+
//this.logger.debug(result);
|
|
506
537
|
for (const node of result.nodes.node) {
|
|
507
|
-
|
|
508
|
-
let device = that.getDevice(node.id) as unknown as ISYNode<any, any, any, any>;
|
|
538
|
+
let device = that.getNode(node.id) as unknown as ISYNode<any, any, any, any>;
|
|
509
539
|
if (device !== null && device !== undefined) {
|
|
510
|
-
// let child = device.children.find((p) => p.address === node.id);
|
|
511
|
-
// if (child) {
|
|
512
|
-
// //Case FanLinc where we treat the light as a child of the fan.
|
|
513
|
-
// device = child;
|
|
514
|
-
// }
|
|
515
540
|
device.parseResult(node.property);
|
|
516
|
-
|
|
517
|
-
// if (Array.isArray(node.property)) {
|
|
518
|
-
// for (let prop of node.property) {
|
|
519
|
-
// device.applyStatus(prop)
|
|
520
|
-
// // device.local[prop.id] = device.convertFrom(prop.value, prop.uom);
|
|
521
|
-
// // device.formatted[prop.id] = prop.formatted;
|
|
522
|
-
// // device.uom[prop.id] = prop.uom;
|
|
523
|
-
// // device.logger(
|
|
524
|
-
// // `Property ${Controls[prop.id].label} (${prop.id}) initialized to: ${device.local[prop.id]} (${
|
|
525
|
-
// // device.formatted[prop.id]
|
|
526
|
-
// // })`
|
|
527
|
-
// // );
|
|
528
|
-
// }
|
|
529
|
-
// } else if (node.property) {
|
|
530
|
-
// device.local[node.property.id] = device.convertFrom(node.property.value, node.property.uom);
|
|
531
|
-
// device.formatted[node.property.id] = node.property.formatted;
|
|
532
|
-
// device.uom[node.property.id] = node.property.uom;
|
|
533
|
-
// device.logger(
|
|
534
|
-
// `Property ${Controls[node.property.id].label} (${node.property.id}) initialized to: ${
|
|
535
|
-
// device.local[node.property.id]
|
|
536
|
-
// } (${device.formatted[node.property.id]})`
|
|
537
|
-
// );
|
|
538
|
-
// }
|
|
539
541
|
}
|
|
540
542
|
}
|
|
541
543
|
} catch (e) {
|
|
@@ -544,9 +546,7 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
544
546
|
}
|
|
545
547
|
|
|
546
548
|
public async sendGetVariable(id: any, type: any, handleResult: (arg0: number, arg1: number) => void) {
|
|
547
|
-
const uriToUse =
|
|
548
|
-
this.logger.info(`Sending ISY command...${uriToUse}`);
|
|
549
|
-
|
|
549
|
+
const uriToUse = `vars/get/${type}/${id}`;
|
|
550
550
|
return this.sendRequest(uriToUse).then((p) => handleResult(p.val, p.init));
|
|
551
551
|
}
|
|
552
552
|
|
|
@@ -584,19 +584,24 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
584
584
|
options: {
|
|
585
585
|
parserOptions?: ParserOptions;
|
|
586
586
|
trailingSlash: boolean;
|
|
587
|
-
requestLogLevel?:
|
|
588
|
-
responseLogLevel?:
|
|
589
|
-
errorLogLevel?:
|
|
590
|
-
|
|
587
|
+
requestLogLevel?: Utils.LogLevel;
|
|
588
|
+
responseLogLevel?: Utils.LogLevel;
|
|
589
|
+
errorLogLevel?: Utils.LogLevel;
|
|
590
|
+
throwOnError?: boolean;
|
|
591
|
+
} & Utils.ISYRequestConfig = { trailingSlash: true }
|
|
591
592
|
): Promise<any> {
|
|
592
593
|
const requestLogLevel = options.requestLogLevel ?? 'debug';
|
|
593
594
|
const responseLogLevel = options.responseLogLevel ?? 'silly';
|
|
594
595
|
url = `${this.protocol}://${this.address}/rest/${url}${options.trailingSlash ? '/' : ''}`;
|
|
595
596
|
this.logger.log(requestLogLevel, `Sending request: ${url}`);
|
|
597
|
+
const reqOps = { ...this.axiosOptions, ...options, url: path.join('/rest', url) };
|
|
598
|
+
/*{
|
|
599
|
+
auth: { username: this.credentials.username, password: this.credentials.password },
|
|
600
|
+
baseURL: `${this.protocol}://${this.address}`,
|
|
601
|
+
|
|
602
|
+
}*/
|
|
596
603
|
try {
|
|
597
|
-
const response = await axios.get(url,
|
|
598
|
-
auth: { username: this.credentials.username, password: this.credentials.password }
|
|
599
|
-
});
|
|
604
|
+
const response = await axios.get(url,reqOps);
|
|
600
605
|
if (response.data) {
|
|
601
606
|
if (response.headers['content-type'].toString().includes('xml')) {
|
|
602
607
|
let curParser = parser;
|
|
@@ -606,18 +611,22 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
606
611
|
this.logger.log(requestLogLevel ?? 'debug', `Response: ${JSON.stringify(s)}`);
|
|
607
612
|
return s;
|
|
608
613
|
} else if (response.headers['content-type'].toString().includes('json')) {
|
|
609
|
-
this.logger.log(responseLogLevel
|
|
614
|
+
this.logger.log(responseLogLevel, `Response: ${JSON.stringify(response.data)}`);
|
|
610
615
|
return JSON.parse(response.data);
|
|
611
616
|
} else {
|
|
612
|
-
this.logger.log(responseLogLevel
|
|
617
|
+
this.logger.log(responseLogLevel, `Response Header: ${JSON.stringify(response.headers)} Response: ${JSON.stringify(response.data)}`);
|
|
613
618
|
return response.data;
|
|
614
619
|
}
|
|
615
620
|
}
|
|
616
621
|
} catch (error) {
|
|
617
|
-
if (options.
|
|
618
|
-
|
|
622
|
+
if (options.throwOnError) {
|
|
623
|
+
throw error;
|
|
619
624
|
} else {
|
|
620
|
-
|
|
625
|
+
if (options.errorLogLevel) {
|
|
626
|
+
this.logger.log(options.errorLogLevel, `Error sending request to ISY: ${error?.message}`);
|
|
627
|
+
} else {
|
|
628
|
+
this.logger.error(`Error sending request to ISY: ${error?.message}`);
|
|
629
|
+
}
|
|
621
630
|
}
|
|
622
631
|
}
|
|
623
632
|
}
|
|
@@ -728,101 +737,113 @@ export class ISY extends EventEmitter implements Disposable {
|
|
|
728
737
|
} */
|
|
729
738
|
|
|
730
739
|
async #readDeviceNodes(obj: { nodes: { node: NodeInfo[] } }) {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
let newDevice: ISYDeviceNode<any, any, any, any> = null;
|
|
745
|
-
|
|
746
|
-
// let deviceTypeInfo = this.isyTypeToTypeName(device.type, device.address);
|
|
747
|
-
// this.logger.info(JSON.stringify(deviceTypeInfo));
|
|
748
|
-
|
|
749
|
-
const enabled = nodeInfo.enabled ?? true;
|
|
750
|
-
const d = await NodeFactory.get(nodeInfo);
|
|
751
|
-
const m = DeviceFactory.getDeviceDetails(nodeInfo);
|
|
752
|
-
const cls = m?.class ?? d;
|
|
753
|
-
nodeInfo.property = Array.isArray(nodeInfo.property) ? nodeInfo.property : [nodeInfo.property];
|
|
754
|
-
nodeInfo.state = nodeInfo.property.reduce((acc, p) => {
|
|
755
|
-
if (p && p?.id) {
|
|
756
|
-
p.name = p.name == '' ? undefined : p.name;
|
|
757
|
-
acc[p.id] = p;
|
|
740
|
+
try {
|
|
741
|
+
this.logger.info('Loading Device Nodes');
|
|
742
|
+
|
|
743
|
+
for (const nodeInfo of obj.nodes.node) {
|
|
744
|
+
try {
|
|
745
|
+
this.logger.debug(`Loading Device Node: ${JSON.stringify(nodeInfo)}`);
|
|
746
|
+
if (!this.deviceMap.has(nodeInfo.pnode)) {
|
|
747
|
+
const address = nodeInfo.address;
|
|
748
|
+
this.deviceMap[nodeInfo.pnode] = {
|
|
749
|
+
address
|
|
750
|
+
};
|
|
751
|
+
} else {
|
|
752
|
+
this.deviceMap[nodeInfo.pnode].push(nodeInfo.address);
|
|
758
753
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
newDevice = new ISYDeviceNode<any, any, any, any>(this, nodeInfo);
|
|
774
|
-
} else if (newDevice !== null) {
|
|
775
|
-
if (m.unsupported) {
|
|
776
|
-
this.logger.warn('Device not currently supported: ' + JSON.stringify(nodeInfo) + ' /n It has been mapped to: ' + d.name);
|
|
777
|
-
}
|
|
778
|
-
try {
|
|
779
|
-
await newDevice.refreshNotes();
|
|
780
|
-
} catch (e) {
|
|
781
|
-
this.logger.debug('No notes found.');
|
|
754
|
+
let newDevice: ISYDeviceNode<any, any, any, any> = null;
|
|
755
|
+
|
|
756
|
+
// let deviceTypeInfo = this.isyTypeToTypeName(device.type, device.address);
|
|
757
|
+
// this.logger.info(JSON.stringify(deviceTypeInfo));
|
|
758
|
+
|
|
759
|
+
const enabled = nodeInfo.enabled ?? true;
|
|
760
|
+
const d = await NodeFactory.get(nodeInfo);
|
|
761
|
+
const m = DeviceFactory.getDeviceDetails(nodeInfo);
|
|
762
|
+
const cls = m?.class ?? d;
|
|
763
|
+
nodeInfo.property = Array.isArray(nodeInfo.property) ? nodeInfo.property : [nodeInfo.property];
|
|
764
|
+
nodeInfo.state = nodeInfo.property.reduce((acc, p) => {
|
|
765
|
+
if (p && p?.id) {
|
|
766
|
+
p.name = p.name == '' ? undefined : p.name;
|
|
767
|
+
acc[p.id] = p;
|
|
782
768
|
}
|
|
769
|
+
return acc;
|
|
770
|
+
}, {});
|
|
771
|
+
newDevice = new cls(this, nodeInfo) as ISYDeviceNode<any, any, any, any>;
|
|
772
|
+
|
|
773
|
+
if (m) {
|
|
774
|
+
newDevice.productName = m.name;
|
|
775
|
+
newDevice.model = `(${m.modelNumber}) ${m.name} v.${m.version}`;
|
|
776
|
+
newDevice.modelNumber = m.modelNumber;
|
|
777
|
+
newDevice.version = m.version;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
if (enabled) {
|
|
781
|
+
if (newDevice === null) {
|
|
782
|
+
this.logger.warn(`Device type resolution failed for ${nodeInfo.name} with type: ${nodeInfo.type} and nodedef: ${nodeInfo.nodeDefId}`);
|
|
783
|
+
newDevice = new ISYDeviceNode<any, any, any, any>(this, nodeInfo);
|
|
784
|
+
} else if (newDevice !== null) {
|
|
785
|
+
if (m.unsupported) {
|
|
786
|
+
this.logger.warn('Device not currently supported: ' + JSON.stringify(nodeInfo) + ' /n It has been mapped to: ' + d.name);
|
|
787
|
+
}
|
|
788
|
+
try {
|
|
789
|
+
await newDevice.refreshNotes();
|
|
790
|
+
} catch (e) {
|
|
791
|
+
this.logger.debug('No notes found.');
|
|
792
|
+
}
|
|
783
793
|
|
|
784
|
-
|
|
785
|
-
|
|
794
|
+
// if (!newDevice.hidden) {
|
|
795
|
+
// }
|
|
786
796
|
|
|
787
|
-
|
|
797
|
+
// this.deviceList.push(newDevice);
|
|
798
|
+
} else {
|
|
799
|
+
}
|
|
800
|
+
this.nodeMap.set(newDevice.address, newDevice);
|
|
788
801
|
} else {
|
|
802
|
+
this.logger.info(`Ignoring disabled device: ${nodeInfo.name}`);
|
|
789
803
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
this.logger.info(`Ignoring disabled device: ${nodeInfo.name}`);
|
|
804
|
+
} catch (e) {
|
|
805
|
+
this.logger.error(`Error loading device node: ${e.message}`);
|
|
793
806
|
}
|
|
794
|
-
} catch (e) {
|
|
795
|
-
this.logger.error(`Error loading device node: ${e.message}`);
|
|
796
807
|
}
|
|
808
|
+
this.logger.info(`${this.nodeMap.size} devices added.`);
|
|
809
|
+
} catch (e) {
|
|
810
|
+
throw new ISYInitializationError(e, 'readDevices');
|
|
797
811
|
}
|
|
798
|
-
|
|
799
|
-
this.logger.info(`${this.nodeMap.size} devices added.`);
|
|
800
812
|
}
|
|
801
813
|
|
|
802
814
|
async #readFolderNodes(result: { nodes: { folder: any } }) {
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
815
|
+
try {
|
|
816
|
+
this.logger.info('Loading Folder Nodes');
|
|
817
|
+
if (result?.nodes?.folder) {
|
|
818
|
+
for (const folder of result.nodes.folder) {
|
|
819
|
+
this.logger.debug(`Loading Folder Node: ${JSON.stringify(folder)}`);
|
|
820
|
+
this.folderMap.set(folder.address, folder.name);
|
|
821
|
+
}
|
|
808
822
|
}
|
|
823
|
+
} catch (e) {
|
|
824
|
+
throw new ISYInitializationError(e, 'readFolders');
|
|
809
825
|
}
|
|
810
826
|
}
|
|
811
827
|
|
|
812
828
|
async #readSceneNodes(result: { nodes: { group: any } }) {
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
829
|
+
try {
|
|
830
|
+
this.logger.info('Loading Scene Nodes');
|
|
831
|
+
for (const scene of result.nodes?.group) {
|
|
832
|
+
if (scene.name === 'ISY' || scene.name === 'IoX' || scene.name === 'Auto DR') {
|
|
833
|
+
continue;
|
|
834
|
+
} // Skip ISY & Auto DR Scenes
|
|
835
|
+
|
|
836
|
+
const newScene = new ISYScene(this, scene);
|
|
837
|
+
try {
|
|
838
|
+
await newScene.refreshNotes();
|
|
839
|
+
} catch (e) {
|
|
840
|
+
this.logger.debug('No notes found.');
|
|
841
|
+
}
|
|
842
|
+
this.sceneList.set(newScene.address, newScene);
|
|
824
843
|
}
|
|
825
|
-
this.
|
|
844
|
+
this.logger.info(`${this.sceneList.size} scenes added.`);
|
|
845
|
+
} catch (e) {
|
|
846
|
+
throw new ISYInitializationError(e, 'readScenes');
|
|
826
847
|
}
|
|
827
848
|
}
|
|
828
849
|
|
package/src/ISYDevice.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Command } from './Definitions/Global/Commands.js';
|
|
2
2
|
import type { Driver } from './Definitions/Global/Drivers.js';
|
|
3
3
|
import type { UnitOfMeasure } from './Definitions/Global/UOM.js';
|
|
4
|
-
import type { Family
|
|
5
|
-
import type {
|
|
4
|
+
import type { Family } from './Definitions/index.js';
|
|
5
|
+
import type { ISY } from './ISY.js';
|
|
6
|
+
import type { ISYNode } from './ISYNode.js';
|
|
6
7
|
import type { ISYScene } from './ISYScene.js';
|
|
7
8
|
import type { DriverState } from './Model/DriverState.js';
|
|
8
9
|
import type { StringKeys } from './Utils.js';
|