2026-06-16 05:02:54 +10:00
2026-06-16 05:02:54 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 04:59:02 +10:00
2026-06-16 05:02:54 +10:00

SPPro Access

Build a system that can connect to an SPPro Serial Port to get sensible data out of it to display it on a serial console and be used in other projects.

Serial decoding is ported to portable C from the open-source neerolyte/selpi project.

This repo is a portable C parser for the SP PRO serial protocol (ported from neerolyte/selpi), packaged as a PlatformIO / Arduino library with an optional thin C++ wrapper. Full protocol notes are in docs/PROTOCOL.md and the ESP32 wiring in docs/HARDWARE.md.

Layout

src/      sppro.h / sppro.c   portable C core: CRC, frame build/parse,
          md5.h  / md5.c       register map + scaling, MD5 login, session layer
          Sppro.h             optional header-only C++/Arduino wrapper (any Stream)
examples/ Esp32SerialMonitor/ ESP32 example (.ino + platformio.ini)
docs/     PROTOCOL.md         wire protocol, CRC, login, register map + scaling
          HARDWARE.md         RS-232 pinout and MAX3232 -> ESP32 wiring
extras/   host/main.c         Linux serial-console dashboard (termios)
          tests/test_sppro.c  host known-answer tests (no hardware)
          Makefile            host build (test / console)
library.json, library.properties, keywords.txt   PlatformIO + Arduino manifests

The core (src/sppro.*) is C99, no dynamic allocation and no I/O — it builds/parses byte buffers and converts raw words to units. I/O is supplied by the caller through a small sppro_transport_t read/write callback, so the same code runs on a host, an MCU, or anything with a serial port. Only src/ and examples/ are part of the published library; extras/ is development tooling (Arduino ignores it).

Use on Arduino / ESP32 (PlatformIO or Arduino IDE)

Add the library (lib_deps = SPPro in PlatformIO once published, or Sketch → Include Library in the Arduino IDE), then use the Sppro wrapper, which works over any Arduino Stream (HardwareSerial, SoftwareSerial, WiFiClient, …):

#include <Sppro.h>
Sppro sp(Serial2);                    // wraps any Stream

void setup() {
  Serial2.begin(57600, SERIAL_8N1, 16, 17);   // via a MAX3232 level shifter
  sp.login("");                                // "" = no serial password
  sp.readScales();
}
void loop() {
  Serial.println(sp.value("BatteryVolts"));    // scaled value, or NAN on error
  delay(5000);
}

A complete ESP32 example is in examples/Esp32SerialMonitor/; build it standalone with cd examples/Esp32SerialMonitor && pio run (it links the parent library via lib_deps = symlink://../..). See docs/HARDWARE.md — the SP PRO port is RS-232 (±12 V) and needs a MAX3232 level shifter; never wire it straight to a GPIO.

Build & test on a host (no hardware)

cd extras
make test     # build and run the host unit tests
make host     # build ./build/sppro-console

Then, with a real SP PRO + USB-RS232 adapter:

./build/sppro-console /dev/ttyUSB0 [serial_password] [interval_seconds]

It logs in, reads the device scale factors, and prints a refreshing dashboard of battery voltage, state of charge, load/solar/generator power, and energy totals. The serial-port password is set on the inverter (front panel → Settings → Communications); pass "" if none is configured, or set SPPRO_PASSWORD.

Use the pure C core (non-Arduino: ESP-IDF, STM32, Linux, Zephyr …)

#include "sppro.h"

sppro_transport_t t = { my_read, my_write, my_ctx };   /* your serial callbacks */
sppro_session_login(&t, "");                            /* MD5 challenge/response */

sppro_scales_t scales;
sppro_session_read_scales(&t, &scales);

double soc, vbat;
sppro_session_read(&t, sppro_reg_by_name("BattSocPercent"), &scales, &soc);
sppro_session_read(&t, sppro_reg_by_name("BatteryVolts"),   &scales, &vbat);

extras/host/main.c is a full worked example of the two callbacks (termios). For environments with their own protocol loop, the pure helpers (sppro_build_query, sppro_parse_query_response, sppro_decode, sppro_crc16, sppro_login_response) can be used without the session/transport layer.

Status & caveats

  • Verified by host unit tests (cd extras && make test): CRC against selpi's documented 0xa000 frame, MD5 known-answers, frame round-trips, and the scaling formulas. The ESP32 example + C++ wrapper are verified to compile/link via PlatformIO. Not yet verified against physical hardware — confirm decoded values against the inverter's own display.
  • On 8-bit AVR, double is 32-bit float, so very large Wh accumulators lose some precision (fine for display). Use the 32-bit-int register types directly if you need exact counts.
  • Read-only monitoring is the focus. Write framing (sppro_build_write / sppro_session_write) exists because login needs it, but no inverter-setting writes are wired into the demos.
  • The register table is a useful subset; add rows from selpi memory/variable.py as needed (decoding is table-driven).

Not-yet-mapped registers (future work)

SPPRO_REGISTERS covers all the live measurements plus the most useful energy totals. The following entries exist in selpi memory/variable.py but are not in the table yet. All are decodable by the existing converters — adding them is pure data (new rows), no new code.

Scale factor (already used internally via sppro_scales_t, just not exposed as a row):

Name Addr Type Conv
CommonScaleForInternalVoltages 41005 u16 raw

Battery "out" energy accumulators (all u32, dc_wh):

Name Addr
BattOutkWhAcc 41143
QuickView_BattOutkWhAcc 41178
BattOutkWhPreviousAcc 41356
BattOutkWh7DayAcc / …AccAvg 41358 / 41360
BattOutkWh30DayAcc / …AccAvg 41362 / 41364
BattOutkWh365DayAcc / …AccAvg 41366 / 41368
BattOutkWhYearAcc / …AccAvg 41370 / 41372
BattOutkWhResetableAcc / …AccAvg 41374 / 41376

Other DC energy:

Name Addr Type Conv
DCkWhOut 41257 u32 dc_wh
Shunt1WhTotalAcc 41305 s32 dc_wh
Shunt1WhTodayAcc 41146 s16 dc_wh

AC energy (input / export / load / solar):

Name Addr Type Conv
ACInputWhTotalAcc 41459 u32 ac_wh
ACInputWhTodayAcc 41151 u16 ac_wh
ACExportWhTotalAcc 41499 u32 ac_wh
ACExportWhTodayAcc 41154 u16 ac_wh
ACLoadWhAcc 41150 u16 ac_wh
ACSolarWhTotalAcc 41519 u32 ac_wh
ACSolarWhTodayAcc 41157 s16 ac_wh

Two quirks when transcribing these:

  • ACSolarWhTotalAcc (41519) is the same address as the already-included TotalKacokWhTotalAcc (41519) — selpi just has two names for it.
  • ACGeneratorPower appears twice in selpi's MAP; the second definition wins (s16, ac_w_signed) — that is the one already in the table. The first (u32, ac_w) is dead.

See Also

S
Description
Seletronics SPPro pure C serial decoder and Arduino wrappers.
Readme MIT 73 KiB
Languages
C 91%
C++ 7.2%
Makefile 1.8%