@switchbot/homebridge-switchbot 1.7.1-beta.1 → 1.7.1-beta.13

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 +9 -2
  2. package/config.schema.json +49 -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 -66
  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 +50 -37
  10. package/dist/devices/colorbulb.js.map +1 -1
  11. package/dist/devices/contact.d.ts +9 -10
  12. package/dist/devices/contact.d.ts.map +1 -1
  13. package/dist/devices/contact.js +105 -137
  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 +70 -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 +42 -36
  22. package/dist/devices/humidifiers.js.map +1 -1
  23. package/dist/devices/meters.d.ts +17 -15
  24. package/dist/devices/meters.d.ts.map +1 -1
  25. package/dist/devices/meters.js +99 -133
  26. package/dist/devices/meters.js.map +1 -1
  27. package/dist/devices/motion.d.ts +8 -9
  28. package/dist/devices/motion.d.ts.map +1 -1
  29. package/dist/devices/motion.js +97 -120
  30. package/dist/devices/motion.js.map +1 -1
  31. package/dist/devices/plugs.d.ts +6 -4
  32. package/dist/devices/plugs.d.ts.map +1 -1
  33. package/dist/devices/plugs.js +44 -31
  34. package/dist/devices/plugs.js.map +1 -1
  35. package/dist/irdevices/airconditioners.d.ts +2 -1
  36. package/dist/irdevices/airconditioners.d.ts.map +1 -1
  37. package/dist/irdevices/airconditioners.js +19 -12
  38. package/dist/irdevices/airconditioners.js.map +1 -1
  39. package/dist/irdevices/airpurifiers.d.ts +4 -3
  40. package/dist/irdevices/airpurifiers.d.ts.map +1 -1
  41. package/dist/irdevices/airpurifiers.js +23 -16
  42. package/dist/irdevices/airpurifiers.js.map +1 -1
  43. package/dist/irdevices/cameras.d.ts +2 -1
  44. package/dist/irdevices/cameras.d.ts.map +1 -1
  45. package/dist/irdevices/cameras.js +19 -12
  46. package/dist/irdevices/cameras.js.map +1 -1
  47. package/dist/irdevices/fans.d.ts +2 -1
  48. package/dist/irdevices/fans.d.ts.map +1 -1
  49. package/dist/irdevices/fans.js +19 -12
  50. package/dist/irdevices/fans.js.map +1 -1
  51. package/dist/irdevices/lights.d.ts +2 -1
  52. package/dist/irdevices/lights.d.ts.map +1 -1
  53. package/dist/irdevices/lights.js +19 -12
  54. package/dist/irdevices/lights.js.map +1 -1
  55. package/dist/irdevices/others.d.ts +3 -2
  56. package/dist/irdevices/others.d.ts.map +1 -1
  57. package/dist/irdevices/others.js +23 -16
  58. package/dist/irdevices/others.js.map +1 -1
  59. package/dist/irdevices/tvs.d.ts +2 -1
  60. package/dist/irdevices/tvs.d.ts.map +1 -1
  61. package/dist/irdevices/tvs.js +19 -12
  62. package/dist/irdevices/tvs.js.map +1 -1
  63. package/dist/irdevices/vacuumcleaners.d.ts +2 -1
  64. package/dist/irdevices/vacuumcleaners.d.ts.map +1 -1
  65. package/dist/irdevices/vacuumcleaners.js +19 -12
  66. package/dist/irdevices/vacuumcleaners.js.map +1 -1
  67. package/dist/irdevices/waterheaters.d.ts +2 -1
  68. package/dist/irdevices/waterheaters.d.ts.map +1 -1
  69. package/dist/irdevices/waterheaters.js +19 -12
  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 +7 -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 +75 -70
  80. package/src/devices/colorbulb.ts +56 -40
  81. package/src/devices/contact.ts +108 -138
  82. package/src/devices/curtains.ts +79 -48
  83. package/src/devices/humidifiers.ts +50 -37
  84. package/src/devices/meters.ts +115 -143
  85. package/src/devices/motion.ts +102 -121
  86. package/src/devices/plugs.ts +47 -32
  87. package/src/irdevices/airconditioners.ts +20 -12
  88. package/src/irdevices/airpurifiers.ts +24 -16
  89. package/src/irdevices/cameras.ts +20 -12
  90. package/src/irdevices/fans.ts +20 -12
  91. package/src/irdevices/lights.ts +20 -12
  92. package/src/irdevices/others.ts +24 -16
  93. package/src/irdevices/tvs.ts +20 -12
  94. package/src/irdevices/vacuumcleaners.ts +20 -12
  95. package/src/irdevices/waterheaters.ts +20 -12
  96. package/src/platform.ts +14 -1
  97. package/src/settings.ts +7 -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'];
