@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
@@ -45,7 +46,6 @@ export class Contact {
45
46
  lightLevel!: serviceData['lightLevel'];
46
47
 
47
48
  // Config
48
- OpenAPI?: boolean;
49
49
  set_minLux!: number;
50
50
  set_maxLux!: number;
51
51
  scanDuration!: number;
@@ -56,14 +56,17 @@ export class Contact {
56
56
  contactUbpdateInProgress!: boolean;
57
57
  doContactUpdate!: Subject<void>;
58
58
 
59
+ // Connection
60
+ private readonly BLE = (this.device.connectionType === 'BLE' || this.device.connectionType === 'Both');
61
+ private readonly OpenAPI = (this.device.connectionType === 'OpenAPI' || this.device.connectionType === 'Both');
62
+
59
63
  constructor(private readonly platform: SwitchBotPlatform, private accessory: PlatformAccessory, public device: device & devicesConfig) {
60
64
  // default placeholders
61
65
  this.logs(device);
62
- this.openAPI();
63
66
  this.scan(device);
64
67
  this.refreshRate(device);
65
68
  this.config(device);
66
- this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
69
+ this.context();
67
70
 
68
71
  // this is subject we use to track when we need to POST changes to the SwitchBot API
69
72
  this.doContactUpdate = new Subject();
@@ -132,11 +135,11 @@ export class Contact {
132
135
  }
133
136
 
134
137
  // Battery Service
135
- if (!device.ble) {
138
+ if (!this.BLE) {
136
139
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Removing Battery Service`);
137
140
  this.batteryService = this.accessory.getService(this.platform.Service.Battery);
138
141
  accessory.removeService(this.batteryService!);
139
- } else if (device.ble && !this.batteryService) {
142
+ } else if (this.BLE && !this.batteryService) {
140
143
  this.debugLog(`${this.device.deviceType}: ${accessory.displayName} Add Battery Service`);
141
144
  (this.batteryService = this.accessory.getService(this.platform.Service.Battery) || this.accessory.addService(this.platform.Service.Battery)),
142
145
  `${accessory.displayName} Battery`;
@@ -161,15 +164,19 @@ export class Contact {
161
164
  * Parse the device status from the SwitchBot api
162
165
  */
163
166
  async parseStatus(): Promise<void> {
164
- if (this.SwitchToOpenAPI || !this.device.ble) {
167
+ if (this.BLE && !this.SwitchToOpenAPI) {
168
+ await this.BLEparseStatus();
169
+ } else if (this.OpenAPI && this.platform.config.credentials?.token) {
170
+ this.SwitchToOpenAPI = false;
165
171
  await this.openAPIparseStatus();
166
172
  } else {
167
- await this.BLEparseStatus();
173
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
174
+ + ` ${this.device.connectionType}, parseStatus will not happen.`);
168
175
  }
169
176
  }
170
177
 
171
178
  async BLEparseStatus(): Promise<void> {
172
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE parseStatus`);
179
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLEparseStatus`);
173
180
  // Door State
174
181
  switch (this.doorState) {
175
182
  case 'open':
@@ -220,40 +227,35 @@ export class Contact {
220
227
  }
221
228
 
222
229
  async openAPIparseStatus(): Promise<void> {
223
- if (this.device.ble) {
224
- this.SwitchToOpenAPI = false;
230
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIparseStatus`);
231
+ // Contact State
232
+ if (this.openState === 'open') {
233
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
234
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
235
+ } else if (this.openState === 'close') {
236
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
237
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
238
+ } else {
239
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openState: ${this.openState}`);
225
240
  }
226
- if (this.platform.config.credentials?.token) {
227
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI parseStatus`);
228
- // Contact State
229
- if (this.openState === 'open') {
230
- this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_NOT_DETECTED;
231
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
232
- } else if (this.openState === 'close') {
233
- this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
234
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
235
- } else {
236
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openState: ${this.openState}`);
237
- }
238
- // Motion State
239
- if (!this.device.contact?.hide_motionsensor) {
240
- this.MotionDetected = this.moveDetected!;
241
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
242
- }
243
- // Light Level
244
- if (!this.device.contact?.hide_lightsensor) {
245
- this.set_minLux = this.minLux();
246
- this.set_maxLux = this.maxLux();
247
- switch (this.brightness) {
248
- case 'dim':
249
- this.CurrentAmbientLightLevel = this.set_minLux;
250
- break;
251
- case 'bright':
252
- default:
253
- this.CurrentAmbientLightLevel = this.set_maxLux;
254
- }
255
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
241
+ // Motion State
242
+ if (!this.device.contact?.hide_motionsensor) {
243
+ this.MotionDetected = this.moveDetected!;
244
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
245
+ }
246
+ // Light Level
247
+ if (!this.device.contact?.hide_lightsensor) {
248
+ this.set_minLux = this.minLux();
249
+ this.set_maxLux = this.maxLux();
250
+ switch (this.brightness) {
251
+ case 'dim':
252
+ this.CurrentAmbientLightLevel = this.set_minLux;
253
+ break;
254
+ case 'bright':
255
+ default:
256
+ this.CurrentAmbientLightLevel = this.set_maxLux;
256
257
  }
258
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
257
259
  }
258
260
  }
259
261
 
@@ -261,15 +263,18 @@ export class Contact {
261
263
  * Asks the SwitchBot API for the latest device information
262
264
  */
263
265
  async refreshStatus(): Promise<void> {
264
- if (this.device.ble) {
266
+ if (this.BLE) {
265
267
  await this.BLERefreshStatus();
266
- } else {
268
+ } else if (this.OpenAPI) {
267
269
  await this.openAPIRefreshStatus();
270
+ } else {
271
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Connection Type:`
272
+ + ` ${this.device.connectionType}, refreshStatus will not happen.`);
268
273
  }
269
274
  }
270
275
 
271
276
  async BLERefreshStatus(): Promise<void> {
272
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLE refreshStatus`);
277
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BLERefreshStatus`);
273
278
  const switchbot = await this.platform.connectBLE();
274
279
  // Convert to BLE Address
275
280
  this.device.bleMac =
@@ -330,112 +335,67 @@ export class Contact {
330
335
  }
331
336
  })
