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!