ARES Vehicle Light Controller
Touch dashboard on the field laptop that drives a USB relay board for amber warning and scene-light triggers, with simulation mode, a watchdog and fail-safe ALL OFF.
Release
Section titled “Release”Release details
- Version
- 0.1.0
- Platform
- Windows 11, Python 3.12+
- Stack
- FastAPI, Uvicorn, Jinja2, Pydantic, pySerial
- UI
- Touch-friendly dark console, WebSocket status updates
- Binding
- Local only by default (127.0.0.1:8765)
- Tests
- pytest, 14 tests
- Built with
- OpenAI Codex
Source: Project README, pyproject.toml and default config (repository not public)
Let the operator control amber warning and scene lighting triggers from the same laptop that runs the ARES CF-33 Field Dashboard, with large touch buttons, one-tap profiles, and an ALL OFF that is always visible and always tried first when anything goes wrong.
Constraints
Section titled “Constraints”- Low current only: the software controls a relay board that triggers an external automotive relay and fuse box or a professional lighting controller.
- No law-enforcement features: no siren tones, no red and blue patterns, and no police-specific modes, by design.
- Offline: no cloud, no external database and no internet-hosted assets.
- Fail-safe: channels default to off, and the app attempts ALL OFF on startup, shutdown, disconnect, watchdog timeout and command faults.
Architecture
Section titled “Architecture”Laptop dashboard (FastAPI + WebSocket) │ pySerial, configurable byte templates ▼USB serial relay board (8 channels, low-current triggers) ▼Automotive relay / fuse box or professional controller (fused) ▼LightsThe relay driver layer has a simulation (mock) driver, a generic serial driver and a KMTronic-style driver. Command templates are set in config, so another board can be supported by changing the byte format rather than the code.
Inside the controller
Section titled “Inside the controller”- One command at a time: every channel, profile, pulse and ALL OFF command runs under a single lock, so two taps can never interleave on the serial line.
- Fault handling: if a relay command fails, the system state goes to FAULT, the fault is recorded (the last 25 are kept in memory and all are logged to disk), and the controller immediately tries ALL OFF. Channels switched off this way are marked as controlled by the “safety lockout”.
- Honest ALL OFF: if ALL OFF itself fails, every channel is shown as FAULT with “ALL OFF could not be confirmed” instead of pretending the lights are off.
- Pulse: a channel can be pulsed for a set number of milliseconds and is left off afterwards.
- Watchdog: a background health check runs once per watchdog interval (5 seconds by default, never more often than once a second) and triggers the fault path if the board stops responding.
- Command templates: each template renders the channel number, a zero-based channel index and the on/off state into either hex bytes (
hex:FF 01 01) or ASCII text, and malformed templates are rejected with a clear error. A write that sends fewer bytes than expected is treated as a timeout fault. - Raw command logging: an optional debug setting logs the exact bytes sent to the board, which helps when confirming a board’s protocol on the bench.
- Live status: the dashboard updates over a WebSocket, so every open screen shows the same channel states, faults and active profile.
| Endpoint | Purpose |
|---|---|
GET /api/health |
Compact read-only summary for a parent dashboard tile: ok flag, connection state, simulation mode, watchdog state, active channel count, recent fault count |
GET /api/status |
Full status, including every channel’s state, who last controlled it, and faults |
GET /api/config |
Public configuration (channels and profiles) |
POST /api/connect, POST /api/disconnect |
Open or close the relay board connection |
POST /api/channel/{id}/on, /off, /toggle, /pulse |
Channel commands |
POST /api/profile/{id}/activate |
Apply a profile |
POST /api/all-off |
ALL OFF |
POST /api/simulation-mode |
Turn simulation mode on or off |
GET /api/logs/recent |
Recent command and fault log entries |
WS /ws/status |
Live status stream |
Logs are written as JSON Lines files (command_log.jsonl and fault_log.jsonl), one timestamped entry per command or fault.
Parts list
Section titled “Parts list”| Part | SKU | Price paid | Key specs | Source | Status |
|---|---|---|---|---|---|
| Field laptop (Windows 11) | TBD | TBD | TBD | TBD | Installed |
| USB serial relay board, 8 channels (KMTronic or Devantech style) | TBD | TBD | Model and byte format to confirm from the board manual | TBD | Planned |
| Automotive relay and fuse box | TBD | TBD | Load-rated, fused near the battery | TBD | Planned |
| Physical kill switch and backup switch panel | TBD | TBD | TBD | TBD | Planned |
Configuration
Section titled “Configuration”Default relay channels (labels are editable in config):
| Channel | Label | Default |
|---|---|---|
| 1 | Rear Warning (amber) | Off |
| 2 | Side Warning (amber) | Off |
| 3 | Front Warning (amber or white) | Off |
| 4 | Scene Left | Off |
| 5 | Scene Right | Off |
| 6 | Rear Scene / Work Light | Off |
| 7 | Brake Override / Brake Pop Hold (only through a compliant controller) | Off |
| 8 | Spare | Off |
Profiles: Parked Incident, Roadside Warning, Scene Lighting, Low Power, Night (dims the dashboard only) and All Off. A profile changes only the channels it lists.
Laptop-specific settings, such as the COM port, go in a local config file that is never committed.
Build steps
Section titled “Build steps”- Install Python 3.12 or newer.
- Run
install_windows.bat, thenrun_windows.bat. The dashboard opens athttp://127.0.0.1:8765. - Leave simulation mode on until the relay board’s command format is confirmed on the bench.
- Copy the example local config, set the board’s COM port, and verify ALL OFF with no lighting loads connected.
- Only then connect low-current trigger wiring to the fused, relay-controlled lighting system.
Testing and verification
Section titled “Testing and verification”| Area | Status |
|---|---|
| pytest suite (config, mock driver, controller safety, profiles, API) | 14 passed on 2026-10-26, run in simulation mode on Linux with Python 3.13 for this page |
| Windows install and run scripts | Not re-run for this page |
| Relay board on the bench | Not yet tested |
| In-vehicle installation | Not installed |
The 14 tests:
- Config: the default config loads correctly; a malformed config fails with a clear error; an environment override file layers over the defaults.
- Mock relay driver: turns channels on and off; ALL OFF turns every channel off; an invalid channel is rejected.
- Controller: an invalid channel is rejected; activating a profile applies its channel states; ALL OFF turns every channel off.
- API: the status endpoint returns the expected structure; the health endpoint is usable by a parent dashboard; the dashboard page renders; simulation mode works with no serial hardware; the buttons toggle profiles and ALL OFF.
Safety notes
Section titled “Safety notes”- Fuse every lighting circuit near the battery, use load-rated relays and wire, and route wiring through grommets and loom.
- Keep a physical kill switch and a backup switch panel so the lights can be controlled if the laptop, relay board or software fails.
- Keep the server bound to the local machine. The LAN test runner is for bench testing on a trusted network only.
How this relates to the F-150 build
Section titled “How this relates to the F-150 build”My F-150 upfit is built around a Whelen CanTrol WC Gen 3 as the lighting controller and siren amplifier. This controller is a separate software project. It is not part of the CanTrol output plan and does not change the truck’s install configuration.
Lessons learned
Section titled “Lessons learned”- Writing the safety rules into the project’s instructions for the coding agent (low current only, ALL OFF always visible, no siren features) kept every later change inside those limits.
Open items
Section titled “Open items”- Choose and document the relay board model, and confirm its byte format from the manual.
- Bench test ALL OFF and the watchdog on the real board with no loads connected.
- Run the test suite on Windows with Python 3.12 and record the result.
- Decide whether the repository will be public.
Changelog
Section titled “Changelog”Project page published.
Rollback: Revert the commit that added this page.