Skip to the content
PCBKitNew board
2 layers48.4 × 46.1 mmSolstice, the printed circuit board in 3D

Serial-to-CAN gateway for Victron MPPT solar charge controller data

Size
48.4 × 46.1 mm
Copper layers
2
Thickness
1.6 mm
Parts
17
Nets
46
Pads
110
Tracks, vias
140, 11
Pours
4
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
13 Feb 2026
Updated
2 Oct 2026

Overview

Solstice is an open-source printed circuit board by trailcurrentoss, from the trailcurrentoss/TrailCurrentSolstice repository on GitHub, published under the MIT licence. It is a 2-layer board of 48.4 × 46.1 mm with 17 parts on 46 nets, routed with 140 tracks and 11 vias.

It is built around the ESP32-WROOM-32 and SN65HVD230D. Its parts include 6 capacitors, 4 resistors, 3 ICs, 3 connectors and 1 inductor. It belongs with the interfaces and adapters and power boards and the ESP32 boards of this library.

Main components

2

README

README.md

TrailCurrent Solstice

TrailCurrent Solstice

Solar gateway module that reads data from a Victron MPPT (Maximum Power Point Tracker) solar charge controller via serial and relays the readings over a CAN bus interface. Part of the TrailCurrent open-source vehicle platform.

Hardware Overview

  • Board: Waveshare ESP32-S3-RS485-CAN
  • Microcontroller: ESP32-S3
  • Function: Serial-to-CAN bus bridge for Victron MPPT solar charge controller data
  • Key Features:
    • Victron MPPT VE.Direct TEXT protocol parsing (solar data)
    • VE.Direct HEX GET polling for SmartShunt extended data (temperature, midpoint voltage, alarms, history)
    • Load control via VE.Direct HEX SET protocol over CAN
    • CAN bus output at 500 kbps
    • Real-time solar panel monitoring
    • OTA firmware updates via CAN-triggered WiFi + HTTP
    • WiFi credential provisioning over CAN bus

Hardware Requirements

Connections

See DOCS/solstice-pinout.svg for a wiring diagram of all external connections.

Components

  • Board: Waveshare ESP32-S3-RS485-CAN — schematic
  • CAN Bus: Built-in transceiver (TX: GPIO 15, RX: GPIO 16, 500 kbps)
  • Serial: Victron MPPT VE.Direct connection via SH1.0 4-pin JST (RX: GPIO 1, TX: GPIO 2 at 19200 baud)
  • Debug Console: USB CDC (115200 baud)

KiCAD Library Dependencies

This project uses the consolidated TrailCurrentKiCADLibraries.

Setup:

bash
# Clone the library
git clone git@github.com:trailcurrentoss/TrailCurrentKiCADLibraries.git

# Set environment variables (add to ~/.bashrc or ~/.zshrc)
export TRAILCURRENT_SYMBOL_DIR="/path/to/TrailCurrentKiCADLibraries/symbols"
export TRAILCURRENT_FOOTPRINT_DIR="/path/to/TrailCurrentKiCADLibraries/footprints"
export TRAILCURRENT_3DMODEL_DIR="/path/to/TrailCurrentKiCADLibraries/3d_models"

See KICAD_ENVIRONMENT_SETUP.md in the library repository for detailed setup instructions.

Opening the Project

  1. Set up environment variables (see Library Dependencies above)
  2. Open KiCAD:
    bash
    kicad EDA/solstice.kicad_pro
  3. Verify libraries load - All symbol and footprint libraries should resolve without errors
  4. View 3D models - Open PCB and press Alt+3 to view the 3D visualization

Schematic Sheets

The design uses a hierarchical schematic with dedicated sheets:

  • Root - Top-level connections
  • Power - Power distribution and regulation
  • CAN - CAN bus transceiver interface
  • MCU - ESP32 microcontroller and support circuits
  • Connectivity - Serial interface to Victron MPPT

Firmware

ESP-IDF 5.5.2 project in the main/ directory.

Setup:

bash
# Source ESP-IDF environment
source ~/esp/v5.5.2/esp-idf/export.sh

# Set target
idf.py set-target esp32s3

# Build firmware
idf.py build

# Flash to board
idf.py -p /dev/ttyUSB0 flash

# Monitor serial output
idf.py -p /dev/ttyUSB0 monitor

Victron VE.Direct Parameters

The firmware parses the following VE.Direct TEXT protocol fields from the MPPT:

ParameterDescription
VBattery voltage
VPVPanel voltage
PPVPanel power (watts)
IPanel current
CSCharge state
ERRError code
H19-H23Historical yield and power data

The firmware also polls the following SmartShunt registers via VE.Direct HEX GET (one every 2 seconds, ~12 s full cycle):

RegisterDescription
0xEDECBattery temperature (0.01 K)
0x0382Midpoint voltage (mV)
0x031EAlarm reason (bitmask)
0x0300Deepest discharge (0.1 Ah) — H1
0x0305Cumulative Ah drawn (0.1 Ah) — H6
0x0303Charge cycles — H4

CAN Bus Protocol

The gateway uses the following CAN message IDs at 500 kbps:

Message 0x00 (3 bytes) - OTA trigger (received):

ByteDescription
0-2Target device MAC bytes (last 3 bytes, matched against hostname)

Triggers the device to connect to WiFi and start an HTTP OTA server for 3 minutes. Upload firmware with:

bash
curl -X POST http://esp32-XXYYZZ.local/ota --data-binary @build/solstice.bin

Message 0x01 - WiFi credential provisioning (received):

Chunked protocol for sending WiFi SSID and password over CAN. Credentials are stored in NVS and persist across reboots. See ota.h for the protocol details.

Message 0x04 (6 bytes) - Firmware version report (transmitted once on boot):

ByteDescription
0-2Last 3 bytes of device WiFi MAC (matches hostname esp32-XXYYZZ)
3-5Semantic version: major, minor, patch

Sent after CAN initialization. Headwaters uses this to track the running firmware version, including after OTA updates.

Message 0x2C (7 bytes) - Solar panel basics (transmitted every 33ms):

ByteDescription
0-1Panel voltage
2-3Solar watts
4-5Battery voltage
6Solar status

Message 0x2D (3 bytes) - Solar current:

ByteDescription
0Current sign
1-2Current magnitude

Message 0x2E (1 byte) - Load control (received):

ByteDescription
0Load state (0x00=OFF, 0x01=ON, 0x04=Default)

When a 0x2E message is received over CAN, the gateway sends a VE.Direct HEX SET command to register 0xEDAB on the MPPT to control the load output.

Message 0x2B (6 bytes) - Shunt extended live data (transmitted every 33ms):

ByteDescription
0-1Temperature (int16 BE, centidegrees C — multiply by 0.01 for °C)
2-3Midpoint voltage (uint16 BE, millivolts)
4-5Alarm reason (uint16 BE, bitmask)

Message 0x2F (6 bytes) - Shunt extended history (transmitted every 33ms):

ByteDescription
0-1Deepest discharge (uint16 BE, whole Ah)
2-3Cumulative Ah drawn (uint16 BE, whole Ah)
4-5Charge cycles (uint16 BE, count)

Both shunt extended messages are populated by periodic VE.Direct HEX GET requests to the SmartShunt. Values update every ~12 seconds (6 registers polled at 2 s intervals).

Project Structure

text
├── main/                         # ESP-IDF firmware source
│   ├── main.c                    # VE.Direct parser, CAN TX/RX, load control
│   ├── ota.h                     # OTA update and WiFi provisioning header
│   ├── ota.c                     # OTA update and WiFi provisioning
│   ├── idf_component.yml         # Managed component dependencies (mdns)
│   └── CMakeLists.txt            # Component build config
├── EDA/                          # KiCAD hardware design files
│   ├── solstice.kicad_pro
│   ├── solstice.kicad_sch        # Root schematic
│   ├── can.kicad_sch             # CAN subsystem
│   ├── connectivity.kicad_sch    # Serial interface
│   ├── mcu.kicad_sch             # MCU subsystem
│   ├── power.kicad_sch           # Power subsystem
│   └── solstice.kicad_pcb        # PCB layout
├── CAD/                          # Enclosure design
│   └── trailcurrent-solstice-housing.FCStd
├── DOCS/                         # Documentation and diagrams
│   ├── solstice-pinout.svg       # External connection diagram
│   └── ESP32-S3-RS485-CAN-Schematic.pdf
├── partitions.csv                # Dual OTA partition table
├── sdkconfig.defaults            # ESP-IDF build defaults
└── CMakeLists.txt                # ESP-IDF project config

