@switchbot/homebridge-switchbot 5.0.0-beta.7 → 5.0.0-beta.71
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 +35 -0
- package/E2E-VERIFICATION.md +121 -0
- package/MIGRATION.md +44 -0
- package/README.md +56 -3
- package/config.schema.json +99 -14823
- 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 +77 -245
- 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 +42 -36
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -12
- 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 -249
- 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 +39 -50
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +39 -688
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +14 -0
- package/docs/assets/icons.js +1 -1
- package/docs/assets/icons.svg +1 -1
- package/docs/assets/main.js +2 -2
- package/docs/assets/style.css +3 -3
- package/docs/index.html +77 -13
- package/docs/variables/default.html +1 -1
- package/package.json +22 -21
- 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 +77 -245
- package/src/homebridge-ui/server.ts +49 -41
- package/src/index.ts +5 -13
- package/src/platform.ts +395 -0
- package/src/settings.ts +12 -277
- package/src/switchbotClient.ts +266 -0
- package/src/utils.ts +45 -713
- 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 -527
- 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 -811
- 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 -701
- 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 -881
- 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 -98
- package/dist/devices-hap/device.d.ts.map +0 -1
- package/dist/devices-hap/device.js +0 -749
- 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 -649
- 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 -392
- package/dist/devices-hap/hub.js.map +0 -1
- package/dist/devices-hap/humidifier.d.ts +0 -68
- package/dist/devices-hap/humidifier.d.ts.map +0 -1
- package/dist/devices-hap/humidifier.js +0 -628
- 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 -382
- 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 -797
- 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 -561
- 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 -379
- 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 -384
- 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 -468
- 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 -395
- 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 -523
- 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 -63
- package/dist/devices-matter/BaseMatterAccessory.d.ts.map +0 -1
- package/dist/devices-matter/BaseMatterAccessory.js +0 -100
- 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 -78
- 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 -107
- 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 -118
- package/dist/devices-matter/OnOffLightAccessory.js.map +0 -1
- package/dist/devices-matter/OnOffOutletAccessory.d.ts +0 -12
- package/dist/devices-matter/OnOffOutletAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OnOffOutletAccessory.js +0 -40
- 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 -68
- package/dist/devices-matter/RoboticVacuumAccessory.d.ts.map +0 -1
- package/dist/devices-matter/RoboticVacuumAccessory.js +0 -334
- 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 -80
- 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/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -14
- package/dist/index.test.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 -68
- package/dist/irdevice/irdevice.d.ts.map +0 -1
- package/dist/irdevice/irdevice.js +0 -298
- 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 -149
- package/dist/platform-hap.d.ts.map +0 -1
- package/dist/platform-hap.js +0 -2861
- package/dist/platform-hap.js.map +0 -1
- package/dist/platform-matter.d.ts +0 -101
- package/dist/platform-matter.d.ts.map +0 -1
- package/dist/platform-matter.js +0 -896
- package/dist/platform-matter.js.map +0 -1
- package/dist/verifyconfig.test.d.ts +0 -2
- package/dist/verifyconfig.test.d.ts.map +0 -1
- package/dist/verifyconfig.test.js +0 -167
- package/dist/verifyconfig.test.js.map +0 -1
- package/src/custom.d.ts +0 -7
- package/src/devices-hap/airpurifier.ts +0 -563
- package/src/devices-hap/blindtilt.ts +0 -1049
- package/src/devices-hap/bot.ts +0 -900
- package/src/devices-hap/ceilinglight.ts +0 -742
- package/src/devices-hap/colorbulb.ts +0 -904
- package/src/devices-hap/contact.ts +0 -457
- package/src/devices-hap/curtain.ts +0 -944
- package/src/devices-hap/device.ts +0 -811
- package/src/devices-hap/fan.ts +0 -711
- package/src/devices-hap/hub.ts +0 -439
- package/src/devices-hap/humidifier.ts +0 -669
- package/src/devices-hap/iosensor.ts +0 -427
- package/src/devices-hap/lightstrip.ts +0 -836
- package/src/devices-hap/lock.ts +0 -620
- package/src/devices-hap/meter.ts +0 -426
- package/src/devices-hap/meterplus.ts +0 -430
- package/src/devices-hap/meterpro.ts +0 -522
- package/src/devices-hap/motion.ts +0 -390
- package/src/devices-hap/plug.ts +0 -423
- package/src/devices-hap/relayswitch.ts +0 -727
- package/src/devices-hap/robotvacuumcleaner.ts +0 -568
- package/src/devices-hap/waterdetector.ts +0 -400
- package/src/devices-matter/BaseMatterAccessory.ts +0 -131
- package/src/devices-matter/ColorLightAccessory.ts +0 -110
- package/src/devices-matter/ColorTemperatureLightAccessory.ts +0 -92
- 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 -123
- 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 -133
- package/src/devices-matter/OnOffOutletAccessory.ts +0 -46
- package/src/devices-matter/OnOffSwitchAccessory.ts +0 -51
- package/src/devices-matter/RoboticVacuumAccessory.ts +0 -407
- 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 -92
- 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/index.test.ts +0 -19
- 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 -344
- 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 -2997
- package/src/platform-matter.ts +0 -1010
- package/src/verifyconfig.test.ts +0 -197
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import type { SwitchBotPluginConfig } from './settings'
|
|
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
|
+
}
|