@switchbot/homebridge-switchbot 2.0.0-beta.2 → 2.0.0-beta.21

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