Hello openHab community.
I’ve created a visualization of my combined pool and home heating system and thought I might as well share it with you. My widget development skills are more than limited so my appologies for the probably bad/inefficient code.
Looking forward to your thoughts, suggestions and ideas!
Here’s the initial version (of my work in progress):
(solar thermal water being sent to pool heat exchanger, pool pump running)
(solar thermal water being sent to house heating system, pool pump not running)
Here’s my setup (excerpt):
- raspberry pi 5b 8GB openHab Server
On roof:
- solar thermal collectors
- photovoltaic solar energy system (17kWp)
In pool house:
- heat exchanger (for pool water/solar thermal system)
- Pool pump (approx 600W) and sand filter system
- Shelly EM (to measure pool pump and pool light power consumption)
- MySensors node in pool house with relays for
- pool pump
- pool lights
and ds18b20 sensors for measuring temperature of - pool water flowing from pool to pump
- pool water flowing from pump back to pool
- solar thermal water flowing in to pool heat exchanger from switching valve (in basement)
- solar thermal water flowing back from pool heat exchanger back to switching valve (in basement)
In basement (HVAC-room):
- Two Growatt inverters and 17kWh battery (connected to openhab via modbus serial)
- European (German) style house heating system (with hot water tank)
- electric switching valve (for switching solar thermal hot water flow to pool heat exchanger or house heating system)
- DIY MySensors node (in basement HVAC-room) with
- relay for electric switching valve
and ds18b20 sensors for measuring temperature of - solar thermal water arriving from roof at switching valve (in basement)
- solar thermal water flowing from switching valve (in basement) back to roof
- solar thermal water flowing from switching valve (in basement) to pool heat exchanger
- solar thermal water returning from pool heat exchanger at switching valve (in basement)
- solar thermal water flowing switching valve to house heating system (heat exchanger in hot water tank)
- solar thermal water returning from house heating system (heat exchanger in hot water tank) to switching valve
- relay for electric switching valve
On ground floor:
- DIY MySensors MQTT Ethernet gateway
In garden:
- inground pool 7m x 3m x 1,7m (23ft x 10ft x 5.6ft)
Summary of the most relevant rules:
- run pool pump for 4h/day
- run pool pump only when solar energy production exceeds house load consumption by at least 1kw
- if not enough excess solar energy production make sure pool pump ran min 4h/day at 7pm each day
- automatically switch valve to pool heat exchanger when solar thermal water temp exceeds predifined threshold and pool temperature below target and difference bt. pool temp and thermal temp exceeds defined threshold
- automatically run pool pump when switching valve switched to pool heat exchanger (to protect pool pipes from melting)
- run pool pump in pool cleaning mode
Here’s the widget code:
uid: Pool_v01
tags: []
props:
parameters:
- context: item
label: Item Umschaltventil
name: itemVentil
required: true
type: TEXT
- context: item
label: Item Solarwasser-Zulauf-Temperatur
name: itemSolarZulaufTemp
required: true
type: TEXT
- context: item
label: Item Solarwasser-Rücklauf-Temperatur
name: itemSolarRuecklaufTemp
required: true
type: TEXT
- context: item
label: Item Solarwasser-Pool-Zulauf-Temperatur (Keller)
name: itemSolarPoolZulaufKellerTemp
required: true
type: TEXT
- context: item
label: Item Solarwasser-Rücklauf-Temperatur (Keller)
name: itemSolarPoolRuecklaufKellerTemp
required: true
type: TEXT
- context: item
label: Item Poolpumpe-Zulauf-Temperatur
name: itemPoolpumpeZulaufTemp
required: true
type: TEXT
- context: item
label: Item Poolpumpe-Rücklauf-Temperatur
name: itemPoolpumpeRuecklaufTemp
required: true
type: TEXT
- context: item
label: Item Poolpumpe-Stromverbrauch
name: itemPoolpumpeWatt
required: true
type: TEXT
- context: item
label: Item Solarwasser-Pool-Zulauf-Temperatur
name: itemSolarPoolZulaufTemp
required: true
type: TEXT
- context: item
label: Item Solarwasser-Pool-Rücklauf-Temperatur
name: itemSolarPoolRuecklaufTemp
required: true
type: TEXT
- context: item
label: Item Kessel-Zulauf-Temperatur
name: itemSolarKesselZulaufTemp
required: true
type: TEXT
- context: item
label: Item Kessel-Rücklauf-Temperatur
name: itemSolarKesselRuecklaufTemp
required: true
type: TEXT
- context: item
label: Item Automatik
name: itemAutomatik
required: true
type: TEXT
- context: item
label: Item Modus
name: itemModus
required: true
type: TEXT
- default: light
description: Farbschema
label: Farbschema
name: colortheme
required: false
type: TEXT
parameterGroups: []
timestamp: Mar 25, 2025, 4:43:11 PM
component: f7-card
config:
footer: '="Modus: " + items[props.itemModus].state + "; Automatik: " +
items[props.itemAutomatik].state'
style:
background: '=(items[props.itemVentil].state == "ON") ?
"url(/static/Solar_heating_pool4.svg)" :
"url(/static/Solar_heating_boiler4.svg)"'
background-position: center
background-size: cover
color: '=(props.colortheme == "dark") ? "white" : "black"'
height: 400px
width: 750px
title: Solarthermie-Heizung
slots:
content:
- component: f7-row
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-top: 130px
margin-left: 203px
width: 100%
slots:
default:
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 50px
justify-content: center
margin-top: 0
width: 375px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: 275px
margin-top: 0px
text-align: center
width: 80px
text: =items[props.itemSolarZulaufTemp].displayState ||
items[props.itemSolarZulaufTemp].state
visible: true
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-top: -0px
width: 375px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: -275px
margin-top: 0px
text-align: left
width: 80px
text: =items[props.itemSolarRuecklaufTemp].displayState ||
items[props.itemSolarRuecklaufTemp].state
- component: f7-row
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-top: 34px
margin-left: 270px
width: 100%
slots:
default:
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: -0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: 45px
margin-top: 0px
text-align: left
width: 160px
text: =items[props.itemPoolpumpeRuecklaufTemp].displayState ||
items[props.itemPoolpumpeRuecklaufTemp].state
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: -0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: -55px
margin-top: 0px
text-align: center
width: 160px
text: =items[props.itemSolarPoolZulaufKellerTemp].displayState ||
items[props.itemSolarPoolZulaufKellerTemp].state
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: 0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: -20px
margin-top: 0px
text-align: left
width: 160px
text: =items[props.itemSolarKesselRuecklaufTemp].displayState ||
items[props.itemSolarKesselRuecklaufTemp].state
- component: f7-row
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-top: 42px
margin-left: 230px
width: 100%
slots:
default:
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: -0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: 0px
margin-top: 0px
text-align: left
width: 160px
text: =items[props.itemSolarPoolZulaufTemp].displayState ||
items[props.itemSolarPoolZulaufTemp].state
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: -35px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: 0px
margin-top: 0px
text-align: left
width: 160px
text: =items[props.itemSolarPoolRuecklaufTemp].displayState ||
items[props.itemSolarPoolRuecklaufTemp].state
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: -0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: -226px
margin-top: 0px
text-align: center
width: 160px
text: =items[props.itemSolarPoolRuecklaufKellerTemp].displayState ||
items[props.itemSolarPoolRuecklaufKellerTemp].state
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: 0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: -200px
margin-top: 0px
text-align: left
width: 160px
text: =items[props.itemSolarKesselZulaufTemp].displayState ||
items[props.itemSolarKesselZulaufTemp].state
- component: f7-row
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-top: 107px
margin-left: 150px
width: 100%
slots:
default:
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: -0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: 20px
margin-top: 0px
text-align: left
width: 160px
text: =items[props.itemPoolpumpeZulaufTemp].displayState ||
items[props.itemPoolpumpeZulaufTemp].state
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: row
height: 0px
justify-content: center
margin-left: -0px
margin-top: 0px
width: 160px
slots:
default:
- component: Label
config:
style:
color: '=(props.colortheme == "dark") ? "white" : "black"'
font-size: 14px
margin-left: 0px
margin-top: 0px
text-align: left
width: 160px
text: =items[props.itemPoolpumpeWatt].displayState ||
items[props.itemPoolpumpeWatt].state
The things, items and rules are very extensive - in case you’re interested in those I’ll happily attach them as files on request.
Looking forward to your feedback (and especially suggestions for optimizating the widget code)
Kind regards,
Ralph…