Ich habe versucht, die Version aus dem ersten Beitrag hier mit meinen PB2A16S20P zum Laufen zu kriegen (Das sind die BMS, die in den DIY Boxen verbaut sind). Das Einzige was funktioniert hat, waren die Zellspannungen. Ich habe mir den Code mal vorgenommen (ich hoffe der Autor hat kein Problem damit) und in ein PIO Projekt gepackt. Dann habe ich das Parsing komplett neu aufgebaut, ausgerichtet an diesem Dokument und Try/Error. Hat mich ein paar Nächte gekostet und es mag auch noch ein paar Glitches enthalten, aber für mich läuft es schon ganz gut.
Bitte fragt nicht, ob ich das für die Arduino IDE umbauen kann, ich werde es nicht tun. Das Entwickeln und Kompilieren + Flashen ist einfach nur pain in the ass mit der Arduino IDE.
OTA habe ich auch rausgeworfen, weil man mit PIO einwandfrei und schnell bauen und flashen kann.
Wer unterstützen will und kann: bitte gerne. Ich bin in CPP nicht zuhause, es kann also sein, dass manche Dinge suboptimal gecoded sind. Aber dafür ist OpenSource ja da. .
Ich habe eine Möglichkeit hinzugefügt, die Rohdaten (Byte Array) über MQTT mitzuliefern. Diese kommen als base64 codierter String und müssen dekodiert werden. Dazu kann man folgendes NodeJS Script benutzen:
NodeJS auf dem PC installieren
Ein leeres Verzeichnis anlegen und reinwechseln mit der Konsole
npm init eingeben und mit Return alles bestätigen
npm i mqtt eingeben und abwarten
eine Datei index.js erstellen und das script unten reinkopieren
satarten mit node index.js
const fs = require("fs");
const mqtt = require("mqtt");
// MQTT client and device
const client = mqtt.connect("mqtt://192.168.178.195");
const device = "JK-PB2A16S20P-01";
const output = "output.csv";
// MQTT topics
const topic_read = `jk_ble_listener/${device}/debug/rawdata`;
const topic_enable = `jk_ble_listener/${device}/parameter/debugging_active_full`;
let count = 0;
client.on("connect", () => {
client.subscribe(topic_read, (err) => {
if (!err) {
client.publish(topic_enable, "true");
} else {
console.error("Error subscribing to topic:", err);
}
});
});
client.on("message", (topic, message) => {
if (topic === topic_read && !message.toString().includes("not published")) {
decode(message.toString())
}
});
function decode(input) {
// Step 1: Decode the Base64 string to a byte array
const byteArray = Buffer.from(input, "base64");
// Check if the count byte has changed to ignore dupes
if (byteArray[5] != count) {
count = byteArray[5];
// Step 2: Convert the byte array to a comma-separated string
const hexArrayString = Array.from(byteArray, (byte) => byte.toString(16).padStart(2, "0")).join(",");
console.log(hexArrayString);
// Step 3: Write the comma-separated string to a CSV file
fs.appendFile(output, hexArrayString + "\n", (err) => {
if (err) {
console.error("Error appending to CSV file:", err);
}
});
}
}
Im Script muss der Device Name und Eure MQTT Server IP angepasst werden. Das Script schaltet über ein MQTT Topic die Rawdaten auf dem ESP32 ein und loggt sie als CSV auf dem PC
Der Rawdata output startet mit dem Publish eines parameters. Dann kommen die Daten unter /debug/rawdata:
Die CSV, die das NodeJS Script daraus aufbereitet, sieht dann so aus. Man sollte das nicht zu lange laufen lassen, da sehr viele Daten in kurzer Zeit zusammenkommen.
Ich habe bei Jikong eine Dokumentation gefunden, für deren MODBUS Protokoll. Tiefenprüfung ergab, dass die BLE Übertragung genau dieses Protokoll abbildet, wenn man vorne den 6 Byte Header der BLE Telegramme abzieht. Entsprechend konnte Ich den Parser erheblich erweitern und noch mehr Infos aus dem BMS pressen. Zudem konnte ich noch ein paar Werte korrigieren. Hier gibts das PDF, für eigene Experimente. http://www.jk-bms.com/Upload/2024-02-21/1345398693.pdf
Die temperatursensor absence mask ist jetzt auch aufgedröselt und der Status der Batterieheizung ebenfalls. Ich lasse die Masken noch drin, zum Gegenprüfen, ob die bitweise Auflösung korrekt funktioniert. Testen ist kaum möglich ohne das Batterie Pack zu demontieren und ein Kabel durchzuknipsen.
Ich habe noch einen optionalen InfluxDB client eingebaut. Der ESP32 kann damit ausgewählte Werte direkt in eine Influx DB V2 schreiben. Von dort können sie von Grafana abgeholt werden. Wenn #define USE_INFLUXDB auskommentiert ist, wird die ganze Influx Geschichte nicht mitkompiliert. Platzprobleme gibt es aber noch nicht, mit oder ohne
Ich habe das Modul seit ein paar Tage am laufen, funktioniert wirklich super, vielen Dank dafür.
Wäre toll, wenn man hier noch die Häufigkeit der Übertragung ändern könnte, im Augenblick sind das dann doch schon relativ viele Nachrichten die da eintrudeln
Hört sich gut an. Momentan ist es so, das die Werte bei jedem eingehenden BLE Telegramm aufbereitet werden, aber nur die, die sich zum letzten Telegramm geändert haben, auf den MQTT published werden. Ein anderer Ansatz wäre, die Daten erstmal nur intern zu sammeln und dann in einem Schwall nach einer festgelegten Zeit alle zu publishen. Ich hatte das eigentlich für ausreichend sparsam erachtet. Bei mir läuft der Mosquito in einem Docker Container auf einem Synology. Der kann das ab.
Ich denk mir mal was aus. Werde es dann über einen Parameter forken, den man auch über MQTT setzen und ändern kann. Sprich wenn Parameter 0, dann so wie es jetzt ist, anderenfalls, wenn der Parameter >= 1 ist, wird er als Sekunden Pause gewertet. Dann kann man sich rantasten ohne flashen zu müssen.
Frage: nutzt Du MQTT oder schreibst Du gleich in eine Influx DB? Der Influx handler geht nämlich nach dem gleichen Prinzip vor.
Edit: es kommt die Tage ein großer Commit. Ich habe den Code komplett refaktored und modularisiert. So langsam werde ich mit CPP warm. RS485 baue ich gerade ein. Das geile bei diesem BMS ist, wenn man mehrere über RS485 als Cluster verbunden hat, bekommt man die Daten von Allen über die Schnittstelle. Das heißt es reicht dann ein ESP32 um alle Akku Packs auf einmal zu erfassen. Die Daten scheinen auf den ersten Blick die Gleichen zu sein. Ich weiß nicht, warum behauptet wird, das über RS485 weniger Daten kommen. Zumindest bei diesem BMS ist das nicht so. Die Devicedaten habe ich noch nicht gesehen. Dafür die Config Daten, die ich wiederum über BLE noch nicht gesehen habe.
im Moment nutze ich nur MQTT und an Influx DB ist es bisher noch nicht angebunden. Die Anzeige der Daten erfolgt zur Zeit noch in FHEM, also alles noch im Teststadium.
Der Mega Commit ist raus, musst mal das git pullen. Der versprochene r/w Parameter heißt publish_delay und möchte einen Integer Sekunden Wert. Schickst Du eine 5, dann kriegst Du nur alle 5 Sekunden Daten published. Eine 0 bedeutet das bisherige Echtzeit Verhalten. Illegale Werte setzen 0. Es werdn trotzdem nur Werte published, die sich seit dem letzen publish verändert haben. Der Wert wird im NV Ram persistent gespeichert, überlebt also sogar einen Neustart und ein Flashen ohne Erase. Auch wenn der Wert "delay" heißt, bremst er das System nicht aus. Der Parser macht halt einfach ein paar Runden nichts, während weiter fleißig BLE Telegramme empfangen werden.
FHEM ist cool, habe ich lange genutzt und habe auch jetzt noch eine Instanz im Docker Container laufen, die mir ein FTUI Tablett in der Küche beliefert.
Edit: der Default Wert für den publish_delay wird im der config.h gesetzt. Bitte das sample anschauen und in Deiner config.h fehlende #define ergänzen
Läuft fettes danke!
Machst du denn noch etwas anderes als für die Community zu programmieren?
Hast du die Möglichkeit des publishen für publish_delay schon implementiert?
Wenn ja, wohin (topic) muss das gepublisht werden?
Du kannst den …./parameter/publish_delay (Screenshot oben) direkt setzen, der ist r/w. Zumindest bei mir hat es funktioniert. Das Setzen sollte sofort Wirkung zeigen und auch einen Neustart des ESP überleben. Ich nutze den MQTT Explorer unter Windows um zu schauen was auf dem MQTT los ist. Mit dem kann man auch publishen.
Mein Problem war, dass ich keine adäquate Lösung für dieses BMS gefunden habe. Ich habe 2 von den YIXIANG 16S DIY Boxen. Die BMS sind über RS485 Daisychained und der Master hängt über CAN am Victron. Der Victron stellt zwar ein paar der Werte zur Verfügung, aber sehr mager. Daher wollte ich was besseres. Die Lösungen, die man im Netz findet, funktionieren alle nicht wirklich mit diesem BMS. Das Geraffels mit ESP Home wollte ich mir nicht antun. Also musste ich halt selbst was machen. Bin ja Programmierer von Beruf, halt nur nicht in CPP unterwegs.
Ich hänge mal an, was ich gestern über RS486 mitgelogt habe. Das sind, zumindest was den Status der Zellen, Spannungen etc. dieselben Daten, die über BLE kommen. Nur eben von allen BMS, die verbunden sind. Ich habe nur das Problem, dass ich mit offline Daten arbeiten muss, weil die Akkus im Keller stehen. Das debugged sich nicht so toll, wenn man zum Testen durchs ganze Haus rennen muss
wahrscheinlich blamiere ich mich gerade , aber wie bekomme ich die ble Verbindung aktiviert? Unter dem Topic Status wird nur reconnecting angezeigt. Muss ich noch hierzu was einstellen?
@thescc
Du musst entweder in der config.h oder in der platformio.ini bei DEVICENAME den korrekten Namen des BMS setzen. Genau so, wie er Dir im Verbindungsmenü der App angezeigt wird. Default sollte der JK-PB2A16S20P-00 sein. Wenn Du den Namen selbst in der App geändert hast, musst Du diesen nehmen. Wenn Du wie ich 2 BMS hast, wird das zweite magischerweise automatisch JK-PB2A16S20P-01 genannt. Ich vermute mal das 00 / 01 Anhängsel wird durch die Dip Schalter gesetzt. Ich habe den DEVICENAME in die platformio.ini rausgeführt, damit ich schnell 2 ESP flashen kann. Die melden sich immer auf den gleiche 2 Com Ports, sodass ich nur unter dem jeweiligen Project Task auf Upload klicken muss und die jeweilige konfiguration automagisch passt. Ansonsten müsste ich vor jedem flashen den DEVICENAME in der config.h ändern. Der DEVICENAME in der platformio.ini hat Vorrang und überschreibt den, der in der config.h gesetzt ist.
Edit: Du darfst nicht per Handy mit dem BMS verbunden sein. Es funktioniert nur eine Verbindung. Entweder der ESP oder das Handy
Ich habe beim Umbau des BLE Stacks auf NimBLE eine interessante Beobachtung gemacht, die vllt für alle von Nutzen ist, die mit den JK und BLE rumfummeln: Das BMS scheint nach genau 5h den BLE Client rauszuschmeißen. Der ESP re-startet dann und verbindet sich neu. Ich versuche das gerade zu umgehen, indem ich jede Stunde die "info" Anfrage neu rausschicke.
Den Parser habe ich mittlerweile auch erweitert, dass er die beim Start empfangene Config mit verwurstet. Diese kommt nur einmal, bei BLE Neuverbindung. Ebenso wie die Device Infos