@switchbot/homebridge-switchbot 0.1.2-beta.0 → 0.1.2-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/.github/workflows/issue-validate.yml +1 -1
  2. package/dist/devices/bots.d.ts +1 -0
  3. package/dist/devices/bots.d.ts.map +1 -1
  4. package/dist/devices/bots.js +70 -22
  5. package/dist/devices/bots.js.map +1 -1
  6. package/dist/devices/bulb.d.ts +10 -1
  7. package/dist/devices/bulb.d.ts.map +1 -1
  8. package/dist/devices/bulb.js +12 -1
  9. package/dist/devices/bulb.js.map +1 -1
  10. package/dist/devices/contact.d.ts +13 -3
  11. package/dist/devices/contact.d.ts.map +1 -1
  12. package/dist/devices/contact.js +77 -2
  13. package/dist/devices/contact.js.map +1 -1
  14. package/dist/devices/curtains.d.ts +19 -8
  15. package/dist/devices/curtains.d.ts.map +1 -1
  16. package/dist/devices/curtains.js +96 -19
  17. package/dist/devices/curtains.js.map +1 -1
  18. package/dist/devices/humidifiers.d.ts.map +1 -1
  19. package/dist/devices/humidifiers.js +2 -2
  20. package/dist/devices/humidifiers.js.map +1 -1
  21. package/dist/devices/meters.d.ts +13 -4
  22. package/dist/devices/meters.d.ts.map +1 -1
  23. package/dist/devices/meters.js +28 -9
  24. package/dist/devices/meters.js.map +1 -1
  25. package/dist/devices/motion.d.ts +11 -3
  26. package/dist/devices/motion.d.ts.map +1 -1
  27. package/dist/devices/motion.js +67 -1
  28. package/dist/devices/motion.js.map +1 -1
  29. package/dist/devices/plugs.d.ts +11 -1
  30. package/dist/devices/plugs.d.ts.map +1 -1
  31. package/dist/devices/plugs.js +67 -1
  32. package/dist/devices/plugs.js.map +1 -1
  33. package/dist/irdevices/airconditioners.js +2 -2
  34. package/dist/irdevices/airconditioners.js.map +1 -1
  35. package/dist/irdevices/airpurifiers.js +2 -2
  36. package/dist/irdevices/airpurifiers.js.map +1 -1
  37. package/dist/irdevices/cameras.js +1 -1
  38. package/dist/irdevices/cameras.js.map +1 -1
  39. package/dist/irdevices/fans.js +1 -1
  40. package/dist/irdevices/fans.js.map +1 -1
  41. package/dist/irdevices/lights.js +3 -3
  42. package/dist/irdevices/lights.js.map +1 -1
  43. package/dist/irdevices/others.js +1 -1
  44. package/dist/irdevices/others.js.map +1 -1
  45. package/dist/irdevices/tvs.d.ts.map +1 -1
  46. package/dist/irdevices/tvs.js +2 -3
  47. package/dist/irdevices/tvs.js.map +1 -1
  48. package/dist/irdevices/vacuumcleaners.js +1 -1
  49. package/dist/irdevices/vacuumcleaners.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/devices/bots.ts +85 -35
  52. package/src/devices/bulb.ts +32 -2
  53. package/src/devices/contact.ts +101 -9
  54. package/src/devices/curtains.ts +135 -35
  55. package/src/devices/humidifiers.ts +7 -2
  56. package/src/devices/meters.ts +50 -14
  57. package/src/devices/motion.ts +90 -7
  58. package/src/devices/plugs.ts +89 -4
  59. package/src/irdevices/airconditioners.ts +2 -2
  60. package/src/irdevices/airpurifiers.ts +2 -2
  61. package/src/irdevices/cameras.ts +1 -1
  62. package/src/irdevices/fans.ts +1 -1
  63. package/src/irdevices/lights.ts +3 -3
  64. package/src/irdevices/others.ts +1 -1
  65. package/src/irdevices/tvs.ts +2 -4
  66. package/src/irdevices/vacuumcleaners.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-var-requires */
