@switchbot/homebridge-switchbot 1.15.1-beta.7 → 1.15.1-beta.8
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.
- package/.prettierrc +1 -1
- package/dist/device/bot.d.ts +8 -7
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +83 -11
- package/dist/device/bot.js.map +1 -1
- package/dist/device/colorbulb.d.ts +8 -7
- package/dist/device/colorbulb.d.ts.map +1 -1
- package/dist/device/colorbulb.js +182 -23
- package/dist/device/colorbulb.js.map +1 -1
- package/dist/device/contact.d.ts +3 -3
- package/dist/device/contact.d.ts.map +1 -1
- package/dist/device/contact.js +50 -7
- package/dist/device/contact.js.map +1 -1
- package/dist/device/curtain.d.ts +9 -8
- package/dist/device/curtain.d.ts.map +1 -1
- package/dist/device/curtain.js +86 -14
- package/dist/device/curtain.js.map +1 -1
- package/dist/device/humidifier.d.ts +8 -7
- package/dist/device/humidifier.d.ts.map +1 -1
- package/dist/device/humidifier.js +152 -27
- package/dist/device/humidifier.js.map +1 -1
- package/dist/device/lock.d.ts +8 -7
- package/dist/device/lock.d.ts.map +1 -1
- package/dist/device/lock.js +84 -12
- package/dist/device/lock.js.map +1 -1
- package/dist/device/meter.d.ts +4 -4
- package/dist/device/meter.d.ts.map +1 -1
- package/dist/device/meter.js +51 -8
- package/dist/device/meter.js.map +1 -1
- package/dist/device/meterplus.d.ts +3 -3
- package/dist/device/meterplus.d.ts.map +1 -1
- package/dist/device/meterplus.js +49 -6
- package/dist/device/meterplus.js.map +1 -1
- package/dist/device/motion.d.ts +3 -3
- package/dist/device/motion.d.ts.map +1 -1
- package/dist/device/motion.js +49 -9
- package/dist/device/motion.js.map +1 -1
- package/dist/device/plug.d.ts +8 -7
- package/dist/device/plug.d.ts.map +1 -1
- package/dist/device/plug.js +83 -11
- package/dist/device/plug.js.map +1 -1
- package/dist/device/striplight.d.ts +8 -7
- package/dist/device/striplight.d.ts.map +1 -1
- package/dist/device/striplight.js +149 -19
- package/dist/device/striplight.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +5 -4
- package/dist/irdevice/airconditioner.d.ts.map +1 -1
- package/dist/irdevice/airconditioner.js +40 -6
- package/dist/irdevice/airconditioner.js.map +1 -1
- package/dist/irdevice/airpurifier.d.ts +5 -4
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +40 -6
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +5 -4
- package/dist/irdevice/camera.d.ts.map +1 -1
- package/dist/irdevice/camera.js +40 -6
- package/dist/irdevice/camera.js.map +1 -1
- package/dist/irdevice/fan.d.ts +7 -6
- package/dist/irdevice/fan.d.ts.map +1 -1
- package/dist/irdevice/fan.js +40 -6
- package/dist/irdevice/fan.js.map +1 -1
- package/dist/irdevice/light.d.ts +5 -4
- package/dist/irdevice/light.d.ts.map +1 -1
- package/dist/irdevice/light.js +40 -6
- package/dist/irdevice/light.js.map +1 -1
- package/dist/irdevice/other.d.ts +5 -4
- package/dist/irdevice/other.d.ts.map +1 -1
- package/dist/irdevice/other.js +40 -6
- package/dist/irdevice/other.js.map +1 -1
- package/dist/irdevice/tv.d.ts +7 -6
- package/dist/irdevice/tv.d.ts.map +1 -1
- package/dist/irdevice/tv.js +40 -6
- package/dist/irdevice/tv.js.map +1 -1
- package/dist/irdevice/vacuumcleaner.d.ts +5 -4
- package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
- package/dist/irdevice/vacuumcleaner.js +40 -6
- package/dist/irdevice/vacuumcleaner.js.map +1 -1
- package/dist/irdevice/waterheater.d.ts +5 -4
- package/dist/irdevice/waterheater.d.ts.map +1 -1
- package/dist/irdevice/waterheater.js +40 -6
- package/dist/irdevice/waterheater.js.map +1 -1
- package/dist/platform.d.ts +3 -5
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +141 -95
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +2 -16
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +3 -3
- package/dist/settings.js.map +1 -1
- package/package.json +6 -7
- package/src/device/bot.ts +87 -15
- package/src/device/colorbulb.ts +186 -41
- package/src/device/contact.ts +49 -10
- package/src/device/curtain.ts +92 -19
- package/src/device/humidifier.ts +164 -30
- package/src/device/lock.ts +88 -16
- package/src/device/meter.ts +51 -12
- package/src/device/meterplus.ts +48 -9
- package/src/device/motion.ts +48 -12
- package/src/device/plug.ts +87 -15
- package/src/device/striplight.ts +161 -24
- package/src/irdevice/airconditioner.ts +43 -8
- package/src/irdevice/airpurifier.ts +43 -8
- package/src/irdevice/camera.ts +43 -8
- package/src/irdevice/fan.ts +44 -9
- package/src/irdevice/light.ts +43 -8
- package/src/irdevice/other.ts +43 -8
- package/src/irdevice/tv.ts +44 -9
- package/src/irdevice/vacuumcleaner.ts +43 -8
- package/src/irdevice/waterheater.ts +43 -8
- package/src/platform.ts +154 -108
- package/src/settings.ts +6 -10
package/src/device/bot.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import
|
|
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 {
|
|
7
|
-
import { Context } from 'vm';
|
|
9
|
+
import { device, devicesConfig, deviceStatus, ad, serviceData, switchbot, payload, 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
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
this.
|
|
562
|
-
|
|
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')) {
|
|
@@ -727,9 +766,42 @@ export class Bot {
|
|
|
727
766
|
);
|
|
728
767
|
|
|
729
768
|
// Make the API request
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
this.
|
|
769
|
+
const t = Date.now();
|
|
770
|
+
const nonce = 'requestID';
|
|
771
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
772
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
773
|
+
const sign = signTerm.toString('base64');
|
|
774
|
+
this.debugLog(`Bot: ${this.accessory.displayName} sign: ${sign}`);
|
|
775
|
+
const options = {
|
|
776
|
+
hostname: HostDomain,
|
|
777
|
+
port: 443,
|
|
778
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
779
|
+
method: 'POST',
|
|
780
|
+
headers: {
|
|
781
|
+
Authorization: this.platform.config.credentials?.token,
|
|
782
|
+
sign: sign,
|
|
783
|
+
nonce: nonce,
|
|
784
|
+
t: t,
|
|
785
|
+
'Content-Type': 'application/json',
|
|
786
|
+
},
|
|
787
|
+
};
|
|
788
|
+
|
|
789
|
+
const req = https.request(options, (res) => {
|
|
790
|
+
this.debugLog(`Bot: ${this.accessory.displayName} Push statusCode: ${res.statusCode}`);
|
|
791
|
+
this.statusCode({ res });
|
|
792
|
+
res.on('data', (d) => {
|
|
793
|
+
this.debugLog(`d: ${d}`);
|
|
794
|
+
});
|
|
795
|
+
});
|
|
796
|
+
|
|
797
|
+
req.on('error', (error) => {
|
|
798
|
+
this.errorLog(`Bot: ${this.accessory.displayName} error: ${error}`);
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
req.write(payload);
|
|
802
|
+
req.end();
|
|
803
|
+
|
|
804
|
+
this.debugLog(`Bot: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
|
|
733
805
|
this.OnCached = this.On;
|
|
734
806
|
this.accessory.context.On = this.OnCached;
|
|
735
807
|
}
|
|
@@ -977,8 +1049,8 @@ export class Bot {
|
|
|
977
1049
|
//throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
|
978
1050
|
}
|
|
979
1051
|
|
|
980
|
-
async statusCode(
|
|
981
|
-
switch (
|
|
1052
|
+
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
1053
|
+
switch (res.statusCode) {
|
|
982
1054
|
case 151:
|
|
983
1055
|
this.errorLog(`Bot: ${this.accessory.displayName} Command not supported by this device type.`);
|
|
984
1056
|
break;
|
|
@@ -999,7 +1071,7 @@ export class Bot {
|
|
|
999
1071
|
case 190:
|
|
1000
1072
|
this.errorLog(
|
|
1001
1073
|
`Bot: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
1002
|
-
` Or command: ${JSON.stringify(
|
|
1074
|
+
` Or command: ${JSON.stringify(res)} format is invalid`,
|
|
1003
1075
|
);
|
|
1004
1076
|
break;
|
|
1005
1077
|
case 100:
|
package/src/device/colorbulb.ts
CHANGED
|
@@ -1,23 +1,12 @@
|
|
|
1
|
-
import
|
|
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, payload, 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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
this.
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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')) {
|
|
@@ -471,9 +496,39 @@ export class ColorBulb {
|
|
|
471
496
|
);
|
|
472
497
|
|
|
473
498
|
// Make the API request
|
|
474
|
-
const
|
|
475
|
-
|
|
476
|
-
this.
|
|
499
|
+
const t = Date.now();
|
|
500
|
+
const nonce = 'requestID';
|
|
501
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
502
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
503
|
+
const sign = signTerm.toString('base64');
|
|
504
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
|
|
505
|
+
const options = {
|
|
506
|
+
hostname: HostDomain,
|
|
507
|
+
port: 443,
|
|
508
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
509
|
+
method: 'POST',
|
|
510
|
+
headers: {
|
|
511
|
+
Authorization: this.platform.config.credentials?.token,
|
|
512
|
+
sign: sign,
|
|
513
|
+
nonce: nonce,
|
|
514
|
+
t: t,
|
|
515
|
+
'Content-Type': 'application/json',
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
const req = https.request(options, (res) => {
|
|
519
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
520
|
+
this.statusCode({ res });
|
|
521
|
+
res.on('data', (d) => {
|
|
522
|
+
this.debugLog(`d: ${d}`);
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
req.on('error', (error) => {
|
|
526
|
+
this.errorLog(`Color Bulb: ${this.accessory.displayName} error: ${error}`);
|
|
527
|
+
});
|
|
528
|
+
req.write(payload);
|
|
529
|
+
req.end();
|
|
530
|
+
|
|
531
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(req)}`);
|
|
477
532
|
this.OnCached = this.On;
|
|
478
533
|
this.accessory.context.On = this.OnCached;
|
|
479
534
|
}
|
|
@@ -523,9 +578,39 @@ export class ColorBulb {
|
|
|
523
578
|
);
|
|
524
579
|
|
|
525
580
|
// Make the API request
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
this.
|
|
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).update(Buffer.from(data, 'utf-8')).digest();
|
|
585
|
+
const sign = signTerm.toString('base64');
|
|
586
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
|
|
587
|
+
const options = {
|
|
588
|
+
hostname: HostDomain,
|
|
589
|
+
port: 443,
|
|
590
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
591
|
+
method: 'POST',
|
|
592
|
+
headers: {
|
|
593
|
+
Authorization: this.platform.config.credentials?.token,
|
|
594
|
+
sign: sign,
|
|
595
|
+
nonce: nonce,
|
|
596
|
+
t: t,
|
|
597
|
+
'Content-Type': 'application/json',
|
|
598
|
+
},
|
|
599
|
+
};
|
|
600
|
+
const req = https.request(options, (res) => {
|
|
601
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
602
|
+
this.statusCode({ res });
|
|
603
|
+
res.on('data', (d) => {
|
|
604
|
+
this.debugLog(`d: ${d}`);
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
req.on('error', (error) => {
|
|
608
|
+
this.errorLog(`Color Bulb: ${this.accessory.displayName} error: ${error}`);
|
|
609
|
+
});
|
|
610
|
+
req.write(payload);
|
|
611
|
+
req.end();
|
|
612
|
+
|
|
613
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(req)}`);
|
|
529
614
|
this.HueCached = this.Hue;
|
|
530
615
|
this.SaturationCached = this.Saturation;
|
|
531
616
|
} else {
|
|
@@ -563,9 +648,39 @@ export class ColorBulb {
|
|
|
563
648
|
);
|
|
564
649
|
|
|
565
650
|
// Make the API request
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
this.
|
|
651
|
+
const t = Date.now();
|
|
652
|
+
const nonce = 'requestID';
|
|
653
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
654
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
655
|
+
const sign = signTerm.toString('base64');
|
|
656
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
|
|
657
|
+
const options = {
|
|
658
|
+
hostname: HostDomain,
|
|
659
|
+
port: 443,
|
|
660
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
661
|
+
method: 'POST',
|
|
662
|
+
headers: {
|
|
663
|
+
Authorization: this.platform.config.credentials?.token,
|
|
664
|
+
sign: sign,
|
|
665
|
+
nonce: nonce,
|
|
666
|
+
t: t,
|
|
667
|
+
'Content-Type': 'application/json',
|
|
668
|
+
},
|
|
669
|
+
};
|
|
670
|
+
const req = https.request(options, (res) => {
|
|
671
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
672
|
+
this.statusCode({ res });
|
|
673
|
+
res.on('data', (d) => {
|
|
674
|
+
this.debugLog(`d: ${d}`);
|
|
675
|
+
});
|
|
676
|
+
});
|
|
677
|
+
req.on('error', (error) => {
|
|
678
|
+
this.errorLog(`Color Bulb: ${this.accessory.displayName} error: ${error}`);
|
|
679
|
+
});
|
|
680
|
+
req.write(payload);
|
|
681
|
+
req.end();
|
|
682
|
+
|
|
683
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(req)}`);
|
|
569
684
|
this.ColorTemperatureCached = this.ColorTemperature;
|
|
570
685
|
} else {
|
|
571
686
|
this.debugLog(
|
|
@@ -599,9 +714,39 @@ export class ColorBulb {
|
|
|
599
714
|
);
|
|
600
715
|
|
|
601
716
|
// Make the API request
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
this.
|
|
717
|
+
const t = Date.now();
|
|
718
|
+
const nonce = 'requestID';
|
|
719
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
720
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
721
|
+
const sign = signTerm.toString('base64');
|
|
722
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} sign: ${sign}`);
|
|
723
|
+
const options = {
|
|
724
|
+
hostname: HostDomain,
|
|
725
|
+
port: 443,
|
|
726
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
727
|
+
method: 'POST',
|
|
728
|
+
headers: {
|
|
729
|
+
Authorization: this.platform.config.credentials?.token,
|
|
730
|
+
sign: sign,
|
|
731
|
+
nonce: nonce,
|
|
732
|
+
t: t,
|
|
733
|
+
'Content-Type': 'application/json',
|
|
734
|
+
},
|
|
735
|
+
};
|
|
736
|
+
const req = https.request(options, (res) => {
|
|
737
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
738
|
+
this.statusCode({ res });
|
|
739
|
+
res.on('data', (d) => {
|
|
740
|
+
this.debugLog(`d: ${d}`);
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
req.on('error', (error) => {
|
|
744
|
+
this.errorLog(`Color Bulb: ${this.accessory.displayName} error: ${error}`);
|
|
745
|
+
});
|
|
746
|
+
req.write(payload);
|
|
747
|
+
req.end();
|
|
748
|
+
|
|
749
|
+
this.debugLog(`Color Bulb: ${this.accessory.displayName} pushChanges: ${JSON.stringify(req)}`);
|
|
605
750
|
this.BrightnessCached = this.Brightness;
|
|
606
751
|
} else {
|
|
607
752
|
this.debugLog(
|
|
@@ -661,8 +806,8 @@ export class ColorBulb {
|
|
|
661
806
|
//throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
|
662
807
|
}
|
|
663
808
|
|
|
664
|
-
statusCode(
|
|
665
|
-
switch (
|
|
809
|
+
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
810
|
+
switch (res.statusCode) {
|
|
666
811
|
case 151:
|
|
667
812
|
this.errorLog(`Color Bulb: ${this.accessory.displayName} Command not supported by this device type.`);
|
|
668
813
|
break;
|
|
@@ -683,7 +828,7 @@ export class ColorBulb {
|
|
|
683
828
|
case 190:
|
|
684
829
|
this.errorLog(
|
|
685
830
|
`Color Bulb: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
686
|
-
` Or command: ${JSON.stringify(
|
|
831
|
+
` Or command: ${JSON.stringify(res)} format is invalid`,
|
|
687
832
|
);
|
|
688
833
|
break;
|
|
689
834
|
case 100:
|
package/src/device/contact.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
this.
|
|
383
|
-
|
|
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')) {
|
package/src/device/curtain.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import https from 'https';
|
|
2
|
+
import crypto from 'crypto';
|
|
3
|
+
import { Context } from 'vm';
|
|
4
|
+
import { MqttClient } from 'mqtt';
|
|
5
|
+
import { IncomingMessage } from 'http';
|
|
2
6
|
import { interval, Subject } from 'rxjs';
|
|
7
|
+
import { connectAsync } from 'async-mqtt';
|
|
3
8
|
import { SwitchBotPlatform } from '../platform';
|
|
4
9
|
import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
|
|
5
10
|
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
6
|
-
import {
|
|
7
|
-
import { Context } from 'vm';
|
|
8
|
-
import { MqttClient } from 'mqtt';
|
|
9
|
-
import { connectAsync } from 'async-mqtt';
|
|
11
|
+
import { device, devicesConfig, serviceData, switchbot, payload, deviceStatus, ad, HostDomain, DevicePath } from '../settings';
|
|
10
12
|
|
|
11
13
|
export class Curtain {
|
|
12
14
|
// Services
|
|
@@ -23,7 +25,7 @@ export class Curtain {
|
|
|
23
25
|
StatusLowBattery?: CharacteristicValue;
|
|
24
26
|
|
|
25
27
|
// OpenAPI Others
|
|
26
|
-
deviceStatus!: deviceStatusResponse;
|
|
28
|
+
deviceStatus!: any; //deviceStatusResponse;
|
|
27
29
|
slidePosition: deviceStatus['slidePosition'];
|
|
28
30
|
moving: deviceStatus['moving'];
|
|
29
31
|
brightness: deviceStatus['brightness'];
|
|
@@ -532,13 +534,51 @@ export class Curtain {
|
|
|
532
534
|
if (this.platform.config.credentials?.token) {
|
|
533
535
|
this.debugLog(`Curtain: ${this.accessory.displayName} OpenAPI refreshStatus`);
|
|
534
536
|
try {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
this.
|
|
541
|
-
|
|
537
|
+
const t = Date.now();
|
|
538
|
+
const nonce = 'requestID';
|
|
539
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
540
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
541
|
+
const sign = signTerm.toString('base64');
|
|
542
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} sign: ${sign}`);
|
|
543
|
+
const options = {
|
|
544
|
+
hostname: HostDomain,
|
|
545
|
+
port: 443,
|
|
546
|
+
path: `${DevicePath}/${this.device.deviceId}/status`,
|
|
547
|
+
method: 'GET',
|
|
548
|
+
headers: {
|
|
549
|
+
Authorization: this.platform.config.credentials?.token,
|
|
550
|
+
sign: sign,
|
|
551
|
+
nonce: nonce,
|
|
552
|
+
t: t,
|
|
553
|
+
'Content-Type': 'application/json',
|
|
554
|
+
},
|
|
555
|
+
};
|
|
556
|
+
const req = https.request(options, (res) => {
|
|
557
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
558
|
+
let rawData = '';
|
|
559
|
+
res.on('data', (d) => {
|
|
560
|
+
rawData += d;
|
|
561
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} d: ${d}`);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
res.on('end', () => {
|
|
565
|
+
try {
|
|
566
|
+
this.deviceStatus = JSON.parse(rawData);
|
|
567
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
|
|
568
|
+
this.slidePosition = this.deviceStatus.body.slidePosition;
|
|
569
|
+
this.moving = this.deviceStatus.body.moving;
|
|
570
|
+
this.brightness = this.deviceStatus.body.brightness;
|
|
571
|
+
this.parseStatus();
|
|
572
|
+
this.updateHomeKitCharacteristics();
|
|
573
|
+
} catch (e: any) {
|
|
574
|
+
this.errorLog(`Curtain: ${this.accessory.displayName} error message: ${e.message}`);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
req.on('error', (e: any) => {
|
|
579
|
+
this.errorLog(`Curtain: ${this.accessory.displayName} error message: ${e.message}`);
|
|
580
|
+
});
|
|
581
|
+
req.end();
|
|
542
582
|
} catch (e: any) {
|
|
543
583
|
this.errorLog(`Curtain: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
|
|
544
584
|
if (this.deviceLogging.includes('debug')) {
|
|
@@ -667,9 +707,42 @@ export class Curtain {
|
|
|
667
707
|
);
|
|
668
708
|
|
|
669
709
|
// Make the API request
|
|
670
|
-
const
|
|
671
|
-
|
|
672
|
-
this.
|
|
710
|
+
const t = Date.now();
|
|
711
|
+
const nonce = 'requestID';
|
|
712
|
+
const data = this.platform.config.credentials?.token + t + nonce;
|
|
713
|
+
const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
|
|
714
|
+
const sign = signTerm.toString('base64');
|
|
715
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} sign: ${sign}`);
|
|
716
|
+
const options = {
|
|
717
|
+
hostname: HostDomain,
|
|
718
|
+
port: 443,
|
|
719
|
+
path: `${DevicePath}/${this.device.deviceId}/commands`,
|
|
720
|
+
method: 'POST',
|
|
721
|
+
headers: {
|
|
722
|
+
Authorization: this.platform.config.credentials?.token,
|
|
723
|
+
sign: sign,
|
|
724
|
+
nonce: nonce,
|
|
725
|
+
t: t,
|
|
726
|
+
'Content-Type': 'application/json',
|
|
727
|
+
},
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
const req = https.request(options, (res) => {
|
|
731
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
|
|
732
|
+
this.statusCode({ res });
|
|
733
|
+
res.on('data', (d) => {
|
|
734
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} d: ${d}`);
|
|
735
|
+
});
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
req.on('error', (error) => {
|
|
739
|
+
this.errorLog(`Curtain: ${this.accessory.displayName} error: ${error}`);
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
req.write(payload);
|
|
743
|
+
req.end();
|
|
744
|
+
|
|
745
|
+
this.debugLog(`Curtain: ${this.accessory.displayName} pushchanges: ${JSON.stringify(req)}`);
|
|
673
746
|
} else {
|
|
674
747
|
this.debugLog(
|
|
675
748
|
`Curtain: ${this.accessory.displayName} No OpenAPI Changes, CurrentPosition & TargetPosition Are the Same.` +
|
|
@@ -752,8 +825,8 @@ export class Curtain {
|
|
|
752
825
|
//throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
|
|
753
826
|
}
|
|
754
827
|
|
|
755
|
-
async statusCode(
|
|
756
|
-
switch (
|
|
828
|
+
async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
|
|
829
|
+
switch (res.statusCode) {
|
|
757
830
|
case 151:
|
|
758
831
|
this.errorLog(`Curtain: ${this.accessory.displayName} Command not supported by this device type.`);
|
|
759
832
|
break;
|
|
@@ -772,7 +845,7 @@ export class Curtain {
|
|
|
772
845
|
case 190:
|
|
773
846
|
this.errorLog(
|
|
774
847
|
`Curtain: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
|
|
775
|
-
` Or command: ${JSON.stringify(
|
|
848
|
+
` Or command: ${JSON.stringify(res)} format is invalid`,
|
|
776
849
|
);
|
|
777
850
|
break;
|
|
778
851
|
case 100:
|