@switchbot/homebridge-switchbot 5.0.0-beta.11 → 5.0.0-beta.110
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 +32 -0
- package/.github/workflows/manual-e2e.yml +115 -0
- package/.github/workflows/release.yml +0 -4
- 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 +170 -14787
- package/dist/device-types.d.ts +31 -0
- package/dist/device-types.d.ts.map +1 -0
- package/dist/device-types.js +216 -0
- package/dist/device-types.js.map +1 -0
- package/dist/deviceFactory.d.ts +13 -0
- package/dist/deviceFactory.d.ts.map +1 -0
- package/dist/deviceFactory.js +120 -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 +298 -0
- package/dist/devices/genericDevice.d.ts.map +1 -0
- package/dist/devices/genericDevice.js +1067 -0
- package/dist/devices/genericDevice.js.map +1 -0
- package/dist/homebridge-ui/endpoints/config.d.ts +3 -0
- package/dist/homebridge-ui/endpoints/config.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/config.js +104 -0
- package/dist/homebridge-ui/endpoints/config.js.map +1 -0
- package/dist/homebridge-ui/endpoints/credentials.d.ts +6 -0
- package/dist/homebridge-ui/endpoints/credentials.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/credentials.js +65 -0
- package/dist/homebridge-ui/endpoints/credentials.js.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts +6 -0
- package/dist/homebridge-ui/endpoints/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/devices.js +342 -0
- package/dist/homebridge-ui/endpoints/devices.js.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts +7 -0
- package/dist/homebridge-ui/endpoints/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/endpoints/discovery.js +171 -0
- package/dist/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/css/styles.css +254 -0
- package/dist/homebridge-ui/public/index.html +112 -247
- package/dist/homebridge-ui/public/js/api.d.ts +19 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/api.js +178 -0
- package/dist/homebridge-ui/public/js/api.js.map +1 -0
- package/dist/homebridge-ui/public/js/api.ts +205 -0
- package/dist/homebridge-ui/public/js/app.d.ts +2 -0
- package/dist/homebridge-ui/public/js/app.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/app.js +1581 -0
- package/dist/homebridge-ui/public/js/app.js.map +7 -0
- package/dist/homebridge-ui/public/js/app.ts +22 -0
- package/dist/homebridge-ui/public/js/constants.d.ts +2 -0
- package/dist/homebridge-ui/public/js/constants.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/constants.js +2 -0
- package/dist/homebridge-ui/public/js/constants.js.map +1 -0
- package/dist/homebridge-ui/public/js/constants.ts +1 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts +3 -0
- package/dist/homebridge-ui/public/js/credentials.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.js +96 -0
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.ts +100 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts +3 -0
- package/dist/homebridge-ui/public/js/devices-delete.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.js +206 -0
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.ts +236 -0
- package/dist/homebridge-ui/public/js/devices.d.ts +9 -0
- package/dist/homebridge-ui/public/js/devices.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/devices.js +81 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices.ts +88 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts +3 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.js +233 -0
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.ts +277 -0
- package/dist/homebridge-ui/public/js/logger.d.ts +6 -0
- package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/logger.js +12 -0
- package/dist/homebridge-ui/public/js/logger.js.map +1 -0
- package/dist/homebridge-ui/public/js/logger.ts +11 -0
- package/dist/homebridge-ui/public/js/modal.d.ts +5 -0
- package/dist/homebridge-ui/public/js/modal.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modal.js +26 -0
- package/dist/homebridge-ui/public/js/modal.js.map +1 -0
- package/dist/homebridge-ui/public/js/modal.ts +28 -0
- package/dist/homebridge-ui/public/js/modals.d.ts +2 -0
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modals.js +177 -0
- package/dist/homebridge-ui/public/js/modals.js.map +1 -0
- package/dist/homebridge-ui/public/js/modals.ts +200 -0
- package/dist/homebridge-ui/public/js/render.d.ts +63 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/render.js +439 -0
- package/dist/homebridge-ui/public/js/render.js.map +1 -0
- package/dist/homebridge-ui/public/js/render.ts +510 -0
- package/dist/homebridge-ui/public/js/toast.d.ts +6 -0
- package/dist/homebridge-ui/public/js/toast.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/toast.js +29 -0
- package/dist/homebridge-ui/public/js/toast.js.map +1 -0
- package/dist/homebridge-ui/public/js/toast.ts +37 -0
- package/dist/homebridge-ui/public/js/types.d.ts +23 -0
- package/dist/homebridge-ui/public/js/types.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/types.js +2 -0
- package/dist/homebridge-ui/public/js/types.js.map +1 -0
- package/dist/homebridge-ui/public/js/types.ts +26 -0
- package/dist/homebridge-ui/server.js +11 -41
- package/dist/homebridge-ui/server.js.map +1 -1
- package/dist/homebridge-ui/utils/config-parser.d.ts +35 -0
- package/dist/homebridge-ui/utils/config-parser.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/config-parser.js +87 -0
- package/dist/homebridge-ui/utils/config-parser.js.map +1 -0
- package/dist/homebridge-ui/utils/device-migration.d.ts +35 -0
- package/dist/homebridge-ui/utils/device-migration.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/device-migration.js +111 -0
- package/dist/homebridge-ui/utils/device-migration.js.map +1 -0
- package/dist/homebridge-ui/utils/logger.d.ts +7 -0
- package/dist/homebridge-ui/utils/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/utils/logger.js +17 -0
- package/dist/homebridge-ui/utils/logger.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -65
- package/dist/index.js.map +1 -1
- package/dist/platform.d.ts +35 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +1567 -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 +207 -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/eslint.config.js +7 -8
- package/nodemon.json +2 -2
- package/package.json +35 -32
- package/scripts/build-ui.js +36 -0
- 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/free-dev-ports.mjs +105 -0
- package/scripts/generate-matter-maps.js +60 -0
- package/scripts/run-e2e-local.sh +14 -0
- package/scripts/sync-device-types.mjs +28 -0
- package/src/device-types.ts +230 -0
- package/src/deviceFactory.ts +163 -0
- package/src/devices/deviceBase.ts +141 -0
- package/src/devices/genericDevice.ts +998 -0
- package/src/homebridge-ui/endpoints/config.ts +123 -0
- package/src/homebridge-ui/endpoints/credentials.ts +74 -0
- package/src/homebridge-ui/endpoints/devices.ts +380 -0
- package/src/homebridge-ui/endpoints/discovery.ts +191 -0
- package/src/homebridge-ui/public/css/styles.css +254 -0
- package/src/homebridge-ui/public/index.html +112 -247
- package/src/homebridge-ui/public/js/api.ts +205 -0
- package/src/homebridge-ui/public/js/app.ts +22 -0
- package/src/homebridge-ui/public/js/constants.ts +1 -0
- package/src/homebridge-ui/public/js/credentials.ts +100 -0
- package/src/homebridge-ui/public/js/devices-delete.ts +236 -0
- package/src/homebridge-ui/public/js/devices.ts +88 -0
- package/src/homebridge-ui/public/js/discovery.ts +277 -0
- package/src/homebridge-ui/public/js/logger.ts +11 -0
- package/src/homebridge-ui/public/js/modal.ts +28 -0
- package/src/homebridge-ui/public/js/modals.ts +200 -0
- package/src/homebridge-ui/public/js/render.ts +510 -0
- package/src/homebridge-ui/public/js/toast.ts +37 -0
- package/src/homebridge-ui/public/js/types.ts +26 -0
- package/src/homebridge-ui/server.ts +11 -43
- package/src/homebridge-ui/utils/config-parser.ts +108 -0
- package/src/homebridge-ui/utils/device-migration.ts +144 -0
- package/src/homebridge-ui/utils/logger.ts +17 -0
- package/src/index.ts +4 -66
- package/src/platform.ts +1566 -0
- package/src/settings.ts +12 -277
- package/src/switchbotClient.ts +216 -0
- package/src/utils.ts +45 -713
- package/switchbot-homebridge-switchbot-5.0.0.tgz +0 -0
- 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/todo/COMPLETED.md +189 -0
- package/todo/README.md +59 -0
- package/todo/TODO.md +205 -0
- package/todo/mockups/filtering-sorting.svg +112 -0
- package/todo/mockups/modal-switchbot-theme.svg +66 -0
- package/todo/mockups/signal-strength-visualization.svg +94 -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 -19
- 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 -120
- package/dist/platform-matter.d.ts.map +0 -1
- package/dist/platform-matter.js +0 -984
- 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 -24
- 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 -1110
- package/src/verifyconfig.test.ts +0 -197
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { SwitchBotHAPPlatform } from '../src/platform'
|
|
3
|
+
|
|
4
|
+
// Minimal mock logger
|
|
5
|
+
const log = {
|
|
6
|
+
info: () => {},
|
|
7
|
+
warn: () => {},
|
|
8
|
+
error: () => {},
|
|
9
|
+
debug: () => {},
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('platform integration (HAP)', () => {
|
|
13
|
+
it('registers HAP accessories using Homebridge API', async () => {
|
|
14
|
+
const registered: any[] = []
|
|
15
|
+
|
|
16
|
+
// Minimal hap stub
|
|
17
|
+
const hap = {
|
|
18
|
+
uuid: { generate: (s: string) => `uuid-${s}` },
|
|
19
|
+
Service: { Switch: 'Switch', Lightbulb: 'Lightbulb' },
|
|
20
|
+
Characteristic: { On: 'On', Brightness: 'Brightness' },
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Simple platformAccessory constructor
|
|
24
|
+
function PlatformAccessory(name: string, uuid: string) {
|
|
25
|
+
this.displayName = name
|
|
26
|
+
this.UUID = uuid
|
|
27
|
+
this.services = []
|
|
28
|
+
this.getService = (type: any) => this.services.find((s: any) => s.type === type)
|
|
29
|
+
this.addService = (type: any) => {
|
|
30
|
+
const s: any = { type, characteristics: {} }
|
|
31
|
+
this.services.push(s)
|
|
32
|
+
return s
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const api: any = {
|
|
37
|
+
hap,
|
|
38
|
+
platformAccessory: PlatformAccessory as any,
|
|
39
|
+
registerPlatformAccessories: (_p: string, _n: string, accs: any[]) => registered.push(...accs),
|
|
40
|
+
on: (_ev: string, cb: Function) => { /* do not auto-run */ },
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const config: any = { devices: [{ id: 'dev1', type: 'light', name: 'L1' }] }
|
|
44
|
+
|
|
45
|
+
const platform = new SwitchBotHAPPlatform(log as any, config, api)
|
|
46
|
+
|
|
47
|
+
// call loadDevices directly to control flow
|
|
48
|
+
await (platform as any).loadDevices()
|
|
49
|
+
|
|
50
|
+
// Expect accessory created and registered
|
|
51
|
+
expect(registered.length).toBeGreaterThanOrEqual(1)
|
|
52
|
+
const keys = Array.from((platform as any).accessories.keys())
|
|
53
|
+
expect(keys.some((k: string) => k.includes('dev1'))).toBeTruthy()
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { SwitchBotClient } from '../src/switchbotClient'
|
|
3
|
+
|
|
4
|
+
describe('SwitchBotClient debounce/coalesce', () => {
|
|
5
|
+
let origFetch: any
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
origFetch = (global as any).fetch
|
|
9
|
+
vi.useFakeTimers()
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
(global as any).fetch = origFetch
|
|
14
|
+
vi.restoreAllMocks()
|
|
15
|
+
vi.useRealTimers()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('coalesces rapid writes for the same device (last write wins)', async () => {
|
|
19
|
+
const respBody = { status: 'ok' }
|
|
20
|
+
const fetchMock = vi.fn(async (url: string, opts: any) => ({ json: async () => respBody }))
|
|
21
|
+
;(global as any).fetch = fetchMock
|
|
22
|
+
|
|
23
|
+
// Set a short debounce in config to keep the test fast
|
|
24
|
+
const c = new SwitchBotClient({ openApiToken: 't', writeDebounceMs: 10 } as any)
|
|
25
|
+
await c.init()
|
|
26
|
+
|
|
27
|
+
const body1 = { command: 'one' }
|
|
28
|
+
const body2 = { command: 'two' }
|
|
29
|
+
|
|
30
|
+
const p1 = c.setDeviceState('d-debounce', body1)
|
|
31
|
+
const p2 = c.setDeviceState('d-debounce', body2)
|
|
32
|
+
|
|
33
|
+
// Fast-forward timers past debounce window
|
|
34
|
+
vi.advanceTimersByTime(20)
|
|
35
|
+
// Allow pending microtasks to resolve
|
|
36
|
+
await Promise.resolve()
|
|
37
|
+
await Promise.resolve()
|
|
38
|
+
|
|
39
|
+
const [r1, r2] = await Promise.all([p1, p2])
|
|
40
|
+
expect(r1).toEqual(respBody)
|
|
41
|
+
expect(r2).toEqual(respBody)
|
|
42
|
+
|
|
43
|
+
// Only one network call should have been made
|
|
44
|
+
expect(fetchMock).toHaveBeenCalledTimes(1)
|
|
45
|
+
const calledBody = JSON.parse(fetchMock.mock.calls[0][1].body)
|
|
46
|
+
expect(calledBody).toEqual(body2)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('does not coalesce writes for different devices', async () => {
|
|
50
|
+
const respBody = { status: 'ok' }
|
|
51
|
+
const fetchMock = vi.fn(async (url: string, opts: any) => ({ json: async () => respBody }))
|
|
52
|
+
;(global as any).fetch = fetchMock
|
|
53
|
+
|
|
54
|
+
const c = new SwitchBotClient({ openApiToken: 't', writeDebounceMs: 10 } as any)
|
|
55
|
+
await c.init()
|
|
56
|
+
|
|
57
|
+
const p1 = c.setDeviceState('d-A', { command: 'a' })
|
|
58
|
+
const p2 = c.setDeviceState('d-B', { command: 'b' })
|
|
59
|
+
|
|
60
|
+
vi.advanceTimersByTime(20)
|
|
61
|
+
await Promise.resolve()
|
|
62
|
+
await Promise.resolve()
|
|
63
|
+
|
|
64
|
+
await Promise.all([p1, p2])
|
|
65
|
+
|
|
66
|
+
expect(fetchMock).toHaveBeenCalledTimes(2)
|
|
67
|
+
const b1 = JSON.parse(fetchMock.mock.calls[0][1].body)
|
|
68
|
+
const b2 = JSON.parse(fetchMock.mock.calls[1][1].body)
|
|
69
|
+
expect(b1).toEqual({ command: 'a' })
|
|
70
|
+
expect(b2).toEqual({ command: 'b' })
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('coalesces multiple rapid writes (three) and resolves all promises with last response', async () => {
|
|
74
|
+
const respBody = { status: 'ok', val: 'last' }
|
|
75
|
+
const fetchMock = vi.fn(async (url: string, opts: any) => ({ json: async () => respBody }))
|
|
76
|
+
;(global as any).fetch = fetchMock
|
|
77
|
+
|
|
78
|
+
const c = new SwitchBotClient({ openApiToken: 't', writeDebounceMs: 10 } as any)
|
|
79
|
+
await c.init()
|
|
80
|
+
|
|
81
|
+
const p1 = c.setDeviceState('d-debounce', { command: 'one' })
|
|
82
|
+
const p2 = c.setDeviceState('d-debounce', { command: 'two' })
|
|
83
|
+
const p3 = c.setDeviceState('d-debounce', { command: 'three' })
|
|
84
|
+
|
|
85
|
+
vi.advanceTimersByTime(20)
|
|
86
|
+
await Promise.resolve()
|
|
87
|
+
await Promise.resolve()
|
|
88
|
+
|
|
89
|
+
const [r1, r2, r3] = await Promise.all([p1, p2, p3])
|
|
90
|
+
expect(r1).toEqual(respBody)
|
|
91
|
+
expect(r2).toEqual(respBody)
|
|
92
|
+
expect(r3).toEqual(respBody)
|
|
93
|
+
|
|
94
|
+
expect(fetchMock).toHaveBeenCalledTimes(1)
|
|
95
|
+
const calledBody = JSON.parse(fetchMock.mock.calls[0][1].body)
|
|
96
|
+
expect(calledBody).toEqual({ command: 'three' })
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('separate writes outside debounce window produce multiple network calls', async () => {
|
|
100
|
+
const respBody1 = { status: 'ok', seq: 1 }
|
|
101
|
+
const respBody2 = { status: 'ok', seq: 2 }
|
|
102
|
+
const fetchMock = vi.fn()
|
|
103
|
+
.mockImplementationOnce(async () => ({ json: async () => respBody1 }))
|
|
104
|
+
.mockImplementationOnce(async () => ({ json: async () => respBody2 }))
|
|
105
|
+
;(global as any).fetch = fetchMock
|
|
106
|
+
|
|
107
|
+
const c = new SwitchBotClient({ openApiToken: 't', writeDebounceMs: 10 } as any)
|
|
108
|
+
await c.init()
|
|
109
|
+
|
|
110
|
+
const p1 = c.setDeviceState('d-debounce', { command: 'one' })
|
|
111
|
+
vi.advanceTimersByTime(20)
|
|
112
|
+
await Promise.resolve()
|
|
113
|
+
await Promise.resolve()
|
|
114
|
+
|
|
115
|
+
const p2 = c.setDeviceState('d-debounce', { command: 'two' })
|
|
116
|
+
vi.advanceTimersByTime(20)
|
|
117
|
+
await Promise.resolve()
|
|
118
|
+
await Promise.resolve()
|
|
119
|
+
|
|
120
|
+
const r1 = await p1
|
|
121
|
+
const r2 = await p2
|
|
122
|
+
|
|
123
|
+
expect(fetchMock).toHaveBeenCalledTimes(2)
|
|
124
|
+
const b1 = JSON.parse(fetchMock.mock.calls[0][1].body)
|
|
125
|
+
const b2 = JSON.parse(fetchMock.mock.calls[1][1].body)
|
|
126
|
+
expect(b1).toEqual({ command: 'one' })
|
|
127
|
+
expect(b2).toEqual({ command: 'two' })
|
|
128
|
+
expect(r1).toEqual(respBody1)
|
|
129
|
+
expect(r2).toEqual(respBody2)
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { SwitchBotClient } from '../src/switchbotClient'
|
|
3
|
+
|
|
4
|
+
describe('SwitchBotClient OpenAPI fallback', () => {
|
|
5
|
+
let origFetch: any
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
origFetch = (global as any).fetch
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
(global as any).fetch = origFetch
|
|
13
|
+
vi.restoreAllMocks()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('throws when no client and no token', async () => {
|
|
17
|
+
const c = new SwitchBotClient({} as any)
|
|
18
|
+
await c.init()
|
|
19
|
+
await expect(c.getDevice('nope')).rejects.toThrow('No SwitchBot client available')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('uses OpenAPI when token provided for getDevice', async () => {
|
|
23
|
+
const fakeResp = { body: { device: { id: 'd1', state: 'ok' } } }
|
|
24
|
+
const fetchMock = vi.fn(async (url: string, opts: any) => ({ json: async () => fakeResp }))
|
|
25
|
+
;(global as any).fetch = fetchMock
|
|
26
|
+
|
|
27
|
+
const c = new SwitchBotClient({ openApiToken: 'token-123' } as any)
|
|
28
|
+
await c.init()
|
|
29
|
+
const res = await c.getDevice('d1')
|
|
30
|
+
expect(res).toEqual(fakeResp)
|
|
31
|
+
expect(fetchMock).toHaveBeenCalledWith('https://api.switch-bot.com/v1.0/devices/d1', { headers: { Authorization: 'token-123' } })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('posts commands to OpenAPI for setDeviceState', async () => {
|
|
35
|
+
const respBody = { status: 'ok' }
|
|
36
|
+
const fetchMock = vi.fn(async (url: string, opts: any) => ({ json: async () => respBody }))
|
|
37
|
+
;(global as any).fetch = fetchMock
|
|
38
|
+
|
|
39
|
+
const c = new SwitchBotClient({ openApiToken: 't' } as any)
|
|
40
|
+
await c.init()
|
|
41
|
+
const body = { command: 'turnOn', parameter: 'default', commandType: 'command' }
|
|
42
|
+
const out = await c.setDeviceState('d2', body)
|
|
43
|
+
expect(out).toEqual(respBody)
|
|
44
|
+
expect(fetchMock).toHaveBeenCalledWith('https://api.switch-bot.com/v1.0/devices/d2/commands', expect.objectContaining({ method: 'POST' }))
|
|
45
|
+
const calledBody = JSON.parse((fetchMock.mock.calls[0][1].body))
|
|
46
|
+
expect(calledBody).toEqual(body)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('propagates fetch errors', async () => {
|
|
50
|
+
const fetchMock = vi.fn(async () => { throw new Error('network') })
|
|
51
|
+
;(global as any).fetch = fetchMock
|
|
52
|
+
const c = new SwitchBotClient({ openApiToken: 't' } as any)
|
|
53
|
+
await c.init()
|
|
54
|
+
await expect(c.getDevice('x')).rejects.toThrow('network')
|
|
55
|
+
})
|
|
56
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { SwitchBotClient } from '../src/switchbotClient'
|
|
3
|
+
|
|
4
|
+
describe('SwitchBotClient', () => {
|
|
5
|
+
it('init does not throw and getDevice throws when no token/client', async () => {
|
|
6
|
+
const c = new SwitchBotClient({})
|
|
7
|
+
await c.init()
|
|
8
|
+
await expect(c.getDevice('nope')).rejects.toThrow()
|
|
9
|
+
})
|
|
10
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { createPlatformProxy } from '../src/utils'
|
|
3
|
+
|
|
4
|
+
describe('createPlatformProxy', () => {
|
|
5
|
+
it('returns Matter platform when preferMatter and enabled', () => {
|
|
6
|
+
class HAP {}
|
|
7
|
+
class Matter {}
|
|
8
|
+
const ProxyCtor: any = createPlatformProxy(HAP, Matter)
|
|
9
|
+
const impl = new (ProxyCtor as any)(console, { preferMatter: true, enableMatter: true }, undefined)
|
|
10
|
+
expect(impl).toBeInstanceOf(Matter)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('returns HAP platform when preferMatter is false', () => {
|
|
14
|
+
class HAP {}
|
|
15
|
+
class Matter {}
|
|
16
|
+
const ProxyCtor: any = createPlatformProxy(HAP, Matter)
|
|
17
|
+
const impl = new (ProxyCtor as any)(console, { preferMatter: false, enableMatter: true }, undefined)
|
|
18
|
+
expect(impl).toBeInstanceOf(HAP)
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Completed TODOs
|
|
2
|
+
|
|
3
|
+
This file tracks all completed features and improvements for the SwitchBot Homebridge Plugin.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Code Refactoring & Architecture
|
|
8
|
+
|
|
9
|
+
### Server-Side Refactoring ✅ COMPLETED
|
|
10
|
+
|
|
11
|
+
- [x] **Split `server.ts` into modular structure**
|
|
12
|
+
- [x] Created `src/homebridge-ui/endpoints/discovery.ts` - Discovery endpoint
|
|
13
|
+
- [x] Created `src/homebridge-ui/endpoints/config.ts` - Config management endpoint
|
|
14
|
+
- [x] Created `src/homebridge-ui/endpoints/devices.ts` - Device CRUD operations
|
|
15
|
+
- [x] Created `src/homebridge-ui/endpoints/credentials.ts` - Credentials endpoint
|
|
16
|
+
- [x] Created `src/homebridge-ui/utils/config-parser.ts` - Config parsing helpers
|
|
17
|
+
- [x] Created `src/homebridge-ui/utils/logger.ts` - Logging utility
|
|
18
|
+
- [x] Updated `src/homebridge-ui/server.ts` - Main entry point (imports and registers endpoints)
|
|
19
|
+
|
|
20
|
+
**Status:** Server endpoints are fully modularized and organized by concern.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Bug Fixes
|
|
25
|
+
|
|
26
|
+
### Invalid Device Type Validation ✅ COMPLETED
|
|
27
|
+
|
|
28
|
+
- [x] **Fix invalid device type in config schema validation**
|
|
29
|
+
- [x] **Issue:** Config validation rejects devices with invalid `configDeviceType` values (e.g., "Lock Vision Pro" is not in valid enum)
|
|
30
|
+
- [x] **Error:** "Value is not accepted. Valid values: ..." error shown in Homebridge UI
|
|
31
|
+
- [x] **Root Cause:** Device types in existing configs may not match current DEVICE_TYPES enum (legacy names, typos, or renamed devices)
|
|
32
|
+
- [x] **Affected Devices:** Any device with `configDeviceType` not matching DEVICE_TYPES enum
|
|
33
|
+
- [x] **Solution:** Implemented device type validation migration and auto-correction
|
|
34
|
+
|
|
35
|
+
**Implementation:**
|
|
36
|
+
- Added `normalizeDeviceType()` — Validates and maps invalid types to valid equivalents
|
|
37
|
+
- Added `isValidDeviceType()` — Checks if device type is in DEVICE_TYPES enum
|
|
38
|
+
- Added `getValidDeviceTypes()` — Returns set of all valid device types
|
|
39
|
+
- Created `src/homebridge-ui/utils/device-migration.ts` — Migration utilities for batch validation
|
|
40
|
+
- Updated `src/homebridge-ui/endpoints/config.ts` — Device loading now validates types and warns about invalid ones
|
|
41
|
+
- Added migration mapping: `"Lock Vision Pro"` → `"Keypad Vision Pro"` (and others)
|
|
42
|
+
- Config endpoint returns `validationWarnings` with invalid device types and suggestions
|
|
43
|
+
|
|
44
|
+
**Status:** Device type validation is now automatic. Invalid types are detected and suggestions provided to users. Auto-correction mappings handle legacy/typo device names.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### Client-Side Refactoring
|
|
49
|
+
|
|
50
|
+
#### Phase 1: Quick Wins
|
|
51
|
+
|
|
52
|
+
##### Extract DEVICE_TYPES constant ✅ COMPLETED
|
|
53
|
+
|
|
54
|
+
- [x] Created `src/device-types.ts` as single source of truth
|
|
55
|
+
- [x] Updated `src/homebridge-ui/public/js/constants.ts` to import from shared source
|
|
56
|
+
- [x] Added `DEVICE_TYPE_NORMALIZATION_MAP` for plugin type lookups
|
|
57
|
+
- [x] Updated `src/deviceFactory.ts` to use normalized type mappings
|
|
58
|
+
- [x] Created `scripts/sync-device-types.mjs` to auto-sync config.schema.json
|
|
59
|
+
- [x] Integrated sync into build process (runs before tsc)
|
|
60
|
+
|
|
61
|
+
**Status:** Device types now single-sourced with auto-sync. Config schema, UI dropdown, and plugin type handling all stay aligned automatically.
|
|
62
|
+
|
|
63
|
+
##### Extract CSS styles ✅ COMPLETED
|
|
64
|
+
|
|
65
|
+

|
|
66
|
+
|
|
67
|
+
- [x] Created `src/homebridge-ui/public/css/styles.css`
|
|
68
|
+
- [x] Moved all inline styles from `src/homebridge-ui/public/index.html` (2.3kb)
|
|
69
|
+
- [x] Updated HTML to `<link rel="stylesheet" href="css/styles.css">`
|
|
70
|
+
- [x] Verified build copies CSS to dist/
|
|
71
|
+
- [x] Tested in browser to confirm styles still work
|
|
72
|
+
- [x] Added SwitchBot red color variables and theme
|
|
73
|
+
- [x] Enhanced modal styling with red accent borders
|
|
74
|
+
- [x] Improved button styling with hover animations
|
|
75
|
+
|
|
76
|
+
**Status:** CSS now externalized and properly linked. Build copies files correctly to dist/. Modal uses SwitchBot red theme with Homebridge-like appearance.
|
|
77
|
+
|
|
78
|
+
#### Phase 2: JavaScript Modularization ✅ COMPLETED
|
|
79
|
+
|
|
80
|
+
- [x] Created `src/homebridge-ui/public/js/api.ts` - API client functions
|
|
81
|
+
- [x] Created `src/homebridge-ui/public/js/discovery.ts` - Discovery UI rendering
|
|
82
|
+
- [x] Created `src/homebridge-ui/public/js/modals.ts` - Modal management
|
|
83
|
+
- [x] Created `src/homebridge-ui/public/js/credentials.ts` - Credentials UI
|
|
84
|
+
- [x] Created `src/homebridge-ui/public/js/toast.ts` & `modal.ts` - UI helpers
|
|
85
|
+
- [x] Created `src/homebridge-ui/public/js/app.ts` - Main app init
|
|
86
|
+
- [x] Updated `src/homebridge-ui/public/index.html` to use bundled app.js
|
|
87
|
+
|
|
88
|
+
**Status:** UI is modularized in TypeScript. Build bundles into app.js (47.0kb). Direct TypeScript imports provide type safety.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Discovery System Enhancements
|
|
93
|
+
|
|
94
|
+
### Signal Strength Visualization ✅ COMPLETED
|
|
95
|
+
|
|
96
|
+

|
|
97
|
+
|
|
98
|
+
- [x] Implement RSSI color-coding system:
|
|
99
|
+
- [x] Green: > -60 dBm (excellent)
|
|
100
|
+
- [x] Yellow: -60 to -75 dBm (good)
|
|
101
|
+
- [x] Orange: -75 to -85 dBm (fair)
|
|
102
|
+
- [x] Red: < -85 dBm (poor/unreliable)
|
|
103
|
+
- [x] Add signal strength bars visual indicator (4-bar system)
|
|
104
|
+
- [x] Add tooltip explaining signal quality
|
|
105
|
+
|
|
106
|
+
**Implementation:**
|
|
107
|
+
- Added `getRssiSignalQuality()` — Determines RSSI level, color, description, and bar count
|
|
108
|
+
- Added `renderSignalBars()` — Visual 4-bar indicator (filled based on signal strength)
|
|
109
|
+
- Added `renderSignalQualityBadge()` — Color-coded badge showing quality level (Excellent/Good/Fair/Poor)
|
|
110
|
+
- Updated `renderDiscoveredDevices()` — Displays bars and badges next to device names for BLE/wireless devices
|
|
111
|
+
- Tooltips show detailed signal info on hover
|
|
112
|
+
|
|
113
|
+
**Status:** Signal visualization now displays for all discovered devices with RSSI data. Color-coded bars and badges provide instant visual feedback about connection quality.
|
|
114
|
+
|
|
115
|
+
### Filtering & Sorting ✅ COMPLETED
|
|
116
|
+
|
|
117
|
+

|
|
118
|
+
|
|
119
|
+
- [x] Add filter buttons: "All | BLE Only | API Only | Both | IR Devices"
|
|
120
|
+
- [x] Add sort dropdown: "Signal Strength | Name | Type | Connection"
|
|
121
|
+
- [x] Add search box to filter by name/ID/type (real-time filtering)
|
|
122
|
+
- [x] Persist filter/sort preferences in localStorage
|
|
123
|
+
|
|
124
|
+
**Implementation:**
|
|
125
|
+
- Added `filterDevices()` — Filters by connection type (BLE/API/Both/IR) and search query (matches name/id/type/model)
|
|
126
|
+
- Added `sortDevices()` — Sorts by name (alphabetical), signal strength (RSSI descending), device type, or connection type
|
|
127
|
+
- Added `getDiscoveryPreferences()` & `setDiscoveryPreferences()` — Persist user preferences in localStorage
|
|
128
|
+
- Updated `discovery.ts` — Creates filter buttons, sort dropdown, and search input dynamically
|
|
129
|
+
- All filtering/sorting is client-side (instant, no API calls)
|
|
130
|
+
- Search is debounced (300ms) for smooth typing
|
|
131
|
+
- Filter buttons highlight active selection
|
|
132
|
+
- Status shows "Showing X of Y device(s)" when filtered
|
|
133
|
+
|
|
134
|
+
**Status:** Full filtering and sorting implemented with localStorage persistence. Discovery page now shows:
|
|
135
|
+
- Filter bar with 5 buttons (All/BLE/API/Both/IR)
|
|
136
|
+
- Sort dropdown with 4 options (Name/Signal Strength/Type/Connection)
|
|
137
|
+
- Real-time search box
|
|
138
|
+
- All preferences saved and restored on next discovery
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Bug Fixes & Technical Debt
|
|
143
|
+
|
|
144
|
+
### Fix lint & lint:fix scripts ✅ COMPLETED
|
|
145
|
+
|
|
146
|
+
- [x] Update ESLint configuration to include `src/homebridge-ui/**/*.ts` files
|
|
147
|
+
- [x] Add HTML linting for `src/homebridge-ui/**/*.html` files
|
|
148
|
+
- [x] Installed `eslint-plugin-html` for inline JavaScript in HTML
|
|
149
|
+
- [x] Update `npm run lint` script to lint both plugin and UI code
|
|
150
|
+
- [x] Update `npm run lint:fix` script to auto-fix both plugin and UI code
|
|
151
|
+
- [x] Fixed existing ESLint errors (regex patterns, multi-statement lines)
|
|
152
|
+
- [x] Lint now passes successfully
|
|
153
|
+
- [x] Test that `npm run lint` runs successfully without errors
|
|
154
|
+
|
|
155
|
+
**Changes Made:**
|
|
156
|
+
- Installed `eslint-plugin-html` package
|
|
157
|
+
- Updated `eslint.config.js` to import and configure HTML plugin
|
|
158
|
+
- Added `html: true` to formatters in ESLint config
|
|
159
|
+
- Updated package.json scripts: `lint` and `lint:fix` now include `src/homebridge-ui/**/*.html`
|
|
160
|
+
- Moved regex patterns to module scope in `server.ts` and `genericDevice.ts`
|
|
161
|
+
- Split multi-statement lines to comply with `style/max-statements-per-line` rule
|
|
162
|
+
- All lint errors fixed - `npm run lint` passes with 0 errors
|
|
163
|
+
|
|
164
|
+
### Fix TypeScript compilation errors in discovery endpoint ✅ COMPLETED
|
|
165
|
+
|
|
166
|
+
- [x] Fixed: Changed `discover({ duration: 5000 })` to `discover({ timeout: 5000 })`
|
|
167
|
+
- [x] Fixed: Changed `switchbot.getDevices()` to use `switchbot.getAPIClient()?.getDevices()`
|
|
168
|
+
- [x] Reviewed node-switchbot v4.0.0-beta.3 API documentation and type definitions
|
|
169
|
+
- [x] Updated discovery implementation to use correct API types (APIDevice, APIInfraredRemote)
|
|
170
|
+
- [x] Fixed property names: `deviceId`, `deviceName`, `deviceType`, `remoteType`
|
|
171
|
+
- [x] Removed references to non-existent properties (`id`, `name`, `type`, `model`, `deviceModel`)
|
|
172
|
+
|
|
173
|
+
**Changes Made:**
|
|
174
|
+
- Updated BLE discovery to use `timeout` parameter instead of `duration`
|
|
175
|
+
- Changed OpenAPI access to use `switchbot.getAPIClient()?.getDevices()`
|
|
176
|
+
- Simplified response parsing: `apiData.deviceList` and `apiData.infraredRemoteList` (no `body` wrapper)
|
|
177
|
+
- Fixed all property accesses to match APIDevice and APIInfraredRemote interfaces
|
|
178
|
+
- Build now succeeds with 0 TypeScript errors
|
|
179
|
+
- All 39 tests still pass
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Notes
|
|
184
|
+
|
|
185
|
+
- All completed features have been tested and verified working
|
|
186
|
+
- Bundle size increased from 35.8kb → 47.0kb with new features
|
|
187
|
+
- Zero TypeScript compilation errors
|
|
188
|
+
- All lint checks passing
|
|
189
|
+
- UI mockups available in `todo/mockups/` directory
|
package/todo/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# TODO Documentation
|
|
2
|
+
|
|
3
|
+
This directory contains all task tracking and planning documentation for the SwitchBot Homebridge Plugin.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
todo/
|
|
9
|
+
├── README.md # This file
|
|
10
|
+
├── TODO.md # Active tasks and upcoming features
|
|
11
|
+
├── COMPLETED.md # Completed features and improvements
|
|
12
|
+
└── mockups/ # UI design mockups
|
|
13
|
+
├── signal-strength-visualization.svg
|
|
14
|
+
├── filtering-sorting.svg
|
|
15
|
+
└── modal-switchbot-theme.svg
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Files
|
|
19
|
+
|
|
20
|
+
### [TODO.md](TODO.md)
|
|
21
|
+
Active tasks and features planned for future releases. Organized by priority:
|
|
22
|
+
- **Must Do (Next Release)** - Critical features blocking next release
|
|
23
|
+
- **Should Do (Soon)** - Important features for near-term releases
|
|
24
|
+
- **Nice to Have (Future)** - Enhancement ideas for future consideration
|
|
25
|
+
|
|
26
|
+
### [COMPLETED.md](COMPLETED.md)
|
|
27
|
+
Archive of completed features and bug fixes. Each completed item includes:
|
|
28
|
+
- Implementation details
|
|
29
|
+
- Date completed
|
|
30
|
+
- Links to related code/files
|
|
31
|
+
- UI mockups (if applicable)
|
|
32
|
+
|
|
33
|
+
### [mockups/](mockups/)
|
|
34
|
+
SVG mockups showing UI designs for completed and planned features:
|
|
35
|
+
- **signal-strength-visualization.svg** - RSSI bars and quality badges for BLE devices
|
|
36
|
+
- **filtering-sorting.svg** - Discovery page filters, sort options, and search
|
|
37
|
+
- **modal-switchbot-theme.svg** - Edit device modal with SwitchBot red theme
|
|
38
|
+
|
|
39
|
+
## Workflow
|
|
40
|
+
|
|
41
|
+
1. **Planning** - New features start as unchecked items in TODO.md
|
|
42
|
+
2. **Development** - Mark items as in-progress while working
|
|
43
|
+
3. **Completion** - When complete, move entire section to COMPLETED.md with implementation details
|
|
44
|
+
4. **UI Features** - Create SVG mockup before or after implementation for documentation
|
|
45
|
+
|
|
46
|
+
## Priority Levels
|
|
47
|
+
|
|
48
|
+
- **Priority: Critical** - Bugs affecting functionality or compatibility
|
|
49
|
+
- **Priority: High** - Features needed for next release
|
|
50
|
+
- **Priority: Medium** - Quality of life improvements
|
|
51
|
+
- **Priority: Low** - Nice-to-have enhancements
|
|
52
|
+
|
|
53
|
+
## Notes
|
|
54
|
+
|
|
55
|
+
- Always update COMPLETED.md when marking features as done
|
|
56
|
+
- Include implementation details and learnings
|
|
57
|
+
- Create mockups for all UI features
|
|
58
|
+
- Keep TODO.md focused on active/upcoming work
|
|
59
|
+
- Archive helps track project progress over time
|