@switchbot/homebridge-switchbot 5.0.0-beta.70 → 5.0.0-beta.72
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.
- package/.github/ISSUE_TEMPLATE/e2e-verification.md +36 -0
- package/.github/workflows/ci.yml +61 -0
- package/.github/workflows/manual-e2e.yml +103 -0
- package/CHANGELOG.md +20 -0
- package/E2E-VERIFICATION.md +121 -0
- package/MIGRATION.md +44 -0
- package/README.md +11 -0
- package/config.schema.json +99 -1940
- package/dist/deviceFactory.d.ts +13 -0
- package/dist/deviceFactory.d.ts.map +1 -0
- package/dist/deviceFactory.js +81 -0
- package/dist/deviceFactory.js.map +1 -0
- package/dist/devices/deviceBase.d.ts +50 -0
- package/dist/devices/deviceBase.d.ts.map +1 -0
- package/dist/devices/deviceBase.js +119 -0
- package/dist/devices/deviceBase.js.map +1 -0
- package/dist/devices/genericDevice.d.ts +283 -0
- package/dist/devices/genericDevice.d.ts.map +1 -0
- package/dist/devices/genericDevice.js +1035 -0
- package/dist/devices/genericDevice.js.map +1 -0
- package/dist/homebridge-ui/public/index.html +72 -440
- package/dist/homebridge-ui/server.d.ts +3 -1
- package/dist/homebridge-ui/server.d.ts.map +1 -1
- package/dist/homebridge-ui/server.js +47 -10
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/platform.d.ts +27 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +404 -0
- package/dist/platform.js.map +1 -0
- package/dist/settings.d.ts +10 -317
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +5 -30
- package/dist/settings.js.map +1 -1
- package/dist/switchbotClient.d.ts +32 -0
- package/dist/switchbotClient.d.ts.map +1 -0
- package/dist/switchbotClient.js +259 -0
- package/dist/switchbotClient.js.map +1 -0
- package/dist/utils.d.ts +36 -248
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +38 -1367
- package/dist/utils.js.map +1 -1
- package/docs/assets/icons.js +1 -1
- package/docs/assets/icons.svg +1 -1
- package/docs/assets/style.css +3 -3
- package/docs/index.html +50 -15
- package/docs/variables/default.html +1 -1
- package/package.json +19 -18
- package/scripts/e2e/README.md +25 -0
- package/scripts/e2e/curtain-e2e.sh +70 -0
- package/scripts/e2e/fan-e2e.sh +75 -0
- package/scripts/e2e/light-advanced-e2e.sh +97 -0
- package/scripts/e2e/light-e2e.sh +75 -0
- package/scripts/e2e/list-accessories.sh +19 -0
- package/scripts/e2e/lock-e2e.sh +65 -0
- package/scripts/generate-matter-maps.js +60 -0
- package/scripts/run-e2e-local.sh +14 -0
- package/src/deviceFactory.ts +122 -0
- package/src/devices/deviceBase.ts +141 -0
- package/src/devices/genericDevice.ts +965 -0
- package/src/homebridge-ui/public/index.html +72 -440
- package/src/homebridge-ui/server.ts +52 -10
- package/src/index.ts +1 -3
- package/src/platform.ts +395 -0
- package/src/settings.ts +12 -352
- package/src/switchbotClient.ts +266 -0
- package/src/utils.ts +47 -1456
- package/test/accessory-restore.spec.ts +73 -0
- package/test/device-mapping.spec.ts +37 -0
- package/test/deviceFactory.spec.ts +18 -0
- package/test/e2e/run-e2e.spec.ts +50 -0
- package/test/fan-swing.spec.ts +29 -0
- package/test/helpers/matter-harness.ts +53 -0
- package/test/lock-users.spec.ts +44 -0
- package/test/matter-childbridge.spec.ts +55 -0
- package/test/matter-descriptors.spec.ts +97 -0
- package/test/matter-device-state.spec.ts +101 -0
- package/test/matter-integration.spec.ts +70 -0
- package/test/platform.integration.spec.ts +55 -0
- package/test/switchbot-client-debounce.spec.ts +131 -0
- package/test/switchbot-client-openapi.spec.ts +56 -0
- package/test/switchbotClient.spec.ts +10 -0
- package/test/utils.spec.ts +20 -0
- package/vitest.config.ts +7 -0
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/clover.xml +0 -15847
- package/coverage/coverage-final.json +0 -42
- package/coverage/docs/assets/dmt/dmt-component-data.js.html +0 -85
- package/coverage/docs/assets/dmt/dmt-components.js.html +0 -286
- package/coverage/docs/assets/dmt/index.html +0 -131
- package/coverage/docs/assets/hierarchy.js.html +0 -85
- package/coverage/docs/assets/icons.js.html +0 -136
- package/coverage/docs/assets/index.html +0 -146
- package/coverage/docs/assets/main.js.html +0 -265
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -191
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -196
- package/coverage/src/device/blindtilt.ts.html +0 -3238
- package/coverage/src/device/bot.ts.html +0 -2803
- package/coverage/src/device/ceilinglight.ts.html +0 -2338
- package/coverage/src/device/colorbulb.ts.html +0 -2824
- package/coverage/src/device/contact.ts.html +0 -1465
- package/coverage/src/device/curtain.ts.html +0 -2869
- package/coverage/src/device/device.ts.html +0 -2500
- package/coverage/src/device/fan.ts.html +0 -2242
- package/coverage/src/device/hub.ts.html +0 -1408
- package/coverage/src/device/humidifier.ts.html +0 -2116
- package/coverage/src/device/index.html +0 -416
- package/coverage/src/device/iosensor.ts.html +0 -1375
- package/coverage/src/device/lightstrip.ts.html +0 -2617
- package/coverage/src/device/lock.ts.html +0 -1963
- package/coverage/src/device/meter.ts.html +0 -1372
- package/coverage/src/device/meterplus.ts.html +0 -1384
- package/coverage/src/device/meterpro.ts.html +0 -1618
- package/coverage/src/device/motion.ts.html +0 -1264
- package/coverage/src/device/plug.ts.html +0 -1372
- package/coverage/src/device/relayswitch.ts.html +0 -2284
- package/coverage/src/device/robotvacuumcleaner.ts.html +0 -1810
- package/coverage/src/device/waterdetector.ts.html +0 -1294
- package/coverage/src/homebridge-ui/index.html +0 -116
- package/coverage/src/homebridge-ui/server.ts.html +0 -229
- package/coverage/src/index.html +0 -161
- package/coverage/src/index.ts.html +0 -124
- package/coverage/src/irdevice/airconditioner.ts.html +0 -1687
- package/coverage/src/irdevice/airpurifier.ts.html +0 -844
- package/coverage/src/irdevice/camera.ts.html +0 -475
- package/coverage/src/irdevice/fan.ts.html +0 -766
- package/coverage/src/irdevice/index.html +0 -251
- package/coverage/src/irdevice/irdevice.ts.html +0 -1117
- package/coverage/src/irdevice/light.ts.html +0 -826
- package/coverage/src/irdevice/other.ts.html +0 -2458
- package/coverage/src/irdevice/tv.ts.html +0 -1222
- package/coverage/src/irdevice/vacuumcleaner.ts.html +0 -466
- package/coverage/src/irdevice/waterheater.ts.html +0 -469
- package/coverage/src/platform.ts.html +0 -8776
- package/coverage/src/settings.ts.html +0 -934
- package/coverage/src/utils.ts.html +0 -2092
- package/dist/devices-hap/airpurifier.d.ts +0 -54
- package/dist/devices-hap/airpurifier.d.ts.map +0 -1
- package/dist/devices-hap/airpurifier.js +0 -533
- package/dist/devices-hap/airpurifier.js.map +0 -1
- package/dist/devices-hap/blindtilt.d.ts +0 -90
- package/dist/devices-hap/blindtilt.d.ts.map +0 -1
- package/dist/devices-hap/blindtilt.js +0 -974
- package/dist/devices-hap/blindtilt.js.map +0 -1
- package/dist/devices-hap/bot.d.ts +0 -102
- package/dist/devices-hap/bot.d.ts.map +0 -1
- package/dist/devices-hap/bot.js +0 -822
- package/dist/devices-hap/bot.js.map +0 -1
- package/dist/devices-hap/ceilinglight.d.ts +0 -85
- package/dist/devices-hap/ceilinglight.d.ts.map +0 -1
- package/dist/devices-hap/ceilinglight.js +0 -707
- package/dist/devices-hap/ceilinglight.js.map +0 -1
- package/dist/devices-hap/colorbulb.d.ts +0 -88
- package/dist/devices-hap/colorbulb.d.ts.map +0 -1
- package/dist/devices-hap/colorbulb.js +0 -921
- package/dist/devices-hap/colorbulb.js.map +0 -1
- package/dist/devices-hap/contact.d.ts +0 -44
- package/dist/devices-hap/contact.d.ts.map +0 -1
- package/dist/devices-hap/contact.js +0 -409
- package/dist/devices-hap/contact.js.map +0 -1
- package/dist/devices-hap/curtain.d.ts +0 -73
- package/dist/devices-hap/curtain.d.ts.map +0 -1
- package/dist/devices-hap/curtain.js +0 -869
- package/dist/devices-hap/curtain.js.map +0 -1
- package/dist/devices-hap/device.d.ts +0 -108
- package/dist/devices-hap/device.d.ts.map +0 -1
- package/dist/devices-hap/device.js +0 -821
- package/dist/devices-hap/device.js.map +0 -1
- package/dist/devices-hap/fan.d.ts +0 -69
- package/dist/devices-hap/fan.d.ts.map +0 -1
- package/dist/devices-hap/fan.js +0 -655
- package/dist/devices-hap/fan.js.map +0 -1
- package/dist/devices-hap/hub.d.ts +0 -37
- package/dist/devices-hap/hub.d.ts.map +0 -1
- package/dist/devices-hap/hub.js +0 -393
- package/dist/devices-hap/hub.js.map +0 -1
- package/dist/devices-hap/humidifier.d.ts +0 -73
- package/dist/devices-hap/humidifier.d.ts.map +0 -1
- package/dist/devices-hap/humidifier.js +0 -716
- package/dist/devices-hap/humidifier.js.map +0 -1
- package/dist/devices-hap/iosensor.d.ts +0 -42
- package/dist/devices-hap/iosensor.d.ts.map +0 -1
- package/dist/devices-hap/iosensor.js +0 -397
- package/dist/devices-hap/iosensor.js.map +0 -1
- package/dist/devices-hap/lightstrip.d.ts +0 -79
- package/dist/devices-hap/lightstrip.d.ts.map +0 -1
- package/dist/devices-hap/lightstrip.js +0 -827
- package/dist/devices-hap/lightstrip.js.map +0 -1
- package/dist/devices-hap/lock.d.ts +0 -53
- package/dist/devices-hap/lock.d.ts.map +0 -1
- package/dist/devices-hap/lock.js +0 -569
- package/dist/devices-hap/lock.js.map +0 -1
- package/dist/devices-hap/meter.d.ts +0 -37
- package/dist/devices-hap/meter.d.ts.map +0 -1
- package/dist/devices-hap/meter.js +0 -380
- package/dist/devices-hap/meter.js.map +0 -1
- package/dist/devices-hap/meterplus.d.ts +0 -42
- package/dist/devices-hap/meterplus.d.ts.map +0 -1
- package/dist/devices-hap/meterplus.js +0 -385
- package/dist/devices-hap/meterplus.js.map +0 -1
- package/dist/devices-hap/meterpro.d.ts +0 -43
- package/dist/devices-hap/meterpro.d.ts.map +0 -1
- package/dist/devices-hap/meterpro.js +0 -469
- package/dist/devices-hap/meterpro.js.map +0 -1
- package/dist/devices-hap/motion.d.ts +0 -42
- package/dist/devices-hap/motion.d.ts.map +0 -1
- package/dist/devices-hap/motion.js +0 -345
- package/dist/devices-hap/motion.js.map +0 -1
- package/dist/devices-hap/plug.d.ts +0 -49
- package/dist/devices-hap/plug.d.ts.map +0 -1
- package/dist/devices-hap/plug.js +0 -400
- package/dist/devices-hap/plug.js.map +0 -1
- package/dist/devices-hap/relayswitch.d.ts +0 -96
- package/dist/devices-hap/relayswitch.d.ts.map +0 -1
- package/dist/devices-hap/relayswitch.js +0 -642
- package/dist/devices-hap/relayswitch.js.map +0 -1
- package/dist/devices-hap/robotvacuumcleaner.d.ts +0 -54
- package/dist/devices-hap/robotvacuumcleaner.d.ts.map +0 -1
- package/dist/devices-hap/robotvacuumcleaner.js +0 -530
- package/dist/devices-hap/robotvacuumcleaner.js.map +0 -1
- package/dist/devices-hap/waterdetector.d.ts +0 -41
- package/dist/devices-hap/waterdetector.d.ts.map +0 -1
- package/dist/devices-hap/waterdetector.js +0 -356
- package/dist/devices-hap/waterdetector.js.map +0 -1
- package/dist/devices-matter/BaseMatterAccessory.d.ts +0 -90
- package/dist/devices-matter/BaseMatterAccessory.d.ts.map +0 -1
- package/dist/devices-matter/BaseMatterAccessory.js +0 -264
- package/dist/devices-matter/BaseMatterAccessory.js.map +0 -1
- package/dist/devices-matter/ColorLightAccessory.d.ts +0 -20
- package/dist/devices-matter/ColorLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ColorLightAccessory.js +0 -95
- package/dist/devices-matter/ColorLightAccessory.js.map +0 -1
- package/dist/devices-matter/ColorTemperatureLightAccessory.d.ts +0 -18
- package/dist/devices-matter/ColorTemperatureLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ColorTemperatureLightAccessory.js +0 -76
- package/dist/devices-matter/ColorTemperatureLightAccessory.js.map +0 -1
- package/dist/devices-matter/ContactSensorAccessory.d.ts +0 -12
- package/dist/devices-matter/ContactSensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ContactSensorAccessory.js +0 -34
- package/dist/devices-matter/ContactSensorAccessory.js.map +0 -1
- package/dist/devices-matter/DimmableLightAccessory.d.ts +0 -58
- package/dist/devices-matter/DimmableLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/DimmableLightAccessory.js +0 -167
- package/dist/devices-matter/DimmableLightAccessory.js.map +0 -1
- package/dist/devices-matter/DoorLockAccessory.d.ts +0 -14
- package/dist/devices-matter/DoorLockAccessory.d.ts.map +0 -1
- package/dist/devices-matter/DoorLockAccessory.js +0 -50
- package/dist/devices-matter/DoorLockAccessory.js.map +0 -1
- package/dist/devices-matter/ExtendedColorLightAccessory.d.ts +0 -21
- package/dist/devices-matter/ExtendedColorLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ExtendedColorLightAccessory.js +0 -106
- package/dist/devices-matter/ExtendedColorLightAccessory.js.map +0 -1
- package/dist/devices-matter/FanAccessory.d.ts +0 -16
- package/dist/devices-matter/FanAccessory.d.ts.map +0 -1
- package/dist/devices-matter/FanAccessory.js +0 -81
- package/dist/devices-matter/FanAccessory.js.map +0 -1
- package/dist/devices-matter/HumiditySensorAccessory.d.ts +0 -12
- package/dist/devices-matter/HumiditySensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/HumiditySensorAccessory.js +0 -34
- package/dist/devices-matter/HumiditySensorAccessory.js.map +0 -1
- package/dist/devices-matter/LeakSensorAccessory.d.ts +0 -12
- package/dist/devices-matter/LeakSensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/LeakSensorAccessory.js +0 -33
- package/dist/devices-matter/LeakSensorAccessory.js.map +0 -1
- package/dist/devices-matter/LightSensorAccessory.d.ts +0 -12
- package/dist/devices-matter/LightSensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/LightSensorAccessory.js +0 -34
- package/dist/devices-matter/LightSensorAccessory.js.map +0 -1
- package/dist/devices-matter/OccupancySensorAccessory.d.ts +0 -12
- package/dist/devices-matter/OccupancySensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OccupancySensorAccessory.js +0 -39
- package/dist/devices-matter/OccupancySensorAccessory.js.map +0 -1
- package/dist/devices-matter/OnOffLightAccessory.d.ts +0 -38
- package/dist/devices-matter/OnOffLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OnOffLightAccessory.js +0 -110
- package/dist/devices-matter/OnOffLightAccessory.js.map +0 -1
- package/dist/devices-matter/OnOffOutletAccessory.d.ts +0 -14
- package/dist/devices-matter/OnOffOutletAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OnOffOutletAccessory.js +0 -43
- package/dist/devices-matter/OnOffOutletAccessory.js.map +0 -1
- package/dist/devices-matter/OnOffSwitchAccessory.d.ts +0 -14
- package/dist/devices-matter/OnOffSwitchAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OnOffSwitchAccessory.js +0 -42
- package/dist/devices-matter/OnOffSwitchAccessory.js.map +0 -1
- package/dist/devices-matter/RoboticVacuumAccessory.d.ts +0 -61
- package/dist/devices-matter/RoboticVacuumAccessory.d.ts.map +0 -1
- package/dist/devices-matter/RoboticVacuumAccessory.js +0 -544
- package/dist/devices-matter/RoboticVacuumAccessory.js.map +0 -1
- package/dist/devices-matter/SmokeCOAlarmAccessory.d.ts +0 -11
- package/dist/devices-matter/SmokeCOAlarmAccessory.d.ts.map +0 -1
- package/dist/devices-matter/SmokeCOAlarmAccessory.js +0 -49
- package/dist/devices-matter/SmokeCOAlarmAccessory.js.map +0 -1
- package/dist/devices-matter/TemperatureSensorAccessory.d.ts +0 -12
- package/dist/devices-matter/TemperatureSensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/TemperatureSensorAccessory.js +0 -36
- package/dist/devices-matter/TemperatureSensorAccessory.js.map +0 -1
- package/dist/devices-matter/ThermostatAccessory.d.ts +0 -19
- package/dist/devices-matter/ThermostatAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ThermostatAccessory.js +0 -95
- package/dist/devices-matter/ThermostatAccessory.js.map +0 -1
- package/dist/devices-matter/VenetianBlindAccessory.d.ts +0 -19
- package/dist/devices-matter/VenetianBlindAccessory.d.ts.map +0 -1
- package/dist/devices-matter/VenetianBlindAccessory.js +0 -99
- package/dist/devices-matter/VenetianBlindAccessory.js.map +0 -1
- package/dist/devices-matter/WindowBlindAccessory.d.ts +0 -17
- package/dist/devices-matter/WindowBlindAccessory.d.ts.map +0 -1
- package/dist/devices-matter/WindowBlindAccessory.js +0 -131
- package/dist/devices-matter/WindowBlindAccessory.js.map +0 -1
- package/dist/devices-matter/custom/PowerStripAccessory.d.ts +0 -97
- package/dist/devices-matter/custom/PowerStripAccessory.d.ts.map +0 -1
- package/dist/devices-matter/custom/PowerStripAccessory.js +0 -265
- package/dist/devices-matter/custom/PowerStripAccessory.js.map +0 -1
- package/dist/devices-matter/custom/index.d.ts +0 -8
- package/dist/devices-matter/custom/index.d.ts.map +0 -1
- package/dist/devices-matter/custom/index.js +0 -8
- package/dist/devices-matter/custom/index.js.map +0 -1
- package/dist/devices-matter/index.d.ts +0 -29
- package/dist/devices-matter/index.d.ts.map +0 -1
- package/dist/devices-matter/index.js +0 -28
- package/dist/devices-matter/index.js.map +0 -1
- package/dist/irdevice/airconditioner.d.ts +0 -61
- package/dist/irdevice/airconditioner.d.ts.map +0 -1
- package/dist/irdevice/airconditioner.js +0 -472
- package/dist/irdevice/airconditioner.js.map +0 -1
- package/dist/irdevice/airpurifier.d.ts +0 -50
- package/dist/irdevice/airpurifier.d.ts.map +0 -1
- package/dist/irdevice/airpurifier.js +0 -213
- package/dist/irdevice/airpurifier.js.map +0 -1
- package/dist/irdevice/camera.d.ts +0 -32
- package/dist/irdevice/camera.d.ts.map +0 -1
- package/dist/irdevice/camera.js +0 -107
- package/dist/irdevice/camera.js.map +0 -1
- package/dist/irdevice/fan.d.ts +0 -36
- package/dist/irdevice/fan.d.ts.map +0 -1
- package/dist/irdevice/fan.js +0 -200
- package/dist/irdevice/fan.js.map +0 -1
- package/dist/irdevice/irdevice.d.ts +0 -69
- package/dist/irdevice/irdevice.d.ts.map +0 -1
- package/dist/irdevice/irdevice.js +0 -339
- package/dist/irdevice/irdevice.js.map +0 -1
- package/dist/irdevice/light.d.ts +0 -36
- package/dist/irdevice/light.d.ts.map +0 -1
- package/dist/irdevice/light.js +0 -206
- package/dist/irdevice/light.js.map +0 -1
- package/dist/irdevice/other.d.ts +0 -57
- package/dist/irdevice/other.d.ts.map +0 -1
- package/dist/irdevice/other.js +0 -778
- package/dist/irdevice/other.js.map +0 -1
- package/dist/irdevice/tv.d.ts +0 -45
- package/dist/irdevice/tv.d.ts.map +0 -1
- package/dist/irdevice/tv.js +0 -327
- package/dist/irdevice/tv.js.map +0 -1
- package/dist/irdevice/vacuumcleaner.d.ts +0 -28
- package/dist/irdevice/vacuumcleaner.d.ts.map +0 -1
- package/dist/irdevice/vacuumcleaner.js +0 -104
- package/dist/irdevice/vacuumcleaner.js.map +0 -1
- package/dist/irdevice/waterheater.d.ts +0 -30
- package/dist/irdevice/waterheater.d.ts.map +0 -1
- package/dist/irdevice/waterheater.js +0 -105
- package/dist/irdevice/waterheater.js.map +0 -1
- package/dist/platform-hap.d.ts +0 -160
- package/dist/platform-hap.d.ts.map +0 -1
- package/dist/platform-hap.js +0 -3041
- package/dist/platform-hap.js.map +0 -1
- package/dist/platform-matter.d.ts +0 -188
- package/dist/platform-matter.d.ts.map +0 -1
- package/dist/platform-matter.js +0 -2545
- package/dist/platform-matter.js.map +0 -1
- package/dist/test/apiRequestTracker.test.d.ts +0 -2
- package/dist/test/apiRequestTracker.test.d.ts.map +0 -1
- package/dist/test/apiRequestTracker.test.js +0 -392
- package/dist/test/apiRequestTracker.test.js.map +0 -1
- package/dist/test/hap/device-webhook-context.test.d.ts +0 -2
- package/dist/test/hap/device-webhook-context.test.d.ts.map +0 -1
- package/dist/test/hap/device-webhook-context.test.js +0 -128
- package/dist/test/hap/device-webhook-context.test.js.map +0 -1
- package/dist/test/hap/platform-hap.logging.test.d.ts +0 -2
- package/dist/test/hap/platform-hap.logging.test.d.ts.map +0 -1
- package/dist/test/hap/platform-hap.logging.test.js +0 -33
- package/dist/test/hap/platform-hap.logging.test.js.map +0 -1
- package/dist/test/hap/platform-hap.test.d.ts +0 -2
- package/dist/test/hap/platform-hap.test.d.ts.map +0 -1
- package/dist/test/hap/platform-hap.test.js +0 -62
- package/dist/test/hap/platform-hap.test.js.map +0 -1
- package/dist/test/helpers/platform-fixtures.d.ts +0 -9
- package/dist/test/helpers/platform-fixtures.d.ts.map +0 -1
- package/dist/test/helpers/platform-fixtures.js +0 -30
- package/dist/test/helpers/platform-fixtures.js.map +0 -1
- package/dist/test/homebridge-ui/server.test.d.ts +0 -2
- package/dist/test/homebridge-ui/server.test.d.ts.map +0 -1
- package/dist/test/homebridge-ui/server.test.js +0 -445
- package/dist/test/homebridge-ui/server.test.js.map +0 -1
- package/dist/test/index.test.d.ts +0 -2
- package/dist/test/index.test.d.ts.map +0 -1
- package/dist/test/index.test.js +0 -19
- package/dist/test/index.test.js.map +0 -1
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.d.ts +0 -2
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.d.ts.map +0 -1
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.js +0 -71
- package/dist/test/matter/devices-matter/baseMatterAccessory.test.js.map +0 -1
- package/dist/test/matter/platform-matter.additional.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.additional.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.additional.test.js +0 -35
- package/dist/test/matter/platform-matter.additional.test.js.map +0 -1
- package/dist/test/matter/platform-matter.bleparse.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.bleparse.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.bleparse.test.js +0 -43
- package/dist/test/matter/platform-matter.bleparse.test.js.map +0 -1
- package/dist/test/matter/platform-matter.cleanup.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.cleanup.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.cleanup.test.js +0 -70
- package/dist/test/matter/platform-matter.cleanup.test.js.map +0 -1
- package/dist/test/matter/platform-matter.keepstale.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.keepstale.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.keepstale.test.js +0 -27
- package/dist/test/matter/platform-matter.keepstale.test.js.map +0 -1
- package/dist/test/matter/platform-matter.logging.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.logging.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.logging.test.js +0 -29
- package/dist/test/matter/platform-matter.logging.test.js.map +0 -1
- package/dist/test/matter/platform-matter.mapping.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.mapping.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.mapping.test.js +0 -43
- package/dist/test/matter/platform-matter.mapping.test.js.map +0 -1
- package/dist/test/matter/platform-matter.openapi-mapping.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.openapi-mapping.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.openapi-mapping.test.js +0 -84
- package/dist/test/matter/platform-matter.openapi-mapping.test.js.map +0 -1
- package/dist/test/matter/platform-matter.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.test.js +0 -117
- package/dist/test/matter/platform-matter.test.js.map +0 -1
- package/dist/test/matter/platform-matter.unregister.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.unregister.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.unregister.test.js +0 -30
- package/dist/test/matter/platform-matter.unregister.test.js.map +0 -1
- package/dist/test/matter/platform-matter.webhook.test.d.ts +0 -2
- package/dist/test/matter/platform-matter.webhook.test.d.ts.map +0 -1
- package/dist/test/matter/platform-matter.webhook.test.js +0 -46
- package/dist/test/matter/platform-matter.webhook.test.js.map +0 -1
- package/dist/test/utils.test.d.ts +0 -2
- package/dist/test/utils.test.d.ts.map +0 -1
- package/dist/test/utils.test.js +0 -95
- package/dist/test/utils.test.js.map +0 -1
- package/dist/test/verifyconfig.test.d.ts +0 -2
- package/dist/test/verifyconfig.test.d.ts.map +0 -1
- package/dist/test/verifyconfig.test.js +0 -167
- package/dist/test/verifyconfig.test.js.map +0 -1
- package/src/custom.d.ts +0 -7
- package/src/devices-hap/airpurifier.ts +0 -568
- package/src/devices-hap/blindtilt.ts +0 -1049
- package/src/devices-hap/bot.ts +0 -910
- package/src/devices-hap/ceilinglight.ts +0 -747
- package/src/devices-hap/colorbulb.ts +0 -940
- package/src/devices-hap/contact.ts +0 -457
- package/src/devices-hap/curtain.ts +0 -944
- package/src/devices-hap/device.ts +0 -890
- package/src/devices-hap/fan.ts +0 -716
- package/src/devices-hap/hub.ts +0 -440
- package/src/devices-hap/humidifier.ts +0 -762
- package/src/devices-hap/iosensor.ts +0 -442
- package/src/devices-hap/lightstrip.ts +0 -863
- package/src/devices-hap/lock.ts +0 -627
- package/src/devices-hap/meter.ts +0 -427
- package/src/devices-hap/meterplus.ts +0 -431
- package/src/devices-hap/meterpro.ts +0 -523
- package/src/devices-hap/motion.ts +0 -390
- package/src/devices-hap/plug.ts +0 -427
- package/src/devices-hap/relayswitch.ts +0 -727
- package/src/devices-hap/robotvacuumcleaner.ts +0 -574
- package/src/devices-hap/waterdetector.ts +0 -400
- package/src/devices-matter/BaseMatterAccessory.ts +0 -302
- package/src/devices-matter/ColorLightAccessory.ts +0 -110
- package/src/devices-matter/ColorTemperatureLightAccessory.ts +0 -90
- package/src/devices-matter/ContactSensorAccessory.ts +0 -41
- package/src/devices-matter/DimmableLightAccessory.ts +0 -192
- package/src/devices-matter/DoorLockAccessory.ts +0 -60
- package/src/devices-matter/ExtendedColorLightAccessory.ts +0 -122
- package/src/devices-matter/FanAccessory.ts +0 -95
- package/src/devices-matter/HumiditySensorAccessory.ts +0 -41
- package/src/devices-matter/LeakSensorAccessory.ts +0 -40
- package/src/devices-matter/LightSensorAccessory.ts +0 -41
- package/src/devices-matter/OccupancySensorAccessory.ts +0 -48
- package/src/devices-matter/OnOffLightAccessory.ts +0 -125
- package/src/devices-matter/OnOffOutletAccessory.ts +0 -51
- package/src/devices-matter/OnOffSwitchAccessory.ts +0 -51
- package/src/devices-matter/RoboticVacuumAccessory.ts +0 -621
- package/src/devices-matter/SmokeCOAlarmAccessory.ts +0 -59
- package/src/devices-matter/TemperatureSensorAccessory.ts +0 -43
- package/src/devices-matter/ThermostatAccessory.ts +0 -110
- package/src/devices-matter/VenetianBlindAccessory.ts +0 -115
- package/src/devices-matter/WindowBlindAccessory.ts +0 -135
- package/src/devices-matter/custom/PowerStripAccessory.ts +0 -309
- package/src/devices-matter/custom/index.ts +0 -8
- package/src/devices-matter/index.ts +0 -29
- package/src/irdevice/airconditioner.ts +0 -533
- package/src/irdevice/airpurifier.ts +0 -252
- package/src/irdevice/camera.ts +0 -129
- package/src/irdevice/fan.ts +0 -226
- package/src/irdevice/irdevice.ts +0 -383
- package/src/irdevice/light.ts +0 -246
- package/src/irdevice/other.ts +0 -790
- package/src/irdevice/tv.ts +0 -378
- package/src/irdevice/vacuumcleaner.ts +0 -126
- package/src/irdevice/waterheater.ts +0 -127
- package/src/platform-hap.ts +0 -3193
- package/src/platform-matter.ts +0 -2703
- package/src/test/apiRequestTracker.test.ts +0 -417
- package/src/test/hap/device-webhook-context.test.ts +0 -136
- package/src/test/hap/platform-hap.logging.test.ts +0 -36
- package/src/test/hap/platform-hap.test.ts +0 -70
- package/src/test/helpers/platform-fixtures.ts +0 -33
- package/src/test/homebridge-ui/server.test.ts +0 -486
- package/src/test/index.test.ts +0 -24
- package/src/test/matter/devices-matter/baseMatterAccessory.test.ts +0 -88
- package/src/test/matter/platform-matter.additional.test.ts +0 -44
- package/src/test/matter/platform-matter.bleparse.test.ts +0 -47
- package/src/test/matter/platform-matter.cleanup.test.ts +0 -86
- package/src/test/matter/platform-matter.keepstale.test.ts +0 -37
- package/src/test/matter/platform-matter.logging.test.ts +0 -33
- package/src/test/matter/platform-matter.mapping.test.ts +0 -57
- package/src/test/matter/platform-matter.openapi-mapping.test.ts +0 -109
- package/src/test/matter/platform-matter.test.ts +0 -144
- package/src/test/matter/platform-matter.unregister.test.ts +0 -39
- package/src/test/matter/platform-matter.webhook.test.ts +0 -54
- package/src/test/utils.test.ts +0 -96
- package/src/test/verifyconfig.test.ts +0 -198
package/src/settings.ts
CHANGED
|
@@ -1,358 +1,18 @@
|
|
|
1
|
-
/* Copyright(C) 2017-2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
|
|
2
|
-
*
|
|
3
|
-
* settings.ts: @switchbot/homebridge-switchbot platform class.
|
|
4
|
-
*/
|
|
5
|
-
import type { IClientOptions } from 'async-mqtt'
|
|
6
|
-
import type { PlatformConfig } from 'homebridge'
|
|
7
|
-
/*
|
|
8
|
-
* For Testing Locally:
|
|
9
|
-
* import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName } from '/Users/Shared/GitHub/OpenWonderLabs/node-switchbot/dist/index.js';
|
|
10
|
-
*/
|
|
11
|
-
import type { device, irdevice, SwitchBotBLEModel, SwitchBotBLEModelFriendlyName, SwitchBotBLEModelName, SwitchBotModel } from 'node-switchbot'
|
|
12
|
-
/**
|
|
13
|
-
* This is the name of the platform that users will use to register the plugin in the Homebridge config.json
|
|
14
|
-
*/
|
|
15
|
-
export const PLATFORM_NAME = 'SwitchBot'
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* This must match the name of your plugin as defined the package.json
|
|
19
|
-
*/
|
|
20
1
|
export const PLUGIN_NAME = '@switchbot/homebridge-switchbot'
|
|
2
|
+
export const PLATFORM_NAME = 'SwitchBot'
|
|
21
3
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
secret?: string
|
|
30
|
-
notice?: string
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface options {
|
|
34
|
-
devices?: devicesConfig[]
|
|
35
|
-
irdevices?: irDevicesConfig[]
|
|
36
|
-
allowInvalidCharacters?: boolean
|
|
37
|
-
// When true, devices declared in config.options.devices that are not
|
|
38
|
-
// discovered via the SwitchBot OpenAPI will still be included (config-only
|
|
39
|
-
// devices). Default: false.
|
|
40
|
-
allowConfigOnlyDevices?: boolean
|
|
41
|
-
/**
|
|
42
|
-
* When true, previously-registered accessories for devices that are no
|
|
43
|
-
* longer discovered or configured will be kept on the bridge. Default: false.
|
|
44
|
-
* When false (default), stale accessories are removed automatically.
|
|
45
|
-
*/
|
|
46
|
-
keepStaleAccessories?: boolean
|
|
47
|
-
mqttURL?: string
|
|
48
|
-
mqttOptions?: IClientOptions
|
|
49
|
-
mqttPubOptions?: IClientOptions
|
|
50
|
-
BLE?: boolean
|
|
51
|
-
discoverBLE?: boolean
|
|
52
|
-
disableLogsforBLE?: boolean
|
|
53
|
-
disableLogsforOpenAPI?: boolean
|
|
54
|
-
hostname?: string
|
|
55
|
-
webhookURL?: string
|
|
56
|
-
/**
|
|
57
|
-
* When true, enables webhook support for all devices by default.
|
|
58
|
-
* Individual devices can override this with their own webhook setting.
|
|
59
|
-
* Requires webhookURL to be configured.
|
|
60
|
-
*/
|
|
61
|
-
webhook?: boolean
|
|
62
|
-
maxRetries?: number
|
|
63
|
-
delayBetweenRetries?: number
|
|
64
|
-
refreshRate?: number
|
|
65
|
-
updateRate?: number
|
|
66
|
-
pushRate?: number
|
|
67
|
-
logging?: string
|
|
68
|
-
/**
|
|
69
|
-
* Maximum number of SwitchBot OpenAPI requests allowed per day.
|
|
70
|
-
* Defaults to 10,000 if not specified.
|
|
71
|
-
*/
|
|
72
|
-
dailyApiLimit?: number
|
|
73
|
-
/**
|
|
74
|
-
* Number of daily API requests reserved for user-initiated commands.
|
|
75
|
-
* When remaining budget falls below this reserve, background polling and discovery
|
|
76
|
-
* are paused until the daily counter resets. Defaults to 1,000.
|
|
77
|
-
*/
|
|
78
|
-
dailyApiReserveForCommands?: number
|
|
79
|
-
/**
|
|
80
|
-
* When true, the plugin will completely stop background polling/discovery
|
|
81
|
-
* once the remaining daily budget reaches the reserve (webhook-only mode).
|
|
82
|
-
* When false, polling continues until the hard daily limit is reached.
|
|
83
|
-
* Default: false.
|
|
84
|
-
*/
|
|
85
|
-
webhookOnlyOnReserve?: boolean
|
|
86
|
-
/**
|
|
87
|
-
* When true, reset the daily API request counter at LOCAL midnight (system timezone).
|
|
88
|
-
* When false (default), reset at UTC midnight. Default: false.
|
|
89
|
-
*/
|
|
90
|
-
dailyApiResetAtLocalMidnight?: boolean
|
|
91
|
-
/**
|
|
92
|
-
* When true, resets the daily API request counter to zero. This is useful for testing purposes.
|
|
93
|
-
*/
|
|
94
|
-
resetDailyApiCounter?: boolean
|
|
95
|
-
/**
|
|
96
|
-
* When set, configures the batch refresh rate (in milliseconds) for Matter devices. Default: 5000 ms.
|
|
97
|
-
*/
|
|
98
|
-
matterBatchRefreshRate?: number
|
|
99
|
-
/**
|
|
100
|
-
* When true, enables batch processing for Matter devices. Default: false.
|
|
101
|
-
*/
|
|
102
|
-
matterBatchConcurrency?: number
|
|
103
|
-
/**
|
|
104
|
-
* When true, enables batch processing for Matter devices. Default: false.
|
|
105
|
-
*/
|
|
106
|
-
matterBatchEnabled?: boolean
|
|
107
|
-
/**
|
|
108
|
-
* When set, adds a random delay (jitter) to batch requests to avoid thundering herd problems.
|
|
109
|
-
*/
|
|
110
|
-
matterBatchJitter?: number
|
|
111
|
-
newFeatureEnabled?: boolean
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export type devicesConfig = botConfig | relaySwitch1Config | relaySwitch1PMConfig | meterConfig | meterProConfig | indoorOutdoorSensorConfig | humidifierConfig | curtainConfig | blindTiltConfig | contactConfig | motionConfig | waterDetectorConfig | plugConfig | colorBulbConfig | stripLightConfig | ceilingLightConfig | lockConfig | hubConfig
|
|
115
|
-
|
|
116
|
-
export interface BaseDeviceConfig extends device {
|
|
117
|
-
bleMac?: string
|
|
118
|
-
model: SwitchBotModel
|
|
119
|
-
bleModel: SwitchBotBLEModel
|
|
120
|
-
bleModelName: SwitchBotBLEModelName
|
|
121
|
-
bleModelFriednlyName: SwitchBotBLEModelFriendlyName
|
|
122
|
-
configDeviceType: string
|
|
123
|
-
configDeviceName?: string
|
|
124
|
-
deviceId: string
|
|
125
|
-
external?: boolean
|
|
126
|
-
refreshRate?: number
|
|
127
|
-
updateRate?: number
|
|
128
|
-
pushRate?: number
|
|
129
|
-
firmware?: string
|
|
130
|
-
logging?: string
|
|
131
|
-
connectionType?: string
|
|
132
|
-
customBLEaddress?: string
|
|
133
|
-
scanDuration?: number
|
|
134
|
-
hide_device?: boolean
|
|
135
|
-
offline?: boolean
|
|
136
|
-
maxRetry?: number
|
|
137
|
-
maxRetries?: number
|
|
138
|
-
delayBetweenRetries?: number
|
|
139
|
-
disableCaching?: boolean
|
|
140
|
-
disablePlatformBLE?: boolean
|
|
141
|
-
mqttURL?: string
|
|
142
|
-
mqttOptions?: IClientOptions
|
|
143
|
-
mqttPubOptions?: IClientOptions
|
|
144
|
-
history?: boolean
|
|
145
|
-
webhook?: boolean
|
|
146
|
-
/**
|
|
147
|
-
* When true, applies this device's configuration to all other devices
|
|
148
|
-
* of the same deviceType/configDeviceType (e.g., all Humidifiers).
|
|
149
|
-
* Specific per-device settings will override these template settings.
|
|
150
|
-
*/
|
|
151
|
-
applyToAllDevicesOfType?: boolean
|
|
4
|
+
export interface SwitchBotPluginConfig {
|
|
5
|
+
openApiToken?: string
|
|
6
|
+
openApiSecret?: string
|
|
7
|
+
preferMatter?: boolean
|
|
8
|
+
enableMatter?: boolean
|
|
9
|
+
// other plugin-specific configuration
|
|
10
|
+
[key: string]: any
|
|
152
11
|
}
|
|
153
12
|
|
|
154
|
-
export
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
type: string
|
|
158
|
-
doublePress?: number
|
|
159
|
-
pushRatePress?: number
|
|
160
|
-
allowPush?: boolean
|
|
161
|
-
multiPress?: boolean
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
export interface relaySwitch1Config extends BaseDeviceConfig {
|
|
165
|
-
configDeviceType: 'Relay Switch 1'
|
|
166
|
-
type: string
|
|
167
|
-
allowPush?: boolean
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
export interface relaySwitch1PMConfig extends BaseDeviceConfig {
|
|
171
|
-
configDeviceType: 'Relay Switch 1PM'
|
|
172
|
-
type: string
|
|
173
|
-
allowPush?: boolean
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
export interface meterConfig extends BaseDeviceConfig {
|
|
177
|
-
configDeviceType: 'Meter' | 'MeterPlus'
|
|
178
|
-
hide_temperature?: boolean
|
|
179
|
-
convertUnitTo?: string
|
|
180
|
-
hide_humidity?: boolean
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
export interface meterProConfig extends BaseDeviceConfig {
|
|
184
|
-
configDeviceType: 'Meter Pro' | 'MeterPro(CO2)'
|
|
185
|
-
hide_temperature?: boolean
|
|
186
|
-
convertUnitTo?: string
|
|
187
|
-
hide_humidity?: boolean
|
|
188
|
-
hide_co2?: boolean
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
export interface indoorOutdoorSensorConfig extends BaseDeviceConfig {
|
|
192
|
-
configDeviceType: 'WoIOSensor'
|
|
193
|
-
hide_temperature?: boolean
|
|
194
|
-
convertUnitTo?: string
|
|
195
|
-
hide_humidity?: boolean
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
export interface humidifierConfig extends BaseDeviceConfig {
|
|
199
|
-
configDeviceType: 'Humidifier' | 'Humidifier2'
|
|
200
|
-
hide_temperature?: boolean
|
|
201
|
-
convertUnitTo?: string
|
|
202
|
-
set_minStep?: number
|
|
203
|
-
/**
|
|
204
|
-
* When true (Humidifier2 only), exposes a Switch service in HomeKit
|
|
205
|
-
* to trigger the built-in Drying Filter mode via OpenAPI (setMode 8).
|
|
206
|
-
*/
|
|
207
|
-
activate_dryingfilter?: boolean
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
export interface curtainConfig extends BaseDeviceConfig {
|
|
211
|
-
configDeviceType: 'Curtain' | 'Curtain3' | 'WoRollerShade' | 'Roller Shade'
|
|
212
|
-
disable_group?: boolean
|
|
213
|
-
hide_lightsensor?: boolean
|
|
214
|
-
set_minLux?: number
|
|
215
|
-
set_maxLux?: number
|
|
216
|
-
set_max?: number
|
|
217
|
-
set_min?: number
|
|
218
|
-
set_minStep?: number
|
|
219
|
-
setCloseMode?: string
|
|
220
|
-
setOpenMode?: string
|
|
221
|
-
silentModeSwitch?: boolean
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
export interface blindTiltConfig extends BaseDeviceConfig {
|
|
225
|
-
configDeviceType: 'Blind Tilt'
|
|
226
|
-
disable_group?: boolean
|
|
227
|
-
mapping?: string
|
|
228
|
-
hide_lightsensor?: boolean
|
|
229
|
-
set_minLux?: number
|
|
230
|
-
set_maxLux?: number
|
|
231
|
-
set_max?: number
|
|
232
|
-
set_min?: number
|
|
233
|
-
set_minStep?: number
|
|
234
|
-
setCloseMode?: string
|
|
235
|
-
setOpenMode?: string
|
|
236
|
-
silentModeSwitch?: boolean
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
export interface contactConfig extends BaseDeviceConfig {
|
|
240
|
-
configDeviceType: 'Contact Sensor'
|
|
241
|
-
hide_lightsensor?: boolean
|
|
242
|
-
set_minLux?: number
|
|
243
|
-
set_maxLux?: number
|
|
244
|
-
hide_motionsensor?: boolean
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
export interface motionConfig extends BaseDeviceConfig {
|
|
248
|
-
configDeviceType: 'Motion Sensor'
|
|
249
|
-
hide_lightsensor?: boolean
|
|
250
|
-
set_minLux?: number
|
|
251
|
-
set_maxLux?: number
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
export interface waterDetectorConfig extends BaseDeviceConfig {
|
|
255
|
-
configDeviceType: 'Water Detector'
|
|
256
|
-
hide_leak?: boolean
|
|
257
|
-
dry?: boolean
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
export interface plugConfig extends BaseDeviceConfig {
|
|
261
|
-
configDeviceType: 'Plug' | 'Plug Mini (US)' | 'Plug Mini (JP)'
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
export interface colorBulbConfig extends BaseDeviceConfig {
|
|
265
|
-
configDeviceType: 'Color Bulb'
|
|
266
|
-
set_minStep?: number
|
|
267
|
-
adaptiveLightingShift?: number
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
export interface stripLightConfig extends BaseDeviceConfig {
|
|
271
|
-
configDeviceType: 'Strip Light'
|
|
272
|
-
set_minStep?: number
|
|
273
|
-
adaptiveLightingShift?: number
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
export interface ceilingLightConfig extends BaseDeviceConfig {
|
|
277
|
-
configDeviceType: 'Ceiling Light' | 'Ceiling Light Pro'
|
|
278
|
-
set_minStep?: number
|
|
279
|
-
adaptiveLightingShift?: number
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
export interface lockConfig extends BaseDeviceConfig {
|
|
283
|
-
configDeviceType: 'Smart Lock' | 'Smart Lock Pro' | 'Smart Lock Ultra'
|
|
284
|
-
hide_contactsensor?: boolean
|
|
285
|
-
activate_latchbutton?: boolean
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
export interface hubConfig extends BaseDeviceConfig {
|
|
289
|
-
configDeviceType: 'Hub 2'
|
|
290
|
-
hide_temperature?: boolean
|
|
291
|
-
convertUnitTo?: string
|
|
292
|
-
hide_humidity?: boolean
|
|
293
|
-
hide_lightsensor?: boolean
|
|
294
|
-
set_minLux?: number
|
|
295
|
-
set_maxLux?: number
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
export type irDevicesConfig = irFanConfig | irLightConfig | irAirConfig | irOtherConfig
|
|
299
|
-
|
|
300
|
-
export interface irBaseDeviceConfig extends irdevice {
|
|
301
|
-
configDeviceName?: string
|
|
302
|
-
configRemoteType?: string
|
|
303
|
-
connectionType?: string
|
|
304
|
-
hide_device?: boolean
|
|
305
|
-
external?: boolean
|
|
306
|
-
refreshRate?: number
|
|
307
|
-
updateRate?: number
|
|
308
|
-
pushRate?: number
|
|
309
|
-
maxRetries?: number
|
|
310
|
-
delayBetweenRetries?: number
|
|
311
|
-
firmware?: string
|
|
312
|
-
deviceId: string
|
|
313
|
-
logging?: string
|
|
314
|
-
customOn?: string
|
|
315
|
-
customOff?: string
|
|
316
|
-
/**
|
|
317
|
-
* When true, applies this IR device's configuration to all other IR devices
|
|
318
|
-
* of the same remoteType/configRemoteType (e.g., all IR Fans).
|
|
319
|
-
* Specific per-device settings will override these template settings.
|
|
320
|
-
*/
|
|
321
|
-
applyToAllDevicesOfType?: boolean
|
|
322
|
-
customize?: boolean
|
|
323
|
-
commandType?: string
|
|
324
|
-
disablePushOn?: boolean
|
|
325
|
-
disablePushOff?: boolean
|
|
326
|
-
disablePushDetail?: boolean
|
|
13
|
+
export const DEFAULT_CONFIG: Partial<SwitchBotPluginConfig> = {
|
|
14
|
+
preferMatter: true,
|
|
15
|
+
enableMatter: true,
|
|
327
16
|
}
|
|
328
17
|
|
|
329
|
-
export
|
|
330
|
-
configRemoteType?: 'Fan' | 'DIY Fan'
|
|
331
|
-
swing_mode?: boolean
|
|
332
|
-
rotation_speed?: boolean
|
|
333
|
-
set_minStep?: number
|
|
334
|
-
set_max?: number
|
|
335
|
-
set_min?: number
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
export interface irLightConfig extends irBaseDeviceConfig {
|
|
339
|
-
configRemoteType?: 'Light' | 'DIY Light'
|
|
340
|
-
stateless?: boolean
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
export interface irAirConfig extends irBaseDeviceConfig {
|
|
344
|
-
configRemoteType?: 'Air Conditioner' | 'DIY Air Conditioner'
|
|
345
|
-
hide_automode?: boolean
|
|
346
|
-
set_max_heat?: number
|
|
347
|
-
set_min_heat?: number
|
|
348
|
-
set_max_cool?: number
|
|
349
|
-
set_min_cool?: number
|
|
350
|
-
meterType?: string
|
|
351
|
-
meterId?: string
|
|
352
|
-
meterUuid?: string
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
export interface irOtherConfig extends irBaseDeviceConfig {
|
|
356
|
-
configRemoteType?: 'Others'
|
|
357
|
-
type?: string
|
|
358
|
-
};
|
|
18
|
+
export type DeviceType = string
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import type { SwitchBotPluginConfig } from './settings.js'
|
|
2
|
+
|
|
3
|
+
export interface ISwitchBotClient {
|
|
4
|
+
init(): Promise<void>
|
|
5
|
+
getDevice(id: string): Promise<any>
|
|
6
|
+
destroy(): Promise<void>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Adapter that tries to use the node-switchbot v4 hybrid API when available.
|
|
10
|
+
export class SwitchBotClient implements ISwitchBotClient {
|
|
11
|
+
private cfg: SwitchBotPluginConfig
|
|
12
|
+
private client: any | null = null
|
|
13
|
+
private baseUrl = 'https://api.switch-bot.com/v1.0'
|
|
14
|
+
// configurable network options
|
|
15
|
+
private requestTimeout = 5000
|
|
16
|
+
private maxRetries = 2
|
|
17
|
+
private baseBackoffMs = 100
|
|
18
|
+
private maxBackoffMs = 2000
|
|
19
|
+
private backoffFactor = 2
|
|
20
|
+
private jitter = true
|
|
21
|
+
// per-device write debounce (ms). 0 = disabled. Configurable via plugin options.
|
|
22
|
+
// Default enabled to coalesce rapid writes and prevent command floods.
|
|
23
|
+
private writeDebounceMs = 100
|
|
24
|
+
// structured logger (expects info/warn/error/debug); defaults to console
|
|
25
|
+
private logger: any
|
|
26
|
+
// per-device retry tracking
|
|
27
|
+
private perDeviceRetries: Map<string, number> = new Map()
|
|
28
|
+
private perDeviceMaxRetries = 3
|
|
29
|
+
// per-device cooldown after exceeding retries (ms)
|
|
30
|
+
private perDeviceCooldownMs = 60_000
|
|
31
|
+
private perDeviceCooldownUntil: Map<string, number> = new Map()
|
|
32
|
+
|
|
33
|
+
constructor(cfg: SwitchBotPluginConfig) {
|
|
34
|
+
this.cfg = cfg
|
|
35
|
+
this.logger = (cfg as any)?.logger ?? console
|
|
36
|
+
if (typeof (cfg as any)?.requestTimeout === 'number') this.requestTimeout = (cfg as any).requestTimeout
|
|
37
|
+
if (typeof (cfg as any)?.maxRetries === 'number') this.maxRetries = (cfg as any).maxRetries
|
|
38
|
+
if (typeof (cfg as any)?.perDeviceMaxRetries === 'number') this.perDeviceMaxRetries = (cfg as any).perDeviceMaxRetries
|
|
39
|
+
if (typeof (cfg as any)?.baseBackoffMs === 'number') this.baseBackoffMs = (cfg as any).baseBackoffMs
|
|
40
|
+
if (typeof (cfg as any)?.maxBackoffMs === 'number') this.maxBackoffMs = (cfg as any).maxBackoffMs
|
|
41
|
+
if (typeof (cfg as any)?.backoffFactor === 'number') this.backoffFactor = (cfg as any).backoffFactor
|
|
42
|
+
if (typeof (cfg as any)?.jitter === 'boolean') this.jitter = (cfg as any).jitter
|
|
43
|
+
if (typeof (cfg as any)?.perDeviceCooldownMs === 'number') this.perDeviceCooldownMs = (cfg as any).perDeviceCooldownMs
|
|
44
|
+
if (typeof (cfg as any)?.writeDebounceMs === 'number') this.writeDebounceMs = (cfg as any).writeDebounceMs
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// pending writes coalescing: deviceId -> { timer, body, resolvers }
|
|
48
|
+
private pendingWrites: Map<string, { timer: any; body: any; resolvers: Array<{ resolve: (v:any)=>void; reject: (e:any)=>void }>; }> = new Map()
|
|
49
|
+
|
|
50
|
+
async init(): Promise<void> {
|
|
51
|
+
// Try to dynamically import the new node-switchbot package. If it exposes
|
|
52
|
+
// a hybrid client we will use it. Otherwise the consumer can implement
|
|
53
|
+
// OpenAPI fallback logic here.
|
|
54
|
+
try {
|
|
55
|
+
const mod = await import('node-switchbot')
|
|
56
|
+
// The new library may export a default or named client. Try common names.
|
|
57
|
+
const m: any = mod as any
|
|
58
|
+
this.client = m?.default ?? m?.SwitchBot ?? m
|
|
59
|
+
if (typeof this.client === 'function') {
|
|
60
|
+
// some builds export a constructor
|
|
61
|
+
this.client = new this.client({ token: this.cfg.openApiToken })
|
|
62
|
+
}
|
|
63
|
+
} catch (e) {
|
|
64
|
+
// If import fails, leave client null and rely on OpenAPI code paths later.
|
|
65
|
+
this.logger?.warn?.('node-switchbot import failed; falling back to OpenAPI when token available')
|
|
66
|
+
this.client = null
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private async fetchWithTimeoutAndRetry(url: string, opts: any = {}, timeoutMs?: number, retries?: number, deviceId?: string) {
|
|
71
|
+
const to = typeof timeoutMs === 'number' ? timeoutMs : this.requestTimeout
|
|
72
|
+
const max = typeof retries === 'number' ? retries : this.maxRetries
|
|
73
|
+
|
|
74
|
+
// Check per-device cooldown
|
|
75
|
+
if (deviceId) {
|
|
76
|
+
const until = this.perDeviceCooldownUntil.get(deviceId) ?? 0
|
|
77
|
+
if (Date.now() < until) {
|
|
78
|
+
const ms = until - Date.now()
|
|
79
|
+
this.logger?.warn?.('device in cooldown, aborting fetch', { deviceId, cooldownMs: ms })
|
|
80
|
+
throw new Error(`device ${deviceId} in cooldown for ${ms}ms`)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let attempt = 0
|
|
85
|
+
while (true) {
|
|
86
|
+
attempt += 1
|
|
87
|
+
// AbortController-based timeout
|
|
88
|
+
const controller = new AbortController()
|
|
89
|
+
const timer = setTimeout(() => controller.abort(), to)
|
|
90
|
+
try {
|
|
91
|
+
this.logger?.debug?.('fetch', { url, attempt, deviceId })
|
|
92
|
+
const fetchOpts = Object.assign({}, opts)
|
|
93
|
+
try {
|
|
94
|
+
Object.defineProperty(fetchOpts, 'signal', { value: controller.signal, enumerable: false, configurable: true })
|
|
95
|
+
} catch (_e) {
|
|
96
|
+
// ignore environments where defineProperty may fail
|
|
97
|
+
}
|
|
98
|
+
const resp = await fetch(url, fetchOpts)
|
|
99
|
+
clearTimeout(timer)
|
|
100
|
+
|
|
101
|
+
// helper to safely read response body when available
|
|
102
|
+
const safeReadBody = async (r: any) => {
|
|
103
|
+
try {
|
|
104
|
+
if (!r) return ''
|
|
105
|
+
if (typeof r.text === 'function') return await r.text()
|
|
106
|
+
if (typeof r.json === 'function') {
|
|
107
|
+
const j = await r.json().catch(() => null)
|
|
108
|
+
return j ? JSON.stringify(j) : ''
|
|
109
|
+
}
|
|
110
|
+
return String(r)
|
|
111
|
+
} catch (_e) {
|
|
112
|
+
return ''
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Some tests/mocks provide response-like objects without numeric `status`.
|
|
117
|
+
// In those cases attempt to parse the body and return a Response-like
|
|
118
|
+
// object so callers (resp.json()) continue to work instead of forcing
|
|
119
|
+
// a retry path.
|
|
120
|
+
if (typeof (resp as any).status !== 'number') {
|
|
121
|
+
const bodyStr = await safeReadBody(resp)
|
|
122
|
+
try {
|
|
123
|
+
const parsed = bodyStr ? JSON.parse(bodyStr) : {}
|
|
124
|
+
if (deviceId) this.perDeviceRetries.set(deviceId, 0)
|
|
125
|
+
return { ok: true, status: 200, json: async () => parsed }
|
|
126
|
+
} catch (_e) {
|
|
127
|
+
if (deviceId) this.perDeviceRetries.set(deviceId, 0)
|
|
128
|
+
return { ok: true, status: 200, json: async () => ({ body: bodyStr }) }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// classify response
|
|
133
|
+
if (resp.ok) {
|
|
134
|
+
if (deviceId) this.perDeviceRetries.set(deviceId, 0)
|
|
135
|
+
return resp
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Do not retry on client errors (4xx), except 429 (rate limit)
|
|
139
|
+
if (resp.status >= 400 && resp.status < 500 && resp.status !== 429) {
|
|
140
|
+
const body = await safeReadBody(resp)
|
|
141
|
+
this.logger?.error?.('fetch non-retriable response', { url, status: resp.status, body })
|
|
142
|
+
const err = new Error(`HTTP ${resp.status}`)
|
|
143
|
+
;(err as any).status = resp.status
|
|
144
|
+
throw err
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// server error / rate limit: treat as retriable
|
|
148
|
+
const body = await safeReadBody(resp)
|
|
149
|
+
this.logger?.warn?.('fetch retriable response', { url, status: resp.status, body })
|
|
150
|
+
// throw to enter retry/catch logic below and apply backoff
|
|
151
|
+
throw new Error(`retriable response: ${resp.status || 'unknown'}`)
|
|
152
|
+
} catch (err: any) {
|
|
153
|
+
clearTimeout(timer)
|
|
154
|
+
const isAbort = err?.name === 'AbortError' || err?.message === 'The user aborted a request.' || err?.message === 'timeout'
|
|
155
|
+
const reason = isAbort ? 'timeout' : err?.message ?? String(err)
|
|
156
|
+
this.logger?.warn?.('fetch failed', { url, attempt, deviceId, reason })
|
|
157
|
+
|
|
158
|
+
// per-device retry guard
|
|
159
|
+
if (deviceId) {
|
|
160
|
+
const prev = this.perDeviceRetries.get(deviceId) ?? 0
|
|
161
|
+
const next = prev + 1
|
|
162
|
+
this.perDeviceRetries.set(deviceId, next)
|
|
163
|
+
if (next > this.perDeviceMaxRetries) {
|
|
164
|
+
this.logger?.error?.('per-device retry limit exceeded, entering cooldown', { deviceId, attempts: next })
|
|
165
|
+
this.perDeviceCooldownUntil.set(deviceId, Date.now() + this.perDeviceCooldownMs)
|
|
166
|
+
throw new Error(`per-device retry limit exceeded for ${deviceId}`)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (attempt > max) throw err
|
|
171
|
+
|
|
172
|
+
// exponential backoff with optional jitter
|
|
173
|
+
let backoff = Math.min(this.baseBackoffMs * Math.pow(this.backoffFactor, attempt - 1), this.maxBackoffMs)
|
|
174
|
+
if (this.jitter) {
|
|
175
|
+
const jitterVal = Math.floor(Math.random() * backoff)
|
|
176
|
+
backoff = Math.floor(backoff / 2) + jitterVal
|
|
177
|
+
}
|
|
178
|
+
this.logger?.debug?.('backoff before retry', { url, attempt, backoff })
|
|
179
|
+
await new Promise((r) => setTimeout(r, backoff))
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async getDevice(id: string): Promise<any> {
|
|
185
|
+
if (this.client && typeof this.client.getDevice === 'function') {
|
|
186
|
+
return this.client.getDevice(id)
|
|
187
|
+
}
|
|
188
|
+
// Fallback: call OpenAPI via HTTP using token if available.
|
|
189
|
+
if (this.cfg.openApiToken) {
|
|
190
|
+
const url = `${this.baseUrl}/devices/${id}`
|
|
191
|
+
const opts = { headers: { Authorization: this.cfg.openApiToken } }
|
|
192
|
+
const resp = await this.fetchWithTimeoutAndRetry(url, opts, undefined, undefined, id)
|
|
193
|
+
return resp.json()
|
|
194
|
+
}
|
|
195
|
+
throw new Error('No SwitchBot client available')
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async setDeviceState(id: string, body: any): Promise<any> {
|
|
199
|
+
// If debounce is disabled do a direct write path
|
|
200
|
+
if (!this.writeDebounceMs || this.writeDebounceMs <= 0) {
|
|
201
|
+
return this._doSetDeviceState(id, body)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Coalesce writes per-device within debounce window. Last write wins.
|
|
205
|
+
return new Promise((resolve, reject) => {
|
|
206
|
+
const existing = this.pendingWrites.get(id)
|
|
207
|
+
if (existing) {
|
|
208
|
+
existing.body = body
|
|
209
|
+
existing.resolvers.push({ resolve, reject })
|
|
210
|
+
// timer already scheduled
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const resolvers: Array<{ resolve: (v:any)=>void; reject: (e:any)=>void }> = [{ resolve, reject }]
|
|
215
|
+
const timer = setTimeout(async () => {
|
|
216
|
+
const entry = this.pendingWrites.get(id)
|
|
217
|
+
if (!entry) return
|
|
218
|
+
this.pendingWrites.delete(id)
|
|
219
|
+
try {
|
|
220
|
+
const out = await this._doSetDeviceState(id, entry.body)
|
|
221
|
+
for (const r of entry.resolvers) r.resolve(out)
|
|
222
|
+
} catch (e) {
|
|
223
|
+
for (const r of entry.resolvers) r.reject(e)
|
|
224
|
+
}
|
|
225
|
+
}, this.writeDebounceMs)
|
|
226
|
+
|
|
227
|
+
this.pendingWrites.set(id, { timer, body, resolvers })
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private async _doSetDeviceState(id: string, body: any): Promise<any> {
|
|
232
|
+
// Prefer client API
|
|
233
|
+
if (this.client && typeof this.client.setDeviceState === 'function') {
|
|
234
|
+
return this.client.setDeviceState(id, body)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Try generic command methods
|
|
238
|
+
if (this.client && typeof this.client.sendCommand === 'function') {
|
|
239
|
+
return this.client.sendCommand(id, body)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// OpenAPI fallback
|
|
243
|
+
if (this.cfg.openApiToken) {
|
|
244
|
+
const url = `${this.baseUrl}/devices/${id}/commands`
|
|
245
|
+
const opts = {
|
|
246
|
+
method: 'POST',
|
|
247
|
+
headers: {
|
|
248
|
+
Authorization: this.cfg.openApiToken,
|
|
249
|
+
'Content-Type': 'application/json',
|
|
250
|
+
},
|
|
251
|
+
body: JSON.stringify(body),
|
|
252
|
+
}
|
|
253
|
+
const resp = await this.fetchWithTimeoutAndRetry(url, opts, undefined, undefined, id)
|
|
254
|
+
return resp.json()
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
throw new Error('No SwitchBot client available for setDeviceState')
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async destroy(): Promise<void> {
|
|
261
|
+
if (this.client && typeof this.client.destroy === 'function') {
|
|
262
|
+
await this.client.destroy()
|
|
263
|
+
}
|
|
264
|
+
this.client = null
|
|
265
|
+
}
|
|
266
|
+
}
|