@switchbot/homebridge-switchbot 5.0.0-beta.43 → 5.0.0-beta.44

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 (109) hide show
  1. package/config.schema.json +61 -9
  2. package/dist/devices-hap/airpurifier.d.ts.map +1 -1
  3. package/dist/devices-hap/airpurifier.js +12 -6
  4. package/dist/devices-hap/airpurifier.js.map +1 -1
  5. package/dist/devices-hap/blindtilt.js +3 -3
  6. package/dist/devices-hap/bot.d.ts.map +1 -1
  7. package/dist/devices-hap/bot.js +16 -5
  8. package/dist/devices-hap/bot.js.map +1 -1
  9. package/dist/devices-hap/ceilinglight.d.ts.map +1 -1
  10. package/dist/devices-hap/ceilinglight.js +13 -7
  11. package/dist/devices-hap/ceilinglight.js.map +1 -1
  12. package/dist/devices-hap/colorbulb.d.ts.map +1 -1
  13. package/dist/devices-hap/colorbulb.js +49 -9
  14. package/dist/devices-hap/colorbulb.js.map +1 -1
  15. package/dist/devices-hap/contact.js +3 -3
  16. package/dist/devices-hap/curtain.js +2 -2
  17. package/dist/devices-hap/curtain.js.map +1 -1
  18. package/dist/devices-hap/device.d.ts.map +1 -1
  19. package/dist/devices-hap/device.js +20 -1
  20. package/dist/devices-hap/device.js.map +1 -1
  21. package/dist/devices-hap/fan.d.ts.map +1 -1
  22. package/dist/devices-hap/fan.js +12 -6
  23. package/dist/devices-hap/fan.js.map +1 -1
  24. package/dist/devices-hap/hub.d.ts.map +1 -1
  25. package/dist/devices-hap/hub.js +6 -5
  26. package/dist/devices-hap/hub.js.map +1 -1
  27. package/dist/devices-hap/humidifier.d.ts +5 -0
  28. package/dist/devices-hap/humidifier.d.ts.map +1 -1
  29. package/dist/devices-hap/humidifier.js +92 -4
  30. package/dist/devices-hap/humidifier.js.map +1 -1
  31. package/dist/devices-hap/iosensor.d.ts.map +1 -1
  32. package/dist/devices-hap/iosensor.js +36 -21
  33. package/dist/devices-hap/iosensor.js.map +1 -1
  34. package/dist/devices-hap/lightstrip.d.ts.map +1 -1
  35. package/dist/devices-hap/lightstrip.js +38 -8
  36. package/dist/devices-hap/lightstrip.js.map +1 -1
  37. package/dist/devices-hap/lock.d.ts.map +1 -1
  38. package/dist/devices-hap/lock.js +14 -6
  39. package/dist/devices-hap/lock.js.map +1 -1
  40. package/dist/devices-hap/meter.d.ts.map +1 -1
  41. package/dist/devices-hap/meter.js +6 -5
  42. package/dist/devices-hap/meter.js.map +1 -1
  43. package/dist/devices-hap/meterplus.d.ts.map +1 -1
  44. package/dist/devices-hap/meterplus.js +6 -5
  45. package/dist/devices-hap/meterplus.js.map +1 -1
  46. package/dist/devices-hap/meterpro.d.ts.map +1 -1
  47. package/dist/devices-hap/meterpro.js +7 -6
  48. package/dist/devices-hap/meterpro.js.map +1 -1
  49. package/dist/devices-hap/motion.js +3 -3
  50. package/dist/devices-hap/plug.d.ts.map +1 -1
  51. package/dist/devices-hap/plug.js +11 -6
  52. package/dist/devices-hap/plug.js.map +1 -1
  53. package/dist/devices-hap/relayswitch.js +3 -3
  54. package/dist/devices-hap/robotvacuumcleaner.d.ts.map +1 -1
  55. package/dist/devices-hap/robotvacuumcleaner.js +13 -6
  56. package/dist/devices-hap/robotvacuumcleaner.js.map +1 -1
  57. package/dist/devices-hap/waterdetector.js +3 -3
  58. package/dist/homebridge-ui/public/index.html +13 -1
  59. package/dist/platform-hap.d.ts.map +1 -1
  60. package/dist/platform-hap.js +38 -2
  61. package/dist/platform-hap.js.map +1 -1
  62. package/dist/platform-matter.d.ts.map +1 -1
  63. package/dist/platform-matter.js +69 -2
  64. package/dist/platform-matter.js.map +1 -1
  65. package/dist/settings.d.ts +12 -1
  66. package/dist/settings.d.ts.map +1 -1
  67. package/dist/settings.js.map +1 -1
  68. package/dist/test/hap/device-webhook-context.test.d.ts +2 -0
  69. package/dist/test/hap/device-webhook-context.test.d.ts.map +1 -0
  70. package/dist/test/hap/device-webhook-context.test.js +128 -0
  71. package/dist/test/hap/device-webhook-context.test.js.map +1 -0
  72. package/dist/test/matter/platform-matter.webhook.test.d.ts +2 -0
  73. package/dist/test/matter/platform-matter.webhook.test.d.ts.map +1 -0
  74. package/dist/test/matter/platform-matter.webhook.test.js +46 -0
  75. package/dist/test/matter/platform-matter.webhook.test.js.map +1 -0
  76. package/dist/utils.d.ts.map +1 -1
  77. package/dist/utils.js +10 -4
  78. package/dist/utils.js.map +1 -1
  79. package/docs/variables/default.html +1 -1
  80. package/package.json +2 -2
  81. package/src/devices-hap/airpurifier.ts +11 -6
  82. package/src/devices-hap/blindtilt.ts +3 -3
  83. package/src/devices-hap/bot.ts +15 -5
  84. package/src/devices-hap/ceilinglight.ts +12 -7
  85. package/src/devices-hap/colorbulb.ts +46 -10
  86. package/src/devices-hap/contact.ts +3 -3
  87. package/src/devices-hap/curtain.ts +2 -2
  88. package/src/devices-hap/device.ts +20 -1
  89. package/src/devices-hap/fan.ts +11 -6
  90. package/src/devices-hap/hub.ts +6 -5
  91. package/src/devices-hap/humidifier.ts +97 -4
  92. package/src/devices-hap/iosensor.ts +36 -21
  93. package/src/devices-hap/lightstrip.ts +35 -8
  94. package/src/devices-hap/lock.ts +13 -6
  95. package/src/devices-hap/meter.ts +6 -5
  96. package/src/devices-hap/meterplus.ts +6 -5
  97. package/src/devices-hap/meterpro.ts +7 -6
  98. package/src/devices-hap/motion.ts +3 -3
  99. package/src/devices-hap/plug.ts +10 -6
  100. package/src/devices-hap/relayswitch.ts +3 -3
  101. package/src/devices-hap/robotvacuumcleaner.ts +12 -6
  102. package/src/devices-hap/waterdetector.ts +3 -3
  103. package/src/homebridge-ui/public/index.html +13 -1
  104. package/src/platform-hap.ts +38 -2
  105. package/src/platform-matter.ts +70 -2
  106. package/src/settings.ts +12 -1
  107. package/src/test/hap/device-webhook-context.test.ts +136 -0
  108. package/src/test/matter/platform-matter.webhook.test.ts +54 -0
  109. package/src/utils.ts +14 -4
@@ -264,7 +264,7 @@ export class AirPurifier extends deviceBase {
264
264
  // Update HomeKit
265
265
  if ((serviceData.model === SwitchBotBLEModel.AirPurifier && SwitchBotBLEModelName.AirPurifier) ?? (serviceData.model === SwitchBotBLEModel.AirPurifierTable && SwitchBotBLEModelName.AirPurifierTable)) {
266
266
  this.serviceData = serviceData
267
- if (serviceData !== undefined || serviceData !== null) {
267
+ if (serviceData !== undefined && serviceData !== null) {
268
268
  await this.BLEparseStatus()
269
269
  await this.updateHomeKitCharacteristics()
270
270
  } else {
@@ -290,7 +290,7 @@ export class AirPurifier extends deviceBase {
290
290
  this.platform.bleEventHandler[this.device.bleMac] = async (context: airPurifierServiceData | airPurifierTableServiceData) => {
291
291
  try {
292
292
  this.serviceData = context
293
- if (context !== undefined || context !== null) {
293
+ if (context !== undefined && context !== null) {
294
294
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
295
295
  await this.BLEparseStatus()
296
296
  await this.updateHomeKitCharacteristics()
@@ -335,7 +335,7 @@ export class AirPurifier extends deviceBase {
335
335
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: airPurifierWebhookContext | airPurifierTableWebhookContext) => {
336
336
  try {
337
337
  this.webhookContext = context
338
- if (context !== undefined || context !== null) {
338
+ if (context !== undefined && context !== null) {
339
339
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
340
340
  await this.parseStatusWebhook()
341
341
  await this.updateHomeKitCharacteristics()
@@ -400,13 +400,18 @@ export class AirPurifier extends deviceBase {
400
400
  switchBotBLE
401
401
  .discover({ model: this.device.bleModel, id: this.device.bleMac })
402
402
  .then(async (device_list: SwitchbotDevice[]) => {
403
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
403
404
  return await this.retryBLE({
404
405
  max: this.maxRetryBLE(),
405
406
  fn: async () => {
406
- if (this.AirPurifier.Active) {
407
- return await (device_list[0] as any).turnOn()
407
+ if (Array.isArray(device_list) && device_list.length > 0) {
408
+ if (this.AirPurifier.Active) {
409
+ return await (device_list[0] as any).turnOn()
410
+ } else {
411
+ return await (device_list[0] as any).turnOff()
412
+ }
408
413
  } else {
409
- return await (device_list[0] as any).turnOff()
414
+ throw new Error('No devices found during discovery.')
410
415
  }
411
416
  },
412
417
  })
@@ -465,7 +465,7 @@ export class BlindTilt extends deviceBase {
465
465
  // Update HomeKit
466
466
  if (serviceData.model === SwitchBotBLEModel.BlindTilt && serviceData.modelName === SwitchBotBLEModelName.BlindTilt) {
467
467
  this.serviceData = serviceData
468
- if (serviceData !== undefined || serviceData !== null) {
468
+ if (serviceData !== undefined && serviceData !== null) {
469
469
  await this.BLEparseStatus()
470
470
  await this.updateHomeKitCharacteristics()
471
471
  } else {
@@ -491,7 +491,7 @@ export class BlindTilt extends deviceBase {
491
491
  this.platform.bleEventHandler[this.device.bleMac] = async (context: blindTiltServiceData) => {
492
492
  try {
493
493
  this.serviceData = context
494
- if (context !== undefined || context !== null) {
494
+ if (context !== undefined && context !== null) {
495
495
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
496
496
  await this.BLEparseStatus()
497
497
  await this.updateHomeKitCharacteristics()
@@ -536,7 +536,7 @@ export class BlindTilt extends deviceBase {
536
536
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: blindTiltWebhookContext) => {
537
537
  try {
538
538
  this.webhookContext = context
539
- if (context !== undefined || context !== null) {
539
+ if (context !== undefined && context !== null) {
540
540
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
541
541
  await this.parseStatusWebhook()
542
542
  await this.updateHomeKitCharacteristics()
@@ -262,7 +262,7 @@ export class Bot extends deviceBase {
262
262
  }
263
263
  } catch (e: any) {
264
264
  await this.apiError(e)
265
- this.errorLog(`failed pushChanges with ${device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)
265
+ this.errorLog(`failed pushChanges with ${device.connectionType} Connection, Error: ${e.message ?? e}`)
266
266
  }
267
267
  this.botUpdateInProgress = false
268
268
  })
@@ -381,7 +381,7 @@ export class Bot extends deviceBase {
381
381
  // Update HomeKit
382
382
  if (serviceData.model === SwitchBotBLEModel.Bot && serviceData.modelName === SwitchBotBLEModelName.Bot) {
383
383
  this.serviceData = serviceData
384
- if (serviceData !== undefined || serviceData !== null) {
384
+ if (serviceData !== undefined && serviceData !== null) {
385
385
  await this.BLEparseStatus()
386
386
  await this.updateHomeKitCharacteristics()
387
387
  } else {
@@ -407,7 +407,7 @@ export class Bot extends deviceBase {
407
407
  this.platform.bleEventHandler[this.device.bleMac] = async (context: botServiceData) => {
408
408
  try {
409
409
  this.serviceData = context
410
- if (context !== undefined || context !== null) {
410
+ if (context !== undefined && context !== null) {
411
411
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
412
412
  await this.BLEparseStatus()
413
413
  await this.updateHomeKitCharacteristics()
@@ -452,7 +452,7 @@ export class Bot extends deviceBase {
452
452
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: botWebhookContext) => {
453
453
  try {
454
454
  this.webhookContext = context
455
- if (context !== undefined || context !== null) {
455
+ if (context !== undefined && context !== null) {
456
456
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
457
457
  await this.parseStatusWebhook()
458
458
  await this.updateHomeKitCharacteristics()
@@ -510,7 +510,17 @@ export class Bot extends deviceBase {
510
510
  .then(async (device_list: SwitchbotDevice[]) => {
511
511
  const deviceList = device_list as WoHand[]
512
512
  this.infoLog(`On: ${this.On}`)
513
- return await deviceList[0].press()
513
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
514
+ return await this.retryBLE({
515
+ max: this.maxRetryBLE(),
516
+ fn: async () => {
517
+ if (deviceList.length > 0) {
518
+ return await deviceList[0].press()
519
+ } else {
520
+ throw new Error('No device found')
521
+ }
522
+ },
523
+ })
514
524
  })
515
525
  .then(async () => {
516
526
  this.successLog(`On: ${this.On} sent over SwitchBot BLE, sent successfully`)
@@ -291,7 +291,7 @@ export class CeilingLight extends deviceBase {
291
291
  // Update HomeKit
292
292
  if ((serviceData.model === SwitchBotBLEModel.CeilingLight || SwitchBotBLEModel.CeilingLightPro) && (serviceData.modelName === SwitchBotBLEModelName.CeilingLight || SwitchBotBLEModelName.CeilingLightPro)) {
293
293
  this.serviceData = serviceData
294
- if (serviceData !== undefined || serviceData !== null) {
294
+ if (serviceData !== undefined && serviceData !== null) {
295
295
  await this.BLEparseStatus()
296
296
  await this.updateHomeKitCharacteristics()
297
297
  } else {
@@ -317,7 +317,7 @@ export class CeilingLight extends deviceBase {
317
317
  this.platform.bleEventHandler[this.device.bleMac] = async (context: ceilingLightServiceData | ceilingLightProServiceData) => {
318
318
  try {
319
319
  this.serviceData = context
320
- if (context !== undefined || context !== null) {
320
+ if (context !== undefined && context !== null) {
321
321
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
322
322
  await this.BLEparseStatus()
323
323
  await this.updateHomeKitCharacteristics()
@@ -362,7 +362,7 @@ export class CeilingLight extends deviceBase {
362
362
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: ceilingLightWebhookContext | ceilingLightProWebhookContext) => {
363
363
  try {
364
364
  this.webhookContext = context
365
- if (context !== undefined || context !== null) {
365
+ if (context !== undefined && context !== null) {
366
366
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
367
367
  await this.parseStatusWebhook()
368
368
  await this.updateHomeKitCharacteristics()
@@ -434,15 +434,20 @@ export class CeilingLight extends deviceBase {
434
434
  switchBotBLE
435
435
  .discover({ model: this.device.bleModel, id: this.device.bleMac })
436
436
  .then(async (device_list: SwitchbotDevice[]) => {
437
- const deviceList = device_list[0] as WoCeilingLight
437
+ const deviceList = device_list as WoCeilingLight[]
438
438
  this.infoLog(`On: ${this.LightBulb.On}`)
439
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
439
440
  return await this.retryBLE({
440
441
  max: this.maxRetryBLE(),
441
442
  fn: async () => {
442
- if (this.LightBulb.On) {
443
- return await deviceList[0].turnOn()
443
+ if (deviceList.length > 0) {
444
+ if (this.LightBulb.On) {
445
+ return await deviceList[0].turnOn()
446
+ } else {
447
+ return await deviceList[0].turnOff()
448
+ }
444
449
  } else {
445
- return await deviceList[0].turnOff()
450
+ throw new Error('No devices found during discovery.')
446
451
  }
447
452
  },
448
453
  })
@@ -326,7 +326,7 @@ export class ColorBulb extends deviceBase {
326
326
  // Update HomeKit
327
327
  if (serviceData.model === SwitchBotBLEModel.ColorBulb && serviceData.modelName === SwitchBotBLEModelName.ColorBulb) {
328
328
  this.serviceData = serviceData
329
- if (serviceData !== undefined || serviceData !== null) {
329
+ if (serviceData !== undefined && serviceData !== null) {
330
330
  await this.BLEparseStatus()
331
331
  await this.updateHomeKitCharacteristics()
332
332
  } else {
@@ -352,7 +352,7 @@ export class ColorBulb extends deviceBase {
352
352
  this.platform.bleEventHandler[this.device.bleMac] = async (context: colorBulbServiceData) => {
353
353
  try {
354
354
  this.serviceData = context
355
- if (context !== undefined || context !== null) {
355
+ if (context !== undefined && context !== null) {
356
356
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
357
357
  await this.BLEparseStatus()
358
358
  await this.updateHomeKitCharacteristics()
@@ -397,7 +397,7 @@ export class ColorBulb extends deviceBase {
397
397
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: colorBulbWebhookContext) => {
398
398
  try {
399
399
  this.webhookContext = context
400
- if (context !== undefined || context !== null) {
400
+ if (context !== undefined && context !== null) {
401
401
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
402
402
  await this.parseStatusWebhook()
403
403
  await this.updateHomeKitCharacteristics()
@@ -480,15 +480,21 @@ export class ColorBulb extends deviceBase {
480
480
  if (switchBotBLE !== false) {
481
481
  switchBotBLE
482
482
  .discover({ model: this.device.bleModel, id: this.device.bleMac })
483
- .then(async (device_list: WoBulb[]) => {
483
+ .then(async (device_list: SwitchbotDevice[]) => {
484
+ const deviceList = device_list as WoBulb[]
484
485
  this.infoLog(`On: ${this.LightBulb.On}`)
486
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
485
487
  return await this.retryBLE({
486
488
  max: this.maxRetryBLE(),
487
489
  fn: async () => {
488
- if (this.LightBulb.On) {
489
- return await device_list[0].turnOn()
490
+ if (deviceList.length > 0) {
491
+ if (this.LightBulb.On) {
492
+ return await deviceList[0].turnOn()
493
+ } else {
494
+ return await deviceList[0].turnOff()
495
+ }
490
496
  } else {
491
- return await device_list[0].turnOff()
497
+ throw new Error('No devices found during discovery.')
492
498
  }
493
499
  },
494
500
  })
@@ -528,7 +534,17 @@ export class ColorBulb extends deviceBase {
528
534
  .then(async (device_list: SwitchbotDevice[]) => {
529
535
  const deviceList = device_list as WoBulb[]
530
536
  this.infoLog(`Target Brightness: ${this.LightBulb.Brightness}`)
531
- return await deviceList[0].setBrightness(Number(this.LightBulb.Brightness))
537
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
538
+ return await this.retryBLE({
539
+ max: this.maxRetryBLE(),
540
+ fn: async () => {
541
+ if (deviceList.length > 0) {
542
+ return await deviceList[0].setBrightness(Number(this.LightBulb.Brightness))
543
+ } else {
544
+ throw new Error('No devices found during discovery.')
545
+ }
546
+ },
547
+ })
532
548
  })
533
549
  .then(async () => {
534
550
  this.successLog(`Brightness: ${this.LightBulb.Brightness} sent over SwitchBot BLE, sent successfully`)
@@ -567,7 +583,17 @@ export class ColorBulb extends deviceBase {
567
583
  .then(async (device_list: SwitchbotDevice[]) => {
568
584
  const deviceList = device_list as WoBulb[]
569
585
  this.infoLog(`ColorTemperature: ${this.LightBulb.ColorTemperature}`)
570
- return await deviceList[0].setColorTemperature(kelvin)
586
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
587
+ return await this.retryBLE({
588
+ max: this.maxRetryBLE(),
589
+ fn: async () => {
590
+ if (deviceList.length > 0) {
591
+ return await deviceList[0].setColorTemperature(kelvin)
592
+ } else {
593
+ throw new Error('No devices found during discovery.')
594
+ }
595
+ },
596
+ })
571
597
  })
572
598
  .then(async () => {
573
599
  this.successLog(`ColorTemperature: ${this.LightBulb.ColorTemperature} sent over SwitchBot BLE, sent successfully`)
@@ -607,7 +633,17 @@ export class ColorBulb extends deviceBase {
607
633
  .then(async (device_list: SwitchbotDevice[]) => {
608
634
  const deviceList = device_list as WoBulb[]
609
635
  this.infoLog(`RGB: ${(this.LightBulb.Brightness, red, green, blue)}`)
610
- return await deviceList[0].setRGB(Number(this.LightBulb.Brightness), red, green, blue)
636
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
637
+ return await this.retryBLE({
638
+ max: this.maxRetryBLE(),
639
+ fn: async () => {
640
+ if (deviceList.length > 0) {
641
+ return await deviceList[0].setRGB(Number(this.LightBulb.Brightness), red, green, blue)
642
+ } else {
643
+ throw new Error('No devices found during discovery.')
644
+ }
645
+ },
646
+ })
611
647
  })
612
648
  .then(async () => {
613
649
  this.successLog(`RGB: ${(this.LightBulb.Brightness, red, green, blue)} sent over SwitchBot BLE, sent successfully`)
@@ -307,7 +307,7 @@ export class Contact extends deviceBase {
307
307
  // Update HomeKit
308
308
  if (serviceData.model === SwitchBotBLEModel.ContactSensor && serviceData.modelName === SwitchBotBLEModelName.ContactSensor) {
309
309
  this.serviceData = serviceData
310
- if (serviceData !== undefined || serviceData !== null) {
310
+ if (serviceData !== undefined && serviceData !== null) {
311
311
  await this.BLEparseStatus()
312
312
  await this.updateHomeKitCharacteristics()
313
313
  } else {
@@ -333,7 +333,7 @@ export class Contact extends deviceBase {
333
333
  this.platform.bleEventHandler[this.device.bleMac] = async (context: contactSensorServiceData) => {
334
334
  try {
335
335
  this.serviceData = context
336
- if (context !== undefined || context !== null) {
336
+ if (context !== undefined && context !== null) {
337
337
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
338
338
  await this.BLEparseStatus()
339
339
  await this.updateHomeKitCharacteristics()
@@ -378,7 +378,7 @@ export class Contact extends deviceBase {
378
378
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: contactSensorWebhookContext) => {
379
379
  try {
380
380
  this.webhookContext = context
381
- if (context !== undefined || context !== null) {
381
+ if (context !== undefined && context !== null) {
382
382
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
383
383
  await this.parseStatusWebhook()
384
384
  await this.updateHomeKitCharacteristics()
@@ -534,7 +534,7 @@ export class Curtain extends deviceBase {
534
534
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: curtainWebhookContext | curtain3WebhookContext) => {
535
535
  try {
536
536
  this.webhookContext = context
537
- if (context !== undefined || context !== null) {
537
+ if (context !== undefined && context !== null) {
538
538
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
539
539
  await this.parseStatusWebhook()
540
540
  await this.updateHomeKitCharacteristics()
@@ -657,7 +657,7 @@ export class Curtain extends deviceBase {
657
657
  const adjustedTargetPosition = 100 - Number(this.WindowCovering.TargetPosition)
658
658
  const { setPositionMode, Mode }: { setPositionMode: number, Mode: string } = await this.setPerformance()
659
659
  this.debugLog(`Mode: ${Mode}, setPositionMode: ${setPositionMode}`)
660
- const adjustedMode = setPositionMode || 'ff'
660
+ const adjustedMode = setPositionMode === 1 ? '01' : '00'
661
661
  let bodyChange: bodyChange
662
662
  if (this.WindowCovering.HoldPosition) {
663
663
  bodyChange = {
@@ -147,7 +147,9 @@ export abstract class deviceBase {
147
147
  device.scanDuration !== 0 && { scanDuration: device.scanDuration },
148
148
  device.offline === true && { offline: device.offline },
149
149
  device.maxRetry !== 0 && { maxRetry: device.maxRetry },
150
- device.webhook === true && { webhook: device.webhook },
150
+ (device.webhook === true || (device.webhook === undefined && this.config.options?.webhook === true)) && {
151
+ webhook: device.webhook !== undefined ? device.webhook : this.config.options?.webhook,
152
+ },
151
153
  device.connectionType !== '' && { connectionType: device.connectionType },
152
154
  device.disablePlatformBLE !== false && { disablePlatformBLE: device.disablePlatformBLE },
153
155
  device.external === true && { external: device.external },
@@ -584,6 +586,12 @@ export abstract class deviceBase {
584
586
  bleModelName: SwitchBotBLEModelName.LockPro,
585
587
  bleModelFriendlyName: SwitchBotBLEModelFriendlyName.LockPro,
586
588
  },
589
+ 'Smart Lock Ultra': {
590
+ model: SwitchBotModel.LockPro,
591
+ bleModel: SwitchBotBLEModel.LockPro,
592
+ bleModelName: SwitchBotBLEModelName.LockPro,
593
+ bleModelFriendlyName: SwitchBotBLEModelFriendlyName.LockPro,
594
+ },
587
595
  'Color Bulb': {
588
596
  model: SwitchBotModel.ColorBulb,
589
597
  bleModel: SwitchBotBLEModel.ColorBulb,
@@ -709,6 +717,17 @@ export abstract class deviceBase {
709
717
  .updateValue(deviceVersion)
710
718
  accessory.context.version = deviceVersion
711
719
  this.debugSuccessLog(`version: ${accessory.context.version}`)
720
+
721
+ // Expose effective webhook setting on accessory context (parity with Matter)
722
+ try {
723
+ const effectiveWebhook = device.webhook !== undefined ? device.webhook : (this.config.options?.webhook === true ? true : undefined)
724
+ if (effectiveWebhook !== undefined) {
725
+ accessory.context.webhook = effectiveWebhook
726
+ this.debugLog(`Effective webhook for ${device.deviceId}: ${String(effectiveWebhook)}`)
727
+ }
728
+ } catch (e: any) {
729
+ this.debugLog(`Failed to set webhook context for ${device.deviceId}: ${e?.message ?? e}`)
730
+ }
712
731
  }
713
732
 
714
733
  async statusCode(statusCode: number): Promise<void> {
@@ -329,7 +329,7 @@ export class Fan extends deviceBase {
329
329
  // Update HomeKit
330
330
  if (serviceData.model === SwitchBotBLEModel.Unknown && SwitchBotBLEModelName.Unknown) {
331
331
  this.serviceData = serviceData
332
- if (serviceData !== undefined || serviceData !== null) {
332
+ if (serviceData !== undefined && serviceData !== null) {
333
333
  await this.BLEparseStatus()
334
334
  await this.updateHomeKitCharacteristics()
335
335
  } else {
@@ -355,7 +355,7 @@ export class Fan extends deviceBase {
355
355
  this.platform.bleEventHandler[this.device.bleMac] = async (context: batteryCirculatorFanServiceData) => {
356
356
  try {
357
357
  this.serviceData = context
358
- if (context !== undefined || context !== null) {
358
+ if (context !== undefined && context !== null) {
359
359
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
360
360
  await this.BLEparseStatus()
361
361
  await this.updateHomeKitCharacteristics()
@@ -400,7 +400,7 @@ export class Fan extends deviceBase {
400
400
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: batteryCirculatorFanWebhookContext) => {
401
401
  try {
402
402
  this.webhookContext = context
403
- if (context !== undefined || context !== null) {
403
+ if (context !== undefined && context !== null) {
404
404
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
405
405
  await this.parseStatusWebhook()
406
406
  await this.updateHomeKitCharacteristics()
@@ -468,13 +468,18 @@ export class Fan extends deviceBase {
468
468
  switchBotBLE
469
469
  .discover({ model: this.device.bleModel, id: this.device.bleMac })
470
470
  .then(async (device_list: SwitchbotDevice[]) => {
471
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
471
472
  return await this.retryBLE({
472
473
  max: this.maxRetryBLE(),
473
474
  fn: async () => {
474
- if (this.Fan.Active) {
475
- return await (device_list[0] as any).turnOn()
475
+ if (Array.isArray(device_list) && device_list.length > 0) {
476
+ if (this.Fan.Active) {
477
+ return await (device_list[0] as any).turnOn()
478
+ } else {
479
+ return await (device_list[0] as any).turnOff()
480
+ }
476
481
  } else {
477
- return await (device_list[0] as any).turnOff()
482
+ throw new Error('No devices found during discovery.')
478
483
  }
479
484
  },
480
485
  })
@@ -211,8 +211,9 @@ export class Hub extends deviceBase {
211
211
 
212
212
  // CurrentTemperature
213
213
  if (!(this.device as hubConfig).hide_temperature && this.TemperatureSensor?.Service) {
214
- this.TemperatureSensor.CurrentTemperature = this.deviceStatus.temperature
215
- this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}°c`)
214
+ // OpenAPI returns Celsius; convert if user configured a different unit
215
+ this.TemperatureSensor.CurrentTemperature = convertUnits(this.deviceStatus.temperature, 'CELSIUS', (this.device as hubConfig).convertUnitTo)
216
+ this.debugLog(`CurrentTemperature: ${this.TemperatureSensor.CurrentTemperature}`)
216
217
  }
217
218
 
218
219
  // LightSensor
@@ -297,7 +298,7 @@ export class Hub extends deviceBase {
297
298
  if ((serviceData.model === SwitchBotBLEModel.Hub2 && serviceData.modelName === SwitchBotBLEModelName.Hub2)
298
299
  || (serviceData.model === SwitchBotBLEModel.Hub3 && serviceData.modelName === SwitchBotBLEModelName.Hub3)) {
299
300
  this.serviceData = serviceData
300
- if (serviceData !== undefined || serviceData !== null) {
301
+ if (serviceData !== undefined && serviceData !== null) {
301
302
  await this.BLEparseStatus()
302
303
  await this.updateHomeKitCharacteristics()
303
304
  } else {
@@ -323,7 +324,7 @@ export class Hub extends deviceBase {
323
324
  this.platform.bleEventHandler[this.device.bleMac] = async (context: hub2ServiceData) => {
324
325
  try {
325
326
  this.serviceData = context
326
- if (context !== undefined || context !== null) {
327
+ if (context !== undefined && context !== null) {
327
328
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
328
329
  await this.BLEparseStatus()
329
330
  await this.updateHomeKitCharacteristics()
@@ -368,7 +369,7 @@ export class Hub extends deviceBase {
368
369
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: hub2WebhookContext) => {
369
370
  try {
370
371
  this.webhookContext = context
371
- if (context !== undefined || context !== null) {
372
+ if (context !== undefined && context !== null) {
372
373
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
373
374
  await this.parseStatusWebhook()
374
375
  await this.updateHomeKitCharacteristics()
@@ -42,6 +42,12 @@ export class Humidifier extends deviceBase {
42
42
  CurrentTemperature: CharacteristicValue
43
43
  }
44
44
 
45
+ private DryingFilterSwitch?: {
46
+ Name: CharacteristicValue
47
+ Service: Service
48
+ On: CharacteristicValue
49
+ }
50
+
45
51
  // OpenAPI
46
52
  deviceStatus!: humidifierStatus | humidifier2Status
47
53
 
@@ -132,6 +138,31 @@ export class Humidifier extends deviceBase {
132
138
  })
133
139
  }
134
140
 
141
+ // Initialize optional Drying Filter Switch (Humidifier2 only)
142
+ if ((device as humidifierConfig).configDeviceType === 'Humidifier2' && (device as humidifierConfig).activate_dryingfilter) {
143
+ accessory.context.DryingFilterSwitch = accessory.context.DryingFilterSwitch ?? {}
144
+ this.DryingFilterSwitch = {
145
+ Name: `${accessory.displayName} Drying Filter`,
146
+ Service: accessory.getService(`${accessory.displayName} Drying Filter`) ?? accessory.addService(this.hap.Service.Switch, `${accessory.displayName} Drying Filter`, 'DryingFilterSwitch') as Service,
147
+ On: false,
148
+ }
149
+ accessory.context.DryingFilterSwitch = this.DryingFilterSwitch as object
150
+
151
+ this.DryingFilterSwitch.Service.setCharacteristic(this.hap.Characteristic.Name, this.DryingFilterSwitch.Name)
152
+ .getCharacteristic(this.hap.Characteristic.On)
153
+ .onGet(() => {
154
+ return this.DryingFilterSwitch!.On
155
+ })
156
+ .onSet(this.DryingFilterOnSet.bind(this))
157
+ this.debugLog('Initialized Drying Filter Switch Service')
158
+ } else {
159
+ const svc = this.accessory.getServiceById(this.hap.Service.Switch, 'DryingFilterSwitch')
160
+ if (svc) {
161
+ this.debugLog('Removing Drying Filter Switch Service')
162
+ this.accessory.removeService(svc)
163
+ }
164
+ }
165
+
135
166
  // Retrieve initial values and updateHomekit
136
167
  try {
137
168
  this.debugLog('Retrieve initial values and update Homekit')
@@ -326,7 +357,7 @@ export class Humidifier extends deviceBase {
326
357
  // Update HomeKit
327
358
  if (serviceData.model === SwitchBotBLEModel.Humidifier && serviceData.modelName === SwitchBotBLEModelName.Humidifier) {
328
359
  this.serviceData = serviceData
329
- if (serviceData !== undefined || serviceData !== null) {
360
+ if (serviceData !== undefined && serviceData !== null) {
330
361
  await this.BLEparseStatus()
331
362
  await this.updateHomeKitCharacteristics()
332
363
  } else {
@@ -352,7 +383,7 @@ export class Humidifier extends deviceBase {
352
383
  this.platform.bleEventHandler[this.device.bleMac] = async (context: humidifierServiceData | humidifier2ServiceData) => {
353
384
  try {
354
385
  this.serviceData = context
355
- if (context !== undefined || context !== null) {
386
+ if (context !== undefined && context !== null) {
356
387
  this.debugLog(`received BLE: ${JSON.stringify(context)}`)
357
388
  await this.BLEparseStatus()
358
389
  await this.updateHomeKitCharacteristics()
@@ -397,7 +428,7 @@ export class Humidifier extends deviceBase {
397
428
  this.platform.webhookEventHandler[this.device.deviceId] = async (context: humidifierWebhookContext | humidifier2WebhookContext) => {
398
429
  try {
399
430
  this.webhookContext = context
400
- if (context !== undefined || context !== null) {
431
+ if (context !== undefined && context !== null) {
401
432
  this.debugLog(`received Webhook: ${JSON.stringify(context)}`)
402
433
  await this.parseStatusWebhook()
403
434
  await this.updateHomeKitCharacteristics()
@@ -446,7 +477,17 @@ export class Humidifier extends deviceBase {
446
477
  switchBotBLE
447
478
  .discover({ model: this.device.bleModel, quick: true, id: this.device.bleMac })
448
479
  .then(async (device_list: SwitchbotDevice[]) => {
449
- return await (device_list[0] as WoHumi).percentage(Number(this.HumidifierDehumidifier.RelativeHumidityHumidifierThreshold))
480
+ this.debugLog(`device_list: ${JSON.stringify(device_list)}`)
481
+ return await this.retryBLE({
482
+ max: this.maxRetryBLE(),
483
+ fn: async () => {
484
+ if (device_list.length > 0) {
485
+ return await (device_list[0] as WoHumi).percentage(Number(this.HumidifierDehumidifier.RelativeHumidityHumidifierThreshold))
486
+ } else {
487
+ throw new Error('No devices found during discovery.')
488
+ }
489
+ },
490
+ })
450
491
  })
451
492
  .then(async () => {
452
493
  this.successLog(`RelativeHumidityHumidifierThreshold: ${this.HumidifierDehumidifier.RelativeHumidityHumidifierThreshold} sent over BLE, sent successfully`)
@@ -630,6 +671,58 @@ export class Humidifier extends deviceBase {
630
671
  if (!(this.device as humidifierConfig).hide_temperature && this.TemperatureSensor?.Service) {
631
672
  await this.updateCharacteristic(this.TemperatureSensor.Service, this.hap.Characteristic.CurrentTemperature, this.TemperatureSensor.CurrentTemperature, 'CurrentTemperature')
632
673
  }
674
+ // DryingFilter switch is momentary; ensure it reflects current cached state
675
+ if (this.DryingFilterSwitch?.Service) {
676
+ await this.updateCharacteristic(this.DryingFilterSwitch.Service, this.hap.Characteristic.On, this.DryingFilterSwitch.On, 'DryingFilter.On')
677
+ }
678
+ }
679
+
680
+ /**
681
+ * Handle requests to set the Drying Filter switch (Humidifier2 only)
682
+ */
683
+ async DryingFilterOnSet(value: CharacteristicValue): Promise<void> {
684
+ if (!this.DryingFilterSwitch?.Service) {
685
+ this.debugLog('DryingFilterOnSet called but service not initialized')
686
+ return
687
+ }
688
+ this.DryingFilterSwitch.On = value
689
+ if (value !== true) {
690
+ // Switch is momentary; ignore turning off manually
691
+ this.debugLog('Drying Filter switch set to false (ignored)')
692
+ return
693
+ }
694
+
695
+ this.infoLog('Trigger Drying Filter mode')
696
+ if (this.OpenAPI && this.platform.config.credentials?.token) {
697
+ const bodyChange: bodyChange = {
698
+ command: 'setMode',
699
+ parameter: '8',
700
+ commandType: 'command',
701
+ }
702
+ this.debugLog(`DryingFilterOnSet, SwitchBot OpenAPI bodyChange: ${JSON.stringify(bodyChange)}`)
703
+ try {
704
+ const deviceStatus = await this.pushChangeRequest(bodyChange)
705
+ this.debugLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
706
+ if (await this.successfulStatusCodes(deviceStatus)) {
707
+ this.debugSuccessLog(`statusCode: ${deviceStatus.statusCode}, deviceStatus: ${JSON.stringify(deviceStatus)}`)
708
+ } else {
709
+ await this.statusCode(deviceStatus.statusCode)
710
+ }
711
+ } catch (e: any) {
712
+ await this.apiError(e)
713
+ this.errorLog(`failed DryingFilterOnSet with ${this.device.connectionType} Connection, Error Message: ${JSON.stringify(e.message)}`)
714
+ }
715
+ } else {
716
+ this.debugWarnLog('Drying Filter requires OpenAPI; BLE not supported for this action')
717
+ }
718
+
719
+ // Auto-reset the momentary switch back to off after a short delay
720
+ setTimeout(async () => {
721
+ if (this.DryingFilterSwitch) {
722
+ this.DryingFilterSwitch.On = false
723
+ await this.updateHomeKitCharacteristics()
724
+ }
725
+ }, 1500)
633
726
  }
634
727
 
635
728
  async BLEPushConnection() {