Eigene Build-Konfiguration "CarPlay" samt Schema, damit der Versuchsbau neben
der TestFlight-App stehen kann: eigener Name, eigene Bundle-ID, persoenliches
Team, manuelles Signing. Debug und Release bleiben unberuehrt.
Wichtig dabei: Die Signing-Einstellungen stehen ausschliesslich in den
Target-Konfigurationen. Steht CODE_SIGN_STYLE auf Projektebene, schreibt der
naechste xcodebuild-Lauf alle uebrigen Konfigurationen auf Manual um und loescht
ihr Team – der TestFlight-Build waere damit hin.
Der CarPlay-Code haengt an `CARPLAY_DEMO` und existiert im regulaeren Build
nicht. Die Szene zeichnet in das gelieferte CPWindow; das CPMapTemplate darueber
bleibt leer, weil es auf dem Stellplatz nichts zu tippen gibt. Die Anzeige
sperrt sich oberhalb von 5 km/h selbst – erzwungen, nicht zugesagt.
Die Groessen sind auf die 400x240 Punkte ausgelegt, die CarPlay liefert, nicht
auf die 800x480 Pixel. In Pixeln gedachte Schriftgroessen sind auf dem
Fahrzeugdisplay doppelt zu gross und schneiden den Text ab.
Bekannt: Unter iOS 26.5 stuerzt Apples CarPlayTemplateUIHost beim Aufbau der
Navigationsleiste ab (`_updateShareButtonVisibility` fragt seinen
destinationSharingDelegate nach `vehicleSupportsDestinationSharing`, den dieser
nicht kennt). Beides ist privates API und von der App aus nicht erreichbar;
unter iOS 18 laeuft es. Szene und Root-Template werden vorher in beiden
Faellen akzeptiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CamperMonitor (Haupt-Repo) und VanAligneiOS (aus dem gemergten
solar-integration-Branch) liefen unter zwei verschiedenen internen
Namen, obwohl die App nach aussen längst einheitlich "VanControl Pro"
heisst. Jetzt durchgängig VanControl:
- Ordner: CamperMonitor/, CamperMonitorWatch/, CamperMonitorComplication/,
VanAligneiOSWidget/ → VanControl/, VanControlWatch/,
VanControlComplication/, VanControlWidget/
- Xcode-Projekt: CamperMonitor.xcodeproj → VanControl.xcodeproj, alle
Targets/Schemes/Produktnamen entsprechend umbenannt
- Bundle-Identifier auf Wunsch mitgeändert: de.s0.fototeddy.VanControl*
(App noch nicht veröffentlicht); dabei auch die
WKCompanionAppBundleIdentifier-Werte korrigiert, die noch das alte
de.fritob-Präfix statt des tatsächlichen de.s0.fototeddy-Präfixes
trugen
- Swift-Dateien/Typen: CamperMonitorApp → VanControlApp,
VanAligneiOSWidget* → VanControlWidget*
- Config/*-Info.plist umbenannt, README.md/Tools/README.md/run-tests.sh
auf die neuen Pfade angepasst
Bewusst unverändert: firmware/vanalign und alle Bezüge auf "VanAlign"
als Namen der Neigungsmesser-Hardware (eigenständiges Produkt, kein
App-Name) sowie der komplette Android/-Ordner.
Build (App, Watch, Debug) und Protokoll-Testlauf grün.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Zwei Dinge in einem Commit, weil sie sich dieselben Dateien teilen:
project.pbxproj und WatchRootView.swift tragen beides.
**Komplikation.** Neues Target CamperMonitorComplication, auf watchOS
sind Komplikationen WidgetKit-Widgets. Es wird in die Watch-App
eingebettet (PlugIns) und bietet die vier Zubehör-Familien an. Ein Tipp
öffnet die App direkt auf der Nivellierung statt in der Geräteliste:
Die Komplikation hängt eine Adresse an, die Watch-App führt dafür jetzt
einen Navigationsweg, den sie von aussen setzen kann. Die Adresse steht
in Shared/WatchDeepLink.swift, weil beide Seiten sie brauchen – ein
Tippfehler auf einer Seite bliebe sonst stumm.
Bewusst ohne Messwert: Eine Komplikation läuft in einem eigenen Prozess
und käme an die Werte nur über eine App-Gruppe, und die verlangt eine
bezahlte Mitgliedschaft. Ein Wert, der beim Blick aufs Zifferblatt
Stunden alt sein kann, wäre ohnehin schlimmer als keiner – man glaubt
ihm. Die Komplikation tut deshalb genau eine Sache, und die zuverlässig.
**Rebranding.** Der sichtbare Name ist überall VanControl Pro:
CFBundleDisplayName beider Apple-Targets, Android-Label, die Texte in
beiden Apps, beide READMEs und der Name der APK im Gitea-Ablauf.
Die Kennungen bleiben, wie sie sind – Bundle-IDs, Android-Paket,
Target-, Ordner- und Schemanamen. Eine geänderte Bundle-ID ist für iOS
eine neue App: Geräte, Fahrzeugprofile und Victron-Schlüssel wären weg,
dazu neue Profile und eine neu zu koppelnde Watch-App. Sichtbar ist
davon nichts, also gibt es dafür auch keinen Grund.
Geprüft: alle drei Apple-Targets bauen, die Erweiterung liegt im
Watch-Bundle unter PlugIns, die Anzeigenamen stimmen im gebauten
Bundle, Tests grün. Die neue Bundle-ID der Erweiterung braucht beim
ersten Lauf aus Xcode ein Profil, das Xcode selbst anlegt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Uhr funkt den Neigungsmesser jetzt selbst an, statt die Werte vom
iPhone weiterreichen zu lassen. Bei diesem einen Gerät geht das, und nur
bei ihm: Es bewirbt seinen Dienst, ist also ohne Einrichtung auffindbar,
und es 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 geöffnetes iPhone, und genau dafür hebt man beim Rangieren den Arm.
Batterie, Solar und Kühlbox bleiben beim Weg über das iPhone: Sie lassen
nur eine Verbindung zu, und die Victron-Schlüssel liegen in dessen
Keychain. Die Einbaulage des Sensors reist einmal mit dem Datensatz
herüber und bleibt auf der Uhr gespeichert – ohne sie stünden längs und
quer je nach Einbau vertauscht.
LevelSession und VanAlignProtocol wandern nach Shared/Bluetooth; beide
sind reines CoreBluetooth und laufen auf watchOS unverändert. Die
Fahrzeugansicht gibt es jetzt auch auf der Uhr, umschaltbar zur Libelle;
Überhöhung und Farbregeln stehen in Shared/VehicleTilt.swift, damit
iPhone und Uhr nicht auseinanderlaufen.
Kalibrieren fällt auf der Uhr weg, samt Befehl. Das gehört einmalig ans
iPhone mit ebenem Fahrzeug; ein Knopf dafür am Handgelenk wäre vor allem
eine Gelegenheit, die Nullage aus Versehen zu verstellen.
Zwei Fehler dabei behoben:
* Beim Start meldete die Uhr dem iPhone nie, dass jemand hinschaut –
onChange(of: scenePhase) feuert beim ersten Erscheinen nicht. Der
schnelle Sendetakt blieb aus, bis die App einmal im Hintergrund war.
* Ein einmal direkt gemessener Wert hatte für immer Vorrang. Blieb der
Sensor stehen, ohne die Verbindung zu trennen, klebte die Anzeige
daran. Jetzt gilt er drei Sekunden als frisch, danach übernimmt der
Stand des iPhones – mit Alter und Grund daneben.
Ausserdem WATCHOS_DEPLOYMENT_TARGET auf 10.0 (Xcode hatte 11.6 gesetzt)
und die Bluetooth-Begründung für das Watch-Target.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Neues Target CamperMonitorWatch, eingebettet in die iPhone-App. Die Uhr
zeigt je Gerät den Hauptwert, die Nivellierung mit Libelle und Keilhöhen,
den Ausrichtungs-Assistenten und stellt die Kühlbox.
Die Uhr funkt nicht selbst, obwohl watchOS das könnte. BMS, Kühlbox und
Neigungsmesser lassen jeweils nur eine Verbindung zu – eine mitlesende Uhr
würde dem iPhone die Verbindung wegnehmen, statt sie zu ergänzen. Und die
Victron-Schlüssel liegen in der Keychain des iPhones; sie ein zweites Mal
auf der Uhr aufzubewahren brächte nichts. Das iPhone bleibt also das
Funkgerät und reicht fertige Messwerte über WatchConnectivity weiter.
Gesendet wird in zwei Takten: ein halber Sekundentakt als Nachricht,
solange die Watch-App im Vordergrund ist und das über eine Frist meldet,
sonst alle zwei Sekunden als Anwendungskontext und nur bei Änderungen.
Läuft die Frist ab, hört das iPhone von selbst wieder auf.
Solange die Uhr hinschaut, hält die App das Funkgerät auch im Hintergrund
am Leben (UIBackgroundModes in Config/CamperMonitor-Info.plist) – beim
Rangieren liegt das iPhone sonst mit dunklem Bildschirm in der Halterung
und die Anzeige am Handgelenk wäre genau dann tot. Die verbundenen Geräte
liefern dabei weiter, die Victron-Werbedaten nicht: ungefiltertes Suchen
lässt iOS im Hintergrund nicht zu.
Der plattformneutrale Modellcode wandert nach Shared/ und wird in beide
Targets übersetzt; LevelState ist dafür aus VanAlignProtocol.swift
herausgelöst. Datensatz und Befehle stehen in Shared/WatchLink und sind
in run-tests.sh abgesichert: Rundlauf, Schutz gegen fremde Formatversion,
Vergleich ohne Zeitstempel und die Auflösung der Zeitangaben.
Geprüft sind der Bau beider Targets samt Einbetten und der Testlauf; auf
echter Hardware noch nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>