Save Thousands on Pool Automation (Pentair SuperFlow VS Automation)

A few weeks ago I had the thought of automating my pool pump, a Pentair SuperFlow VS, with Home Assistant. I’ve been talking about redoing the pool controls since we bought the house, and even more so since the original pump failed a few months after moving in.

I priced out the commercially available options both installed and DIY - and the price was insane. Just to put it in perspective, if I bought Pentair’s solution for a control panel that will do the below plus control valves, heater, etc. the price was at minimum $1,500 without installation.

Without more pool hardware I had the following goals:

  • Turn the pump on and off and set a speed with HA
  • Run the pump on a schedule from HA
  • Easily enable/disable the schedule from HA
  • Issues voice commands to turn the pump on/off, set a speed, and disable/enable the schedule

Later, I’ll add valve actuators as well, but this is what I can do currently given the pool hardware I’ve upgraded so far.

I had the thought that the control was probably just a low voltage relay. In my current setup, the pump is on a mechanical timer which I’ve disabled and left permanently on but the pump has it’s own built in schedule. The salt cell auto shuts down when there’s no flow, and I only have mechanical valves. After researching I found this in the pump’s manual. Really have to appreciate Pentair’s level of detail in here.

So I selected Konnected as my solution of choice - but any set of 4 relays should do the trick here. I went with Konnected because 1) I’ve worked with it before and 2) I didn’t need to write code outside of HA or do any soldering 3) They’re on sale now and the price was right. So far in this project I’ve spent about $115. $55 for the Konnected gear below, and $60 for the proprietary Pentair cable noted in the manual. That’s right - the cable was more than the electronics to control the pump. I just need to buy the housing and related hardware to put it in outside. The cable will be here in a few days and I can see it in action, but I have the below connected to a breadboard DIY kit turning off LED’s from a pass through LV signal, and it’s all working. Here’s the raw setup. I’ll post pictures in the housing when I get there.

The following is a step by step walk through of how I set this up. I’m fairly new to Home Assistant, especially with templating, so if you see a space where I can improve/simplify this please let me know. I’ll be posting photo’s and videos of this working as I complete the install, but this is the initial programming and function. Also note, this is not my whole configuration - only the parts that pertain to the pool, so as always, you may already have some of these domains defined in your configuration and you need to add values - not duplicate the domains.

First we need to setup the Konnected module in configuration.yaml. This is not a tutorial on setting up or wiring Konnected, there’s plenty of documentation for that listed below. For my setup, I don’t use discovery due to firewall rules and different vlans, and I set static IP’s in my Unifi Controller.

konnected:
  access_token: !secret konnected_key
  api_host: http://HOME_ASSISTANT_ADDRESS:8123
  devices:
    - id: KONNECTED_MAC_ADDRESS
      host: KONNECTED_IP_ADDRESS
      port: KONNECTED_PORT
      binary_sensors:
      switches:
        - zone: 1
          name: 'Pool Quick Clean'
        - zone: 2
          name: 'Pool Speed 1'
        - zone: 3
          name: 'Pool Speed 2'
        - zone: 4
          name: 'Pool Speed 3'

For this project I used the 6-zone relay kit, V1 on sale as of this post for $49:

And a 4 channel relay:

For more information on how to configure Konnected, see the documentation here:

One of the first things I did was define schedule times using the input_datetime entity. These are used to build a schedule similar to what was in the pump out of the box, so myself or another user can change the scheduled times easily without having to restart HA or interact with the configuration or the pump.

In configuration.yaml:

input_datetime:
  pool_1_start:
    name: 'Pool Speed 1 Start Time'
    has_date: false
    has_time: true
  pool_2_start:
    name: 'Pool Speed 2 Start Time'
    has_date: false
    has_time: true
  pool_3_start:
    name: 'Pool Speed 3 Start Time'
    has_date: false
    has_time: true
  pool_stop:
    name: 'Pool Stop Time'
    has_date: false
    has_time: true

