import Foundation /// VotronicSolarESP – zweiter ESP32 im Fahrzeug, liest einen /// Votronic-Solarladeregler aus und stellt die Werte über einen eigenen /// BLE-Dienst bereit. Siehe `firmware/vanalign/esp32_ble_solar.yaml`. /// /// Wie beim Neigungsmesser: kein Rahmenprotokoll, jede Messgrösse liegt in /// einer eigenen Charakteristik, alle sind reine Lesewerte, der Client fragt /// sie im Takt ab. enum VotronicSolarESPProtocol { /// Wird vom Gerät beworben, das Gerät ist darüber auffindbar. static let serviceUUID = "05C9A349-2B8E-4B1D-9C9D-C247E9A6A001" static let batteryVoltageUUID = "05C9A349-2B8E-4B1D-9C9D-C247E9A6A101" static let pvVoltageUUID = "05C9A349-2B8E-4B1D-9C9D-C247E9A6A102" static let pvCurrentUUID = "05C9A349-2B8E-4B1D-9C9D-C247E9A6A103" static let pvPowerUUID = "05C9A349-2B8E-4B1D-9C9D-C247E9A6A104" static let controllerTempUUID = "05C9A349-2B8E-4B1D-9C9D-C247E9A6A105" /// Bit0 Batterie lädt, Bit1 Batterie entlädt, Bit2 PV-Regler aktiv, /// Bit3 PV-Strombegrenzung, Bit4 AES aktiv. static let statusFlagsUUID = "05C9A349-2B8E-4B1D-9C9D-C247E9A6A106" /// Liest einen Messwert aus vier Bytes, little-endian – wie beim /// Neigungsmesser legt die Firmware den Float per `memcpy` ab. static func float(from data: Data) -> Double? { guard data.count >= 4 else { return nil } var raw: UInt32 = 0 for (index, byte) in data.prefix(4).enumerated() { raw |= UInt32(byte) << UInt32(8 * index) } let value = Float(bitPattern: raw) guard value.isFinite else { return nil } return Double(value) } struct StatusFlags { var isBatteryCharging = false var isBatteryDischarging = false var isControllerActive = false var isCurrentLimited = false var isAESActive = false } static func statusFlags(from data: Data) -> StatusFlags? { guard let byte = data.first else { return nil } var flags = StatusFlags() flags.isBatteryCharging = byte & (1 << 0) != 0 flags.isBatteryDischarging = byte & (1 << 1) != 0 flags.isControllerActive = byte & (1 << 2) != 0 flags.isCurrentLimited = byte & (1 << 3) != 0 flags.isAESActive = byte & (1 << 4) != 0 return flags } }