@switchbot/homebridge-switchbot 2.0.0-beta.19 → 2.0.0-beta.20

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 (112) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/README.md +1 -2
  3. package/config.schema.json +51 -32
  4. package/dist/device/bot.d.ts +32 -29
  5. package/dist/device/bot.d.ts.map +1 -1
  6. package/dist/device/bot.js +549 -575
  7. package/dist/device/bot.js.map +1 -1
  8. package/dist/device/colorbulb.d.ts +33 -15
  9. package/dist/device/colorbulb.d.ts.map +1 -1
  10. package/dist/device/colorbulb.js +426 -341
  11. package/dist/device/colorbulb.js.map +1 -1
  12. package/dist/device/contact.d.ts +16 -9
  13. package/dist/device/contact.d.ts.map +1 -1
  14. package/dist/device/contact.js +246 -208
  15. package/dist/device/contact.js.map +1 -1
  16. package/dist/device/curtain.d.ts +21 -18
  17. package/dist/device/curtain.d.ts.map +1 -1
  18. package/dist/device/curtain.js +449 -449
  19. package/dist/device/curtain.js.map +1 -1
  20. package/dist/device/humidifier.d.ts +22 -20
  21. package/dist/device/humidifier.d.ts.map +1 -1
  22. package/dist/device/humidifier.js +346 -324
  23. package/dist/device/humidifier.js.map +1 -1
  24. package/dist/device/lock.d.ts +22 -10
  25. package/dist/device/lock.d.ts.map +1 -1
  26. package/dist/device/lock.js +257 -178
  27. package/dist/device/lock.js.map +1 -1
  28. package/dist/device/meter.d.ts +21 -14
  29. package/dist/device/meter.d.ts.map +1 -1
  30. package/dist/device/meter.js +287 -239
  31. package/dist/device/meter.js.map +1 -1
  32. package/dist/device/meterplus.d.ts +23 -10
  33. package/dist/device/meterplus.d.ts.map +1 -1
  34. package/dist/device/meterplus.js +308 -190
  35. package/dist/device/meterplus.js.map +1 -1
  36. package/dist/device/motion.d.ts +17 -10
  37. package/dist/device/motion.d.ts.map +1 -1
  38. package/dist/device/motion.js +225 -193
  39. package/dist/device/motion.js.map +1 -1
  40. package/dist/device/plug.d.ts +24 -17
  41. package/dist/device/plug.d.ts.map +1 -1
  42. package/dist/device/plug.js +270 -267
  43. package/dist/device/plug.js.map +1 -1
  44. package/dist/device/striplight.d.ts +36 -14
  45. package/dist/device/striplight.d.ts.map +1 -1
  46. package/dist/device/striplight.js +447 -299
  47. package/dist/device/striplight.js.map +1 -1
  48. package/dist/irdevice/airconditioner.d.ts +7 -14
  49. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  50. package/dist/irdevice/airconditioner.js +177 -169
  51. package/dist/irdevice/airconditioner.js.map +1 -1
  52. package/dist/irdevice/airpurifier.d.ts +3 -5
  53. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  54. package/dist/irdevice/airpurifier.js +72 -57
  55. package/dist/irdevice/airpurifier.js.map +1 -1
  56. package/dist/irdevice/camera.d.ts +3 -4
  57. package/dist/irdevice/camera.d.ts.map +1 -1
  58. package/dist/irdevice/camera.js +47 -33
  59. package/dist/irdevice/camera.js.map +1 -1
  60. package/dist/irdevice/fan.d.ts +3 -4
  61. package/dist/irdevice/fan.d.ts.map +1 -1
  62. package/dist/irdevice/fan.js +66 -48
  63. package/dist/irdevice/fan.js.map +1 -1
  64. package/dist/irdevice/light.d.ts +3 -4
  65. package/dist/irdevice/light.d.ts.map +1 -1
  66. package/dist/irdevice/light.js +48 -47
  67. package/dist/irdevice/light.js.map +1 -1
  68. package/dist/irdevice/other.d.ts +3 -4
  69. package/dist/irdevice/other.d.ts.map +1 -1
  70. package/dist/irdevice/other.js +47 -33
  71. package/dist/irdevice/other.js.map +1 -1
  72. package/dist/irdevice/tv.d.ts +10 -11
  73. package/dist/irdevice/tv.d.ts.map +1 -1
  74. package/dist/irdevice/tv.js +64 -48
  75. package/dist/irdevice/tv.js.map +1 -1
  76. package/dist/irdevice/vacuumcleaner.d.ts +7 -12
  77. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  78. package/dist/irdevice/vacuumcleaner.js +52 -41
  79. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  80. package/dist/irdevice/waterheater.d.ts +6 -11
  81. package/dist/irdevice/waterheater.d.ts.map +1 -1
  82. package/dist/irdevice/waterheater.js +52 -42
  83. package/dist/irdevice/waterheater.js.map +1 -1
  84. package/dist/platform.d.ts +0 -4
  85. package/dist/platform.d.ts.map +1 -1
  86. package/dist/platform.js +44 -66
  87. package/dist/platform.js.map +1 -1
  88. package/dist/settings.d.ts +3 -3
  89. package/dist/settings.d.ts.map +1 -1
  90. package/package.json +7 -6
  91. package/src/device/bot.ts +551 -589
  92. package/src/device/colorbulb.ts +441 -375
  93. package/src/device/contact.ts +249 -213
  94. package/src/device/curtain.ts +452 -461
  95. package/src/device/humidifier.ts +358 -365
  96. package/src/device/lock.ts +263 -179
  97. package/src/device/meter.ts +302 -253
  98. package/src/device/meterplus.ts +319 -194
  99. package/src/device/motion.ts +230 -199
  100. package/src/device/plug.ts +273 -274
  101. package/src/device/striplight.ts +460 -316
  102. package/src/irdevice/airconditioner.ts +181 -183
  103. package/src/irdevice/airpurifier.ts +70 -60
  104. package/src/irdevice/camera.ts +46 -36
  105. package/src/irdevice/fan.ts +64 -49
  106. package/src/irdevice/light.ts +47 -51
  107. package/src/irdevice/other.ts +46 -36
  108. package/src/irdevice/tv.ts +64 -51
  109. package/src/irdevice/vacuumcleaner.ts +52 -45
  110. package/src/irdevice/waterheater.ts +50 -45
  111. package/src/platform.ts +44 -68
  112. package/src/settings.ts +3 -3