2
- import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
2
+ import { Service, PlatformAccessory, CharacteristicValue, MacAddress } from 'homebridge';
3
3
  import { SwitchBotPlatform } from '../platform';
4
4
  import { interval, Subject } from 'rxjs';
5
5
  import { debounceTime, skipWhile, tap } from 'rxjs/operators';
@@ -7,31 +7,51 @@ import { DeviceURL, device, deviceStatusResponse } from '../settings';
7
7
  import { AxiosResponse } from 'axios';
8
8
 
9
9
  export class Curtain {
10
+ // Services
10
11
  private service: Service;
12
+ private lightSensorService: Service;
11
13
 
14
+ // Characteristic Values
12
15
  CurrentPosition!: CharacteristicValue;
13
16
  PositionState!: CharacteristicValue;
14
17
  TargetPosition!: CharacteristicValue;
15
- deviceStatus!: deviceStatusResponse;
16
- setNewTarget!: boolean;
17
- setNewTargetTimer!: NodeJS.Timeout;
18
+ CurrentAmbientLightLevel!: CharacteristicValue;
18
19
 
19
- curtainUpdateInProgress!: boolean;
20
- doCurtainUpdate;
21
- switchbot;
20
+ // Others
21
+ deviceStatus!: deviceStatusResponse;
22
22
  moveTimer!: NodeJS.Timeout;
23
+ ScanIntervalId!: NodeJS.Timeout;
24
+ setNewTargetTimer!: NodeJS.Timeout;
25
+ AutoDisableFastScanTimeoutId!: NodeJS.Timeout;
26
+ setNewTarget!: boolean;
23
27
  moveTime!: number;
24
28
  ScanDuration: any;
25
29
  ReverseDir: any;
26
30
  FastScanEnabled!: boolean;
27
- ScanIntervalId!: NodeJS.Timeout;
28
31
  FastScanInterval!: number;
29
32
  SlowScanInterval!: number;
30
33
  OpenCloseThreshold: any;
31
34
  PreviousPosition: any;
32
35
  Position: any;
33
- AutoDisableFastScanTimeoutId;
34
36
  FastScanDuration: number | undefined;
37
+ switchbot!: {
38
+ discover: (
39
+ arg0:
40
+ {
41
+ duration: any;
42
+ model: string;
43
+ quick: boolean;
44
+ id: MacAddress;
45
+ }
46
+ ) => Promise<any>;
47
+ wait: (
48
+ arg0: number
49
+ ) => any;
50
+ };
51
+
52
+ // Updates
53
+ curtainUpdateInProgress!: boolean;
54
+ doCurtainUpdate;
35
55
 
36
56
  constructor(
37
57
  private readonly platform: SwitchBotPlatform,
@@ -75,7 +95,7 @@ export class Curtain {
75
95
  // you can create multiple services for each accessory
76
96
  (this.service =
77
97
  accessory.getService(this.platform.Service.WindowCovering) ||
78
- accessory.addService(this.platform.Service.WindowCovering)), '%s %s', device.deviceName, device.deviceType;
98
+ accessory.addService(this.platform.Service.WindowCovering)), `${device.deviceName} ${device.deviceType}`;
79
99
 
80
100
  // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
81
101
  // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
@@ -111,6 +131,21 @@ export class Curtain {
111
131
  })
112
132
  .onSet(this.TargetPositionSet.bind(this));
113
133
 
134
+ //set up brightness level from the builtin sensor as light sensor accessory
135
+ (this.lightSensorService =
136
+ accessory.getService(this.platform.Service.LightSensor) ||
137
+ accessory.addService(this.platform.Service.LightSensor)), 'Builtin Lightsensor of %s %s', device.deviceName, device.deviceType;
138
+ this.lightSensorService.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
139
+ // handle on / off events using the On characteristic
140
+ this.lightSensorService.getCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel).onGet(() => {
141
+ if (this.CurrentAmbientLightLevel === 'bright') {
142
+ return 100000;
143
+ } else {
144
+ return 0.0001;
145
+ }
146
+ });
147
+
148
+
114
149
  // Update Homekit
