Pool Monitor Card

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
1 Like

Hello, looks good
May I ask what kind of measuring device you use?
I want to do that too.

Greets

ICO pool v2 Salt, bridged from Home-Assistant, as openHAB binding is not available.

Oh okay.. Thx

In the meanwhile an openHAB binding is available: Ondilo - Bindings | openHAB

1 Like