@switchbot/homebridge-switchbot 1.7.1-beta.0 → 1.7.1-beta.12

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 (97) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/config.schema.json +80 -36
  3. package/dist/devices/bots.d.ts +7 -5
  4. package/dist/devices/bots.d.ts.map +1 -1
  5. package/dist/devices/bots.js +72 -69
  6. package/dist/devices/bots.js.map +1 -1
  7. package/dist/devices/colorbulb.d.ts +9 -4
  8. package/dist/devices/colorbulb.d.ts.map +1 -1
  9. package/dist/devices/colorbulb.js +46 -36
  10. package/dist/devices/colorbulb.js.map +1 -1
  11. package/dist/devices/contact.d.ts +6 -3
  12. package/dist/devices/contact.d.ts.map +1 -1
  13. package/dist/devices/contact.js +59 -108
  14. package/dist/devices/contact.js.map +1 -1
  15. package/dist/devices/curtains.d.ts +11 -4
  16. package/dist/devices/curtains.d.ts.map +1 -1
  17. package/dist/devices/curtains.js +67 -44
  18. package/dist/devices/curtains.js.map +1 -1
  19. package/dist/devices/humidifiers.d.ts +8 -2
  20. package/dist/devices/humidifiers.d.ts.map +1 -1
  21. package/dist/devices/humidifiers.js +39 -36
  22. package/dist/devices/humidifiers.js.map +1 -1
  23. package/dist/devices/meters.d.ts +14 -12
  24. package/dist/devices/meters.d.ts.map +1 -1
  25. package/dist/devices/meters.js +63 -103
  26. package/dist/devices/meters.js.map +1 -1
  27. package/dist/devices/motion.d.ts +10 -3
  28. package/dist/devices/motion.d.ts.map +1 -1
  29. package/dist/devices/motion.js +114 -68
  30. package/dist/devices/motion.js.map +1 -1
  31. package/dist/devices/plugs.d.ts +3 -1
  32. package/dist/devices/plugs.d.ts.map +1 -1
  33. package/dist/devices/plugs.js +8 -1
  34. package/dist/devices/plugs.js.map +1 -1
  35. package/dist/irdevices/airconditioners.d.ts +1 -0
  36. package/dist/irdevices/airconditioners.d.ts.map +1 -1
  37. package/dist/irdevices/airconditioners.js +6 -0
  38. package/dist/irdevices/airconditioners.js.map +1 -1
  39. package/dist/irdevices/airpurifiers.d.ts +1 -0
  40. package/dist/irdevices/airpurifiers.d.ts.map +1 -1
  41. package/dist/irdevices/airpurifiers.js +6 -0
  42. package/dist/irdevices/airpurifiers.js.map +1 -1
  43. package/dist/irdevices/cameras.d.ts +1 -0
  44. package/dist/irdevices/cameras.d.ts.map +1 -1
  45. package/dist/irdevices/cameras.js +6 -0
  46. package/dist/irdevices/cameras.js.map +1 -1
  47. package/dist/irdevices/fans.d.ts +1 -0
  48. package/dist/irdevices/fans.d.ts.map +1 -1
  49. package/dist/irdevices/fans.js +6 -0
  50. package/dist/irdevices/fans.js.map +1 -1
  51. package/dist/irdevices/lights.d.ts +1 -0
  52. package/dist/irdevices/lights.d.ts.map +1 -1
  53. package/dist/irdevices/lights.js +6 -0
  54. package/dist/irdevices/lights.js.map +1 -1
  55. package/dist/irdevices/others.d.ts +1 -0
  56. package/dist/irdevices/others.d.ts.map +1 -1
  57. package/dist/irdevices/others.js +6 -0
  58. package/dist/irdevices/others.js.map +1 -1
  59. package/dist/irdevices/tvs.d.ts +1 -0
  60. package/dist/irdevices/tvs.d.ts.map +1 -1
  61. package/dist/irdevices/tvs.js +6 -0
  62. package/dist/irdevices/tvs.js.map +1 -1
  63. package/dist/irdevices/vacuumcleaners.d.ts +1 -0
  64. package/dist/irdevices/vacuumcleaners.d.ts.map +1 -1
  65. package/dist/irdevices/vacuumcleaners.js +6 -0
  66. package/dist/irdevices/vacuumcleaners.js.map +1 -1
  67. package/dist/irdevices/waterheaters.d.ts +1 -0
  68. package/dist/irdevices/waterheaters.d.ts.map +1 -1
  69. package/dist/irdevices/waterheaters.js +6 -0
  70. package/dist/irdevices/waterheaters.js.map +1 -1
  71. package/dist/platform.d.ts +2 -1
  72. package/dist/platform.d.ts.map +1 -1
  73. package/dist/platform.js +14 -1
  74. package/dist/platform.js.map +1 -1
  75. package/dist/settings.d.ts +13 -1
  76. package/dist/settings.d.ts.map +1 -1
  77. package/dist/settings.js.map +1 -1
  78. package/package.json +5 -5
  79. package/src/devices/bots.ts +74 -72
  80. package/src/devices/colorbulb.ts +52 -39
  81. package/src/devices/contact.ts +61 -113
  82. package/src/devices/curtains.ts +76 -48
  83. package/src/devices/humidifiers.ts +47 -37
  84. package/src/devices/meters.ts +79 -113
  85. package/src/devices/motion.ts +125 -74
  86. package/src/devices/plugs.ts +11 -2
  87. package/src/irdevices/airconditioners.ts +7 -0
  88. package/src/irdevices/airpurifiers.ts +7 -0
  89. package/src/irdevices/cameras.ts +7 -0
  90. package/src/irdevices/fans.ts +7 -0
  91. package/src/irdevices/lights.ts +7 -0
  92. package/src/irdevices/others.ts +7 -0
  93. package/src/irdevices/tvs.ts +7 -0
  94. package/src/irdevices/vacuumcleaners.ts +7 -0
  95. package/src/irdevices/waterheaters.ts +7 -0
  96. package/src/platform.ts +14 -1
  97. package/src/settings.ts +14 -1
@@ -2,7 +2,7 @@ import { interval, Subject } from 'rxjs';
2
2
  import { skipWhile } from 'rxjs/operators';
3
3
  import { SwitchBotPlatform } from '../platform';
4
4
  import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
5
- import { DeviceURL, device, devicesConfig, serviceData, switchbot, deviceStatusResponse } from '../settings';
5
+ import { DeviceURL, device, devicesConfig, serviceData, switchbot, deviceStatusResponse, deviceStatus } from '../settings';
6
6
 
7
7
  /**
8
8
  * Platform Accessory
@@ -24,11 +24,15 @@ export class Contact {
24
24
  StatusLowBattery!: CharacteristicValue;
25
25
 
26
26
  // OpenAPI others
27
+ openState: deviceStatus['openState'];
28
+ moveDetected: deviceStatus['moveDetected'];
29
+ brightness: deviceStatus['brightness'];
27
30
  deviceStatus!: deviceStatusResponse;
28
31
 
29
32
  // BLE Others
30
33
  connected?: boolean;
31
34
  switchbot!: switchbot;
35
+ SwitchToOpenAPI!: boolean;
32
36
  serviceData!: serviceData;
33
37
  battery!: serviceData['battery'];
34
38
  movement!: serviceData['movement'];
@@ -38,7 +42,6 @@ export class Contact {
38
42
  // Config
39
43
  set_minLux!: number;
40
44
  set_maxLux!: number;
41
- spaceBetweenLevels!: number;
42
45
  scanDuration!: number;
43
46
  deviceLogging!: string;
44
47
  deviceRefreshRate!: number;
@@ -56,13 +59,9 @@ export class Contact {
56
59
  this.logs();
57
60
  this.scan();
58
61
  this.refreshRate();
62
+ this.config(device);
59
63
  this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
60
64
 
61
- // Contact Config
62
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} Config: (ble: ${device.ble}, offline: ${device.offline},`
63
- + ` hide_lightsensor: ${device.contact?.hide_lightsensor}, hide_motionsensor: ${device.contact?.hide_motionsensor})`);
64
-
65
-
66
65
  // this is subject we use to track when we need to POST changes to the SwitchBot API
67
66
  this.doContactUpdate = new Subject();
68
67
  this.contactUbpdateInProgress = false;
@@ -92,7 +91,7 @@ export class Contact {
92
91
  this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.displayName);
93
92
 
94
93
  // each service must implement at-minimum the "required characteristics" for the given service type
95
- // see https://developers.homebridge.io/#/service/MotionSensor
94
+ // see https://developers.homebridge.io/#/service/ContactSensor
96
95
 
97
96
  // Motion Sensor Service
98
97
  if (device.contact?.hide_motionsensor) {
@@ -128,12 +127,21 @@ export class Contact {
128
127
  this.debugLog(`Contact Sensor: ${accessory.displayName} Light Sensor Service Not Added`);
129
128
  }
130
129
 
131
- if (device.ble) {
130
+ // Battery Service
131
+ if (!device.ble) {
132
+ this.debugLog(`Contact Sensor: ${accessory.displayName} Removing Battery Service`);
133
+ this.batteryService = this.accessory.getService(this.platform.Service.Battery);
134
+ accessory.removeService(this.batteryService!);
135
+ } else if (device.ble && !this.batteryService) {
136
+ this.debugLog(`Contact Sensor: ${accessory.displayName} Add Battery Service`);
132
137
  (this.batteryService =
133
- accessory.getService(this.platform.Service.Battery) ||
134
- accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`;
138
+ this.accessory.getService(this.platform.Service.Battery) ||
139
+ this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`;
135
140
 
136
141
  this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`);
142
+
143
+ } else {
144
+ this.debugLog(`Contact Sensor: ${accessory.displayName} Battery Service Not Added`);
137
145
  }
138
146
 
139
147
  // Retrieve initial values and updateHomekit
@@ -147,6 +155,12 @@ export class Contact {
147
155
  });
148
156
  }
149
157
 
158
+ config(device: device & devicesConfig) {
159
+ if (device.contact !== undefined) {
160
+ this.warnLog(`Contact Sensor: ${this.accessory.displayName} Config: ${JSON.stringify(device.contact)}`);
161
+ }
162
+ }
163
+
150
164
  refreshRate() {
151
165
  if (this.device.refreshRate) {
152
166
  this.deviceRefreshRate = this.accessory.context.refreshRate = this.device.refreshRate;
@@ -195,7 +209,7 @@ export class Contact {
195
209
  }
196
210
 
197
211
  private minLux(): number {
198
- if (this.device.curtain?.set_minLux) {
212
+ if (this.device.contact?.set_minLux) {
199
213
  this.set_minLux = this.device.contact!.set_minLux!;
200
214
  } else {
201
215
  this.set_minLux = 1;
@@ -204,7 +218,7 @@ export class Contact {
204
218
  }
205
219
 
206
220
  private maxLux(): number {
207
- if (this.device.curtain?.set_maxLux) {
221
+ if (this.device.contact?.set_maxLux) {
208
222
  this.set_maxLux = this.device.contact!.set_maxLux!;
209
223
  } else {
210
224
  this.set_maxLux = 6001;
@@ -216,19 +230,15 @@ export class Contact {
216
230
  * Parse the device status from the SwitchBot api
217
231
  */
