neon.ninja

Sharing enlightening moments of home automation

Smarter Swimming Pool 1: Pool Pump

When I bought my house I also inherited a nice outdoor swimming pool. Little did I know about pool maintenance back then and so during the first couple of months everything that could go wrong did go wrong. Anyway, I am now in a position to go beyond the static pool maintenance and am smartening up the whole thing. This post is the first one in a short series describing various small improvements I have made – starting with making the pool pump a bit smarter.

Pool Pump – Before

The pool pump needs to run several hours per day – a little less in winter and a bit more in summer during the swimming season. Mine was hooked up to a simple timer switch which turned on the pool pump and the liquid chlorine pump at the same time. And over the course of the year I had to fiddle around with the timer switch to increase and decrease the duration as necessary.

Pool timer switch

The timer switch is a simple approach, but comes with a few disadvantages:

  • To make most of my self-produced solar electricity, I had to continuously modify the switch’s settings.
  • During a power outage the timer just stops, and continuous afterwards wherever it left, i.e. I had to realign the timer after each outage.
  • There is no feedback, i.e. if for example the fuse blows for whatever reason the pump stops working and it just takes a few days until the water turns green and a lot of chemicals are required to fix this.

Pool Pump – After

Remote control the pump

To be able to control the pool pump through Home Assistant, I first of all had to have the ability to remote control the electricity circuit. My first choice was a Z-Wave switch, but unfortunately the power outlet is in a very inconvenient position: behind and under the pool, quite far away from the house and far from any location where a repeater would have helped. The outlet and the switch are not water-proof, so both had to remain inside the pool pump cupboard. And I could not find a Z-Wave switch with an external antenna.

Modified WeMo Insight switch

Next, I looked at Wifi switches, and settled on a WeMo Insight. There are a few tear-down reports for that switch which taught me how to replace the built-in antenna with a pigtail cable, so that I could connect a 3 metre antenna cable (SMA male to female jack, coax RG58) with the external antenna mounted on the pool fence, well above the water level so that it can reach my Wifi.

WeMo Insight’s external antenna

The integration of the WeMo Insight switch into Home Assistant was working as expected – well at least after a small fix to the underlying library, since WeMo now apparently uses more network ports where the switches can be listening on.

Pool wifi switch distribution: The WeMo Insight switches the power board at the top where pool pump and liquid chlorine feeder are connected.

Once that was working I could focus on the actual automation.

Of course you can use other types of switches depending your individual circumstances or preferences. In the following configuration snippets you will have to replace the entity id switch.wemo_insight_pool with your switch’s entity id; it just needs to support states on and off as well as services turn_on and turn_off.

Automating the pump

With a pool pump switched by Home Assistant I still wanted some level of control and introduced several levers and switches, and also implemented a level of monitoring and reporting.

Pool pump control panel

Controls – Auto, On and Off

Anything that you would normally just turn on or off and that should be automated in the future would probably require a 3-way-switch with the options: Auto, On and Off. While On and Off simply turn the attached Wifi switch on or off and the automation is ignored, in Auto mode the automation component is controlling the switch state.

input_select:
  pool_pump:
    name: Pool Pump mode
    options:
      - 'Auto'
      - 'On'
      - 'Off'
    initial: 'Auto'
    icon: mdi:engine

Controls – Swimming Season or not

I am distinguishing between Swimming Season and Off-peak Season. With a simple switch (input_boolean) I can change the current mode.

input_boolean:
  swimming_season:
    name: Swimming Season
    icon: mdi:swim

Controls – Duration

For each mode – swimming or off-peak – a separate duration can be configured defining how many hours per day the pool pump should run. For now I kept it simple only allowing to select a full number of hours with reasonable minimums and maximums.

input_number:
  run_pool_pump_hours_swimming_season:
    name: Run Pool Pump in Swimming Season
    min: 1
    max: 8
    step: 1
    mode: slider
  run_pool_pump_hours_off_season:
    name: Run Pool Pump in Off Season
    min: 1
    max: 6
    step: 1
    mode: slider

Automating the Wifi switch

The actual automation of the pool pump is triggered every 5 minutes with a check that compares the current state of the system with how it should be. Since the pool pump should run at daytime to make use of my solar electricity, and cannot run during the night due to local council restrictions, I added a condition to only run the check from one hour before sunrise to one hour after sunset. The actual check is happening inside a custom component. I ruled out the other options – a script would not be powerful enough, and an app based on AppDaemon would introduce another level of complexity without a real benefit compared to Home Assistant’s custom component.
The reason for the regular checks instead of just calculating static on/off times is that this approach can survive outages, and will just pick up when Home Assistant is restarted.

automation:
  - alias: 'Pool Pump On'
    trigger:
      - platform: state
        entity_id: input_select.pool_pump
        to: 'On'
    action:
      service: homeassistant.turn_on
      entity_id: switch.wemo_insight_pool
  - alias: 'Pool Pump Off'
    trigger:
      - platform: state
        entity_id: input_select.pool_pump
        to: 'Off'
    action:
      service: homeassistant.turn_off
      entity_id: switch.wemo_insight_pool
  - alias: 'Check Pool Pump'
    trigger:
      - platform: time
        minutes: '/5'
        seconds: 00
    condition:
      condition: and
      conditions:
        - condition: sun
          after: sunrise
          after_offset: '-1:00:00'
        - condition: sun
          before: sunset
          before_offset: '1:00:00'
    action:
      service: pool_pump_service.check
      data:
        switch_entity_id: switch.wemo_insight_pool

Custom component

The code below follows this high-level structure:

  • If the pool pump mode is set to ‘Auto’, continue with the check.
  • If the sun is above the horizon, continue with the check, otherwise switch the pump off.
  • If set to swimming season, split the total time into 3 runs (1st and 3rd for 25% of the configured duration, and 2nd run for 50%), if in off season split the total time into 2 runs (1st and 2nd run for 50% of the configured duration each).
    Start the first run at the hard-coded number of minutes after sunrise and leave on for the calculated amount of time. Start the second run after the first one-hour break. And in swimming season schedule a third run, again after a break after the second run.

All the selected and hard-coded timings can be fine-tuned to match the individual circumstances. In my case, I am observing a steep increase in solar electricity production early in the morning and hence selected the start of the first run accordingly. In off season the second run is then happening around noon when the solar electricity production is at its peak. During swimming season the first run starts even earlier and a longer break happens in the afternoon before the third run finishes shortly before sunset – and shortly before solar electricity production decreases.

What is currently missing in this setup is displaying the next start or stop time.

# Check if pool pump is supposed to run, and turn it on or off accordingly
import logging

from datetime import timedelta

from homeassistant.helpers.sun import get_astral_event_date
from homeassistant.util import dt as dt_util

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'pool_pump_service'

ATTRIBUTE_SWITCH_ENTITY_ID = 'switch_entity_id'
OFF_SEASON_MAX_DURATION = 6.0
OFF_SEASON_RUN_1_AFTER_SUNRISE_OFFSET_MINS = 120
OFF_SEASON_1ST_BREAK_MINUTES = 60
SWIMMING_SEASON_MAX_DURATION = 8.25
SWIMMING_SEASON_RUN_1_AFTER_SUNRISE_OFFSET_MINS = 75
SWIMMING_SEASON_BREAK_1_MINUTES = 60
SWIMMING_SEASON_BREAK_2_MINUTES = 165

