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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/README.md +1 -2
  3. package/config.schema.json +51 -32
  4. package/dist/device/bot.d.ts +32 -29
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +549 -575
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/colorbulb.d.ts +33 -15
  9. package/dist/device/colorbulb.d.ts.map +1 -1
  10. package/dist/device/colorbulb.js +426 -341
  11. package/dist/device/colorbulb.js.map +1 -1
  12. package/dist/device/contact.d.ts +16 -9
  13. package/dist/device/contact.d.ts.map +1 -1
  14. package/dist/device/contact.js +246 -208
  15. package/dist/device/contact.js.map +1 -1
  16. package/dist/device/curtain.d.ts +21 -18
  17. package/dist/device/curtain.d.ts.map +1 -1
  18. package/dist/device/curtain.js +449 -449
  19. package/dist/device/curtain.js.map +1 -1
  20. package/dist/device/humidifier.d.ts +22 -20
  21. package/dist/device/humidifier.d.ts.map +1 -1
  22. package/dist/device/humidifier.js +346 -324
  23. package/dist/device/humidifier.js.map +1 -1
  24. package/dist/device/lock.d.ts +22 -10
  25. package/dist/device/lock.d.ts.map +1 -1
  26. package/dist/device/lock.js +257 -178
  27. package/dist/device/lock.js.map +1 -1
  28. package/dist/device/meter.d.ts +21 -14
  29. package/dist/device/meter.d.ts.map +1 -1
  30. package/dist/device/meter.js +287 -239
  31. package/dist/device/meter.js.map +1 -1
  32. package/dist/device/meterplus.d.ts +23 -10
  33. package/dist/device/meterplus.d.ts.map +1 -1
  34. package/dist/device/meterplus.js +308 -190
  35. package/dist/device/meterplus.js.map +1 -1
  36. package/dist/device/motion.d.ts +17 -10
  37. package/dist/device/motion.d.ts.map +1 -1
  38. package/dist/device/motion.js +225 -193
  39. package/dist/device/motion.js.map +1 -1
  40. package/dist/device/plug.d.ts +24 -17
  41. package/dist/device/plug.d.ts.map +1 -1
  42. package/dist/device/plug.js +270 -267
  43. package/dist/device/plug.js.map +1 -1
  44. package/dist/device/striplight.d.ts +36 -14
  45. package/dist/device/striplight.d.ts.map +1 -1
  46. package/dist/device/striplight.js +447 -299
  47. package/dist/device/striplight.js.map +1 -1
  48. package/dist/irdevice/airconditioner.d.ts +7 -14
  49. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  50. package/dist/irdevice/airconditioner.js +177 -169
  51. package/dist/irdevice/airconditioner.js.map +1 -1
  52. package/dist/irdevice/airpurifier.d.ts +3 -5
  53. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  54. package/dist/irdevice/airpurifier.js +72 -57
  55. package/dist/irdevice/airpurifier.js.map +1 -1
  56. package/dist/irdevice/camera.d.ts +3 -4
  57. package/dist/irdevice/camera.d.ts.map +1 -1
  58. package/dist/irdevice/camera.js +47 -33
  59. package/dist/irdevice/camera.js.map +1 -1
  60. package/dist/irdevice/fan.d.ts +3 -4
  61. package/dist/irdevice/fan.d.ts.map +1 -1
  62. package/dist/irdevice/fan.js +66 -48
  63. package/dist/irdevice/fan.js.map +1 -1
  64. package/dist/irdevice/light.d.ts +3 -4
  65. package/dist/irdevice/light.d.ts.map +1 -1
  66. package/dist/irdevice/light.js +48 -47
  67. package/dist/irdevice/light.js.map +1 -1
  68. package/dist/irdevice/other.d.ts +3 -4
  69. package/dist/irdevice/other.d.ts.map +1 -1
  70. package/dist/irdevice/other.js +47 -33
  71. package/dist/irdevice/other.js.map +1 -1
  72. package/dist/irdevice/tv.d.ts +10 -11
  73. package/dist/irdevice/tv.d.ts.map +1 -1
  74. package/dist/irdevice/tv.js +64 -48
  75. package/dist/irdevice/tv.js.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.d.ts +7 -12
  77. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.js +52 -41
  79. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  80. package/dist/irdevice/waterheater.d.ts +6 -11
  81. package/dist/irdevice/waterheater.d.ts.map +1 -1
  82. package/dist/irdevice/waterheater.js +52 -42
  83. package/dist/irdevice/waterheater.js.map +1 -1
  84. package/dist/platform.d.ts +0 -4
  85. package/dist/platform.d.ts.map +1 -1
  86. package/dist/platform.js +44 -66
  87. package/dist/platform.js.map +1 -1
  88. package/dist/settings.d.ts +3 -3
  89. package/dist/settings.d.ts.map +1 -1
  90. package/package.json +7 -6
  91. package/src/device/bot.ts +551 -589
  92. package/src/device/colorbulb.ts +441 -375
  93. package/src/device/contact.ts +249 -213
  94. package/src/device/curtain.ts +452 -461
  95. package/src/device/humidifier.ts +358 -365
  96. package/src/device/lock.ts +263 -179
  97. package/src/device/meter.ts +302 -253
  98. package/src/device/meterplus.ts +319 -194
  99. package/src/device/motion.ts +230 -199
  100. package/src/device/plug.ts +273 -274
  101. package/src/device/striplight.ts +460 -316
  102. package/src/irdevice/airconditioner.ts +181 -183
  103. package/src/irdevice/airpurifier.ts +70 -60
  104. package/src/irdevice/camera.ts +46 -36
  105. package/src/irdevice/fan.ts +64 -49
  106. package/src/irdevice/light.ts +47 -51
  107. package/src/irdevice/other.ts +46 -36
  108. package/src/irdevice/tv.ts +64 -51
  109. package/src/irdevice/vacuumcleaner.ts +52 -45
  110. package/src/irdevice/waterheater.ts +50 -45
  111. package/src/platform.ts +44 -68
  112. package/src/settings.ts +3 -3