License

MIT License - See LICENSE file for details.

This is open source hardware. You are free to use, modify, and distribute these designs under the terms of the MIT license.

Contributing

Improvements and contributions are welcome! Please submit issues or pull requests.

Support

For questions about:

Parts

17
QtyValueFootprintReferences
322uFCapacitor_SMD:C_1206_3216Metric_Pad1.33x1.80mm_HandSolderC1, C5, C6
210kResistor_SMD:R_1206_3216Metric_Pad1.30x1.75mm_HandSolderR1, R4
10.1uFCapacitor_SMD:C_1206_3216Metric_Pad1.33x1.80mm_HandSolderC2
1100nFCapacitor_SMD:C_1206_3216MetricC4
110uFCapacitor_SMD:C_1206_3216MetricC3
11kResistor_SMD:R_1206_3216Metric_Pad1.30x1.75mm_HandSolderR3
12kResistor_SMD:R_1206_3216Metric_Pad1.30x1.75mm_HandSolderR2
1AP63203WU-7CustomLibraries:AP63203WU7IC1
1Conn_01x04Connector:GenericPad_01x04J3
1Conn_01x04CustomLibraries:CAN_PLUS_POWERJ2
1Conn_01x06Connector_PinHeader_2.54mm:PinHeader_1x06_P2.54mm_HorizontalJ1
1ESP32-WROOM-32RF_Module:ESP32-WROOM-32U1
1NLV32T-3R9J-EF (3.9uH)Inductor_SMD:NLV32T-3R9J-EFL1
1SN65HVD230Package_SO:SOIC-8_3.9x4.9mm_P1.27mmU2

Questions

How big is the Solstice PCB?

It measures 48.4 × 46.1 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Solstice use?

17 parts, built around the ESP32-WROOM-32 and SN65HVD230D. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Solstice KiCad files?

From the trailcurrentoss/TrailCurrentSolstice repository on GitHub, at the commit this page was made from: the board is EDA/solstice.kicad_pcb and its schematic EDA/can.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Solstice design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 2 layers47.5 × 71.5 mmESP32 Wifi2CAN Rev0.1, the printed circuit board in 3D

    ESP32 Wifi2CAN Rev0.1

    ampnics/CAN-to-WiFi-Converter-Dongle-

    CAN to WiFi Converter PCB using ESP32! This step-by-step tutorial covers schematic creation, PCB layout, and best practices for signal integrity. Perfect for automotive and IoT applications!

    72 parts9
  • 2 layers147 × 92 mmVan, the printed circuit board in 3D

    Van

    blinken/vandal

    An ESP32-based lighting control system for campervans (or anything else)

    227 parts6GPL-3.0
  • 2 layersGCAN gauge, the printed circuit board in 3D

    GCAN gauge

    willemcvu/gCAN-gauge

    An open-source ESP32-based programmable digital gauge targeted at EV conversions

    49 parts4MIT
  • 2 layers40 × 75 mmTWC, the printed circuit board in 3D

    TWC

    jnicolson/TWCController

    Wireless Controller for a Gen 2 Tesla Wall Charger (hardware and software)

    45 parts3GPL-3.0
  • 2 layers56.5 × 50.3 mmTesla Ambient Lighting, the printed circuit board in 3D

    Tesla Ambient Lighting

    jaketheduque/ESP32-Ambient-Lighting

    Check out the project website here: https://jaketheduque.github.io/ESP32-Ambient-Lighting/

    32 parts2
  • 4 layers48 × 31.4 mmPelletmon, the printed circuit board in 3D

    Pelletmon

    Majr98/pelletmon

    Monitor Estyma-compatibile boiler via CANbus with WiFi / IoT.

    18 parts1GPL-3.0
  • 2 layers132 × 56 mmDashboard, the printed circuit board in 3D

    Dashboard

    marcutudor79/electronic-module-for-the-dashboard-of-upbdrive-racing-car

    My Bachelor's degree that consists of the electronic module for the Formula Student race car and it's testing module

    127 partsApache-2.0
  • 2 layers26.9 × 21.5 mmTinCAN, the printed circuit board in 3D

    TinCAN

    maxbarkouras/tinCAN-telephone

    Remotely send and receive CAN messages over WiFi.

    5 partsMIT