BiasFandClaude Opus 5 fc73f730a7 BMS: Warten auf die Notify-Bestätigung nicht mehr endlos
Die Suche nach dem richtigen Verbindungsweg blieb auf dem ersten
Kandidaten stehen: gesendet wurde erst, nachdem iOS das Abonnieren der
Notify-Charakteristik bestätigt hat. Bestätigt ein Modul das nie – bei
der WattCycle-Batterie auf FFF1 der Fall –, wurde weder je eine Anfrage
geschickt noch zum nächsten Kandidaten gewechselt. Die Diagnose zeigte
dauerhaft "1 von 16" und "0 Anfragen / 0 Byte".

Die Aktivierung eines Kandidaten hat jetzt ein Zeitlimit von vier
Sekunden. Läuft es ab, geht es zum nächsten; ist es der einzige Weg,
wird trotzdem gesendet – manche Module antworten auch ohne bestätigtes
Abonnement. Ein Token verhindert, dass verspätete Rückmeldungen eines
bereits verworfenen Kandidaten den aktuellen durcheinanderbringen.

Damit sich Fortschritt überhaupt beobachten lässt, wird die Diagnose
jetzt bei jeder gesendeten Anfrage aktualisiert statt nur am Ende einer
Runde, und zeigt zusätzlich Verbindungszustand, ob der Empfang abonniert
ist, und wann zuletzt gesendet wurde. Die Suche ist enger getaktet, damit
alle Wege in gut zwei Minuten durch sind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:38:31 +02:00
2026-08-30 10:36:52 +02:00
2026-08-30 10:36:52 +02:00
2026-08-30 10:36:52 +02:00
2026-08-30 10:36:52 +02:00

Camper Monitor

iOS-App, die per Bluetooth LE die Energieanlage im Wohnmobil ausliest:

Gerät Weg Was ankommt
Victron Ladebooster (Orion-TR Smart / Orion XS) Instant Readout im Advertisement Ein-/Ausgangsspannung, beim XS auch Ströme und Ladeleistung, Zustand, Abschaltgrund
Victron Solarladeregler (SmartSolar MPPT) Instant Readout im Advertisement PV-Leistung, Batteriespannung, Ladestrom, Tagesertrag, Laststrom, Ladezustand (Bulk/Absorption/Float)
Batterie-BMS (Bulltron/Daly, WattCycle/JBD) GATT-Verbindung, alle 5 s abgefragt SoC, Spannung, Strom, Restkapazität, alle Einzelzellspannungen, Zelldifferenz, Temperaturen, Zyklen, MOSFET-Status

Ein Victron SmartShunt/BMV wird ebenfalls unterstützt, falls später einer dazukommt.

Bauen und installieren

open /Users/fritob/GIT/Camper-Management/CamperMonitor.xcodeproj

Dann in Xcode:

  1. Target CamperMonitorSigning & Capabilities → dein Apple-Team auswählen. Die Bundle-ID de.fritob.CamperMonitor ggf. anpassen, falls sie schon vergeben ist.
  2. iPhone per Kabel anschließen, oben als Ziel wählen, ⌘R.

Wichtig: Der Simulator hat kein Bluetooth. Die App startet dort, findet aber nie ein Gerät. Zum Testen muss sie auf ein echtes iPhone.

Mit einem kostenlosen Apple-Account läuft die App 7 Tage und muss dann neu installiert werden; mit einem bezahlten Developer-Account ein Jahr.

Einrichtung in der App

Victron-Geräte

Victron-Geräte senden ihre Messwerte etwa im Sekundentakt verschlüsselt im BLE-Advertisement. Es wird nichts verbunden und nichts gestört VictronConnect kann parallel laufen. Dafür brauchst du pro Gerät einmalig den Schlüssel:

  1. VictronConnect öffnen, Gerät anwählen
  2. Zahnrad (Einstellungen) → ⋮ oben rechts → Produkt-Info
  3. Instant Readout einschalten
  4. Verschlüsselungsdaten anzeigen → der Schlüssel sind 32 Hex-Zeichen

In der App: + → Gerät aus der Liste wählen (Victron-Geräte werden erkannt und die Art vorausgefüllt) → Schlüssel einfügen → Sichern.

Der Schlüssel liegt in der iOS-Keychain, nicht in den UserDefaults.

Wenn „Schlüssel passt nicht" erscheint

Victron sendet das erste Byte des Schlüssels unverschlüsselt mit, damit sich ein falscher Schlüssel sofort erkennen lässt. Die Detailansicht des Geräts hat dafür den Abschnitt Diagnose:

  • Gerät sendet als erstes Schlüsselbyte was das Gerät erwartet
  • Eingetragener Schlüssel beginnt mit was in der App steht

Stimmen die beiden nicht überein, gehört der Schlüssel zu einem anderen Gerät. Bei mehreren Victron-Geräten ist das die mit Abstand häufigste Ursache: In VictronConnect prüfen, dass wirklich dieses Gerät geöffnet war, als der Schlüssel angezeigt wurde.

Die Diagnose zeigt außerdem Produkt-ID, Datensatztyp und die Rohdaten des Advertisements letztere lassen sich durch langes Antippen kopieren.

Batterie / BMS

