Skip to main content
Stylized dawn light over an off-grid camper with solar panels angled toward the sunrise, forest treeline in the foreground

Solstice

Every watt in, every amp out. Solstice bridges a Victron MPPT solar controller and SmartShunt onto the CAN bus so the rest of your rig knows exactly what the sun is doing and exactly where the battery stands, in real time.

What's Inside  /  Module

The Solar & Battery Gateway

One small black box in your rig that listens to Victron and speaks CAN. Solar harvest on one side, battery state of charge on the other, and a single module reporting all of it to Headwaters at 30 Hz.

Built around the Waveshare ESP32-S3 RS485 CAN board. One UART runs VE.Direct to a Victron MPPT charge controller (with bidirectional HEX SET for load control). A second UART reads VE.Direct from a SmartShunt in parallel. The firmware parses both TEXT streams and republishes the values on the TrailCurrent CAN bus at 500 kbps. WiFi credentials and OTA updates travel in over the bus; no local config needed.

ESP32-S3 ESP-IDF VE.Direct CAN Bus MPPT SmartShunt OTA
View on GitHub
TrailCurrent Solstice enclosure rendering

At a Glance

One module. Two Victron talkers. The whole energy picture on the bus.

Solar In

Reads VE.Direct TEXT from a Victron MPPT charge controller at 19200 baud: panel voltage, panel current, solar watts, battery voltage, charge state, and error codes. Republishes as CAN message 0x2C (solar basics) and 0x2D (solar current) every 33 ms.

Battery In

A second UART reads VE.Direct TEXT from a Victron SmartShunt in parallel: battery voltage, current, state of charge, wattage, and time–to–go. Published as CAN messages 0x23 (voltage, current, SOC) and 0x24 (watts, TTG). This replaces the retired Ampline module.

Load Control Out

Listens for CAN message 0x2E from Headwaters and writes a VE.Direct HEX SET to the MPPT's load-output register. Turn the Victron load relay on, off, or back to its default schedule from anywhere on the bus, your phone, or the PWA dashboard.

Bill of Materials

Everything you need to build one Solstice, top to bottom.

Qty Part Description Source
1 Waveshare ESP32-S3-RS485-CAN ESP32-S3 industrial board with on-board CAN transceiver and RS485, wide 6–36 V DC input, screw-terminal I/O, and a 2×10 IDC ribbon header that carries both VE.Direct UART pairs to the MPPT and SmartShunt. Datasheet. Waveshare
2 Deutsch DTM04-4P Connector Sealed 4-pin receptacles, one on each short end of the case. One carries 12 V power and the TrailCurrent CAN pair (CAN-H, CAN-L). The other lands the two Victron VE.Direct serial pairs on a single ribbon cable run. Solid grey TPA with orange wedge lock and silver-plated contact pins. TE Connectivity
1 Victron MPPT Charge Controller Any Victron SmartSolar MPPT with a VE.Direct port. Solstice talks to the TEXT protocol at 19200 baud and issues HEX SET to the load-output register (0xEDAB) when the bus requests a load state change. Victron Energy
1 Victron SmartShunt Any Victron shunt with a VE.Direct port that meets your setup's amperage requirements, wired across the battery bank for state of charge, voltage, current, wattage, and time–to–go. Solstice reads the shunt's VE.Direct TEXT output RX-only. Victron Energy
1 2×10 IDC Ribbon Cable Generic 20-position IDC ribbon cable, 2.0 mm pitch, sized to match the Waveshare board's 2×10 GPIO pin header. One end crimps onto the Waveshare header; the other end breaks out to the two VE.Direct pigtails going to the MPPT and shunt. See solstice-ribbon-cable.svg for the wire-to-GPIO mapping. Hardware store
1 Case Bottom 3D printed. 90 × 110 × 23 mm (including mounting tabs). Integrated standoffs for the Waveshare board, two DTM connector ports on opposite short ends, and four mounting tabs at the corners. Black ABS. 3D printed (STL below)
1 Case Cover 3D printed. 65 × 110 × 7.5 mm. Embossed TrailCurrent logo on the top face, "TC" and "VE" call-outs on opposite corners, and four clearance holes for the cover screws. Black ABS. 3D printed (STL below)
2 M2.5 × 4 mm Machine Screws (board mount) Secure the Waveshare board to its two integrated standoffs inside the case bottom. Black pan-head to match the case. Hardware store
4 M2.5 × 6 mm Machine Screws (cover) Close the cover onto the case bottom at the four corners. Black pan-head. Hardware store

Technical Drawings

Orthographic views of the full assembly, straight out of the FreeCAD model.

Solstice top view with dimensions

Top View

Embossed TrailCurrent logo centered on the cover, "TC" and "VE" call-outs on opposite corners, and four cover screws at the corners. Four mounting tabs flare out from the body; the two DTM connectors peek out of the short ends.

Solstice front view with dimensions

Front (Connector End)

Looking straight at the Deutsch DTM04-4P receptacle. Four silver-plated pins in a grey TPA housing with the orange secondary lock visible on the wire-entry side. This is where 12 V power and the CAN pair land.

Solstice right side with dimensions

Right Side

The long profile. Cover seam runs along the top, mounting tabs flare at the corners, and the DTM connectors protrude slightly past the short ends for cable clearance.

Solstice left side with dimensions

Left Side

Mirror of the right side. The case is symmetric end-to-end, so Solstice drops into the rig the same way no matter which short end points where.

