@switchbot/homebridge-switchbot 3.5.1-beta.12 → 3.5.1-beta.14

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 (150) hide show
  1. package/config.schema.json +19 -3
  2. package/dist/device/blindtilt.d.ts +6 -4
  3. package/dist/device/blindtilt.d.ts.map +1 -1
  4. package/dist/device/blindtilt.js +56 -44
  5. package/dist/device/blindtilt.js.map +1 -1
  6. package/dist/device/bot.d.ts +6 -3
  7. package/dist/device/bot.d.ts.map +1 -1
  8. package/dist/device/bot.js +37 -23
  9. package/dist/device/bot.js.map +1 -1
  10. package/dist/device/ceilinglight.d.ts +6 -3
  11. package/dist/device/ceilinglight.d.ts.map +1 -1
  12. package/dist/device/ceilinglight.js +39 -20
  13. package/dist/device/ceilinglight.js.map +1 -1
  14. package/dist/device/colorbulb.d.ts +6 -3
  15. package/dist/device/colorbulb.d.ts.map +1 -1
  16. package/dist/device/colorbulb.js +41 -30
  17. package/dist/device/colorbulb.js.map +1 -1
  18. package/dist/device/contact.d.ts +6 -3
  19. package/dist/device/contact.d.ts.map +1 -1
  20. package/dist/device/contact.js +39 -27
  21. package/dist/device/contact.js.map +1 -1
  22. package/dist/device/curtain.d.ts +6 -4
  23. package/dist/device/curtain.d.ts.map +1 -1
  24. package/dist/device/curtain.js +34 -21
  25. package/dist/device/curtain.js.map +1 -1
  26. package/dist/device/device.d.ts +6 -3
  27. package/dist/device/device.d.ts.map +1 -1
  28. package/dist/device/device.js +54 -125
  29. package/dist/device/device.js.map +1 -1
  30. package/dist/device/fan.d.ts +6 -3
  31. package/dist/device/fan.d.ts.map +1 -1
  32. package/dist/device/fan.js +47 -28
  33. package/dist/device/fan.js.map +1 -1
  34. package/dist/device/hub.d.ts +6 -3
  35. package/dist/device/hub.d.ts.map +1 -1
  36. package/dist/device/hub.js +42 -25
  37. package/dist/device/hub.js.map +1 -1
  38. package/dist/device/humidifier.d.ts +6 -3
  39. package/dist/device/humidifier.d.ts.map +1 -1
  40. package/dist/device/humidifier.js +42 -25
  41. package/dist/device/humidifier.js.map +1 -1
  42. package/dist/device/iosensor.d.ts +6 -3
  43. package/dist/device/iosensor.d.ts.map +1 -1
  44. package/dist/device/iosensor.js +38 -23
  45. package/dist/device/iosensor.js.map +1 -1
  46. package/dist/device/lightstrip.d.ts +6 -3
  47. package/dist/device/lightstrip.d.ts.map +1 -1
  48. package/dist/device/lightstrip.js +42 -26
  49. package/dist/device/lightstrip.js.map +1 -1
  50. package/dist/device/lock.d.ts +6 -3
  51. package/dist/device/lock.d.ts.map +1 -1
  52. package/dist/device/lock.js +32 -21
  53. package/dist/device/lock.js.map +1 -1
  54. package/dist/device/meter.d.ts +6 -3
  55. package/dist/device/meter.d.ts.map +1 -1
  56. package/dist/device/meter.js +37 -23
  57. package/dist/device/meter.js.map +1 -1
  58. package/dist/device/meterplus.d.ts +6 -3
  59. package/dist/device/meterplus.d.ts.map +1 -1
  60. package/dist/device/meterplus.js +36 -23
  61. package/dist/device/meterplus.js.map +1 -1
  62. package/dist/device/motion.d.ts +6 -3
  63. package/dist/device/motion.d.ts.map +1 -1
  64. package/dist/device/motion.js +32 -21
  65. package/dist/device/motion.js.map +1 -1
  66. package/dist/device/plug.d.ts +6 -3
  67. package/dist/device/plug.d.ts.map +1 -1
  68. package/dist/device/plug.js +26 -15
  69. package/dist/device/plug.js.map +1 -1
  70. package/dist/device/robotvacuumcleaner.d.ts +6 -3
  71. package/dist/device/robotvacuumcleaner.d.ts.map +1 -1
  72. package/dist/device/robotvacuumcleaner.js +33 -20
  73. package/dist/device/robotvacuumcleaner.js.map +1 -1
  74. package/dist/device/waterdetector.d.ts +6 -3
  75. package/dist/device/waterdetector.d.ts.map +1 -1
  76. package/dist/device/waterdetector.js +37 -22
  77. package/dist/device/waterdetector.js.map +1 -1
  78. package/dist/irdevice/airconditioner.d.ts.map +1 -1
  79. package/dist/irdevice/airconditioner.js +19 -72
  80. package/dist/irdevice/airconditioner.js.map +1 -1
  81. package/dist/irdevice/airpurifier.js +4 -4
  82. package/dist/irdevice/airpurifier.js.map +1 -1
  83. package/dist/irdevice/camera.d.ts.map +1 -1
  84. package/dist/irdevice/camera.js +3 -10
  85. package/dist/irdevice/camera.js.map +1 -1
  86. package/dist/irdevice/fan.d.ts.map +1 -1
  87. package/dist/irdevice/fan.js +7 -25
  88. package/dist/irdevice/fan.js.map +1 -1
  89. package/dist/irdevice/irdevice.d.ts +1 -1
  90. package/dist/irdevice/irdevice.js +2 -2
  91. package/dist/irdevice/irdevice.js.map +1 -1
  92. package/dist/irdevice/light.d.ts.map +1 -1
  93. package/dist/irdevice/light.js +9 -27
  94. package/dist/irdevice/light.js.map +1 -1
  95. package/dist/irdevice/other.js +1 -1
  96. package/dist/irdevice/other.js.map +1 -1
  97. package/dist/irdevice/tv.d.ts.map +1 -1
  98. package/dist/irdevice/tv.js +3 -18
  99. package/dist/irdevice/tv.js.map +1 -1
  100. package/dist/irdevice/vacuumcleaner.d.ts.map +1 -1
  101. package/dist/irdevice/vacuumcleaner.js +2 -9
  102. package/dist/irdevice/vacuumcleaner.js.map +1 -1
  103. package/dist/irdevice/waterheater.d.ts.map +1 -1
  104. package/dist/irdevice/waterheater.js +2 -9
  105. package/dist/irdevice/waterheater.js.map +1 -1
  106. package/dist/platform.d.ts +3 -5
  107. package/dist/platform.d.ts.map +1 -1
  108. package/dist/platform.js +13 -13
  109. package/dist/platform.js.map +1 -1
  110. package/dist/settings.d.ts +9 -8
  111. package/dist/settings.d.ts.map +1 -1
  112. package/dist/settings.js.map +1 -1
  113. package/dist/types/bledevicestatus.d.ts +2 -1
  114. package/dist/types/bledevicestatus.d.ts.map +1 -1
  115. package/dist/types/devicestatus.d.ts +1 -1
  116. package/dist/types/devicestatus.d.ts.map +1 -1
  117. package/package.json +9 -9
  118. package/src/device/blindtilt.ts +59 -46
  119. package/src/device/bot.ts +46 -24
  120. package/src/device/ceilinglight.ts +51 -20
  121. package/src/device/colorbulb.ts +44 -30
  122. package/src/device/contact.ts +42 -27
  123. package/src/device/curtain.ts +44 -22
  124. package/src/device/device.ts +56 -112
  125. package/src/device/fan.ts +60 -29
  126. package/src/device/hub.ts +54 -28
  127. package/src/device/humidifier.ts +54 -30
  128. package/src/device/iosensor.ts +44 -26
  129. package/src/device/lightstrip.ts +47 -27
  130. package/src/device/lock.ts +48 -22
  131. package/src/device/meter.ts +53 -25
  132. package/src/device/meterplus.ts +49 -25
  133. package/src/device/motion.ts +44 -23
  134. package/src/device/plug.ts +33 -16
  135. package/src/device/robotvacuumcleaner.ts +48 -22
  136. package/src/device/waterdetector.ts +55 -24
  137. package/src/irdevice/airconditioner.ts +19 -65
  138. package/src/irdevice/airpurifier.ts +4 -4
  139. package/src/irdevice/camera.ts +4 -9
  140. package/src/irdevice/fan.ts +10 -22
  141. package/src/irdevice/irdevice.ts +2 -2
  142. package/src/irdevice/light.ts +10 -24
  143. package/src/irdevice/other.ts +1 -1
  144. package/src/irdevice/tv.ts +5 -16
  145. package/src/irdevice/vacuumcleaner.ts +3 -8
  146. package/src/irdevice/waterheater.ts +3 -8
  147. package/src/platform.ts +14 -14
  148. package/src/settings.ts +10 -8
  149. package/src/types/bledevicestatus.ts +4 -2
  150. 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;
@@ -175,12 +184,11 @@ export class Curtain extends deviceBase {
175
184
  }
176
185
 
177
186
  // Retrieve initial values and updateHomekit
187
+ this.debugLog('Retrieve initial values and update Homekit');
178
188
  this.refreshStatus();
179
189
 
180
- // Update Homekit
181
- this.updateHomeKitCharacteristics();
182
-
183
190
  //regisiter webhook event handler
191
+ this.debugLog('Registering Webhook Event Handler');
184
192
  this.registerWebhook();
185
193
 
186
194
  // History
@@ -293,22 +301,24 @@ export class Curtain extends deviceBase {
293
301
  }, 10 * 60 * 1000);
294
302
  }
295
303
 
296
- async BLEparseStatus(serviceData: curtainServiceData | curtain3ServiceData): Promise<void> {
304
+ async BLEparseStatus(): Promise<void> {
297
305
  await this.debugLog('BLEparseStatus');
306
+ await this.debugLog(`(position, battery) = BLE:(${this.serviceData.position}, ${this.serviceData.battery}),`
307
+ + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
298
308
  // CurrentPosition
299
- this.WindowCovering.CurrentPosition = 100 - serviceData.position;
309
+ this.WindowCovering.CurrentPosition = 100 -this.serviceData.position;
300
310
  await this.getCurrentPostion();
301
311
  // CurrentAmbientLightLevel
302
312
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
303
313
  const set_minLux = this.device.curtain?.set_minLux ?? 1;
304
314
  const set_maxLux = this.device.curtain?.set_maxLux ?? 6001;
305
- const lightLevel = Number(serviceData.lightLevel);
315
+ const lightLevel = this.serviceData.lightLevel;
306
316
  this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 19);
307
- this.debugLog(`LightLevel: ${serviceData.lightLevel},`
317
+ this.debugLog(`LightLevel: ${this.serviceData.lightLevel},`
308
318
  + ` CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`);
309
319
  }
310
320
  // BatteryLevel
311
- this.Battery.BatteryLevel = Number(serviceData.battery);
321
+ this.Battery.BatteryLevel = this.serviceData.battery;
312
322
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
313
323
  // StatusLowBattery
314
324
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
@@ -316,16 +326,18 @@ export class Curtain extends deviceBase {
316
326
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
317
327
  }
318
328
 
319
- async openAPIparseStatus(deviceStatus: curtainStatus): Promise<void> {
329
+ async openAPIparseStatus(): Promise<void> {
320
330
  await this.debugLog('openAPIparseStatus');
331
+ await this.debugLog(`(slidePosition, battery) = OpenAPI:(${this.deviceStatus.slidePosition}, ${this.deviceStatus.battery}),`
332
+ + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
321
333
  // CurrentPosition
322
- this.WindowCovering.CurrentPosition = 100 - deviceStatus.slidePosition;
334
+ this.WindowCovering.CurrentPosition = 100 - this.deviceStatus.slidePosition;
323
335
  await this.setMinMax();
324
336
  await this.debugLog(`Curtain ${this.accessory.displayName} CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
325
337
  if (this.setNewTarget) {
326
338
  await this.infoLog('Checking Status ...');
327
339
  }
328
- if (this.setNewTarget && deviceStatus.moving) {
340
+ if (this.setNewTarget && this.deviceStatus.moving) {
329
341
  await this.setMinMax();
330
342
  if (Number(this.WindowCovering.TargetPosition) > this.WindowCovering.CurrentPosition) {
331
343
  await this.debugLog(`Closing, CurrentPosition: ${this.WindowCovering.CurrentPosition}`);
@@ -351,25 +363,29 @@ export class Curtain extends deviceBase {
351
363
  }
352
364
  await this.debugLog(`CurrentPosition: ${this.WindowCovering.CurrentPosition}, TargetPosition: ${this.WindowCovering.TargetPosition},`
353
365
  + ` PositionState: ${this.WindowCovering.PositionState},`);
366
+
354
367
  // Brightness
355
368
  if (!this.device.curtain?.hide_lightsensor && this.LightSensor?.Service) {
356
369
  const set_minLux = this.device.curtain?.set_minLux ?? 1;
357
370
  const set_maxLux = this.device.curtain?.set_maxLux ?? 6001;
358
- const lightLevel = deviceStatus.lightLevel === 'bright' ? set_maxLux : set_minLux;
371
+ const lightLevel = this.deviceStatus.lightLevel === 'bright' ? set_maxLux : set_minLux;
359
372
  this.LightSensor.CurrentAmbientLightLevel = await this.getLightLevel(lightLevel, set_minLux, set_maxLux, 2);
360
373
  await this.debugLog(`${this.device.deviceType}: ${this.accessory.displayName}`
361
374
  + ` CurrentAmbientLightLevel: ${this.LightSensor.CurrentAmbientLightLevel}`);
362
375
  }
376
+
363
377
  // BatteryLevel
364
- this.Battery.BatteryLevel = Number(deviceStatus.battery);
378
+ this.Battery.BatteryLevel = this.deviceStatus.battery;
365
379
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
380
+
366
381
  // StatusLowBattery
367
382
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
368
383
  ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
369
384
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
385
+
370
386
  // Firmware Version
371
- if (deviceStatus.version) {
372
- const version = deviceStatus.version.toString();
387
+ if (this.deviceStatus.version) {
388
+ const version = this.deviceStatus.version.toString();
373
389
  await this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`);
374
390
  const deviceVersion = version.replace(/^V|-.*$/g, '') ?? '0.0.0';
375
391
  this.accessory
@@ -383,16 +399,19 @@ export class Curtain extends deviceBase {
383
399
  }
384
400
  }
385
401
 
386
- async parseStatusWebhook(context: curtainWebhookContext | curtain3WebhookContext): Promise<void> {
402
+ async parseStatusWebhook(): Promise<void> {
387
403
  await this.debugLog('parseStatusWebhook');
388
- await this.debugLog(`(slidePosition, battery) = Webhook:(${context.slidePosition}, ${context.battery}),`
404
+ await this.debugLog(`(slidePosition, battery) = Webhook:(${this.webhookContext.slidePosition}, ${this.webhookContext.battery}),`
389
405
  + ` current:(${this.WindowCovering.CurrentPosition}, ${this.Battery.BatteryLevel})`);
406
+
390
407
  // CurrentPosition
391
- this.WindowCovering.CurrentPosition = 100 - context.slidePosition;
408
+ this.WindowCovering.CurrentPosition = 100 - this.webhookContext.slidePosition;
392
409
  await this.getCurrentPostion();
410
+
393
411
  // BatteryLevel
394
- this.Battery.BatteryLevel = context.battery;
412
+ this.Battery.BatteryLevel = this.webhookContext.battery;
395
413
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
414
+
396
415
  // StatusLowBattery
397
416
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
398
417
  ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
@@ -429,7 +448,8 @@ export class Curtain extends deviceBase {
429
448
  // Update HomeKit
430
449
  if ((serviceData.model === SwitchBotBLEModel.Curtain || SwitchBotBLEModel.Curtain3)
431
450
  && (serviceData.modelName === SwitchBotBLEModelName.Curtain || SwitchBotBLEModelName.Curtain3)) {
432
- await this.BLEparseStatus(serviceData);
451
+ this.serviceData = serviceData;
452
+ await this.BLEparseStatus();
433
453
  await this.updateHomeKitCharacteristics();
434
454
  } else {
435
455
  await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
@@ -447,7 +467,8 @@ export class Curtain extends deviceBase {
447
467
  await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);;
448
468
  if (await this.successfulStatusCodes(statusCode, deviceStatus)) {
449
469
  await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
450
- await this.openAPIparseStatus(deviceStatus.body);
470
+ this.deviceStatus = deviceStatus.body;
471
+ await this.openAPIparseStatus();
451
472
  await this.updateHomeKitCharacteristics();
452
473
  } else {
453
474
  await this.debugWarnLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
@@ -465,7 +486,8 @@ export class Curtain extends deviceBase {
465
486
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: curtainWebhookContext | curtain3WebhookContext) => {
466
487
  try {
467
488
  await this.debugLog(`received Webhook: ${JSON.stringify(context)}`);
468
- await this.parseStatusWebhook(context);
489
+ this.webhookContext = context;
490
+ await this.parseStatusWebhook();
469
491
  await this.updateHomeKitCharacteristics();
470
492
  } catch (e: any) {
471
493
  await this.errorLog(`failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);
@@ -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
 
@@ -68,7 +72,7 @@ export abstract class deviceBase {
68
72
  this.getDeviceConfigSettings(accessory, 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
@@ -76,82 +80,41 @@ export abstract class deviceBase {
76
80
  .setCharacteristic(this.hap.Characteristic.Manufacturer, 'SwitchBot')
77
81
  .setCharacteristic(this.hap.Characteristic.AppMatchingIdentifier, 'id1087374760')
78
82
  .setCharacteristic(this.hap.Characteristic.Name, device.deviceName ?? accessory.displayName)
79
- .setCharacteristic(this.hap.Characteristic.ConfiguredName, device.deviceName ?? accessory.displayName)
83
+ .setCharacteristic(this.hap.Characteristic.ConfiguredName, String(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;
114
- // 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
- }
100
+ const refreshRate = device.refreshRate ? 'Device Config' : this.config.options?.refreshRate ? 'Platform Config' : 'Default';
101
+ this.deviceUpdateRate = device.updateRate ?? this.config.options?.updateRate ?? 5;
125
102
  accessory.context.deviceUpdateRate = this.deviceUpdateRate;
126
- // 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
- }
103
+ const updateRate = device.updateRate ? 'Device Config' : this.config.options?.updateRate ? 'Platform Config' : 'Default';
104
+ this.devicePushRate = device.pushRate ?? this.config.options?.pushRate ?? 1;
137
105
  accessory.context.devicePushRate = this.devicePushRate;
106
+ const pushRate = device.pushRate ? 'Device Config' : this.config.options?.pushRate ? 'Platform Config' : 'Default';
107
+ await this.debugLog(`Using ${refreshRate} refreshRate: ${this.deviceRefreshRate}, ${updateRate} updateRate: ${this.deviceUpdateRate},`
108
+ + ` ${pushRate} pushRate: ${this.devicePushRate}`);
138
109
  }
139
110
 
140
111
  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
- }
112
+ this.deviceMaxRetries = device.maxRetries ?? 5;
113
+ const maxRetries = device.maxRetries ? 'Device' : 'Default';
114
+ this.deviceDelayBetweenRetries = device.delayBetweenRetries ? (device.delayBetweenRetries * 1000) : 3000;
115
+ const delayBetweenRetries = device.delayBetweenRetries ? 'Device' : 'Default';
116
+ await this.debugLog(`Using ${maxRetries} Max Retries: ${this.deviceMaxRetries},`
117
+ + ` ${delayBetweenRetries} Delay Between Retries: ${this.deviceDelayBetweenRetries}`);
155
118
  }
156
119
 
157
120
  async retryBLE({ max, fn }: { max: number; fn: { (): any; (): Promise<any> } }): Promise<null> {
@@ -167,14 +130,12 @@ export abstract class deviceBase {
167
130
  }
168
131
 
169
132
  async maxRetryBLE(): Promise<number> {
170
- if (this.device.maxRetry) {
171
- return this.device.maxRetry;
172
- } else {
173
- return 5;
174
- }
133
+ return this.device.maxRetry ? this.device.maxRetry : 5;
175
134
  }
176
135
 
177
136
  async getDeviceScanDuration(accessory: PlatformAccessory, device: device & devicesConfig): Promise<void> {
137
+ this.scanDuration = device.scanDuration ? (this.deviceUpdateRate > device.scanDuration) ? this.deviceUpdateRate : device.scanDuration
138
+ ? (this.deviceUpdateRate > 1) ? this.deviceUpdateRate : 1 : this.deviceUpdateRate : 1;
178
139
  if (device.scanDuration) {
179
140
  if (this.deviceUpdateRate > device.scanDuration) {
180
141
  this.scanDuration = this.deviceUpdateRate;
@@ -231,6 +192,12 @@ export abstract class deviceBase {
231
192
  if (device.mqttURL !== '') {
232
193
  deviceConfig['mqttURL'] = device.mqttURL;
233
194
  }
195
+ if (device.mqttOptions) {
196
+ deviceConfig['mqttOptions'] = device.mqttOptions;
197
+ }
198
+ if (device.mqttPubOptions) {
199
+ deviceConfig['mqttPubOptions'] = device.mqttPubOptions;
200
+ }
234
201
  if (device.maxRetries !== 0) {
235
202
  deviceConfig['maxRetries'] = device.maxRetries;
236
203
  }
@@ -319,21 +286,10 @@ export abstract class deviceBase {
319
286
  const numberOfLevels = spaceBetweenLevels + 1;
320
287
  this.debugLog(`LightLevel: ${lightLevel}, set_minLux: ${set_minLux}, set_maxLux: ${set_maxLux}, spaceBetweenLevels: ${spaceBetweenLevels},`
321
288
  + ` 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}`);
289
+ const CurrentAmbientLightLevel = lightLevel === 1 ? set_minLux : lightLevel = numberOfLevels
290
+ ? set_maxLux : ((set_maxLux - set_minLux) / spaceBetweenLevels) * (Number(lightLevel) - 1);
291
+ await this.debugLog(`CurrentAmbientLightLevel: ${CurrentAmbientLightLevel}, LightLevel: ${lightLevel}, set_minLux: ${set_minLux},`
292
+ + ` set_maxLux: ${set_maxLux}`);
337
293
  return CurrentAmbientLightLevel;
338
294
  }
339
295
 
@@ -342,41 +298,29 @@ export abstract class deviceBase {
342
298
  * 'homebridge-switchbot/${this.device.deviceType}/xx:xx:xx:xx:xx:xx'
343
299
  */
344
300
  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
- }
301
+ const mac = this.device.deviceId?.toLowerCase().match(/[\s\S]{1,2}/g)?.join(':');
302
+ const options = this.deviceMqttPubOptions ?? {};
303
+ const mqttTopic = topic ? `/${topic}` : '';
304
+ const mqttMessageTopic = topic ? `${topic}/` : '';
359
305
  this.mqttClient?.publish(`homebridge-switchbot/${this.device.deviceType}/${mac}${mqttTopic}`, `${message}`, options);
360
306
  this.debugLog(`MQTT message: ${mqttMessageTopic}${message} options:${JSON.stringify(options)}`);
361
307
  }
362
308
 
363
309
  /*
364
- * Setup MQTT hadler if URL is specified.
310
+ * MQTT Settings
365
311
  */
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
- }
312
+ async getMqttSettings(device: device & devicesConfig): Promise<void> {
313
+ // mqttURL
314
+ this.deviceMqttURL = device.mqttURL ?? this.config.options?.mqttURL ?? '';
315
+ const mqttURL = device.mqttURL ? 'Device Config' : this.config.options?.mqttURL ? 'Platform Config' : 'Default';
316
+ // mqttOptions
317
+ this.deviceMqttOptions = device.mqttOptions ?? this.config.options?.mqttOptions ?? {};
318
+ const mqttOptions = device.mqttOptions ? 'Device Config' : this.config.options?.mqttOptions ? 'Platform Config' : 'Default';
319
+ // mqttPubOptions
320
+ this.deviceMqttPubOptions = device.mqttPubOptions ?? this.config.options?.mqttPubOptions ?? {};
321
+ const mqttPubOptions = device.mqttPubOptions ? 'Device Config' : this.config.options?.mqttPubOptions ? 'Platform Config' : 'Default';
322
+ await this.debugLog(`Using ${mqttURL} MQTT URL: ${this.deviceMqttURL}, ${mqttOptions} mqttOptions: ${JSON.stringify(this.deviceMqttOptions)},`
323
+ + ` ${mqttPubOptions} mqttPubOptions: ${JSON.stringify(this.deviceMqttPubOptions)}`);
380
324
  }
381
325
 
382
326
  /*
package/src/device/fan.ts CHANGED
@@ -39,6 +39,15 @@ export class Fan extends deviceBase {
39
39
  Brightness: CharacteristicValue;
40
40
  };
41
41
 
42
+ // OpenAPI
43
+ deviceStatus!: batteryCirculatorFanStatus;
44
+
45
+ //Webhook
46
+ webhookContext!: batteryCirculatorFanWebhookContext;
47
+
48
+ // BLE
49
+ serviceData!: batteryCirculatorFanServiceData;
50
+
42
51
  // Updates
43
52
  fanUpdateInProgress!: boolean;
44
53
  doFanUpdate!: Subject<void>;
@@ -149,10 +158,12 @@ export class Fan extends deviceBase {
149
158
  .onSet(this.BrightnessSet.bind(this));
150
159
 
151
160
  // Retrieve initial values and updateHomekit
161
+ this.debugLog('Retrieve initial values and update Homekit');
152
162
  this.refreshStatus();
153
163
 
154
- // Update Homekit
155
- this.updateHomeKitCharacteristics();
164
+ //regisiter webhook event handler
165
+ this.debugLog('Registering Webhook Event Handler');
166
+ this.registerWebhook();
156
167
 
157
168
  //regisiter webhook event handler
158
169
  this.registerWebhook();
@@ -184,35 +195,45 @@ export class Fan extends deviceBase {
184
195
  });
185
196
  }
186
197
 
187
- async BLEparseStatus(serviceData: batteryCirculatorFanServiceData): Promise<void> {
198
+ async BLEparseStatus(): Promise<void> {
188
199
  await this.debugLog('BLEparseStatus');
200
+ await this.debugLog(`(powerState, fanSpeed) = BLE:(${this.serviceData.state}, ${this.serviceData.fanSpeed}), current:(${this.Fan.Active},`
201
+ + ` ${this.Fan.RotationSpeed})`);
202
+
189
203
  // Active
190
- this.Fan.Active = serviceData.state === 'on' ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE;
204
+ this.Fan.Active = this.serviceData.state === 'on' ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE;
191
205
  await this.debugLog(`Active: ${this.Fan.Active}`);
206
+
207
+ // RotationSpeed
208
+ this.Fan.RotationSpeed = this.serviceData.fanSpeed;
192
209
  }
193
210
 
194
- async openAPIparseStatus(deviceStatus: batteryCirculatorFanStatus) {
211
+ async openAPIparseStatus() {
195
212
  await this.debugLog('openAPIparseStatus');
213
+ await this.debugLog(`(version, battery, powerState, oscillation, chargingStatus, fanSpeed) = OpenAPI:(${this.deviceStatus.version},`
214
+ + ` ${this.deviceStatus.battery}, ${this.deviceStatus.power}, ${this.deviceStatus.oscillation}, ${this.deviceStatus.chargingStatus},`
215
+ + ` ${this.deviceStatus.fanSpeed}), current:(${this.accessory.context.deviceVersion}, ${this.Battery.BatteryLevel}, ${this.Fan.Active},`
216
+ + ` ${this.Fan.SwingMode}, ${this.Battery.ChargingState}, ${this.Fan.RotationSpeed})`);
196
217
 
197
218
  // Active
198
- this.Fan.Active = deviceStatus.power === 'on' ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE;
219
+ this.Fan.Active = this.deviceStatus.power === 'on' ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE;
199
220
  this.debugLog(`Active: ${this.Fan.Active}`);
200
221
 
201
222
  // SwingMode
202
- this.Fan.SwingMode = deviceStatus.oscillation === 'on' ?
223
+ this.Fan.SwingMode = this.deviceStatus.oscillation === 'on' ?
203
224
  this.hap.Characteristic.SwingMode.SWING_ENABLED : this.hap.Characteristic.SwingMode.SWING_DISABLED;
204
225
  await this.debugLog(`SwingMode: ${this.Fan.SwingMode}`);
205
226
 
206
227
  // RotationSpeed
207
- this.Fan.RotationSpeed = deviceStatus.fanSpeed;
228
+ this.Fan.RotationSpeed = this.deviceStatus.fanSpeed;
208
229
  await this.debugLog(`RotationSpeed: ${this.Fan.RotationSpeed}`);
209
230
 
210
231
  // ChargingState
211
- this.Battery.ChargingState = deviceStatus.chargingStatus === 'charging' ?
232
+ this.Battery.ChargingState = this.deviceStatus.chargingStatus === 'charging' ?
212
233
  this.hap.Characteristic.ChargingState.CHARGING : this.hap.Characteristic.ChargingState.NOT_CHARGING;
213
234
 
214
235
  // BatteryLevel
215
- this.Battery.BatteryLevel = Number(deviceStatus.battery);
236
+ this.Battery.BatteryLevel = this.deviceStatus.battery;
216
237
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
217
238
 
218
239
  // StatusLowBattery
@@ -221,9 +242,9 @@ export class Fan extends deviceBase {
221
242
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
222
243
 
223
244
  // Firmware Version
224
- const version = deviceStatus.version.toString();
225
- await this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`);
226
- if (deviceStatus.version) {
245
+ if (this.deviceStatus.version) {
246
+ const version = this.deviceStatus.version.toString();
247
+ await this.debugLog(`Firmware Version: ${version.replace(/^V|-.*$/g, '')}`);
227
248
  const deviceVersion = version.replace(/^V|-.*$/g, '') ?? '0.0.0';
228
249
  this.accessory
229
250
  .getService(this.hap.Service.AccessoryInformation)!
@@ -236,36 +257,43 @@ export class Fan extends deviceBase {
236
257
  }
237
258
  }
238
259
 
239
- async parseStatusWebhook(context: batteryCirculatorFanWebhookContext): Promise<void> {
260
+ async parseStatusWebhook(): Promise<void> {
240
261
  await this.debugLog('parseStatusWebhook');
241
- await this.debugLog(`(version, battery, powerState, oscillation, chargingStatus, fanSpeed) = Webhook:(${context.version}, ${context.battery},`
242
- + ` ${context.powerState}, ${context.oscillation}, ${context.chargingStatus}, ${context.fanSpeed}),`
243
- + ` current:(${this.accessory.context.deviceVersion}, ${this.Battery.BatteryLevel}, ${this.Fan.Active}, ${this.Fan.SwingMode},`
244
- + ` ${this.Battery.ChargingState}, ${this.Fan.RotationSpeed})`);
262
+ await this.debugLog(`(version, battery, powerState, oscillation, chargingStatus, fanSpeed) = Webhook:(${this.webhookContext.version},`
263
+ + ` ${this.webhookContext.battery}, ${this.webhookContext.powerState}, ${this.webhookContext.oscillation},`
264
+ + ` ${this.webhookContext.chargingStatus}, ${this.webhookContext.fanSpeed}), current:(${this.accessory.context.deviceVersion},`
265
+ + ` ${this.Battery.BatteryLevel}, ${this.Fan.Active}, ${this.Fan.SwingMode}, ${this.Battery.ChargingState}, ${this.Fan.RotationSpeed})`);
266
+
245
267
  // Active
246
- this.Fan.Active = context.powerState === 'ON' ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE;
268
+ this.Fan.Active = this.webhookContext.powerState === 'ON' ? this.hap.Characteristic.Active.ACTIVE : this.hap.Characteristic.Active.INACTIVE;
247
269
  await this.debugLog(`Active: ${this.Fan.Active}`);
270
+
248
271
  // SwingMode
249
- this.Fan.SwingMode = context.oscillation === 'on' ?
272
+ this.Fan.SwingMode = this.webhookContext.oscillation === 'on' ?
250
273
  this.hap.Characteristic.SwingMode.SWING_ENABLED : this.hap.Characteristic.SwingMode.SWING_DISABLED;
251
274
  await this.debugLog(`SwingMode: ${this.Fan.SwingMode}`);
275
+
252
276
  // RotationSpeed
253
- this.Fan.RotationSpeed = context.fanSpeed;
277
+ this.Fan.RotationSpeed = this.webhookContext.fanSpeed;
254
278
  await this.debugLog(`RotationSpeed: ${this.Fan.RotationSpeed}`);
279
+
255
280
  // BatteryLevel
256
- this.Battery.BatteryLevel = context.battery;
281
+ this.Battery.BatteryLevel = this.webhookContext.battery;
257
282
  await this.debugLog(`BatteryLevel: ${this.Battery.BatteryLevel}`);
283
+
258
284
  // StatusLowBattery
259
285
  this.Battery.StatusLowBattery = this.Battery.BatteryLevel < 10
260
286
  ? this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_LOW : this.hap.Characteristic.StatusLowBattery.BATTERY_LEVEL_NORMAL;
261
287
  await this.debugLog(`StatusLowBattery: ${this.Battery.StatusLowBattery}`);
288
+
262
289
  // ChargingState
263
- this.Battery.ChargingState = context.chargingStatus === 'charging' ?
290
+ this.Battery.ChargingState = this.webhookContext.chargingStatus === 'charging' ?
264
291
  this.hap.Characteristic.ChargingState.CHARGING : this.hap.Characteristic.ChargingState.NOT_CHARGING;
265
292
  await this.debugLog(`ChargingState: ${this.Battery.ChargingState}`);
293
+
266
294
  // FirmwareVersion
267
- if (context.version) {
268
- const deviceVersion = context.version.replace(/^V|-.*$/g, '') ?? '0.0.0';
295
+ if (this.webhookContext.version) {
296
+ const deviceVersion = this.webhookContext.version.replace(/^V|-.*$/g, '') ?? '0.0.0';
269
297
  this.accessory
270
298
  .getService(this.hap.Service.AccessoryInformation)!
271
299
  .setCharacteristic(this.hap.Characteristic.HardwareRevision, deviceVersion)
@@ -303,10 +331,11 @@ export class Fan extends deviceBase {
303
331
  // Start to monitor advertisement packets
304
332
  (async () => {
305
333
  // Start to monitor advertisement packets
306
- const serviceData = await this.monitorAdvertisementPackets(switchbot) as unknown as batteryCirculatorFanServiceData;
334
+ const serviceData = await this.monitorAdvertisementPackets(switchbot) as batteryCirculatorFanServiceData;
307
335
  // Update HomeKit
308
336
  if (serviceData.model === SwitchBotBLEModel.Unknown && SwitchBotBLEModelName.Unknown) {
309
- await this.BLEparseStatus(serviceData);
337
+ this.serviceData = serviceData;
338
+ await this.BLEparseStatus();
310
339
  await this.updateHomeKitCharacteristics();
311
340
  } else {
312
341
  await this.errorLog(`failed to get serviceData, serviceData: ${serviceData}`);
@@ -324,7 +353,8 @@ export class Fan extends deviceBase {
324
353
  await this.debugLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);;
325
354
  if (await this.successfulStatusCodes(statusCode, deviceStatus)) {
326
355
  await this.debugSuccessLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
327
- await this.openAPIparseStatus(deviceStatus.body);
356
+ this.deviceStatus = deviceStatus.body;
357
+ await this.openAPIparseStatus();
328
358
  await this.updateHomeKitCharacteristics();
329
359
  } else {
330
360
  await this.debugWarnLog(`statusCode: ${statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`);
@@ -342,7 +372,8 @@ export class Fan extends deviceBase {
342
372
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: batteryCirculatorFanWebhookContext) => {
343
373
  try {
344
374
  await this.debugLog(`received Webhook: ${JSON.stringify(context)}`);
345
- await this.parseStatusWebhook(context);
375
+ this.webhookContext = context;
376
+ await this.parseStatusWebhook();
346
377
  await this.updateHomeKitCharacteristics();
347
378
  } catch (e: any) {
348
379
  await this.errorLog(`failed to handle webhook. Received: ${JSON.stringify(context)} Error: ${e}`);