@switchbot/homebridge-switchbot 1.15.1-beta.0 → 1.15.1-beta.10

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 (117) hide show
  1. package/.github/ISSUE_TEMPLATE/bug-report.yml +1 -0
  2. package/.github/ISSUE_TEMPLATE/feature-request.yml +1 -0
  3. package/.github/ISSUE_TEMPLATE/support-request.yml +1 -0
  4. package/.prettierrc +1 -1
  5. package/CHANGELOG.md +9 -0
  6. package/config.schema.json +11 -4
  7. package/dist/device/bot.d.ts +8 -7
  8. package/dist/device/bot.d.ts.map +1 -1
  9. package/dist/device/bot.js +104 -28
  10. package/dist/device/bot.js.map +1 -1
  11. package/dist/device/colorbulb.d.ts +8 -7
  12. package/dist/device/colorbulb.d.ts.map +1 -1
  13. package/dist/device/colorbulb.js +223 -58
  14. package/dist/device/colorbulb.js.map +1 -1
  15. package/dist/device/contact.d.ts +3 -3
  16. package/dist/device/contact.d.ts.map +1 -1
  17. package/dist/device/contact.js +54 -11
  18. package/dist/device/contact.js.map +1 -1
  19. package/dist/device/curtain.d.ts +9 -8
  20. package/dist/device/curtain.d.ts.map +1 -1
  21. package/dist/device/curtain.js +102 -28
  22. package/dist/device/curtain.js.map +1 -1
  23. package/dist/device/humidifier.d.ts +8 -7
  24. package/dist/device/humidifier.d.ts.map +1 -1
  25. package/dist/device/humidifier.js +187 -66
  26. package/dist/device/humidifier.js.map +1 -1
  27. package/dist/device/lock.d.ts +8 -7
  28. package/dist/device/lock.d.ts.map +1 -1
  29. package/dist/device/lock.js +98 -22
  30. package/dist/device/lock.js.map +1 -1
  31. package/dist/device/meter.d.ts +4 -4
  32. package/dist/device/meter.d.ts.map +1 -1
  33. package/dist/device/meter.js +55 -12
  34. package/dist/device/meter.js.map +1 -1
  35. package/dist/device/meterplus.d.ts +3 -3
  36. package/dist/device/meterplus.d.ts.map +1 -1
  37. package/dist/device/meterplus.js +53 -10
  38. package/dist/device/meterplus.js.map +1 -1
  39. package/dist/device/motion.d.ts +3 -3
  40. package/dist/device/motion.d.ts.map +1 -1
  41. package/dist/device/motion.js +53 -13
  42. package/dist/device/motion.js.map +1 -1
  43. package/dist/device/plug.d.ts +8 -7
  44. package/dist/device/plug.d.ts.map +1 -1
  45. package/dist/device/plug.js +100 -24
  46. package/dist/device/plug.js.map +1 -1
  47. package/dist/device/striplight.d.ts +8 -7
  48. package/dist/device/striplight.d.ts.map +1 -1
  49. package/dist/device/striplight.js +186 -47
  50. package/dist/device/striplight.js.map +1 -1
  51. package/dist/irdevice/airconditioner.d.ts +7 -6
  52. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  53. package/dist/irdevice/airconditioner.js +40 -6
  54. package/dist/irdevice/airconditioner.js.map +1 -1
  55. package/dist/irdevice/airpurifier.d.ts +7 -6
  56. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  57. package/dist/irdevice/airpurifier.js +46 -11
  58. package/dist/irdevice/airpurifier.js.map +1 -1
  59. package/dist/irdevice/camera.d.ts +7 -6
  60. package/dist/irdevice/camera.d.ts.map +1 -1
  61. package/dist/irdevice/camera.js +40 -6
  62. package/dist/irdevice/camera.js.map +1 -1
  63. package/dist/irdevice/fan.d.ts +8 -7
  64. package/dist/irdevice/fan.d.ts.map +1 -1
  65. package/dist/irdevice/fan.js +40 -6
  66. package/dist/irdevice/fan.js.map +1 -1
  67. package/dist/irdevice/light.d.ts +7 -6
  68. package/dist/irdevice/light.d.ts.map +1 -1
  69. package/dist/irdevice/light.js +40 -6
  70. package/dist/irdevice/light.js.map +1 -1
  71. package/dist/irdevice/other.d.ts +7 -6
  72. package/dist/irdevice/other.d.ts.map +1 -1
  73. package/dist/irdevice/other.js +40 -6
  74. package/dist/irdevice/other.js.map +1 -1
  75. package/dist/irdevice/tv.d.ts +8 -7
  76. package/dist/irdevice/tv.d.ts.map +1 -1
  77. package/dist/irdevice/tv.js +40 -6
  78. package/dist/irdevice/tv.js.map +1 -1
  79. package/dist/irdevice/vacuumcleaner.d.ts +7 -6
  80. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  81. package/dist/irdevice/vacuumcleaner.js +40 -6
  82. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  83. package/dist/irdevice/waterheater.d.ts +7 -6
  84. package/dist/irdevice/waterheater.d.ts.map +1 -1
  85. package/dist/irdevice/waterheater.js +40 -6
  86. package/dist/irdevice/waterheater.js.map +1 -1
  87. package/dist/platform.d.ts +10 -6
  88. package/dist/platform.d.ts.map +1 -1
  89. package/dist/platform.js +211 -93
  90. package/dist/platform.js.map +1 -1
  91. package/dist/settings.d.ts +4 -21
  92. package/dist/settings.d.ts.map +1 -1
  93. package/dist/settings.js +3 -3
  94. package/dist/settings.js.map +1 -1
  95. package/package.json +12 -12
  96. package/src/device/bot.ts +104 -37
  97. package/src/device/colorbulb.ts +227 -95
  98. package/src/device/contact.ts +53 -14
  99. package/src/device/curtain.ts +105 -38
  100. package/src/device/humidifier.ts +189 -84
  101. package/src/device/lock.ts +97 -30
  102. package/src/device/meter.ts +55 -16
  103. package/src/device/meterplus.ts +52 -13
  104. package/src/device/motion.ts +52 -16
  105. package/src/device/plug.ts +101 -33
  106. package/src/device/striplight.ts +189 -68
  107. package/src/irdevice/airconditioner.ts +44 -9
  108. package/src/irdevice/airpurifier.ts +52 -17
  109. package/src/irdevice/camera.ts +46 -11
  110. package/src/irdevice/fan.ts +50 -15
  111. package/src/irdevice/light.ts +48 -13
  112. package/src/irdevice/other.ts +46 -11
  113. package/src/irdevice/tv.ts +56 -21
  114. package/src/irdevice/vacuumcleaner.ts +46 -11
  115. package/src/irdevice/waterheater.ts +46 -11
  116. package/src/platform.ts +232 -107
  117. package/src/settings.ts +4 -25