def setup(hass, config):

    """Set up is called when Home Assistant is loading our component."""
    def switch_pool_pump(switch_entity_id, target_state):
        switch = hass.states.get(switch_entity_id)
        if switch:
            if switch.state == target_state:
                # Already in the correct state
                _LOGGER.info("Switch is in correct state: %s", target_state)
            else:
                # Not in the correct state
                data = { "entity_id": switch_entity_id }
                if target_state == 'on':
                    hass.services.call('homeassistant', 'turn_on', data)
                else:
                    hass.services.call('homeassistant', 'turn_off', data)
                _LOGGER.info("Switched from '%s' to '%s'", switch.state,
                             target_state)
        else:
            _LOGGER.warning("Switch unavailable: %s", switch_entity_id)

    def handle_check(call):
        _LOGGER.info("Starting pool pump check")
        switch_entity_id = call.data.get(ATTRIBUTE_SWITCH_ENTITY_ID)
        # Read the pool pump configuration
        mode = hass.states.get('input_select.pool_pump')
        swimming_season = hass.states.get('input_boolean.swimming_season')
        run_hours_swimming_season = min(SWIMMING_SEASON_MAX_DURATION,
                                        float(hass.states.get(
                                              'input_number.run_pool_pump_hours_swimming_season').state))
        run_hours_off_season = min(OFF_SEASON_MAX_DURATION,
                                   float(hass.states.get(
                                         'input_number.run_pool_pump_hours_off_season').state))
        _LOGGER.info("* Pool pump mode: %s", mode.state)
        _LOGGER.info("* Swimming season: %s", swimming_season.state)
        _LOGGER.info("* Pool pump run hours swimming season: %s",
                     run_hours_swimming_season)
        _LOGGER.info("* Pool pump run hours off season: %s",
                     run_hours_off_season)
        # Only check if pool pump is set to 'Auto'
        if mode.state == 'Auto':
            _LOGGER.info("Pool pump set to 'Auto'")
            # Get sun details for today
            now = dt_util.now()
            _LOGGER.info("* Time is now %s", now)
            sun = hass.states.get('sun.sun')
            if sun.state == 'above_horizon':
                _LOGGER.info("* Sun above horizon")
                date = now.date()
                sunrise = get_astral_event_date(hass, 'sunrise', date)
                sunset = get_astral_event_date(hass, 'sunset', date)
                _LOGGER.info("* Sunrise: %s",
                             sunrise.astimezone(hass.config.time_zone))
                _LOGGER.info("* Sunset: %s",
                             sunset.astimezone(hass.config.time_zone))
                if swimming_season.state == 'on':
                    # Swimming Season (Summer)
                    _LOGGER.info("* Swimming season")
                    duration1 = run_hours_swimming_season * 60.0 * 0.25
                    duration2 = run_hours_swimming_season * 60.0 * 0.5
                    duration3 = run_hours_swimming_season * 60.0 * 0.25
                    _LOGGER.info(
                        "* Run pool pump 3 times for %s/%s/%s minutes",
                        duration1, duration2, duration3) 
                   # Check for 1st run
                    run_1_start = sunrise + timedelta(
                        minutes=SWIMMING_SEASON_RUN_1_AFTER_SUNRISE_OFFSET_MINS)
                    run_1_stop = run_1_start + timedelta(minutes=duration1)
                    _LOGGER.info("* Run 1/3: %s - %s",
                                 run_1_start.astimezone(hass.config.time_zone),
                                 run_1_stop.astimezone(hass.config.time_zone))
                    if run_1_start <= now <= run_1_stop:
                        # Turn on pool pump
                        _LOGGER.info("* Pool pump should be on (Run 1/3)")
                        switch_pool_pump(switch_entity_id, 'on')
                    else:
                        # Check for 2nd run
                        run_2_start = run_1_stop + timedelta(
                            minutes=SWIMMING_SEASON_BREAK_1_MINUTES)
                        run_2_stop = run_2_start + timedelta(minutes=duration2)
                        _LOGGER.info("* Run 2/3: %s - %s",
                                     run_2_start.astimezone(
                                         hass.config.time_zone),
                                     run_2_stop.astimezone(
                                         hass.config.time_zone))
                        if run_2_start <= now <= run_2_stop:
                            # Turn on pool pump
                            _LOGGER.info("* Pool pump should be on (Run 2/3)")
                            switch_pool_pump(switch_entity_id, 'on')
                        else:
                            # Check for 3rd run
                            run_3_start = run_2_stop + timedelta(
                                minutes=SWIMMING_SEASON_BREAK_2_MINUTES)
                            run_3_stop = run_3_start + timedelta(
                                minutes=duration3)
                            _LOGGER.info("* Run 3/3: %s - %s",
                                         run_3_start.astimezone(
                                             hass.config.time_zone),
                                         run_3_stop.astimezone(
                                             hass.config.time_zone))
                            if run_3_start <= now <= run_3_stop:
                                # Turn on pool pump
                                _LOGGER.info(
                                    "* Pool pump should be on (Run 3/3)")
                                switch_pool_pump(switch_entity_id, 'on')
                            else:
                                # Turn off pool pump
                                _LOGGER.info("* Pool pump should be off")
                                switch_pool_pump(switch_entity_id, 'off')
                else:
                    # Off Season (Winter)
                    _LOGGER.info("* Off season")
                    duration = run_hours_off_season * 60.0 * 0.5
                    _LOGGER.info("* Run pool pump 2 times for %s/%s minutes",
                                 duration, duration)
                    # Check for 1st run
                    run_1_start = sunrise + timedelta(
                        minutes=OFF_SEASON_RUN_1_AFTER_SUNRISE_OFFSET_MINS)
                    run_1_stop = run_1_start + timedelta(minutes=duration)
                    _LOGGER.info("* Run 1/2: %s - %s",
                                 run_1_start.astimezone(hass.config.time_zone),
                                 run_1_stop.astimezone(hass.config.time_zone))
                    if run_1_start <= now <= run_1_stop:
                        # Turn on pool pump
                        _LOGGER.info("* Pool pump should be on (Run 1/2)")
                        switch_pool_pump(switch_entity_id, 'on')
                    else:
                        # Check for 2nd run
                        run_2_start = run_1_stop + timedelta(
                            minutes=OFF_SEASON_1ST_BREAK_MINUTES)
                        run_2_stop = run_2_start + timedelta(minutes=duration)
                        _LOGGER.info("* Run 2/2: %s - %s",
                                     run_2_start.astimezone(
                                         hass.config.time_zone),
                                     run_2_stop.astimezone(
                                         hass.config.time_zone))
                        if run_2_start <= now <= run_2_stop:
                            # Turn on pool pump
                            _LOGGER.info("* Pool pump should be on (Run 2/2)")
                            switch_pool_pump(switch_entity_id, 'on')
                        else:
                            # Turn off pool pump
                            _LOGGER.info("* Pool pump should be off")
                            switch_pool_pump(switch_entity_id, 'off')
            else:
                _LOGGER.info("* Sun below horizon")
                # Turn pool pump if it's still running
                _LOGGER.info("* Pool pump should be off")
                switch_pool_pump(switch_entity_id, 'off')
        else:
            _LOGGER.info("Pool pump set to '%s'", mode.state)
    hass.services.register(DOMAIN, 'check', handle_check)
    # Return boolean to indicate that initialisation was successfully.
    return True

