Skip to content

Contributing

How to get involved with the Xregulator project, what to know before changing code, and what's expected of a contribution. Written for anyone who wants to report a bug, suggest a feature, or submit code.


How to engage

Report unclear behavior even if it may not be a bug — confusing behavior is a documentation defect at minimum.

Before you change code

The following disciplines exist because each one has been violated before, with real consequences.

The telemetry three-way sync

Live data reaches the dashboard over four server-sent-event channels (see the telemetry pipeline). Each channel's packet is a comma-separated list of numbers, matched by position to a field-name array in the browser. That means any field you add or remove must be changed in three places at once:

  1. the firmware field-count marker (the sentinel value at the bottom of the channel's index list, e.g. CSV1_FIELD_COUNT in 3_functions.ino),
  2. the packet-building format string (the snprintf call for that channel in 3_functions.ino — one conversion specifier per field), and
  3. the matching JavaScript field array (CSV1_FIELDS, CSV2_FIELDS, CSV3_FIELDS, or TS_FIELDS in web_src/script.js).

If these three drift out of sync, the failure is silent: the format string drops trailing fields, the browser sees a count mismatch, and the entire channel is rejected — not just your new field. Always verify all three together before calling a telemetry change done.

Pick the right plumbing pattern

There are three established patterns for wiring a new variable through the system, depending on what it is:

  • a fast-changing live value the dashboard should plot in real time — see adding telemetry,
  • a user-configurable setting that persists across reboots and echoes back to its form field — see adding a setting,
  • a button or control on the dashboard that triggers a firmware action — see adding a dashboard control.

Classify first, then follow the matching recipe. The most common mistake is plumbing a setting through a telemetry channel meant for diagnostics, which sends redundant traffic and breaks the echo-on-change behavior.

Comments move with code

When you edit code, edit the comments around it in the same change. A stale comment is worse than none — both humans and AI assistants take comments at face value here. Don't delete existing comments unless the code they describe is gone.

Plain English first in UI copy

Any text a user sees — labels, tooltips, console messages, documentation — leads with plain English and puts the technical term in parentheses after, e.g. "current-limited phase (CC phase)". Raw firmware identifiers (cv_I, VoltageKp, etc.) never appear in user-facing copy; use the dashboard label names instead. No emojis, anywhere.

Expectations for a contribution

  • No formal test suite exists. The bar instead: your change must compile cleanly in the Arduino IDE (board: ESP32-S3 — see Building the Firmware), and you should sanity-test it on a real device or at least exercise the affected dashboard behavior in a browser. Say in the PR what you tested and how.
  • Small, focused pull requests are strongly preferred. One concern per PR. A 50-line change that does one thing reviewably beats a 500-line change that does three.
  • Match the house style. Flat layout, descriptive global names, minimal abstraction. Don't introduce class hierarchies, clever indirection, or new dependencies to "clean things up" — the monolithic style is a deliberate choice (see Start Here).
  • Safety-relevant code gets extra scrutiny. Anything touching the field control loop, the protections, or shutdown paths (charging control, safeties and protections) will be reviewed conservatively and may need bench-test evidence. This device drives real charging hardware on real boats.

License

The project is licensed under the GNU General Public License v3 (GPLv3). By submitting a contribution you agree it is provided under the same license. Don't submit code you don't have the right to license this way.