diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 8e06638..3f9393e 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -21,3 +21,36 @@ Arduino/ESP32 library for reading Victron Energy devices via Bluetooth Low Energ **Modified files:** - TODO + +### Session: 2026-02-11 13:51 +**Modified files:** +- .claude/CLAUDE.md +- .claude/scripts/update-claude-md.sh +- TODO +- examples/MultiDevice/src/main.cpp + + +### Session: 2026-02-11 15:57 +**Modified files:** +- .claude/CLAUDE.md +- .claude/scripts/update-claude-md.sh +- TODO +- examples/MultiDevice/src/main.cpp + + +### Session: 2026-02-12 18:02 +**Modified files:** +- .claude/CLAUDE.md +- .claude/scripts/update-claude-md.sh +- TODO +- examples/MultiDevice/src/main.cpp + + +### Session: 2026-02-12 18:02 +**Modified files:** +- .claude/CLAUDE.md +- .claude/scripts/update-claude-md.sh +- TODO +- examples/MultiDevice/src/main.cpp +- library.json + diff --git a/TODO b/TODO index 4ae1fc8..a7647fb 100644 --- a/TODO +++ b/TODO @@ -25,3 +25,7 @@ Seems mbedTLS is better choice as auotmatic hardware support even on ESP32 - whe * Example scan anything * With and without Callback * Platformio.ini files into example data + +# Logging and Debugging + +* The debugging is very verbose and hard to read - maybe group the messages together for repeats diff --git a/examples/Logger/platformio.ini b/examples/Logger/platformio.ini new file mode 100644 index 0000000..0d345cd --- /dev/null +++ b/examples/Logger/platformio.ini @@ -0,0 +1,143 @@ +[env] +lib_extra_dirs = ../.. + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino + +; Serial monitor settings +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder + +; Build flags +build_flags = + -DCORE_DEBUG_LEVEL=3 + +; Library dependencies +lib_deps = + ; VictronBLE library will be automatically included from parent directory + +; Optional: Specify partition scheme if needed +; board_build.partitions = default.csv + +[env:esp32-s3] +platform = espressif32 +board = esp32-s3-devkitc-1 +framework = arduino +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +build_flags = + -D ARDUINO_USB_MODE=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 +# -DCORE_DEBUG_LEVEL=3 + +[env:esp32-s3-debug] +platform = espressif32 +board = esp32-s3-devkitc-1 +framework = arduino +#monitor_speed = 115200 +#monitor_filters = esp32_exception_decoder +upload_protocol = esp-builtin + +; Debug configuration for GDB +debug_tool = esp-builtin +debug_init_break = tbreak setup +debug_speed = 5000 +debug_load_mode = always + +; Build flags for debugging +build_flags = + -DCORE_DEBUG_LEVEL=5 ; Maximum ESP32 debug level + -O0 ; Disable optimization for debugging + -g3 ; Maximum debug information +build_type = debug + +[env:esp32-c3] +platform = espressif32 +framework = arduino +board = esp32-c3-devkitm-1 +board_build.mcu = esp32c3 +board_build.f_cpu = 160000000L +board_build.flash_mode = dio +board_build.partitions = default.csv +monitor_speed = 115200 +monitor_filters = time, default, esp32_exception_decoder +upload_speed = 921600 +# NOTE: Need these two ARDUIO_USB modes to work with serial +build_flags = + -Os + -I src + -D ARDUINO_ESP32C3_DEV + -D CONFIG_IDF_TARGET_ESP32C3 + -D ARDUINO_USB_MODE=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 +lib_deps = + elapsedMillis + +[env:esp32-c3-debug] +platform = espressif32 +board = esp32-c3-devkitc-02 +framework = arduino +monitor_speed = 115200 + +; Upload configuration +upload_protocol = esp-builtin + +; Debug configuration for GDB +debug_tool = esp-builtin +debug_init_break = tbreak setup +debug_speed = 5000 +debug_load_mode = always + +; Build flags for debugging +build_flags = + -DCORE_DEBUG_LEVEL=5 ; Maximum ESP32 debug level + -O0 ; Disable optimization for debugging + -g3 ; Maximum debug information +build_type = debug + +[env:m5stick] +platform = espressif32 +board = m5stick-c +framework = arduino +board_build.mcu = esp32 +board_build.f_cpu = 240000000L +board_build.partitions = no_ota.csv +#upload_protocol = espota +#upload_port = Button.local +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +#debug_tool = esp-prog ; esp-bridge, esp-prog ; or ftdi, esp-builtin, jlink, etc. +# debug_speed = 5000 ; optional: JTAG speed in kHz +#build_flags = +# -DCORE_DEBUG_LEVEL=5 ; ESP32 debug level +# -O0 ; no optimization +# -g3 ; max debug info +build_flags = + -Os +lib_deps = + M5StickC + elapsedMillis + +[env:tough] +board = m5stack-core2 +board_build.mcu = esp32 +platform = espressif32 +framework = arduino +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +debug_tool = esp-bridge ; esp-bridge, esp-prog ; or ftdi, esp-builtin, jlink, etc. +# debug_speed = 5000 ; optional: JTAG speed in kHz +build_flags = + -DCORE_DEBUG_LEVEL=5 ; ESP32 debug level + -O0 ; no optimization + -g3 ; max debug info + -DARDUINO_M5STACK_TOUGH + -DDISPLAY_WIDTH=320 + -DDISPLAY_HEIGHT=240 + -DHAS_TOUCH=1 + -DBUFFER_LINES=10 +lib_deps = + M5Unified + elapsedMillis diff --git a/examples/Logger/src/main.cpp b/examples/Logger/src/main.cpp new file mode 100644 index 0000000..d4a080d --- /dev/null +++ b/examples/Logger/src/main.cpp @@ -0,0 +1,167 @@ +/** + * VictronBLE Logger Example + * + * Demonstrates change-detection logging for Solar Charger data. + * Only logs to serial when a value changes (ignoring RSSI), or once + * per minute if nothing has changed. This keeps serial output quiet + * and is useful for long-running monitoring / data logging. + * + * Setup: + * 1. Get your device encryption keys from the VictronConnect app + * 2. Update the device configurations below with your MAC and key + */ + +#include +#include "VictronBLE.h" + +VictronBLE victron; + +// Tracks last-logged values per device for change detection +struct SolarChargerSnapshot { + bool valid = false; + SolarChargerState chargeState; + float batteryVoltage; + float batteryCurrent; + float panelVoltage; + float panelPower; + uint16_t yieldToday; + float loadCurrent; + unsigned long lastLogTime = 0; + uint32_t packetsSinceLastLog = 0; +}; + +// Store a snapshot per device (index by MAC string) +static const int MAX_DEVICES = 4; +static String deviceMACs[MAX_DEVICES]; +static SolarChargerSnapshot snapshots[MAX_DEVICES]; +static int deviceCount = 0; + +static const unsigned long LOG_INTERVAL_MS = 60000; // 1 minute + +static int findOrAddDevice(const String& mac) { + for (int i = 0; i < deviceCount; i++) { + if (deviceMACs[i] == mac) return i; + } + if (deviceCount < MAX_DEVICES) { + deviceMACs[deviceCount] = mac; + return deviceCount++; + } + return -1; +} + +static String chargeStateName(SolarChargerState state) { + switch (state) { + case CHARGER_OFF: return "Off"; + case CHARGER_LOW_POWER: return "Low Power"; + case CHARGER_FAULT: return "Fault"; + case CHARGER_BULK: return "Bulk"; + case CHARGER_ABSORPTION: return "Absorption"; + case CHARGER_FLOAT: return "Float"; + case CHARGER_STORAGE: return "Storage"; + case CHARGER_EQUALIZE: return "Equalize"; + case CHARGER_INVERTING: return "Inverting"; + case CHARGER_POWER_SUPPLY: return "Power Supply"; + case CHARGER_EXTERNAL_CONTROL: return "External Control"; + default: return "Unknown"; + } +} + +static void logData(const SolarChargerData& data, const char* reason, uint32_t packets) { + Serial.println("[" + data.deviceName + "] " + reason + + " pkts:" + String(packets) + + " | State:" + chargeStateName(data.chargeState) + + " Batt:" + String(data.batteryVoltage, 2) + "V" + + " " + String(data.batteryCurrent, 2) + "A" + + " PV:" + String(data.panelVoltage, 1) + "V" + + " " + String(data.panelPower, 0) + "W" + + " Yield:" + String(data.yieldToday) + "Wh" + + (data.loadCurrent > 0 ? " Load:" + String(data.loadCurrent, 2) + "A" : "")); +} + +class LoggerCallback : public VictronDeviceCallback { +public: + void onSolarChargerData(const SolarChargerData& data) override { + int idx = findOrAddDevice(data.macAddress); + if (idx < 0) return; + + SolarChargerSnapshot& prev = snapshots[idx]; + unsigned long now = millis(); + prev.packetsSinceLastLog++; + + if (!prev.valid) { + // First reading - always log + logData(data, "INIT", prev.packetsSinceLastLog); + } else { + // Check for changes (everything except RSSI) + bool changed = false; + if (prev.chargeState != data.chargeState) changed = true; + if (prev.batteryVoltage != data.batteryVoltage) changed = true; + if (prev.batteryCurrent != data.batteryCurrent) changed = true; + if (prev.panelVoltage != data.panelVoltage) changed = true; + if (prev.panelPower != data.panelPower) changed = true; + if (prev.yieldToday != data.yieldToday) changed = true; + if (prev.loadCurrent != data.loadCurrent) changed = true; + + if (changed) { + logData(data, "CHG", prev.packetsSinceLastLog); + } else if (now - prev.lastLogTime >= LOG_INTERVAL_MS) { + logData(data, "HEARTBEAT", prev.packetsSinceLastLog); + } else { + return; // Nothing to log + } + } + + // Update snapshot + prev.packetsSinceLastLog = 0; + prev.valid = true; + prev.chargeState = data.chargeState; + prev.batteryVoltage = data.batteryVoltage; + prev.batteryCurrent = data.batteryCurrent; + prev.panelVoltage = data.panelVoltage; + prev.panelPower = data.panelPower; + prev.yieldToday = data.yieldToday; + prev.loadCurrent = data.loadCurrent; + prev.lastLogTime = now; + } +}; + +LoggerCallback callback; + +void setup() { + Serial.begin(115200); + delay(1000); + + Serial.println("\n=== VictronBLE Logger Example ===\n"); + + if (!victron.begin(5)) { + Serial.println("ERROR: Failed to initialize VictronBLE!"); + Serial.println(victron.getLastError()); + while (1) delay(1000); + } + + victron.setDebug(false); + victron.setCallback(&callback); + + // Add your devices here + victron.addDevice( + "Rainbow48V", + "E4:05:42:34:14:F3", + "0ec3adf7433dd61793ff2f3b8ad32ed8", + DEVICE_TYPE_SOLAR_CHARGER + ); + + victron.addDevice( + "ScottTrailer", + "e64559783cfb", + "3fa658aded4f309b9bc17a2318cb1f56", + DEVICE_TYPE_SOLAR_CHARGER + ); + + Serial.println("Configured " + String(victron.getDeviceCount()) + " devices"); + Serial.println("Logging on change, or every 60s heartbeat\n"); +} + +void loop() { + victron.loop(); + delay(100); +} diff --git a/examples/MultiDevice/src/main.cpp b/examples/MultiDevice/src/main.cpp index 7126308..bccd870 100644 --- a/examples/MultiDevice/src/main.cpp +++ b/examples/MultiDevice/src/main.cpp @@ -30,8 +30,14 @@ VictronBLE victron; // Device callback class - gets called when new data arrives class MyVictronCallback : public VictronDeviceCallback { public: + uint32_t solarChargerCount = 0; + uint32_t batteryMonitorCount = 0; + uint32_t inverterCount = 0; + uint32_t dcdcConverterCount = 0; + void onSolarChargerData(const SolarChargerData& data) override { - Serial.println("\n=== Solar Charger: " + data.deviceName + " ==="); + solarChargerCount++; + Serial.println("\n=== Solar Charger: " + data.deviceName + " (#" + String(solarChargerCount) + ") ==="); Serial.println("MAC: " + data.macAddress); Serial.println("RSSI: " + String(data.rssi) + " dBm"); Serial.println("State: " + getChargeStateName(data.chargeState)); @@ -47,7 +53,8 @@ public: } void onBatteryMonitorData(const BatteryMonitorData& data) override { - Serial.println("\n=== Battery Monitor: " + data.deviceName + " ==="); + batteryMonitorCount++; + Serial.println("\n=== Battery Monitor: " + data.deviceName + " (#" + String(batteryMonitorCount) + ") ==="); Serial.println("MAC: " + data.macAddress); Serial.println("RSSI: " + String(data.rssi) + " dBm"); Serial.println("Voltage: " + String(data.voltage, 2) + " V"); @@ -84,7 +91,8 @@ public: } void onInverterData(const InverterData& data) override { - Serial.println("\n=== Inverter/Charger: " + data.deviceName + " ==="); + inverterCount++; + Serial.println("\n=== Inverter/Charger: " + data.deviceName + " (#" + String(inverterCount) + ") ==="); Serial.println("MAC: " + data.macAddress); Serial.println("RSSI: " + String(data.rssi) + " dBm"); Serial.println("Battery: " + String(data.batteryVoltage, 2) + " V"); @@ -107,7 +115,8 @@ public: } void onDCDCConverterData(const DCDCConverterData& data) override { - Serial.println("\n=== DC-DC Converter: " + data.deviceName + " ==="); + dcdcConverterCount++; + Serial.println("\n=== DC-DC Converter: " + data.deviceName + " (#" + String(dcdcConverterCount) + ") ==="); Serial.println("MAC: " + data.macAddress); Serial.println("RSSI: " + String(data.rssi) + " dBm"); Serial.println("Input: " + String(data.inputVoltage, 2) + " V"); @@ -157,7 +166,7 @@ void setup() { } // Enable debug output (optional) - victron.setDebug(true); + victron.setDebug(false); // Set callback for data updates victron.setCallback(&callback); @@ -176,6 +185,13 @@ void setup() { DEVICE_TYPE_SOLAR_CHARGER // Device type ); + victron.addDevice( + "ScottTrailer", // Device name + "e64559783cfb", + "3fa658aded4f309b9bc17a2318cb1f56", + DEVICE_TYPE_SOLAR_CHARGER // Device type + ); + // Example: Solar Charger #1 /* victron.addDevice( diff --git a/library.json b/library.json index 33d1298..e82672e 100644 --- a/library.json +++ b/library.json @@ -26,6 +26,11 @@ "name": "MultiDevice", "base": "examples/MultiDevice", "files": ["src/main.cpp"] + }, + { + "name": "Logger", + "base": "examples/Logger", + "files": ["src/main.cpp"] } ], "export": {