@@ -35,7 +35,6 @@ export class Plug {
35
35
  currentPower: serviceData['currentPower'];
36
36
 
37
37
  // Config
38
- OpenAPI?: boolean;
39
38
  scanDuration!: number;
40
39
  deviceLogging!: string;
41
40
  deviceRefreshRate!: number;
@@ -44,17 +43,17 @@ export class Plug {
44
43
  plugUpdateInProgress!: boolean;
45
44
  doPlugUpdate!: Subject<void>;
46
45
 
46
+ // Connection
47
+ private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
48
+ private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
49
+
47
50
  constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
48
51
  // default placeholders
49
52
  this.logs(device);
50
53
  this.scan(device);
51
54
  this.refreshRate(device);
52
55
  this.config(device);
53
- if (this.On === undefined) {
54
- this.On = false;
55
- } else {
56
- this.On = this.accessory.context.On;
57
- }
56
+ this.context();
58
57
 
59
58
  // this is subject we use to track when we need to POST changes to the SwitchBot API
60
59
  this.doPlugUpdate = new Subject();
@@ -90,7 +89,7 @@ export class Plug {
90
89
  // see https://developers.homebridge.io/#/service/Outlet
91
90
 
92
91
  // create handlers for required characteristics
93
- this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.handleOnSet.bind(this));
92
+ this.outletService.getCharacteristic(this.platform.Characteristic.On).onSet(this.OnSet.bind(this));
94
93
 
95
94
  // Update Homekit
96
95
  this.updateHomeKitCharacteristics();
@@ -115,27 +114,31 @@ export class Plug {
115
114
  try {
116
115
  await this.pushChanges();
117
116
  } catch (e: any) {
118
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges`);
119
- if (this.deviceLogging.includes('debug')) {
120
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges,`
121
- + ` Error Message: ${superStringify(e.message)}`);
122
- }
123
117
  this.apiError(e);
118
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
119
+ + ` Error Message: ${superStringify(e.message)}`);
124
120
  }
125
121
  this.plugUpdateInProgress = false;
