@switchbot/homebridge-switchbot 3.5.1-beta.9 → 3.5.2-beta.0

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 (158) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/config.schema.json +19 -3
  3. package/dist/device/blindtilt.d.ts +6 -4
  4. package/dist/device/blindtilt.d.ts.map +1 -1
  5. package/dist/device/blindtilt.js +61 -47
  6. package/dist/device/blindtilt.js.map +1 -1
  7. package/dist/device/bot.d.ts +6 -3
  8. package/dist/device/bot.d.ts.map +1 -1
  9. package/dist/device/bot.js +60 -26
  10. package/dist/device/bot.js.map +1 -1
  11. package/dist/device/ceilinglight.d.ts +6 -3
  12. package/dist/device/ceilinglight.d.ts.map +1 -1
  13. package/dist/device/ceilinglight.js +48 -30
  14. package/dist/device/ceilinglight.js.map +1 -1
  15. package/dist/device/colorbulb.d.ts +6 -3
  16. package/dist/device/colorbulb.d.ts.map +1 -1
  17. package/dist/device/colorbulb.js +54 -37
  18. package/dist/device/colorbulb.js.map +1 -1
  19. package/dist/device/contact.d.ts +6 -3
  20. package/dist/device/contact.d.ts.map +1 -1
  21. package/dist/device/contact.js +46 -32
  22. package/dist/device/contact.js.map +1 -1
  23. package/dist/device/curtain.d.ts +6 -4
  24. package/dist/device/curtain.d.ts.map +1 -1
  25. package/dist/device/curtain.js +42 -28
  26. package/dist/device/curtain.js.map +1 -1
  27. package/dist/device/device.d.ts +7 -4
  28. package/dist/device/device.d.ts.map +1 -1
  29. package/dist/device/device.js +61 -152
  30. package/dist/device/device.js.map +1 -1
  31. package/dist/device/fan.d.ts +6 -3
  32. package/dist/device/fan.d.ts.map +1 -1
  33. package/dist/device/fan.js +54 -33
  34. package/dist/device/fan.js.map +1 -1
  35. package/dist/device/hub.d.ts +6 -3
  36. package/dist/device/hub.d.ts.map +1 -1
  37. package/dist/device/hub.js +50 -31
  38. package/dist/device/hub.js.map +1 -1
  39. package/dist/device/humidifier.d.ts +6 -3
  40. package/dist/device/humidifier.d.ts.map +1 -1
  41. package/dist/device/humidifier.js +48 -29
  42. package/dist/device/humidifier.js.map +1 -1
  43. package/dist/device/iosensor.d.ts +6 -3
  44. package/dist/device/iosensor.d.ts.map +1 -1
  45. package/dist/device/iosensor.js +45 -28
  46. package/dist/device/iosensor.js.map +1 -1
  47. package/dist/device/lightstrip.d.ts +6 -3
  48. package/dist/device/lightstrip.d.ts.map +1 -1
  49. package/dist/device/lightstrip.js +47 -29
  50. package/dist/device/lightstrip.js.map +1 -1
  51. package/dist/device/lock.d.ts +6 -3
  52. package/dist/device/lock.d.ts.map +1 -1
  53. package/dist/device/lock.js +39 -26
  54. package/dist/device/lock.js.map +1 -1
  55. package/dist/device/meter.d.ts +6 -3
  56. package/dist/device/meter.d.ts.map +1 -1
  57. package/dist/device/meter.js +44 -28
  58. package/dist/device/meter.js.map +1 -1
  59. package/dist/device/meterplus.d.ts +6 -3
  60. package/dist/device/meterplus.d.ts.map +1 -1
  61. package/dist/device/meterplus.js +43 -28
  62. package/dist/device/meterplus.js.map +1 -1
  63. package/dist/device/motion.d.ts +6 -3
  64. package/dist/device/motion.d.ts.map +1 -1
  65. package/dist/device/motion.js +38 -25
  66. package/dist/device/motion.js.map +1 -1
  67. package/dist/device/plug.d.ts +6 -3
  68. package/dist/device/plug.d.ts.map +1 -1
  69. package/dist/device/plug.js +31 -18
  70. package/dist/device/plug.js.map +1 -1
  71. package/dist/device/robotvacuumcleaner.d.ts +6 -3
  72. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  73. package/dist/device/robotvacuumcleaner.js +38 -23
  74. package/dist/device/robotvacuumcleaner.js.map +1 -1
  75. package/dist/device/waterdetector.d.ts +6 -3
  76. package/dist/device/waterdetector.d.ts.map +1 -1
  77. package/dist/device/waterdetector.js +44 -27
  78. package/dist/device/waterdetector.js.map +1 -1
  79. package/dist/homebridge-ui/public/index.html +2 -2
  80. package/dist/irdevice/airconditioner.d.ts +1 -3
  81. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  82. package/dist/irdevice/airconditioner.js +67 -177
  83. package/dist/irdevice/airconditioner.js.map +1 -1
  84. package/dist/irdevice/airpurifier.d.ts +0 -1
  85. package/dist/irdevice/airpurifier.d.ts.map +1 -1
  86. package/dist/irdevice/airpurifier.js +24 -53
  87. package/dist/irdevice/airpurifier.js.map +1 -1
  88. package/dist/irdevice/camera.d.ts.map +1 -1
  89. package/dist/irdevice/camera.js +12 -17
  90. package/dist/irdevice/camera.js.map +1 -1
  91. package/dist/irdevice/fan.d.ts.map +1 -1
  92. package/dist/irdevice/fan.js +22 -38
  93. package/dist/irdevice/fan.js.map +1 -1
  94. package/dist/irdevice/irdevice.d.ts +22 -10
  95. package/dist/irdevice/irdevice.d.ts.map +1 -1
  96. package/dist/irdevice/irdevice.js +94 -100
  97. package/dist/irdevice/irdevice.js.map +1 -1
  98. package/dist/irdevice/light.d.ts.map +1 -1
  99. package/dist/irdevice/light.js +20 -38
  100. package/dist/irdevice/light.js.map +1 -1
  101. package/dist/irdevice/other.d.ts.map +1 -1
  102. package/dist/irdevice/other.js +79 -77
  103. package/dist/irdevice/other.js.map +1 -1
  104. package/dist/irdevice/tv.d.ts.map +1 -1
  105. package/dist/irdevice/tv.js +38 -53
  106. package/dist/irdevice/tv.js.map +1 -1
  107. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  108. package/dist/irdevice/vacuumcleaner.js +11 -16
  109. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  110. package/dist/irdevice/waterheater.d.ts.map +1 -1
  111. package/dist/irdevice/waterheater.js +11 -16
  112. package/dist/irdevice/waterheater.js.map +1 -1
  113. package/dist/platform.d.ts +4 -6
  114. package/dist/platform.d.ts.map +1 -1
  115. package/dist/platform.js +564 -665
  116. package/dist/platform.js.map +1 -1
  117. package/dist/settings.d.ts +10 -8
  118. package/dist/settings.d.ts.map +1 -1
  119. package/dist/settings.js.map +1 -1
  120. package/dist/types/bledevicestatus.d.ts +2 -1
  121. package/dist/types/bledevicestatus.d.ts.map +1 -1
  122. package/dist/types/devicestatus.d.ts +1 -1
  123. package/dist/types/devicestatus.d.ts.map +1 -1
  124. package/package.json +14 -14
  125. package/src/device/blindtilt.ts +65 -49
  126. package/src/device/bot.ts +80 -27
  127. package/src/device/ceilinglight.ts +58 -32
  128. package/src/device/colorbulb.ts +58 -44
  129. package/src/device/contact.ts +50 -32
  130. package/src/device/curtain.ts +52 -29
  131. package/src/device/device.ts +63 -135
  132. package/src/device/fan.ts +68 -34
  133. package/src/device/hub.ts +63 -34
  134. package/src/device/humidifier.ts +61 -34
  135. package/src/device/iosensor.ts +52 -31
  136. package/src/device/lightstrip.ts +53 -30
  137. package/src/device/lock.ts +56 -27
  138. package/src/device/meter.ts +61 -30
  139. package/src/device/meterplus.ts +57 -30
  140. package/src/device/motion.ts +51 -27
  141. package/src/device/plug.ts +39 -19
  142. package/src/device/robotvacuumcleaner.ts +54 -25
  143. package/src/device/waterdetector.ts +63 -29
  144. package/src/homebridge-ui/public/index.html +2 -2
  145. package/src/irdevice/airconditioner.ts +76 -165
  146. package/src/irdevice/airpurifier.ts +29 -49
  147. package/src/irdevice/camera.ts +13 -16
  148. package/src/irdevice/fan.ts +25 -35
  149. package/src/irdevice/irdevice.ts +97 -96
  150. package/src/irdevice/light.ts +21 -35
  151. package/src/irdevice/other.ts +79 -77
  152. package/src/irdevice/tv.ts +40 -51
  153. package/src/irdevice/vacuumcleaner.ts +12 -15
  154. package/src/irdevice/waterheater.ts +12 -15
  155. package/src/platform.ts +566 -696
  156. package/src/settings.ts +11 -8
  157. package/src/types/bledevicestatus.ts +4 -2
  158. package/src/types/devicestatus.ts +1 -1
