forked from fritob/Camper-Monitor
Die WattCycle-Batterie meldete sich am FFF0-Dienst, nahm aber keine Kommandos an. Grund: dort ist FFF1 die erste beschreibbare Charakteristik, sie sieht schreibbar aus und bleibt trotzdem stumm – Kommandos gehören auf FFF2. Statt die richtige Charakteristik zu raten, stellt BMSSession jetzt alle Paare aus schreibbarer und benachrichtigender Charakteristik zusammen, jeweils mit und ohne Schreibbestätigung, und arbeitet sie ab, bis eines antwortet. Bekannte Paare (FFF2/FFF1, FF02/FF01, Nordic UART) kommen zuerst dran; ein Kandidat, der sich nicht abonnieren lässt, wird sofort übersprungen. Auf jedem Weg werden weiterhin Daly klassisch, Daly Modbus und JBD angefragt. Die Diagnose zeigt dazu den vollständigen GATT-Baum des Geräts, den gerade versuchten Weg samt Position in der Kandidatenliste sowie Zähler für gesendete Anfragen und empfangene Bytes. Damit lässt sich unterscheiden, ob das BMS die Kommandos gar nicht annimmt oder ein unbekanntes Protokoll spricht. Nebenbei: "caravan" existiert nicht als SF-Symbol und ließ SwiftUI stillschweigend auf Text zurückfallen – in den Demodaten ersetzt. README auf Profile und WattCycle/JBD nachgezogen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
161 lines
7.4 KiB
Markdown
161 lines
7.4 KiB
Markdown
# 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
|
||
|
||
```bash
|
||
open /Users/fritob/GIT/Camper-Management/CamperMonitor.xcodeproj
|
||
```
|
||
|
||
Dann in Xcode:
|
||
|
||
1. Target `CamperMonitor` → **Signing & 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
|
||
|
||
```bash
|
||
./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.
|