@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
@@ -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, deviceStatusResponse, payload, deviceStatus } from '../settings';
7
- import { Context } from 'vm';
9
+ import { device, devicesConfig, serviceData, ad, deviceStatus, HostDomain, DevicePath } from '../settings';
8
10
 
9
11
  /**
10
12
  * Platform Accessory
@@ -32,7 +34,7 @@ export class Humidifier {
32
34
  lackWater: deviceStatus['lackWater'];
33
35
  temperature: deviceStatus['temperature'];
34
36
  nebulizationEfficiency: deviceStatus['nebulizationEfficiency'];
35
- deviceStatus!: deviceStatusResponse;
37
+ deviceStatus!: any; //deviceStatusResponse;
36
38
 
37
39
  // BLE Others
38
40
  connected?: boolean;
@@ -215,7 +217,7 @@ export class Humidifier {
215
217
  }
216
218
 
217
219
  async openAPIparseStatus(): Promise<void> {
218
- if (this.platform.config.credentials?.openToken) {
220
+ if (this.platform.config.credentials?.token) {
219
221
  this.debugLog(`Humidifier: ${this.accessory.displayName} OpenAPI parseStatus`);
220
222
  // Current Relative Humidity
221
223
  this.CurrentRelativeHumidity = this.humidity!;
@@ -347,7 +349,7 @@ export class Humidifier {
347
349
  `Humidifier: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
348
350
  );
349
351
  }
350
- if (this.platform.config.credentials?.openToken) {
352
+ if (this.platform.config.credentials?.token) {
351
353
  this.warnLog(`Humidifier: ${this.accessory.displayName} Using OpenAPI Connection`);
352
354
  await this.openAPIRefreshStatus();
353
355
  }
@@ -378,30 +380,63 @@ export class Humidifier {
378
380
 
379
381
  async BLEconnection(switchbot: any): Promise<void> {
380
382
  this.errorLog(`Humidifier: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
381
- if (this.platform.config.credentials?.openToken) {
383
+ if (this.platform.config.credentials?.token) {
382
384
  this.warnLog(`Humidifier: ${this.accessory.displayName} Using OpenAPI Connection`);
383
385
  await this.openAPIRefreshStatus();
384
386
  }
385
387
  }
386
388
 
387
389
  async openAPIRefreshStatus(): Promise<void> {
388
- if (this.platform.config.credentials?.openToken) {
390
+ if (this.platform.config.credentials?.token) {
389
391
  this.debugLog(`Humidifier: ${this.accessory.displayName} OpenAPI refreshStatus`);
390
392
  try {
391
- this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
392
- if (this.deviceStatus.message === 'success') {
393
- this.debugLog(`Humidifier: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
394
- this.auto = this.deviceStatus.body.auto;
395
- this.power = this.deviceStatus.body.power;
396
- this.lackWater = this.deviceStatus.body.lackWater;
397
- this.humidity = this.deviceStatus.body.humidity;
398
- this.temperature = this.deviceStatus.body.temperature;
399
- this.nebulizationEfficiency = this.deviceStatus.body.nebulizationEfficiency;
400
- this.parseStatus();
401
- this.updateHomeKitCharacteristics();
402
- } else {
403
- this.errorLog(`Humidifier: ${this.accessory.displayName} message: ${JSON.stringify(this.deviceStatus.message)}`);
404
- }
393
+ const t = Date.now();
394
+ const nonce = 'requestID';
395
+ const data = this.platform.config.credentials?.token + t + nonce;
396
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
397
+ const sign = signTerm.toString('base64');
398
+ this.debugLog(`Humidifier: ${this.accessory.displayName} sign: ${sign}`);
399
+ const options = {
400
+ hostname: HostDomain,
401
+ port: 443,
402
+ path: `${DevicePath}/${this.device.deviceId}/status`,
403
+ method: 'GET',
404
+ headers: {
405
+ Authorization: this.platform.config.credentials?.token,
406
+ sign: sign,
407
+ nonce: nonce,
408
+ t: t,
409
+ 'Content-Type': 'application/json',
410
+ },
411
+ };
412
+ const req = https.request(options, (res) => {
413
+ this.debugLog(`Humidifier: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
414
+ let rawData = '';
415
+ res.on('data', (d) => {
416
+ rawData += d;
417
+ this.debugLog(`Humidifier: ${this.accessory.displayName} d: ${d}`);
418
+ });
419
+ res.on('end', () => {
420
+ try {
421
+ this.deviceStatus = JSON.parse(rawData);
422
+ this.debugLog(`Humidifier: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
423
+ this.auto = this.deviceStatus.body.auto;
424
+ this.power = this.deviceStatus.body.power;
425
+ this.lackWater = this.deviceStatus.body.lackWater;
426
+ this.humidity = this.deviceStatus.body.humidity;
427
+ this.temperature = this.deviceStatus.body.temperature;
428
+ this.nebulizationEfficiency = this.deviceStatus.body.nebulizationEfficiency;
429
+ this.parseStatus();
430
+ this.updateHomeKitCharacteristics();
431
+ } catch (e: any) {
432
+ this.errorLog(`Humidifier: ${this.accessory.displayName} error message: ${e.message}`);
433
+ }
434
+ });
435
+ });
436
+ req.on('error', (e: any) => {
437
+ this.errorLog(`Humidifier: ${this.accessory.displayName} error message: ${e.message}`);
438
+ });
439
+ req.end();
405
440
  } catch (e: any) {
406
441
  this.errorLog(`Humidifier: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
407
442
  if (this.deviceLogging.includes('debug')) {
@@ -457,7 +492,7 @@ export class Humidifier {
457
492
  `Humidifier: ${this.accessory.displayName} failed pushChanges with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
458
493
  );
459
494
  }
460
- if (this.platform.config.credentials?.openToken) {
495
+ if (this.platform.config.credentials?.token) {
461
496
  this.warnLog(`Humidifier: ${this.accessory.displayName} Using OpenAPI Connection`);
462
497
  await this.openAPIpushChanges();
463
498
  }
@@ -465,7 +500,7 @@ export class Humidifier {
465
500
  });
466
501
  } else {
467
502
  this.errorLog(`Humidifier: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
468
- if (this.platform.config.credentials?.openToken) {
503
+ if (this.platform.config.credentials?.token) {
469
504
  this.warnLog(`Humidifier: ${this.accessory.displayName} Using OpenAPI Connection`);
470
505
  await this.openAPIpushChanges();
471
506
  }
@@ -473,39 +508,55 @@ export class Humidifier {
473
508
  }
474
509
 
475
510
  async openAPIpushChanges(): Promise<void> {
476
- if (this.platform.config.credentials?.openToken) {
511
+ if (this.platform.config.credentials?.token) {
477
512
  this.debugLog(`Humidifier: ${this.accessory.displayName} OpenAPI pushChanges`);
478
513
  if (
479
514
  this.TargetHumidifierDehumidifierState === this.platform.Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER &&
480
515
  this.Active === this.platform.Characteristic.Active.ACTIVE
481
516
  ) {
482
- try {
483
- this.debugLog(`Pushing Manual: ${this.RelativeHumidityHumidifierThreshold}!`);
484
- const payload = {
485
- commandType: 'command',
486
- command: 'setMode',
487
- parameter: `${this.RelativeHumidityHumidifierThreshold}`,
488
- } as payload;
489
-
490
- this.infoLog(
491
- `Humidifier: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
492
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
493
- );
494
-
495
- // Make the API request
496
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
497
- this.debugLog(`Humidifier: ${this.accessory.displayName} pushChanges: ${JSON.stringify(push.data)}`);
498
- this.statusCode(push);
499
- } catch (e: any) {
500
- this.errorLog(`Humidifier: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection`);
501
- if (this.deviceLogging.includes('debug')) {
502
- this.errorLog(
503
- `Humidifier: ${this.accessory.displayName} failed pushChanges with OpenAPI Connection,` +
504
- ` Error Message: ${JSON.stringify(e.message)}`,
505
- );
506
- }
517
+ // Make Push On request to the API
518
+ const t = Date.now();
519
+ const nonce = 'requestID';
520
+ const data = this.platform.config.credentials?.token + t + nonce;
521
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
522
+ .update(Buffer.from(data, 'utf-8'))
523
+ .digest();
524
+ const sign = signTerm.toString('base64');
525
+ this.debugLog(`Humidifier: ${this.accessory.displayName} sign: ${sign}`);
526
+ this.debugLog(`Pushing Manual: ${this.RelativeHumidityHumidifierThreshold}!`);
527
+ const body = JSON.stringify({
528
+ 'command': 'setMode',
529
+ 'parameter': `${this.RelativeHumidityHumidifierThreshold}`,
530
+ 'commandType': 'command',
531
+ });
532
+ this.infoLog(`Humidifier: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
533
+ const options = {
534
+ hostname: HostDomain,
535
+ port: 443,
536
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
537
+ method: 'POST',
538
+ headers: {
539
+ 'Authorization': this.platform.config.credentials?.token,
540
+ 'sign': sign,
541
+ 'nonce': nonce,
542
+ 't': t,
543
+ 'Content-Type': 'application/json',
544
+ 'Content-Length': body.length,
545
+ },
546
+ };
547
+ const req = https.request(options, res => {
548
+ this.debugLog(`Humidifier: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
549
+ res.on('data', d => {
550
+ this.debugLog(`Humidifier: ${this.accessory.displayName} d: ${d}`);
551
+ });
552
+ });
553
+ req.on('error', (e: any) => {
554
+ this.errorLog(`Humidifier: ${this.accessory.displayName} error message: ${e.message}`);
507
555
  this.apiError(e);
508
- }
556
+ });
557
+ req.write(body);
558
+ req.end();
559
+ this.debugLog(`Humidifier: ${this.accessory.displayName} openAPIpushChanges: ${JSON.stringify(req)}`);
509
560
  } else if (
510
561
  this.TargetHumidifierDehumidifierState === this.platform.Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER &&
511
562
  this.Active === this.platform.Characteristic.Active.ACTIVE
@@ -526,22 +577,49 @@ export class Humidifier {
526
577
  this.TargetHumidifierDehumidifierState === this.platform.Characteristic.TargetHumidifierDehumidifierState.HUMIDIFIER_OR_DEHUMIDIFIER &&
527
578
  this.Active === this.platform.Characteristic.Active.ACTIVE
528
579
  ) {
580
+ // Make Push On request to the API
581
+ const t = Date.now();
582
+ const nonce = 'requestID';
583
+ const data = this.platform.config.credentials?.token + t + nonce;
584
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
585
+ .update(Buffer.from(data, 'utf-8'))
586
+ .digest();
587
+ const sign = signTerm.toString('base64');
588
+ this.debugLog(`Humidifier: ${this.accessory.displayName} sign: ${sign}`);
529
589
  this.debugLog('Pushing Auto!');
530
- const payload = {
531
- commandType: 'command',
532
- command: 'setMode',
533
- parameter: 'auto',
534
- } as payload;
535
-
536
- this.infoLog(
537
- `Humidifier: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
538
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
539
- );
540
-
541
- // Make the API request
542
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
543
- this.debugLog(`Humidifier: ${this.accessory.displayName} pushAutoChanges: ${JSON.stringify(push.data)}`);
544
- this.statusCode(push);
590
+ const body = JSON.stringify({
591
+ 'command': 'setMode',
592
+ 'parameter': 'auto',
593
+ 'commandType': 'command',
594
+ });
595
+ this.infoLog(`Humidifier: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
596
+ const options = {
597
+ hostname: HostDomain,
598
+ port: 443,
599
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
600
+ method: 'POST',
601
+ headers: {
602
+ 'Authorization': this.platform.config.credentials?.token,
603
+ 'sign': sign,
604
+ 'nonce': nonce,
605
+ 't': t,
606
+ 'Content-Type': 'application/json',
607
+ 'Content-Length': body.length,
608
+ },
609
+ };
610
+ const req = https.request(options, res => {
611
+ this.debugLog(`Humidifier: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
612
+ this.statusCode({ res });
613
+ res.on('data', d => {
614
+ this.debugLog(`Humidifier: ${this.accessory.displayName} d: ${d}`);
615
+ });
616
+ });
617
+ req.on('error', (e: any) => {
618
+ this.errorLog(`Humidifier: ${this.accessory.displayName} error message: ${e.message}`);
619
+ });
620
+ req.write(body);
621
+ req.end();
622
+ this.debugLog(`Humidifier: ${this.accessory.displayName} pushAutoChanges: ${JSON.stringify(req)}`);
545
623
  }
546
624
  } catch (e: any) {
547
625
  this.errorLog(`Humidifier: ${this.accessory.displayName} failed pushAutoChanges with OpenAPI Connection`);
@@ -561,22 +639,49 @@ export class Humidifier {
561
639
  async pushActiveChanges(): Promise<void> {
562
640
  try {
563
641
  if (this.Active === this.platform.Characteristic.Active.INACTIVE) {
642
+ // Make Push On request to the API
643
+ const t = Date.now();
644
+ const nonce = 'requestID';
645
+ const data = this.platform.config.credentials?.token + t + nonce;
646
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
647
+ .update(Buffer.from(data, 'utf-8'))
648
+ .digest();
649
+ const sign = signTerm.toString('base64');
650
+ this.debugLog(`Humidifier: ${this.accessory.displayName} sign: ${sign}`);
564
651
  this.debugLog('Pushing Off!');
565
- const payload = {
566
- commandType: 'command',
567
- command: 'turnOff',
568
- parameter: 'default',
569
- } as payload;
570
-
571
- this.infoLog(
572
- `Humidifier: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
573
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
574
- );
575
-
576
- // Make the API request
577
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
578
- this.debugLog(`Humidifier: ${this.accessory.displayName} pushActiveChanges: ${JSON.stringify(push.data)}`);
579
- this.statusCode(push);
652
+ const body = JSON.stringify({
653
+ 'command': 'turnOff',
654
+ 'parameter': 'default',
655
+ 'commandType': 'command',
656
+ });
657
+ this.infoLog(`Humidifier: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
658
+ const options = {
659
+ hostname: HostDomain,
660
+ port: 443,
661
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
662
+ method: 'POST',
663
+ headers: {
664
+ 'Authorization': this.platform.config.credentials?.token,
665
+ 'sign': sign,
666
+ 'nonce': nonce,
667
+ 't': t,
668
+ 'Content-Type': 'application/json',
669
+ 'Content-Length': body.length,
670
+ },
671
+ };
672
+ const req = https.request(options, res => {
673
+ this.debugLog(`Humidifier: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
674
+ this.statusCode({ res });
675
+ res.on('data', d => {
676
+ this.debugLog(`Humidifier: ${this.accessory.displayName} d: ${d}`);
677
+ });
678
+ });
679
+ req.on('error', (e: any) => {
680
+ this.errorLog(`Humidifier: ${this.accessory.displayName} error message: ${e.message}`);
681
+ });
682
+ req.write(body);
683
+ req.end();
684
+ this.debugLog(`Humidifier: ${this.accessory.displayName} pushActiveChanges: ${JSON.stringify(req)}`);
580
685
  }
581
686
  } catch (e: any) {
582
687
  this.errorLog(`Humidifier: ${this.accessory.displayName} failed pushActiveChanges with OpenAPI Connection`);
@@ -677,8 +782,8 @@ export class Humidifier {
677
782
  //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
678
783
  }
679
784
 
680
- async statusCode(push: AxiosResponse<{ statusCode: number }>): Promise<void> {
681
- switch (push.data.statusCode) {
785
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
786
+ switch (res.statusCode) {
682
787
  case 151:
683
788
  this.errorLog(`Humidifier: ${this.accessory.displayName} Command not supported by this device type.`);
684
789
  break;
@@ -699,7 +804,7 @@ export class Humidifier {
699
804
  case 190:
700
805
  this.errorLog(
701
806
  `Humidifier: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
702
- ` Or command: ${JSON.stringify(push.data)} format is invalid`,
807
+ ` Or command: ${JSON.stringify(res)} format is invalid`,
703
808
  );
704
809
  break;
705
810
  case 100:
@@ -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, deviceStatusResponse, payload, deviceStatus } from '../settings';
7
- import { Context } from 'vm';
9
+ import { device, devicesConfig, deviceStatus, HostDomain, DevicePath } from '../settings';
8
10
 
9
11
  export class Lock {
10
12
  // Services
@@ -19,7 +21,7 @@ export class Lock {
19
21
  // OpenAPI Others
20
22
  doorState!: deviceStatus['doorState'];
21
23
  lockState!: deviceStatus['lockState'];
22
- deviceStatus!: deviceStatusResponse;
24
+ deviceStatus!: any; //deviceStatusResponse;
23
25
 
24
26
  // Config
25
27
  scanDuration!: number;
@@ -151,12 +153,49 @@ export class Lock {
151
153
 
152
154
  async refreshStatus(): Promise<void> {
153
155
  try {
154
- this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
155
- this.debugLog(`Lock: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
156
- this.lockState = this.deviceStatus.body.lockState;
157
- this.doorState = this.deviceStatus.body.doorState;
158
- this.parseStatus();
159
- this.updateHomeKitCharacteristics();
156
+ const t = Date.now();
157
+ const nonce = 'requestID';
158
+ const data = this.platform.config.credentials?.token + t + nonce;
159
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
160
+ const sign = signTerm.toString('base64');
161
+ this.debugLog(`Lock: ${this.accessory.displayName} sign: ${sign}`);
162
+ const options = {
163
+ hostname: HostDomain,
164
+ port: 443,
165
+ path: `${DevicePath}/${this.device.deviceId}/status`,
166
+ method: 'GET',
167
+ headers: {
168
+ Authorization: this.platform.config.credentials?.token,
169
+ sign: sign,
170
+ nonce: nonce,
171
+ t: t,
172
+ 'Content-Type': 'application/json',
173
+ },
174
+ };
175
+ const req = https.request(options, (res) => {
176
+ this.debugLog(`Lock: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
177
+ let rawData = '';
178
+ res.on('data', (d) => {
179
+ rawData += d;
180
+ this.debugLog(`Lock: ${this.accessory.displayName} d: ${d}`);
181
+ });
182
+ res.on('end', () => {
183
+ try {
184
+ this.deviceStatus = JSON.parse(rawData);
185
+ this.debugLog(`Lock: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
186
+ this.lockState = this.deviceStatus.body.lockState;
187
+ this.doorState = this.deviceStatus.body.doorState;
188
+ this.parseStatus();
189
+ this.updateHomeKitCharacteristics();
190
+ } catch (e: any) {
191
+ this.errorLog(`Lock: ${this.accessory.displayName} error message: ${e.message}`);
192
+ }
193
+ });
194
+ });
195
+ req.on('error', (e: any) => {
196
+ this.errorLog(`Lock: ${this.accessory.displayName} error message: ${e.message}`);
197
+ });
198
+ req.end();
160
199
  } catch (e: any) {
161
200
  this.errorLog(`Lock: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
162
201
  if (this.deviceLogging.includes('debug')) {
@@ -175,26 +214,54 @@ export class Lock {
175
214
  * Lock - "command" "unlock" "default" = set to ???? state - LockCurrentState
176
215
  */
