@switchbot/homebridge-switchbot 2.0.0-beta.19 → 2.0.0-beta.20

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 (112) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/README.md +1 -2
  3. package/config.schema.json +51 -32
  4. package/dist/device/bot.d.ts +32 -29
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +549 -575
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/colorbulb.d.ts +33 -15
  9. package/dist/device/colorbulb.d.ts.map +1 -1
  10. package/dist/device/colorbulb.js +426 -341
  11. package/dist/device/colorbulb.js.map +1 -1
  12. package/dist/device/contact.d.ts +16 -9
  13. package/dist/device/contact.d.ts.map +1 -1
  14. package/dist/device/contact.js +246 -208
  15. package/dist/device/contact.js.map +1 -1
  16. package/dist/device/curtain.d.ts +21 -18
  17. package/dist/device/curtain.d.ts.map +1 -1
  18. package/dist/device/curtain.js +449 -449
  19. package/dist/device/curtain.js.map +1 -1
  20. package/dist/device/humidifier.d.ts +22 -20
  21. package/dist/device/humidifier.d.ts.map +1 -1
  22. package/dist/device/humidifier.js +346 -324
  23. package/dist/device/humidifier.js.map +1 -1
  24. package/dist/device/lock.d.ts +22 -10
  25. package/dist/device/lock.d.ts.map +1 -1
  26. package/dist/device/lock.js +257 -178
  27. package/dist/device/lock.js.map +1 -1
  28. package/dist/device/meter.d.ts +21 -14
  29. package/dist/device/meter.d.ts.map +1 -1
  30. package/dist/device/meter.js +287 -239
  31. package/dist/device/meter.js.map +1 -1
  32. package/dist/device/meterplus.d.ts +23 -10
  33. package/dist/device/meterplus.d.ts.map +1 -1
  34. package/dist/device/meterplus.js +308 -190
  35. package/dist/device/meterplus.js.map +1 -1
  36. package/dist/device/motion.d.ts +17 -10
  37. package/dist/device/motion.d.ts.map +1 -1
  38. package/dist/device/motion.js +225 -193
  39. package/dist/device/motion.js.map +1 -1
  40. package/dist/device/plug.d.ts +24 -17
  41. package/dist/device/plug.d.ts.map +1 -1
  42. package/dist/device/plug.js +270 -267
  43. package/dist/device/plug.js.map +1 -1
  44. package/dist/device/striplight.d.ts +36 -14
  45. package/dist/device/striplight.d.ts.map +1 -1
  46. package/dist/device/striplight.js +447 -299
  47. package/dist/device/striplight.js.map +1 -1
  48. package/dist/irdevice/airconditioner.d.ts +7 -14
  49. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  50. package/dist/irdevice/airconditioner.js +177 -169
  51. package/dist/irdevice/airconditioner.js.map +1 -1
  52. package/dist/irdevice/airpurifier.d.ts +3 -5
  53. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  54. package/dist/irdevice/airpurifier.js +72 -57
  55. package/dist/irdevice/airpurifier.js.map +1 -1
  56. package/dist/irdevice/camera.d.ts +3 -4
  57. package/dist/irdevice/camera.d.ts.map +1 -1
  58. package/dist/irdevice/camera.js +47 -33
  59. package/dist/irdevice/camera.js.map +1 -1
  60. package/dist/irdevice/fan.d.ts +3 -4
  61. package/dist/irdevice/fan.d.ts.map +1 -1
  62. package/dist/irdevice/fan.js +66 -48
  63. package/dist/irdevice/fan.js.map +1 -1
  64. package/dist/irdevice/light.d.ts +3 -4
  65. package/dist/irdevice/light.d.ts.map +1 -1
  66. package/dist/irdevice/light.js +48 -47
  67. package/dist/irdevice/light.js.map +1 -1
  68. package/dist/irdevice/other.d.ts +3 -4
  69. package/dist/irdevice/other.d.ts.map +1 -1
  70. package/dist/irdevice/other.js +47 -33
  71. package/dist/irdevice/other.js.map +1 -1
  72. package/dist/irdevice/tv.d.ts +10 -11
  73. package/dist/irdevice/tv.d.ts.map +1 -1
  74. package/dist/irdevice/tv.js +64 -48
  75. package/dist/irdevice/tv.js.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.d.ts +7 -12
  77. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.js +52 -41
  79. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  80. package/dist/irdevice/waterheater.d.ts +6 -11
  81. package/dist/irdevice/waterheater.d.ts.map +1 -1
  82. package/dist/irdevice/waterheater.js +52 -42
  83. package/dist/irdevice/waterheater.js.map +1 -1
  84. package/dist/platform.d.ts +0 -4
  85. package/dist/platform.d.ts.map +1 -1
  86. package/dist/platform.js +44 -66
  87. package/dist/platform.js.map +1 -1
  88. package/dist/settings.d.ts +3 -3
  89. package/dist/settings.d.ts.map +1 -1
  90. package/package.json +7 -6
  91. package/src/device/bot.ts +551 -589
  92. package/src/device/colorbulb.ts +441 -375
  93. package/src/device/contact.ts +249 -213
  94. package/src/device/curtain.ts +452 -461
  95. package/src/device/humidifier.ts +358 -365
  96. package/src/device/lock.ts +263 -179
  97. package/src/device/meter.ts +302 -253
  98. package/src/device/meterplus.ts +319 -194
  99. package/src/device/motion.ts +230 -199
  100. package/src/device/plug.ts +273 -274
  101. package/src/device/striplight.ts +460 -316
  102. package/src/irdevice/airconditioner.ts +181 -183
  103. package/src/irdevice/airpurifier.ts +70 -60
  104. package/src/irdevice/camera.ts +46 -36
  105. package/src/irdevice/fan.ts +64 -49
  106. package/src/irdevice/light.ts +47 -51
  107. package/src/irdevice/other.ts +46 -36
  108. package/src/irdevice/tv.ts +64 -51
  109. package/src/irdevice/vacuumcleaner.ts +52 -45
  110. package/src/irdevice/waterheater.ts +50 -45
  111. package/src/platform.ts +44 -68
  112. package/src/settings.ts +3 -3
