/* * sppro_esp32.ino - read a Selectronic SP PRO from an ESP32 over UART2. * * Reuses the portable core unchanged. Copy src/sppro.c, src/sppro.h, src/md5.c * and src/md5.h next to this .ino (Arduino compiles all source in the sketch * folder), or add src/ as a library. * * Wiring (see docs/HARDWARE.md) - the SP PRO port is RS-232 (+/-12V), so a * level shifter is required; do NOT wire it straight to the ESP32: * * SP PRO RJ45 pin 3 (TXD) --> MAX3232 R1IN ; R1OUT --> ESP32 GPIO16 (RX2) * ESP32 GPIO17 (TX2) --> MAX3232 T1IN ; T1OUT --> SP PRO RJ45 pin 6 (RXD) * SP PRO RJ45 pin 4/5 (GND)--> MAX3232 GND --> ESP32 GND (common ground!) * ESP32 3V3 --> MAX3232 VCC (+ four 0.1uF charge-pump caps) * * Set SPPRO_PASSWORD to the inverter's serial-port password ("" if none). */ extern "C" { #include "sppro.h" } static const int PIN_RX = 16; /* ESP32 RX2 <- MAX3232 R1OUT */ static const int PIN_TX = 17; /* ESP32 TX2 -> MAX3232 T1IN */ static const char *SPPRO_PASSWORD = ""; static sppro_scales_t g_scales; static bool g_ready = false; /* ----- transport bound to Serial2 ---------------------------------------- */ static int esp_read(void *ctx, uint8_t *buf, size_t len) { (void)ctx; size_t got = 0; /* brief wait so a frame that is mid-flight is not reported as "empty" */ unsigned long start = millis(); while (got < len && (millis() - start) < 200) { while (Serial2.available() && got < len) { buf[got++] = (uint8_t)Serial2.read(); start = millis(); } if (got == 0) delay(1); else break; } return (int)got; /* 0 on timeout */ } static int esp_write(void *ctx, const uint8_t *buf, size_t len) { (void)ctx; return (int)Serial2.write(buf, len); } static sppro_transport_t g_transport = { esp_read, esp_write, nullptr }; /* ----- sketch ------------------------------------------------------------- */ static bool connect_sppro() { if (sppro_session_login(&g_transport, SPPRO_PASSWORD) != SPPRO_OK) { Serial.println("login failed - check wiring/password"); return false; } if (sppro_session_read_scales(&g_transport, &g_scales) != SPPRO_OK) { Serial.println("could not read scale factors"); return false; } Serial.println("connected to SP PRO"); return true; } static void show(const char *name) { const sppro_reg_t *reg = sppro_reg_by_name(name); double value; if (!reg) return; if (sppro_session_read(&g_transport, reg, &g_scales, &value) != SPPRO_OK) { Serial.printf("%-26s (read error)\n", reg->description); return; } if (reg->conv == SPPRO_C_SHUNT_NAME) Serial.printf("%-26s %12s\n", reg->description, sppro_shunt_name((int)value)); else Serial.printf("%-26s %12.2f %s\n", reg->description, value, reg->units); } void setup() { Serial.begin(115200); Serial2.begin(SPPRO_BAUD, SERIAL_8N1, PIN_RX, PIN_TX); delay(200); g_ready = connect_sppro(); } void loop() { if (!g_ready) { delay(2000); g_ready = connect_sppro(); return; } Serial.println("\n== Selectronic SP PRO =="); show("BatteryVolts"); show("BattSocPercent"); show("BatteryTemperature"); show("DCBatteryPower"); show("LoadAcPower"); show("CombinedKacoAcPowerHiRes"); show("ACGeneratorPower"); delay(5000); }