@switchbot/homebridge-switchbot 2.6.0-beta.4 → 2.6.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 (143) hide show
  1. package/.vscode/tasks.json +13 -0
  2. package/CHANGELOG.md +4 -2
  3. package/README.md +18 -9
  4. package/dist/device/blindtilt.d.ts +1 -5
  5. package/dist/device/blindtilt.d.ts.map +1 -1
  6. package/dist/device/blindtilt.js +80 -140
  7. package/dist/device/blindtilt.js.map +1 -1
  8. package/dist/device/bot.d.ts +1 -5
  9. package/dist/device/bot.d.ts.map +1 -1
  10. package/dist/device/bot.js +79 -138
  11. package/dist/device/bot.js.map +1 -1
  12. package/dist/device/ceilinglight.d.ts +2 -6
  13. package/dist/device/ceilinglight.d.ts.map +1 -1
  14. package/dist/device/ceilinglight.js +157 -304
  15. package/dist/device/ceilinglight.js.map +1 -1
  16. package/dist/device/colorbulb.d.ts +2 -6
  17. package/dist/device/colorbulb.d.ts.map +1 -1
  18. package/dist/device/colorbulb.js +164 -311
  19. package/dist/device/colorbulb.js.map +1 -1
  20. package/dist/device/contact.d.ts +1 -5
  21. package/dist/device/contact.d.ts.map +1 -1
  22. package/dist/device/contact.js +36 -72
  23. package/dist/device/contact.js.map +1 -1
  24. package/dist/device/curtain.d.ts +1 -5
  25. package/dist/device/curtain.d.ts.map +1 -1
  26. package/dist/device/curtain.js +78 -138
  27. package/dist/device/curtain.js.map +1 -1
  28. package/dist/device/hub.d.ts +2 -6
  29. package/dist/device/hub.d.ts.map +1 -1
  30. package/dist/device/hub.js +30 -63
  31. package/dist/device/hub.js.map +1 -1
  32. package/dist/device/humidifier.d.ts +1 -5
  33. package/dist/device/humidifier.d.ts.map +1 -1
  34. package/dist/device/humidifier.js +115 -228
  35. package/dist/device/humidifier.js.map +1 -1
  36. package/dist/device/iosensor.d.ts +1 -5
  37. package/dist/device/iosensor.d.ts.map +1 -1
  38. package/dist/device/iosensor.js +38 -74
  39. package/dist/device/iosensor.js.map +1 -1
  40. package/dist/device/{striplight.d.ts → lightstrip.d.ts} +2 -10
  41. package/dist/device/lightstrip.d.ts.map +1 -0
  42. package/dist/device/{striplight.js → lightstrip.js} +138 -194
  43. package/dist/device/lightstrip.js.map +1 -0
  44. package/dist/device/lock.d.ts +1 -5
  45. package/dist/device/lock.d.ts.map +1 -1
  46. package/dist/device/lock.js +66 -126
  47. package/dist/device/lock.js.map +1 -1
  48. package/dist/device/meter.d.ts +1 -5
  49. package/dist/device/meter.d.ts.map +1 -1
  50. package/dist/device/meter.js +38 -74
  51. package/dist/device/meter.js.map +1 -1
  52. package/dist/device/meterplus.d.ts +1 -5
  53. package/dist/device/meterplus.d.ts.map +1 -1
  54. package/dist/device/meterplus.js +39 -75
  55. package/dist/device/meterplus.js.map +1 -1
  56. package/dist/device/motion.d.ts +1 -5
  57. package/dist/device/motion.d.ts.map +1 -1
  58. package/dist/device/motion.js +35 -72
  59. package/dist/device/motion.js.map +1 -1
  60. package/dist/device/plug.d.ts +1 -5
  61. package/dist/device/plug.d.ts.map +1 -1
  62. package/dist/device/plug.js +65 -126
  63. package/dist/device/plug.js.map +1 -1
  64. package/dist/device/robotvacuumcleaner.d.ts +1 -5
  65. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  66. package/dist/device/robotvacuumcleaner.js +79 -151
  67. package/dist/device/robotvacuumcleaner.js.map +1 -1
  68. package/dist/irdevice/airconditioner.d.ts +3 -7
  69. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  70. package/dist/irdevice/airconditioner.js +34 -62
  71. package/dist/irdevice/airconditioner.js.map +1 -1
  72. package/dist/irdevice/airpurifier.d.ts +3 -7
  73. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  74. package/dist/irdevice/airpurifier.js +31 -59
  75. package/dist/irdevice/airpurifier.js.map +1 -1
  76. package/dist/irdevice/camera.d.ts +1 -5
  77. package/dist/irdevice/camera.d.ts.map +1 -1
  78. package/dist/irdevice/camera.js +30 -57
  79. package/dist/irdevice/camera.js.map +1 -1
  80. package/dist/irdevice/fan.d.ts +2 -6
  81. package/dist/irdevice/fan.d.ts.map +1 -1
  82. package/dist/irdevice/fan.js +39 -66
  83. package/dist/irdevice/fan.js.map +1 -1
  84. package/dist/irdevice/light.d.ts +1 -5
  85. package/dist/irdevice/light.d.ts.map +1 -1
  86. package/dist/irdevice/light.js +32 -59
  87. package/dist/irdevice/light.js.map +1 -1
  88. package/dist/irdevice/other.d.ts +1 -5
  89. package/dist/irdevice/other.d.ts.map +1 -1
  90. package/dist/irdevice/other.js +30 -57
  91. package/dist/irdevice/other.js.map +1 -1
  92. package/dist/irdevice/tv.d.ts +3 -7
  93. package/dist/irdevice/tv.d.ts.map +1 -1
  94. package/dist/irdevice/tv.js +46 -76
  95. package/dist/irdevice/tv.js.map +1 -1
  96. package/dist/irdevice/vacuumcleaner.d.ts +2 -6
  97. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  98. package/dist/irdevice/vacuumcleaner.js +30 -58
  99. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  100. package/dist/irdevice/waterheater.d.ts +7 -23
  101. package/dist/irdevice/waterheater.d.ts.map +1 -1
  102. package/dist/irdevice/waterheater.js +41 -74
  103. package/dist/irdevice/waterheater.js.map +1 -1
  104. package/dist/platform.d.ts +14 -5
  105. package/dist/platform.d.ts.map +1 -1
  106. package/dist/platform.js +156 -149
  107. package/dist/platform.js.map +1 -1
  108. package/dist/settings.d.ts +4 -0
  109. package/dist/settings.d.ts.map +1 -1
  110. package/dist/settings.js +5 -1
  111. package/dist/settings.js.map +1 -1
  112. package/nodemon.json +1 -1
  113. package/package.json +10 -10
  114. package/src/device/blindtilt.ts +122 -181
  115. package/src/device/bot.ts +96 -149
  116. package/src/device/ceilinglight.ts +172 -315
  117. package/src/device/colorbulb.ts +178 -324
  118. package/src/device/contact.ts +48 -78
  119. package/src/device/curtain.ts +93 -148
  120. package/src/device/hub.ts +34 -63
  121. package/src/device/humidifier.ts +135 -243
  122. package/src/device/iosensor.ts +49 -79
  123. package/src/device/{striplight.ts → lightstrip.ts} +148 -200
  124. package/src/device/lock.ts +78 -134
  125. package/src/device/meter.ts +48 -78
  126. package/src/device/meterplus.ts +50 -80
  127. package/src/device/motion.ts +46 -77
  128. package/src/device/plug.ts +76 -134
  129. package/src/device/robotvacuumcleaner.ts +91 -159
  130. package/src/irdevice/airconditioner.ts +56 -81
  131. package/src/irdevice/airpurifier.ts +41 -67
  132. package/src/irdevice/camera.ts +35 -60
  133. package/src/irdevice/fan.ts +46 -71
  134. package/src/irdevice/light.ts +38 -63
  135. package/src/irdevice/other.ts +35 -60
  136. package/src/irdevice/tv.ts +52 -80
  137. package/src/irdevice/vacuumcleaner.ts +36 -62
  138. package/src/irdevice/waterheater.ts +46 -76
  139. package/src/platform.ts +144 -158
  140. package/src/settings.ts +5 -0
  141. package/.github/npm-version-script.js +0 -81
  142. package/dist/device/striplight.d.ts.map +0 -1
  143. package/dist/device/striplight.js.map +0 -1