package/src/device/bot.ts CHANGED
@@ -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'];
@@ -53,7 +53,6 @@ export class Bot {
53
53
  scanDuration!: number;
54
54
  deviceLogging!: string;
55
55
  deviceRefreshRate!: number;
56
- OpenAPI?: boolean;
57
56
 
58
57
  // Others
59
58
  doublePress!: number;
@@ -62,29 +61,20 @@ export class Bot {
62
61
  botUpdateInProgress!: boolean;
63
62
  doBotUpdate!: Subject<void>;
64
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
+
65
68
  constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
66
69
  // default placeholders
67
70
  this.logs(device);
68
- this.openAPI();
69
71
  this.scan(device);
70
72
  this.refreshRate(device);
71
73
  this.PressOrSwitch(device);
72
74
  this.allowPushChanges(device);
73
75
  this.config(device);
74
- if (this.On === undefined) {
75
- this.On = false;
76
- this.accessory.context.On = this.On;
77
- } else {
78
- this.On = this.accessory.context.On;
79
- }
80
- if (device.bot?.doublePress) {
81
- this.doublePress = device.bot?.doublePress;
82
- this.accessory.context.doublePress = this.doublePress;
83
- } else {
84
- this.doublePress = 1;
85
- }
86
- this.BatteryLevel = 100;
87
- this.StatusLowBattery = 0;
76
+ this.context();
77
+ this.DoublePress(device);
88
78
 
89
79
  // this is subject we use to track when we need to POST changes to the SwitchBot API
90
80
  this.doBotUpdate = new Subject();
@@ -122,7 +112,7 @@ export class Bot {
122
112
  this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Switch`);
123
113
 
124
114
  this.switchService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
125
- 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));
126
116
  } else if (device.bot?.deviceType === 'garagedoor') {
127
117
  this.removeFanService(accessory);
128
118
  this.removeLockService(accessory);
@@ -141,7 +131,7 @@ export class Bot {
141
131
  this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Garage Door Opener`);
142
132
 
143
133
  this.garageDoorService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
144
- 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));
145
135
  this.garageDoorService.setCharacteristic(this.platform.Characteristic.ObstructionDetected, false);
146
136
  } else if (device.bot?.deviceType === 'door') {
147
137
  this.removeFanService(accessory);
@@ -168,7 +158,7 @@ export class Bot {
168
158
  maxValue: 100,
169
159
  minStep: 100,
170
160
  })
171
- .onSet(this.handleOnSet.bind(this));
161
+ .onSet(this.OnSet.bind(this));
172
162
  this.doorService.setCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
173
163
  } else if (device.bot?.deviceType === 'window') {
174
164
  this.removeFanService(accessory);
@@ -195,7 +185,7 @@ export class Bot {
195
185
  maxValue: 100,
196
186
  minStep: 100,
197
187
  })
198
- .onSet(this.handleOnSet.bind(this));
188
+ .onSet(this.OnSet.bind(this));
199
189
  this.windowService.setCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
200
190
  } else if (device.bot?.deviceType === 'windowcovering') {
201
191
  this.removeFanService(accessory);
@@ -223,7 +213,7 @@ export class Bot {
223
213
  maxValue: 100,
224
214
  minStep: 100,
225
215
  })
226
- .onSet(this.handleOnSet.bind(this));
216
+ .onSet(this.OnSet.bind(this));
227
217
  this.windowCoveringService.setCharacteristic(this.platform.Characteristic.PositionState, this.platform.Characteristic.PositionState.STOPPED);