The code is registered as a service so that it can easily be used in an automation action.

The custom component is stored in a file [config_dir]/custom_components/pool_pump_service.py. And to make the custom component known to Home Assistant a simple configuration entry is required:

# Enable custom component
pool_pump_service:

Future improvements of the automation could include actual current power production and the weather forecast, so that for example the pool pump could be deferred if it’s cloudy in the morning while sunshine is predicted for the afternoon. Another improvement could be a better coordination of the pool pump with other appliances running during the day.

Monitoring – How much energy is used?

Knowing how much energy is used is not just a nice byproduct that the WeMo Insight switch provides. The current power usage is a very useful indicator if the pool pump is running – as opposed to just knowing if the switch is turned on. I also had a couple of occasions where Home Assistant claimed to have turned on the switch and showed it as on, but had actually lost the connection and neither switch nor pump were actually on.

sensor:
  - platform: template
    sensors:
      wemo_insight_pool_energy_today:
        value_template: '{% if (states.switch.wemo_insight_pool.attributes.today_energy_kwh) %}{{ states.switch.wemo_insight_pool.attributes.today_energy_kwh | float(2) }}{% else %}0.0{% endif %}'
        friendly_name: "WeMo Insight Pool Energy Today"
        unit_of_measurement: "kWh"
      wemo_insight_pool_current_power:
        value_template: '{% if is_state("switch.wemo_insight_pool", "on") %}{{ states.switch.wemo_insight_pool.attributes.current_power_w | float(0) }}{% else %}0{% endif %}'
        friendly_name: "WeMo Insight Pool Current Power"
        unit_of_measurement: "W"

The reason for the if-statements in the above configuration is that the WeMo Insight switch does not always report a value or does not report the attribute at all.

Monitoring – Pump running or not?

To know if the pool pump is actually running or not I am using the previous sensor that reports the current power usage of the switch. In the following binary sensor I am assuming that the pool pump is on if the switch reports more than 8W of power usage.

Pool pump running badge
binary_sensor:
  - platform: template
    sensors:
      pool_pump_running:
        value_template: "{{ states.sensor.wemo_insight_pool_current_power.state | float > 8 }}"
        friendly_name: "Pool Pump running"
        device_class: moving
Pool pump running dashboard widget

Monitoring – How long is the pump running?

Based on the binary template sensor that determines whether or not the pump is running, I can now use the history_stats sensor to tell me how long the pump has been running each day.

sensor:
  - platform: history_stats
    name: Pool Pump running today
    entity_id: binary_sensor.pool_pump_running
    state: 'on'
    type: time
    start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
    end: '{{ now() }}'

Reporting – The daily message