@@ -7,6 +7,7 @@ import superStringify from 'super-stringify';
7
7
  import { SwitchBotPlatform } from '../platform';
8
8
  import { Service, PlatformAccessory, CharacteristicValue } from 'homebridge';
9
9
  import { device, devicesConfig, serviceData, switchbot, deviceStatus, ad, HostDomain, DevicePath } from '../settings';
10
+ import { IncomingMessage } from 'http';
10
11
 
11
12
  /**
12
13
  * Platform Accessory
@@ -33,15 +34,14 @@ export class Motion {
33
34
  // BLE Others
34
35
  connected?: boolean;
35
36
  switchbot!: switchbot;
36
- SwitchToOpenAPI?: boolean;
37
37
  serviceData!: serviceData;
38
38
  address!: ad['address'];
39
+ SwitchToOpenAPI?: boolean;
39
40
  battery!: serviceData['battery'];
40
41
  movement!: serviceData['movement'];
41
42
  lightLevel!: serviceData['lightLevel'];
42
43
 
43
44
  // Config
44
- OpenAPI?: boolean;
45
45
  set_minLux!: number;
46
46
  set_maxLux!: number;
47
47
  scanDuration!: number;
@@ -52,14 +52,17 @@ export class Motion {
52
52
  motionUbpdateInProgress!: boolean;
53
53
  doMotionUpdate!: Subject<void>;
54
54
 
55
+ // Connection
56
+ private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
57
+ private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
58
+
55
59
  constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
56
60
  // default placeholders
57
61
  this.logs(device);
58
- this.openAPI();
59
62
  this.scan(device);
60
63
  this.refreshRate(device);
61
64
  this.config(device);
62
- this.MotionDetected = false;
65
+ this.context();
63
66
 
64
67
  // this is subject we use to track when we need to POST changes to the SwitchBot API
65
68
  this.doMotionUpdate = new Subject();
@@ -111,11 +114,11 @@ export class Motion {
111
114
  }
112
115
 
113
116
  // Battery Service
114
- if (!device.ble) {
117
+ if (!this.BLE) {
115
118
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`);
116
119
  this.batteryService = this.accessory.getService(this.platform.Service.Battery);
117
120
  accessory.removeService(this.batteryService!);
118
- } else if (device.ble && !this.batteryService) {
121
+ } else if (this.BLE && !this.batteryService) {
119
122
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`);
120
123
  (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)),
121
124
  `${accessory.displayName} Battery`;
@@ -140,15 +143,19 @@ export class Motion {
140
143
  * Parse the device status from the SwitchBot api
141
144
  */