228
218
  } else if (device.bot?.deviceType === 'lock') {
229
219
  this.removeFanService(accessory);
@@ -242,7 +232,7 @@ export class Bot {
242
232
  this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Lock`);
243
233
 
244
234
  this.lockService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
245
- 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));
246
236
  } else if (device.bot?.deviceType === 'faucet') {
247
237
  this.removeFanService(accessory);
248
238
  this.removeLockService(accessory);
@@ -260,7 +250,7 @@ export class Bot {
260
250
  this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Faucet`);
261
251
 
262
252
  this.faucetService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
263
- 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));
264
254
  } else if (device.bot?.deviceType === 'fan') {
265
255
  this.removeLockService(accessory);
266
256
  this.removeDoorService(accessory);
@@ -278,7 +268,7 @@ export class Bot {
278
268
  this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Fan`);
279
269
 
280
270
  this.fanService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
281
- 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));
282
272
  } else if (device.bot?.deviceType === 'stateful') {
283
273
  this.removeFanService(accessory);
284
274
  this.removeLockService(accessory);
@@ -300,7 +290,7 @@ export class Bot {
300
290
  this.statefulProgrammableSwitchService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
301
291
  this.statefulProgrammableSwitchService
302
292
  .getCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState)
303
- .onSet(this.handleOnSet.bind(this));
293
+ .onSet(this.OnSet.bind(this));
304
294
  } else {
305
295
  this.removeFanService(accessory);
306
296
  this.removeLockService(accessory);
@@ -318,15 +308,15 @@ export class Bot {
318
308
  this.infoLog(`${this.device.deviceType}: ${accessory.displayName} Displaying as Outlet`);
319
309
 
320
310
  this.outletService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
321
- 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));
322
312
  }
323
313
 
324
314
  // Battery Service
325
- if (!device.ble) {
315
+ if (!this.BLE) {
326
316
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`);
327
317
  this.batteryService = this.accessory.getService(this.platform.Service.Battery);
328
318
  accessory.removeService(this.batteryService!);
329
- } else if (device.ble && !this.batteryService) {
319
+ } else if (this.BLE && !this.batteryService) {
330
320
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`);
331
321
  (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)),
332
322
  `${accessory.displayName} Battery`;
@@ -347,30 +337,25 @@ export class Bot {
347
337
  });
348
338
 
349
339
  // Watch for Bot change events
350
- // 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
351
341
  this.doBotUpdate
352
342
  .pipe(
353
343
  tap(() => {
354
344
  this.botUpdateInProgress = true;
355
345
  }),
356
- debounceTime(100),
346
+ debounceTime(this.platform.config.options!.pushRate! * 1000),
357
347
  )
358
348
  .subscribe(async () => {
359
349
  try {
360
- interval(100)
350
+ interval(15000)
361
351
  .pipe(take(this.doublePress!))
362
352
  .subscribe(async () => {
363
353
  await this.pushChanges();
364
354
  });
365
355
  } catch (e: any) {
366
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges`);
367
- if (this.deviceLogging.includes('debug')) {
368
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges,`
369
- + ` Error Message: ${superStringify(e.message)}`);
370
- }
371
- if (this.platform.debugMode) {
372
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges,` + ` Error: ${superStringify(e)}`);
373
- }
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)}`);
374
359
  }
375
360
  this.botUpdateInProgress = false;
376
361
  });
@@ -380,15 +365,19 @@ export class Bot {
380
365
  * Parse the device status from the SwitchBot api
381
366
  */
382
367
  async parseStatus(): Promise<void> {
383
- 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;
384
372
  await this.openAPIparseStatus();
385
373
  } else {
386
- await this.BLEparseStatus();
374
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
375
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
387
376
  }
388
377
  }
389
378
 
390
379
  async BLEparseStatus(): Promise<void> {
391
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE parseStatus`);
380
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
392
381
  // BLEmode (true if Switch Mode) | (false if Press Mode)
393
382
  if (this.mode) {
394
383
  this.accessory.context.On = this.On;
@@ -415,37 +404,35 @@ export class Bot {
415
404
  }
416
405
 
417
406
  async openAPIparseStatus(): Promise<void> {
418
- if (this.device.ble) {
419
- this.SwitchToOpenAPI = false;
420
- }
421
- if (this.platform.config.credentials?.token) {
422
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI parseStatus`);
423
- 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) {
424
414
  this.On = false;
425
- this.accessory.context.On = this.On;
426
- } else {
427
- this.accessory.context.On = this.On;
428
- if (this.On === undefined) {
429
- this.On = false;
430
- }
431
415
  }
432
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
433
416
  }
417
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
434
418
  }
435
419
 
436
420
  /**
437
421
  * Asks the SwitchBot API for the latest device information
438
422
  */
439
423
  async refreshStatus(): Promise<void> {
440
- if (this.device.ble) {
424
+ if (this.BLE) {
441
425
  await this.BLERefreshStatus();
442
- } else {
426
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
443
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.`);
444
431
  }
445
432
  }
446
433
 
447
434
  async BLERefreshStatus(): Promise<void> {
448
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE refreshStatus`);
435
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
449
436
  const switchbot = await this.platform.connectBLE();
450
437
  // Convert to BLE Address
451
438
  this.device.bleMac = this.device
@@ -455,157 +442,113 @@ export class Bot {
455
442
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
456
443
  this.getCustomBLEAddress(switchbot);
457
444
  // Start to monitor advertisement packets
458
- if (switchbot === false) {
459
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection: ${switchbot}`);
460
- }
461
- switchbot
462
- .startScan({
463
- model: 'H',
464
- id: this.device.bleMac,
465
- })
466
- .then(() => {
445
+ if (switchbot !== false) {
446
+ switchbot
447
+ .startScan({
448
+ model: 'H',
449
+ id: this.device.bleMac,
450
+ })
451
+ .then(() => {
467
452
  // Set an event hander
468
- switchbot.onadvertisement = (ad: ad) => {
469
- this.address = ad.address;
470
- if (this.deviceLogging.includes('debug')) {
471
- this.infoLog(this.address);
472
- this.infoLog(this.device.bleMac);
473
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address Found: ${this.address}`);
474
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac}`);
475
- }
476
- this.serviceData = ad.serviceData;
477
- this.mode = ad.serviceData.mode;
478
- this.state = ad.serviceData.state;
479
- this.battery = ad.serviceData.battery;
480
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
481
- this.debugLog(
482
- `${this.device.deviceType}: ${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},` +
483
468
  ` mode: ${ad.serviceData.mode}, state: ${ad.serviceData.state}, battery: ${ad.serviceData.battery}`,
484
- );
485
-
486
- if (this.serviceData) {
487
- this.connected = true;
488
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
489
- } else {
490
- this.connected = false;
491
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} connected: ${this.connected}`);
492
- }
493
- };
494
- // Wait 2 seconds
495
- return switchbot.wait(this.scanDuration * 1000);
496
- })
497
- .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 () => {
498
483
  // Stop to monitor
499
- switchbot.stopScan();
500
- if (this.connected) {
501
- this.parseStatus();
502
- this.updateHomeKitCharacteristics();
503
- } else {
504
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
505
- if (this.platform.config.credentials?.token) {
506
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
507
- this.SwitchToOpenAPI = true;
508
- await this.openAPIRefreshStatus();
484
+ switchbot.stopScan();
485
+ if (this.connected) {
486
+ this.parseStatus();
487
+ this.updateHomeKitCharacteristics();
488
+ } else {
489
+ await this.BLEconnection(switchbot);
509
490
  }
510
- }
511
- })
512
- .catch(async (e: any) => {
513
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
514
- if (this.deviceLogging.includes('debug')) {
515
- this.errorLog(
516
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
517
- + ` Error Message: ${superStringify(e.message)}`,
518
- );
519
- }
520
- if (this.platform.config.credentials?.token) {
521
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
522
- this.SwitchToOpenAPI = true;
523
- await this.openAPIRefreshStatus();
524
- }
525
- this.apiError(e);
526
- });
527
- }
528
-
529
- async getCustomBLEAddress(switchbot: any) {
530
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
531
- (async () => {
532
- // Start to monitor advertisement packets
533
- await switchbot.startScan({
534
- 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);
535
497
  });
536
- // Set an event handler
537
- switchbot.onadvertisement = (ad: any) => {
538
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
539
- };
540
- await switchbot.wait(10000);
541
- // Stop to monitor
542
- switchbot.stopScan();
543
- })();
498
+ } else {
499
+ await this.BLEconnection(switchbot);
544
500
  }
545
501
  }
546
502
 
547
503
  async openAPIRefreshStatus(): Promise<void> {
548
- if (this.platform.config.credentials?.token && this.OpenAPI) {
549
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI refreshStatus`);
550
- try {
551
- const t = Date.now();
552
- const nonce = 'requestID';
553
- const data = this.platform.config.credentials?.token + t + nonce;
554
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
555
- const sign = signTerm.toString('base64');
556
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
557
- const options = {
558
- hostname: HostDomain,
559
- port: 443,
560
- path: `${DevicePath}/${this.device.deviceId}/status`,
561
- method: 'GET',
562
- headers: {
563
- Authorization: this.platform.config.credentials?.token,
564
- sign: sign,
565
- nonce: nonce,
566
- t: t,
567
- 'Content-Type': 'application/json',
568
- },
569
- };
570
- const req = https.request(options, (res) => {
571
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Refresh statusCode: ${res.statusCode}`);
572
- let rawData = '';
573
- res.on('data', (d) => {
574
- rawData += d;
575
- this.debugLog(`d: ${d}`);
576
- });
577
- res.on('end', () => {
578
- try {
579
- this.deviceStatus = JSON.parse(rawData);
580
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
581
- this.power = this.deviceStatus.body.power;
582
- this.parseStatus();
583
- this.updateHomeKitCharacteristics();
584
- } catch (e: any) {
585
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
586
- }
587
- });
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}`);
588
531
  });
589
- req.on('error', (e: any) => {
590
- this.errorLog(`${this.device.deviceType}: ${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
+ }
591
542
  });
592
- req.end();
593
- } catch (e: any) {
594
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
595
- if (this.deviceLogging.includes('debug')) {
596
- this.errorLog(
597
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
598
- + ` Error Message: ${superStringify(e.message)}`,
599
- );
600
- }
601
- if (this.platform.debugMode) {
602
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
603
- + ` Error: ${superStringify(e)}`);
604
- }
605
- this.apiError(e);
606
- }
607
- } else {
608
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
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)}`);
609
552
  }
610
553
  }
611
554
 
@@ -617,10 +560,13 @@ export class Bot {
617
560
  * Bot - "command" "press" "default" = trigger press
618
561
  */
619
562
  async pushChanges(): Promise<void> {
620
- if (this.device.ble) {
621
- await this.BLEpushChanges();
622
- } else {
563
+ if (this.BLE) {
564
+ await this.BLERefreshStatus();
565
+ } else if (this.OpenAPI) {
623
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.`);
624
570
  }
625
571
  interval(5000)
626
572
  .pipe(take(1))
@@ -630,9 +576,9 @@ export class Bot {
630
576
  }
631
577
 
632
578
  async BLEpushChanges(): Promise<void> {
633
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE pushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
579
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
634
580
  if (this.On !== this.accessory.context.On || this.allowPush) {
635
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE pushChanges`);
581
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
636
582
  const switchbot = await this.platform.connectBLE();
637
583
  // Convert to BLE Address
638
584
  this.device.bleMac = this.device
@@ -662,22 +608,13 @@ export class Bot {
662
608
  }, 500);
663
609
  })
664
610
  .catch(async (e: any) => {
665
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
666
- if (this.deviceLogging.includes('debug')) {
667
- this.errorLog(
668
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
669
- + ` Error Message: ${superStringify(e.message)}`,
670
- );
671
- }
672
- if (this.platform.debugMode) {
673
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
674
- + ` Error: ${superStringify(e)}`);
675
- }
676
- if (this.platform.config.credentials?.token) {
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') {
677
615
  this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
678
616
  await this.openAPIpushChanges();
679
617
  }
680
- this.apiError(e);
681
618
  });
682
619
  } else if (this.botMode === 'switch') {
683
620
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode: ${this.botMode}`);
@@ -692,127 +629,145 @@ export class Bot {
692
629
  this.accessory.context.On = this.On;
693
630
  })
694
631
  .catch(async (e: any) => {
695
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
696
- if (this.deviceLogging.includes('debug')) {
697
- this.errorLog(
698
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
699
- + ` Error Message: ${superStringify(e.message)}`,
700
- );
701
- }
702
- if (this.platform.debugMode) {
703
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
704
- + ` Error: ${superStringify(e)}`);
705
- }
706
- if (this.platform.config.credentials?.token) {
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') {
707
636
  this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
708
637
  await this.openAPIpushChanges();
709
638
  }
710
- this.apiError(e);
711
639
  });
712
640
  } else {
713
- throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
641
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
714
642
  }
643
+ } else {
644
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, `
645
+ +`OnCached: ${this.accessory.context.On}`);
715
646
  }
716
- this.accessory.context.On = this.On;
717
647
  }
718
648
 
719
- async turnOnOff(device_list: any): Promise<any> {
720
- return await this.retry({
721
- max: await this.maxRetry(),
722
- fn: () => {
723
- if (this.On) {
724
- 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;
725
675
  } else {
726
- 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.`);
727
677
  }
728
- },
729
- });
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
+ }
730
721
  }
731
722
 
732
- async openAPIpushChanges(): Promise<void> {
733
- if (this.platform.config.credentials?.token && this.OpenAPI) {
734
- try {
735
- if (this.On !== this.accessory.context.On || this.allowPush) {
736
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI pushChanges`);
737
- // Make Push On request to the API
738
- const t = Date.now();
739
- const nonce = 'requestID';
740
- const data = this.platform.config.credentials?.token + t + nonce;
741
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
742
- .update(Buffer.from(data, 'utf-8'))
743
- .digest();
744
- const sign = signTerm.toString('base64');
745
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
746
- let command = '';
747
- if (this.botMode === 'switch' && this.On) {
748
- command = 'turnOn';
749
- this.On = true;
750
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
751
- } else if (this.botMode === 'switch' && !this.On) {
752
- command = 'turnOff';
753
- this.On = false;
754
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
755
- } else if (this.botMode === 'press') {
756
- command = 'press';
757
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Press Mode`);
758
- this.On = false;
759
- } else {
760
- throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Device Paramters not set for this Bot.`);
761
- }
762
- const body = superStringify({
763
- 'command': `${command}`,
764
- 'parameter': 'default',
765
- 'commandType': 'command',
766
- });
767
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
768
- const options = {
769
- hostname: HostDomain,
770
- port: 443,
771
- path: `${DevicePath}/${this.device.deviceId}/commands`,
772
- method: 'POST',
773
- headers: {
774
- 'Authorization': this.platform.config.credentials?.token,
775
- 'sign': sign,
776
- 'nonce': nonce,
777
- 't': t,
778
- 'Content-Type': 'application/json',
779
- 'Content-Length': body.length,
780
- },
781
- };
782
- const req = https.request(options, res => {
783
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
784
- this.statusCode({ res });
785
- res.on('data', d => {
786
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
787
- });
788
- });
789
- req.on('error', (e: any) => {
790
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
791
- });
792
- req.write(body);
793
- req.end();
794
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
795
- this.accessory.context.On = this.On;
796
- }
797
- } catch (e: any) {
798
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
799
- if (this.deviceLogging.includes('debug')) {
800
- this.errorLog(
801
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,`
802
- + ` Error Message: ${superStringify(e.message)}`,
803
- );
804
- }
805
- if (this.platform.debugMode) {
806
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,`
807
- + ` Error: ${superStringify(e)}`);
808
- }
809
- 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;
810
733
  }
811
- } else {
812
- if (this.deviceLogging.includes('debug')) {
813
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, device status will not be sent.`);
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;
814
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;
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
  /**
@@ -996,7 +951,7 @@ export class Bot {
996
951
  }
997
952
  }
998
953
  this.accessory.context.On = this.On;
999
- if (this.device.ble) {
954
+ if (this.BLE) {
1000
955
  if (this.BatteryLevel === undefined) {
1001
956
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
1002
957
  } else {
@@ -1014,137 +969,143 @@ export class Bot {
1014
969
  }
1015
970
  }
1016
971
 
1017
- async apiError(e: any): Promise<void> {
1018
- if (this.device.bot?.deviceType === 'garagedoor') {
1019
- this.garageDoorService?.updateCharacteristic(this.platform.Characteristic.TargetDoorState, e);
1020
- this.garageDoorService?.updateCharacteristic(this.platform.Characteristic.CurrentDoorState, e);
1021
- this.garageDoorService?.updateCharacteristic(this.platform.Characteristic.ObstructionDetected, e);
1022
- } else if (this.device.bot?.deviceType === 'door') {
1023
- this.doorService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
1024
- this.doorService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
1025
- this.doorService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
1026
- } else if (this.device.bot?.deviceType === 'window') {
1027
- this.windowService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
1028
- this.windowService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
1029
- this.windowService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
1030
- } else if (this.device.bot?.deviceType === 'windowcovering') {
1031
- this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
1032
- this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
1033
- this.windowCoveringService?.updateCharacteristic(this.platform.Characteristic.PositionState, e);
1034
- } else if (this.device.bot?.deviceType === 'lock') {
1035
- this.doorService?.updateCharacteristic(this.platform.Characteristic.LockTargetState, e);
1036
- this.doorService?.updateCharacteristic(this.platform.Characteristic.LockCurrentState, e);
1037
- } else if (this.device.bot?.deviceType === 'faucet') {
1038
- this.faucetService?.updateCharacteristic(this.platform.Characteristic.Active, e);
1039
- } else if (this.device.bot?.deviceType === 'fan') {
1040
- this.fanService?.updateCharacteristic(this.platform.Characteristic.On, e);
1041
- } else if (this.device.bot?.deviceType === 'stateful') {
1042
- this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchEvent, e);
1043
- this.statefulProgrammableSwitchService?.updateCharacteristic(this.platform.Characteristic.ProgrammableSwitchOutputState, e);
1044
- } else if (this.device.bot?.deviceType === 'switch') {
1045
- this.switchService?.updateCharacteristic(this.platform.Characteristic.On, e);
1046
- } else {
1047
- 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`);
1048
977
  }