Kein Schlüssel nötig. Auswählen, Art auf Batterie / BMS stellen, Sichern. Bulltron-Akkus melden sich meist als DL-…, WattCycle je nach Charge unter eigenem Namen findest du nichts, in der Geräteliste auf Alle umschalten.

Die App probiert drei Protokolle durch und übernimmt, was antwortet:

Dialekt Verbreitung
Daly klassisch (A5) Bulltron und viele Daly-BMS
Daly Modbus (D2) neuere Daly-Firmware
JBD / Xiaoxiang (DD A5) WattCycle und viele andere LiFePO4-Akkus

Auch die GATT-Charakteristiken werden gesucht statt vorausgesetzt, weil sich die BLE-Module zwischen Herstellern und Chargen unterscheiden. Welches Protokoll erkannt wurde, steht in der Detailansicht unter Diagnose zusammen mit der letzten Rohantwort.

Nur eine App gleichzeitig kann mit dem BMS verbunden sein. Wenn die Hersteller-App offen ist, bekommt Camper Monitor keine Verbindung.

Mehrere Fahrzeuge

Oben links im Dashboard sitzt der Fahrzeugwechsel. Jedes Profil hat seinen eigenen Gerätesatz; die App scannt und verbindet immer nur für das gewählte Fahrzeug. Über Fahrzeuge verwalten… lassen sich Profile anlegen, umbenennen, mit einem Symbol versehen und löschen. Geräte, die vor der Profilverwaltung eingerichtet wurden, wandern beim Update automatisch ins erste Profil.

Ohne Fahrzeug ansehen

Ein Demo-Modus füllt die App mit erfundenen Werten, damit sich die Ansichten ohne Bluetooth prüfen lassen. In Xcode unter Product → Scheme → Edit Scheme → Run → Arguments die Umgebungsvariable CAMPER_DEMO auf 1 setzen. Er greift nur in Debug-Builds.

Protokolle prüfen

./run-tests.sh

Prüft die Entschlüsselung und die Rahmenverarbeitung ohne Hardware und ohne Simulator unter anderem AES-CTR gegen den Referenzvektor aus NIST SP 800-38A und die Prüfsummen beider Daly-Dialekte.

Aufbau

CamperMonitor/
├── Models/
│   ├── Profile.swift             Fahrzeug
│   ├── ConfiguredDevice.swift    Eingerichtetes Gerät, Rolle, Transportart
│   ├── DeviceSnapshot.swift      Messwerte in Anzeigeform
│   └── VictronCodes.swift        Klartexte für Zustands-/Fehlercodes
├── Bluetooth/
│   ├── BluetoothManager.swift    Zentraler Scan, Verbindungen, Verlauf
│   ├── VictronAdvertisement.swift Advertisement entschlüsseln und auswerten
│   ├── AESCounterMode.swift      AES-128-CTR (CommonCrypto)
│   ├── BitReader.swift           Bitweises Lesen der gepackten Felder
│   ├── DalyProtocol.swift        Daly-Rahmen und Prüfsummen
│   ├── DalyState.swift           Sammelt Daly-Antworten zu einem Gesamtbild
│   ├── JBDProtocol.swift         JBD/Xiaoxiang (WattCycle), Rahmen und Auswertung
│   └── BMSSession.swift          GATT-Verbindung, Protokollerkennung, Abfrage
├── Store/
│   ├── DeviceStore.swift         Geräteliste, Persistenz
│   └── KeychainStore.swift       Victron-Schlüssel
└── Views/
    ├── DashboardView.swift       Kachelübersicht
    ├── DeviceCard.swift          Eine Kachel
    ├── DeviceDetailView.swift    Alle Werte, Verlauf, Zellspannungen, Diagnose
    ├── ProfilesView.swift        Fahrzeuge anlegen und verwalten
    └── AddDeviceView.swift       Scannen und Einrichten

Bekannte Grenzen

  • Kein Hintergrundbetrieb. iOS erlaubt das ungefilterte Scannen nach Advertisements nur im Vordergrund. Die App pausiert, sobald sie in den Hintergrund geht, und nimmt beim Zurückkommen wieder auf.
  • Das Modbus-Registerlayout des neuen Daly-Protokolls variiert zwischen Firmwareständen. Das klassische A5-Protokoll und das JBD-Protokoll sind gut dokumentiert; falls dein BMS Modbus spricht und Werte unplausibel aussehen, muss das Mapping in DalyState.apply(registers:) am realen Gerät nachgezogen werden.
  • Welches BMS in einem WattCycle-Akku steckt, ist nicht garantiert. Die Unterstützung ist auf JBD/Xiaoxiang ausgelegt, das dort üblich ist. Meldet die Diagnose dauerhaft „wird ermittelt“, spricht der Akku etwas anderes die dort angezeigte Rohantwort ist dann der Ansatzpunkt.
  • Die Feldbelegungen der Victron-Datensätze stammen aus Victrons „Extra Manufacturer Data“-Beschreibung. Solarladeregler und DC/DC-Wandler sind die am besten belegten Typen.
  • Die Bluetooth-Kennung eines Geräts ist pro iPhone eindeutig. Auf einem zweiten Gerät müssen die Geräte neu eingerichtet werden.
S
Description
No description provided
Readme
5.7 MiB
Languages
Kotlin 50.1%
Swift 49.5%
Shell 0.4%