home     Inhaltsverzeichnis
erste Version am 07.10.2017
letzte Änderung am 15.10.2017

Zirkulationspumpen-Steuerung - Seite 6


Firmware V1 - Fortsetzung

Endlich wieder Wochenende. In der vergangenen Woche hatte ich nach Feierabend einfach keinen Nerv mehr, mich auch dann noch mit Computern [im Allgemeinen] zu befassen
Meine jetzige Entwicklungs-Hardware besteht wieder aus einem WeMos-D1-Mini, an dem ein RTC-Modul und vier DS18B20-Sensoren angeschlossen sind. Damit lässt sich eine neue Firmware-Version schlicht und ergreifend einfacher auf den ESP8266-12E hochladen, als mit meinem Programmier-Board (bei dem der Hochlade-Modus immer mit zwei Tastern eingeleitet werden muss).

Der Python-SocketServer kennt mittlerweile die folgenden Kommandos:

Kommando
Parameter
Rückgabe
Bemerkungen
"GET_TIME"
-
Ortszeit als String
Format: "YYYY.MM.DD hh:mm:ss"
"SSID.n="
"<ssid>"
"OK" oder "NEW,<ssid>"
n=["1", "2", "3"]
"SOCKSRV_IPADR.n=" "<xxx.xxx.xxx.xxx>"
"OK" oder "NEW,xxx.xxx.xxx.xxx" n=["1", "2"]
"SOCKSRV_PORT.n=" "<portnummer>"
"OK" oder "NEW,yyyyy" n=["1", "2"]
"SENSORS="
"<adr>,<adr>,<adr>,<adr>" "BAD" oder "ELZR"
"ELZR" oder "LEZR" oder ....
"GET_POWER_ON_BITMAP" -
Bitmap in der Länge von 252 Byte
"GET_SYNC_TIMES" -
String in der Länge 20 für 10 Zeiten (hh:mm)
"GET_THRESHOLDS" -
String in der Länge 16 16 8-bittige Zahlen
"SENSORHOUR.hh="
"4 Byte, binärer Timestamp" +
"60*7 Byte, binäre Sensordaten"
"OK" hh in [00-23]
"INFO="
<data>
"OK"
schreibt <data> ins Log

Die Firmware enthält ebenfalls entsprechende Funktionen, um diese Kommandos zu verarbeiten, die internen Variablen zu setzen und sie bei Änderung ins EEPROM zu kopieren.
Auf Python-Seite werden die anfragbaren Daten in statischen Variablen gehalten, die gemeldeten Temperaturen werden in eine Datenbank geschrieben (die kompatibel zu LoggerView ist).

Weil es jetzt mehr als eine Sync-Zeit pro Tag geben kann, funktioniert die hier angedachte Logik nicht mehr. Ziel soll sein, dass zu jeder Sync-Zeit einmalig mit dem SocketServer synchronisiert wird. War ein Sync nicht erfolgreich, soll es fünf Minuten später erneut probiert werden. Vielleicht so:

setup()
   nextSync=0
blockSync=0
loop() sysTime=now()
über alle SyncZeiten(h, m): wenn hour(sysTime)==h && minute(sysTime)==m && sysTime>blockSync: nextSync=sysTime blockSync=sysTime+60 break
wenn nextSync!=0 && sysTime>=nextSync: if(sync()) // wenn Sync erfolgreich war nextSync=0 else nextSync+=5*60 // +5 Minuten
Das setzt zwar voraus, dass loop() mindestens einmal pro Minute durchlaufen wird - aber das sollte ja gewährleistet sein.

Somit brauche ich jetzt nur noch die Steuerlogik in loop().
Also speziell die Temperatur-abhängige Schaltung der Pumpe.
Und die Ansteuerung der LEDs.

Jetzt muss ich wohl zunächst die mal die ganzen Temperatur-Schaltregeln zusammensammeln, die ich mir auf den vorigen Seiten immer mal wieder neu überlegt habe. Und konsolidieren. Und gegen die Daten prüfen, die der andere WeMos in den letzten zwei Wochen gesammelt hat.
  1. eine minimale Einschaltdauer könnte Sinn machen, besser wäre aber wohl eine entsprechende Hysterese zwischen den Ein/Aus-Bedingungen
  2. Pumpe ein, wenn das Bit in der Schaltzeiten-Bitmap für den aktuellen 5-Minuten-Block gesetzt ist
  3. Pumpe ein, wenn (E>5256°C or L>60°C) - Legionellen-Funktion der Heizung läuft
  4. Pumpe aus, wenn Z>52°C und Legionellen-Funktion erkannt worden war
  5. Pumpe aus, wenn bei erkannter Legionellen-Funktion bereits seit zwei Stunden gepumpt wurde
  6. Pumpe trotz gesetzten Bitmap-Bit nicht ein, wenn (Z>45°C and E<52°C)
Punkt 2. steht nicht in Frage. Damit wird auch gleichzeitig eine minimale Einschaltdauer von fünf Minuten sichergestellt. Ausschalten erst wieder, wenn das Bit für die aktuelle Zeit nicht mehr gesetzt ist und zusätzlich Z>45°C meldet. Das wäre dann der Normal-Betrieb.
Wird 3. erkannt, muss die Pumpe auch unabhängig vom Schaltzeiten-Bit eingeschaltet werden. Die Mindest-Einschaltdauer beträgt eine Stunde. Meldet nach dieser Stunde Z>52°C, wird abgeschaltet. Spätestens nach einer weiteren Stunde wird ebenfalls abgeschaltet. Danach ist die Legionellen-Erkennung in beiden Fällen für den aktuellen Tag zu sperren.
Also formal etwa:
setup():
   leg_mode=0
leg_time=0 leg_date=0 loop(): wenn Einschalt-Bit für aktuelle Zeit gesetzt: Pumpe einschalten bzw. eingeschaltet lassen sonst: wenn leg_mode==0 && Z>45°C: Pumpe ausschalten wenn now()>leg_date && (E>56°C || L>60°C): Pumpe einschalten leg_mode=1 leg_time=now()+60*60 [Sek.] leg_date=now()+60*60*24 [Sek.] wenn leg_mode==1 && now()>leg_time && Z>52°C: leg_mode=0 Pumpe ausschalten wenn leg_mode==1 && now()>(leg_time+60*60 [Sek.]): leg_mode=0 Pumpe ausschalten

So. Es war etwa Sa. 20:30 Uhr, als ich die Schaltung erstmalig (temporär) in Betrieb genommen habe.
Einiges an Fehlerbehandlung ist derzeit zwar bestenfalls als Kommentar in der Firmware ... aber was solls. Testen tut schließlich not.

War aber nicht für lange. Es ist noch DebugCode aktiv gewesen, der bei der Schaltung für Sensor-Zuordnungs-Verwirrung gesorgt hat.
Die relevante Stelle war schnell gefunden und auskommentiert. Aber nachdem ich die Sensoren nun eh vom jeweiligen Rohr entfernt hatte, habe ich gleich alle vier Sensoren neu identifiziert.
Das war um 21:11 Uhr und sah so aus:
Screenshot von LoggerView für die Sensor-Zuordnung

Die vier Blips zwischen 21:19 und 21:29 Uhr sind durch "Sensor in die Hand nehmen" entstanden und dienten der Sensor-Zuordnung bzw. -Identifizierung.
Um 21:51 Uhr habe ich einen Test der Legionellen-Funktions-Erkennung mit einem Feuerzeug an Sensor(E) durchgeführt.

Um 22:07 Uhr war die Schaltung samt Sensoren wieder im Heizungsraum.
Gegen 22:15 Uhr hatten die Sensoren die Rohr-Temperaturen angenommen.
Die Pumpe wurde über die Einschalt-Bitmap um 22:30 und um 23:00 Uhr eingeschaltet und jeweils wieder ausgeschaltet, als die Temperatur an Sensor(Z) 45°C überschritten hatte.


die ersten neun Stunden produktiv

Das hier sind die Daten der ersten neun Stunden des heutigen Tages:
Screenshot LoggerView: die erste Nacht und der Morgen

Und hier der Ausschnitt vom ersten Teil des ersten Arbeitstages der Schaltung:
Screenshot von LoggerView: Meine Zirkulationspumpen-Steuerung hat den ersten Morgen gearbeitet

Die eingestellten Schaltzeiten waren: 06:00, 06:30, 07:00, 07:30, 08:00 und 08:30 Uhr.
Genau so habe ich mir das vorgestellt. Damit dürfte ich jetzt auch auf eine mittlere Leistungsaufnahme von ca. 5W über einen gesamten Tag kommen. Dafür könnte die Pumpe somit 1/5 der Zeit laufen.
Die Leistungsaufnahme der Schaltung im Leerlauf liegt bei 0.2W, mit eingeschaltetem Relais bei 0.8W.
Das ergäbe (4*0.2W+0.8W)/5=0.32W mittlere Stromaufnahme für meine Schaltung. Geschenkt.
Folglich wäre das ursprüngliche Ziel bereits jetzt erreicht. Und ich bekomme zusätzlich sogar eine Temperatur-Statistik.

Ärgerlicherweise habe ich heute morgen den Sync um 09:00 Uhr verpasst. Die gestern testhalber eingestellten Sync-Zeiten lauten:
syncTimes=[ ( 22,  15),     # 03:15 / 255 für "ungültig"
            ( 22,  20),     # die Anzahl der Elemente muss zu NUMBER_SYNCTIMES in der FW passen!
            ( 22,  30),
            (  3,  15),
            ( 22,  40),
            ( 22,  50),
            ( 25,  40),
            (  7,   0),
            (  8,   0),
            (  9,   0) ]
Hätte ich kurz vor 09:00 Uhr im SocketServer noch eine Sync-Zeit von z.B. 12:00 Uhr eingestellt, hätte die Schaltung diese beim Sync um 09:00 Uhr empfangen und ich könnte heute ggf. noch Parameter anpassen oder jüngere Temperatur-Daten sehen.
So muss ich nun bis 22:15 Uhr warten, bis der nächste Sync erfolgt.
Natürlich könnte ich den Reset-Button der Schaltung betätigen, würde dann jedoch die seit 09:00 Uhr gesammelten Temperatur-Daten verlieren.
Es könnte nicht schaden, noch einen Sonder-Sync-Taster (analog zu meinen Loggern) nachzurüsten. Die GPIOs 0, 2, 4, 5, 12, 13 und 14 sind bereits vergeben. Blieben GPIO 15 und 16. Oder auch der ADC-Pin.

Weil ich jetzt erstmal eh nicht weitermachen kann, hier das Archiv mit dem Firmware-Sourcecode und hier der Python-SocketServer in der derzeit halbfertigen Version.
Leider wird sich die Finalisierung der Firmware in nächster Zeit ziemlich ziehen, weil ich mindestens die folgenden vier Wochen komplett auf Dienstreise sein werde.


sonderbare Dinge geschehen

Ich habe dann doch auf die Daten ab 09:00 Uhr verzichtet und einen Reset ausgelöst. Schließlich muss der WLAN-Router hier im Keller nicht dauerhaft eingeschaltet sein. Der war nämlich primär für den ersten WeMos-D1-Mini unter Strom, der alle fünf Sekunden seine Daten loswerden wollte (meine anderen beiden Router rebooten sich jede Nacht kurz nach 03:00 Uhr).
Und der Test, wie gut und zuverlässig der Connect mit dem Router im Wohnzimmer klappt, stand noch aus. Wenn ich dann aber ab morgen (um 04:30 Uhr) für den Rest der Woche nicht mehr da bin, hätte ich ein ungutes Gefühl, den Rest der Familie hier mit einer ungetesteten Konfiguration alleine zu lassen. Das könnte sich wieder negativ auf die Wasser-Rechnung auswirken.

Der Connect am Wohnzimmer-Router klappt zwar problemlos, aber nebenbei habe ich dann festgestellt, dass sich die Schaltung im Heizungsraum anders verhält, als hier im Büro.
Bei einem Warmstart im Heizungsraum werden die Sensoren nicht erkannt. Trage ich die Schaltung vom Büro in den Heizungsraum, klappt erstmal alles. Löse ich dann aber nach ein paar Minuten einen Reset aus, kommt der ESP8266-12E zwar hoch und macht seinen WLAN-Connect - meldet dabei allerdings Null erkannte Sensoren.

Als Folge-Test habe ich ein Verlängerungskabel genommen und die Schaltung darüber von außerhalb des Heizungsraums versorgt. Damit möchte ich herausfinden, ob es nun an der Wärme im Raum liegt oder ob es daran liegt, dass die 230V im Heizungsraum irgendwie schmutzig sind.

Laut Datenblatt vom ds18b20 sind Schreib/Lese-Zugriffe auf das integrierte EEPROM nur bis +55°C spezifiziert. Andererseits gilt für den Baustein an sich -55°C bis +125°C. Außerdem steigt die Temperatur ja nur Montags bei der Legionellen-Funktion an maximal zwei Sensoren über +55°C.

Mit "Strom von außen" sieht es erstmal besser aus. So ein Mist. Ein zusätzlicher Kondensator könnte helfen. Den Kondensator hinter dem 3.3V-Regler habe ich aber bewusst klein gewählt, weil ich bei meinem Programmier-Board mit 100µF Reset-Probleme festgestellt hatte. Möglicherweise wäre ein 2200µF Elko vor dem Regler eine Option.
Wie unerfreulich. Nun passiert genau das, was ich eigentlich dringlichst vermeiden wolle: ich muss mich ständig an der Heizung vorbei-zwängen, um irgendwas an der Schaltung rumtüdern zu können.

Ebenfalls denkbar wäre, die Sensor-Adressen im EEPROM abzulegen und sie immer, wenn vom discoverOneWireDevices() keine Sensoren erkannt wurden, aus dem EEPROM zu laden. Das könnte zwar ein Workaround sein, jedoch will ich lieber der Ursache auf die Spur kommen.

Es verhärtet sich der Verdacht, dass die Betätigung des Reset-Tasters im Heizungsraum zu Sensor-Erkennungs-Problemen führt, ein echtes stromlos-machen der Schaltung hingegen nicht diesen Effekt hat. Damit wäre es kein dramatisches Problem, weil ein Stromausfall ja dazu führen würde, dass die Schaltung zeitweilig stromlos ist.
Aber warum ist das hier im Büro nicht passiert?

Okay, beim Betätigen des Reset-Tasters werden die ds18b20 nicht zurückgesetzt, beim PowerOn machen sie zwangsläufig einen Neustart. Ohne ihre Adresse zu kennen, kann ich sie über den OneWire-Bus nicht ansprechen - um ihnen z.B. einen Reset-Befehl schicken zu können. Also könnte ich sie bestenfalls mittels Hardware zum Reset zwingen. Zum Beispiel, in dem ich ihnen die Versorgungsspannung nähme. Und zwar einfach dadurch, dass sie ihr Vcc aus einem GPIO des ESP8266-12E bekämen.
Aber wie grauenvoll wird denn der Test von so einem Umbau werden....!? Das Problem tritt nur im Heizungsraum auf. Und offenbar auch nur dann, wenn sämtliche Komponenten der Schaltung bereits die dort vorherrschende Temperatur angenommen haben.
Unabhängig davon bin ich nicht wirklich überzeugt, dass dieser Umbau das Problem behebt. Warum sollte sich ein warmer ds18b20 nicht mehr discovern lassen, wenn er es in kaltem Zustand problemlos tut?

Eben habe ich die Firmware insofern erweitert, dass bei Null erkannten Sensoren die vier Adressen der jetzigen ds18b20 nach ROMcode_g[] kopiert werden. Beim Dummy-Read wird jetzt zusätzlich geprüft, ob valide Daten vom jeweils adressierten Sensor zurückgeliefert wurden - also quasi, ob er [noch] existent ist. Beides ("manuelle Adressen gesetzt" und "Sensor nicht existent") führt zu einer Meldung an den SocketServer innerhalb des doFullSync().
Und natürlich kam es, wie es kommen musste: Die Schaltung hat sauber gestartet und alle Sensoren erkannt. Ebenso ist ein fünf Minuten später ausgelöster Reset sauber durchgelaufen. Man möchte brechen.

Nun habe ich noch dafür gesorgt, dass zwischendurch mal die Pumpe eingeschaltet wird und habe dann einen Reset ausgelöst. Ergebnis wie zuvor: alles klappt sauber ohne Sonderbehandlung.
Wie soll ich denn so erkennen, ob sich Sensoren, die nicht discovered werden konnten, trotzdem unter ihren Adressen ansprechen lassen und vor allen Dingen, ob sie valide Daten liefern?

Ich lasse die Schaltung jetzt trotzdem die Woche über durchlaufen und habe gerade meine Frau angeleitet, wie sie im Notfall auf den FRITZ!Powerline 546E-Adapter mit seinen statischen Zeiten zurückschwenken kann, sollte meine Schaltung dicke Backen machen. Aber eigentlich dürfte es höchstens nach einem Stromausfall Probleme geben können.


Bei nächster Gelegenheit könnte ich die Firmware noch insofern erweitern, dass die Fälle
sinnvoll verarbeitet werden. In so einem Fall wäre auf reine Zeitsteuerung umzuschalten. Außer bei Sensor(R). Von dem hängt ja nix ab. Und bei Sensor(L) wäre es auch nicht wirklich schlimm.
Jedoch sind die jetzigen fünf-Minuten-Blöcke vielleicht etwas knapp. Zehn oder 15 Minuten wären wohl geeigneter.


Denkfehler, Tippfehler und Hardware-Fehler

