- detectSystemMessages() erkennt jetzt auch den Uebergang zu einem GPS-Fix (flankengetriggert wie Battery/Failsafe), Meldung "GPS fix acquired (N satellites)". - Die automatisch erkannten Verbindungsmeldungen heissen jetzt "Drone connected"/"Drone disconnected" statt "Connected"/"Connection lost" - praeziser an die tatsaechliche Bedeutung angelehnt (Eintreffen/Ausbleiben echter Telemetrie-Frames, nicht nur des rohen Socket-Zustands). - DroneProfile: feste Pack-Alarmspannung (batteryVoltageGreenMinV/RedMinV) ersetzt durch batteryCellCount + Pro-Zelle-Schwellwerte (batteryVoltageGreenMinPerCellV/RedMinPerCellV, LiPo-Standardwerte 3.4/3.2 V als Default). Die alten Feldnamen bleiben als berechnete Getter (Zellenzahl * Pro-Zelle-Wert) erhalten, damit telemetry_field_status.dart unveraendert bleibt. T1-Ranger-Standardprofil auf 4S gesetzt. - DB-Schema v8 -> v9 (additiv, alte Pack-Spannungs-Spalten bleiben als tote Spalten stehen), Repository und Share-Codec-Im-/Export entsprechend angepasst; alte Exportdateien ohne die neuen Felder fallen auf die DroneProfile-Defaults zurueck statt eine unbekannte Zellenzahl zu raten. - DroneProfileEditor: "Battery voltage alarm"-Gruppe um ein Zellenzahl-Feld erweitert und auf V/Zelle umbenannt. - Tests ergaenzt/angepasst: GPS-Fix-Erkennung (Unit + Provider-Integration), neuer v8->v9-Migrationstest analog zum bestehenden v7->v8-Test, Connected/Disconnected-Umbenennung in Provider- und Widget-Tests, Cell-Count-Roundtrip in Repository- und Share-Codec-Tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
123 lines
5.1 KiB
Dart
123 lines
5.1 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../domain/telemetry/system_message.dart';
|
|
import '../../transport/connection_type.dart';
|
|
import '../../transport/flight_controller_link.dart';
|
|
import 'connection_settings_provider.dart';
|
|
import 'telemetry_provider.dart';
|
|
|
|
/// Haelt die Liste der System Messages plus das manuelle [log()] (Doku:
|
|
/// "aendere das warnings Menü in System Messages"). Bewusst schlank, ohne
|
|
/// jede Telemetrie-/Verbindungsbeobachtung: mission_meta_provider.dart und
|
|
/// active_drone_profile_provider.dart rufen log() auch aus dem Plan-Modus
|
|
/// heraus auf (Missions-/Drohnenprofilwechsel) - wuerde diese Klasse selbst
|
|
/// telemetryProvider beobachten, risse schon ein simpler Missionswechsel im
|
|
/// Plan-Modus ungewollt den kompletten Telemetrie-/Transport-Stack (inkl.
|
|
/// echtem MSP/UDP-Transport) mit hoch. Die automatische Erkennung
|
|
/// (Drone connected/disconnected/GPS-Fix/Batterie/Failsafe/Verbindungstyp-
|
|
/// Wechsel) sitzt deshalb separat in [systemMessageAutoLogProvider], die
|
|
/// ausschliesslich der Fly-Modus beobachtet.
|
|
class SystemMessageLogNotifier extends Notifier<List<SystemMessage>> {
|
|
@override
|
|
List<SystemMessage> build() => [];
|
|
|
|
/// Fuegt einen Eintrag manuell hinzu (Doku: "Wegpunkte uebertragen",
|
|
/// "Wechsel der Mission oder des Drohnenprofils") - fuer Ereignisse, die
|
|
/// vom Aufloeser einer konkreten Aktion gemeldet werden, statt aus
|
|
/// Telemetrie/Einstellungen automatisch erkannt zu werden.
|
|
void log(String message, {SystemMessageSeverity severity = SystemMessageSeverity.info}) {
|
|
state = [
|
|
SystemMessage(timestamp: DateTime.now(), message: message, severity: severity),
|
|
...state,
|
|
];
|
|
}
|
|
|
|
void clear() => state = [];
|
|
}
|
|
|
|
final systemMessageLogProvider =
|
|
NotifierProvider<SystemMessageLogNotifier, List<SystemMessage>>(
|
|
SystemMessageLogNotifier.new);
|
|
|
|
/// Automatische Erkennung von Drone-connected/-disconnected/GPS-Fix/
|
|
/// Batterie-/Failsafe-/Verbindungstyp-Aenderungen (Doku: "wenn die
|
|
/// Verbindung hergestellt wird/verloren geht, der verbindungstyp geaendert
|
|
/// wird, gps fix aquired") - getrennt von
|
|
/// [systemMessageLogProvider] selbst (siehe dessen Doku), damit Plan-Modus-
|
|
/// Code, der nur log() fuer eine manuelle Meldung braucht, nicht versehentlich
|
|
/// telemetryProvider mit hochzieht. autoDispose: nur beobachtet, waehrend
|
|
/// irgendwer (FlyScreen) diesen Provider liest - verlaesst der Nutzer den
|
|
/// Fly-Modus, wird die Beobachtung wieder abgebaut wie bei telemetryProvider
|
|
/// selbst.
|
|
final systemMessageAutoLogProvider = Provider.autoDispose<void>((ref) {
|
|
TelemetryFrame? previousFrame;
|
|
var hadData = false;
|
|
|
|
ref.listen<AsyncValue<TelemetryFrame>>(telemetryProvider, (previous, next) {
|
|
next.when(
|
|
data: (frame) {
|
|
final log = ref.read(systemMessageLogProvider.notifier);
|
|
// Flankengetriggert wie "Drone disconnected" unten, nur umgekehrt -
|
|
// anders als dort ist hier kein Sonderfall fuer die allererste
|
|
// Verbindung noetig: der Uebergang "noch keine Daten" -> "erste
|
|
// Daten" ist immer ein echtes "Drone connected", auch beim
|
|
// allerersten Mal. Bewusst an das Eintreffen eines echten
|
|
// Telemetrie-Frames gebunden statt an den rohen Socket-/Link-
|
|
// Zustand (Doku: "drone connected/disconnected (receiving valid
|
|
// telemetry)") - ein offener Socket ohne auswertbare MSP-Antworten
|
|
// zaehlt also nicht als "connected".
|
|
if (!hadData) {
|
|
log.log('Drone connected');
|
|
}
|
|
final events = detectSystemMessages(
|
|
previous: previousFrame,
|
|
current: frame,
|
|
now: DateTime.now(),
|
|
);
|
|
previousFrame = frame;
|
|
hadData = true;
|
|
for (final event in events) {
|
|
log.log(event.message, severity: event.severity);
|
|
}
|
|
},
|
|
error: (error, stackTrace) {
|
|
// Nur melden, wenn zuvor bereits Frames flossen - sonst wuerde
|
|
// schon das (normale) Ausbleiben der allerersten Verbindung als
|
|
// "Drone disconnected" auftauchen.
|
|
if (hadData) {
|
|
ref.read(systemMessageLogProvider.notifier)
|
|
.log('Drone disconnected', severity: SystemMessageSeverity.critical);
|
|
}
|
|
previousFrame = null;
|
|
hadData = false;
|
|
},
|
|
loading: () {},
|
|
);
|
|
});
|
|
|
|
// Verbindungsart-Wechsel (Doku: "Verbindungstyp geaendert") - nur ab dem
|
|
// zweiten geladenen Wert protokollieren, sonst wuerde bereits das
|
|
// erstmalige Laden der Einstellungen aus der DB als "Wechsel" erscheinen.
|
|
ConnectionType? previousType;
|
|
var sawFirstLoad = false;
|
|
ref.listen(connectionSettingsProvider, (previous, next) {
|
|
final type = next.value?.connectionType;
|
|
if (type == null) return;
|
|
if (!sawFirstLoad) {
|
|
sawFirstLoad = true;
|
|
previousType = type;
|
|
return;
|
|
}
|
|
if (type != previousType) {
|
|
ref.read(systemMessageLogProvider.notifier)
|
|
.log('Connection type changed to ${_connectionTypeLabel(type)}');
|
|
previousType = type;
|
|
}
|
|
});
|
|
});
|
|
|
|
String _connectionTypeLabel(ConnectionType type) => switch (type) {
|
|
ConnectionType.wifi => 'WiFi mLRS UDP',
|
|
ConnectionType.mock => 'Mock (Test)',
|
|
};
|