@@ -52,16 +56,12 @@ export class Contact {
52
56
  public device: device & devicesConfig,
53
57
  ) {
54
58
  // default placeholders
55
- this.logs();
56
- this.scan();
57
- this.refreshRate();
59
+ this.logs(device);
60
+ this.scan(device);
61
+ this.refreshRate(device);
62
+ this.config(device);
58
63
  this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
59
64
 
60
- // Contact Config
61
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} Config: (ble: ${device.ble}, offline: ${device.offline},`
62
- + ` hide_lightsensor: ${device.contact?.hide_lightsensor}, hide_motionsensor: ${device.contact?.hide_motionsensor},`
63
- + ` set_minLux: ${this.device.contact?.set_minLux}, set_maxLux: ${this.device.contact?.set_maxLux})`);
64
-
65
65
  // this is subject we use to track when we need to POST changes to the SwitchBot API
66
66
  this.doContactUpdate = new Subject();
67
67
  this.contactUbpdateInProgress = false;
@@ -128,12 +128,20 @@ export class Contact {
128
128
  }
129
129
 
130
130
  // Battery Service
131
- if (device.ble) {
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,50 +155,62 @@ export class Contact {
147
155
  });
148
156
  }
149
157
 
150
- refreshRate() {
151
- if (this.device.refreshRate) {
152
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.device.refreshRate;
153
- if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
154
- this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
155
- }
158
+ config(device: device & devicesConfig) {
159
+ const config: any = device.contact;
160
+ if (device.ble !== undefined) {
161
+ config['ble'] = device.ble;
162
+ }
163
+ if (device.logging !== undefined) {
164
+ config['logging'] = device.logging;
165
+ }
166
+ if (device.refreshRate !== undefined) {
167
+ config['refreshRate'] = device.refreshRate;
168
+ }
169
+ if (device.scanDuration !== undefined) {
170
+ config['scanDuration'] = device.scanDuration;
171
+ }
172
+ if (config !== undefined) {
173
+ this.warnLog(`Contact Sensor: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
174
+ }
175
+ }
176
+
177
+ refreshRate(device: device & devicesConfig) {
178
+ if (device.refreshRate) {
179
+ this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
180
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
156
181
  } else if (this.platform.config.options!.refreshRate) {
157
182
  this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
158
- if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
159
- this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
160
- }
183
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
161
184
  }
162
185
  }
163
186
 
