perf(homekit): optimize motion detector with frame-based timing

Replace time.Now() calls in hot path with frame-based timing:
- Pre-compute triggerLevel (integer comparison instead of float division)
- Calibrate hold/cooldown budgets from FPS (default 30fps)
- Periodic FPS recalibration every 150 frames for accuracy
- Active motion path: 47ns → 3.6ns (13x faster)

Update schema.json with detect mode and motion_threshold.
Add threshold tuning guide to README.
This commit is contained in:
Sergey Krashevich
2026-03-05 08:50:27 +03:00
parent a591186da6
commit 78ef8fc064
4 changed files with 204 additions and 110 deletions
+20 -1
View File
@@ -145,7 +145,26 @@ homekit:
motion_threshold: 1.0 # P-frame size / baseline ratio to trigger motion (default: 2.0)
```
The `motion_threshold` controls sensitivity. Lower values = more sensitive. Typical values: 1.5 (high sensitivity) to 3.0 (low sensitivity). Default 2.0 works well for most real cameras with static scenes.
The `motion_threshold` controls sensitivity — it's the ratio of P-frame size to the adaptive baseline. When a P-frame exceeds `baseline × threshold`, motion is triggered.
| Scenario | threshold | Notes |
|---|---|---|
| Quiet indoor scene | 1.31.5 | Low noise, stable baseline, even small motion is visible |
| Standard camera (yard, hallway) | 2.0 (default) | Good balance between sensitivity and false positives |
| Outdoor with trees/shadows/wind | 2.53.0 | Wind and shadows produce medium P-frames, need margin |
| Busy street / complex scene | 3.05.0 | Lots of background motion, react only to large events |
Values below 1.0 are meaningless (triggers on every frame). Values above 5.0 require very large motion (person filling half the frame).
**How to tune:** set `log.level: trace` and watch `motion: status` lines — they show current `ratio`. Walk in front of the camera and note the ratio values:
```
motion: status baseline=5000 ratio=0.95 ← quiet
motion: status baseline=5000 ratio=3.21 ← person walked by
motion: status baseline=5000 ratio=1.40 ← shadow/wind
```
Set threshold between "noise" and "real motion". In this example, 2.0 is a good choice (ignores 1.4, catches 3.2).
**Motion API:**