@switchbot/homebridge-switchbot 5.0.0-beta.15 → 5.0.0-beta.150
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/.changeset/config.json +14 -0
- package/.github/ISSUE_TEMPLATE/e2e-verification.md +36 -0
- package/.github/copilot-instructions.md +39 -0
- package/.github/workflows/ci.yml +32 -0
- package/.github/workflows/manual-e2e.yml +115 -0
- package/.github/workflows/release.yml +0 -4
- package/.husky/pre-push +15 -0
- package/CHANGELOG.md +35 -0
- package/E2E-VERIFICATION.md +121 -0
- package/MIGRATION.md +54 -0
- package/README.md +136 -4
- package/TODO.md +263 -0
- package/config.schema.json +284 -14787
- package/dist/SwitchBotHAPPlatform.d.ts +133 -0
- package/dist/SwitchBotHAPPlatform.d.ts.map +1 -0
- package/dist/SwitchBotHAPPlatform.js +555 -0
- package/dist/SwitchBotHAPPlatform.js.map +1 -0
- package/dist/SwitchBotMatterPlatform.d.ts +141 -0
- package/dist/SwitchBotMatterPlatform.d.ts.map +1 -0
- package/dist/SwitchBotMatterPlatform.js +536 -0
- package/dist/SwitchBotMatterPlatform.js.map +1 -0
- package/dist/device-types.d.ts +31 -0
- package/dist/device-types.d.ts.map +1 -0
- package/dist/device-types.js +246 -0
- package/dist/device-types.js.map +1 -0
- package/dist/deviceCommandMapper.d.ts +10 -0
- package/dist/deviceCommandMapper.d.ts.map +1 -0
- package/dist/deviceCommandMapper.js +319 -0
- package/dist/deviceCommandMapper.js.map +1 -0
- package/dist/deviceFactory.d.ts +14 -0
- package/dist/deviceFactory.d.ts.map +1 -0
- package/dist/deviceFactory.js +159 -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 +320 -0
- package/dist/devices/genericDevice.d.ts.map +1 -0
- package/dist/devices/genericDevice.js +1363 -0
- package/dist/devices/genericDevice.js.map +1 -0
- package/dist/errors.d.ts +38 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.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 +90 -0
- package/dist/homebridge-ui/endpoints/config.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 +81 -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 +212 -0
- package/dist/homebridge-ui/endpoints/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/css/styles.css +472 -0
- package/dist/homebridge-ui/public/index.html +210 -244
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts +3 -0
- package/dist/homebridge-ui/public/js/advanced-settings.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/advanced-settings.js +95 -0
- package/dist/homebridge-ui/public/js/advanced-settings.js.map +1 -0
- package/dist/homebridge-ui/public/js/advanced-settings.ts +94 -0
- package/dist/homebridge-ui/public/js/api.d.ts +66 -0
- package/dist/homebridge-ui/public/js/api.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/api.js +281 -0
- package/dist/homebridge-ui/public/js/api.js.map +1 -0
- package/dist/homebridge-ui/public/js/api.ts +342 -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 +3863 -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 +99 -0
- package/dist/homebridge-ui/public/js/credentials.js.map +1 -0
- package/dist/homebridge-ui/public/js/credentials.ts +105 -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 +199 -0
- package/dist/homebridge-ui/public/js/devices-delete.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices-delete.ts +227 -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 +96 -0
- package/dist/homebridge-ui/public/js/devices.js.map +1 -0
- package/dist/homebridge-ui/public/js/devices.ts +105 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts +4 -0
- package/dist/homebridge-ui/public/js/discovery.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.js +1374 -0
- package/dist/homebridge-ui/public/js/discovery.js.map +1 -0
- package/dist/homebridge-ui/public/js/discovery.ts +1498 -0
- package/dist/homebridge-ui/public/js/logger.d.ts +7 -0
- package/dist/homebridge-ui/public/js/logger.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/logger.js +17 -0
- package/dist/homebridge-ui/public/js/logger.js.map +1 -0
- package/dist/homebridge-ui/public/js/logger.ts +17 -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 +15 -0
- package/dist/homebridge-ui/public/js/modals.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/modals.js +673 -0
- package/dist/homebridge-ui/public/js/modals.js.map +1 -0
- package/dist/homebridge-ui/public/js/modals.ts +761 -0
- package/dist/homebridge-ui/public/js/render.d.ts +71 -0
- package/dist/homebridge-ui/public/js/render.d.ts.map +1 -0
- package/dist/homebridge-ui/public/js/render.js +953 -0
- package/dist/homebridge-ui/public/js/render.js.map +1 -0
- package/dist/homebridge-ui/public/js/render.ts +1077 -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 +9 -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 +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/settings.d.ts +11 -249
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +6 -30
- package/dist/settings.js.map +1 -1
- package/dist/switchbotClient.d.ts +28 -0
- package/dist/switchbotClient.d.ts.map +1 -0
- package/dist/switchbotClient.js +175 -0
- package/dist/switchbotClient.js.map +1 -0
- package/dist/utils.d.ts +92 -115
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1117 -902
- package/dist/utils.js.map +1 -1
- package/docs/assets/highlight.css +28 -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 +148 -13
- package/docs/variables/default.html +3 -1
- package/eslint.config.js +7 -8
- package/nodemon.json +2 -2
- package/package.json +36 -32
- package/scripts/build-ui.js +37 -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 +77 -0
- package/scripts/run-e2e-local.sh +14 -0
- package/scripts/sync-device-types.mjs +31 -0
- package/src/SwitchBotHAPPlatform.ts +558 -0
- package/src/SwitchBotMatterPlatform.ts +538 -0
- package/src/device-types.ts +261 -0
- package/src/deviceCommandMapper.ts +333 -0
- package/src/deviceFactory.ts +201 -0
- package/src/devices/deviceBase.ts +141 -0
- package/src/devices/genericDevice.ts +1337 -0
- package/src/errors.ts +35 -0
- package/src/homebridge-ui/endpoints/config.ts +110 -0
- package/src/homebridge-ui/endpoints/devices.ts +88 -0
- package/src/homebridge-ui/endpoints/discovery.ts +233 -0
- package/src/homebridge-ui/public/css/styles.css +472 -0
- package/src/homebridge-ui/public/index.html +210 -244
- package/src/homebridge-ui/public/js/advanced-settings.ts +94 -0
- package/src/homebridge-ui/public/js/api.ts +342 -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 +105 -0
- package/src/homebridge-ui/public/js/devices-delete.ts +227 -0
- package/src/homebridge-ui/public/js/devices.ts +105 -0
- package/src/homebridge-ui/public/js/discovery.ts +1498 -0
- package/src/homebridge-ui/public/js/logger.ts +17 -0
- package/src/homebridge-ui/public/js/modal.ts +28 -0
- package/src/homebridge-ui/public/js/modals.ts +761 -0
- package/src/homebridge-ui/public/js/render.ts +1077 -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 +9 -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 +12 -4
- package/src/settings.ts +14 -277
- package/src/switchbotClient.ts +181 -0
- package/src/utils.ts +1106 -900
- package/test/client/switchbot-client-debounce.spec.ts +35 -0
- package/test/client/switchbot-client-openapi.spec.ts +19 -0
- package/test/client/switchbotClient.spec.ts +23 -0
- package/test/device/device-mapping.spec.ts +23 -0
- package/test/device/deviceBase.spec.ts +26 -0
- package/test/device/deviceFactory-edge.spec.ts +15 -0
- package/test/device/deviceFactory.spec.ts +33 -0
- package/test/device/fan-swing.spec.ts +34 -0
- package/test/device/genericDevice-blepoll.spec.ts +47 -0
- package/test/device/irdevice.spec.ts +9 -0
- package/test/device/lock-users.spec.ts +35 -0
- package/test/device/matter-descriptors.spec.ts +22 -0
- package/test/device/matter-device-state.spec.ts +37 -0
- package/test/e2e/run-e2e.spec.ts +48 -0
- package/test/errors/errors.spec.ts +10 -0
- package/test/helpers/matter-harness.ts +64 -0
- package/test/homebridge-ui/server.spec.ts +9 -0
- package/test/platform/accessory-restore.spec.ts +37 -0
- package/test/platform/matter-childbridge.spec.ts +34 -0
- package/test/platform/matter-integration.spec.ts +33 -0
- package/test/platform/platform-edge.spec.ts +73 -0
- package/test/platform/platform.integration.spec.ts +34 -0
- package/test/utils/utils-extra.spec.ts +10 -0
- package/test/utils/utils.spec.ts +53 -0
- package/todo/TODO.md +80 -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/baseMatterAccessory.test.d.ts +0 -2
- package/dist/baseMatterAccessory.test.d.ts.map +0 -1
- package/dist/baseMatterAccessory.test.js +0 -71
- package/dist/baseMatterAccessory.test.js.map +0 -1
- 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 -831
- 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 -78
- package/dist/devices-matter/BaseMatterAccessory.d.ts.map +0 -1
- package/dist/devices-matter/BaseMatterAccessory.js +0 -244
- package/dist/devices-matter/BaseMatterAccessory.js.map +0 -1
- package/dist/devices-matter/ColorLightAccessory.d.ts +0 -20
- package/dist/devices-matter/ColorLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ColorLightAccessory.js +0 -95
- package/dist/devices-matter/ColorLightAccessory.js.map +0 -1
- package/dist/devices-matter/ColorTemperatureLightAccessory.d.ts +0 -18
- package/dist/devices-matter/ColorTemperatureLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ColorTemperatureLightAccessory.js +0 -76
- package/dist/devices-matter/ColorTemperatureLightAccessory.js.map +0 -1
- package/dist/devices-matter/ContactSensorAccessory.d.ts +0 -12
- package/dist/devices-matter/ContactSensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ContactSensorAccessory.js +0 -34
- package/dist/devices-matter/ContactSensorAccessory.js.map +0 -1
- package/dist/devices-matter/DimmableLightAccessory.d.ts +0 -58
- package/dist/devices-matter/DimmableLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/DimmableLightAccessory.js +0 -167
- package/dist/devices-matter/DimmableLightAccessory.js.map +0 -1
- package/dist/devices-matter/DoorLockAccessory.d.ts +0 -14
- package/dist/devices-matter/DoorLockAccessory.d.ts.map +0 -1
- package/dist/devices-matter/DoorLockAccessory.js +0 -50
- package/dist/devices-matter/DoorLockAccessory.js.map +0 -1
- package/dist/devices-matter/ExtendedColorLightAccessory.d.ts +0 -21
- package/dist/devices-matter/ExtendedColorLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/ExtendedColorLightAccessory.js +0 -106
- package/dist/devices-matter/ExtendedColorLightAccessory.js.map +0 -1
- package/dist/devices-matter/FanAccessory.d.ts +0 -16
- package/dist/devices-matter/FanAccessory.d.ts.map +0 -1
- package/dist/devices-matter/FanAccessory.js +0 -81
- package/dist/devices-matter/FanAccessory.js.map +0 -1
- package/dist/devices-matter/HumiditySensorAccessory.d.ts +0 -12
- package/dist/devices-matter/HumiditySensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/HumiditySensorAccessory.js +0 -34
- package/dist/devices-matter/HumiditySensorAccessory.js.map +0 -1
- package/dist/devices-matter/LeakSensorAccessory.d.ts +0 -12
- package/dist/devices-matter/LeakSensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/LeakSensorAccessory.js +0 -33
- package/dist/devices-matter/LeakSensorAccessory.js.map +0 -1
- package/dist/devices-matter/LightSensorAccessory.d.ts +0 -12
- package/dist/devices-matter/LightSensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/LightSensorAccessory.js +0 -34
- package/dist/devices-matter/LightSensorAccessory.js.map +0 -1
- package/dist/devices-matter/OccupancySensorAccessory.d.ts +0 -12
- package/dist/devices-matter/OccupancySensorAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OccupancySensorAccessory.js +0 -39
- package/dist/devices-matter/OccupancySensorAccessory.js.map +0 -1
- package/dist/devices-matter/OnOffLightAccessory.d.ts +0 -38
- package/dist/devices-matter/OnOffLightAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OnOffLightAccessory.js +0 -110
- package/dist/devices-matter/OnOffLightAccessory.js.map +0 -1
- package/dist/devices-matter/OnOffOutletAccessory.d.ts +0 -14
- package/dist/devices-matter/OnOffOutletAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OnOffOutletAccessory.js +0 -43
- package/dist/devices-matter/OnOffOutletAccessory.js.map +0 -1
- package/dist/devices-matter/OnOffSwitchAccessory.d.ts +0 -14
- package/dist/devices-matter/OnOffSwitchAccessory.d.ts.map +0 -1
- package/dist/devices-matter/OnOffSwitchAccessory.js +0 -42
- package/dist/devices-matter/OnOffSwitchAccessory.js.map +0 -1
- package/dist/devices-matter/RoboticVacuumAccessory.d.ts +0 -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 -398
- 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 -145
- package/dist/platform-hap.d.ts.map +0 -1
- package/dist/platform-hap.js +0 -2823
- package/dist/platform-hap.js.map +0 -1
- package/dist/platform-matter.d.ts +0 -131
- package/dist/platform-matter.d.ts.map +0 -1
- package/dist/platform-matter.js +0 -1002
- package/dist/platform-matter.js.map +0 -1
- package/dist/utils.test.d.ts +0 -2
- package/dist/utils.test.d.ts.map +0 -1
- package/dist/utils.test.js +0 -95
- package/dist/utils.test.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/baseMatterAccessory.test.ts +0 -88
- 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 -884
- 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 -273
- package/src/devices-matter/ColorLightAccessory.ts +0 -110
- package/src/devices-matter/ColorTemperatureLightAccessory.ts +0 -90
- package/src/devices-matter/ContactSensorAccessory.ts +0 -41
- package/src/devices-matter/DimmableLightAccessory.ts +0 -192
- package/src/devices-matter/DoorLockAccessory.ts +0 -60
- package/src/devices-matter/ExtendedColorLightAccessory.ts +0 -122
- package/src/devices-matter/FanAccessory.ts +0 -95
- package/src/devices-matter/HumiditySensorAccessory.ts +0 -41
- package/src/devices-matter/LeakSensorAccessory.ts +0 -40
- package/src/devices-matter/LightSensorAccessory.ts +0 -41
- package/src/devices-matter/OccupancySensorAccessory.ts +0 -48
- package/src/devices-matter/OnOffLightAccessory.ts +0 -125
- package/src/devices-matter/OnOffOutletAccessory.ts +0 -51
- package/src/devices-matter/OnOffSwitchAccessory.ts +0 -51
- package/src/devices-matter/RoboticVacuumAccessory.ts +0 -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 -435
- 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 -2952
- package/src/platform-matter.ts +0 -1129
- package/src/utils.test.ts +0 -96
- package/src/verifyconfig.test.ts +0 -198
package/dist/utils.js
CHANGED
|
@@ -1,945 +1,1160 @@
|
|
|
1
|
-
export var BlindTiltMappingMode;
|
|
2
|
-
(function (BlindTiltMappingMode) {
|
|
3
|
-
BlindTiltMappingMode["OnlyUp"] = "only_up";
|
|
4
|
-
BlindTiltMappingMode["OnlyDown"] = "only_down";
|
|
5
|
-
BlindTiltMappingMode["DownAndUp"] = "down_and_up";
|
|
6
|
-
BlindTiltMappingMode["UpAndDown"] = "up_and_down";
|
|
7
|
-
BlindTiltMappingMode["UseTiltForDirection"] = "use_tilt_for_direction";
|
|
8
|
-
})(BlindTiltMappingMode || (BlindTiltMappingMode = {}));
|
|
9
|
-
export function isCurtainDevice(device) {
|
|
10
|
-
return device.deviceType === 'Curtain' || device.deviceType === 'Curtain3';
|
|
11
|
-
}
|
|
12
|
-
export function isBlindTiltDevice(device) {
|
|
13
|
-
return device.deviceType === 'Blind Tilt';
|
|
14
|
-
}
|
|
15
|
-
export function sleep(ms) {
|
|
16
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
17
|
-
}
|
|
18
1
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @
|
|
2
|
+
* Indicates which device types should prefer Matter if available.
|
|
3
|
+
* Based on HAP service mappings: device implementations use specific HomeKit services
|
|
4
|
+
* that map to corresponding Matter clusters when Matter is enabled.
|
|
5
|
+
*
|
|
6
|
+
* @property {boolean} [deviceType] - True if the device type supports Matter, false otherwise.
|
|
7
|
+
* @example
|
|
8
|
+
* DEVICE_MATTER_SUPPORTED['bot'] // true
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Factory function to create Matter handlers with Homebridge logger integration.
|
|
12
|
+
* Returns handler objects for supported device types, mapping Matter cluster actions to SwitchBot API calls.
|
|
13
|
+
*
|
|
14
|
+
* @param log - Homebridge logger instance
|
|
15
|
+
* @param deviceId - SwitchBot device ID
|
|
16
|
+
* @param type - Device type string
|
|
17
|
+
* @param client - SwitchBot client instance
|
|
18
|
+
* @returns Handler object for Matter clusters
|
|
24
19
|
*/
|
|
25
|
-
export
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
export const DEVICE_MATTER_SUPPORTED = {
|
|
21
|
+
// Core devices
|
|
22
|
+
'bot': true, // Switch → OnOff
|
|
23
|
+
'curtain': true, // WindowCovering → WindowCovering
|
|
24
|
+
'fan': true, // Fan → FanControl
|
|
25
|
+
'light': true, // Lightbulb → OnOff + LevelControl
|
|
26
|
+
'lightstrip': true, // Lightbulb (color) → OnOff + LevelControl + ColorControl
|
|
27
|
+
'motion': true, // MotionSensor → OccupancySensing
|
|
28
|
+
'contact': true, // ContactSensor → BooleanState
|
|
29
|
+
'vacuum': true, // Switch → RobotVacuumCleaner
|
|
30
|
+
'lock': true, // LockMechanism → DoorLock
|
|
31
|
+
'humidifier': true, // Fan + Humidity → OnOff + FanControl + RelativeHumidityMeasurement
|
|
32
|
+
'temperature': true, // TemperatureSensor → TemperatureMeasurement
|
|
33
|
+
// Switch devices
|
|
34
|
+
'relay': true, // Switch → OnOff
|
|
35
|
+
'relay switch 1': true, // Switch → OnOff
|
|
36
|
+
'relay switch 1pm': true, // Switch → OnOff
|
|
37
|
+
'plug': true, // Outlet → OnOff
|
|
38
|
+
'plug mini (jp)': true, // Outlet → OnOff
|
|
39
|
+
'plug mini (us)': true, // Outlet → OnOff
|
|
40
|
+
// Window covering variants
|
|
41
|
+
'blindtilt': true, // WindowCovering → WindowCovering
|
|
42
|
+
'blind tilt': true, // WindowCovering → WindowCovering
|
|
43
|
+
'curtain3': true, // WindowCovering → WindowCovering
|
|
44
|
+
'rollershade': true, // WindowCovering → WindowCovering
|
|
45
|
+
'roller shade': true, // WindowCovering → WindowCovering
|
|
46
|
+
'worollershade': true, // WindowCovering → WindowCovering
|
|
47
|
+
'wo rollershade': true, // WindowCovering → WindowCovering
|
|
48
|
+
// Vacuum variants (normalized to 'vacuum' before lookup)
|
|
49
|
+
'wosweeper': true, // VacuumDevice → RobotVacuumCleaner
|
|
50
|
+
'wosweepermini': true, // VacuumDevice → RobotVacuumCleaner
|
|
51
|
+
'wosweeperminipro': true, // VacuumDevice → RobotVacuumCleaner
|
|
52
|
+
'k10+': true, // VacuumDevice → RobotVacuumCleaner
|
|
53
|
+
'k10+ pro': true, // VacuumDevice → RobotVacuumCleaner
|
|
54
|
+
// Sensors
|
|
55
|
+
'meter': true, // TemperatureSensor + HumiditySensor → TemperatureMeasurement + RelativeHumidityMeasurement
|
|
56
|
+
'meterplus': true, // TemperatureSensor + HumiditySensor → TemperatureMeasurement + RelativeHumidityMeasurement
|
|
57
|
+
'meter plus (jp)': true, // TemperatureSensor + HumiditySensor → TemperatureMeasurement + RelativeHumidityMeasurement
|
|
58
|
+
'meterpro': true, // TemperatureSensor + HumiditySensor → TemperatureMeasurement + RelativeHumidityMeasurement
|
|
59
|
+
'meterpro(co2)': true, // TemperatureSensor + HumiditySensor → TemperatureMeasurement + RelativeHumidityMeasurement
|
|
60
|
+
'waterdetector': true, // LeakSensor → BooleanState
|
|
61
|
+
'water detector': true, // LeakSensor → BooleanState
|
|
62
|
+
// Other devices
|
|
63
|
+
'smart fan': true, // Fan → FanControl
|
|
64
|
+
'strip light': true, // Lightbulb (color) → OnOff + LevelControl + ColorControl
|
|
65
|
+
'hub 2': false, // Hub device - not exposed as accessory
|
|
66
|
+
'walletfinder': false, // Button device - Matter support TBD
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Default Matter cluster configurations by device type.
|
|
70
|
+
* Maps device types to their Matter cluster states (used when device doesn't provide clusters).
|
|
71
|
+
* Note: wosweeper/curtain/plug variants are normalized before cluster lookup (see loadDevices).
|
|
72
|
+
*
|
|
73
|
+
* @property {object} [deviceType] - The default cluster state for the device type.
|
|
74
|
+
* @example
|
|
75
|
+
* DEVICE_MATTER_CLUSTERS['bot'] // { onOff: { onOff: false } }
|
|
76
|
+
*/
|
|
77
|
+
export const DEVICE_MATTER_CLUSTERS = {
|
|
78
|
+
// Core devices - aligned with HAP service implementations
|
|
79
|
+
bot: { onOff: { onOff: false } }, // Switch → OnOff
|
|
80
|
+
vacuum: {
|
|
81
|
+
rvcRunMode: {
|
|
82
|
+
supportedModes: [
|
|
83
|
+
{ label: 'Idle', mode: 0, modeTags: [{ value: 16384 }] },
|
|
84
|
+
{ label: 'Cleaning', mode: 1, modeTags: [{ value: 16385 }] },
|
|
85
|
+
],
|
|
86
|
+
currentMode: 0,
|
|
87
|
+
},
|
|
88
|
+
rvcCleanMode: {
|
|
89
|
+
supportedModes: [
|
|
90
|
+
{ label: 'Vacuum', mode: 0, modeTags: [{ value: 16385 }] },
|
|
91
|
+
],
|
|
92
|
+
currentMode: 0,
|
|
93
|
+
},
|
|
94
|
+
rvcOperationalState: {
|
|
95
|
+
operationalStateList: [
|
|
96
|
+
{ operationalStateId: 0 }, // Stopped
|
|
97
|
+
{ operationalStateId: 1 }, // Running
|
|
98
|
+
{ operationalStateId: 2 }, // Paused
|
|
99
|
+
{ operationalStateId: 3 }, // Error (required)
|
|
100
|
+
{ operationalStateId: 64 }, // Seeking charger
|
|
101
|
+
{ operationalStateId: 65 }, // Charging
|
|
102
|
+
{ operationalStateId: 66 }, // Docked
|
|
103
|
+
],
|
|
104
|
+
operationalState: 66,
|
|
105
|
+
},
|
|
106
|
+
}, // Switch in HAP, RobotVacuumCleaner in Matter
|
|
107
|
+
curtain: {
|
|
108
|
+
windowCovering: {
|
|
109
|
+
currentPositionLiftPercent100ths: 0,
|
|
110
|
+
targetPositionLiftPercent100ths: 0,
|
|
111
|
+
operationalStatus: {
|
|
112
|
+
global: 0,
|
|
113
|
+
lift: 0,
|
|
114
|
+
tilt: 0,
|
|
115
|
+
},
|
|
116
|
+
endProductType: 0,
|
|
117
|
+
configStatus: {
|
|
118
|
+
operational: true,
|
|
119
|
+
onlineReserved: true,
|
|
120
|
+
liftMovementReversed: false,
|
|
121
|
+
liftPositionAware: true,
|
|
122
|
+
tiltPositionAware: false,
|
|
123
|
+
liftEncoderControlled: true,
|
|
124
|
+
tiltEncoderControlled: false,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
}, // WindowCovering → WindowCovering (includes curtain3, rollershade variants via normalization)
|
|
128
|
+
blindtilt: {
|
|
129
|
+
windowCovering: {
|
|
130
|
+
currentPositionLiftPercent100ths: 0,
|
|
131
|
+
targetPositionLiftPercent100ths: 0,
|
|
132
|
+
currentPositionTiltPercent100ths: 0,
|
|
133
|
+
targetPositionTiltPercent100ths: 0,
|
|
134
|
+
operationalStatus: {
|
|
135
|
+
global: 0,
|
|
136
|
+
lift: 0,
|
|
137
|
+
tilt: 0,
|
|
138
|
+
},
|
|
139
|
+
endProductType: 8,
|
|
140
|
+
configStatus: {
|
|
141
|
+
operational: true,
|
|
142
|
+
onlineReserved: true,
|
|
143
|
+
liftMovementReversed: false,
|
|
144
|
+
liftPositionAware: true,
|
|
145
|
+
tiltPositionAware: true,
|
|
146
|
+
liftEncoderControlled: true,
|
|
147
|
+
tiltEncoderControlled: true,
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
}, // WindowCovering with tilt → WindowCovering
|
|
151
|
+
fan: {
|
|
152
|
+
onOff: { onOff: false },
|
|
153
|
+
fanControl: {
|
|
154
|
+
fanMode: 0,
|
|
155
|
+
percentCurrent: 0,
|
|
156
|
+
percentSetting: 0,
|
|
157
|
+
speedCurrent: 0,
|
|
158
|
+
speedMax: 100,
|
|
159
|
+
},
|
|
160
|
+
}, // Fan → OnOff + FanControl
|
|
161
|
+
light: {
|
|
162
|
+
onOff: { onOff: false },
|
|
163
|
+
levelControl: {
|
|
164
|
+
currentLevel: 0,
|
|
165
|
+
minLevel: 0,
|
|
166
|
+
maxLevel: 254,
|
|
167
|
+
},
|
|
168
|
+
}, // Lightbulb → OnOff + LevelControl
|
|
169
|
+
lightstrip: {
|
|
170
|
+
onOff: { onOff: false },
|
|
171
|
+
levelControl: {
|
|
172
|
+
currentLevel: 0,
|
|
173
|
+
minLevel: 0,
|
|
174
|
+
maxLevel: 254,
|
|
175
|
+
},
|
|
176
|
+
colorControl: {
|
|
177
|
+
colorMode: 0,
|
|
178
|
+
},
|
|
179
|
+
}, // Lightbulb with color → OnOff + LevelControl + ColorControl
|
|
180
|
+
lock: {
|
|
181
|
+
doorLock: {
|
|
182
|
+
lockState: 0,
|
|
183
|
+
lockType: 0,
|
|
184
|
+
actuatorEnabled: true,
|
|
185
|
+
operatingMode: 0,
|
|
186
|
+
},
|
|
187
|
+
}, // LockMechanism → DoorLock
|
|
188
|
+
motion: {
|
|
189
|
+
occupancySensing: {
|
|
190
|
+
occupancy: 0,
|
|
191
|
+
occupancySensorType: 0,
|
|
192
|
+
},
|
|
193
|
+
}, // MotionSensor → OccupancySensing
|
|
194
|
+
contact: {
|
|
195
|
+
booleanState: {
|
|
196
|
+
stateValue: false,
|
|
197
|
+
},
|
|
198
|
+
}, // ContactSensor → BooleanState
|
|
199
|
+
humidifier: {
|
|
200
|
+
onOff: { onOff: false },
|
|
201
|
+
fanControl: {
|
|
202
|
+
fanMode: 0,
|
|
203
|
+
percentCurrent: 0,
|
|
204
|
+
},
|
|
205
|
+
relativeHumidityMeasurement: {
|
|
206
|
+
measuredValue: 0,
|
|
207
|
+
minMeasuredValue: 0,
|
|
208
|
+
maxMeasuredValue: 100,
|
|
209
|
+
},
|
|
210
|
+
}, // HumidifierDehumidifier → OnOff + FanControl + RelativeHumidityMeasurement
|
|
211
|
+
temperature: {
|
|
212
|
+
temperatureMeasurement: {
|
|
213
|
+
measuredValue: 0,
|
|
214
|
+
minMeasuredValue: -27315,
|
|
215
|
+
maxMeasuredValue: 32767,
|
|
216
|
+
},
|
|
217
|
+
}, // TemperatureSensor → TemperatureMeasurement
|
|
218
|
+
// Switch/Outlet devices
|
|
219
|
+
relay: { onOff: { onOff: false } }, // Switch → OnOff
|
|
220
|
+
plug: {
|
|
221
|
+
onOff: { onOff: false },
|
|
222
|
+
electricalMeasurement: {
|
|
223
|
+
activePower: 0,
|
|
224
|
+
rmsCurrent: 0,
|
|
225
|
+
rmsVoltage: 0,
|
|
226
|
+
},
|
|
227
|
+
}, // Outlet → OnOff + ElectricalMeasurement (for PM models)
|
|
228
|
+
// Sensors
|
|
229
|
+
meter: {
|
|
230
|
+
temperatureMeasurement: {
|
|
231
|
+
measuredValue: 0,
|
|
232
|
+
minMeasuredValue: -27315,
|
|
233
|
+
maxMeasuredValue: 32767,
|
|
234
|
+
},
|
|
235
|
+
relativeHumidityMeasurement: {
|
|
236
|
+
measuredValue: 0,
|
|
237
|
+
minMeasuredValue: 0,
|
|
238
|
+
maxMeasuredValue: 100,
|
|
239
|
+
},
|
|
240
|
+
}, // TemperatureSensor + HumiditySensor → TemperatureMeasurement + RelativeHumidityMeasurement
|
|
241
|
+
waterdetector: {
|
|
242
|
+
booleanState: {
|
|
243
|
+
stateValue: false,
|
|
244
|
+
},
|
|
245
|
+
}, // LeakSensor → BooleanState
|
|
246
|
+
};
|
|
247
|
+
export function createMatterHandlers(log, deviceId, type, client) {
|
|
248
|
+
const lowerType = type.toLowerCase();
|
|
249
|
+
switch (lowerType) {
|
|
250
|
+
case 'vacuum':
|
|
251
|
+
return {
|
|
252
|
+
rvcRunMode: {
|
|
253
|
+
changeToMode: async (request) => {
|
|
254
|
+
const modeNames = ['Idle', 'Cleaning', 'Mapping'];
|
|
255
|
+
const modeName = modeNames[request?.newMode] || `Unknown (${request?.newMode})`;
|
|
256
|
+
log.info(`[${deviceId}] RVC run mode change requested: ${modeName}`);
|
|
257
|
+
if (!client) {
|
|
258
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
259
|
+
return { success: false };
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
// For K10+ family: use 'start' to begin cleaning (mode 1 = Cleaning)
|
|
263
|
+
// For older K10+: only supports start/stop/dock
|
|
264
|
+
// For newer K20+/S10/S20: supports startClean with more parameters
|
|
265
|
+
// Map Matter mode to SwitchBot command
|
|
266
|
+
const switchBotCommand = request?.newMode === 1 ? 'start' : 'stop';
|
|
267
|
+
const body = {
|
|
268
|
+
command: switchBotCommand,
|
|
269
|
+
parameter: 'default',
|
|
270
|
+
commandType: 'command',
|
|
271
|
+
};
|
|
272
|
+
log.debug(`[${deviceId}] Sending RVC mode change request:`, JSON.stringify(body));
|
|
273
|
+
const result = await client.setDeviceState(deviceId, body);
|
|
274
|
+
log.debug(`[${deviceId}] RVC mode change API response:`, JSON.stringify(result));
|
|
275
|
+
log.info(`[${deviceId}] RVC mode changed successfully to ${switchBotCommand}`);
|
|
276
|
+
return { success: true, result };
|
|
277
|
+
}
|
|
278
|
+
catch (e) {
|
|
279
|
+
log.error(`[${deviceId}] Failed to change RVC mode:`, e);
|
|
280
|
+
return { success: false, error: e };
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
rvcCleanMode: {
|
|
285
|
+
changeToMode: async (request) => {
|
|
286
|
+
const modeName = request?.newMode !== undefined ? `Mode ${request.newMode}` : 'Unknown';
|
|
287
|
+
log.info(`[${deviceId}] RVC clean mode change requested: ${modeName}`);
|
|
288
|
+
if (!client) {
|
|
289
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
290
|
+
return { success: false };
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
// Clean mode (vacuum/mop/etc) not directly supported via Matter for K10+
|
|
294
|
+
// K20+ Pro and newer models support via startClean action parameter
|
|
295
|
+
log.info(`[${deviceId}] Clean mode change requires startClean command (not yet implemented for Matter)`);
|
|
296
|
+
return { success: true };
|
|
297
|
+
}
|
|
298
|
+
catch (e) {
|
|
299
|
+
log.error(`[${deviceId}] Failed to change RVC clean mode:`, e);
|
|
300
|
+
return { success: false, error: e };
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
rvcOperationalState: {
|
|
305
|
+
pause: async () => {
|
|
306
|
+
log.info(`[${deviceId}] RVC pause command received`);
|
|
307
|
+
if (!client) {
|
|
308
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
309
|
+
return { success: false };
|
|
310
|
+
}
|
|
311
|
+
try {
|
|
312
|
+
const body = {
|
|
313
|
+
command: 'stop',
|
|
314
|
+
parameter: 'default',
|
|
315
|
+
commandType: 'command',
|
|
316
|
+
};
|
|
317
|
+
log.debug(`[${deviceId}] Sending RVC pause request:`, JSON.stringify(body));
|
|
318
|
+
const result = await client.setDeviceState(deviceId, body);
|
|
319
|
+
log.debug(`[${deviceId}] RVC pause API response:`, JSON.stringify(result));
|
|
320
|
+
log.info(`[${deviceId}] RVC paused successfully`);
|
|
321
|
+
return { success: true, result };
|
|
322
|
+
}
|
|
323
|
+
catch (e) {
|
|
324
|
+
log.error(`[${deviceId}] Failed to pause RVC:`, e);
|
|
325
|
+
return { success: false, error: e };
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
resume: async () => {
|
|
329
|
+
log.info(`[${deviceId}] RVC resume command received`);
|
|
330
|
+
if (!client) {
|
|
331
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
332
|
+
return { success: false };
|
|
333
|
+
}
|
|
334
|
+
try {
|
|
335
|
+
const body = {
|
|
336
|
+
command: 'start',
|
|
337
|
+
parameter: 'default',
|
|
338
|
+
commandType: 'command',
|
|
339
|
+
};
|
|
340
|
+
log.debug(`[${deviceId}] Sending RVC resume request:`, JSON.stringify(body));
|
|
341
|
+
const result = await client.setDeviceState(deviceId, body);
|
|
342
|
+
log.debug(`[${deviceId}] RVC resume API response:`, JSON.stringify(result));
|
|
343
|
+
log.info(`[${deviceId}] RVC resumed successfully`);
|
|
344
|
+
return { success: true, result };
|
|
345
|
+
}
|
|
346
|
+
catch (e) {
|
|
347
|
+
log.error(`[${deviceId}] Failed to resume RVC:`, e);
|
|
348
|
+
return { success: false, error: e };
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
goHome: async () => {
|
|
352
|
+
log.info(`[${deviceId}] RVC goHome command received`);
|
|
353
|
+
if (!client) {
|
|
354
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
355
|
+
return { success: false };
|
|
356
|
+
}
|
|
357
|
+
try {
|
|
358
|
+
const body = {
|
|
359
|
+
command: 'dock',
|
|
360
|
+
parameter: 'default',
|
|
361
|
+
commandType: 'command',
|
|
362
|
+
};
|
|
363
|
+
log.debug(`[${deviceId}] Sending RVC goHome request:`, JSON.stringify(body));
|
|
364
|
+
const result = await client.setDeviceState(deviceId, body);
|
|
365
|
+
log.debug(`[${deviceId}] RVC goHome API response:`, JSON.stringify(result));
|
|
366
|
+
log.info(`[${deviceId}] RVC sent to dock successfully`);
|
|
367
|
+
return { success: true, result };
|
|
368
|
+
}
|
|
369
|
+
catch (e) {
|
|
370
|
+
log.error(`[${deviceId}] Failed to send goHome command:`, e);
|
|
371
|
+
return { success: false, error: e };
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
case 'bot':
|
|
377
|
+
return {
|
|
378
|
+
onOff: {
|
|
379
|
+
on: async () => {
|
|
380
|
+
log.info(`[${deviceId}] Bot ON command received`);
|
|
381
|
+
if (!client) {
|
|
382
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
383
|
+
return { success: false };
|
|
384
|
+
}
|
|
385
|
+
try {
|
|
386
|
+
const result = await client.setDeviceState(deviceId, {
|
|
387
|
+
command: 'turnOn',
|
|
388
|
+
parameter: 'default',
|
|
389
|
+
commandType: 'command',
|
|
390
|
+
});
|
|
391
|
+
log.info(`[${deviceId}] Bot turned on successfully`);
|
|
392
|
+
return { success: true, result };
|
|
393
|
+
}
|
|
394
|
+
catch (e) {
|
|
395
|
+
log.error(`[${deviceId}] Failed to turn on Bot:`, e);
|
|
396
|
+
return { success: false, error: e };
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
off: async () => {
|
|
400
|
+
log.info(`[${deviceId}] Bot OFF command received`);
|
|
401
|
+
if (!client) {
|
|
402
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
403
|
+
return { success: false };
|
|
404
|
+
}
|
|
405
|
+
try {
|
|
406
|
+
const result = await client.setDeviceState(deviceId, {
|
|
407
|
+
command: 'turnOff',
|
|
408
|
+
parameter: 'default',
|
|
409
|
+
commandType: 'command',
|
|
410
|
+
});
|
|
411
|
+
log.info(`[${deviceId}] Bot turned off successfully`);
|
|
412
|
+
return { success: true, result };
|
|
413
|
+
}
|
|
414
|
+
catch (e) {
|
|
415
|
+
log.error(`[${deviceId}] Failed to turn off Bot:`, e);
|
|
416
|
+
return { success: false, error: e };
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
};
|
|
421
|
+
case 'curtain':
|
|
422
|
+
case 'blindtilt':
|
|
423
|
+
return {
|
|
424
|
+
windowCovering: {
|
|
425
|
+
goToLiftPercentage: async (request) => {
|
|
426
|
+
const percentage = request?.liftPercent100thsValue;
|
|
427
|
+
log.info(`[${deviceId}] Curtain position change requested: ${percentage}`);
|
|
428
|
+
if (!client) {
|
|
429
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
430
|
+
return { success: false };
|
|
431
|
+
}
|
|
432
|
+
try {
|
|
433
|
+
// Convert Matter percentage (0-10000) to SwitchBot (0-100)
|
|
434
|
+
const position = Math.max(0, Math.min(100, Math.round((percentage || 0) / 100)));
|
|
435
|
+
const result = await client.setDeviceState(deviceId, {
|
|
436
|
+
command: 'setPosition',
|
|
437
|
+
parameter: String(position),
|
|
438
|
+
commandType: 'command',
|
|
439
|
+
});
|
|
440
|
+
log.info(`[${deviceId}] Curtain position set to ${position}% successfully`);
|
|
441
|
+
return { success: true, result };
|
|
442
|
+
}
|
|
443
|
+
catch (e) {
|
|
444
|
+
log.error(`[${deviceId}] Failed to set curtain position:`, e);
|
|
445
|
+
return { success: false, error: e };
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
upOrOpen: async () => {
|
|
449
|
+
log.info(`[${deviceId}] Curtain open command received`);
|
|
450
|
+
if (!client) {
|
|
451
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
452
|
+
return { success: false };
|
|
453
|
+
}
|
|
454
|
+
try {
|
|
455
|
+
const result = await client.setDeviceState(deviceId, {
|
|
456
|
+
command: 'open',
|
|
457
|
+
parameter: 'default',
|
|
458
|
+
commandType: 'command',
|
|
459
|
+
});
|
|
460
|
+
log.info(`[${deviceId}] Curtain opened successfully`);
|
|
461
|
+
return { success: true, result };
|
|
462
|
+
}
|
|
463
|
+
catch (e) {
|
|
464
|
+
log.error(`[${deviceId}] Failed to open curtain:`, e);
|
|
465
|
+
return { success: false, error: e };
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
downOrClose: async () => {
|
|
469
|
+
log.info(`[${deviceId}] Curtain close command received`);
|
|
470
|
+
if (!client) {
|
|
471
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
472
|
+
return { success: false };
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
const result = await client.setDeviceState(deviceId, {
|
|
476
|
+
command: 'close',
|
|
477
|
+
parameter: 'default',
|
|
478
|
+
commandType: 'command',
|
|
479
|
+
});
|
|
480
|
+
log.info(`[${deviceId}] Curtain closed successfully`);
|
|
481
|
+
return { success: true, result };
|
|
482
|
+
}
|
|
483
|
+
catch (e) {
|
|
484
|
+
log.error(`[${deviceId}] Failed to close curtain:`, e);
|
|
485
|
+
return { success: false, error: e };
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
stopMotion: async () => {
|
|
489
|
+
log.info(`[${deviceId}] Curtain stop command received`);
|
|
490
|
+
if (!client) {
|
|
491
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
492
|
+
return { success: false };
|
|
493
|
+
}
|
|
494
|
+
try {
|
|
495
|
+
const result = await client.setDeviceState(deviceId, {
|
|
496
|
+
command: 'pause',
|
|
497
|
+
parameter: 'default',
|
|
498
|
+
commandType: 'command',
|
|
499
|
+
});
|
|
500
|
+
log.info(`[${deviceId}] Curtain motion stopped successfully`);
|
|
501
|
+
return { success: true, result };
|
|
502
|
+
}
|
|
503
|
+
catch (e) {
|
|
504
|
+
log.error(`[${deviceId}] Failed to stop curtain:`, e);
|
|
505
|
+
return { success: false, error: e };
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
case 'plug':
|
|
511
|
+
return {
|
|
512
|
+
onOff: {
|
|
513
|
+
on: async () => {
|
|
514
|
+
log.info(`[${deviceId}] Plug ON command received`);
|
|
515
|
+
if (!client) {
|
|
516
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
517
|
+
return { success: false };
|
|
518
|
+
}
|
|
519
|
+
try {
|
|
520
|
+
const result = await client.setDeviceState(deviceId, {
|
|
521
|
+
command: 'turnOn',
|
|
522
|
+
parameter: 'default',
|
|
523
|
+
commandType: 'command',
|
|
524
|
+
});
|
|
525
|
+
log.info(`[${deviceId}] Plug turned on successfully`);
|
|
526
|
+
return { success: true, result };
|
|
527
|
+
}
|
|
528
|
+
catch (e) {
|
|
529
|
+
log.error(`[${deviceId}] Failed to turn on plug:`, e);
|
|
530
|
+
return { success: false, error: e };
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
off: async () => {
|
|
534
|
+
log.info(`[${deviceId}] Plug OFF command received`);
|
|
535
|
+
if (!client) {
|
|
536
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
537
|
+
return { success: false };
|
|
538
|
+
}
|
|
539
|
+
try {
|
|
540
|
+
const result = await client.setDeviceState(deviceId, {
|
|
541
|
+
command: 'turnOff',
|
|
542
|
+
parameter: 'default',
|
|
543
|
+
commandType: 'command',
|
|
544
|
+
});
|
|
545
|
+
log.info(`[${deviceId}] Plug turned off successfully`);
|
|
546
|
+
return { success: true, result };
|
|
547
|
+
}
|
|
548
|
+
catch (e) {
|
|
549
|
+
log.error(`[${deviceId}] Failed to turn off plug:`, e);
|
|
550
|
+
return { success: false, error: e };
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
case 'lock':
|
|
556
|
+
return {
|
|
557
|
+
doorLock: {
|
|
558
|
+
setLockState: async (request) => {
|
|
559
|
+
const state = request?.lockState === 1 ? 'LOCKED' : 'UNLOCKED';
|
|
560
|
+
log.info(`[${deviceId}] Lock state change requested: ${state}`);
|
|
561
|
+
if (!client) {
|
|
562
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
563
|
+
return { success: false };
|
|
564
|
+
}
|
|
565
|
+
try {
|
|
566
|
+
const command = request?.lockState === 1 ? 'lock' : 'unlock';
|
|
567
|
+
const result = await client.setDeviceState(deviceId, {
|
|
568
|
+
command,
|
|
569
|
+
parameter: 'default',
|
|
570
|
+
commandType: 'command',
|
|
571
|
+
});
|
|
572
|
+
log.info(`[${deviceId}] Lock ${state} successfully`);
|
|
573
|
+
return { success: true, result };
|
|
574
|
+
}
|
|
575
|
+
catch (e) {
|
|
576
|
+
log.error(`[${deviceId}] Failed to change lock state:`, e);
|
|
577
|
+
return { success: false, error: e };
|
|
578
|
+
}
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
};
|
|
582
|
+
case 'fan':
|
|
583
|
+
return {
|
|
584
|
+
onOff: {
|
|
585
|
+
on: async () => {
|
|
586
|
+
log.info(`[${deviceId}] Fan ON command received`);
|
|
587
|
+
if (!client) {
|
|
588
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
589
|
+
return { success: false };
|
|
590
|
+
}
|
|
591
|
+
try {
|
|
592
|
+
const result = await client.setDeviceState(deviceId, {
|
|
593
|
+
command: 'turnOn',
|
|
594
|
+
parameter: 'default',
|
|
595
|
+
commandType: 'command',
|
|
596
|
+
});
|
|
597
|
+
log.info(`[${deviceId}] Fan turned on successfully`);
|
|
598
|
+
return { success: true, result };
|
|
599
|
+
}
|
|
600
|
+
catch (e) {
|
|
601
|
+
log.error(`[${deviceId}] Failed to turn on fan:`, e);
|
|
602
|
+
return { success: false, error: e };
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
off: async () => {
|
|
606
|
+
log.info(`[${deviceId}] Fan OFF command received`);
|
|
607
|
+
if (!client) {
|
|
608
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
609
|
+
return { success: false };
|
|
610
|
+
}
|
|
611
|
+
try {
|
|
612
|
+
const result = await client.setDeviceState(deviceId, {
|
|
613
|
+
command: 'turnOff',
|
|
614
|
+
parameter: 'default',
|
|
615
|
+
commandType: 'command',
|
|
616
|
+
});
|
|
617
|
+
log.info(`[${deviceId}] Fan turned off successfully`);
|
|
618
|
+
return { success: true, result };
|
|
619
|
+
}
|
|
620
|
+
catch (e) {
|
|
621
|
+
log.error(`[${deviceId}] Failed to turn off fan:`, e);
|
|
622
|
+
return { success: false, error: e };
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
},
|
|
626
|
+
fanControl: {
|
|
627
|
+
setFanSpeed: async (request) => {
|
|
628
|
+
const speed = request?.percentSetting || 0;
|
|
629
|
+
log.info(`[${deviceId}] Fan speed change requested: ${speed}%`);
|
|
630
|
+
if (!client) {
|
|
631
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
632
|
+
return { success: false };
|
|
633
|
+
}
|
|
634
|
+
try {
|
|
635
|
+
// Convert percentage to SwitchBot fan speed parameter
|
|
636
|
+
const speedParam = Math.max(1, Math.min(100, speed));
|
|
637
|
+
const result = await client.setDeviceState(deviceId, {
|
|
638
|
+
command: 'setFanSpeed',
|
|
639
|
+
parameter: String(speedParam),
|
|
640
|
+
commandType: 'command',
|
|
641
|
+
});
|
|
642
|
+
log.info(`[${deviceId}] Fan speed set to ${speedParam}% successfully`);
|
|
643
|
+
return { success: true, result };
|
|
644
|
+
}
|
|
645
|
+
catch (e) {
|
|
646
|
+
log.error(`[${deviceId}] Failed to set fan speed:`, e);
|
|
647
|
+
return { success: false, error: e };
|
|
648
|
+
}
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
};
|
|
652
|
+
case 'light':
|
|
653
|
+
return {
|
|
654
|
+
onOff: {
|
|
655
|
+
on: async () => {
|
|
656
|
+
log.info(`[${deviceId}] Light ON command received`);
|
|
657
|
+
if (!client) {
|
|
658
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
659
|
+
return { success: false };
|
|
660
|
+
}
|
|
661
|
+
try {
|
|
662
|
+
const result = await client.setDeviceState(deviceId, {
|
|
663
|
+
command: 'turnOn',
|
|
664
|
+
parameter: 'default',
|
|
665
|
+
commandType: 'command',
|
|
666
|
+
});
|
|
667
|
+
log.info(`[${deviceId}] Light turned on successfully`);
|
|
668
|
+
return { success: true, result };
|
|
669
|
+
}
|
|
670
|
+
catch (e) {
|
|
671
|
+
log.error(`[${deviceId}] Failed to turn on light:`, e);
|
|
672
|
+
return { success: false, error: e };
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
off: async () => {
|
|
676
|
+
log.info(`[${deviceId}] Light OFF command received`);
|
|
677
|
+
if (!client) {
|
|
678
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
679
|
+
return { success: false };
|
|
680
|
+
}
|
|
681
|
+
try {
|
|
682
|
+
const result = await client.setDeviceState(deviceId, {
|
|
683
|
+
command: 'turnOff',
|
|
684
|
+
parameter: 'default',
|
|
685
|
+
commandType: 'command',
|
|
686
|
+
});
|
|
687
|
+
log.info(`[${deviceId}] Light turned off successfully`);
|
|
688
|
+
return { success: true, result };
|
|
689
|
+
}
|
|
690
|
+
catch (e) {
|
|
691
|
+
log.error(`[${deviceId}] Failed to turn off light:`, e);
|
|
692
|
+
return { success: false, error: e };
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
levelControl: {
|
|
697
|
+
moveToLevel: async (request) => {
|
|
698
|
+
const level = request?.level || 0;
|
|
699
|
+
// Convert from 0-254 to 0-100
|
|
700
|
+
const brightness = Math.round((level / 254) * 100);
|
|
701
|
+
log.info(`[${deviceId}] Light brightness change requested: ${brightness}%`);
|
|
702
|
+
if (!client) {
|
|
703
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
704
|
+
return { success: false };
|
|
705
|
+
}
|
|
706
|
+
try {
|
|
707
|
+
const param = Math.max(0, Math.min(100, brightness));
|
|
708
|
+
const result = await client.setDeviceState(deviceId, {
|
|
709
|
+
command: 'setBrightness',
|
|
710
|
+
parameter: String(param),
|
|
711
|
+
commandType: 'command',
|
|
712
|
+
});
|
|
713
|
+
log.info(`[${deviceId}] Light brightness set to ${param}% successfully`);
|
|
714
|
+
return { success: true, result };
|
|
715
|
+
}
|
|
716
|
+
catch (e) {
|
|
717
|
+
log.error(`[${deviceId}] Failed to set light brightness:`, e);
|
|
718
|
+
return { success: false, error: e };
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
};
|
|
723
|
+
case 'lightstrip':
|
|
724
|
+
return {
|
|
725
|
+
onOff: {
|
|
726
|
+
on: async () => {
|
|
727
|
+
log.info(`[${deviceId}] Lightstrip ON command received`);
|
|
728
|
+
if (!client) {
|
|
729
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
730
|
+
return { success: false };
|
|
731
|
+
}
|
|
732
|
+
try {
|
|
733
|
+
const result = await client.setDeviceState(deviceId, {
|
|
734
|
+
command: 'turnOn',
|
|
735
|
+
parameter: 'default',
|
|
736
|
+
commandType: 'command',
|
|
737
|
+
});
|
|
738
|
+
log.info(`[${deviceId}] Lightstrip turned on successfully`);
|
|
739
|
+
return { success: true, result };
|
|
740
|
+
}
|
|
741
|
+
catch (e) {
|
|
742
|
+
log.error(`[${deviceId}] Failed to turn on lightstrip:`, e);
|
|
743
|
+
return { success: false, error: e };
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
off: async () => {
|
|
747
|
+
log.info(`[${deviceId}] Lightstrip OFF command received`);
|
|
748
|
+
if (!client) {
|
|
749
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
750
|
+
return { success: false };
|
|
751
|
+
}
|
|
752
|
+
try {
|
|
753
|
+
const result = await client.setDeviceState(deviceId, {
|
|
754
|
+
command: 'turnOff',
|
|
755
|
+
parameter: 'default',
|
|
756
|
+
commandType: 'command',
|
|
757
|
+
});
|
|
758
|
+
log.info(`[${deviceId}] Lightstrip turned off successfully`);
|
|
759
|
+
return { success: true, result };
|
|
760
|
+
}
|
|
761
|
+
catch (e) {
|
|
762
|
+
log.error(`[${deviceId}] Failed to turn off lightstrip:`, e);
|
|
763
|
+
return { success: false, error: e };
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
},
|
|
767
|
+
levelControl: {
|
|
768
|
+
moveToLevel: async (request) => {
|
|
769
|
+
const level = request?.level || 0;
|
|
770
|
+
// Convert from 0-254 to 0-100
|
|
771
|
+
const brightness = Math.round((level / 254) * 100);
|
|
772
|
+
log.info(`[${deviceId}] Lightstrip brightness change requested: ${brightness}%`);
|
|
773
|
+
if (!client) {
|
|
774
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
775
|
+
return { success: false };
|
|
776
|
+
}
|
|
777
|
+
try {
|
|
778
|
+
const param = Math.max(0, Math.min(100, brightness));
|
|
779
|
+
const result = await client.setDeviceState(deviceId, {
|
|
780
|
+
command: 'setBrightness',
|
|
781
|
+
parameter: String(param),
|
|
782
|
+
commandType: 'command',
|
|
783
|
+
});
|
|
784
|
+
log.info(`[${deviceId}] Lightstrip brightness set to ${param}% successfully`);
|
|
785
|
+
return { success: true, result };
|
|
786
|
+
}
|
|
787
|
+
catch (e) {
|
|
788
|
+
log.error(`[${deviceId}] Failed to set lightstrip brightness:`, e);
|
|
789
|
+
return { success: false, error: e };
|
|
790
|
+
}
|
|
791
|
+
},
|
|
792
|
+
},
|
|
793
|
+
colorControl: {
|
|
794
|
+
moveToHueAndSaturation: async (request) => {
|
|
795
|
+
const hue = request?.hue || 0;
|
|
796
|
+
const saturation = request?.saturation || 0;
|
|
797
|
+
log.info(`[${deviceId}] Lightstrip color change requested: hue=${hue}, sat=${saturation}`);
|
|
798
|
+
if (!client) {
|
|
799
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
800
|
+
return { success: false };
|
|
801
|
+
}
|
|
802
|
+
try {
|
|
803
|
+
// Convert hue (0-254) and saturation (0-254) to combined color parameter
|
|
804
|
+
// SwitchBot typically expects RGB or HSV format as parameter
|
|
805
|
+
const colorParam = `${Math.round(hue)},${Math.round(saturation)}`;
|
|
806
|
+
const result = await client.setDeviceState(deviceId, {
|
|
807
|
+
command: 'setColor',
|
|
808
|
+
parameter: colorParam,
|
|
809
|
+
commandType: 'command',
|
|
810
|
+
});
|
|
811
|
+
log.info(`[${deviceId}] Lightstrip color set successfully`);
|
|
812
|
+
return { success: true, result };
|
|
813
|
+
}
|
|
814
|
+
catch (e) {
|
|
815
|
+
log.error(`[${deviceId}] Failed to set lightstrip color:`, e);
|
|
816
|
+
return { success: false, error: e };
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
moveToColorTemperature: async (request) => {
|
|
820
|
+
const mireds = request?.colorTemperatureMireds || 400;
|
|
821
|
+
// Convert mireds (158-500 typical range) to Kelvin: K = 1000000 / mireds
|
|
822
|
+
const kelvin = Math.round(1000000 / mireds);
|
|
823
|
+
log.info(`[${deviceId}] Lightstrip color temperature change requested: ${mireds} mireds (${kelvin}K)`);
|
|
824
|
+
if (!client) {
|
|
825
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
826
|
+
return { success: false };
|
|
827
|
+
}
|
|
828
|
+
try {
|
|
829
|
+
// Map Kelvin to SwitchBot color temperature parameter (typically 0-100 or specific values)
|
|
830
|
+
// Normalize to 0-100 scale where 0=warm (2700K) and 100=cool (6500K)
|
|
831
|
+
const colorTempParam = Math.max(0, Math.min(100, Math.round(((kelvin - 2700) / 3800) * 100)));
|
|
832
|
+
const result = await client.setDeviceState(deviceId, {
|
|
833
|
+
command: 'setColorTemperature',
|
|
834
|
+
parameter: String(colorTempParam),
|
|
835
|
+
commandType: 'command',
|
|
836
|
+
});
|
|
837
|
+
log.info(`[${deviceId}] Lightstrip color temperature set to ${kelvin}K successfully`);
|
|
838
|
+
return { success: true, result };
|
|
839
|
+
}
|
|
840
|
+
catch (e) {
|
|
841
|
+
log.error(`[${deviceId}] Failed to set lightstrip color temperature:`, e);
|
|
842
|
+
return { success: false, error: e };
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
},
|
|
846
|
+
};
|
|
847
|
+
case 'humidifier':
|
|
848
|
+
return {
|
|
849
|
+
onOff: {
|
|
850
|
+
on: async () => {
|
|
851
|
+
log.info(`[${deviceId}] Humidifier ON command received`);
|
|
852
|
+
if (!client) {
|
|
853
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
854
|
+
return { success: false };
|
|
855
|
+
}
|
|
856
|
+
try {
|
|
857
|
+
const result = await client.setDeviceState(deviceId, {
|
|
858
|
+
command: 'turnOn',
|
|
859
|
+
parameter: 'default',
|
|
860
|
+
commandType: 'command',
|
|
861
|
+
});
|
|
862
|
+
log.info(`[${deviceId}] Humidifier turned on successfully`);
|
|
863
|
+
return { success: true, result };
|
|
864
|
+
}
|
|
865
|
+
catch (e) {
|
|
866
|
+
log.error(`[${deviceId}] Failed to turn on humidifier:`, e);
|
|
867
|
+
return { success: false, error: e };
|
|
868
|
+
}
|
|
869
|
+
},
|
|
870
|
+
off: async () => {
|
|
871
|
+
log.info(`[${deviceId}] Humidifier OFF command received`);
|
|
872
|
+
if (!client) {
|
|
873
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
874
|
+
return { success: false };
|
|
875
|
+
}
|
|
876
|
+
try {
|
|
877
|
+
const result = await client.setDeviceState(deviceId, {
|
|
878
|
+
command: 'turnOff',
|
|
879
|
+
parameter: 'default',
|
|
880
|
+
commandType: 'command',
|
|
881
|
+
});
|
|
882
|
+
log.info(`[${deviceId}] Humidifier turned off successfully`);
|
|
883
|
+
return { success: true, result };
|
|
884
|
+
}
|
|
885
|
+
catch (e) {
|
|
886
|
+
log.error(`[${deviceId}] Failed to turn off humidifier:`, e);
|
|
887
|
+
return { success: false, error: e };
|
|
888
|
+
}
|
|
889
|
+
},
|
|
890
|
+
},
|
|
891
|
+
fanControl: {
|
|
892
|
+
setFanSpeed: async (request) => {
|
|
893
|
+
const speed = request?.percentSetting || 0;
|
|
894
|
+
log.info(`[${deviceId}] Humidifier speed change requested: ${speed}%`);
|
|
895
|
+
if (!client) {
|
|
896
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
897
|
+
return { success: false };
|
|
898
|
+
}
|
|
899
|
+
try {
|
|
900
|
+
// Convert percentage to SwitchBot humidifier speed parameter
|
|
901
|
+
const speedParam = Math.max(1, Math.min(100, speed));
|
|
902
|
+
const result = await client.setDeviceState(deviceId, {
|
|
903
|
+
command: 'setFanSpeed',
|
|
904
|
+
parameter: String(speedParam),
|
|
905
|
+
commandType: 'command',
|
|
906
|
+
});
|
|
907
|
+
log.info(`[${deviceId}] Humidifier speed set to ${speedParam}% successfully`);
|
|
908
|
+
return { success: true, result };
|
|
909
|
+
}
|
|
910
|
+
catch (e) {
|
|
911
|
+
log.error(`[${deviceId}] Failed to set humidifier speed:`, e);
|
|
912
|
+
return { success: false, error: e };
|
|
913
|
+
}
|
|
914
|
+
},
|
|
915
|
+
},
|
|
916
|
+
};
|
|
917
|
+
case 'relay':
|
|
918
|
+
return {
|
|
919
|
+
onOff: {
|
|
920
|
+
on: async () => {
|
|
921
|
+
log.info(`[${deviceId}] Relay ON command received`);
|
|
922
|
+
if (!client) {
|
|
923
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
924
|
+
return { success: false };
|
|
925
|
+
}
|
|
926
|
+
try {
|
|
927
|
+
const result = await client.setDeviceState(deviceId, {
|
|
928
|
+
command: 'turnOn',
|
|
929
|
+
parameter: 'default',
|
|
930
|
+
commandType: 'command',
|
|
931
|
+
});
|
|
932
|
+
log.info(`[${deviceId}] Relay turned on successfully`);
|
|
933
|
+
return { success: true, result };
|
|
934
|
+
}
|
|
935
|
+
catch (e) {
|
|
936
|
+
log.error(`[${deviceId}] Failed to turn on relay:`, e);
|
|
937
|
+
return { success: false, error: e };
|
|
938
|
+
}
|
|
939
|
+
},
|
|
940
|
+
off: async () => {
|
|
941
|
+
log.info(`[${deviceId}] Relay OFF command received`);
|
|
942
|
+
if (!client) {
|
|
943
|
+
log.warn(`[${deviceId}] No SwitchBot client available`);
|
|
944
|
+
return { success: false };
|
|
945
|
+
}
|
|
946
|
+
try {
|
|
947
|
+
const result = await client.setDeviceState(deviceId, {
|
|
948
|
+
command: 'turnOff',
|
|
949
|
+
parameter: 'default',
|
|
950
|
+
commandType: 'command',
|
|
951
|
+
});
|
|
952
|
+
log.info(`[${deviceId}] Relay turned off successfully`);
|
|
953
|
+
return { success: true, result };
|
|
954
|
+
}
|
|
955
|
+
catch (e) {
|
|
956
|
+
log.error(`[${deviceId}] Failed to turn off relay:`, e);
|
|
957
|
+
return { success: false, error: e };
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
},
|
|
961
|
+
};
|
|
962
|
+
default:
|
|
963
|
+
return undefined;
|
|
31
964
|
}
|
|
32
|
-
return humidity;
|
|
33
965
|
}
|
|
34
966
|
/**
|
|
35
|
-
*
|
|
967
|
+
* Resolves the Matter device type for a given device, using the Matter API and device type mappings.
|
|
968
|
+
* Used to map normalized device types to Matter device type definitions.
|
|
969
|
+
*
|
|
970
|
+
* @param matterApi - The Matter API object containing deviceTypes
|
|
971
|
+
* @param type - The normalized device type string
|
|
972
|
+
* @param createdDeviceType - Optionally, an already created device type object
|
|
973
|
+
* @param clusters - Optionally, the clusters object for the device
|
|
974
|
+
* @returns The resolved Matter device type object
|
|
36
975
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
976
|
+
const DEVICE_MATTER_DEVICE_TYPE_KEYS = {
|
|
977
|
+
bot: 'OnOffSwitch',
|
|
978
|
+
vacuum: 'RoboticVacuumCleaner',
|
|
979
|
+
curtain: 'WindowCovering',
|
|
980
|
+
blindtilt: 'WindowCovering',
|
|
981
|
+
fan: 'Fan',
|
|
982
|
+
light: 'DimmableLight',
|
|
983
|
+
lightstrip: 'ExtendedColorLight',
|
|
984
|
+
lock: 'DoorLock',
|
|
985
|
+
motion: 'MotionSensor',
|
|
986
|
+
contact: 'ContactSensor',
|
|
987
|
+
humidifier: 'Fan',
|
|
988
|
+
temperature: 'TemperatureSensor',
|
|
989
|
+
relay: 'OnOffSwitch',
|
|
990
|
+
plug: 'OnOffOutlet',
|
|
991
|
+
meter: 'TemperatureSensor',
|
|
992
|
+
waterdetector: 'LeakSensor',
|
|
993
|
+
};
|
|
994
|
+
export function resolveMatterDeviceType(matterApi, type, createdDeviceType, clusters) {
|
|
995
|
+
if (createdDeviceType && typeof createdDeviceType === 'object' && typeof createdDeviceType.with === 'function') {
|
|
996
|
+
return createdDeviceType;
|
|
40
997
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
998
|
+
const lowerType = (typeof createdDeviceType === 'string' && createdDeviceType) ? createdDeviceType.toLowerCase() : (type || '').toLowerCase();
|
|
999
|
+
// Cluster-based upgrade for color lights if descriptor omitted device type.
|
|
1000
|
+
const hasColorControl = !!clusters?.colorControl;
|
|
1001
|
+
const inferredType = hasColorControl && lowerType === 'light'
|
|
1002
|
+
? 'lightstrip'
|
|
1003
|
+
: lowerType;
|
|
1004
|
+
const mappedKey = DEVICE_MATTER_DEVICE_TYPE_KEYS[inferredType] || 'OnOffSwitch';
|
|
1005
|
+
return matterApi?.deviceTypes?.[mappedKey] || matterApi?.deviceTypes?.OnOffSwitch;
|
|
46
1006
|
}
|
|
47
1007
|
/**
|
|
48
|
-
*
|
|
1008
|
+
* Canonical Matter cluster ID mapping (from matter.js clusters).
|
|
1009
|
+
* Maps cluster names to their numeric cluster IDs.
|
|
49
1010
|
*
|
|
50
|
-
* @
|
|
51
|
-
*
|
|
1011
|
+
* @example
|
|
1012
|
+
* MATTER_CLUSTER_IDS.OnOff // 0x0006
|
|
52
1013
|
*/
|
|
53
|
-
export
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return value;
|
|
63
|
-
}, ' ');
|
|
64
|
-
}
|
|
1014
|
+
export const MATTER_CLUSTER_IDS = {
|
|
1015
|
+
OnOff: 0x0006,
|
|
1016
|
+
LevelControl: 0x0008,
|
|
1017
|
+
ColorControl: 0x0300,
|
|
1018
|
+
WindowCovering: 0x0102,
|
|
1019
|
+
DoorLock: 0x0101,
|
|
1020
|
+
FanControl: 0x0202,
|
|
1021
|
+
RelativeHumidityMeasurement: 0x0405,
|
|
1022
|
+
};
|
|
65
1023
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
1024
|
+
* Common Matter attribute IDs grouped by cluster.
|
|
1025
|
+
* Maps cluster names to objects mapping attribute names to their numeric attribute IDs.
|
|
1026
|
+
*
|
|
1027
|
+
* @example
|
|
1028
|
+
* MATTER_ATTRIBUTE_IDS.OnOff.OnOff // 0x0000
|
|
1029
|
+
*/
|
|
1030
|
+
export const MATTER_ATTRIBUTE_IDS = {
|
|
1031
|
+
OnOff: { OnOff: 0x0000 },
|
|
1032
|
+
LevelControl: { CurrentLevel: 0x0000 },
|
|
1033
|
+
ColorControl: { CurrentHue: 0x0000, CurrentSaturation: 0x0001, ColorTemperatureMireds: 0x0002 },
|
|
1034
|
+
WindowCovering: { CurrentPosition: 0x0000, TargetPosition: 0x0001 },
|
|
1035
|
+
FanControl: { SpeedCurrent: 0x0000 },
|
|
1036
|
+
DoorLock: { LockState: 0x0000 },
|
|
1037
|
+
RelativeHumidityMeasurement: { MeasuredValue: 0x0000 },
|
|
1038
|
+
};
|
|
1039
|
+
/**
|
|
1040
|
+
* Normalizes a device type string for Matter integration.
|
|
1041
|
+
* Maps various device type aliases and variants to canonical Matter device types.
|
|
1042
|
+
*
|
|
1043
|
+
* @param {string | undefined | null} typeValue - The device type string to normalize.
|
|
1044
|
+
* @returns {string} The normalized device type string for Matter.
|
|
68
1045
|
*
|
|
69
|
-
* @
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
1046
|
+
* @example
|
|
1047
|
+
* normalizeTypeForMatter('wosweeper') // 'vacuum'
|
|
1048
|
+
* normalizeTypeForMatter('curtain3') // 'curtain'
|
|
1049
|
+
* normalizeTypeForMatter('plug mini (us)') // 'plug'
|
|
73
1050
|
*/
|
|
74
|
-
export function
|
|
75
|
-
|
|
76
|
-
|
|
1051
|
+
export function normalizeTypeForMatter(typeValue) {
|
|
1052
|
+
const raw = String(typeValue || '').trim().toLowerCase();
|
|
1053
|
+
if (!raw) {
|
|
1054
|
+
return 'unknown';
|
|
77
1055
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const vacuumFormatRegex = /^[a-z0-9]{12,18}$/i;
|
|
82
|
-
// Check if the deviceId is already in a valid MAC address format
|
|
83
|
-
if (macAddressRegex.test(deviceId)) {
|
|
84
|
-
return cassSensative ? deviceId : deviceId.toLowerCase();
|
|
1056
|
+
// Vacuum variants
|
|
1057
|
+
if (['wosweeper', 'wosweepermini', 'wosweeperminipro', 'k10+', 'k10+ pro'].includes(raw)) {
|
|
1058
|
+
return 'vacuum';
|
|
85
1059
|
}
|
|
86
|
-
//
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
return cassSensative ? formattedDeviceId : formattedDeviceId.toLowerCase();
|
|
1060
|
+
// Window covering variants
|
|
1061
|
+
if (['curtain', 'curtain3', 'rollershade', 'roller shade', 'worollershade', 'wo rollershade'].includes(raw)) {
|
|
1062
|
+
return 'curtain';
|
|
90
1063
|
}
|
|
91
|
-
//
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
return cassSensative ? formattedDeviceId : formattedDeviceId.toLowerCase();
|
|
1064
|
+
// Blind tilt variants (normalized to 'blindtilt' for Matter since it uses tilt-capable cluster)
|
|
1065
|
+
if (['blindtilt', 'blind tilt'].includes(raw)) {
|
|
1066
|
+
return 'blindtilt';
|
|
95
1067
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Credit:
|
|
101
|
-
* https://github.com/WickyNilliams/pure-color
|
|
102
|
-
*/
|
|
103
|
-
r = Number.parseInt(r);
|
|
104
|
-
g = Number.parseInt(g);
|
|
105
|
-
b = Number.parseInt(b);
|
|
106
|
-
const min = Math.min(r, g, b);
|
|
107
|
-
const max = Math.max(r, g, b);
|
|
108
|
-
const delta = max - min;
|
|
109
|
-
let h;
|
|
110
|
-
let s;
|
|
111
|
-
if (max === 0) {
|
|
112
|
-
s = 0;
|
|
1068
|
+
// Plug variants
|
|
1069
|
+
if (['plug mini (jp)', 'plug mini (us)', 'plug mini (eu)'].includes(raw)) {
|
|
1070
|
+
return 'plug';
|
|
113
1071
|
}
|
|
114
|
-
|
|
115
|
-
|
|
1072
|
+
// Meter variants
|
|
1073
|
+
if (['meterplus', 'meter plus', 'meter plus (jp)', 'meterpro', 'meter pro', 'meterpro(co2)', 'meter pro (co2)'].includes(raw)) {
|
|
1074
|
+
return 'meter';
|
|
116
1075
|
}
|
|
117
|
-
|
|
118
|
-
|
|
1076
|
+
// Relay switch variants
|
|
1077
|
+
if (['relay switch 1', 'relay switch 1pm'].includes(raw)) {
|
|
1078
|
+
return 'relay';
|
|
119
1079
|
}
|
|
120
|
-
|
|
121
|
-
|
|
1080
|
+
// Water detector variants
|
|
1081
|
+
if (['water detector', 'waterdetector'].includes(raw)) {
|
|
1082
|
+
return 'waterdetector';
|
|
122
1083
|
}
|
|
123
|
-
|
|
124
|
-
|
|
1084
|
+
// Fan variants
|
|
1085
|
+
if (['smart fan', 'circulator fan', 'battery circulator fan', 'standing circulator fan'].includes(raw)) {
|
|
1086
|
+
return 'fan';
|
|
125
1087
|
}
|
|
126
|
-
|
|
127
|
-
|
|
1088
|
+
// Light variants
|
|
1089
|
+
if (['strip light', 'strip light 3', 'rgbic neon rope light', 'rgbic neon wire rope light', 'rgbicww floor lamp', 'rgbicww strip light'].includes(raw)) {
|
|
1090
|
+
return 'lightstrip';
|
|
128
1091
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
h += 360;
|
|
1092
|
+
if (['color bulb', 'ceiling light', 'ceiling light pro', 'candle warmer lamp', 'floor lamp'].includes(raw)) {
|
|
1093
|
+
return 'light';
|
|
132
1094
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
/*
|
|
137
|
-
Credit:
|
|
138
|
-
https://github.com/WickyNilliams/pure-color
|
|
139
|
-
*/
|
|
140
|
-
h = Number.parseInt(h) / 60;
|
|
141
|
-
s = Number.parseInt(s) / 100;
|
|
142
|
-
const f = h - Math.floor(h);
|
|
143
|
-
const p = 255 * (1 - s);
|
|
144
|
-
const q = 255 * (1 - s * f);
|
|
145
|
-
const t = 255 * (1 - s * (1 - f));
|
|
146
|
-
let rgb;
|
|
147
|
-
switch (Math.floor(h) % 6) {
|
|
148
|
-
case 0:
|
|
149
|
-
rgb = [255, t, p];
|
|
150
|
-
break;
|
|
151
|
-
case 1:
|
|
152
|
-
rgb = [q, 255, p];
|
|
153
|
-
break;
|
|
154
|
-
case 2:
|
|
155
|
-
rgb = [p, 255, t];
|
|
156
|
-
break;
|
|
157
|
-
case 3:
|
|
158
|
-
rgb = [p, q, 255];
|
|
159
|
-
break;
|
|
160
|
-
case 4:
|
|
161
|
-
rgb = [t, p, 255];
|
|
162
|
-
break;
|
|
163
|
-
case 5:
|
|
164
|
-
rgb = [255, p, q];
|
|
165
|
-
break;
|
|
1095
|
+
// Sensor variants
|
|
1096
|
+
if (raw === 'motion sensor') {
|
|
1097
|
+
return 'motion';
|
|
166
1098
|
}
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
rgb[2] *= 0.8;
|
|
170
|
-
if (rgb[1] <= 25 && rgb[2] <= 25) {
|
|
171
|
-
rgb[1] = 0;
|
|
172
|
-
rgb[2] = 0;
|
|
173
|
-
}
|
|
1099
|
+
if (['contact sensor', 'presence sensor'].includes(raw)) {
|
|
1100
|
+
return 'contact';
|
|
174
1101
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// Set kelvin to nearest 100, between 2000 and 7100
|
|
179
|
-
k = Math.round(k / 100) * 100;
|
|
180
|
-
k = Math.max(Math.min(k, 7100), 2000);
|
|
181
|
-
// k should now appear in our table of kelvin to rgb
|
|
182
|
-
const values = {
|
|
183
|
-
2000: [255, 141, 11],
|
|
184
|
-
2100: [255, 146, 29],
|
|
185
|
-
2200: [255, 147, 44],
|
|
186
|
-
2300: [255, 152, 54],
|
|
187
|
-
2400: [255, 157, 63],
|
|
188
|
-
2500: [255, 166, 69],
|
|
189
|
-
2600: [255, 170, 77],
|
|
190
|
-
2700: [255, 174, 84],
|
|
191
|
-
2800: [255, 173, 94],
|
|
192
|
-
2900: [255, 177, 101],
|
|
193
|
-
3000: [255, 180, 107],
|
|
194
|
-
3100: [255, 189, 111],
|
|
195
|
-
3200: [255, 187, 120],
|
|
196
|
-
3300: [255, 195, 124],
|
|
197
|
-
3400: [255, 198, 130],
|
|
198
|
-
3500: [255, 201, 135],
|
|
199
|
-
3600: [255, 203, 141],
|
|
200
|
-
3700: [255, 206, 146],
|
|
201
|
-
3800: [255, 204, 153],
|
|
202
|
-
3900: [255, 206, 159],
|
|
203
|
-
4000: [255, 213, 161],
|
|
204
|
-
4100: [255, 215, 166],
|
|
205
|
-
4200: [255, 217, 171],
|
|
206
|
-
4300: [255, 219, 175],
|
|
207
|
-
4400: [255, 221, 180],
|
|
208
|
-
4500: [255, 223, 184],
|
|
209
|
-
4600: [255, 225, 188],
|
|
210
|
-
4700: [255, 226, 192],
|
|
211
|
-
4800: [255, 228, 196],
|
|
212
|
-
4900: [255, 229, 200],
|
|
213
|
-
5000: [255, 231, 204],
|
|
214
|
-
5100: [255, 230, 210],
|
|
215
|
-
5200: [255, 234, 211],
|
|
216
|
-
5300: [255, 235, 215],
|
|
217
|
-
5400: [255, 237, 218],
|
|
218
|
-
5500: [255, 236, 224],
|
|
219
|
-
5700: [255, 240, 228],
|
|
220
|
-
5800: [255, 241, 231],
|
|
221
|
-
5900: [255, 243, 234],
|
|
222
|
-
6000: [255, 244, 237],
|
|
223
|
-
6100: [255, 245, 240],
|
|
224
|
-
6200: [255, 246, 243],
|
|
225
|
-
6300: [255, 247, 247],
|
|
226
|
-
6400: [255, 248, 251],
|
|
227
|
-
6500: [255, 249, 253],
|
|
228
|
-
6600: [254, 249, 255],
|
|
229
|
-
6700: [252, 247, 255],
|
|
230
|
-
6800: [249, 246, 255],
|
|
231
|
-
6900: [247, 245, 255],
|
|
232
|
-
7000: [245, 243, 255],
|
|
233
|
-
7100: [243, 242, 255],
|
|
234
|
-
};
|
|
235
|
-
// Return the value
|
|
236
|
-
return values[k];
|
|
237
|
-
}
|
|
238
|
-
export function m2hs(m) {
|
|
239
|
-
/*
|
|
240
|
-
Credit:
|
|
241
|
-
https://github.com/homebridge/HAP-NodeJS
|
|
242
|
-
*/
|
|
243
|
-
const table = {
|
|
244
|
-
100: [19, 222.1],
|
|
245
|
-
101: [18.7, 222.2],
|
|
246
|
-
102: [18.4, 222.3],
|
|
247
|
-
103: [18.2, 222.3],
|
|
248
|
-
104: [17.9, 222.4],
|
|
249
|
-
105: [17.6, 222.5],
|
|
250
|
-
106: [17.3, 222.7],
|
|
251
|
-
107: [17, 222.8],
|
|
252
|
-
108: [16.7, 222.9],
|
|
253
|
-
109: [16.4, 223],
|
|
254
|
-
110: [16.1, 223.2],
|
|
255
|
-
111: [15.8, 223.3],
|
|
256
|
-
112: [15.4, 223.4],
|
|
257
|
-
113: [15.2, 223.6],
|
|
258
|
-
114: [14.9, 223.8],
|
|
259
|
-
115: [14.7, 223.9],
|
|
260
|
-
116: [14.3, 224.1],
|
|
261
|
-
117: [14.1, 224.2],
|
|
262
|
-
118: [13.8, 224.4],
|
|
263
|
-
119: [13.5, 224.6],
|
|
264
|
-
120: [13.2, 224.8],
|
|
265
|
-
121: [12.9, 225],
|
|
266
|
-
122: [12.5, 225.3],
|
|
267
|
-
123: [12.2, 225.6],
|
|
268
|
-
124: [11.8, 225.9],
|
|
269
|
-
125: [11.4, 226.3],
|
|
270
|
-
126: [11.1, 226.7],
|
|
271
|
-
127: [10.7, 227.1],
|
|
272
|
-
128: [10.3, 227.6],
|
|
273
|
-
129: [9.9, 228],
|
|
274
|
-
130: [9.6, 228.5],
|
|
275
|
-
131: [9.3, 229.1],
|
|
276
|
-
132: [8.9, 229.6],
|
|
277
|
-
133: [8.5, 230.2],
|
|
278
|
-
134: [8.2, 230.9],
|
|
279
|
-
135: [7.8, 231.6],
|
|
280
|
-
136: [7.5, 232.5],
|
|
281
|
-
137: [7.1, 233.5],
|
|
282
|
-
138: [6.7, 234.6],
|
|
283
|
-
139: [6.3, 235.8],
|
|
284
|
-
140: [6, 237.1],
|
|
285
|
-
141: [5.6, 238.9],
|
|
286
|
-
142: [5.2, 240.9],
|
|
287
|
-
143: [5, 242.9],
|
|
288
|
-
144: [4.8, 244.9],
|
|
289
|
-
145: [4.6, 246.9],
|
|
290
|
-
146: [4.4, 249.3],
|
|
291
|
-
147: [4.3, 251.9],
|
|
292
|
-
148: [4.1, 254.9],
|
|
293
|
-
149: [3.9, 258],
|
|
294
|
-
150: [3.7, 261.8],
|
|
295
|
-
151: [3.4, 265.9],
|
|
296
|
-
152: [3.2, 271],
|
|
297
|
-
153: [3, 276.4],
|
|
298
|
-
154: [2.8, 283.6],
|
|
299
|
-
155: [2.6, 290.4],
|
|
300
|
-
156: [2.3, 295.3],
|
|
301
|
-
157: [2.1, 300],
|
|
302
|
-
158: [1.9, 300],
|
|
303
|
-
159: [1.6, 300],
|
|
304
|
-
160: [1.4, 195.8],
|
|
305
|
-
161: [1.2, 84.3],
|
|
306
|
-
162: [1.3, 58.2],
|
|
307
|
-
163: [1.5, 55.9],
|
|
308
|
-
164: [1.7, 53.2],
|
|
309
|
-
165: [1.9, 50.2],
|
|
310
|
-
166: [2.1, 47.1],
|
|
311
|
-
167: [2.4, 44.5],
|
|
312
|
-
168: [2.6, 42.6],
|
|
313
|
-
169: [2.9, 40.9],
|
|
314
|
-
170: [3.1, 39.5],
|
|
315
|
-
171: [3.4, 38.3],
|
|
316
|
-
172: [3.7, 37.3],
|
|
317
|
-
173: [3.9, 36.5],
|
|
318
|
-
174: [4.2, 35.7],
|
|
319
|
-
175: [4.4, 35.1],
|
|
320
|
-
176: [4.6, 34.5],
|
|
321
|
-
177: [4.9, 34],
|
|
322
|
-
178: [5.1, 33.5],
|
|
323
|
-
179: [5.3, 33],
|
|
324
|
-
180: [5.6, 32.7],
|
|
325
|
-
181: [5.8, 32.3],
|
|
326
|
-
182: [6, 32],
|
|
327
|
-
183: [6.3, 31.7],
|
|
328
|
-
184: [6.5, 31.4],
|
|
329
|
-
185: [6.7, 31.2],
|
|
330
|
-
186: [7, 30.9],
|
|
331
|
-
187: [7.2, 30.7],
|
|
332
|
-
188: [7.4, 30.5],
|
|
333
|
-
189: [7.6, 30.3],
|
|
334
|
-
190: [7.9, 30.1],
|
|
335
|
-
191: [8.1, 29.9],
|
|
336
|
-
192: [8.4, 29.7],
|
|
337
|
-
193: [8.6, 29.6],
|
|
338
|
-
194: [8.9, 29.5],
|
|
339
|
-
195: [9.1, 29.3],
|
|
340
|
-
196: [9.4, 29.2],
|
|
341
|
-
197: [9.6, 29.1],
|
|
342
|
-
198: [9.8, 29],
|
|
343
|
-
199: [10, 28.9],
|
|
344
|
-
200: [10.2, 28.7],
|
|
345
|
-
201: [10.5, 28.7],
|
|
346
|
-
202: [10.7, 28.6],
|
|
347
|
-
203: [11, 28.5],
|
|
348
|
-
204: [11.2, 28.4],
|
|
349
|
-
205: [11.4, 28.3],
|
|
350
|
-
206: [11.6, 28.3],
|
|
351
|
-
207: [11.8, 28.2],
|
|
352
|
-
208: [12.1, 28.1],
|
|
353
|
-
209: [12.3, 28.1],
|
|
354
|
-
210: [12.5, 28],
|
|
355
|
-
211: [12.7, 28],
|
|
356
|
-
212: [12.9, 27.9],
|
|
357
|
-
213: [13.2, 27.8],
|
|
358
|
-
214: [13.4, 27.8],
|
|
359
|
-
215: [13.6, 27.7],
|
|
360
|
-
216: [13.8, 27.7],
|
|
361
|
-
217: [14, 27.7],
|
|
362
|
-
218: [14.3, 27.6],
|
|
363
|
-
219: [14.5, 27.6],
|
|
364
|
-
220: [14.7, 27.5],
|
|
365
|
-
221: [14.9, 27.5],
|
|
366
|
-
222: [15.1, 27.5],
|
|
367
|
-
223: [15.3, 27.4],
|
|
368
|
-
224: [15.5, 27.4],
|
|
369
|
-
225: [15.8, 27.4],
|
|
370
|
-
226: [16, 27.3],
|
|
371
|
-
227: [16.2, 27.3],
|
|
372
|
-
228: [16.4, 27.3],
|
|
373
|
-
229: [16.6, 27.3],
|
|
374
|
-
230: [16.8, 27.2],
|
|
375
|
-
231: [17, 27.2],
|
|
376
|
-
232: [17.2, 27.2],
|
|
377
|
-
233: [17.4, 27.2],
|
|
378
|
-
234: [17.6, 27.2],
|
|
379
|
-
235: [17.8, 27.1],
|
|
380
|
-
236: [18, 27.1],
|
|
381
|
-
237: [18.2, 27.1],
|
|
382
|
-
238: [18.4, 27.1],
|
|
383
|
-
239: [18.7, 27.1],
|
|
384
|
-
240: [18.8, 27],
|
|
385
|
-
241: [19, 27],
|
|
386
|
-
242: [19.2, 27],
|
|
387
|
-
243: [19.4, 27],
|
|
388
|
-
244: [19.6, 27],
|
|
389
|
-
245: [19.8, 27],
|
|
390
|
-
246: [20, 27],
|
|
391
|
-
247: [20.3, 26.9],
|
|
392
|
-
248: [20.5, 26.9],
|
|
393
|
-
249: [20.6, 26.9],
|
|
394
|
-
250: [20.8, 26.9],
|
|
395
|
-
251: [21, 26.9],
|
|
396
|
-
252: [21.3, 26.9],
|
|
397
|
-
253: [21.5, 26.9],
|
|
398
|
-
254: [21.6, 26.9],
|
|
399
|
-
255: [21.8, 26.8],
|
|
400
|
-
256: [22, 26.8],
|
|
401
|
-
257: [22.2, 26.8],
|
|
402
|
-
258: [22.4, 26.8],
|
|
403
|
-
259: [22.6, 26.8],
|
|
404
|
-
260: [22.8, 26.8],
|
|
405
|
-
261: [23, 26.8],
|
|
406
|
-
262: [23.2, 26.8],
|
|
407
|
-
263: [23.4, 26.8],
|
|
408
|
-
264: [23.6, 26.8],
|
|
409
|
-
265: [23.8, 26.8],
|
|
410
|
-
266: [24, 26.8],
|
|
411
|
-
267: [24.1, 26.8],
|
|
412
|
-
268: [24.3, 26.8],
|
|
413
|
-
269: [24.5, 26.8],
|
|
414
|
-
270: [24.7, 26.8],
|
|
415
|
-
271: [24.8, 26.8],
|
|
416
|
-
272: [25.1, 26.7],
|
|
417
|
-
273: [25.3, 26.7],
|
|
418
|
-
274: [25.4, 26.7],
|
|
419
|
-
275: [25.6, 26.7],
|
|
420
|
-
276: [25.8, 26.7],
|
|
421
|
-
277: [26, 26.7],
|
|
422
|
-
278: [26.1, 26.7],
|
|
423
|
-
279: [26.3, 26.7],
|
|
424
|
-
280: [26.5, 26.7],
|
|
425
|
-
281: [26.7, 26.7],
|
|
426
|
-
282: [26.9, 26.7],
|
|
427
|
-
283: [27.1, 26.7],
|
|
428
|
-
284: [27.3, 26.7],
|
|
429
|
-
285: [27.5, 26.7],
|
|
430
|
-
286: [27.7, 26.7],
|
|
431
|
-
287: [27.8, 26.7],
|
|
432
|
-
288: [28, 26.7],
|
|
433
|
-
289: [28.2, 26.7],
|
|
434
|
-
290: [28.4, 26.7],
|
|
435
|
-
291: [28.6, 26.7],
|
|
436
|
-
292: [28.8, 26.7],
|
|
437
|
-
293: [28.9, 26.7],
|
|
438
|
-
294: [29.1, 26.7],
|
|
439
|
-
295: [29.3, 26.7],
|
|
440
|
-
296: [29.5, 26.7],
|
|
441
|
-
297: [29.6, 26.7],
|
|
442
|
-
298: [29.8, 26.7],
|
|
443
|
-
299: [30, 26.7],
|
|
444
|
-
300: [30.2, 26.7],
|
|
445
|
-
301: [30.4, 26.7],
|
|
446
|
-
302: [30.5, 26.7],
|
|
447
|
-
303: [30.7, 26.7],
|
|
448
|
-
304: [30.9, 26.7],
|
|
449
|
-
305: [31.1, 26.7],
|
|
450
|
-
306: [31.2, 26.7],
|
|
451
|
-
307: [31.4, 26.7],
|
|
452
|
-
308: [31.6, 26.7],
|
|
453
|
-
309: [31.8, 26.8],
|
|
454
|
-
310: [31.9, 26.8],
|
|
455
|
-
311: [32.1, 26.8],
|
|
456
|
-
312: [32.3, 26.8],
|
|
457
|
-
313: [32.5, 26.8],
|
|
458
|
-
314: [32.6, 26.8],
|
|
459
|
-
315: [32.8, 26.8],
|
|
460
|
-
316: [33, 26.8],
|
|
461
|
-
317: [33.2, 26.8],
|
|
462
|
-
318: [33.3, 26.8],
|
|
463
|
-
319: [33.5, 26.8],
|
|
464
|
-
320: [33.7, 26.8],
|
|
465
|
-
321: [33.8, 26.8],
|
|
466
|
-
322: [34, 26.8],
|
|
467
|
-
323: [34.2, 26.8],
|
|
468
|
-
324: [34.4, 26.8],
|
|
469
|
-
325: [34.5, 26.8],
|
|
470
|
-
326: [34.7, 26.8],
|
|
471
|
-
327: [34.9, 26.8],
|
|
472
|
-
328: [35.1, 26.8],
|
|
473
|
-
329: [35.2, 26.8],
|
|
474
|
-
330: [35.4, 26.8],
|
|
475
|
-
331: [35.5, 26.8],
|
|
476
|
-
332: [35.7, 26.8],
|
|
477
|
-
333: [35.9, 26.8],
|
|
478
|
-
334: [36.1, 26.8],
|
|
479
|
-
335: [36.3, 26.9],
|
|
480
|
-
336: [36.5, 26.9],
|
|
481
|
-
337: [36.7, 26.9],
|
|
482
|
-
338: [36.9, 26.9],
|
|
483
|
-
339: [37.1, 26.9],
|
|
484
|
-
340: [37.2, 26.9],
|
|
485
|
-
341: [37.4, 26.9],
|
|
486
|
-
342: [37.5, 26.9],
|
|
487
|
-
343: [37.7, 26.9],
|
|
488
|
-
344: [37.9, 26.9],
|
|
489
|
-
345: [38.1, 26.9],
|
|
490
|
-
346: [38.3, 26.9],
|
|
491
|
-
347: [38.5, 26.9],
|
|
492
|
-
348: [38.7, 26.9],
|
|
493
|
-
349: [38.9, 26.9],
|
|
494
|
-
350: [39, 26.9],
|
|
495
|
-
351: [39.2, 26.9],
|
|
496
|
-
352: [39.3, 27],
|
|
497
|
-
353: [39.5, 27],
|
|
498
|
-
354: [39.7, 27],
|
|
499
|
-
355: [39.9, 27],
|
|
500
|
-
356: [40.1, 27],
|
|
501
|
-
357: [40.2, 27],
|
|
502
|
-
358: [40.4, 27],
|
|
503
|
-
359: [40.6, 27],
|
|
504
|
-
360: [40.8, 27],
|
|
505
|
-
361: [40.9, 27],
|
|
506
|
-
362: [41.1, 27],
|
|
507
|
-
363: [41.2, 27],
|
|
508
|
-
364: [41.4, 27],
|
|
509
|
-
365: [41.6, 27],
|
|
510
|
-
366: [41.8, 27],
|
|
511
|
-
367: [42, 27],
|
|
512
|
-
368: [42.1, 27.1],
|
|
513
|
-
369: [42.3, 27.1],
|
|
514
|
-
370: [42.4, 27.1],
|
|
515
|
-
371: [42.6, 27.1],
|
|
516
|
-
372: [42.8, 27.1],
|
|
517
|
-
373: [43, 27.1],
|
|
518
|
-
374: [43.1, 27.1],
|
|
519
|
-
375: [43.2, 27.1],
|
|
520
|
-
376: [43.4, 27.1],
|
|
521
|
-
377: [43.6, 27.1],
|
|
522
|
-
378: [43.8, 27.1],
|
|
523
|
-
379: [43.9, 27.1],
|
|
524
|
-
380: [44.1, 27.1],
|
|
525
|
-
381: [44.3, 27.2],
|
|
526
|
-
382: [44.4, 27.2],
|
|
527
|
-
383: [44.6, 27.2],
|
|
528
|
-
384: [44.7, 27.2],
|
|
529
|
-
385: [44.9, 27.2],
|
|
530
|
-
386: [45.1, 27.2],
|
|
531
|
-
387: [45.3, 27.2],
|
|
532
|
-
388: [45.5, 27.2],
|
|
533
|
-
389: [45.6, 27.2],
|
|
534
|
-
390: [45.8, 27.2],
|
|
535
|
-
391: [46, 27.2],
|
|
536
|
-
392: [46.2, 27.3],
|
|
537
|
-
393: [46.4, 27.3],
|
|
538
|
-
394: [46.5, 27.3],
|
|
539
|
-
395: [46.7, 27.3],
|
|
540
|
-
396: [46.9, 27.3],
|
|
541
|
-
397: [47.1, 27.3],
|
|
542
|
-
398: [47.2, 27.3],
|
|
543
|
-
399: [47.4, 27.3],
|
|
544
|
-
400: [47.6, 27.3],
|
|
545
|
-
401: [47.7, 27.3],
|
|
546
|
-
402: [47.9, 27.3],
|
|
547
|
-
403: [48.1, 27.3],
|
|
548
|
-
404: [48.3, 27.3],
|
|
549
|
-
405: [48.5, 27.4],
|
|
550
|
-
406: [48.7, 27.4],
|
|
551
|
-
407: [48.8, 27.4],
|
|
552
|
-
408: [49, 27.4],
|
|
553
|
-
409: [49.2, 27.4],
|
|
554
|
-
410: [49.4, 27.4],
|
|
555
|
-
411: [49.6, 27.4],
|
|
556
|
-
412: [49.7, 27.4],
|
|
557
|
-
413: [49.9, 27.4],
|
|
558
|
-
414: [50.1, 27.4],
|
|
559
|
-
415: [50.2, 27.4],
|
|
560
|
-
416: [50.4, 27.4],
|
|
561
|
-
417: [50.6, 27.5],
|
|
562
|
-
418: [50.7, 27.5],
|
|
563
|
-
419: [50.9, 27.5],
|
|
564
|
-
420: [51.1, 27.5],
|
|
565
|
-
421: [51.2, 27.5],
|
|
566
|
-
422: [51.4, 27.5],
|
|
567
|
-
423: [51.6, 27.5],
|
|
568
|
-
424: [51.7, 27.5],
|
|
569
|
-
425: [51.9, 27.5],
|
|
570
|
-
426: [52.1, 27.5],
|
|
571
|
-
427: [51.2, 27.6],
|
|
572
|
-
428: [52.4, 27.6],
|
|
573
|
-
429: [52.5, 27.6],
|
|
574
|
-
430: [52.7, 27.6],
|
|
575
|
-
431: [52.9, 27.6],
|
|
576
|
-
432: [53.1, 27.6],
|
|
577
|
-
433: [53.2, 27.6],
|
|
578
|
-
434: [53.4, 27.6],
|
|
579
|
-
435: [53.6, 27.6],
|
|
580
|
-
436: [53.7, 27.6],
|
|
581
|
-
437: [53.9, 27.6],
|
|
582
|
-
438: [54.1, 27.7],
|
|
583
|
-
439: [54.2, 27.7],
|
|
584
|
-
440: [54.3, 27.7],
|
|
585
|
-
441: [54.5, 27.7],
|
|
586
|
-
442: [54.7, 27.7],
|
|
587
|
-
443: [54.8, 27.7],
|
|
588
|
-
444: [55, 27.7],
|
|
589
|
-
445: [55.2, 27.7],
|
|
590
|
-
446: [55.3, 27.7],
|
|
591
|
-
447: [55.5, 27.7],
|
|
592
|
-
448: [55.7, 27.7],
|
|
593
|
-
449: [55.8, 27.8],
|
|
594
|
-
450: [56, 27.8],
|
|
595
|
-
451: [56.2, 27.8],
|
|
596
|
-
452: [56.3, 27.8],
|
|
597
|
-
453: [56.5, 27.8],
|
|
598
|
-
454: [56.7, 27.8],
|
|
599
|
-
455: [56.8, 27.8],
|
|
600
|
-
456: [57, 27.8],
|
|
601
|
-
457: [57.2, 27.8],
|
|
602
|
-
458: [57.3, 27.9],
|
|
603
|
-
459: [57.4, 27.9],
|
|
604
|
-
460: [57.6, 27.9],
|
|
605
|
-
461: [57.8, 27.9],
|
|
606
|
-
462: [57.9, 27.9],
|
|
607
|
-
463: [58.1, 27.9],
|
|
608
|
-
464: [58.3, 27.9],
|
|
609
|
-
465: [58.4, 27.9],
|
|
610
|
-
466: [58.6, 27.9],
|
|
611
|
-
467: [58.8, 27.9],
|
|
612
|
-
468: [59, 28],
|
|
613
|
-
469: [59.1, 28],
|
|
614
|
-
470: [59.2, 28],
|
|
615
|
-
471: [59.4, 28],
|
|
616
|
-
472: [59.6, 28],
|
|
617
|
-
473: [59.7, 28],
|
|
618
|
-
474: [60, 28],
|
|
619
|
-
475: [60.1, 28],
|
|
620
|
-
476: [60.2, 28],
|
|
621
|
-
477: [60.4, 28],
|
|
622
|
-
478: [60.6, 28.1],
|
|
623
|
-
479: [60.7, 28.1],
|
|
624
|
-
480: [60.9, 28.1],
|
|
625
|
-
481: [60.1, 28.1],
|
|
626
|
-
482: [60.3, 28.1],
|
|
627
|
-
483: [61.4, 28.1],
|
|
628
|
-
484: [61.5, 28.1],
|
|
629
|
-
485: [61.7, 28.1],
|
|
630
|
-
486: [61.9, 28.1],
|
|
631
|
-
487: [62, 28.2],
|
|
632
|
-
488: [62.2, 28.2],
|
|
633
|
-
489: [62.3, 28.2],
|
|
634
|
-
490: [62.5, 28.2],
|
|
635
|
-
491: [62.7, 28.2],
|
|
636
|
-
492: [62.8, 28.2],
|
|
637
|
-
493: [63, 28.2],
|
|
638
|
-
494: [63.2, 28.2],
|
|
639
|
-
495: [63.3, 28.2],
|
|
640
|
-
496: [63.4, 28.2],
|
|
641
|
-
497: [63.6, 28.2],
|
|
642
|
-
498: [63.8, 28.3],
|
|
643
|
-
499: [63.9, 28.3],
|
|
644
|
-
500: [64.1, 28.3],
|
|
645
|
-
};
|
|
646
|
-
const input = Math.min(Math.max(Math.round(m), 140), 500);
|
|
647
|
-
const toReturn = table[input];
|
|
648
|
-
return [Math.round(toReturn[1]), Math.round(toReturn[0])];
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* Remove deviceConfig entries that contain only default/empty values.
|
|
652
|
-
* Returns undefined if nothing meaningful remains.
|
|
653
|
-
*/
|
|
654
|
-
export function cleanDeviceConfig(deviceConfig) {
|
|
655
|
-
if (!deviceConfig || typeof deviceConfig !== 'object') {
|
|
656
|
-
return undefined;
|
|
1102
|
+
// Lock variants
|
|
1103
|
+
if (['smart lock', 'smart lock pro', 'smart lock ultra', 'lock lite', 'keypad', 'keypad touch', 'keypad vision', 'keypad vision pro', 'lock vision pro'].includes(raw)) {
|
|
1104
|
+
return 'lock';
|
|
657
1105
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
continue;
|
|
662
|
-
}
|
|
663
|
-
const hasMeaningful = Object.values(cfg).some((v) => {
|
|
664
|
-
if (v === null || v === undefined) {
|
|
665
|
-
return false;
|
|
666
|
-
}
|
|
667
|
-
if (typeof v === 'boolean') {
|
|
668
|
-
return v === true;
|
|
669
|
-
}
|
|
670
|
-
if (typeof v === 'string') {
|
|
671
|
-
return v.trim().length > 0;
|
|
672
|
-
}
|
|
673
|
-
if (typeof v === 'number') {
|
|
674
|
-
return Number.isFinite(v);
|
|
675
|
-
}
|
|
676
|
-
if (Array.isArray(v)) {
|
|
677
|
-
return v.length > 0;
|
|
678
|
-
}
|
|
679
|
-
if (typeof v === 'object') {
|
|
680
|
-
return Object.keys(v).length > 0;
|
|
681
|
-
}
|
|
682
|
-
return true;
|
|
683
|
-
});
|
|
684
|
-
if (hasMeaningful) {
|
|
685
|
-
cleaned[deviceName] = cfg;
|
|
686
|
-
}
|
|
1106
|
+
// Climate variant
|
|
1107
|
+
if (raw === 'humidifier2') {
|
|
1108
|
+
return 'humidifier';
|
|
687
1109
|
}
|
|
688
|
-
|
|
689
|
-
return cleaned;
|
|
690
|
-
}
|
|
691
|
-
return undefined;
|
|
1110
|
+
return raw;
|
|
692
1111
|
}
|
|
693
1112
|
/**
|
|
694
|
-
*
|
|
1113
|
+
* Normalizes a Homebridge PlatformConfig object to a SwitchBotPluginConfig.
|
|
695
1114
|
*
|
|
696
|
-
* @param
|
|
697
|
-
* @
|
|
698
|
-
* @param opts - optional overrides for maxRetries and delayBetweenRetries
|
|
699
|
-
* @param opts.maxRetries - override for maxRetries
|
|
700
|
-
* @param opts.delayBetweenRetries - override for delayBetweenRetries
|
|
1115
|
+
* @param raw The raw Homebridge platform config object.
|
|
1116
|
+
* @returns The normalized plugin config object.
|
|
701
1117
|
*/
|
|
702
|
-
export function
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
return retryCommandFunc(deviceObj, bodyChange, opts?.maxRetries, opts?.delayBetweenRetries);
|
|
706
|
-
};
|
|
707
|
-
}
|
|
708
|
-
/**
|
|
709
|
-
* Factory that returns a function to perform BLE actions using a SwitchBotBLE client.
|
|
710
|
-
* Handles discovery retries and method invocation on the discovered device instance.
|
|
711
|
-
*
|
|
712
|
-
* @param switchBotBLE - instance of SwitchBotBLE (may be undefined)
|
|
713
|
-
* @param deviceObj - the device object (used to obtain bleModel/deviceId)
|
|
714
|
-
* @param opts - optional retry settings
|
|
715
|
-
* @param opts.bleRetries - number of BLE discovery retries
|
|
716
|
-
* @param opts.bleRetryDelay - delay between BLE retries in ms
|
|
717
|
-
*/
|
|
718
|
-
export function makeBLESender(switchBotBLE, deviceObj, opts) {
|
|
719
|
-
return async (methodName, ...args) => {
|
|
720
|
-
if (!switchBotBLE) {
|
|
721
|
-
throw new Error('Platform BLE not available');
|
|
722
|
-
}
|
|
723
|
-
const id = formatDeviceIdAsMac(deviceObj.deviceId);
|
|
724
|
-
const maxRetries = opts?.bleRetries ?? 2;
|
|
725
|
-
const retryDelay = opts?.bleRetryDelay ?? 500;
|
|
726
|
-
let attempt = 0;
|
|
727
|
-
while (attempt < maxRetries) {
|
|
728
|
-
try {
|
|
729
|
-
const list = await switchBotBLE.discover({ model: deviceObj.bleModel, id });
|
|
730
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
731
|
-
throw new Error('BLE device not found');
|
|
732
|
-
}
|
|
733
|
-
const deviceInst = list[0];
|
|
734
|
-
if (typeof deviceInst[methodName] !== 'function') {
|
|
735
|
-
throw new TypeError(`BLE method ${methodName} not available on device`);
|
|
736
|
-
}
|
|
737
|
-
return await deviceInst[methodName](...args);
|
|
738
|
-
}
|
|
739
|
-
catch (e) {
|
|
740
|
-
attempt++;
|
|
741
|
-
if (attempt >= maxRetries) {
|
|
742
|
-
throw e;
|
|
743
|
-
}
|
|
744
|
-
await sleep(retryDelay);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
throw new Error('BLE operation failed');
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
/**
|
|
751
|
-
* Decide effective connection type for a device given platform options.
|
|
752
|
-
* Mirrors the logic previously in platform-matter.
|
|
753
|
-
*/
|
|
754
|
-
export function chooseConnectionType(platformOptions, deviceObj) {
|
|
755
|
-
if (deviceObj?.connectionType) {
|
|
756
|
-
return deviceObj.connectionType === 'BLE' ? 'BLE' : 'OpenAPI';
|
|
757
|
-
}
|
|
758
|
-
if (platformOptions?.BLE && (deviceObj?.bleModel || (typeof deviceObj?.deviceId === 'string' && deviceObj.deviceId.length > 0))) {
|
|
759
|
-
return 'BLE';
|
|
1118
|
+
export function normalizeConfig(raw) {
|
|
1119
|
+
if (!raw) {
|
|
1120
|
+
return {};
|
|
760
1121
|
}
|
|
761
|
-
return
|
|
1122
|
+
return { ...raw };
|
|
762
1123
|
}
|
|
1124
|
+
// Create a Proxy constructor that instantiates the right platform implementation at runtime.
|
|
763
1125
|
/**
|
|
764
|
-
*
|
|
765
|
-
* This encapsulates the multi-fallback detection used across the project.
|
|
766
|
-
*/
|
|
767
|
-
/**
|
|
768
|
-
* Detect whether Matter is enabled on the provided Homebridge API object.
|
|
769
|
-
* Returns an object with an `enabled` boolean and an optional `reason` string
|
|
770
|
-
* describing which check matched (useful for diagnostics).
|
|
771
|
-
*/
|
|
772
|
-
export function detectMatter(apiObj) {
|
|
773
|
-
try {
|
|
774
|
-
const maybe = apiObj.isMatterEnabled;
|
|
775
|
-
if (typeof maybe === 'function') {
|
|
776
|
-
return { enabled: Boolean(maybe.call(apiObj)), reason: 'api.isMatterEnabled() returned truthy' };
|
|
777
|
-
}
|
|
778
|
-
if (typeof maybe !== 'undefined') {
|
|
779
|
-
return { enabled: Boolean(maybe), reason: 'api.isMatterEnabled property present' };
|
|
780
|
-
}
|
|
781
|
-
const server = apiObj.server ?? apiObj.homebridgeServer ?? apiObj.homebridge_server;
|
|
782
|
-
const serverMaybe = server?.isMatterEnabled;
|
|
783
|
-
if (typeof serverMaybe === 'function') {
|
|
784
|
-
return { enabled: Boolean(serverMaybe.call(server)), reason: 'server.isMatterEnabled() returned truthy' };
|
|
785
|
-
}
|
|
786
|
-
if (typeof server?.isMatterEnabled !== 'undefined') {
|
|
787
|
-
return { enabled: Boolean(server.isMatterEnabled), reason: 'server.isMatterEnabled property present' };
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
catch (e) {
|
|
791
|
-
return { enabled: false, reason: `error during detection: ${String(e?.message ?? e)}` };
|
|
792
|
-
}
|
|
793
|
-
return { enabled: false, reason: 'no isMatterEnabled API or server fallback detected' };
|
|
794
|
-
}
|
|
795
|
-
/**
|
|
796
|
-
* Backwards-compatible boolean wrapper for detectMatter.
|
|
797
|
-
*/
|
|
798
|
-
export function detectMatterEnabled(apiObj) {
|
|
799
|
-
return detectMatter(apiObj).enabled;
|
|
800
|
-
}
|
|
801
|
-
/**
|
|
802
|
-
* Create platform logging helpers used by both HAP and Matter platforms.
|
|
1126
|
+
* Creates a proxy class that instantiates the correct platform implementation (HAP or Matter) at runtime.
|
|
803
1127
|
*
|
|
804
|
-
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
const getPL = async () => {
|
|
811
|
-
try {
|
|
812
|
-
return await getPlatformLogging();
|
|
813
|
-
}
|
|
814
|
-
catch {
|
|
815
|
-
return undefined;
|
|
816
|
-
}
|
|
817
|
-
};
|
|
818
|
-
const loggingIsDebug = async () => {
|
|
819
|
-
const pl = await getPL();
|
|
820
|
-
return pl === 'debugMode' || pl === 'debug';
|
|
821
|
-
};
|
|
822
|
-
const enablingPlatformLogging = async () => {
|
|
823
|
-
const pl = await getPL();
|
|
824
|
-
return pl === 'debugMode' || pl === 'debug' || pl === 'standard';
|
|
825
|
-
};
|
|
826
|
-
return {
|
|
827
|
-
infoLog: async (...args) => {
|
|
828
|
-
if (await enablingPlatformLogging()) {
|
|
829
|
-
log.info(String(...args));
|
|
830
|
-
}
|
|
831
|
-
},
|
|
832
|
-
successLog: async (...args) => {
|
|
833
|
-
if (await enablingPlatformLogging()) {
|
|
834
|
-
// Some Logging implementations expose `success` — call if present
|
|
835
|
-
;
|
|
836
|
-
log.success?.(String(...args)) ?? log.info(String(...args));
|
|
837
|
-
}
|
|
838
|
-
},
|
|
839
|
-
debugSuccessLog: async (...args) => {
|
|
840
|
-
if (await enablingPlatformLogging()) {
|
|
841
|
-
if (await loggingIsDebug()) {
|
|
842
|
-
;
|
|
843
|
-
log.success?.('[DEBUG]', String(...args)) ?? log.info('[DEBUG]', String(...args));
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
},
|
|
847
|
-
warnLog: async (...args) => {
|
|
848
|
-
if (await enablingPlatformLogging()) {
|
|
849
|
-
log.warn(String(...args));
|
|
850
|
-
}
|
|
851
|
-
},
|
|
852
|
-
debugWarnLog: async (...args) => {
|
|
853
|
-
if (await enablingPlatformLogging()) {
|
|
854
|
-
if (await loggingIsDebug()) {
|
|
855
|
-
log.warn('[DEBUG]', String(...args));
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
},
|
|
859
|
-
errorLog: async (...args) => {
|
|
860
|
-
if (await enablingPlatformLogging()) {
|
|
861
|
-
log.error(String(...args));
|
|
862
|
-
}
|
|
863
|
-
},
|
|
864
|
-
debugErrorLog: async (...args) => {
|
|
865
|
-
if (await enablingPlatformLogging()) {
|
|
866
|
-
if (await loggingIsDebug()) {
|
|
867
|
-
log.error('[DEBUG]', String(...args));
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
},
|
|
871
|
-
debugLog: async (...args) => {
|
|
872
|
-
if (await enablingPlatformLogging()) {
|
|
873
|
-
const pl = await getPL();
|
|
874
|
-
if (pl === 'debug') {
|
|
875
|
-
log.info('[DEBUG]', String(...args));
|
|
876
|
-
}
|
|
877
|
-
else if (pl === 'debugMode') {
|
|
878
|
-
log.debug(String(...args));
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
},
|
|
882
|
-
loggingIsDebug,
|
|
883
|
-
enablingPlatformLogging,
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
/**
|
|
887
|
-
* Create a Platform proxy class that selects between two platform constructors
|
|
888
|
-
* (HAP vs Matter) at runtime using `detectMatter`. Returns a class suitable
|
|
889
|
-
* for passing to `api.registerPlatform`.
|
|
1128
|
+
* @param HAPPlatform The HAP platform class constructor.
|
|
1129
|
+
* @param MatterPlatform The Matter platform class constructor.
|
|
1130
|
+
* @returns A proxy class that delegates to the correct platform implementation.
|
|
1131
|
+
*
|
|
1132
|
+
* @class SwitchBotPlatformProxy
|
|
1133
|
+
* @property impl The instantiated platform implementation (HAP or Matter).
|
|
890
1134
|
*/
|
|
891
|
-
export function createPlatformProxy(
|
|
892
|
-
return class
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1135
|
+
export function createPlatformProxy(HAPPlatform, MatterPlatform) {
|
|
1136
|
+
return class SwitchBotPlatformProxy {
|
|
1137
|
+
/** The instantiated platform implementation (HAP or Matter) */
|
|
1138
|
+
impl;
|
|
1139
|
+
/**
|
|
1140
|
+
* Constructs the proxy and instantiates the correct platform implementation.
|
|
1141
|
+
* @param log Logger instance
|
|
1142
|
+
* @param config Platform config
|
|
1143
|
+
* @param api Homebridge API instance
|
|
1144
|
+
* @returns The instantiated platform implementation
|
|
1145
|
+
*/
|
|
897
1146
|
constructor(log, config, api) {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
const PlatformCtor = isMatter ? MatterCtor : HAPCtor;
|
|
906
|
-
this.delegate = new PlatformCtor(this.log, this.config, this.api);
|
|
907
|
-
}
|
|
908
|
-
configureAccessory(accessory) {
|
|
909
|
-
try {
|
|
910
|
-
if (this.delegate && typeof this.delegate.configureAccessory === 'function') {
|
|
911
|
-
return this.delegate.configureAccessory(accessory);
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
catch (e) {
|
|
915
|
-
// swallow — preserve previous behaviour where delegate errors don't bubble here
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
configureMatterAccessory(accessory) {
|
|
919
|
-
try {
|
|
920
|
-
if (this.delegate && typeof this.delegate.configureMatterAccessory === 'function') {
|
|
921
|
-
return this.delegate.configureMatterAccessory(accessory);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
catch (e) {
|
|
925
|
-
// swallow — delegate may not implement this or may throw
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
get accessories() {
|
|
929
|
-
try {
|
|
930
|
-
return this.delegate?.accessories;
|
|
931
|
-
}
|
|
932
|
-
catch (e) {
|
|
933
|
-
return undefined;
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
get matterAccessories() {
|
|
937
|
-
try {
|
|
938
|
-
return this.delegate?.matterAccessories;
|
|
939
|
-
}
|
|
940
|
-
catch (e) {
|
|
941
|
-
return undefined;
|
|
1147
|
+
const cfg = normalizeConfig(config);
|
|
1148
|
+
const preferMatter = cfg.preferMatter ?? true;
|
|
1149
|
+
const enableMatter = cfg.enableMatter ?? true;
|
|
1150
|
+
const matterAvailable = !!(api?.isMatterAvailable?.() && api?.isMatterEnabled?.());
|
|
1151
|
+
if (enableMatter && preferMatter && MatterPlatform && matterAvailable) {
|
|
1152
|
+
this.impl = new MatterPlatform(log, cfg, api);
|
|
1153
|
+
return this.impl;
|
|
942
1154
|
}
|
|
1155
|
+
// Fallback to HAP
|
|
1156
|
+
this.impl = new HAPPlatform(log, cfg, api);
|
|
1157
|
+
return this.impl;
|
|
943
1158
|
}
|
|
944
1159
|
};
|
|
945
1160
|
}
|