drone status menue: fixed empty display bug without active telemetry stream
This commit is contained in:
@@ -43,6 +43,15 @@ SignalLevel _levelLowerIsBetter(double value, double greenMax, double redMax) {
|
|||||||
/// Reine Ableitung aus normalisierten Telemetriewerten + den
|
/// Reine Ableitung aus normalisierten Telemetriewerten + den
|
||||||
/// Ampel-Schwellwerten des aktiven Drohnenprofils - kein MSP-/
|
/// Ampel-Schwellwerten des aktiven Drohnenprofils - kein MSP-/
|
||||||
/// Protokollwissen, siehe computeDroneStatus-Doku.
|
/// Protokollwissen, siehe computeDroneStatus-Doku.
|
||||||
|
///
|
||||||
|
/// [hasData] ist false, solange noch gar kein Telemetrie-Frame vorliegt
|
||||||
|
/// (Doku: "Felder auch anzeigen koennen, bevor Daten empfangen wurden") -
|
||||||
|
/// erzwingt dann fuer ALLE Felder rot, unabhaengig von den uebergebenen
|
||||||
|
/// Platzhalterwerten. Ohne das wuerde z.B. "Current draw" (ein Feld, bei dem
|
||||||
|
/// ein NIEDRIGER Wert gut ist) mit dem neutralen Platzhalter 0 faelschlich
|
||||||
|
/// gruen erscheinen ("sehr niedriger Verbrauch" statt "keine Daten") - anders
|
||||||
|
/// als bei den "hoeher ist besser"-Feldern, wo ein 0/negativer Platzhalter
|
||||||
|
/// zufaellig schon unter der Rot-Schwelle liegt.
|
||||||
TelemetryFieldStatus computeTelemetryFieldStatus({
|
TelemetryFieldStatus computeTelemetryFieldStatus({
|
||||||
required int numSat,
|
required int numSat,
|
||||||
required bool hasFix,
|
required bool hasFix,
|
||||||
@@ -52,7 +61,18 @@ TelemetryFieldStatus computeTelemetryFieldStatus({
|
|||||||
required int linkQuality,
|
required int linkQuality,
|
||||||
required int snrDb,
|
required int snrDb,
|
||||||
required DroneProfile profile,
|
required DroneProfile profile,
|
||||||
|
bool hasData = true,
|
||||||
}) {
|
}) {
|
||||||
|
if (!hasData) {
|
||||||
|
return const TelemetryFieldStatus(
|
||||||
|
numSat: SignalLevel.red,
|
||||||
|
hdop: SignalLevel.red,
|
||||||
|
currentA: SignalLevel.red,
|
||||||
|
batteryVoltage: SignalLevel.red,
|
||||||
|
rxQuality: SignalLevel.red,
|
||||||
|
rxSnr: SignalLevel.red,
|
||||||
|
);
|
||||||
|
}
|
||||||
return TelemetryFieldStatus(
|
return TelemetryFieldStatus(
|
||||||
numSat: _levelHigherIsBetter(
|
numSat: _levelHigherIsBetter(
|
||||||
numSat.toDouble(),
|
numSat.toDouble(),
|
||||||
|
|||||||
@@ -110,65 +110,66 @@ class _DroneStatusWarningsPanelState extends ConsumerState<DroneStatusWarningsPa
|
|||||||
|
|
||||||
// --- Status ---
|
// --- Status ---
|
||||||
|
|
||||||
|
// Zeigt die Statuszeilen unabhaengig davon, ob bereits ein Telemetrie-Frame
|
||||||
|
// vorliegt (Doku: "endloser Lade-Screen ohne die Datenfelder anzuzeigen" -
|
||||||
|
// z.B. WLAN gewaehlt, aber noch nicht verbunden) - `telemetry` bleibt dann
|
||||||
|
// dauerhaft AsyncLoading, .value ist einfach null. Analog zu FlyScreen.
|
||||||
|
// droneStatus (siehe dortige Doku) werden Platzhalterwerte verwendet, damit
|
||||||
|
// computeTelemetryFieldStatus trotzdem eine (dann durchgehend rote) Ampel
|
||||||
|
// liefert, statt hier zusaetzlich zwischen "noch nie verbunden" und
|
||||||
|
// "Verbindung verloren" zu unterscheiden. Einzelne Werte zeigen dennoch
|
||||||
|
// '—' statt eines erfundenen Messwerts (0 A/0 V saehe sonst wie ein echter,
|
||||||
|
// kritischer Messwert statt wie "keine Daten" aus).
|
||||||
Widget _statusTab() {
|
Widget _statusTab() {
|
||||||
final telemetry = ref.watch(telemetryProvider);
|
final frame = ref.watch(telemetryProvider).value;
|
||||||
final droneProfile = ref.watch(activeDroneProfileProvider);
|
final droneProfile = ref.watch(activeDroneProfileProvider);
|
||||||
return telemetry.when(
|
final fieldStatus = computeTelemetryFieldStatus(
|
||||||
data: (frame) {
|
numSat: frame?.numSat ?? 0,
|
||||||
final fieldStatus = computeTelemetryFieldStatus(
|
hasFix: frame?.hasFix ?? false,
|
||||||
numSat: frame.numSat,
|
hdop: frame?.hdop ?? 99.0,
|
||||||
hasFix: frame.hasFix,
|
currentA: frame?.currentA ?? 0,
|
||||||
hdop: frame.hdop,
|
batteryVoltage: frame?.batteryVoltage ?? 0,
|
||||||
currentA: frame.currentA,
|
linkQuality: frame?.linkQuality ?? 0,
|
||||||
batteryVoltage: frame.batteryVoltage,
|
snrDb: frame?.snrDb ?? -99,
|
||||||
linkQuality: frame.linkQuality,
|
profile: droneProfile,
|
||||||
snrDb: frame.snrDb,
|
hasData: frame != null,
|
||||||
profile: droneProfile,
|
);
|
||||||
);
|
return ListView(
|
||||||
return ListView(
|
padding: const EdgeInsets.all(16),
|
||||||
padding: const EdgeInsets.all(16),
|
children: _statusGrid([
|
||||||
children: _statusGrid([
|
// Farbcodierte Felder zuerst (Doku: "drone status felder im menue
|
||||||
// Farbcodierte Felder zuerst (Doku: "drone status felder im
|
// auch farblich kodieren", Schwellwerte je Drohnenprofil - siehe
|
||||||
// menue auch farblich kodieren", Schwellwerte je Drohnenprofil -
|
// computeTelemetryFieldStatus), informelle Felder ohne Ampel-
|
||||||
// siehe computeTelemetryFieldStatus), informelle Felder ohne
|
// Bewertung (Koordinaten/Heading/Alt/Speed) danach. Je 2 Felder pro
|
||||||
// Ampel-Bewertung (Koordinaten/Heading/Alt/Speed) danach. Je 2
|
// Zeile (Doku: "platz effizienter nutzen").
|
||||||
// Felder pro Zeile (Doku: "platz effizienter nutzen").
|
_statusRow('GPS satellites', frame != null ? '${frame.numSat}' : '—', level: fieldStatus.numSat),
|
||||||
_statusRow('GPS satellites', '${frame.numSat}', level: fieldStatus.numSat),
|
_statusRow(
|
||||||
_statusRow(
|
'GPS precision (HDOP)',
|
||||||
'GPS precision (HDOP)',
|
frame != null && frame.hasFix ? frame.hdop.toStringAsFixed(2) : '—',
|
||||||
frame.hasFix ? frame.hdop.toStringAsFixed(2) : '—',
|
level: fieldStatus.hdop,
|
||||||
level: fieldStatus.hdop,
|
),
|
||||||
),
|
_statusRow(
|
||||||
_statusRow(
|
'Current draw',
|
||||||
'Current draw',
|
frame != null ? '${frame.currentA.toStringAsFixed(1)} A' : '—',
|
||||||
'${frame.currentA.toStringAsFixed(1)} A',
|
level: fieldStatus.currentA,
|
||||||
level: fieldStatus.currentA,
|
),
|
||||||
),
|
_statusRow(
|
||||||
_statusRow(
|
'Battery voltage',
|
||||||
'Battery voltage',
|
frame != null ? '${frame.batteryVoltage.toStringAsFixed(2)} V' : '—',
|
||||||
'${frame.batteryVoltage.toStringAsFixed(2)} V',
|
level: fieldStatus.batteryVoltage,
|
||||||
level: fieldStatus.batteryVoltage,
|
),
|
||||||
),
|
_statusRow('RX quality', frame != null ? '${frame.linkQuality}%' : '—', level: fieldStatus.rxQuality),
|
||||||
_statusRow('RX quality', '${frame.linkQuality}%', level: fieldStatus.rxQuality),
|
_statusRow('RX SNR', frame != null ? '${frame.snrDb} dB' : '—', level: fieldStatus.rxSnr),
|
||||||
_statusRow('RX SNR', '${frame.snrDb} dB', level: fieldStatus.rxSnr),
|
_statusRow(
|
||||||
_statusRow(
|
'GPS coordinates',
|
||||||
'GPS coordinates',
|
frame != null && frame.hasFix
|
||||||
frame.hasFix
|
? '${frame.lat.toStringAsFixed(6)}, ${frame.lon.toStringAsFixed(6)}'
|
||||||
? '${frame.lat.toStringAsFixed(6)}, ${frame.lon.toStringAsFixed(6)}'
|
: '—',
|
||||||
: '—',
|
),
|
||||||
),
|
_statusRow('Heading', frame != null ? '${frame.headingDeg.round()}°' : '—'),
|
||||||
_statusRow('Heading', '${frame.headingDeg.round()}°'),
|
_statusRow('Altitude', frame != null ? '${frame.altitudeM.toStringAsFixed(0)} m' : '—'),
|
||||||
_statusRow('Altitude', '${frame.altitudeM.toStringAsFixed(0)} m'),
|
_statusRow('Speed', frame != null ? '${frame.speedMs.toStringAsFixed(1)} m/s' : '—'),
|
||||||
_statusRow('Speed', '${frame.speedMs.toStringAsFixed(1)} m/s'),
|
]),
|
||||||
]),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
loading: () => const Center(
|
|
||||||
child: CircularProgressIndicator(color: Color(0xFF4D9DFF)),
|
|
||||||
),
|
|
||||||
error: (err, st) => const Center(
|
|
||||||
child: Text('No telemetry', style: TextStyle(color: Colors.white60, fontSize: 15)),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user