diff --git a/app/lib/domain/mission/drone_profile.dart b/app/lib/domain/mission/drone_profile.dart index 0903f81..8a578f6 100644 --- a/app/lib/domain/mission/drone_profile.dart +++ b/app/lib/domain/mission/drone_profile.dart @@ -17,6 +17,18 @@ class DroneProfile { required this.maxRangeM, required this.maxEnduranceMin, required this.maxAltitudeM, + this.gpsSatGreenMin = defaultGpsSatGreenMin, + this.gpsSatRedMin = defaultGpsSatRedMin, + this.hdopGreenMax = defaultHdopGreenMax, + this.hdopRedMax = defaultHdopRedMax, + this.currentGreenMaxA = defaultCurrentGreenMaxA, + this.currentRedMaxA = defaultCurrentRedMaxA, + this.batteryVoltageGreenMinV = defaultBatteryVoltageGreenMinV, + this.batteryVoltageRedMinV = defaultBatteryVoltageRedMinV, + this.rxQualityGreenMin = defaultRxQualityGreenMin, + this.rxQualityRedMin = defaultRxQualityRedMin, + this.rxSnrGreenMinDb = defaultRxSnrGreenMinDb, + this.rxSnrRedMinDb = defaultRxSnrRedMinDb, }); /// Null fuer ein noch nicht gespeichertes (neu angelegtes) Profil. @@ -34,6 +46,42 @@ class DroneProfile { final double maxEnduranceMin; final double maxAltitudeM; + /// Ampel-Schwellwerte fuer die farbcodierten Telemetriefelder im + /// Drohnen-Status-Menue (Doku: "Schwellwerte fuer die Ampel-Kodierung im + /// Drohnenprofil anlegen", siehe domain/telemetry/telemetry_field_status.dart) + /// - je Feld eine Gruen- und eine Rot-Schwelle, dazwischen gilt gelb. + /// *Max/*GreenMax bei Feldern, bei denen ein NIEDRIGER Wert gut ist (HDOP), + /// *Min/*GreenMin bei Feldern, bei denen ein HOHER Wert gut ist (alle + /// anderen). Default-Werte als statische Konstanten (statt nur inline im + /// Konstruktor), damit sie auch als Fallback beim Import aelterer, noch + /// ohne diese Felder exportierter Profile dienen koennen (siehe + /// drone_share_codec.dart). + final double gpsSatGreenMin; + final double gpsSatRedMin; + final double hdopGreenMax; + final double hdopRedMax; + final double currentGreenMaxA; + final double currentRedMaxA; + final double batteryVoltageGreenMinV; + final double batteryVoltageRedMinV; + final double rxQualityGreenMin; + final double rxQualityRedMin; + final double rxSnrGreenMinDb; + final double rxSnrRedMinDb; + + static const defaultGpsSatGreenMin = 8.0; + static const defaultGpsSatRedMin = 6.0; + static const defaultHdopGreenMax = 2.0; + static const defaultHdopRedMax = 5.0; + static const defaultCurrentGreenMaxA = 20.0; + static const defaultCurrentRedMaxA = 30.0; + static const defaultBatteryVoltageGreenMinV = 20.4; + static const defaultBatteryVoltageRedMinV = 19.2; + static const defaultRxQualityGreenMin = 70.0; + static const defaultRxQualityRedMin = 50.0; + static const defaultRxSnrGreenMinDb = 0.0; + static const defaultRxSnrRedMinDb = -10.0; + /// T1 Ranger (Heewing) - Standardprofil (Doku 3.5), analog DEFAULT_DRONE /// im HTML-Demonstrator. static const _t1RangerName = 'T1 Ranger'; @@ -76,6 +124,18 @@ class DroneProfile { double? maxRangeM, double? maxEnduranceMin, double? maxAltitudeM, + double? gpsSatGreenMin, + double? gpsSatRedMin, + double? hdopGreenMax, + double? hdopRedMax, + double? currentGreenMaxA, + double? currentRedMaxA, + double? batteryVoltageGreenMinV, + double? batteryVoltageRedMinV, + double? rxQualityGreenMin, + double? rxQualityRedMin, + double? rxSnrGreenMinDb, + double? rxSnrRedMinDb, }) { return DroneProfile( id: id ?? this.id, @@ -91,6 +151,18 @@ class DroneProfile { maxRangeM: maxRangeM ?? this.maxRangeM, maxEnduranceMin: maxEnduranceMin ?? this.maxEnduranceMin, maxAltitudeM: maxAltitudeM ?? this.maxAltitudeM, + gpsSatGreenMin: gpsSatGreenMin ?? this.gpsSatGreenMin, + gpsSatRedMin: gpsSatRedMin ?? this.gpsSatRedMin, + hdopGreenMax: hdopGreenMax ?? this.hdopGreenMax, + hdopRedMax: hdopRedMax ?? this.hdopRedMax, + currentGreenMaxA: currentGreenMaxA ?? this.currentGreenMaxA, + currentRedMaxA: currentRedMaxA ?? this.currentRedMaxA, + batteryVoltageGreenMinV: batteryVoltageGreenMinV ?? this.batteryVoltageGreenMinV, + batteryVoltageRedMinV: batteryVoltageRedMinV ?? this.batteryVoltageRedMinV, + rxQualityGreenMin: rxQualityGreenMin ?? this.rxQualityGreenMin, + rxQualityRedMin: rxQualityRedMin ?? this.rxQualityRedMin, + rxSnrGreenMinDb: rxSnrGreenMinDb ?? this.rxSnrGreenMinDb, + rxSnrRedMinDb: rxSnrRedMinDb ?? this.rxSnrRedMinDb, ); } } diff --git a/app/lib/domain/telemetry/telemetry_field_status.dart b/app/lib/domain/telemetry/telemetry_field_status.dart new file mode 100644 index 0000000..468baa1 --- /dev/null +++ b/app/lib/domain/telemetry/telemetry_field_status.dart @@ -0,0 +1,89 @@ +import '../mission/drone_profile.dart'; +import 'drone_status.dart'; + +/// Ampel-Farbcodierung je einzelnem Telemetriefeld im Drohnen-Status-Menue +/// (Doku: "drone status felder im menue auch farblich kodieren") - anders +/// als [computeDroneStatus] (das Verbindungs-/Positionsqualitaet je zu einem +/// kombinierten Signal fuer die Fusszeilen-Pille zusammenfasst) bewertet +/// dies jedes Feld einzeln anhand der Schwellwerte im aktiven [DroneProfile]. +class TelemetryFieldStatus { + const TelemetryFieldStatus({ + required this.numSat, + required this.hdop, + required this.currentA, + required this.batteryVoltage, + required this.rxQuality, + required this.rxSnr, + }); + + final SignalLevel numSat; + final SignalLevel hdop; + final SignalLevel currentA; + final SignalLevel batteryVoltage; + final SignalLevel rxQuality; + final SignalLevel rxSnr; +} + +/// Fuer Felder, bei denen ein HOHER Wert gut ist (Satelliten, RX-Qualitaet/ +/// -SNR): rot unterhalb [redMin], gruen ab [greenMin], dazwischen gelb. +SignalLevel _levelHigherIsBetter(double value, double greenMin, double redMin) { + if (value < redMin) return SignalLevel.red; + if (value < greenMin) return SignalLevel.yellow; + return SignalLevel.green; +} + +/// Fuer Felder, bei denen ein NIEDRIGER Wert gut ist (HDOP): rot oberhalb +/// [redMax], gruen bis [greenMax], dazwischen gelb. +SignalLevel _levelLowerIsBetter(double value, double greenMax, double redMax) { + if (value > redMax) return SignalLevel.red; + if (value > greenMax) return SignalLevel.yellow; + return SignalLevel.green; +} + +/// Reine Ableitung aus normalisierten Telemetriewerten + den +/// Ampel-Schwellwerten des aktiven Drohnenprofils - kein MSP-/ +/// Protokollwissen, siehe computeDroneStatus-Doku. +TelemetryFieldStatus computeTelemetryFieldStatus({ + required int numSat, + required bool hasFix, + required double hdop, + required double currentA, + required double batteryVoltage, + required int linkQuality, + required int snrDb, + required DroneProfile profile, +}) { + return TelemetryFieldStatus( + numSat: _levelHigherIsBetter( + numSat.toDouble(), + profile.gpsSatGreenMin, + profile.gpsSatRedMin, + ), + // Ohne Fix ist der HDOP-Wert bedeutungslos/veraltet (siehe Anzeige in + // drone_status_warnings_panel.dart, die dafuer bereits '—' zeigt) - dann + // unabhaengig vom Zahlenwert rot statt eines irrefuehrend guten Signals. + hdop: hasFix + ? _levelLowerIsBetter(hdop, profile.hdopGreenMax, profile.hdopRedMax) + : SignalLevel.red, + currentA: _levelLowerIsBetter( + currentA, + profile.currentGreenMaxA, + profile.currentRedMaxA, + ), + batteryVoltage: _levelHigherIsBetter( + batteryVoltage, + profile.batteryVoltageGreenMinV, + profile.batteryVoltageRedMinV, + ), + rxQuality: _levelHigherIsBetter( + linkQuality.toDouble(), + profile.rxQualityGreenMin, + profile.rxQualityRedMin, + ), + rxSnr: _levelHigherIsBetter( + snrDb.toDouble(), + profile.rxSnrGreenMinDb, + profile.rxSnrRedMinDb, + ), + ); +} diff --git a/app/lib/services/database/app_database.dart b/app/lib/services/database/app_database.dart index aaf5e30..cbbe7ae 100644 --- a/app/lib/services/database/app_database.dart +++ b/app/lib/services/database/app_database.dart @@ -50,6 +50,32 @@ class DroneProfiles extends Table { RealColumn get maxRangeM => real()(); RealColumn get maxEnduranceMin => real()(); RealColumn get maxAltitudeM => real()(); + + /// Ampel-Schwellwerte fuer die Telemetriefelder im Drohnen-Status-Menue + /// (siehe domain.DroneProfile-Doku und domain/telemetry/ + /// telemetry_field_status.dart) - Defaults identisch zu den + /// DroneProfile.default*-Konstanten. + RealColumn get gpsSatGreenMin => + real().withDefault(const Constant(8.0))(); + RealColumn get gpsSatRedMin => real().withDefault(const Constant(6.0))(); + RealColumn get hdopGreenMax => real().withDefault(const Constant(2.0))(); + RealColumn get hdopRedMax => real().withDefault(const Constant(5.0))(); + RealColumn get currentGreenMaxA => + real().withDefault(const Constant(20.0))(); + RealColumn get currentRedMaxA => + real().withDefault(const Constant(30.0))(); + RealColumn get batteryVoltageGreenMinV => + real().withDefault(const Constant(20.4))(); + RealColumn get batteryVoltageRedMinV => + real().withDefault(const Constant(19.2))(); + RealColumn get rxQualityGreenMin => + real().withDefault(const Constant(70.0))(); + RealColumn get rxQualityRedMin => + real().withDefault(const Constant(50.0))(); + RealColumn get rxSnrGreenMinDb => + real().withDefault(const Constant(0.0))(); + RealColumn get rxSnrRedMinDb => + real().withDefault(const Constant(-10.0))(); } /// Einzeilige Einstellungstabelle (id fest 0) fuer app-weite Auswahl, die @@ -110,7 +136,7 @@ class AppDatabase extends _$AppDatabase { AppDatabase.forTesting(super.executor); @override - int get schemaVersion => 7; + int get schemaVersion => 8; @override MigrationStrategy get migration => MigrationStrategy( @@ -157,6 +183,26 @@ class AppDatabase extends _$AppDatabase { if (from < 7) { await m.addColumn(missions, missions.terrainProfileJson); } + if (from < 8) { + await m.addColumn(droneProfiles, droneProfiles.gpsSatGreenMin); + await m.addColumn(droneProfiles, droneProfiles.gpsSatRedMin); + await m.addColumn(droneProfiles, droneProfiles.hdopGreenMax); + await m.addColumn(droneProfiles, droneProfiles.hdopRedMax); + await m.addColumn(droneProfiles, droneProfiles.currentGreenMaxA); + await m.addColumn(droneProfiles, droneProfiles.currentRedMaxA); + await m.addColumn( + droneProfiles, + droneProfiles.batteryVoltageGreenMinV, + ); + await m.addColumn( + droneProfiles, + droneProfiles.batteryVoltageRedMinV, + ); + await m.addColumn(droneProfiles, droneProfiles.rxQualityGreenMin); + await m.addColumn(droneProfiles, droneProfiles.rxQualityRedMin); + await m.addColumn(droneProfiles, droneProfiles.rxSnrGreenMinDb); + await m.addColumn(droneProfiles, droneProfiles.rxSnrRedMinDb); + } }, ); diff --git a/app/lib/services/database/app_database.g.dart b/app/lib/services/database/app_database.g.dart index 17693c8..52af030 100644 --- a/app/lib/services/database/app_database.g.dart +++ b/app/lib/services/database/app_database.g.dart @@ -721,6 +721,151 @@ class $DroneProfilesTable extends DroneProfiles type: DriftSqlType.double, requiredDuringInsert: true, ); + static const VerificationMeta _gpsSatGreenMinMeta = const VerificationMeta( + 'gpsSatGreenMin', + ); + @override + late final GeneratedColumn gpsSatGreenMin = GeneratedColumn( + 'gps_sat_green_min', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(8.0), + ); + static const VerificationMeta _gpsSatRedMinMeta = const VerificationMeta( + 'gpsSatRedMin', + ); + @override + late final GeneratedColumn gpsSatRedMin = GeneratedColumn( + 'gps_sat_red_min', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(6.0), + ); + static const VerificationMeta _hdopGreenMaxMeta = const VerificationMeta( + 'hdopGreenMax', + ); + @override + late final GeneratedColumn hdopGreenMax = GeneratedColumn( + 'hdop_green_max', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(2.0), + ); + static const VerificationMeta _hdopRedMaxMeta = const VerificationMeta( + 'hdopRedMax', + ); + @override + late final GeneratedColumn hdopRedMax = GeneratedColumn( + 'hdop_red_max', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(5.0), + ); + static const VerificationMeta _currentGreenMaxAMeta = const VerificationMeta( + 'currentGreenMaxA', + ); + @override + late final GeneratedColumn currentGreenMaxA = GeneratedColumn( + 'current_green_max_a', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(20.0), + ); + static const VerificationMeta _currentRedMaxAMeta = const VerificationMeta( + 'currentRedMaxA', + ); + @override + late final GeneratedColumn currentRedMaxA = GeneratedColumn( + 'current_red_max_a', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(30.0), + ); + static const VerificationMeta _batteryVoltageGreenMinVMeta = + const VerificationMeta('batteryVoltageGreenMinV'); + @override + late final GeneratedColumn batteryVoltageGreenMinV = + GeneratedColumn( + 'battery_voltage_green_min_v', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(20.4), + ); + static const VerificationMeta _batteryVoltageRedMinVMeta = + const VerificationMeta('batteryVoltageRedMinV'); + @override + late final GeneratedColumn batteryVoltageRedMinV = + GeneratedColumn( + 'battery_voltage_red_min_v', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(19.2), + ); + static const VerificationMeta _rxQualityGreenMinMeta = const VerificationMeta( + 'rxQualityGreenMin', + ); + @override + late final GeneratedColumn rxQualityGreenMin = + GeneratedColumn( + 'rx_quality_green_min', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(70.0), + ); + static const VerificationMeta _rxQualityRedMinMeta = const VerificationMeta( + 'rxQualityRedMin', + ); + @override + late final GeneratedColumn rxQualityRedMin = GeneratedColumn( + 'rx_quality_red_min', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(50.0), + ); + static const VerificationMeta _rxSnrGreenMinDbMeta = const VerificationMeta( + 'rxSnrGreenMinDb', + ); + @override + late final GeneratedColumn rxSnrGreenMinDb = GeneratedColumn( + 'rx_snr_green_min_db', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(0.0), + ); + static const VerificationMeta _rxSnrRedMinDbMeta = const VerificationMeta( + 'rxSnrRedMinDb', + ); + @override + late final GeneratedColumn rxSnrRedMinDb = GeneratedColumn( + 'rx_snr_red_min_db', + aliasedName, + false, + type: DriftSqlType.double, + requiredDuringInsert: false, + defaultValue: const Constant(-10.0), + ); @override List get $columns => [ id, @@ -736,6 +881,18 @@ class $DroneProfilesTable extends DroneProfiles maxRangeM, maxEnduranceMin, maxAltitudeM, + gpsSatGreenMin, + gpsSatRedMin, + hdopGreenMax, + hdopRedMax, + currentGreenMaxA, + currentRedMaxA, + batteryVoltageGreenMinV, + batteryVoltageRedMinV, + rxQualityGreenMin, + rxQualityRedMin, + rxSnrGreenMinDb, + rxSnrRedMinDb, ]; @override String get aliasedName => _alias ?? actualTableName; @@ -872,6 +1029,114 @@ class $DroneProfilesTable extends DroneProfiles } else if (isInserting) { context.missing(_maxAltitudeMMeta); } + if (data.containsKey('gps_sat_green_min')) { + context.handle( + _gpsSatGreenMinMeta, + gpsSatGreenMin.isAcceptableOrUnknown( + data['gps_sat_green_min']!, + _gpsSatGreenMinMeta, + ), + ); + } + if (data.containsKey('gps_sat_red_min')) { + context.handle( + _gpsSatRedMinMeta, + gpsSatRedMin.isAcceptableOrUnknown( + data['gps_sat_red_min']!, + _gpsSatRedMinMeta, + ), + ); + } + if (data.containsKey('hdop_green_max')) { + context.handle( + _hdopGreenMaxMeta, + hdopGreenMax.isAcceptableOrUnknown( + data['hdop_green_max']!, + _hdopGreenMaxMeta, + ), + ); + } + if (data.containsKey('hdop_red_max')) { + context.handle( + _hdopRedMaxMeta, + hdopRedMax.isAcceptableOrUnknown( + data['hdop_red_max']!, + _hdopRedMaxMeta, + ), + ); + } + if (data.containsKey('current_green_max_a')) { + context.handle( + _currentGreenMaxAMeta, + currentGreenMaxA.isAcceptableOrUnknown( + data['current_green_max_a']!, + _currentGreenMaxAMeta, + ), + ); + } + if (data.containsKey('current_red_max_a')) { + context.handle( + _currentRedMaxAMeta, + currentRedMaxA.isAcceptableOrUnknown( + data['current_red_max_a']!, + _currentRedMaxAMeta, + ), + ); + } + if (data.containsKey('battery_voltage_green_min_v')) { + context.handle( + _batteryVoltageGreenMinVMeta, + batteryVoltageGreenMinV.isAcceptableOrUnknown( + data['battery_voltage_green_min_v']!, + _batteryVoltageGreenMinVMeta, + ), + ); + } + if (data.containsKey('battery_voltage_red_min_v')) { + context.handle( + _batteryVoltageRedMinVMeta, + batteryVoltageRedMinV.isAcceptableOrUnknown( + data['battery_voltage_red_min_v']!, + _batteryVoltageRedMinVMeta, + ), + ); + } + if (data.containsKey('rx_quality_green_min')) { + context.handle( + _rxQualityGreenMinMeta, + rxQualityGreenMin.isAcceptableOrUnknown( + data['rx_quality_green_min']!, + _rxQualityGreenMinMeta, + ), + ); + } + if (data.containsKey('rx_quality_red_min')) { + context.handle( + _rxQualityRedMinMeta, + rxQualityRedMin.isAcceptableOrUnknown( + data['rx_quality_red_min']!, + _rxQualityRedMinMeta, + ), + ); + } + if (data.containsKey('rx_snr_green_min_db')) { + context.handle( + _rxSnrGreenMinDbMeta, + rxSnrGreenMinDb.isAcceptableOrUnknown( + data['rx_snr_green_min_db']!, + _rxSnrGreenMinDbMeta, + ), + ); + } + if (data.containsKey('rx_snr_red_min_db')) { + context.handle( + _rxSnrRedMinDbMeta, + rxSnrRedMinDb.isAcceptableOrUnknown( + data['rx_snr_red_min_db']!, + _rxSnrRedMinDbMeta, + ), + ); + } return context; } @@ -933,6 +1198,54 @@ class $DroneProfilesTable extends DroneProfiles DriftSqlType.double, data['${effectivePrefix}max_altitude_m'], )!, + gpsSatGreenMin: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}gps_sat_green_min'], + )!, + gpsSatRedMin: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}gps_sat_red_min'], + )!, + hdopGreenMax: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}hdop_green_max'], + )!, + hdopRedMax: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}hdop_red_max'], + )!, + currentGreenMaxA: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}current_green_max_a'], + )!, + currentRedMaxA: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}current_red_max_a'], + )!, + batteryVoltageGreenMinV: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}battery_voltage_green_min_v'], + )!, + batteryVoltageRedMinV: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}battery_voltage_red_min_v'], + )!, + rxQualityGreenMin: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}rx_quality_green_min'], + )!, + rxQualityRedMin: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}rx_quality_red_min'], + )!, + rxSnrGreenMinDb: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}rx_snr_green_min_db'], + )!, + rxSnrRedMinDb: attachedDatabase.typeMapping.read( + DriftSqlType.double, + data['${effectivePrefix}rx_snr_red_min_db'], + )!, ); } @@ -956,6 +1269,23 @@ class DroneProfile extends DataClass implements Insertable { final double maxRangeM; final double maxEnduranceMin; final double maxAltitudeM; + + /// Ampel-Schwellwerte fuer die Telemetriefelder im Drohnen-Status-Menue + /// (siehe domain.DroneProfile-Doku und domain/telemetry/ + /// telemetry_field_status.dart) - Defaults identisch zu den + /// DroneProfile.default*-Konstanten. + final double gpsSatGreenMin; + final double gpsSatRedMin; + final double hdopGreenMax; + final double hdopRedMax; + final double currentGreenMaxA; + final double currentRedMaxA; + final double batteryVoltageGreenMinV; + final double batteryVoltageRedMinV; + final double rxQualityGreenMin; + final double rxQualityRedMin; + final double rxSnrGreenMinDb; + final double rxSnrRedMinDb; const DroneProfile({ required this.id, required this.name, @@ -970,6 +1300,18 @@ class DroneProfile extends DataClass implements Insertable { required this.maxRangeM, required this.maxEnduranceMin, required this.maxAltitudeM, + required this.gpsSatGreenMin, + required this.gpsSatRedMin, + required this.hdopGreenMax, + required this.hdopRedMax, + required this.currentGreenMaxA, + required this.currentRedMaxA, + required this.batteryVoltageGreenMinV, + required this.batteryVoltageRedMinV, + required this.rxQualityGreenMin, + required this.rxQualityRedMin, + required this.rxSnrGreenMinDb, + required this.rxSnrRedMinDb, }); @override Map toColumns(bool nullToAbsent) { @@ -987,6 +1329,20 @@ class DroneProfile extends DataClass implements Insertable { map['max_range_m'] = Variable(maxRangeM); map['max_endurance_min'] = Variable(maxEnduranceMin); map['max_altitude_m'] = Variable(maxAltitudeM); + map['gps_sat_green_min'] = Variable(gpsSatGreenMin); + map['gps_sat_red_min'] = Variable(gpsSatRedMin); + map['hdop_green_max'] = Variable(hdopGreenMax); + map['hdop_red_max'] = Variable(hdopRedMax); + map['current_green_max_a'] = Variable(currentGreenMaxA); + map['current_red_max_a'] = Variable(currentRedMaxA); + map['battery_voltage_green_min_v'] = Variable( + batteryVoltageGreenMinV, + ); + map['battery_voltage_red_min_v'] = Variable(batteryVoltageRedMinV); + map['rx_quality_green_min'] = Variable(rxQualityGreenMin); + map['rx_quality_red_min'] = Variable(rxQualityRedMin); + map['rx_snr_green_min_db'] = Variable(rxSnrGreenMinDb); + map['rx_snr_red_min_db'] = Variable(rxSnrRedMinDb); return map; } @@ -1005,6 +1361,18 @@ class DroneProfile extends DataClass implements Insertable { maxRangeM: Value(maxRangeM), maxEnduranceMin: Value(maxEnduranceMin), maxAltitudeM: Value(maxAltitudeM), + gpsSatGreenMin: Value(gpsSatGreenMin), + gpsSatRedMin: Value(gpsSatRedMin), + hdopGreenMax: Value(hdopGreenMax), + hdopRedMax: Value(hdopRedMax), + currentGreenMaxA: Value(currentGreenMaxA), + currentRedMaxA: Value(currentRedMaxA), + batteryVoltageGreenMinV: Value(batteryVoltageGreenMinV), + batteryVoltageRedMinV: Value(batteryVoltageRedMinV), + rxQualityGreenMin: Value(rxQualityGreenMin), + rxQualityRedMin: Value(rxQualityRedMin), + rxSnrGreenMinDb: Value(rxSnrGreenMinDb), + rxSnrRedMinDb: Value(rxSnrRedMinDb), ); } @@ -1027,6 +1395,22 @@ class DroneProfile extends DataClass implements Insertable { maxRangeM: serializer.fromJson(json['maxRangeM']), maxEnduranceMin: serializer.fromJson(json['maxEnduranceMin']), maxAltitudeM: serializer.fromJson(json['maxAltitudeM']), + gpsSatGreenMin: serializer.fromJson(json['gpsSatGreenMin']), + gpsSatRedMin: serializer.fromJson(json['gpsSatRedMin']), + hdopGreenMax: serializer.fromJson(json['hdopGreenMax']), + hdopRedMax: serializer.fromJson(json['hdopRedMax']), + currentGreenMaxA: serializer.fromJson(json['currentGreenMaxA']), + currentRedMaxA: serializer.fromJson(json['currentRedMaxA']), + batteryVoltageGreenMinV: serializer.fromJson( + json['batteryVoltageGreenMinV'], + ), + batteryVoltageRedMinV: serializer.fromJson( + json['batteryVoltageRedMinV'], + ), + rxQualityGreenMin: serializer.fromJson(json['rxQualityGreenMin']), + rxQualityRedMin: serializer.fromJson(json['rxQualityRedMin']), + rxSnrGreenMinDb: serializer.fromJson(json['rxSnrGreenMinDb']), + rxSnrRedMinDb: serializer.fromJson(json['rxSnrRedMinDb']), ); } @override @@ -1046,6 +1430,20 @@ class DroneProfile extends DataClass implements Insertable { 'maxRangeM': serializer.toJson(maxRangeM), 'maxEnduranceMin': serializer.toJson(maxEnduranceMin), 'maxAltitudeM': serializer.toJson(maxAltitudeM), + 'gpsSatGreenMin': serializer.toJson(gpsSatGreenMin), + 'gpsSatRedMin': serializer.toJson(gpsSatRedMin), + 'hdopGreenMax': serializer.toJson(hdopGreenMax), + 'hdopRedMax': serializer.toJson(hdopRedMax), + 'currentGreenMaxA': serializer.toJson(currentGreenMaxA), + 'currentRedMaxA': serializer.toJson(currentRedMaxA), + 'batteryVoltageGreenMinV': serializer.toJson( + batteryVoltageGreenMinV, + ), + 'batteryVoltageRedMinV': serializer.toJson(batteryVoltageRedMinV), + 'rxQualityGreenMin': serializer.toJson(rxQualityGreenMin), + 'rxQualityRedMin': serializer.toJson(rxQualityRedMin), + 'rxSnrGreenMinDb': serializer.toJson(rxSnrGreenMinDb), + 'rxSnrRedMinDb': serializer.toJson(rxSnrRedMinDb), }; } @@ -1063,6 +1461,18 @@ class DroneProfile extends DataClass implements Insertable { double? maxRangeM, double? maxEnduranceMin, double? maxAltitudeM, + double? gpsSatGreenMin, + double? gpsSatRedMin, + double? hdopGreenMax, + double? hdopRedMax, + double? currentGreenMaxA, + double? currentRedMaxA, + double? batteryVoltageGreenMinV, + double? batteryVoltageRedMinV, + double? rxQualityGreenMin, + double? rxQualityRedMin, + double? rxSnrGreenMinDb, + double? rxSnrRedMinDb, }) => DroneProfile( id: id ?? this.id, name: name ?? this.name, @@ -1077,6 +1487,19 @@ class DroneProfile extends DataClass implements Insertable { maxRangeM: maxRangeM ?? this.maxRangeM, maxEnduranceMin: maxEnduranceMin ?? this.maxEnduranceMin, maxAltitudeM: maxAltitudeM ?? this.maxAltitudeM, + gpsSatGreenMin: gpsSatGreenMin ?? this.gpsSatGreenMin, + gpsSatRedMin: gpsSatRedMin ?? this.gpsSatRedMin, + hdopGreenMax: hdopGreenMax ?? this.hdopGreenMax, + hdopRedMax: hdopRedMax ?? this.hdopRedMax, + currentGreenMaxA: currentGreenMaxA ?? this.currentGreenMaxA, + currentRedMaxA: currentRedMaxA ?? this.currentRedMaxA, + batteryVoltageGreenMinV: + batteryVoltageGreenMinV ?? this.batteryVoltageGreenMinV, + batteryVoltageRedMinV: batteryVoltageRedMinV ?? this.batteryVoltageRedMinV, + rxQualityGreenMin: rxQualityGreenMin ?? this.rxQualityGreenMin, + rxQualityRedMin: rxQualityRedMin ?? this.rxQualityRedMin, + rxSnrGreenMinDb: rxSnrGreenMinDb ?? this.rxSnrGreenMinDb, + rxSnrRedMinDb: rxSnrRedMinDb ?? this.rxSnrRedMinDb, ); DroneProfile copyWithCompanion(DroneProfilesCompanion data) { return DroneProfile( @@ -1109,6 +1532,42 @@ class DroneProfile extends DataClass implements Insertable { maxAltitudeM: data.maxAltitudeM.present ? data.maxAltitudeM.value : this.maxAltitudeM, + gpsSatGreenMin: data.gpsSatGreenMin.present + ? data.gpsSatGreenMin.value + : this.gpsSatGreenMin, + gpsSatRedMin: data.gpsSatRedMin.present + ? data.gpsSatRedMin.value + : this.gpsSatRedMin, + hdopGreenMax: data.hdopGreenMax.present + ? data.hdopGreenMax.value + : this.hdopGreenMax, + hdopRedMax: data.hdopRedMax.present + ? data.hdopRedMax.value + : this.hdopRedMax, + currentGreenMaxA: data.currentGreenMaxA.present + ? data.currentGreenMaxA.value + : this.currentGreenMaxA, + currentRedMaxA: data.currentRedMaxA.present + ? data.currentRedMaxA.value + : this.currentRedMaxA, + batteryVoltageGreenMinV: data.batteryVoltageGreenMinV.present + ? data.batteryVoltageGreenMinV.value + : this.batteryVoltageGreenMinV, + batteryVoltageRedMinV: data.batteryVoltageRedMinV.present + ? data.batteryVoltageRedMinV.value + : this.batteryVoltageRedMinV, + rxQualityGreenMin: data.rxQualityGreenMin.present + ? data.rxQualityGreenMin.value + : this.rxQualityGreenMin, + rxQualityRedMin: data.rxQualityRedMin.present + ? data.rxQualityRedMin.value + : this.rxQualityRedMin, + rxSnrGreenMinDb: data.rxSnrGreenMinDb.present + ? data.rxSnrGreenMinDb.value + : this.rxSnrGreenMinDb, + rxSnrRedMinDb: data.rxSnrRedMinDb.present + ? data.rxSnrRedMinDb.value + : this.rxSnrRedMinDb, ); } @@ -1127,13 +1586,25 @@ class DroneProfile extends DataClass implements Insertable { ..write('maxDescentRate: $maxDescentRate, ') ..write('maxRangeM: $maxRangeM, ') ..write('maxEnduranceMin: $maxEnduranceMin, ') - ..write('maxAltitudeM: $maxAltitudeM') + ..write('maxAltitudeM: $maxAltitudeM, ') + ..write('gpsSatGreenMin: $gpsSatGreenMin, ') + ..write('gpsSatRedMin: $gpsSatRedMin, ') + ..write('hdopGreenMax: $hdopGreenMax, ') + ..write('hdopRedMax: $hdopRedMax, ') + ..write('currentGreenMaxA: $currentGreenMaxA, ') + ..write('currentRedMaxA: $currentRedMaxA, ') + ..write('batteryVoltageGreenMinV: $batteryVoltageGreenMinV, ') + ..write('batteryVoltageRedMinV: $batteryVoltageRedMinV, ') + ..write('rxQualityGreenMin: $rxQualityGreenMin, ') + ..write('rxQualityRedMin: $rxQualityRedMin, ') + ..write('rxSnrGreenMinDb: $rxSnrGreenMinDb, ') + ..write('rxSnrRedMinDb: $rxSnrRedMinDb') ..write(')')) .toString(); } @override - int get hashCode => Object.hash( + int get hashCode => Object.hashAll([ id, name, minSpeed, @@ -1147,7 +1618,19 @@ class DroneProfile extends DataClass implements Insertable { maxRangeM, maxEnduranceMin, maxAltitudeM, - ); + gpsSatGreenMin, + gpsSatRedMin, + hdopGreenMax, + hdopRedMax, + currentGreenMaxA, + currentRedMaxA, + batteryVoltageGreenMinV, + batteryVoltageRedMinV, + rxQualityGreenMin, + rxQualityRedMin, + rxSnrGreenMinDb, + rxSnrRedMinDb, + ]); @override bool operator ==(Object other) => identical(this, other) || @@ -1164,7 +1647,19 @@ class DroneProfile extends DataClass implements Insertable { other.maxDescentRate == this.maxDescentRate && other.maxRangeM == this.maxRangeM && other.maxEnduranceMin == this.maxEnduranceMin && - other.maxAltitudeM == this.maxAltitudeM); + other.maxAltitudeM == this.maxAltitudeM && + other.gpsSatGreenMin == this.gpsSatGreenMin && + other.gpsSatRedMin == this.gpsSatRedMin && + other.hdopGreenMax == this.hdopGreenMax && + other.hdopRedMax == this.hdopRedMax && + other.currentGreenMaxA == this.currentGreenMaxA && + other.currentRedMaxA == this.currentRedMaxA && + other.batteryVoltageGreenMinV == this.batteryVoltageGreenMinV && + other.batteryVoltageRedMinV == this.batteryVoltageRedMinV && + other.rxQualityGreenMin == this.rxQualityGreenMin && + other.rxQualityRedMin == this.rxQualityRedMin && + other.rxSnrGreenMinDb == this.rxSnrGreenMinDb && + other.rxSnrRedMinDb == this.rxSnrRedMinDb); } class DroneProfilesCompanion extends UpdateCompanion { @@ -1181,6 +1676,18 @@ class DroneProfilesCompanion extends UpdateCompanion { final Value maxRangeM; final Value maxEnduranceMin; final Value maxAltitudeM; + final Value gpsSatGreenMin; + final Value gpsSatRedMin; + final Value hdopGreenMax; + final Value hdopRedMax; + final Value currentGreenMaxA; + final Value currentRedMaxA; + final Value batteryVoltageGreenMinV; + final Value batteryVoltageRedMinV; + final Value rxQualityGreenMin; + final Value rxQualityRedMin; + final Value rxSnrGreenMinDb; + final Value rxSnrRedMinDb; const DroneProfilesCompanion({ this.id = const Value.absent(), this.name = const Value.absent(), @@ -1195,6 +1702,18 @@ class DroneProfilesCompanion extends UpdateCompanion { this.maxRangeM = const Value.absent(), this.maxEnduranceMin = const Value.absent(), this.maxAltitudeM = const Value.absent(), + this.gpsSatGreenMin = const Value.absent(), + this.gpsSatRedMin = const Value.absent(), + this.hdopGreenMax = const Value.absent(), + this.hdopRedMax = const Value.absent(), + this.currentGreenMaxA = const Value.absent(), + this.currentRedMaxA = const Value.absent(), + this.batteryVoltageGreenMinV = const Value.absent(), + this.batteryVoltageRedMinV = const Value.absent(), + this.rxQualityGreenMin = const Value.absent(), + this.rxQualityRedMin = const Value.absent(), + this.rxSnrGreenMinDb = const Value.absent(), + this.rxSnrRedMinDb = const Value.absent(), }); DroneProfilesCompanion.insert({ this.id = const Value.absent(), @@ -1210,6 +1729,18 @@ class DroneProfilesCompanion extends UpdateCompanion { required double maxRangeM, required double maxEnduranceMin, required double maxAltitudeM, + this.gpsSatGreenMin = const Value.absent(), + this.gpsSatRedMin = const Value.absent(), + this.hdopGreenMax = const Value.absent(), + this.hdopRedMax = const Value.absent(), + this.currentGreenMaxA = const Value.absent(), + this.currentRedMaxA = const Value.absent(), + this.batteryVoltageGreenMinV = const Value.absent(), + this.batteryVoltageRedMinV = const Value.absent(), + this.rxQualityGreenMin = const Value.absent(), + this.rxQualityRedMin = const Value.absent(), + this.rxSnrGreenMinDb = const Value.absent(), + this.rxSnrRedMinDb = const Value.absent(), }) : name = Value(name), minSpeed = Value(minSpeed), cruiseSpeed = Value(cruiseSpeed), @@ -1236,6 +1767,18 @@ class DroneProfilesCompanion extends UpdateCompanion { Expression? maxRangeM, Expression? maxEnduranceMin, Expression? maxAltitudeM, + Expression? gpsSatGreenMin, + Expression? gpsSatRedMin, + Expression? hdopGreenMax, + Expression? hdopRedMax, + Expression? currentGreenMaxA, + Expression? currentRedMaxA, + Expression? batteryVoltageGreenMinV, + Expression? batteryVoltageRedMinV, + Expression? rxQualityGreenMin, + Expression? rxQualityRedMin, + Expression? rxSnrGreenMinDb, + Expression? rxSnrRedMinDb, }) { return RawValuesInsertable({ if (id != null) 'id': id, @@ -1251,6 +1794,20 @@ class DroneProfilesCompanion extends UpdateCompanion { if (maxRangeM != null) 'max_range_m': maxRangeM, if (maxEnduranceMin != null) 'max_endurance_min': maxEnduranceMin, if (maxAltitudeM != null) 'max_altitude_m': maxAltitudeM, + if (gpsSatGreenMin != null) 'gps_sat_green_min': gpsSatGreenMin, + if (gpsSatRedMin != null) 'gps_sat_red_min': gpsSatRedMin, + if (hdopGreenMax != null) 'hdop_green_max': hdopGreenMax, + if (hdopRedMax != null) 'hdop_red_max': hdopRedMax, + if (currentGreenMaxA != null) 'current_green_max_a': currentGreenMaxA, + if (currentRedMaxA != null) 'current_red_max_a': currentRedMaxA, + if (batteryVoltageGreenMinV != null) + 'battery_voltage_green_min_v': batteryVoltageGreenMinV, + if (batteryVoltageRedMinV != null) + 'battery_voltage_red_min_v': batteryVoltageRedMinV, + if (rxQualityGreenMin != null) 'rx_quality_green_min': rxQualityGreenMin, + if (rxQualityRedMin != null) 'rx_quality_red_min': rxQualityRedMin, + if (rxSnrGreenMinDb != null) 'rx_snr_green_min_db': rxSnrGreenMinDb, + if (rxSnrRedMinDb != null) 'rx_snr_red_min_db': rxSnrRedMinDb, }); } @@ -1268,6 +1825,18 @@ class DroneProfilesCompanion extends UpdateCompanion { Value? maxRangeM, Value? maxEnduranceMin, Value? maxAltitudeM, + Value? gpsSatGreenMin, + Value? gpsSatRedMin, + Value? hdopGreenMax, + Value? hdopRedMax, + Value? currentGreenMaxA, + Value? currentRedMaxA, + Value? batteryVoltageGreenMinV, + Value? batteryVoltageRedMinV, + Value? rxQualityGreenMin, + Value? rxQualityRedMin, + Value? rxSnrGreenMinDb, + Value? rxSnrRedMinDb, }) { return DroneProfilesCompanion( id: id ?? this.id, @@ -1283,6 +1852,20 @@ class DroneProfilesCompanion extends UpdateCompanion { maxRangeM: maxRangeM ?? this.maxRangeM, maxEnduranceMin: maxEnduranceMin ?? this.maxEnduranceMin, maxAltitudeM: maxAltitudeM ?? this.maxAltitudeM, + gpsSatGreenMin: gpsSatGreenMin ?? this.gpsSatGreenMin, + gpsSatRedMin: gpsSatRedMin ?? this.gpsSatRedMin, + hdopGreenMax: hdopGreenMax ?? this.hdopGreenMax, + hdopRedMax: hdopRedMax ?? this.hdopRedMax, + currentGreenMaxA: currentGreenMaxA ?? this.currentGreenMaxA, + currentRedMaxA: currentRedMaxA ?? this.currentRedMaxA, + batteryVoltageGreenMinV: + batteryVoltageGreenMinV ?? this.batteryVoltageGreenMinV, + batteryVoltageRedMinV: + batteryVoltageRedMinV ?? this.batteryVoltageRedMinV, + rxQualityGreenMin: rxQualityGreenMin ?? this.rxQualityGreenMin, + rxQualityRedMin: rxQualityRedMin ?? this.rxQualityRedMin, + rxSnrGreenMinDb: rxSnrGreenMinDb ?? this.rxSnrGreenMinDb, + rxSnrRedMinDb: rxSnrRedMinDb ?? this.rxSnrRedMinDb, ); } @@ -1328,6 +1911,46 @@ class DroneProfilesCompanion extends UpdateCompanion { if (maxAltitudeM.present) { map['max_altitude_m'] = Variable(maxAltitudeM.value); } + if (gpsSatGreenMin.present) { + map['gps_sat_green_min'] = Variable(gpsSatGreenMin.value); + } + if (gpsSatRedMin.present) { + map['gps_sat_red_min'] = Variable(gpsSatRedMin.value); + } + if (hdopGreenMax.present) { + map['hdop_green_max'] = Variable(hdopGreenMax.value); + } + if (hdopRedMax.present) { + map['hdop_red_max'] = Variable(hdopRedMax.value); + } + if (currentGreenMaxA.present) { + map['current_green_max_a'] = Variable(currentGreenMaxA.value); + } + if (currentRedMaxA.present) { + map['current_red_max_a'] = Variable(currentRedMaxA.value); + } + if (batteryVoltageGreenMinV.present) { + map['battery_voltage_green_min_v'] = Variable( + batteryVoltageGreenMinV.value, + ); + } + if (batteryVoltageRedMinV.present) { + map['battery_voltage_red_min_v'] = Variable( + batteryVoltageRedMinV.value, + ); + } + if (rxQualityGreenMin.present) { + map['rx_quality_green_min'] = Variable(rxQualityGreenMin.value); + } + if (rxQualityRedMin.present) { + map['rx_quality_red_min'] = Variable(rxQualityRedMin.value); + } + if (rxSnrGreenMinDb.present) { + map['rx_snr_green_min_db'] = Variable(rxSnrGreenMinDb.value); + } + if (rxSnrRedMinDb.present) { + map['rx_snr_red_min_db'] = Variable(rxSnrRedMinDb.value); + } return map; } @@ -1346,7 +1969,19 @@ class DroneProfilesCompanion extends UpdateCompanion { ..write('maxDescentRate: $maxDescentRate, ') ..write('maxRangeM: $maxRangeM, ') ..write('maxEnduranceMin: $maxEnduranceMin, ') - ..write('maxAltitudeM: $maxAltitudeM') + ..write('maxAltitudeM: $maxAltitudeM, ') + ..write('gpsSatGreenMin: $gpsSatGreenMin, ') + ..write('gpsSatRedMin: $gpsSatRedMin, ') + ..write('hdopGreenMax: $hdopGreenMax, ') + ..write('hdopRedMax: $hdopRedMax, ') + ..write('currentGreenMaxA: $currentGreenMaxA, ') + ..write('currentRedMaxA: $currentRedMaxA, ') + ..write('batteryVoltageGreenMinV: $batteryVoltageGreenMinV, ') + ..write('batteryVoltageRedMinV: $batteryVoltageRedMinV, ') + ..write('rxQualityGreenMin: $rxQualityGreenMin, ') + ..write('rxQualityRedMin: $rxQualityRedMin, ') + ..write('rxSnrGreenMinDb: $rxSnrGreenMinDb, ') + ..write('rxSnrRedMinDb: $rxSnrRedMinDb') ..write(')')) .toString(); } @@ -2375,6 +3010,18 @@ typedef $$DroneProfilesTableCreateCompanionBuilder = required double maxRangeM, required double maxEnduranceMin, required double maxAltitudeM, + Value gpsSatGreenMin, + Value gpsSatRedMin, + Value hdopGreenMax, + Value hdopRedMax, + Value currentGreenMaxA, + Value currentRedMaxA, + Value batteryVoltageGreenMinV, + Value batteryVoltageRedMinV, + Value rxQualityGreenMin, + Value rxQualityRedMin, + Value rxSnrGreenMinDb, + Value rxSnrRedMinDb, }); typedef $$DroneProfilesTableUpdateCompanionBuilder = DroneProfilesCompanion Function({ @@ -2391,6 +3038,18 @@ typedef $$DroneProfilesTableUpdateCompanionBuilder = Value maxRangeM, Value maxEnduranceMin, Value maxAltitudeM, + Value gpsSatGreenMin, + Value gpsSatRedMin, + Value hdopGreenMax, + Value hdopRedMax, + Value currentGreenMaxA, + Value currentRedMaxA, + Value batteryVoltageGreenMinV, + Value batteryVoltageRedMinV, + Value rxQualityGreenMin, + Value rxQualityRedMin, + Value rxSnrGreenMinDb, + Value rxSnrRedMinDb, }); class $$DroneProfilesTableFilterComposer @@ -2466,6 +3125,66 @@ class $$DroneProfilesTableFilterComposer column: $table.maxAltitudeM, builder: (column) => ColumnFilters(column), ); + + ColumnFilters get gpsSatGreenMin => $composableBuilder( + column: $table.gpsSatGreenMin, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get gpsSatRedMin => $composableBuilder( + column: $table.gpsSatRedMin, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get hdopGreenMax => $composableBuilder( + column: $table.hdopGreenMax, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get hdopRedMax => $composableBuilder( + column: $table.hdopRedMax, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get currentGreenMaxA => $composableBuilder( + column: $table.currentGreenMaxA, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get currentRedMaxA => $composableBuilder( + column: $table.currentRedMaxA, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get batteryVoltageGreenMinV => $composableBuilder( + column: $table.batteryVoltageGreenMinV, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get batteryVoltageRedMinV => $composableBuilder( + column: $table.batteryVoltageRedMinV, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get rxQualityGreenMin => $composableBuilder( + column: $table.rxQualityGreenMin, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get rxQualityRedMin => $composableBuilder( + column: $table.rxQualityRedMin, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get rxSnrGreenMinDb => $composableBuilder( + column: $table.rxSnrGreenMinDb, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get rxSnrRedMinDb => $composableBuilder( + column: $table.rxSnrRedMinDb, + builder: (column) => ColumnFilters(column), + ); } class $$DroneProfilesTableOrderingComposer @@ -2541,6 +3260,66 @@ class $$DroneProfilesTableOrderingComposer column: $table.maxAltitudeM, builder: (column) => ColumnOrderings(column), ); + + ColumnOrderings get gpsSatGreenMin => $composableBuilder( + column: $table.gpsSatGreenMin, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get gpsSatRedMin => $composableBuilder( + column: $table.gpsSatRedMin, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get hdopGreenMax => $composableBuilder( + column: $table.hdopGreenMax, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get hdopRedMax => $composableBuilder( + column: $table.hdopRedMax, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get currentGreenMaxA => $composableBuilder( + column: $table.currentGreenMaxA, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get currentRedMaxA => $composableBuilder( + column: $table.currentRedMaxA, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get batteryVoltageGreenMinV => $composableBuilder( + column: $table.batteryVoltageGreenMinV, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get batteryVoltageRedMinV => $composableBuilder( + column: $table.batteryVoltageRedMinV, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get rxQualityGreenMin => $composableBuilder( + column: $table.rxQualityGreenMin, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get rxQualityRedMin => $composableBuilder( + column: $table.rxQualityRedMin, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get rxSnrGreenMinDb => $composableBuilder( + column: $table.rxSnrGreenMinDb, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get rxSnrRedMinDb => $composableBuilder( + column: $table.rxSnrRedMinDb, + builder: (column) => ColumnOrderings(column), + ); } class $$DroneProfilesTableAnnotationComposer @@ -2606,6 +3385,66 @@ class $$DroneProfilesTableAnnotationComposer column: $table.maxAltitudeM, builder: (column) => column, ); + + GeneratedColumn get gpsSatGreenMin => $composableBuilder( + column: $table.gpsSatGreenMin, + builder: (column) => column, + ); + + GeneratedColumn get gpsSatRedMin => $composableBuilder( + column: $table.gpsSatRedMin, + builder: (column) => column, + ); + + GeneratedColumn get hdopGreenMax => $composableBuilder( + column: $table.hdopGreenMax, + builder: (column) => column, + ); + + GeneratedColumn get hdopRedMax => $composableBuilder( + column: $table.hdopRedMax, + builder: (column) => column, + ); + + GeneratedColumn get currentGreenMaxA => $composableBuilder( + column: $table.currentGreenMaxA, + builder: (column) => column, + ); + + GeneratedColumn get currentRedMaxA => $composableBuilder( + column: $table.currentRedMaxA, + builder: (column) => column, + ); + + GeneratedColumn get batteryVoltageGreenMinV => $composableBuilder( + column: $table.batteryVoltageGreenMinV, + builder: (column) => column, + ); + + GeneratedColumn get batteryVoltageRedMinV => $composableBuilder( + column: $table.batteryVoltageRedMinV, + builder: (column) => column, + ); + + GeneratedColumn get rxQualityGreenMin => $composableBuilder( + column: $table.rxQualityGreenMin, + builder: (column) => column, + ); + + GeneratedColumn get rxQualityRedMin => $composableBuilder( + column: $table.rxQualityRedMin, + builder: (column) => column, + ); + + GeneratedColumn get rxSnrGreenMinDb => $composableBuilder( + column: $table.rxSnrGreenMinDb, + builder: (column) => column, + ); + + GeneratedColumn get rxSnrRedMinDb => $composableBuilder( + column: $table.rxSnrRedMinDb, + builder: (column) => column, + ); } class $$DroneProfilesTableTableManager @@ -2652,6 +3491,18 @@ class $$DroneProfilesTableTableManager Value maxRangeM = const Value.absent(), Value maxEnduranceMin = const Value.absent(), Value maxAltitudeM = const Value.absent(), + Value gpsSatGreenMin = const Value.absent(), + Value gpsSatRedMin = const Value.absent(), + Value hdopGreenMax = const Value.absent(), + Value hdopRedMax = const Value.absent(), + Value currentGreenMaxA = const Value.absent(), + Value currentRedMaxA = const Value.absent(), + Value batteryVoltageGreenMinV = const Value.absent(), + Value batteryVoltageRedMinV = const Value.absent(), + Value rxQualityGreenMin = const Value.absent(), + Value rxQualityRedMin = const Value.absent(), + Value rxSnrGreenMinDb = const Value.absent(), + Value rxSnrRedMinDb = const Value.absent(), }) => DroneProfilesCompanion( id: id, name: name, @@ -2666,6 +3517,18 @@ class $$DroneProfilesTableTableManager maxRangeM: maxRangeM, maxEnduranceMin: maxEnduranceMin, maxAltitudeM: maxAltitudeM, + gpsSatGreenMin: gpsSatGreenMin, + gpsSatRedMin: gpsSatRedMin, + hdopGreenMax: hdopGreenMax, + hdopRedMax: hdopRedMax, + currentGreenMaxA: currentGreenMaxA, + currentRedMaxA: currentRedMaxA, + batteryVoltageGreenMinV: batteryVoltageGreenMinV, + batteryVoltageRedMinV: batteryVoltageRedMinV, + rxQualityGreenMin: rxQualityGreenMin, + rxQualityRedMin: rxQualityRedMin, + rxSnrGreenMinDb: rxSnrGreenMinDb, + rxSnrRedMinDb: rxSnrRedMinDb, ), createCompanionCallback: ({ @@ -2682,6 +3545,18 @@ class $$DroneProfilesTableTableManager required double maxRangeM, required double maxEnduranceMin, required double maxAltitudeM, + Value gpsSatGreenMin = const Value.absent(), + Value gpsSatRedMin = const Value.absent(), + Value hdopGreenMax = const Value.absent(), + Value hdopRedMax = const Value.absent(), + Value currentGreenMaxA = const Value.absent(), + Value currentRedMaxA = const Value.absent(), + Value batteryVoltageGreenMinV = const Value.absent(), + Value batteryVoltageRedMinV = const Value.absent(), + Value rxQualityGreenMin = const Value.absent(), + Value rxQualityRedMin = const Value.absent(), + Value rxSnrGreenMinDb = const Value.absent(), + Value rxSnrRedMinDb = const Value.absent(), }) => DroneProfilesCompanion.insert( id: id, name: name, @@ -2696,6 +3571,18 @@ class $$DroneProfilesTableTableManager maxRangeM: maxRangeM, maxEnduranceMin: maxEnduranceMin, maxAltitudeM: maxAltitudeM, + gpsSatGreenMin: gpsSatGreenMin, + gpsSatRedMin: gpsSatRedMin, + hdopGreenMax: hdopGreenMax, + hdopRedMax: hdopRedMax, + currentGreenMaxA: currentGreenMaxA, + currentRedMaxA: currentRedMaxA, + batteryVoltageGreenMinV: batteryVoltageGreenMinV, + batteryVoltageRedMinV: batteryVoltageRedMinV, + rxQualityGreenMin: rxQualityGreenMin, + rxQualityRedMin: rxQualityRedMin, + rxSnrGreenMinDb: rxSnrGreenMinDb, + rxSnrRedMinDb: rxSnrRedMinDb, ), withReferenceMapper: (p0) => p0 .map((e) => (e.readTable(table), BaseReferences(db, table, e))) diff --git a/app/lib/services/database/drone_profile_repository.dart b/app/lib/services/database/drone_profile_repository.dart index 1f97d94..4134be3 100644 --- a/app/lib/services/database/drone_profile_repository.dart +++ b/app/lib/services/database/drone_profile_repository.dart @@ -60,6 +60,18 @@ class DroneProfileRepository { maxRangeM: row.maxRangeM, maxEnduranceMin: row.maxEnduranceMin, maxAltitudeM: row.maxAltitudeM, + gpsSatGreenMin: row.gpsSatGreenMin, + gpsSatRedMin: row.gpsSatRedMin, + hdopGreenMax: row.hdopGreenMax, + hdopRedMax: row.hdopRedMax, + currentGreenMaxA: row.currentGreenMaxA, + currentRedMaxA: row.currentRedMaxA, + batteryVoltageGreenMinV: row.batteryVoltageGreenMinV, + batteryVoltageRedMinV: row.batteryVoltageRedMinV, + rxQualityGreenMin: row.rxQualityGreenMin, + rxQualityRedMin: row.rxQualityRedMin, + rxSnrGreenMinDb: row.rxSnrGreenMinDb, + rxSnrRedMinDb: row.rxSnrRedMinDb, ); DroneProfilesCompanion _toCompanion(domain.DroneProfile profile) => @@ -76,5 +88,17 @@ class DroneProfileRepository { maxRangeM: Value(profile.maxRangeM), maxEnduranceMin: Value(profile.maxEnduranceMin), maxAltitudeM: Value(profile.maxAltitudeM), + gpsSatGreenMin: Value(profile.gpsSatGreenMin), + gpsSatRedMin: Value(profile.gpsSatRedMin), + hdopGreenMax: Value(profile.hdopGreenMax), + hdopRedMax: Value(profile.hdopRedMax), + currentGreenMaxA: Value(profile.currentGreenMaxA), + currentRedMaxA: Value(profile.currentRedMaxA), + batteryVoltageGreenMinV: Value(profile.batteryVoltageGreenMinV), + batteryVoltageRedMinV: Value(profile.batteryVoltageRedMinV), + rxQualityGreenMin: Value(profile.rxQualityGreenMin), + rxQualityRedMin: Value(profile.rxQualityRedMin), + rxSnrGreenMinDb: Value(profile.rxSnrGreenMinDb), + rxSnrRedMinDb: Value(profile.rxSnrRedMinDb), ); } diff --git a/app/lib/services/sharing/drone_share_codec.dart b/app/lib/services/sharing/drone_share_codec.dart index 17f2674..096ca9a 100644 --- a/app/lib/services/sharing/drone_share_codec.dart +++ b/app/lib/services/sharing/drone_share_codec.dart @@ -24,6 +24,18 @@ String buildDroneExportJson(DroneProfile profile) { 'maxRangeM': profile.maxRangeM, 'maxEnduranceMin': profile.maxEnduranceMin, 'maxAltitudeM': profile.maxAltitudeM, + 'gpsSatGreenMin': profile.gpsSatGreenMin, + 'gpsSatRedMin': profile.gpsSatRedMin, + 'hdopGreenMax': profile.hdopGreenMax, + 'hdopRedMax': profile.hdopRedMax, + 'currentGreenMaxA': profile.currentGreenMaxA, + 'currentRedMaxA': profile.currentRedMaxA, + 'batteryVoltageGreenMinV': profile.batteryVoltageGreenMinV, + 'batteryVoltageRedMinV': profile.batteryVoltageRedMinV, + 'rxQualityGreenMin': profile.rxQualityGreenMin, + 'rxQualityRedMin': profile.rxQualityRedMin, + 'rxSnrGreenMinDb': profile.rxSnrGreenMinDb, + 'rxSnrRedMinDb': profile.rxSnrRedMinDb, }, }; return const JsonEncoder.withIndent(' ').convert(map); @@ -88,6 +100,15 @@ ParsedDroneImport parseDroneImportJson(String jsonText) { } } + // Ampel-Schwellwerte (siehe DroneProfile-Doku) sind bewusst NICHT Teil von + // _requiredNumericFields - aeltere, vor deren Einfuehrung exportierte + // Profildateien haben diese Felder noch nicht und sollen trotzdem + // importierbar bleiben (dann gelten die DroneProfile.default*-Werte). + double numOrDefault(String field, double fallback) { + final v = droneData[field]; + return v is num ? v.toDouble() : fallback; + } + final profile = DroneProfile( name: name, minSpeed: (droneData['minSpeed'] as num).toDouble(), @@ -101,6 +122,24 @@ ParsedDroneImport parseDroneImportJson(String jsonText) { maxRangeM: (droneData['maxRangeM'] as num).toDouble(), maxEnduranceMin: (droneData['maxEnduranceMin'] as num).toDouble(), maxAltitudeM: (droneData['maxAltitudeM'] as num).toDouble(), + gpsSatGreenMin: numOrDefault('gpsSatGreenMin', DroneProfile.defaultGpsSatGreenMin), + gpsSatRedMin: numOrDefault('gpsSatRedMin', DroneProfile.defaultGpsSatRedMin), + hdopGreenMax: numOrDefault('hdopGreenMax', DroneProfile.defaultHdopGreenMax), + hdopRedMax: numOrDefault('hdopRedMax', DroneProfile.defaultHdopRedMax), + currentGreenMaxA: numOrDefault('currentGreenMaxA', DroneProfile.defaultCurrentGreenMaxA), + currentRedMaxA: numOrDefault('currentRedMaxA', DroneProfile.defaultCurrentRedMaxA), + batteryVoltageGreenMinV: numOrDefault( + 'batteryVoltageGreenMinV', + DroneProfile.defaultBatteryVoltageGreenMinV, + ), + batteryVoltageRedMinV: numOrDefault( + 'batteryVoltageRedMinV', + DroneProfile.defaultBatteryVoltageRedMinV, + ), + rxQualityGreenMin: numOrDefault('rxQualityGreenMin', DroneProfile.defaultRxQualityGreenMin), + rxQualityRedMin: numOrDefault('rxQualityRedMin', DroneProfile.defaultRxQualityRedMin), + rxSnrGreenMinDb: numOrDefault('rxSnrGreenMinDb', DroneProfile.defaultRxSnrGreenMinDb), + rxSnrRedMinDb: numOrDefault('rxSnrRedMinDb', DroneProfile.defaultRxSnrRedMinDb), ); final appVersion = decoded['appVersion'] as String?; diff --git a/app/lib/ui/widgets/drone_profile_editor.dart b/app/lib/ui/widgets/drone_profile_editor.dart index 8ffd2e6..db16a89 100644 --- a/app/lib/ui/widgets/drone_profile_editor.dart +++ b/app/lib/ui/widgets/drone_profile_editor.dart @@ -65,6 +65,52 @@ class _DroneProfileEditorState extends ConsumerState { (key: 'maxAltitudeM', label: 'Ceiling', min: 50.0, max: 10000.0, stepBig: 100.0, stepSmall: 10.0, decimals: 0, unit: 'm'), ], ), + // Ampel-Schwellwerte fuer die farbcodierten Telemetriefelder im + // Drohnen-Status-Menue (Doku: "Schwellwerte fuer die Ampel-Kodierung im + // Drohnenprofil anlegen", siehe domain/telemetry/telemetry_field_status.dart) - + // je Feld Gruen-/Rot-Schwelle als eigene Gruppe, analog Climb/Descent oben. + ( + title: 'GPS satellites alarm', + fields: [ + (key: 'gpsSatGreenMin', label: 'Green from', min: 0.0, max: 20.0, stepBig: 2.0, stepSmall: 1.0, decimals: 0, unit: 'sat'), + (key: 'gpsSatRedMin', label: 'Red below', min: 0.0, max: 20.0, stepBig: 2.0, stepSmall: 1.0, decimals: 0, unit: 'sat'), + ], + ), + ( + title: 'GPS precision (HDOP) alarm', + fields: [ + (key: 'hdopGreenMax', label: 'Green up to', min: 0.5, max: 10.0, stepBig: 1.0, stepSmall: 0.1, decimals: 1, unit: ''), + (key: 'hdopRedMax', label: 'Red above', min: 0.5, max: 20.0, stepBig: 1.0, stepSmall: 0.1, decimals: 1, unit: ''), + ], + ), + ( + title: 'Current draw alarm (A)', + fields: [ + (key: 'currentGreenMaxA', label: 'Green up to', min: 1.0, max: 200.0, stepBig: 10.0, stepSmall: 1.0, decimals: 0, unit: 'A'), + (key: 'currentRedMaxA', label: 'Red above', min: 1.0, max: 300.0, stepBig: 10.0, stepSmall: 1.0, decimals: 0, unit: 'A'), + ], + ), + ( + title: 'Battery voltage alarm (V)', + fields: [ + (key: 'batteryVoltageGreenMinV', label: 'Green from', min: 5.0, max: 60.0, stepBig: 1.0, stepSmall: 0.1, decimals: 1, unit: 'V'), + (key: 'batteryVoltageRedMinV', label: 'Red below', min: 5.0, max: 60.0, stepBig: 1.0, stepSmall: 0.1, decimals: 1, unit: 'V'), + ], + ), + ( + title: 'RX link quality alarm (%)', + fields: [ + (key: 'rxQualityGreenMin', label: 'Green from', min: 0.0, max: 100.0, stepBig: 10.0, stepSmall: 1.0, decimals: 0, unit: '%'), + (key: 'rxQualityRedMin', label: 'Red below', min: 0.0, max: 100.0, stepBig: 10.0, stepSmall: 1.0, decimals: 0, unit: '%'), + ], + ), + ( + title: 'RX SNR alarm (dB)', + fields: [ + (key: 'rxSnrGreenMinDb', label: 'Green from', min: -30.0, max: 30.0, stepBig: 5.0, stepSmall: 1.0, decimals: 0, unit: 'dB'), + (key: 'rxSnrRedMinDb', label: 'Red below', min: -30.0, max: 30.0, stepBig: 5.0, stepSmall: 1.0, decimals: 0, unit: 'dB'), + ], + ), ]; double _fieldValue(DroneProfile p, String key) => switch (key) { @@ -79,6 +125,18 @@ class _DroneProfileEditorState extends ConsumerState { 'maxRangeM' => p.maxRangeM, 'maxEnduranceMin' => p.maxEnduranceMin, 'maxAltitudeM' => p.maxAltitudeM, + 'gpsSatGreenMin' => p.gpsSatGreenMin, + 'gpsSatRedMin' => p.gpsSatRedMin, + 'hdopGreenMax' => p.hdopGreenMax, + 'hdopRedMax' => p.hdopRedMax, + 'currentGreenMaxA' => p.currentGreenMaxA, + 'currentRedMaxA' => p.currentRedMaxA, + 'batteryVoltageGreenMinV' => p.batteryVoltageGreenMinV, + 'batteryVoltageRedMinV' => p.batteryVoltageRedMinV, + 'rxQualityGreenMin' => p.rxQualityGreenMin, + 'rxQualityRedMin' => p.rxQualityRedMin, + 'rxSnrGreenMinDb' => p.rxSnrGreenMinDb, + 'rxSnrRedMinDb' => p.rxSnrRedMinDb, _ => throw ArgumentError(key), }; @@ -120,6 +178,18 @@ class _DroneProfileEditorState extends ConsumerState { maxRangeM: v('maxRangeM'), maxEnduranceMin: v('maxEnduranceMin'), maxAltitudeM: v('maxAltitudeM'), + gpsSatGreenMin: v('gpsSatGreenMin'), + gpsSatRedMin: v('gpsSatRedMin'), + hdopGreenMax: v('hdopGreenMax'), + hdopRedMax: v('hdopRedMax'), + currentGreenMaxA: v('currentGreenMaxA'), + currentRedMaxA: v('currentRedMaxA'), + batteryVoltageGreenMinV: v('batteryVoltageGreenMinV'), + batteryVoltageRedMinV: v('batteryVoltageRedMinV'), + rxQualityGreenMin: v('rxQualityGreenMin'), + rxQualityRedMin: v('rxQualityRedMin'), + rxSnrGreenMinDb: v('rxSnrGreenMinDb'), + rxSnrRedMinDb: v('rxSnrRedMinDb'), ); final repo = ref.read(droneProfileRepositoryProvider); diff --git a/app/lib/ui/widgets/drone_status_warnings_panel.dart b/app/lib/ui/widgets/drone_status_warnings_panel.dart index b0d7c97..dd5a76e 100644 --- a/app/lib/ui/widgets/drone_status_warnings_panel.dart +++ b/app/lib/ui/widgets/drone_status_warnings_panel.dart @@ -2,7 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../domain/telemetry/drone_event.dart'; +import '../../domain/telemetry/drone_status.dart'; +import '../../domain/telemetry/telemetry_field_status.dart'; import '../dmc_colors.dart'; +import '../providers/active_drone_profile_provider.dart'; import '../providers/drone_event_log_provider.dart'; import '../providers/telemetry_provider.dart'; @@ -109,36 +112,56 @@ class _DroneStatusWarningsPanelState extends ConsumerState ListView( - padding: const EdgeInsets.all(16), - children: [ - _statusRow('GPS satellites', '${frame.numSat}'), - _statusRow( - 'GPS precision (HDOP)', - frame.hasFix ? frame.hdop.toStringAsFixed(2) : '—', - ), - _statusRow( - 'GPS coordinates', - frame.hasFix - ? '${frame.lat.toStringAsFixed(6)}, ${frame.lon.toStringAsFixed(6)}' - : '—', - ), - _statusRow('Current draw', '${frame.currentA.toStringAsFixed(1)} A'), - _statusRow('Battery voltage', '${frame.batteryVoltage.toStringAsFixed(2)} V'), - _statusRow('Heading', '${frame.headingDeg.round()}°'), - _statusRow('RX quality / SNR', '${frame.linkQuality}% / ${frame.snrDb} dB'), - // Downlink-Qualitaet/-SNR und die Akku-SoC des Sendemoduls selbst - // (nicht der Drohne) sind ueber keinen MSP-GET-Befehl abrufbar - - // rxLinkStatistics_t (iNAV 9.1, rx.h) hat zwar ein downlinkLQ-Feld, - // das wird aber nur per MSP2_COMMON_SET_MSP_RC_LINK_STATS von - // aussen HINEINgeschrieben, nie per GET zurueckgelesen; eine - // Downlink-SNR oder eine Sender-Akkugroesse existiert im Struct - // ueberhaupt nicht (verifiziert im lokalen iNAV-Checkout, - // release/9.1). - _statusRow('TX battery SoC / quality / SNR', 'Not available (not exposed via MSP)'), - ], - ), + data: (frame) { + final fieldStatus = computeTelemetryFieldStatus( + numSat: frame.numSat, + hasFix: frame.hasFix, + hdop: frame.hdop, + currentA: frame.currentA, + batteryVoltage: frame.batteryVoltage, + linkQuality: frame.linkQuality, + snrDb: frame.snrDb, + profile: droneProfile, + ); + return ListView( + padding: const EdgeInsets.all(16), + children: [ + // Farbcodierte Felder zuerst (Doku: "drone status felder im + // menue auch farblich kodieren", Schwellwerte je Drohnenprofil - + // siehe computeTelemetryFieldStatus), informelle Felder ohne + // Ampel-Bewertung (Koordinaten/Heading/Alt/Speed) danach. + _statusRow('GPS satellites', '${frame.numSat}', level: fieldStatus.numSat), + _statusRow( + 'GPS precision (HDOP)', + frame.hasFix ? frame.hdop.toStringAsFixed(2) : '—', + level: fieldStatus.hdop, + ), + _statusRow( + 'Current draw', + '${frame.currentA.toStringAsFixed(1)} A', + level: fieldStatus.currentA, + ), + _statusRow( + 'Battery voltage', + '${frame.batteryVoltage.toStringAsFixed(2)} V', + level: fieldStatus.batteryVoltage, + ), + _statusRow('RX quality', '${frame.linkQuality}%', level: fieldStatus.rxQuality), + _statusRow('RX SNR', '${frame.snrDb} dB', level: fieldStatus.rxSnr), + _statusRow( + 'GPS coordinates', + frame.hasFix + ? '${frame.lat.toStringAsFixed(6)}, ${frame.lon.toStringAsFixed(6)}' + : '—', + ), + _statusRow('Heading', '${frame.headingDeg.round()}°'), + _statusRow('Altitude', '${frame.altitudeM.toStringAsFixed(0)} m'), + _statusRow('Speed', '${frame.speedMs.toStringAsFixed(1)} m/s'), + ], + ); + }, loading: () => const Center( child: CircularProgressIndicator(color: Color(0xFF4D9DFF)), ), @@ -148,7 +171,14 @@ class _DroneStatusWarningsPanelState extends ConsumerState