Finally working decode MPPT

This commit is contained in:
2025-12-29 20:00:05 +11:00
parent d3b1c632db
commit 0863f8572c
3 changed files with 16 additions and 50 deletions

View File

@@ -176,38 +176,6 @@ void setup() {
DEVICE_TYPE_SOLAR_CHARGER // Device type DEVICE_TYPE_SOLAR_CHARGER // Device type
); );
// XXX These numbers make no sesne, one above is correct - wrong MAC?
victron.addDevice(
"Rainbow48Vb", // Device name
"3ffd00b83ffd00be",
"0ec3adf7433dd61793ff2f3b8ad32ed8", // Encryption key (32 hex chars)
DEVICE_TYPE_SOLAR_CHARGER // Device type
);
// WHY this one work?
victron.addDevice(
"Rainbow48Vc", // Device name
"3ffd00a83ffd00ae",
"0ec3adf7433dd61793ff2f3b8ad32ed8", // Encryption key (32 hex chars)
DEVICE_TYPE_SOLAR_CHARGER // Device type
);
// WHY this one work?
victron.addDevice(
"Rainbow48Vd", // Device name
"3fca91c83fca91ce",
"0ec3adf7433dd61793ff2f3b8ad32ed8", // Encryption key (32 hex chars)
DEVICE_TYPE_SOLAR_CHARGER // Device type
);
// WHY this one work?
victron.addDevice(
"Rainbow48Vf", // Device name
"3fcf38283fcf382e",
"0ec3adf7433dd61793ff2f3b8ad32ed8", // Encryption key (32 hex chars)
DEVICE_TYPE_SOLAR_CHARGER // Device type
);
// Example: Solar Charger #1 // Example: Solar Charger #1
/* /*
victron.addDevice( victron.addDevice(

View File

@@ -147,7 +147,7 @@ void VictronBLE::processDevice(BLEAdvertisedDevice advertisedDevice) {
// Get MAC address from the advertised device // Get MAC address from the advertised device
String mac = macAddressToString(advertisedDevice.getAddress()); String mac = macAddressToString(advertisedDevice.getAddress());
String normalizedMAC = normalizeMAC(mac); String normalizedMAC = normalizeMAC(mac);
if (debugEnabled) { if (debugEnabled) {
debugPrint("Raw MAC: " + mac + " -> Normalized: " + normalizedMAC); debugPrint("Raw MAC: " + mac + " -> Normalized: " + normalizedMAC);
} }
@@ -244,16 +244,15 @@ 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("Model ID: 0x" + String(manufacturerData.modelID, HEX));
debugPrint("Readout Type: 0x" + String(manufacturerData.readoutType, 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));
} }
// Get device type from record type field
uint8_t deviceType = manufacturerData.victronRecordType;
// Build IV (initialization vector) from nonce // Build IV (initialization vector) from nonce
// IV is 16 bytes: nonce (2 bytes little-endian) + zeros (14 bytes) // IV is 16 bytes: nonce (2 bytes little-endian) + zeros (14 bytes)
uint8_t iv[16] = {0}; uint8_t iv[16] = {0};
@@ -273,7 +272,7 @@ bool VictronBLE::parseAdvertisement(const String& macAddress) {
// Parse based on device type // Parse based on device type
bool parseOk = false; bool parseOk = false;
switch (deviceType) { switch (manufacturerData.victronRecordType) {
case DEVICE_TYPE_SOLAR_CHARGER: case DEVICE_TYPE_SOLAR_CHARGER:
if (deviceInfo->data && deviceInfo->data->deviceType == DEVICE_TYPE_SOLAR_CHARGER) { if (deviceInfo->data && deviceInfo->data->deviceType == DEVICE_TYPE_SOLAR_CHARGER) {
parseOk = parseSolarCharger(decrypted, sizeof(decrypted), parseOk = parseSolarCharger(decrypted, sizeof(decrypted),
@@ -306,7 +305,7 @@ bool VictronBLE::parseAdvertisement(const String& macAddress) {
break; break;
default: default:
debugPrint("Unknown device type: 0x" + String(deviceType, HEX)); debugPrint("Unknown device type: 0x" + String(manufacturerData.victronRecordType, HEX));
return false; return false;
} }
@@ -315,7 +314,7 @@ bool VictronBLE::parseAdvertisement(const String& macAddress) {
// Call appropriate callback // Call appropriate callback
if (callback) { if (callback) {
switch (deviceType) { switch (manufacturerData.victronRecordType) {
case DEVICE_TYPE_SOLAR_CHARGER: case DEVICE_TYPE_SOLAR_CHARGER:
callback->onSolarChargerData(*(SolarChargerData*)deviceInfo->data); callback->onSolarChargerData(*(SolarChargerData*)deviceInfo->data);
break; break;

View File

@@ -58,16 +58,15 @@ enum SolarChargerState {
// Manufacturer data structure (outer envelope) // Manufacturer data structure (outer envelope)
typedef struct { typedef struct {
uint16_t vendorID; // Victron vendor ID (0x02E1) uint16_t vendorID; // vendor ID
uint8_t beaconType; // Should be 0x10 (Product Advertisement) uint8_t beaconType; // Should be 0x10 (Product Advertisement) for the packets we want
uint8_t modelID; // Model identifier byte uint8_t unknownData1[3]; // Unknown data
uint8_t readoutType; // Type of data readout uint8_t victronRecordType; // Should be 0x01 (Solar Charger) for the packets we want
uint8_t victronRecordType; // Record type (device type) uint16_t nonceDataCounter; // Nonce
uint16_t nonceDataCounter; // Nonce for encryption (IV bytes 0-1) uint8_t encryptKeyMatch; // Should match pre-shared encryption key byte 0
uint8_t encryptKeyMatch; // Should match pre-shared encryption key byte 0 uint8_t victronEncryptedData[21]; // (31 bytes max per BLE spec - size of previous elements)
uint8_t victronEncryptedData[21]; // Encrypted payload (max 21 bytes) uint8_t nullPad; // extra byte because toCharArray() adds a \0 byte.
} __attribute__((packed)) victronManufacturerData; } __attribute__((packed)) victronManufacturerData;
// Decrypted payload structures for each device type // Decrypted payload structures for each device type
// Solar Charger decrypted payload // Solar Charger decrypted payload