Nun ist die Schaltung eine Woche gelaufen. Die Pumpe war dabei fast immer an.  :-(
Den ersten Fehler habe ich noch am Montag um 04:xx Uhr erkennen können - leider war da keine Zeit mehr, ihn auch zu beheben.
Der Fehler sah so aus, dass die Pumpe nach der letzten Einschaltzeit um 22:00 Uhr nicht mehr ausgeschaltet wurde. Die programmierte Ausschaltbedingung lautete Sensor(Z)>45°C. Dummerweise hatte die Heizung um die Uhrzeit aber schon auf Nachtmodus umgeschaltet und von Sensor(L) wurden nur noch 44°C gemeldet. Somit konnte Sensor(Z) schwerlich die 45°C übersteigen.
Das passierte erst um 05:25 Uhr. Die Heizung hatte um 04:55 Uhr mit dem Heizen angefangen.
Der Fix dafür könnte also eine erweiterte Abschaltbedingung sein:   Z>45°C  or  Z+3>L

Danach hätte den Tag über alles gut sein können. Um 05:45 Uhr wurde die Pumpe regulär über Einschalt-Bitmap eingeschaltet.
Gegen 06:00 Uhr hat Sensor(E)>56°C gemeldet, was korrekterweise zur Aktivierung der Legionellen-Funktion geführt hat.
Um 07:00 Uhr hätte wieder abgeschaltet werden sollen, weil Sensor(Z) zu diesem Zeitpunkt über 52°C gemeldet hat.
Jedoch war die nächste Bitmap-Einschaltzeit genau um 07:00 Uhr. Weitere um 07:30, 08:00 und um 10:00 Uhr.
Die Pumpe wurde trotzdem erst um 10:05 Uhr abgeschaltet. Warum auch immer.....Sensor(Z) hat bis 08:34 Uhr durchgängig über 52°C gemeldet.
Um 13:00 Uhr wurde gemäß Bitmap eingeschaltet und nie wieder ausgeschaltet, weil Sensor(E) ab 13:09 Uhr konstant +85°C gemeldet hat. Am Dienstag wurde zwar zwischen 05:15 und 05:18 Uhr kurz mal wieder 45°C gemeldet, aber ansonsten blieb es bei den +85°C. Und zwar bis zum Samstag 00:21 Uhr - als ich einen Reset ausgelöst und die Pumpe wieder auf den FRITZ!Powerline 546E-Adapter gesteckt habe. Was für ein Fiasko.

In der Rechnung, die den nach einer oder zwei Stunden beendeten Legionellen-Mode für den Rest des Tages blockieren soll, war ein Tippfehler. Um den Modus bis zum folgenden Tag zu sperren, sollten 60*60*24 [Sekunden] zur aktuellen Zeit addiert werden. Leider stand da aber 60*60+24. Somit wurde die Pumpe wahrscheinlich einmal pro Stunde für wenige Sekunden ausgeschaltet. Also ein Doppelfehler: +24 statt *24 und der falsche Sensor-Wert von 85°C.

Die +85°C kennzeichnen laut Datenblatt zum ds18b20 den "power-on reset value of the temperature register".
Was auch immer mir das jetzt sagen soll....!?
Google liefert zwar reichlich Treffer auf "ds18b20 85°C", jedoch geht es in den Beiträgen fast immer darum, dass der Chip dauerhaft bzw. von Anfang an 85°C meldet. Bei mir hat er ja zuerst durchaus korrekte Werte geliefert und ist dann mittendrin auf seinen "power-on reset value" umgeschwenkt.

Vielleicht könnte ein kleinerer Pullup-Widerstand was bewirken - wie hier vorgeschlagen. Oder, wie unmittelbar darüber vorgeschlagen, den Vcc der ds18b20 an 5V statt 3.3V klemmen.
Andererseits schreibt der Hersteller in seiner ds18b20-FAQ zum Pullup, dass der 4,7KΩ "required for both 5V and 3.3V applications" wäre.

Ich sollte wohl die Schalt-Logik nochmal komplett neu überdenken.
Es braucht drei Modi:
- Normal-Modus
- Legionellen-Modus
- Sensor-Ausfall- bzw. Temperatur-unabhängiger-Modus
In jedem Fall ist dabei sicherzustellen, dass die Pumpe maximal alle fünf Minuten ihren Einschalt-Zustand ändern darf.
Und es wäre genau abzuwägen, von welchem Modus unter welchen Umständen in welchen anderen Modus gewechselt werden kann, damit ein Schwingen zwischen den Modi vermieden wird.
Wobei Sensor-Ausfälle natürlich vorzugsweise komplett vermieden werden sollten.

Modus (bisher)
Übergangs-Bedingung
Modus (neu)
Normal
Sensor-Daten oberhalb Schwellwert (nur einmal pro Tag)
Legionellen
Normaljederzeit bei Sensor-Störung
Temperatur-unabhängig
Legionellennach Abschluss
Normal
Legionellenjederzeit bei Sensor-StörungTemperatur-unabhängig
Temperatur-unabhängigjederzeit bei gültigen Sensor-DatenNormal
Temperatur-unabhängigjederzeit bei gültigen Sensor-Daten oberhalb Schwellwert (nur einmal pro Tag)Legionellen

So vielleicht:
setup()
  Pumpe=aus
  pumpe_aus_zeit=0      # keine Ausschaltzeit für die Pumpe
  pumpe_ein_zeit=0      # Einschalten der Pumpe nicht blockieren
  leg_mode=aus          # kein Legionellen-Modus
  leg_aus_zeit=0        # keine Endzeit für den Legionellen-Modus
  leg_ein_datum=0       # keine Tages-Blockade für den Legionellen-Modus

loop()
  wenn Sensor-Daten nicht valide sind
    # ----------------------------
    # Zeitsteuerung
    # ----------------------------
    wenn jetzt>pumpe_ein_zeit AND EinschaltBitmap(jetzt)==1
      Pumpe=ein
      leg_mode=aus
      pumpe_aus_zeit=jetzt + 10 Minuten
    wenn Pumpe==ein AND pumpe_aus_zeit>0 AND jetzt>pumpe_aus_zeit
      Pumpe=aus
      leg_mode=aus
      pumpe_aus_zeit=0
      pumpe_ein_zeit=jetzt + 5 Minuten
  sonst (Sensor-Daten sind valide)
    # ----------------------------
    # Legionellen-Modus
    # ----------------------------
    wenn leg_mode==aus AND (Sensor(E)>56°C OR Sensor(L)>60°C)
      wenn jetzt>leg_ein_datum AND jetzt>pumpe_ein_zeit
        Pumpe=ein
        leg_mode=ein
        leg_aus_zeit=jetzt + 60 Minuten
        leg_ein_datum=jetzt + 1 Tag     # Legionellen-Modus für diesen Tag sperren
        pumpe_aus_zeit=leg_aus_zeit + 15 Minuten
    wenn leg_mode==ein AND Pumpe==ein
      wenn jetzt>leg_aus_zeit AND Sensor(Z)>52°C
        Pumpe=aus
        leg_mode=aus
        pumpe_ein_zeit=jetzt + 5 Minuten
      sonst wenn jetzt>(leg_aus_zeit + 60 Minuten)
        Pumpe=aus
        leg_mode=aus
        pumpe_ein_zeit=jetzt + 5 Minuten
    sonst (Sensor-Daten sind valide und kein Legionellen-Modus erkannt)
      # ----------------------------
      # Normal-Betrieb
      # ----------------------------
      wenn jetzt>pumpe_ein_zeit AND EinschaltBitmap(jetzt)==1
        Pumpe=ein
        pumpe_aus_zeit=jetzt + 15 Minuten
      wenn Pumpe==ein
        wenn pumpe_aus_zeit>0 AND jetzt>pumpe_aus_zeit
          Pumpe=aus
          pumpe_aus_zeit=0
          pumpe_ein_zeit=jetzt + 5 Minuten
        wenn EinschaltBitmap(jetzt)==0 AND (Sensor(Z)>45°C OR Sensor(Z)+3°C>Sensor(L))
          Pumpe=aus
          pumpe_aus_zeit=0
          pumpe_ein_zeit=jetzt + 5 Minuten
Als kleine Hardware-Änderung habe ich noch eingebaut, dass die ds18b20 ihr Vcc jetzt aus GPIO15 beziehen.
Vom ersten Eindruck her hatte das den erwünschten Effekt, dass die Sensoren nach Betätigung des Reset-Tasters und durchlaufen der setup()-Routine sauber initialisiert sind und sich sauber discovern lassen.
Das Problem mit den +85°C besteht jedoch weiterhin. Weil es bisher immer am Sensor(E) aufgetreten ist, habe ich zunächst die Steckplätze von Sensor(E) und Sensor(R) vertauscht.
Offensichtlich liegt es aber nicht am Steckplatz. Der Fehler bleibt bei Sensor(E).
Also daher Tausch der Sensor-Zuordnung im Python-Script, Tausch der Sensor-Installationsorte und Reset der Schaltung.
Und...siehe da, die +85°C wandern zum Sensor(R). Auch nicht schön - aber von dem hängt nix ab. Dementsprechend wird Sensor(R) auch nicht auf valide Messwerte hin geprüft und beeinflusst folglich die Umschaltung auf den Zeitsteuerungs-Betrieb nicht.
Sollte der 85°C-Fehler jetzt irgendwann wieder zum Sensor(E) wandern, kann es wohl nur noch daran liegen, dass dessen Temperatur häufiger über der von Sensor(L) liegt, als Sensor(L) über Sensor(E) liegt - und es dem Chip auf die Dauer zu warm wird....wir werden sehen.....

Hat echt nicht lange gedauert. Etwa eine Stunde später hat Sensor(E) zwar weiterhin valide Werte gemeldet, Sensor(R) ist bei seinen 85°C geblieben, aber nun ist auch noch Sensor(L) durchgedreht. Konstant 255,9°C.

Daher habe ich eben gerade sämtliche Sensoren von diesem Typ gegen welche aus dieser Charge ausgetauscht. An Letztere musste ich allerdings erst noch ca. 1,8m dreipoliges Kabel dranlöten, alle Kontakte schön mit Schrumpfschlauch isolieren und final noch den Sensor mit einem dickeren Stück Schrumpfschlauch quasi mit dem Kabel-Mantel verschweißen.
Sehr erfreulich an der Sache war, dass ich die neuen Sensoren komplett auf Python-Seite definieren konnte. Die Firmware blieb unverändert. Pro Sensor hat es zwei Resets gebraucht. Den ersten, um die neue Sensor-Adresse ans Python-Script zu melden und den zweiten, um die neue Sensor-Adresse fest seinem Installationsort zuzuweisen.
Jetzt sehen alle vier Werte wieder gut und valide aus. Erstmal zumindest. Ob das so bleibt, wird sich zeigen.

Damit geht es dann nächstes Wochenende auf der nächsten Seite weiter.