@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,16 +1,13 @@
1
- import https from 'https';
2
- import crypto from 'crypto';
3
1
  import { Context } from 'vm';
2
+ import { request } from 'undici';
3
+ import { sleep } from '../utils';
4
4
  import { MqttClient } from 'mqtt';
5
- import { IncomingMessage } from 'http';
6
5
  import { interval, Subject } from 'rxjs';
7
6
  import { connectAsync } from 'async-mqtt';
8
- import superStringify from 'super-stringify';
9
7
  import { SwitchBotPlatform } from '../platform';
10
8
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
11
9
  import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
12
- import { device, devicesConfig, serviceData, switchbot, deviceStatus, ad, HostDomain, DevicePath } from '../settings';
13
- import { sleep } from '../utils';
10
+ import { device, devicesConfig, serviceData, switchbot, deviceStatus, ad, Devices } from '../settings';
14
11
 
15
12
  export class Curtain {
16
13
  // Services
@@ -217,7 +214,7 @@ export class Curtain {
217
214
  } catch (e: any) {
218
215
  this.apiError(e);
219
216
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed pushChanges with ${this.device.connectionType} Connection,`
220
- + ` Error Message: ${superStringify(e.message)}`);
217
+ + ` Error Message: ${JSON.stringify(e.message)}`);
221
218
  }
222
219
  this.curtainUpdateInProgress = false;
223
220
  });
@@ -236,7 +233,7 @@ export class Curtain {
236
233
  } else {
237
234
  await this.offlineOff();
238
235
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
239
- + ` ${this.device.connectionType}, parseStatus will not happen.`);
236
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
240
237
  }
241
238
  }
242
239
 
@@ -273,7 +270,7 @@ export class Curtain {
273
270
  }
274
271
  this.debugLog(
275
272
  `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
276
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
273
+ ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
277
274
  );
278
275
 
279
276
  if (!this.device.curtain?.hide_lightsensor) {
@@ -291,7 +288,7 @@ export class Curtain {
291
288
  this.CurrentAmbientLightLevel = (this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels;
292
289
  this.debugLog(
293
290
  `${this.device.deviceType}: ${this.accessory.displayName} LightLevel: ${this.lightLevel},` +
294
- ` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`,
291
+ ` Calculation: ${(this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels}`,
295
292
  );
296
293
  break;
297
294
  case 3:
@@ -340,7 +337,7 @@ export class Curtain {
340
337
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
341
338
  }
342
339
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel},`
343
- +` StatusLowBattery: ${this.StatusLowBattery}`);
340
+ + ` StatusLowBattery: ${this.StatusLowBattery}`);
344
341
  }
345
342
 
346
343
  async openAPIparseStatus(): Promise<void> {
@@ -379,7 +376,7 @@ export class Curtain {
379
376
  }
380
377
  this.debugLog(
381
378
  `${this.device.deviceType}: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},` +
382
- ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
379
+ ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`,
383
380
  );
384
381
 
385
382
  if (!this.device.curtain?.hide_lightsensor) {
@@ -408,7 +405,7 @@ export class Curtain {
408
405
  } else {
409
406
  await this.offlineOff();
410
407
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
411
- + ` ${this.device.connectionType}, refreshStatus will not happen.`);
408
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
412
409
  }
413
410
  }
414
411
 
