Kühlbox: fehlenden zweiten Fühler erkennen
Deine Diagnose hat es gezeigt. Die Box sendet 30 Byte Nutzlast, also den langen Datensatz - hat aber nur einen Fühler. Für den fehlenden zweiten meldet sie -128, den üblichen Platzhalter, und die Einstellungen der rechten Zone stehen auf lauter Nullen. Meine Erkennung hat diesen Platzhalter für einen Messwert gehalten und die Box deshalb für zweizonig gehalten. Damit ging der lange Stellbefehl raus, 31 Byte statt 20 - und den verwirft sie wortlos. Die Solltemperatur ging weiter, weil sie ein eigenes, kurzes Kommando hat und von der Zonenfrage nicht berührt wird. Genau dieses Bild stand im Bericht. Als zweite Zone gilt jetzt nur noch, wo der zweite Fühler auch wirklich misst. Für diese Box heisst das: 20 Byte, ein Schreibvorgang. Nebenbei fiel auf, dass die Anzeige eine rechte Zone mit -128 Grad geführt hat. Auch das ist damit weg. Die echte Antwort der Box steht als Prüfung im Testlauf, mitsamt der Möglichkeit, die Erkennung in den Geräteeinstellungen zu übersteuern. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+46
-6
@@ -530,13 +530,12 @@ checkEqual("leerer zweiter Block gilt nicht als zweite Zone", padded.isDualZone,
|
||||
// 20 Byte noch in einen Schreibvorgang, aus dem langen nicht mehr. Ohne
|
||||
// Aufteilen verwirft die Box ihn wortlos – genau das war der Fehler.
|
||||
checkEqual("Stellbefehl aus dem kurzen Datensatz", offBytes.count, 20)
|
||||
// Der Befehl folgt der Länge, in der die Box selbst antwortet – nicht dem,
|
||||
// was die Anzeige aus dem leeren zweiten Block macht. Eine Box, die den
|
||||
// langen Datensatz sendet, nimmt nur den langen Befehl an.
|
||||
checkEqual("langer Datensatz heisst langer Stellbefehl",
|
||||
padded.settingsCommand(poweredOn: false)?.count, 31)
|
||||
checkEqual("die Anzeige bleibt trotzdem einzonig", padded.isDualZone, false)
|
||||
// Eine Einzonen-Box, die den langen Datensatz nur auffüllt, bekommt den
|
||||
// kurzen Befehl – den langen nimmt sie nicht an.
|
||||
checkEqual("aufgefüllter Datensatz heisst trotzdem kurzer Stellbefehl",
|
||||
padded.settingsCommand(poweredOn: false)?.count, 20)
|
||||
|
||||
padded.zoneMode = .dual
|
||||
guard let longPacket = padded.settingsCommand(poweredOn: true) else {
|
||||
check("Stellbefehl aus dem langen Datensatz wird gebaut", false); exit(1)
|
||||
}
|
||||
@@ -584,6 +583,47 @@ let expectedOff = Data([
|
||||
])
|
||||
checkEqual("Ausschaltbefehl der IceCube Dual stimmt byteweise",
|
||||
iceCube.settingsCommand(poweredOn: false), expectedOff)
|
||||
// Eine echte Box aus dem Feld: 30 Byte Nutzlast, aber nur ein Fühler. Sie
|
||||
// füllt den zweiten Block mit Nullen auf und meldet für den fehlenden
|
||||
// zweiten Fühler -128. Der Stellbefehl muss trotzdem der kurze sein - der
|
||||
// lange wurde von ihr wortlos verworfen, und genau daran scheiterte das
|
||||
// Ein- und Ausschalten.
|
||||
let paddedIceCubePayload: [UInt8] = [
|
||||
0x00, // Bedienfeld frei
|
||||
0x01, // eingeschaltet
|
||||
0x01, // Eco
|
||||
0x02, // Batteriewächter hoch
|
||||
0x09, // Soll 9
|
||||
0x14, 0xEC, // Grenzen 20 / -20
|
||||
0x02, 0x00, 0x00, // Rückschaltdifferenz, Verzögerung, Celsius
|
||||
0x00, 0x00, 0xFD, 0x00, // Kompressordrehzahlen
|
||||
0x17, // Ist 23
|
||||
0x64, // 100 %
|
||||
0x0E, 0x03, // 14,3 V
|
||||
0x00, 0x00, 0x00, 0x00, // rechte Zone: nur Füllung
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x80, // kein zweiter Fühler
|
||||
0x00, // Kompressor aus
|
||||
0x01, 0x00, // was darüber hinaus kommt
|
||||
]
|
||||
var single = AlpicoolState()
|
||||
for frame in AlpicoolProtocol.extractFrames(from:
|
||||
alpicoolResponse(command: 0x01, payload: paddedIceCubePayload)).frames {
|
||||
single.apply(frame)
|
||||
}
|
||||
checkEqual("30 Byte Nutzlast werden gelesen", single.leftCurrent, 23)
|
||||
checkEqual("fehlender zweiter Fühler heisst eine Zone", single.isDualZone, false)
|
||||
checkEqual("und damit der kurze Stellbefehl",
|
||||
single.settingsCommand(poweredOn: false)?.count, 20)
|
||||
checkEqual("der in einen Schreibvorgang passt",
|
||||
AlpicoolProtocol.chunks(single.settingsCommand(poweredOn: false)!,
|
||||
limit: AlpicoolProtocol.maxWriteSize).count, 1)
|
||||
// Von Hand lässt sich die Erkennung übersteuern, falls sie danebenliegt.
|
||||
single.zoneMode = .dual
|
||||
checkEqual("von Hand erzwungen wird er wieder lang",
|
||||
single.settingsCommand(poweredOn: false)?.count, 31)
|
||||
single.zoneMode = .automatic
|
||||
|
||||
// Ob ein Stellbefehl gewirkt hat, wird an den Einstellungsbytes abgelesen -
|
||||
// nicht an den Messwerten, die ohnehin schwanken.
|
||||
let fingerprintBefore = iceCube.settingsFingerprint
|
||||
|
||||
Reference in New Issue
Block a user