126
122
  });
127
123
  }
128
124
 
125
+ /**
126
+ * Parse the device status from the SwitchBot api
127
+ */
129
128
  async parseStatus(): Promise<void> {
130
- if (this.SwitchToOpenAPI || !this.device.ble) {
129
+ if (this.BLE && !this.SwitchToOpenAPI) {
130
+ await this.BLEparseStatus();
131
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
132
+ this.SwitchToOpenAPI = false;
131
133
  await this.openAPIparseStatus();
132
134
  } else {
133
- await this.BLEparseStatus();
135
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
136
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
134
137
  }
135
138
  }
136
139
 
137
140
  async BLEparseStatus(): Promise<void> {
138
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE parseStatus`);
141
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
139
142
  // State
140
143
  switch (this.state) {
141
144
  case 'on':
@@ -148,6 +151,7 @@ export class Plug {
148
151
  }
149
152
 
150
153
  async openAPIparseStatus() {
154
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
151
155
  switch (this.power) {
152
156
  case 'on':
153
157
  this.On = true;
@@ -158,16 +162,22 @@ export class Plug {
158
162
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
159
163
  }
160
164
 
165
+ /**
166
+ * Asks the SwitchBot API for the latest device information
167
+ */
161
168
  async refreshStatus(): Promise<void> {
162
- if (this.device.ble) {
169
+ if (this.BLE) {
163
170
  await this.BLERefreshStatus();
164
- } else {
171
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
165
172
  await this.openAPIRefreshStatus();
173
+ } else {
174
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
175
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
166
176
  }
167
177
  }
168
178
 
169
179
  async BLERefreshStatus(): Promise<void> {
170
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE refreshStatus`);
180
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
171
181
  const switchbot = await this.platform.connectBLE();
172
182
  // Convert to BLE Address
173
183
  this.device.bleMac = this.device
@@ -230,117 +240,66 @@ export class Plug {
230
240
  }
231
241
  })
232
242
  .catch(async (e: any) => {
233
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
234
- if (this.deviceLogging.includes('debug')) {
235
- this.errorLog(
236
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection,`
237
- + ` Error Message: ${superStringify(e.message)}`,
238
- );
239
- }
240
- if (this.platform.config.credentials?.token) {
241
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
242
- this.SwitchToOpenAPI = true;
243
- await this.openAPIRefreshStatus();
244
- }
245
243
  this.apiError(e);
244
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
245
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
246
+ await this.BLEconnection(switchbot);
246
247
  });
247
248
  } else {
248
249
  await this.BLEconnection(switchbot);
249
250
  }
250
251
  }
251
252
 
252
- BLEmodel(): 'g' | 'j' {
253
- if (this.device.deviceType === 'Plug Mini (US)') {
254
- return 'g';
255
- } else {
256
- return 'j';
257
- }
258
- }
259
-
260
- async getCustomBLEAddress(switchbot: any) {
261
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
262
- (async () => {
263
- // Start to monitor advertisement packets
264
- await switchbot.startScan({
265
- model: this.BLEmodel(),
266
- });
267
- // Set an event handler
268
- switchbot.onadvertisement = (ad: any) => {
269
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
270
- };
271
- await switchbot.wait(10000);
272
- // Stop to monitor
273
- switchbot.stopScan();
274
- })();
275
- }
276
- }
277
-
278
- async BLEconnection(switchbot: any): Promise<void> {
279
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
280
- if (this.platform.config.credentials?.token) {
281
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
282
- this.SwitchToOpenAPI = true;
283
- await this.openAPIRefreshStatus();
284
- }
285
- }
286
-
287
253
  async openAPIRefreshStatus() {
288
- if (this.OpenAPI) {
289
- try {
290
- const t = Date.now();
291
- const nonce = 'requestID';
292
- const data = this.platform.config.credentials?.token + t + nonce;
293
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
294
- const sign = signTerm.toString('base64');
295
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
296
- const options = {
297
- hostname: HostDomain,
298
- port: 443,
299
- path: `${DevicePath}/${this.device.deviceId}/status`,
300
- method: 'GET',
301
- headers: {
302
- Authorization: this.platform.config.credentials?.token,
303
- sign: sign,
304
- nonce: nonce,
305
- t: t,
306
- 'Content-Type': 'application/json',
307
- },
308
- };
309
- const req = https.request(options, (res) => {
310
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
311
- let rawData = '';
312
- res.on('data', (d) => {
313
- rawData += d;
314
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
315
- });
316
- res.on('end', () => {
317
- try {
318
- this.deviceStatus = JSON.parse(rawData);
319
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
320
- this.power = this.deviceStatus.body.power;
321
- this.parseStatus();
322
- this.updateHomeKitCharacteristics();
323
- } catch (e: any) {
324
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
325
- }
326
- });
254
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
255
+ try {
256
+ const t = Date.now();
257
+ const nonce = 'requestID';
258
+ const data = this.platform.config.credentials?.token + t + nonce;
259
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
260
+ const sign = signTerm.toString('base64');
261
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
262
+ const options = {
263
+ hostname: HostDomain,
264
+ port: 443,
265
+ path: `${DevicePath}/${this.device.deviceId}/status`,
266
+ method: 'GET',
267
+ headers: {
268
+ Authorization: this.platform.config.credentials?.token,
269
+ sign: sign,
270
+ nonce: nonce,
271
+ t: t,
272
+ 'Content-Type': 'application/json',
273
+ },
274
+ };
275
+ const req = https.request(options, (res) => {
276
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
277
+ this.statusCode({ res });
278
+ let rawData = '';
279
+ res.on('data', (d) => {
280
+ rawData += d;
281
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
327
282
  });
328
- req.on('error', (e: any) => {
329
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
283
+ res.on('end', () => {
284
+ try {
285
+ this.deviceStatus = JSON.parse(rawData);
286
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
287
+ this.power = this.deviceStatus.body.power;
288
+ this.parseStatus();
289
+ this.updateHomeKitCharacteristics();
290
+ } catch (e: any) {
291
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
292
+ }
330
293
  });
331
- req.end();
332
- } catch (e: any) {
333
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
334
- if (this.deviceLogging.includes('debug')) {
335
- this.errorLog(
336
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,`
337
- + ` Error Message: ${superStringify(e.message)}`,
338
- );
339
- }
340
- this.apiError(e);
341
- }
342
- } else {
343
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
294
+ });
295
+ req.on('error', (e: any) => {
296
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
297
+ });
298
+ req.end();
299
+ } catch (e: any) {
300
+ this.apiError(e);
301
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
302
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
344
303
  }
345
304
  }
346
305
 
