Inspired by Home-Assistant Pool Monitor Card v2 I created this openHAB Widget.
Screenshots
t.b.d.
Changelog
- v0.1
- initial beta version - using hard coded items
- v0.2
- show target values (time and ORP), only when active
- v0.3
- added items to show delta
- added inputs to change targets (time, ORP)
- added button to confirm recommendation
- show time of last measure
Resources
uid: pool_monitor_card
tags: []
props:
parameters: []
parameterGroups: []
timestamp: Jul 14, 2025, 8:17:56 AM
component: f7-card
config:
style:
border-radius: 12px
padding: 2%
width: 196%
slots:
default:
- component: f7-block
config:
style:
padding: 0
slots:
default:
- component: oh-button
config:
action: analyze
actionAnalyzerItems:
- ICOpool_Temperature
- ICOpool_PH
- ICOpool_OxydoReductionPotential
- ICOpool_Salt
- ShellyPoolControl_FlowPower_Power
- ShellyPoolControl_ChlorinatorPower_Power
- ShellyPool_PowerConsumption
style:
--f7-button-text-transform: none
color: white
font-size: 1em
font-weight: bold
margin-top: 12px
text-align: left
text: "='๐ก๏ธ Temperature: ' + items.ICOpool_Temperature.state +
((items.ICOpool_TemperatureDelta.numericState >=
Math.max(items.ICOpool_Temperature.numericState * 0.02, 0.1)) ?
' โ๏ธ ' : ((items.ICOpool_TemperatureDelta.numericState <=
-Math.max(items.ICOpool_Temperature.numericState * 0.02, 0.1)) ?
' โ๏ธ ' : ' โก๏ธ ')) + items.ICOpool_TemperatureDelta.displayState"
- component: f7-block
config:
style:
background: linear-gradient(to right, blue 0%, green 25%, orange 50%, red 100%)
border-radius: 8px
height: 20px
margin-bottom: -19px
position: relative
z-index: 5
- component: oh-slider
config:
color: "=(Number.parseFloat(items.ICOpool_Temperature.state.split(' ')[0]) < 25)
? 'orange' :
((Number.parseFloat(items.ICOpool_Temperature.state.split('
')[0]) > 28) ? 'orange' : 'green')"
disabled: true
item: ICOpool_Temperature
label: true
max: 40
min: 5
style:
margin-bottom: 12px
position: relative
z-index: 50
- component: oh-button
config:
action: analyze
actionAnalyzerItems:
- ICOpool_Temperature
- ICOpool_PH
- ICOpool_OxydoReductionPotential
- ICOpool_Salt
- ShellyPoolControl_FlowPower_Power
- ShellyPoolControl_ChlorinatorPower_Power
- ShellyPool_PowerConsumption
style:
--f7-button-text-transform: none
color: white
font-size: 1em
font-weight: bold
text-align: left
text: "='๐งช PH level: ' + items.ICOpool_PH.state +
((items.ICOpool_PHDelta.numericState >=
Math.max(items.ICOpool_PH.numericState * 0.02, 0.1)) ? ' โ๏ธ ' :
((items.ICOpool_PHDelta.numericState <=
-Math.max(items.ICOpool_PH.numericState * 0.02, 0.1)) ? ' โ๏ธ ' :
' โก๏ธ ')) + items.ICOpool_PHDelta.displayState"
- component: f7-block
config:
style:
background: linear-gradient(to right, red 20%, green 50%, red 80%)
border-radius: 8px
height: 20px
margin-bottom: -19px
z-index: 5
- component: oh-slider
config:
color: "=(Number.parseFloat(items.ICOpool_PH.state.split(' ')[0]) < 7.2) ?
'orange' : ((Number.parseFloat(items.ICOpool_PH.state.split('
')[0]) > 7.6) ? 'orange' : 'green')"
disabled: true
item: ICOpool_PH
max: 8.6
min: 6.2
step: 0.1
style:
margin-bottom: 12px
z-index: 50
- component: oh-button
config:
action: analyze
actionAnalyzerItems:
- ICOpool_Temperature
- ICOpool_PH
- ICOpool_OxydoReductionPotential
- ICOpool_Salt
- ShellyPoolControl_FlowPower_Power
- ShellyPoolControl_ChlorinatorPower_Power
- ShellyPool_PowerConsumption
style:
--f7-button-text-transform: none
color: white
font-size: 1em
font-weight: bold
text-align: left
text: "='๐งผ ORP: ' + items.ICOpool_OxydoReductionPotential.state +
((items.ICOpool_OxydoReductionPotentialDelta.numericState >=
Math.max(items.ICOpool_OxydoReductionPotential.numericState *
0.02, 0.1)) ? ' โ๏ธ ' :
((items.ICOpool_OxydoReductionPotentialDelta.numericState <=
-Math.max(items.ICOpool_OxydoReductionPotential.numericState *
0.02, 0.1)) ? ' โ๏ธ ' : ' โก๏ธ ')) +
items.ICOpool_OxydoReductionPotentialDelta.displayState"
- component: f7-block
config:
style:
background: linear-gradient(to right, red 0%, green 30%, green 50%, green 70%,
red 100%)
border-radius: 8px
height: 20px
margin-bottom: -19px
z-index: 5
- component: oh-slider
config:
color: "=(Number.parseFloat(items.ICOpool_OxydoReductionPotential.state.split('
')[0]) < 650) ? 'orange' :
((Number.parseFloat(items.ICOpool_OxydoReductionPotential.state\
.split(' ')[0]) > 750) ? 'orange' : 'green')"
disabled: true
item: ICOpool_OxydoReductionPotential
max: 800
min: 500
step: 0.1
style:
margin-bottom: 12px
z-index: 50
- component: oh-button
config:
action: analyze
actionAnalyzerItems:
- ICOpool_Temperature
- ICOpool_PH
- ICOpool_OxydoReductionPotential
- ICOpool_Salt
- ShellyPoolControl_FlowPower_Power
- ShellyPoolControl_ChlorinatorPower_Power
- ShellyPool_PowerConsumption
style:
--f7-button-text-transform: none
color: white
font-size: 1em
font-weight: bold
text-align: left
text: "='๐ง Salinity: ' + items.ICOpool_Salt.state +
((items.ICOpool_SaltDelta.numericState >=
Math.max(items.ICOpool_Salt.numericState * 0.02, 0.1)) ? ' โ๏ธ '
: ((items.ICOpool_SaltDelta.numericState <=
-Math.max(items.ICOpool_Salt.numericState * 0.02, 0.1)) ? ' โ๏ธ '
: ' โก๏ธ ')) + items.ICOpool_SaltDelta.displayState"
- component: f7-block
config:
style:
background: linear-gradient(to right, red 0%, green 50%, red 100%)
border-radius: 8px
height: 20px
margin-bottom: -19px
z-index: 5
- component: oh-slider
config:
color: "=(Number.parseFloat(items.ICOpool_Salt.state.split(' ')[0]) < 2500) ?
'orange' : ((Number.parseFloat(items.ICOpool_Salt.state.split('
')[0]) > 3500) ? 'orange' : 'green')"
disabled: true
item: ICOpool_Salt
max: 4000
min: 2000
step: 0.1
style:
margin-bottom: 12px
z-index: 50
- component: f7-row
slots:
default:
- component: f7-col
config:
align: right
width: auto
slots:
default:
- component: oh-button
config:
action: rule
actionRule: PoolControl_StartStopFlow
iconColor: "=(items.ShellyPoolControl_FlowPower_Power.state == 'ON') ? 'blue' :
'gray'"
iconF7: "=(items.ShellyPoolControl_FlowPower_Power.state == 'ON') ?
'play_rectangle_fill' : 'play_rectangle'"
text: ๐ฆ
- component: f7-col
config:
align: right
width: auto
slots:
default:
- component: oh-button
config:
action: rule
actionRule: PoolControl_StartStopChlorinator
iconColor: "=(items.ShellyPoolControl_ChlorinatorPower_Power.state == 'ON') ?
'orange' : 'gray'"
iconF7: "=(items.ShellyPoolControl_ChlorinatorPower_Power.state == 'ON') ?
'play_rectangle_fill' : 'play_rectangle'"
text: ๐งผ
- component: f7-col
config:
align: right
width: auto
slots:
default:
- component: oh-button
config:
action: rule
actionRule: PoolControl_SwitchPhase
disabled: "=(items.ShellyPoolControl_ChlorinatorPower_Power.state == 'ON') ?
true : false"
iconColor: green
iconF7: "=(items.ShellyPoolControl_ChlorinatorPhase_Power.state == 'ON') ?
'plus_slash_minus' : 'minus_slash_plus'"
text: ๐
- component: f7-row
slots:
default:
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: oh-input
config:
item: PoolControl_CurrentEnd
sendButton: true
style:
color: white
font-size: 0.95em
font-weight: bold
type: time
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: Label
config:
style:
color: white
font-size: 1em
font-weight: bold
text: "=(items.ShellyPoolControl_ChlorinatorPower_Power.state == 'ON') ? '๐ฏ ' +
items.PoolControl_ORPTarget.state: ''"
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: Label
config:
style:
color: gray
font-size: 0.8em
text: ='๐ ' + items.ShellyPool_PowerConsumption.state
- component: f7-row
slots:
default:
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: oh-input
config:
item: PoolControl_RegularStart
sendButton: true
style:
color: gray
font-size: 0.8em
font-weight: bold
type: time
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: oh-input
config:
item: PoolControl_ORPTarget
sendButton: true
style:
color: gray
font-size: 0.8em
type: text
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: Label
config:
style:
color: gray
font-size: 0.8em
- component: f7-row
slots:
default:
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: oh-input
config:
item: PoolControl_RegularEnd
sendButton: true
style:
color: gray
font-size: 0.8em
font-weight: bold
type: time
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: oh-button
config:
action: command
actionCommand: ok
actionItem: ICOpool_RecommendationStatus
style:
--f7-button-text-transform: none
color: gray
font-size: 0.8em
text: ='โ๏ธ ' + items.ICOpool_RecommendationTitle.state
- component: f7-col
config:
align: center
width: auto
slots:
default:
- component: Label
config:
style:
color: gray
font-size: 0.8em
text: = 'last measure ๐ ' + items.ICOpool_LastUpdate.displayState