@switchbot/homebridge-switchbot 1.15.1-beta.7 → 1.15.1-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.prettierrc +1 -1
  2. package/dist/device/bot.d.ts +8 -7
  3. package/dist/device/bot.d.ts.map +1 -1
  4. package/dist/device/bot.js +97 -21
  5. package/dist/device/bot.js.map +1 -1
  6. package/dist/device/colorbulb.d.ts +8 -7
  7. package/dist/device/colorbulb.d.ts.map +1 -1
  8. package/dist/device/colorbulb.js +221 -56
  9. package/dist/device/colorbulb.js.map +1 -1
  10. package/dist/device/contact.d.ts +3 -3
  11. package/dist/device/contact.d.ts.map +1 -1
  12. package/dist/device/contact.js +50 -7
  13. package/dist/device/contact.js.map +1 -1
  14. package/dist/device/curtain.d.ts +9 -8
  15. package/dist/device/curtain.d.ts.map +1 -1
  16. package/dist/device/curtain.js +95 -21
  17. package/dist/device/curtain.js.map +1 -1
  18. package/dist/device/humidifier.d.ts +8 -7
  19. package/dist/device/humidifier.d.ts.map +1 -1
  20. package/dist/device/humidifier.js +180 -59
  21. package/dist/device/humidifier.js.map +1 -1
  22. package/dist/device/lock.d.ts +8 -7
  23. package/dist/device/lock.d.ts.map +1 -1
  24. package/dist/device/lock.js +98 -22
  25. package/dist/device/lock.js.map +1 -1
  26. package/dist/device/meter.d.ts +4 -4
  27. package/dist/device/meter.d.ts.map +1 -1
  28. package/dist/device/meter.js +51 -8
  29. package/dist/device/meter.js.map +1 -1
  30. package/dist/device/meterplus.d.ts +3 -3
  31. package/dist/device/meterplus.d.ts.map +1 -1
  32. package/dist/device/meterplus.js +49 -6
  33. package/dist/device/meterplus.js.map +1 -1
  34. package/dist/device/motion.d.ts +3 -3
  35. package/dist/device/motion.d.ts.map +1 -1
  36. package/dist/device/motion.js +49 -9
  37. package/dist/device/motion.js.map +1 -1
  38. package/dist/device/plug.d.ts +8 -7
  39. package/dist/device/plug.d.ts.map +1 -1
  40. package/dist/device/plug.js +96 -20
  41. package/dist/device/plug.js.map +1 -1
  42. package/dist/device/striplight.d.ts +8 -7
  43. package/dist/device/striplight.d.ts.map +1 -1
  44. package/dist/device/striplight.js +186 -47
  45. package/dist/device/striplight.js.map +1 -1
  46. package/dist/irdevice/airconditioner.d.ts +7 -6
  47. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  48. package/dist/irdevice/airconditioner.js +40 -6
  49. package/dist/irdevice/airconditioner.js.map +1 -1
  50. package/dist/irdevice/airpurifier.d.ts +7 -6
  51. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  52. package/dist/irdevice/airpurifier.js +46 -11
  53. package/dist/irdevice/airpurifier.js.map +1 -1
  54. package/dist/irdevice/camera.d.ts +7 -6
  55. package/dist/irdevice/camera.d.ts.map +1 -1
  56. package/dist/irdevice/camera.js +40 -6
  57. package/dist/irdevice/camera.js.map +1 -1
  58. package/dist/irdevice/fan.d.ts +8 -7
  59. package/dist/irdevice/fan.d.ts.map +1 -1
  60. package/dist/irdevice/fan.js +40 -6
  61. package/dist/irdevice/fan.js.map +1 -1
  62. package/dist/irdevice/light.d.ts +7 -6
  63. package/dist/irdevice/light.d.ts.map +1 -1
  64. package/dist/irdevice/light.js +40 -6
  65. package/dist/irdevice/light.js.map +1 -1
  66. package/dist/irdevice/other.d.ts +7 -6
  67. package/dist/irdevice/other.d.ts.map +1 -1
  68. package/dist/irdevice/other.js +40 -6
  69. package/dist/irdevice/other.js.map +1 -1
  70. package/dist/irdevice/tv.d.ts +8 -7
  71. package/dist/irdevice/tv.d.ts.map +1 -1
  72. package/dist/irdevice/tv.js +40 -6
  73. package/dist/irdevice/tv.js.map +1 -1
  74. package/dist/irdevice/vacuumcleaner.d.ts +7 -6
  75. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.js +40 -6
  77. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  78. package/dist/irdevice/waterheater.d.ts +7 -6
  79. package/dist/irdevice/waterheater.d.ts.map +1 -1
  80. package/dist/irdevice/waterheater.js +40 -6
  81. package/dist/irdevice/waterheater.js.map +1 -1
  82. package/dist/platform.d.ts +3 -5
  83. package/dist/platform.d.ts.map +1 -1
  84. package/dist/platform.js +141 -95
  85. package/dist/platform.js.map +1 -1
  86. package/dist/settings.d.ts +2 -21
  87. package/dist/settings.d.ts.map +1 -1
  88. package/dist/settings.js +3 -3
  89. package/dist/settings.js.map +1 -1
  90. package/package.json +6 -7
  91. package/src/device/bot.ts +97 -30
  92. package/src/device/colorbulb.ts +225 -93
  93. package/src/device/contact.ts +49 -10
  94. package/src/device/curtain.ts +98 -31
  95. package/src/device/humidifier.ts +182 -77
  96. package/src/device/lock.ts +97 -30
  97. package/src/device/meter.ts +51 -12
  98. package/src/device/meterplus.ts +48 -9
  99. package/src/device/motion.ts +48 -12
  100. package/src/device/plug.ts +97 -29
  101. package/src/device/striplight.ts +189 -68
  102. package/src/irdevice/airconditioner.ts +44 -9
  103. package/src/irdevice/airpurifier.ts +52 -17
  104. package/src/irdevice/camera.ts +46 -11
  105. package/src/irdevice/fan.ts +50 -15
  106. package/src/irdevice/light.ts +48 -13
  107. package/src/irdevice/other.ts +46 -11
  108. package/src/irdevice/tv.ts +56 -21
  109. package/src/irdevice/vacuumcleaner.ts +46 -11
  110. package/src/irdevice/waterheater.ts +46 -11
  111. package/src/platform.ts +154 -108
  112. package/src/settings.ts +2 -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;
