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:
-
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.
-
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.
-
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).
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:
Firmware analysis. I statically analysed the A329S firmware (the
cardvbinary on the Novatek NA51102) to confirm the undocumented netapp HTTP grammar —http://<cam>/?custom=1&cmd=<id>&par=<value>with XML replies, thecmd=3014settings dump, and the rough command-id ranges. That gave the protocol shape but not what each id means.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 intocommand_map.json— the app's.dbitself is NOT redistributed, andscripts/build_command_map.pyregenerates it. This is what powers the per-setting option labels in the UI.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=3010is format SD, and3013wedges 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:
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).