Kühlbox: Zonen richtig erkennen, Stellbefehle nicht mehr abschneiden
Zwei Fehler am Gerät gefunden. Einzonen-Boxen als Doppelzone erkannt: Manche senden den langen Datensatz einer Zweizonen-Box mit, füllen den zweiten Block aber mit Nullen. Die Nutzlastlänge allein taugt deshalb nicht als Kriterium. Als zweizonig gilt jetzt nur, wo dieser Block überhaupt Inhalt hat, und in den Geräteeinstellungen lässt sich die Erkennung auf "Eine Zone" oder "Zwei Zonen" festnageln. Einschalten reagierte nicht: Ein/Aus und Betriebsart schicken den kompletten Einstellungsblock, der mit dem langen Datensatz auf 31 Byte kommt. Ohne ausgehandelte MTU nimmt BLE aber nur 20 Nutzbytes je Schreibvorgang an, der Rest wurde stillschweigend verworfen. Die Solltemperatur ging als kurzes Paket durch, alles Längere nicht. Lange Pakete werden jetzt anhand von maximumWriteValueLength aufgeteilt und versetzt geschrieben; die Statusabfrage danach wartet entsprechend länger. Aus dem kurzen Datensatz ist der Befehl übrigens genau 20 Byte groß und hätte gerade noch gepasst - deshalb trat es nur an dieser Box auf. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -81,6 +81,10 @@ final class BMSSession: NSObject {
|
||||
private var jbdState = JBDState()
|
||||
private var wattCycleState = WattCycleState()
|
||||
private(set) var alpicoolState = AlpicoolState()
|
||||
/// Aus den Geräteeinstellungen; übersteuert die automatische Erkennung.
|
||||
var fridgeZoneMode: FridgeZoneMode = .automatic {
|
||||
didSet { alpicoolState.zoneMode = fridgeZoneMode }
|
||||
}
|
||||
/// Ob die Kühlbox in dieser Sitzung schon angemeldet wurde.
|
||||
private var didBind = false
|
||||
private var buffer: [UInt8] = []
|
||||
@@ -372,7 +376,27 @@ final class BMSSession: NSObject {
|
||||
guard let endpoint = currentEndpoint, peripheral.state == .connected else { return }
|
||||
sentFrameCount += 1
|
||||
lastSendAt = Date()
|
||||
peripheral.writeValue(data, for: endpoint.write, type: endpoint.writeType)
|
||||
|
||||
// Was in einen Schreibvorgang passt, hängt an der ausgehandelten MTU.
|
||||
// Längeres muss aufgeteilt werden, sonst verwirft das Gerät es
|
||||
// wortlos – der Einstellungsblock einer Kühlbox ist so ein Fall.
|
||||
let limit = peripheral.maximumWriteValueLength(for: endpoint.writeType)
|
||||
let pieces = AlpicoolProtocol.chunks(data, limit: limit)
|
||||
|
||||
for (index, piece) in pieces.enumerated() {
|
||||
guard index > 0 else {
|
||||
peripheral.writeValue(piece, for: endpoint.write, type: endpoint.writeType)
|
||||
continue
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(
|
||||
deadline: .now() + Double(index) * AlpicoolProtocol.chunkDelay
|
||||
) { [weak self] in
|
||||
guard let self, self.peripheral.state == .connected,
|
||||
let current = self.currentEndpoint else { return }
|
||||
self.peripheral.writeValue(piece, for: current.write, type: current.writeType)
|
||||
}
|
||||
}
|
||||
|
||||
// Sofort melden, sonst sieht die Diagnose sekundenlang nach Stillstand
|
||||
// aus, obwohl gerade gesucht wird.
|
||||
publishDiagnostics()
|
||||
@@ -384,7 +408,8 @@ final class BMSSession: NSObject {
|
||||
/// die Anzeige dem Gerät folgt statt der Vermutung.
|
||||
func sendControl(_ packet: Data) {
|
||||
send(packet)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { [weak self] in
|
||||
// Genug Abstand, damit ein aufgeteiltes Paket vollständig draußen ist.
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
|
||||
guard let self, self.dialect == .alpicool else { return }
|
||||
self.send(AlpicoolProtocol.packet(.query))
|
||||
}
|
||||
@@ -403,6 +428,7 @@ final class BMSSession: NSObject {
|
||||
buffer = fridgeRemainder
|
||||
adopt(.alpicool)
|
||||
for frame in fridgeFrames { alpicoolState.apply(frame) }
|
||||
alpicoolState.zoneMode = fridgeZoneMode
|
||||
onFridgeState?(alpicoolState)
|
||||
publish(alpicoolState.snapshot(deviceID: deviceID, rssi: nil),
|
||||
usable: alpicoolState.hasStatus)
|
||||
|
||||
Reference in New Issue
Block a user