@@ -434,18 +431,18 @@ export class Curtain {
434
431
  switchbot.onadvertisement = async (ad: any) => {
435
432
  this.address = ad.address;
436
433
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Config BLE Address: ${this.device.bleMac},`
437
- + ` BLE Address Found: ${this.address}`);
434
+ + ` BLE Address Found: ${this.address}`);
438
435
  this.serviceData = ad.serviceData;
439
436
  this.calibration = ad.serviceData.calibration;
440
437
  this.battery = ad.serviceData.battery;
441
438
  this.inMotion = ad.serviceData.inMotion;
442
439
  this.position = ad.serviceData.position;
443
440
  this.lightLevel = ad.serviceData.lightLevel;
444
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${superStringify(ad.serviceData)}`);
441
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} serviceData: ${JSON.stringify(ad.serviceData)}`);
445
442
  this.debugLog(
446
443
  `${this.device.deviceType}: ${this.accessory.displayName} calibration: ${ad.serviceData.calibration}, ` +
447
- `position: ${ad.serviceData.position}, lightLevel: ${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}, ` +
448
- `inMotion: ${ad.serviceData.inMotion}`);
444
+ `position: ${ad.serviceData.position}, lightLevel: ${ad.serviceData.lightLevel}, battery: ${ad.serviceData.battery}, ` +
445
+ `inMotion: ${ad.serviceData.inMotion}`);
449
446
 
450
447
  if (this.serviceData) {
451
448
  this.connected = true;
@@ -466,7 +463,7 @@ export class Curtain {
466
463
  .catch(async (e: any) => {
467
464
  this.apiError(e);
468
465
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
469
- + ` Connection, Error Message: ${superStringify(e.message)}`);
466
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
470
467
  await this.BLERefreshConnection(switchbot);
471
468
  });
472
469
  } else {
@@ -477,54 +474,26 @@ export class Curtain {
477
474
  async openAPIRefreshStatus(): Promise<void> {
478
475
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
479
476
  try {
480
- const t = Date.now();
481
- const nonce = 'requestID';
482
- const data = this.platform.config.credentials?.token + t + nonce;
483
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
484
- const sign = signTerm.toString('base64');
485
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
486
- const options = {
487
- hostname: HostDomain,
488
- port: 443,
489
- path: `${DevicePath}/${this.device.deviceId}/status`,
490
- method: 'GET',
491
- headers: {
492
- Authorization: this.platform.config.credentials?.token,
493
- sign: sign,
494
- nonce: nonce,
495
- t: t,
496
- 'Content-Type': 'application/json',
497
- },
498
- };
499
- const req = https.request(options, (res) => {
500
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
501
- let rawData = '';
502
- res.on('data', (d) => {
503
- rawData += d;
504
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
505
- });
506
- res.on('end', () => {
507
- try {
508
- this.deviceStatus = JSON.parse(rawData);
509
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
510
- this.slidePosition = this.deviceStatus.body.slidePosition;
511
- this.moving = this.deviceStatus.body.moving;
512
- this.brightness = this.deviceStatus.body.brightness;
513
- this.openAPIparseStatus();
514
- this.updateHomeKitCharacteristics();
515
- } catch (e: any) {
516
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
517
- }
518
- });
477
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, {
478
+ headers: this.platform.generateHeaders(),
519
479
  });
520
- req.on('error', (e: any) => {
521
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
522
- });
523
- req.end();
480
+ const deviceStatus = await body.json();
481
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
482
+ this.statusCode(statusCode);
483
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
484
+ this.debugLog(
485
+ `${this.device.deviceType}: ${this.accessory.displayName
486
+ } refreshStatus: ${JSON.stringify(deviceStatus)}`,
487
+ );
488
+ this.slidePosition = deviceStatus.body.slidePosition;
489
+ this.moving = deviceStatus.body.moving;
490
+ this.brightness = deviceStatus.body.brightness;
491
+ this.openAPIparseStatus();
492
+ this.updateHomeKitCharacteristics();
524
493
  } catch (e: any) {
525
494
  this.apiError(e);
526
495
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
527
- + ` Connection, Error Message: ${superStringify(e.message)}`);
496
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
528
497
  }
529
498
  }
530
499
 
@@ -538,7 +507,7 @@ export class Curtain {
538
507
  } else {
539
508
  await this.offlineOff();
540
509
  this.debugWarnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
541
- + ` ${this.device.connectionType}, pushChanges will not happen.`);
510
+ + ` ${this.device.connectionType}, pushChanges will not happen.`);
542
511
  }
543
512
  // Refresh the status from the API
544
513
  interval(15000)
@@ -581,7 +550,7 @@ export class Curtain {
581
550
  .catch(async (e: any) => {
582
551
  this.apiError(e);
583
552
  this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLEpushChanges with ${this.device.connectionType}`
584
- + ` Connection, Error Message: ${superStringify(e.message)}`);
553
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
585
554
  await this.BLEPushConnection();
586
555
  throw new Error('Connection error');
587
556
  });
@@ -593,7 +562,7 @@ export class Curtain {
593
562
  }