Showing the details on the Home Assistant dashboard is one thing, but I thought it would be useful to send myself a daily message confirming how many hours the pool pump had been running, compared to how long it was supposed to run. Since I already integrated Pushover, it was just a matter of formatting the message and send it out each day, 30 minutes after sunset.

automation:
  - alias: 'Report Pool Pump'
    trigger:
      - platform: sun
        event: sunset
        offset: '00:30:00'
    action:
      service: notify.pushover
      data_template:
        message: "Pool Pump was on for {{states.sensor.pool_pump_running_today.attributes.value}} today. 
({%- if is_state('input_boolean.swimming_season', 'on') -%}Swimming Season / {{ states.input_number.run_pool_pump_hours_swimming_season.state | round(0) }}h{%- else -%}Off Season / {{ states.input_number.run_pool_pump_hours_off_season.state | round(0) }}h{%- endif -%})."
        title: "Pool Pump Report"
        data:
          html: 1
Pool pump report via Pushover

Outlook

Now that the pool pump is fixed up, I will look at monitoring the water temperature in the next post.

Update 18 Apr 2019

Home Assistant 0.86 introduced time_pattern for triggering an automation on a regular basis. If you are using version 0.86 or later, please change the above automation for checking the pool pump to:

automation:
  - alias: 'Check Pool Pump'
    trigger:
      - platform: time_pattern
        minutes: '/5'
        seconds: 00
    condition:
      condition: and
      conditions:
        - condition: sun
          after: sunrise
          after_offset: '-1:00:00'
        - condition: sun
          before: sunset
          before_offset: '1:00:00'
    action:
      service: pool_pump_service.check
      data:
        switch_entity_id: switch.wemo_insight_pool

Smarter Swimming Pool Series

  1. Pool Pump
  2. Water Temperature
  3. Water Level
  4. Liquid Chlorine Level
  5. Improvements Under the Surface
  6. Chlorinator Refurbishment
  7. Pool Gate

Comments

34 responses to “Smarter Swimming Pool 1: Pool Pump”

  1. xbmcnut Avatar

    Love your work. Thanks for your detailed instructions. I want to replicate but I’m not strong on coding and doubting my ability to mod your custom service to have my pump run 1hr after sunrise for the programmed input select time. I run 8hrs in season and 4hrs off season. Is that something you could share without taking up too much of your time?

    1. malte Avatar
      malte

      Thanks for your feedback.
      The existing input sliders already allow you to control the duration in season and off season.
      And you can change the start of the pump by modifying the constants at the top of the custom component code. The following two control the offset after sunrise in minutes when the pump should run for off season and swimming season respectively. To start 60 minutes after sunrise, just change the values to 60.
      OFF_SEASON_RUN_1_AFTER_SUNRISE_OFFSET_MINS = 60
      SWIMMING_SEASON_RUN_1_AFTER_SUNRISE_OFFSET_MINS = 60

  2. Pierre Scerri Avatar
    Pierre Scerri

    Hi,

    Just what I’m looking for. Great job.

    Question:

    Max duration is defined in the ‘input_number’ definition and in the custom component code. Aren’t they the same? Or is there a reason for this?

    I’ve got the code running with a Sonoff Basic switch. Seems to be fine except that I can’t use the ‘Pump Running’ bit as there is no sense of power usage in the Sonoff. May I could us a Sonoff POW.

    Anyway thank you for that. I learned a lot just trying to get your setup to work on mine.

    1. malte Avatar
      malte

      Glad to hear that it’s working for you.

      Yes, in principle you are right about the max duration. The reason why I separated the two is that the input slider allows to select the desired duration in hours, and it requires its min and max configuration. In the custom component though I am just double-checking that the selected duration value is reasonable for this algorithm which tries to run the pump while the sun shines to use of solar electricity.
      For example, if you wanted going beyond the 8.25 hours during swimming season, you would probably need to adjust the breaks between the runs.

  3. Pierre Scerri Avatar
    Pierre Scerri

    Thank you for the feedback.

    Can you tell me where I can find information about the ‘Logging’ aspect of your code?

    1. malte Avatar
      malte

      I am using the standard logger, and if you haven’t changed the log configuration in HA, you should see entries under ‘custom_components.pool_pump_service’ at ‘INFO’ level in your log file. If that is too much information in the log file for you, you could change the log level, e.g.
      logger:   default: info   logs:     custom_components.pool_pump_service: warning

      1. Pierre Scerri Avatar
        Pierre Scerri

        Thank you. Great Stuff

  4. Pierre Scerri Avatar
    Pierre Scerri

    Thank you. That’s it. Great Stuff.

  5. Michael lindborg Avatar
    Michael lindborg

    Great write-up! I will be looking closer at this as we reach spring. The pool is still under 50cm of snow here in Sweden. In season, my pool pump runs more or less 24×7 in order for the heat pump to work. An issue that I will be looking to automate is that some weeks, there is soo much pollen and debris from surrounding trees that the filter gets clogged, the flow is reduced and the heat pump stops. I have ordered a flow sensor that will be connected to an esp8266 sending mqtt messages to Home Assistant. Whenever the flow drops benath certain threshold, I will get a notification and hopefully be able to correct before heat pump stops. If heat pump stops, pool pump should be stopped as well.

    1. malte Avatar
      malte

      Thanks. Good idea to monitor the water flow. I have a similar challenge here and was already thinking about various approaches.

  6. Pierre Scerri Avatar
    Pierre Scerri

    Hi

    Lately (Hassio 0.93.2) the pool_pump_service has not been running and giving this error:

    Sun Jun 02 2019 18:46:01 GMT+0200 (CEST)

    ‘NoneType’ object has no attribute ‘lower’
    Traceback (most recent call last):
    File “/usr/local/lib/python3.7/site-packages/homeassistant/components/websocket_api/commands.py”, line 121, in handle_call_service
    connection.context(msg))
    File “/usr/local/lib/python3.7/site-packages/homeassistant/core.py”, line 1141, in async_call
    self._execute_service(handler, service_call))
    File “/usr/local/lib/python3.7/site-packages/homeassistant/core.py”, line 1165, in _execute_service
    await self._hass.async_add_executor_job(handler.func, service_call)
    File “/usr/local/lib/python3.7/concurrent/futures/thread.py”, line 57, in run
    result = self.fn(*self.args, **self.kwargs)
    File “/config/custom_components/pool_pump_service.py”, line 168, in handle_check
    switch_pool_pump(switch_entity_id, ‘off’)
    File “/config/custom_components/pool_pump_service.py”, line 29, in switch_pool_pump
    switch = hass.states.get(switch_entity_id)
    File “/usr/local/lib/python3.7/site-packages/homeassistant/core.py”, line 829, in get
    return self._states.get(entity_id.lower())
    AttributeError: ‘NoneType’ object has no attribute ‘lower’

    1. malte Avatar
      malte

      Hi Pierre,

      the only way I could reproduce this is if the service call is missing the switch_entity_id altogether.
      Could you please double-check that your automation that calls the pool_pump_service.check actually does define this parameter?

      The action part should look something like shown above, for example in the “Update 18 Apr 2019” section (sorry, the comments section here does not support indentation, so yaml configuration doesn’t really work in here).

  7. Gaetan Avatar
    Gaetan

    Dear Malte,

    Many thanks for your great work that inspire me!
    I test some automation now with template condition instead of custom_component, it seems to work fine. I store some calculated timestamp in sensor (cycle1_start, cycle1_stop etc) and I make 2 automations “Auto On” and “Auto Off” like that :
    - alias: 'Pool Pump Auto Off' trigger: - platform: time_pattern minutes: '/5' condition: - condition: state entity_id: input_boolean.pool_wintering state: 'off' - condition: state entity_id: input_select.pool_pump state: 'Auto' - condition: state entity_id: switch.pool_pump state: 'on' - condition: template value_template: >- {{ not ((states('sensor.now_timestamp') >= states('sensor.pool_pump_cycle1_start') and states('sensor.now_timestamp') = states('sensor.pool_pump_cycle2_start') and states('sensor.now_timestamp') = states('sensor.pool_pump_cycle2_start') and states('sensor.now_timestamp') <= states('sensor.pool_pump_cycle3_stop'))) }} action: service: switch.turn_off entity_id: switch.pool_pump

    Have a nice day
    Gaetan

    1. Pro2col Avatar
      Pro2col

      Gaetan, could you show me more on your sensor cycles ? Id like to try your method as I too am having the same problem as Pierre (AttributeError: ‘NoneType’ object has no attribute ‘lower’)

      I dont have a switch for my sonfoff avaialble called switch_pool_pump, but only light.pool_pump and not sure how to edit the Python code for that or change light to switch.

      Thanks

      1. malte Avatar
        malte

        Hi Pro2col,
        as also just mentioned on the HA community forum, please have a look if you can find a more detailed error message in your log file. This would help with troubleshooting.

  8. Giovanni Avatar
    Giovanni

    Hi, is there a way not to block the pump even after sunset? that is, based only on the starts and the total time set?

    1. malte Avatar
      malte

      Hi Giovanni,
      the above code does not actually block the pump after sunset. The first run of the day is based on sunrise, but the pump would just keep going and not stop at sunset.
      However, to ensure the whole system is in balance, you should look at a few things:
      1. The automation that checks if the pump should be running or not must run longer to ensure that the pump will be shut off eventually. You could either just remove the two conditions that limit the check, or change the offsets.
      2. You may need to increase the max values of the input_number sliders that define the number of hours per day, so that you can run the pump longer.
      3. If you change the max of the input_number sliders then you have to adjust the constants SWIMMING_SEASON_MAX_DURATION and OFF_SEASON_MAX_DURATION which I built in as a safeguard.

  9. Giovanni Avatar
    Giovanni

    Thanks Malte,

    i change all things, but about 10 minute before sunset the pump go off:

    2020-04-18 19:35:00 INFO (MainThread) [homeassistant.components.automation] Executing Check Laghetto Pump
    2020-04-18 19:35:00 INFO (MainThread) [homeassistant.components.automation] Check Laghetto Pump: Running script
    2020-04-18 19:35:00 INFO (MainThread) [homeassistant.components.automation] Check Laghetto Pump: Executing step call service
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] Starting laghetto pump check
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Laghetto pump mode: Auto
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Laghetto season: off
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Laghetto pump run hours laghetto season: 12.0
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Laghetto pump run hours off season: 12.0
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] Laghetto pump set to ‘Auto’
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Time is now 2020-04-18 19:35:00.021030+02:00
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Sun above horizon
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Sunrise: 2020-04-18 06:13:55+02:00
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Sunset: 2020-04-18 19:34:57+02:00
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Off season Laghetto
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Run 1/3: 2020-04-18 07:13:55+02:00 – 2020-04-18 13:13:55+02:00
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Run 2/3: 2020-04-18 14:13:55+02:00 – 2020-04-18 17:13:55+02:00
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Run 3/3: 2020-04-18 18:13:55+02:00 – 2020-04-18 21:13:55+02:00
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] * Laghetto pump should be on (Run 3/3)
    2020-04-18 19:35:00 INFO (SyncWorker_11) [custom_components.laghetto_pump_service] Switch is in correct state: on
    —–
    5 minute later:

    2020-04-18 19:40:00 INFO (MainThread) [homeassistant.components.automation] Executing Check Laghetto Pump
    2020-04-18 19:40:00 INFO (MainThread) [homeassistant.components.automation] Check Laghetto Pump: Running script
    2020-04-18 19:40:00 INFO (MainThread) [homeassistant.components.automation] Check Laghetto Pump: Executing step call service
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] Starting laghetto pump check
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] * Laghetto pump mode: Auto
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] * Laghetto season: off
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] * Laghetto pump run hours laghetto season: 12.0
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] * Laghetto pump run hours off season: 12.0
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] Laghetto pump set to ‘Auto’
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] * Time is now 2020-04-18 19:40:00.019980+02:00
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] * Sun below horizon
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] * Laghetto pump should be off
    2020-04-18 19:40:00 INFO (SyncWorker_2) [custom_components.laghetto_pump_service] Switched from ‘on’ to ‘off’

    1. malte Avatar
      malte

      Yes, of course, I forgot that there is a check built in that turns the pump off after sunset.
      The simplest way – without making too many changes to the source code – would be to just ignore the state of the sun:

      BEFORE

      if sun.state == 'above_horizon':
          _LOGGER.info("* Sun above horizon")

      AFTER

      if True:
          _LOGGER.info("* Sun %s", sun.state)
  10. Giovanni Avatar
    Giovanni

    Hi malte,

    everything went well until a few days ago, and now I have these errors for laghetto_pump_service which I have renamed. https://paste.ubuntu.com/p/rz35Nhh5hQ/

    1. malte Avatar
      malte

      Hi Giovanni, has this issue started when you upgraded to 0.109? Is there anything wrong in the frontend, like an entity not showing at all or with a wrong translation?
      There are open issues that contain very similar stacktraces to the one you see: https://github.com/home-assistant/core/issues/34977 and https://github.com/home-assistant/core/issues/34857

      1. Giovanni Avatar
        Giovanni

        Thanks

        1. malte Avatar
          malte

          Please check if an upgrade to 0.109.3 fixes your issue. That release includes: Fix translation merging for custom components without translations #35032

  11. Johan Avatar
    Johan

    Hi Malte,

    The solution you found for your pool problems are genius. I am very new to Homeassistant but would like to implement your solution. Can you point me in the right direction to read about adding custom components to HA. It is unclear where to add all the code.

    I was thinking that somehow HA will pick up the custom components when the files on github are added to custom_components/pool_pump but it did not. At least not for me.

    Thank you in advance!

    Regards,

    Johan

    1. malte Avatar
      malte

      Hi Johan,
      thanks for your feedback and your interest.
      Basically you need to create the custom_components folder inside your configuration folder, i.e. where your configuration.yaml is located.
      BTW: In the meantime I’ve uploaded the custom component code to GitHub.

      Also, if you run Home Assistant in a way that support HACS, you may want to consider taking a look at this add-on which is based on my code above.
      Thanks,
      Malte

  12. moliveira Avatar
    moliveira

    Hi,
    I have 3 electricity tariff, can the automations be change so automation only runs on lower tariffs periods?

    1. malte Avatar
      malte

      Hi moliveira, sure, you could do that. Are your tariffs fixed to certain times of the day or are they varying? If fixed time, then you could probably get away with a much simpler approach to run your pool pump for a period of time within the timeframe when you pay least for electricity.
      My main driver for this custom component was that I am trying to use as much solar electricity as possible, hence the focus on running the pool pump when the sun is shining 🙂

      1. moliveira Avatar
        moliveira

        Hi malte,
        Yes they are fixed I just wanted to adapt this custom component with an option to run on lower tariffs. But not being able to do it…

  13. Giovanni Avatar
    Giovanni

    Hi malte, the integration dosen’t work, maybe for new version of HA?

    1. malte Avatar
      malte

      Hi Giovanni, do you get an error message? A couple of HA versions ago the requirement for custom integrations to have a version number has been enforced.
      Please compare your version with the current version on GitHub – specifically the file manifest.json.

  14. Giovanni Avatar
    Giovanni

    Hi malte,

    im getting this error from HA:

    Check Pool Pump: Error executing script. Unexpected error for call_service at pos 1: tzinfo argument must be None or of a tzinfo subclass, not type ‘str’
    While executing automation automation.check_pool_pump
    Traceback (most recent call last):
    File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 379, in _async_step
    await getattr(self, handler)()
    File “/usr/src/homeassistant/homeassistant/helpers/script.py”, line 582, in _async_call_service_step
    await service_task
    File “/usr/src/homeassistant/homeassistant/core.py”, line 1634, in async_call
    task.result()
    File “/usr/src/homeassistant/homeassistant/core.py”, line 1677, in _execute_service
    await self._hass.async_add_executor_job(
    File “/usr/local/lib/python3.9/concurrent/futures/thread.py”, line 58, in run
    result = self.fn(*self.args, **self.kwargs)
    File “/config/custom_components/pool_pump_service/__init__.py”, line 81, in handle_check
    sunrise.astimezone(hass.config.time_zone))
    TypeError: tzinfo argument must be None or of a tzinfo subclass, not type ‘str’

    Can You help me?

    1. malte Avatar
      malte

      Hi Giovanni, I think the issue here is in a log statement where sunrise time is converted into the local timezone, and apparently the date library has changed and is now expecting a timezone parameter, not a string.
      You could try to replace all occurrences of astimezone(hass.config.time_zone) with astimezone(dt_util.get_time_zone(hass.config.time_zone)) and see if that fixes the issue.
      Other than that, I’d recommend taking a look at a refurbished version of my pool pump manager on GitHub.

  15. Dean Avatar

    Thanks for these posts!.
    Annoyingly, i’ve just gotten into Home Assistant and you’ve now opened a whole kettle of fish!
    Off to buy some 40mm pipe, plenty of adaptors and some sensors 🙂 Plenty of time till the summer season here on the central coast

    1. malte Avatar
      malte

      Hi Dean, thanks for your message. It’s indeed the best time to experiment with pool automations now until the next swimming season starts.
      I’m wiring up a reed switch for the pool gate at the moment – more blog posts coming soon.

Leave a Reply

Your email address will not be published. Required fields are marked *