106 lines
3.2 KiB
Arduino
106 lines
3.2 KiB
Arduino
/*
|
|
* 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);
|
|
}
|