import Foundation /// Welche Rolle ein Gerät im Camper spielt. Bestimmt Icon, Sortierung und /// welche Kennzahl als "Hauptwert" auf der Kachel gross dargestellt wird. enum DeviceRole: String, Codable, CaseIterable, Identifiable, Sendable { //case chargeBooster //case batteryMonitor //case bms //case fridge case leveling case solar var id: String { rawValue } var title: String { switch self { //case .chargeBooster: return "Ladebooster" //case .batteryMonitor: return "Batteriemonitor" //case .bms: return "Batterie / BMS" //case .fridge: return "Kühlbox" case .leveling: return "Nivellierung" case .solar: return "Solarladeregler" } } var symbol: String { switch self { //case .chargeBooster: return "bolt.car" //case .batteryMonitor: return "gauge.with.dots.needle.bottom.50percent" //case .bms: return "battery.100percent.bolt" //case .fridge: return "refrigerator" case .leveling: return "level" case .solar: return "sun.max" } } /// Es gibt keine Geräte mehr, die nur auf Anforderung verbunden werden – /// der Neigungsmesser bleibt immer verbunden. var connectsOnDemand: Bool { false } /*/// Ob nur verbunden wird, während die Ansicht des Geräts offen ist. /// /// Die Kühlbox meldet jede Verbindung an ihrem Display an und verlangt je /// nach Modell sogar einen Tastendruck; dauerhaft verbunden zu sein ist /// dort also nicht unsichtbar, sondern lästig. Ihre Werte ändern sich /// ausserdem langsam, und was auf der Übersicht zählt – der Sollwert – /// ändert sich überhaupt nur, wenn jemand ihn ändert. /// /// BMS und Neigungsmesser bleiben dagegen verbunden: Sie stören nicht, und /// ihre Werte will man laufend sehen. var connectsOnDemand: Bool { self == .fridge }*/ /// Der Neigungsmesser braucht eine echte GATT-Verbindung, um Werte zu liefern. var transport: DeviceTransport { return .connect } /*/// Victron-Geräte werden passiv über das Advertisement gelesen, das Daly BMS /// braucht eine echte GATT-Verbindung. var transport: DeviceTransport { switch self { case .bms, .fridge, .leveling: return .connect default: return .advertisement } }*/ } enum DeviceTransport: Sendable { /// Passives Mitlesen der BLE-Werbedaten (Victron Instant Readout). case advertisement /// Verbindungsaufbau, Kommando schreiben, Antwort per Notify lesen (Daly). case connect } /*/// Wie viele Kühlzonen eine Box hat. Manche Einzonen-Boxen senden den langen /// Datensatz einer Doppelzonen-Box mit, weshalb die Erkennung übersteuerbar ist. enum FridgeZoneMode: String, Codable, CaseIterable, Identifiable, Sendable { case automatic case single case dual var id: String { rawValue } var title: String { switch self { case .automatic: return "Automatisch" case .single: return "Eine Zone" case .dual: return "Zwei Zonen" } } }*/ /// Ein vom Nutzer eingerichtetes Gerät. Der Victron-Schlüssel liegt nicht hier, /// sondern in der Keychain (siehe `KeychainStore`). struct ConfiguredDevice: Identifiable, Codable, Hashable, Sendable { var id: UUID var name: String var role: DeviceRole /// Zu welchem Fahrzeug das Gerät gehört. var profileID: UUID /// CoreBluetooth-Identifier des Peripherals. Pro iPhone stabil, aber nicht /// geräteübergreifend – deshalb wird beim Einrichten neu gescannt. var peripheralID: UUID /// Zuletzt gesehener Advertised Name, nur zur Wiedererkennung in der UI. var advertisedName: String? /// Nur für Kühlboxen. //var fridgeZoneMode: FridgeZoneMode = .automatic /// Nur für den Neigungsmesser: wie er im Fahrzeug sitzt. var sensorOrientation = SensorOrientation.identity init(id: UUID = UUID(), name: String, role: DeviceRole, profileID: UUID, peripheralID: UUID, advertisedName: String? = nil) { self.id = id self.name = name self.role = role self.profileID = profileID self.peripheralID = peripheralID self.advertisedName = advertisedName } /// Geräte, die vor der Profilverwaltung angelegt wurden, haben noch keine /// Zuordnung – die landen im Standardprofil. init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) id = try container.decode(UUID.self, forKey: .id) name = try container.decode(String.self, forKey: .name) role = try container.decode(DeviceRole.self, forKey: .role) profileID = try container.decodeIfPresent(UUID.self, forKey: .profileID) ?? Profile.defaultID peripheralID = try container.decode(UUID.self, forKey: .peripheralID) advertisedName = try container.decodeIfPresent(String.self, forKey: .advertisedName) //fridgeZoneMode = try container.decodeIfPresent(FridgeZoneMode.self, forKey: .fridgeZoneMode) // ?? .automatic sensorOrientation = try container.decodeIfPresent(SensorOrientation.self, forKey: .sensorOrientation) ?? .identity } }