594
563
  } else {
595
564
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No BLEpushChanges, CurrentPosition & TargetPosition Are the Same.` +
596
- ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
565
+ ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
597
566
  );
598
567
  }
599
568
  }
@@ -619,77 +588,48 @@ export class Curtain {
619
588
  }
620
589
 
621
590
  async openAPIpushChanges(): Promise<void> {
622
- try {
623
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI pushChanges`);
624
- if ((this.TargetPosition !== this.CurrentPosition) || this.device.disableCaching) {
625
- // Make Push On request to the API
626
- const t = Date.now();
627
- const nonce = 'requestID';
628
- const data = this.platform.config.credentials?.token + t + nonce;
629
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
630
- .update(Buffer.from(data, 'utf-8'))
631
- .digest();
632
- const sign = signTerm.toString('base64');
633
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
634
- this.debugLog(`Pushing ${this.TargetPosition}`);
635
- const adjustedTargetPosition = 100 - Number(this.TargetPosition);
636
- if (Number(this.TargetPosition) > 50) {
637
- this.setPositionMode = this.device.curtain?.setOpenMode;
638
- } else {
639
- this.setPositionMode = this.device.curtain?.setCloseMode;
640
- }
641
- if (this.setPositionMode === '1') {
642
- this.Mode = 'Silent Mode';
643
- } else if (this.setPositionMode === '0') {
644
- this.Mode = 'Performance Mode';
645
- } else {
646
- this.Mode = 'Default Mode';
647
- }
648
- this.debugLog(`${this.accessory.displayName} Mode: ${this.Mode}`);
649
- const adjustedMode = this.setPositionMode || 'ff';
650
- const body = superStringify({
651
- 'command': 'setPosition',
652
- 'parameter': `0,${adjustedMode},${adjustedTargetPosition}`,
653
- 'commandType': 'command',
654
- });
655
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
656
- const options = {
657
- hostname: HostDomain,
658
- port: 443,
659
- path: `${DevicePath}/${this.device.deviceId}/commands`,
591
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI pushChanges`);
592
+ if ((this.TargetPosition !== this.CurrentPosition) || this.device.disableCaching) {
593
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Pushing ${this.TargetPosition}`);
594
+ const adjustedTargetPosition = 100 - Number(this.TargetPosition);
595
+ if (Number(this.TargetPosition) > 50) {
596
+ this.setPositionMode = this.device.curtain?.setOpenMode;
597
+ } else {
598
+ this.setPositionMode = this.device.curtain?.setCloseMode;
599
+ }
600
+ if (this.setPositionMode === '1') {
601
+ this.Mode = 'Silent Mode';
602
+ } else if (this.setPositionMode === '0') {
603
+ this.Mode = 'Performance Mode';
604
+ } else {
605
+ this.Mode = 'Default Mode';
606
+ }
607
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Mode: ${this.Mode}`);
608
+ const adjustedMode = this.setPositionMode || 'ff';
609
+ const body = JSON.stringify({
610
+ 'command': 'setPosition',
611
+ 'parameter': `0,${adjustedMode},${adjustedTargetPosition}`,
612
+ 'commandType': 'command',
613
+ });
614
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Sending request to SwitchBot API, body: ${body},`);
615
+ try {
616
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/commands`, {
660
617
  method: 'POST',
661
- headers: {
662
- 'Authorization': this.platform.config.credentials?.token,
663
- 'sign': sign,
664
- 'nonce': nonce,
665
- 't': t,
666
- 'Content-Type': 'application/json',
667
- 'Content-Length': body.length,
668
- },
669
- };
670
- const req = https.request(options, res => {
671
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges statusCode: ${res.statusCode}`);
672
- this.statusCode({ res });
673
- res.on('data', d => {
674
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
675
- });
618
+ headers: this.platform.generateHeaders(),
676
619
  });
677
- req.on('error', (e: any) => {
678
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
679
- });
680
- req.write(body);
681
- req.end();
682
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIpushChanges: ${superStringify(req)}`);
683
- } else {
684
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.`
685
- +` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`,
620
+ const deviceStatus = await body.json();
621
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
622
+ this.statusCode(statusCode);
623
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
624
+ } catch (e: any) {
625
+ this.apiError(e);
626
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
627
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`,
686
628
  );
687
629
  }
688
- } catch (e: any) {
689
- this.apiError(e);
690
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIpushChanges with ${this.device.connectionType}`
691
- + ` Connection, Error Message: ${superStringify(e.message)}`,
692
- );
630
+ } else {
631
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.`
632
+ + ` CurrentPosition: ${this.CurrentPosition}, TargetPosition ${this.TargetPosition}`);
693
633
  }
694
634
  }
695
635
 
@@ -782,7 +722,7 @@ export class Curtain {
782
722
  this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
783
723
  this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
784
724
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
785
- + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
725
+ + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
786
726
  }
787
727
  }
788
728
  if (this.BLE) {
@@ -820,7 +760,7 @@ export class Curtain {
820
760
  ?.join(':');
821
761
  const options = this.device.mqttPubOptions || {};
822
762
  this.mqttClient?.publish(`homebridge-switchbot/curtain/${mac}/${topic}`, `${message}`, options);
823
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${topic}/${message} options:${superStringify(options)}`);
763
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MQTT message: ${topic}/${message} options:${JSON.stringify(options)}`);
824
764
  }
825
765
 
826
766
  /*
@@ -860,7 +800,7 @@ export class Curtain {
860
800
  });
861
801
  // Set an event handler
862
802
  switchbot.onadvertisement = (ad: any) => {
863
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
803
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${JSON.stringify(ad, null, ' ')}`);
864
804
  };
