From d651b297c93ff1c9ab2f9c05f68e3ff22eaebedf Mon Sep 17 00:00:00 2001 From: decodism Date: Fri, 22 Sep 2023 19:14:05 +0200 Subject: [PATCH] Add max energy --- BatFiKit/Sources/AppShared/Formatters.swift | 32 +++++++++++++++++++ BatFiKit/Sources/AppShared/PowerState.swift | 7 ++-- .../Sources/BatteryInfo/BatteryInfoView.swift | 4 +++ .../ClientsLive/PowerSourceClient.swift | 14 +++++++- BatFiKit/Sources/L10n/Localizable.xcstrings | 22 +++++++++++++ BatFiKit/Sources/L10n/Strings.swift | 8 +++++ 6 files changed, 84 insertions(+), 3 deletions(-) diff --git a/BatFiKit/Sources/AppShared/Formatters.swift b/BatFiKit/Sources/AppShared/Formatters.swift index 4223d4a..2301aa2 100644 --- a/BatFiKit/Sources/AppShared/Formatters.swift +++ b/BatFiKit/Sources/AppShared/Formatters.swift @@ -6,6 +6,7 @@ // import Foundation +import L10n public let timeFormatter: DateComponentsFormatter = { let formatter = DateComponentsFormatter() @@ -31,3 +32,34 @@ public let percentageFormatter: NumberFormatter = { formatter.maximumFractionDigits = 0 return formatter }() + +public let energyFormatter: MeasurementFormatter = { + let formatter = CustomMeasurementFormatter() + formatter.unitOptions = .providedUnit + formatter.unitStyle = .short + let numberFormatter = NumberFormatter() + numberFormatter.numberStyle = .decimal + numberFormatter.minimumFractionDigits = 3 + numberFormatter.maximumFractionDigits = 3 + formatter.numberFormatter = numberFormatter + return formatter +}() + +private class CustomMeasurementFormatter: MeasurementFormatter { + override func string(from measurement: Measurement) -> String { + var string = super.string(from: measurement) + if unitStyle == .short { + if string.count >= measurement.unit.symbol.count + 2 { + let index = string.index(string.endIndex, offsetBy: -(measurement.unit.symbol.count + 1)) + if string[index].isWhitespace { + string.remove(at: index) + } + } + } + return string + } +} + +public extension UnitEnergy { + static let wattHours = UnitEnergy(symbol: L10n.UnitEnergy.Symbol.wattHours, converter: UnitConverterLinear(coefficient: 3600)) +} diff --git a/BatFiKit/Sources/AppShared/PowerState.swift b/BatFiKit/Sources/AppShared/PowerState.swift index 63a8d51..3f7fc62 100644 --- a/BatFiKit/Sources/AppShared/PowerState.swift +++ b/BatFiKit/Sources/AppShared/PowerState.swift @@ -18,6 +18,7 @@ public struct PowerState: CustomStringConvertible, Equatable { public let batteryTemperature: Double public let chargerConnected: Bool public let optimizedBatteryChargingEngaged: Bool + public let batteryMaxEnergy: Double public init( batteryLevel: Int, @@ -29,7 +30,8 @@ public struct PowerState: CustomStringConvertible, Equatable { batteryCapacity: Double, batteryTemperature: Double, chargerConnected: Bool, - optimizedBatteryChargingEngaged: Bool + optimizedBatteryChargingEngaged: Bool, + batteryMaxEnergy: Double ) { self.batteryLevel = batteryLevel self.isCharging = isCharging @@ -41,11 +43,12 @@ public struct PowerState: CustomStringConvertible, Equatable { self.batteryTemperature = batteryTemperature self.chargerConnected = chargerConnected self.optimizedBatteryChargingEngaged = optimizedBatteryChargingEngaged + self.batteryMaxEnergy = batteryMaxEnergy } public var description: String { """ -PowerState |==> is charging: \(isCharging), battery level: \(batteryLevel), power source: \(powerSource), time left: \(timeLeft), time to charge: \(timeToCharge), cycle count: \(batteryCycleCount), battery capacity: \(batteryCapacity), battery temperature: \(batteryTemperature)°C, charger connected: \(chargerConnected), optimized battery charging engaged: \(optimizedBatteryChargingEngaged) +PowerState |==> is charging: \(isCharging), battery level: \(batteryLevel), power source: \(powerSource), time left: \(timeLeft), time to charge: \(timeToCharge), cycle count: \(batteryCycleCount), battery capacity: \(batteryCapacity), battery temperature: \(batteryTemperature)°C, charger connected: \(chargerConnected), optimized battery charging engaged: \(optimizedBatteryChargingEngaged), battery max energy: \(batteryMaxEnergy)Wh """ } } diff --git a/BatFiKit/Sources/BatteryInfo/BatteryInfoView.swift b/BatFiKit/Sources/BatteryInfo/BatteryInfoView.swift index 06b4ecd..f62d6ac 100644 --- a/BatFiKit/Sources/BatteryInfo/BatteryInfoView.swift +++ b/BatFiKit/Sources/BatteryInfo/BatteryInfoView.swift @@ -56,6 +56,10 @@ public struct BatteryInfoView: View { label: l10n.Additional.batteryCapacity, info: percentageFormatter.string(from: NSNumber(floatLiteral: powerState.batteryCapacity))! ) + BatteryAdditionalInfo( + label: l10n.Additional.fullChargeEnergy, + info: energyFormatter.string(from: Measurement(value: powerState.batteryMaxEnergy, unit: UnitEnergy.wattHours)) + ) } .frame(maxWidth: .infinity) } diff --git a/BatFiKit/Sources/ClientsLive/PowerSourceClient.swift b/BatFiKit/Sources/ClientsLive/PowerSourceClient.swift index 2d4860c..9bad4f7 100644 --- a/BatFiKit/Sources/ClientsLive/PowerSourceClient.swift +++ b/BatFiKit/Sources/ClientsLive/PowerSourceClient.swift @@ -165,6 +165,17 @@ private func getPowerSourceInfo() throws -> PowerState { throw PowerSourceError.infoMissing } let batteryHealth = Double(maxCapacity) / Double(designCapacity) + + guard + let batteryData: [String: Any] = getValue("BatteryData", from: service), + let lifetimeData = batteryData["LifetimeData"] as? [String: Any], + let minimumPackVoltage = lifetimeData["MinimumPackVoltage"] as? Int, + let maximumPackVoltage = lifetimeData["MaximumPackVoltage"] as? Int + else { + throw PowerSourceError.infoMissing + } + let midVoltage = ((Double(minimumPackVoltage) / 1000) + (Double(maximumPackVoltage) / 1000)) / 2 + let maxEnergy = (Double(maxCapacity) / 1000) * midVoltage let powerState = PowerState( batteryLevel: batteryLevel, @@ -176,7 +187,8 @@ private func getPowerSourceInfo() throws -> PowerState { batteryCapacity: batteryHealth, batteryTemperature: batteryTemperature, chargerConnected: chargerConnected, - optimizedBatteryChargingEngaged: optimizedBatteryCharging + optimizedBatteryChargingEngaged: optimizedBatteryCharging, + batteryMaxEnergy: maxEnergy ) return powerState } diff --git a/BatFiKit/Sources/L10n/Localizable.xcstrings b/BatFiKit/Sources/L10n/Localizable.xcstrings index 15589ef..cb5bbf3 100644 --- a/BatFiKit/Sources/L10n/Localizable.xcstrings +++ b/BatFiKit/Sources/L10n/Localizable.xcstrings @@ -494,6 +494,17 @@ } } }, + "battery_info.label.additional.full_charge_energy" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Full Charge Energy" + } + } + } + }, "battery_info.label.additional.power_source" : { "extractionState" : "extracted_with_value", "localizations" : { @@ -3026,6 +3037,17 @@ } } } + }, + "unit_energy.symbol.watt_hours" : { + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Wh" + } + } + } } }, "version" : "1.0" diff --git a/BatFiKit/Sources/L10n/Strings.swift b/BatFiKit/Sources/L10n/Strings.swift index f49cc82..0da7e3e 100644 --- a/BatFiKit/Sources/L10n/Strings.swift +++ b/BatFiKit/Sources/L10n/Strings.swift @@ -82,6 +82,8 @@ public enum L10n { public static let powerSource = String(localized: "battery_info.label.additional.power_source", defaultValue: "Power Source", bundle: Bundle.module) /// Temperature public static let temperature = String(localized: "battery_info.label.additional.temperature", defaultValue: "Temperature", bundle: Bundle.module) + /// Full Charge Energy + public static let fullChargeEnergy = String(localized: "battery_info.label.additional.full_charge_energy", defaultValue: "Full Charge Energy", bundle: Bundle.module) } public enum Main { /// Battery @@ -375,4 +377,10 @@ public enum L10n { } } } + public enum UnitEnergy { + public enum Symbol { + /// Wh + public static let wattHours = String(localized: "unit_energy.symbol.watt_hours", defaultValue: "Wh", bundle: Bundle.module) + } + } }