@@ -355,74 +314,67 @@ export class Plug {
355
314
  */
356
315
 
357
316
  async pushChanges(): Promise<void> {
358
- if (this.device.ble) {
317
+ if (this.BLE) {
359
318
  await this.BLEpushChanges();
360
- } else {
319
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
361
320
  await this.openAPIpushChanges();
321
+ } else {
322
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
323
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
362
324
  }
363
- }
364
-
365
- async BLEpushChanges(): Promise<void> {
366
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE pushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
367
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE pushChanges`);
368
- const switchbot = await this.platform.connectBLE();
369
- // Convert to BLE Address
370
- this.device.bleMac = this.device
371
- .deviceId!.match(/.{1,2}/g)!
372
- .join(':')
373
- .toLowerCase();
374
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
375
- switchbot
376
- .discover({
377
- model: this.BLEmodel(),
378
- id: this.device.bleMac,
379
- })
380
- .then((device_list: any) => {
381
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
382
- return this.turnOnOff(device_list);
383
- })
384
- .then(() => {
385
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
386
- this.On = false;
387
- })
388
- .catch(async (e: any) => {
389
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection`);
390
- if (this.deviceLogging.includes('debug')) {
391
- this.errorLog(
392
- `${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
393
- + ` Error Message: ${superStringify(e.message)}`,
394
- );
395
- }
396
- if (this.platform.debugMode) {
397
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with BLE Connection,`
398
- + ` Error: ${superStringify(e)}`);
399
- }
400
- if (this.platform.config.credentials?.token) {
401
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
402
- await this.openAPIpushChanges();
403
- }
404
- this.apiError(e);
325
+ interval(5000)
326
+ .pipe(take(1))
327
+ .subscribe(async () => {
328
+ await this.refreshStatus();
405
329
  });
406
330
  }
407
331
 
408
- async turnOnOff(device_list: any): Promise<any> {
409
- return await this.retry({
410
- max: await this.maxRetry(),
411
- fn: () => {
412
- if (this.On) {
413
- return device_list[0].turnOn({ id: this.device.bleMac });
414
- } else {
415
- return device_list[0].turnOff({ id: this.device.bleMac });
416
- }
417
- },
418
- });
332
+ async BLEpushChanges(): Promise<void> {
333
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges`);
334
+ if (this.On !== this.accessory.context.On) {
335
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEpushChanges On: ${this.On} OnCached: ${this.accessory.context.On}`);
336
+ const switchbot = await this.platform.connectBLE();
337
+ // Convert to BLE Address
338
+ this.device.bleMac = this.device
339
+ .deviceId!.match(/.{1,2}/g)!
340
+ .join(':')
341
+ .toLowerCase();
342
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
343
+ switchbot
344
+ .discover({
345
+ model: this.BLEmodel(),
346
+ id: this.device.bleMac,
347
+ })
348
+ .then((device_list: any) => {
349
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
350
+ return this.turnOnOff(device_list);
351
+ })
352
+ .then(() => {
353
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Done.`);
354
+ this.On = false;
355
+ })
356
+ .catch(async (e: any) => {
357
+ this.apiError(e);
358
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
359
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
360
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
361
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
362
+ await this.openAPIpushChanges();
363
+ }
364
+ });
365
+ } else {
366
+ this.debugLog(
367
+ `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, `
368
+ +`OnCached: ${this.accessory.context.On}`,
369
+ );
370
+ }
419
371
  }
420
372
 
421
373
  async openAPIpushChanges() {
422
- if (this.platform.config.credentials?.token && this.OpenAPI) {
374
+ try {
423
375
  if (this.On !== this.accessory.context.On) {
424
376
  // Make Push On request to the API
425
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI pushChanges`);
377
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
426
378
  const t = Date.now();
427
379
  const nonce = 'requestID';
428
380
  const data = this.platform.config.credentials?.token + t + nonce;
@@ -459,7 +411,7 @@ export class Plug {
459
411
  },
460
412
  };
461
413
  const req = https.request(options, res => {
462
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
414
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
463
415
  this.statusCode({ res });
464
416
  res.on('data', d => {
465
417
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
@@ -471,17 +423,30 @@ export class Plug {
471
423
  req.write(body);
472
424
  req.end();
473
425
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
426
+ } else {
427
+ this.debugLog(
428
+ `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, `
429
+ +`OnCached: ${this.accessory.context.On}`,
430
+ );
474
431
  }
475
- interval(5000)
476
- .pipe(take(1))
477
- .subscribe(async () => {
478
- await this.refreshStatus();
479
- });
480
- } else {
481
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
432
+ } catch (e: any) {
433
+ this.apiError(e);
434
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
435
+ + ` Connection, Error Message: ${superStringify(e.message)}`,
436
+ );
482
437
  }
483
438
  }
484
439
 
440
+ /**
441
+ * Handle requests to set the value of the "On" characteristic
442
+ */
443
+ async OnSet(value: CharacteristicValue): Promise<void> {
444
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Set On: ${value}`);
445
+
446
+ this.On = value;
447
+ this.doPlugUpdate.next();
448
+ }
449
+
485
450
  async updateHomeKitCharacteristics(): Promise<void> {
486
451
  if (this.On === undefined) {
487
452
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} On: ${this.On}`);
@@ -492,9 +457,100 @@ export class Plug {
492
457
  }
493
458
  }
494
459
 
495
- async apiError(e: any): Promise<void> {
496
- this.outletService.updateCharacteristic(this.platform.Characteristic.On, e);
497
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
460
+ BLEmodel(): 'g' | 'j' {
461
+ if (this.device.deviceType === 'Plug Mini (US)') {
462
+ return 'g';
463
+ } else {
464
+ return 'j';
465
+ }
466
+ }
467
+
468
+ async getCustomBLEAddress(switchbot: any) {
469
+ if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
470
+ (async () => {
471
+ // Start to monitor advertisement packets
472
+ await switchbot.startScan({
473
+ model: this.BLEmodel(),
474
+ });
475
+ // Set an event handler
476
+ switchbot.onadvertisement = (ad: any) => {
477
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
478
+ };
479
+ await switchbot.wait(10000);
480
+ // Stop to monitor
481
+ switchbot.stopScan();
482
+ })();
483
+ }
484
+ }
485
+
486
+ async BLEconnection(switchbot: any): Promise<void> {
487
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
488
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
489
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
490
+ this.SwitchToOpenAPI = true;
491
+ await this.openAPIRefreshStatus();
492
+ }
493
+ }
494
+
495
+ async turnOnOff(device_list: any): Promise<any> {
496
+ return await this.retry({
497
+ max: await this.maxRetry(),
498
+ fn: () => {
499
+ if (this.On) {
500
+ return device_list[0].turnOn({ id: this.device.bleMac });
501
+ } else {
502
+ return device_list[0].turnOff({ id: this.device.bleMac });
503
+ }
504
+ },
505
+ });
506
+ }
507
+
508
+ async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
509
+ return fn().catch(async (err: any) => {
510
+ if (max === 0) {
511
+ throw err;
512
+ }
513
+ this.infoLog(err);
514
+ this.infoLog('Retrying');
515
+ await this.switchbot.wait(1000);
516
+ return this.retry({ max: max - 1, fn });
517
+ });
518
+ }
519
+
520
+ async maxRetry(): Promise<number> {
521
+ let maxRetry: number;
522
+ if (this.device.bot?.maxRetry) {
523
+ maxRetry = this.device.bot?.maxRetry;
524
+ } else {
525
+ maxRetry = 5;
526
+ }
527
+ return maxRetry;
528
+ }
529
+
530
+ model(device: device & devicesConfig): string {
531
+ let model: string;
532
+ if (device.deviceType === 'Plug Mini (US)') {
533
+ model = 'W1901400';
534
+ } else if (device.deviceType === 'Plug Mini (JP)') {
535
+ model = 'W2001400';
536
+ } else {
537
+ model = 'SP11';
538
+ }
539
+ return model;
540
+ }
541
+
542
+ async scan(device: device & devicesConfig): Promise<void> {
543
+ if (device.scanDuration) {
544
+ this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
545
+ if (this.BLE) {
546
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
547
+ }
548
+ } else {
549
+ this.scanDuration = this.accessory.context.scanDuration = 1;
550
+ if (this.BLE) {
551
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
552
+ }
553
+ }
498
554
  }
