@switchbot/homebridge-switchbot 2.0.0-beta.8 → 2.0.0
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/CHANGELOG.md +10 -1
- package/README.md +3 -2
- package/config.schema.json +91 -19
- package/dist/device/bot.d.ts +34 -28
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +657 -648
- package/dist/device/bot.js.map +1 -1
- package/dist/device/ceilinglight.d.ts +137 -0
- package/dist/device/ceilinglight.d.ts.map +1 -0
- package/dist/device/ceilinglight.js +1127 -0
- package/dist/device/ceilinglight.js.map +1 -0
- package/dist/device/colorbulb.d.ts +36 -19
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +486 -309
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +18 -8
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +306 -237
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +23 -16
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +566 -502
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/humidifier.d.ts +24 -18
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +453 -369
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/lock.d.ts +27 -8
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +305 -148
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +22 -16
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +367 -267
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +24 -12
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +381 -213
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +18 -8
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +279 -216
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +27 -17
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +295 -251
- package/dist/device/plug.js.map +1 -1
- package/dist/device/striplight.d.ts +43 -19
- package/dist/device/striplight.d.ts.map +1 -1
- package/dist/device/striplight.js +506 -262
- package/dist/device/striplight.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +9 -12
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +278 -230
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +5 -3
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +154 -104
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +11 -8
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +133 -86
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +10 -7
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +160 -109
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/light.d.ts +11 -8
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +137 -103
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +11 -8
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +145 -98
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +12 -9
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +143 -93
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +9 -10
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +132 -89
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +8 -9
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +132 -89
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +13 -12
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +524 -418
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +19 -11
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js.map +1 -1
- package/homebridge-ui/public/index.html +1 -0
- package/package.json +11 -9
- package/src/device/bot.ts +656 -659
- package/src/device/ceilinglight.ts +1208 -0
- package/src/device/colorbulb.ts +490 -344
- package/src/device/contact.ts +309 -241
- package/src/device/curtain.ts +571 -516
- package/src/device/humidifier.ts +456 -403
- package/src/device/lock.ts +314 -149
- package/src/device/meter.ts +378 -280
- package/src/device/meterplus.ts +391 -219
- package/src/device/motion.ts +285 -222
- package/src/device/plug.ts +299 -260
- package/src/device/striplight.ts +522 -289
- package/src/irdevice/airconditioner.ts +282 -241
- package/src/irdevice/airpurifier.ts +151 -103
- package/src/irdevice/camera.ts +131 -85
- package/src/irdevice/fan.ts +157 -106
- package/src/irdevice/light.ts +135 -103
- package/src/irdevice/other.ts +143 -97
- package/src/irdevice/tv.ts +142 -93
- package/src/irdevice/vacuumcleaner.ts +131 -89
- package/src/irdevice/waterheater.ts +130 -89
- package/src/platform.ts +522 -446
- package/src/settings.ts +20 -11
- package/.github/npm-version-script.js +0 -81
package/src/device/bot.ts
CHANGED
|
@@ -3,6 +3,7 @@ import crypto from 'crypto';
|
|
|
3
3
|
import { Context } from 'vm';
|
|
4
4
|
import { IncomingMessage } from 'http';
|
|
5
5
|
import { interval, Subject } from 'rxjs';
|
|
6
|
+
import superStringify from 'super-stringify';
|
|
6
7
|
import { SwitchBotPlatform } from '../platform';
|
|
7
8
|
import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
|
|
8
9
|
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
@@ -29,7 +30,6 @@ export class Bot {
|
|
|
29
30
|
|
|
30
31
|
// Characteristic Values
|
|
31
32
|
On!: CharacteristicValue;
|
|
32
|
-
OnCached!: CharacteristicValue;
|
|
33
33
|
BatteryLevel!: CharacteristicValue;
|
|
34
34
|
StatusLowBattery!: CharacteristicValue;
|
|
35
35
|
|
|
@@ -40,7 +40,6 @@ export class Bot {
|
|
|
40
40
|
// BLE Others
|
|
41
41
|
connected?: boolean;
|
|
42
42
|
switchbot!: switchbot;
|
|
43
|
-
SwitchToOpenAPI?: boolean;
|
|
44
43
|
serviceData!: serviceData;
|
|
45
44
|
address!: ad['address'];
|
|
46
45
|
mode!: serviceData['mode'];
|
|
@@ -61,6 +60,10 @@ export class Bot {
|
|
|
61
60
|
botUpdateInProgress!: boolean;
|
|
62
61
|
doBotUpdate!: Subject<void>;
|
|
63
62
|
|
|
63
|
+
// Connection
|
|
64
|
+
private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'BLE/OpenAPI');
|
|
65
|
+
private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'BLE/OpenAPI');
|
|
66
|
+
|
|
64
67
|
constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
|
|
65
68
|
// default placeholders
|
|
66
69
|
this.logs(device);
|
|
@@ -69,20 +72,8 @@ export class Bot {
|
|
|
69
72
|
this.PressOrSwitch(device);
|
|
70
73
|
this.allowPushChanges(device);
|
|
71
74
|
this.config(device);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.accessory.context.On = this.On;
|
|
75
|
-
} else {
|
|
76
|
-
this.On = this.accessory.context.On;
|
|
77
|
-
}
|
|
78
|
-
if (device.bot?.doublePress) {
|
|
79
|
-
this.doublePress = device.bot?.doublePress;
|
|
80
|
-
this.accessory.context.doublePress = this.doublePress;
|
|
81
|
-
} else {
|
|
82
|
-
this.doublePress = 1;
|
|
83
|
-
}
|
|
84
|
-
this.BatteryLevel = 100;
|
|
85
|
-
this.StatusLowBattery = 0;
|
|
75
|
+
this.context();
|
|
76
|
+
this.DoublePress(device);
|
|
86
77
|
|
|
87
78
|
// this is subject we use to track when we need to POST changes to the SwitchBot API
|
|
88
79
|
this.doBotUpdate = new Subject();
|
|
@@ -117,10 +108,10 @@ export class Bot {
|
|
|
117
108
|
// Add switchService
|
|
118
109
|
(this.switchService = accessory.getService(this.platform.Service.Switch) || accessory.addService(this.platform.Service.Switch)),
|
|
119
110
|
`${accessory.displayName} Switch`;
|
|
120
|
-
this.infoLog(
|
|
111
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Switch`);
|
|
121
112
|
|
|
122
113
|
this.switchService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
123
|
-
this.switchService.getCharacteristic(this.platform.Characteristic.On).onSet(this.
|
|
114
|
+
this.switchService.getCharacteristic(this.platform.Characteristic.On).onSet(this.OnSet.bind(this));
|
|
124
115
|
} else if (device.bot?.deviceType === 'garagedoor') {
|
|
125
116
|
this.removeFanService(accessory);
|
|
126
117
|
this.removeLockService(accessory);
|
|
@@ -136,10 +127,10 @@ export class Bot {
|
|
|
136
127
|
(this.garageDoorService =
|
|
137
128
|
accessory.getService(this.platform.Service.GarageDoorOpener) || accessory.addService(this.platform.Service.GarageDoorOpener)),
|
|
138
129
|
`${accessory.displayName} Garage Door Opener`;
|
|
139
|
-
this.infoLog(
|
|
130
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Garage Door Opener`);
|
|
140
131
|
|
|
141
132
|
this.garageDoorService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
142
|
-
this.garageDoorService.getCharacteristic(this.platform.Characteristic.TargetDoorState).onSet(this.
|
|
133
|
+
this.garageDoorService.getCharacteristic(this.platform.Characteristic.TargetDoorState).onSet(this.OnSet.bind(this));
|
|
143
134
|
this.garageDoorService.setCharacteristic(this.platform.Characteristic.ObstructionDetected, false);
|
|
144
135
|
} else if (device.bot?.deviceType === 'door') {
|
|
145
136
|
this.removeFanService(accessory);
|
|
@@ -155,7 +146,7 @@ export class Bot {
|
|
|
155
146
|
// Add switchService
|
|
156
147
|
(this.doorService = accessory.getService(this.platform.Service.Door) || accessory.addService(this.platform.Service.Door)),
|
|
157
148
|
`${accessory.displayName} Door`;
|
|
158
|
-
this.infoLog(
|
|
149
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Door`);
|
|
159
150
|
|
|
160
151
|
this.doorService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
161
152
|
this.doorService
|
|
@@ -166,7 +157,7 @@ export class Bot {
|
|
|
166
157
|
maxValue: 100,
|
|
167
158
|
minStep: 100,
|
|
168
159
|
})
|
|
169
|
-
.onSet(this.
|
|
160
|
+
.onSet(this.OnSet.bind(this));
|
|
170
161
|
this.doorService.setCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
|
|
171
162
|
} else if (device.bot?.deviceType === 'window') {
|
|
172
163
|
this.removeFanService(accessory);
|
|
@@ -182,7 +173,7 @@ export class Bot {
|
|
|
182
173
|
// Add switchService
|
|
183
174
|
(this.windowService = accessory.getService(this.platform.Service.Window) || accessory.addService(this.platform.Service.Window)),
|
|
184
175
|
`${accessory.displayName} Window`;
|
|
185
|
-
this.infoLog(
|
|
176
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window`);
|
|
186
177
|
|
|
187
178
|
this.windowService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
188
179
|
this.windowService
|
|
@@ -193,7 +184,7 @@ export class Bot {
|
|
|
193
184
|
maxValue: 100,
|
|
194
185
|
minStep: 100,
|
|
195
186
|
})
|
|
196
|
-
.onSet(this.
|
|
187
|
+
.onSet(this.OnSet.bind(this));
|
|
197
188
|
this.windowService.setCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
|
|
198
189
|
} else if (device.bot?.deviceType === 'windowcovering') {
|
|
199
190
|
this.removeFanService(accessory);
|
|
@@ -210,7 +201,7 @@ export class Bot {
|
|
|
210
201
|
(this.windowCoveringService =
|
|
211
202
|
accessory.getService(this.platform.Service.WindowCovering) || accessory.addService(this.platform.Service.WindowCovering)),
|
|
212
203
|
`${accessory.displayName} Window Covering`;
|
|
213
|
-
this.infoLog(
|
|
204
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Window Covering`);
|
|
214
205
|
|
|
215
206
|
this.windowCoveringService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
216
207
|
this.windowCoveringService
|
|
@@ -221,7 +212,7 @@ export class Bot {
|
|
|
221
212
|
maxValue: 100,
|
|
222
213
|
minStep: 100,
|
|
223
214
|
})
|
|
224
|
-
.onSet(this.
|
|
215
|
+
.onSet(this.OnSet.bind(this));
|
|
225
216
|
this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
|
|
226
217
|
} else if (device.bot?.deviceType === 'lock') {
|
|
227
218
|
this.removeFanService(accessory);
|
|
@@ -237,10 +228,10 @@ export class Bot {
|
|
|
237
228
|
// Add switchService
|
|
238
229
|
(this.lockService = accessory.getService(this.platform.Service.LockMechanism) || accessory.addService(this.platform.Service.LockMechanism)),
|
|
239
230
|
`${accessory.displayName} Lock`;
|
|
240
|
-
this.infoLog(
|
|
231
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Lock`);
|
|
241
232
|
|
|
242
233
|
this.lockService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
243
|
-
this.lockService.getCharacteristic(this.platform.Characteristic.LockTargetState).onSet(this.
|
|
234
|
+
this.lockService.getCharacteristic(this.platform.Characteristic.LockTargetState).onSet(this.OnSet.bind(this));
|
|
244
235
|
} else if (device.bot?.deviceType === 'faucet') {
|
|
245
236
|
this.removeFanService(accessory);
|
|
246
237
|
this.removeLockService(accessory);
|
|
@@ -255,10 +246,10 @@ export class Bot {
|
|
|
255
246
|
// Add switchService
|
|
256
247
|
(this.faucetService = accessory.getService(this.platform.Service.Faucet) || accessory.addService(this.platform.Service.Faucet)),
|
|
257
248
|
`${accessory.displayName} Faucet`;
|
|
258
|
-
this.infoLog(
|
|
249
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Faucet`);
|
|
259
250
|
|
|
260
251
|
this.faucetService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
261
|
-
this.faucetService.getCharacteristic(this.platform.Characteristic.Active).onSet(this.
|
|
252
|
+
this.faucetService.getCharacteristic(this.platform.Characteristic.Active).onSet(this.OnSet.bind(this));
|
|
262
253
|
} else if (device.bot?.deviceType === 'fan') {
|
|
263
254
|
this.removeLockService(accessory);
|
|
264
255
|
this.removeDoorService(accessory);
|
|
@@ -273,10 +264,10 @@ export class Bot {
|
|
|
273
264
|
// Add switchService
|
|
274
265
|
(this.fanService = accessory.getService(this.platform.Service.Fan) || accessory.addService(this.platform.Service.Fan)),
|
|
275
266
|
`${accessory.displayName} Fan`;
|
|
276
|
-
this.infoLog(
|
|
267
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Fan`);
|
|
277
268
|
|
|
278
269
|
this.fanService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
279
|
-
this.fanService.getCharacteristic(this.platform.Characteristic.On).onSet(this.
|
|
270
|
+
this.fanService.getCharacteristic(this.platform.Characteristic.On).onSet(this.OnSet.bind(this));
|
|
280
271
|
} else if (device.bot?.deviceType === 'stateful') {
|
|
281
272
|
this.removeFanService(accessory);
|
|
282
273
|
this.removeLockService(accessory);
|
|
@@ -293,12 +284,12 @@ export class Bot {
|
|
|
293
284
|
accessory.getService(this.platform.Service.StatefulProgrammableSwitch) ||
|
|
294
285
|
accessory.addService(this.platform.Service.StatefulProgrammableSwitch)),
|
|
295
286
|
`${accessory.displayName} Stateful Programmable Switch`;
|
|
296
|
-
this.infoLog(
|
|
287
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Stateful Programmable Switch`);
|
|
297
288
|
|
|
298
289
|
this.statefulProgrammableSwitchService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
299
290
|
this.statefulProgrammableSwitchService
|
|
300
291
|
.getCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState)
|
|
301
|
-
.onSet(this.
|
|
292
|
+
.onSet(this.OnSet.bind(this));
|
|
302
293
|
} else {
|
|
303
294
|
this.removeFanService(accessory);
|
|
304
295
|
this.removeLockService(accessory);
|
|
@@ -313,25 +304,25 @@ export class Bot {
|
|
|
313
304
|
// Add outletService
|
|
314
305
|
(this.outletService = accessory.getService(this.platform.Service.Outlet) || accessory.addService(this.platform.Service.Outlet)),
|
|
315
306
|
`${accessory.displayName} Outlet`;
|
|
316
|
-
this.infoLog(
|
|
307
|
+
this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Outlet`);
|
|
317
308
|
|
|
318
309
|
this.outletService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
|
|
319
|
-
this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.
|
|
310
|
+
this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.OnSet.bind(this));
|
|
320
311
|
}
|
|
321
312
|
|
|
322
313
|
// Battery Service
|
|
323
|
-
if (!
|
|
324
|
-
this.debugLog(
|
|
314
|
+
if (!this.BLE) {
|
|
315
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`);
|
|
325
316
|
this.batteryService = this.accessory.getService(this.platform.Service.Battery);
|
|
326
317
|
accessory.removeService(this.batteryService!);
|
|
327
|
-
} else if (
|
|
328
|
-
this.debugLog(
|
|
318
|
+
} else if (this.BLE && !this.batteryService) {
|
|
319
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`);
|
|
329
320
|
(this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)),
|
|
330
321
|
`${accessory.displayName} Battery`;
|
|
331
322
|
|
|
332
323
|
this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`);
|
|
333
324
|
} else {
|
|
334
|
-
this.debugLog(
|
|
325
|
+
this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Battery Service Not Added`);
|
|
335
326
|
}
|
|
336
327
|
|
|
337
328
|
// Retrieve initial values and updateHomekit
|
|
@@ -345,29 +336,25 @@ export class Bot {
|
|
|
345
336
|
});
|
|
346
337
|
|
|
347
338
|
// Watch for Bot change events
|
|
348
|
-
// We put in a debounce of
|
|
339
|
+
// We put in a debounce of 1000ms so we don't make duplicate calls
|
|
349
340
|
this.doBotUpdate
|
|
350
341
|
.pipe(
|
|
351
342
|
tap(() => {
|
|
352
343
|
this.botUpdateInProgress = true;
|
|
353
344
|
}),
|
|
354
|
-
debounceTime(
|
|
345
|
+
debounceTime(this.platform.config.options!.pushRate! * 1000),
|
|
355
346
|
)
|
|
356
347
|
.subscribe(async () => {
|
|
357
348
|
try {
|
|
358
|
-
interval(
|
|
349
|
+
interval(15000)
|
|
359
350
|
.pipe(take(this.doublePress!))
|
|
360
351
|
.subscribe(async () => {
|
|
361
352
|
await this.pushChanges();
|
|
362
353
|
});
|
|
363
354
|
} catch (e: any) {
|
|
364
|
-
this.
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
368
|
-
if (this.platform.debugMode) {
|
|
369
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges,` + ` Error: ${JSON.stringify(e)}`);
|
|
370
|
-
}
|
|
355
|
+
this.apiError(e);
|
|
356
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
|
|
357
|
+
+ ` Error Message: ${superStringify(e.message)}`);
|
|
371
358
|
}
|
|
372
359
|
this.botUpdateInProgress = false;
|
|
373
360
|
});
|
|
@@ -377,28 +364,29 @@ export class Bot {
|
|
|
377
364
|
* Parse the device status from the SwitchBot api
|
|
378
365
|
*/
|
|
379
366
|
async parseStatus(): Promise<void> {
|
|
380
|
-
if (this.
|
|
367
|
+
if (this.BLE) {
|
|
368
|
+
await this.BLEparseStatus();
|
|
369
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
381
370
|
await this.openAPIparseStatus();
|
|
382
371
|
} else {
|
|
383
|
-
|
|
372
|
+
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
373
|
+
+ ` ${this.device.connectionType}, parseStatus will not happen.`);
|
|
384
374
|
}
|
|
385
375
|
}
|
|
386
376
|
|
|
387
377
|
async BLEparseStatus(): Promise<void> {
|
|
388
|
-
this.debugLog(
|
|
378
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
|
|
389
379
|
// BLEmode (true if Switch Mode) | (false if Press Mode)
|
|
390
380
|
if (this.mode) {
|
|
391
|
-
this.
|
|
392
|
-
this.accessory.context.On = this.OnCached;
|
|
381
|
+
this.accessory.context.On = this.On;
|
|
393
382
|
if (this.On === undefined) {
|
|
394
383
|
this.On = Boolean(this.state);
|
|
395
384
|
}
|
|
396
|
-
this.debugLog(
|
|
385
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, mode: ${this.mode}, On: ${this.On}`);
|
|
397
386
|
} else {
|
|
398
387
|
this.On = false;
|
|
399
|
-
this.
|
|
400
|
-
this.accessory.
|
|
401
|
-
this.debugLog(`Bot: ${this.accessory.displayName} Press Mode, mode: ${this.mode}, On: ${this.On}`);
|
|
388
|
+
this.accessory.context.On = this.On;
|
|
389
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode, mode: ${this.mode}, On: ${this.On}`);
|
|
402
390
|
}
|
|
403
391
|
|
|
404
392
|
this.BatteryLevel = Number(this.battery);
|
|
@@ -410,207 +398,151 @@ export class Bot {
|
|
|
410
398
|
if (Number.isNaN(this.BatteryLevel)) {
|
|
411
399
|
this.BatteryLevel = 100;
|
|
412
400
|
}
|
|
413
|
-
this.debugLog(
|
|
401
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
|
|
414
402
|
}
|
|
415
403
|
|
|
416
404
|
async openAPIparseStatus(): Promise<void> {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
405
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
|
|
406
|
+
if (this.botMode === 'press') {
|
|
407
|
+
this.On = false;
|
|
408
|
+
this.accessory.context.On = this.On;
|
|
409
|
+
} else {
|
|
410
|
+
this.accessory.context.On = this.On;
|
|
411
|
+
if (this.On === undefined) {
|
|
423
412
|
this.On = false;
|
|
424
|
-
this.OnCached = this.On;
|
|
425
|
-
this.accessory.context.On = this.OnCached;
|
|
426
|
-
} else {
|
|
427
|
-
/*if (this.power === 'on') {
|
|
428
|
-
this.On = true;
|
|
429
|
-
this.OnCached = this.On;
|
|
430
|
-
this.accessory.context.On = this.OnCached;
|
|
431
|
-
} else {
|
|
432
|
-
this.On = false;
|
|
433
|
-
this.OnCached = this.On;
|
|
434
|
-
this.accessory.context.On = this.OnCached;
|
|
435
|
-
}*/
|
|
436
|
-
this.OnCached = this.On;
|
|
437
|
-
this.accessory.context.On = this.OnCached;
|
|
438
|
-
if (this.On === undefined) {
|
|
439
|
-
this.On = false;
|
|
440
|
-
}
|
|
441
413
|
}
|
|
442
|
-
this.debugLog(`Bot: ${this.accessory.displayName} On: ${this.On}`);
|
|
443
414
|
}
|
|
415
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
444
416
|
}
|
|
445
417
|
|
|
446
418
|
/**
|
|
447
419
|
* Asks the SwitchBot API for the latest device information
|
|
448
420
|
*/
|
|
449
421
|
async refreshStatus(): Promise<void> {
|
|
450
|
-
if (this.
|
|
422
|
+
if (this.BLE) {
|
|
451
423
|
await this.BLERefreshStatus();
|
|
452
|
-
} else {
|
|
424
|
+
} else if (this.OpenAPI && this.platform.config.credentials?.token) {
|
|
453
425
|
await this.openAPIRefreshStatus();
|
|
426
|
+
} else {
|
|
427
|
+
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
428
|
+
+ ` ${this.device.connectionType}, refreshStatus will not happen.`);
|
|
454
429
|
}
|
|
455
430
|
}
|
|
456
431
|
|
|
457
432
|
async BLERefreshStatus(): Promise<void> {
|
|
458
|
-
this.debugLog(
|
|
433
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
|
|
459
434
|
const switchbot = await this.platform.connectBLE();
|
|
460
435
|
// Convert to BLE Address
|
|
461
436
|
this.device.bleMac = this.device
|
|
462
437
|
.deviceId!.match(/.{1,2}/g)!
|
|
463
438
|
.join(':')
|
|
464
439
|
.toLowerCase();
|
|
465
|
-
this.debugLog(
|
|
440
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
|
|
466
441
|
this.getCustomBLEAddress(switchbot);
|
|
467
442
|
// Start to monitor advertisement packets
|
|
468
|
-
if (switchbot
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
})
|
|
476
|
-
.then(() => {
|
|
443
|
+
if (switchbot !== false) {
|
|
444
|
+
switchbot
|
|
445
|
+
.startScan({
|
|
446
|
+
model: 'H',
|
|
447
|
+
id: this.device.bleMac,
|
|
448
|
+
})
|
|
449
|
+
.then(() => {
|
|
477
450
|
// Set an event hander
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
this.
|
|
482
|
-
this.
|
|
483
|
-
this.
|
|
484
|
-
this.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
this.battery = ad.serviceData.battery;
|
|
490
|
-
this.debugLog(`Bot: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
|
|
491
|
-
this.debugLog(
|
|
492
|
-
`Bot: ${this.accessory.displayName}, model: ${ad.serviceData.model}, modelName: ${ad.serviceData.modelName},` +
|
|
451
|
+
switchbot.onadvertisement = (ad: ad) => {
|
|
452
|
+
this.address = ad.address;
|
|
453
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},`
|
|
454
|
+
+ ` BLE Address Found: ${this.address}`);
|
|
455
|
+
this.serviceData = ad.serviceData;
|
|
456
|
+
this.mode = ad.serviceData.mode;
|
|
457
|
+
this.state = ad.serviceData.state;
|
|
458
|
+
this.battery = ad.serviceData.battery;
|
|
459
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
|
|
460
|
+
this.debugLog(
|
|
461
|
+
`${this.device.deviceType}: ${this.accessory.displayName}, model: ${ad.serviceData.model}, modelName: ${ad.serviceData.modelName},` +
|
|
493
462
|
` mode: ${ad.serviceData.mode}, state: ${ad.serviceData.state}, battery: ${ad.serviceData.battery}`,
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
if (this.serviceData) {
|
|
466
|
+
this.connected = true;
|
|
467
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
|
|
468
|
+
} else {
|
|
469
|
+
this.connected = false;
|
|
470
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
// Wait 2 seconds
|
|
474
|
+
return switchbot.wait(this.scanDuration * 1000);
|
|
475
|
+
})
|
|
476
|
+
.then(async () => {
|
|
508
477
|
// Stop to monitor
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
if (this.platform.config.credentials?.token) {
|
|
516
|
-
this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
517
|
-
this.SwitchToOpenAPI = true;
|
|
518
|
-
await this.openAPIRefreshStatus();
|
|
478
|
+
switchbot.stopScan();
|
|
479
|
+
if (this.connected) {
|
|
480
|
+
this.BLEparseStatus();
|
|
481
|
+
this.updateHomeKitCharacteristics();
|
|
482
|
+
} else {
|
|
483
|
+
await this.BLERefreshConnection(switchbot);
|
|
519
484
|
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
this.
|
|
526
|
-
`Bot: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
|
|
527
|
-
);
|
|
528
|
-
}
|
|
529
|
-
if (this.platform.config.credentials?.token) {
|
|
530
|
-
this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
531
|
-
this.SwitchToOpenAPI = true;
|
|
532
|
-
await this.openAPIRefreshStatus();
|
|
533
|
-
}
|
|
534
|
-
this.apiError(e);
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
async getCustomBLEAddress(switchbot: any) {
|
|
539
|
-
if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
|
|
540
|
-
(async () => {
|
|
541
|
-
// Start to monitor advertisement packets
|
|
542
|
-
await switchbot.startScan({
|
|
543
|
-
model: 'H',
|
|
485
|
+
})
|
|
486
|
+
.catch(async (e: any) => {
|
|
487
|
+
this.apiError(e);
|
|
488
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
|
|
489
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
490
|
+
await this.BLERefreshConnection(switchbot);
|
|
544
491
|
});
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
this.warnLog(`Bot: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
|
|
548
|
-
};
|
|
549
|
-
await switchbot.wait(10000);
|
|
550
|
-
// Stop to monitor
|
|
551
|
-
switchbot.stopScan();
|
|
552
|
-
})();
|
|
492
|
+
} else {
|
|
493
|
+
await this.BLERefreshConnection(switchbot);
|
|
553
494
|
}
|
|
554
495
|
}
|
|
555
496
|
|
|
556
497
|
async openAPIRefreshStatus(): Promise<void> {
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
this.debugLog(`d: ${d}`);
|
|
585
|
-
});
|
|
586
|
-
res.on('end', () => {
|
|
587
|
-
try {
|
|
588
|
-
this.deviceStatus = JSON.parse(rawData);
|
|
589
|
-
this.debugLog(`Bot: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
|
|
590
|
-
this.power = this.deviceStatus.body.power;
|
|
591
|
-
this.parseStatus();
|
|
592
|
-
this.updateHomeKitCharacteristics();
|
|
593
|
-
} catch (e: any) {
|
|
594
|
-
this.errorLog(`Bot: ${this.accessory.displayName} error message: ${e.message}`);
|
|
595
|
-
}
|
|
596
|
-
});
|
|
498
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
|
|
499
|
+
try {
|
|
500
|
+
const t = Date.now();
|
|
501
|
+
const nonce = 'requestID';
|
|
502
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
503
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
504
|
+
const sign = signTerm.toString('base64');
|
|
505
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
506
|
+
const options = {
|
|
507
|
+
hostname: HostDomain,
|
|
508
|
+
port: 443,
|
|
509
|
+
path: `${DevicePath}/${this.device.deviceId}/status`,
|
|
510
|
+
method: 'GET',
|
|
511
|
+
headers: {
|
|
512
|
+
Authorization: this.platform.config.credentials?.token,
|
|
513
|
+
sign: sign,
|
|
514
|
+
nonce: nonce,
|
|
515
|
+
t: t,
|
|
516
|
+
'Content-Type': 'application/json',
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
const req = https.request(options, (res) => {
|
|
520
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
|
|
521
|
+
let rawData = '';
|
|
522
|
+
res.on('data', (d) => {
|
|
523
|
+
rawData += d;
|
|
524
|
+
this.debugLog(`d: ${d}`);
|
|
597
525
|
});
|
|
598
|
-
|
|
599
|
-
|
|
526
|
+
res.on('end', () => {
|
|
527
|
+
try {
|
|
528
|
+
this.deviceStatus = JSON.parse(rawData);
|
|
529
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
|
|
530
|
+
this.power = this.deviceStatus.body.power;
|
|
531
|
+
this.openAPIparseStatus();
|
|
532
|
+
this.updateHomeKitCharacteristics();
|
|
533
|
+
} catch (e: any) {
|
|
534
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
535
|
+
}
|
|
600
536
|
});
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
this.errorLog(
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` + ` Error: ${JSON.stringify(e)}`);
|
|
611
|
-
}
|
|
612
|
-
this.apiError(e);
|
|
613
|
-
}
|
|
537
|
+
});
|
|
538
|
+
req.on('error', (e: any) => {
|
|
539
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
540
|
+
});
|
|
541
|
+
req.end();
|
|
542
|
+
} catch (e: any) {
|
|
543
|
+
this.apiError(e);
|
|
544
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
|
|
545
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`);
|
|
614
546
|
}
|
|
615
547
|
}
|
|
616
548
|
|
|
@@ -622,10 +554,13 @@ export class Bot {
|
|
|
622
554
|
* Bot - "command" "press" "default" = trigger press
|
|
623
555
|
*/
|
|
624
556
|
async pushChanges(): Promise<void> {
|
|
625
|
-
if (this.
|
|
557
|
+
if (this.BLE) {
|
|
626
558
|
await this.BLEpushChanges();
|
|
627
|
-
} else {
|
|
559
|
+
} else if (this.OpenAPI) {
|
|
628
560
|
await this.openAPIpushChanges();
|
|
561
|
+
} else {
|
|
562
|
+
this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
|
|
563
|
+
+ ` ${this.device.connectionType}, pushChanges will not happen.`);
|
|
629
564
|
}
|
|
630
565
|
interval(5000)
|
|
631
566
|
.pipe(take(1))
|
|
@@ -635,184 +570,192 @@ export class Bot {
|
|
|
635
570
|
}
|
|
636
571
|
|
|
637
572
|
async BLEpushChanges(): Promise<void> {
|
|
638
|
-
this.debugLog(
|
|
639
|
-
if (this.On !== this.
|
|
640
|
-
this.debugLog(
|
|
573
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
|
|
574
|
+
if (this.On !== this.accessory.context.On || this.allowPush) {
|
|
575
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
|
|
641
576
|
const switchbot = await this.platform.connectBLE();
|
|
642
577
|
// Convert to BLE Address
|
|
643
578
|
this.device.bleMac = this.device
|
|
644
579
|
.deviceId!.match(/.{1,2}/g)!
|
|
645
580
|
.join(':')
|
|
646
581
|
.toLowerCase();
|
|
647
|
-
this.debugLog(
|
|
582
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
|
|
648
583
|
//if (switchbot !== false) {
|
|
649
584
|
if (this.botMode === 'press') {
|
|
650
|
-
this.debugLog(
|
|
585
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
|
|
651
586
|
switchbot
|
|
652
587
|
.discover({ model: 'H', quick: true, id: this.device.bleMac })
|
|
653
588
|
.then((device_list: { press: (arg0: { id: string | undefined }) => any }[]) => {
|
|
654
|
-
this.infoLog(
|
|
589
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
655
590
|
return device_list[0].press({ id: this.device.bleMac });
|
|
656
591
|
})
|
|
657
592
|
.then(() => {
|
|
658
|
-
this.debugLog(
|
|
659
|
-
this.On =
|
|
660
|
-
this.OnCached = this.On;
|
|
661
|
-
this.accessory.context.On = this.OnCached;
|
|
593
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
|
|
594
|
+
this.accessory.context.On = this.On;
|
|
662
595
|
setTimeout(() => {
|
|
663
596
|
if (this.device.bot?.deviceType === 'switch') {
|
|
664
597
|
this.switchService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
|
|
665
598
|
} else {
|
|
666
599
|
this.outletService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
|
|
667
600
|
}
|
|
668
|
-
this.debugLog(
|
|
601
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}, Switch Timeout`);
|
|
669
602
|
}, 500);
|
|
670
603
|
})
|
|
671
604
|
.catch(async (e: any) => {
|
|
672
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
|
|
673
|
-
if (this.deviceLogging.includes('debug')) {
|
|
674
|
-
this.errorLog(
|
|
675
|
-
`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
|
|
676
|
-
);
|
|
677
|
-
}
|
|
678
|
-
if (this.platform.debugMode) {
|
|
679
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error: ${JSON.stringify(e)}`);
|
|
680
|
-
}
|
|
681
|
-
if (this.platform.config.credentials?.token) {
|
|
682
|
-
this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
683
|
-
await this.openAPIpushChanges();
|
|
684
|
-
}
|
|
685
605
|
this.apiError(e);
|
|
606
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
|
|
607
|
+
+ ` Connection & botMode: ${this.botMode}, Error Message: ${superStringify(e.message)}`);
|
|
608
|
+
await this.BLEPushConnection();
|
|
686
609
|
});
|
|
687
610
|
} else if (this.botMode === 'switch') {
|
|
688
|
-
this.debugLog(
|
|
611
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode: ${this.botMode}`);
|
|
689
612
|
switchbot
|
|
690
613
|
.discover({ model: 'H', quick: true, id: this.device.bleMac })
|
|
691
614
|
.then((device_list: any) => {
|
|
692
|
-
this.infoLog(
|
|
615
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
693
616
|
return this.turnOnOff(device_list);
|
|
694
617
|
})
|
|
695
618
|
.then(() => {
|
|
696
|
-
this.debugLog(
|
|
697
|
-
this.
|
|
698
|
-
this.accessory.context.On = this.OnCached;
|
|
619
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
|
|
620
|
+
this.accessory.context.On = this.On;
|
|
699
621
|
})
|
|
700
622
|
.catch(async (e: any) => {
|
|
701
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
|
|
702
|
-
if (this.deviceLogging.includes('debug')) {
|
|
703
|
-
this.errorLog(
|
|
704
|
-
`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
|
|
705
|
-
);
|
|
706
|
-
}
|
|
707
|
-
if (this.platform.debugMode) {
|
|
708
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error: ${JSON.stringify(e)}`);
|
|
709
|
-
}
|
|
710
|
-
if (this.platform.config.credentials?.token) {
|
|
711
|
-
this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
|
|
712
|
-
await this.openAPIpushChanges();
|
|
713
|
-
}
|
|
714
623
|
this.apiError(e);
|
|
624
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
|
|
625
|
+
+ ` Connection & botMode: ${this.botMode}, Error Message: ${superStringify(e.message)}`);
|
|
626
|
+
await this.BLEPushConnection();
|
|
715
627
|
});
|
|
716
628
|
} else {
|
|
717
|
-
|
|
629
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
|
|
718
630
|
}
|
|
631
|
+
} else {
|
|
632
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, `
|
|
633
|
+
+`OnCached: ${this.accessory.context.On}`);
|
|
719
634
|
}
|
|
720
|
-
this.OnCached = this.On;
|
|
721
|
-
this.accessory.context.On = this.OnCached;
|
|
722
635
|
}
|
|
723
636
|
|
|
724
|
-
async
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
637
|
+
async openAPIpushChanges(): Promise<void> {
|
|
638
|
+
try {
|
|
639
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
|
|
640
|
+
if (this.On !== this.accessory.context.On || this.allowPush) {
|
|
641
|
+
// Make Push On request to the API
|
|
642
|
+
const t = Date.now();
|
|
643
|
+
const nonce = 'requestID';
|
|
644
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
645
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
|
|
646
|
+
.update(Buffer.from(data, 'utf-8'))
|
|
647
|
+
.digest();
|
|
648
|
+
const sign = signTerm.toString('base64');
|
|
649
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
|
|
650
|
+
let command = '';
|
|
651
|
+
if (this.botMode === 'switch' && this.On) {
|
|
652
|
+
command = 'turnOn';
|
|
653
|
+
this.On = true;
|
|
654
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
|
|
655
|
+
} else if (this.botMode === 'switch' && !this.On) {
|
|
656
|
+
command = 'turnOff';
|
|
657
|
+
this.On = false;
|
|
658
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
|
|
659
|
+
} else if (this.botMode === 'press') {
|
|
660
|
+
command = 'press';
|
|
661
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode`);
|
|
662
|
+
this.On = false;
|
|
730
663
|
} else {
|
|
731
|
-
|
|
664
|
+
throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Device Paramters not set for this Bot.`);
|
|
732
665
|
}
|
|
733
|
-
|
|
734
|
-
|
|
666
|
+
const body = superStringify({
|
|
667
|
+
'command': `${command}`,
|
|
668
|
+
'parameter': 'default',
|
|
669
|
+
'commandType': 'command',
|
|
670
|
+
});
|
|
671
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
|
|
672
|
+
const options = {
|
|
673
|
+
hostname: HostDomain,
|
|
674
|
+
port: 443,
|
|
675
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
676
|
+
method: 'POST',
|
|
677
|
+
headers: {
|
|
678
|
+
'Authorization': this.platform.config.credentials?.token,
|
|
679
|
+
'sign': sign,
|
|
680
|
+
'nonce': nonce,
|
|
681
|
+
't': t,
|
|
682
|
+
'Content-Type': 'application/json',
|
|
683
|
+
'Content-Length': body.length,
|
|
684
|
+
},
|
|
685
|
+
};
|
|
686
|
+
const req = https.request(options, res => {
|
|
687
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
|
|
688
|
+
this.statusCode({ res });
|
|
689
|
+
res.on('data', d => {
|
|
690
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
req.on('error', (e: any) => {
|
|
694
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
|
|
695
|
+
});
|
|
696
|
+
req.write(body);
|
|
697
|
+
req.end();
|
|
698
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
|
|
699
|
+
} else {
|
|
700
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, `
|
|
701
|
+
+`OnCached: ${this.accessory.context.On}`);
|
|
702
|
+
}
|
|
703
|
+
} catch (e: any) {
|
|
704
|
+
this.apiError(e);
|
|
705
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
|
|
706
|
+
+ ` Connection, Error Message: ${superStringify(e.message)}`,
|
|
707
|
+
);
|
|
708
|
+
}
|
|
735
709
|
}
|
|
736
710
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
'Authorization': this.platform.config.credentials?.token,
|
|
780
|
-
'sign': sign,
|
|
781
|
-
'nonce': nonce,
|
|
782
|
-
't': t,
|
|
783
|
-
'Content-Type': 'application/json',
|
|
784
|
-
'Content-Length': body.length,
|
|
785
|
-
},
|
|
786
|
-
};
|
|
787
|
-
const req = https.request(options, res => {
|
|
788
|
-
this.debugLog(`Bot: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
789
|
-
this.statusCode({ res });
|
|
790
|
-
res.on('data', d => {
|
|
791
|
-
this.debugLog(`Bot: ${this.accessory.displayName} d: ${d}`);
|
|
792
|
-
});
|
|
793
|
-
});
|
|
794
|
-
req.on('error', (e: any) => {
|
|
795
|
-
this.errorLog(`Bot: ${this.accessory.displayName} error message: ${e.message}`);
|
|
796
|
-
});
|
|
797
|
-
req.write(body);
|
|
798
|
-
req.end();
|
|
799
|
-
this.debugLog(`Bot: ${this.accessory.displayName} openAPIpushChanges: ${JSON.stringify(req)}`);
|
|
800
|
-
this.OnCached = this.On;
|
|
801
|
-
this.accessory.context.On = this.OnCached;
|
|
802
|
-
}
|
|
803
|
-
} catch (e: any) {
|
|
804
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
|
|
805
|
-
if (this.deviceLogging.includes('debug')) {
|
|
806
|
-
this.errorLog(
|
|
807
|
-
`Bot: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
|
|
808
|
-
);
|
|
809
|
-
}
|
|
810
|
-
if (this.platform.debugMode) {
|
|
811
|
-
this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,` + ` Error: ${JSON.stringify(e)}`);
|
|
812
|
-
}
|
|
813
|
-
this.apiError(e);
|
|
711
|
+
/**
|
|
712
|
+
* Handle requests to set the "On" characteristic
|
|
713
|
+
*/
|
|
714
|
+
async OnSet(value: CharacteristicValue): Promise<void> {
|
|
715
|
+
if (this.device.bot?.deviceType === 'garagedoor') {
|
|
716
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetDoorState: ${value}`);
|
|
717
|
+
if (value === this.platform.Characteristic.TargetDoorState.CLOSED) {
|
|
718
|
+
this.On = false;
|
|
719
|
+
} else {
|
|
720
|
+
this.On = true;
|
|
721
|
+
}
|
|
722
|
+
} else if (
|
|
723
|
+
this.device.bot?.deviceType === 'door' ||
|
|
724
|
+
this.device.bot?.deviceType === 'window' ||
|
|
725
|
+
this.device.bot?.deviceType === 'windowcovering'
|
|
726
|
+
) {
|
|
727
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set TargetPosition: ${value}`);
|
|
728
|
+
if (value === 0) {
|
|
729
|
+
this.On = false;
|
|
730
|
+
} else {
|
|
731
|
+
this.On = true;
|
|
732
|
+
}
|
|
733
|
+
} else if (this.device.bot?.deviceType === 'lock') {
|
|
734
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set LockTargetState: ${value}`);
|
|
735
|
+
if (value === this.platform.Characteristic.LockTargetState.SECURED) {
|
|
736
|
+
this.On = false;
|
|
737
|
+
} else {
|
|
738
|
+
this.On = true;
|
|
739
|
+
}
|
|
740
|
+
} else if (this.device.bot?.deviceType === 'faucet') {
|
|
741
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set Active: ${value}`);
|
|
742
|
+
if (value === this.platform.Characteristic.Active.INACTIVE) {
|
|
743
|
+
this.On = false;
|
|
744
|
+
} else {
|
|
745
|
+
this.On = true;
|
|
746
|
+
}
|
|
747
|
+
} else if (this.device.bot?.deviceType === 'stateful') {
|
|
748
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set ProgrammableSwitchOutputState: ${value}`);
|
|
749
|
+
if (value === 0) {
|
|
750
|
+
this.On = false;
|
|
751
|
+
} else {
|
|
752
|
+
this.On = true;
|
|
814
753
|
}
|
|
754
|
+
} else {
|
|
755
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
|
|
756
|
+
this.On = value;
|
|
815
757
|
}
|
|
758
|
+
this.doBotUpdate.next();
|
|
816
759
|
}
|
|
817
760
|
|
|
818
761
|
/**
|
|
@@ -821,7 +764,7 @@ export class Bot {
|
|
|
821
764
|
async updateHomeKitCharacteristics(): Promise<void> {
|
|
822
765
|
if (this.device.bot?.deviceType === 'garagedoor') {
|
|
823
766
|
if (this.On === undefined) {
|
|
824
|
-
this.debugLog(
|
|
767
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
825
768
|
} else {
|
|
826
769
|
if (this.On) {
|
|
827
770
|
this.garageDoorService?.updateCharacteristic(
|
|
@@ -832,7 +775,8 @@ export class Bot {
|
|
|
832
775
|
this.platform.Characteristic.CurrentDoorState,
|
|
833
776
|
this.platform.Characteristic.CurrentDoorState.OPEN,
|
|
834
777
|
);
|
|
835
|
-
this.debugLog(
|
|
778
|
+
this.debugLog(`${this.device.deviceType}: `
|
|
779
|
+
+ `${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`);
|
|
836
780
|
} else {
|
|
837
781
|
this.garageDoorService?.updateCharacteristic(
|
|
838
782
|
this.platform.Characteristic.TargetDoorState,
|
|
@@ -842,47 +786,48 @@ export class Bot {
|
|
|
842
786
|
this.platform.Characteristic.CurrentDoorState,
|
|
843
787
|
this.platform.Characteristic.CurrentDoorState.CLOSED,
|
|
844
788
|
);
|
|
845
|
-
this.debugLog(
|
|
789
|
+
this.debugLog(`${this.device.deviceType}: `
|
|
790
|
+
+`${this.accessory.displayName} updateCharacteristic TargetDoorState: Open, CurrentDoorState: Open`);
|
|
846
791
|
}
|
|
847
792
|
}
|
|
848
|
-
this.debugLog(
|
|
793
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Garage Door On: ${this.On}`);
|
|
849
794
|
} else if (this.device.bot?.deviceType === 'door') {
|
|
850
795
|
if (this.On === undefined) {
|
|
851
|
-
this.debugLog(
|
|
796
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
852
797
|
} else {
|
|
853
798
|
if (this.On) {
|
|
854
799
|
this.doorService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, 100);
|
|
855
800
|
this.doorService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, 100);
|
|
856
801
|
this.doorService?.updateCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
|
|
857
|
-
this.debugLog(
|
|
802
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 100, CurrentPosition: 100`);
|
|
858
803
|
} else {
|
|
859
804
|
this.doorService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, 0);
|
|
860
805
|
this.doorService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, 0);
|
|
861
806
|
this.doorService?.updateCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
|
|
862
|
-
this.debugLog(
|
|
807
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 0, CurrentPosition: 0`);
|
|
863
808
|
}
|
|
864
809
|
}
|
|
865
|
-
this.debugLog(
|
|
810
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Door On: ${this.On}`);
|
|
866
811
|
} else if (this.device.bot?.deviceType === 'window') {
|
|
867
812
|
if (this.On === undefined) {
|
|
868
|
-
this.debugLog(
|
|
813
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
869
814
|
} else {
|
|
870
815
|
if (this.On) {
|
|
871
816
|
this.windowService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, 100);
|
|
872
817
|
this.windowService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, 100);
|
|
873
818
|
this.windowService?.updateCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
|
|
874
|
-
this.debugLog(
|
|
819
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 100, CurrentPosition: 100`);
|
|
875
820
|
} else {
|
|
876
821
|
this.windowService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, 0);
|
|
877
822
|
this.windowService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, 0);
|
|
878
823
|
this.windowService?.updateCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
|
|
879
|
-
this.debugLog(
|
|
824
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 0, CurrentPosition: 0`);
|
|
880
825
|
}
|
|
881
826
|
}
|
|
882
|
-
this.debugLog(
|
|
827
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Window On: ${this.On}`);
|
|
883
828
|
} else if (this.device.bot?.deviceType === 'windowcovering') {
|
|
884
829
|
if (this.On === undefined) {
|
|
885
|
-
this.debugLog(
|
|
830
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
886
831
|
} else {
|
|
887
832
|
if (this.On) {
|
|
888
833
|
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, 100);
|
|
@@ -891,7 +836,7 @@ export class Bot {
|
|
|
891
836
|
this.platform.Characteristic.PositionState,
|
|
892
837
|
this.platform.Characteristic.PositionState.STOPPED,
|
|
893
838
|
);
|
|
894
|
-
this.debugLog(
|
|
839
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 100, CurrentPosition: 100`);
|
|
895
840
|
} else {
|
|
896
841
|
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, 0);
|
|
897
842
|
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, 0);
|
|
@@ -899,13 +844,13 @@ export class Bot {
|
|
|
899
844
|
this.platform.Characteristic.PositionState,
|
|
900
845
|
this.platform.Characteristic.PositionState.STOPPED,
|
|
901
846
|
);
|
|
902
|
-
this.debugLog(
|
|
847
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic TargetPosition: 0, CurrentPosition: 0`);
|
|
903
848
|
}
|
|
904
849
|
}
|
|
905
|
-
this.debugLog(
|
|
850
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Window Covering On: ${this.On}`);
|
|
906
851
|
} else if (this.device.bot?.deviceType === 'lock') {
|
|
907
852
|
if (this.On === undefined) {
|
|
908
|
-
this.debugLog(
|
|
853
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
909
854
|
} else {
|
|
910
855
|
if (this.On) {
|
|
911
856
|
this.lockService?.updateCharacteristic(
|
|
@@ -916,46 +861,48 @@ export class Bot {
|
|
|
916
861
|
this.platform.Characteristic.LockCurrentState,
|
|
917
862
|
this.platform.Characteristic.LockCurrentState.UNSECURED,
|
|
918
863
|
);
|
|
919
|
-
this.debugLog(
|
|
864
|
+
this.debugLog(`${this.device.deviceType}: `
|
|
865
|
+
+ `${this.accessory.displayName} updateCharacteristic LockTargetState: UNSECURED, LockCurrentState: UNSECURED`);
|
|
920
866
|
} else {
|
|
921
867
|
this.lockService?.updateCharacteristic(this.platform.Characteristic.LockTargetState, this.platform.Characteristic.LockTargetState.SECURED);
|
|
922
868
|
this.lockService?.updateCharacteristic(
|
|
923
869
|
this.platform.Characteristic.LockCurrentState,
|
|
924
870
|
this.platform.Characteristic.LockCurrentState.SECURED,
|
|
925
871
|
);
|
|
926
|
-
this.debugLog(
|
|
872
|
+
this.debugLog(`${this.device.deviceType}: `
|
|
873
|
+
+ `${this.accessory.displayName} updateCharacteristic LockTargetState: SECURED, LockCurrentState: SECURED`);
|
|
927
874
|
}
|
|
928
875
|
}
|
|
929
|
-
this.debugLog(
|
|
876
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Lock On: ${this.On}`);
|
|
930
877
|
} else if (this.device.bot?.deviceType === 'faucet') {
|
|
931
878
|
if (this.On === undefined) {
|
|
932
|
-
this.debugLog(
|
|
879
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
933
880
|
} else {
|
|
934
881
|
if (this.On) {
|
|
935
882
|
this.faucetService?.updateCharacteristic(this.platform.Characteristic.Active, this.platform.Characteristic.Active.ACTIVE);
|
|
936
|
-
this.debugLog(
|
|
883
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Active: ${this.On}`);
|
|
937
884
|
} else {
|
|
938
885
|
this.faucetService?.updateCharacteristic(this.platform.Characteristic.Active, this.platform.Characteristic.Active.INACTIVE);
|
|
939
|
-
this.debugLog(
|
|
886
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic Active: ${this.On}`);
|
|
940
887
|
}
|
|
941
888
|
}
|
|
942
|
-
this.debugLog(
|
|
889
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Faucet On: ${this.On}`);
|
|
943
890
|
} else if (this.device.bot?.deviceType === 'fan') {
|
|
944
891
|
if (this.On === undefined) {
|
|
945
|
-
this.debugLog(
|
|
892
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
946
893
|
} else {
|
|
947
894
|
if (this.On) {
|
|
948
895
|
this.fanService?.updateCharacteristic(this.platform.Characteristic.On, this.On);
|
|
949
|
-
this.debugLog(
|
|
896
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
|
|
950
897
|
} else {
|
|
951
898
|
this.fanService?.updateCharacteristic(this.platform.Characteristic.On, this.On);
|
|
952
|
-
this.debugLog(
|
|
899
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
|
|
953
900
|
}
|
|
954
901
|
}
|
|
955
|
-
this.debugLog(
|
|
902
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Fan On: ${this.On}`);
|
|
956
903
|
} else if (this.device.bot?.deviceType === 'stateful') {
|
|
957
904
|
if (this.On === undefined) {
|
|
958
|
-
this.debugLog(
|
|
905
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
959
906
|
} else {
|
|
960
907
|
if (this.On) {
|
|
961
908
|
this.statefulProgrammableSwitchService?.updateCharacteristic(
|
|
@@ -963,179 +910,196 @@ export class Bot {
|
|
|
963
910
|
this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
|
|
964
911
|
);
|
|
965
912
|
this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState, 1);
|
|
966
|
-
this.debugLog(
|
|
913
|
+
this.debugLog(`${this.device.deviceType}: `
|
|
914
|
+
+ `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 1`);
|
|
967
915
|
} else {
|
|
968
916
|
this.statefulProgrammableSwitchService?.updateCharacteristic(
|
|
969
917
|
this.platform.Characteristic.ProgrammableSwitchEvent,
|
|
970
918
|
this.platform.Characteristic.ProgrammableSwitchEvent.SINGLE_PRESS,
|
|
971
919
|
);
|
|
972
920
|
this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState, 0);
|
|
973
|
-
this.debugLog(
|
|
921
|
+
this.debugLog(`${this.device.deviceType}: `
|
|
922
|
+
+ `${this.accessory.displayName} updateCharacteristic ProgrammableSwitchEvent: SINGLE, ProgrammableSwitchOutputState: 0`);
|
|
974
923
|
}
|
|
975
924
|
}
|
|
976
|
-
this.debugLog(
|
|
925
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatefulProgrammableSwitch On: ${this.On}`);
|
|
977
926
|
} else if (this.device.bot?.deviceType === 'switch') {
|
|
978
927
|
if (this.On === undefined) {
|
|
979
|
-
this.debugLog(
|
|
928
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
980
929
|
} else {
|
|
981
930
|
this.switchService?.updateCharacteristic(this.platform.Characteristic.On, this.On);
|
|
982
|
-
this.debugLog(
|
|
931
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
|
|
983
932
|
}
|
|
984
933
|
} else {
|
|
985
934
|
if (this.On === undefined) {
|
|
986
|
-
this.debugLog(
|
|
935
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
|
|
987
936
|
} else {
|
|
988
937
|
this.outletService?.updateCharacteristic(this.platform.Characteristic.On, this.On);
|
|
989
|
-
this.debugLog(
|
|
938
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic On: ${this.On}`);
|
|
990
939
|
}
|
|
991
940
|
}
|
|
992
|
-
|
|
941
|
+
this.accessory.context.On = this.On;
|
|
942
|
+
if (this.BLE) {
|
|
993
943
|
if (this.BatteryLevel === undefined) {
|
|
994
|
-
this.debugLog(
|
|
944
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
|
|
995
945
|
} else {
|
|
946
|
+
this.accessory.context.BatteryLevel = this.BatteryLevel;
|
|
996
947
|
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
|
|
997
|
-
this.debugLog(
|
|
948
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
|
|
998
949
|
}
|
|
999
950
|
if (this.StatusLowBattery === undefined) {
|
|
1000
|
-
this.debugLog(
|
|
951
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
|
|
1001
952
|
} else {
|
|
953
|
+
this.accessory.context.StatusLowBattery = this.StatusLowBattery;
|
|
1002
954
|
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
|
|
1003
|
-
this.debugLog(
|
|
955
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
|
|
1004
956
|
}
|
|
1005
957
|
}
|
|
1006
958
|
}
|
|
1007
959
|
|
|
1008
|
-
async
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
this.
|
|
1013
|
-
} else if (this.device.bot?.deviceType === 'door') {
|
|
1014
|
-
this.doorService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
1015
|
-
this.doorService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
1016
|
-
this.doorService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
1017
|
-
} else if (this.device.bot?.deviceType === 'window') {
|
|
1018
|
-
this.windowService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
1019
|
-
this.windowService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
1020
|
-
this.windowService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
1021
|
-
} else if (this.device.bot?.deviceType === 'windowcovering') {
|
|
1022
|
-
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
1023
|
-
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
1024
|
-
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
1025
|
-
} else if (this.device.bot?.deviceType === 'lock') {
|
|
1026
|
-
this.doorService?.updateCharacteristic(this.platform.Characteristic.LockTargetState, e);
|
|
1027
|
-
this.doorService?.updateCharacteristic(this.platform.Characteristic.LockCurrentState, e);
|
|
1028
|
-
} else if (this.device.bot?.deviceType === 'faucet') {
|
|
1029
|
-
this.faucetService?.updateCharacteristic(this.platform.Characteristic.Active, e);
|
|
1030
|
-
} else if (this.device.bot?.deviceType === 'fan') {
|
|
1031
|
-
this.fanService?.updateCharacteristic(this.platform.Characteristic.On, e);
|
|
1032
|
-
} else if (this.device.bot?.deviceType === 'stateful') {
|
|
1033
|
-
this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchEvent, e);
|
|
1034
|
-
this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState, e);
|
|
1035
|
-
} else if (this.device.bot?.deviceType === 'switch') {
|
|
1036
|
-
this.switchService?.updateCharacteristic(this.platform.Characteristic.On, e);
|
|
1037
|
-
} else {
|
|
1038
|
-
this.outletService?.updateCharacteristic(this.platform.Characteristic.On, e);
|
|
1039
|
-
}
|
|
1040
|
-
if (this.device.ble) {
|
|
1041
|
-
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
|
|
1042
|
-
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
|
|
960
|
+
async removeOutletService(accessory: PlatformAccessory): Promise<void> {
|
|
961
|
+
// If outletService still pressent, then remove first
|
|
962
|
+
this.outletService = this.accessory.getService(this.platform.Service.Outlet);
|
|
963
|
+
if (this.outletService) {
|
|
964
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Outlet Service`);
|
|
1043
965
|
}
|
|
1044
|
-
|
|
966
|
+
accessory.removeService(this.outletService!);
|
|
1045
967
|
}
|
|
1046
968
|
|
|
1047
|
-
async
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
case 152:
|
|
1053
|
-
this.errorLog(`Bot: ${this.accessory.displayName} Device not found.`);
|
|
1054
|
-
break;
|
|
1055
|
-
case 160:
|
|
1056
|
-
this.errorLog(`Bot: ${this.accessory.displayName} Command is not supported.`);
|
|
1057
|
-
break;
|
|
1058
|
-
case 161:
|
|
1059
|
-
this.errorLog(`Bot: ${this.accessory.displayName} Device is offline.`);
|
|
1060
|
-
this.offlineOff();
|
|
1061
|
-
break;
|
|
1062
|
-
case 171:
|
|
1063
|
-
this.errorLog(`Bot: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
|
|
1064
|
-
this.offlineOff();
|
|
1065
|
-
break;
|
|
1066
|
-
case 190:
|
|
1067
|
-
this.errorLog(
|
|
1068
|
-
`Bot: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
1069
|
-
` Or command: ${JSON.stringify(res)} format is invalid`,
|
|
1070
|
-
);
|
|
1071
|
-
break;
|
|
1072
|
-
case 100:
|
|
1073
|
-
this.debugLog(`Bot: ${this.accessory.displayName} Command successfully sent.`);
|
|
1074
|
-
break;
|
|
1075
|
-
default:
|
|
1076
|
-
this.debugLog(`Bot: ${this.accessory.displayName} Unknown statusCode.`);
|
|
969
|
+
async removeGarageDoorService(accessory: PlatformAccessory): Promise<void> {
|
|
970
|
+
// If garageDoorService still pressent, then remove first
|
|
971
|
+
this.garageDoorService = this.accessory.getService(this.platform.Service.GarageDoorOpener);
|
|
972
|
+
if (this.garageDoorService) {
|
|
973
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Garage Door Service`);
|
|
1077
974
|
}
|
|
975
|
+
accessory.removeService(this.garageDoorService!);
|
|
1078
976
|
}
|
|
1079
977
|
|
|
1080
|
-
async
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
} else {
|
|
1086
|
-
this.outletService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
|
|
1087
|
-
}
|
|
978
|
+
async removeDoorService(accessory: PlatformAccessory): Promise<void> {
|
|
979
|
+
// If doorService still pressent, then remove first
|
|
980
|
+
this.doorService = this.accessory.getService(this.platform.Service.Door);
|
|
981
|
+
if (this.doorService) {
|
|
982
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Door Service`);
|
|
1088
983
|
}
|
|
984
|
+
accessory.removeService(this.doorService!);
|
|
1089
985
|
}
|
|
1090
986
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
this.device.
|
|
1105
|
-
|
|
1106
|
-
)
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
|
|
987
|
+
async removeLockService(accessory: PlatformAccessory): Promise<void> {
|
|
988
|
+
// If lockService still pressent, then remove first
|
|
989
|
+
this.lockService = this.accessory.getService(this.platform.Service.LockMechanism);
|
|
990
|
+
if (this.lockService) {
|
|
991
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Lock Service`);
|
|
992
|
+
}
|
|
993
|
+
accessory.removeService(this.lockService!);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
async removeFaucetService(accessory: PlatformAccessory): Promise<void> {
|
|
997
|
+
// If faucetService still pressent, then remove first
|
|
998
|
+
this.faucetService = this.accessory.getService(this.platform.Service.Faucet);
|
|
999
|
+
if (this.faucetService) {
|
|
1000
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Faucet Service`);
|
|
1001
|
+
}
|
|
1002
|
+
accessory.removeService(this.faucetService!);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
async removeFanService(accessory: PlatformAccessory): Promise<void> {
|
|
1006
|
+
// If fanService still pressent, then remove first
|
|
1007
|
+
this.fanService = this.accessory.getService(this.platform.Service.Fan);
|
|
1008
|
+
if (this.fanService) {
|
|
1009
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Fan Service`);
|
|
1010
|
+
}
|
|
1011
|
+
accessory.removeService(this.fanService!);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
async removeWindowService(accessory: PlatformAccessory): Promise<void> {
|
|
1015
|
+
// If windowService still pressent, then remove first
|
|
1016
|
+
this.windowService = this.accessory.getService(this.platform.Service.Window);
|
|
1017
|
+
if (this.windowService) {
|
|
1018
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Window Service`);
|
|
1019
|
+
}
|
|
1020
|
+
accessory.removeService(this.windowService!);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
async removeWindowCoveringService(accessory: PlatformAccessory): Promise<void> {
|
|
1024
|
+
// If windowCoveringService still pressent, then remove first
|
|
1025
|
+
this.windowCoveringService = this.accessory.getService(this.platform.Service.WindowCovering);
|
|
1026
|
+
if (this.windowCoveringService) {
|
|
1027
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Window Covering Service`);
|
|
1028
|
+
}
|
|
1029
|
+
accessory.removeService(this.windowCoveringService!);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
async removeStatefulProgrammableSwitchService(accessory: PlatformAccessory): Promise<void> {
|
|
1033
|
+
// If statefulProgrammableSwitchService still pressent, then remove first
|
|
1034
|
+
this.statefulProgrammableSwitchService = this.accessory.getService(this.platform.Service.StatefulProgrammableSwitch);
|
|
1035
|
+
if (this.statefulProgrammableSwitchService) {
|
|
1036
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Stateful Programmable Switch Service`);
|
|
1037
|
+
}
|
|
1038
|
+
accessory.removeService(this.statefulProgrammableSwitchService!);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
async removeSwitchService(accessory: PlatformAccessory): Promise<void> {
|
|
1042
|
+
// If switchService still pressent, then remove first
|
|
1043
|
+
this.switchService = this.accessory.getService(this.platform.Service.Switch);
|
|
1044
|
+
if (this.switchService) {
|
|
1045
|
+
this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Switch Service`);
|
|
1046
|
+
}
|
|
1047
|
+
accessory.removeService(this.switchService!);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
private DoublePress(device: device & devicesConfig) {
|
|
1051
|
+
if (device.bot?.doublePress) {
|
|
1052
|
+
this.doublePress = device.bot?.doublePress;
|
|
1053
|
+
this.accessory.context.doublePress = this.doublePress;
|
|
1134
1054
|
} else {
|
|
1135
|
-
this.
|
|
1136
|
-
|
|
1055
|
+
this.doublePress = 1;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
async getCustomBLEAddress(switchbot: any) {
|
|
1060
|
+
if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
|
|
1061
|
+
(async () => {
|
|
1062
|
+
// Start to monitor advertisement packets
|
|
1063
|
+
await switchbot.startScan({
|
|
1064
|
+
model: 'H',
|
|
1065
|
+
});
|
|
1066
|
+
// Set an event handler
|
|
1067
|
+
switchbot.onadvertisement = (ad: any) => {
|
|
1068
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
|
|
1069
|
+
};
|
|
1070
|
+
await switchbot.wait(10000);
|
|
1071
|
+
// Stop to monitor
|
|
1072
|
+
switchbot.stopScan();
|
|
1073
|
+
})();
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
async BLEPushConnection() {
|
|
1078
|
+
if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
|
|
1079
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Push Changes`);
|
|
1080
|
+
await this.openAPIpushChanges();
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
async BLERefreshConnection(switchbot: any): Promise<void> {
|
|
1085
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
|
|
1086
|
+
if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
|
|
1087
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection to Refresh Status`);
|
|
1088
|
+
await this.openAPIRefreshStatus();
|
|
1137
1089
|
}
|
|
1138
|
-
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
async turnOnOff(device_list: any): Promise<any> {
|
|
1093
|
+
return await this.retry({
|
|
1094
|
+
max: await this.maxRetry(),
|
|
1095
|
+
fn: () => {
|
|
1096
|
+
if (this.On) {
|
|
1097
|
+
return device_list[0].turnOn({ id: this.device.bleMac });
|
|
1098
|
+
} else {
|
|
1099
|
+
return device_list[0].turnOff({ id: this.device.bleMac });
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
1102
|
+
});
|
|
1139
1103
|
}
|
|
1140
1104
|
|
|
1141
1105
|
async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
|
|
@@ -1160,76 +1124,134 @@ export class Bot {
|
|
|
1160
1124
|
return maxRetry;
|
|
1161
1125
|
}
|
|
1162
1126
|
|
|
1163
|
-
async
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
if (device.
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
if (device.
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
}
|
|
1177
|
-
if (device.scanDuration !== undefined) {
|
|
1178
|
-
config['scanDuration'] = device.scanDuration;
|
|
1179
|
-
}
|
|
1180
|
-
if (device.offline !== undefined) {
|
|
1181
|
-
config['offline'] = device.offline;
|
|
1182
|
-
}
|
|
1183
|
-
if (Object.entries(config).length !== 0) {
|
|
1184
|
-
this.infoLog(`Bot: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
|
|
1127
|
+
async PressOrSwitch(device: device & devicesConfig): Promise<void> {
|
|
1128
|
+
if (!device.bot?.mode) {
|
|
1129
|
+
this.botMode = 'switch';
|
|
1130
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} does not have bot mode set in the Plugin's SwitchBot Device Settings,`);
|
|
1131
|
+
this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} is defaulting to "${this.botMode}" mode, you may experience issues.`);
|
|
1132
|
+
} else if (device.bot?.mode === 'switch') {
|
|
1133
|
+
this.botMode = 'switch';
|
|
1134
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
|
|
1135
|
+
} else if (device.bot?.mode === 'press') {
|
|
1136
|
+
this.botMode = 'press';
|
|
1137
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
|
|
1138
|
+
} else {
|
|
1139
|
+
throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
|
|
1185
1140
|
}
|
|
1186
1141
|
}
|
|
1187
1142
|
|
|
1188
|
-
async
|
|
1189
|
-
if (device.
|
|
1190
|
-
this.
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
1194
|
-
this.debugLog(`Bot: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
1143
|
+
async allowPushChanges(device: device & devicesConfig): Promise<void> {
|
|
1144
|
+
if (device.bot?.allowPush) {
|
|
1145
|
+
this.allowPush = true;
|
|
1146
|
+
} else {
|
|
1147
|
+
this.allowPush = false;
|
|
1195
1148
|
}
|
|
1149
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Allowing Push Changes: ${this.allowPush}`);
|
|
1196
1150
|
}
|
|
1197
1151
|
|
|
1198
1152
|
async scan(device: device & devicesConfig): Promise<void> {
|
|
1199
1153
|
if (device.scanDuration) {
|
|
1200
1154
|
this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
|
|
1201
|
-
if (
|
|
1202
|
-
this.debugLog(
|
|
1155
|
+
if (this.BLE) {
|
|
1156
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
|
|
1203
1157
|
}
|
|
1204
1158
|
} else {
|
|
1205
1159
|
this.scanDuration = this.accessory.context.scanDuration = 1;
|
|
1206
|
-
if (this.
|
|
1207
|
-
this.debugLog(
|
|
1160
|
+
if (this.BLE) {
|
|
1161
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
|
|
1208
1162
|
}
|
|
1209
1163
|
}
|
|
1210
1164
|
}
|
|
1211
1165
|
|
|
1212
|
-
async
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1166
|
+
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
1167
|
+
switch (res.statusCode) {
|
|
1168
|
+
case 151:
|
|
1169
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
|
|
1170
|
+
break;
|
|
1171
|
+
case 152:
|
|
1172
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
|
|
1173
|
+
break;
|
|
1174
|
+
case 160:
|
|
1175
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
|
|
1176
|
+
break;
|
|
1177
|
+
case 161:
|
|
1178
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
|
|
1179
|
+
this.offlineOff();
|
|
1180
|
+
break;
|
|
1181
|
+
case 171:
|
|
1182
|
+
this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
|
|
1183
|
+
this.offlineOff();
|
|
1184
|
+
break;
|
|
1185
|
+
case 190:
|
|
1186
|
+
this.errorLog(
|
|
1187
|
+
`${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
1188
|
+
` Or command: ${superStringify(res)} format is invalid`,
|
|
1189
|
+
);
|
|
1190
|
+
break;
|
|
1191
|
+
case 100:
|
|
1192
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
|
|
1193
|
+
break;
|
|
1194
|
+
default:
|
|
1195
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
async offlineOff(): Promise<void> {
|
|
1200
|
+
if (this.device.offline) {
|
|
1201
|
+
this.On = false;
|
|
1202
|
+
if (this.device.bot?.deviceType === 'switch') {
|
|
1203
|
+
this.switchService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
|
|
1204
|
+
} else {
|
|
1205
|
+
this.outletService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
|
|
1206
|
+
}
|
|
1207
|
+
await this.updateHomeKitCharacteristics();
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
async apiError(e: any): Promise<void> {
|
|
1212
|
+
if (this.device.bot?.deviceType === 'garagedoor') {
|
|
1213
|
+
this.garageDoorService?.updateCharacteristic(this.platform.Characteristic.TargetDoorState, e);
|
|
1214
|
+
this.garageDoorService?.updateCharacteristic(this.platform.Characteristic.CurrentDoorState, e);
|
|
1215
|
+
this.garageDoorService?.updateCharacteristic(this.platform.Characteristic.ObstructionDetected, e);
|
|
1216
|
+
} else if (this.device.bot?.deviceType === 'door') {
|
|
1217
|
+
this.doorService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
1218
|
+
this.doorService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
1219
|
+
this.doorService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
1220
|
+
} else if (this.device.bot?.deviceType === 'window') {
|
|
1221
|
+
this.windowService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
1222
|
+
this.windowService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
1223
|
+
this.windowService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
1224
|
+
} else if (this.device.bot?.deviceType === 'windowcovering') {
|
|
1225
|
+
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
1226
|
+
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
1227
|
+
this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
1228
|
+
} else if (this.device.bot?.deviceType === 'lock') {
|
|
1229
|
+
this.doorService?.updateCharacteristic(this.platform.Characteristic.LockTargetState, e);
|
|
1230
|
+
this.doorService?.updateCharacteristic(this.platform.Characteristic.LockCurrentState, e);
|
|
1231
|
+
} else if (this.device.bot?.deviceType === 'faucet') {
|
|
1232
|
+
this.faucetService?.updateCharacteristic(this.platform.Characteristic.Active, e);
|
|
1233
|
+
} else if (this.device.bot?.deviceType === 'fan') {
|
|
1234
|
+
this.fanService?.updateCharacteristic(this.platform.Characteristic.On, e);
|
|
1235
|
+
} else if (this.device.bot?.deviceType === 'stateful') {
|
|
1236
|
+
this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchEvent, e);
|
|
1237
|
+
this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState, e);
|
|
1238
|
+
} else if (this.device.bot?.deviceType === 'switch') {
|
|
1239
|
+
this.switchService?.updateCharacteristic(this.platform.Characteristic.On, e);
|
|
1222
1240
|
} else {
|
|
1223
|
-
this.
|
|
1224
|
-
|
|
1241
|
+
this.outletService?.updateCharacteristic(this.platform.Characteristic.On, e);
|
|
1242
|
+
}
|
|
1243
|
+
if (this.BLE) {
|
|
1244
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
|
|
1245
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
|
|
1225
1246
|
}
|
|
1226
1247
|
}
|
|
1227
1248
|
|
|
1228
1249
|
FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
|
|
1229
1250
|
let FirmwareRevision: string;
|
|
1230
|
-
this.debugLog(
|
|
1231
|
-
|
|
1232
|
-
this.debugLog(
|
|
1251
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
|
|
1252
|
+
+ ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
|
|
1253
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
|
|
1254
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
|
|
1233
1255
|
if (accessory.context.FirmwareRevision) {
|
|
1234
1256
|
FirmwareRevision = accessory.context.FirmwareRevision;
|
|
1235
1257
|
} else if (device.firmware) {
|
|
@@ -1240,119 +1262,78 @@ export class Bot {
|
|
|
1240
1262
|
return FirmwareRevision;
|
|
1241
1263
|
}
|
|
1242
1264
|
|
|
1243
|
-
|
|
1244
|
-
if (
|
|
1245
|
-
this.
|
|
1246
|
-
this.
|
|
1247
|
-
this.warnLog(`Bot: ${this.accessory.displayName} is defaulting to "${this.botMode}" mode, you may experience issues.`);
|
|
1248
|
-
} else if (device.bot?.mode === 'switch') {
|
|
1249
|
-
this.botMode = 'switch';
|
|
1250
|
-
this.debugLog(`Bot: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
|
|
1251
|
-
} else if (device.bot?.mode === 'press') {
|
|
1252
|
-
this.botMode = 'press';
|
|
1253
|
-
this.debugLog(`Bot: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
|
|
1265
|
+
private context() {
|
|
1266
|
+
if (this.On === undefined) {
|
|
1267
|
+
this.On = false;
|
|
1268
|
+
this.accessory.context.On = this.On;
|
|
1254
1269
|
} else {
|
|
1255
|
-
|
|
1270
|
+
this.On = this.accessory.context.On;
|
|
1256
1271
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
async allowPushChanges(device: device & devicesConfig): Promise<void> {
|
|
1260
|
-
if (device.bot?.allowPush) {
|
|
1261
|
-
this.allowPush = true;
|
|
1272
|
+
if (this.BatteryLevel === undefined) {
|
|
1273
|
+
this.BatteryLevel = 100;
|
|
1262
1274
|
} else {
|
|
1263
|
-
this.
|
|
1275
|
+
this.BatteryLevel = this.accessory.context.BatteryLevel;
|
|
1264
1276
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
this.outletService = this.accessory.getService(this.platform.Service.Outlet);
|
|
1271
|
-
if (this.outletService) {
|
|
1272
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Outlet Service`);
|
|
1277
|
+
if (this.StatusLowBattery === undefined) {
|
|
1278
|
+
this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
|
|
1279
|
+
this.accessory.context.StatusLowBattery = this.StatusLowBattery;
|
|
1280
|
+
} else {
|
|
1281
|
+
this.StatusLowBattery = this.accessory.context.StatusLowBattery;
|
|
1273
1282
|
}
|
|
1274
|
-
accessory.removeService(this.outletService!);
|
|
1275
1283
|
}
|
|
1276
1284
|
|
|
1277
|
-
async
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1285
|
+
async refreshRate(device: device & devicesConfig): Promise<void> {
|
|
1286
|
+
if (device.refreshRate) {
|
|
1287
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
|
|
1288
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
|
|
1289
|
+
} else if (this.platform.config.options!.refreshRate) {
|
|
1290
|
+
this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
|
|
1291
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
|
|
1282
1292
|
}
|
|
1283
|
-
accessory.removeService(this.garageDoorService!);
|
|
1284
1293
|
}
|
|
1285
1294
|
|
|
1286
|
-
async
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Door Service`);
|
|
1295
|
+
async config(device: device & devicesConfig): Promise<void> {
|
|
1296
|
+
let config = {};
|
|
1297
|
+
if (device.bot) {
|
|
1298
|
+
config = device.bot;
|
|
1291
1299
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
async removeLockService(accessory: PlatformAccessory): Promise<void> {
|
|
1296
|
-
// If lockService still pressent, then remove first
|
|
1297
|
-
this.lockService = this.accessory.getService(this.platform.Service.LockMechanism);
|
|
1298
|
-
if (this.lockService) {
|
|
1299
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Lock Service`);
|
|
1300
|
+
if (device.connectionType !== undefined) {
|
|
1301
|
+
config['connectionType'] = device.connectionType;
|
|
1300
1302
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
async removeFaucetService(accessory: PlatformAccessory): Promise<void> {
|
|
1305
|
-
// If faucetService still pressent, then remove first
|
|
1306
|
-
this.faucetService = this.accessory.getService(this.platform.Service.Faucet);
|
|
1307
|
-
if (this.faucetService) {
|
|
1308
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Faucet Service`);
|
|
1303
|
+
if (device.external !== undefined) {
|
|
1304
|
+
config['external'] = device.external;
|
|
1309
1305
|
}
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
async removeFanService(accessory: PlatformAccessory): Promise<void> {
|
|
1314
|
-
// If fanService still pressent, then remove first
|
|
1315
|
-
this.fanService = this.accessory.getService(this.platform.Service.Fan);
|
|
1316
|
-
if (this.fanService) {
|
|
1317
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Fan Service`);
|
|
1306
|
+
if (device.logging !== undefined) {
|
|
1307
|
+
config['logging'] = device.logging;
|
|
1318
1308
|
}
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
async removeWindowService(accessory: PlatformAccessory): Promise<void> {
|
|
1323
|
-
// If windowService still pressent, then remove first
|
|
1324
|
-
this.windowService = this.accessory.getService(this.platform.Service.Window);
|
|
1325
|
-
if (this.windowService) {
|
|
1326
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Window Service`);
|
|
1309
|
+
if (device.refreshRate !== undefined) {
|
|
1310
|
+
config['refreshRate'] = device.refreshRate;
|
|
1327
1311
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
async removeWindowCoveringService(accessory: PlatformAccessory): Promise<void> {
|
|
1332
|
-
// If windowCoveringService still pressent, then remove first
|
|
1333
|
-
this.windowCoveringService = this.accessory.getService(this.platform.Service.WindowCovering);
|
|
1334
|
-
if (this.windowCoveringService) {
|
|
1335
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Window Covering Service`);
|
|
1312
|
+
if (device.scanDuration !== undefined) {
|
|
1313
|
+
config['scanDuration'] = device.scanDuration;
|
|
1336
1314
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
this.statefulProgrammableSwitchService = this.accessory.getService(this.platform.Service.StatefulProgrammableSwitch);
|
|
1343
|
-
if (this.statefulProgrammableSwitchService) {
|
|
1344
|
-
this.warnLog(`Bot: ${accessory.displayName} Removing Leftover Stateful Programmable Switch Service`);
|
|
1315
|
+
if (device.offline !== undefined) {
|
|
1316
|
+
config['offline'] = device.offline;
|
|
1317
|
+
}
|
|
1318
|
+
if (Object.entries(config).length !== 0) {
|
|
1319
|
+
this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
|
|
1345
1320
|
}
|
|
1346
|
-
accessory.removeService(this.statefulProgrammableSwitchService!);
|
|
1347
1321
|
}
|
|
1348
1322
|
|
|
1349
|
-
async
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1323
|
+
async logs(device: device & devicesConfig): Promise<void> {
|
|
1324
|
+
if (this.platform.debugMode) {
|
|
1325
|
+
this.deviceLogging = this.accessory.context.logging = 'debugMode';
|
|
1326
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
|
|
1327
|
+
} else if (device.logging) {
|
|
1328
|
+
this.deviceLogging = this.accessory.context.logging = device.logging;
|
|
1329
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
|
|
1330
|
+
} else if (this.platform.config.options?.logging) {
|
|
1331
|
+
this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
|
|
1332
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
|
|
1333
|
+
} else {
|
|
1334
|
+
this.deviceLogging = this.accessory.context.logging = 'standard';
|
|
1335
|
+
this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
|
|
1354
1336
|
}
|
|
1355
|
-
accessory.removeService(this.switchService!);
|
|
1356
1337
|
}
|
|
1357
1338
|
|
|
1358
1339
|
/**
|
|
@@ -1370,12 +1351,28 @@ export class Bot {
|
|
|
1370
1351
|
}
|
|
1371
1352
|
}
|
|
1372
1353
|
|
|
1354
|
+
debugWarnLog(...log: any[]): void {
|
|
1355
|
+
if (this.enablingDeviceLogging()) {
|
|
1356
|
+
if (this.deviceLogging?.includes('debug')) {
|
|
1357
|
+
this.platform.log.warn('[DEBUG]', String(...log));
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1373
1362
|
errorLog(...log: any[]): void {
|
|
1374
1363
|
if (this.enablingDeviceLogging()) {
|
|
1375
1364
|
this.platform.log.error(String(...log));
|
|
1376
1365
|
}
|
|
1377
1366
|
}
|
|
1378
1367
|
|
|
1368
|
+
debugErrorLog(...log: any[]): void {
|
|
1369
|
+
if (this.enablingDeviceLogging()) {
|
|
1370
|
+
if (this.deviceLogging?.includes('debug')) {
|
|
1371
|
+
this.platform.log.error('[DEBUG]', String(...log));
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1379
1376
|
debugLog(...log: any[]): void {
|
|
1380
1377
|
if (this.enablingDeviceLogging()) {
|
|
1381
1378
|
if (this.deviceLogging === 'debug') {
|