Namen leichter ändern, Oberfläche entlasten
Umbenennen war zwar möglich, aber praktisch unauffindbar: das Eingabe- feld trug nur einen Platzhalter, und übernommen wurde erst über einen zusätzlichen Knopf. Jetzt steht "Name" als Beschriftung davor, der Knopf ist weg, gesichert wird beim Abschluss der Eingabe und beim Verlassen der Ansicht. Der Funkname steht darunter als "Gefunden als", damit das Gerät weiter zuzuordnen ist. Beim Einrichten wird nicht mehr der Funkname vorgeschlagen - Namen wie "WTaEaAA25342229" taugen nicht als Anzeigename -, sondern die Art des Geräts, sofern der Funkname kryptisch wirkt. Die Detailansicht arbeitete auf einer Momentaufnahme des Geräts. Nach dem Umbenennen oder nach dem Umstellen der Kühlzonen zeigte sie deshalb weiter die alten Werte; sie liest den Stand jetzt aus dem Speicher. Gegen die träge Oberfläche: CoreBluetooth meldet jedes Advertisement einzeln und auf dem Hauptthread, und gescannt wird mit Duplikaten über alle Geräte in Reichweite. Victron sendet mehrmals je Sekunde, dazu kommt alles andere in Funkreichweite. Ausgewertet wird jetzt höchstens einmal je Sekunde und Gerät, die Geräteliste beim Einrichten alle zwei Sekunden, die Rohdaten der Diagnose alle drei. Ein Advertisement mehr ändert die Anzeige ohnehin nicht, kostet aber Entschlüsselung und eine Neuzeichnung. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -139,6 +139,22 @@ final class BluetoothManager: NSObject {
|
||||
private var pendingDiscoveries: [UUID: Discovery] = [:]
|
||||
private var discoveryFlushTimer: Timer?
|
||||
|
||||
/// Wann ein Peripheral zuletzt ausgewertet wurde.
|
||||
///
|
||||
/// CoreBluetooth meldet jedes Advertisement einzeln und auf dem
|
||||
/// Hauptthread. Victron sendet mehrmals je Sekunde, dazu kommt alles
|
||||
/// andere in Funkreichweite – auf einem Stellplatz schnell hunderte
|
||||
/// Ereignisse pro Sekunde, die der Oberfläche die Zeit zum Zeichnen
|
||||
/// nehmen. Öfter als hier festgelegt wird deshalb nichts verarbeitet.
|
||||
private var lastHandledAdvertisement: [UUID: Date] = [:]
|
||||
private let minimumAdvertisementInterval: TimeInterval = 0.9
|
||||
/// Für die Geräteliste reicht ein gröberer Takt.
|
||||
private let minimumDiscoveryInterval: TimeInterval = 2.0
|
||||
/// Die Rohdatenanzeige der Diagnose muss nicht live mitlaufen.
|
||||
private var lastDiagnosticsUpdate: [UUID: Date] = [:]
|
||||
private var lastDiscoveryUpdate: [UUID: Date] = [:]
|
||||
private let minimumDiagnosticsInterval: TimeInterval = 3.0
|
||||
|
||||
/// Wieviele Messpunkte je Gerät im Verlauf behalten werden.
|
||||
private let historyLimit = 720
|
||||
|
||||
@@ -208,6 +224,8 @@ final class BluetoothManager: NSObject {
|
||||
diagnostics = diagnostics.filter { known.contains($0.key) }
|
||||
bmsDiagnostics = bmsDiagnostics.filter { known.contains($0.key) }
|
||||
fridgeStates = fridgeStates.filter { known.contains($0.key) }
|
||||
lastHandledAdvertisement.removeAll()
|
||||
lastDiagnosticsUpdate.removeAll()
|
||||
connectManagedPeripherals()
|
||||
restartScan()
|
||||
}
|
||||
@@ -215,6 +233,7 @@ final class BluetoothManager: NSObject {
|
||||
func clearDiscoveries() {
|
||||
discoveries.removeAll()
|
||||
pendingDiscoveries.removeAll()
|
||||
lastDiscoveryUpdate.removeAll()
|
||||
}
|
||||
|
||||
private func startDiscoveryFlush() {
|
||||
@@ -337,7 +356,13 @@ final class BluetoothManager: NSObject {
|
||||
rssi: Int) {
|
||||
// Zuerst den unverschlüsselten Rahmen festhalten – gerade wenn der
|
||||
// Schlüssel nicht passt, ist das die einzige verwertbare Information.
|
||||
if let envelope = VictronAdvertisement.envelope(from: manufacturerData) {
|
||||
// Der Hex-String kostet mehr als die Auswertung selbst, deshalb nur
|
||||
// gelegentlich, und immer wenn noch gar nichts angezeigt werden kann.
|
||||
let needsDiagnostics = diagnostics[device.id] == nil
|
||||
|| Date().timeIntervalSince(lastDiagnosticsUpdate[device.id] ?? .distantPast)
|
||||
>= minimumDiagnosticsInterval
|
||||
if needsDiagnostics, let envelope = VictronAdvertisement.envelope(from: manufacturerData) {
|
||||
lastDiagnosticsUpdate[device.id] = Date()
|
||||
diagnostics[device.id] = VictronDiagnostics(
|
||||
productID: envelope.productID,
|
||||
recordType: envelope.recordType,
|
||||
@@ -445,12 +470,23 @@ extension BluetoothManager: CBCentralManagerDelegate {
|
||||
advertisementData: [String: Any],
|
||||
rssi RSSI: NSNumber) {
|
||||
let rssi = RSSI.intValue
|
||||
let now = Date()
|
||||
let identifier = peripheral.identifier
|
||||
|
||||
if isDiscovering {
|
||||
if isDiscovering,
|
||||
now.timeIntervalSince(lastDiscoveryUpdate[identifier] ?? .distantPast)
|
||||
>= minimumDiscoveryInterval {
|
||||
lastDiscoveryUpdate[identifier] = now
|
||||
updateDiscovery(peripheral: peripheral, advertisementData: advertisementData, rssi: rssi)
|
||||
}
|
||||
|
||||
guard let device = store.device(withPeripheralID: peripheral.identifier) else { return }
|
||||
guard let device = store.device(withPeripheralID: identifier) else { return }
|
||||
|
||||
// Ein Advertisement mehr ändert die Anzeige nicht, kostet aber
|
||||
// Entschlüsselung und eine Neuzeichnung.
|
||||
guard now.timeIntervalSince(lastHandledAdvertisement[identifier] ?? .distantPast)
|
||||
>= minimumAdvertisementInterval else { return }
|
||||
lastHandledAdvertisement[identifier] = now
|
||||
|
||||
switch device.role.transport {
|
||||
case .advertisement:
|
||||
|
||||
Reference in New Issue
Block a user