1049
- if (this.device.ble) {
1050
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
1051
- 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`);
1052
986
  }
1053
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
987
+ accessory.removeService(this.garageDoorService!);
1054
988
  }
1055
989
 
1056
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
1057
- switch (res.statusCode) {
1058
- case 151:
1059
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
1060
- break;
1061
- case 152:
1062
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
1063
- break;
1064
- case 160:
1065
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
1066
- break;
1067
- case 161:
1068
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
1069
- this.offlineOff();
1070
- break;
1071
- case 171:
1072
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
1073
- this.offlineOff();
1074
- break;
1075
- case 190:
1076
- this.errorLog(
1077
- `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
1078
- ` Or command: ${superStringify(res)} format is invalid`,
1079
- );
1080
- break;
1081
- case 100:
1082
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
1083
- break;
1084
- default:
1085
- this.debugLog(`${this.device.deviceType}: ${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`);
1086
995
  }
996
+ accessory.removeService(this.doorService!);
1087
997
  }
1088
998
 
1089
- async offlineOff(): Promise<void> {
1090
- if (this.device.offline) {
1091
- this.On = false;
1092
- if (this.device.bot?.deviceType === 'switch') {
1093
- this.switchService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
1094
- } else {
1095
- this.outletService?.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
1096
- }
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`);
1097
1004
  }
1005
+ accessory.removeService(this.lockService!);
1098
1006
  }
1099
1007
 
1100
- /**
1101
- * Handle requests to set the "On" characteristic
1102
- */
1103
- async handleOnSet(value: CharacteristicValue): Promise<void> {
1104
- if (this.device.bot?.deviceType === 'garagedoor') {
1105
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetDoorState: ${value}`);
1106
- if (value === this.platform.Characteristic.TargetDoorState.CLOSED) {
1107
- this.On = false;
1108
- } else {
1109
- this.On = true;
1110
- }
1111
- } else if (
1112
- this.device.bot?.deviceType === 'door' ||
1113
- this.device.bot?.deviceType === 'window' ||
1114
- this.device.bot?.deviceType === 'windowcovering'
1115
- ) {
1116
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} TargetPosition: ${value}`);
1117
- if (value === 0) {
1118
- this.On = false;
1119
- } else {
1120
- this.On = true;
1121
- }
1122
- } else if (this.device.bot?.deviceType === 'lock') {
1123
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} LockTargetState: ${value}`);
1124
- if (value === this.platform.Characteristic.LockTargetState.SECURED) {
1125
- this.On = false;
1126
- } else {
1127
- this.On = true;
1128
- }
1129
- } else if (this.device.bot?.deviceType === 'faucet') {
1130
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Active: ${value}`);
1131
- if (value === this.platform.Characteristic.Active.INACTIVE) {
1132
- this.On = false;
1133
- } else {
1134
- this.On = true;
1135
- }
1136
- } else if (this.device.bot?.deviceType === 'stateful') {
1137
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ProgrammableSwitchOutputState: ${value}`);
1138
- if (value === 0) {
1139
- this.On = false;
1140
- } else {
1141
- this.On = true;
1142
- }
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;
1143
1066
  } else {
1144
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${value}`);
1145
- this.On = value;
1067
+ this.doublePress = 1;
1068
+ }
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();
1146
1095
  }
1147
- this.doBotUpdate.next();
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
+ });
1148
1109
  }
1149
1110
 
1150
1111
  async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
@@ -1169,80 +1130,125 @@ export class Bot {
1169
1130
  return maxRetry;
1170
1131
  }
1171
1132
 
1172
- async config(device: device & devicesConfig): Promise<void> {
1173
- let config = {};
1174
- if (device.bot) {
1175
- config = device.bot;
1176
- }
1177
- if (device.ble) {
1178
- config['ble'] = device.ble;
1179
- }
1180
- if (device.openAPI !== undefined) {
1181
- config['openAPI'] = device.openAPI;
1182
- }
1183
- if (device.logging !== undefined) {
1184
- config['logging'] = device.logging;
1185
- }
1186
- if (device.refreshRate !== undefined) {
1187
- config['refreshRate'] = device.refreshRate;
1188
- }
1189
- if (device.scanDuration !== undefined) {
1190
- config['scanDuration'] = device.scanDuration;
1191
- }
1192
- if (device.offline !== undefined) {
1193
- config['offline'] = device.offline;
1194
- }
1195
- if (Object.entries(config).length !== 0) {
1196
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
1197
- }
1198
- }
1199
-
1200
- async refreshRate(device: device & devicesConfig): Promise<void> {
1201
- if (device.refreshRate) {
1202
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
1203
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
1204
- } else if (this.platform.config.options!.refreshRate) {
1205
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
1206
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
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}`);
1207
1146
  }
