@deadeye920/camera-ui-bin-presence
v1.0.20
Published
A camera.ui plugin that watches a fixed corner of the garden, classifies whether both wheelie bins are present using a locally-trained OpenVINO model, and exposes that as a sensor camera.ui automations (and Home Assistant, via camera.ui's HA bridge) can r
Readme
Bin Presence
A camera.ui plugin that watches a fixed corner of the garden, classifies whether both wheelie bins are present using a locally-trained OpenVINO model, and exposes that as a sensor camera.ui automations (and Home Assistant, via camera.ui's HA bridge) can react to.
Why
Steve has two bins that live side by side in the same garden spot. An existing Home Assistant automation already reminds him which bin to put out on collection day — this plugin's job is to confirm whether that actually happened, so a follow-up reminder can fire if both bins are still sitting there when they shouldn't be.
How it works
- The plugin attaches a Classifier-type sensor to each camera it's assigned to.
- It triggers whenever the camera's own object detector reports a person, animal, or vehicle — bins don't move on their own, so it piggybacks on other activity rather than watching continuously. A configurable cooldown (default 60s) avoids saving near-duplicate frames from the same burst of motion.
- On trigger, it pulls a fresh, full-resolution snapshot directly from the camera (not the auto-cropped trigger region the host would otherwise hand it) and crops it to a named Motion Zone, drawn visually via camera.ui's own Edit Zones UI rather than hand-typed pixel coordinates.
- The cropped image is classified by a MobileNetV2 model (trained via transfer learning on manually-sorted snapshots, then exported to OpenVINO IR format) running locally via openvino-node — no cloud calls.
- The result (both_present or one_present, plus confidence) is saved into the snapshot filename's log line, and the sensor's Detected property is set to true when both bins are present (the state worth a reminder for) and false when one's already out.
- The cropped image is also saved to disk either way, split into a per-camera subfolder, building up a labelled-by-hand training set over time for retraining.
Setup
- Install the plugin from the camera.ui plugin store: @deadeye920/camera-ui-bin-presence
- Assign it to each camera that can see the bin corner. Prefer a fixed-angle camera — a camera whose view can move (e.g. PTZ auto-repositioning at night) will crop the wrong area, since the zone's coordinates are percentage-based against whatever the camera is currently looking at.
- On each of those cameras, open Edit Zones -> Motion, draw a zone around the bin corner, and name it to match the plugin's Zone name setting (default: Bins).
- Adjust Cooldown (seconds) if needed (default: 60).
- Build a camera.ui automation: trigger on Sensor Change (All properties) for the Bin Presence sensor, add a Sensor State condition checking Detected (not Labels — see note below), and use Control Sensor actions to drive a switch: Detected=true -> switch on, Detected=false -> switch off. That switch can then be exposed to Home Assistant.
Note: comparing the classifier's Labels property directly in a Sensor State condition was found to always evaluate true regardless of the sensor's actual value — a likely camera.ui automation-engine bug. Checking the boolean Detected property instead works reliably.
Where snapshots land
/mnt/recordings/bin-presence-snapshots//.png
On the Proxmox host, this mergerfs-backed path is also visible at /mnt/pve/cameraui-storage/bin-presence-snapshots/.
Training a new model
Training happens on a separate LXC (bin-training, CT 116) with the same storage mounted in, using a small Python/PyTorch pipeline:
- Sort newly-collected snapshots into training-data/both_present and training-data/one_present using the small local web tool (bin-sorter.py) run on the Proxmox host.
- Run train.py — MobileNetV2 transfer learning with class-weighted sampling, saves model.pth.
- Run export.py — converts to OpenVINO IR format (model.xml + model.bin), with explicit output tensor naming (required, or inference fails with "Attempt to get a name for a Tensor without names").
- Copy both files into this project's model/ folder, rebuild, and republish.
Development
npm install npx tsc --noEmit (type-check) npx tsc (build to dist/) npm version patch npm publish --access public
Then update the plugin version in camera.ui's plugin store.
Note: openvino-node's native runtime is bundled directly into the published package (bundledDependencies) rather than relying on its own postinstall download, since camera.ui's plugin installer runs npm install with scripts disabled. If re-running npm install openvino-node locally, check node_modules/openvino-node/bin/ for symlinks before publishing — they don't survive packaging intact and need converting to real file copies (see CHANGELOG 1.0.13-1.0.17 for the exact commands).
See CHANGELOG.md for full version history.