package/src/device/bot.ts CHANGED
@@ -1,10 +1,12 @@
1
- import { AxiosResponse } from 'axios';
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { Context } from 'vm';
4
+ import { IncomingMessage } from 'http';
2
5
  import { interval, Subject } from 'rxjs';
3
6
  import { SwitchBotPlatform } from '../platform';
4
7
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
5
8
  import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
6
- import { DeviceURL, device, devicesConfig, serviceData, ad, switchbot, deviceStatusResponse, payload, deviceStatus } from '../settings';
7
- import { Context } from 'vm';
9
+ import { device, devicesConfig, deviceStatus, ad, serviceData, switchbot, HostDomain, DevicePath } from '../settings';
8
10
 
9
11
  /**
10
12
  * Platform Accessory
@@ -33,7 +35,7 @@ export class Bot {
33
35
 
34
36
  // OpenAPI Others
35
37
  power: deviceStatus['power'];
36
- deviceStatus!: deviceStatusResponse;
38
+ deviceStatus!: any; //deviceStatusResponse;
37
39
 
38
40
  // BLE Others
39
41
  connected?: boolean;
@@ -415,7 +417,7 @@ export class Bot {
415
417
  if (this.device.ble) {
416
418
  this.SwitchToOpenAPI = false;
417
419
  }
418
- if (this.platform.config.credentials?.openToken) {
420
+ if (this.platform.config.credentials?.token) {
419
421
  this.debugLog(`Bot: ${this.accessory.displayName} OpenAPI parseStatus`);
420
422
  if (this.botMode === 'press') {
421
423
  this.On = false;
@@ -510,7 +512,7 @@ export class Bot {
510
512
  this.updateHomeKitCharacteristics();
511
513
  } else {
512
514
  this.errorLog(`Bot: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
513
- if (this.platform.config.credentials?.openToken) {
515
+ if (this.platform.config.credentials?.token) {
514
516
  this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
515
517
  this.SwitchToOpenAPI = true;
516
518
  await this.openAPIRefreshStatus();
@@ -524,7 +526,7 @@ export class Bot {
524
526
  `Bot: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
525
527
  );
526
528
  }
527
- if (this.platform.config.credentials?.openToken) {
529
+ if (this.platform.config.credentials?.token) {
528
530
  this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
529
531
  this.SwitchToOpenAPI = true;
530
532
  await this.openAPIRefreshStatus();
@@ -552,14 +554,51 @@ export class Bot {
552
554
  }
553
555
 
554
556
  async openAPIRefreshStatus(): Promise<void> {
555
- if (this.platform.config.credentials?.openToken) {
557
+ if (this.platform.config.credentials?.token) {
556
558
  this.debugLog(`Bot: ${this.accessory.displayName} OpenAPI refreshStatus`);
557
559
  try {
558
- this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
559
- this.debugLog(`Bot: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
560
- this.power = this.deviceStatus.body.power;
561
- this.parseStatus();
562
- this.updateHomeKitCharacteristics();
560
+ const t = Date.now();
561
+ const nonce = 'requestID';
562
+ const data = this.platform.config.credentials?.token + t + nonce;
563
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
564
+ const sign = signTerm.toString('base64');
565
+ this.debugLog(`Bot: ${this.accessory.displayName} sign: ${sign}`);
566
+ const options = {
567
+ hostname: HostDomain,
568
+ port: 443,
569
+ path: `${DevicePath}/${this.device.deviceId}/status`,
570
+ method: 'GET',
571
+ headers: {
572
+ Authorization: this.platform.config.credentials?.token,
573
+ sign: sign,
574
+ nonce: nonce,
575
+ t: t,
576
+ 'Content-Type': 'application/json',
577
+ },
578
+ };
579
+ const req = https.request(options, (res) => {
580
+ this.debugLog(`Bot: ${this.accessory.displayName} Refresh statusCode: ${res.statusCode}`);
581
+ let rawData = '';
582
+ res.on('data', (d) => {
583
+ rawData += d;
584
+ this.debugLog(`d: ${d}`);
585
+ });
586
+ res.on('end', () => {
587
+ try {
588
+ this.deviceStatus = JSON.parse(rawData);
589
+ this.debugLog(`Bot: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
590
+ this.power = this.deviceStatus.body.power;
591
+ this.parseStatus();
592
+ this.updateHomeKitCharacteristics();
593
+ } catch (e: any) {
594
+ this.errorLog(`Bot: ${this.accessory.displayName} error message: ${e.message}`);
595
+ }
596
+ });
597
+ });
598
+ req.on('error', (e: any) => {
599
+ this.errorLog(`Bot: ${this.accessory.displayName} error message: ${e.message}`);
600
+ });
601
+ req.end();
563
602
  } catch (e: any) {
564
603
  this.errorLog(`Bot: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
565
604
  if (this.deviceLogging.includes('debug')) {
@@ -639,7 +678,7 @@ export class Bot {
639
678
  if (this.platform.debugMode) {
640
679
  this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error: ${JSON.stringify(e)}`);
641
680
  }
642
- if (this.platform.config.credentials?.openToken) {
681
+ if (this.platform.config.credentials?.token) {
643
682
  this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
644
683
  await this.openAPIpushChanges();
645
684
  }
@@ -668,7 +707,7 @@ export class Bot {
668
707
  if (this.platform.debugMode) {
669
708
  this.errorLog(`Bot: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error: ${JSON.stringify(e)}`);
670
709
  }
671
- if (this.platform.config.credentials?.openToken) {
710
+ if (this.platform.config.credentials?.token) {
672
711
  this.warnLog(`Bot: ${this.accessory.displayName} Using OpenAPI Connection`);
673
712
  await this.openAPIpushChanges();
674
713
  }
@@ -696,40 +735,68 @@ export class Bot {
696
735
  }
697
736
 
698
737
  async openAPIpushChanges(): Promise<void> {
699
- if (this.platform.config.credentials?.openToken) {
738
+ if (this.platform.config.credentials?.token) {
700
739
  try {
701
740
  if (this.On !== this.OnCached || this.allowPush) {
702
741
  this.debugLog(`Bot: ${this.accessory.displayName} OpenAPI pushChanges`);
703
- const payload = {
704
- commandType: 'command',
705
- parameter: 'default',
706
- } as payload;
707
-
742
+ // Make Push On request to the API
743
+ const t = Date.now();
744
+ const nonce = 'requestID';
745
+ const data = this.platform.config.credentials?.token + t + nonce;
746
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
747
+ .update(Buffer.from(data, 'utf-8'))
748
+ .digest();
749
+ const sign = signTerm.toString('base64');
750
+ this.debugLog(`Bot: ${this.accessory.displayName} sign: ${sign}`);
751
+ let command = '';
708
752
  if (this.botMode === 'switch' && this.On) {
709
- payload.command = 'turnOn';
753
+ command = 'turnOn';
710
754
  this.On = true;
711
755
  this.debugLog(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
712
756
  } else if (this.botMode === 'switch' && !this.On) {
713
- payload.command = 'turnOff';
757
+ command = 'turnOff';
714
758
  this.On = false;
715
759
  this.debugLog(`Bot: ${this.accessory.displayName} Switch Mode, Turning ${this.On}`);
716
760
  } else if (this.botMode === 'press') {
717
- payload.command = 'press';
761
+ command = 'press';
718
762
  this.debugLog(`Bot: ${this.accessory.displayName} Press Mode`);
719
763
  this.On = false;
720
764
  } else {
721
765
  throw new Error(`Bot: ${this.accessory.displayName} Device Paramters not set for this Bot.`);
722
766
  }
723
-
724
- this.infoLog(
725
- `Bot: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
726
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
727
- );
728
-
729
- // Make the API request
730
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
731
- this.debugLog(`Bot: ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
732
- this.statusCode(push);
767
+ const body = JSON.stringify({
768
+ 'command': `${command}`,
769
+ 'parameter': 'default',
770
+ 'commandType': 'command',
771
+ });
772
+ this.infoLog(`Bot: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
773
+ const options = {
774
+ hostname: HostDomain,
775
+ port: 443,
776
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
777
+ method: 'POST',
778
+ headers: {
779
+ 'Authorization': this.platform.config.credentials?.token,
780
+ 'sign': sign,
781
+ 'nonce': nonce,
782
+ 't': t,
783
+ 'Content-Type': 'application/json',
784
+ 'Content-Length': body.length,
785
+ },
786
+ };
787
+ const req = https.request(options, res => {
788
+ this.debugLog(`Bot: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
789
+ this.statusCode({ res });
790
+ res.on('data', d => {
791
+ this.debugLog(`Bot: ${this.accessory.displayName} d: ${d}`);
792
+ });
793
+ });
794
+ req.on('error', (e: any) => {
795
+ this.errorLog(`Bot: ${this.accessory.displayName} error message: ${e.message}`);
796
+ });
797
+ req.write(body);
798
+ req.end();
799
+ this.debugLog(`Bot: ${this.accessory.displayName} openAPIpushChanges: ${JSON.stringify(req)}`);
733
800
  this.OnCached = this.On;
734
801
  this.accessory.context.On = this.OnCached;
735
802
  }
@@ -977,8 +1044,8 @@ export class Bot {
977
1044
  //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
978
1045
  }
979
1046
 
980
- async statusCode(push: AxiosResponse<{ statusCode: number }>): Promise<void> {
981
- switch (push.data.statusCode) {
1047
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
1048
+ switch (res.statusCode) {
982
1049
  case 151:
983
1050
  this.errorLog(`Bot: ${this.accessory.displayName} Command not supported by this device type.`);
984
1051
  break;
@@ -999,7 +1066,7 @@ export class Bot {
999
1066
  case 190:
1000
1067
  this.errorLog(
1001
1068
  `Bot: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
1002
- ` Or command: ${JSON.stringify(push.data)} format is invalid`,
1069
+ ` Or command: ${JSON.stringify(res)} format is invalid`,
1003
1070
  );
1004
1071
  break;
1005
1072
  case 100:
@@ -1,23 +1,12 @@
1
- import { AxiosResponse } from 'axios';
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { Context } from 'vm';
4
+ import { IncomingMessage } from 'http';
2
5
  import { interval, Subject } from 'rxjs';
3
6
  import { SwitchBotPlatform } from '../platform';
4
7
  import { debounceTime, skipWhile, tap } from 'rxjs/operators';
5
8
  import { Service, PlatformAccessory, CharacteristicValue, ControllerConstructor, Controller, ControllerServiceMap } from 'homebridge';
6
- import {
7
- DeviceURL,
8
- device,
9
- devicesConfig,
10
- switchbot,
11
- deviceStatusResponse,
12
- payload,
13
- hs2rgb,
14
- rgb2hs,
15
- m2hs,
16
- deviceStatus,
17
- serviceData,
18
- ad,
19
- } from '../settings';
20
- import { Context } from 'vm';
9
+ import { device, devicesConfig, deviceStatus, switchbot, hs2rgb, rgb2hs, m2hs, serviceData, ad, HostDomain, DevicePath } from '../settings';
21
10
 
22
11
  /**
23
12
  * Platform Accessory
@@ -45,7 +34,7 @@ export class ColorBulb {
45
34
  color: deviceStatus['color'];
46
35
  brightness: deviceStatus['brightness'];
47
36
  colorTemperature?: deviceStatus['colorTemperature'];
48
- deviceStatus!: deviceStatusResponse;
37
+ deviceStatus!: any; //deviceStatusResponse;
49
38
 
50
39
  // BLE Others
51
40
  connected?: boolean;
@@ -378,7 +367,7 @@ export class ColorBulb {
378
367
  `Color Bulb: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
379
368
  );
380
369
  }
381
- if (this.platform.config.credentials?.openToken) {
370
+ if (this.platform.config.credentials?.token) {
382
371
  this.warnLog(`Color Bulb: ${this.accessory.displayName} Using OpenAPI Connection`);
383
372
  this.SwitchToOpenAPI = true;
384
373
  await this.openAPIRefreshStatus();
@@ -410,7 +399,7 @@ export class ColorBulb {
410
399
 
411
400
  async BLEconnection(switchbot: any): Promise<void> {
412
401
  this.errorLog(`Color Bulb: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
413
- if (this.platform.config.credentials?.openToken) {
402
+ if (this.platform.config.credentials?.token) {
414
403
  this.warnLog(`Color Bulb: ${this.accessory.displayName} Using OpenAPI Connection`);
415
404
  this.SwitchToOpenAPI = true;
416
405
  await this.openAPIRefreshStatus();
@@ -419,15 +408,51 @@ export class ColorBulb {
419
408
 
420
409
  private async openAPIRefreshStatus() {
421
410
  try {
422
- this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
423
- this.debugLog(`Color Bulb: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
424
- this.power = this.deviceStatus.body.power;
425
- this.color = this.deviceStatus.body.color;
426
- this.brightness = this.deviceStatus.body.brightness;
427
- this.colorTemperature = this.deviceStatus.body.colorTemperature;
428
-
429
- this.parseStatus();
430
- this.updateHomeKitCharacteristics();
411
+ const t = Date.now();
412
+ const nonce = 'requestID';
413
+ const data = this.platform.config.credentials?.token + t + nonce;
414
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
415
+ const sign = signTerm.toString('base64');
416
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
417
+ const options = {
418
+ hostname: HostDomain,
419
+ port: 443,
420
+ path: `${DevicePath}/${this.device.deviceId}/status`,
421
+ method: 'GET',
422
+ headers: {
423
+ Authorization: this.platform.config.credentials?.token,
424
+ sign: sign,
425
+ nonce: nonce,
426
+ t: t,
427
+ 'Content-Type': 'application/json',
428
+ },
429
+ };
430
+ const req = https.request(options, (res) => {
431
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} Refresh statusCode: ${res.statusCode}`);
432
+ let rawData = '';
433
+ res.on('data', (d) => {
434
+ rawData += d;
435
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} d: ${d}`);
436
+ });
437
+ res.on('end', () => {
438
+ try {
439
+ this.deviceStatus = JSON.parse(rawData);
440
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
441
+ this.power = this.deviceStatus.body.power;
442
+ this.color = this.deviceStatus.body.color;
443
+ this.brightness = this.deviceStatus.body.brightness;
444
+ this.colorTemperature = this.deviceStatus.body.colorTemperature;
445
+ this.parseStatus();
446
+ this.updateHomeKitCharacteristics();
447
+ } catch (e: any) {
448
+ this.errorLog(`Color Bulb: ${this.accessory.displayName} error message: ${e.message}`);
449
+ }
450
+ });
451
+ });
452
+ req.on('error', (e: any) => {
453
+ this.errorLog(`Color Bulb: ${this.accessory.displayName} error message: ${e.message}`);
454
+ });
455
+ req.end();
431
456
  } catch (e: any) {
432
457
  this.errorLog(`Color Bulb: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
433
458
  if (this.deviceLogging.includes('debug')) {
@@ -453,38 +478,66 @@ export class ColorBulb {
453
478
  async pushChanges(): Promise<void> {
454
479
  try {
455
480
  if (this.On !== this.OnCached) {
456
- // Push On Update
457
- const payload = {
458
- commandType: 'command',
459
- parameter: 'default',
460
- } as payload;
461
-
481
+ // Make Push On request to the API
482
+ const t = Date.now();
483
+ const nonce = 'requestID';
484
+ const data = this.platform.config.credentials?.token + t + nonce;
485
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
486
+ .update(Buffer.from(data, 'utf-8'))
487
+ .digest();
488
+ const sign = signTerm.toString('base64');
489
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
490
+
491
+ let command = '';
462
492
  if (this.On) {
463
- payload.command = 'turnOn';
493
+ command = 'turnOn';
464
494
  } else {
465
- payload.command = 'turnOff';
495
+ command = 'turnOff';
466
496
  }
467
-
468
- this.infoLog(
469
- `Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
470
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
471
- );
472
-
473
- // Make the API request
474
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
475
- this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
476
- this.statusCode(push);
497
+ const body = JSON.stringify({
498
+ 'command': `${command}`,
499
+ 'parameter': 'default',
500
+ 'commandType': 'command',
501
+ });
502
+ this.infoLog(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
503
+ const options = {
504
+ hostname: HostDomain,
505
+ port: 443,
506
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
507
+ method: 'POST',
508
+ headers: {
509
+ 'Authorization': this.platform.config.credentials?.token,
510
+ 'sign': sign,
511
+ 'nonce': nonce,
512
+ 't': t,
513
+ 'Content-Type': 'application/json',
514
+ 'Content-Length': body.length,
515
+ },
516
+ };
517
+ const req = https.request(options, res => {
518
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
519
+ this.statusCode({ res });
520
+ res.on('data', d => {
521
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} d: ${d}`);
522
+ });
523
+ });
524
+ req.on('error', (e: any) => {
525
+ this.errorLog(`Color Bulb: ${this.accessory.displayName} error message: ${e.message}`);
526
+ });
527
+ req.write(body);
528
+ req.end();
529
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(req)}`);
477
530
  this.OnCached = this.On;
478
531
  this.accessory.context.On = this.OnCached;
479
532
  }
480
533
  // Push Brightness Update
481
534
  if (this.On) {
482
- await this.pushBrightnessChanges();
535
+ //await this.pushBrightnessChanges();
483
536
  }
484
537
 
485
538
  // Push ColorTemperature Update
486
539
  if (this.On) {
487
- await this.pushColorTemperatureChanges();
540
+ //await this.pushColorTemperatureChanges();
488
541
  }
489
542
 
490
543
  // Push Hue & Saturation Update
@@ -511,21 +564,47 @@ export class ColorBulb {
511
564
  const [red, green, blue] = hs2rgb(Number(this.Hue), Number(this.Saturation));
512
565
  this.debugLog(`Color Bulb: ${this.accessory.displayName} rgb: ${JSON.stringify([red, green, blue])}`);
513
566
 
514
- const payload = {
515
- commandType: 'command',
516
- command: 'setColor',
517
- parameter: `${red}:${green}:${blue}`,
518
- } as payload;
519
-
520
- this.infoLog(
521
- `Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
522
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
523
- );
524
-
525
- // Make the API request
526
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
527
- this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
528
- this.statusCode(push);
567
+ // Make Push Hue/Saturation request to the API
568
+ const t = Date.now();
569
+ const nonce = 'requestID';
570
+ const data = this.platform.config.credentials?.token + t + nonce;
571
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
572
+ .update(Buffer.from(data, 'utf-8'))
573
+ .digest();
574
+ const sign = signTerm.toString('base64');
575
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
576
+ const body = JSON.stringify({
577
+ 'command': 'setColor',
578
+ 'parameter': `${red}:${green}:${blue}`,
579
+ 'commandType': 'command',
580
+ });
581
+ this.infoLog(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
582
+ const options = {
583
+ hostname: HostDomain,
584
+ port: 443,
585
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
586
+ method: 'POST',
587
+ headers: {
588
+ 'Authorization': this.platform.config.credentials?.token,
589
+ 'sign': sign,
590
+ 'nonce': nonce,
591
+ 't': t,
592
+ 'Content-Type': 'application/json',
593
+ 'Content-Length': body.length,
594
+ },
595
+ };
596
+ const req = https.request(options, res => {
597
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
598
+ res.on('data', d => {
599
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} d: ${d}`);
600
+ });
601
+ });
602
+ req.on('error', (e: any) => {
603
+ this.errorLog(`Color Bulb: ${this.accessory.displayName} error message: ${e.message}`);
604
+ });
605
+ req.write(body);
606
+ req.end();
607
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} pushHueSaturationChanges: ${JSON.stringify(req)}`);
529
608
  this.HueCached = this.Hue;
530
609
  this.SaturationCached = this.Saturation;
531
610
  } else {
@@ -551,21 +630,48 @@ export class ColorBulb {
551
630
  const kelvin = Math.round(1000000 / Number(this.ColorTemperature));
552
631
  this.cacheKelvin = kelvin;
553
632
 
554
- const payload = {
555
- commandType: 'command',
556
- command: 'setColorTemperature',
557
- parameter: `${kelvin}`,
558
- } as payload;
559
-
560
- this.infoLog(
561
- `Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
562
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
563
- );
633
+ // Make Push On request to the API
634
+ const t = Date.now();
635
+ const nonce = 'requestID';
636
+ const data = this.platform.config.credentials?.token + t + nonce;
637
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
638
+ .update(Buffer.from(data, 'utf-8'))
639
+ .digest();
640
+ const sign = signTerm.toString('base64');
641
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
642
+ const body = JSON.stringify({
643
+ 'command': 'setColorTemperature',
644
+ 'parameter': `${kelvin}`,
645
+ 'commandType': 'command',
646
+ });
647
+ this.infoLog(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
648
+ const options = {
649
+ hostname: HostDomain,
650
+ port: 443,
651
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
652
+ method: 'POST',
653
+ headers: {
654
+ 'Authorization': this.platform.config.credentials?.token,
655
+ 'sign': sign,
656
+ 'nonce': nonce,
657
+ 't': t,
658
+ 'Content-Type': 'application/json',
659
+ 'Content-Length': body.length,
660
+ },
661
+ };
662
+ const req = https.request(options, res => {
663
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
664
+ res.on('data', d => {
665
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} d: ${d}`);
666
+ });
667
+ });
668
+ req.on('error', (e: any) => {
669
+ this.errorLog(`Color Bulb: ${this.accessory.displayName} error message: ${e.message}`);
670
+ });
671
+ req.write(body);
672
+ req.end();
564
673
 
565
- // Make the API request
566
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
567
- this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
568
- this.statusCode(push);
674
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} pushColorTemperatureChanges: ${JSON.stringify(req)}`);
569
675
  this.ColorTemperatureCached = this.ColorTemperature;
570
676
  } else {
571
677
  this.debugLog(
@@ -587,21 +693,47 @@ export class ColorBulb {
587
693
  async pushBrightnessChanges(): Promise<void> {
588
694
  try {
589
695
  if (this.Brightness !== this.BrightnessCached) {
590
- const payload = {
591
- commandType: 'command',
592
- command: 'setBrightness',
593
- parameter: `${this.Brightness}`,
594
- } as payload;
595
-
596
- this.infoLog(
597
- `Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
598
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
599
- );
600
-
601
- // Make the API request
602
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
603
- this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
604
- this.statusCode(push);
696
+ // Make Push On request to the API
697
+ const t = Date.now();
698
+ const nonce = 'requestID';
699
+ const data = this.platform.config.credentials?.token + t + nonce;
700
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
701
+ .update(Buffer.from(data, 'utf-8'))
702
+ .digest();
703
+ const sign = signTerm.toString('base64');
704
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
705
+ const body = JSON.stringify({
706
+ 'command': 'setBrightness',
707
+ 'parameter': `${this.Brightness}`,
708
+ 'commandType': 'command',
709
+ });
710
+ this.infoLog(`Color Bulb: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
711
+ const options = {
712
+ hostname: HostDomain,
713
+ port: 443,
714
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
715
+ method: 'POST',
716
+ headers: {
717
+ 'Authorization': this.platform.config.credentials?.token,
718
+ 'sign': sign,
719
+ 'nonce': nonce,
720
+ 't': t,
721
+ 'Content-Type': 'application/json',
722
+ 'Content-Length': body.length,
723
+ },
724
+ };
725
+ const req = https.request(options, res => {
726
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
727
+ res.on('data', d => {
728
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} d: ${d}`);
729
+ });
730
+ });
731
+ req.on('error', (e: any) => {
732
+ this.errorLog(`Color Bulb: ${this.accessory.displayName} error message: ${e.message}`);
733
+ });
734
+ req.write(body);
735
+ req.end();
736
+ this.debugLog(`Color Bulb: ${this.accessory.displayName} pushBrightnessChanges: ${JSON.stringify(req)}`);
605
737
  this.BrightnessCached = this.Brightness;
606
738
  } else {
607
739
  this.debugLog(
@@ -661,8 +793,8 @@ export class ColorBulb {
661
793
  //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
662
794
  }
663
795
 
664
- statusCode(push: AxiosResponse<{ statusCode: number }>): void {
665
- switch (push.data.statusCode) {
796
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
797
+ switch (res.statusCode) {
666
798
  case 151:
667
799
  this.errorLog(`Color Bulb: ${this.accessory.displayName} Command not supported by this device type.`);
668
800
  break;
@@ -683,7 +815,7 @@ export class ColorBulb {
683
815
  case 190:
684
816
  this.errorLog(
685
817
  `Color Bulb: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
686
- ` Or command: ${JSON.stringify(push.data)} format is invalid`,
818
+ ` Or command: ${JSON.stringify(res)} format is invalid`,
687
819
  );
688
820
  break;
689
821
  case 100: