Die Pool-Tagebücher
Ich habe einen Freund mit einem Pool. Dieser Freund – aus Anonymitätsgründen nennen wir ihn Tom – hat diesen Pool selbst gebaut. Er liegt in einem riesigen Garten neben einem zur gleichen Zeit entstandenen Teich. Zwischen Teich und Pool hat Tom eine Holzterrasse mit Sonnenschirm und Liegemöglichkeiten angelegt, auf der man wunderbar Nachmittage verbringen kann.
Tom hat auch eine Frau und Kinder, die diesen Pool ebenfalls benutzen. Seine Familie liebt den Pool und nutzt ihn gerne. Nach einem Jahr im Betrieb wurde jedoch eine gewisse Beschwerde immer lauter: Der Pool war zu kalt. Außerhalb des Hochsommers, also an den ersten und letzten warmen Tagen des Jahres, war die Wassertemperatur für das geschätzte Volk schlicht zu niedrig.
Tom nimmt Beschwerden ernst. Obwohl er sie nicht wirklich teilte (15°C Wassertemperatur empfand er als völlig ausreichend), nahm er sich ihrer an. Jeder vernünftig denkende Mensch wäre wohl in den nächstgelegenen Baumarkt marschiert, hätte eine Wärmepumpen-basierte Poolheizung besorgt und diese verbaut. Die Familie wäre glücklich gewesen und alles wäre gut gewesen.
Nicht so Tom. Der Garten liegt auf einem ehemaligen Bauernhof, bietet also reichlich Platz. Außerdem schweißt Tom gerne. Was lag also näher, als gebrauchte Solarpaneele zur Warmwasserbereitung zu kaufen, diese auf eine selbst geschweißte Stahlkonstruktion an die Garagenfassade zu montieren und den Filterkreis um diese Paneele zu erweitern? Das Resultat waren ca. 10 kW Heizleistung im Filterkreis.
Zunächst war alles gut: Der Pool wurde an sonnigen Tagen spürbar schneller warm und die Familie war zufrieden. Doch schnell stieg der Bedarf nach noch mehr “Pooltagen” und damit nach höherer Heizleistung. Tom besorgte weitere Paneele und erweiterte die Anlage auf beachtliche 20 kW. Der Pool war nun warm – zumindest solange die Pumpe lief. Wurde jedoch vergessen, die Pumpe einzuschalten, blieb der Pool kalt. Schlimmer noch: Wenn das Wasser in den Paneelen bei Sonnenschein nicht zirkulierte, wurde es heißer und heißer – bis die Leitungen explodieren.
Jeder vernünftig denkende Mensch hätte nun eine Zeitschaltuhr und ein Überdruckventil eingebaut. Nicht so Tom. Er beging einen strategischen Fehler: Er fragte mich nach einer Idee.
Dieser Artikel wird etwas länger werden, denn ich beschreibe hier meine Erlebnisse auf einer ungewissen Reise.
Kapitel 1: Der Anfang
Die Anforderungen: Der Pool sollte möglichst effizient beheizt werden. Die Paneele lieferten die nötige Energie, und eine Automatisierung sollte sicherstellen, dass das Wasser zirkulierte, sobald die Sonne schien – oder zumindest warnen, falls dies nicht der Fall war. Die Filterfunktion musste dabei erhalten bleiben.
Die erste Version: Sensoren sollten das Poolwasser (Vorlauf), die Heizung und den Rücklauf überwachen. Sobald die Temperatur in den Paneelen anstieg, sollte die Pumpe automatisch anspringen.
Das Konzept: Wir installierten einen Raspberry Pi 4, OneWire-Thermometer und einen Pimoroni Automation HAT in einem Schaltschrank nahe der Pumpe. Die Steuerung der 230V-Pumpe erfolgte über ein Relais.
| Komponente | Link | Beschreibung |
|---|---|---|
| Raspberry Pi 4 (4GB) | Raspberry Pi Foundation | Die zentrale Steuereinheit |
| Automation HAT | Pimoroni | Monitoring & Relais-Steuerung |
| DS18B20 Sensoren | - | Wasserfeste OneWire-Thermometer |
Die Software: Eine Kernanforderung war, dass Tom die Programmierung selbst anpassen konnte. Da er kein Softwareentwickler ist, brauchten wir eine Lösung, die intuitiv, aber dennoch leistungsfähig war: Node-RED.
[!TIP] Node-RED ist ein flow-basiertes Entwicklungswerkzeug, das Hardware-Geräte, APIs und Online-Dienste über einen Browser-Editor miteinander verknüpft. Mehr erfahren
In der ersten Iteration legten wir GPIO25 des Raspberry Pi auf einen Klemmblock und verbanden das Relais des Automation HAT mit der Pumpe. Das gesamte System wurde auf einer Hutschiene montiert.
Version 1: Der erste kompakte Aufbau mit Pi 4 und Automation HAT.
In Node-RED nutzten wir primär zwei Packages:
node-red-contrib-1wirefür die Temperaturmessung.node-red-contrib-automation-hatfür die I/O-Steuerung.
Die IDs der OneWire-Thermometer ließen sich einfach über die Konsole (ls /sys/bus/w1/devices/) ermitteln und in Node-RED zuordnen. Ein Nachmittag später war es vollbracht: Der Pool wurde beheizt, sobald die Paneele heiß genug waren, und die Pumpe schaltete sich abends automatisch aus.
Kapitel 2: Die Erweiterung
Natürlich waren wir damit noch nicht fertig. Das System verschickte noch keine Benachrichtigungen, und Tom musste den Filter immer noch manuell rückspülen – wie ein Tier. Das musste sich ändern.
Neue Anforderungen: Wir benötigten elektrische Ventile für die Rückspülung (Invertierung des Flusses, um Schmutz abzulassen). Zudem installierten wir Durchflussmesser im Vorlauf und im Heizkreis sowie Drucksensoren zur Überwachung des Systemzustands.
Für die Ventile bauten wir ein 24V-Netzteil und zusätzliche Relais (Waveshare Relay Board) ein. Der gesamte Schaltschrank wurde neu verkabelt.
Version 2: Neu verkabelt mit zusätzlichem Relay Board und 24V-Netzteil für die Ventile.
Dabei stießen wir auf ein Problem: Das Automation-HAT-Package erlaubte kein hochfrequentes Auslesen der analogen Eingänge. Die Durchflussmesser erzeugten jedoch ein Pulssignal, dessen Frequenz wir erfassen mussten. Die Lösung war ein separates Python-Skript, das die Eingänge mit hoher Frequenz ausliest und die Daten als JSON an Node-RED übergibt:
Skript: hat_input.py (Anzeigen)
#!/usr/bin/env python3
"""
Monitors digital pulse frequencies and analog voltages on a Raspberry Pi.
This script uses the pigpio library to count pulses on two specified GPIO pins
and the Adafruit CircuitPython ADS1x15 library to read analog voltages from
three channels of an ADS1015 ADC.
The data is output as a JSON object to standard output at a configurable rate.
"""
import sys
import time
import json
import statistics
import pigpio
import board, busio
import adafruit_ads1x15.ads1015 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
# --- Configuration ---
output_rate_hz = 1.0
if len(sys.argv) > 1:
try:
output_rate_hz = float(sys.argv[1])
if output_rate_hz <= 0:
sys.exit(1)
except ValueError:
sys.exit(1)
integration_time = 1.0 / output_rate_hz
VOLTAGE_COMPENSATION_FACTOR = 5.7
# GPIO pins for the flow sensors (using BCM numbering).
FLOW_SENSOR_PIN_1 = 26
FLOW_SENSOR_PIN_2 = 20
# --- Setup pigpio for pulse counting ---
pi = pigpio.pi()
if not pi.connected:
sys.exit(1)
pulse_count_1 = 0
pulse_count_2 = 0
def cb1(gpio, level, tick):
global pulse_count_1
if level == 1: pulse_count_1 += 1
def cb2(gpio, level, tick):
global pulse_count_2
if level == 1: pulse_count_2 += 1
cb1_handle = pi.callback(FLOW_SENSOR_PIN_1, pigpio.RISING_EDGE, cb1)
cb2_handle = pi.callback(FLOW_SENSOR_PIN_2, pigpio.RISING_EDGE, cb2)
pi.set_glitch_filter(FLOW_SENSOR_PIN_1, 100)
pi.set_glitch_filter(FLOW_SENSOR_PIN_2, 100)
# --- Setup I2C ADC ---
i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS.ADS1015(i2c)
ads.gain = 1
ads.data_rate = 128
chan0 = AnalogIn(ads, ADS.P0)
chan1 = AnalogIn(ads, ADS.P1)
chan2 = AnalogIn(ads, ADS.P2)
def get_stable_voltage(channel, num_samples=21):
readings = []
for _ in range(num_samples):
readings.append(channel.voltage)
time.sleep(0.005)
return statistics.median(readings)
try:
last_time = time.monotonic()
last_pulse_count_1 = 0
last_pulse_count_2 = 0
next_output_time = time.monotonic()
while True:
next_output_time += integration_time
sleep_time = next_output_time - time.monotonic()
if sleep_time > 0:
time.sleep(sleep_time)
current_time = time.monotonic()
elapsed_time = current_time - last_time
current_pulse_count_1 = pulse_count_1
current_pulse_count_2 = pulse_count_2
if elapsed_time > 0:
frequency_1 = (current_pulse_count_1 - last_pulse_count_1) / elapsed_time
frequency_2 = (current_pulse_count_2 - last_pulse_count_2) / elapsed_time
else:
frequency_1 = frequency_2 = 0.0
last_time, last_pulse_count_1, last_pulse_count_2 = current_time, current_pulse_count_1, current_pulse_count_2
try:
v1 = get_stable_voltage(chan0) * VOLTAGE_COMPENSATION_FACTOR
v2 = get_stable_voltage(chan1) * VOLTAGE_COMPENSATION_FACTOR
v3 = get_stable_voltage(chan2) * VOLTAGE_COMPENSATION_FACTOR
except:
continue
data = {
"pin26": round(frequency_1, 2),
"pin20": round(frequency_2, 2),
"analog1": round(v1, 2),
"analog2": round(v2, 2),
"analog3": round(v3, 2)
}
print(json.dumps(data))
sys.stdout.flush()
except KeyboardInterrupt:
pass
finally:
cb1_handle.cancel()
cb2_handle.cancel()
pi.stop()
Nun war das System eigentlich perfekt: Tom konnte die Logik selbst anpassen, das System konnte heizen sowie spülen, und wir hatten alle kritischen Werte im Blick. Der erste Winter verging, und im Frühling bestand die Anlage die erste Funktionsprüfung mit Bravour.
Kapitel 3: Die Tücke der Technik
Was passiert jedoch, wenn zwar alle Sensoren funktionieren und die Automatik die Pumpe korrekt ansteuert, aber die mechanischen Ventile nicht zuverlässig schalten?
Richtig: Die Leitung explodiert.