Then using templates, create two sensors. One as a generic time sensor, and one as a template that uses the current values of the previous four input_datetime entities. Note, there isn’t in logic here to check the values are sequential, so you could easily break automation by setting speed 2 earlier than speed 1, etc… Still working on a better solution for this.

In configuration.yaml:

sensor:
  - platform: time_date
    display_options:
      - 'time'
  - platform: template
    sensors:
        poolschedule:
            friendly_name: 'Pool Schedule'
            value_template: >-
                {% set t = states('sensor.time')| timestamp_custom('%H:%M', false)%}
                {% set s1 = state_attr('input_datetime.pool_1_start', 'timestamp') | int | timestamp_custom('%H:%M', false) %}
                {% set s2 = state_attr('input_datetime.pool_2_start', 'timestamp') | int | timestamp_custom('%H:%M', false) %}
                {% set s3 = state_attr('input_datetime.pool_3_start', 'timestamp') | int | timestamp_custom('%H:%M', false) %}
                {% set st = state_attr('input_datetime.pool_stop', 'timestamp') | int | timestamp_custom('%H:%M', false) %}
                {%- if t >= s1 and t < s2 %}
                  Speed 1
                {%- elif t >= s2 and t < s3 %}
                  Speed 2
                {%- elif t >= s3 and t < st %}
                  Speed 3
                {%- else %}
                  Off
                {%- endif %}

I needed a single on off switch to control the pool. This gives an overall on/off state history, but also allows the voice command “Hey Google, Turn On the Pool”. For turn on I set the default to speed one. I also have all 4 speeds exposed to Google so I can also say “Hey Google, Turn on Pool Speed 3”. This switch also allows for “Hey Google, Turn Off the Pool” regardless of which speed is running.

In configuration.yaml:

switch:
  - platform: template
    switches:
      pool_on:
        friendly_name: "Pool"
        value_template: "{{ is_state('switch.pool_quick_clean', 'on') or is_state('switch.pool_speed_1', 'on') or is_state('switch.pool_speed_2', 'on') or is_state('switch.pool_speed_3', 'on')}}"
        turn_on:
          service: switch.turn_on
          data:
            entity_id:
              - switch.pool_speed_1
        turn_off:
          service: switch.turn_off
          data:
            entity_id:
              - switch.pool_quick_clean
              - switch.pool_speed_1
              - switch.pool_speed_2
              - switch.pool_speed_3

Then I defined an Input Select to allow changing of the pool speed in one location.

In configuration.yaml:

input_select:
  pool_control:
    name: 'Pool'
    icon: mdi:pool
    options:
      - 'Off'
      - 'Quick Clean'
      - 'Speed 1'
      - 'Speed 2'
      - 'Speed 3'

Now I set some automations to switch speeds, only one should be active at a time, but there should be some overlap so the pump doesn’t shut off and go to prime mode. Also, here we’ll update the Input Select to the new running speed. I’m sure there was a cleaner way to do these with templates, but I couldn’t quite get it working. This works, it’s just a lot of duplication.

In automations.yaml:

### POOL CONTROLS ###

### Switch Controls. For the Pentair pump, we need to put a delay beween switching states on and off.

### Switch off other speeds after Quick clean is turned on
- alias: Quick Clean On
  trigger:
  - platform: state
    entity_id: switch.pool_quick_clean
    from: 'off'
    to: 'on'  
  action:
  - service: input_select.select_option
    data_template:
      entity_id: input_select.pool_control
      option: 'Quick Clean'
  - delay: '00:00:01'
  - service: switch.turn_off
    entity_id: switch.pool_speed_1
  - service: switch.turn_off
    entity_id: switch.pool_speed_2
  - service: switch.turn_off
    entity_id: switch.pool_speed_3
    
### Switch off other speeds after Speed 1 is turned on
- alias: Speed 1 On
  trigger:
  - platform: state
    entity_id: switch.pool_speed_1
    from: 'off'
    to: 'on'  
  action:
  - service: input_select.select_option
    data_template:
      entity_id: input_select.pool_control
      option: 'Speed 1'
  - delay: '00:00:01'
  - service: switch.turn_off
    entity_id: switch.pool_quick_clean
  - service: switch.turn_off
    entity_id: switch.pool_speed_2
  - service: switch.turn_off
    entity_id: switch.pool_speed_3
    
### Switch off other speeds after Speed 2 is turned on
- alias: Speed 2 On
  trigger:
  - platform: state
    entity_id: switch.pool_speed_2
    from: 'off'
    to: 'on'  
  action:
  - service: input_select.select_option
    data_template:
      entity_id: input_select.pool_control
      option: 'Speed 2'
  - delay: '00:00:01'
  - service: switch.turn_off
    entity_id: switch.pool_quick_clean
  - service: switch.turn_off
    entity_id: switch.pool_speed_1
  - service: switch.turn_off
    entity_id: switch.pool_speed_3
    
### Switch off other speeds after Speed 3 is turned on
- alias: Speed 3 On
  trigger:
  - platform: state
    entity_id: switch.pool_speed_3
    from: 'off'
    to: 'on'  
  action:
  - service: input_select.select_option
    data_template:
      entity_id: input_select.pool_control
      option: 'Speed 3'
  - delay: '00:00:01'
  - service: switch.turn_off
    entity_id: switch.pool_quick_clean
  - service: switch.turn_off
    entity_id: switch.pool_speed_1
  - service: switch.turn_off
    entity_id: switch.pool_speed_2
      
### Set Input Select to off on state change of overall pool
- alias: Update Input Select to Off
  trigger:
  - platform: state
    entity_id: switch.pool_on
    from: 'on'
    to: 'off'
  action:
  - service: input_select.select_option
    data_template:
      entity_id: input_select.pool_control
      option: 'Off'

### Set pool back to current state on Reboot of HA
### This isn't ideal, but it ensures the pool stays on schedule if HA is rebooted.
- alias: Set Pool to Current State on Reboot
  trigger:
  - platform: homeassistant
    event: start
  action:
  - delay: '00:00:10'
  - service: switch.turn_on
    data_template:
      entity_id: >
        {% if is_state("input_select.pool_control", "Quick Clean") %}
        switch.pool_quick_clean
        {% elif is_state("input_select.pool_control", "Speed 1") %}
        switch.pool_speed_1
        {% elif is_state("input_select.pool_control", "Speed 2") %}
        switch.pool_speed_2
        {% elif is_state("input_select.pool_control", "Speed 3") %}
        switch.pool_speed_3
        {% else %}
        none
        {% endif %}

Now trigger the switches based on the Input select state change, so the user can select a speed and we don’t need to represent all 4 switches in the UI:

In automations.yaml:

### Input Select Pool Control
- alias: Change Pool Speed
  trigger:
  - platform: state
    entity_id: input_select.pool_control
  action:
  - service: switch.turn_on
    data_template:
      entity_id: >
        {% if is_state("input_select.pool_control", "Quick Clean") %}
        switch.pool_quick_clean
        {% elif is_state("input_select.pool_control", "Speed 1") %}
        switch.pool_speed_1
        {% elif is_state("input_select.pool_control", "Speed 2") %}
        switch.pool_speed_2
        {% elif is_state("input_select.pool_control", "Speed 3") %}
        switch.pool_speed_3
        {% else %}
        none
        {% endif %}

And turn everything off using our switch template if the selection is off:

In automations.yaml

### Turn off pool
- alias: Turn off pool
  trigger:
  - platform: state
    entity_id: input_select.pool_control
  action:
  - service: switch.turn_off
    data_template:
      entity_id: >
        {% if is_state("input_select.pool_control", "Off") %}
        switch.pool_on
        {% else %}
        none
        {% endif %}

Finally, we need to trigger the pool on the schedule sensor we defined earlier. Since the values are the same between the sensor and the input select, we just set the input select to the state of the schedule sensor:

