Files
DoorCounter/README.md
Peter Woolery 62931e26ff fix(cv): add per-direction crossing cooldown to suppress track-churn double-counts
When a blob briefly drops below CV_MIN_BLOB_PX, its track is killed and respawns,
causing the same person to generate multiple counts per visit (~50/min observed
in field). Add a per-direction cooldown (default 5 frames ≈ 0.8s @ 5 fps) that
drops subsequent entries (or exits) within the window of the last counted one.
Entry and exit cooldowns are tracked independently.

Fixed at compile time for now; exposing as a server-push tunable is deferred
until the server-push-config branch lands. See docs/server-prompt-crossing-
cooldown.md for the server-side coordination notes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 06:33:11 -07:00

119 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DoorCounter
Retail door traffic counter using M5Stack TimerCamera-F (ESP32 + OV3660). Counts entries/exits via overhead camera CV, passively scans BLE foot traffic, and reports hourly to `logs.research.bike`.
## Hardware
- **Device**: M5Stack TimerCamera-F (ESP32-S, OV3660, PSRAM, WiFi/BLE)
- **Mount**: Overhead, camera pointing straight down, centered above doorway
- **Power**: USB (any phone charger)
## Firmware
Built with PlatformIO. Target: `timercam`.
```bash
cd firmware
pio run -t upload --upload-port /dev/ttyUSB0
```
### What it does
| Module | Behavior |
|--------|----------|
| CV pipeline | 5 fps, 96×96 grayscale, blob tracking, line-crossing count with per-direction cooldown |
| BLE scanner | Continuous passive scan; deinits during hourly upload to free heap |
| Reporter | Hourly HMAC-signed POST; 60s boot report for fast connectivity check |
| Provisioning | Captive portal AP on first boot for WiFi setup |
| OTA | Arduino OTA; operator push via `ota_push.py` |
### Reporting intervals
- **First report**: 60 seconds after NTP sync (connectivity check)
- **Subsequent reports**: every 3600 seconds
### Crossing cooldown
To suppress double-counts from track churn (a blob briefly dropping below the
minimum-blob-pixel threshold, causing the tracker to kill and respawn a track
that then re-crosses the line), each direction enforces a cooldown window
between counted crossings. Default: `CV_CROSSING_COOLDOWN_FRAMES = 5`, which
suppresses any second crossing in the same direction whose frame gap is `< 5`
— ≈0.8s at 5 fps. Entries and exits maintain separate cooldowns, so a real entry
immediately followed by a real exit still counts both. See
`firmware/lib/cv/cv.h`.
## Operator Setup
### 1. Flash firmware
```bash
cd firmware
pio run -t upload --upload-port /dev/ttyUSB0
```
### 2. Provision device identity
```bash
python tools/flash_device.py \
--port /dev/ttyUSB0 \
--device-id dc-0042 \
--location-id retailer-123 \
--hmac-secret <32-byte-hex> \
--wifi-ssid "StoreWiFi" \
--wifi-password "secret"
```
WiFi credentials are optional — if omitted, device starts captive portal on boot.
### 3. OTA updates
```bash
python tools/ota_push.py \
--host dc-0042.local \
--firmware firmware/.pio/build/timercam/firmware.bin
```
## End User Setup
1. Mount device overhead, camera pointing straight down
2. Plug into USB power
3. Connect phone to `DoorCounter-Setup` WiFi
4. Browser opens automatically → enter store WiFi password → done
**LED indicators**: Red = no WiFi · Blue = counting · Yellow = uploading
## API
Endpoint: `http://logs.research.bike`
| Endpoint | Data |
|----------|------|
| `POST /api/v1/camera/events/batch` | Hourly entry/exit counts |
| `POST /api/v1/events/batch` | Hourly BLE proximity records |
| `POST /api/v1/heartbeat` | Device health (uptime, RSSI, pending records) |
All requests are HMAC-SHA256 signed. See [design spec](docs/superpowers/specs/2026-04-13-door-counter-design.md) for full API shapes and auth scheme.
## Project Structure
```
DoorCounter/
├── firmware/
│ ├── platformio.ini
│ ├── lib/hmac/ — HMAC-SHA256 signing library
│ └── src/
│ ├── main.cpp — FreeRTOS tasks, boot sequence
│ ├── config.* — NVS read/write
│ ├── provisioning.* — captive portal
│ ├── camera.* — frame capture + CV pipeline
│ ├── ble_scanner.* — BLE passive scan
│ └── reporter.* — hourly batch POST + local buffer
├── tools/
│ ├── flash_device.py — NVS provisioning script
│ └── ota_push.py — OTA push script
├── docs/superpowers/specs/
│ └── 2026-04-13-door-counter-design.md
└── server/ — API server (separate deployment)
```