164
- scan() {
165
- if (this.device.scanDuration) {
166
- this.scanDuration = this.accessory.context.scanDuration = this.device.scanDuration;
167
- if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
168
- this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
187
+ scan(device: device & devicesConfig) {
188
+ if (device.scanDuration) {
189
+ this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
190
+ if (device.ble) {
191
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
169
192
  }
170
193
  } else {
171
194
  this.scanDuration = this.accessory.context.scanDuration = 1;
172
- if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
173
- this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
195
+ if (this.device.ble) {
196
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
174
197
  }
175
198
  }
176
199
  }
177
200
 
178
- logs() {
201
+ logs(device: device & devicesConfig) {
179
202
  if (this.platform.debugMode) {
180
- this.deviceLogging = this.accessory.context.logging = 'debug';
181
- this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
182
- } else if (this.device.logging) {
183
- this.deviceLogging = this.accessory.context.logging = this.device.logging;
184
- if (this.deviceLogging === 'debug' || this.deviceLogging === 'standard') {
185
- this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
186
- }
203
+ this.deviceLogging = this.accessory.context.logging = 'debugMode';
204
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
205
+ } else if (device.logging) {
206
+ this.deviceLogging = this.accessory.context.logging = device.logging;
207
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
187
208
  } else if (this.platform.config.options?.logging) {
188
209
  this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
189
- if (this.deviceLogging === 'debug' || this.deviceLogging === 'standard') {
190
- this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
191
- }
210
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
192
211
  } else {
193
212
  this.deviceLogging = this.accessory.context.logging = 'standard';
213
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
194
214
  }
195
215
  }
196
216
 
@@ -216,10 +236,10 @@ export class Contact {
216
236
  * Parse the device status from the SwitchBot api
217
237
  */
218
238
  async parseStatus() {
219
- if (this.device.ble) {
220
- await this.BLEparseStatus();
221
- } else {
239
+ if (this.SwitchToOpenAPI || !this.device.ble) {
222
240
  await this.openAPIparseStatus();
241
+ } else {
242
+ await this.BLEparseStatus();
223
243
  }
224
244
  }
225
245
 
@@ -240,27 +260,23 @@ export class Contact {
240
260
  }
241
261
  // Movement
242
262
  if (!this.device.contact?.hide_motionsensor) {
243
- if (this.movement === undefined && this.platform.config.credentials?.openToken) {
244
- this.openAPImotion();
245
- } else if (this.movement === undefined) {
246
- this.movement = false;
247
- this.BLEmotion();
248
- } else {
249
- this.BLEmotion();
250
- }
263
+ this.MotionDetected = Boolean(this.movement);
264
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
251
265
  }
252
266
  // Light Level
253
267
  if (!this.device.contact?.hide_lightsensor) {
254
268
  this.set_minLux = this.minLux();
255
269
  this.set_maxLux = this.maxLux();
256
- if (this.lightLevel === undefined && this.platform.config.credentials?.openToken) {
257
- this.openAPIlux();
258
- } else if (this.lightLevel === undefined) {
259
- this.lightLevel = 100;
260
- this.BLElux();
261
- } else {
262
- this.BLElux();
270
+ switch (this.lightLevel) {
271
+ case 'dark':
272
+ case 0:
273
+ this.CurrentAmbientLightLevel = this.set_minLux;
274
+ break;
275
+ default:
276
+ this.CurrentAmbientLightLevel = this.set_maxLux;
263
277
  }
278
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
279
+ + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
264
280
  }
265
281
  // Battery
266
282
  if (this.battery === undefined) {
@@ -275,73 +291,44 @@ export class Contact {
275
291
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}, StatusLowBattery: ${this.StatusLowBattery}`);
276
292
  }
277
293
 
278
- private BLEmotion() {
279
- this.MotionDetected = Boolean(this.movement);
280
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
281
- }
282
-
283
- private BLElux() {
284
- switch (this.lightLevel) {
285
- case 'dark':
286
- case 0:
287
- this.CurrentAmbientLightLevel = this.set_minLux;
288
- break;
289
- default:
290
- this.CurrentAmbientLightLevel = this.set_maxLux;
291
- }
292
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} LightLevel: ${this.lightLevel},`
293
- + ` CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
294
- }
295
-
296
294
  private async openAPIparseStatus() {
295
+ if (this.device.ble) {
296
+ this.SwitchToOpenAPI = false;
297
+ }
297
298
  if (this.platform.config.credentials?.openToken) {
299
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
298
300
  // Contact State
299
- this.openAPIcontact();
301
+ if (this.openState === 'open') {
302
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
303
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
304
+ } else if (this.openState === 'close') {
305
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
306
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
307
+ } else {
308
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} openState: ${this.openState}`);
309
+ }
300
310
  // Motion State
301
311
  if (!this.device.contact?.hide_motionsensor) {
302
- this.openAPImotion();
312
+ this.MotionDetected = this.moveDetected!;
313
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
303
314
  }
304
315
  // Light Level
305
316
  if (!this.device.contact?.hide_lightsensor) {
306
- this.openAPIlux();
317
+ this.set_minLux = this.minLux();
318
+ this.set_maxLux = this.maxLux();
319
+ switch (this.brightness) {
320
+ case 'dim':
321
+ this.CurrentAmbientLightLevel = this.set_minLux;
322
+ break;
323
+ case 'bright':
324
+ default:
325
+ this.CurrentAmbientLightLevel = this.set_maxLux;
326
+ }
327
+ this.debugLog(`Contact Sensor: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
307
328
  }
308
329
  }
309
330
  }
310
331
 
311
- private openAPIlux() {
312
- this.set_minLux = this.minLux();
313
- this.set_maxLux = this.maxLux();
314
- switch (this.deviceStatus.body.brightness) {
315
- case 'dim':
316
- this.CurrentAmbientLightLevel = this.set_minLux;
317
- break;
318
- case 'bright':
319
- default:
320
- this.CurrentAmbientLightLevel = this.set_maxLux;
321
- }
322
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
323
- }
324
-
325
- private openAPImotion() {
326
- if (typeof this.deviceStatus.body.moveDetected === 'boolean') {
327
- this.MotionDetected = this.deviceStatus.body.moveDetected;
328
- }
329
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
330
- }
331
-
332
- private openAPIcontact() {
333
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} OpenAPI parseStatus`);
334
- if (this.deviceStatus.body.openState === 'open') {
335
- this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
336
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
337
- } else if (this.deviceStatus.body.openState === 'close') {
338
- this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
339
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
340
- } else {
341
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} openState: ${this.deviceStatus.body.openState}`);
342
- }
343
- }
344
-
345
332
  /**
346
333
  * Asks the SwitchBot API for the latest device information
347
334
  */
@@ -353,34 +340,12 @@ export class Contact {
353
340
  }
354
341
  }
355
342
 
356
- public async connectBLE() {
357
- let switchbot: any;
358
- try {
359
- // eslint-disable-next-line @typescript-eslint/no-var-requires
360
- const Switchbot = require('node-switchbot');
361
- switchbot = new Switchbot();
362
- // Convert to BLE Address
363
- this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
364
- this.debugLog(`Contact Sensor: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
365
- } catch (e: any) {
366
- switchbot = false;
367
- this.errorLog(`Contact Sensor: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot}`);
368
- if (this.deviceLogging === 'debug') {
369
- this.errorLog(`Contact Sensor: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot},`
370
- + ` Error Message: ${JSON.stringify(e.message)}`);
371
- }
372
- if (this.platform.debugMode) {
373
- this.errorLog(`Contact Sensor: ${this.accessory.displayName} 'node-switchbot' found: ${switchbot},`
374
- + ` Error: ${JSON.stringify(e)}`);
375
- }
376
- }
377
- return switchbot;
378
- }
379
-
380
343
  private async BLERefreshStatus() {
381
344
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} BLE refreshStatus`);
382
- // eslint-disable-next-line @typescript-eslint/no-var-requires
383
- const switchbot = await this.connectBLE();
345
+ const switchbot = await this.platform.connectBLE();
346
+ // Convert to BLE Address
347
+ this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
348
+ this.debugLog(`Curtain: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
384
349
  // Start to monitor advertisement packets
385
350
  if (switchbot !== false) {
386
351
  switchbot.startScan({
@@ -433,6 +398,7 @@ export class Contact {
433
398
  }
434
399
  if (this.platform.config.credentials?.openToken) {
435
400
  this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
401
+ this.SwitchToOpenAPI = true;
436
402
  await this.openAPIRefreshStatus();
437
403
  }
438
404
  this.apiError(e);
@@ -446,6 +412,7 @@ export class Contact {
446
412
  this.errorLog(`Contact Sensor: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
447
413
  if (this.platform.config.credentials?.openToken) {
448
414
  this.warnLog(`Contact Sensor: ${this.accessory.displayName} Using OpenAPI Connection`);
415
+ this.SwitchToOpenAPI = true;
449
416
  await this.openAPIRefreshStatus();
450
417
  }
451
418
  }
@@ -456,6 +423,9 @@ export class Contact {
456
423
  try {
457
424
  this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
458
425
  this.debugLog(`Contact Sensor: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
426
+ this.openState = this.deviceStatus.body.openState;
427
+ this.moveDetected = this.deviceStatus.body.moveDetected;
428
+ this.brightness = this.deviceStatus.body.brightness;
459
429
  this.parseStatus();
460
430
  this.updateHomeKitCharacteristics();
461
431
  } 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,16 +22,20 @@ 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'];
33
38
  lightLevel: serviceData['lightLevel'];
34
- spaceBetweenLevels!: number;
35
39
 
36
40
  // Target
37
41
  setNewTarget!: boolean;
@@ -39,7 +43,7 @@ export class Curtain {
39
43
 
40
44
  // Config
41
45
  set_minStep!: number;
42
- curtainRefreshRate!: number;
46
+ updateRate!: number;
43
47
  set_minLux!: number;
44
48
  set_maxLux!: number;
45
49
  scanDuration!: number;
@@ -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,25 @@ export class Curtain {
193
209
  });
194
210
  }
195
211
 
212
+ config(device: device & devicesConfig) {
213
+ const config: any = device.curtain;
214
+ if (device.ble !== undefined) {
215
+ config['ble'] = device.ble;
216
+ }
217
+ if (device.logging !== undefined) {
218
+ config['logging'] = device.logging;
219
+ }
220
+ if (device.refreshRate !== undefined) {
221
+ config['refreshRate'] = device.refreshRate;
222
+ }
223
+ if (device.scanDuration !== undefined) {
224
+ config['scanDuration'] = device.scanDuration;
225
+ }
226
+ if (config !== undefined) {
227
+ this.warnLog(`Curtain: ${this.accessory.displayName} Config: ${JSON.stringify(config)}`);
228
+ }
229
+ }
230
+
196
231
  refreshRate() {
197
232
  // refreshRate
198
233
  if (this.device.refreshRate) {
@@ -206,14 +241,14 @@ export class Curtain {
206
241
  this.warnLog(`Curtain: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
207
242
  }
208
243
  }
209
- // curtainRefreshRate
210
- if (this.device?.curtain?.refreshRate) {
211
- this.curtainRefreshRate = this.device?.curtain?.refreshRate;
244
+ // updateRate
245
+ if (this.device?.curtain?.updateRate) {
246
+ this.updateRate = this.device?.curtain?.updateRate;
212
247
  if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
213
248
  this.warnLog(`Curtain: ${this.accessory.displayName} Using Device Config Curtain refreshRate: ${this.deviceRefreshRate}`);
214
249
  }
215
250
  } else {
216
- this.curtainRefreshRate = 5;
251
+ this.updateRate = 5;
217
252
  if (this.platform.debugMode || (this.deviceLogging === 'debug')) {
218
253
  this.warnLog(`Curtain: ${this.accessory.displayName} Using Default Curtain Refresh Rate.`);
219
254
  }
@@ -253,30 +288,6 @@ export class Curtain {
253
288
  }
254
289
  }
255
290
 
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
291
  private minStep(): number {
281
292
  if (this.device.curtain?.set_minStep) {
282
293
  this.set_minStep = this.device.curtain?.set_minStep;
@@ -304,16 +315,20 @@ export class Curtain {
304
315
  return this.set_maxLux;
305
316
  }
306
317
 
318
+ /**
319
+ * Parse the device status from the SwitchBot api
320
+ */
307
321
  async parseStatus() {
308
- if (this.device.ble) {
309
- await this.BLEparseStatus();
310
- } else {
322
+ if (this.SwitchToOpenAPI || !this.device.ble) {
311
323
  await this.openAPIparseStatus();
324
+ } else {
325
+ await this.BLEparseStatus();
312
326
  }
313
327
  }
314
328
 
315
329
  private async BLEparseStatus() {
316
330
  this.debugLog(`Curtain: ${this.accessory.displayName} BLE parseStatus`);
331
+ // CurrentPosition
317
332
  this.setMinMax();
318
333
  this.CurrentPosition = 100 - Number(this.position);
319
334
  this.debugLog(`Curtain: ${this.accessory.displayName} CurrentPosition ${this.CurrentPosition}`);
@@ -339,6 +354,7 @@ export class Curtain {
339
354
  // If Curtain calibration distance is short, there will be an error between the current percentage and the target percentage.
340
355
  this.TargetPosition = this.CurrentPosition;
341
356
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
357
+ this.debugLog(`Curtain: ${this.accessory.displayName} Stopped`);
342
358
  }
343
359
  }
344
360
  this.debugLog(`Curtain: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
@@ -407,17 +423,20 @@ export class Curtain {
407
423
  }
408
424
 
409
425
  private async openAPIparseStatus() {
426
+ if (this.device.ble) {
427
+ this.SwitchToOpenAPI = false;
428
+ }
410
429
  if (this.platform.config.credentials?.openToken) {
411
430
  this.debugLog(`Curtain: ${this.accessory.displayName} OpenAPI parseStatus`);
412
431
  // CurrentPosition
413
432
  this.setMinMax();
414
- this.CurrentPosition = 100 - this.deviceStatus.body.slidePosition!;
433
+ this.CurrentPosition = 100 - Number(this.slidePosition);
415
434
  this.debugLog(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition}`);
416
435
  if (this.setNewTarget) {
417
- this.infoLog(`Checking ${this.accessory.displayName} Status ...`);
436
+ this.infoLog(`Curtain: ${this.accessory.displayName} Checking Status ...`);
418
437
  }
419
438
 
420
- if (this.deviceStatus.body.moving) {
439
+ if (this.setNewTarget && this.moving) {
421
440
  this.setMinMax();
422
441
  if (this.TargetPosition > this.CurrentPosition) {
423
442
  this.debugLog(`Curtain: ${this.accessory.displayName} Closing, CurrentPosition: ${this.CurrentPosition} `);
@@ -435,6 +454,7 @@ export class Curtain {
435
454
  /*If Curtain calibration distance is short, there will be an error between the current percentage and the target percentage.*/
436
455
  this.TargetPosition = this.CurrentPosition;
437
456
  this.PositionState = this.platform.Characteristic.PositionState.STOPPED;
457
+ this.debugLog(`Curtain: ${this.accessory.displayName} Stopped`);
438
458
  }
439
459
  }
440
460
  this.debugLog(`Curtain: ${this.accessory.displayName} CurrentPosition: ${this.CurrentPosition},`
@@ -444,7 +464,7 @@ export class Curtain {
444
464
  this.set_minLux = this.minLux();
445
465
  this.set_maxLux = this.maxLux();
446
466
  // Brightness
447
- switch (this.deviceStatus.body.brightness) {
467
+ switch (this.brightness) {
448
468
  case 'dim':
449
469
  this.CurrentAmbientLightLevel = this.set_minLux;
450
470
  break;
@@ -467,8 +487,10 @@ export class Curtain {
467
487
 
468
488
  private async BLERefreshStatus() {
469
489
  this.debugLog(`Curtain: ${this.accessory.displayName} BLE refreshStatus`);
470
- // eslint-disable-next-line @typescript-eslint/no-var-requires
471
- const switchbot = await this.connectBLE();
490
+ const switchbot = await this.platform.connectBLE();
491
+ // Convert to BLE Address
492
+ this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
493
+ this.debugLog(`Curtain: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
472
494
  // Start to monitor advertisement packets
473
495
  if (switchbot !== false) {
474
496
  switchbot.startScan({
@@ -506,6 +528,7 @@ export class Curtain {
506
528
  this.errorLog(`Curtain: ${this.accessory.displayName} wasn't able to establish BLE Connection`);
507
529
  if (this.platform.config.credentials?.openToken) {
508
530
  this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
531
+ this.SwitchToOpenAPI = true;
509
532
  await this.openAPIRefreshStatus();
510
533
  }
511
534
  }
@@ -521,6 +544,7 @@ export class Curtain {
521
544
  }
522
545
  if (this.platform.config.credentials?.openToken) {
523
546
  this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
547
+ this.SwitchToOpenAPI = true;
524
548
  await this.openAPIRefreshStatus();
525
549
  }
526
550
  this.apiError(e);
@@ -534,6 +558,7 @@ export class Curtain {
534
558
  this.errorLog(`Curtain: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
535
559
  if (this.platform.config.credentials?.openToken) {
536
560
  this.warnLog(`Curtain: ${this.accessory.displayName} Using OpenAPI Connection`);
561
+ this.SwitchToOpenAPI = true;
537
562
  await this.openAPIRefreshStatus();
538
563
  }
539
564
  }
@@ -544,6 +569,9 @@ export class Curtain {
544
569
  try {
545
570
  this.deviceStatus = (await this.platform.axios.get(`${DeviceURL}/${this.device.deviceId}/status`)).data;
546
571
  this.debugLog(`Curtain: ${this.accessory.displayName} refreshStatus: ${JSON.stringify(this.deviceStatus)}`);
572
+ this.slidePosition = this.deviceStatus.body.slidePosition;
573
+ this.moving = this.deviceStatus.body.moving;
574
+ this.brightness = this.deviceStatus.body.brightness;
547
575
  this.parseStatus();
548
576
  this.updateHomeKitCharacteristics();
549
577
  } catch (e: any) {
@@ -578,7 +606,10 @@ export class Curtain {
578
606
  private async BLEpushChanges() {
579
607
  if (this.TargetPosition !== this.CurrentPosition) {
580
608
  this.debugLog(`Curtain: ${this.accessory.displayName} BLE pushChanges`);
581
- const switchbot = await this.connectBLE();
609
+ const switchbot = await this.platform.connectBLE();
610
+ // Convert to BLE Address
611
+ this.device.bleMac = ((this.device.deviceId!.match(/.{1,2}/g))!.join(':')).toLowerCase();
612
+ this.debugLog(`Curtain: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
582
613
  if (switchbot !== false) {
583
614
  switchbot.discover({ model: 'c', quick: true, id: this.device.bleMac }).then((device_list) => {
584
615
  this.infoLog(`${this.accessory.displayName} Target Position: ${this.TargetPosition}`);