Decoding working for MPPT

This commit is contained in:
2025-12-29 20:22:41 +11:00
parent 0863f8572c
commit 26b0196791
5 changed files with 21 additions and 30 deletions

View File

@@ -10,6 +10,8 @@ This is an initial release (v0.1.1) and has not yet been tested with real Victro
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. 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.
## Features ## Features
-**Multiple Device Support**: Monitor multiple Victron devices simultaneously -**Multiple Device Support**: Monitor multiple Victron devices simultaneously

12
TODO
View File

@@ -6,3 +6,15 @@
* Sh3dNg version and examples uses structs to get data - seems to work * Sh3dNg version and examples uses structs to get data - seems to work
* Example generated uses manually managing a string * Example generated uses manually managing a string
* Reconsider what is best and use * Reconsider what is best and use
# Debugging
Use standard ESP32 debugging stuff. Handler should not be string but more like printf? Consider alternatives
Make sure debugging can be to file or serial etc
# Decrypting
Review 2 methods of decrypting and check it is working correctly
Seems mbedTLS is better choice as auotmatic hardware support even on ESP32 - where as the esp_aes version is not portable.

View File

@@ -1,6 +1,6 @@
{ {
"name": "VictronBLE", "name": "VictronBLE",
"version": "0.1.2", "version": "0.2.1",
"description": "ESP32 library for reading Victron Energy device data via Bluetooth Low Energy (BLE) advertisements. Supports SmartSolar MPPT, SmartShunt, BMV, MultiPlus, Orion and other Victron devices.", "description": "ESP32 library for reading Victron Energy device data via Bluetooth Low Energy (BLE) advertisements. Supports SmartSolar MPPT, SmartShunt, BMV, MultiPlus, Orion and other Victron devices.",
"keywords": "victron, ble, bluetooth, solar, mppt, battery, smartshunt, smartsolar, bmv, inverter, multiplus, esp32, iot, energy, monitoring", "keywords": "victron, ble, bluetooth, solar, mppt, battery, smartshunt, smartsolar, bmv, inverter, multiplus, esp32, iot, energy, monitoring",
"repository": { "repository": {

View File

@@ -42,6 +42,7 @@ bool VictronBLE::begin(uint32_t scanDuration) {
if (!pBLEScan) { if (!pBLEScan) {
lastError = "Failed to create BLE scanner"; lastError = "Failed to create BLE scanner";
debugPrint(lastError);
return false; return false;
} }
@@ -60,11 +61,13 @@ bool VictronBLE::begin(uint32_t scanDuration) {
bool VictronBLE::addDevice(const VictronDeviceConfig& config) { bool VictronBLE::addDevice(const VictronDeviceConfig& config) {
if (config.macAddress.length() == 0) { if (config.macAddress.length() == 0) {
lastError = "MAC address cannot be empty"; lastError = "MAC address cannot be empty";
debugPrint(lastError);
return false; return false;
} }
if (config.encryptionKey.length() != 32) { if (config.encryptionKey.length() != 32) {
lastError = "Encryption key must be 32 hex characters"; lastError = "Encryption key must be 32 hex characters";
debugPrint(lastError);
return false; return false;
} }
@@ -83,6 +86,7 @@ bool VictronBLE::addDevice(const VictronDeviceConfig& config) {
// Convert encryption key from hex string to bytes // Convert encryption key from hex string to bytes
if (!hexStringToBytes(config.encryptionKey, info->encryptionKeyBytes, 16)) { if (!hexStringToBytes(config.encryptionKey, info->encryptionKeyBytes, 16)) {
lastError = "Invalid encryption key format"; lastError = "Invalid encryption key format";
debugPrint(lastError);
delete info; delete info;
return false; return false;
} }
@@ -136,7 +140,6 @@ void VictronBLE::loop() {
// BLE callback implementation // BLE callback implementation
void VictronBLEAdvertisedDeviceCallbacks::onResult(BLEAdvertisedDevice advertisedDevice) { void VictronBLEAdvertisedDeviceCallbacks::onResult(BLEAdvertisedDevice advertisedDevice) {
// XXX why victronBLE and not just this? or nothing since inside same object - to do with callback?
if (victronBLE) { if (victronBLE) {
victronBLE->processDevice(advertisedDevice); victronBLE->processDevice(advertisedDevice);
} }
@@ -159,8 +162,6 @@ void VictronBLE::processDevice(BLEAdvertisedDevice advertisedDevice) {
// XXX Storing it this way is not thread safe - is that issue on this ESP32? // XXX Storing it this way is not thread safe - is that issue on this ESP32?
debugPrint("Getting manufacturer data: Size=" + String(mfgData.length())); debugPrint("Getting manufacturer data: Size=" + String(mfgData.length()));
mfgData.copy((char*)&manufacturerData, (mfgData.length() > sizeof(manufacturerData) ? sizeof(manufacturerData) : mfgData.length())); mfgData.copy((char*)&manufacturerData, (mfgData.length() > sizeof(manufacturerData) ? sizeof(manufacturerData) : mfgData.length()));
// XXX Rather than copy, we can use pointers to .data
// Delete string? Or keep, or alternative buuffer handling
} }
// Pointer? XXX // Pointer? XXX
@@ -185,7 +186,6 @@ void VictronBLE::processDevice(BLEAdvertisedDevice advertisedDevice) {
// Check if this is one of our configured devices // Check if this is one of our configured devices
auto it = devices.find(normalizedMAC); auto it = devices.find(normalizedMAC);
if (it == devices.end()) { if (it == devices.end()) {
// XXX Check if the device is a Victron device // XXX Check if the device is a Victron device
// This needs lots of improvemet and only do in debug // This needs lots of improvemet and only do in debug
if (manufacturerData.vendorID == VICTRON_MANUFACTURER_ID) { if (manufacturerData.vendorID == VICTRON_MANUFACTURER_ID) {
@@ -211,8 +211,6 @@ void VictronBLE::processDevice(BLEAdvertisedDevice advertisedDevice) {
DeviceInfo* deviceInfo = it->second; DeviceInfo* deviceInfo = it->second;
// XXX Use struct like code in Sh3dNg
// Check if it's Victron (manufacturer ID 0x02E1) // Check if it's Victron (manufacturer ID 0x02E1)
if (manufacturerData.vendorID != VICTRON_MANUFACTURER_ID) { if (manufacturerData.vendorID != VICTRON_MANUFACTURER_ID) {
debugPrint("Skipping non VICTRON"); debugPrint("Skipping non VICTRON");
@@ -244,11 +242,7 @@ bool VictronBLE::parseAdvertisement(const String& macAddress) {
if (debugEnabled) { if (debugEnabled) {
debugPrint("Vendor ID: 0x" + String(manufacturerData.vendorID, HEX)); debugPrint("Vendor ID: 0x" + String(manufacturerData.vendorID, HEX));
// XXX What is beaconType and modelID and readoutType
debugPrint("Beacon Type: 0x" + String(manufacturerData.beaconType, HEX)); debugPrint("Beacon Type: 0x" + String(manufacturerData.beaconType, HEX));
// debugPrint("Model ID: 0x" + String(manufacturerData.modelID, HEX));
// debugPrint("Readout Type: 0x" + String(manufacturerData.readoutType, HEX));
// recordType - e.g. MPPT ?
debugPrint("Record Type: 0x" + String(manufacturerData.victronRecordType, HEX)); debugPrint("Record Type: 0x" + String(manufacturerData.victronRecordType, HEX));
debugPrint("Nonce: 0x" + String(manufacturerData.nonceDataCounter, HEX)); debugPrint("Nonce: 0x" + String(manufacturerData.nonceDataCounter, HEX));
} }
@@ -266,6 +260,7 @@ bool VictronBLE::parseAdvertisement(const String& macAddress) {
sizeof(manufacturerData.victronEncryptedData), sizeof(manufacturerData.victronEncryptedData),
deviceInfo->encryptionKeyBytes, iv, decrypted)) { deviceInfo->encryptionKeyBytes, iv, decrypted)) {
lastError = "Decryption failed"; lastError = "Decryption failed";
debugPrint(lastError);
return false; return false;
} }
@@ -338,7 +333,6 @@ bool VictronBLE::parseAdvertisement(const String& macAddress) {
} }
// Decrypt advertisement using AES-128-CTR // Decrypt advertisement using AES-128-CTR
// XX Compare mbedlts_aes vs esp_aes
bool VictronBLE::decryptAdvertisement(const uint8_t* encrypted, size_t encLen, bool VictronBLE::decryptAdvertisement(const uint8_t* encrypted, size_t encLen,
const uint8_t* key, const uint8_t* iv, const uint8_t* key, const uint8_t* iv,
uint8_t* decrypted) { uint8_t* decrypted) {
@@ -666,22 +660,6 @@ String VictronBLE::normalizeMAC(String mac) {
// Debug helpers // Debug helpers
void VictronBLE::debugPrint(const String& message) { void VictronBLE::debugPrint(const String& message) {
if (debugEnabled) { if (debugEnabled)
Serial.println("[VictronBLE] " + message); Serial.println("[VictronBLE] " + message);
} }
}
// XXX Can't we use debugPrintf instead for hex struct etc?
void VictronBLE::debugPrintHex(const char* label, const uint8_t* data, size_t len) {
if (!debugEnabled) return;
Serial.print("[VictronBLE] ");
Serial.print(label);
Serial.print(": ");
for (size_t i = 0; i < len; i++) {
if (data[i] < 0x10) Serial.print("0");
Serial.print(data[i], HEX);
Serial.print(" ");
}
Serial.println();
}

View File

@@ -313,7 +313,6 @@ private:
bool parseDCDCConverter(const uint8_t* data, size_t len, DCDCConverterData& result); bool parseDCDCConverter(const uint8_t* data, size_t len, DCDCConverterData& result);
void debugPrint(const String& message); void debugPrint(const String& message);
void debugPrintHex(const char* label, const uint8_t* data, size_t len);
String macAddressToString(BLEAddress address); String macAddressToString(BLEAddress address);
String normalizeMAC(String mac); String normalizeMAC(String mac);