177
216
  async pushChanges(): Promise<void> {
178
- const payload = {
179
- commandType: 'command',
180
- parameter: 'default',
181
- } as payload;
182
-
217
+ // Make Push On request to the API
218
+ const t = Date.now();
219
+ const nonce = 'requestID';
220
+ const data = this.platform.config.credentials?.token + t + nonce;
221
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret)
222
+ .update(Buffer.from(data, 'utf-8'))
223
+ .digest();
224
+ const sign = signTerm.toString('base64');
225
+ this.debugLog(`Lock: ${this.accessory.displayName} sign: ${sign}`);
226
+ let command = '';
183
227
  if (this.LockTargetState) {
184
- payload.command = 'lock';
228
+ command = 'lock';
185
229
  } else {
186
- payload.command = 'unlock';
230
+ command = 'unlock';
187
231
  }
188
-
189
- this.infoLog(
190
- `Lock: ${this.accessory.displayName} Sending request to SwitchBot API. command: ${payload.command},` +
191
- ` parameter: ${payload.parameter}, commandType: ${payload.commandType}`,
192
- );
193
-
194
- // Make the API request
195
- const push: any = await this.platform.axios.post(`${DeviceURL}/${this.device.deviceId}/commands`, payload);
196
- this.debugLog(`Lock: ${this.accessory.displayName} pushchanges: ${JSON.stringify(push.data)}`);
197
- this.statusCode(push);
232
+ const body = JSON.stringify({
233
+ 'command': `${command}`,
234
+ 'parameter': 'default',
235
+ 'commandType': 'command',
236
+ });
237
+ this.infoLog(`Lock: ${this.accessory.displayName} Sending request to SwitchBot API. body: ${body},`);
238
+ const options = {
239
+ hostname: HostDomain,
240
+ port: 443,
241
+ path: `${DevicePath}/${this.device.deviceId}/commands`,
242
+ method: 'POST',
243
+ headers: {
244
+ 'Authorization': this.platform.config.credentials?.token,
245
+ 'sign': sign,
246
+ 'nonce': nonce,
247
+ 't': t,
248
+ 'Content-Type': 'application/json',
249
+ 'Content-Length': body.length,
250
+ },
251
+ };
252
+ const req = https.request(options, res => {
253
+ this.debugLog(`Lock: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
254
+ this.statusCode({ res });
255
+ res.on('data', d => {
256
+ this.debugLog(`Lock: ${this.accessory.displayName} d: ${d}`);
257
+ });
258
+ });
259
+ req.on('error', (e: any) => {
260
+ this.errorLog(`Lock: ${this.accessory.displayName} error message: ${e.message}`);
261
+ });
262
+ req.write(body);
263
+ req.end();
264
+ this.debugLog(`Lock: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
198
265
  this.accessory.context.On = this.LockTargetState;
199
266
  interval(5000)
200
267
  .pipe(take(1))
@@ -235,8 +302,8 @@ export class Lock {
235
302
  //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
236
303
  }
237
304
 
238
- async statusCode(push: AxiosResponse<{ statusCode: number }>): Promise<void> {
239
- switch (push.data.statusCode) {
305
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
306
+ switch (res.statusCode) {
240
307
  case 151:
241
308
  this.errorLog(`Lock: ${this.accessory.displayName} Command not supported by this device type.`);
242
309
  break;
@@ -255,7 +322,7 @@ export class Lock {
255
322
  case 190:
256
323
  this.errorLog(
257
324
  `Lock: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
258
- ` Or command: ${JSON.stringify(push.data)} format is invalid`,
325
+ ` Or command: ${JSON.stringify(res)} format is invalid`,
259
326
  );
260
327
  break;
261
328
  case 100:
@@ -1,12 +1,14 @@
1
+ import https from 'https';
2
+ import crypto from 'crypto';
3
+ import { Context } from 'vm';
4
+ import { hostname } from 'os';
5
+ import { MqttClient } from 'mqtt';
6
+ import { connectAsync } from 'async-mqtt';
1
7
  import { interval, Subject } from 'rxjs';
2
8
  import { skipWhile } from 'rxjs/operators';
3
9
  import { SwitchBotPlatform } from '../platform';
4
10
  import { Service, PlatformAccessory, Units, CharacteristicValue } from 'homebridge';
5
- import { DeviceURL, device, devicesConfig, serviceData, ad, switchbot, deviceStatusResponse, temperature, deviceStatus } from '../settings';
6
- import { Context } from 'vm';
7
- import { MqttClient } from 'mqtt';
8
- import { connectAsync } from 'async-mqtt';
9
- import { hostname } from 'os';
11
+ import { device, devicesConfig, serviceData, ad, switchbot, temperature, deviceStatus, HostDomain, DevicePath } from '../settings';
10
12
 
11
13
  /**
12
14
  * Platform Accessory
@@ -33,7 +35,7 @@ export class Meter {
33
35
  // OpenAPI Others
34
36
  Temperature: deviceStatus['temperature'];
35
37
  Humidity: deviceStatus['humidity'];
36
- deviceStatus!: deviceStatusResponse;
38
+ deviceStatus!: any; //deviceStatusResponse;
37
39
 
38
40
  // BLE Others
39
41
  connected?: boolean;
@@ -268,7 +270,7 @@ export class Meter {
268
270
  if (this.device.ble) {
269
271
  this.SwitchToOpenAPI = false;
270
272
  }
271
- if (this.platform.config.credentials?.openToken) {
273
+ if (this.platform.config.credentials?.token) {
272
274
  this.debugLog(`Meter: ${this.accessory.displayName} OpenAPI parseStatus`);
273
275
  // Current Relative Humidity
274
276
  if (!this.device.meter?.hide_humidity) {
@@ -364,7 +366,7 @@ export class Meter {
364
366
  `Meter: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` + ` Error Message: ${JSON.stringify(e.message)}`,
365
367
  );
366
368
  }
367
- if (this.platform.config.credentials?.openToken) {
369
+ if (this.platform.config.credentials?.token) {
368
370
  this.warnLog(`Meter: ${this.accessory.displayName} Using OpenAPI Connection`);
369
371
  this.SwitchToOpenAPI = true;
370
372
  this.openAPIRefreshStatus();
@@ -396,7 +398,7 @@ export class Meter {
396
398
 
397
399
  async BLEconnection(switchbot: any): Promise<void> {
398
400
  this.errorLog(`Meter: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
399
- if (this.platform.config.credentials?.openToken) {
401
+ if (this.platform.config.credentials?.token) {
400
402
  this.warnLog(`Meter: ${this.accessory.displayName} Using OpenAPI Connection`);
401
403
  this.SwitchToOpenAPI = true;
402
404
  await this.openAPIRefreshStatus();
@@ -404,15 +406,52 @@ export class Meter {
404
406
  }
405
407
 
406
408
  async openAPIRefreshStatus(): Promise<void> {
407
- if (this.platform.config.credentials?.openToken) {
409
+ if (this.platform.config.credentials?.token) {
408
410
  this.debugLog(`Meter: ${this.accessory.displayName} OpenAPI RefreshStatus`);
409
411
  try {
410
- this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
411
- this.debugLog(`Meter: ${this.accessory.displayName} openAPIRefreshStatus: ${JSON.stringify(this.deviceStatus)}`);
412
- this.Humidity = this.deviceStatus.body.humidity!;
413
- this.Temperature = this.deviceStatus.body.temperature!;
414
- this.parseStatus();
415
- this.updateHomeKitCharacteristics();
412
+ const t = Date.now();
413
+ const nonce = 'requestID';
414
+ const data = this.platform.config.credentials?.token + t + nonce;
415
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
416
+ const sign = signTerm.toString('base64');
417
+ this.debugLog(`Meter: ${this.accessory.displayName} sign: ${sign}`);
418
+ const options = {
419
+ hostname: HostDomain,
420
+ port: 443,
421
+ path: `${DevicePath}/${this.device.deviceId}/status`,
422
+ method: 'GET',
423
+ headers: {
424
+ Authorization: this.platform.config.credentials?.token,
425
+ sign: sign,
426
+ nonce: nonce,
427
+ t: t,
428
+ 'Content-Type': 'application/json',
429
+ },
430
+ };
431
+ const req = https.request(options, (res) => {
432
+ this.debugLog(`Meter: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
433
+ let rawData = '';
434
+ res.on('data', (d) => {
435
+ rawData += d;
436
+ this.debugLog(`Meter: ${this.accessory.displayName} d: ${d}`);
437
+ });
438
+ res.on('end', () => {
439
+ try {
440
+ this.deviceStatus = JSON.parse(rawData);
441
+ this.debugLog(`Meter: ${this.accessory.displayName} openAPIRefreshStatus: ${JSON.stringify(this.deviceStatus)}`);
442
+ this.Humidity = this.deviceStatus.body.humidity!;
443
+ this.Temperature = this.deviceStatus.body.temperature!;
444
+ this.parseStatus();
445
+ this.updateHomeKitCharacteristics();
446
+ } catch (e: any) {
447
+ this.errorLog(`Meter: ${this.accessory.displayName} error message: ${e.message}`);
448
+ }
449
+ });
450
+ });
451
+ req.on('error', (e: any) => {
452
+ this.errorLog(`Meter: ${this.accessory.displayName} error message: ${e.message}`);
453
+ });
454
+ req.end();
416
455
  } catch (e: any) {
417
456
  this.errorLog(`Meter: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
418
457
  if (this.deviceLogging.includes('debug')) {