@@ -40,6 +40,15 @@ export class Curtain extends deviceBase {
40
40
  CurrentAmbientLightLevel?: CharacteristicValue;
41
41
  };
42
42
 
43
+ // OpenAPI
44
+ deviceStatus!: curtainStatus;
45
+
46
+ //Webhook
47
+ webhookContext!: curtainWebhookContext | curtain3WebhookContext;
48
+
49
+ // BLE
50
+ serviceData!: curtainServiceData | curtain3ServiceData;
51
+
43
52
  // Target
44
53
  setNewTarget!: boolean;
45
54
  setNewTargetTimer!: NodeJS.Timeout;
@@ -54,6 +63,8 @@ export class Curtain extends deviceBase {
54
63
  device: device & devicesConfig,
55
64
  ) {
56
65
  super(platform, accessory, device);
66
+ // Set category
67
+ accessory.category = this.hap.Categories.WINDOW_COVERING;
57
68
 
58
69
  // this is subject we use to track when we need to POST changes to the SwitchBot API
59
70
  this.doCurtainUpdate = new Subject();
@@ -175,12 +186,11 @@ export class Curtain extends deviceBase {
175
186
  }
176
187
 
177
188
  // Retrieve initial values and updateHomekit
189
+ this.debugLog('Retrieve initial values and update Homekit');
178
190
  this.refreshStatus();
179
191
 
180
- // Update Homekit
181
- this.updateHomeKitCharacteristics();
182
-
183
192
  //regisiter webhook event handler
193
+ this.debugLog('Registering Webhook Event Handler');
184
194
  this.registerWebhook();
185
195
 
186
196
  // History
@@ -256,7 +266,7 @@ export class Curtain extends deviceBase {
256
266
  });