499
555
 
500
556
  async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
@@ -534,51 +590,46 @@ export class Plug {
534
590
  if (this.device.offline) {
535
591
  this.On = false;
536
592
  this.outletService.getCharacteristic(this.platform.Characteristic.On).updateValue(this.On);
593
+ await this.updateHomeKitCharacteristics();
537
594
  }
538
595
  }
539
596
 
540
- /**
541
- * Handle requests to set the value of the "On" characteristic
542
- */
543
- async handleOnSet(value: CharacteristicValue): Promise<void> {
544
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} - Set On: ${value}`);
545
-
546
- this.On = value;
547
- this.doPlugUpdate.next();
597
+ async apiError(e: any): Promise<void> {
598
+ this.outletService.updateCharacteristic(this.platform.Characteristic.On, e);
548
599
  }
549
600
 
550
- model(device: device & devicesConfig): string {
551
- let model: string;
552
- if (device.deviceType === 'Plug Mini (US)') {
553
- model = 'W1901400';
554
- } else if (device.deviceType === 'Plug Mini (JP)') {
555
- model = 'W2001400';
601
+ FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
602
+ let FirmwareRevision: string;
603
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
604
+ +` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
605
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
606
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
607
+ if (accessory.context.FirmwareRevision) {
608
+ FirmwareRevision = accessory.context.FirmwareRevision;
609
+ } else if (device.firmware) {
610
+ FirmwareRevision = device.firmware;
556
611
  } else {
557
- model = 'SP11';
612
+ FirmwareRevision = this.platform.version;
558
613
  }
559
- return model;
614
+ return FirmwareRevision;
560
615
  }
561
616
 
562
- async retry({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
563
- return fn().catch(async (err: any) => {
564
- if (max === 0) {
565
- throw err;
566
- }
567
- this.infoLog(err);
568
- this.infoLog('Retrying');
569
- await this.switchbot.wait(1000);
570
- return this.retry({ max: max - 1, fn });
571
- });
617
+ async context() {
618
+ if (this.On === undefined) {
619
+ this.On = false;
620
+ } else {
621
+ this.On = this.accessory.context.On;
622
+ }
572
623
  }
573
624
 
574
- async maxRetry(): Promise<number> {
575
- let maxRetry: number;
576
- if (this.device.bot?.maxRetry) {
577
- maxRetry = this.device.bot?.maxRetry;
578
- } else {
579
- maxRetry = 5;
625
+ async refreshRate(device: device & devicesConfig): Promise<void> {
626
+ if (device.refreshRate) {
627
+ this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
628
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
629
+ } else if (this.platform.config.options!.refreshRate) {
630
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
631
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
580
632
  }
581
- return maxRetry;
582
633
  }
583
634
 
584
635
  async config(device: device & devicesConfig): Promise<void> {
@@ -586,11 +637,8 @@ export class Plug {
586
637
  if (device.plug) {
587
638
  config = device.plug;
588
639
  }
589
- if (device.ble !== undefined) {
590
- config['ble'] = device.ble;
591
- }
592
- if (device.openAPI !== undefined) {
593
- config['openAPI'] = device.openAPI;
640
+ if (device.connectionType !== undefined) {
641
+ config['connectionType'] = device.connectionType;
594
642
  }
595
643
  if (device.logging !== undefined) {
596
644
  config['logging'] = device.logging;
@@ -609,39 +657,6 @@ export class Plug {
609
657
  }
610
658
  }
611
659
 
612
- async refreshRate(device: device & devicesConfig): Promise<void> {
613
- if (device.refreshRate) {
614
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
615
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
616
- } else if (this.platform.config.options!.refreshRate) {
617
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
618
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
619
- }
620
- }
621
-
622
- async openAPI() {
623
- if (!this.device.openAPI) {
624
- this.OpenAPI = true;
625
- } else {
626
- this.OpenAPI = this.device.openAPI;
627
- }
628
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI: ${this.OpenAPI}`);
629
- }
630
-
631
- async scan(device: device & devicesConfig): Promise<void> {
632
- if (device.scanDuration) {
633
- this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
634
- if (device.ble) {
635
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
636
- }
637
- } else {
638
- this.scanDuration = this.accessory.context.scanDuration = 1;
639
- if (this.device.ble) {
640
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
641
- }
642
- }
643
- }
644
-
645
660
  async logs(device: device & devicesConfig): Promise<void> {
646
661
  if (this.platform.debugMode) {
647
662
  this.deviceLogging = this.accessory.context.logging = 'debugMode';
@@ -658,22 +673,6 @@ export class Plug {
658
673
  }
659
674
  }
660
675
 
661
- FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
662
- let FirmwareRevision: string;
663
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
664
- +` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
665
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
666
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
667
- if (accessory.context.FirmwareRevision) {
668
- FirmwareRevision = accessory.context.FirmwareRevision;
669
- } else if (device.firmware) {
670
- FirmwareRevision = device.firmware;
671
- } else {
672
- FirmwareRevision = this.platform.version;
673
- }
674
- return FirmwareRevision;
675
- }
676
-
677
676
  /**
678
677
  * Logging for Device
679
678
  */