In automations.yaml

### Run pool on schedule
- alias: Run Pool Schedule
  trigger:
  - platform: state
    entity_id: sensor.poolschedule
  action:
    - service: input_select.select_option
      data_template:
        entity_id: input_select.pool_control
        option: "{{ states('sensor.poolschedule') }}"

Added bonus, I wanted to be able to tell Google to disable/enable the schedule automation, so these scripts were added to scripts.yaml and then put in to routines with friendly names in Google Home so I can simply say “Hey Google, disable the pool schedule”:

In scripts.yaml:

disablepoolschedule:
  alias: Disable The Pool Schedule
  sequence:
  - data: {}
    entity_id: automation.run_pool_schedule
    service: homeassistant.turn_off
    
enablepoolschedule:
  alias: Enable The Pool Schedule
  sequence:
  - data: {}
    entity_id: automation.run_pool_schedule
    service: homeassistant.turn_on

And if you need help with the Lovelace vertical stack card, here is the code I used for the short version of the card to include history.

In the LoveLace card code editor for a vertical-stack card:

cards:
  - entities:
      - entity: input_select.pool_control
      - entity: switch.pool_on
        icon: 'mdi:pool'
      - entity: sensor.poolschedule
        icon: 'mdi:calendar'
        name: Schedule Mode
      - entity: automation.run_pool_schedule
        icon: 'mdi:calendar'
    show_header_toggle: false
    type: entities
  - entities:
      - entity: switch.pool_on
        name: Pool
      - entity: input_select.pool_control
        name: Pool Speed
      - entity: sensor.poolschedule
        name: Schedule
      - entity: automation.run_pool_schedule
        name: Enabled
    hours_to_show: 24
    refresh_interval: 5
    type: history-graph
title: Pool Controls
type: vertical-stack

Here’s photos of my LoveLace cards. The short card is on my main dashboard (for myself and the wife/kids to use). The long card contains all controls in case I need to troubleshoot later and is on a different tab:

*** Update ***

Here’s a short video of it in action. Obviously very temporary setup for the sake of ensuring it was all working, but happy to report it works well!

20 Likes

Very cool. I’m a little confused exactly what purpose the Konnected serves. Couldn’t you achieve the same result using a Rpi or NodeMCU?

You absolutely could… I just jumped at the low price of the hardware and the lack of need for any building/coding myself while the hardware was on sale. The Konnected board is just a NodeMCU board with the Konnected firmware pre-installed. It was a basically convenience factor.

Great stuff! I am in the same process as you moving forward with automation (though I already had an Intermatic Z-wave pool relay system that I’m trying to communicate with). Thanks for posting all your scripts, reasoning, etc. I’ll definitely crib some of the ideas.

Regarding relays, a good option might be an ESP8266 based relay that can be flashed with Tasmota so that it can be configured to be controlled via MQTT directly from HA (over WiFi). For example:

1 Like

Absolutely. To be honest I wasn’t familiar with Tasmota and the ESP8266 devices when I did this, and I already had Konnected running elsewhere in the house, so it was ease/convenience. As I add to this setup I’ll be looking at Tasmota devices going forward… I just put in my first 6 Tasmota switches and working on the remaining 32 :slight_smile:

esphome.io is a good alternative to tasmota for this stuff too.

Do you know if your solution for controlling pump speed would also work with a Pentair Intelliflo?

P.S. I think it might - they sell this thing https://www.pentair.com/content/dam/extranet/product-related/product-manuals/pool-and-spa-equipment/IntelliComm_II_Interface_Adapter_English.pdf which basically looks like just a simple 4 channel relay

2 Likes

My Intelliflo plump came with the cable that plugs into the port on the side. I have often wondered if I could control the pump with my own device.

Im getting this guy tomorrow, https://www.amazon.com/gp/product/B004VU8RQO/ref=ppx_yo_dt_b_asin_title_o04_s00?ie=UTF8&psc=1, with this and some simple 24v relays it should be doable