Overall dimensions: 90 × 115 × 27.5 mm (includes mounting tabs and the DTM connector protrusions). Cover area on its own is 65 × 110 mm. Source CAD lives in the CAD folder of the Solstice repo.

3D Printed Parts

Two pieces, black ABS, single filament. A ready-to-print project lives on Makerworld, and the raw .3mf and STL files are in the CAD folder of the repo.

Solstice case bottom, 3D printed

Case Bottom

The main body. Integrated standoffs hold the Waveshare board, two DTM04-4P openings on opposite short ends, and four mounting tabs at the corners for the install. Prints with the open top facing up so the walls grow straight off the build plate.

  • Dimensions: 90 × 110 × 23 mm (with tabs)
  • Material: Black ABS
  • Nozzle: 0.4 mm
  • Layer height: 0.2 mm
  • Walls: 2 perimeters
  • Infill: 15% grid
  • Orientation: Open side up (standoffs point at the nozzle)
  • Supports: Tree (auto), enabled
  • Nozzle temp: 270 °C
  • Bed temp: 90 °C
  • File: BodyTrailCurrentSolsticeEnclosureBottomV4.stl
Solstice case cover, 3D printed

Case Cover

The lid. Embossed TrailCurrent logo centered on the top face, "TC" and "VE" call-outs on opposite corners, and four clearance holes for the cover screws. Prints flat with the logo face up so the embossed detail comes off the nozzle cleanly.

  • Dimensions: 65 × 110 × 7.5 mm
  • Material: Black ABS
  • Nozzle: 0.4 mm
  • Layer height: 0.2 mm
  • Walls: 2 perimeters
  • Infill: 15% grid
  • Orientation: Logo face up
  • Supports: Tree (auto), enabled
  • Nozzle temp: 270 °C
  • Bed temp: 90 °C
  • File: BodyTrailCurrentSolsticeEnclosureCoverV1.stl

Assembly

Drop the Waveshare board in, land the two DTM4 connectors, run the ribbon cable, close the cover.

  1. 1

    Print the case

    Open TrailCurrentSolsticeEnclosure.3mf from the CAD folder in Bambu Studio (or Orca). Black ABS, 0.2 mm layers, 15% grid infill, 2 walls, tree supports on the bottom. The cover prints flat with no supports needed.

  2. 2

    Flash the Waveshare board

    On the bench, clone the Solstice repo, source the ESP-IDF 5.5 environment, run idf.py set-target esp32s3 and idf.py build flash monitor. First boot, the board sits quiet waiting for WiFi credentials over CAN from Headwaters.

  3. 3

    Mount the Waveshare board

    Lower the ESP32-S3-RS485-CAN board into the case bottom so its terminal blocks line up with the interior mounting standoffs. Drive two M2.5 × 4 mm black pan-head screws through the board into the standoffs. Snug, not cranked down; the printed threads are gentle.

  4. 4

    Press in the DTM connectors

    Two Deutsch DTM04-4P receptacles, one on each short end. Press each through its opening from outside and retain with the case-provided lip. One connector lands 12 V / GND / CAN-H / CAN-L to the Waveshare screw terminal. The other feeds the two VE.Direct serial pairs into the case so the ribbon cable can carry them across to the Waveshare GPIO header.

  5. 5

    Route the ribbon cable

    Plug the 2×10 IDC ribbon onto the Waveshare board's GPIO header. The other end breaks out into two VE.Direct pigtails: one to the Victron MPPT (GPIO 3 / GPIO 14 for TX / RX), one to the shunt (GPIO 4 for RX-only). See solstice-ribbon-cable.svg for the exact pin mapping.

  6. 6

    Close the case

    Drop the cover on with the logo facing up and the "TC" / "VE" call-outs oriented toward the right short end. Secure with four M2.5 × 6 mm black pan-head screws at the corners.

  7. 7

    Hook it up

    Mate the DTM cables in the rig: 12 V and the CAN pair to the vehicle bus, and the VE.Direct pigtails to the MPPT and SmartShunt VE.Direct ports. Power up and watch Solstice start publishing CAN IDs 0x23, 0x24, 0x2C, and 0x2D to Headwaters.

CAN Bus Protocol

Seven message IDs at 500 kbps. Every 33 ms, or on demand.

CAN ID Direction Contents
0x23 TX  (every 33 ms) Shunt basic data 1: battery voltage, battery current, state of charge.
0x24 TX  (every 33 ms) Shunt basic data 2: battery wattage and time-to-go.
0x2C TX  (every 33 ms) Solar basics: panel voltage, solar watts, battery voltage, solar status.
0x2D TX  (every 33 ms) Solar current: sign byte plus magnitude.
0x2E RX Load control: 0x00=OFF, 0x01=ON, 0x04=Default. Triggers a VE.Direct HEX SET on the MPPT's load register.
0x00 RX OTA trigger. Matches the last 3 bytes of the device WiFi MAC; wakes Solstice to join WiFi and expose an HTTP OTA endpoint for 3 minutes.
0x04 TX  (boot once) Firmware version report. Last 3 bytes of MAC + semver major/minor/patch. Headwaters uses this to track the running build.

Full wiring diagram lives in DOCS/solstice-pinout.svg on GitHub.

Build Your Own Solstice

Every file is in the repository: KiCAD-compatible pinout docs, ESP-IDF firmware, FreeCAD enclosure, and the Makerworld print profile. Fork it, build it, make it yours.

Solstice on GitHub