@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.
- package/.github/ISSUE_TEMPLATE/bug-report.yml +1 -0
- package/.github/ISSUE_TEMPLATE/feature-request.yml +1 -0
- package/.github/ISSUE_TEMPLATE/support-request.yml +1 -0
- package/.prettierrc +1 -1
- package/CHANGELOG.md +9 -0
- package/config.schema.json +11 -4
- package/dist/device/bot.d.ts +8 -7
- package/dist/device/bot.d.ts.map +1 -1
- package/dist/device/bot.js +104 -28
- 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 +223 -58
- 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 +54 -11
- 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 +102 -28
- 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 +187 -66
- 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 +98 -22
- 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 +55 -12
- 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 +53 -10
- 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 +53 -13
- 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 +100 -24
- 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 +186 -47
- package/dist/device/striplight.js.map +1 -1
- package/dist/irdevice/airconditioner.d.ts +7 -6
- 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 +7 -6
- package/dist/irdevice/airpurifier.d.ts.map +1 -1
- package/dist/irdevice/airpurifier.js +46 -11
- package/dist/irdevice/airpurifier.js.map +1 -1
- package/dist/irdevice/camera.d.ts +7 -6
- 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 +8 -7
- 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 +7 -6
- 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 +7 -6
- 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 +8 -7
- 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 +7 -6
- 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 +7 -6
- 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 +10 -6
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +211 -93
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +4 -21
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +3 -3
- package/dist/settings.js.map +1 -1
- package/package.json +12 -12
- package/src/device/bot.ts +104 -37
- package/src/device/colorbulb.ts +227 -95
- package/src/device/contact.ts +53 -14
- package/src/device/curtain.ts +105 -38
- package/src/device/humidifier.ts +189 -84
- package/src/device/lock.ts +97 -30
- package/src/device/meter.ts +55 -16
- package/src/device/meterplus.ts +52 -13
- package/src/device/motion.ts +52 -16
- package/src/device/plug.ts +101 -33
- package/src/device/striplight.ts +189 -68
- package/src/irdevice/airconditioner.ts +44 -9
- package/src/irdevice/airpurifier.ts +52 -17
- package/src/irdevice/camera.ts +46 -11
- package/src/irdevice/fan.ts +50 -15
- package/src/irdevice/light.ts +48 -13
- package/src/irdevice/other.ts +46 -11
- package/src/irdevice/tv.ts +56 -21
- package/src/irdevice/vacuumcleaner.ts +46 -11
- package/src/irdevice/waterheater.ts +46 -11
- package/src/platform.ts +232 -107
- package/src/settings.ts +4 -25
package/src/device/humidifier.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, 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?.
|
|
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?.
|
|
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?.
|
|
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?.
|
|
390
|
+
if (this.platform.config.credentials?.token) {
|
|
389
391
|
this.debugLog(`Humidifier: ${this.accessory.displayName} OpenAPI refreshStatus`);
|
|
390
392
|
try {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
this.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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?.
|
|
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?.
|
|
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?.
|
|
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
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
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(
|
|
681
|
-
switch (
|
|
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(
|
|
807
|
+
` Or command: ${JSON.stringify(res)} format is invalid`,
|
|
703
808
|
);
|
|
704
809
|
break;
|
|
705
810
|
case 100:
|
package/src/device/lock.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, 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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
228
|
+
command = 'lock';
|
|
185
229
|
} else {
|
|
186
|
-
|
|
230
|
+
command = 'unlock';
|
|
187
231
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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(
|
|
239
|
-
switch (
|
|
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(
|
|
325
|
+
` Or command: ${JSON.stringify(res)} format is invalid`,
|
|
259
326
|
);
|
|
260
327
|
break;
|
|
261
328
|
case 100:
|
package/src/device/meter.ts
CHANGED
|
@@ -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 {
|
|
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?.
|
|
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?.
|
|
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?.
|
|
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?.
|
|
409
|
+
if (this.platform.config.credentials?.token) {
|
|
408
410
|
this.debugLog(`Meter: ${this.accessory.displayName} OpenAPI RefreshStatus`);
|
|
409
411
|
try {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
this.
|
|
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')) {
|