332
337
  .catch(async (e: any) => {
333
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection`);
334
- if (this.deviceLogging.includes('debug')) {
335
- this.errorLog(
336
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with BLE Connection,` +
337
- ` Error Message: ${superStringify(e.message)}`,
338
- );
339
- }
340
- if (this.platform.config.credentials?.token) {
341
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
342
- this.SwitchToOpenAPI = true;
343
- await this.openAPIRefreshStatus();
344
- }
345
338
  this.apiError(e);
339
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed BLERefreshStatus with ${this.device.connectionType}`
340
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
341
+ await this.BLEconnection(switchbot);
346
342
  });
347
343
  } else {
348
344
  await this.BLEconnection(switchbot);
349
345
  }
350
346
  }
351
347
 
352
- async getCustomBLEAddress(switchbot: any) {
353
- if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
354
- (async () => {
355
- // Start to monitor advertisement packets
356
- await switchbot.startScan({
357
- model: 'd',
358
- });
359
- // Set an event handler
360
- switchbot.onadvertisement = (ad: any) => {
361
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
362
- };
363
- await switchbot.wait(10000);
364
- // Stop to monitor
365
- switchbot.stopScan();
366
- })();
367
- }
368
- }
369
-
370
- async BLEconnection(switchbot: any): Promise<void> {
371
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
372
- if (this.platform.config.credentials?.token) {
373
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
374
- this.SwitchToOpenAPI = true;
375
- await this.openAPIRefreshStatus();
376
- }
377
- }
378
-
379
348
  async openAPIRefreshStatus(): Promise<void> {
380
- if (this.platform.config.credentials?.token && this.OpenAPI) {
381
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI refreshStatus`);
382
- try {
383
- const t = Date.now();
384
- const nonce = 'requestID';
385
- const data = this.platform.config.credentials?.token + t + nonce;
386
- const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
387
- const sign = signTerm.toString('base64');
388
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
389
- const options = {
390
- hostname: HostDomain,
391
- port: 443,
392
- path: `${DevicePath}/${this.device.deviceId}/status`,
393
- method: 'GET',
394
- headers: {
395
- Authorization: this.platform.config.credentials?.token,
396
- sign: sign,
397
- nonce: nonce,
398
- t: t,
399
- 'Content-Type': 'application/json',
400
- },
401
- };
402
- const req = https.request(options, (res) => {
403
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} statusCode: ${res.statusCode}`);
404
- let rawData = '';
405
- res.on('data', (d) => {
406
- rawData += d;
407
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
408
- });
409
- res.on('end', () => {
410
- try {
411
- this.deviceStatus = JSON.parse(rawData);
412
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
413
- this.openState = this.deviceStatus.body.openState;
414
- this.moveDetected = this.deviceStatus.body.moveDetected;
415
- this.brightness = this.deviceStatus.body.brightness;
416
- this.parseStatus();
417
- this.updateHomeKitCharacteristics();
418
- } catch (e: any) {
419
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
420
- }
421
- });
349
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus`);
350
+ try {
351
+ const t = Date.now();
352
+ const nonce = 'requestID';
353
+ const data = this.platform.config.credentials?.token + t + nonce;
354
+ const signTerm = crypto.createHmac('sha256', this.platform.config.credentials?.secret).update(Buffer.from(data, 'utf-8')).digest();
355
+ const sign = signTerm.toString('base64');
356
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} sign: ${sign}`);
357
+ const options = {
358
+ hostname: HostDomain,
359
+ port: 443,
360
+ path: `${DevicePath}/${this.device.deviceId}/status`,
361
+ method: 'GET',
362
+ headers: {
363
+ Authorization: this.platform.config.credentials?.token,
364
+ sign: sign,
365
+ nonce: nonce,
366
+ t: t,
367
+ 'Content-Type': 'application/json',
368
+ },
369
+ };
370
+ const req = https.request(options, (res) => {
371
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} openAPIRefreshStatus statusCode: ${res.statusCode}`);
372
+ let rawData = '';
373
+ res.on('data', (d) => {
374
+ rawData += d;
375
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} d: ${d}`);
422
376
  });
423
- req.on('error', (e: any) => {
424
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
377
+ res.on('end', () => {
378
+ try {
379
+ this.deviceStatus = JSON.parse(rawData);
380
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} refreshStatus: ${superStringify(this.deviceStatus)}`);
381
+ this.openState = this.deviceStatus.body.openState;
382
+ this.moveDetected = this.deviceStatus.body.moveDetected;
383
+ this.brightness = this.deviceStatus.body.brightness;
384
+ this.parseStatus();
385
+ this.updateHomeKitCharacteristics();
386
+ } catch (e: any) {
387
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
388
+ }
425
389
  });
