@homebridge-plugins/homebridge-eufy-security 4.7.2 → 5.0.0-beta.1
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/AUTHORS +4 -0
- package/CODE_OF_CONDUCT.md +30 -0
- package/CONTRIBUTING.md +77 -0
- package/README.md +152 -49
- package/SECURITY.md +30 -0
- package/config.schema.json +92 -3
- package/dist/account/ownership.js +290 -0
- package/dist/account/ownership.js.map +1 -0
- package/dist/account/persistence.js +274 -0
- package/dist/account/persistence.js.map +1 -0
- package/dist/account/temporary-authentication.js +348 -0
- package/dist/account/temporary-authentication.js.map +1 -0
- package/dist/configuration.js +167 -0
- package/dist/configuration.js.map +1 -0
- package/dist/device/member-evidence.js +66 -0
- package/dist/device/member-evidence.js.map +1 -0
- package/dist/device/member-trust.js +114 -0
- package/dist/device/member-trust.js.map +1 -0
- package/dist/device/snapshot.js +190 -0
- package/dist/device/snapshot.js.map +1 -0
- package/dist/diagnostics.js +2218 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/homekit/adapter.js +2 -0
- package/dist/homekit/adapter.js.map +1 -0
- package/dist/homekit/adapters/battery.js +208 -0
- package/dist/homekit/adapters/battery.js.map +1 -0
- package/dist/homekit/adapters/camera-controls.js +527 -0
- package/dist/homekit/adapters/camera-controls.js.map +1 -0
- package/dist/homekit/adapters/camera-streaming.js +1515 -0
- package/dist/homekit/adapters/camera-streaming.js.map +1 -0
- package/dist/homekit/adapters/contact.js +138 -0
- package/dist/homekit/adapters/contact.js.map +1 -0
- package/dist/homekit/adapters/doorbell.js +57 -0
- package/dist/homekit/adapters/doorbell.js.map +1 -0
- package/dist/homekit/adapters/information.js +55 -0
- package/dist/homekit/adapters/information.js.map +1 -0
- package/dist/homekit/adapters/lock.js +489 -0
- package/dist/homekit/adapters/lock.js.map +1 -0
- package/dist/homekit/adapters/motion.js +100 -0
- package/dist/homekit/adapters/motion.js.map +1 -0
- package/dist/homekit/adapters/registry.js +26 -0
- package/dist/homekit/adapters/registry.js.map +1 -0
- package/dist/homekit/adapters/security-system.js +425 -0
- package/dist/homekit/adapters/security-system.js.map +1 -0
- package/dist/homekit/adapters/siren.js +136 -0
- package/dist/homekit/adapters/siren.js.map +1 -0
- package/dist/homekit/adapters/smart-light.js +662 -0
- package/dist/homekit/adapters/smart-light.js.map +1 -0
- package/dist/homekit/coverage-matrix.js +119 -0
- package/dist/homekit/coverage-matrix.js.map +1 -0
- package/dist/homekit/device-control.js +175 -0
- package/dist/homekit/device-control.js.map +1 -0
- package/dist/homekit/reconciler.js +319 -0
- package/dist/homekit/reconciler.js.map +1 -0
- package/dist/homekit/representation.js +23 -0
- package/dist/homekit/representation.js.map +1 -0
- package/dist/index.js +4 -9
- package/dist/index.js.map +1 -1
- package/dist/media/contracts.js +2 -0
- package/dist/media/contracts.js.map +1 -0
- package/dist/media/last-successful-image.js +208 -0
- package/dist/media/last-successful-image.js.map +1 -0
- package/dist/media/live-stream.js +1003 -0
- package/dist/media/live-stream.js.map +1 -0
- package/dist/media/recording.js +560 -0
- package/dist/media/recording.js.map +1 -0
- package/dist/media/session-budget.js +39 -0
- package/dist/media/session-budget.js.map +1 -0
- package/dist/media/snapshot.js +406 -0
- package/dist/media/snapshot.js.map +1 -0
- package/dist/media/station-live-sessions.js +101 -0
- package/dist/media/station-live-sessions.js.map +1 -0
- package/dist/platform.js +97 -809
- package/dist/platform.js.map +1 -1
- package/dist/runtime/channel.js +375 -0
- package/dist/runtime/channel.js.map +1 -0
- package/dist/runtime/owner.js +682 -0
- package/dist/runtime/owner.js.map +1 -0
- package/dist/runtime/sdk-client.js +211 -0
- package/dist/runtime/sdk-client.js.map +1 -0
- package/dist/runtime/tracker.js +211 -0
- package/dist/runtime/tracker.js.map +1 -0
- package/dist/settings.js +1 -43
- package/dist/settings.js.map +1 -1
- package/dist/storage.js +59 -0
- package/dist/storage.js.map +1 -0
- package/dist/ui/dashboard.js +181 -0
- package/dist/ui/dashboard.js.map +1 -0
- package/dist/ui/device-image.js +22 -0
- package/dist/ui/device-image.js.map +1 -0
- package/dist/ui/runtime-channel-client.js +305 -0
- package/dist/ui/runtime-channel-client.js.map +1 -0
- package/dist/ui/server.js +259 -0
- package/dist/ui/server.js.map +1 -0
- package/homebridge-ui/public/app.css +1902 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T1250.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2070.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2080.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2081.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2103.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2117.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2118.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2119.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T211A.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2120.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2123.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2128.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2130.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2132.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2150.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2181.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2182.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2190.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2192.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2193.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2194.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2210.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2250.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2251.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2252.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2253.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2254.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2255.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2256.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2257.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2258.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2259.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2261.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2262.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2266.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2267.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2268.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2270.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2272.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2273.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2276.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2277.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2278.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2280.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2292.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2320.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2351.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2352.webp +0 -0
- package/homebridge-ui/public/assets/devices/clean/clean-T2353.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L00.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L01.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L02.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L04.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L10.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L20.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L30.webp +0 -0
- package/homebridge-ui/public/assets/devices/life/life-T8L40.webp +0 -0
- package/homebridge-ui/public/assets/devices/mower/mower-T2801.webp +0 -0
- package/homebridge-ui/public/assets/devices/mower/mower-T280B.webp +0 -0
- package/homebridge-ui/public/assets/devices/mower/mower-T2880.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T7400.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T7401.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8001.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8002.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8010.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8021.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8023.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8025.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8030.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8110.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8111.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8112.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8113.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8114.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8122.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8123.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8124.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8130.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8131.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8134.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8140.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8141.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8150.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8151.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8152.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8153.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8160.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8161.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8162.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8170.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8171.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8172.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8173.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8200.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8200X.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8201.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8203.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8210.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8213.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8214.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8222.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8400.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8401.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8410.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8411.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8414.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8416.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8417.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8419.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8419N.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8420.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8420X.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8422.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8423.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8424.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8425.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8441.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8442.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8452.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T84A0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T84A1.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8500.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8502.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8503.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8504.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8506.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8510.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8510P.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8520.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8520P.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8530.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8531.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85D0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85L0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85P0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T85V0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8600.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T86P2.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8790.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T87B0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T87B2.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8900.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8910.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8920.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8960.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8B0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8E00.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8N00.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T8W11C.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90F0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90M0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90R0.webp +0 -0
- package/homebridge-ui/public/assets/devices/security/security-T90S0.webp +0 -0
- package/homebridge-ui/public/assets/icons/inventory.svg +1 -1
- package/homebridge-ui/public/assets/icons/troubleshoot.svg +1 -0
- package/homebridge-ui/public/assets/icons/warning.svg +1 -1
- package/homebridge-ui/public/assets/logo-dark.svg +10 -0
- package/homebridge-ui/public/assets/logo.svg +10 -0
- package/homebridge-ui/public/i18n/en.json +218 -0
- package/homebridge-ui/public/i18n/fr.json +218 -0
- package/homebridge-ui/public/index.html +377 -28
- package/homebridge-ui/public/js/app.js +1065 -0
- package/homebridge-ui/public/js/dashboard.js +385 -0
- package/homebridge-ui/public/js/legacy-settings.js +37 -0
- package/homebridge-ui/public/js/profile-wizard.js +68 -0
- package/homebridge-ui/server.js +2 -1393
- package/i18n/runtime/en.json +100 -0
- package/media/Snapshot-Unavailable.jpg +0 -0
- package/media/Snapshot-black.jpg +0 -0
- package/media/camera-disabled.jpg +0 -0
- package/media/camera-offline.jpg +0 -0
- package/package.json +29 -24
- package/.claude/CLAUDE.md +0 -175
- package/.claude/PRD.md +0 -241
- package/.claude/docs/debug-recording-lessons.md +0 -91
- package/.claude/docs/hksv-recording-fix.md +0 -160
- package/.claude/skills/architect/SKILL.md +0 -76
- package/.claude/skills/developer/SKILL.md +0 -59
- package/.claude/skills/new-device-support/SKILL.md +0 -212
- package/.claude/skills/new-device-support/check-device.mjs +0 -363
- package/.claude/skills/new-device-support/map-properties.mjs +0 -450
- package/.claude/skills/new-device-support/verify-device.mjs +0 -272
- package/.claude/skills/planner/SKILL.md +0 -100
- package/.claude/skills/qa/SKILL.md +0 -79
- package/.claude/skills/support/SKILL.md +0 -175
- package/.prettierignore +0 -7
- package/.prettierrc.json +0 -7
- package/FUNDING.yml +0 -1
- package/dist/accessories/AutoSyncStationAccessory.js +0 -157
- package/dist/accessories/AutoSyncStationAccessory.js.map +0 -1
- package/dist/accessories/BaseAccessory.js +0 -261
- package/dist/accessories/BaseAccessory.js.map +0 -1
- package/dist/accessories/CameraAccessory.js +0 -459
- package/dist/accessories/CameraAccessory.js.map +0 -1
- package/dist/accessories/Device.js +0 -65
- package/dist/accessories/Device.js.map +0 -1
- package/dist/accessories/EntrySensorAccessory.js +0 -48
- package/dist/accessories/EntrySensorAccessory.js.map +0 -1
- package/dist/accessories/GarageDoorAccessory.js +0 -160
- package/dist/accessories/GarageDoorAccessory.js.map +0 -1
- package/dist/accessories/LockAccessory.js +0 -142
- package/dist/accessories/LockAccessory.js.map +0 -1
- package/dist/accessories/MotionSensorAccessory.js +0 -48
- package/dist/accessories/MotionSensorAccessory.js.map +0 -1
- package/dist/accessories/SmartDropAccessory.js +0 -141
- package/dist/accessories/SmartDropAccessory.js.map +0 -1
- package/dist/accessories/StationAccessory.js +0 -373
- package/dist/accessories/StationAccessory.js.map +0 -1
- package/dist/config.js +0 -26
- package/dist/config.js.map +0 -1
- package/dist/controller/DebugRecordingManager.js +0 -402
- package/dist/controller/DebugRecordingManager.js.map +0 -1
- package/dist/controller/LocalLivestreamManager.js +0 -371
- package/dist/controller/LocalLivestreamManager.js.map +0 -1
- package/dist/controller/recordingDelegate.js +0 -252
- package/dist/controller/recordingDelegate.js.map +0 -1
- package/dist/controller/snapshotDelegate.js +0 -348
- package/dist/controller/snapshotDelegate.js.map +0 -1
- package/dist/controller/streamingDelegate.js +0 -389
- package/dist/controller/streamingDelegate.js.map +0 -1
- package/dist/interfaces.js +0 -2
- package/dist/interfaces.js.map +0 -1
- package/dist/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/Snapshot-black.png +0 -0
- package/dist/media/camera-disabled.png +0 -0
- package/dist/media/camera-offline.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.png +0 -0
- package/dist/media/media/Snapshot-Unavailable.xcf +0 -0
- package/dist/media/media/Snapshot-black.png +0 -0
- package/dist/media/media/camera-disabled.png +0 -0
- package/dist/media/media/camera-offline.png +0 -0
- package/dist/utils/Talkback.js +0 -162
- package/dist/utils/Talkback.js.map +0 -1
- package/dist/utils/accessoriesStore.js +0 -210
- package/dist/utils/accessoriesStore.js.map +0 -1
- package/dist/utils/configTypes.js +0 -38
- package/dist/utils/configTypes.js.map +0 -1
- package/dist/utils/ffmpeg.js +0 -1111
- package/dist/utils/ffmpeg.js.map +0 -1
- package/dist/utils/interfaces.js +0 -8
- package/dist/utils/interfaces.js.map +0 -1
- package/dist/utils/utils.js +0 -224
- package/dist/utils/utils.js.map +0 -1
- package/dist/version.js +0 -2
- package/dist/version.js.map +0 -1
- package/homebridge-eufy-security.png +0 -0
- package/homebridge-ui/diagnosticsCrypto.js +0 -112
- package/homebridge-ui/public/app.js +0 -237
- package/homebridge-ui/public/assets/devices/4g_lte_cam_s330_large.png +0 -0
- package/homebridge-ui/public/assets/devices/4g_lte_starlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C30.png +0 -0
- package/homebridge-ui/public/assets/devices/BATTERY_DOORBELL_C31.png +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell2k_large.png +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell2kdual_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/batterydoorbell_e340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufy-security-client.png +0 -0
- package/homebridge-ui/public/assets/devices/eufyCamS4_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2cpro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3c_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycam3pro_large.png +0 -0
- package/homebridge-ui/public/assets/devices/eufycam_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/eufycame330_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/flood_freeze_sensor_e20_t90F0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight2pro_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlight_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/floodlightcame340_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/garage_camera_t8452_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase3_large.png +0 -0
- package/homebridge-ui/public/assets/devices/homebase_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/homebasemini_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC210_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC220_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamC220_t8419N_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamE30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamc120_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcammini_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/indoorcamp24_large.png +0 -0
- package/homebridge-ui/public/assets/devices/indoorcams350_large.png +0 -0
- package/homebridge-ui/public/assets/devices/keypad_large.png +0 -0
- package/homebridge-ui/public/assets/devices/minibase_chime_T8023_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/motionsensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/nvr_s4_max_T8N00_large.png +0 -0
- package/homebridge-ui/public/assets/devices/pir_sensor_e20_large.png +0 -0
- package/homebridge-ui/public/assets/devices/poe_bullet_ptz_cam_s4_T8E00_large.png +0 -0
- package/homebridge-ui/public/assets/devices/sensor_large.png +0 -0
- package/homebridge-ui/public/assets/devices/siren_sensor_e20_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartdrop_t8790_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8500_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8503_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8504_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t8510P_t8520P_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85D0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85L0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85P0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_t85V0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8502_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8506_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_and_wifi_t8520_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_touch_t8510_wifibridge_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_video_t8530_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlock_video_t8531_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartlockwifibridge_t8021_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s10_t7400_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smartsafe_s12_t7401_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_card_t87B2_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smarttrack_link_t87B0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/smoke_alarm_e10_t90S0_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocamc210_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocamc35_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocame30_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocame40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocame42_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocaml20_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams220_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solocams340_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solocams40_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/soloindoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc22_large.png +0 -0
- package/homebridge-ui/public/assets/devices/solooutdoorcamc24_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/unknown.png +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s100_large.png +0 -0
- package/homebridge-ui/public/assets/devices/walllight_s120_large.png +0 -0
- package/homebridge-ui/public/assets/devices/water_freeze_sensor_t8920_large.png +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell1080p_large.jpg +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbell2k_large.png +0 -0
- package/homebridge-ui/public/assets/devices/wireddoorbelldual_large.jpg +0 -0
- package/homebridge-ui/public/assets/icons/attach.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_0.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_1.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_2.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_3.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_4.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_5.svg +0 -1
- package/homebridge-ui/public/assets/icons/battery_6.svg +0 -1
- package/homebridge-ui/public/assets/icons/copy.svg +0 -1
- package/homebridge-ui/public/assets/icons/delete.svg +0 -1
- package/homebridge-ui/public/assets/icons/download.svg +0 -1
- package/homebridge-ui/public/assets/icons/info.svg +0 -1
- package/homebridge-ui/public/assets/icons/refresh.svg +0 -1
- package/homebridge-ui/public/assets/icons/satellite_alt.svg +0 -1
- package/homebridge-ui/public/assets/icons/solar_power.svg +0 -1
- package/homebridge-ui/public/components/device-card.js +0 -174
- package/homebridge-ui/public/components/guard-modes.js +0 -88
- package/homebridge-ui/public/components/number-input.js +0 -121
- package/homebridge-ui/public/components/select.js +0 -73
- package/homebridge-ui/public/components/toggle.js +0 -68
- package/homebridge-ui/public/services/api.js +0 -250
- package/homebridge-ui/public/services/config.js +0 -144
- package/homebridge-ui/public/style.css +0 -818
- package/homebridge-ui/public/utils/countries.js +0 -73
- package/homebridge-ui/public/utils/device-images.js +0 -102
- package/homebridge-ui/public/utils/helpers.js +0 -115
- package/homebridge-ui/public/views/dashboard.js +0 -226
- package/homebridge-ui/public/views/device-detail.js +0 -654
- package/homebridge-ui/public/views/diagnostics.js +0 -402
- package/homebridge-ui/public/views/login.js +0 -650
- package/homebridge-ui/public/views/recordings.js +0 -319
- package/homebridge-ui/public/views/settings.js +0 -197
- package/homebridge-ui/public/views/unsupported-detail.js +0 -296
- package/media/Snapshot-Unavailable.png +0 -0
- package/media/Snapshot-Unavailable.xcf +0 -0
- package/media/Snapshot-black.png +0 -0
- package/media/camera-disabled.png +0 -0
- package/media/camera-offline.png +0 -0
- package/scripts/decrypt-diagnostics.mjs +0 -257
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# Debug Recording Pipeline — Lessons Learned (PRs #888–#894, 2026-03-26)
|
|
2
|
-
|
|
3
|
-
Six PRs in one day to fix a feature that should have landed in one or two. Root causes were not understanding the FFmpeg process architecture, fixing symptoms instead of root causes, and not testing against real hardware before merging.
|
|
4
|
-
|
|
5
|
-
## 1. Understand the P2P FFmpeg process architecture BEFORE touching it
|
|
6
|
-
|
|
7
|
-
P2P cameras use SEPARATE FFmpeg processes for video and audio. The video process has only one input (raw H264 via TCP). There is no `input 1` for audio. Any `-map 1:a` on the video process will fail silently or crash.
|
|
8
|
-
|
|
9
|
-
**Rule**: Before adding FFmpeg arguments, trace the FULL command that gets spawned. Check `ffmpeg-<serial>.log` in diagnostics. Verify what each input index maps to.
|
|
10
|
-
|
|
11
|
-
**Why**: PRs #888, #890, #891 all tried to add audio to the video process file tee — impossible by architecture. Three PRs wasted.
|
|
12
|
-
|
|
13
|
-
**How to apply**: When modifying `getCombinedArguments()` or `buildRawMuxArgs()`, always log or mentally construct the full FFmpeg command and verify each `-i` and `-map` index.
|
|
14
|
-
|
|
15
|
-
## 2. Homebridge plugin UI runs in an iframe with strict CSP
|
|
16
|
-
|
|
17
|
-
Homebridge enforces `frame-src 'self' data: https://developers.homebridge.io`. This means:
|
|
18
|
-
- `data:` URIs work for downloads
|
|
19
|
-
- `blob:` URLs are BLOCKED
|
|
20
|
-
|
|
21
|
-
**Rule**: Never use `URL.createObjectURL()` / `blob:` for downloads in the plugin UI. Use the same `btoa()` + `data:` URI pattern as diagnostics download.
|
|
22
|
-
|
|
23
|
-
**Why**: PR #893 switched to Blob URLs for "memory efficiency", immediately broke downloads. Had to revert.
|
|
24
|
-
|
|
25
|
-
**How to apply**: When writing download logic in `homebridge-ui/`, copy the pattern from `diagnostics.js` `_downloadDiagnostics()`. Check CSP before changing.
|
|
26
|
-
|
|
27
|
-
## 3. Destroy PassThrough forks when their consumer dies
|
|
28
|
-
|
|
29
|
-
When piping a source stream to multiple PassThrough forks via `.pipe()`, if ANY fork's consumer dies (e.g., FFmpeg crashes) and the fork is not destroyed, it fills its internal buffer (16KB default) and applies permanent backpressure on the source — starving ALL other consumers.
|
|
30
|
-
|
|
31
|
-
**Rule**: Always destroy PassThrough forks when their downstream consumer exits. Store references and destroy in cleanup handlers.
|
|
32
|
-
|
|
33
|
-
**Why**: PR #888 created forks without cleanup. The bug was masked by 4MB highWaterMark in #890, exposed when removed in #891, finally fixed in #893.
|
|
34
|
-
|
|
35
|
-
**How to apply**: Any time you create a `new PassThrough()` and pipe a shared source into it, ensure the fork is destroyed when its consumer (FFmpeg, socket, etc.) exits. Use both socket `close` handler AND session cleanup as belt-and-suspenders.
|
|
36
|
-
|
|
37
|
-
## 4. FFmpeg ignores stdin when reading from TCP
|
|
38
|
-
|
|
39
|
-
When FFmpeg reads input from a TCP socket (`-i tcp://...`), it is blocked in the socket read loop and does NOT monitor stdin. Writing `'q'` or `'q\n'` to stdin has no effect. The process will never exit gracefully via stdin.
|
|
40
|
-
|
|
41
|
-
**Rule**: To stop FFmpeg reading from TCP, destroy the TCP socket. FFmpeg detects EOF and exits cleanly, finalizing the container.
|
|
42
|
-
|
|
43
|
-
**Why**: PR #888 used `stdin.write('q')`, #893 added newline, neither worked. FFmpeg was always SIGKILL'd after timeout. PR #894 fixed it by destroying the socket.
|
|
44
|
-
|
|
45
|
-
**How to apply**: In `stopSessionBySerial()`, destroy `session.videoSocket` and `session.audioSocket` instead of writing to stdin.
|
|
46
|
-
|
|
47
|
-
## 5. P2P data is inherently bursty — never use wallclock timestamps
|
|
48
|
-
|
|
49
|
-
`-use_wallclock_as_timestamps 1` assigns PTS based on when FFmpeg receives each frame. P2P delivers data in bursts at every level: initial buffer dump, ongoing video chunks (~1.3s gaps between bursts), and audio (entire ADTS batch arrives in one TCP write). Wallclock faithfully records these arrival times, producing choppy video and crushed audio (25s of audio crammed into 2ms of timestamps).
|
|
50
|
-
|
|
51
|
-
Deferred piping (PR #891) only prevents the initial buffer dump. It does NOT make ongoing P2P delivery real-time.
|
|
52
|
-
|
|
53
|
-
**Rule**: Never use `-use_wallclock_as_timestamps` for P2P recordings. Use `-fflags +genpts -r <fps>` for video (generates smooth PTS from declared framerate) and `-fflags +genpts` for audio (generates PTS from sample rate). The FPS comes from `metadata.videoFPS`.
|
|
54
|
-
|
|
55
|
-
**Why**: PR #888 used wallclock -> burst -> 0.07s. PR #894 used wallclock + deferred piping -> choppy video (1.3s frame gaps) and silent audio (all timestamps within 2ms). PR #897 uses genpts + fps from metadata.
|
|
56
|
-
|
|
57
|
-
**How to apply**: In `buildRawMuxArgs()`, use `-fflags +genpts -r <fps>` before each input. Deferred piping in `LocalLivestreamManager.onStationLivestreamStart` is still needed to prevent the initial buffer burst from skewing the generated PTS.
|
|
58
|
-
|
|
59
|
-
## 6. The processed file tee copies raw INPUT, not encoded OUTPUT
|
|
60
|
-
|
|
61
|
-
In FFmpeg multi-output, `-map 0:v -c:v copy` on a second output copies from INPUT 0 (raw P2P), not the encoded output of the first output. To capture the encoded stream, you'd need the `tee` muxer (blocked by SRTP params) or double encoding (wasteful).
|
|
62
|
-
|
|
63
|
-
**Rule**: Don't use the file tee to capture "what HomeKit sees". It captures the raw P2P feed. For P2P cameras, use DebugRecordingManager instead (captures both video+audio). Keep the file tee only for RTSP cameras where DebugRecordingManager doesn't apply.
|
|
64
|
-
|
|
65
|
-
**Why**: PRs #888-#891 assumed the file tee captured the encoded stream. It never did.
|
|
66
|
-
|
|
67
|
-
## 7. HomeKit probes streams with a stop/restart cycle
|
|
68
|
-
|
|
69
|
-
HomeKit sends startStream -> runs for 2-3s -> sends stopStream -> waits -> sends startStream again. This is normal probe behavior. If the file recording uses the P2P sessionId (which persists across HomeKit sessions), the second start overwrites the first file.
|
|
70
|
-
|
|
71
|
-
**Rule**: For any per-HomeKit-session file recording, use `request.sessionID` (HomeKit's session ID), not the P2P livestream sessionId.
|
|
72
|
-
|
|
73
|
-
**How to apply**: Relevant if the RTSP file tee is ever extended. Currently moot for P2P since the file tee was removed.
|
|
74
|
-
|
|
75
|
-
## 8. Test against real hardware before merging
|
|
76
|
-
|
|
77
|
-
Every PR #888-#893 was merged and found broken on the next beta. A single 15-second test (enable debug livestream -> stream camera -> check recording) would have caught most issues immediately.
|
|
78
|
-
|
|
79
|
-
**Rule**: Before merging debug recording changes, the test plan MUST actually be executed. At minimum: enable feature, stream for 15s, ffprobe the output, check eufy-security.log for errors.
|
|
80
|
-
|
|
81
|
-
**Why**: The ADTS crash (FFmpeg exit 255) was visible in the very first test. The 0.07s duration was visible in the first ffprobe. Six PRs could have been two.
|
|
82
|
-
|
|
83
|
-
## 9. Fragmented MP4 breaks VLC and QuickTime
|
|
84
|
-
|
|
85
|
-
`-movflags frag_keyframe+empty_moov` writes fragmented MP4 (fMP4) — designed for live streaming, not file playback. VLC shows ~1s of content then stops. QuickTime can't play it at all.
|
|
86
|
-
|
|
87
|
-
**Rule**: Use `-movflags +faststart` for debug recordings written to disk. Standard MP4 with moov relocated to the start is universally playable.
|
|
88
|
-
|
|
89
|
-
**Why**: PR #897 used fMP4 for crash resilience (already-written fragments survive SIGKILL). But graceful shutdown via socket destroy (lesson #4) makes this unnecessary. PR #898 switched to faststart.
|
|
90
|
-
|
|
91
|
-
**How to apply**: Only use `frag_keyframe+empty_moov` when streaming to a non-seekable output (e.g., HTTP). For file output, always use `+faststart`.
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
# HKSV Recording Reliability Fix
|
|
2
|
-
|
|
3
|
-
**PR:** [#878](https://github.com/homebridge-plugins/homebridge-eufy-security/pull/878)
|
|
4
|
-
**Branch:** `fix/hksv-recording-reliability`
|
|
5
|
-
**Affects:** All cameras with HomeKit Secure Video enabled
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Problem
|
|
10
|
-
|
|
11
|
-
HKSV recordings never appeared in the Apple Home timeline. Users could enable HKSV in Apple Home settings, but no recordings were captured on motion events. Two independent issues combined to make HKSV completely non-functional.
|
|
12
|
-
|
|
13
|
-
## Root Cause 1: HKSV state lost on every restart
|
|
14
|
-
|
|
15
|
-
### How HKSV state persistence works
|
|
16
|
-
|
|
17
|
-
When a user enables HKSV for a camera in Apple Home:
|
|
18
|
-
|
|
19
|
-
1. HomeKit sets the `Active` characteristic to `true` on the `CameraRecordingManagement` service
|
|
20
|
-
2. HAP-NodeJS stores this in two places:
|
|
21
|
-
- The `cachedAccessories` JSON (service characteristic values)
|
|
22
|
-
- The `ControllerStorage` file (controller-specific state)
|
|
23
|
-
3. On next boot, `CameraController._initWithServices()` restores services from cache
|
|
24
|
-
4. `ControllerStorage.restoreController()` calls `deserialize()` to restore `recordingActive`
|
|
25
|
-
|
|
26
|
-
### What was broken
|
|
27
|
-
|
|
28
|
-
`CameraAccessory.configureVideoStream()` removed two controller-managed services (`CameraOperatingMode` and `DataStreamTransportManagement`) from the cached accessory before calling `configureController()`. This was added to prevent a "duplicate UUID error".
|
|
29
|
-
|
|
30
|
-
However, this broke the restoration flow:
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
HAP-NodeJS CameraController._initWithServices():
|
|
34
|
-
|
|
35
|
-
IF all 3 services found in cache:
|
|
36
|
-
→ Reuse cached services (preserves Active state) ✓
|
|
37
|
-
|
|
38
|
-
ELSE (any service missing):
|
|
39
|
-
→ Create NEW services with Active=false ✗
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
By removing 2 of the 3 services, every restart forced the `ELSE` path, resetting `recordingActive` to `false`. HomeKit set `Active=true` once, but it was lost on every boot.
|
|
43
|
-
|
|
44
|
-
### The fix
|
|
45
|
-
|
|
46
|
-
Removed the stale service removal code entirely. HAP-NodeJS's `_initWithServices()` already handles service reuse through its `serializedControllers` path — the "duplicate UUID error" it was designed to prevent doesn't occur when services are properly managed by the controller.
|
|
47
|
-
|
|
48
|
-
## Root Cause 2: P2P cold-start delay
|
|
49
|
-
|
|
50
|
-
### The timing problem
|
|
51
|
-
|
|
52
|
-
When HomeKit requests an HKSV recording after motion detection, the recording delegate must:
|
|
53
|
-
|
|
54
|
-
1. Establish a P2P connection to the camera (`getLocalLiveStream()`)
|
|
55
|
-
2. Start FFmpeg to transcode the stream
|
|
56
|
-
3. Begin yielding fMP4 fragments to HomeKit
|
|
57
|
-
|
|
58
|
-
Step 1 takes **~4.8 seconds** (observed in diagnostics). HomeKit has an approximate **5-second timeout** for the first data. This means recordings frequently failed to start in time.
|
|
59
|
-
|
|
60
|
-
### How reference implementations solve this
|
|
61
|
-
|
|
62
|
-
| Plugin | Approach | Prebuffer Duration |
|
|
63
|
-
|--------|----------|--------------------|
|
|
64
|
-
| homebridge-unifi-protect | Always-on RTSP timeshift buffer | Configurable |
|
|
65
|
-
| Scrypted | Ring buffer, 2.5x HomeKit's prebufferLength | 10s default |
|
|
66
|
-
| homebridge-camera-ui | Always-on prebuffer | 4s |
|
|
67
|
-
|
|
68
|
-
All use prebuffering. For battery-powered Eufy cameras, always-on prebuffering is not viable.
|
|
69
|
-
|
|
70
|
-
### The fix: motion-triggered P2P pre-warming
|
|
71
|
-
|
|
72
|
-
When the plugin detects motion (before HomeKit even requests a recording), it proactively starts the P2P connection:
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
Motion Detected → Plugin sets MotionDetected=true on characteristic
|
|
76
|
-
→ Plugin calls preWarmStream() (P2P starts in background)
|
|
77
|
-
→ HomeKit receives motion notification
|
|
78
|
-
→ HomeKit sends DATA_SEND OPEN → handleRecordingStreamRequest()
|
|
79
|
-
→ getLocalLiveStream() returns instantly (P2P already warm)
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
A new `preWarmStream()` method on `LocalLivestreamManager` starts the P2P connection without creating a consumer fork. The stream auto-cleans up after the `STOP_GRACE_MS` (5 seconds) grace period if HomeKit doesn't request a recording.
|
|
83
|
-
|
|
84
|
-
RTSP cameras are excluded from pre-warming since their stream URL is immediately available.
|
|
85
|
-
|
|
86
|
-
## Additional fix: updateRecordingActive log bug
|
|
87
|
-
|
|
88
|
-
`recordingDelegate.ts` line 282 had swapped log arguments:
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
// Before (wrong — message as camera name, camera name as message):
|
|
92
|
-
log.debug(`Recording: ${active}`, this.accessory.displayName);
|
|
93
|
-
|
|
94
|
-
// After (correct):
|
|
95
|
-
log.info(this.camera.getName(), `HKSV recording enabled/disabled by HomeKit.`);
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
This made HKSV state changes invisible in logs, making the root cause much harder to diagnose. Promoted to INFO level since this is a critical diagnostic signal.
|
|
99
|
-
|
|
100
|
-
## HKSV Recording Flow (Architecture Reference)
|
|
101
|
-
|
|
102
|
-
```
|
|
103
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
104
|
-
│ eufy-security-client │
|
|
105
|
-
│ Device emits 'motion detected' / 'person detected' / etc. │
|
|
106
|
-
└──────────────────────────┬──────────────────────────────────┘
|
|
107
|
-
│
|
|
108
|
-
▼
|
|
109
|
-
┌──────────────────────────────────────────────────────────────┐
|
|
110
|
-
│ CameraAccessory.ts │
|
|
111
|
-
│ 1. characteristic.updateValue(true) → HomeKit notified │
|
|
112
|
-
│ 2. preWarmStream() → P2P starts warming │
|
|
113
|
-
└──────────────────────────┬───────────────────────────────────┘
|
|
114
|
-
│
|
|
115
|
-
┌────────────┴────────────┐
|
|
116
|
-
│ │
|
|
117
|
-
▼ ▼
|
|
118
|
-
┌──────────────────────┐ ┌─────────────────────────────────┐
|
|
119
|
-
│ LocalLivestream │ │ HAP-NodeJS RecordingManagement │
|
|
120
|
-
│ Manager.ts │ │ │
|
|
121
|
-
│ P2P connecting... │ │ HomeKit receives MotionDetected │
|
|
122
|
-
│ Stream warming... │ │ HomeKit decides to record │
|
|
123
|
-
│ ✓ Stream ready │ │ DATA_SEND OPEN → │
|
|
124
|
-
└──────────┬───────────┘ └───────────────┬───────────────────┘
|
|
125
|
-
│ │
|
|
126
|
-
│ ▼
|
|
127
|
-
│ ┌───────────────────────────────────┐
|
|
128
|
-
│ │ recordingDelegate.ts │
|
|
129
|
-
│ │ handleRecordingStreamRequest() │
|
|
130
|
-
└──────────────►│ configureInputSource() │
|
|
131
|
-
P2P already │ → getLocalLiveStream() instant │
|
|
132
|
-
warm! │ FFmpeg starts │
|
|
133
|
-
│ yield fMP4 fragments → HomeKit │
|
|
134
|
-
└───────────────────────────────────┘
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Files Changed
|
|
138
|
-
|
|
139
|
-
| File | Change |
|
|
140
|
-
|------|--------|
|
|
141
|
-
| `src/accessories/CameraAccessory.ts` | Removed stale service removal; added motion-triggered pre-warming |
|
|
142
|
-
| `src/controller/LocalLivestreamManager.ts` | Added `preWarmStream()` method; updated `isStreamActive()` |
|
|
143
|
-
| `src/controller/recordingDelegate.ts` | Fixed `updateRecordingActive` log arguments |
|
|
144
|
-
|
|
145
|
-
## User Impact
|
|
146
|
-
|
|
147
|
-
### After upgrading
|
|
148
|
-
|
|
149
|
-
Users who had HKSV enabled but never saw recordings should see them start working. Some users may need to:
|
|
150
|
-
|
|
151
|
-
1. Restart Homebridge after the upgrade
|
|
152
|
-
2. If recordings still don't appear, toggle HKSV off and on in Apple Home:
|
|
153
|
-
- Open Home app → Camera settings → Recording Options → Disable → Re-enable
|
|
154
|
-
|
|
155
|
-
### Battery considerations
|
|
156
|
-
|
|
157
|
-
The P2P pre-warming starts a livestream connection on every motion event. For battery-powered cameras:
|
|
158
|
-
- The stream only runs for 5 seconds if HomeKit doesn't request a recording
|
|
159
|
-
- This is similar to what already happens for snapshot fetching on motion
|
|
160
|
-
- Impact on battery life should be minimal but is worth monitoring
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: architect
|
|
3
|
-
description: Answer quick architectural questions, debug mini-issues, explore the codebase, and help improve skills and workflows. Use this skill when the user asks "how does X work", "where is Y", "why does Z happen", wants to understand code flow, trace a bug through the system, or asks about the relationship between components. Also use when the user wants to improve an existing skill or refine development workflows. This is the lightweight, exploratory counterpart to the planner -- use it for questions and small fixes, not multi-file changes.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Architect
|
|
7
|
-
|
|
8
|
-
You are an architectural advisor for homebridge-eufy-security. You answer questions quickly, trace code paths, debug small issues, and help refine the development workflow. You are the "thinking" mode -- fast, focused, and precise.
|
|
9
|
-
|
|
10
|
-
Refer to CLAUDE.md for the full architecture and project conventions.
|
|
11
|
-
|
|
12
|
-
## What you do
|
|
13
|
-
|
|
14
|
-
### Codebase exploration
|
|
15
|
-
|
|
16
|
-
When the user asks "how does X work" or "where is Y":
|
|
17
|
-
|
|
18
|
-
1. Search the codebase (Glob, Grep) to find the relevant code
|
|
19
|
-
2. Read the key files
|
|
20
|
-
3. Explain the flow concisely with file:line references
|
|
21
|
-
4. Draw the path through the system if it crosses multiple files
|
|
22
|
-
|
|
23
|
-
Quick-reference starting points:
|
|
24
|
-
|
|
25
|
-
| Question | Start here |
|
|
26
|
-
|---|---|
|
|
27
|
-
| Device discovery? | `src/platform.ts` -- `onStationAdded`, `onDeviceAdded`, `register_device` |
|
|
28
|
-
| Streaming? | `src/controller/streamingDelegate.ts` -> `LocalLivestreamManager.ts` |
|
|
29
|
-
| HKSV recording? | `src/controller/recordingDelegate.ts` |
|
|
30
|
-
| Snapshots? | `src/controller/snapshotDelegate.ts` |
|
|
31
|
-
| UI <-> plugin? | `src/utils/accessoriesStore.ts` -> `homebridge-ui/server.js` |
|
|
32
|
-
| Arm/disarm? | `src/accessories/StationAccessory.ts` |
|
|
33
|
-
| Two-way audio? | `src/utils/Talkback.ts` |
|
|
34
|
-
|
|
35
|
-
### Mini-bug debugging
|
|
36
|
-
|
|
37
|
-
For small, contained bugs:
|
|
38
|
-
|
|
39
|
-
1. Reproduce the understanding -- what's expected vs what happens?
|
|
40
|
-
2. Trace the code path from trigger to symptom
|
|
41
|
-
3. Identify the root cause with file:line reference
|
|
42
|
-
4. If it's a one-line fix, suggest it directly
|
|
43
|
-
5. If it's bigger, recommend using the planner skill
|
|
44
|
-
|
|
45
|
-
### Skill and workflow improvement
|
|
46
|
-
|
|
47
|
-
When the user wants to refine skills or workflows:
|
|
48
|
-
|
|
49
|
-
1. Read the current skill/workflow file
|
|
50
|
-
2. Identify what's working and what's not based on user feedback
|
|
51
|
-
3. Suggest specific, minimal changes
|
|
52
|
-
4. Apply changes after user approval
|
|
53
|
-
|
|
54
|
-
### Quick code review
|
|
55
|
-
|
|
56
|
-
When asked to review code or a diff:
|
|
57
|
-
|
|
58
|
-
1. Focus on correctness, not style
|
|
59
|
-
2. Check the architectural boundaries (plugin vs eufy-security-client)
|
|
60
|
-
3. Flag potential issues with file:line references
|
|
61
|
-
4. Don't nitpick -- only flag things that could break or confuse
|
|
62
|
-
|
|
63
|
-
## How to respond
|
|
64
|
-
|
|
65
|
-
- Be concise. Use file:line references.
|
|
66
|
-
- Show the relevant code snippet when it helps understanding.
|
|
67
|
-
- If the answer requires reading more than 3-4 files, use subagents for parallel exploration.
|
|
68
|
-
- If the question turns into a multi-file change request, suggest switching to the planner skill.
|
|
69
|
-
- If you're unsure, say so. Don't speculate about code you haven't read.
|
|
70
|
-
|
|
71
|
-
## What you don't do
|
|
72
|
-
|
|
73
|
-
- Don't make multi-file code changes (use planner -> developer)
|
|
74
|
-
- Don't run builds or lint (use QA skill)
|
|
75
|
-
- Don't create PRs or push code (use the git workflow directly)
|
|
76
|
-
- Don't write lengthy essays -- keep answers tight and actionable
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: developer
|
|
3
|
-
description: Execute code changes following an approved plan or direct user instructions. Use this skill when the user says "implement", "code it", "go ahead", "execute the plan", or when transitioning from the planner skill after approval. Also use for direct coding tasks where the user provides clear, specific instructions. This skill writes clean, correct code respecting all project conventions.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Developer
|
|
7
|
-
|
|
8
|
-
You are a code execution agent for homebridge-eufy-security. You write code that is clean, correct, and follows every project convention. You either execute an approved plan from the planner skill, or implement direct user instructions.
|
|
9
|
-
|
|
10
|
-
Follow all conventions in CLAUDE.md (ESM imports, lint, architecture patterns, code style, git workflow).
|
|
11
|
-
|
|
12
|
-
## Before writing any code
|
|
13
|
-
|
|
14
|
-
1. **Read first**: Read every file you intend to modify. Understand existing patterns before touching them.
|
|
15
|
-
2. **Check the plan**: If a plan was approved, follow it exactly. If you spot an issue with the plan during implementation, stop and flag it -- don't silently deviate.
|
|
16
|
-
3. **Branch check**: Verify you're on the correct branch per CLAUDE.md git workflow.
|
|
17
|
-
|
|
18
|
-
## Implementation workflow
|
|
19
|
-
|
|
20
|
-
### Step 1 -- Write the code
|
|
21
|
-
|
|
22
|
-
Make changes file by file, following the plan order. For each file:
|
|
23
|
-
- Use the Edit tool for modifications (not Bash with sed/awk)
|
|
24
|
-
- Use Write only for new files
|
|
25
|
-
- Keep changes minimal and focused
|
|
26
|
-
- Don't add features beyond what was requested
|
|
27
|
-
- Don't refactor surrounding code while fixing a bug
|
|
28
|
-
|
|
29
|
-
### Step 2 -- Self-review
|
|
30
|
-
|
|
31
|
-
After all changes are made, re-read each modified file to verify:
|
|
32
|
-
- No syntax errors
|
|
33
|
-
- Imports use `.js` extensions
|
|
34
|
-
- No accidental duplicate code
|
|
35
|
-
- Changes match the plan
|
|
36
|
-
|
|
37
|
-
### Step 3 -- Verify
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
npm run lint
|
|
41
|
-
npm run build
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
If either fails, fix the issue immediately. Do not commit code that doesn't lint or build.
|
|
45
|
-
|
|
46
|
-
### Step 4 -- Commit
|
|
47
|
-
|
|
48
|
-
Follow the git workflow from CLAUDE.md. Stage each logical change individually.
|
|
49
|
-
|
|
50
|
-
## Chaining
|
|
51
|
-
|
|
52
|
-
After committing, automatically invoke the **qa** skill to verify the changes before pushing. Do not wait for the user to ask -- QA is part of the development flow.
|
|
53
|
-
|
|
54
|
-
## When things go wrong
|
|
55
|
-
|
|
56
|
-
- **Lint failure**: Fix the warning. Don't disable the rule.
|
|
57
|
-
- **Build failure**: Read the error. If it's a type error, trace it back. If it's an import error, check `.js` extensions.
|
|
58
|
-
- **Plan doesn't work**: Stop. Explain what you found. Don't improvise a workaround without user approval.
|
|
59
|
-
- **Unclear requirement**: Ask. Don't guess.
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: new-device-support
|
|
3
|
-
description: Full workflow to add support for a new Eufy Security device type (cameras, locks, sensors, and other devices) across eufy-security-client and homebridge-eufy-security. Covers exploration, implementation, build verification, and git/PR creation.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Add New Eufy Security Device Support
|
|
7
|
-
|
|
8
|
-
You are adding support for a new device type to the eufy-security ecosystem. The user will provide a GitHub issue URL or device details (model name, model number like T86P2, device type number like 111). They may also provide raw device properties JSON.
|
|
9
|
-
|
|
10
|
-
Use `$ARGUMENTS` for the issue URL or device details.
|
|
11
|
-
|
|
12
|
-
## Phase 1 — Gather Information
|
|
13
|
-
|
|
14
|
-
1. **Fetch the GitHub issue** (if URL provided) to extract: device name, model number (e.g. T86P2), device type number, raw properties JSON, firmware version, and any reference PRs. Note: users on recent eufy-security-client versions see a structured "unknown device" debug message that includes raw properties in a format directly usable with the mapping script.
|
|
15
|
-
2. **Check for existing upstream work** — before starting, search for PRs that already add this device:
|
|
16
|
-
```bash
|
|
17
|
-
gh pr list --repo bropat/eufy-security-client --state all --search "<model> OR <device-type-number>" --limit 10
|
|
18
|
-
```
|
|
19
|
-
If a PR exists: review its diff to see what's already implemented, what's missing (e.g. missing GenericTypeProperty label, incomplete DeviceCommands), and whether it's merged, open, or stale. If merged, the device may only need homebridge-eufy-security side changes. If open but incomplete, coordinate with the PR author or build on their work. If the PR has review comments, check for flagged issues.
|
|
20
|
-
3. **Pre-flight checks** — before proceeding, confirm you have:
|
|
21
|
-
- Device type number (required — cannot proceed without it)
|
|
22
|
-
- Raw device properties JSON (required for accurate property mapping — if missing, ask the user to enable debug logging and re-export diagnostics)
|
|
23
|
-
- Model number / display name (needed for enum naming and documentation)
|
|
24
|
-
- If the device type number is completely unknown (not in any existing code), investigate: check the model number prefix pattern, look at raw properties to infer capabilities (camera properties? lock properties? sensor properties?), and check Eufy's product pages for the model.
|
|
25
|
-
4. **Run the pre-implementation audit**: Before writing any code, run the audit script to see what already exists:
|
|
26
|
-
```bash
|
|
27
|
-
node homebridge-eufy-security/.claude/skills/new-device-support/check-device.mjs <type-number> [--pr-search <model>]
|
|
28
|
-
```
|
|
29
|
-
This checks all 6 registration points in types.ts, classification methods in device.ts, device-images.js, finds the closest existing devices by property overlap, and searches upstream PRs. Use its output to understand the starting point.
|
|
30
|
-
5. **Run the property mapping script**: Save the raw properties JSON to a temp file and run:
|
|
31
|
-
```bash
|
|
32
|
-
node homebridge-eufy-security/.claude/skills/new-device-support/map-properties.mjs /tmp/<device>-raw-props.json --closest
|
|
33
|
-
```
|
|
34
|
-
This maps each raw `param_type` to its `CommandType`/`ParamType` enum name, matching property constants, and which existing device types use them. It also outputs a suggested DeviceProperties block. The `--closest` flag ranks existing devices by property overlap to identify the best base device.
|
|
35
|
-
6. **Ask the user** two questions:
|
|
36
|
-
- Image naming convention (check if images already exist or need renaming)
|
|
37
|
-
- Enum name for the DeviceType (e.g. `CAMERA_4G_S330`)
|
|
38
|
-
|
|
39
|
-
## Phase 2 — Plan (use EnterPlanMode)
|
|
40
|
-
|
|
41
|
-
Create a detailed plan covering all files that need changes. The plan must be based on the actual raw device properties — never guess which properties a device supports.
|
|
42
|
-
|
|
43
|
-
### Determine device category
|
|
44
|
-
|
|
45
|
-
Before planning file changes, identify the device category — this determines which classification methods and accessory classes apply:
|
|
46
|
-
|
|
47
|
-
- **Camera** (including doorbells, floodlights, indoor cameras, solo cameras, 4G cameras): uses `CameraAccessory` in the plugin. Classification methods: `isCamera()`, and optionally `isDoorbell()`, `isFloodLight()`, `isIndoorCamera()`, `isPanAndTiltCamera()`, `isOutdoorPanAndTiltCamera()`, `isSoloCameras()`, etc. Note: `isSoloCameras()` is a composite method that includes outdoor PTZ, wall light cams, and other standalone camera types.
|
|
48
|
-
- **WallLightCam**: uses `CameraAccessory`. Classification: `isWallLightCam()`. This category is heavily referenced in `station.ts` (50+ references) for livestream, talkback, property handling, and command routing — expect substantial `station.ts` changes.
|
|
49
|
-
- **GarageCamera**: uses `CameraAccessory`. Classification: `isGarageCamera()`. Has dedicated property variants (e.g. `DeviceWatermarkGarageCameraProperty`, `DeviceMotionDetectionSensitivityGarageCameraProperty`). Also has `isGarageCameraBySn()` for serial number matching.
|
|
50
|
-
- **Lock** (BLE, WiFi, WiFi Video variants): uses `LockAccessory`. Classification methods: `isLock()`, `isLockWifi()`, `isLockBle()`, `isLockWifiVideo()`, etc. Locks have many specialized type guard methods (e.g. `isLockWifiT8531()`, `isLockWifiR10()`) — check existing patterns carefully. Locks may require changes in **three additional layers** beyond this skill's primary scope — flag these to the user:
|
|
51
|
-
- `src/mqtt/` — MQTT protocol for lock communication
|
|
52
|
-
- `src/p2p/session.ts` — P2P session initialization uses `Device.isLockWifi()` and `Device.isLockWifiNoFinger()` for lock sequence generation
|
|
53
|
-
- `src/http/station.ts` — lock-specific routing at station level
|
|
54
|
-
- **Sensor** (entry sensor, motion sensor, PIR sensor): uses `EntrySensorAccessory` or `MotionSensorAccessory`. Classification: `isSensor()`, `isEntrySensor()`, `isMotionSensor()`. Note: `isSensor()` is static-only — no public instance method exists.
|
|
55
|
-
- **SmartDrop**: uses `SmartDropAccessory`. Classification: `isSmartDrop()`. Also has `isSmartDropBySn()` for serial number matching.
|
|
56
|
-
- **SmartSafe**: no HomeKit accessory currently. Classification: `isSmartSafe()`.
|
|
57
|
-
- **Tracker/SmartTrack**: no HomeKit accessory currently. Classification: `isSmartTrack()`.
|
|
58
|
-
- **Keypad**: no HomeKit accessory currently. Classification: `isKeyPad()`.
|
|
59
|
-
- **WaterFreezeSensor**: no HomeKit accessory currently. Classification: check for `WATER_FREEZE_SENSOR_*` in DeviceType enum.
|
|
60
|
-
- **Siren**: no HomeKit accessory currently. Classification: check for `SIREN_SENSOR_*` in DeviceType enum.
|
|
61
|
-
- **New category**: if the device doesn't fit any existing category, a new accessory class is needed in `src/accessories/`, a new classification method, and a new `if` block in `register_device()`. Flag this to the user — it's a significantly larger task.
|
|
62
|
-
|
|
63
|
-
### Files to modify in eufy-security-client
|
|
64
|
-
|
|
65
|
-
#### `src/http/types.ts` — 6 locations:
|
|
66
|
-
|
|
67
|
-
1. **DeviceType enum**: Add `ENUM_NAME = <number>, //<model>` in numeric order
|
|
68
|
-
2. **GenericTypeProperty `states` field**: Add `<number>: "<Display Name> (<Model>)"` inside the `states` object in numeric order. **WARNING**: This is one of the most commonly forgotten steps. Missing this label causes the device to display as a raw number in downstream UIs (see upstream PR #828 where 5 device types had missing labels).
|
|
69
|
-
3. **DeviceProperties**: Add `[DeviceType.ENUM_NAME]` block. Always starts with `...GenericDeviceProperties`. Map each raw param_type to its corresponding `PropertyName.*` property constant. Base on the closest existing device but only include properties that match the raw data.
|
|
70
|
-
4. **StationProperties**: Add `[DeviceType.ENUM_NAME]` block if device can act as its own station (solo cameras, integrated devices). Use `...BaseStationProperties` plus station-specific properties.
|
|
71
|
-
5. **DeviceCommands**: Add `[DeviceType.ENUM_NAME]` array. Commands depend on device capabilities (livestream, talkback, pan/tilt, download, snooze, preset positions, calibrate, alarm).
|
|
72
|
-
6. **StationCommands**: Add `[DeviceType.ENUM_NAME]` array if device has station properties. Typically `[CommandName.StationReboot, CommandName.StationTriggerAlarmSound]`.
|
|
73
|
-
|
|
74
|
-
#### `src/http/device.ts` — Classification methods:
|
|
75
|
-
|
|
76
|
-
Add the new device type to all applicable static classification methods. There are two kinds:
|
|
77
|
-
|
|
78
|
-
**Broad classification methods** (add device to these as applicable):
|
|
79
|
-
- `isCamera()` — if it's a camera/doorbell/floodlight
|
|
80
|
-
- `hasBattery()` — if battery-powered (critical — omitting this means no battery service in HomeKit)
|
|
81
|
-
- `isPanAndTiltCamera()` — if has PTZ
|
|
82
|
-
- `isOutdoorPanAndTiltCamera()` — if outdoor PTZ (included by `isSoloCameras()`)
|
|
83
|
-
- `isSoloCameras()` — composite method aggregating solo/standalone camera types
|
|
84
|
-
- `isFloodLight()`, `isIndoorCamera()`, `isDoorbell()`, `isWallLightCam()`, `isGarageCamera()` — as applicable
|
|
85
|
-
- `isLock()`, `isLockWifi()`, `isLockBle()`, `isLockWifiNoFinger()` — if it's a lock variant
|
|
86
|
-
- `isSensor()`, `isEntrySensor()`, `isMotionSensor()` — if it's a sensor
|
|
87
|
-
- `isSmartDrop()`, `isSmartSafe()`, `isSmartTrack()`, `isKeyPad()` — as applicable
|
|
88
|
-
|
|
89
|
-
Note: Not all broad methods have public instance counterparts (e.g. `isSensor()` is static-only). Don't create instance methods where none exist for the pattern.
|
|
90
|
-
|
|
91
|
-
**`isSupported()` check**: After adding to `DeviceProperties` map, `Device.isSupported(type)` automatically returns `true` (it checks `DeviceProperties[type] !== undefined`). This is the foundation of device registration — if `DeviceProperties` entry is missing, the device is silently unsupported regardless of all other registrations.
|
|
92
|
-
|
|
93
|
-
Add a **new dedicated type guard method** (static + instance pair):
|
|
94
|
-
```typescript
|
|
95
|
-
static isNewDevice(type: number): boolean {
|
|
96
|
-
//<Model>
|
|
97
|
-
return DeviceType.ENUM_NAME == type;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public isNewDevice(): boolean {
|
|
101
|
-
return Device.isNewDevice(this.rawDevice.device_type);
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
Update serial number checks if applicable (all are static-only, no instance methods):
|
|
106
|
-
- `isIntegratedDeviceBySn()` — add `sn.startsWith("<model>")` if the device is integrated/standalone
|
|
107
|
-
- `isSoloCameraBySn()` — add `sn.startsWith("<model>")` if it's a solo camera
|
|
108
|
-
- `isSmartDropBySn()` — add if it's a SmartDrop variant
|
|
109
|
-
- `isGarageCameraBySn()` — add if it's a garage camera variant
|
|
110
|
-
- `isFloodlightBySn()` — add if it's a floodlight variant
|
|
111
|
-
|
|
112
|
-
#### `src/http/station.ts`:
|
|
113
|
-
|
|
114
|
-
- `isIntegratedDevice()` — if the device is standalone or can pair as its own station, it may already be covered by `isSoloCameras()`, `isFloodLight()`, etc. Only add explicit check if needed.
|
|
115
|
-
|
|
116
|
-
#### `src/push/service.ts`:
|
|
117
|
-
|
|
118
|
-
- If the device is 4G LTE or needs special push notification handling, expand the normalization block (line 768) to include the new type guard.
|
|
119
|
-
|
|
120
|
-
#### `docs/supported_devices.md`:
|
|
121
|
-
|
|
122
|
-
Add an entry in the correct table section:
|
|
123
|
-
```markdown
|
|
124
|
-
|  | <Display Name> (<Model>) | :wrench: | Firmware: <version> |
|
|
125
|
-
```
|
|
126
|
-
Use `:wrench:` for initial support.
|
|
127
|
-
|
|
128
|
-
### Files to modify in homebridge-eufy-security
|
|
129
|
-
|
|
130
|
-
#### `src/platform.ts` — `register_device()`:
|
|
131
|
-
|
|
132
|
-
Verify the new device type is handled by `register_device()`. This method uses independent `if` blocks (not `else if`) to map device types to accessory classes. If the device is a camera, it falls through to the camera path. If it's a lock, sensor, or SmartDrop, it hits those specific checks. If it's a new category that doesn't match any existing check, the device won't get an accessory — flag this to the user.
|
|
133
|
-
|
|
134
|
-
#### `homebridge-ui/public/utils/device-images.js`:
|
|
135
|
-
|
|
136
|
-
Add a case in the `getImage()` switch:
|
|
137
|
-
```javascript
|
|
138
|
-
case <type_number>: return '<image_large>.png';
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
#### Image assets:
|
|
142
|
-
|
|
143
|
-
- Rename or add images in `eufy-security-client/docs/_media/` (small + large)
|
|
144
|
-
- Rename or add image in `homebridge-eufy-security/homebridge-ui/public/assets/devices/` (large only)
|
|
145
|
-
|
|
146
|
-
## Phase 3 — Implement
|
|
147
|
-
|
|
148
|
-
Execute the plan. Key implementation notes:
|
|
149
|
-
|
|
150
|
-
- **Property mapping**: Use the output from `map-properties.mjs` (Phase 1) as the primary guide. Many property constants have large variant families (e.g. `DeviceMotionDetection*` has 40+ variants, `DeviceFloodlightLight*` has 12+, `DeviceVideoRecordingQuality*` has 11+). When multiple constants match the same `param_type`, pick the variant used by the closest existing device — check the "Used by DeviceTypes" column in the script output and the `--closest` flag results.
|
|
151
|
-
- **Companion custom properties**: Some properties have required companions with `custom_*` keys that never appear in raw device data (they're populated at runtime). The script detects these and marks them with `⚠ companion`. Always include them — omitting a companion breaks functionality silently. Key pairs: `DeviceRTSPStream` → `DeviceRTSPStreamUrl`, `DeviceWifiRSSI` → `DeviceWifiSignalLevel`, `DeviceCellularRSSI` → `DeviceCellularSignalLevel`.
|
|
152
|
-
- **Insert in order**: When adding to enums, switch statements, or `if` chains, maintain numeric ordering by device type number.
|
|
153
|
-
- **Audio recording property**: Different device families use different audio recording property constants (e.g. `DeviceAudioRecordingProperty`, `DeviceAudioRecordingStarlight4gLTEProperty`). Match the closest existing device.
|
|
154
|
-
|
|
155
|
-
### Registration verification checklist
|
|
156
|
-
|
|
157
|
-
After implementing all changes, run the post-implementation verification script:
|
|
158
|
-
```bash
|
|
159
|
-
node homebridge-eufy-security/.claude/skills/new-device-support/verify-device.mjs <ENUM_NAME>
|
|
160
|
-
```
|
|
161
|
-
This automatically checks all required registration points and reports PASS/FAIL:
|
|
162
|
-
|
|
163
|
-
1. `DeviceType` enum definition
|
|
164
|
-
2. `GenericTypeProperty` states
|
|
165
|
-
3. `DeviceProperties` map
|
|
166
|
-
4. `DeviceCommands` map
|
|
167
|
-
5. `StationProperties` map (if device acts as its own station — reported as WARN if missing)
|
|
168
|
-
6. `StationCommands` map (if device has station properties — reported as WARN if missing)
|
|
169
|
-
7. Dedicated type guard method (static + instance) in device.ts
|
|
170
|
-
8. Broad classification methods (isCamera, isLock, etc.) in device.ts
|
|
171
|
-
9. `docs/supported_devices.md` entry (reported as WARN if missing)
|
|
172
|
-
10. `*BySn` serial number methods (reported as WARN if missing — not all devices need these)
|
|
173
|
-
11. device-images.js case in homebridge-eufy-security
|
|
174
|
-
|
|
175
|
-
The script exits with code 1 if any required checks fail. A device type that is defined in the enum but missing from DeviceProperties will silently fall back to GenericDeviceProperties with only ~3 basic properties (name, model, serial). This is the most common implementation error — see upstream issue #853 where LOCK_85V0 was added to the enum but never registered in the lookup maps.
|
|
176
|
-
|
|
177
|
-
## Phase 4 — Build & Lint Verification
|
|
178
|
-
|
|
179
|
-
Run build and lint for both repos. Note: eufy-security-client lint may fail due to a pre-existing `jiti` library issue unrelated to our changes — the TypeScript build succeeding is sufficient validation.
|
|
180
|
-
|
|
181
|
-
## Phase 5 — Git & PR
|
|
182
|
-
|
|
183
|
-
Follow CLAUDE.md Git Workflow for commit messages, branch naming, and PR body format. This skill creates **two PRs** across repos:
|
|
184
|
-
|
|
185
|
-
### eufy-security-client (cross-fork)
|
|
186
|
-
|
|
187
|
-
1. Discard unrelated changes (e.g. `package-lock.json`)
|
|
188
|
-
2. Sync develop: `git fetch upstream && git checkout develop && git merge upstream/develop`
|
|
189
|
-
3. Branch: `git checkout -b feat/<device-slug>`
|
|
190
|
-
4. Stage only: images, `src/http/types.ts`, `src/http/device.ts`, `src/push/service.ts`, `docs/supported_devices.md`
|
|
191
|
-
5. Cross-fork PR:
|
|
192
|
-
```bash
|
|
193
|
-
gh pr create --repo bropat/eufy-security-client --base develop \
|
|
194
|
-
--head lenoxys:feat/<device-slug> \
|
|
195
|
-
--title "feat: add <Device Name> (<Model>, type <number>) support" \
|
|
196
|
-
--body-file /tmp/pr-body-<branch>.md
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### homebridge-eufy-security
|
|
200
|
-
|
|
201
|
-
1. Branch from current beta: `git checkout -b feat/<device-slug>`
|
|
202
|
-
2. Stage: `homebridge-ui/public/utils/device-images.js` + any added image
|
|
203
|
-
3. PR to current beta branch:
|
|
204
|
-
```bash
|
|
205
|
-
gh pr create --base beta-<current-version> \
|
|
206
|
-
--title "feat: add <Device Name> (<Model>) image" \
|
|
207
|
-
--body-file /tmp/pr-body-<branch>.md
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Cross-referencing
|
|
211
|
-
|
|
212
|
-
After both PRs are created, update both bodies so they reference each other.
|