1 Like

I just completed the same project. I have the same pool pump (Pentair Superflo VS) and just set to work to integrate it into Home Assistant. I also wanted to use automation to slow the pump when my solar array’s power output falls below my house power demand… but I have yet to get that going.

It is awesome to get this going with so little effort!

I also designed and 3d printed an enclosure for it.
Thingiverse - ESPHome Pool Control Box

esphome:
  name: pool
  platform: ESP32
  board: nodemcu-32s

wifi:
  ssid: !secret wifissid
  password: !secret wifipass

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  #ap:
  #  ssid: "Pool Fallback Hotspot"
  #  password: "IQkNijFST3Ec"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: !secret apipass

ota:
  password: !secret otapass

switch:
  - platform: gpio
    name: "Pool Low Speed"
    pin: GPIO32
    id: lowspeed
    inverted: true
    interlock: [medspeed, highspeed, cleanspeed]
  - platform: gpio
    name: "Pool Medium Speed"
    pin: GPIO33
    id: medspeed
    inverted: true
    interlock: [lowspeed, highspeed, cleanspeed]
  - platform: gpio
    name: "Pool High Speed"
    pin: GPIO25
    id: highspeed
    inverted: true
    interlock: [lowspeed, medspeed, cleanspeed]
  - platform: gpio
    name: "Pool Cleaning Speed"
    pin: GPIO26
    id: cleanspeed
    inverted: true
    interlock: [lowspeed, medspeed, highspeed]

sensor:
  - platform: ct_clamp
    sensor: poolcurrent
    name: "Pool Pump Current"
    update_interval: 10s
    id: poolamps
    filters:
      - calibrate_linear:
          - 0.02 -> 0
          - 0.34 -> 7.375
  - platform: adc
    pin: GPIO34
    id: poolcurrent
    attenuation: 11db
    update_interval: 10s
  - platform: template
    name: "Pool Pump Watts"
    id: poolwatts
    lambda: return id(poolamps).state * 240;
    accuracy_decimals: 0
    unit_of_measurement: W
    icon: "mdi:flash-circle"
    update_interval: 60s

time:
  - platform: sntp
    on_time:
      - seconds: 0
        minutes: 0
        hours: 8
        then:
          - switch.turn_on: highspeed
      - seconds: 0
        minutes: 0
        hours: 10
        then:
          - switch.turn_on: medspeed
      - seconds: 0
        minutes: 0
        hours: 18
        then:
          - switch.turn_on: lowspeed
      - seconds: 0
        minutes: 0
        hours: 0
        then:
          - switch.turn_off: highspeed
          - switch.turn_off: medspeed
          - switch.turn_off: lowspeed
          - switch.turn_off: cleanspeed
1 Like

This is amazing. I replicated this solution using the Konnected hardware and your provided code. It 99% works on the first try! We have the Konnected hardware in the house already for our alarm, so I was keen to use it again for this.

The only thing Im noticing is that when I select a pump speed, in some cases the previous pump speed does not deactivate. I haven’t managed to determine a pattern to it yet. But any ideas of what could be wrong would be appreciated.

Not sure one that, but it might be related to the async changes made to the Konnected integration several iterations ago. Try changing the template switch for the pool on/off switch to this:

- platform: template
    switches:
      pool_on:
        friendly_name: "Pool"
        value_template: "{{ is_state('switch.pool_quick_clean', 'on') or is_state('switch.pool_speed_1', 'on') or is_state('switch.pool_speed_2', 'on') or is_state('switch.pool_speed_3', 'on')}}"
        turn_on:
          service: switch.turn_on
          data:
            entity_id:
              - switch.pool_speed_3
        turn_off:
          service: switch.turn_off
          data_template:
            entity_id: >
              {% if is_state('switch.pool_quick_clean', 'on') %}
                switch.pool_quick_clean
              {% elif is_state('switch.pool_speed_1', 'on') %}
                switch.pool_speed_1
              {% elif is_state('switch.pool_speed_2', 'on') %}
                switch.pool_speed_2
              {% elif is_state('switch.pool_speed_3', 'on') %}
                switch.pool_speed_3
              {% endif %}