426
- req.end();
427
- } catch (e: any) {
428
- this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection`);
429
- if (this.deviceLogging.includes('debug')) {
430
- this.errorLog(
431
- `${this.device.deviceType}: ${this.accessory.displayName} failed refreshStatus with OpenAPI Connection,` +
432
- ` Error Message: ${superStringify(e.message)}`,
433
- );
434
- }
435
- this.apiError(e);
436
- }
437
- } else {
438
- this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} OpenAPI is disabled, commands will not be sent.`);
390
+ });
391
+ req.on('error', (e: any) => {
392
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} error message: ${e.message}`);
393
+ });
394
+ req.end();
395
+ } catch (e: any) {
396
+ this.apiError(e);
397
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} failed openAPIRefreshStatus with ${this.device.connectionType}`
398
+ + ` Connection, Error Message: ${superStringify(e.message)}`);
439
399
  }
440
400
  }
441
401
 
@@ -446,6 +406,7 @@ export class Contact {
446
406
  if (this.ContactSensorState === undefined) {
447
407
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} ContactSensorState: ${this.ContactSensorState}`);
448
408
  } else {
409
+ this.accessory.context.ContactSensorState = this.ContactSensorState;
449
410
  this.contactSensorservice.updateCharacteristic(this.platform.Characteristic.ContactSensorState, this.ContactSensorState);
450
411
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic ContactSensorState: ${this.ContactSensorState}`);
451
412
  }