257
267
  const motion: Service =
258
268
  this.accessory.getService(this.hap.Service.MotionSensor) ||
259
- this.accessory.addService(this.hap.Service.MotionSensor, `${this.accessory.displayName} Motion`);
269
+ this.accessory.addService(this.hap.Service.MotionSensor, 'Motion');
260
270
  motion.addOptionalCharacteristic(this.platform.eve.Characteristics.LastActivation);
261
271
  motion.getCharacteristic(this.platform.eve.Characteristics.LastActivation).onGet(() => {
262
272
  const lastActivation = this.accessory.context.lastActivation
@@ -293,22 +303,24 @@ export class Curtain extends deviceBase {
293
303
  }, 10 * 60 * 1000);
294
304
  }
295
305
 
296
- async BLEparseStatus(serviceData: curtainServiceData | curtain3ServiceData): Promise<void> {
306
+ async BLEparseStatus(): Promise<void> {
297
307
  await this.debugLog('BLEparseStatus');
308
+ await this.debugLog(`(position, battery) = BLE:(${this.serviceData.position}, ${this.serviceData.battery}),`
309
+ + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
298
310
  // CurrentPosition
299
- this.WindowCovering.CurrentPosition = 100 - serviceData.position;
311
+ this.WindowCovering.CurrentPosition = 100 -this.serviceData.position;
300
312
  await this.getCurrentPostion();
301
313
  // CurrentAmbientLightLevel
302
314
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
303
315
  const set_minLux = this.device.curtain?.set_minLux ?? 1;
304
316
  const set_maxLux = this.device.curtain?.set_maxLux ?? 6001;
305
- const lightLevel = Number(serviceData.lightLevel);
317
+ const lightLevel = this.serviceData.lightLevel;
306
318
  this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 19);
307
- this.debugLog(`LightLevel: ${serviceData.lightLevel},`
319
+ this.debugLog(`LightLevel: ${this.serviceData.lightLevel},`
308
320
  + ` CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`);
309
321
  }
310
322
  // BatteryLevel
311
- this.Battery.BatteryLevel = Number(serviceData.battery);
323
+ this.Battery.BatteryLevel = this.serviceData.battery;
312
324
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
313
325
  // StatusLowBattery
314
326
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
@@ -316,16 +328,18 @@ export class Curtain extends deviceBase {
316
328
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
317
329
  }
318
330
 
319
- async openAPIparseStatus(deviceStatus: curtainStatus): Promise<void> {
331
+ async openAPIparseStatus(): Promise<void> {
320
332
  await this.debugLog('openAPIparseStatus');
333
+ await this.debugLog(`(slidePosition, battery) = OpenAPI:(${this.deviceStatus.slidePosition}, ${this.deviceStatus.battery}),`
334
+ + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
321
335
  // CurrentPosition
322
- this.WindowCovering.CurrentPosition = 100 - deviceStatus.slidePosition;
336
+ this.WindowCovering.CurrentPosition = 100 - this.deviceStatus.slidePosition;
323
337
  await this.setMinMax();
324
- await this.debugLog(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
338
+ await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
325
339
  if (this.setNewTarget) {
326
340
  await this.infoLog('Checking Status ...');
327
341
  }
328
- if (this.setNewTarget && deviceStatus.moving) {
342
+ if (this.setNewTarget && this.deviceStatus.moving) {
329
343
  await this.setMinMax();
330
344
  if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
331
345
  await this.debugLog(`Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
@@ -351,25 +365,28 @@ export class Curtain extends deviceBase {
351
365
  }
352
366
  await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition},`
353
367
  + ` PositionState: ${this.WindowCovering.PositionState},`);
368
+
354
369
  // Brightness
355
370
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
356
371
  const set_minLux = this.device.curtain?.set_minLux ?? 1;
357
372
  const set_maxLux = this.device.curtain?.set_maxLux ?? 6001;
358
- const lightLevel = deviceStatus.lightLevel === 'bright' ? set_maxLux : set_minLux;
373
+ const lightLevel = this.deviceStatus.lightLevel === 'bright' ? set_maxLux : set_minLux;
359
374
  this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 2);
360
- await this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
361
- + ` CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`);
375
+ await this.debugLog(`CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`);
362
376
  }
377
+
363
378
  // BatteryLevel
364
- this.Battery.BatteryLevel = Number(deviceStatus.battery);
379
+ this.Battery.BatteryLevel = this.deviceStatus.battery;
365
380
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
381
+
366
382
  // StatusLowBattery
367
383
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
368
384
  ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
369
385
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
386
+
370
387
  // Firmware Version
371
- if (deviceStatus.version) {
372
- const version = deviceStatus.version.toString();
388
+ if (this.deviceStatus.version) {
389
+ const version = this.deviceStatus.version.toString();
373
390
  await this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`);
374
391
  const deviceVersion = version.replace(/^V|-.*$/g, '') ?? '0.0.0';
375
392
  this.accessory
@@ -378,21 +395,24 @@ export class Curtain extends deviceBase {
378
395
  .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
379
396
  .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
380
397
  .updateValue(deviceVersion);
381
- this.accessory.context.deviceVersion = deviceVersion;
382
- await this.debugSuccessLog(`deviceVersion: ${this.accessory.context.deviceVersion}`);
398
+ this.accessory.context.version = deviceVersion;
399
+ await this.debugSuccessLog(`version: ${this.accessory.context.version}`);
383
400
  }
384
401
  }
385
402
 
386
- async parseStatusWebhook(context: curtainWebhookContext | curtain3WebhookContext): Promise<void> {
403
+ async parseStatusWebhook(): Promise<void> {
387
404
  await this.debugLog('parseStatusWebhook');
388
- await this.debugLog(`(slidePosition, battery) = Webhook:(${context.slidePosition}, ${context.battery}),`
405
+ await this.debugLog(`(slidePosition, battery) = Webhook:(${this.webhookContext.slidePosition}, ${this.webhookContext.battery}),`
389
406
  + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
407
+
390
408
  // CurrentPosition
391
- this.WindowCovering.CurrentPosition = 100 - context.slidePosition;
409
+ this.WindowCovering.CurrentPosition = 100 - this.webhookContext.slidePosition;
392
410
  await this.getCurrentPostion();
411
+
393
412
  // BatteryLevel
394
- this.Battery.BatteryLevel = context.battery;
413
+ this.Battery.BatteryLevel = this.webhookContext.battery;
395
414
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
415
+
396
416
  // StatusLowBattery
397
417
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
398
418
  ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
@@ -429,7 +449,8 @@ export class Curtain extends deviceBase {
429
449
  // Update HomeKit
430
450
  if ((serviceData.model === SwitchBotBLEModel.Curtain || SwitchBotBLEModel.Curtain3)
431
451
  && (serviceData.modelName === SwitchBotBLEModelName.Curtain || SwitchBotBLEModelName.Curtain3)) {
432
- await this.BLEparseStatus(serviceData);
452
+ this.serviceData = serviceData;
453
+ await this.BLEparseStatus();
433
454
  await this.updateHomeKitCharacteristics();
434
455
  } else {
435
456
  await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
@@ -447,7 +468,8 @@ export class Curtain extends deviceBase {
447
468
  await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);;
448
469
  if (await this.successfulStatusCodes(statusCode, deviceStatus)) {
449
470
  await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
450
- await this.openAPIparseStatus(deviceStatus.body);
471
+ this.deviceStatus = deviceStatus.body;
472
+ await this.openAPIparseStatus();
451
473
  await this.updateHomeKitCharacteristics();
452
474
  } else {
453
475
  await this.debugWarnLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
@@ -465,7 +487,8 @@ export class Curtain extends deviceBase {
465
487
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: curtainWebhookContext | curtain3WebhookContext) => {
466
488
  try {
467
489
  await this.debugLog(`received Webhook: ${JSON.stringify(context)}`);
468
- await this.parseStatusWebhook(context);
490
+ this.webhookContext = context;
491
+ await this.parseStatusWebhook();
469
492
  await this.updateHomeKitCharacteristics();
470
493
  } catch (e: any) {
471
494
  await this.errorLog(`failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
@@ -682,7 +705,7 @@ export class Curtain extends deviceBase {
682
705
  }
683
706
 
684
707
  async BLERefreshConnection(switchbot: any): Promise<void> {
685
- await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${JSON.stringify(switchbot)}`);
708
+ await this.errorLog(`wasn't able to establish BLE Connection, node-switchbot: ${switchbot}`);
686
709
  if (this.platform.config.credentials?.token && this.device.connectionType === 'BLE/OpenAPI') {
687
710
  await this.warnLog('Using OpenAPI Connection to Refresh Status');
688
711
  await this.openAPIRefreshStatus();
@@ -5,9 +5,9 @@
5
5
 
6
6
  import { hostname } from 'os';
7
7
  import { request } from 'undici';
8
- import asyncmqtt from 'async-mqtt';
9
8
  import { Devices } from '../settings.js';
10
9
  import { BlindTiltMappingMode, sleep } from '../utils.js';
10
+ import { SwitchBotModel, SwitchBotBLEModel, SwitchBotBLEModelName, SwitchBotBLEModelFriendlyName } from 'node-switchbot';
11
11
 
12
12
  import type { MqttClient } from 'mqtt';
13
13
  import type { device } from '../types/devicelist.js';
@@ -15,7 +15,6 @@ import type { ad } from '../types/bledevicestatus.js';
15
15
  import type { SwitchBotPlatform } from '../platform.js';
16
16
  import type { SwitchBotPlatformConfig, devicesConfig } from '../settings.js';
17
17
  import type { API, CharacteristicValue, HAP, Logging, PlatformAccessory, Service } from 'homebridge';
18
- import { SwitchBotModel, SwitchBotBLEModel, SwitchBotBLEModelName, SwitchBotBLEModelFriendlyName } from 'node-switchbot';
19
18
 
20
19
  export abstract class deviceBase {
21
20
  public readonly api: API;
@@ -39,6 +38,11 @@ export abstract class deviceBase {
39
38
  protected deviceModel!: SwitchBotModel;
40
39
  protected deviceBLEModel!: SwitchBotBLEModel;
41
40
 
41
+ // MQTT
42
+ protected deviceMqttURL!: string;
43
+ protected deviceMqttOptions!: any;
44
+ protected deviceMqttPubOptions!: any;
45
+
42
46
  // BLE
43
47
  protected scanDuration!: number;
44
48
 
@@ -65,93 +69,54 @@ export abstract class deviceBase {
65
69
  this.getDeviceLogSettings(accessory, device);
66
70
  this.getDeviceRateSettings(accessory, device);
67
71
  this.getDeviceRetry(device);
68
- this.getDeviceConfigSettings(accessory, device);
72
+ this.getDeviceConfigSettings(device);
69
73
  this.getDeviceContext(accessory, device);
70
74
  this.getDeviceScanDuration(accessory, device);
71
- this.setupMqtt(device);
75
+ this.getMqttSettings(device);
72
76
 
73
77
  // Set accessory information
74
78
  accessory
75
79
  .getService(this.hap.Service.AccessoryInformation)!
76
80
  .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
77
81
  .setCharacteristic(this.hap.Characteristic.AppMatchingIdentifier, 'id1087374760')
78
- .setCharacteristic(this.hap.Characteristic.Name, device.deviceName ?? accessory.displayName)
79
- .setCharacteristic(this.hap.Characteristic.ConfiguredName, device.deviceName ?? accessory.displayName)
82
+ .setCharacteristic(this.hap.Characteristic.Name, device.configDeviceName ?? device.deviceName ?? accessory.displayName)
83
+ .setCharacteristic(this.hap.Characteristic.ConfiguredName, device.configDeviceName ?? device.deviceName ?? accessory.displayName)
80
84
  .setCharacteristic(this.hap.Characteristic.Model, device.model ?? accessory.context.model)
81
85
  .setCharacteristic(this.hap.Characteristic.ProductData, device.deviceId ?? accessory.context.deviceId)
82
86
  .setCharacteristic(this.hap.Characteristic.SerialNumber, device.deviceId);
83
87
  }
84
88
 
85
89
  async getDeviceLogSettings(accessory: PlatformAccessory, device: device & devicesConfig): Promise<void> {
86
- if (this.platform.debugMode) {
87
- this.deviceLogging = accessory.context.logging = 'debugMode';
88
- this.debugWarnLog(`Using Debug Mode Logging: ${this.deviceLogging}`);
89
- } else if (device.logging) {
90
- this.deviceLogging = accessory.context.logging = device.logging;
91
- this.debugWarnLog(`Using Device Config Logging: ${this.deviceLogging}`);
92
- } else if (this.config.logging) {
93
- this.deviceLogging = accessory.context.logging = this.config.logging;
94
- this.debugWarnLog(`Using Platform Config Logging: ${this.deviceLogging}`);
95
- } else {
96
- this.deviceLogging = accessory.context.logging = 'standard';
97
- this.debugWarnLog(`Logging Not Set, Using: ${this.deviceLogging}`);
98
- }
90
+ this.deviceLogging = this.platform.debugMode ? 'debugMode' : device.logging ?? this.config.logging ?? 'standard';
91
+ const logging = this.platform.debugMode ? 'Debug Mode' : device.logging ? 'Device Config' : this.config.logging ? 'Platform Config' : 'Default';
92
+ accessory.context.deviceLogging = this.deviceLogging;
93
+ await this.debugLog(`Using ${logging} Logging: ${this.deviceLogging}`);
99
94
  }
100
95
 
101
96
  async getDeviceRateSettings(accessory: PlatformAccessory, device: device & devicesConfig): Promise<void> {
102
97
  // refreshRate
103
- if (device.refreshRate) {
104
- this.deviceRefreshRate = device.refreshRate;
105
- this.debugLog(`Using Device Config refreshRate: ${this.deviceRefreshRate}`);
106
- } else if (this.config.options?.refreshRate) {
107
- this.deviceRefreshRate = this.config.options.refreshRate;
108
- this.debugLog(`Using Platform Config refreshRate: ${this.deviceRefreshRate}`);
109
- } else {
110
- this.deviceRefreshRate = 5;
111
- this.debugLog(`Using Default refreshRate: ${this.deviceRefreshRate}`);
112
- }
98
+ this.deviceRefreshRate = device.refreshRate ?? this.config.options?.refreshRate ?? 5;
113
99
  accessory.context.deviceRefreshRate = this.deviceRefreshRate;
100
+ const refreshRate = device.refreshRate ? 'Device Config' : this.config.options?.refreshRate ? 'Platform Config' : 'Default';
114
101
  // updateRate
115
- if (device.updateRate) {
116
- this.deviceUpdateRate = device.updateRate;
117
- this.debugLog(`Using Device Config updateRate: ${this.deviceUpdateRate}`);
118
- } else if (this.config.options?.updateRate) {
119
- this.deviceUpdateRate = this.config.options.updateRate;
120
- this.debugLog(`Using Platform Config updateRate: ${this.deviceUpdateRate}`);
121
- } else {
122
- this.deviceUpdateRate = 5;
123
- this.debugLog(`Using Default updateRate: ${this.deviceUpdateRate}`);
124
- }
102
+ this.deviceUpdateRate = device.updateRate ?? this.config.options?.updateRate ?? 5;
125
103
  accessory.context.deviceUpdateRate = this.deviceUpdateRate;
104
+ const updateRate = device.updateRate ? 'Device Config' : this.config.options?.updateRate ? 'Platform Config' : 'Default';
126
105
  // pushRate
127
- if (device.pushRate) {
128
- this.devicePushRate = device.pushRate;
129
- this.debugLog(`Using Device Config pushRate: ${this.deviceUpdateRate}`);
130
- } else if (this.config.options?.pushRate) {
131
- this.devicePushRate = this.config.options.pushRate;
132
- this.debugLog(`Using Platform Config pushRate: ${this.deviceUpdateRate}`);
133
- } else {
134
- this.devicePushRate = 1;
135
- this.debugLog(`Using Default pushRate: ${this.deviceUpdateRate}`);
136
- }
106
+ this.devicePushRate = device.pushRate ?? this.config.options?.pushRate ?? 1;
137
107
  accessory.context.devicePushRate = this.devicePushRate;
108
+ const pushRate = device.pushRate ? 'Device Config' : this.config.options?.pushRate ? 'Platform Config' : 'Default';
109
+ await this.debugLog(`Using ${refreshRate} refreshRate: ${this.deviceRefreshRate}, ${updateRate} updateRate: ${this.deviceUpdateRate},`
110
+ + ` ${pushRate} pushRate: ${this.devicePushRate}`);
138
111
  }
139
112
 
140
113
  async getDeviceRetry(device: device & devicesConfig): Promise<void> {
141
- if (device.maxRetries) {
142
- this.deviceMaxRetries = device.maxRetries;
143
- this.debugLog(`Using Device Max Retries: ${this.deviceMaxRetries}`);
144
- } else {
145
- this.deviceMaxRetries = 5; // Maximum number of retries
146
- this.debugLog(`Max Retries Not Set, Using: ${this.deviceMaxRetries}`);
147
- }
148
- if (device.delayBetweenRetries) {
149
- this.deviceDelayBetweenRetries = device.delayBetweenRetries * 1000;
150
- this.debugLog(`Using Device Delay Between Retries: ${this.deviceDelayBetweenRetries}`);
151
- } else {
152
- this.deviceDelayBetweenRetries = 3000; // Delay between retries in milliseconds
153
- this.debugLog(`Delay Between Retries Not Set, Using: ${this.deviceDelayBetweenRetries}`);
154
- }
114
+ this.deviceMaxRetries = device.maxRetries ?? 5;
115
+ const maxRetries = device.maxRetries ? 'Device' : 'Default';
116
+ this.deviceDelayBetweenRetries = device.delayBetweenRetries ? (device.delayBetweenRetries * 1000) : 3000;
117
+ const delayBetweenRetries = device.delayBetweenRetries ? 'Device' : 'Default';
118
+ await this.debugLog(`Using ${maxRetries} Max Retries: ${this.deviceMaxRetries},`
119
+ + ` ${delayBetweenRetries} Delay Between Retries: ${this.deviceDelayBetweenRetries}`);
155
120
  }
156
121
 
157
122
  async retryBLE({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
@@ -167,14 +132,12 @@ export abstract class deviceBase {
167
132
  }
168
133
 
169
134
  async maxRetryBLE(): Promise<number> {
170
- if (this.device.maxRetry) {
171
- return this.device.maxRetry;
172
- } else {
173
- return 5;
174
- }
135
+ return this.device.maxRetry ? this.device.maxRetry : 5;
175
136
  }
176
137
 
177
138
  async getDeviceScanDuration(accessory: PlatformAccessory, device: device & devicesConfig): Promise<void> {
139
+ this.scanDuration = device.scanDuration ? (this.deviceUpdateRate > device.scanDuration) ? this.deviceUpdateRate : device.scanDuration
140
+ ? (this.deviceUpdateRate > 1) ? this.deviceUpdateRate : 1 : this.deviceUpdateRate : 1;
178
141
  if (device.scanDuration) {
179
142
  if (this.deviceUpdateRate > device.scanDuration) {
180
143
  this.scanDuration = this.deviceUpdateRate;
@@ -199,7 +162,7 @@ export abstract class deviceBase {
199
162
  }
200
163
  }
201
164
 
202
- async getDeviceConfigSettings(accessory: PlatformAccessory, device: device & devicesConfig): Promise<void> {
165
+ async getDeviceConfigSettings(device: device & devicesConfig): Promise<void> {
203
166
  const deviceConfig = {};
204
167
  if (device.logging !== 'standard') {
205
168
  deviceConfig['logging'] = device.logging;
@@ -231,6 +194,12 @@ export abstract class deviceBase {
231
194
  if (device.mqttURL !== '') {
232
195
  deviceConfig['mqttURL'] = device.mqttURL;
233
196
  }
197
+ if (device.mqttOptions) {
198
+ deviceConfig['mqttOptions'] = device.mqttOptions;
199
+ }
200
+ if (device.mqttPubOptions) {
201
+ deviceConfig['mqttPubOptions'] = device.mqttPubOptions;
202
+ }
234
203
  if (device.maxRetries !== 0) {
235
204
  deviceConfig['maxRetries'] = device.maxRetries;
236
205
  }
@@ -319,21 +288,10 @@ export abstract class deviceBase {
319
288
  const numberOfLevels = spaceBetweenLevels + 1;
320
289
  this.debugLog(`LightLevel: ${lightLevel}, set_minLux: ${set_minLux}, set_maxLux: ${set_maxLux}, spaceBetweenLevels: ${spaceBetweenLevels},`
321
290
  + ` numberOfLevels: ${numberOfLevels}`);
322
- let CurrentAmbientLightLevel: number;
323
- switch (lightLevel) {
324
- case 1:
325
- CurrentAmbientLightLevel = set_minLux;
326
- this.debugLog(`LightLevel: ${lightLevel}, set_minLux: ${set_minLux}`);
327
- break;
328
- case numberOfLevels:
329
- CurrentAmbientLightLevel = set_maxLux;
330
- this.debugLog(`LightLevel: ${lightLevel}, set_maxLux: ${set_maxLux}`);
331
- break;
332
- default:
333
- CurrentAmbientLightLevel = ((set_maxLux - set_minLux) / spaceBetweenLevels) * (Number(lightLevel) - 1);
334
- this.debugLog(`LightLevel: ${lightLevel}`);
335
- }
336
- this.debugLog(`CurrentAmbientLightLevel: ${CurrentAmbientLightLevel}`);
291
+ const CurrentAmbientLightLevel = lightLevel === 1 ? set_minLux : lightLevel = numberOfLevels
292
+ ? set_maxLux : ((set_maxLux - set_minLux) / spaceBetweenLevels) * (Number(lightLevel) - 1);
293
+ await this.debugLog(`CurrentAmbientLightLevel: ${CurrentAmbientLightLevel}, LightLevel: ${lightLevel}, set_minLux: ${set_minLux},`
294
+ + ` set_maxLux: ${set_maxLux}`);
337
295
  return CurrentAmbientLightLevel;
338
296
  }
339
297
 
@@ -342,41 +300,29 @@ export abstract class deviceBase {
342
300
  * 'homebridge-switchbot/${this.device.deviceType}/xx:xx:xx:xx:xx:xx'
343
301
  */
344
302
  async mqttPublish(message: string, topic?: string) {
345
- const mac = this.device.deviceId
346
- ?.toLowerCase()
347
- .match(/[\s\S]{1,2}/g)
348
- ?.join(':');
349
- const options = this.device.mqttPubOptions || {};
350
- let mqttTopic: string;
351
- let mqttMessageTopic: string;
352
- if (topic) {
353
- mqttTopic = `/${topic}`;
354
- mqttMessageTopic = `${topic}/`;
355
- } else {
356
- mqttTopic = '';
357
- mqttMessageTopic = '';
358
- }
303
+ const mac = this.device.deviceId?.toLowerCase().match(/[\s\S]{1,2}/g)?.join(':');
304
+ const options = this.deviceMqttPubOptions ?? {};
305
+ const mqttTopic = topic ? `/${topic}` : '';
306
+ const mqttMessageTopic = topic ? `${topic}/` : '';
359
307
  this.mqttClient?.publish(`homebridge-switchbot/${this.device.deviceType}/${mac}${mqttTopic}`, `${message}`, options);
360
308
  this.debugLog(`MQTT message: ${mqttMessageTopic}${message} options:${JSON.stringify(options)}`);
361
309
  }
362
310
 
363
311
  /*
364
- * Setup MQTT hadler if URL is specified.
312
+ * MQTT Settings
365
313
  */
366
- async setupMqtt(device: device & devicesConfig): Promise<void> {
367
- if (device.mqttURL) {
368
- try {
369
- const { connectAsync } = asyncmqtt;
370
- this.mqttClient = await connectAsync(device.mqttURL, device.mqttOptions || {});
371
- this.debugLog('MQTT connection has been established successfully.');
372
- this.mqttClient.on('error', (e: Error) => {
373
- this.errorLog(`Failed to publish MQTT messages. ${e}`);
374
- });
375
- } catch (e) {
376
- this.mqttClient = null;
377
- this.errorLog(`Failed to establish MQTT connection. ${e}`);
378
- }
379
- }
314
+ async getMqttSettings(device: device & devicesConfig): Promise<void> {
315
+ // mqttURL
316
+ this.deviceMqttURL = device.mqttURL ?? this.config.options?.mqttURL ?? '';
317
+ const mqttURL = device.mqttURL ? 'Device Config' : this.config.options?.mqttURL ? 'Platform Config' : 'Default';
318
+ // mqttOptions
319
+ this.deviceMqttOptions = device.mqttOptions ?? this.config.options?.mqttOptions ?? {};
320
+ const mqttOptions = device.mqttOptions ? 'Device Config' : this.config.options?.mqttOptions ? 'Platform Config' : 'Default';
321
+ // mqttPubOptions
322
+ this.deviceMqttPubOptions = device.mqttPubOptions ?? this.config.options?.mqttPubOptions ?? {};
323
+ const mqttPubOptions = device.mqttPubOptions ? 'Device Config' : this.config.options?.mqttPubOptions ? 'Platform Config' : 'Default';
324
+ await this.debugLog(`Using ${mqttURL} MQTT URL: ${this.deviceMqttURL}, ${mqttOptions} mqttOptions: ${JSON.stringify(this.deviceMqttOptions)},`
325
+ + ` ${mqttPubOptions} mqttPubOptions: ${JSON.stringify(this.deviceMqttPubOptions)}`);
380
326
  }
381
327
 
382
328
  /*
@@ -715,32 +661,14 @@ export abstract class deviceBase {
715
661
  device.bleModelName = SwitchBotBLEModelName.Unknown;
716
662
  device.bleModelFriednlyName = SwitchBotBLEModelFriendlyName.Unknown;
717
663
  }
718
- this.debugLog(`Model: ${device.model}, BLE Model: ${device.bleModel}, BLE Model Name: ${device.bleModelName}, `
664
+ await this.debugLog(`Model: ${device.model}, BLE Model: ${device.bleModel}, BLE Model Name: ${device.bleModelName}, `
719
665
  + `BLE Model Friendly Name: ${device.bleModelFriednlyName}`);
720
666
  accessory.context.model = device.model;
721
667
  accessory.context.bleModel = device.bleModel;
722
668
  accessory.context.bleModelName = device.bleModelName;
723
669
  accessory.context.bleModelFriednlyName = device.bleModelFriednlyName;
724
670
 
725
- // Firmware Version
726
- let deviceFirmwareVersion: string;
727
- if (device.firmware) {
728
- deviceFirmwareVersion = device.firmware;
729
- this.debugSuccessLog(`1 FirmwareRevision: ${device.firmware}`);
730
- } else if (device.version) {
731
- deviceFirmwareVersion = JSON.stringify(device.version);
732
- this.debugSuccessLog(`2 FirmwareRevision: ${device.version}`);
733
- } else if (accessory.context.deviceVersion) {
734
- deviceFirmwareVersion = accessory.context.deviceVersion;
735
- this.debugSuccessLog(`3 FirmwareRevision: ${accessory.context.deviceVersion}`);
736
- } else {
737
- deviceFirmwareVersion = this.platform.version ?? '0.0.0';
738
- if (this.platform.version) {
739
- this.debugSuccessLog(`4 FirmwareRevision: ${this.platform.version}`);
740
- } else {
741
- this.debugSuccessLog(`5 FirmwareRevision: ${deviceFirmwareVersion}`);
742
- }
743
- }
671
+ const deviceFirmwareVersion = device.firmware ?? device.version ?? accessory.context.version ?? this.platform.version ?? '0.0.0';
744
672
  const version = deviceFirmwareVersion.toString();
745
673
  this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`);
746
674
  let deviceVersion: string;
@@ -759,8 +687,8 @@ export abstract class deviceBase {
759
687
  .setCharacteristic(this.hap.Characteristic.FirmwareRevision, deviceVersion)
760
688
  .getCharacteristic(this.hap.Characteristic.FirmwareRevision)
761
689
  .updateValue(deviceVersion);
762
- accessory.context.deviceVersion = deviceVersion;
763
- this.debugSuccessLog(`deviceVersion: ${accessory.context.deviceVersion}`);
690
+ accessory.context.version = deviceVersion;
691
+ this.debugSuccessLog(`version: ${accessory.context.version}`);
764
692
  }
765
693
 
766
694
  async statusCode(statusCode: number): Promise<void> {