142
145
  async parseStatus(): Promise<void> {
143
- if (this.SwitchToOpenAPI || !this.device.ble) {
146
+ if (this.BLE && !this.SwitchToOpenAPI) {
147
+ await this.BLEparseStatus();
148
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
149
+ this.SwitchToOpenAPI = false;
144
150
  await this.openAPIparseStatus();
145
151
  } else {
146
- await this.BLEparseStatus();
152
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
153
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
147
154
  }
148
155
  }
149
156
 
150
157
  async BLEparseStatus(): Promise<void> {
151
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE parseStatus`);
158
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
152
159
  // Movement
153
160
  this.MotionDetected = this.movement!;
154
161
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
@@ -184,28 +191,23 @@ export class Motion {
184
191
  }
185
192
 
186
193
  async openAPIparseStatus(): Promise<void> {
187
- if (this.device.ble) {
188
- this.SwitchToOpenAPI = false;
189
- }
190
- if (this.platform.config.credentials?.token) {
191
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI parseStatus`);
192
- // Motion State
193
- this.MotionDetected = this.moveDetected!;
194
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
195
- // Light Level
196
- if (!this.device.motion?.hide_lightsensor) {
197
- this.set_minLux = this.minLux();
198
- this.set_maxLux = this.maxLux();
199
- switch (this.brightness) {
200
- case 'dim':
201
- this.CurrentAmbientLightLevel = this.set_minLux;
202
- break;
203
- case 'bright':
204
- default:
205
- this.CurrentAmbientLightLevel = this.set_maxLux;
206
- }
207
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
194
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
195
+ // Motion State
196
+ this.MotionDetected = this.moveDetected!;
197
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
198
+ // Light Level
199
+ if (!this.device.motion?.hide_lightsensor) {
200
+ this.set_minLux = this.minLux();
201
+ this.set_maxLux = this.maxLux();
202
+ switch (this.brightness) {
203
+ case 'dim':
204
+ this.CurrentAmbientLightLevel = this.set_minLux;
205
+ break;
206
+ case 'bright':
207
+ default:
208
+ this.CurrentAmbientLightLevel = this.set_maxLux;
208
209
  }
210
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
209
211
  }
210
212
  }
211
213
 
@@ -213,15 +215,18 @@ export class Motion {
213
215
  * Asks the SwitchBot API for the latest device information
214
216
  */
215
217
  async refreshStatus(): Promise<void> {
216
- if (this.device.ble) {
218
+ if (this.BLE) {
217
219
  await this.BLERefreshStatus();
218
- } else {
220
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
219
221
  await this.openAPIRefreshStatus();
222
+ } else {
223
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
224
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
220
225
  }
221
226
  }
222
227
 
223
228
  async BLERefreshStatus(): Promise<void> {
224
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE RefreshStatus`);
229
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
225
230
  const switchbot = await this.platform.connectBLE();
226
231
  // Convert to BLE Address
227
232
  this.device.bleMac =
@@ -231,7 +236,6 @@ export class Motion {
231
236
  .join(':')
232
237
  .toLowerCase();
233
238
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE Address: ${this.device.bleMac}`);
234
-
235
239
  this.getCustomBLEAddress(switchbot);
236
240
  // Start to monitor advertisement packets
237
241
  if (switchbot !== false) {
@@ -282,111 +286,67 @@ export class Motion {
282
286
  }
283
287
  })
284
288
  .catch(async (e: any) => {
285
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
286
- if (this.deviceLogging.includes('debug')) {
287
- this.errorLog(
288
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` +
289
- ` Error Message: ${superStringify(e.message)}`,
290
- );
291
- }
292
- if (this.platform.config.credentials?.token) {
293
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
294
- this.SwitchToOpenAPI = true;
295
- await this.openAPIRefreshStatus();
296
- }
297
289
  this.apiError(e);
290
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
291
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
292
+ await this.BLEconnection(switchbot);
298
293
  });
299
294
  } else {
300
295
  await this.BLEconnection(switchbot);
301
296
  }
302
297
  }
303
298
 
304
- async getCustomBLEAddress(switchbot: any) {
305
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
306
- (async () => {
307
- // Start to monitor advertisement packets
308
- await switchbot.startScan({
309
- model: 's',
310
- });
311
- // Set an event handler
312
- switchbot.onadvertisement = (ad: any) => {
313
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
314
- };
315
- await switchbot.wait(10000);
316
- // Stop to monitor
317
- switchbot.stopScan();
318
- })();
319
- }
320
- }
321
-
322
- async BLEconnection(switchbot: any): Promise<void> {
323
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
324
- if (this.platform.config.credentials?.token) {
325
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
326
- this.SwitchToOpenAPI = true;
327
- await this.openAPIRefreshStatus();
328
- }
329
- }
330
-
331
299
  async openAPIRefreshStatus(): Promise<void> {
332
- if (this.platform.config.credentials?.token && this.OpenAPI) {
333
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI RefreshStatus`);
334
- try {
335
- const t = Date.now();
336
- const nonce = 'requestID';
337
- const data = this.platform.config.credentials?.token + t + nonce;
338
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
339
- const sign = signTerm.toString('base64');
340
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
341
- const options = {
342
- hostname: HostDomain,
343
- port: 443,
344
- path: `${DevicePath}/${this.device.deviceId}/status`,
345
- method: 'GET',
346
- headers: {
347
- Authorization: this.platform.config.credentials?.token,
348
- sign: sign,
349
- nonce: nonce,
350
- t: t,
351
- 'Content-Type': 'application/json',
352
- },
353
- };
354
- const req = https.request(options, (res) => {
355
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
356
- let rawData = '';
357
- res.on('data', (d) => {
358
- rawData += d;
359
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
360
- });
361
- res.on('end', () => {
362
- try {
363
- this.deviceStatus = JSON.parse(rawData);
364
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
365
- this.moveDetected = this.deviceStatus.body.moveDetected;
366
- this.brightness = this.deviceStatus.body.brightness;
367
- this.parseStatus();
368
- this.updateHomeKitCharacteristics();
369
- } catch (e: any) {
370
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
371
- }
372
- });
300
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
301
+ try {
302
+ const t = Date.now();
303
+ const nonce = 'requestID';
304
+ const data = this.platform.config.credentials?.token + t + nonce;
305
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
306
+ const sign = signTerm.toString('base64');
307
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
308
+ const options = {
309
+ hostname: HostDomain,
310
+ port: 443,
311
+ path: `${DevicePath}/${this.device.deviceId}/status`,
312
+ method: 'GET',
313
+ headers: {
314
+ Authorization: this.platform.config.credentials?.token,
315
+ sign: sign,
316
+ nonce: nonce,
317
+ t: t,
318
+ 'Content-Type': 'application/json',
319
+ },
320
+ };
321
+ const req = https.request(options, (res) => {
322
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
323
+ this.statusCode({ res });
324
+ let rawData = '';
325
+ res.on('data', (d) => {
326
+ rawData += d;
327
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
373
328
  });
374
- req.on('error', (e: any) => {
375
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
329
+ res.on('end', () => {
330
+ try {
331
+ this.deviceStatus = JSON.parse(rawData);
332
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus: ${superStringify(this.deviceStatus)}`);
333
+ this.moveDetected = this.deviceStatus.body.moveDetected;
334
+ this.brightness = this.deviceStatus.body.brightness;
335
+ this.parseStatus();
336
+ this.updateHomeKitCharacteristics();
337
+ } catch (e: any) {
338
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
339
+ }
376
340
  });
377
- req.end();
378
- } catch (e: any) {
379
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
380
- if (this.deviceLogging.includes('debug')) {
381
- this.errorLog(
382
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` +
383
- ` Error Message: ${superStringify(e.message)}`,
384
- );
385
- }
386
- this.apiError(e);
387
- }
388
- } else {
389
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
341
+ });
342
+ req.on('error', (e: any) => {
343
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
344
+ });
345
+ req.end();
346
+ } catch (e: any) {
347
+ this.apiError(e);
348
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
349
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
390
350
  }
391
351
  }
392
352
 
@@ -397,25 +357,29 @@ export class Motion {
397
357
  if (this.MotionDetected === undefined) {
398
358
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
399
359
  } else {
360
+ this.accessory.context.MotionDetected = this.MotionDetected;
400
361
  this.motionSensorService.updateCharacteristic(this.platform.Characteristic.MotionDetected, this.MotionDetected);
401
362
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic MotionDetected: ${this.MotionDetected}`);
402
363
  }
403
- if (this.device.ble) {
364
+ if (this.BLE) {
404
365
  if (this.BatteryLevel === undefined) {
405
366
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
406
367
  } else {
368
+ this.accessory.context.BatteryLevel = this.BatteryLevel;
407
369
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
408
370
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
409
371
  }
410
372
  if (this.StatusLowBattery === undefined) {
411
373
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
412
374
  } else {
375
+ this.accessory.context.StatusLowBattery = this.StatusLowBattery;
413
376
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
414
377
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
415
378
  }
416
379
  if (this.CurrentAmbientLightLevel === undefined) {
417
380
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
418
381
  } else {
382
+ this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
419
383
  this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
420
384
  this.debugLog(
421
385
  `${this.device.deviceType}: ${this.accessory.displayName}`
@@ -425,90 +389,116 @@ export class Motion {
425
389
  }
426
390
  }
427
391
 
428
- async apiError(e: any): Promise<void> {
429
- this.motionSensorService.updateCharacteristic(this.platform.Characteristic.MotionDetected, e);
430
- if (this.device.ble) {
431
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
432
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
433
- this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
392
+ async getCustomBLEAddress(switchbot: any) {
393
+ if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
394
+ (async () => {
395
+ // Start to monitor advertisement packets
396
+ await switchbot.startScan({
397
+ model: 's',
398
+ });
399
+ // Set an event handler
400
+ switchbot.onadvertisement = (ad: any) => {
401
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
402
+ };
403
+ await switchbot.wait(10000);
404
+ // Stop to monitor
405
+ switchbot.stopScan();
406
+ })();
434
407
  }
435
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
436
408
  }
437
409
 
438
- async config(device: device & devicesConfig): Promise<void> {
439
- let config = {};
440
- if (device.motion) {
441
- config = device.motion;
442
- }
443
- if (device.ble !== undefined) {
444
- config['ble'] = device.ble;
445
- }
446
- if (device.openAPI !== undefined) {
447
- config['openAPI'] = device.openAPI;
448
- }
449
- if (device.logging !== undefined) {
450
- config['logging'] = device.logging;
451
- }
452
- if (device.refreshRate !== undefined) {
453
- config['refreshRate'] = device.refreshRate;
454
- }
455
- if (device.scanDuration !== undefined) {
456
- config['scanDuration'] = device.scanDuration;
457
- }
458
- if (device.offline !== undefined) {
459
- config['offline'] = device.offline;
460
- }
461
- if (Object.entries(config).length !== 0) {
462
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
410
+ async BLEconnection(switchbot: any): Promise<void> {
411
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
412
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
413
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
414
+ this.SwitchToOpenAPI = true;
415
+ await this.openAPIRefreshStatus();
463
416
  }
464
417
  }
465
418
 
466
- async refreshRate(device: device & devicesConfig): Promise<void> {
467
- if (device.refreshRate) {
468
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
469
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
470
- } else if (this.platform.config.options!.refreshRate) {
471
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
472
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
419
+ minLux(): number {
420
+ if (this.device.motion?.set_minLux) {
421
+ this.set_minLux = this.device.motion!.set_minLux!;
422
+ } else {
423
+ this.set_minLux = 1;
473
424
  }
425
+ return this.set_minLux;
474
426
  }
475
427
 
476
- async openAPI() {
477
- if (!this.device.openAPI) {
478
- this.OpenAPI = true;
428
+ maxLux(): number {
429
+ if (this.device.motion?.set_maxLux) {
430
+ this.set_maxLux = this.device.motion!.set_maxLux!;
479
431
  } else {
480
- this.OpenAPI = this.device.openAPI;
432
+ this.set_maxLux = 6001;
481
433
  }
482
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI: ${this.OpenAPI}`);
434
+ return this.set_maxLux;
483
435
  }
484
436
 
485
437
  async scan(device: device & devicesConfig): Promise<void> {
486
438
  if (device.scanDuration) {
487
439
  this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
488
- if (device.ble) {
440
+ if (this.BLE) {
489
441
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
490
442
  }
491
443
  } else {
492
444
  this.scanDuration = this.accessory.context.scanDuration = 1;
493
- if (this.device.ble) {
445
+ if (this.BLE) {
494
446
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
495
447
  }
496
448
  }
497
449
  }
498
450
 
499
- async logs(device: device & devicesConfig): Promise<void> {
500
- if (this.platform.debugMode) {
501
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
502
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
503
- } else if (device.logging) {
504
- this.deviceLogging = this.accessory.context.logging = device.logging;
505
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
506
- } else if (this.platform.config.options?.logging) {
507
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
508
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
509
- } else {
510
- this.deviceLogging = this.accessory.context.logging = 'standard';
511
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
451
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
452
+ switch (res.statusCode) {
453
+ case 151:
454
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
455
+ break;
456
+ case 152:
457
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
458
+ break;
459
+ case 160:
460
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
461
+ break;
462
+ case 161:
463
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
464
+ this.offlineOff();
465
+ break;
466
+ case 171:
467
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
468
+ this.offlineOff();
469
+ break;
470
+ case 190:
471
+ this.errorLog(
472
+ `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
473
+ ` Or command: ${superStringify(res)} format is invalid`,
474
+ );
475
+ break;
476
+ case 100:
477
+ if (this.platform.debugMode) {
478
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
479
+ }
480
+ break;
481
+ default:
482
+ if (this.platform.debugMode) {
483
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
484
+ }
485
+ }
486
+ }
487
+
488
+ async offlineOff(): Promise<void> {
489
+ if (this.device.offline) {
490
+ this.MotionDetected = false;
491
+ this.motionSensorService.getCharacteristic(this.platform.Characteristic.MotionDetected).updateValue(this.MotionDetected);
492
+ await this.updateHomeKitCharacteristics();
493
+ }
494
+ }
495
+
496
+ async apiError(e: any): Promise<void> {
497
+ this.motionSensorService.updateCharacteristic(this.platform.Characteristic.MotionDetected, e);
498
+ if (this.BLE) {
499
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
500
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
501
+ this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
512
502
  }
513
503
  }
514
504
 
@@ -528,22 +518,63 @@ export class Motion {
528
518
  return FirmwareRevision;
529
519
  }
530
520
 
531
- minLux(): number {
532
- if (this.device.motion?.set_minLux) {
533
- this.set_minLux = this.device.motion!.set_minLux!;
521
+ async context() {
522
+ if (this.MotionDetected === undefined) {
523
+ this.MotionDetected = false;
534
524
  } else {
535
- this.set_minLux = 1;
525
+ this.MotionDetected = this.accessory.context.MotionDetected;
536
526
  }
537
- return this.set_minLux;
538
527
  }
539
528
 
540
- maxLux(): number {
541
- if (this.device.motion?.set_maxLux) {
542
- this.set_maxLux = this.device.motion!.set_maxLux!;
529
+ async refreshRate(device: device & devicesConfig): Promise<void> {
530
+ if (device.refreshRate) {
531
+ this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
532
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
533
+ } else if (this.platform.config.options!.refreshRate) {
534
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
535
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
536
+ }
537
+ }
538
+
539
+ async config(device: device & devicesConfig): Promise<void> {
540
+ let config = {};
541
+ if (device.motion) {
542
+ config = device.motion;
543
+ }
544
+ if (device.connectionType !== undefined) {
545
+ config['connectionType'] = device.connectionType;
546
+ }
547
+ if (device.logging !== undefined) {
548
+ config['logging'] = device.logging;
549
+ }
550
+ if (device.refreshRate !== undefined) {
551
+ config['refreshRate'] = device.refreshRate;
552
+ }
553
+ if (device.scanDuration !== undefined) {
554
+ config['scanDuration'] = device.scanDuration;
555
+ }
556
+ if (device.offline !== undefined) {
557
+ config['offline'] = device.offline;
558
+ }
559
+ if (Object.entries(config).length !== 0) {
560
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
561
+ }
562
+ }
563
+
564
+ async logs(device: device & devicesConfig): Promise<void> {
565
+ if (this.platform.debugMode) {
566
+ this.deviceLogging = this.accessory.context.logging = 'debugMode';
567
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
568
+ } else if (device.logging) {
569
+ this.deviceLogging = this.accessory.context.logging = device.logging;
570
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
571
+ } else if (this.platform.config.options?.logging) {
572
+ this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
573
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
543
574
  } else {
544
- this.set_maxLux = 6001;
575
+ this.deviceLogging = this.accessory.context.logging = 'standard';
576
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
545
577
  }
546
- return this.set_maxLux;
547
578
  }
548
579
 
549
580
  /**