Skip to content

Camera Control in UI #22

Description

@droomurray

Rob,

Thanks for viofosync — it's a really nice piece of work, and it's become the way I manage my A329S footage.

I've opened PR #21 with a feature you might consider merging: a Camera tab and /api/camera/* endpoints to read and adjust the dashcam's own settings over Wi-Fi (parking mode, watermarks, HDR, LEDs, GPS, loop length, bitrate, etc.), alongside the existing sync/browse/export features.

How it was built — I wanted the mapping to be grounded rather than guessed, so it came together in three stages:

  1. Firmware analysis. I statically analysed the A329S firmware (the cardv binary on the Novatek NA51102) to confirm the undocumented netapp HTTP grammar — http://<cam>/?custom=1&cmd=<id>&par=<value> with XML replies, the cmd=3014 settings dump, and the rough command-id ranges. That gave the protocol shape but not what each id means.

  2. App decompilation. To get real semantics I decompiled the official VIOFO Android app (apkeep → jadx) and found it ships a SQLite asset (device-cmd-manager.db) that maps every command id to a key, description, and option enumeration, per camera model. I reformatted just that factual API data into command_map.json — the app's .db itself is NOT redistributed, and scripts/build_command_map.py regenerates it. This is what powers the per-setting option labels in the UI.

  3. Automated testing against a real camera. I then wrote a harness that drives the actual web API and round-trips every setting against my A329S — read current value, write a different valid value, confirm it applied by re-reading the camera's live config, then restore the original — exporting the full settings dump before and after to prove nothing was left changed. That empirical pass is where the safety behaviour came from: it's how I found that some "reads" are actually destructive actions (a bare cmd=3010 is format SD, and 3013 wedges the daemon), which settings are silently rejected while recording (so the layer briefly stops/restarts recording for those), and which simply can't be set over Wi-Fi (resolution) or need a lens that isn't attached.

The result of all that is baked into the safeguards:

  • Destructive commands (format, factory reset, firmware update, delete, reboot, restart-Wi-Fi, SSD format/delete) are on a hard denylist — refused before any request is built and never shown in the UI. Writes are allow-listed to enumerated settings, validated against the camera's own option list, and read back to verify. One request at a time so it won't overrun the camera's single-threaded daemon.
  • Honest about limits. Settings the camera won't change over Wi-Fi (resolution, exposure) or that need an unattached lens are shown read-only with the reason, and the lens-dependent ones re-enable automatically when the rear/interior camera is connected.
  • Tests + docs. Offline unit tests (no hardware needed) for the denylist/validation/verify logic, plus a README section.

One thing I'd flag for your call: that derived command map is reformatted from VIOFO's app data — if you'd rather handle it differently, I'm happy to change it. And it's only been validated against my A329S; other models are mapped from the app data but untested, so it'd benefit from others trying it.

No pressure at all to merge — your project, your call. Happy to adjust anything (squash, trim the data file, rework the UI to match your conventions, whatever helps).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions