fototeddyandClaude Sonnet 5 8401f62d91 California-Seitenansicht eng zuschneiden statt in quadratischer Leinwand
Die Vorlage lag auf einer quadratischen 1254×1254-Leinwand, der Van
darin füllte aber nur rund 59% der Höhe – bei deklariertem
sideAspect = 1 (quadratisch) rechnete SwiftUI die Anzeigegrösse für
dieses volle Quadrat, wodurch der Van in der gemeinsamen Bildhülle
deutlich kleiner erschien als Vanster, dessen Vorlage eng auf die
Silhouette zugeschnitten ist.

Bild jetzt auf den Inhalt zugeschnitten (plus kleiner Rand, wie bei
Vanster), sideAspect entsprechend von 1 auf das tatsächliche Verhältnis
der zugeschnittenen Vorlage (1212×790) angepasst. In beiden
Asset-Katalogen ersetzt (iPhone und Watch, siehe vorherigen Commit zur
Watch-Fahrzeuggrafik).

Die Heckansicht war laut Rückmeldung bereits optisch stimmig und blieb
unverändert.

Build (App + Watch) und Tests grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 20:27:20 +02:00
2026-08-30 14:21:28 +02:00

VanControl Pro

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) GATT-Verbindung, alle 5 s abgefragt SoC, Spannung, Strom, Restkapazität, alle Einzelzellspannungen, Zelldifferenz, Temperaturen, Zyklen, MOSFET-Status
Kompressor-Kühlbox (Alpicool und Baugleiche) GATT-Verbindung, lesen und stellen Ist- und Solltemperatur je Zone, Betriebsart, Kompressorstatus, Bordspannung, Batterieanzeige
Neigungsmesser (VanAlign Pro) GATT-Verbindung Längs- und Querneigung als Libelle, Kalibrierung aus der App
Votronic-Solarladeregler (über eigene ESP32-Bridge) GATT-Verbindung, im Takt abgefragt PV-Leistung, PV-Spannung/-Strom, Batteriespannung, Reglertemperatur, Lade-/Reglerstatus

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

Victron- und Votronic-Solarladeregler sind zwei getrennte Geräterollen, absichtlich nicht zusammengelegt: Der Victron-Regler meldet sich passiv und verschlüsselt im Advertisement, der Votronic-Regler hängt über eine eigene ESP32-Bridge (siehe unten) an einer GATT-Verbindung grundverschiedene Übertragungswege für grundverschiedene Hardware. In Code und Einstellungen tragen beide deshalb konsequent victron/votronic im Namen.

Der Neigungsmesser zeigt sich zusätzlich als Live Activity auf Sperrbildschirm, Dynamic Island und seit iOS 26 automatisch im CarPlay-Dashboard, siehe Live Activity.

Dazu gehört eine Apple-Watch-App: Übersicht, Nivellierung samt Ausrichtungs-Assistent mit Vibration und die Steuerung der Kühlbox am Handgelenk. Den Neigungsmesser funkt die Uhr selbst an, alles Übrige kommt über das iPhone warum diese Aufteilung, steht unter Apple Watch.

Die Firmware des Neigungsmessers liegt mit im Projekt, siehe firmware/vanalign. Der Votronic-Solarregler hängt an einer zweiten, unabhängigen ESP32-Bridge Firmware und BLE-Dienst dafür liegen als firmware/vanalign/esp32_ble_solar.yaml im selben Ordner.

Bauen und installieren

open VanControl.xcodeproj

Dann in Xcode:

  1. Bei allen vier Targets VanControl, VanControlWatch, VanControlComplication, VanControlLiveActivityExtension unter Signing & Capabilities dein Apple-Team auswählen. Die Bundle-IDs ggf. anpassen, falls sie schon vergeben sind; die der Watch-App muss die des iPhones mit angehängtem .watchkitapp bleiben, die der Komplikation zusätzlich .levelwidget.
  2. iPhone per Kabel anschließen, oben als Ziel wählen, ⌘R.

Das Schema VanControl baut die Watch-App mit und bettet sie ein. Dafür muss die watchOS-Plattform in Xcode installiert sein sonst bricht schon das Übersetzen des Symbolkatalogs ab:

xcodebuild -downloadPlatform watchOS

Auf die Uhr kommt die App danach von selbst: Sie steckt in der iPhone-App und taucht in der Watch-App des iPhones unter Verfügbare Apps auf.

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) viele LiFePO4-Akkus mit eigener App
WattCycle (1E/7E) WattCycle-Bluetooth-Serie

WattCycle-Akkus verlangen eine Besonderheit: vor der ersten Abfrage muss der Text HiLink auf eine eigene Freischalt-Charakteristik (FFFA) geschrieben werden, sonst bleiben sie auf jede Anfrage stumm. Die App macht das automatisch, sobald ein Gerät diese Charakteristik anbietet. Modell, Hersteller und Seriennummer liest sie einmalig mit aus und zeigt sie in der Detailansicht unter Gerät.

Protokoll und Feldbelegung stammen aus frabnet/esphome-wattcycle-ble; die Prüfsummen-Variante von dort ist gegen den klassischen Modbus-CRC nachgerechnet, die Anfragerahmen sind byteweise in run-tests.sh abgesichert.

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 VanControl Pro keine Verbindung.

Kühlbox

Die IceCube-Boxen von Plug-in Festivals sind umgelabelte Alpicool-Boxen erkennbar daran, dass der Hersteller die App „Alpicool T-Series“ nennt. Dasselbe Protokoll sprechen auch BrassMonkey und Ocean Comfort.

Beim Einrichten Art auf Kühlbox stellen. Die App meldet sich beim Verbinden selbst an; steht APP im Display der Box, verlangt sie dabei einen Tastendruck am Gerät.

Verbunden wird nur, während die Kühlbox geöffnet ist. Jede Verbindung meldet sich an ihrem Display an und stört, wer gerade davorsteht; und ihre Werte ändern sich langsam. Auf der Übersicht steht deshalb nicht die gemessene Innentemperatur, sondern der zuletzt gestellte Stand Sollwert, Ein/Aus, Eco oder Max, dazu wann er gestellt wurde. Der bleibt richtig, auch wenn er von gestern ist: Ein Sollwert ändert sich nur, wenn jemand ihn ändert. Eine Innentemperatur von gestern sähe dagegen aus wie eine von jetzt.

Sobald du die Box öffnest, verbindet die App sich und zeigt alles live; beim Verlassen der Ansicht trennt sie wieder. Dasselbe gilt für die Uhr: Auch von dort wird die Verbindung nur angefordert, solange die Kühlbox-Ansicht offen ist. Ein Stellbefehl geht ebenfalls immer durch ist die Box gerade nicht verbunden, wird er gemerkt und geht raus, sobald sie antwortet.

BMS und Neigungsmesser bleiben dagegen dauerhaft verbunden. Sie stören dabei nicht, und ihre Werte will man laufend sehen.

Neben den Messwerten gibt es hier als einzigem Gerät auch Bedienelemente: Ein/Aus, Eco oder Max, Solltemperatur je Zone und die Bedienfeldsperre. Alle Schalter zeigen den Stand, den die Box zurückmeldet nach jedem Stellbefehl wird ihr Zustand neu abgefragt, statt die Eingabe anzunehmen. Das Ausschalten fragt einmal nach, weil dabei die Kühlung stoppt.

Interessant für die Energieübersicht: Die Box misst die Bordspannung und meldet sie mit, was einen Quervergleich zu Batterie und Solarregler erlaubt.

Protokoll und Feldbelegung stammen aus Gruni22/alpicool_ha_ble.

Votronic-Solarladeregler

Anders als der Victron-Regler hängt der Votronic-Regler nicht selbst am BLE-Advertising er wird über eine eigene, unabhängige ESP32-Bridge ausgelesen (siehe firmware/vanalign/esp32_ble_solar.yaml). Die Bridge bewirbt ihren eigenen Dienst, wird beim Einrichten also automatisch erkannt und die Art vorbelegt, genau wie beim Neigungsmesser.

Die Bridge liest den Regler über dessen Displaylink-Port (UART) mit der externen ESPHome-Komponente syssi/esphome-votronic aus und stellt PV-Leistung, PV-Spannung/-Strom, Batteriespannung, Reglertemperatur sowie Lade- und Reglerstatus über eigene Charakteristiken bereit reine Lesewerte, im Takt abgefragt wie beim Neigungsmesser.

Nivellierung

Der Neigungsmesser VanAlign Pro ist ein ESP32 mit MPU6050, der Längs- und Querneigung über Bluetooth bereitstellt. Er bewirbt seinen Dienst, wird beim Einrichten also sicher erkannt und die Art vorbelegt.

Die Detailansicht bietet zwei Darstellungen, umschaltbar und über Starts hinweg gemerkt:

  • Libelle die Blase wandert dorthin, wo das Fahrzeug höher steht, wie bei einer echten Wasserwaage. Ringe markieren Toleranz und zwei Grad.
  • Fahrzeug Seitenansicht für längs, Heckansicht für quer, beide gekippt. Die Heckansicht teilt die Blickrichtung des Fahrers, links im Bild ist also links am Fahrzeug. Die Neigung ist dreifach überhöht dargestellt, sonst wäre sie bei zwei Grad kaum zu erkennen; die angezeigten Gradzahlen sind echt.

In beiden Fällen: grün heißt eben (bis 0,5°), orange bis zwei Grad, darüber rot. Dazu steht in Worten, welche Seite höher steht.

Die Fahrzeugansicht kennt mehrere Grafikstile (aktuell Vanster und California), einstellbar je Fahrzeugprofil. Die Zeichnungen stammen aus dem Ursprungsprojekt VanAlign Pro. Sie liegen als Schablonen im Asset-Katalog und werden je nach Abweichung eingefärbt; die Helligkeit des Originals wurde dafür in Deckkraft übersetzt, damit Fenster und Konturen beim Einfärben erhalten bleiben.

Im Querformat rücken Libelle bzw. Fahrzeugansicht und die übrigen Angaben nebeneinander statt untereinander gedacht fürs Handy in der Halterung beim Rangieren, wo man beiläufig hinschaut statt zu scrollen. Das gilt auch für den Ausrichtungs-Assistenten weiter unten.

Vor der ersten Nutzung die Einbaulage bestimmen. Sitzt der Sensor quer, gedreht oder kopfüber, meldet er längs und quer vertauscht oder mit falschem Vorzeichen. Der Assistent unter Sensor → Einbaulage klärt das durch zwei Kippbewegungen: einmal die Front nach unten, einmal die linke Seite. Aus der Reaktion ergibt sich die Zuordnung geraten wird nichts.

Dabei wird auch eine Verdrehung um die Hochachse mitgemessen, also der Fall, dass der Sensor schräg statt längs im Fahrzeug klebt. Ohne diese Korrektur verteilt sich eine reine Querneigung auf beide Achsen: Das Fahrzeug kippt zur Seite, und die Längsanzeige kippt sichtbar mit bei 20° Verdrehung mit gut einem Drittel des Werts. Der Winkel steht im Ergebnis des Assistenten („um 20° verdreht") und wird von da an herausgerechnet.

Beim Kalibrieren liesse sich das nicht ermitteln, und zwar grundsätzlich nicht: Es misst eine einzige Lage und zieht sie als Nullpunkt ab. Eine Drehung um die Hochachse steckt darin nicht eben sieht in jeder Verdrehung gleich aus. Dafür braucht es zwei Kippbewegungen in bekannte Richtungen, und genau die macht der Einbaulage-Assistent.

Beides liegt im Sensor, nicht in der App

Sowohl die Kalibrierung als auch die Einbaulage speichert der ESP32 selbst und gibt sie an jeden aus, der fragt. Das ist der Punkt, sobald mehr als ein Gerät im Spiel ist: iPhone, Apple Watch und Android-App zeigen dasselbe, und bestimmt werden muss beides nur ein einziges Mal, von welchem Gerät aus auch immer.

wo
Nullpunkt der Kalibrierung im ESP (pitch_offset, roll_offset), wird dort auch schon abgezogen
Einbaulage samt Verdrehung im ESP, Charakteristik …3428, lesbar und schreibbar
Spurweite und Radstand in der jeweiligen App, im Fahrzeugprofil

Beim Verbinden liest jede App die Einbaulage aus dem Gerät und übernimmt sie. Wer sie neu bestimmt, schreibt sie hinauf. Steht dort noch nichts ältere Firmware oder nie bestimmt , gilt weiter, was die App örtlich gespeichert hat; kaputtgehen kann dabei nichts.

Angewandt wird sie trotzdem in den Apps und nicht im Sensor. Der Sensor verwahrt sie nur: Würde er die Winkel schon umgerechnet melden, rechnete jede ältere App die Korrektur ein zweites Mal ein.

Die acht Byte der Charakteristik sind in VanAlignProtocol beschrieben und in run-tests.sh byteweise festgenagelt daran hängen drei Apps und die Firmware.

Danach kalibrieren: Fahrzeug eben stellen, dann Auf aktuelle Lage kalibrieren. Ohne das zeigt die Anzeige die Lage des Sensors, nicht die des Fahrzeugs je nachdem, wie schief er eingebaut ist.

Die Werte werden zweimal je Sekunde abgefragt. Bietet ein Gerät notify an, werden sie stattdessen abonniert die mitgelieferte Firmware tut das allerdings nicht, siehe deren README.

Ob bereits kalibriert wurde, meldet nicht jede Firmware zurück. Fehlt die Angabe, gilt sie als unbekannt und die App warnt nicht eine Warnung, die sich nie abstellen lässt, wäre schlimmer als keine. Kalibrieren aus der App braucht Firmware 1.0.2.

Ausrichtungs-Assistent

Von der Nivellierungs-Ansicht aus erreichbar, gedacht fürs Rangieren. Er verfolgt die Neigung über die Zeit und sagt, ob es gerade besser oder schlechter wird und wo es am besten stand: „Vor 4 Sekunden stand das Fahrzeug 0,8° flacher." Steht der Camper in der Toleranz, meldet das Gerät sich mit einer Vibration; das Display bleibt solange wach.

Bewusst ohne Positionsbestimmung. Aus einem MEMS-Beschleunigungssensor lässt sich keine brauchbare Strecke ableiten, weil der Fehler beim zweifachen Integrieren quadratisch mit der Zeit wächst und die Beschleunigungen im Schritttempo ohnehin im Rauschen untergehen. Gebraucht wird das auch nicht: Beim Einparken lautet die Frage nie „wo stehe ich", sondern „wird es besser". Das steckt vollständig im zeitlichen Verlauf der Neigung ohne jede Annahme über das Gelände.

Sind beim Fahrzeug Spurweite und Radstand hinterlegt, rechnet der Assistent zusätzlich die nötige Höhe der Auffahrkeile aus je Rad, als Draufsicht auf das Fahrzeug. Getrennte Angaben für quer und längs wären irreführend: „rechts 8 cm" und „vorne 4 cm" beschreiben dasselbe Fahrzeug, und unter beiden liegt teils dasselbe Rad. Es steht auf vier Punkten, also gehören vier Zahlen hin.

Das ist reine Geometrie und damit exakt: 2,0° Querneigung bei 2,00 m Spurweite ergeben 7,0 cm unter beide Räder der tieferstehenden Seite; kommen 1,5° Längsneigung bei 3,50 m Radstand dazu, braucht die tiefste Ecke 16,1 cm, ihre Nachbarn 9,2 und 7,0 cm, und das höchststehende Rad bleibt liegen. Die Maße stehen im Fahrzeugprofil, erreichbar über das ⓘ in der Fahrzeugliste.

Live Activity

In der Nivellierungs-Ansicht lässt sich eine Live Activity einschalten, die die Neigung auch bei gesperrtem Bildschirm zeigt: Sperrbildschirm, Dynamic Island und seit iOS 26, ohne eigenes CarPlay-Ziel nötig automatisch im CarPlay-Dashboard. Der Schalter ist deaktiviert, solange keine Messwerte anliegen, sonst startete die Anzeige gleich mit einem veralteten Stand.

Die Aktualisierung ist bewusst auf höchstens einmal je Sekunde gedrosselt. Der Neigungsmesser liefert deutlich öfter, und stiesse jede Messung sofort eine Aktualisierung an, drosselt iOS das von sich aus zunehmend stärker sichtbar vor allem in CarPlay, dessen Dashboard ohnehin zurückhaltender aktualisiert als Sperrbildschirm oder Dynamic Island. Innerhalb der Sperrfrist eingehende Messwerte werden nicht verworfen, sondern der jeweils neueste für ihr Ende vorgemerkt.

Ein kurzer Verbindungsabbruch beendet die Aktivität nicht sofort erst nach zwölf Sekunden ohne Verbindung, und meldet sich das Gerät vorher zurück, läuft sie unverändert weiter. War sie wegen einer längeren Trennung wirklich beendet, startet sie bei der nächsten Verbindung automatisch neu.

Apple Watch

Die Uhr zeigt dasselbe wie das Dashboard, nur auf das eingedampft, wofür man den Arm hebt:

  • Übersicht je Gerät der Hauptwert und ein Punkt für den Zustand der Verbindung. Ganz unten steht, wie alt der Stand ist.

  • Nivellierung drei Seiten zum Wischen, weil auf diesem Bildschirm ein Wisch besser zu treffen ist als eine Scrollposition:

    1. Neigung wahlweise als Fahrzeugansicht wie am iPhone (Seiten- und Heckansicht, dreifach überhöht) oder als Libelle; umschaltbar und über Starts hinweg gemerkt. Dazu, was zu tun ist, und woher die Werte kommen.
    2. Keile die Höhe je Rad als Draufsicht. Fehlen Spurweite und Radstand im Fahrzeugprofil, steht das dort statt einer leeren Seite.
    3. Ausrichten der Assistent fürs Rangieren.

    Kalibriert wird nur am iPhone: Das gehört einmalig auf ebenen Boden, und ein Knopf dafür an der Uhr wäre vor allem eine Gelegenheit, die Nullage aus Versehen zu verstellen.

  • Ausrichten derselbe Assistent wie am iPhone: Tendenz, Rat und der Hinweis auf den flachsten Punkt der letzten anderthalb Minuten. Steht das Fahrzeug in der Toleranz, vibriert die Uhr. Das ist der eigentliche Gewinn gegenüber dem iPhone beim Rangieren schaut niemand aufs Display, aber die Vibration am Handgelenk kommt an.

  • Kühlbox ein/aus, Eco oder Max und die Solltemperatur, über die Krone gestellt. Verbunden wird die Box erst beim Öffnen dieser Ansicht, davor steht dort der zuletzt gestellte Stand.

Wer mit wem funkt

Die Aufteilung folgt dem, was jedes Gerät hergibt.

Den Neigungsmesser funkt die Uhr selbst an. Er bewirbt seinen Dienst, ist also ohne jede Einrichtung auffindbar, und er ist unverschlüsselt es gibt keinen Schlüssel, der auf der Uhr ein zweites Mal lagern müsste. Damit steht die Nivellierung am Handgelenk ohne iPhone: kein geöffnetes Telefon, keine Reichweite dorthin. Genau dafür hebt man beim Rangieren den Arm.

Die Einbaulage des Sensors reist einmal vom iPhone herüber und bleibt auf der Uhr gespeichert. Ohne sie stünden längs und quer je nach Einbau vertauscht oder mit falschem Vorzeichen eingestellt wird sie weiterhin nur am iPhone, im Assistenten dort.

Alles Übrige kommt über das iPhone. Zwei Gründe, beide hart:

  • BMS und Kühlbox lassen jeweils nur eine Verbindung zu. Eine mitlesende Uhr nähme dem iPhone die Verbindung weg, statt sie zu ergänzen.
  • Die Victron-Schlüssel liegen in der Keychain des iPhones. Sie auf die Uhr zu kopieren hiesse, sie ein zweites Mal aufzubewahren, ohne dass der zweite Ort irgendetwas brächte.

Was die Uhr stellt, stellt also in Wahrheit das iPhone und angezeigt wird auch dort nur, was das Gerät zurückmeldet, nicht der Tastendruck.

Was das für den Betrieb heisst

Für Batterie, Solar und Kühlbox muss VanControl Pro auf dem iPhone laufen. Solange die Uhr meldet, dass jemand hinschaut, hält die App das Funkgerät auch im Hintergrund am Leben; die Victron-Werbedaten stehen dabei still, weil iOS im Hintergrund kein ungefiltertes Suchen erlaubt.

Für die Nivellierung gilt das alles nicht die läuft an der Uhr allein. Gefunkt wird dort nur im Vordergrund: watchOS lässt eine App im Hintergrund ohnehin kaum scannen, und beim Ausrichten schaut man auf die Uhr.

Gesendet wird in zwei Takten: ein halber Sekundentakt, solange die Watch-App im Vordergrund ist, sonst alle zwei Sekunden und nur bei Änderungen. Der schnelle Takt läuft über eine Frist, die die Uhr regelmässig erneuert schläft sie ein, hört das iPhone von selbst wieder auf.

Was die Uhr zeigt, ist immer Weitergereichtes. Deshalb steht auf jedem Bildschirm das Alter des Standes: Eine abgerissene Strecke zum iPhone sähe sonst genauso aus wie ein Fahrzeug, an dem sich nichts tut.

Diagnose

Im Alltag zeigt die App nur Messwerte und Bedienelemente. Die technischen Angaben erkanntes Protokoll, Bluetooth-Merkmale, gesendete Befehle, Rohdaten der letzten Antwort sind ausgeblendet und lassen sich unter Einstellungen → Diagnose anzeigen einschalten. Die Einstellungen sitzen im Fahrzeugmenü oben links im Dashboard.

Meldet ein Gerät einen Fehler oder fehlt ein Victron-Schlüssel, werden die Angaben unabhängig davon eingeblendet dann sind sie genau das, was weiterhilft.

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 Fahrzeugen und Messwerten, damit sich die Ansichten ohne Bluetooth prüfen lassen auch ohne die Hardware zur Hand zu haben. Auf zwei Wegen einzuschalten:

  • Schalter in den Einstellungen (Einstellungen → Entwicklung → Demo-Modus) in jeder Build-Konfiguration verfügbar, auch in TestFlight- und App-Store-Builds. Der Weg für jeden lokal installierten Build ohne Xcode-Verbindung. Wirkt erst nach einem Neustart der App (im App-Umschalter nach oben wischen, dann neu öffnen), weil DeviceStore und BluetoothManager den Stand nur beim Start lesen.

  • Umgebungsvariable CAMPER_DEMO=1 nur in Debug-Builds, in Xcode unter Product → Scheme → Edit Scheme → Run → Arguments, oder im Simulator direkt:

    xcrun simctl launch --terminate-running-process booted <deine-bundle-id>
    # mit SIMCTL_CHILD_CAMPER_DEMO=1 davor
    

Solange der Demo-Modus läuft, schreibt die App nichts in die echte Geräteliste Änderungen an den erfundenen Fahrzeugen/Geräten verschwinden beim Ausschalten wieder.

Die Watch-App kennt nur den Umgebungsvariablen-Weg und braucht dann kein iPhone: Im Schema VanControlWatch dieselbe Variable setzen. Die Neigung wandert dort langsam hin und her, sonst hätte der Ausrichtungs-Assistent nichts zu zeigen.

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

firmware/vanalign/               Firmware der beiden ESP32 im Fahrzeug (ESPHome)
├── esp32_ble.yaml               Neigungsmessung und Bluetooth-Schnittstelle
├── esp32_ble_solar.yaml         Zweiter ESP32: Votronic-Solarregler über BLE
└── experimente/                 Nicht für den Betrieb nötig

Shared/                          In iPhone- und Watch-App übersetzt
├── Models/
│   ├── Profile.swift             Fahrzeug samt Maßen
│   ├── AlignmentAssistant.swift  Verlauf, Tendenz und Keilhöhe je Rad
│   ├── SensorOrientation.swift   Einbaulage und ihre Erkennung
│   ├── ConfiguredDevice.swift    Eingerichtetes Gerät, Rolle, Transportart
│   ├── DeviceSnapshot.swift      Messwerte in Anzeigeform
│   ├── LevelState.swift          Neigung, Toleranz und Klartext dazu
│   ├── VictronCodes.swift        Klartexte für Zustands-/Fehlercodes
│   └── VehicleGraphicStyle.swift Grafikstile der Fahrzeugansicht (Vanster/California)
├── Bluetooth/
│   ├── VanAlignProtocol.swift    Neigungsmesser: Winkel und Kalibrierung
│   ├── LevelSession.swift        Verbindung zum Neigungsmesser (iPhone und Uhr)
│   ├── VotronicSolarESPProtocol.swift  Votronic-Solarregler: Charakteristiken, Statusbits
│   └── VotronicSolarESPSession.swift   GATT-Verbindung zur Solar-Bridge, im Takt abgefragt
├── VehicleTilt.swift             Überhöhung und Farben der Fahrzeugansicht
├── WheelLiftPlan.swift           Keilhöhen als Draufsicht auf die vier Räder
└── WatchLink/
    └── WatchLink.swift           Datensatz und Befehle zwischen iPhone und Uhr

SharedActivity/                  In Haupt-App und Live-Activity-Extension übersetzt
├── LevelActivityAttributes.swift     Inhalt der Live Activity (ActivityKit)
└── LevelDirectionFormatting.swift    "H 1.8°" statt Vorzeichen, für App und Extension gleich

VanControl/
├── 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, Rahmen und Auswertung
│   ├── WattCycleProtocol.swift   WattCycle, Freischaltung und Auswertung
│   ├── AlpicoolProtocol.swift    Kühlboxen: Auswertung und Stellbefehle
│   └── BMSSession.swift          GATT-Verbindung, Protokollerkennung, Abfrage
├── LiveActivity/
│   └── LevelActivityManager.swift  Startet/aktualisiert/beendet die Live Activity, drosselt auf 1 Hz
├── Store/
│   ├── DeviceStore.swift         Geräteliste, Persistenz
│   ├── DemoData.swift            Erfundene Werte für den Demo-Modus
│   └── KeychainStore.swift       Victron-Schlüssel
├── Watch/
│   └── PhoneWatchLink.swift      Sendet den Stand, nimmt Befehle der Uhr an
└── Views/
    ├── DashboardView.swift       Kachelübersicht
    ├── DeviceCard.swift          Eine Kachel
    ├── DeviceDetailView.swift    Alle Werte, Verlauf, Zellspannungen, Diagnose
    ├── ProfilesView.swift        Fahrzeuge anlegen und verwalten
    ├── FridgeControls.swift      Bedienelemente der Kühlbox
    ├── LevelView.swift           Libelle, Kalibrierung, Live-Activity-Schalter
    ├── LevelSetupView.swift      Einbaulage und Nullpunkt
    ├── AlignmentAssistantView.swift  Ausrichtungs-Assistent fürs Rangieren
    ├── VehicleTiltView.swift     Neigung am Fahrzeug dargestellt
    ├── VictronKeyView.swift      Verschlüsselungsschlüssel eintragen
    ├── SettingsView.swift        App-Einstellungen
    ├── SensorSetupView.swift     Assistent für die Einbaulage
    └── AddDeviceView.swift       Scannen und Einrichten

VanControlWatch/              watchOS-App
├── CamperWatchApp.swift          Einstieg, meldet dem iPhone das Hinschauen
├── PhoneLink.swift               Gegenstelle zum iPhone
├── WatchLevelRadio.swift         Eigene Bluetooth-Verbindung zum Neigungsmesser
├── WatchDemo.swift               Erfundene Werte für den Simulator
└── Views/
    ├── WatchRootView.swift       Übersicht und Altersangabe
    ├── WatchBubble.swift         Libelle für den kleinen Bildschirm
    ├── WatchVehicleView.swift    Fahrzeugansicht auf Uhrgrösse
    ├── WatchLevelView.swift      Die drei Seiten: Neigung, Keile, Ausrichten
    ├── WatchAlignView.swift      Ausrichten mit Vibration
    ├── WatchDeviceDetailView.swift  Alle Werte eines Geräts
    └── WatchFridgeControls.swift Kühlbox stellen

VanControlComplication/       Zifferblatt-Komplikation (watchOS)
└── LevelComplication.swift       Tippt auf die Nivellierung, ohne eigenen Messwert

VanControlLiveActivity/       Live-Activity-Extension (WidgetKit)
├── VanControlLiveActivityBundle.swift  Einstieg der Extension
└── VanControlLiveActivity.swift        Ansicht für Sperrbildschirm, Dynamic Island, CarPlay

Config/
├── VanControl-Info.plist               Nur der Hintergrundbetrieb für die Uhr
└── VanControlComplication-Info.plist    Anzeigename der Komplikation

Bekannte Grenzen

  • Im Hintergrund nur die verbundenen Geräte. iOS erlaubt das ungefilterte Scannen nach Advertisements nur im Vordergrund; die Victron-Werte stehen im Hintergrund also still. Verbundene Geräte Neigungsmesser, BMS, Kühlbox laufen weiter, aber nur solange die Uhr meldet, dass jemand hinschaut. Ohne Uhr pausiert die App im Hintergrund vollständig und nimmt beim Zurückkommen wieder auf.
  • Die Uhr braucht das iPhone ausser für die Nivellierung. Batterie, Solar und Kühlbox zeigt sie nur, was von dort kommt; ist das iPhone ausser Reichweite, steht dort, wie alt der letzte Stand ist. Den Neigungsmesser erreicht sie selbst.
  • Neigungsmesser und Uhr: Der ESP32 nimmt mehrere Verbindungen an, iPhone und Uhr können also gleichzeitig mitlesen. Weist er die zweite ab, hilft es, die iPhone-App zu schliessen dann gehört der Sensor der Uhr.
  • Auf der Uhr muss beim ersten Start Bluetooth erlaubt werden, sonst bleibt die Nivellierung dort leer.
  • Die Live Activity aktualisiert höchstens einmal je Sekunde. Öfter drosselt iOS lokale Aktualisierungen ohnehin von sich aus, zunehmend stärker sichtbar vor allem in CarPlay. Siehe Live Activity.
  • 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.
  • Die Feldbelegung der BMS-Datensätze ist nicht an jedem Modell geprüft. Meldet die Diagnose dauerhaft „wird ermittelt“, spricht der Akku ein Protokoll, das die App nicht kennt 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
13 MiB
Languages
Kotlin 50.1%
Swift 49.5%
Shell 0.4%