@@ -1,14 +1,11 @@
1
- import https from 'https';
2
- import crypto from 'crypto';
3
1
  import { Context } from 'vm';
4
- import { IncomingMessage } from 'http';
5
- import superStringify from 'super-stringify';
2
+ import { request } from 'undici';
3
+ import { sleep } from '../utils';
6
4
  import { interval, Subject } from 'rxjs';
7
5
  import { SwitchBotPlatform } from '../platform';
8
6
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
7
+ import { device, devicesConfig, deviceStatus, switchbot, hs2rgb, rgb2hs, m2hs, serviceData, ad, Devices } from '../settings';
9
8
  import { Service, PlatformAccessory, CharacteristicValue, ControllerConstructor, Controller, ControllerServiceMap } from 'homebridge';
10
- import { device, devicesConfig, deviceStatus, switchbot, hs2rgb, rgb2hs, m2hs, serviceData, ad, HostDomain, DevicePath } from '../settings';
11
- import { sleep } from '../utils';
12
9
 
13
10
  /**
14
11
  * Platform Accessory
@@ -177,7 +174,7 @@ export class CeilingLight {
177
174
  this.accessory.context.adaptiveLighting = true;
178
175
  this.debugLog(
179
176
  `${this.device.deviceType}: ${this.accessory.displayName} adaptiveLighting: ${this.accessory.context.adaptiveLighting},` +
180
- ` adaptiveLightingShift: ${this.adaptiveLightingShift}`,
177
+ ` adaptiveLightingShift: ${this.adaptiveLightingShift}`,
181
178
  );
182
179
  }
183
180
 
@@ -206,7 +203,7 @@ export class CeilingLight {
206
203
  } catch (e: any) {
207
204
  this.apiError(e);
208
205
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
209
- + ` Error Message: ${superStringify(e.message)}`);
206
+ + ` Error Message: ${JSON.stringify(e.message)}`);
210
207
  }
211
208
  this.ceilingLightUpdateInProgress = false;
212
209
  });
@@ -237,7 +234,7 @@ export class CeilingLight {
237
234
  } else {
238
235
  await this.offlineOff();
239
236
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
240
- + ` ${this.device.connectionType}, parseStatus will not happen.`);
237
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
241
238
  }
242
239
  }
243
240
 
@@ -271,15 +268,15 @@ export class CeilingLight {
271
268
 
272
269
  // Color, Hue & Brightness
273
270
  if (this.color) {
274
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} color: ${superStringify(this.color)}`);
271
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} color: ${JSON.stringify(this.color)}`);
275
272
  const [red, green, blue] = this.color!.split(':');
276
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} red: ${superStringify(red)}`);
277
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} green: ${superStringify(green)}`);
278
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${superStringify(blue)}`);
273
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} red: ${JSON.stringify(red)}`);
274
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} green: ${JSON.stringify(green)}`);
275
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} blue: ${JSON.stringify(blue)}`);
279
276
 
280
277
  const [hue, saturation] = rgb2hs(Number(red), Number(green), Number(blue));
281
278
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
282
- + ` hs: ${superStringify(rgb2hs(Number(red), Number(green), Number(blue)))}`);
279
+ + ` hs: ${JSON.stringify(rgb2hs(Number(red), Number(green), Number(blue)))}`);
283
280
 
284
281
  // Hue
285
282
  this.Hue = hue;
@@ -315,7 +312,7 @@ export class CeilingLight {
315
312
  } else {
316
313
  await this.offlineOff();
317
314
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
318
- + ` ${this.device.connectionType}, refreshStatus will not happen.`);
315
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
319
316
  }
320
317
  }
321
318
 
@@ -341,8 +338,8 @@ export class CeilingLight {
341
338
  switchbot.onadvertisement = async (ad: any) => {
342
339
  this.address = ad.address;
343
340
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},`
344
- + ` BLE Address Found: ${this.address}`);
345
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
341
+ + ` BLE Address Found: ${this.address}`);
342
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
346
343
  this.serviceData = ad.serviceData;
347
344
  //this.state = ad.serviceData.state;
348
345
  //this.delay = ad.serviceData.delay;
@@ -351,7 +348,7 @@ export class CeilingLight {
351
348
  //this.wifiRssi = ad.serviceData.wifiRssi;
352
349
  //this.overload = ad.serviceData.overload;
353
350
  //this.currentPower = ad.serviceData.currentPower;
354
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
351
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
355
352
  /*this.debugLog(
356
353
  `${this.device.deviceType}: ${this.accessory.displayName} state: ${ad.serviceData.state}, ` +
357
354
  `delay: ${ad.serviceData.delay}, timer: ${ad.serviceData.timer}, syncUtcTime: ${ad.serviceData.syncUtcTime} ` +
@@ -371,13 +368,13 @@ export class CeilingLight {
371
368
  return await sleep(this.scanDuration * 1000);
372
369
  })
373
370
  .then(async () => {
374
- // Stop to monitor
371
+ // Stop to monitor
375
372
  await this.stopScanning(switchbot);
376
373
  })
377
374
  .catch(async (e: any) => {
378
375
  this.apiError(e);
379
376
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
380
- + ` Connection, Error Message: ${superStringify(e.message)}`);
377
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
381
378
  await this.BLERefreshConnection(switchbot);
382
379
  });
383
380
  } else {
@@ -388,56 +385,27 @@ export class CeilingLight {
388
385
  async openAPIRefreshStatus() {
389
386
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
390
387
  try {
391
- const t = Date.now();
392
- const nonce = 'requestID';
393
- const data = this.platform.config.credentials?.token + t + nonce;
394
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
395
- const sign = signTerm.toString('base64');
396
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
397
- const options = {
398
- hostname: HostDomain,
399
- port: 443,
400
- path: `${DevicePath}/${this.device.deviceId}/status`,
401
- method: 'GET',
402
- headers: {
403
- Authorization: this.platform.config.credentials?.token,
404
- sign: sign,
405
- nonce: nonce,
406
- t: t,
407
- 'Content-Type': 'application/json',
408
- },
409
- };
410
- const req = https.request(options, (res) => {
411
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
412
- this.statusCode({ res });
413
- let rawData = '';
414
- res.on('data', (d) => {
415
- rawData += d;
416
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
417
- });
418
- res.on('end', () => {
419
- try {
420
- this.deviceStatus = JSON.parse(rawData);
421
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
422
- this.power = this.deviceStatus.body.power;
423
- this.color = this.deviceStatus.body.color;
424
- this.brightness = this.deviceStatus.body.brightness;
425
- this.colorTemperature = this.deviceStatus.body.colorTemperature;
426
- this.openAPIparseStatus();
427
- this.updateHomeKitCharacteristics();
428
- } catch (e: any) {
429
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
430
- }
431
- });
388
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, {
389
+ headers: this.platform.generateHeaders(),
432
390
  });
433
- req.on('error', (e: any) => {
434
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
435
- });
436
- req.end();
391
+ const deviceStatus = await body.json();
392
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
393
+ this.statusCode(statusCode);
394
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
395
+ this.debugLog(
396
+ `${this.device.deviceType}: ${this.accessory.displayName
397
+ } refreshStatus: ${JSON.stringify(deviceStatus)}`,
398
+ );
399
+ this.power = deviceStatus.body.power;
400
+ this.color = deviceStatus.body.color;
401
+ this.brightness = deviceStatus.body.brightness;
402
+ this.colorTemperature = deviceStatus.body.colorTemperature;
403
+ this.openAPIparseStatus();
404
+ this.updateHomeKitCharacteristics();
437
405
  } catch (e: any) {
438
406
  this.apiError(e);
439
407
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
440
- + ` Connection, Error Message: ${superStringify(e.message)}`);
408
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
441
409
  }
442
410
  }
443
411
 
@@ -462,7 +430,7 @@ export class CeilingLight {
462
430
  } else {
463
431
  await this.offlineOff();
464
432
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
465
- + ` ${this.device.connectionType}, pushChanges will not happen.`);
433
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
466
434
  }
467
435
  // Refresh the status from the API
468
436
  interval(15000)
@@ -509,270 +477,158 @@ export class CeilingLight {
509
477
  .catch(async (e: any) => {
510
478
  this.apiError(e);
511
479
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
512
- + ` Connection, Error Message: ${superStringify(e.message)}`);
480
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
513
481
  await this.BLEPushConnection();
514
482
  });
515
483
  } else {
516
484
  this.debugLog(
517
485
  `${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges.` + `On: ${this.On}, `
518
- +`OnCached: ${this.accessory.context.On}`,
486
+ + `OnCached: ${this.accessory.context.On}`,
519
487
  );
520
488
  }
521
489
  }
522
490
 
523
491
  async openAPIpushChanges(): Promise<void> {
524
- try {
525
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges`);
526
- if (this.On !== this.accessory.context.On) {
527
- // Make Push On request to the API
528
- const t = Date.now();
529
- const nonce = 'requestID';
530
- const data = this.platform.config.credentials?.token + t + nonce;
531
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
532
- .update(Buffer.from(data, 'utf-8'))
533
- .digest();
534
- const sign = signTerm.toString('base64');
535
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
536
-
537
- let command = '';
538
- if (this.On) {
539
- command = 'turnOn';
540
- } else {
541
- command = 'turnOff';
542
- }
543
- const body = superStringify({
544
- 'command': `${command}`,
545
- 'parameter': 'default',
546
- 'commandType': 'command',
547
- });
548
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
549
- const options = {
550
- hostname: HostDomain,
551
- port: 443,
552
- path: `${DevicePath}/${this.device.deviceId}/commands`,
492
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI pushChanges`);
493
+ if (this.On !== this.accessory.context.On) {
494
+ let command = '';
495
+ if (this.On) {
496
+ command = 'turnOn';
497
+ } else {
498
+ command = 'turnOff';
499
+ }
500
+ const body = JSON.stringify({
501
+ 'command': `${command}`,
502
+ 'parameter': 'default',
503
+ 'commandType': 'command',
504
+ });
505
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
506
+ try {
507
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
553
508
  method: 'POST',
554
- headers: {
555
- 'Authorization': this.platform.config.credentials?.token,
556
- 'sign': sign,
557
- 'nonce': nonce,
558
- 't': t,
559
- 'Content-Type': 'application/json',
560
- 'Content-Length': body.length,
561
- },
562
- };
563
- const req = https.request(options, res => {
564
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
565
- this.statusCode({ res });
566
- res.on('data', d => {
567
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
568
- });
509
+ headers: this.platform.generateHeaders(),
569
510
  });
570
- req.on('error', (e: any) => {
571
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
572
- });
573
- req.write(body);
574
- req.end();
575
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushChanges: ${superStringify(req)}`);
576
- } else {
577
- this.debugLog(
578
- `${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, `
579
- +`OnCached: ${this.accessory.context.On}`,
511
+ const deviceStatus = await body.json();
512
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
513
+ this.statusCode(statusCode);
514
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
515
+ } catch (e: any) {
516
+ this.apiError(e);
517
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
518
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
580
519
  );
581
520
  }
582
- // Push Brightness Update
583
- if (this.On) {
584
- await this.pushBrightnessChanges();
585
- }
586
- // Push ColorTemperature Update
587
- if (this.On) {
588
- await this.pushColorTemperatureChanges();
589
- }
590
- // Push Hue & Saturation Update
591
- if (this.On) {
592
- await this.pushHueSaturationChanges();
593
- }
594
- } catch (e: any) {
595
- this.apiError(e);
596
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
597
- + ` Connection, Error Message: ${superStringify(e.message)}`,
598
- );
521
+ } else {
522
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No openAPIpushChanges.` + `On: ${this.On}, `
523
+ + `OnCached: ${this.accessory.context.On}`);
524
+ }
525
+ // Push Hue & Saturation Update
526
+ if (this.On) {
527
+ await this.pushHueSaturationChanges();
528
+ }
529
+ // Push ColorTemperature Update
530
+ if (this.On) {
531
+ await this.pushColorTemperatureChanges();
532
+ }
533
+ // Push Brightness Update
534
+ if (this.On) {
535
+ await this.pushBrightnessChanges();
599
536
  }
600
537
  }
601
538
 
602
539
  async pushHueSaturationChanges(): Promise<void> {
603
- try {
604
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges`);
605
- if (this.Hue !== this.accessory.context.Hue || this.Saturation !== this.accessory.context.Saturation) {
606
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${superStringify(this.Hue)}`);
607
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${superStringify(this.Saturation)}`);
608
-
609
- const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation));
610
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} rgb: ${superStringify([red, green, blue])}`);
611
- // Make Push Hue/Saturation request to the API
612
- const t = Date.now();
613
- const nonce = 'requestID';
614
- const data = this.platform.config.credentials?.token + t + nonce;
615
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
616
- .update(Buffer.from(data, 'utf-8'))
617
- .digest();
618
- const sign = signTerm.toString('base64');
619
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
620
- const body = superStringify({
621
- 'command': 'setColor',
622
- 'parameter': `${red}:${green}:${blue}`,
623
- 'commandType': 'command',
624
- });
625
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
626
- const options = {
627
- hostname: HostDomain,
628
- port: 443,
629
- path: `${DevicePath}/${this.device.deviceId}/commands`,
540
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges`);
541
+ if (this.Hue !== this.accessory.context.Hue || this.Saturation !== this.accessory.context.Saturation) {
542
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Hue: ${JSON.stringify(this.Hue)}`);
543
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Saturation: ${JSON.stringify(this.Saturation)}`);
544
+ const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation));
545
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`);
546
+ const body = JSON.stringify({
547
+ 'command': 'setColor',
548
+ 'parameter': `${red}:${green}:${blue}`,
549
+ 'commandType': 'command',
550
+ });
551
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
552
+ try {
553
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
630
554
  method: 'POST',
631
- headers: {
632
- 'Authorization': this.platform.config.credentials?.token,
633
- 'sign': sign,
634
- 'nonce': nonce,
635
- 't': t,
636
- 'Content-Type': 'application/json',
637
- 'Content-Length': body.length,
638
- },
639
- };
640
- const req = https.request(options, res => {
641
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges statusCode: ${res.statusCode}`);
642
- res.on('data', d => {
643
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
644
- });
645
- });
646
- req.on('error', (e: any) => {
647
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
555
+ headers: this.platform.generateHeaders(),
648
556
  });
649
- req.write(body);
650
- req.end();
651
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushHueSaturationChanges: ${superStringify(req)}`);
652
- } else {
653
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, `
654
- + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`);
557
+ const deviceStatus = await body.json();
558
+ this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`);
559
+ this.statusCode(statusCode);
560
+ this.debugLog(`Headers: ${JSON.stringify(headers)}`);
561
+ } catch (e: any) {
562
+ this.apiError(e);
563
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}`
564
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
565
+ );
655
566
  }
656
- } catch (e: any) {
657
- this.apiError(e);
658
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushHueSaturationChanges with ${this.device.connectionType}`
659
- + ` Connection, Error Message: ${superStringify(e.message)}`);
567
+ } else {
568
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushHueSaturationChanges. Hue: ${this.Hue}, `
569
+ + `HueCached: ${this.accessory.context.Hue}, Saturation: ${this.Saturation}, SaturationCached: ${this.accessory.context.Saturation}`);
660
570
  }
661
571
  }
662
572
 
663
573
  async pushColorTemperatureChanges(): Promise<void> {
664
- try {
665
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushColorTemperatureChanges`);
666
- if (this.ColorTemperature !== this.accessory.context.ColorTemperature) {
667
- const kelvin = Math.round(1000000 / Number(this.ColorTemperature));
668
- this.cacheKelvin = kelvin;
669
-
670
- // Make Push On request to the API
671
- const t = Date.now();
672
- const nonce = 'requestID';
673
- const data = this.platform.config.credentials?.token + t + nonce;
674
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
675
- .update(Buffer.from(data, 'utf-8'))
676
- .digest();
677
- const sign = signTerm.toString('base64');
678
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
679
- const body = superStringify({
680
- 'command': 'setColorTemperature',
681
- 'parameter': `${kelvin}`,
682
- 'commandType': 'command',
683
- });
684
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
685
- const options = {
686
- hostname: HostDomain,
687
- port: 443,
688
- path: `${DevicePath}/${this.device.deviceId}/commands`,
574
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushColorTemperatureChanges`);
575
+ if (this.ColorTemperature !== this.accessory.context.ColorTemperature) {
576
+ const kelvin = Math.round(1000000 / Number(this.ColorTemperature));
577
+ this.cacheKelvin = kelvin;
578
+ const body = JSON.stringify({
579
+ 'command': 'setColorTemperature',
580
+ 'parameter': `${kelvin}`,
581
+ 'commandType': 'command',
582
+ });
583
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
584
+ try {
585
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
689
586
  method: 'POST',
690
- headers: {
691
- 'Authorization': this.platform.config.credentials?.token,
692
- 'sign': sign,
693
- 'nonce': nonce,
694
- 't': t,
695
- 'Content-Type': 'application/json',
696
- 'Content-Length': body.length,
697
- },
698
- };
699
- const req = https.request(options, res => {
700
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
701
- res.on('data', d => {
702
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
703
- });
704
- });
705
- req.on('error', (e: any) => {
706
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
587
+ headers: this.platform.generateHeaders(),
707
588
  });
708
- req.write(body);
709
- req.end();
710
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushColorTemperatureChanges: ${superStringify(req)}`);
711
- this.accessory.context.ColorTemperature = this.ColorTemperature;
712
- } else {
713
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.` +
714
- `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`);
589
+ const deviceStatus = await body.json();
590
+ this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`);
591
+ this.statusCode(statusCode);
592
+ this.debugLog(`Headers: ${JSON.stringify(headers)}`);
593
+ } catch (e: any) {
594
+ this.apiError(e);
595
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with ${this.device.connectionType}`
596
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
597
+ );
715
598
  }
716
- } catch (e: any) {
717
- this.apiError(e);
718
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushColorTemperatureChanges with ${this.device.connectionType}`
719
- + ` Connection, Error Message: ${superStringify(e.message)}`);
599
+ } else {
600
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushColorTemperatureChanges.` +
601
+ `ColorTemperature: ${this.ColorTemperature}, ColorTemperatureCached: ${this.accessory.context.ColorTemperature}`);
720
602
  }
721
603
  }
722
604
 
723
605
  async pushBrightnessChanges(): Promise<void> {
724
- try {
725
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges`);
726
- if (this.Brightness !== this.accessory.context.Brightness) {
727
- // Make Push On request to the API
728
- const t = Date.now();
729
- const nonce = 'requestID';
730
- const data = this.platform.config.credentials?.token + t + nonce;
731
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
732
- .update(Buffer.from(data, 'utf-8'))
733
- .digest();
734
- const sign = signTerm.toString('base64');
735
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
736
- const body = superStringify({
737
- 'command': 'setBrightness',
738
- 'parameter': `${this.Brightness}`,
739
- 'commandType': 'command',
740
- });
741
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
742
- const options = {
743
- hostname: HostDomain,
744
- port: 443,
745
- path: `${DevicePath}/${this.device.deviceId}/commands`,
606
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges`);
607
+ if (this.Brightness !== this.accessory.context.Brightness) {
608
+ const body = JSON.stringify({
609
+ 'command': 'setBrightness',
610
+ 'parameter': `${this.Brightness}`,
611
+ 'commandType': 'command',
612
+ });
613
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
614
+ try {
615
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
746
616
  method: 'POST',
747
- headers: {
748
- 'Authorization': this.platform.config.credentials?.token,
749
- 'sign': sign,
750
- 'nonce': nonce,
751
- 't': t,
752
- 'Content-Type': 'application/json',
753
- 'Content-Length': body.length,
754
- },
755
- };
756
- const req = https.request(options, res => {
757
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges statusCode: ${res.statusCode}`);
758
- res.on('data', d => {
759
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
760
- });
761
- });
762
- req.on('error', (e: any) => {
763
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
617
+ headers: this.platform.generateHeaders(),
764
618
  });
765
- req.write(body);
766
- req.end();
767
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} pushBrightnessChanges: ${superStringify(req)}`);
768
- } else {
769
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` + `Brightness: ${this.Brightness}, `
770
- +`BrightnessCached: ${this.accessory.context.Brightness}`);
619
+ const deviceStatus = await body.json();
620
+ this.debugLog(`Devices: ${JSON.stringify(deviceStatus.body)}`);
621
+ this.statusCode(statusCode);
622
+ this.debugLog(`Headers: ${JSON.stringify(headers)}`);
623
+ } catch (e: any) {
624
+ this.apiError(e);
625
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}`
626
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
627
+ );
771
628
  }
772
- } catch (e: any) {
773
- this.apiError(e);
774
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushBrightnessChanges with ${this.device.connectionType}`
775
- + ` Connection, Error Message: ${superStringify(e.message)}`);
629
+ } else {
630
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No pushBrightnessChanges.` + `Brightness: ${this.Brightness}, `
631
+ + `BrightnessCached: ${this.accessory.context.Brightness}`);
776
632
  }
777
633
  }
778
634
 
@@ -941,7 +797,7 @@ export class CeilingLight {
941
797
  });
942
798
  // Set an event handler
943
799
  switchbot.onadvertisement = (ad: any) => {
944
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
800
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
945
801
  };
946
802
  await sleep(10000);
947
803
  // Stop to monitor
@@ -1008,40 +864,41 @@ export class CeilingLight {
1008
864
  }
1009
865
  }
1010
866
 
1011
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
1012
- switch (res.statusCode) {
867
+ async statusCode(statusCode: number): Promise<void> {
868
+ switch (statusCode) {
1013
869
  case 151:
1014
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
870
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
1015
871
  break;
1016
872
  case 152:
1017
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
873
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
1018
874
  break;
1019
875
  case 160:
1020
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
876
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
1021
877
  break;
1022
878
  case 161:
1023
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
1024
- await this.offlineOff();
879
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
880
+ this.offlineOff();
1025
881
  break;
1026
882
  case 171:
1027
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
1028
- await this.offlineOff();
883
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
884
+ + `Hub: ${this.device.hubDeviceId}`);
885
+ this.offlineOff();
1029
886
  break;
1030
887
  case 190:
1031
888
  this.errorLog(
1032
889
  `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
1033
- ` Or command: ${superStringify(res)} format is invalid`,
890
+ ` Or command format is invalid, statusCode: ${statusCode}`,
1034
891
  );
1035
892
  break;
1036
893
  case 100:
1037
- if (this.platform.debugMode) {
1038
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
1039
- }
894
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
895
+ break;
896
+ case 200:
897
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
1040
898
  break;
1041
899
  default:
1042
- if (this.platform.debugMode) {
1043
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
1044
- }
900
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: `
901
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
1045
902
  }
1046
903
  }
1047
904
 
@@ -1063,7 +920,7 @@ export class CeilingLight {
1063
920
  FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
1064
921
  let FirmwareRevision: string;
1065
922
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
1066
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
923
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
1067
924
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
1068
925
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
1069
926
  if (accessory.context.FirmwareRevision) {
@@ -1143,7 +1000,7 @@ export class CeilingLight {
1143
1000
  config['maxRetry'] = device.maxRetry;
1144
1001
  }
1145
1002
  if (Object.entries(config).length !== 0) {
1146
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
1003
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
1147
1004
  }
1148
1005
  }
1149
1006