That removes the chance of too many async web calls to the Konnected board - I haven’t gotten confirmation from them but it seems that the board can only handle 1-2 concurrent calls. My issue was never with changing speed, but trying to shut the whole pool off.

Also, by the time my setup was moved to production I had moved to a NodeRed flow to control it all and ditched the YAML automations posted here, so I might have run in to the same issue. If you have NodeRed here’s a paste bin for that flow… It’s ugly, but if you familiar with NodeRed it’s not super hard to follow. This has worked perfectly for me with one exception.

https://pastebin.com/SsTPtwWA

Obviously you’ll need to edit each node to match you entity names. Also, part of this flow (the pool schedule) assumes you have the HACS NodeRed component installed (to turn the pool schedule on/off from HA).

I will tell you I have a case open with Konnected at the moment, the relays don’t preserve states on HA or Konnected reboot as they should. so be mindful of what your pool is doing if you restart the Konnected board and/or Home Assistant while it’s running.

Thanks Ryan! I really appreciate the response.

I’ll give this a try and maybe will move to NodeRed as well (it was on the list to learn that). I’ll let you know how I go.

Thanks for the heads up about the relay persistance. I have this just sitting on my desk for now and will be running it through its paces before connecting to the pump control line.

The Node Red worked great!

I did lose the switch for turning the schedule on and off. Im not sure if anything needed to also change in the Scripts and whether anything needed to stay in the automations file.

Apologies, I am new at this!

How can I buy you a beer/coffee?

Small update on this project - after some time of being frustrated unexpected state changes, I actually did end up flashing the Konnected NodeMCU with Tasmota, and the behavior is much better. So now, this same setup is running Tasmota and controlled via MQTT. I also added two additional relays for some string lights and the pool light itself (had no neutral at the mechanical switch so just attached the broken hot to one of the relays instead and put a Tasmota switch in place of the old mechanical switch with rules to control the relay).

have you had a chance to get this working yet? i also have an intelliflo pump and have been wanting to set up automation for it as well, but there’s no way i’m spending $1500+ on an intellitouch system.

Absolutely… Added a relay for my pool light, and a MJ dimmer for our string light as well. Only changes from the original setup is I flashed the Konnected NodeMCU to Tasmota, and my automations are in NodeRed now.

I have an intelliflo pump, you just need the Intellicom adapter for it, and then you can control via relay. I have an ESP32 controlling 5v optocoupler relays: 4 relays for pump speeds, 2 relays for JVA valves, 3 relays for pool/spa lights and pool heater on/off. I installed two temp sensors, one for the water in the pipes to control the pool heater, and one ambient one, i may add one more for the inside of the box to trigger a fan, it gets pretty hot in there. It seems harder than it is, its quite simple, i decided to get a bit fancy and put it on some perfboard to make it look nice but in theory you dont really need to do it though the wiring might get messy.

how are you controlling so many different things? aren’t there only 4 program slots on the intellicom adapter?

edit: nvm, only four of them are pump speeds. i re-read it now…my bad.

Yeah exactly, I have an 8 relay board and a 4 relay board. The 4 relay board supports 15amps@125vac for some of the higher powered stuff on the same circuits as my pool lights. The 8 relay board is the common 10amps@125vac. I went with 5v relays just because they’re a little easier to work with on the bench as you can power them off an esp8266 or esp32 without needing any outside power supply. In my cabinet I picked up a 24v and 5v meanwell DIN DC power supply and mounted it on a rail. I have plans to later pull out the 5v power supply and just step down the 24v supply to 5v. Overall fun project. I want to try and integrate some extra buttons to trigger 1 or 2 hour timer for ‘quick cleans’, and maybe a ‘spa mode’ and ‘pool mode’.