115
150
  this.updateHomeKitCharacteristics();
116
151
 
@@ -187,35 +222,94 @@ export class Curtain {
187
222
  }
188
223
  }
189
224
  }
225
+ // Brightness
226
+ switch (this.deviceStatus.body.brightness) {
227
+ case 'dim':
228
+ this.CurrentAmbientLightLevel = 0.0001;
229
+ break;
230
+ default:
231
+ this.CurrentAmbientLightLevel = 100000;
232
+ }
190
233
  this.platform.debug(
191
- `Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},
192
- TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState}`);
234
+ `Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}
235
+ , TargetPosition: ${this.TargetPosition}, PositionState: ${this.PositionState}
236
+ , CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
193
237
  }
194
238
 
195
239
  async refreshStatus() {
196
240
  if (this.platform.config.options?.ble?.includes(this.device.deviceId!)) {
197
- this.platform.log.warn('BLE DEVICE-1');
241
+ this.platform.log.warn('BLE DEVICE-REFRESH-1');
242
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
243
+ const Switchbot = require('node-switchbot');
244
+ const switchbot = new Switchbot();
245
+ const colon = this.device.deviceId!.match(/.{1,2}/g);
246
+ const bleMac = colon!.join(':'); //returns 1A:23:B4:56:78:9A;
247
+ this.device.bleMac = bleMac.toLowerCase();
248
+ if (this.platform.config.options.debug) {
249
+ this.platform.log.warn(this.device.bleMac!);
250
+ }
251
+ switchbot.onadvertisement = (ad: any) => {
252
+ this.platform.log.info(JSON.stringify(ad, null, ' '));
253
+ this.platform.log.warn('ad:', JSON.stringify(ad));
254
+ };
255
+ switchbot
256
+ .startScan({
257
+ id: this.device.bleMac,
258
+ })
259
+ .then(() => {
260
+ return switchbot.wait(this.platform.config.options!.refreshRate! * 1000);
261
+ })
262
+ .then(() => {
263
+ switchbot.stopScan();
264
+ })
265
+ .catch(async (error: any) => {
266
+ this.platform.log.error(error);
267
+ await this.openAPIRefreshStatus();
268
+ });
269
+ setInterval(() => {
270
+ this.platform.log.info('Start scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
271
+ switchbot
272
+ .startScan({
273
+ mode: 'T',
274
+ id: bleMac,
275
+ })
276
+ .then(() => {
277
+ return switchbot.wait(this.platform.config.options!.refreshRate! * 1000);
278
+ })
279
+ .then(() => {
280
+ switchbot.stopScan();
281
+ this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
282
+ })
283
+ .catch(async (error: any) => {
284
+ this.platform.log.error(error);
285
+ await this.openAPIRefreshStatus();
286
+ });
287
+ }, this.platform.config.options!.refreshRate! * 60000);
198
288
  } else {
199
- try {
200
- this.platform.debug('Curtain - Reading', `${DeviceURL}/${this.device.deviceId}/status`);
201
- const deviceStatus: deviceStatusResponse = (
202
- await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)
203
- ).data;
204
- if (deviceStatus.message === 'success') {
205
- this.deviceStatus = deviceStatus;
206
- this.platform.debug(`Curtain ${this.accessory.displayName} refreshStatus - ${JSON.stringify(this.deviceStatus)}`);
207
- this.setMinMax();
208
- this.parseStatus();
209
- this.updateHomeKitCharacteristics();
210
- }
211
- } catch (e: any) {
212
- this.platform.log.error(
213
- `Curtain - Failed to refresh status of ${this.device.deviceName}`,
214
- JSON.stringify(e.message),
215
- this.platform.debug(`Curtain ${this.accessory.displayName} - ${JSON.stringify(e)}`),
216
- );
217
- this.apiError(e);
289
+ await this.openAPIRefreshStatus();
290
+ }
291
+ }
292
+
293
+ private async openAPIRefreshStatus() {
294
+ try {
295
+ this.platform.debug('Curtain - Reading', `${DeviceURL}/${this.device.deviceId}/status`);
296
+ const deviceStatus: deviceStatusResponse = (
297
+ await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)
298
+ ).data;
299
+ if (deviceStatus.message === 'success') {
300
+ this.deviceStatus = deviceStatus;
301
+ this.platform.debug(`Curtain ${this.accessory.displayName} refreshStatus - ${JSON.stringify(this.deviceStatus)}`);
302
+ this.setMinMax();
303
+ this.parseStatus();
304
+ this.updateHomeKitCharacteristics();
218
305
  }
306
+ } catch (e: any) {
307
+ this.platform.log.error(
308
+ `Curtain - Failed to refresh status of ${this.device.deviceName}`,
309
+ JSON.stringify(e.message),
310
+ this.platform.debug(`Curtain ${this.accessory.displayName} - ${JSON.stringify(e)}`),
311
+ );
312
+ this.apiError(e);
219
313
  }
220
314
  }
221
315
 
@@ -258,7 +352,9 @@ export class Curtain {
258
352
  CurrentPosition: this.CurrentPosition,
259
353
  PositionState: this.PositionState,
260
354
  TargetPosition: this.TargetPosition,
261
- })}`);
355
+ CurrentAmbientLightLevel: this.CurrentAmbientLightLevel,
356
+ })}`,
357
+ );
262
358
  this.setMinMax();
263
359
  if (this.CurrentPosition !== undefined) {
264
360
  this.service.updateCharacteristic(this.platform.Characteristic.CurrentPosition, this.CurrentPosition);
@@ -269,12 +365,16 @@ export class Curtain {
269
365
  if (this.TargetPosition !== undefined) {
270
366
  this.service.updateCharacteristic(this.platform.Characteristic.TargetPosition, this.TargetPosition);
271
367
  }
368
+ if (this.CurrentAmbientLightLevel !== undefined) {
369
+ this.lightSensorService.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
370
+ }
272
371
  }
273
372
 
274
373
  public apiError(e: any) {
275
374
  this.service.updateCharacteristic(this.platform.Characteristic.CurrentPosition, e);
276
375
  this.service.updateCharacteristic(this.platform.Characteristic.PositionState, e);
277
376
  this.service.updateCharacteristic(this.platform.Characteristic.TargetPosition, e);
377
+ this.service.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
278
378
  }
279
379
 
280
380
 
@@ -406,7 +506,7 @@ export class Curtain {
406
506
  * Ask the device to start moving to the given position (which must be a device value and not an HomeKit value).
407
507
  * Returns a Promise that's resolved as soon as the command was sent to the device.
408
508
  */
409
- public runToPosition(pos: number): Promise<void> {
509
+ public async runToPosition(pos: number): Promise<void> {
410
510
  const SwitchBot = require('node-switchbot');
411
511
  const switchbot = new SwitchBot();
412
512
 
@@ -533,4 +633,4 @@ export class Curtain {
533
633
  }
534
634
  }
535
635
  }
536
- }
636
+ }
@@ -11,9 +11,11 @@ import { AxiosResponse } from 'axios';
11
11
  * Each accessory may expose multiple services of different service types.
12
12
  */
13
13
  export class Humidifier {
14
+ // Services
14
15
  private service: Service;
15
16
  temperatureservice?: Service;
16
17
 
18
+ // Characteristic Values
17
19
  CurrentRelativeHumidity!: CharacteristicValue;
18
20
  CurrentTemperature!: CharacteristicValue;
19
21
  TargetHumidifierDehumidifierState!: CharacteristicValue;
@@ -21,8 +23,11 @@ export class Humidifier {
21
23
  RelativeHumidityHumidifierThreshold!: CharacteristicValue;
22
24
  Active!: CharacteristicValue;
23
25
  WaterLevel!: CharacteristicValue;
26
+
27
+ // Others
24
28
  deviceStatus!: deviceStatusResponse;
25
29
 
30
+ // Updates
26
31
  humidifierUpdateInProgress!: boolean;
27
32
  doHumidifierUpdate;
28
33
 
@@ -58,7 +63,7 @@ export class Humidifier {
58
63
  // you can create multiple services for each accessory
59
64
  (this.service =
60
65
  accessory.getService(this.platform.Service.HumidifierDehumidifier) ||
61
- accessory.addService(this.platform.Service.HumidifierDehumidifier)), '%s %s', device.deviceName, device.deviceType;
66
+ accessory.addService(this.platform.Service.HumidifierDehumidifier)), `${device.deviceName} ${device.deviceType}`;
62
67
 
63
68
  // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
64
69
  // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
@@ -113,7 +118,7 @@ export class Humidifier {
113
118
  }
114
119
  (this.temperatureservice =
115
120
  this.accessory.getService(this.platform.Service.TemperatureSensor) ||
116
- this.accessory.addService(this.platform.Service.TemperatureSensor)), '%s %s TemperatureSensor', device.deviceName, device.deviceType;
121
+ this.accessory.addService(this.platform.Service.TemperatureSensor)), `${device.deviceName} ${device.deviceType} TemperatureSensor`;
117
122
 
118
123
  this.temperatureservice
119
124
  .getCharacteristic(this.platform.Characteristic.CurrentTemperature)
@@ -1,4 +1,4 @@
1
- import { Service, PlatformAccessory, Units, CharacteristicValue } from 'homebridge';
1
+ import { Service, PlatformAccessory, Units, CharacteristicValue, MacAddress } from 'homebridge';
2
2
  import { SwitchBotPlatform } from '../platform';
3
3
  import { interval, Subject } from 'rxjs';
4
4
  import { skipWhile } from 'rxjs/operators';
@@ -10,10 +10,12 @@ import { DeviceURL, device, deviceStatusResponse } from '../settings';
10
10
  * Each accessory may expose multiple services of different service types.
11
11
  */
12
12
  export class Meter {
13
+ // Services
13
14
  private service: Service;
14
15
  temperatureservice?: Service;
15
16
  humidityservice?: Service;
16
17
 
18
+ // Characteristic Values
17
19
  CurrentRelativeHumidity!: CharacteristicValue;
18
20
  CurrentTemperature!: CharacteristicValue;
19
21
  BatteryLevel!: CharacteristicValue;
@@ -21,13 +23,29 @@ export class Meter {
21
23
  StatusLowBattery!: CharacteristicValue;
22
24
  Active!: CharacteristicValue;
23
25
  WaterLevel!: CharacteristicValue;
26
+
27
+ // Others
24
28
  deviceStatus!: deviceStatusResponse;
25
- switchbot;
29
+ BLEtemperature!: number;
30
+ BLEHumidity!: number;
31
+ switchbot!: {
32
+ discover: (
33
+ arg0:
34
+ {
35
+ duration: any;
36
+ model: string;
37
+ quick: boolean;
38
+ id: MacAddress;
39
+ }
40
+ ) => Promise<any>;
41
+ wait: (
42
+ arg0: number
43
+ ) => any;
44
+ };
26
45
 
46
+ // Updates
27
47
  meterUpdateInProgress!: boolean;
28
48
  doMeterUpdate;
29
- BLEtemperature: any;
30
- BLEHumidity: any;
31
49
 
32
50
  constructor(
33
51
  private readonly platform: SwitchBotPlatform,
@@ -40,6 +58,17 @@ export class Meter {
40
58
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
41
59
  this.CurrentRelativeHumidity = 0;
42
60
  this.CurrentTemperature = 0;
61
+ if (this.platform.config.options?.ble?.includes(this.device.deviceId!)) {
62
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
63
+ const SwitchBot = require('node-switchbot');
64
+ this.switchbot = new SwitchBot();
65
+ const colon = device.deviceId!.match(/.{1,2}/g);
66
+ const bleMac = colon!.join(':'); //returns 1A:23:B4:56:78:9A;
67
+ this.device.bleMac = bleMac.toLowerCase();
68
+ if (this.platform.config.options.debug) {
69
+ this.platform.log.warn(this.device.bleMac.toLowerCase());
70
+ }
71
+ }
43
72
 
44
73
  // this is subject we use to track when we need to POST changes to the SwitchBot API
45
74
  this.doMeterUpdate = new Subject();
@@ -59,7 +88,7 @@ export class Meter {
59
88
  // you can create multiple services for each accessory
60
89
  (this.service =
61
90
  accessory.getService(this.platform.Service.Battery) ||
62
- accessory.addService(this.platform.Service.Battery)), '%s %s', device.deviceName, device.deviceType;
91
+ accessory.addService(this.platform.Service.Battery)), `${device.deviceName} ${device.deviceType}`;
63
92
 
64
93
  // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
65
94
  // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
@@ -88,7 +117,7 @@ export class Meter {
88
117
  }
89
118
  (this.temperatureservice =
90
119
  this.accessory.getService(this.platform.Service.TemperatureSensor) ||
91
- this.accessory.addService(this.platform.Service.TemperatureSensor)), '%s %s TemperatureSensor', device.deviceName, device.deviceType;
120
+ this.accessory.addService(this.platform.Service.TemperatureSensor)), `${device.deviceName} ${device.deviceType} TemperatureSensor`;
92
121
 
93
122
  this.temperatureservice
94
123
  .getCharacteristic(this.platform.Characteristic.CurrentTemperature)
@@ -119,7 +148,7 @@ export class Meter {
119
148
  } else if (!this.humidityservice) {
120
149
  (this.humidityservice =
121
150
  this.accessory.getService(this.platform.Service.HumiditySensor) ||
122
- this.accessory.addService(this.platform.Service.HumiditySensor)), '%s %s HumiditySensor', device.deviceName, device.deviceType;
151
+ this.accessory.addService(this.platform.Service.HumiditySensor)), `${device.deviceName} ${device.deviceType} HumiditySensor`;
123
152
 
124
153
  this.humidityservice
125
154
  .getCharacteristic(this.platform.Characteristic.CurrentRelativeHumidity)
@@ -194,6 +223,7 @@ export class Meter {
194
223
  */
195
224
  async refreshStatus() {
196
225
  if (this.platform.config.options?.ble?.includes(this.device.deviceId!)) {
226
+ this.platform.log.warn('BLE DEVICE-REFRESH');
197
227
  // eslint-disable-next-line @typescript-eslint/no-var-requires
198
228
  const Switchbot = require('node-switchbot');
199
229
  const switchbot = new Switchbot();
@@ -221,14 +251,15 @@ export class Meter {
221
251
  .then(() => {
222
252
  switchbot.stopScan();
223
253
  })
224
- .catch((error: any) => {
254
+ .catch(async (error: any) => {
225
255
  this.platform.log.error(error);
256
+ await this.openAPIRefreshStatus();
226
257
  });
227
258
  setInterval(() => {
228
- // log.info("Start scan " + name + "(" + bleMac + ")");
259
+ this.platform.log.info('Start scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
229
260
  switchbot
230
261
  .startScan({
231
- // mode: 'T',
262
+ mode: 'T',
232
263
  id: bleMac,
233
264
  })
234
265
  .then(() => {
@@ -236,20 +267,26 @@ export class Meter {
236
267
  })
237
268
  .then(() => {
238
269
  switchbot.stopScan();
239
- this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + bleMac + ')');
270
+ this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
240
271
  })
241
- .catch((error: any) => {
272
+ .catch(async (error: any) => {
242
273
  this.platform.log.error(error);
274
+ await this.openAPIRefreshStatus();
243
275
  });
244
276
  }, this.platform.config.options!.refreshRate! * 60000);
277
+ } else {
278
+ await this.openAPIRefreshStatus();
245
279
  }
280
+ }
281
+
282
+ private async openAPIRefreshStatus() {
246
283
  try {
247
284
  const deviceStatus: deviceStatusResponse = (
248
285
  await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)
249
286
  ).data;
250
287
  if (deviceStatus.message === 'success') {
251
288
  this.deviceStatus = deviceStatus;
252
- this.platform.debug(`Meter ${this.accessory.displayName} refreshStatus - ${JSON.stringify(this.deviceStatus)}`);
289
+ this.platform.debug(`Meter ${this.accessory.displayName} openAPIRefreshStatus - ${JSON.stringify(this.deviceStatus)}`);
253
290
  this.parseStatus();
254
291
  this.updateHomeKitCharacteristics();
255
292
  }
@@ -262,7 +299,6 @@ export class Meter {
262
299
  );
263
300
  this.apiError(e);
264
301
  }
265
-
266
302
  }
267
303
 
268
304
  /**
@@ -1,4 +1,4 @@
1
- import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
1
+ import { Service, PlatformAccessory, CharacteristicValue, MacAddress } from 'homebridge';
2
2
  import { SwitchBotPlatform } from '../platform';
3
3
  import { interval, Subject } from 'rxjs';
4
4
  import { skipWhile } from 'rxjs/operators';
@@ -10,13 +10,30 @@ import { DeviceURL, device, deviceStatusResponse } from '../settings';
10
10
  * Each accessory may expose multiple services of different service types.
11
11
  */
12
12
  export class Motion {
13
+ // Services
13
14
  private service: Service;
14
- temperatureservice?: Service;
15
- humidityservice?: Service;
16
15
 
16
+ // Characteristic Values
17
17
  MotionDetected!: CharacteristicValue;
18
- deviceStatus!: deviceStatusResponse;
19
18
 
19
+ // Others
20
+ deviceStatus!: deviceStatusResponse;
21
+ switchbot!: {
22
+ discover: (
23
+ arg0:
24
+ {
25
+ duration: any;
26
+ model: string;
27
+ quick: boolean;
28
+ id: MacAddress;
29
+ }
30
+ ) => Promise<any>;
31
+ wait: (
32
+ arg0: number
33
+ ) => any;
34
+ };
35
+
36
+ // Updates
20
37
  motionUbpdateInProgress!: boolean;
21
38
  doMotionUpdate;
22
39
 
@@ -28,6 +45,19 @@ export class Motion {
28
45
  // default placeholders
29
46
  this.MotionDetected = false;
30
47
 
48
+ // BLE Connection
49
+ if (this.platform.config.options?.ble?.includes(this.device.deviceId!)) {
50
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
51
+ const SwitchBot = require('node-switchbot');
52
+ this.switchbot = new SwitchBot();
53
+ const colon = device.deviceId!.match(/.{1,2}/g);
54
+ const bleMac = colon!.join(':'); //returns 1A:23:B4:56:78:9A;
55
+ this.device.bleMac = bleMac.toLowerCase();
56
+ if (this.platform.config.options.debug) {
57
+ this.platform.log.warn(this.device.bleMac.toLowerCase());
58
+ }
59
+ }
60
+
31
61
  // this is subject we use to track when we need to POST changes to the SwitchBot API
32
62
  this.doMotionUpdate = new Subject();
33
63
  this.motionUbpdateInProgress = false;
@@ -46,7 +76,7 @@ export class Motion {
46
76
  // you can create multiple services for each accessory
47
77
  (this.service =
48
78
  accessory.getService(this.platform.Service.MotionSensor) ||
49
- accessory.addService(this.platform.Service.MotionSensor)), '%s %s', device.deviceName, device.deviceType;
79
+ accessory.addService(this.platform.Service.MotionSensor)), `${device.deviceName} ${device.deviceType}`;
50
80
 
51
81
  // To avoid "Cannot add a Service with the same UUID another Service without also defining a unique 'subtype' property." error,
52
82
  // when creating multiple services of the same type, you need to use the following syntax to specify a name and subtype id:
@@ -89,6 +119,60 @@ export class Motion {
89
119
  * Asks the SwitchBot API for the latest device information
90
120
  */
91
121
  async refreshStatus() {
122
+ if (this.platform.config.options?.ble?.includes(this.device.deviceId!)) {
123
+ this.platform.log.warn('BLE DEVICE-REFRESH');
124
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
125
+ const Switchbot = require('node-switchbot');
126
+ const switchbot = new Switchbot();
127
+ const colon = this.device.deviceId!.match(/.{1,2}/g);
128
+ const bleMac = colon!.join(':'); //returns 1A:23:B4:56:78:9A;
129
+ this.device.bleMac = bleMac.toLowerCase();
130
+ if (this.platform.config.options.debug) {
131
+ this.platform.log.warn(this.device.bleMac!);
132
+ }
133
+ switchbot.onadvertisement = (ad: any) => {
134
+ this.platform.log.info(JSON.stringify(ad, null, ' '));
135
+ this.platform.log.warn('ad:', JSON.stringify(ad));
136
+ };
137
+ switchbot
138
+ .startScan({
139
+ id: this.device.bleMac,
140
+ })
141
+ .then(() => {
142
+ return switchbot.wait(this.platform.config.options!.refreshRate! * 1000);
143
+ })
144
+ .then(() => {
145
+ switchbot.stopScan();
146
+ })
147
+ .catch(async (error: any) => {
148
+ this.platform.log.error(error);
149
+ await this.openAPIRefreshStatus();
150
+ });
151
+ setInterval(() => {
152
+ this.platform.log.info('Start scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
153
+ switchbot
154
+ .startScan({
155
+ mode: 'M',
156
+ id: bleMac,
157
+ })
158
+ .then(() => {
159
+ return switchbot.wait(this.platform.config.options!.refreshRate! * 1000);
160
+ })
161
+ .then(() => {
162
+ switchbot.stopScan();
163
+ this.platform.log.info('Stop scan ' + this.device.deviceName + '(' + this.device.bleMac + ')');
164
+ })
165
+ .catch(async (error: any) => {
166
+ this.platform.log.error(error);
167
+ await this.openAPIRefreshStatus();
168
+ });
169
+ }, this.platform.config.options!.refreshRate! * 60000);
170
+ } else {
171
+ await this.openAPIRefreshStatus();
172
+ }
173
+ }
174
+
175
+ private async openAPIRefreshStatus() {
92
176
  try {
93
177
  const deviceStatus: deviceStatusResponse = (
94
178
  await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)
@@ -105,8 +189,7 @@ export class Motion {
105
189
  'Motion - Failed to update status of',
106
190
  this.device.deviceName,
107
191
  JSON.stringify(e.message),
108
- this.platform.debug(`Motion ${this.accessory.displayName} - ${JSON.stringify(e)}`),
109
- );
192
+ this.platform.debug(`Motion ${this.accessory.displayName} - ${JSON.stringify(e)}`));
110
193
  this.apiError(e);
111
194
  }
112
195
  }