@@ -555,11 +557,48 @@ export class Bot {
555
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')) {
@@ -700,36 +739,64 @@ export class Bot {
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;
@@ -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:
@@ -1,9 +1,11 @@
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { Context } from 'vm';
1
4
  import { interval, Subject } from 'rxjs';
2
5
  import { skipWhile } from 'rxjs/operators';
3
6
  import { SwitchBotPlatform } from '../platform';
4
7
  import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
5
- import { DeviceURL, device, devicesConfig, serviceData, switchbot, deviceStatusResponse, deviceStatus, ad } from '../settings';
6
- import { Context } from 'vm';
8
+ import { device, devicesConfig, serviceData, switchbot, deviceStatus, ad, HostDomain, DevicePath } from '../settings';
7
9
 
8
10
  /**
9
11
  * Platform Accessory
@@ -28,7 +30,7 @@ export class Contact {
28
30
  openState: deviceStatus['openState'];
29
31
  moveDetected: deviceStatus['moveDetected'];
30
32
  brightness: deviceStatus['brightness'];
31
- deviceStatus!: deviceStatusResponse;
33
+ deviceStatus!: any; //deviceStatusResponse;
32
34
 
33
35
  // BLE Others
34
36
  connected?: boolean;
@@ -374,13 +376,50 @@ export class Contact {
374
376
  if (this.platform.config.credentials?.token) {
375
377
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} OpenAPI refreshStatus`);
376
378
  try {
377
- this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
378
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
379
- this.openState = this.deviceStatus.body.openState;
380
- this.moveDetected = this.deviceStatus.body.moveDetected;
381
- this.brightness = this.deviceStatus.body.brightness;
382
- this.parseStatus();
383
- this.updateHomeKitCharacteristics();
379
+ const t = Date.now();
380
+ const nonce = 'requestID';
381
+ const data = this.platform.config.credentials?.token + t + nonce;
382
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
383
+ const sign = signTerm.toString('base64');
384
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} sign: ${sign}`);
385
+ const options = {
386
+ hostname: HostDomain,
387
+ port: 443,
388
+ path: `${DevicePath}/${this.device.deviceId}/status`,
389
+ method: 'GET',
390
+ headers: {
391
+ Authorization: this.platform.config.credentials?.token,
392
+ sign: sign,
393
+ nonce: nonce,
394
+ t: t,
395
+ 'Content-Type': 'application/json',
396
+ },
397
+ };
398
+ const req = https.request(options, (res) => {
399
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
400
+ let rawData = '';
401
+ res.on('data', (d) => {
402
+ rawData += d;
403
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} d: ${d}`);
404
+ });
405
+ res.on('end', () => {
406
+ try {
407
+ this.deviceStatus = JSON.parse(rawData);
408
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
409
+ this.openState = this.deviceStatus.body.openState;
410
+ this.moveDetected = this.deviceStatus.body.moveDetected;
411
+ this.brightness = this.deviceStatus.body.brightness;
412
+ this.parseStatus();
413
+ this.updateHomeKitCharacteristics();
414
+ } catch (e: any) {
415
+ this.errorLog(`Contact Sensor: ${this.accessory.displayName} error message: ${e.message}`);
416
+ }
417
+ });
418
+ });
419
+ req.on('error', (e: any) => {
420
+ this.errorLog(`Contact Sensor: ${this.accessory.displayName} error message: ${e.message}`);
421
+ });
422
+ req.end();
384
423
  } catch (e: any) {
385
424
  this.errorLog(`Contact Sensor: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
386
425
  if (this.deviceLogging.includes('debug')) {