865
805
  await sleep(10000);
866
806
  // Stop to monitor
@@ -950,7 +890,7 @@ export class Curtain {
950
890
  this.scanDuration = this.updateRate;
951
891
  if (this.BLE) {
952
892
  this.warnLog(`${this.device.deviceType}: `
953
- + `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`);
893
+ + `${this.accessory.displayName} scanDuration is less than updateRate, overriding scanDuration with updateRate`);
954
894
  }
955
895
  } else {
956
896
  this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
@@ -970,36 +910,41 @@ export class Curtain {
970
910
  }
971
911
  }
972
912
 
973
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
974
- switch (res.statusCode) {
913
+ async statusCode(statusCode: number): Promise<void> {
914
+ switch (statusCode) {
975
915
  case 151:
976
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
916
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
977
917
  break;
978
918
  case 152:
979
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
919
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
980
920
  break;
981
921
  case 160:
982
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
922
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
983
923
  break;
984
924
  case 161:
985
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
925
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
986
926
  this.offlineOff();
987
927
  break;
988
928
  case 171:
989
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
929
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
930
+ + `Hub: ${this.device.hubDeviceId}`);
990
931
  this.offlineOff();
991
932
  break;
992
933
  case 190:
993
934
  this.errorLog(
994
935
  `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
995
- ` Or command: ${superStringify(res)} format is invalid`,
936
+ ` Or command format is invalid, statusCode: ${statusCode}`,
996
937
  );
997
938
  break;
998
939
  case 100:
999
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
940
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
941
+ break;
942
+ case 200:
943
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
1000
944
  break;
1001
945
  default:
1002
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
946
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: `
947
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
1003
948
  }
1004
949
  }
1005
950
 
@@ -1027,7 +972,7 @@ export class Curtain {
1027
972
  FirmwareRevision(accessory: PlatformAccessory<Context>, device: device & devicesConfig): CharacteristicValue {
1028
973
  let FirmwareRevision: string;
1029
974
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
1030
- + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
975
+ + ` accessory.context.FirmwareRevision: ${accessory.context.FirmwareRevision}`);
1031
976
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} device.firmware: ${device.firmware}`);
1032
977
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} this.platform.version: ${this.platform.version}`);
1033
978
  if (accessory.context.FirmwareRevision) {
@@ -1106,7 +1051,7 @@ export class Curtain {
1106
1051
  config['maxRetry'] = device.maxRetry;
1107
1052
  }
1108
1053
  if (Object.entries(config).length !== 0) {
1109
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
1054
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
1110
1055
  }
1111
1056
  }
1112
1057
 
package/src/device/hub.ts CHANGED
@@ -1,13 +1,10 @@
1
- import https from 'https';
2
- import crypto from 'crypto';
3
1
  import { Context } from 'vm';
4
- import { IncomingMessage } from 'http';
5
2
  import { interval } from 'rxjs';
6
- import superStringify from 'super-stringify';
3
+ import { request } from 'undici';
4
+ import { sleep } from '../utils';
7
5
  import { SwitchBotPlatform } from '../platform';
6
+ import { device, devicesConfig, Devices } from '../settings';
8
7
  import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
9
- import { device, devicesConfig, HostDomain, DevicePath } from '../settings';
10
- import { sleep } from '../utils';
11
8
 