218
232
  async parseStatus() {
219
- if (this.device.ble) {
220
- await this.BLEparseStatus();
221
- } else {
233
+ if (this.SwitchToOpenAPI || !this.device.ble) {
222
234
  await this.openAPIparseStatus();
235
+ } else {
236
+ await this.BLEparseStatus();
223
237
  }
224
238
  }
225
239
 
226
240
  private async BLEparseStatus() {
227
241
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} BLE parseStatus`);
228
- if (!this.device.contact?.hide_motionsensor) {
229
- // Movement
230
- this.MotionDetected = Boolean(this.movement);
231
- }
232
242
  // Door State
233
243
  switch (this.doorState) {
234
244
  case 'open':
@@ -242,110 +252,65 @@ export class Contact {
242
252
  default:
243
253
  this.errorLog(`Contact Sensor: ${this.accessory.displayName} timeout no closed, doorstate: ${this.doorState}`);
244
254
  }
245
- // Light Level
246
- if (!this.device.contact?.hide_lightsensor) {
247
- switch (this.lightLevel) {
248
- case 'dark':
249
- case 0:
250
- this.CurrentAmbientLightLevel = 0.0001;
251
- break;
252
- default:
253
- this.CurrentAmbientLightLevel = 100000;
254
- }
255
+ // Movement
256
+ if (!this.device.contact?.hide_motionsensor) {
257
+ this.MotionDetected = Boolean(this.movement);
258
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
255
259
  }
256
-
257
- /*
258
260
  // Light Level
259
261
  if (!this.device.contact?.hide_lightsensor) {
260
262
  this.set_minLux = this.minLux();
261
263
  this.set_maxLux = this.maxLux();
262
- this.spaceBetweenLevels = 9;
263
-
264
- //
265
264
  switch (this.lightLevel) {
266
- case 1:
265
+ case 'dark':
266
+ case 0:
267
267
  this.CurrentAmbientLightLevel = this.set_minLux;
268
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
269
- break;
270
- case 2:
271
- this.CurrentAmbientLightLevel = ((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels);
272
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
273
- + ` Calculation: ${((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels)}`);
274
- break;
275
- case 3:
276
- this.CurrentAmbientLightLevel = (((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 2);
277
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
278
- break;
279
- case 4:
280
- this.CurrentAmbientLightLevel = (((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 3);
281
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
282
- break;
283
- case 5:
284
- this.CurrentAmbientLightLevel = (((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 4);
285
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
286
- break;
287
- case 6:
288
- this.CurrentAmbientLightLevel = (((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 5);
289
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
290
268
  break;
291
- case 7:
292
- this.CurrentAmbientLightLevel = (((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 6);
293
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
294
- break;
295
- case 8:
296
- this.CurrentAmbientLightLevel = (((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 7);
297
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
298
- break;
299
- case 9:
300
- this.CurrentAmbientLightLevel = (((this.set_maxLux - this.set_minLux) / this.spaceBetweenLevels) * 8);
301
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel}`);
302
- break;
303
- case 10:
304
269
  default:
305
270
  this.CurrentAmbientLightLevel = this.set_maxLux;
306
- this.debugLog();
307
271
  }
