@switchbot/homebridge-switchbot 0.2.0-alpha.2 → 1.0.1-beta.2
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/workflows/nodejs-beta.yml +1 -1
- package/.github/workflows/nodejs.yml +1 -1
- package/.github/workflows/{prerelease.js → prerelease-beta.js} +0 -0
- package/CHANGELOG.md +1 -1
- package/README.md +9 -5
- package/config.schema.json +370 -142
- package/dist/devices/bots.d.ts +18 -34
- package/dist/devices/bots.d.ts.map +1 -1
- package/dist/devices/bots.js +166 -171
- package/dist/devices/bots.js.map +1 -1
- package/dist/devices/{bulb.d.ts → colorbulb.d.ts} +12 -19
- package/dist/devices/colorbulb.d.ts.map +1 -0
- package/dist/devices/{bulb.js → colorbulb.js} +34 -32
- package/dist/devices/colorbulb.js.map +1 -0
- package/dist/devices/contact.d.ts +18 -16
- package/dist/devices/contact.d.ts.map +1 -1
- package/dist/devices/contact.js +101 -44
- package/dist/devices/contact.js.map +1 -1
- package/dist/devices/curtains.d.ts +17 -51
- package/dist/devices/curtains.d.ts.map +1 -1
- package/dist/devices/curtains.js +170 -248
- package/dist/devices/curtains.js.map +1 -1
- package/dist/devices/humidifiers.d.ts +13 -4
- package/dist/devices/humidifiers.d.ts.map +1 -1
- package/dist/devices/humidifiers.js +81 -8
- package/dist/devices/humidifiers.js.map +1 -1
- package/dist/devices/indoorcam.d.ts +6 -13
- package/dist/devices/indoorcam.d.ts.map +1 -1
- package/dist/devices/indoorcam.js.map +1 -1
- package/dist/devices/meters.d.ts +12 -15
- package/dist/devices/meters.d.ts.map +1 -1
- package/dist/devices/meters.js +38 -44
- package/dist/devices/meters.js.map +1 -1
- package/dist/devices/motion.d.ts +17 -15
- package/dist/devices/motion.d.ts.map +1 -1
- package/dist/devices/motion.js +87 -40
- package/dist/devices/motion.js.map +1 -1
- package/dist/devices/plugs.d.ts +6 -13
- package/dist/devices/plugs.d.ts.map +1 -1
- package/dist/devices/plugs.js.map +1 -1
- package/dist/irdevices/airconditioners.d.ts +10 -10
- package/dist/irdevices/airconditioners.d.ts.map +1 -1
- package/dist/irdevices/airconditioners.js +29 -9
- package/dist/irdevices/airconditioners.js.map +1 -1
- package/dist/irdevices/airpurifiers.d.ts +11 -11
- package/dist/irdevices/airpurifiers.d.ts.map +1 -1
- package/dist/irdevices/airpurifiers.js.map +1 -1
- package/dist/irdevices/cameras.d.ts +3 -3
- package/dist/irdevices/cameras.d.ts.map +1 -1
- package/dist/irdevices/cameras.js.map +1 -1
- package/dist/irdevices/fans.d.ts +6 -6
- package/dist/irdevices/fans.d.ts.map +1 -1
- package/dist/irdevices/fans.js +10 -10
- package/dist/irdevices/fans.js.map +1 -1
- package/dist/irdevices/lights.d.ts +3 -3
- package/dist/irdevices/lights.d.ts.map +1 -1
- package/dist/irdevices/lights.js.map +1 -1
- package/dist/irdevices/others.d.ts +3 -3
- package/dist/irdevices/others.d.ts.map +1 -1
- package/dist/irdevices/others.js.map +1 -1
- package/dist/irdevices/tvs.d.ts +3 -3
- package/dist/irdevices/tvs.d.ts.map +1 -1
- package/dist/irdevices/tvs.js +7 -5
- package/dist/irdevices/tvs.js.map +1 -1
- package/dist/irdevices/vacuumcleaners.d.ts +3 -3
- package/dist/irdevices/vacuumcleaners.d.ts.map +1 -1
- package/dist/irdevices/vacuumcleaners.js.map +1 -1
- package/dist/irdevices/waterheaters.d.ts +3 -3
- package/dist/irdevices/waterheaters.d.ts.map +1 -1
- package/dist/irdevices/waterheaters.js.map +1 -1
- package/dist/platform.d.ts +3 -2
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +136 -46
- package/dist/platform.js.map +1 -1
- package/dist/settings.d.ts +51 -8
- package/dist/settings.d.ts.map +1 -1
- package/package.json +65 -65
- package/src/devices/bots.ts +188 -193
- package/src/devices/{bulb.ts → colorbulb.ts} +46 -51
- package/src/devices/contact.ts +124 -68
- package/src/devices/curtains.ts +192 -300
- package/src/devices/humidifiers.ts +97 -14
- package/src/devices/indoorcam.ts +10 -20
- package/src/devices/meters.ts +57 -69
- package/src/devices/motion.ts +108 -62
- package/src/devices/plugs.ts +8 -19
- package/src/irdevices/airconditioners.ts +43 -20
- package/src/irdevices/airpurifiers.ts +15 -11
- package/src/irdevices/cameras.ts +5 -3
- package/src/irdevices/fans.ts +22 -16
- package/src/irdevices/lights.ts +5 -3
- package/src/irdevices/others.ts +5 -3
- package/src/irdevices/tvs.ts +13 -7
- package/src/irdevices/vacuumcleaners.ts +5 -3
- package/src/irdevices/waterheaters.ts +5 -3
- package/src/platform.ts +148 -49
- package/src/settings.ts +80 -8
- package/dist/devices/bulb.d.ts.map +0 -1
- package/dist/devices/bulb.js.map +0 -1
|
@@ -1,46 +1,34 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { PlatformAccessory, CharacteristicValue
|
|
2
|
+
import { PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
3
3
|
import { SwitchBotPlatform } from '../platform';
|
|
4
|
-
import {
|
|
4
|
+
import { Subject } from 'rxjs';
|
|
5
|
+
import { device, devicesConfig, serviceData, switchbot, deviceStatusResponse } from '../settings';
|
|
5
6
|
export declare class Curtain {
|
|
6
7
|
private readonly platform;
|
|
7
8
|
private accessory;
|
|
8
9
|
device: device & devicesConfig;
|
|
9
10
|
private service;
|
|
10
11
|
private lightSensorService;
|
|
12
|
+
private batteryService?;
|
|
11
13
|
CurrentPosition: CharacteristicValue;
|
|
12
14
|
PositionState: CharacteristicValue;
|
|
13
15
|
TargetPosition: CharacteristicValue;
|
|
14
16
|
CurrentAmbientLightLevel: CharacteristicValue;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
setNewTargetTimer: NodeJS.Timeout;
|
|
19
|
-
AutoDisableFastScanTimeoutId: NodeJS.Timeout;
|
|
17
|
+
BatteryLevel?: CharacteristicValue;
|
|
18
|
+
StatusLowBattery?: CharacteristicValue;
|
|
19
|
+
deviceStatus: deviceStatusResponse;
|
|
20
20
|
setNewTarget: boolean;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
PreviousPosition: any;
|
|
29
|
-
Position: any;
|
|
30
|
-
FastScanDuration: number | undefined;
|
|
21
|
+
setNewTargetTimer: NodeJS.Timeout;
|
|
22
|
+
switchbot: switchbot;
|
|
23
|
+
serviceData: serviceData;
|
|
24
|
+
calibration: serviceData['calibration'];
|
|
25
|
+
battery: serviceData['battery'];
|
|
26
|
+
position: serviceData['position'];
|
|
27
|
+
lightLevel: serviceData['lightLevel'];
|
|
31
28
|
set_minStep: number;
|
|
32
29
|
refreshRate: number;
|
|
33
|
-
switchbot: {
|
|
34
|
-
discover: (arg0: {
|
|
35
|
-
duration: any;
|
|
36
|
-
model: string;
|
|
37
|
-
quick: boolean;
|
|
38
|
-
id: MacAddress;
|
|
39
|
-
}) => Promise<any>;
|
|
40
|
-
wait: (arg0: number) => any;
|
|
41
|
-
};
|
|
42
30
|
curtainUpdateInProgress: boolean;
|
|
43
|
-
doCurtainUpdate:
|
|
31
|
+
doCurtainUpdate: Subject<void>;
|
|
44
32
|
constructor(platform: SwitchBotPlatform, accessory: PlatformAccessory, device: device & devicesConfig);
|
|
45
33
|
private curtainRefreshRate;
|
|
46
34
|
private minStep;
|
|
@@ -48,7 +36,8 @@ export declare class Curtain {
|
|
|
48
36
|
private BLEparseStatus;
|
|
49
37
|
private openAPIparseStatus;
|
|
50
38
|
refreshStatus(): Promise<void>;
|
|
51
|
-
private
|
|
39
|
+
private connectBLE;
|
|
40
|
+
private BLERefreshStatus;
|
|
52
41
|
private openAPIRefreshStatus;
|
|
53
42
|
pushChanges(): Promise<void>;
|
|
54
43
|
private BLEpushChanges;
|
|
@@ -60,29 +49,6 @@ export declare class Curtain {
|
|
|
60
49
|
* Handle requests to set the value of the "Target Position" characteristic
|
|
61
50
|
*/
|
|
62
51
|
TargetPositionSet(value: CharacteristicValue): void;
|
|
63
|
-
/**
|
|
64
|
-
* Convert to/from device/HomeKit's position, since:
|
|
65
|
-
*
|
|
66
|
-
* - opened is 0% in HomeKit and 100% in Curtain device.
|
|
67
|
-
* - closed is 100% in HomeKit, 0% in Curtain device.
|
|
68
|
-
*/
|
|
69
|
-
convertFromHomeKitPosition(n: number): number;
|
|
70
|
-
/**
|
|
71
|
-
* Ask the device to start moving to the given position (which must be a device value and not an HomeKit value).
|
|
72
|
-
* Returns a Promise that's resolved as soon as the command was sent to the device.
|
|
73
|
-
*/
|
|
74
|
-
runToPosition(pos: number): Promise<void>;
|
|
75
|
-
/**
|
|
76
|
-
* Start a faster scan loop (using fastScanInterval). Used in calls to `runToPosition` to
|
|
77
|
-
* report quicker on device position change. Will disable on its own as soon if the curtain's
|
|
78
|
-
* device position does not change for more than `fastScanDuration`.
|
|
79
|
-
*/
|
|
80
|
-
private startFastScan;
|
|
81
|
-
private stopFastScan;
|
|
82
|
-
private get scanInterval();
|
|
83
|
-
private startScanLoop;
|
|
84
|
-
private scan;
|
|
85
|
-
private applyPosition;
|
|
86
52
|
setMinMax(): void;
|
|
87
53
|
}
|
|
88
54
|
//# sourceMappingURL=curtains.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"curtains.d.ts","sourceRoot":"","sources":["../../src/devices/curtains.ts"],"names":[],"mappings":";AACA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,
|
|
1
|
+
{"version":3,"file":"curtains.d.ts","sourceRoot":"","sources":["../../src/devices/curtains.ts"],"names":[],"mappings":";AACA,OAAO,EAAW,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAY,OAAO,EAAE,MAAM,MAAM,CAAC;AAEzC,OAAO,EAAa,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAG7G,qBAAa,OAAO;IAoChB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,SAAS;IACV,MAAM,EAAE,MAAM,GAAG,aAAa;IApCvC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,cAAc,CAAC,CAAU;IAGjC,eAAe,EAAG,mBAAmB,CAAC;IACtC,aAAa,EAAG,mBAAmB,CAAC;IACpC,cAAc,EAAG,mBAAmB,CAAC;IACrC,wBAAwB,EAAG,mBAAmB,CAAC;IAC/C,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,gBAAgB,CAAC,EAAE,mBAAmB,CAAC;IAGvC,YAAY,EAAG,oBAAoB,CAAC;IACpC,YAAY,EAAG,OAAO,CAAC;IACvB,iBAAiB,EAAG,MAAM,CAAC,OAAO,CAAC;IAGnC,SAAS,EAAG,SAAS,CAAC;IACtB,WAAW,EAAG,WAAW,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACxC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IAChC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;IAClC,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAGtC,WAAW,EAAG,MAAM,CAAC;IACrB,WAAW,EAAG,MAAM,CAAC;IAGrB,uBAAuB,EAAG,OAAO,CAAC;IAClC,eAAe,EAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBAGb,QAAQ,EAAE,iBAAiB,EACpC,SAAS,EAAE,iBAAiB,EAC7B,MAAM,EAAE,MAAM,GAAG,aAAa;IA+HvC,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,OAAO;IAST,WAAW;YAUH,cAAc;YA0Ed,kBAAkB;IA4C1B,aAAa;IAUnB,OAAO,CAAC,UAAU;YAWJ,gBAAgB;YAkChB,oBAAoB;IAc5B,WAAW;YAUH,cAAc;YAad,kBAAkB;IA6BhC,4BAA4B;IAiDrB,QAAQ,CAAC,CAAC,EAAE,GAAG;IAWtB,OAAO,CAAC,UAAU;IA4BlB;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,mBAAmB;IAgCrC,SAAS;CAYjB"}
|
package/dist/devices/curtains.js
CHANGED
|
@@ -9,12 +9,14 @@ class Curtain {
|
|
|
9
9
|
this.platform = platform;
|
|
10
10
|
this.accessory = accessory;
|
|
11
11
|
this.device = device;
|
|
12
|
+
// Curtain Config
|
|
13
|
+
this.platform.device(`[Curtain Config] ble: ${device.ble}, disable_group: ${device.curtain?.disable_group},`
|
|
14
|
+
+ ` refreshRate: ${device.curtain?.refreshRate}, set_max: ${device.curtain?.set_max}, set_min: ${device.curtain?.set_min},`
|
|
15
|
+
+ ` set_minStep: ${device.curtain?.set_minStep}`);
|
|
12
16
|
// default placeholders
|
|
13
|
-
this.setMinMax();
|
|
14
17
|
this.CurrentPosition = 0;
|
|
15
18
|
this.TargetPosition = 0;
|
|
16
19
|
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
17
|
-
this.ScanDuration = this.platform.config.options.refreshRate;
|
|
18
20
|
// BLE Connection
|
|
19
21
|
if (device.ble) {
|
|
20
22
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
@@ -61,7 +63,7 @@ class Curtain {
|
|
|
61
63
|
validValueRanges: [0, 100],
|
|
62
64
|
})
|
|
63
65
|
.onGet(() => {
|
|
64
|
-
return
|
|
66
|
+
return this.CurrentPosition;
|
|
65
67
|
});
|
|
66
68
|
this.service
|
|
67
69
|
.getCharacteristic(this.platform.Characteristic.TargetPosition)
|
|
@@ -75,15 +77,6 @@ class Curtain {
|
|
|
75
77
|
accessory.getService(this.platform.Service.LightSensor) ||
|
|
76
78
|
accessory.addService(this.platform.Service.LightSensor)), `${device.deviceName} Light Sensor`;
|
|
77
79
|
this.lightSensorService.setCharacteristic(this.platform.Characteristic.Name, `${device.deviceName} Light Sensor`);
|
|
78
|
-
// handle on / off events using the On characteristic
|
|
79
|
-
this.lightSensorService.getCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel).onGet(() => {
|
|
80
|
-
if (this.CurrentAmbientLightLevel === 'bright') {
|
|
81
|
-
return 100000;
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
return 0.0001;
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
80
|
// Update Homekit
|
|
88
81
|
this.updateHomeKitCharacteristics();
|
|
89
82
|
// Start an update interval
|
|
@@ -153,9 +146,81 @@ class Curtain {
|
|
|
153
146
|
}
|
|
154
147
|
async BLEparseStatus() {
|
|
155
148
|
this.platform.device('Curtains BLE Device parseStatus');
|
|
149
|
+
this.CurrentPosition = 100 - Number(this.position);
|
|
150
|
+
this.setMinMax();
|
|
151
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition - Device is Currently: ${this.CurrentPosition}`);
|
|
152
|
+
if (this.setNewTarget) {
|
|
153
|
+
this.platform.log.info(`Checking ${this.accessory.displayName} Status ...`);
|
|
154
|
+
}
|
|
155
|
+
if (this.setNewTarget) {
|
|
156
|
+
if (this.TargetPosition > this.CurrentPosition) {
|
|
157
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} - Current position: ${this.CurrentPosition} closing`);
|
|
158
|
+
this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
|
|
159
|
+
}
|
|
160
|
+
else if (this.TargetPosition < this.CurrentPosition) {
|
|
161
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} - Current position: ${this.CurrentPosition} opening`);
|
|
162
|
+
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
this.platform.debug(`Curtain ${this.CurrentPosition} - standby`);
|
|
166
|
+
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} - Current position: ${this.CurrentPosition} standby`);
|
|
171
|
+
if (!this.setNewTarget) {
|
|
172
|
+
/*If Curtain calibration distance is short, there will be an error between the current percentage and the target percentage.*/
|
|
173
|
+
this.TargetPosition = this.CurrentPosition;
|
|
174
|
+
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Brightness
|
|
178
|
+
switch (this.lightLevel) {
|
|
179
|
+
case 1:
|
|
180
|
+
this.CurrentAmbientLightLevel = 0.0001;
|
|
181
|
+
break;
|
|
182
|
+
case 2:
|
|
183
|
+
this.CurrentAmbientLightLevel = 100;
|
|
184
|
+
break;
|
|
185
|
+
case 3:
|
|
186
|
+
this.CurrentAmbientLightLevel = 200;
|
|
187
|
+
break;
|
|
188
|
+
case 4:
|
|
189
|
+
this.CurrentAmbientLightLevel = 4000;
|
|
190
|
+
break;
|
|
191
|
+
case 5:
|
|
192
|
+
this.CurrentAmbientLightLevel = 12000;
|
|
193
|
+
break;
|
|
194
|
+
case 6:
|
|
195
|
+
this.CurrentAmbientLightLevel = 28000;
|
|
196
|
+
break;
|
|
197
|
+
case 7:
|
|
198
|
+
this.CurrentAmbientLightLevel = 56000;
|
|
199
|
+
break;
|
|
200
|
+
case 8:
|
|
201
|
+
this.CurrentAmbientLightLevel = 75000;
|
|
202
|
+
break;
|
|
203
|
+
case 9:
|
|
204
|
+
this.CurrentAmbientLightLevel = 90000;
|
|
205
|
+
break;
|
|
206
|
+
case 10:
|
|
207
|
+
default:
|
|
208
|
+
this.CurrentAmbientLightLevel = 100000;
|
|
209
|
+
}
|
|
210
|
+
// Battery
|
|
211
|
+
this.BatteryLevel = Number(this.battery);
|
|
212
|
+
if (this.BatteryLevel < 10) {
|
|
213
|
+
this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
|
|
217
|
+
}
|
|
218
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
|
|
219
|
+
+ ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`
|
|
220
|
+
+ ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
156
221
|
}
|
|
157
222
|
async openAPIparseStatus() {
|
|
158
|
-
this.
|
|
223
|
+
this.platform.device('Curtains OpenAPI Device parseStatus');
|
|
159
224
|
this.CurrentPosition = 100 - this.deviceStatus.body.slidePosition;
|
|
160
225
|
this.setMinMax();
|
|
161
226
|
this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition - Device is Currently: ${this.CurrentPosition}`);
|
|
@@ -189,77 +254,72 @@ class Curtain {
|
|
|
189
254
|
case 'dim':
|
|
190
255
|
this.CurrentAmbientLightLevel = 0.0001;
|
|
191
256
|
break;
|
|
257
|
+
case 'bright':
|
|
192
258
|
default:
|
|
193
259
|
this.CurrentAmbientLightLevel = 100000;
|
|
194
260
|
}
|
|
195
|
-
this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}
|
|
196
|
-
|
|
197
|
-
|
|
261
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
|
|
262
|
+
+ ` TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState},`
|
|
263
|
+
+ ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
198
264
|
}
|
|
199
265
|
async refreshStatus() {
|
|
200
266
|
if (this.device.ble) {
|
|
201
267
|
this.platform.device('BLE');
|
|
202
|
-
await this.
|
|
268
|
+
await this.BLERefreshStatus();
|
|
203
269
|
}
|
|
204
270
|
else {
|
|
205
271
|
this.platform.device('OpenAPI');
|
|
206
272
|
await this.openAPIRefreshStatus();
|
|
207
273
|
}
|
|
208
274
|
}
|
|
209
|
-
|
|
210
|
-
this.platform.debug('Curtains BLE Device RefreshStatus');
|
|
275
|
+
connectBLE() {
|
|
211
276
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
212
277
|
const Switchbot = require('node-switchbot');
|
|
213
278
|
const switchbot = new Switchbot();
|
|
214
279
|
const colon = this.device.deviceId.match(/.{1,2}/g);
|
|
215
280
|
const bleMac = colon.join(':'); //returns 1A:23:B4:56:78:9A;
|
|
216
281
|
this.device.bleMac = bleMac.toLowerCase();
|
|
217
|
-
this.platform.
|
|
218
|
-
switchbot
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
this.
|
|
224
|
-
|
|
225
|
-
|
|
282
|
+
this.platform.device(this.device.bleMac);
|
|
283
|
+
return switchbot;
|
|
284
|
+
}
|
|
285
|
+
async BLERefreshStatus() {
|
|
286
|
+
this.platform.debug('Curtains BLE Device RefreshStatus');
|
|
287
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
288
|
+
const switchbot = this.connectBLE();
|
|
289
|
+
// Start to monitor advertisement packets
|
|
290
|
+
switchbot.startScan({
|
|
291
|
+
model: 'c',
|
|
226
292
|
id: this.device.bleMac,
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
293
|
+
}).then(() => {
|
|
294
|
+
// Set an event hander
|
|
295
|
+
switchbot.onadvertisement = (ad) => {
|
|
296
|
+
this.serviceData = ad.serviceData;
|
|
297
|
+
this.platform.device(`${this.device.bleMac}: ${JSON.stringify(ad.serviceData)}`);
|
|
298
|
+
this.calibration = ad.serviceData.calibration;
|
|
299
|
+
this.battery = ad.serviceData.battery;
|
|
300
|
+
this.position = ad.serviceData.position;
|
|
301
|
+
this.lightLevel = ad.serviceData.lightLevel;
|
|
302
|
+
this.platform.device(`${this.accessory.displayName}, Calibration: ${ad.serviceData.calibration}, Position: ${ad.serviceData.position},`
|
|
303
|
+
+ ` Light Level: ${ad.serviceData.lightLevel}, Battery: ${ad.serviceData.battery}`);
|
|
304
|
+
};
|
|
305
|
+
// Wait 10 seconds
|
|
306
|
+
return switchbot.wait(10000);
|
|
307
|
+
}).then(() => {
|
|
308
|
+
// Stop to monitor
|
|
232
309
|
switchbot.stopScan();
|
|
233
|
-
|
|
234
|
-
.
|
|
235
|
-
|
|
310
|
+
this.parseStatus();
|
|
311
|
+
this.updateHomeKitCharacteristics();
|
|
312
|
+
}).catch(async (e) => {
|
|
313
|
+
this.platform.log.error(`BLE Connection Failed: ${e.message}`);
|
|
314
|
+
this.platform.log.warn('Using OpenAPI Connection');
|
|
236
315
|
await this.openAPIRefreshStatus();
|
|
237
316
|
});
|
|
238
|
-
setInterval(() => {
|
|
239
|
-
this.platform.log.info('Start scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
|
|
240
|
-
switchbot
|
|
241
|
-
.startScan({
|
|
242
|
-
mode: 'T',
|
|
243
|
-
id: bleMac,
|
|
244
|
-
})
|
|
245
|
-
.then(() => {
|
|
246
|
-
return switchbot.wait(this.platform.config.options.refreshRate * 1000);
|
|
247
|
-
})
|
|
248
|
-
.then(() => {
|
|
249
|
-
switchbot.stopScan();
|
|
250
|
-
this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
|
|
251
|
-
})
|
|
252
|
-
.catch(async (error) => {
|
|
253
|
-
this.platform.log.error(error);
|
|
254
|
-
await this.openAPIRefreshStatus();
|
|
255
|
-
});
|
|
256
|
-
}, this.platform.config.options.refreshRate * 60000);
|
|
257
317
|
}
|
|
258
318
|
async openAPIRefreshStatus() {
|
|
319
|
+
this.platform.debug('Curtains OpenAPI Device RefreshStatus');
|
|
259
320
|
try {
|
|
260
321
|
this.deviceStatus = (await this.platform.axios.get(`${settings_1.DeviceURL}/${this.device.deviceId}/status`)).data;
|
|
261
322
|
this.platform.debug(`Curtain ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
|
|
262
|
-
this.setMinMax();
|
|
263
323
|
this.parseStatus();
|
|
264
324
|
this.updateHomeKitCharacteristics();
|
|
265
325
|
}
|
|
@@ -281,6 +341,15 @@ class Curtain {
|
|
|
281
341
|
}
|
|
282
342
|
async BLEpushChanges() {
|
|
283
343
|
this.platform.device('Curtains BLE Device pushChanges');
|
|
344
|
+
const switchbot = this.connectBLE();
|
|
345
|
+
switchbot.discover({ model: 'c', quick: true, id: this.device.bleMac }).then((device_list) => {
|
|
346
|
+
this.platform.log.info(`${this.accessory.displayName}, Target Position: ${this.TargetPosition}`);
|
|
347
|
+
return device_list[0].runToPos(100 - Number(this.TargetPosition));
|
|
348
|
+
}).then(() => {
|
|
349
|
+
this.platform.device('Done.');
|
|
350
|
+
}).catch((e) => {
|
|
351
|
+
this.platform.log.error(`BLE pushChanges Error Message: ${e.message}`);
|
|
352
|
+
});
|
|
284
353
|
}
|
|
285
354
|
async OpenAPIpushChanges() {
|
|
286
355
|
if (this.TargetPosition !== this.CurrentPosition) {
|
|
@@ -294,7 +363,6 @@ class Curtain {
|
|
|
294
363
|
this.platform.log.info('Sending request for', this.accessory.displayName, 'to SwitchBot API. command:', payload.command, 'parameter:', payload.parameter, 'commandType:', payload.commandType);
|
|
295
364
|
this.platform.debug(`Curtain ${this.accessory.displayName} pushchanges: ${JSON.stringify(payload)}`);
|
|
296
365
|
// Make the API request
|
|
297
|
-
this.platform.log.error(this.device.deviceId);
|
|
298
366
|
const push = (await this.platform.axios.post(`${settings_1.DeviceURL}/${this.device.deviceId}/commands`, payload));
|
|
299
367
|
this.platform.debug(`Curtain ${this.accessory.displayName} Changes pushed: ${JSON.stringify(push.data)}`);
|
|
300
368
|
this.statusCode(push);
|
|
@@ -302,12 +370,11 @@ class Curtain {
|
|
|
302
370
|
}
|
|
303
371
|
updateHomeKitCharacteristics() {
|
|
304
372
|
this.platform.debug(`Curtain ${this.accessory.displayName} updateHomeKitCharacteristics - ${JSON.stringify({
|
|
305
|
-
CurrentPosition:
|
|
373
|
+
CurrentPosition: this.CurrentPosition,
|
|
306
374
|
PositionState: this.PositionState,
|
|
307
|
-
TargetPosition:
|
|
375
|
+
TargetPosition: this.TargetPosition,
|
|
308
376
|
CurrentAmbientLightLevel: this.CurrentAmbientLightLevel,
|
|
309
377
|
})}`);
|
|
310
|
-
this.setMinMax();
|
|
311
378
|
if (this.CurrentPosition === undefined) {
|
|
312
379
|
this.platform.debug(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
|
|
313
380
|
}
|
|
@@ -336,12 +403,32 @@ class Curtain {
|
|
|
336
403
|
this.lightSensorService.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
|
|
337
404
|
this.platform.device(`Curtain ${this.accessory.displayName} updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
338
405
|
}
|
|
406
|
+
if (this.device.ble) {
|
|
407
|
+
if (this.BatteryLevel === undefined) {
|
|
408
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
|
|
412
|
+
this.platform.device(`Curtain ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
|
|
413
|
+
}
|
|
414
|
+
if (this.StatusLowBattery === undefined) {
|
|
415
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
|
|
419
|
+
this.platform.device(`Curtain ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
339
422
|
}
|
|
340
423
|
apiError(e) {
|
|
341
424
|
this.service.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
|
|
342
425
|
this.service.updateCharacteristic(this.platform.Characteristic.PositionState, e);
|
|
343
426
|
this.service.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
|
|
344
427
|
this.lightSensorService.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
|
|
428
|
+
if (this.device.ble) {
|
|
429
|
+
this.batteryService.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
|
|
430
|
+
this.batteryService.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
|
|
431
|
+
}
|
|
345
432
|
}
|
|
346
433
|
statusCode(push) {
|
|
347
434
|
switch (push.data.statusCode) {
|
|
@@ -374,199 +461,34 @@ class Curtain {
|
|
|
374
461
|
* Handle requests to set the value of the "Target Position" characteristic
|
|
375
462
|
*/
|
|
376
463
|
TargetPositionSet(value) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
else if (this.TargetPosition < this.CurrentPosition) {
|
|
385
|
-
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
386
|
-
}
|
|
387
|
-
else {
|
|
388
|
-
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
389
|
-
}
|
|
390
|
-
if (this.PositionState === this.platform.Characteristic.PositionState.STOPPED) {
|
|
391
|
-
this.service?.getCharacteristic(this.platform.Characteristic.TargetPosition).updateValue(this.TargetPosition);
|
|
392
|
-
this.service?.getCharacteristic(this.platform.Characteristic.CurrentPosition).updateValue(this.CurrentPosition);
|
|
393
|
-
this.service?.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
394
|
-
}
|
|
395
|
-
else {
|
|
396
|
-
this.runToPosition(this.convertFromHomeKitPosition(this.TargetPosition))
|
|
397
|
-
.then(() => {
|
|
398
|
-
this.platform.log.info('Done.');
|
|
399
|
-
this.platform.log.info('Target position of Curtain has been set to: ' + this.TargetPosition + '%');
|
|
400
|
-
this.moveTimer = setTimeout(() => {
|
|
401
|
-
// log.info("setTimeout", this.positionState.toString(), this.currentPosition.toString(), this.targetPosition.toString());
|
|
402
|
-
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
403
|
-
// this.curtainService?.getCharacteristic(hap.Characteristic.TargetPosition).updateValue(this.targetPosition);
|
|
404
|
-
this.service?.getCharacteristic(this.platform.Characteristic.CurrentPosition).updateValue(this.CurrentPosition);
|
|
405
|
-
this.service?.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
406
|
-
}, this.moveTime);
|
|
407
|
-
})
|
|
408
|
-
.catch((error) => {
|
|
409
|
-
this.platform.log.error(error);
|
|
410
|
-
this.moveTimer = setTimeout(() => {
|
|
411
|
-
this.TargetPosition = this.CurrentPosition;
|
|
412
|
-
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
413
|
-
this.service?.getCharacteristic(this.platform.Characteristic.TargetPosition).updateValue(this.TargetPosition);
|
|
414
|
-
// this.curtainService?.getCharacteristic(hap.Characteristic.CurrentPosition).updateValue(this.currentPosition);
|
|
415
|
-
this.service?.getCharacteristic(this.platform.Characteristic.PositionState).updateValue(this.PositionState);
|
|
416
|
-
}, 1000);
|
|
417
|
-
this.platform.log.info('Target position of Curtain failed to be set to: ' + this.TargetPosition + '%');
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
else {
|
|
422
|
-
this.platform.debug(`Curtain ${this.accessory.displayName} - Set TargetPosition: ${value}`);
|
|
423
|
-
this.TargetPosition = value;
|
|
424
|
-
if (value > this.CurrentPosition) {
|
|
425
|
-
this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
|
|
426
|
-
this.setNewTarget = true;
|
|
427
|
-
this.setMinMax();
|
|
428
|
-
}
|
|
429
|
-
else if (value < this.CurrentPosition) {
|
|
430
|
-
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
431
|
-
this.setNewTarget = true;
|
|
432
|
-
this.setMinMax();
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
436
|
-
this.setNewTarget = false;
|
|
437
|
-
this.setMinMax();
|
|
438
|
-
}
|
|
439
|
-
this.service.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
|
|
440
|
-
/**
|
|
441
|
-
* If Curtain movement time is short, the moving flag from backend is always false.
|
|
442
|
-
* The minimum time depends on the network control latency.
|
|
443
|
-
*/
|
|
444
|
-
clearTimeout(this.setNewTargetTimer);
|
|
445
|
-
if (this.setNewTarget) {
|
|
446
|
-
this.setNewTargetTimer = setTimeout(() => {
|
|
447
|
-
this.platform.debug(`Curtain ${this.accessory.displayName} - setNewTarget ${this.setNewTarget} timeout`);
|
|
448
|
-
this.setNewTarget = false;
|
|
449
|
-
}, 10000);
|
|
450
|
-
}
|
|
451
|
-
this.doCurtainUpdate.next();
|
|
464
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} - Set TargetPosition: ${value}`);
|
|
465
|
+
this.TargetPosition = value;
|
|
466
|
+
this.setMinMax();
|
|
467
|
+
if (value > this.CurrentPosition) {
|
|
468
|
+
this.PositionState = this.platform.Characteristic.PositionState.INCREASING;
|
|
469
|
+
this.setNewTarget = true;
|
|
452
470
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
*
|
|
457
|
-
* - opened is 0% in HomeKit and 100% in Curtain device.
|
|
458
|
-
* - closed is 100% in HomeKit, 0% in Curtain device.
|
|
459
|
-
*/
|
|
460
|
-
convertFromHomeKitPosition(n) {
|
|
461
|
-
let covertToDevicePosition;
|
|
462
|
-
if (this.ReverseDir) {
|
|
463
|
-
covertToDevicePosition = n;
|
|
471
|
+
else if (value < this.CurrentPosition) {
|
|
472
|
+
this.PositionState = this.platform.Characteristic.PositionState.DECREASING;
|
|
473
|
+
this.setNewTarget = true;
|
|
464
474
|
}
|
|
465
475
|
else {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
return covertToDevicePosition;
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Ask the device to start moving to the given position (which must be a device value and not an HomeKit value).
|
|
472
|
-
* Returns a Promise that's resolved as soon as the command was sent to the device.
|
|
473
|
-
*/
|
|
474
|
-
async runToPosition(pos) {
|
|
475
|
-
const SwitchBot = require('node-switchbot');
|
|
476
|
-
const switchbot = new SwitchBot();
|
|
477
|
-
return switchbot
|
|
478
|
-
.discover({ duration: this.ScanDuration, model: 'c', quick: false })
|
|
479
|
-
.then((device_list) => {
|
|
480
|
-
let targetDevice = null;
|
|
481
|
-
for (const device of device_list) {
|
|
482
|
-
this.platform.log.info(device.modelName, device.address);
|
|
483
|
-
if (device.address === this.device.bleMac.toLowerCase()) {
|
|
484
|
-
targetDevice = device;
|
|
485
|
-
break;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
if (!targetDevice) {
|
|
489
|
-
return new Promise((resolve, reject) => {
|
|
490
|
-
reject(new Error('Curtain \'' + this.device.deviceName + '\' (' + this.device.bleMac.toLowerCase() + '): device not found.'));
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
this.startFastScan();
|
|
494
|
-
this.platform.log.info(`Curtain ${this.device.deviceName} (${this.device.bleMac.toLowerCase()}) is moving to ${pos}...`);
|
|
495
|
-
return targetDevice.runToPos(pos);
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Start a faster scan loop (using fastScanInterval). Used in calls to `runToPosition` to
|
|
500
|
-
* report quicker on device position change. Will disable on its own as soon if the curtain's
|
|
501
|
-
* device position does not change for more than `fastScanDuration`.
|
|
502
|
-
*/
|
|
503
|
-
startFastScan() {
|
|
504
|
-
if (this.FastScanEnabled) {
|
|
505
|
-
return;
|
|
476
|
+
this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
|
|
477
|
+
this.setNewTarget = false;
|
|
506
478
|
}
|
|
507
|
-
this.
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
return this.FastScanEnabled ? this.FastScanInterval : this.SlowScanInterval;
|
|
519
|
-
}
|
|
520
|
-
startScanLoop() {
|
|
521
|
-
if (this.ScanIntervalId !== null) {
|
|
522
|
-
clearInterval(this.ScanIntervalId);
|
|
523
|
-
}
|
|
524
|
-
this.platform.log.info(`Curtain ${this.device.deviceName}: starting scan loop with interval ${this.scanInterval}`);
|
|
525
|
-
this.ScanIntervalId = setInterval(() => {
|
|
526
|
-
this.scan().catch((err) => {
|
|
527
|
-
this.platform.log.error(`error while scanning for Curtain ${this.device.deviceName}: ${err}`);
|
|
528
|
-
});
|
|
529
|
-
}, this.scanInterval);
|
|
530
|
-
}
|
|
531
|
-
scan() {
|
|
532
|
-
return new Promise((resolve, reject) => {
|
|
533
|
-
const SwitchBot = require('node-switchbot');
|
|
534
|
-
const switchbot = new SwitchBot();
|
|
535
|
-
switchbot.onadvertisement = (ad) => {
|
|
536
|
-
this.applyPosition(ad);
|
|
537
|
-
};
|
|
538
|
-
switchbot.startScan({ id: this.device.bleMac.toLowerCase() })
|
|
539
|
-
.then(() => {
|
|
540
|
-
return switchbot.wait(this.ScanDuration);
|
|
541
|
-
})
|
|
542
|
-
.then(() => {
|
|
543
|
-
resolve();
|
|
544
|
-
switchbot.stopScan();
|
|
545
|
-
})
|
|
546
|
-
.catch((err) => {
|
|
547
|
-
reject(err);
|
|
548
|
-
});
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
applyPosition(ad) {
|
|
552
|
-
let pos = ad.serviceData.position;
|
|
553
|
-
if (pos + this.OpenCloseThreshold >= 100) {
|
|
554
|
-
pos = 100;
|
|
555
|
-
}
|
|
556
|
-
else if (pos - this.OpenCloseThreshold <= 0) {
|
|
557
|
-
pos = 0;
|
|
558
|
-
}
|
|
559
|
-
if (pos === this.PreviousPosition) {
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
this.PreviousPosition = this.Position;
|
|
563
|
-
this.Position = pos;
|
|
564
|
-
if (this.AutoDisableFastScanTimeoutId !== null) {
|
|
565
|
-
clearTimeout(this.AutoDisableFastScanTimeoutId);
|
|
479
|
+
this.service.setCharacteristic(this.platform.Characteristic.PositionState, this.PositionState);
|
|
480
|
+
/**
|
|
481
|
+
* If Curtain movement time is short, the moving flag from backend is always false.
|
|
482
|
+
* The minimum time depends on the network control latency.
|
|
483
|
+
*/
|
|
484
|
+
clearTimeout(this.setNewTargetTimer);
|
|
485
|
+
if (this.setNewTarget) {
|
|
486
|
+
this.setNewTargetTimer = setTimeout(() => {
|
|
487
|
+
this.platform.debug(`Curtain ${this.accessory.displayName} - setNewTarget ${this.setNewTarget} timeout`);
|
|
488
|
+
this.setNewTarget = false;
|
|
489
|
+
}, 10000);
|
|
566
490
|
}
|
|
567
|
-
this.
|
|
568
|
-
this.stopFastScan();
|
|
569
|
-
}, this.FastScanDuration);
|
|
491
|
+
this.doCurtainUpdate.next();
|
|
570
492
|
}
|
|
571
493
|
setMinMax() {
|
|
572
494
|
if (this.device.curtain?.set_min) {
|