@switchbot/homebridge-switchbot 2.0.0-beta.8 → 2.0.0

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