308
- this.debugLog(`Curtain: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
272
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
309
273
  + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
310
- }*/
311
-
312
-
274
+ }
313
275
  // Battery
276
+ if (this.battery === undefined) {
277
+ this.battery === 100;
278
+ }
314
279
  this.BatteryLevel = Number(this.battery);
315
280
  if (this.BatteryLevel < 10) {
316
281
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW;
317
282
  } else {
318
283
  this.StatusLowBattery = this.platform.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
319
284
  }
320
-
321
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}, MotionDetected: `
322
- + `${this.MotionDetected}, CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}, BatteryLevel: ${this.BatteryLevel}`);
285
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
323
286
  }
324
287
 
325
288
  private async openAPIparseStatus() {
289
+ if (this.device.ble) {
290
+ this.SwitchToOpenAPI = false;
291
+ }
326
292
  if (this.platform.config.credentials?.openToken) {
327
- // Contact State
328
293
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
329
- if (this.deviceStatus.body.openState === 'open') {
294
+ // Contact State
295
+ if (this.openState === 'open') {
330
296
  this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
331
297
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
332
- } else if (this.deviceStatus.body.openState === 'close') {
298
+ } else if (this.openState === 'close') {
333
299
  this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
334
300
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
335
301
  } else {
336
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} openState: ${this.deviceStatus.body.openState}`);
302
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} openState: ${this.openState}`);
337
303
  }
338
304
  // Motion State
339
305
  if (!this.device.contact?.hide_motionsensor) {
340
- this.MotionDetected = Boolean(this.deviceStatus.body.moveDetected);
306
+ this.MotionDetected = this.moveDetected!;
307
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
341
308
  }
342
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
343
309
  // Light Level
344
310
  if (!this.device.contact?.hide_lightsensor) {
345
311
  this.set_minLux = this.minLux();
346
312
  this.set_maxLux = this.maxLux();
347
- // Brightness
348
- switch (this.deviceStatus.body.brightness) {
313
+ switch (this.brightness) {
349
314
  case 'dim':
350
315
  this.CurrentAmbientLightLevel = this.set_minLux;
351
316
  break;
@@ -369,34 +334,12 @@ export class Contact {
369
334
  }
370
335
  }
371
336
 
372
- public async connectBLE() {
373
- let switchbot: any;
374
- try {
375
- // eslint-disable-next-line @typescript-eslint/no-var-requires
376
- const Switchbot = require('node-switchbot');
377
- switchbot = new Switchbot();
378
- // Convert to BLE Address
379
- this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
380
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
381
- } catch (e: any) {
382
- switchbot = false;
383
- this.errorLog(`Contact Sensor: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot}`);
384
- if (this.deviceLogging === 'debug') {
385
- this.errorLog(`Contact Sensor: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot},`
386
- + ` Error Message: ${JSON.stringify(e.message)}`);
387
- }
388
- if (this.platform.debugMode) {
389
- this.errorLog(`Contact Sensor: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot},`
390
- + ` Error: ${JSON.stringify(e)}`);
391
- }
392
- }
393
- return switchbot;
394
- }
395
-
396
337
  private async BLERefreshStatus() {
397
338
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} BLE refreshStatus`);
398
- // eslint-disable-next-line @typescript-eslint/no-var-requires
399
- const switchbot = await this.connectBLE();
339
+ const switchbot = await this.platform.connectBLE();
340
+ // Convert to BLE Address
341
+ this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
342
+ this.debugLog(`Curtain: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
400
343
  // Start to monitor advertisement packets
401
344
  if (switchbot !== false) {
402
345
  switchbot.startScan({
@@ -449,6 +392,7 @@ export class Contact {
449
392
  }
450
393
  if (this.platform.config.credentials?.openToken) {
451
394
  this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
395
+ this.SwitchToOpenAPI = true;
452
396
  await this.openAPIRefreshStatus();
453
397
  }
454
398
  this.apiError(e);
@@ -462,6 +406,7 @@ export class Contact {
462
406
  this.errorLog(`Contact Sensor: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
463
407
  if (this.platform.config.credentials?.openToken) {
464
408
  this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
409
+ this.SwitchToOpenAPI = true;
465
410
  await this.openAPIRefreshStatus();
466
411
  }
467
412
  }
@@ -472,6 +417,9 @@ export class Contact {
472
417
  try {
473
418
  this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
474
419
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
420
+ this.openState = this.deviceStatus.body.openState;
421
+ this.moveDetected = this.deviceStatus.body.moveDetected;
422
+ this.brightness = this.deviceStatus.body.brightness;
475
423
  this.parseStatus();
476
424
  this.updateHomeKitCharacteristics();
477
425
  } catch (e: any) {
@@ -4,7 +4,7 @@ import { interval, Subject } from 'rxjs';
4
4
  import { SwitchBotPlatform } from '../platform';
5
5
  import { debounceTime, skipWhile, take, tap } from 'rxjs/operators';
6
6
  import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
7
- import { DeviceURL, device, devicesConfig, serviceData, switchbot, deviceStatusResponse, payload } from '../settings';
7
+ import { DeviceURL, device, devicesConfig, serviceData, switchbot, deviceStatusResponse, payload, deviceStatus } from '../settings';
8
8
 
9
9
  export class Curtain {
10
10
  // Services
@@ -22,11 +22,16 @@ export class Curtain {
22
22
 
23
23
  // OpenAPI Others
24
24
  deviceStatus!: deviceStatusResponse;
25
+ slidePosition: deviceStatus['slidePosition'];
26
+ moving: deviceStatus['moving'];
27
+ brightness: deviceStatus['brightness'];
25
28
 
26
29
  // BLE Others
27
30
  connected?: boolean;
28
31
  switchbot!: switchbot;
32
+ SwitchToOpenAPI?: boolean;
29
33
  serviceData!: serviceData;
34
+ spaceBetweenLevels!: number;
30
35
  calibration: serviceData['calibration'];
31
36
  battery: serviceData['battery'];
32
37
  position: serviceData['position'];
@@ -38,13 +43,12 @@ export class Curtain {
38
43
 
39
44
  // Config
40
45
  set_minStep!: number;
41
- curtainRefreshRate!: number;
46
+ updateRate!: number;
42
47
  set_minLux!: number;
43
48
  set_maxLux!: number;
44
49
  scanDuration!: number;
45
50
  deviceLogging!: string;
46
51
  deviceRefreshRate!: number;
47
- spaceBetweenLevels!: number;
48
52
 
49
53
  // Updates
50
54
  curtainUpdateInProgress!: boolean;
@@ -60,16 +64,11 @@ export class Curtain {
60
64
  this.scan();
61
65
  this.setMinMax();
62
66
  this.refreshRate();
67
+ this.config(device);
63
68
  this.CurrentPosition = 0;
64
69
  this.TargetPosition = 0;
65
70
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
66
71
 
67
- // Curtain Config
68
- this.debugLog(`Curtain: ${this.accessory.displayName} Config: (ble: ${device.ble}, disable_group: ${device.curtain?.disable_group},`
69
- + ` hide_lightsensor: ${device.curtain?.hide_lightsensor}, set_minLux: ${device.curtain?.set_minLux}, set_maxLux: `
70
- + `${device.curtain?.set_maxLux}, refreshRate: ${device.curtain?.refreshRate}, set_max: ${device.curtain?.set_max}, set_min: `
71
- + `${device.curtain?.set_min}, set_minStep: ${device.curtain?.set_minStep})`);
72
-
73
72
  // this is subject we use to track when we need to POST changes to the SwitchBot API
74
73
  this.doCurtainUpdate = new Subject();
75
74
  this.curtainUpdateInProgress = false;
@@ -142,6 +141,23 @@ export class Curtain {
142
141
  this.debugLog(`Curtain: ${accessory.displayName} Light Sensor Service Not Added`);
143
142
  }
144
143
 
144
+ // Battery Service
145
+ if (!device.ble) {
146
+ this.debugLog(`Curtain: ${accessory.displayName} Removing Battery Service`);
147
+ this.batteryService = this.accessory.getService(this.platform.Service.Battery);
148
+ accessory.removeService(this.batteryService!);
149
+ } else if (device.ble && !this.batteryService) {
150
+ this.debugLog(`Curtain: ${accessory.displayName} Add Battery Service`);
151
+ (this.batteryService =
152
+ this.accessory.getService(this.platform.Service.Battery) ||
153
+ this.accessory.addService(this.platform.Service.Battery)), `${accessory.displayName} Battery`;
154
+
155
+ this.batteryService.setCharacteristic(this.platform.Characteristic.Name, `${accessory.displayName} Battery`);
156
+
157
+ } else {
158
+ this.debugLog(`Curtain: ${accessory.displayName} Battery Service Not Added`);
159
+ }
160
+
145
161
 
146
162
  // Update Homekit
147
163
  this.updateHomeKitCharacteristics();
@@ -154,7 +170,7 @@ export class Curtain {
154
170
  });
155
171
 
156
172
  // update slide progress
157
- interval(this.curtainRefreshRate * 1000)
173
+ interval(this.updateRate * 1000)
158
174
  .pipe(skipWhile(() => this.curtainUpdateInProgress))
159
175
  .subscribe(() => {
160
176
  if (this.PositionState === this.platform.Characteristic.PositionState.STOPPED) {
@@ -193,6 +209,22 @@ export class Curtain {
193
209
  });
194
210
  }
195
211
 
212
+ config(device: device & devicesConfig) {
213
+ const config: any = device.curtain;
214
+ if (device.curtain !== undefined) {
215
+ if (device.ble !== undefined) {
216
+ config['ble'] = device.ble;
217
+ }
218
+ if (device.logging !== undefined) {
219
+ config['logging'] = device.logging;
220
+ }
221
+ if (device.refreshRate !== undefined) {
222
+ config['refreshRate'] = device.refreshRate;
223
+ }
224
+ this.warnLog(`Curtain: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
225
+ }
226
+ }
227
+
196
228
  refreshRate() {
197
229
  // refreshRate
198
230
  if (this.device.refreshRate) {
@@ -206,14 +238,14 @@ export class Curtain {
206
238
  this.warnLog(`Curtain: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
207
239
  }
208
240
  }
209
- // curtainRefreshRate
210
- if (this.device?.curtain?.refreshRate) {
211
- this.curtainRefreshRate = this.device?.curtain?.refreshRate;
241
+ // updateRate
242
+ if (this.device?.curtain?.updateRate) {
243
+ this.updateRate = this.device?.curtain?.updateRate;
212
244
  if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
213
245
  this.warnLog(`Curtain: ${this.accessory.displayName} Using Device Config Curtain refreshRate: ${this.deviceRefreshRate}`);
214
246
  }
215
247
  } else {
216
- this.curtainRefreshRate = 5;
248
+ this.updateRate = 5;
217
249
  if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
218
250
  this.warnLog(`Curtain: ${this.accessory.displayName} Using Default Curtain Refresh Rate.`);
219
251
  }
@@ -253,30 +285,6 @@ export class Curtain {
253
285
  }
254
286
  }
255
287
 
256
- public async connectBLE() {
257
- let switchbot: any;
258
- try {
259
- // eslint-disable-next-line @typescript-eslint/no-var-requires
260
- const Switchbot = require('node-switchbot');
261
- switchbot = new Switchbot();
262
- // Convert to BLE Address
263
- this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
264
- this.debugLog(`Curtain: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
265
- } catch (e: any) {
266
- switchbot = false;
267
- this.errorLog(`Curtain: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot}`);
268
- if (this.deviceLogging === 'debug') {
269
- this.errorLog(`Curtain: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot},`
270
- + ` Error Message: ${JSON.stringify(e.message)}`);
271
- }
272
- if (this.platform.debugMode) {
273
- this.errorLog(`Curtain: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot},`
274
- + ` Error: ${JSON.stringify(e)}`);
275
- }
276
- }
277
- return switchbot;
278
- }
279
-
280
288
  private minStep(): number {
281
289
  if (this.device.curtain?.set_minStep) {
282
290
  this.set_minStep = this.device.curtain?.set_minStep;
@@ -304,16 +312,20 @@ export class Curtain {
304
312
  return this.set_maxLux;
305
313
  }
306
314
 
315
+ /**
316
+ * Parse the device status from the SwitchBot api
317
+ */
307
318
  async parseStatus() {
308
- if (this.device.ble) {
309
- await this.BLEparseStatus();
310
- } else {
319
+ if (this.SwitchToOpenAPI || !this.device.ble) {
311
320
  await this.openAPIparseStatus();
321
+ } else {
322
+ await this.BLEparseStatus();
312
323
  }
313
324
  }
314
325
 
315
326
  private async BLEparseStatus() {
316
327
  this.debugLog(`Curtain: ${this.accessory.displayName} BLE parseStatus`);
328
+ // CurrentPosition
317
329
  this.setMinMax();
318
330
  this.CurrentPosition = 100 - Number(this.position);
319
331
  this.debugLog(`Curtain: ${this.accessory.displayName} CurrentPosition ${this.CurrentPosition}`);
@@ -339,6 +351,7 @@ export class Curtain {
339
351
  // If Curtain calibration distance is short, there will be an error between the current percentage and the target percentage.
340
352
  this.TargetPosition = this.CurrentPosition;
341
353
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
354
+ this.debugLog(`Curtain: ${this.accessory.displayName} Stopped`);
342
355
  }
343
356
  }
344
357
  this.debugLog(`Curtain: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
@@ -407,17 +420,20 @@ export class Curtain {
407
420
  }
408
421
 
409
422
  private async openAPIparseStatus() {
423
+ if (this.device.ble) {
424
+ this.SwitchToOpenAPI = false;
425
+ }
410
426
  if (this.platform.config.credentials?.openToken) {
411
427
  this.debugLog(`Curtain: ${this.accessory.displayName} OpenAPI parseStatus`);
412
428
  // CurrentPosition
413
429
  this.setMinMax();
414
- this.CurrentPosition = 100 - this.deviceStatus.body.slidePosition!;
430
+ this.CurrentPosition = 100 - Number(this.slidePosition);
415
431
  this.debugLog(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
416
432
  if (this.setNewTarget) {
417
- this.infoLog(`Checking ${this.accessory.displayName} Status ...`);
433
+ this.infoLog(`Curtain: ${this.accessory.displayName} Checking Status ...`);
418
434
  }
419
435
 
420
- if (this.deviceStatus.body.moving) {
436
+ if (this.setNewTarget && this.moving) {
421
437
  this.setMinMax();
422
438
  if (this.TargetPosition > this.CurrentPosition) {
423
439
  this.debugLog(`Curtain: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition} `);
@@ -435,6 +451,7 @@ export class Curtain {
435
451
  /*If Curtain calibration distance is short, there will be an error between the current percentage and the target percentage.*/
436
452
  this.TargetPosition = this.CurrentPosition;
437
453
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
454
+ this.debugLog(`Curtain: ${this.accessory.displayName} Stopped`);
438
455
  }
439
456
  }
440
457
  this.debugLog(`Curtain: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
@@ -444,7 +461,7 @@ export class Curtain {
444
461
  this.set_minLux = this.minLux();
445
462
  this.set_maxLux = this.maxLux();
446
463
  // Brightness
447
- switch (this.deviceStatus.body.brightness) {
464
+ switch (this.brightness) {
448
465
  case 'dim':
449
466
  this.CurrentAmbientLightLevel = this.set_minLux;
450
467
  break;
@@ -467,8 +484,10 @@ export class Curtain {
467
484
 
468
485
  private async BLERefreshStatus() {
469
486
  this.debugLog(`Curtain: ${this.accessory.displayName} BLE refreshStatus`);
470
- // eslint-disable-next-line @typescript-eslint/no-var-requires
471
- const switchbot = await this.connectBLE();
487
+ const switchbot = await this.platform.connectBLE();
488
+ // Convert to BLE Address
489
+ this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
490
+ this.debugLog(`Curtain: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
472
491
  // Start to monitor advertisement packets
473
492
  if (switchbot !== false) {
474
493
  switchbot.startScan({
@@ -506,6 +525,7 @@ export class Curtain {
506
525
  this.errorLog(`Curtain: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
507
526
  if (this.platform.config.credentials?.openToken) {
508
527
  this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
528
+ this.SwitchToOpenAPI = true;
509
529
  await this.openAPIRefreshStatus();
510
530
  }
511
531
  }
@@ -521,6 +541,7 @@ export class Curtain {
521
541
  }
522
542
  if (this.platform.config.credentials?.openToken) {
523
543
  this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
544
+ this.SwitchToOpenAPI = true;
524
545
  await this.openAPIRefreshStatus();
525
546
  }
526
547
  this.apiError(e);
@@ -534,6 +555,7 @@ export class Curtain {
534
555
  this.errorLog(`Curtain: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
535
556
  if (this.platform.config.credentials?.openToken) {
536
557
  this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
558
+ this.SwitchToOpenAPI = true;
537
559
  await this.openAPIRefreshStatus();
538
560
  }
539
561
  }
@@ -544,6 +566,9 @@ export class Curtain {
544
566
  try {
545
567
  this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
546
568
  this.debugLog(`Curtain: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
569
+ this.slidePosition = this.deviceStatus.body.slidePosition;
570
+ this.moving = this.deviceStatus.body.moving;
571
+ this.brightness = this.deviceStatus.body.brightness;
547
572
  this.parseStatus();
548
573
  this.updateHomeKitCharacteristics();
549
574
  } catch (e: any) {
@@ -578,7 +603,10 @@ export class Curtain {
578
603
  private async BLEpushChanges() {
579
604
  if (this.TargetPosition !== this.CurrentPosition) {
580
605
  this.debugLog(`Curtain: ${this.accessory.displayName} BLE pushChanges`);
581
- const switchbot = await this.connectBLE();
606
+ const switchbot = await this.platform.connectBLE();
607
+ // Convert to BLE Address
608
+ this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
609
+ this.debugLog(`Curtain: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
582
610
  if (switchbot !== false) {
583
611
  switchbot.discover({ model: 'c', quick: true, id: this.device.bleMac }).then((device_list) => {
584
612
  this.infoLog(`${this.accessory.displayName} Target Position: ${this.TargetPosition}`);