home     Inhaltsverzeichnis
erste Version am 17.09.2017
letzte Änderung am 25.09.2017

Zirkulationspumpen-Steuerung - Seite 2


Überlegungen zum Programmablauf

In der folgenden Tabelle habe ich die Folgerungen aus den einzelnen Temperatur-Messwerten zusammengestellt:
Sensor
Zustand / Messwert
Folgerung
R
20°C < sensor(R) < 30°C Raumtemperatur ist valide
R
sonst Warnung ausgeben!



L
sensor(L) <= sensor(R)
die Heizung ist ausgeschaltet oder defekt
L
sensor(R) < sensor(L) <= 40°C
der Speicher wird gerade erwärmt
L
40°C < sensor(L) <= 60°C
warmes Wasser steht im Speicher bereit
L
wenn sensor(L) > 60°C
Anti-Legionellen-Funktion der Heizung läuft
L
Wert steigt
das Wasser im Speicher wird erwärmt



E
sensor(E) <= sensor(R)
die Rohre sind kalt
E
sensor(E) <= 40°C
die Rohre sind kalt
E
40°C < sensor(E) < 60°C
warmes Wasser wird oder ist im Haus bereitgestellt
E
sensor(E) > 60°C
Anti-Legionellen-Funktion der Heizung läuft
E
Wert steigt warmes Wasser wird entnommen oder umgewälzt
E
Wert sinkt
es wird kein warmes Wasser entnommen und nicht umgewälzt



Z
sensor(Z) <= sensor(R)
das warme Wasser wird nicht umgewälzt
Z
sensor(R) < sensor(Z) <= 40°C
Umwälzung läuft, ist aber noch nicht abgeschlossen
Z
40°C < sensor(Z) <= 60°C
Umwälzung läuft und kann demnächst beendet werden
Z
sensor(Z) >= (sensor(E)-delta)
in den Rohren steht warmes Wasser / Umwälzung kann beendet werden
Z
sensor(Z) > 60°C Anti-Legionellen-Funktion der Heizung kann demnächst beendet werden

Zwei quasi-statische Parameter sind vom Programm zu ermitteln:
Statt mit vorab ermittelten Zeiten und Temperatur-Deltas zu arbeiten, könnte die Pumpe auch grundsätzlich so lange eingeschaltet bleiben, bis sich die von Sensor Z gemeldete Temperatur ein paar Minuten lang nicht weiter an die von Sensor E annähert.

Hier noch ein Schaubild, das den Brauchwasser-Kreislauf samt Rohr-Nummern und Sensor-Bezeichnungen darstellt:
 Schema-Zeichnung
        Brauchwasser-Kreislauf


erste Tests (trocken)

Mittlerweile sind alle Bauteile / Komponenten geliefert. Meine erste Test-Schaltung besteht aus einem WeMos-D1-Mini und vier DS18B20, die jetzt alle über einen Pin mit der CPU verbunden sind. Auch spricht die Schaltung bereits mit einem Python-Script, stellt darüber die System-Zeit, überträgt die erkannten Sensor-Adressen und empfängt deren Zuordnung zu ihrer Funktion. Allerdings liegt noch alles auf meinem Schreibtisch und hat den Heizungsraum noch nicht gesehen.
Stattdessen läuft die Pumpe jetzt erstmal testhalber über einen FRITZ!Powerline 546E-Adapter - also mit statischer Zeitsteuerung. Offenbar können von dem Ding beim Wochenprogramm jedoch nur 140 Schaltzeiten verarbeitet werden. Und das langt nicht, um die Pumpe täglich zwischen 05:30 und 22:00 Uhr einmal pro Stunde ein- und 15 Minuten später wieder auszuschalten.

Folgende neue Ideen oder Problemstellungen sind dabei bisher entstanden:
Daraus folgt:

Derzeit offen sind folgende Fragen:

Erkennung von Warmwasser-Entnahme:
Wenn trotz abgeschalteter Pumpe die Temperatur an Sensor E steigt, wird warmes Wasser entnommen.
Bei eingeschalteter Pumpe kann nicht erkannt werden, ob gerade warmes Wasser entnommen wird.
Steigt der Wert an Sensor L, wird das Wasser im Speicher erwärmt.

Wird kein warmes Wasser entnommen, sollte die Abkühldauer des Wassers im Speicher konstant sein.
Wird warmes Wasser entnommen, fließt kaltes Wasser nach und das Wasser im Speicher muss schneller wieder erhitzt werden.

Wenn die Pumpe zwischen 22:00 und 05:00 Uhr immer aus ist, sollten die Rohre hinreichend ausgekühlt sein. Dieser Zustand wäre daran zu erkennen, dass die Sensoren E, Z und R ähnliche Werte liefern. Wird die Pumpe eingeschaltet, steigt zuerst Sensor E (auf 52°C). Parallel, etwas zeitverzögert steigt auch Sensor Z. Die Dauer zwischen "Pumpe ein" und Sensor Z auf Maximum ist dann am größten, wenn zwischendurch kein warmes Wasser entnommen wird.


erste Messwerte von den Rohren

Nun habe ich die ersten echten Daten. Die Schaltung ist noch auf einem Breadboard verbaut und liegt offen auf der Aqua Unit (Bilder anklicken für volle Größe):
Zirkulationspumpen-Steuerung auf
        Breadboard im Heizungsraum

Die Sensoren sind weitestgehend an ihrem finalen Installationsort angebracht:
Sensor-Installation an den Rohren
Als Sensor-Halterung habe ich jeweils 1/3 von sog. PE T-Stücken verwendet. Final sollen noch Schlauchschellen drüber.

Der Start war am Samstag um 20:45:47 Uhr.
Folgende Pumpen-Schaltzeiten sind in dem Fritz!Powerline546E-Modul eingestellt:
aktive Schaltzeiten im FRITZ!Powerline
        546E-Adapter

Und dies sind die gemeldeten Temperaturen:
Rohr-Temperaturen

Kurz nach 21:00 Uhr hatten sich die Sensoren hinreichend akklimatisiert und melden valide Werte.
Kurz vor 23:00 Uhr war offenbar die letzte Warmwasser-Entnahme.
Gegen 07:20 Uhr habe ich als erster geduscht.

Unerwartet sind folgende Erkenntnisse:
Ganz besonders verwunderlich finde ich, dass gegen 22:30 Uhr die Temperatur an Rohr 3(Z) um fast 10°C ansteigt, obwohl die Pumpe nicht eingeschaltet gewesen ist. Ähnliches gegen 07:45 Uhr.
Die eindeutige Stromlosigkeit der Pumpe ist auch an der Energieanzeige vom Powerline-Adapter abzulesen:
Screenshot aus dem WebGUI der 546E
Was auch immer diese kleinen Ausschläge (z.B. von 07:45 bis 08:00 Uhr) sein mögen...!?

Nachtrag: ein Telefonat mit meinem Kollegen Ralf R. aus R. hat diesbezüglich Klärung gebracht: wird irgendwo warmes Wasser entnommen, dann fließt das warme Wasser natürlich auf allen verfügbaren Wegen zu dieser Stelle. Das Zirkulations-Rohr ist einer dieser verfügbaren Wege. Damit fließt das Wasser in eigentlich falscher Richtung durch das Rohr. Wenn die Pumpe nicht eingeschaltet ist und Wasser in die entgegengesetzte Richtung fließt, wird die Pumpe vom fließenden Wasser angetrieben und der Motor wird zum Generator - was dann auch die kleinen Ausschläge in der Energieanzeige erklären könnte. Ist sie eingeschaltet und wird gleichzeitig Wasser entnommen, muss sie am stärksten arbeiten - was wiederum die besonders hohen Ausschläge in der Energieanzeige erklären könnte.
Wobei sich dann eigentlich noch die Frage stellt, ob es für die Pumpe nicht gesünder wäre, die bereits laufende Pumpe abzuschalten, wenn eine Wasser-Entnahme erkannt würde. Schließlich müsste sie dann nicht gegenan-arbeiten. Andererseits lässt sich in diesem Fall (ohne Durchfluss-Sensoren in beiden Rohren) wohl nur schwer erkennen, ob gerade warmes Wasser entnommen wird.

Zumindest eine sichere Erkenntnis habe ich anhand der Daten schon erlangt: ich werde die jeweilige Steilheit der Temperatur-Kurven ermitteln und berücksichtigen müssen. Einfache Schwellwerte pro Sensor werden nicht reichen, um eine Ein/Aus-Entscheidung für die Pumpe treffen zu können......


Steuerung der Pumpe (v1, simpel)

Weil das Fritz!Powerline546E-Modul nur 140 Schaltpunkte pro Woche erlaubt, sollte ich das Relais für die Zirkulationspumpe möglichst bald über meine Schaltung ansteuern.
Die erste, provisorische Betriebsart könnte so aussehen, dass die Pumpe grundsätzlich nur zwischen 05:45 und 22:00 Uhr angesteuert wird. Immer dann, wenn Sensor Z unter 40°C fällt, wird die Pumpe für mindestens 10 Minuten eingeschaltet. Sollte der Wert von Sensor E nach dieser Zeit mehr als 5°C über dem Wert von Sensor Z liegen, bleibt sie für weitere 5 Minuten an.
Gleichzeitig sollte die Firmware auf täglich einmaligen WLAN-Connect umgestellt werden (derzeit ist die Schaltung dauerhaft mit dem SocketServer verbunden und sendet alle fünf Sekunden die vier Sensor-Werte samt Timestamp).
Ohne dauerhafte Verbindung müssen die Sensor-Werte im RAM des ESP8266-12E gehalten werden. 4*12 Bit=48 Bit=6 Byte. Da fehlt aber noch das Bad-Flag. Also 7 Byte alle fünf Sekunden.
7*(60/5)=84 Byte pro Minute. 84*60=5.040 Byte pro Stunde. 5040*24=120.960 Byte=119 KB pro Tag.
Das müsste passen. Bei Bedarf könnte sonst auch einfach alle 12 Stunden mit dem SocketServer kommuniziert werden.
Und wenn ein Satz Sensor-Werte nur einmal pro Minute gespeichert würde, ergäbe das lächerliche 7*60*24=10.080 Byte.
Dann könnte statt Bad-Flag auch einfach zu jedem validen Satz der zugehörige Timestamp abgelegt werden. Das sollte die Verwaltung des Arrays vereinfachen. Jeder Satz hätte seine eigene absolute Zeit und es gäbe nur valide Sätze im Array.
Damit würde das Array also (4+6)*60*24=14.400 Byte belegen.
Der Pseudocode für die Hauptschleife sieht so aus:
  setup:
      initSensors()                                                     // dummy-read für "Temperature Conversion Time"
      clearSensorData_subMinuteArray()                                  // Speicher initialisieren
      clearSensorDataArray()
      connectSocketServer()		                                // mit WLAN und SocketServer verbinden
      setSystemDateTime(getDateTimeFromSocketServer())			// Zeit holen und einstellen
      setSensorAssignment(getSensorAssignmentFromSocketServer())	// Sensor-Funktions-Zuordnung übernehmen
      disconnectSocketServer()		                                // Verbindung beenden
      lastSync=systemDateTime-1[Tag]                                    // Timestamp, wann zuletzt gesync't wurde
      newMinute=systemTime.Minute                                       // die derzeitige Minute
      switchOffTime=-1                                                  // negativ für "Pumpe aus", sonst Ausschaltzeit

  loop:
      if newMinute!=systemTime.Minute:                                  // wenn eine neue Minute anfängt
          // die in der letzten Minute gesammelten Daten zu einem Minuten-Wert zusammenfassen und speichern
          storeSensorData(average(sensorData_subMinute))
          newMinute=systemTime.Minute
          clearSensorData_subMinuteArray()

storeSensorData_subMinute() // Sensordaten im Minuten-Speicher ablegen
if systemTime>=03:30 && lastSync+23[Stunden]<=systemDateTime: // wenn es Zeit für den Sync ist connectSocketServer() // SystemZeit korrigieren und Daten senden setSystemDateTime(getDateTimeFromSocketServer()) sendSensorDataArray() clearSensorDataArray() disconnectSocketServer() lastSync=systemDateTime
if switchOffTime==-1: // wenn die Pumpe z.Zt. aus ist if systemTime>=05:45 && systemTime<22:00: // und wenn die aktive Zeit läuft if sensorValue(Z)<40[°C]: // und wenn die Temperatur im Zirkulations-Rohr zu niedrig ist switchPump(On) // Pumpe einschalten switchOffTime=systemTime+10[Minuten] // für mindestens 10 Minuten else: // wenn die Pumpe z.Zt. eingeschaltet ist if systemTime>=switchOffTime: // und wenn die Pumpe 10 Minuten an war if sensorValue(Z)+5[°C]<sensorValue(E): // und wenn sich die Temperatur noch nicht hinreichend an die des Entnahme-Rohrs angeglichen hat switchOffTime=systemTime+5[Minuten] // Pumpe weitere 5 Minuten eingeschaltet lassen else: switchPump(Off) // ansonsten Pumpe ausschalten switchOffTime=-1
delay(5[Sekunden])
Ich will im Heizungsraum nicht mit fliegenden 230V-Strippen rumhantieren müssen. Folglich muss ich mich parallel zur Pumpenansteuerungs-Firmware auch gleich um die Gehäuse-Bearbeitung kümmern. Und irgendwie gefällt mir die ursprüngliche Idee nicht mehr, alles in ein Gehäuse zu stecken.
Alternativ wäre denkbar, eine abgesetzte 230V-Einheit zu bauen, in der sich nur das Schaltnetzteil und das Relais-Modul befänden. Neben den zwei Strippen für den 230V Eingang und den geschalteten 230V Ausgang bräuchte es noch eine Buchse mit drei Kontakten für +5V DC, GND und Relais-Ansteuerung.
Der entscheidende Vorteil daran wäre, dass ich es bei zukünftigen Änderungen oder Erweiterungen nur noch mit 5V Gleichspannung zu tun hätte.
Das zweite Gehäuse bräuchte eine Buchse für die Verbindung zum ersten Gehäuse, drei Anschlüsse für die Sensoren und zwei LEDs. Innen befände sich mindestens ein 3.3V-Regler, ein DS18B20 und der ESP8266-12E.
Bei Bedarf noch ein RTC-Modul mit Puffer-Batterie. Und vielleicht komme ich ja noch auf die Idee, dass ich außerdem ein kleines Display zur Anzeige der Live-Daten haben möchte.
Im Zweifelsfall ließe sich dieses Modul leicht (und günstig) zweimal bauen. Damit hätte ich dann immer ein Modul produktiv und ein weiteres zum Testen.
Das hört sich gut an. So mache ich das.

Oder auch nicht.
Zwar hätte ich ein Gehäuse in meinem Fundus, in das Schaltnetzteil und Relais-Modul gerade so reinpassen würden, aber irgendwie wird mir das damit zu eng und friemelig. Außerdem müsste ich da wahrscheinlich auch noch diverse [hässliche] Lüftungslöcher reinbohren. Der letzte und ausschlaggebende Grund, mich dann doch wieder gegen zwei einzelne Gehäuse zu entscheiden, war, dass ich nix schickes gefunden habe, mit dem ich die drei Leitungen zwischen den zwei Gehäusen steckbar hätte herstellen können.

Daher jetzt die neue Idee, ein schön großes Gehäuse (das sogar schon Lüftungsschlitze hat) zu nehmen, in das
fest eingebaut werden. Für die CPU-Platine wird es einen Leiterplatten-Verbinder geben, über den diese befestigt und gleichzeitig elektrisch verbunden wird (so ähnlich wie auf diesem Foto).

Damit gehts auf der nächsten Seite weiter.