Files
BiasFandClaude Opus 5 edf3f5b779 Neigungsmesser: Einrichtung auf eine eigene Seite
Kalibrierung und Einbaulage standen direkt unter der Libelle. Wer im
Fahrzeug die Anzeige abliest und dabei scrollt, verstellt so leicht den
Nullpunkt - und merkt es nicht, weil die Anzeige danach schlicht null
zeigt. Beides liegt jetzt hinter "Neigungsmesser einrichten".

In der Geräteansicht bleibt, was im Betrieb gebraucht wird: die Libelle,
die Werte und der Ausrichtungs-Assistent. Die Einrichtungszeile nennt den
Stand, damit man nicht erst hineinschauen muss - fehlt der Nullpunkt,
steht das dort.

Die Namen sagen jetzt, was geschieht. "Auf aktuelle Lage kalibrieren"
klang nach einer Messung, gemeint ist das Festlegen des Nullpunkts: jetzt
"Aktuelle Lage als eben übernehmen", das Zurücksetzen entsprechend
"Nullpunkt verwerfen". Aus dem Hauptwort "Einbaulage" wird "Einbaulage
bestimmen".

Die beiden Schritte stehen in der Reihenfolge, in der sie gehören: erst
die Einbaulage, sonst legt der Nullpunkt sich auf die falsche Achse.
Beide Knöpfe bleiben stumm, solange keine Werte ankommen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 09:38:01 +02:00

126 lines
4.9 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import SwiftUI
/// Einrichtung des Neigungsmessers: Einbaulage und Nullpunkt.
///
/// Beides wird einmal eingestellt und danach kaum wieder angefasst. In der
/// Geräteansicht standen die Knöpfe direkt unter der Libelle ein Fehlgriff
/// beim Ablesen verstellte dort den Nullpunkt. Deshalb liegen sie hier.
///
/// Die Reihenfolge ist nicht beliebig: erst muss klar sein, welche Achse des
/// Sensors welche des Fahrzeugs ist, sonst wird der Nullpunkt auf die falsche
/// Achse gelegt.
struct LevelSetupView: View {
let device: ConfiguredDevice
@Environment(BluetoothManager.self) private var bluetooth
@State private var showSensorSetup = false
@State private var showResetConfirmation = false
private var state: LevelState { bluetooth.levelStates[device.id] ?? LevelState() }
/// Immer der aktuelle Stand `device` veraltet, sobald der Assistent
/// eine neue Einbaulage gespeichert hat.
@Environment(DeviceStore.self) private var store
private var currentDevice: ConfiguredDevice {
store.devices.first { $0.id == device.id } ?? device
}
var body: some View {
List {
Section {
HStack(spacing: 24) {
reading("Längs", state.pitch)
reading("Quer", state.roll)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 4)
}
Section {
Button {
showSensorSetup = true
} label: {
LabeledContent {
Text(currentDevice.sensorOrientation.summary)
.font(.caption)
} label: {
Label("Einbaulage bestimmen",
systemImage: "arrow.triangle.2.circlepath")
}
}
.disabled(!state.hasReading)
} header: {
Text("Schritt 1 Einbaulage")
} footer: {
Text("Sitzt der Sensor quer oder verdreht im Fahrzeug, meldet er längs "
+ "und quer vertauscht. Der Assistent klärt das durch zweimaliges "
+ "Kippen. Danach den Nullpunkt setzen.")
}
Section {
Button {
bluetooth.calibrateLevel(for: device.id)
} label: {
Label("Aktuelle Lage als eben übernehmen", systemImage: "scope")
}
.disabled(!state.hasReading)
if !state.isKnownUncalibrated {
Button(role: .destructive) {
showResetConfirmation = true
} label: {
// Ohne das bliebe das Symbol in der Akzentfarbe, während
// die Beschriftung rot ist.
Label("Nullpunkt verwerfen", systemImage: "arrow.uturn.backward")
.foregroundStyle(.red)
}
}
} header: {
Text("Schritt 2 Nullpunkt")
} footer: {
Text(calibrationHint)
}
}
.navigationTitle("Neigungsmesser einrichten")
.navigationBarTitleDisplayMode(.inline)
.sheet(isPresented: $showSensorSetup) {
SensorSetupView(device: currentDevice)
}
.confirmationDialog("Nullpunkt verwerfen?",
isPresented: $showResetConfirmation,
titleVisibility: .visible) {
Button("Verwerfen", role: .destructive) {
bluetooth.resetLevelCalibration(for: device.id)
}
} message: {
Text("Die Anzeige zeigt danach wieder die Lage des Sensors.")
}
}
private var calibrationHint: String {
if state.isCalibrated, let pitchOffset = state.pitchOffset,
let rollOffset = state.rollOffset {
return String(format: "Der Nullpunkt liegt bei %.1f° längs und %.1f° quer. "
+ "Zum Neusetzen das Fahrzeug eben stellen und dann tippen.",
pitchOffset, rollOffset)
}
if state.isKnownUncalibrated {
return "Noch kein Nullpunkt gesetzt die Anzeige zeigt die Lage des "
+ "Sensors, nicht die des Fahrzeugs. Fahrzeug eben stellen, dann tippen."
}
// Ältere Firmware gibt die Offsets nicht heraus.
return "Zum Setzen das Fahrzeug eben stellen und dann tippen. Ob schon ein "
+ "Nullpunkt gesetzt wurde, meldet dieses Gerät nicht zurück."
}
private func reading(_ title: String, _ value: Double?) -> some View {
VStack(spacing: 2) {
Text(value.map { String(format: "%.1f°", $0) } ?? "")
.font(.title2.weight(.semibold).monospacedDigit())
Text(title)
.font(.caption)
.foregroundStyle(.secondary)
}
}
}