@switchbot/homebridge-switchbot 0.2.0-alpha.1 → 1.0.1-beta.1
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 +350 -126
- package/dist/devices/bots.d.ts +17 -33
- package/dist/devices/bots.d.ts.map +1 -1
- package/dist/devices/bots.js +103 -152
- 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} +32 -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 +168 -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 +78 -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 +35 -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 +50 -8
- package/dist/settings.d.ts.map +1 -1
- package/package.json +65 -65
- package/src/devices/bots.ts +126 -176
- package/src/devices/{bulb.ts → colorbulb.ts} +43 -51
- package/src/devices/contact.ts +124 -68
- package/src/devices/curtains.ts +189 -300
- package/src/devices/humidifiers.ts +93 -14
- package/src/devices/indoorcam.ts +10 -20
- package/src/devices/meters.ts +53 -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 +79 -8
- package/dist/devices/bulb.d.ts.map +0 -1
- package/dist/devices/bulb.js.map +0 -1
|
@@ -2,7 +2,8 @@ import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
|
2
2
|
import { SwitchBotPlatform } from '../platform';
|
|
3
3
|
import { interval, Subject } from 'rxjs';
|
|
4
4
|
import { debounceTime, skipWhile, tap } from 'rxjs/operators';
|
|
5
|
-
import { DeviceURL, device, devicesConfig } from '../settings';
|
|
5
|
+
import { DeviceURL, device, devicesConfig, serviceData, ad, deviceStatusResponse } from '../settings';
|
|
6
|
+
import { AxiosResponse } from 'axios';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Platform Accessory
|
|
@@ -23,13 +24,21 @@ export class Humidifier {
|
|
|
23
24
|
Active!: CharacteristicValue;
|
|
24
25
|
WaterLevel!: CharacteristicValue;
|
|
25
26
|
|
|
26
|
-
//
|
|
27
|
-
deviceStatus!:
|
|
27
|
+
// OpenAPI
|
|
28
|
+
deviceStatus!: deviceStatusResponse;
|
|
29
|
+
|
|
30
|
+
// BLE Others
|
|
31
|
+
serviceData!: serviceData;
|
|
32
|
+
onState!: serviceData['onState'];
|
|
33
|
+
autoMode!: serviceData['autoMode'];
|
|
34
|
+
percentage!: serviceData['percentage'];
|
|
35
|
+
|
|
36
|
+
// Config
|
|
37
|
+
set_minStep?: number;
|
|
28
38
|
|
|
29
39
|
// Updates
|
|
30
40
|
humidifierUpdateInProgress!: boolean;
|
|
31
|
-
doHumidifierUpdate
|
|
32
|
-
set_minStep: number | undefined;
|
|
41
|
+
doHumidifierUpdate!: Subject<void>;
|
|
33
42
|
|
|
34
43
|
constructor(
|
|
35
44
|
private readonly platform: SwitchBotPlatform,
|
|
@@ -180,7 +189,11 @@ export class Humidifier {
|
|
|
180
189
|
*/
|
|
181
190
|
parseStatus() {
|
|
182
191
|
// Current Relative Humidity
|
|
183
|
-
|
|
192
|
+
if (this.device.ble) {
|
|
193
|
+
this.CurrentRelativeHumidity = this.percentage!;
|
|
194
|
+
} else {
|
|
195
|
+
this.CurrentRelativeHumidity = this.deviceStatus.body.humidity!;
|
|
196
|
+
}
|
|
184
197
|
this.platform.debug(`Humidifier ${this.accessory.displayName} CurrentRelativeHumidity: ${this.CurrentRelativeHumidity}`);
|
|
185
198
|
this.platform.device(JSON.stringify(this.deviceStatus.body));
|
|
186
199
|
// Water Level
|
|
@@ -191,12 +204,16 @@ export class Humidifier {
|
|
|
191
204
|
}
|
|
192
205
|
this.platform.debug(`Humidifier ${this.accessory.displayName} WaterLevel: ${this.WaterLevel}`);
|
|
193
206
|
// Active
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
207
|
+
if (this.device.ble) {
|
|
208
|
+
this.Active = this.State();
|
|
209
|
+
} else {
|
|
210
|
+
switch (this.deviceStatus.body.power) {
|
|
211
|
+
case 'on':
|
|
212
|
+
this.Active = this.platform.Characteristic.Active.ACTIVE;
|
|
213
|
+
break;
|
|
214
|
+
default:
|
|
215
|
+
this.Active = this.platform.Characteristic.Active.INACTIVE;
|
|
216
|
+
}
|
|
200
217
|
}
|
|
201
218
|
this.platform.debug(`Humidifier ${this.accessory.displayName} Active: ${this.Active}`);
|
|
202
219
|
// Target Humidifier Dehumidifier State
|
|
@@ -226,15 +243,77 @@ export class Humidifier {
|
|
|
226
243
|
this.platform.debug(`Humidifier ${this.accessory.displayName} CurrentHumidifierDehumidifierState: ${this.CurrentHumidifierDehumidifierState}`);
|
|
227
244
|
// Current Temperature
|
|
228
245
|
if (!this.device.humidifier?.hide_temperature) {
|
|
229
|
-
this.CurrentTemperature = this.deviceStatus.body.temperature;
|
|
246
|
+
this.CurrentTemperature = Number(this.deviceStatus.body.temperature);
|
|
230
247
|
this.platform.debug(`Humidifier ${this.accessory.displayName} CurrentTemperature: ${this.CurrentTemperature}`);
|
|
231
248
|
}
|
|
232
249
|
}
|
|
233
250
|
|
|
251
|
+
private State(): CharacteristicValue {
|
|
252
|
+
if (this.onState) {
|
|
253
|
+
return this.platform.Characteristic.Active.ACTIVE;
|
|
254
|
+
} else {
|
|
255
|
+
return this.platform.Characteristic.Active.INACTIVE;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
234
259
|
/**
|
|
235
260
|
* Asks the SwitchBot API for the latest device information
|
|
236
261
|
*/
|
|
237
262
|
async refreshStatus() {
|
|
263
|
+
if (this.device.ble) {
|
|
264
|
+
this.platform.device('BLE');
|
|
265
|
+
await this.BLERefreshStatus();
|
|
266
|
+
} else {
|
|
267
|
+
this.platform.device('OpenAPI');
|
|
268
|
+
await this.openAPIRefreshStatus();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private connectBLE() {
|
|
273
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
274
|
+
const Switchbot = require('node-switchbot');
|
|
275
|
+
const switchbot = new Switchbot();
|
|
276
|
+
const colon = this.device.deviceId!.match(/.{1,2}/g);
|
|
277
|
+
const bleMac = colon!.join(':'); //returns 1A:23:B4:56:78:9A;
|
|
278
|
+
this.device.bleMac = bleMac.toLowerCase();
|
|
279
|
+
this.platform.device(this.device.bleMac!);
|
|
280
|
+
return switchbot;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private async BLERefreshStatus() {
|
|
284
|
+
this.platform.device('Bot BLE Device refreshStatus');
|
|
285
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
286
|
+
const switchbot = this.connectBLE();
|
|
287
|
+
// Start to monitor advertisement packets
|
|
288
|
+
switchbot.startScan({
|
|
289
|
+
model: 'e',
|
|
290
|
+
id: this.device.bleMac,
|
|
291
|
+
}).then(() => {
|
|
292
|
+
// Set an event hander
|
|
293
|
+
switchbot.onadvertisement = (ad: ad) => {
|
|
294
|
+
this.serviceData = ad.serviceData;
|
|
295
|
+
this.autoMode = ad.serviceData.autoMode;
|
|
296
|
+
this.onState = ad.serviceData.onState;
|
|
297
|
+
this.percentage = ad.serviceData.percentage;
|
|
298
|
+
this.platform.device(`${this.device.bleMac}: ${JSON.stringify(ad.serviceData)}`);
|
|
299
|
+
this.platform.device(`${this.accessory.displayName}, Model: ${ad.serviceData.model}, Model Name: ${ad.serviceData.modelName},`
|
|
300
|
+
+ `autoMode: ${ad.serviceData.autoMode}, onState: ${ad.serviceData.onState}, percentage: ${ad.serviceData.percentage}`);
|
|
301
|
+
};
|
|
302
|
+
// Wait 10 seconds
|
|
303
|
+
return switchbot.wait(10000);
|
|
304
|
+
}).then(() => {
|
|
305
|
+
// Stop to monitor
|
|
306
|
+
switchbot.stopScan();
|
|
307
|
+
this.parseStatus();
|
|
308
|
+
this.updateHomeKitCharacteristics();
|
|
309
|
+
}).catch(async (e: any) => {
|
|
310
|
+
this.platform.log.error(`BLE Connection Failed: ${e.message}`);
|
|
311
|
+
this.platform.log.warn('Using OpenAPI Connection');
|
|
312
|
+
await this.openAPIRefreshStatus();
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private async openAPIRefreshStatus() {
|
|
238
317
|
try {
|
|
239
318
|
this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
|
|
240
319
|
if (this.deviceStatus.message === 'success') {
|
|
@@ -436,7 +515,7 @@ export class Humidifier {
|
|
|
436
515
|
}
|
|
437
516
|
}
|
|
438
517
|
|
|
439
|
-
private statusCode(push: {
|
|
518
|
+
private statusCode(push: AxiosResponse<{ statusCode: number;}>) {
|
|
440
519
|
switch (push.data.statusCode) {
|
|
441
520
|
case 151:
|
|
442
521
|
this.platform.log.error('Command not supported by this device type.');
|
package/src/devices/indoorcam.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Service, PlatformAccessory, CharacteristicValue
|
|
1
|
+
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
2
2
|
import { SwitchBotPlatform } from '../platform';
|
|
3
3
|
import { interval, Subject } from 'rxjs';
|
|
4
4
|
import { debounceTime, skipWhile, tap } from 'rxjs/operators';
|
|
5
|
-
import { DeviceURL, device, devicesConfig } from '../settings';
|
|
5
|
+
import { DeviceURL, device, devicesConfig, switchbot, deviceStatusResponse } from '../settings';
|
|
6
|
+
import { AxiosResponse } from 'axios';
|
|
6
7
|
|
|
7
8
|
export class IndoorCam {
|
|
8
9
|
// Services
|
|
@@ -12,26 +13,15 @@ export class IndoorCam {
|
|
|
12
13
|
On!: CharacteristicValue;
|
|
13
14
|
OutletInUse!: CharacteristicValue;
|
|
14
15
|
|
|
15
|
-
// Others
|
|
16
|
-
deviceStatus!:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
duration: any;
|
|
22
|
-
model: string;
|
|
23
|
-
quick: boolean;
|
|
24
|
-
id: MacAddress;
|
|
25
|
-
}
|
|
26
|
-
) => Promise<any>;
|
|
27
|
-
wait: (
|
|
28
|
-
arg0: number
|
|
29
|
-
) => any;
|
|
30
|
-
};
|
|
16
|
+
// OpenAPI Others
|
|
17
|
+
deviceStatus!: deviceStatusResponse;
|
|
18
|
+
|
|
19
|
+
// BLE Others
|
|
20
|
+
switchbot!: switchbot;
|
|
31
21
|
|
|
32
22
|
// Updates
|
|
33
23
|
cameraUpdateInProgress!: boolean;
|
|
34
|
-
doCameraUpdate
|
|
24
|
+
doCameraUpdate!: Subject<void>;
|
|
35
25
|
|
|
36
26
|
constructor(
|
|
37
27
|
private readonly platform: SwitchBotPlatform,
|
|
@@ -259,7 +249,7 @@ export class IndoorCam {
|
|
|
259
249
|
}
|
|
260
250
|
|
|
261
251
|
|
|
262
|
-
private statusCode(push: {
|
|
252
|
+
private statusCode(push: AxiosResponse<{ statusCode: number;}>) {
|
|
263
253
|
switch (push.data.statusCode) {
|
|
264
254
|
case 151:
|
|
265
255
|
this.platform.log.error('Command not supported by this device type.');
|
package/src/devices/meters.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Service, PlatformAccessory, Units, CharacteristicValue
|
|
1
|
+
import { Service, PlatformAccessory, Units, CharacteristicValue } from 'homebridge';
|
|
2
2
|
import { SwitchBotPlatform } from '../platform';
|
|
3
3
|
import { interval, Subject } from 'rxjs';
|
|
4
4
|
import { skipWhile } from 'rxjs/operators';
|
|
5
|
-
import { DeviceURL, device, devicesConfig } from '../settings';
|
|
5
|
+
import { DeviceURL, device, devicesConfig, serviceData, ad, switchbot, deviceStatusResponse } from '../settings';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Platform Accessory
|
|
@@ -24,28 +24,20 @@ export class Meter {
|
|
|
24
24
|
Active!: CharacteristicValue;
|
|
25
25
|
WaterLevel!: CharacteristicValue;
|
|
26
26
|
|
|
27
|
-
// Others
|
|
28
|
-
deviceStatus!:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
switchbot!:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
quick: boolean;
|
|
38
|
-
id: MacAddress;
|
|
39
|
-
}
|
|
40
|
-
) => Promise<any>;
|
|
41
|
-
wait: (
|
|
42
|
-
arg0: number
|
|
43
|
-
) => any;
|
|
44
|
-
};
|
|
27
|
+
// OpenAPI Others
|
|
28
|
+
deviceStatus!: deviceStatusResponse;
|
|
29
|
+
|
|
30
|
+
// BLE Others
|
|
31
|
+
switchbot!: switchbot;
|
|
32
|
+
serviceData!: serviceData;
|
|
33
|
+
battery!: serviceData['battery'];
|
|
34
|
+
humidity!: serviceData['humidity'];
|
|
35
|
+
fahrenheit!: serviceData['fahrenheit'];
|
|
36
|
+
temperature!: serviceData['temperature'];
|
|
45
37
|
|
|
46
38
|
// Updates
|
|
47
39
|
meterUpdateInProgress!: boolean;
|
|
48
|
-
doMeterUpdate
|
|
40
|
+
doMeterUpdate: Subject<void>;
|
|
49
41
|
|
|
50
42
|
constructor(
|
|
51
43
|
private readonly platform: SwitchBotPlatform,
|
|
@@ -211,7 +203,7 @@ export class Meter {
|
|
|
211
203
|
// Current Relative Humidity
|
|
212
204
|
if (!this.device.meter?.hide_humidity) {
|
|
213
205
|
if (this.device.ble) {
|
|
214
|
-
this.CurrentRelativeHumidity = this.
|
|
206
|
+
this.CurrentRelativeHumidity = Number(this.humidity);
|
|
215
207
|
} else {
|
|
216
208
|
this.CurrentRelativeHumidity = this.deviceStatus.body.humidity!;
|
|
217
209
|
}
|
|
@@ -221,14 +213,14 @@ export class Meter {
|
|
|
221
213
|
// Current Temperature
|
|
222
214
|
if (!this.device.meter?.hide_temperature) {
|
|
223
215
|
if (this.device.ble) {
|
|
224
|
-
this.CurrentTemperature = this.
|
|
216
|
+
this.CurrentTemperature = Number(this.temperature);
|
|
225
217
|
} else {
|
|
226
218
|
if (this.device.meter?.unit === 1) {
|
|
227
219
|
this.CurrentTemperature = this.toFahrenheit(this.deviceStatus.body.temperature!);
|
|
228
220
|
} else if (this.device.meter?.unit === 0) {
|
|
229
221
|
this.CurrentTemperature = this.toCelsius(this.deviceStatus.body.temperature!);
|
|
230
222
|
} else {
|
|
231
|
-
this.CurrentTemperature = this.deviceStatus.body.temperature;
|
|
223
|
+
this.CurrentTemperature = Number(this.deviceStatus.body.temperature);
|
|
232
224
|
}
|
|
233
225
|
}
|
|
234
226
|
this.platform.debug(`Meter ${this.accessory.displayName} - Temperature: ${this.CurrentTemperature}°c`);
|
|
@@ -248,8 +240,7 @@ export class Meter {
|
|
|
248
240
|
}
|
|
249
241
|
}
|
|
250
242
|
|
|
251
|
-
private
|
|
252
|
-
this.platform.debug('Meter BLE Device RefreshStatus');
|
|
243
|
+
private connectBLE() {
|
|
253
244
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
254
245
|
const Switchbot = require('node-switchbot');
|
|
255
246
|
const switchbot = new Switchbot();
|
|
@@ -257,49 +248,42 @@ export class Meter {
|
|
|
257
248
|
const bleMac = colon!.join(':'); //returns 1A:23:B4:56:78:9A;
|
|
258
249
|
this.device.bleMac = bleMac.toLowerCase();
|
|
259
250
|
this.platform.device(this.device.bleMac!);
|
|
260
|
-
switchbot
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
|
|
297
|
-
})
|
|
298
|
-
.catch(async (error: any) => {
|
|
299
|
-
this.platform.log.error(error);
|
|
300
|
-
await this.openAPIRefreshStatus();
|
|
301
|
-
});
|
|
302
|
-
}, this.platform.config.options!.refreshRate! * 60000);
|
|
251
|
+
return switchbot;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private async BLErefreshStatus() {
|
|
255
|
+
this.platform.debug('Meter BLE Device RefreshStatus');
|
|
256
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
257
|
+
const switchbot = this.connectBLE();
|
|
258
|
+
// Start to monitor advertisement packets
|
|
259
|
+
switchbot.startScan({
|
|
260
|
+
model: 'e',
|
|
261
|
+
id: this.device.bleMac,
|
|
262
|
+
}).then(() => {
|
|
263
|
+
// Set an event hander
|
|
264
|
+
switchbot.onadvertisement = (ad: ad) => {
|
|
265
|
+
this.serviceData = ad.serviceData;
|
|
266
|
+
this.temperature = ad.serviceData.temperature;
|
|
267
|
+
this.fahrenheit = ad.serviceData.fahrenheit;
|
|
268
|
+
this.humidity = ad.serviceData.humidity;
|
|
269
|
+
this.battery = ad.serviceData.battery;
|
|
270
|
+
this.platform.device(`${this.device.bleMac}: ${JSON.stringify(ad.serviceData)}`);
|
|
271
|
+
this.platform.device(`${this.accessory.displayName}, Model: ${ad.serviceData.model}, Model Name: ${ad.serviceData.modelName},`
|
|
272
|
+
+ `Temperature: ${ad.serviceData.temperature}, Fahrenheit: ${ad.serviceData.fahrenheit}, Humidity: ${ad.serviceData.humidity}`
|
|
273
|
+
+ `Battery: ${ad.serviceData.battery}`);
|
|
274
|
+
};
|
|
275
|
+
// Wait 10 seconds
|
|
276
|
+
return switchbot.wait(10000);
|
|
277
|
+
}).then(() => {
|
|
278
|
+
// Stop to monitor
|
|
279
|
+
switchbot.stopScan();
|
|
280
|
+
this.parseStatus();
|
|
281
|
+
this.updateHomeKitCharacteristics();
|
|
282
|
+
}).catch(async (e: any) => {
|
|
283
|
+
this.platform.log.error(`BLE Connection Failed: ${e.message}`);
|
|
284
|
+
this.platform.log.warn('Using OpenAPI Connection');
|
|
285
|
+
await this.openAPIRefreshStatus();
|
|
286
|
+
});
|
|
303
287
|
}
|
|
304
288
|
|
|
305
289
|
private async openAPIRefreshStatus() {
|
package/src/devices/motion.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Service, PlatformAccessory, CharacteristicValue
|
|
1
|
+
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
2
2
|
import { SwitchBotPlatform } from '../platform';
|
|
3
3
|
import { interval, Subject } from 'rxjs';
|
|
4
4
|
import { skipWhile } from 'rxjs/operators';
|
|
5
|
-
import { DeviceURL, device, devicesConfig } from '../settings';
|
|
5
|
+
import { DeviceURL, device, devicesConfig, serviceData, switchbot, deviceStatusResponse } from '../settings';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Platform Accessory
|
|
@@ -12,31 +12,28 @@ import { DeviceURL, device, devicesConfig } from '../settings';
|
|
|
12
12
|
export class Motion {
|
|
13
13
|
// Services
|
|
14
14
|
private service: Service;
|
|
15
|
+
private lightSensorService?: Service;
|
|
16
|
+
private batteryService?: Service;
|
|
15
17
|
|
|
16
18
|
// Characteristic Values
|
|
17
19
|
MotionDetected!: CharacteristicValue;
|
|
20
|
+
BatteryLevel?: CharacteristicValue;
|
|
21
|
+
StatusLowBattery?: CharacteristicValue;
|
|
22
|
+
CurrentAmbientLightLevel?: CharacteristicValue;
|
|
18
23
|
|
|
19
|
-
// Others
|
|
20
|
-
deviceStatus!:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
quick: boolean;
|
|
29
|
-
id: MacAddress;
|
|
30
|
-
}
|
|
31
|
-
) => Promise<any>;
|
|
32
|
-
wait: (
|
|
33
|
-
arg0: number
|
|
34
|
-
) => any;
|
|
35
|
-
};
|
|
24
|
+
// OpenAPI Others
|
|
25
|
+
deviceStatus!: deviceStatusResponse;
|
|
26
|
+
|
|
27
|
+
// BLE Others
|
|
28
|
+
switchbot!: switchbot;
|
|
29
|
+
serviceData!: serviceData;
|
|
30
|
+
battery!: serviceData['battery'];
|
|
31
|
+
movement!: serviceData['movement'];
|
|
32
|
+
lightLevel!: serviceData['lightLevel'];
|
|
36
33
|
|
|
37
34
|
// Updates
|
|
38
35
|
motionUbpdateInProgress!: boolean;
|
|
39
|
-
doMotionUpdate
|
|
36
|
+
doMotionUpdate!: Subject<void>;
|
|
40
37
|
|
|
41
38
|
constructor(
|
|
42
39
|
private readonly platform: SwitchBotPlatform,
|
|
@@ -77,6 +74,21 @@ export class Motion {
|
|
|
77
74
|
accessory.getService(this.platform.Service.MotionSensor) ||
|
|
78
75
|
accessory.addService(this.platform.Service.MotionSensor)), `${accessory.displayName} Motion Sensor`;
|
|
79
76
|
|
|
77
|
+
if (device.ble) {
|
|
78
|
+
(this.lightSensorService =
|
|
79
|
+
accessory.getService(this.platform.Service.LightSensor) ||
|
|
80
|
+
accessory.addService(this.platform.Service.LightSensor)), `${accessory.displayName} Light Sensor`;
|
|
81
|
+
|
|
82
|
+
this.lightSensorService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Light Sensor`);
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
(this.batteryService =
|
|
86
|
+
accessory.getService(this.platform.Service.Battery) ||
|
|
87
|
+
accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`;
|
|
88
|
+
|
|
89
|
+
this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`);
|
|
90
|
+
}
|
|
91
|
+
|
|
80
92
|
// To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
|
|
81
93
|
// when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
|
|
82
94
|
// accessory.getService('NAME') ?? accessory.addService(this.platform.Service.Motion, 'NAME', 'USER_DEFINED_SUBTYPE');
|
|
@@ -116,8 +128,24 @@ export class Motion {
|
|
|
116
128
|
}
|
|
117
129
|
|
|
118
130
|
private async BLEparseStatus() {
|
|
119
|
-
this.MotionDetected = Boolean(this.
|
|
131
|
+
this.MotionDetected = Boolean(this.movement);
|
|
120
132
|
this.platform.debug(`${this.accessory.displayName}, MotionDetected: ${this.MotionDetected}`);
|
|
133
|
+
// Light Level
|
|
134
|
+
switch (this.lightLevel) {
|
|
135
|
+
case 'dark':
|
|
136
|
+
case 0:
|
|
137
|
+
this.CurrentAmbientLightLevel = 0.0001;
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
this.CurrentAmbientLightLevel = 100000;
|
|
141
|
+
}
|
|
142
|
+
// Battery
|
|
143
|
+
this.BatteryLevel = Number(this.battery);
|
|
144
|
+
if (this.BatteryLevel < 10) {
|
|
145
|
+
this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
|
|
146
|
+
} else {
|
|
147
|
+
this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
|
|
148
|
+
}
|
|
121
149
|
}
|
|
122
150
|
|
|
123
151
|
private async openAPIparseStatus() {
|
|
@@ -131,15 +159,14 @@ export class Motion {
|
|
|
131
159
|
async refreshStatus() {
|
|
132
160
|
if (this.device.ble) {
|
|
133
161
|
this.platform.device('BLE');
|
|
134
|
-
await this.
|
|
162
|
+
await this.BLERefreshStatus();
|
|
135
163
|
} else {
|
|
136
164
|
this.platform.device('OpenAPI');
|
|
137
165
|
await this.openAPIRefreshStatus();
|
|
138
166
|
}
|
|
139
167
|
}
|
|
140
168
|
|
|
141
|
-
private
|
|
142
|
-
this.platform.debug('Motion BLE Device RefreshStatus');
|
|
169
|
+
private connectBLE() {
|
|
143
170
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
144
171
|
const Switchbot = require('node-switchbot');
|
|
145
172
|
const switchbot = new Switchbot();
|
|
@@ -147,46 +174,40 @@ export class Motion {
|
|
|
147
174
|
const bleMac = colon!.join(':'); //returns 1A:23:B4:56:78:9A;
|
|
148
175
|
this.device.bleMac = bleMac.toLowerCase();
|
|
149
176
|
this.platform.device(this.device.bleMac!);
|
|
150
|
-
switchbot
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
this.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return switchbot.wait(this.platform.config.options!.refreshRate! * 1000);
|
|
178
|
-
})
|
|
179
|
-
.then(() => {
|
|
180
|
-
switchbot.stopScan();
|
|
181
|
-
this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
|
|
182
|
-
})
|
|
183
|
-
.catch(async (error: any) => {
|
|
184
|
-
this.platform.log.error(error);
|
|
185
|
-
await this.openAPIRefreshStatus();
|
|
186
|
-
});
|
|
177
|
+
return switchbot;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private async BLERefreshStatus() {
|
|
181
|
+
this.platform.debug('Motion BLE Device RefreshStatus');
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
183
|
+
const switchbot = this.connectBLE();
|
|
184
|
+
// Start to monitor advertisement packets
|
|
185
|
+
switchbot.startScan({
|
|
186
|
+
model: 's',
|
|
187
|
+
id: this.device.bleMac,
|
|
188
|
+
}).then(() => {
|
|
189
|
+
// Set an event hander
|
|
190
|
+
switchbot.onadvertisement = (ad: any) => {
|
|
191
|
+
this.serviceData = ad.serviceData;
|
|
192
|
+
this.platform.device(`${this.device.bleMac}: ${JSON.stringify(ad.serviceData)}`);
|
|
193
|
+
this.movement = ad.serviceData.movement;
|
|
194
|
+
this.battery = ad.serviceData.battery;
|
|
195
|
+
this.lightLevel = ad.serviceData.lightLevel;
|
|
196
|
+
this.platform.device(`${this.accessory.displayName}, Movement: ${ad.serviceData.movement}, Light Level: ${ad.serviceData.lightLevel},`
|
|
197
|
+
+ ` Battery: ${ad.serviceData.battery}`);
|
|
198
|
+
};
|
|
199
|
+
// Wait 10 seconds
|
|
200
|
+
return switchbot.wait(10000);
|
|
201
|
+
}).then(() => {
|
|
202
|
+
// Stop to monitor
|
|
203
|
+
switchbot.stopScan();
|
|
187
204
|
this.parseStatus();
|
|
188
205
|
this.updateHomeKitCharacteristics();
|
|
189
|
-
}
|
|
206
|
+
}).catch(async (e: any) => {
|
|
207
|
+
this.platform.log.error(`BLE Connection Failed: ${e.message}`);
|
|
208
|
+
this.platform.log.warn('Using OpenAPI Connection');
|
|
209
|
+
await this.openAPIRefreshStatus();
|
|
210
|
+
});
|
|
190
211
|
}
|
|
191
212
|
|
|
192
213
|
private async openAPIRefreshStatus() {
|
|
@@ -212,9 +233,34 @@ export class Motion {
|
|
|
212
233
|
this.service.updateCharacteristic(this.platform.Characteristic.MotionDetected, this.MotionDetected);
|
|
213
234
|
this.platform.device(`Motion ${this.accessory.displayName} updateCharacteristic MotionDetected: ${this.MotionDetected}`);
|
|
214
235
|
}
|
|
236
|
+
if (this.device.ble) {
|
|
237
|
+
if (this.BatteryLevel === undefined) {
|
|
238
|
+
this.platform.debug(`Motion ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
|
|
239
|
+
} else {
|
|
240
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
|
|
241
|
+
this.platform.device(`Motion ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
|
|
242
|
+
}
|
|
243
|
+
if (this.StatusLowBattery === undefined) {
|
|
244
|
+
this.platform.debug(`Motion ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
|
|
245
|
+
} else {
|
|
246
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
|
|
247
|
+
this.platform.device(`Motion ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
|
|
248
|
+
}
|
|
249
|
+
if (this.CurrentAmbientLightLevel === undefined) {
|
|
250
|
+
this.platform.debug(`Motion ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
251
|
+
} else {
|
|
252
|
+
this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
|
|
253
|
+
this.platform.device(`Motion ${this.accessory.displayName} updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
215
256
|
}
|
|
216
257
|
|
|
217
258
|
public apiError(e: any) {
|
|
218
259
|
this.service.updateCharacteristic(this.platform.Characteristic.MotionDetected, e);
|
|
260
|
+
if (this.device.ble) {
|
|
261
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
|
|
262
|
+
this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
|
|
263
|
+
this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
|
|
264
|
+
}
|
|
219
265
|
}
|
|
220
266
|
}
|
package/src/devices/plugs.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Service, PlatformAccessory, CharacteristicValue
|
|
1
|
+
import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
|
|
2
2
|
import { SwitchBotPlatform } from '../platform';
|
|
3
3
|
import { interval, Subject } from 'rxjs';
|
|
4
4
|
import { debounceTime, skipWhile, tap } from 'rxjs/operators';
|
|
5
|
-
import { DeviceURL, device, devicesConfig } from '../settings';
|
|
5
|
+
import { DeviceURL, device, devicesConfig, switchbot, deviceStatusResponse } from '../settings';
|
|
6
6
|
|
|
7
7
|
export class Plug {
|
|
8
8
|
// Services
|
|
@@ -12,26 +12,15 @@ export class Plug {
|
|
|
12
12
|
On!: CharacteristicValue;
|
|
13
13
|
OutletInUse!: CharacteristicValue;
|
|
14
14
|
|
|
15
|
-
// Others
|
|
16
|
-
deviceStatus!:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
duration: any;
|
|
22
|
-
model: string;
|
|
23
|
-
quick: boolean;
|
|
24
|
-
id: MacAddress;
|
|
25
|
-
}
|
|
26
|
-
) => Promise<any>;
|
|
27
|
-
wait: (
|
|
28
|
-
arg0: number
|
|
29
|
-
) => any;
|
|
30
|
-
};
|
|
15
|
+
// OpenAPI Others
|
|
16
|
+
deviceStatus!: deviceStatusResponse;
|
|
17
|
+
|
|
18
|
+
// BLE Others
|
|
19
|
+
switchbot!: switchbot;
|
|
31
20
|
|
|
32
21
|
// Updates
|
|
33
22
|
plugUpdateInProgress!: boolean;
|
|
34
|
-
doPlugUpdate
|
|
23
|
+
doPlugUpdate!: Subject<void>;
|
|
35
24
|
|
|
36
25
|
constructor(
|
|
37
26
|
private readonly platform: SwitchBotPlatform,
|