@@ -453,6 +414,7 @@ export class Contact {
453
414
  if (this.MotionDetected === undefined) {
454
415
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} MotionDetected: ${this.MotionDetected}`);
455
416
  } else {
417
+ this.accessory.context.MotionDetected = this.MotionDetected;
456
418
  this.motionService?.updateCharacteristic(this.platform.Characteristic.MotionDetected, this.MotionDetected);
457
419
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic MotionDetected: ${this.MotionDetected}`);
458
420
  }
@@ -461,115 +423,146 @@ export class Contact {
461
423
  if (this.CurrentAmbientLightLevel === undefined) {
462
424
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`);
463
425
  } else {
426
+ this.accessory.context.CurrentAmbientLightLevel = this.CurrentAmbientLightLevel;
464
427
  this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, this.CurrentAmbientLightLevel);
465
- this.debugLog(
466
- `${this.device.deviceType}: ${this.accessory.displayName}`
428
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
467
429
  + ` updateCharacteristic CurrentAmbientLightLevel: ${this.CurrentAmbientLightLevel}`,
468
430
  );
469
431
  }
470
432
  }
471
- if (this.device.ble) {
433
+ if (this.BLE) {
472
434
  if (this.BatteryLevel === undefined) {
473
435
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} BatteryLevel: ${this.BatteryLevel}`);
474
436
  } else {
437
+ this.accessory.context.BatteryLevel = this.BatteryLevel;
475
438
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, this.BatteryLevel);
476
439
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic BatteryLevel: ${this.BatteryLevel}`);
477
440
  }
478
441
  if (this.StatusLowBattery === undefined) {
479
442
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} StatusLowBattery: ${this.StatusLowBattery}`);
480
443
  } else {
444
+ this.accessory.context.StatusLowBattery = this.StatusLowBattery;
481
445
  this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, this.StatusLowBattery);
482
446
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} updateCharacteristic StatusLowBattery: ${this.StatusLowBattery}`);
483
447
  }
484
448
  }
485
449
  }
486
450
 
487
- async apiError(e: any): Promise<void> {
488
- this.contactSensorservice.updateCharacteristic(this.platform.Characteristic.ContactSensorState, e);
489
- if (!this.device.contact?.hide_motionsensor) {
490
- this.motionService?.updateCharacteristic(this.platform.Characteristic.MotionDetected, e);
491
- }
492
- if (!this.device.contact?.hide_lightsensor) {
493
- this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
494
- }
495
- if (this.device.ble) {
496
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
497
- this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
451
+ async getCustomBLEAddress(switchbot: any) {
452
+ if (this.device.customBLEaddress && this.deviceLogging.includes('debug')) {
453
+ (async () => {
454
+ // Start to monitor advertisement packets
455
+ await switchbot.startScan({
456
+ model: 'd',
457
+ });
458
+ // Set an event handler
459
+ switchbot.onadvertisement = (ad: any) => {
460
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} ad: ${superStringify(ad, null, ' ')}`);
461
+ };
462
+ await switchbot.wait(10000);
463
+ // Stop to monitor
464
+ switchbot.stopScan();
465
+ })();
498
466
  }
499
- //throw new this.platform.api.hap.HapStatusError(HAPStatus.SERVICE_COMMUNICATION_FAILURE);
500
467
  }
501
468
 
502
- async config(device: device & devicesConfig): Promise<void> {
503
- let config = {};
504
- if (device.contact) {
505
- config = device.contact;
506
- }
507
- if (device.ble) {
508
- config['ble'] = device.ble;
509
- }
510
- if (device.openAPI !== undefined) {
511
- config['openAPI'] = device.openAPI;
512
- }
513
- if (device.logging !== undefined) {
514
- config['logging'] = device.logging;
515
- }
516
- if (device.refreshRate !== undefined) {
517
- config['refreshRate'] = device.refreshRate;
518
- }
519
- if (device.scanDuration !== undefined) {
520
- config['scanDuration'] = device.scanDuration;
521
- }
522
- if (Object.entries(config).length !== 0) {
523
- this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
469
+ async BLEconnection(switchbot: any): Promise<void> {
470
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
471
+ if (this.platform.config.credentials?.token && this.device.connectionType !== 'Both') {
472
+ this.warnLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI Connection`);
473
+ this.SwitchToOpenAPI = true;
474
+ await this.openAPIRefreshStatus();
524
475
  }
525
476
  }
526
477
 
527
- async refreshRate(device: device & devicesConfig): Promise<void> {
528
- if (device.refreshRate) {
529
- this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
530
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
531
- } else if (this.platform.config.options!.refreshRate) {
532
- this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
533
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
478
+ minLux(): number {
479
+ if (this.device.contact?.set_minLux) {
480
+ this.set_minLux = this.device.contact!.set_minLux!;
481
+ } else {
482
+ this.set_minLux = 1;
534
483
  }
484
+ return this.set_minLux;
535
485
  }
536
486
 
537
- async openAPI() {
538
- if (!this.device.openAPI) {
539
- this.OpenAPI = true;
487
+ maxLux(): number {
488
+ if (this.device.contact?.set_maxLux) {
489
+ this.set_maxLux = this.device.contact!.set_maxLux!;
540
490
  } else {
541
- this.OpenAPI = this.device.openAPI;
491
+ this.set_maxLux = 6001;
542
492
  }
543
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using OpenAPI: ${this.OpenAPI}`);
493
+ return this.set_maxLux;
544
494
  }
545
495
 
546
496
  async scan(device: device & devicesConfig): Promise<void> {
547
497
  if (device.scanDuration) {
548
498
  this.scanDuration = this.accessory.context.scanDuration = device.scanDuration;
549
- if (device.ble) {
499
+ if (this.BLE) {
550
500
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config scanDuration: ${this.scanDuration}`);
551
501
  }
552
502
  } else {
553
503
  this.scanDuration = this.accessory.context.scanDuration = 1;
554
- if (this.device.ble) {
504
+ if (this.BLE) {
555
505
  this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Default scanDuration: ${this.scanDuration}`);
556
506
  }
557
507
  }
558
508
  }
559
509
 
560
- async logs(device: device & devicesConfig): Promise<void> {
561
- if (this.platform.debugMode) {
562
- this.deviceLogging = this.accessory.context.logging = 'debugMode';
563
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
564
- } else if (device.logging) {
565
- this.deviceLogging = this.accessory.context.logging = device.logging;
566
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
567
- } else if (this.platform.config.options?.logging) {
568
- this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
569
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
570
- } else {
571
- this.deviceLogging = this.accessory.context.logging = 'standard';
572
- this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
510
+ async statusCode({ res }: { res: IncomingMessage }): Promise<void> {
511
+ switch (res.statusCode) {
512
+ case 151:
513
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command not supported by this device type.`);
514
+ break;
515
+ case 152:
516
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device not found.`);
517
+ break;
518
+ case 160:
519
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Command is not supported.`);
520
+ break;
521
+ case 161:
522
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} Device is offline.`);
523
+ this.offlineOff();
524
+ break;
525
+ case 171:
526
+ this.errorLog(`${this.device.deviceType}: ${this.accessory.displayName} is offline. Hub: ${this.device.hubDeviceId}`);
527
+ this.offlineOff();
528
+ break;
529
+ case 190:
530
+ this.errorLog(
531
+ `${this.device.deviceType}: ${this.accessory.displayName} Device internal error due to device states not synchronized with server,` +
532
+ ` Or command: ${superStringify(res)} format is invalid`,
533
+ );
534
+ break;
535
+ case 100:
536
+ if (this.platform.debugMode) {
537
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Command successfully sent.`);
538
+ }
539
+ break;
540
+ default:
541
+ if (this.platform.debugMode) {
542
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Unknown statusCode.`);
543
+ }
544
+ }
545
+ }
546
+
547
+ async offlineOff(): Promise<void> {
548
+ if (this.device.offline) {
549
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
550
+ this.contactSensorservice.getCharacteristic(this.platform.Characteristic.ContactSensorState).updateValue(this.ContactSensorState);
551
+ await this.updateHomeKitCharacteristics();
552
+ }
553
+ }
554
+
555
+ async apiError(e: any): Promise<void> {
556
+ this.contactSensorservice.updateCharacteristic(this.platform.Characteristic.ContactSensorState, e);
557
+ if (!this.device.contact?.hide_motionsensor) {
558
+ this.motionService?.updateCharacteristic(this.platform.Characteristic.MotionDetected, e);
559
+ }
560
+ if (!this.device.contact?.hide_lightsensor) {
561
+ this.lightSensorService?.updateCharacteristic(this.platform.Characteristic.CurrentAmbientLightLevel, e);
562
+ }
563
+ if (this.BLE) {
564
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.BatteryLevel, e);
565
+ this.batteryService?.updateCharacteristic(this.platform.Characteristic.StatusLowBattery, e);
573
566
  }
574
567
  }