12
9
  export class Hub {
13
10
  // Services
@@ -163,56 +160,25 @@ export class Hub {
163
160
  async openAPIRefreshStatus(): Promise<void> {
164
161
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
165
162
  try {
166
- const t = Date.now();
167
- const nonce = 'requestID';
168
- const data = this.platform.config.credentials?.token + t + nonce;
169
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
170
- const sign = signTerm.toString('base64');
171
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
172
- const options = {
173
- hostname: HostDomain,
174
- port: 443,
175
- path: `${DevicePath}/${this.device.deviceId}/status`,
176
- method: 'GET',
177
- headers: {
178
- Authorization: this.platform.config.credentials?.token,
179
- sign: sign,
180
- nonce: nonce,
181
- t: t,
182
- 'Content-Type': 'application/json',
183
- },
184
- };
185
- const req = https.request(options, (res) => {
186
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
187
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}: ${res}`);
188
- let rawData = '';
189
- res.on('data', (d) => {
190
- rawData += d;
191
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
192
- });
193
- res.on('end', () => {
194
- try {
195
- this.deviceStatus = JSON.parse(rawData);
196
- this.CurrentTemperature = this.deviceStatus.body.temperature;
197
- this.CurrentRelativeHumidity = this.deviceStatus.body.humidity;
198
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
199
- this.openAPIparseStatus();
200
- this.updateHomeKitCharacteristics();
201
- } catch (e: any) {
202
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
203
- }
204
- });
205
- });
206
- req.on('error', (e: any) => {
207
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
163
+ const { body, statusCode, headers } = await request(`${Devices}/${this.device.deviceId}/status`, {
164
+ headers: this.platform.generateHeaders(),
208
165
  });
209
- req.end();
166
+ const deviceStatus = await body.json();
167
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Devices: ${JSON.stringify(deviceStatus.body)}`);
168
+ this.statusCode(statusCode);
169
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Headers: ${JSON.stringify(headers)}`);
170
+ this.debugLog(
171
+ `${this.device.deviceType}: ${this.accessory.displayName
172
+ } refreshStatus: ${JSON.stringify(deviceStatus)}`,
173
+ );
174
+ this.CurrentTemperature = deviceStatus.body.temperature;
175
+ this.CurrentRelativeHumidity = deviceStatus.body.humidity;
176
+ this.openAPIparseStatus();
177
+ this.updateHomeKitCharacteristics();
210
178
  } catch (e: any) {
211
179
  this.apiError(e);
212
- this.errorLog(
213
- `${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}` +
214
- ` Connection, Error Message: ${superStringify(e.message)}`,
215
- );
180
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
181
+ + ` Connection, Error Message: ${JSON.stringify(e.message)}`);
216
182
  }
217
183
  }
218
184
 
@@ -246,36 +212,41 @@ export class Hub {
246
212
  this.hubTemperatureSensor?.updateCharacteristic(this.platform.Characteristic.CurrentTemperature, this.CurrentTemperature);
247
213
  }
248
214
 
249
- async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
250
- switch (res.statusCode) {
215
+ async statusCode(statusCode: number): Promise<void> {
216
+ switch (statusCode) {
251
217
  case 151:
252
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
218
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this deviceType, statusCode: ${statusCode}`);
253
219
  break;
254
220
  case 152:
255
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
221
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found, statusCode: ${statusCode}`);
256
222
  break;
257
223
  case 160:
258
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
224
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported, statusCode: ${statusCode}`);
259
225
  break;
260
226
  case 161:
261
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
227
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline, statusCode: ${statusCode}`);
262
228
  this.offlineOff();
263
229
  break;
264
230
  case 171:
265
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline. Hub: ${this.device.hubDeviceId}`);
231
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Hub Device is offline, statusCode: ${statusCode}. `
232
+ + `Hub: ${this.device.hubDeviceId}`);
266
233
  this.offlineOff();
267
234
  break;
268
235
  case 190:
269
236
  this.errorLog(
270
237
  `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
271
- ` Or command: ${superStringify(res)} format is invalid`,
238
+ ` Or command format is invalid, statusCode: ${statusCode}`,
272
239
  );
273
240
  break;
274
241
  case 100:
275
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
242
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent, statusCode: ${statusCode}`);
243
+ break;
244
+ case 200:
245
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Request successful, statusCode: ${statusCode}`);
276
246
  break;
277
247
  default:
278
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
248
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode: `
249
+ + `${statusCode}, Submit Bugs Here: ' + 'https://tinyurl.com/SwitchBotBug`);
279
250
  }
280
251
  }
281
252