1208
1147
  }
1209
1148
 
1210
- async openAPI() {
1211
- if (!this.device.openAPI) {
1212
- this.OpenAPI = true;
1149
+ async allowPushChanges(device: device & devicesConfig): Promise<void> {
1150
+ if (device.bot?.allowPush) {
1151
+ this.allowPush = true;
1213
1152
  } else {
1214
- this.OpenAPI = this.device.openAPI;
1153
+ this.allowPush = false;
1215
1154
  }
1216
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI: ${this.OpenAPI}`);
1155
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Allowing Push Changes: ${this.allowPush}`);
1217
1156
  }
1218
1157
 
1219
1158
  async scan(device: device & devicesConfig): Promise<void> {
1220
1159
  if (device.scanDuration) {
1221
1160
  this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
1222
- if (device.ble) {
1161
+ if (this.BLE) {
1223
1162
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
1224
1163
  }
1225
1164
  } else {
1226
1165
  this.scanDuration = this.accessory.context.scanDuration = 1;
1227
- if (this.device.ble) {
1166
+ if (this.BLE) {
1228
1167
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
1229
1168
  }
1230
1169
  }
1231
1170
  }
1232
1171
 
1233
- async logs(device: device & devicesConfig): Promise<void> {
1234
- if (this.platform.debugMode) {
1235
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
1236
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
1237
- } else if (device.logging) {
1238
- this.deviceLogging = this.accessory.context.logging = device.logging;
1239
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
1240
- } else if (this.platform.config.options?.logging) {
1241
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
1242
- this.debugLog(`${this.device.deviceType}: ${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);
1243
1246
  } else {
1244
- this.deviceLogging = this.accessory.context.logging = 'standard';
1245
- this.debugLog(`${this.device.deviceType}: ${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);
1246
1252
  }
1247
1253
  }
1248
1254
 
@@ -1262,119 +1268,75 @@ export class Bot {
1262
1268
  return FirmwareRevision;
1263
1269
  }
1264
1270
 
1265
- async PressOrSwitch(device: device & devicesConfig): Promise<void> {
1266
- if (!device.bot?.mode) {
1267
- this.botMode = 'switch';
1268
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} does not have bot mode set in the Plugin's SwitchBot Device Settings,`);
1269
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} is defaulting to "${this.botMode}" mode, you may experience issues.`);
1270
- } else if (device.bot?.mode === 'switch') {
1271
- this.botMode = 'switch';
1272
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Bot Mode: ${this.botMode}`);
1273
- } else if (device.bot?.mode === 'press') {
1274
- this.botMode = 'press';
1275
- this.debugLog(`${this.device.deviceType}: ${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;
1276
1275
  } else {
1277
- throw new Error(`${this.device.deviceType}: ${this.accessory.displayName} Bot Mode: ${this.botMode}`);
1276
+ this.On = this.accessory.context.On;
1278
1277
  }
1279
- }
1280
-
1281
- async allowPushChanges(device: device & devicesConfig): Promise<void> {
1282
- if (device.bot?.allowPush) {
1283
- this.allowPush = true;
1278
+ if (this.BatteryLevel === undefined) {
1279
+ this.BatteryLevel = 100;
1284
1280
  } else {
1285
- this.allowPush = false;
1281
+ this.BatteryLevel = this.accessory.context.BatteryLevel;
1286
1282
  }
1287
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Allowing Push Changes: ${this.allowPush}`);
1288
- }
1289
-
1290
- async removeOutletService(accessory: PlatformAccessory): Promise<void> {
1291
- // If outletService still pressent, then remove first
1292
- this.outletService = this.accessory.getService(this.platform.Service.Outlet);
1293
- if (this.outletService) {
1294
- this.warnLog(`${this.device.deviceType}: ${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;
1295
1288
  }
1296
- accessory.removeService(this.outletService!);
1297
1289
  }
1298
1290
 
1299
- async removeGarageDoorService(accessory: PlatformAccessory): Promise<void> {
1300
- // If garageDoorService still pressent, then remove first
1301
- this.garageDoorService = this.accessory.getService(this.platform.Service.GarageDoorOpener);
1302
- if (this.garageDoorService) {
1303
- this.warnLog(`${this.device.deviceType}: ${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}`);
1304
1298
  }
1305
- accessory.removeService(this.garageDoorService!);
1306
1299
  }
1307
1300
 
1308
- async removeDoorService(accessory: PlatformAccessory): Promise<void> {
1309
- // If doorService still pressent, then remove first
1310
- this.doorService = this.accessory.getService(this.platform.Service.Door);
1311
- if (this.doorService) {
1312
- this.warnLog(`${this.device.deviceType}: ${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;
1313
1305
  }
1314
- accessory.removeService(this.doorService!);
1315
- }
1316
-
1317
- async removeLockService(accessory: PlatformAccessory): Promise<void> {
1318
- // If lockService still pressent, then remove first
1319
- this.lockService = this.accessory.getService(this.platform.Service.LockMechanism);
1320
- if (this.lockService) {
1321
- this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Lock Service`);
1306
+ if (device.connectionType !== undefined) {
1307
+ config['connectionType'] = device.connectionType;
1322
1308
  }
1323
- accessory.removeService(this.lockService!);
1324
- }
1325
-
1326
- async removeFaucetService(accessory: PlatformAccessory): Promise<void> {
1327
- // If faucetService still pressent, then remove first
1328
- this.faucetService = this.accessory.getService(this.platform.Service.Faucet);
1329
- if (this.faucetService) {
1330
- this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Faucet Service`);
1309
+ if (device.logging !== undefined) {
1310
+ config['logging'] = device.logging;
1331
1311
  }
1332
- accessory.removeService(this.faucetService!);
1333
- }
1334
-
1335
- async removeFanService(accessory: PlatformAccessory): Promise<void> {
1336
- // If fanService still pressent, then remove first
1337
- this.fanService = this.accessory.getService(this.platform.Service.Fan);
1338
- if (this.fanService) {
1339
- this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Fan Service`);
1312
+ if (device.refreshRate !== undefined) {
1313
+ config['refreshRate'] = device.refreshRate;
1340
1314
  }
1341
- accessory.removeService(this.fanService!);
1342
- }
1343
-
1344
- async removeWindowService(accessory: PlatformAccessory): Promise<void> {
1345
- // If windowService still pressent, then remove first
1346
- this.windowService = this.accessory.getService(this.platform.Service.Window);
1347
- if (this.windowService) {
1348
- this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Window Service`);
1315
+ if (device.scanDuration !== undefined) {
1316
+ config['scanDuration'] = device.scanDuration;
1349
1317
  }
1350
- accessory.removeService(this.windowService!);
1351
- }
1352
-
1353
- async removeWindowCoveringService(accessory: PlatformAccessory): Promise<void> {
1354
- // If windowCoveringService still pressent, then remove first
1355
- this.windowCoveringService = this.accessory.getService(this.platform.Service.WindowCovering);
1356
- if (this.windowCoveringService) {
1357
- this.warnLog(`${this.device.deviceType}: ${accessory.displayName} Removing Leftover Window Covering Service`);
1318
+ if (device.offline !== undefined) {
1319
+ config['offline'] = device.offline;
1358
1320
  }
1359
- accessory.removeService(this.windowCoveringService!);
1360
- }
1361
-
1362
- async removeStatefulProgrammableSwitchService(accessory: PlatformAccessory): Promise<void> {
1363
- // If statefulProgrammableSwitchService still pressent, then remove first
1364
- this.statefulProgrammableSwitchService = this.accessory.getService(this.platform.Service.StatefulProgrammableSwitch);
1365
- if (this.statefulProgrammableSwitchService) {
1366
- this.warnLog(`${this.device.deviceType}: ${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)}`);
1367
1323
  }
1368
- accessory.removeService(this.statefulProgrammableSwitchService!);
1369
1324
  }
1370
1325
 
1371
- async removeSwitchService(accessory: PlatformAccessory): Promise<void> {
1372
- // If switchService still pressent, then remove first
1373
- this.switchService = this.accessory.getService(this.platform.Service.Switch);
1374
- if (this.switchService) {
1375
- this.warnLog(`${this.device.deviceType}: ${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}`);
1376
1339
  }
1377
- accessory.removeService(this.switchService!);
1378
1340
  }
1379
1341
 
1380
1342
  /**