575
568
 
@@ -589,22 +582,65 @@ export class Contact {
589
582
  return FirmwareRevision;
590
583
  }
591
584
 
592
- minLux(): number {
593
- if (this.device.contact?.set_minLux) {
594
- this.set_minLux = this.device.contact!.set_minLux!;
585
+ async context() {
586
+ if (this.MotionDetected === undefined) {
587
+ this.MotionDetected = false;
595
588
  } else {
596
- this.set_minLux = 1;
589
+ this.MotionDetected = this.accessory.context.MotionDetected;
590
+ }
591
+ if (this.ContactSensorState === undefined) {
592
+ this.ContactSensorState = this.platform.Characteristic.ContactSensorState.CONTACT_DETECTED;
593
+ } else {
594
+ this.ContactSensorState = this.accessory.context.ContactSensorState;
597
595
  }
598
- return this.set_minLux;
599
596
  }
600
597
 
601
- maxLux(): number {
602
- if (this.device.contact?.set_maxLux) {
603
- this.set_maxLux = this.device.contact!.set_maxLux!;
598
+ async refreshRate(device: device & devicesConfig): Promise<void> {
599
+ if (device.refreshRate) {
600
+ this.deviceRefreshRate = this.accessory.context.refreshRate = device.refreshRate;
601
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config refreshRate: ${this.deviceRefreshRate}`);
602
+ } else if (this.platform.config.options!.refreshRate) {
603
+ this.deviceRefreshRate = this.accessory.context.refreshRate = this.platform.config.options!.refreshRate;
604
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
605
+ }
606
+ }
607
+
608
+ async config(device: device & devicesConfig): Promise<void> {
609
+ let config = {};
610
+ if (device.contact) {
611
+ config = device.contact;
612
+ }
613
+ if (device.connectionType !== undefined) {
614
+ config['connectionType'] = device.connectionType;
615
+ }
616
+ if (device.logging !== undefined) {
617
+ config['logging'] = device.logging;
618
+ }
619
+ if (device.refreshRate !== undefined) {
620
+ config['refreshRate'] = device.refreshRate;
621
+ }
622
+ if (device.scanDuration !== undefined) {
623
+ config['scanDuration'] = device.scanDuration;
624
+ }
625
+ if (Object.entries(config).length !== 0) {
626
+ this.infoLog(`${this.device.deviceType}: ${this.accessory.displayName} Config: ${superStringify(config)}`);
627
+ }
628
+ }
629
+
630
+ async logs(device: device & devicesConfig): Promise<void> {
631
+ if (this.platform.debugMode) {
632
+ this.deviceLogging = this.accessory.context.logging = 'debugMode';
633
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Debug Mode Logging: ${this.deviceLogging}`);
634
+ } else if (device.logging) {
635
+ this.deviceLogging = this.accessory.context.logging = device.logging;
636
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Device Config Logging: ${this.deviceLogging}`);
637
+ } else if (this.platform.config.options?.logging) {
638
+ this.deviceLogging = this.accessory.context.logging = this.platform.config.options?.logging;
639
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Using Platform Config Logging: ${this.deviceLogging}`);
604
640
  } else {
605
- this.set_maxLux = 6001;
641
+ this.deviceLogging = this.accessory.context.logging = 'standard';
642
+ this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName} Logging Not Set, Using: ${this.deviceLogging}`);
606
643
  }
607
- return this.set_maxLux;
608
644
  }
609
645
 
610
646
  /**