Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hallo, ich habe kein ESPHome mit HA möchte aber mein Victron Smart Shunt mit ESP dennoch auslesen und bekomme nur Mist ausgegeben #94

Open
svenessar opened this issue Feb 14, 2025 · 0 comments

Comments

@svenessar
Copy link

svenessar commented Feb 14, 2025

ich komme einfach nicht weiter und werd noch bekloppt :-(

das ist mein Code:

`
#include <BLEDevice.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <aes/esp_aes.h> // ESP32 AES-Bibliothek
#include <ArduinoJson.h>

#define USE_String

// --- BLE Setup ---
BLEScan *pBLEScan;

// Gerätedaten und Schlüssel (hier nur für den SmartShunt)
typedef struct {
String address; // MAC-Adresse
String name; // Gerätename
uint8_t key[16]; // AES-Schlüssel (16 Byte)

// SmartShunt-Daten
uint16_t batteryVoltage; // in mV
int16_t batteryCurrent; // in mA (signed)
uint8_t soc; // in %
uint16_t energy; // firmwareabhängig (z. B. Wh)
uint16_t power; // z. B. in W
uint32_t lastUpdate; // Zeitstempel (millis)
} DeviceKey;

#define MAX_DEVICES 1
DeviceKey deviceKeys[MAX_DEVICES];
int numDevices = 0;

// Hilfsfunktion: Gibt den Index eines Geräts anhand der MAC-Adresse zurück
int getDeviceIndex(const String &address) {
for (int i = 0; i < numDevices; i++) {
if (deviceKeys[i].address == address)
return i;
}
return -1;
}

// --- Victron SmartShunt Datenstrukturen ---
typedef struct {
uint16_t batteryVoltage;
int16_t batteryCurrent;
uint8_t soc;
uint16_t energy;
uint16_t power;
uint8_t padding[7]; // Padding, nicht ausgewertet
} attribute((packed)) victronSmartShuntData;

void publishData(int index) {
StaticJsonDocument<256> doc;
JsonObject device = doc.createNestedObject();
device["address"] = deviceKeys[index].address;
device["name"] = deviceKeys[index].name;
device["batteryVoltage"] = deviceKeys[index].batteryVoltage / 1000.0; // in V
device["batteryCurrent"] = deviceKeys[index].batteryCurrent / 1000.0; // in A
device["soc"] = deviceKeys[index].soc;
device["energy"] = deviceKeys[index].energy;
device["power"] = deviceKeys[index].power;
device["lastUpdate"] = deviceKeys[index].lastUpdate;

String response;
serializeJson(doc, response);
Serial.println("Daten: " + response);
}

// --- BLE Callback für SmartShunt ---
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) override {
#ifdef USE_String
String manData = advertisedDevice.getManufacturerData();
#else
std::string manData = advertisedDevice.getManufacturerData();
#endif
if (!advertisedDevice.haveManufacturerData())
return;

String deviceAddress = advertisedDevice.getAddress().toString();
int deviceIndex = getDeviceIndex(deviceAddress);
if (deviceIndex < 0) {
  // Unbekanntes Gerät – ignorieren
  return;
}

int manDataSize = manData.length();  // Erwartet 29 Byte
if (manDataSize != 29) {
  Serial.printf("Gerät %s: Herstellerdatenlänge %d ≠ 29, überspringe\n", deviceAddress.c_str(), manDataSize);
  return;
}

// Herstellerdaten in ein Byte-Array kopieren
uint8_t manDataBuf[29];

#ifdef USE_String
manData.toCharArray((char *)manDataBuf, 29);
#else
memcpy(manDataBuf, manData.data(), 29);
#endif

// Prüfe Vendor-ID: Bei Victron SmartShunt liegt die Vendor-ID in den ersten 2 Bytes in little-endian!
uint16_t vendorID = (manDataBuf[1] << 8) | manDataBuf[0];
if (vendorID != 0x02e1) {
  // Nicht von Victron
  return;
}

// Wir nehmen an, dass der verschlüsselte Payload 16 Byte lang ist und ab Offset 13 beginnt:
uint8_t encryptedPayload[16];
memcpy(encryptedPayload, manDataBuf + 13, 16);

// Entschlüsseln (AES-128 im ECB-Modus)
uint8_t decryptedPayload[16];
esp_aes_context ctx;
esp_aes_init(&ctx);
uint8_t *key = deviceKeys[deviceIndex].key;
int keyBits = 128;
int status = esp_aes_setkey(&ctx, key, keyBits);
if (status != 0) {
  Serial.printf("Fehler in esp_aes_setkey: %d\n", status);
  esp_aes_free(&ctx);
  return;
}
status = esp_aes_crypt_ecb(&ctx, 0, encryptedPayload, decryptedPayload); // 0 = Entschlüsseln
if (status != 0) {
  Serial.printf("Fehler in esp_aes_crypt_ecb: %d\n", status);
  esp_aes_free(&ctx);
  return;
}
esp_aes_free(&ctx);

// Den entschlüsselten Payload in die SmartShunt-Datenstruktur casten
victronSmartShuntData *shuntData = (victronSmartShuntData *)decryptedPayload;

// Werte aktualisieren
deviceKeys[deviceIndex].batteryVoltage = shuntData->batteryVoltage;
deviceKeys[deviceIndex].batteryCurrent = shuntData->batteryCurrent;
deviceKeys[deviceIndex].soc = shuntData->soc;
deviceKeys[deviceIndex].energy = shuntData->energy;
deviceKeys[deviceIndex].power = shuntData->power;
deviceKeys[deviceIndex].lastUpdate = millis();

Serial.printf("SmartShunt %s: %.2f V, %.2f A, SoC: %d%%, Energy: %d, Power: %d\n",
              deviceAddress.c_str(),
              deviceKeys[deviceIndex].batteryVoltage / 1000.0,
              deviceKeys[deviceIndex].batteryCurrent / 1000.0,
              deviceKeys[deviceIndex].soc,
              deviceKeys[deviceIndex].energy,
              deviceKeys[deviceIndex].power);

publishData(deviceIndex);

}
};

void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("Starte Victron SmartShunt BLE-Scan...");

// --- Konfiguriere den SmartShunt (DeviceKey) ---
numDevices = MAX_DEVICES; // Für dieses Beispiel nur ein Gerät
deviceKeys[0].address = "XXXX"; // Bekannte MAC-Adresse des SmartShunt
deviceKeys[0].name = "shunt";
uint8_t key0[16] = {
XXXXX
};
memcpy(deviceKeys[0].key, key0, 16);

// --- BLE initialisieren ---
BLEDevice::init("");
pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->setInterval(100);
pBLEScan->setWindow(99);

Serial.println("Setup abgeschlossen.");
}

void loop() {
// Starte einen Scan (hier 1 Sekunde)
pBLEScan->start(1, false);
pBLEScan->clearResults(); // Ergebnisse löschen, um Speicher freizugeben
delay(2000);
}
`

das ist meine Ausgabe:
Daten: [{"address":"xxx","name":"shunt","batteryVoltage":21.913,"batteryCurrent":14.473,"soc":5,"energy":31372,"power":10332,"lastUpdate":1631929}]

was totaler Blödsinn ist, weil ich 26,53V/ -5A und 88% habe

kann mir bitte jemand helfen... ich finde leider keine Daten, wie ich die entschlüsselten Daten interpretieren kann.

Vieeeeeelen Dank
Sven

@svenessar svenessar changed the title Halle, ich habe kein ESPHome mit HA möchte aber mein Victron Smart Shunt mit ESP dennoch auslesen und bekomme nur Mist ausgegeben Hallo, ich habe kein ESPHome mit HA möchte aber mein Victron Smart Shunt mit ESP dennoch auslesen und bekomme nur Mist ausgegeben Feb 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant