Waehrend eines Verbindungsverlusts frieren die TelemetryFrame-Werte
bewusst ein (telemetryProvider.value bleibt auf dem letzten Stand, siehe
vorherigen Commit) - die Fusszeilen-Pille im Fly-Modus hat daraus bislang
weiterhin den zuletzt bekannten (ggf. laengst veralteten) Zustand
abgeleitet, statt den Verbindungsverlust selbst widerzuspiegeln.
- domain/telemetry/drone_status.dart: neuer DroneState.disconnected,
computeDroneStatus() bekommt einen neuen Parameter `connected` - hat
Vorrang vor allem anderen (auch vor Emergency) und uebersteuert
connectionQuality auf rot. positionQuality bleibt bewusst unveraendert
(folgt weiterhin den eingefrorenen Werten) - laut Anfrage sollen nur
Drohnen-Icon und Verbindungsqualitaet, nicht die Positionsqualitaet, rot
erzwungen werden.
- fly_screen.dart: `connected: !telemetryAsync.hasError` statt der
bisherigen Ableitung aus einzelnen Telemetriewerten.
- bottom_stats_bar.dart: neues Label/Farbe ("disconnected", rot) fuer den
neuen Zustand in der Drohnen-Status-Pille.
Auf dem Pixel_10a-Emulator verifiziert: WiFi-Verbindungsart (noch nie
verbunden) zeigt bereits korrekt rotes Papierflieger-Icon, rote
Verbindungsqualitaet, rotes Satelliten-Icon und "disconnected" in rot;
Mock-Verbindung zeigt unveraendert normal gruen "ready".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
246 lines
6.3 KiB
Dart
246 lines
6.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import 'package:dmc_app/domain/telemetry/drone_status.dart';
|
|
|
|
void main() {
|
|
group('computeDroneStatus - connectionQuality', () {
|
|
test('gruen bei LQ >=70% und SNR >=0dB', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 70,
|
|
snrDb: 0,
|
|
navMode: 0,
|
|
);
|
|
expect(status.connectionQuality, SignalLevel.green);
|
|
});
|
|
|
|
test('gelb bei LQ >=70% aber SNR <0dB (Rauschen trotz guter LQ)', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 90,
|
|
snrDb: -1,
|
|
navMode: 0,
|
|
);
|
|
expect(status.connectionQuality, SignalLevel.yellow);
|
|
});
|
|
|
|
test('gelb bei LQ zwischen 50% und 70%', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 60,
|
|
snrDb: 5,
|
|
navMode: 0,
|
|
);
|
|
expect(status.connectionQuality, SignalLevel.yellow);
|
|
});
|
|
|
|
test('rot bei LQ <50%', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 20,
|
|
snrDb: 10,
|
|
navMode: 0,
|
|
);
|
|
expect(status.connectionQuality, SignalLevel.red);
|
|
});
|
|
});
|
|
|
|
group('computeDroneStatus - positionQuality', () {
|
|
test('gruen bei >=8 Satelliten und HDOP <2.0', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 9,
|
|
hdop: 1.5,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 0,
|
|
);
|
|
expect(status.positionQuality, SignalLevel.green);
|
|
});
|
|
|
|
test('gelb bei >=6 Satelliten und HDOP <5.0, aber nicht gruen-Schwelle', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 6,
|
|
hdop: 3.0,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 0,
|
|
);
|
|
expect(status.positionQuality, SignalLevel.yellow);
|
|
});
|
|
|
|
test('rot ohne GPS-Fix, unabhaengig von Satelliten/HDOP', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: false,
|
|
numSat: 12,
|
|
hdop: 0.5,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 0,
|
|
);
|
|
expect(status.positionQuality, SignalLevel.red);
|
|
});
|
|
|
|
test('rot bei wenigen Satelliten trotz Fix', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 3,
|
|
hdop: 8.0,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 0,
|
|
);
|
|
expect(status.positionQuality, SignalLevel.red);
|
|
});
|
|
});
|
|
|
|
group('computeDroneStatus - state', () {
|
|
test('error hat Vorrang, sobald navMode Emergency (15) ist', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: true,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 15,
|
|
);
|
|
expect(status.state, DroneState.error);
|
|
});
|
|
|
|
test('waypoint, wenn armed und navMode Waypoint mission (3)', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: true,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 3,
|
|
);
|
|
expect(status.state, DroneState.waypoint);
|
|
});
|
|
|
|
test('armed, wenn armed aber kein Waypoint-Modus (z.B. Hold)', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: true,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 1,
|
|
);
|
|
expect(status.state, DroneState.armed);
|
|
});
|
|
|
|
test('ready, wenn nicht armed aber GPS-Fix vorhanden', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 0,
|
|
);
|
|
expect(status.state, DroneState.ready);
|
|
});
|
|
|
|
test('idle, wenn nicht armed und kein GPS-Fix', () {
|
|
final status = computeDroneStatus(
|
|
connected: true,
|
|
armed: false,
|
|
hasFix: false,
|
|
numSat: 0,
|
|
hdop: 99.99,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
navMode: 0,
|
|
);
|
|
expect(status.state, DroneState.idle);
|
|
});
|
|
});
|
|
|
|
group('computeDroneStatus - connected: false (Doku: "Statuspille ... muss '
|
|
'eine rote Drohne, eine rote Verbindungsqualität und den Status text '
|
|
'in rot disconnected anzeigen")', () {
|
|
test('state ist disconnected, unabhaengig von allen anderen Werten', () {
|
|
final status = computeDroneStatus(
|
|
connected: false,
|
|
armed: true,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 80,
|
|
snrDb: 5,
|
|
// Emergency-navMode haette ohne den connected-Vorrang "error"
|
|
// ergeben statt "disconnected".
|
|
navMode: 15,
|
|
);
|
|
expect(status.state, DroneState.disconnected);
|
|
});
|
|
|
|
test('connectionQuality ist rot, unabhaengig von linkQuality/snrDb', () {
|
|
final status = computeDroneStatus(
|
|
connected: false,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
// Waeren an sich beste Werte (gruen) - werden von connected:false
|
|
// trotzdem uebersteuert.
|
|
linkQuality: 100,
|
|
snrDb: 20,
|
|
navMode: 0,
|
|
);
|
|
expect(status.connectionQuality, SignalLevel.red);
|
|
});
|
|
|
|
test('positionQuality folgt weiterhin den (eingefrorenen) Telemetriewerten '
|
|
'- nur Drohne/Verbindungsqualitaet werden per Doku explizit rot '
|
|
'gefordert', () {
|
|
final status = computeDroneStatus(
|
|
connected: false,
|
|
armed: false,
|
|
hasFix: true,
|
|
numSat: 10,
|
|
hdop: 1.0,
|
|
linkQuality: 0,
|
|
snrDb: -99,
|
|
navMode: 0,
|
|
);
|
|
expect(status.positionQuality, SignalLevel.green);
|
|
});
|
|
});
|
|
}
|