diff --git a/lib/connector/meshcore_connector.dart b/lib/connector/meshcore_connector.dart index 2c56c373..9fa0032f 100644 --- a/lib/connector/meshcore_connector.dart +++ b/lib/connector/meshcore_connector.dart @@ -15,6 +15,7 @@ import '../models/path_selection.dart'; import '../helpers/reaction_helper.dart'; import '../helpers/smaz.dart'; import '../services/app_debug_log_service.dart'; +import '../utils/battery_utils.dart'; import '../services/ble_debug_log_service.dart'; import '../services/message_retry_service.dart'; import '../services/path_history_service.dart'; @@ -92,6 +93,7 @@ class MeshCoreConnector extends ChangeNotifier { int? _currentSf; int? _currentCr; int? _batteryMillivolts; + String? _reportedBatteryChemistry; // From firmware, if available double? _selfLatitude; double? _selfLongitude; bool _isLoadingContacts = false; @@ -203,6 +205,7 @@ class MeshCoreConnector extends ChangeNotifier { int? get currentCr => _currentCr; Map? get currentCustomVars => _currentCustomVars; int? get batteryMillivolts => _batteryMillivolts; + String? get reportedBatteryChemistry => _reportedBatteryChemistry; int get maxContacts => _maxContacts; int get maxChannels => _maxChannels; bool get isSyncingQueuedMessages => _isSyncingQueuedMessages; @@ -219,30 +222,21 @@ class MeshCoreConnector extends ChangeNotifier { ); String _batteryChemistryForDevice() { + // User setting is the source of truth (they can override firmware) final deviceId = _device?.remoteId.toString(); - if (deviceId == null || _appSettingsService == null) return 'nmc'; - return _appSettingsService!.batteryChemistryForDevice(deviceId); - } - - int _estimateBatteryPercent(int millivolts, String chemistry) { - final range = _batteryVoltageRange(chemistry); - final minMv = range.$1; - final maxMv = range.$2; - if (millivolts <= minMv) return 0; - if (millivolts >= maxMv) return 100; - return (((millivolts - minMv) * 100) / (maxMv - minMv)).round(); - } - - (int, int) _batteryVoltageRange(String chemistry) { - switch (chemistry) { - case 'lifepo4': - return (2600, 3650); - case 'lipo': - return (3000, 4200); - case 'nmc': - default: - return (3000, 4200); + if (deviceId != null && _appSettingsService != null) { + return _appSettingsService!.batteryChemistryForDevice(deviceId); + } + // Fall back to firmware if available and meaningful (not 'none') + if (_reportedBatteryChemistry != null && _reportedBatteryChemistry != 'none') { + return _reportedBatteryChemistry!; } + return 'lipo'; + } + + // Uses shared utility from battery_utils.dart + int? _estimateBatteryPercent(int millivolts, String chemistry) { + return estimateBatteryPercent(millivolts, chemistry); } List getMessages(Contact contact) { @@ -923,6 +917,7 @@ class MeshCoreConnector extends ChangeNotifier { _selfLatitude = null; _selfLongitude = null; _batteryMillivolts = null; + _reportedBatteryChemistry = null; _batteryRequested = false; _awaitingSelfInfo = false; _maxContacts = _defaultMaxContacts; @@ -1892,11 +1887,21 @@ class MeshCoreConnector extends ChangeNotifier { // [1-2] = battery_mv (uint16 LE) // [3-6] = storage_used_kb (uint32 LE) // [7-10] = storage_total_kb (uint32 LE) + // [11] = battery_chemistry (optional: 0=none, 1=lipo, 2=lifepo4, 3=leadacid) if (frame.length >= 3) { _batteryMillivolts = readUint16LE(frame, 1); + + // Check for optional chemistry byte at offset 11 (protocol extension) + if (frame.length > 11) { + _reportedBatteryChemistry = chemistryFromByte(frame[11]); + } + final volts = (_batteryMillivolts! / 1000.0).toStringAsFixed(2); + final chemInfo = _reportedBatteryChemistry != null + ? ' [$_reportedBatteryChemistry]' + : ''; _appDebugLogService?.info( - 'Pulled battery: $volts V ($_batteryMillivolts mV)', + 'Pulled battery: $volts V ($_batteryMillivolts mV)$chemInfo', tag: 'Battery', ); notifyListeners(); diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 460bc9d1..b707a438 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Информация за системата", "repeater_battery": "Батерия", + "repeater_batteryChemistry": "Тип батерия", + "repeater_powerSource": "Източник на захранване", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Слънчева", + "repeater_powerCharging": "Зареждане", + "repeater_powerBatteryOnly": "Само батерия", + "repeater_powerNone": "Няма захранване", "repeater_clockAtLogin": "Часовник (при влизане)", "repeater_uptime": "Наличност", "repeater_queueLength": "Дължина на опашката", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 0a72559c..4ff35a9e 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Systeminformation", "repeater_battery": "Akku", + "repeater_batteryChemistry": "Akkutyp", + "repeater_powerSource": "Stromquelle", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solar", + "repeater_powerCharging": "Lädt", + "repeater_powerBatteryOnly": "Nur Akku", + "repeater_powerNone": "Keine Stromquelle", "repeater_clockAtLogin": "Uhr (bei Anmeldung)", "repeater_uptime": "Verfügbarkeit", "repeater_queueLength": "Warteschlangenlänge", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ee5cf7d6..e36d239b 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -82,6 +82,15 @@ "settings_radioSettings": "Radio Settings", "settings_radioSettingsSubtitle": "Frequency, power, spreading factor", "settings_radioSettingsUpdated": "Radio settings updated", + "settings_batterySettings": "Battery Settings", + "settings_batterySettingsSubtitle": "Battery chemistry type", + "settings_batteryType": "Type", + "settings_batteryFirmwareDefault": "Device default: {chemistry}", + "@settings_batteryFirmwareDefault": { + "placeholders": { + "chemistry": {"type": "String"} + } + }, "settings_location": "Location", "settings_locationSubtitle": "GPS coordinates", "settings_locationUpdated": "Location and GPS settings updated", @@ -206,9 +215,10 @@ } }, "appSettings_batteryChemistryConnectFirst": "Connect to a device to choose", - "appSettings_batteryNmc": "18650 NMC (3.0-4.2V)", - "appSettings_batteryLifepo4": "LiFePO4 (2.6-3.65V)", - "appSettings_batteryLipo": "LiPo (3.0-4.2V)", + "appSettings_batteryNone": "No Battery", + "appSettings_batteryLipo": "LiPo (3.7V)", + "appSettings_batteryLifepo4": "LiFePO4 (3.2V)", + "appSettings_batteryLeadAcid": "Lead Acid (12V)", "appSettings_mapDisplay": "Map Display", "appSettings_showRepeaters": "Show Repeaters", "appSettings_showRepeatersSubtitle": "Display repeater nodes on the map", @@ -806,6 +816,13 @@ }, "repeater_systemInformation": "System Information", "repeater_battery": "Battery", + "repeater_batteryChemistry": "Battery Type", + "repeater_powerSource": "Power Source", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solar", + "repeater_powerCharging": "Charging", + "repeater_powerBatteryOnly": "Battery only", + "repeater_powerNone": "No power source", "repeater_clockAtLogin": "Clock (at login)", "repeater_uptime": "Uptime", "repeater_queueLength": "Queue Length", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index c6dad1ff..5e44d2bf 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Información del sistema", "repeater_battery": "Batería", + "repeater_batteryChemistry": "Tipo de batería", + "repeater_powerSource": "Fuente de alimentación", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solar", + "repeater_powerCharging": "Cargando", + "repeater_powerBatteryOnly": "Solo batería", + "repeater_powerNone": "Sin fuente de alimentación", "repeater_clockAtLogin": "Reloj (al inicio de sesión)", "repeater_uptime": "Tiempo de actividad", "repeater_queueLength": "Longitud de la cola", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index c1157ed3..f42db7d4 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Informations Système", "repeater_battery": "Batterie", + "repeater_batteryChemistry": "Type de batterie", + "repeater_powerSource": "Source d'alimentation", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solaire", + "repeater_powerCharging": "En charge", + "repeater_powerBatteryOnly": "Batterie seule", + "repeater_powerNone": "Aucune source", "repeater_clockAtLogin": "Horloge (au démarrage)", "repeater_uptime": "Disponibilité", "repeater_queueLength": "Longueur de la file d'attente", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index c32e8638..23ac734a 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Informazioni di sistema", "repeater_battery": "Batteria", + "repeater_batteryChemistry": "Tipo di batteria", + "repeater_powerSource": "Fonte di alimentazione", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solare", + "repeater_powerCharging": "In carica", + "repeater_powerBatteryOnly": "Solo batteria", + "repeater_powerNone": "Nessuna alimentazione", "repeater_clockAtLogin": "Orologio (all'accesso)", "repeater_uptime": "Disponibilità", "repeater_queueLength": "Lunghezza della coda", diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 055667fa..da98dc18 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -460,6 +460,30 @@ abstract class AppLocalizations { /// **'Radio settings updated'** String get settings_radioSettingsUpdated; + /// No description provided for @settings_batterySettings. + /// + /// In en, this message translates to: + /// **'Battery Settings'** + String get settings_batterySettings; + + /// No description provided for @settings_batterySettingsSubtitle. + /// + /// In en, this message translates to: + /// **'Battery chemistry type'** + String get settings_batterySettingsSubtitle; + + /// No description provided for @settings_batteryType. + /// + /// In en, this message translates to: + /// **'Type'** + String get settings_batteryType; + + /// No description provided for @settings_batteryFirmwareDefault. + /// + /// In en, this message translates to: + /// **'Device default: {chemistry}'** + String settings_batteryFirmwareDefault(String chemistry); + /// No description provided for @settings_location. /// /// In en, this message translates to: @@ -1108,23 +1132,29 @@ abstract class AppLocalizations { /// **'Connect to a device to choose'** String get appSettings_batteryChemistryConnectFirst; - /// No description provided for @appSettings_batteryNmc. + /// No description provided for @appSettings_batteryNone. + /// + /// In en, this message translates to: + /// **'No Battery'** + String get appSettings_batteryNone; + + /// No description provided for @appSettings_batteryLipo. /// /// In en, this message translates to: - /// **'18650 NMC (3.0-4.2V)'** - String get appSettings_batteryNmc; + /// **'LiPo (3.7V)'** + String get appSettings_batteryLipo; /// No description provided for @appSettings_batteryLifepo4. /// /// In en, this message translates to: - /// **'LiFePO4 (2.6-3.65V)'** + /// **'LiFePO4 (3.2V)'** String get appSettings_batteryLifepo4; - /// No description provided for @appSettings_batteryLipo. + /// No description provided for @appSettings_batteryLeadAcid. /// /// In en, this message translates to: - /// **'LiPo (3.0-4.2V)'** - String get appSettings_batteryLipo; + /// **'Lead Acid (12V)'** + String get appSettings_batteryLeadAcid; /// No description provided for @appSettings_mapDisplay. /// @@ -3081,6 +3111,48 @@ abstract class AppLocalizations { /// **'Battery'** String get repeater_battery; + /// No description provided for @repeater_batteryChemistry. + /// + /// In en, this message translates to: + /// **'Battery Type'** + String get repeater_batteryChemistry; + + /// No description provided for @repeater_powerSource. + /// + /// In en, this message translates to: + /// **'Power Source'** + String get repeater_powerSource; + + /// No description provided for @repeater_powerUsb. + /// + /// In en, this message translates to: + /// **'USB'** + String get repeater_powerUsb; + + /// No description provided for @repeater_powerSolar. + /// + /// In en, this message translates to: + /// **'Solar'** + String get repeater_powerSolar; + + /// No description provided for @repeater_powerCharging. + /// + /// In en, this message translates to: + /// **'Charging'** + String get repeater_powerCharging; + + /// No description provided for @repeater_powerBatteryOnly. + /// + /// In en, this message translates to: + /// **'Battery only'** + String get repeater_powerBatteryOnly; + + /// No description provided for @repeater_powerNone. + /// + /// In en, this message translates to: + /// **'No power source'** + String get repeater_powerNone; + /// No description provided for @repeater_clockAtLogin. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 701429e6..744ce952 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -188,6 +188,20 @@ class AppLocalizationsBg extends AppLocalizations { String get settings_radioSettingsUpdated => 'Радио настройките са актуализирани'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Местоположение'; @@ -548,13 +562,16 @@ class AppLocalizationsBg extends AppLocalizations { 'Свържете се с устройство, за да изберете.'; @override - String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'Литиев полимер (3.0-4.2V)'; @override String get appSettings_batteryLifepo4 => 'Литиево желязо фосфат (2.6-3.65V)'; @override - String get appSettings_batteryLipo => 'Литиев полимер (3.0-4.2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Карта за показване'; @@ -1705,6 +1722,27 @@ class AppLocalizationsBg extends AppLocalizations { @override String get repeater_battery => 'Батерия'; + @override + String get repeater_batteryChemistry => 'Тип батерия'; + + @override + String get repeater_powerSource => 'Източник на захранване'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Слънчева'; + + @override + String get repeater_powerCharging => 'Зареждане'; + + @override + String get repeater_powerBatteryOnly => 'Само батерия'; + + @override + String get repeater_powerNone => 'Няма захранване'; + @override String get repeater_clockAtLogin => 'Часовник (при влизане)'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index 514a7a19..724f3fa1 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -187,6 +187,20 @@ class AppLocalizationsDe extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Funkparameter aktualisiert'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Ort'; @@ -545,13 +559,16 @@ class AppLocalizationsDe extends AppLocalizations { 'Verbinde ein Gerät, um zu wählen'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0–4,2 V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0–4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65 V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0–4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Kartendarstellung'; @@ -1702,6 +1719,27 @@ class AppLocalizationsDe extends AppLocalizations { @override String get repeater_battery => 'Akku'; + @override + String get repeater_batteryChemistry => 'Akkutyp'; + + @override + String get repeater_powerSource => 'Stromquelle'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solar'; + + @override + String get repeater_powerCharging => 'Lädt'; + + @override + String get repeater_powerBatteryOnly => 'Nur Akku'; + + @override + String get repeater_powerNone => 'Keine Stromquelle'; + @override String get repeater_clockAtLogin => 'Uhr (bei Anmeldung)'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 040d8090..86399d03 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -186,6 +186,20 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Radio settings updated'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Location'; @@ -540,13 +554,16 @@ class AppLocalizationsEn extends AppLocalizations { 'Connect to a device to choose'; @override - String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.7V)'; @override - String get appSettings_batteryLifepo4 => 'LiFePO4 (2.6-3.65V)'; + String get appSettings_batteryLifepo4 => 'LiFePO4 (3.2V)'; @override - String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Map Display'; @@ -1675,6 +1692,27 @@ class AppLocalizationsEn extends AppLocalizations { @override String get repeater_battery => 'Battery'; + @override + String get repeater_batteryChemistry => 'Battery Type'; + + @override + String get repeater_powerSource => 'Power Source'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solar'; + + @override + String get repeater_powerCharging => 'Charging'; + + @override + String get repeater_powerBatteryOnly => 'Battery only'; + + @override + String get repeater_powerNone => 'No power source'; + @override String get repeater_clockAtLogin => 'Clock (at login)'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index e65cbcd3..c4e083e9 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -187,6 +187,20 @@ class AppLocalizationsEs extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Ajustes de radio actualizados'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Ubicación'; @@ -546,13 +560,16 @@ class AppLocalizationsEs extends AppLocalizations { 'Conéctate a un dispositivo para elegir'; @override - String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2.6-3.65V)'; @override - String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Visualización del Mapa'; @@ -1699,6 +1716,27 @@ class AppLocalizationsEs extends AppLocalizations { @override String get repeater_battery => 'Batería'; + @override + String get repeater_batteryChemistry => 'Tipo de batería'; + + @override + String get repeater_powerSource => 'Fuente de alimentación'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solar'; + + @override + String get repeater_powerCharging => 'Cargando'; + + @override + String get repeater_powerBatteryOnly => 'Solo batería'; + + @override + String get repeater_powerNone => 'Sin fuente de alimentación'; + @override String get repeater_clockAtLogin => 'Reloj (al inicio de sesión)'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 4496fc84..6d7f7434 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -187,6 +187,20 @@ class AppLocalizationsFr extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Paramètres radio mis à jour'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Emplacement'; @@ -548,13 +562,16 @@ class AppLocalizationsFr extends AppLocalizations { 'Connectez un appareil pour choisir'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Affichage de la carte'; @@ -1710,6 +1727,27 @@ class AppLocalizationsFr extends AppLocalizations { @override String get repeater_battery => 'Batterie'; + @override + String get repeater_batteryChemistry => 'Type de batterie'; + + @override + String get repeater_powerSource => 'Source d\'alimentation'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solaire'; + + @override + String get repeater_powerCharging => 'En charge'; + + @override + String get repeater_powerBatteryOnly => 'Batterie seule'; + + @override + String get repeater_powerNone => 'Aucune source'; + @override String get repeater_clockAtLogin => 'Horloge (au démarrage)'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 02345c4e..9d7fa8aa 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -187,6 +187,20 @@ class AppLocalizationsIt extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Impostazioni radio aggiornate'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Posizione'; @@ -545,13 +559,16 @@ class AppLocalizationsIt extends AppLocalizations { 'Connetti a un dispositivo per scegliere'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Visualizzazione Mappa'; @@ -1699,6 +1716,27 @@ class AppLocalizationsIt extends AppLocalizations { @override String get repeater_battery => 'Batteria'; + @override + String get repeater_batteryChemistry => 'Tipo di batteria'; + + @override + String get repeater_powerSource => 'Fonte di alimentazione'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solare'; + + @override + String get repeater_powerCharging => 'In carica'; + + @override + String get repeater_powerBatteryOnly => 'Solo batteria'; + + @override + String get repeater_powerNone => 'Nessuna alimentazione'; + @override String get repeater_clockAtLogin => 'Orologio (all\'accesso)'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 292181fc..1b593e96 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -186,6 +186,20 @@ class AppLocalizationsNl extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Radio instellingen bijgewerkt'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Locatie'; @@ -543,13 +557,16 @@ class AppLocalizationsNl extends AppLocalizations { 'Verbind met een apparaat om te selecteren'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Kaartweergave'; @@ -1693,6 +1710,27 @@ class AppLocalizationsNl extends AppLocalizations { @override String get repeater_battery => 'Batterij'; + @override + String get repeater_batteryChemistry => 'Batterijtype'; + + @override + String get repeater_powerSource => 'Stroombron'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Zonne-energie'; + + @override + String get repeater_powerCharging => 'Opladen'; + + @override + String get repeater_powerBatteryOnly => 'Alleen batterij'; + + @override + String get repeater_powerNone => 'Geen stroombron'; + @override String get repeater_clockAtLogin => 'Tijd (bij aanmelden)'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 08323295..45bd49e0 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -188,6 +188,20 @@ class AppLocalizationsPl extends AppLocalizations { String get settings_radioSettingsUpdated => 'Ustawienia radia zostały zaktualizowane'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Lokalizacja'; @@ -548,13 +562,16 @@ class AppLocalizationsPl extends AppLocalizations { 'Połącz się z urządzeniem, aby wybrać'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65 V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Wyświetlanie mapy'; @@ -1703,6 +1720,27 @@ class AppLocalizationsPl extends AppLocalizations { @override String get repeater_battery => 'Bateria'; + @override + String get repeater_batteryChemistry => 'Typ baterii'; + + @override + String get repeater_powerSource => 'Źródło zasilania'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solarny'; + + @override + String get repeater_powerCharging => 'Ładowanie'; + + @override + String get repeater_powerBatteryOnly => 'Tylko bateria'; + + @override + String get repeater_powerNone => 'Brak źródła zasilania'; + @override String get repeater_clockAtLogin => 'Godzina (przy logowaniu)'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index eadea3bc..4515a7ec 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -188,6 +188,20 @@ class AppLocalizationsPt extends AppLocalizations { String get settings_radioSettingsUpdated => 'Configurações de rádio atualizadas'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Localização'; @@ -547,13 +561,16 @@ class AppLocalizationsPt extends AppLocalizations { 'Conecte-se a um dispositivo para escolher'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6-3,65V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Exibição do Mapa'; @@ -1700,6 +1717,27 @@ class AppLocalizationsPt extends AppLocalizations { @override String get repeater_battery => 'Bateria'; + @override + String get repeater_batteryChemistry => 'Tipo de bateria'; + + @override + String get repeater_powerSource => 'Fonte de energia'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solar'; + + @override + String get repeater_powerCharging => 'Carregando'; + + @override + String get repeater_powerBatteryOnly => 'Apenas bateria'; + + @override + String get repeater_powerNone => 'Sem fonte de energia'; + @override String get repeater_clockAtLogin => 'Relógio (no login)'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index ec0f1ba3..e29b2366 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -186,6 +186,20 @@ class AppLocalizationsRu extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Настройки радио обновлены'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Позиция'; @@ -546,13 +560,16 @@ class AppLocalizationsRu extends AppLocalizations { 'Подключитесь к устройству, чтобы выбрать'; @override - String get appSettings_batteryNmc => '18650 NMC (3.0–4.2 В)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0–4.2 В)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2.6–3.65 В)'; @override - String get appSettings_batteryLipo => 'LiPo (3.0–4.2 В)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Отображение карты'; @@ -1702,6 +1719,27 @@ class AppLocalizationsRu extends AppLocalizations { @override String get repeater_battery => 'Батарея'; + @override + String get repeater_batteryChemistry => 'Тип батареи'; + + @override + String get repeater_powerSource => 'Источник питания'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Солнечная'; + + @override + String get repeater_powerCharging => 'Зарядка'; + + @override + String get repeater_powerBatteryOnly => 'Только батарея'; + + @override + String get repeater_powerNone => 'Нет питания'; + @override String get repeater_clockAtLogin => 'Время (при входе)'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 346047b0..0e3dea6f 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -187,6 +187,20 @@ class AppLocalizationsSk extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Nastavenia rádia aktualizované'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Lokalita'; @@ -540,13 +554,16 @@ class AppLocalizationsSk extends AppLocalizations { 'Pripojte sa k zariadeniu na výber'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Zobrazenie mapy'; @@ -1695,6 +1712,27 @@ class AppLocalizationsSk extends AppLocalizations { @override String get repeater_battery => 'Batéria'; + @override + String get repeater_batteryChemistry => 'Typ batérie'; + + @override + String get repeater_powerSource => 'Zdroj napájania'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Solárna'; + + @override + String get repeater_powerCharging => 'Nabíjanie'; + + @override + String get repeater_powerBatteryOnly => 'Len batéria'; + + @override + String get repeater_powerNone => 'Žiadny zdroj napájania'; + @override String get repeater_clockAtLogin => 'Čas (při přihlášení)'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index ed711224..fc6756b0 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -187,6 +187,20 @@ class AppLocalizationsSl extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Radio nastavitve posodobljene'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Lokacija'; @@ -542,13 +556,16 @@ class AppLocalizationsSl extends AppLocalizations { 'Za izbiro se poveži z napravo'; @override - String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65 V)'; @override - String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Prikaz zemljevida'; @@ -1694,6 +1711,27 @@ class AppLocalizationsSl extends AppLocalizations { @override String get repeater_battery => 'Baterija'; + @override + String get repeater_batteryChemistry => 'Tip baterije'; + + @override + String get repeater_powerSource => 'Vir napajanja'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Sončna'; + + @override + String get repeater_powerCharging => 'Polnjenje'; + + @override + String get repeater_powerBatteryOnly => 'Samo baterija'; + + @override + String get repeater_powerNone => 'Ni vira napajanja'; + @override String get repeater_clockAtLogin => 'Ure (pri prijavi)'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 97b849fa..bc7bde5b 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -187,6 +187,20 @@ class AppLocalizationsSv extends AppLocalizations { String get settings_radioSettingsUpdated => 'Radioinställningarna har uppdaterats'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Plats'; @@ -537,13 +551,16 @@ class AppLocalizationsSv extends AppLocalizations { 'Anslut till en enhet för att välja'; @override - String get appSettings_batteryNmc => '18650 NMC (3.0-4.2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2,6–3,65V)'; @override - String get appSettings_batteryLipo => 'LiPo (3.0-4.2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Kartvisning'; @@ -1684,6 +1701,27 @@ class AppLocalizationsSv extends AppLocalizations { @override String get repeater_battery => 'Batteri'; + @override + String get repeater_batteryChemistry => 'Batterityp'; + + @override + String get repeater_powerSource => 'Strömkälla'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Sol'; + + @override + String get repeater_powerCharging => 'Laddar'; + + @override + String get repeater_powerBatteryOnly => 'Endast batteri'; + + @override + String get repeater_powerNone => 'Ingen strömkälla'; + @override String get repeater_clockAtLogin => 'Klocka (vid inloggning)'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 899d540d..6fb64253 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -187,6 +187,20 @@ class AppLocalizationsUk extends AppLocalizations { @override String get settings_radioSettingsUpdated => 'Налаштування радіо оновлено'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => 'Розташування'; @@ -544,13 +558,16 @@ class AppLocalizationsUk extends AppLocalizations { 'Підключіть пристрій, щоб вибрати'; @override - String get appSettings_batteryNmc => '18650 NMC (3.0-4.2В)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => 'LiPo (3.0-4.2В)'; @override String get appSettings_batteryLifepo4 => 'LiFePO4 (2.6-3.65В)'; @override - String get appSettings_batteryLipo => 'LiPo (3.0-4.2В)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => 'Відображення карти'; @@ -1703,6 +1720,27 @@ class AppLocalizationsUk extends AppLocalizations { @override String get repeater_battery => 'Батарея'; + @override + String get repeater_batteryChemistry => 'Тип батареї'; + + @override + String get repeater_powerSource => 'Джерело живлення'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => 'Сонячна'; + + @override + String get repeater_powerCharging => 'Заряджання'; + + @override + String get repeater_powerBatteryOnly => 'Тільки батарея'; + + @override + String get repeater_powerNone => 'Немає джерела живлення'; + @override String get repeater_clockAtLogin => 'Годинник (при вході)'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 77467924..6e901a36 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -184,6 +184,20 @@ class AppLocalizationsZh extends AppLocalizations { @override String get settings_radioSettingsUpdated => '收音机设置已更新'; + @override + String get settings_batterySettings => 'Battery Settings'; + + @override + String get settings_batterySettingsSubtitle => 'Battery chemistry type'; + + @override + String get settings_batteryType => 'Type'; + + @override + String settings_batteryFirmwareDefault(String chemistry) { + return 'Device default: $chemistry'; + } + @override String get settings_location => '地点'; @@ -517,13 +531,16 @@ class AppLocalizationsZh extends AppLocalizations { String get appSettings_batteryChemistryConnectFirst => '连接到设备以进行选择'; @override - String get appSettings_batteryNmc => '18650 型号,NMC 电池(3.0-4.2V)'; + String get appSettings_batteryNone => 'No Battery'; + + @override + String get appSettings_batteryLipo => '锂离子电池 (3.0-4.2V)'; @override String get appSettings_batteryLifepo4 => '磷酸铁锂 (2.6-3.65V)'; @override - String get appSettings_batteryLipo => '锂离子电池 (3.0-4.2V)'; + String get appSettings_batteryLeadAcid => 'Lead Acid (12V)'; @override String get appSettings_mapDisplay => '地图展示'; @@ -1623,6 +1640,27 @@ class AppLocalizationsZh extends AppLocalizations { @override String get repeater_battery => '电池'; + @override + String get repeater_batteryChemistry => '电池类型'; + + @override + String get repeater_powerSource => '电源'; + + @override + String get repeater_powerUsb => 'USB'; + + @override + String get repeater_powerSolar => '太阳能'; + + @override + String get repeater_powerCharging => '充电中'; + + @override + String get repeater_powerBatteryOnly => '仅电池'; + + @override + String get repeater_powerNone => '无电源'; + @override String get repeater_clockAtLogin => '登录时的时间'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index e94deb37..2de54e4f 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Systeeminformatie", "repeater_battery": "Batterij", + "repeater_batteryChemistry": "Batterijtype", + "repeater_powerSource": "Stroombron", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Zonne-energie", + "repeater_powerCharging": "Opladen", + "repeater_powerBatteryOnly": "Alleen batterij", + "repeater_powerNone": "Geen stroombron", "repeater_clockAtLogin": "Tijd (bij aanmelden)", "repeater_uptime": "Beschikbaarheid", "repeater_queueLength": "Wachttijd", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 44552c3c..eede34bb 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Informacje o systemie", "repeater_battery": "Bateria", + "repeater_batteryChemistry": "Typ baterii", + "repeater_powerSource": "Źródło zasilania", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solarny", + "repeater_powerCharging": "Ładowanie", + "repeater_powerBatteryOnly": "Tylko bateria", + "repeater_powerNone": "Brak źródła zasilania", "repeater_clockAtLogin": "Godzina (przy logowaniu)", "repeater_uptime": "Dostępność", "repeater_queueLength": "Długość kolejki", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 56a7f2b2..1a527bd2 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Informações do Sistema", "repeater_battery": "Bateria", + "repeater_batteryChemistry": "Tipo de bateria", + "repeater_powerSource": "Fonte de energia", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solar", + "repeater_powerCharging": "Carregando", + "repeater_powerBatteryOnly": "Apenas bateria", + "repeater_powerNone": "Sem fonte de energia", "repeater_clockAtLogin": "Relógio (no login)", "repeater_uptime": "Disponibilidade", "repeater_queueLength": "Comprimento da Fila", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 0bca5ef0..5e608a9b 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -486,6 +486,13 @@ "repeater_errorLoadingStatus": "Ошибка загрузки статуса: {error}", "repeater_systemInformation": "Системная информация", "repeater_battery": "Батарея", + "repeater_batteryChemistry": "Тип батареи", + "repeater_powerSource": "Источник питания", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Солнечная", + "repeater_powerCharging": "Зарядка", + "repeater_powerBatteryOnly": "Только батарея", + "repeater_powerNone": "Нет питания", "repeater_clockAtLogin": "Время (при входе)", "repeater_uptime": "Время работы", "repeater_queueLength": "Длина очереди", diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index d61cca61..955d088e 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Informácie o systéme", "repeater_battery": "Batéria", + "repeater_batteryChemistry": "Typ batérie", + "repeater_powerSource": "Zdroj napájania", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Solárna", + "repeater_powerCharging": "Nabíjanie", + "repeater_powerBatteryOnly": "Len batéria", + "repeater_powerNone": "Žiadny zdroj napájania", "repeater_clockAtLogin": "Čas (při přihlášení)", "repeater_uptime": "Dostupnosť", "repeater_queueLength": "Dĺžka fronty", diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index cbc4e3f6..2d9239c9 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Informacije o sistemu", "repeater_battery": "Baterija", + "repeater_batteryChemistry": "Tip baterije", + "repeater_powerSource": "Vir napajanja", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Sončna", + "repeater_powerCharging": "Polnjenje", + "repeater_powerBatteryOnly": "Samo baterija", + "repeater_powerNone": "Ni vira napajanja", "repeater_clockAtLogin": "Ure (pri prijavi)", "repeater_uptime": "Čas delovanja", "repeater_queueLength": "Dolžina čakalne vrste", diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 05f77cb8..f939abb2 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -898,6 +898,13 @@ }, "repeater_systemInformation": "Systeminformation", "repeater_battery": "Batteri", + "repeater_batteryChemistry": "Batterityp", + "repeater_powerSource": "Strömkälla", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Sol", + "repeater_powerCharging": "Laddar", + "repeater_powerBatteryOnly": "Endast batteri", + "repeater_powerNone": "Ingen strömkälla", "repeater_clockAtLogin": "Klocka (vid inloggning)", "repeater_uptime": "Tillgänglighet", "repeater_queueLength": "Köans längd", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 3362d409..6fcca663 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -899,6 +899,13 @@ }, "repeater_systemInformation": "Системна інформація", "repeater_battery": "Батарея", + "repeater_batteryChemistry": "Тип батареї", + "repeater_powerSource": "Джерело живлення", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "Сонячна", + "repeater_powerCharging": "Заряджання", + "repeater_powerBatteryOnly": "Тільки батарея", + "repeater_powerNone": "Немає джерела живлення", "repeater_clockAtLogin": "Годинник (при вході)", "repeater_uptime": "Час роботи", "repeater_queueLength": "Довжина черги", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index c941461a..cda23ba7 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -921,6 +921,13 @@ }, "repeater_systemInformation": "系统信息", "repeater_battery": "电池", + "repeater_batteryChemistry": "电池类型", + "repeater_powerSource": "电源", + "repeater_powerUsb": "USB", + "repeater_powerSolar": "太阳能", + "repeater_powerCharging": "充电中", + "repeater_powerBatteryOnly": "仅电池", + "repeater_powerNone": "无电源", "repeater_clockAtLogin": "登录时的时间", "repeater_uptime": "正常运行时间", "repeater_queueLength": "排队长度", diff --git a/lib/models/app_settings.dart b/lib/models/app_settings.dart index 3edb68fa..bd674b4d 100644 --- a/lib/models/app_settings.dart +++ b/lib/models/app_settings.dart @@ -21,6 +21,7 @@ class AppSettings { final String? languageOverride; // null = system default final bool appDebugLogEnabled; final Map batteryChemistryByDeviceId; + final Map repeaterBatteryChemistryByPublicKey; AppSettings({ this.clearPathOnMaxRetry = false, @@ -43,7 +44,10 @@ class AppSettings { this.languageOverride, this.appDebugLogEnabled = false, Map? batteryChemistryByDeviceId, - }) : batteryChemistryByDeviceId = batteryChemistryByDeviceId ?? {}; + Map? repeaterBatteryChemistryByPublicKey, + }) : batteryChemistryByDeviceId = batteryChemistryByDeviceId ?? {}, + repeaterBatteryChemistryByPublicKey = + repeaterBatteryChemistryByPublicKey ?? {}; Map toJson() { return { @@ -67,6 +71,8 @@ class AppSettings { 'language_override': languageOverride, 'app_debug_log_enabled': appDebugLogEnabled, 'battery_chemistry_by_device_id': batteryChemistryByDeviceId, + 'repeater_battery_chemistry_by_public_key': + repeaterBatteryChemistryByPublicKey, }; } @@ -101,6 +107,11 @@ class AppSettings { (key, value) => MapEntry(key.toString(), value.toString()), ) ?? {}, + repeaterBatteryChemistryByPublicKey: + (json['repeater_battery_chemistry_by_public_key'] as Map?)?.map( + (key, value) => MapEntry(key.toString(), value.toString()), + ) ?? + {}, ); } @@ -125,6 +136,7 @@ class AppSettings { Object? languageOverride = _unset, bool? appDebugLogEnabled, Map? batteryChemistryByDeviceId, + Map? repeaterBatteryChemistryByPublicKey, }) { return AppSettings( clearPathOnMaxRetry: clearPathOnMaxRetry ?? this.clearPathOnMaxRetry, @@ -154,6 +166,9 @@ class AppSettings { appDebugLogEnabled: appDebugLogEnabled ?? this.appDebugLogEnabled, batteryChemistryByDeviceId: batteryChemistryByDeviceId ?? this.batteryChemistryByDeviceId, + repeaterBatteryChemistryByPublicKey: + repeaterBatteryChemistryByPublicKey ?? + this.repeaterBatteryChemistryByPublicKey, ); } } diff --git a/lib/screens/app_settings_screen.dart b/lib/screens/app_settings_screen.dart index 135babd4..ddddad66 100644 --- a/lib/screens/app_settings_screen.dart +++ b/lib/screens/app_settings_screen.dart @@ -391,9 +391,27 @@ class AppSettingsScreen extends StatelessWidget { ) { final deviceId = connector.deviceId; final isConnected = connector.isConnected && deviceId != null; - final selection = isConnected - ? settingsService.batteryChemistryForDevice(deviceId) - : 'nmc'; + final isFromFirmware = connector.reportedBatteryChemistry != null; + final chemistry = isConnected + ? (isFromFirmware + ? connector.reportedBatteryChemistry! + : settingsService.batteryChemistryForDevice(deviceId)) + : 'lipo'; + + // Don't show battery card if firmware reports no battery + if (isFromFirmware && chemistry == 'none') { + return const SizedBox.shrink(); + } + + String chemistryDisplayName(String chem) { + return switch (chem) { + 'none' => context.l10n.appSettings_batteryNone, + 'lipo' => context.l10n.appSettings_batteryLipo, + 'lifepo4' => context.l10n.appSettings_batteryLifepo4, + 'leadacid' => context.l10n.appSettings_batteryLeadAcid, + _ => context.l10n.appSettings_batteryLipo, + }; + } return Card( child: Column( @@ -416,33 +434,52 @@ class AppSettingsScreen extends StatelessWidget { ) : context.l10n.appSettings_batteryChemistryConnectFirst, ), - trailing: DropdownButton( - value: selection, - onChanged: isConnected - ? (value) { - if (value != null) { - settingsService.setBatteryChemistryForDevice( - deviceId, - value, - ); - } - } - : null, - items: [ - DropdownMenuItem( - value: 'nmc', - child: Text(context.l10n.appSettings_batteryNmc), - ), - DropdownMenuItem( - value: 'lifepo4', - child: Text(context.l10n.appSettings_batteryLifepo4), - ), - DropdownMenuItem( - value: 'lipo', - child: Text(context.l10n.appSettings_batteryLipo), - ), - ], - ), + trailing: isFromFirmware + // Firmware-reported: show as read-only text with lock icon + ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(chemistryDisplayName(chemistry)), + const SizedBox(width: 8), + Icon( + Icons.lock_outline, + size: 16, + color: Colors.grey[500], + ), + ], + ) + // User-configurable: show dropdown + : DropdownButton( + value: chemistry, + onChanged: isConnected + ? (value) { + if (value != null) { + settingsService.setBatteryChemistryForDevice( + deviceId, + value, + ); + } + } + : null, + items: [ + DropdownMenuItem( + value: 'none', + child: Text(context.l10n.appSettings_batteryNone), + ), + DropdownMenuItem( + value: 'lipo', + child: Text(context.l10n.appSettings_batteryLipo), + ), + DropdownMenuItem( + value: 'lifepo4', + child: Text(context.l10n.appSettings_batteryLifepo4), + ), + DropdownMenuItem( + value: 'leadacid', + child: Text(context.l10n.appSettings_batteryLeadAcid), + ), + ], + ), ), ], ), diff --git a/lib/screens/repeater_status_screen.dart b/lib/screens/repeater_status_screen.dart index 472b0137..1c5e9f65 100644 --- a/lib/screens/repeater_status_screen.dart +++ b/lib/screens/repeater_status_screen.dart @@ -4,11 +4,14 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../l10n/l10n.dart'; +import '../l10n/app_localizations.dart'; import '../models/contact.dart'; import '../models/path_selection.dart'; import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; import '../services/repeater_command_service.dart'; +import '../services/app_settings_service.dart'; +import '../utils/battery_utils.dart'; import '../widgets/path_management_dialog.dart'; class RepeaterStatusScreen extends StatefulWidget { @@ -54,6 +57,8 @@ class _RepeaterStatusScreenState extends State { int? _dupFlood; int? _dupDirect; PathSelection? _pendingStatusSelection; + String? _reportedChemistry; // From firmware, if available + PowerState? _powerState; // Power source info from firmware @override void initState() { @@ -157,6 +162,25 @@ class _RepeaterStatusScreenState extends State { offset += 2; final rxAirSecs = data.getUint32(offset, Endian.little); + // Check for optional chemistry byte at offset 60 (protocol extension) + // 0=none, 1=lipo, 2=lifepo4, 3=leadacid + String? reportedChem; + PowerState? powerState; + if (frame.length > _statusResponseBytes) { + reportedChem = chemistryFromByte(frame[_statusResponseBytes]); + + // Parse power state byte (offset 61) and input voltage (bytes 62-63) + if (frame.length > _statusResponseBytes + 1) { + final powerFlags = frame[_statusResponseBytes + 1]; + int? inputMv; + if (frame.length > _statusResponseBytes + 3) { + inputMv = frame[_statusResponseBytes + 2] | + (frame[_statusResponseBytes + 3] << 8); + } + powerState = PowerState(powerFlags, inputMv); + } + } + _statusTimeout?.cancel(); if (!mounted) return; setState(() { @@ -178,6 +202,8 @@ class _RepeaterStatusScreenState extends State { _lastSnr = lastSnrRaw / 4.0; _dupDirect = directDups; _dupFlood = floodDups; + _reportedChemistry = reportedChem; + _powerState = powerState; }); _recordStatusResult(true); } @@ -251,6 +277,8 @@ class _RepeaterStatusScreenState extends State { _directRx = null; _dupFlood = null; _dupDirect = null; + _reportedChemistry = null; + _powerState = null; }); try { @@ -438,6 +466,12 @@ class _RepeaterStatusScreenState extends State { Widget _buildSystemInfoCard() { final l10n = context.l10n; + final settingsService = context.watch(); + final userChemistry = + settingsService.batteryChemistryForRepeater(widget.repeater.publicKeyHex); + // Prefer firmware-reported chemistry, fall back to user setting + final chemistry = _reportedChemistry ?? userChemistry; + return Card( child: Padding( padding: const EdgeInsets.all(16), @@ -461,7 +495,16 @@ class _RepeaterStatusScreenState extends State { ], ), const Divider(), - _buildInfoRow(l10n.repeater_battery, _batteryText()), + _buildInfoRow(l10n.repeater_battery, _batteryText(chemistry)), + // Only show chemistry row if there's a battery to configure + if (chemistry != 'none') + _buildBatteryChemistryRow( + settingsService, + chemistry, + isFromFirmware: _reportedChemistry != null, + ), + // Show power source row if firmware reports power state + if (_powerState != null) _buildPowerSourceRow(l10n), _buildInfoRow(l10n.repeater_clockAtLogin, _clockText()), _buildInfoRow(l10n.repeater_uptime, _formatDuration(_uptimeSecs)), _buildInfoRow(l10n.repeater_queueLength, _formatValue(_queueLen)), @@ -472,6 +515,171 @@ class _RepeaterStatusScreenState extends State { ); } + Widget _buildBatteryChemistryRow( + AppSettingsService settingsService, + String currentChemistry, { + required bool isFromFirmware, + }) { + final l10n = context.l10n; + + // Map chemistry code to display name + String chemistryDisplayName(String chem) { + return switch (chem) { + 'none' => l10n.appSettings_batteryNone, + 'lipo' => l10n.appSettings_batteryLipo, + 'lifepo4' => l10n.appSettings_batteryLifepo4, + 'leadacid' => l10n.appSettings_batteryLeadAcid, + _ => l10n.appSettings_batteryLipo, + }; + } + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 130, + child: Text( + l10n.repeater_batteryChemistry, + style: TextStyle( + color: Colors.grey[600], + fontWeight: FontWeight.w500, + ), + ), + ), + Expanded( + child: isFromFirmware + // Firmware-reported: show as read-only text with indicator + ? Row( + children: [ + Flexible( + child: Text( + chemistryDisplayName(currentChemistry), + style: const TextStyle(fontWeight: FontWeight.w400), + overflow: TextOverflow.ellipsis, + ), + ), + const SizedBox(width: 8), + Icon( + Icons.lock_outline, + size: 16, + color: Colors.grey[500], + ), + ], + ) + // User-configurable: show dropdown + : DropdownButton( + value: currentChemistry, + isDense: true, + underline: const SizedBox.shrink(), + onChanged: (value) { + if (value != null) { + settingsService.setBatteryChemistryForRepeater( + widget.repeater.publicKeyHex, + value, + ); + } + }, + items: [ + DropdownMenuItem( + value: 'none', + child: Text(l10n.appSettings_batteryNone), + ), + DropdownMenuItem( + value: 'lipo', + child: Text(l10n.appSettings_batteryLipo), + ), + DropdownMenuItem( + value: 'lifepo4', + child: Text(l10n.appSettings_batteryLifepo4), + ), + DropdownMenuItem( + value: 'leadacid', + child: Text(l10n.appSettings_batteryLeadAcid), + ), + ], + ), + ), + ], + ), + ); + } + + Widget _buildPowerSourceRow(AppLocalizations l10n) { + final power = _powerState; + if (power == null) return const SizedBox.shrink(); + + // Build list of status parts + final parts = []; + if (power.isUsbConnected) parts.add(l10n.repeater_powerUsb); + if (power.isSolarConnected) parts.add(l10n.repeater_powerSolar); + if (power.isCharging) parts.add(l10n.repeater_powerCharging); + + // Add input voltage if available + final voltageStr = power.inputVoltageString; + if (voltageStr != null) parts.add('${voltageStr}V'); + + // Fallback text if no external power + final statusText = parts.isEmpty + ? (power.isBatteryPresent + ? l10n.repeater_powerBatteryOnly + : l10n.repeater_powerNone) + : parts.join(' / '); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 130, + child: Text( + l10n.repeater_powerSource, + style: TextStyle( + color: Colors.grey[600], + fontWeight: FontWeight.w500, + ), + ), + ), + Expanded( + child: Row( + children: [ + // USB icon + if (power.isUsbConnected) + Padding( + padding: const EdgeInsets.only(right: 6), + child: Icon(Icons.usb, size: 18, color: Colors.blue[600]), + ), + // Solar icon + if (power.isSolarConnected) + Padding( + padding: const EdgeInsets.only(right: 6), + child: + Icon(Icons.wb_sunny, size: 18, color: Colors.orange[600]), + ), + // Charging icon + if (power.isCharging) + Padding( + padding: const EdgeInsets.only(right: 6), + child: Icon(Icons.battery_charging_full, + size: 18, color: Colors.green[600]), + ), + Flexible( + child: Text( + statusText, + style: const TextStyle(fontWeight: FontWeight.w400), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ], + ), + ); + } + Widget _buildRadioStatsCard() { final l10n = context.l10n; return Card( @@ -589,21 +797,15 @@ class _RepeaterStatusScreenState extends State { return double.tryParse(value.toString()); } - String _batteryText() { + String _batteryText(String chemistry) { if (_batteryMv == null) return '—'; - final percent = _batteryPercentFromMv(_batteryMv!); + if (chemistry == 'none') return 'N/A (external power)'; + final percent = estimateBatteryPercent(_batteryMv!, chemistry); + if (percent == null) return '—'; final volts = (_batteryMv! / 1000.0).toStringAsFixed(2); return '$percent% / ${volts}V'; } - int _batteryPercentFromMv(int millivolts) { - const minMv = 3000; - const maxMv = 4200; - if (millivolts <= minMv) return 0; - if (millivolts >= maxMv) return 100; - return (((millivolts - minMv) * 100) / (maxMv - minMv)).round(); - } - String _clockText() { if (_statusRequestedAt == null) return '—'; final dt = _statusRequestedAt!; diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 415d5081..bc83741f 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -5,8 +5,10 @@ import 'package:package_info_plus/package_info_plus.dart'; import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; +import '../l10n/app_localizations.dart'; import '../l10n/l10n.dart'; import '../models/radio_settings.dart'; +import '../services/app_settings_service.dart'; import 'app_settings_screen.dart'; import 'app_debug_log_screen.dart'; import 'ble_debug_log_screen.dart'; @@ -225,6 +227,14 @@ class _SettingsScreenState extends State { onTap: () => _editLocation(context, connector), ), const Divider(height: 1), + ListTile( + leading: const Icon(Icons.battery_full), + title: Text(l10n.settings_batterySettings), + subtitle: Text(l10n.settings_batterySettingsSubtitle), + trailing: const Icon(Icons.chevron_right), + onTap: () => _showBatterySettings(context, connector), + ), + const Divider(height: 1), ListTile( leading: const Icon(Icons.visibility_off_outlined), title: Text(l10n.settings_privacyMode), @@ -428,6 +438,113 @@ class _SettingsScreenState extends State { ); } + void _showBatterySettings(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; + final settingsService = Provider.of(context, listen: false); + final deviceId = connector.deviceId; + final firmwareChemistry = connector.reportedBatteryChemistry; + // User setting takes precedence, fall back to firmware, then default + final chemistry = deviceId != null + ? settingsService.batteryChemistryForDevice(deviceId) + : (firmwareChemistry ?? 'lipo'); + + final millivolts = connector.batteryMillivolts; + final percent = connector.batteryPercent; + + showDialog( + context: context, + builder: (dialogContext) => AlertDialog( + title: Text(l10n.settings_batterySettings), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (millivolts != null) + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '${(millivolts / 1000.0).toStringAsFixed(2)}V', + style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), + ), + if (percent != null) ...[ + const SizedBox(width: 12), + Text( + '($percent%)', + style: TextStyle(fontSize: 18, color: Colors.grey[400]), + ), + ], + ], + ), + ), + ListTile( + contentPadding: EdgeInsets.zero, + title: Text(l10n.settings_batteryType), + trailing: DropdownButton( + value: chemistry, + onChanged: deviceId != null + ? (value) { + if (value != null) { + settingsService.setBatteryChemistryForDevice(deviceId, value); + Navigator.pop(dialogContext); + // Reopen to show updated value + _showBatterySettings(context, connector); + } + } + : null, + items: [ + DropdownMenuItem( + value: 'none', + child: Text(l10n.appSettings_batteryNone), + ), + DropdownMenuItem( + value: 'lipo', + child: Text(l10n.appSettings_batteryLipo), + ), + DropdownMenuItem( + value: 'lifepo4', + child: Text(l10n.appSettings_batteryLifepo4), + ), + DropdownMenuItem( + value: 'leadacid', + child: Text(l10n.appSettings_batteryLeadAcid), + ), + ], + ), + ), + if (firmwareChemistry != null && firmwareChemistry != 'none') + Padding( + padding: const EdgeInsets.only(top: 8), + child: Text( + l10n.settings_batteryFirmwareDefault( + _chemistryDisplayName(l10n, firmwareChemistry), + ), + style: TextStyle(fontSize: 12, color: Colors.grey[600]), + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(dialogContext), + child: Text(l10n.common_close), + ), + ], + ), + ); + } + + String _chemistryDisplayName(AppLocalizations l10n, String chem) { + return switch (chem) { + 'none' => l10n.appSettings_batteryNone, + 'lipo' => l10n.appSettings_batteryLipo, + 'lifepo4' => l10n.appSettings_batteryLifepo4, + 'leadacid' => l10n.appSettings_batteryLeadAcid, + _ => l10n.appSettings_batteryLipo, + }; + } + void _editLocation(BuildContext context, MeshCoreConnector connector) { final l10n = context.l10n; final latController = TextEditingController(); diff --git a/lib/services/app_settings_service.dart b/lib/services/app_settings_service.dart index c1e8fc62..ca408c3f 100644 --- a/lib/services/app_settings_service.dart +++ b/lib/services/app_settings_service.dart @@ -13,8 +13,9 @@ class AppSettingsService extends ChangeNotifier { String batteryChemistryForDevice(String deviceId) { final stored = _settings.batteryChemistryByDeviceId[deviceId]; - if (stored == 'liion') return 'nmc'; - return stored ?? 'nmc'; + // Migrate old values to new protocol + if (stored == 'liion' || stored == 'nmc') return 'lipo'; + return stored ?? 'lipo'; } Future loadSettings() async { @@ -132,4 +133,24 @@ class AppSettingsService extends ChangeNotifier { _settings.copyWith(batteryChemistryByDeviceId: updated), ); } + + String batteryChemistryForRepeater(String publicKeyHex) { + final stored = _settings.repeaterBatteryChemistryByPublicKey[publicKeyHex]; + // Migrate old values to new protocol + if (stored == 'nmc') return 'lipo'; + return stored ?? 'lipo'; + } + + Future setBatteryChemistryForRepeater( + String publicKeyHex, + String chemistry, + ) async { + final updated = Map.from( + _settings.repeaterBatteryChemistryByPublicKey, + ); + updated[publicKeyHex] = chemistry; + await updateSettings( + _settings.copyWith(repeaterBatteryChemistryByPublicKey: updated), + ); + } } diff --git a/lib/utils/battery_utils.dart b/lib/utils/battery_utils.dart new file mode 100644 index 00000000..77866493 --- /dev/null +++ b/lib/utils/battery_utils.dart @@ -0,0 +1,72 @@ +// Battery chemistry protocol values: +// 0x00 = none (no battery / external power) +// 0x01 = lipo (3.7V lithium polymer) +// 0x02 = lifepo4 (3.2V lithium iron phosphate) +// 0x03 = leadacid (12V lead acid) + +/// Returns the (minMv, maxMv) voltage range for the given battery chemistry. +/// Returns null for 'none' (no battery). +(int, int)? batteryVoltageRange(String chemistry) { + switch (chemistry) { + case 'none': + return null; // No battery + case 'lipo': + return (3000, 4200); + case 'lifepo4': + return (2600, 3650); + case 'leadacid': + return (10500, 12700); // 12V lead acid + default: + return (3000, 4200); // Default to lipo curve + } +} + +/// Estimates battery percentage from millivolts based on chemistry type. +/// Returns null for 'none' (no battery). +int? estimateBatteryPercent(int millivolts, String chemistry) { + if (chemistry == 'none') return null; + final range = batteryVoltageRange(chemistry); + if (range == null) return null; + final minMv = range.$1; + final maxMv = range.$2; + if (millivolts <= minMv) return 0; + if (millivolts >= maxMv) return 100; + return (((millivolts - minMv) * 100) / (maxMv - minMv)).round(); +} + +/// Converts chemistry byte from protocol to string identifier. +String chemistryFromByte(int byte) { + return switch (byte) { + 0x00 => 'none', + 0x01 => 'lipo', + 0x02 => 'lifepo4', + 0x03 => 'leadacid', + _ => 'lipo', // Default fallback + }; +} + +/// Power state flags parsed from protocol byte 61. +/// Bitmask: USB=0x01, Solar=0x02, Charging=0x04, Battery=0x08 +class PowerState { + static const int usbConnected = 0x01; + static const int solarConnected = 0x02; + static const int charging = 0x04; + static const int batteryPresent = 0x08; + + final int flags; + final int? inputMv; + + const PowerState(this.flags, [this.inputMv]); + + bool get isUsbConnected => (flags & usbConnected) != 0; + bool get isSolarConnected => (flags & solarConnected) != 0; + bool get isCharging => (flags & charging) != 0; + bool get isBatteryPresent => (flags & batteryPresent) != 0; + bool get hasExternalPower => isUsbConnected || isSolarConnected; + + /// Returns input voltage as a formatted string (e.g., "5.03"), or null if unavailable. + String? get inputVoltageString { + if (inputMv == null || inputMv == 0) return null; + return (inputMv! / 1000.0).toStringAsFixed(2); + } +} diff --git a/untranslated.json b/untranslated.json index 9e26dfee..92070d89 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1 +1,141 @@ -{} \ No newline at end of file +{ + "bg": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "de": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "es": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "fr": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "it": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "nl": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "pl": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "pt": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "ru": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "sk": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "sl": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "sv": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "uk": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ], + + "zh": [ + "settings_batterySettings", + "settings_batterySettingsSubtitle", + "settings_batteryType", + "settings_batteryFirmwareDefault", + "appSettings_batteryNone", + "appSettings_batteryLeadAcid", + "repeater_batteryChemistry" + ] +}