Improve readme ready for v0.4 release
This commit is contained in:
@@ -252,3 +252,18 @@ a843eb9 Keep v0.3.1
|
||||
- src/VictronBLE.cpp
|
||||
- src/VictronBLE.h
|
||||
|
||||
|
||||
### Session: 2026-02-28 14:40
|
||||
**Commits:**
|
||||
```
|
||||
39a89c8 Versions v0.4 ready for release
|
||||
4944757 Fix to be non blocking without tasks
|
||||
31765c7 Update notes
|
||||
```
|
||||
**Modified files:**
|
||||
- .claude/CLAUDE.md
|
||||
- README.md
|
||||
- VERSIONS
|
||||
- library.json
|
||||
- library.properties
|
||||
|
||||
|
||||
269
README.md
269
README.md
@@ -2,16 +2,15 @@
|
||||
|
||||
ESP32 library for reading Victron Energy device data via Bluetooth Low Energy (BLE) advertisements.
|
||||
|
||||
**⚠️ INITIAL RELEASE - LIMITED TESTING DONE**
|
||||
**⚠️ API CHANGE in v0.4 — not backwards compatible with v0.3.x**
|
||||
|
||||
This is an initial release (v0.3.1) and has been tested with MPPT on an ESP32-S3 and ESP32-C3.
|
||||
Use with caution and please report any issues you encounter. Testing and feedback are greatly appreciated!
|
||||
v0.4 is a major rework of the library internals: new callback API, reduced memory usage, non-blocking scanning. See [VERSIONS](VERSIONS) for full details. A stable **v1.0** release with a consistent, long-term API is coming soon.
|
||||
|
||||
---
|
||||
|
||||
Why another library? Most of the Victron BLE examples are built into other frameworks (e.g. ESPHome) and I want a library that can be used in all ESP32 systems, including ESPHome or other frameworks. With long term plan to try and move others to this library and improve code with many eyes.
|
||||
|
||||
Currently supportin ESP32 S and C series (tested on older ESP32, and ESP32-S3 and ESP32-C3). Other chipsets can be added with abstraction of Bluetooth code.
|
||||
Currently supporting ESP32 S and C series (tested on older ESP32, ESP32-S3 and ESP32-C3). Other chipsets can be added with abstraction of Bluetooth code.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -81,38 +80,34 @@ Use the VictronConnect app to get your device's encryption key:
|
||||
|
||||
VictronBLE victron;
|
||||
|
||||
// Callback for data updates
|
||||
class MyCallback : public VictronDeviceCallback {
|
||||
public:
|
||||
void onSolarChargerData(const SolarChargerData& data) override {
|
||||
Serial.printf("Solar: %.2fV, %.2fA, %dW\n",
|
||||
data.batteryVoltage,
|
||||
data.batteryCurrent,
|
||||
data.panelPower);
|
||||
// Callback — receives a VictronDevice*, switch on deviceType
|
||||
void onVictronData(const VictronDevice* dev) {
|
||||
if (dev->deviceType == DEVICE_TYPE_SOLAR_CHARGER) {
|
||||
Serial.printf("Solar %s: %.2fV %.2fA %dW\n",
|
||||
dev->name,
|
||||
dev->solar.batteryVoltage,
|
||||
dev->solar.batteryCurrent,
|
||||
(int)dev->solar.panelPower);
|
||||
}
|
||||
};
|
||||
|
||||
MyCallback callback;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Initialize library
|
||||
victron.begin(5); // 5 second scan duration
|
||||
victron.setCallback(&callback);
|
||||
victron.setCallback(onVictronData);
|
||||
|
||||
// Add your device (replace with your MAC and key)
|
||||
victron.addDevice(
|
||||
"My MPPT", // Name
|
||||
"AA:BB:CC:DD:EE:FF", // MAC address
|
||||
"0123456789abcdef0123456789abcdef", // Encryption key
|
||||
DEVICE_TYPE_SOLAR_CHARGER // Device type
|
||||
DEVICE_TYPE_SOLAR_CHARGER // Device type (optional, auto-detected)
|
||||
);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
victron.loop();
|
||||
delay(100);
|
||||
victron.loop(); // Non-blocking, returns immediately
|
||||
}
|
||||
```
|
||||
|
||||
@@ -125,130 +120,113 @@ void loop() {
|
||||
```cpp
|
||||
bool begin(uint32_t scanDuration = 5);
|
||||
```
|
||||
Initialize BLE and start scanning. Returns `true` on success.
|
||||
Initialize BLE scanning. Returns `true` on success.
|
||||
|
||||
**Parameters:**
|
||||
- `scanDuration`: BLE scan duration in seconds (default: 5)
|
||||
- `scanDuration`: BLE scan window in seconds (default: 5)
|
||||
|
||||
#### Device Management
|
||||
|
||||
```cpp
|
||||
bool addDevice(String name, String macAddress, String encryptionKey,
|
||||
VictronDeviceType expectedType = DEVICE_TYPE_UNKNOWN);
|
||||
bool addDevice(const char* name, const char* mac, const char* hexKey,
|
||||
VictronDeviceType type = DEVICE_TYPE_UNKNOWN);
|
||||
```
|
||||
Add a device to monitor.
|
||||
Add a device to monitor (max 8 devices).
|
||||
|
||||
**Parameters:**
|
||||
- `name`: Friendly name for the device
|
||||
- `macAddress`: Device MAC address (format: "AA:BB:CC:DD:EE:FF")
|
||||
- `encryptionKey`: 32-character hex encryption key from VictronConnect
|
||||
- `expectedType`: Device type (optional, for validation)
|
||||
- `mac`: Device MAC address (format: `"AA:BB:CC:DD:EE:FF"` or `"aabbccddeeff"`)
|
||||
- `hexKey`: 32-character hex encryption key from VictronConnect
|
||||
- `type`: Device type (optional, auto-detected from BLE advertisement)
|
||||
|
||||
**Returns:** `true` on success
|
||||
|
||||
```cpp
|
||||
void removeDevice(String macAddress);
|
||||
```
|
||||
Remove a device from monitoring.
|
||||
|
||||
```cpp
|
||||
size_t getDeviceCount();
|
||||
size_t getDeviceCount() const;
|
||||
```
|
||||
Get the number of configured devices.
|
||||
|
||||
#### Data Access
|
||||
#### Callback
|
||||
|
||||
```cpp
|
||||
bool getSolarChargerData(String macAddress, SolarChargerData& data);
|
||||
bool getBatteryMonitorData(String macAddress, BatteryMonitorData& data);
|
||||
bool getInverterData(String macAddress, InverterData& data);
|
||||
bool getDCDCConverterData(String macAddress, DCDCConverterData& data);
|
||||
void setCallback(VictronCallback cb);
|
||||
```
|
||||
Get latest data for a specific device. Returns `true` if data is valid.
|
||||
Set a function pointer callback. Called when new data arrives from a device. The callback receives a `const VictronDevice*` — switch on `deviceType` to access the appropriate data union member.
|
||||
|
||||
```cpp
|
||||
std::vector<String> getDevicesByType(VictronDeviceType type);
|
||||
typedef void (*VictronCallback)(const VictronDevice* device);
|
||||
```
|
||||
Get MAC addresses of all devices of a specific type.
|
||||
|
||||
#### Callbacks
|
||||
#### Configuration
|
||||
|
||||
```cpp
|
||||
void setCallback(VictronDeviceCallback* callback);
|
||||
void setMinInterval(uint32_t ms);
|
||||
```
|
||||
Set callback object to receive data updates automatically.
|
||||
|
||||
#### Utilities
|
||||
Set minimum callback interval per device (default: 1000ms). Callbacks are also suppressed when the device nonce hasn't changed (data unchanged).
|
||||
|
||||
```cpp
|
||||
void setDebug(bool enable);
|
||||
```
|
||||
Enable/disable debug output to Serial.
|
||||
|
||||
```cpp
|
||||
String getLastError();
|
||||
```
|
||||
Get last error message.
|
||||
#### Main Loop
|
||||
|
||||
```cpp
|
||||
void loop();
|
||||
```
|
||||
Process BLE scanning and data updates. Call this in your main loop.
|
||||
Call in your main loop. Non-blocking — returns immediately if a scan is already running. Scan restarts automatically when it completes.
|
||||
|
||||
### Data Structures
|
||||
|
||||
#### SolarChargerData
|
||||
#### VictronDevice (main struct)
|
||||
|
||||
All device types share this struct. Access type-specific data via the union member matching `deviceType`.
|
||||
|
||||
```cpp
|
||||
struct SolarChargerData {
|
||||
String deviceName;
|
||||
String macAddress;
|
||||
struct VictronDevice {
|
||||
char name[32];
|
||||
char mac[13]; // 12 hex chars + null
|
||||
VictronDeviceType deviceType;
|
||||
int8_t rssi; // Signal strength (dBm)
|
||||
uint32_t lastUpdate; // millis() of last update
|
||||
bool dataValid; // Data validity flag
|
||||
bool dataValid;
|
||||
union {
|
||||
VictronSolarData solar;
|
||||
VictronBatteryData battery;
|
||||
VictronInverterData inverter;
|
||||
VictronDCDCData dcdc;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
SolarChargerState chargeState; // Charging state
|
||||
#### VictronSolarData
|
||||
|
||||
```cpp
|
||||
struct VictronSolarData {
|
||||
uint8_t chargeState; // SolarChargerState enum
|
||||
uint8_t errorCode;
|
||||
float batteryVoltage; // V
|
||||
float batteryCurrent; // A
|
||||
float panelVoltage; // V (calculated)
|
||||
float panelPower; // W
|
||||
uint16_t yieldToday; // Wh
|
||||
float loadCurrent; // A (if load output present)
|
||||
};
|
||||
```
|
||||
|
||||
**Charge States:**
|
||||
- `CHARGER_OFF` - Off
|
||||
- `CHARGER_LOW_POWER` - Low power
|
||||
- `CHARGER_FAULT` - Fault
|
||||
- `CHARGER_BULK` - Bulk charging
|
||||
- `CHARGER_ABSORPTION` - Absorption
|
||||
- `CHARGER_FLOAT` - Float
|
||||
- `CHARGER_STORAGE` - Storage mode
|
||||
- `CHARGER_EQUALIZE` - Equalize
|
||||
- `CHARGER_INVERTING` - Inverting (HUB-4)
|
||||
- `CHARGER_POWER_SUPPLY` - Power supply mode
|
||||
- `CHARGER_EXTERNAL_CONTROL` - External control
|
||||
**Charge States** (`chargeState` values):
|
||||
`CHARGER_OFF`, `CHARGER_LOW_POWER`, `CHARGER_FAULT`, `CHARGER_BULK`, `CHARGER_ABSORPTION`, `CHARGER_FLOAT`, `CHARGER_STORAGE`, `CHARGER_EQUALIZE`, `CHARGER_INVERTING`, `CHARGER_POWER_SUPPLY`, `CHARGER_EXTERNAL_CONTROL`
|
||||
|
||||
#### BatteryMonitorData
|
||||
#### VictronBatteryData
|
||||
|
||||
```cpp
|
||||
struct BatteryMonitorData {
|
||||
String deviceName;
|
||||
String macAddress;
|
||||
int8_t rssi;
|
||||
uint32_t lastUpdate;
|
||||
bool dataValid;
|
||||
|
||||
struct VictronBatteryData {
|
||||
float voltage; // V
|
||||
float current; // A (+ charging, - discharging)
|
||||
float temperature; // °C (if configured)
|
||||
float auxVoltage; // V (starter battery/midpoint)
|
||||
uint16_t remainingMinutes; // Time remaining
|
||||
float consumedAh; // Ah consumed
|
||||
float temperature; // C (0 if aux is voltage)
|
||||
float auxVoltage; // V (0 if aux is temperature)
|
||||
uint16_t remainingMinutes;
|
||||
float consumedAh; // Ah
|
||||
float soc; // State of charge %
|
||||
|
||||
// Alarms
|
||||
bool alarmLowVoltage;
|
||||
bool alarmHighVoltage;
|
||||
bool alarmLowSOC;
|
||||
@@ -257,39 +235,25 @@ struct BatteryMonitorData {
|
||||
};
|
||||
```
|
||||
|
||||
#### InverterData
|
||||
#### VictronInverterData
|
||||
|
||||
```cpp
|
||||
struct InverterData {
|
||||
String deviceName;
|
||||
String macAddress;
|
||||
int8_t rssi;
|
||||
uint32_t lastUpdate;
|
||||
bool dataValid;
|
||||
|
||||
struct VictronInverterData {
|
||||
float batteryVoltage; // V
|
||||
float batteryCurrent; // A
|
||||
float acPower; // W (+ inverting, - charging)
|
||||
uint8_t state; // Inverter state
|
||||
|
||||
// Alarms
|
||||
bool alarmHighVoltage;
|
||||
uint8_t state;
|
||||
bool alarmLowVoltage;
|
||||
bool alarmHighVoltage;
|
||||
bool alarmHighTemperature;
|
||||
bool alarmOverload;
|
||||
};
|
||||
```
|
||||
|
||||
#### DCDCConverterData
|
||||
#### VictronDCDCData
|
||||
|
||||
```cpp
|
||||
struct DCDCConverterData {
|
||||
String deviceName;
|
||||
String macAddress;
|
||||
int8_t rssi;
|
||||
uint32_t lastUpdate;
|
||||
bool dataValid;
|
||||
|
||||
struct VictronDCDCData {
|
||||
float inputVoltage; // V
|
||||
float outputVoltage; // V
|
||||
float outputCurrent; // A
|
||||
@@ -305,80 +269,54 @@ struct DCDCConverterData {
|
||||
```cpp
|
||||
void setup() {
|
||||
victron.begin(5);
|
||||
victron.setCallback(&callback);
|
||||
victron.setCallback(onVictronData);
|
||||
|
||||
// Add multiple devices
|
||||
victron.addDevice("MPPT 1", "AA:BB:CC:DD:EE:01", "key1...", DEVICE_TYPE_SOLAR_CHARGER);
|
||||
victron.addDevice("MPPT 2", "AA:BB:CC:DD:EE:02", "key2...", DEVICE_TYPE_SOLAR_CHARGER);
|
||||
victron.addDevice("SmartShunt", "AA:BB:CC:DD:EE:03", "key3...", DEVICE_TYPE_BATTERY_MONITOR);
|
||||
victron.addDevice("Inverter", "AA:BB:CC:DD:EE:04", "key4...", DEVICE_TYPE_INVERTER);
|
||||
// Add multiple devices (type is auto-detected from BLE advertisements)
|
||||
victron.addDevice("MPPT 1", "AA:BB:CC:DD:EE:01", "key1...");
|
||||
victron.addDevice("MPPT 2", "AA:BB:CC:DD:EE:02", "key2...");
|
||||
victron.addDevice("SmartShunt", "AA:BB:CC:DD:EE:03", "key3...");
|
||||
victron.addDevice("Inverter", "AA:BB:CC:DD:EE:04", "key4...");
|
||||
}
|
||||
```
|
||||
|
||||
### Manual Data Polling
|
||||
### Handling Multiple Device Types
|
||||
|
||||
```cpp
|
||||
void loop() {
|
||||
victron.loop();
|
||||
|
||||
// Query specific device
|
||||
SolarChargerData mpptData;
|
||||
if (victron.getSolarChargerData("AA:BB:CC:DD:EE:FF", mpptData)) {
|
||||
if (mpptData.dataValid) {
|
||||
// Use data
|
||||
float power = mpptData.panelPower;
|
||||
}
|
||||
void onVictronData(const VictronDevice* dev) {
|
||||
switch (dev->deviceType) {
|
||||
case DEVICE_TYPE_SOLAR_CHARGER:
|
||||
Serial.printf("%s: %.2fV %dW\n", dev->name,
|
||||
dev->solar.batteryVoltage, (int)dev->solar.panelPower);
|
||||
break;
|
||||
case DEVICE_TYPE_BATTERY_MONITOR:
|
||||
Serial.printf("%s: %.2fV %.1f%%\n", dev->name,
|
||||
dev->battery.voltage, dev->battery.soc);
|
||||
break;
|
||||
case DEVICE_TYPE_INVERTER:
|
||||
Serial.printf("%s: %dW\n", dev->name, (int)dev->inverter.acPower);
|
||||
break;
|
||||
case DEVICE_TYPE_DCDC_CONVERTER:
|
||||
Serial.printf("%s: %.2fV -> %.2fV\n", dev->name,
|
||||
dev->dcdc.inputVoltage, dev->dcdc.outputVoltage);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
```
|
||||
|
||||
### Find All Devices of a Type
|
||||
### Callback Throttling
|
||||
|
||||
```cpp
|
||||
void loop() {
|
||||
victron.loop();
|
||||
void setup() {
|
||||
victron.begin(5);
|
||||
victron.setCallback(onVictronData);
|
||||
victron.setMinInterval(2000); // Callback at most every 2 seconds per device
|
||||
|
||||
// Get all solar chargers
|
||||
std::vector<String> mppts = victron.getDevicesByType(DEVICE_TYPE_SOLAR_CHARGER);
|
||||
|
||||
for (const String& mac : mppts) {
|
||||
SolarChargerData data;
|
||||
if (victron.getSolarChargerData(mac, data)) {
|
||||
Serial.println(data.deviceName + ": " + String(data.panelPower) + "W");
|
||||
}
|
||||
}
|
||||
|
||||
delay(5000);
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Callback Interface
|
||||
|
||||
Implement `VictronDeviceCallback` to receive automatic updates:
|
||||
|
||||
```cpp
|
||||
class MyCallback : public VictronDeviceCallback {
|
||||
public:
|
||||
void onSolarChargerData(const SolarChargerData& data) override {
|
||||
// Handle solar charger update
|
||||
}
|
||||
|
||||
void onBatteryMonitorData(const BatteryMonitorData& data) override {
|
||||
// Handle battery monitor update
|
||||
}
|
||||
|
||||
void onInverterData(const InverterData& data) override {
|
||||
// Handle inverter update
|
||||
}
|
||||
|
||||
void onDCDCConverterData(const DCDCConverterData& data) override {
|
||||
// Handle DC-DC converter update
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Data Received
|
||||
@@ -418,7 +356,10 @@ Based on official [Victron BLE documentation](https://www.victronenergy.com/live
|
||||
See the `examples/` directory for:
|
||||
|
||||
- **MultiDevice**: Monitor multiple devices with callbacks
|
||||
- More examples coming soon!
|
||||
- **Logger**: Change-detection logging for Solar Charger data
|
||||
- **Repeater**: Collect BLE data and re-transmit via ESPNow broadcast
|
||||
- **Receiver**: Receive ESPNow packets from a Repeater and display data
|
||||
- **FakeRepeater**: Generate test ESPNow packets without real Victron hardware
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
Reference in New Issue
Block a user