Automation to trigger pool chlorine dosing pump

I have been tuning this automation for about a month now but I cannot get it to work quite the way I want it to.

I want this automation to take a reading from sensor.pool_fc. If this reading is below 4 and the pool pump has been running for at least 30 mins, execute the automation to inject chlorine.

The pool pump runs 2x a day for 4 hours each time. I want the automation to wait until the pool pump has running for 30 mins before triggering so fresh water can be read from the sensors. After 30 mins of pump run time and if the free chlorine has been below 4 for 30 mins the chlorinator automation runs and injects chlorine. I then want the automation to delay for 55 minutes so the chlorine has time to disperse and then run again. The problem is the automation does not run again. The free chlorine is below 4, the pump has been running for over 30 mins and the automation is not triggering.

Here is a history of the sensor.pool_fc that show is has been consistently below 4 for 24 hours:

image

During this 24 hour period the automation attempted to run at 1am, 1:21am, 3:53am and 4:54am. The pump was not running at this time so the automation did not run. The pump was running from 5-9am and from 3-7pm and the fc was below 4 but the automation did not run.

Any suggestions to clean up the automation and get it to run the way I would like it to?

alias: Pool Auto Chlorinator
description: ''
trigger:
  - platform: numeric_state
    entity_id: sensor.pool_fc
    below: '4'
    for: '00:30:00'
condition:
  - condition: state
    entity_id: switch.sonoff_pool_pump
    state: 'on'
    for: '00:30:00'
action:
  - service: automation.trigger
    target:
      entity_id: automation.pool_increase_cl_1ppm
  - service: automation.trigger
    target:
      entity_id: automation.bleach_pump_activate
  - delay:
      hours: 0
      minutes: 55
      seconds: 0
      milliseconds: 0
mode: restart

Your numeric state trigger only fires when sensor.pool_fc’s value goes from above 4 to below 4 and stays there for half an hour.

Just a simple proof of concept:
I would add a trigger for the pump being on for 30 minutes and an extra condition to check if sensor.pool_fc has been below 4 for 30 minutes.

This still does not handle the second injection after 55 minutes. It could potentially fire a second injection if sensor.pool_fc rose above 4, fell below 4 and stayed there for 30 minutes.

I don’t think the delay at the end is the way to go.

Maybe your sensor was temporarily unavailable and triggered the automation 30 minutes after it came back online. Although than wouldn’t explain why it triggered at 1:21, that’d be too early after 1:00am.

Post all of the automations. It appears that three are involved but only one has been posted.

try this:

trigger:
  - platform: numeric_state
    entity_id: sensor.pool_fc
    below: '4'
    for: '00:30:00'
  - platform: state
    entity_id: switch.sonoff_pool_pump
    to: 'on'
    for: '00:30:00'
  - platform: template
    value_template: >
      {{ (as_timestamp(now()) - as_timestamp(states.automation.<whatever_the_entity_id_for_this_automation>.attributes.last_triggered)) > 3300 }}
condition:
  - condition: state
    entity_id: switch.sonoff_pool_pump
    state: 'on'
    for: '00:30:00'
  - condition: numeric_state
    entity_id: sensor.pool_fc
    state: '4'
    for: '00:30:00'
action:
  - service: automation.trigger
    target:
      entity_id: automation.pool_increase_cl_1ppm
  - service: automation.trigger
    target:
      entity_id: automation.bleach_pump_activate
mode: restart

it will triiger after the pump is running for 30 minutes then check the chlorine

it will trigger when the chlorine goes below 4 for 30 minutes then checks the pump

it will trigger when the automation ran more than 55 minutes ago and check the pump and chlorine.

I think that should work. Obviously not tested since I don’t have a pool :slightly_smiling_face:

1 Like

I tried your suggestion. It appears you cannot have a numeric state condition with a for value as it threw an error so I tried it without it. I figured have the sensor_pool_fc below 4 for 30 mins in the trigger would be enough of a safe guard.

Unfortunately it is still not running the automation every 55 mins. Here is the history:
image

The Pool_fc has been above 4 for the last 24 hours so I did not expect it to runthe actions but from what the history is showing it only executed 5x during 24 hourrs.

alias: Pool Auto Chlorinator
description: ''
trigger:
  - platform: numeric_state
    entity_id: sensor.pool_fc
    below: '4'
    for: '00:30:00'
  - platform: state
    entity_id: switch.sonoff_pool_pump
    to: 'on'
    for: '00:30:00'
  - platform: template
    value_template: >-
      {{ (as_timestamp(now()) -
      as_timestamp(states.automation.pool_auto_chlorinator.attributes.last_triggered))
      > 3300 }}
condition:
  - condition: state
    entity_id: switch.sonoff_pool_pump
    state: 'on'
    for: '00:30:00'
  - condition: numeric_state
    entity_id: sensor.pool_fc
    below: '4'
action:
  - service: automation.trigger
    target:
      entity_id: automation.pool_increase_cl_1ppm
  - service: automation.trigger
    target:
      entity_id: automation.bleach_pump_activate
mode: restart

Here is the Pool increase CL 1ppm:

alias: Pool Increase CL 1ppm
description: ''
trigger: []
condition: []
action:
  - service: input_number.set_value
    data:
      entity_id: input_number.bleach_pump_duration
      value: 72
mode: single

and the Bleach pump activate:

- alias: Bleach_pump_activate
trigger:
  - platform: state
    entity_id: input_boolean.bleach_pump_start
    to: 'on'
action:
  - service: mqtt.publish
    data_template:
      {
         "topic": "Pool",
         "payload": "orp:on:{{ states.input_number.bleach_pump_duration.state|int }}"
      }
  - delay: '00:00:01'
  - service: input_boolean.turn_off
    data:
      entity_id: input_boolean.bleach_pump_start

I agree with your thinking about why it may not be triggering again. It does occasionally drop drop the sensor for short periods of time. I tried to get around that by using a mean value for the sensor. I created sensor.pool_fc_mean but also experienced the same issue. I did notice that 1-2 times that the mean sensor would also become invalid. That was probably due to the sensor.pool_fc going offline for the sampling period. Maybe I should look to see if it is possible to create a mean sensor that ignores nan values? I do not know if that is possible.

  - platform: statistics
    entity_id: sensor.pool_fc
    name: pool_fc_mean
    sampling_size: 30
    max_age: 1800

The documentation indicates a Numeric State Trigger supports the use of the for option.

It seems to work as a trigger but not as a condition. None of the examples in the documentation that I can find use the “for” option in a condition and the editor throws an error message when I try to add it.

Maybe I am missing something but there is not option in the editor to add it when you are using it as a condition:

and here is the error when I am editing in yaml mode and try to add it:

You are correct. I misread what you wrote. Whereas both State Trigger and State Condition support an optional for, only Numeric State Trigger supports it, not Numeric State Condition.

It won’t run the automation every 55 minutes.

it only runs the automation at 55 minutes if the automation was run the first time by the chlorine and pump conditions.

after the pump/chlorine conditions are met the first time and the automation runs then 55 minutes later it will check the pump/chlorine conditions again. If those conditions aren’t met (i.e. everything is good) then the automation won’t run until the pump/chlorine conditions are met again (i.e. chlorine low with the pump running) then it will run again.

then after 55 minutes it checks the conditions again…etc…

I believe I am following your lodging. But the automation is not running even when the conditions are being met. For example it will run first time in the morning and then wait 55 minutes. The conditions are still valid for it to run again, for example the pump is still running and the chlorine is below 4 but the automation will not run again or it runs at random and weird times.

What are your thoughts about creating another automation that just triggers this automation every hour?

can you look in the automation trace for it and see why it’s not running when you expect it to and/or when it runs at random and weird times?

OK, just to recap…

  1. the pump turns on at 5am.

  2. 30 minutes later the automation triggers.

  3. the automation checks to see if the chlorine is below 4 (and that the p[ump is running but that was established by the trigger).

  4. if it is then the automation runs the actions. it also sets the time that the automation was last_triggered.

  5. 55 minutes later it triggers again based on the last_triggred time.

  6. it checks that the pump has been running for 30 minutes and that the chlorine is still below 4.

  7. if yes then it runs the actions and resets the last_triggered time. rinse and repeat. if no then everything stops.

  8. if at some point the chlorine falls below 4 for 30 minutes the automation will then trigger.

  9. it checks that the pump has been running for 30 minutes.

  10. it runs the actions and sets the last_triggered time.

  11. restart at step 5 above.

  12. repeat all of the above actions for the pump starting at 3pm.

if the chlorine goes below 4 at any point during the time period of 5-9am or 3-7pm it will trigger the automation (whether the actions run depends on the pump status). it doesn’t need to be more than 55 minutes since the last time it ran. it is triggered by the chlorine level.

Create a Trigger-based Template Binary Sensor that reports on when the value of sensor.pool_fc is below 4 for at least 30 minutes. It reports off when the value is above 4 for at least a minute (adjust the duration to suit your preference).

template:
  - trigger:
      - platform: numeric_state
        entity_id: sensor.pool_fc
        below: 4
        for: '00:30:00'
      - platform: numeric_state
        entity_id: sensor.pool_fc
        above: 4
        for: '00:01:00'
      - platform: event
        event_type: event_template_reloaded
    binary_sensor:
      - name: Low Chlorine
        state: '{{ states('sensor.pool_fc') | float <= 4 }}'

Create the following automation.

alias: Pool Auto Chlorinator
mode: restart
trigger:
- platform: state
  entity_id: switch.sonoff_pool_pump
  to: 'on'
  for: '00:30:00'
condition: "{{ is_state('binary_sensor.low_chlorine', 'on') }}"
action:
- repeat:
    while:
    - "{{ states('sensor.pool_fc') | float <= 4 }}"
    - "{{ repeat.index <= 2 }}"
    sequence:
    - service: mqtt.publish
      data:
        topic: Pool
        payload: "orp:on:72"
    - delay: '00:55:00'

How it works

The automation is triggered when the pump is on for at least 30 minutes. If binary_sensor.low_chlorine is on, it proceeds to execute the action.

The action performs a maximum of two repetitions of injecting chlorine (by publishing orp:on:72 to the pool topic). The first iteration is virtually guaranteed because the value of sensor.pool_fc is less than 4 and repeat.index hasn’t incremented yet. After publishing the payload it waits for 55 minutes.

After 55 minutes have passed it attempts to perform a second iteration but only if the free chlorine level is still below 4. If it is then more chlorine is injected and it waits another 55 minutes. After the delay expires, it will exit because repeat.index is already 2 so it cannot repeat a third time (even if free chlorine is remains below 4). However, if you wish to allow it perform a potential third repetition, just change 2 to 3 in "{{ repeat.index <= 2 }}"


EDIT

Added third trigger to the Trigger-based Template Binary Sensor to ensure template is updated whenever template entities are reloaded.

Yes you have it correct. I have looked at the trace json but it only shows the last execution. For example the last time it executed was 5:30am. As I am typing this it is 6:53an. I expected it to have run at 6:25am

{
  "trace": {
    "last_step": "condition/1/entity_id/0",
    "run_id": "672717",
    "state": "stopped",
    "script_execution": "failed_conditions",
    "timestamp": {
      "start": "2021-09-11T09:30:00.027918+00:00",
      "finish": "2021-09-11T09:30:00.028212+00:00"
    },
    "domain": "automation",
    "item_id": "1626787528516",
    "trigger": "state of switch.sonoff_pool_pump",
    "trace": {
      "trigger/1": [
        {
          "path": "trigger/1",
          "timestamp": "2021-09-11T09:30:00.028070+00:00",
          "changed_variables": {
            "trigger": {
              "platform": "state",
              "entity_id": "switch.sonoff_pool_pump",
              "from_state": {
                "entity_id": "switch.sonoff_pool_pump",
                "state": "off",
                "attributes": {
                  "friendly_name": "Sonoff Pool Pump",
                  "icon": "mdi:pool"
                },
                "last_changed": "2021-09-10T23:00:00.051412+00:00",
                "last_updated": "2021-09-10T23:00:00.051412+00:00",
                "context": {
                  "id": "038c44539ef711f7fc4611ca21a615e2",
                  "parent_id": null,
                  "user_id": null
                }
              },
              "to_state": {
                "entity_id": "switch.sonoff_pool_pump",
                "state": "on",
                "attributes": {
                  "friendly_name": "Sonoff Pool Pump",
                  "icon": "mdi:pool"
                },
                "last_changed": "2021-09-11T09:00:00.026395+00:00",
                "last_updated": "2021-09-11T09:00:00.026395+00:00",
                "context": {
                  "id": "3b37242fa9a1b6e70e9bde8ed9c0b823",
                  "parent_id": null,
                  "user_id": null
                }
              },
              "for": {
                "__type": "<class 'datetime.timedelta'>",
                "total_seconds": 1800
              },
              "attribute": null,
              "description": "state of switch.sonoff_pool_pump",
              "id": "1"
            }
          }
        }
      ],
      "condition/0": [
        {
          "path": "condition/0",
          "timestamp": "2021-09-11T09:30:00.028100+00:00",
          "result": {
            "result": true
          }
        }
      ],
      "condition/0/entity_id/0": [
        {
          "path": "condition/0/entity_id/0",
          "timestamp": "2021-09-11T09:30:00.028119+00:00",
          "result": {
            "result": true,
            "state": "on",
            "duration": "2021-09-11T09:00:00.028139+00:00"
          }
        }
      ],
      "condition/1": [
        {
          "path": "condition/1",
          "timestamp": "2021-09-11T09:30:00.028168+00:00",
          "result": {
            "result": false
          }
        }
      ],
      "condition/1/entity_id/0": [
        {
          "path": "condition/1/entity_id/0",
          "timestamp": "2021-09-11T09:30:00.028184+00:00",
          "result": {
            "result": false,
            "state": 8.55,
            "wanted_state_below": 4
          }
        }
      ]
    },
    "config": {
      "id": "1626787528516",
      "alias": "Pool Auto Chlorinator",
      "description": "",
      "trigger": [
        {
          "platform": "numeric_state",
          "entity_id": "sensor.pool_fc",
          "below": "4",
          "for": "00:30:00"
        },
        {
          "platform": "state",
          "entity_id": "switch.sonoff_pool_pump",
          "to": "on",
          "for": "00:30:00"
        },
        {
          "platform": "template",
          "value_template": "{{ (as_timestamp(now()) - as_timestamp(states.automation.pool_auto_chlorinator.attributes.last_triggered)) > 3300 }}"
        }
      ],
      "condition": [
        {
          "condition": "state",
          "entity_id": "switch.sonoff_pool_pump",
          "state": "on",
          "for": "00:30:00"
        },
        {
          "condition": "numeric_state",
          "entity_id": "sensor.pool_fc",
          "below": "4"
        }
      ],
      "action": [
        {
          "service": "automation.trigger",
          "target": {
            "entity_id": "automation.pool_increase_cl_1ppm"
          }
        },
        {
          "service": "automation.trigger",
          "target": {
            "entity_id": "automation.bleach_pump_activate"
          }
        }
      ],
      "mode": "restart"
    },
    "blueprint_inputs": null,
    "context": {
      "id": "51947be4820a13bc5c2fd6dd8738e26d",
      "parent_id": "3b37242fa9a1b6e70e9bde8ed9c0b823",
      "user_id": null
    }
  },
  "logbookEntries": []
}

This looks great. When I get back home this afternoon I will try it. Thank you very much for spending the time to write this up.

If you look at the conditions it tells you why it didn’t run:

      "condition/1/entity_id/0": [
        {
          "path": "condition/1/entity_id/0",
          "timestamp": "2021-09-11T09:30:00.028184+00:00",
          "result": {
            "result": false,
            "state": 8.55,
            "wanted_state_below": 4

the state of chlorine was 8.55. the condition is less than 4

the automation actions won’t run if the pump is off or chlorine is above 4. those are the conditions.

I did not think about this before I posted the trace…There has been no need for the automation to run for the last 24 hours as the chlorine levels have been above 4. When they drop below 4 and the pump has been running for at least 30 mins and the automation does not run, I will post that trace.

@123 I have having an issue creating the template sensor. I have my config split into files:
sensor: !include sensors.yaml
binary_sensor: !include binarysensor.yaml

I have added the template code to my binarysensor.yaml:

  - platform: template
    trigger:
      - platform: numeric_state
        entity_id: sensor.pool_fc
        below: 4
        for: '00:30:00'
      - platform: numeric_state
        entity_id: sensor.pool_fc
        above: 4
        for: '00:01:00'
      - platform: event
        event_type: event_template_reloaded
    binary_sensor:
      - name: Low Chlorine
      - state: "{{ states('sensor.pool_fc') | float <= 4 }}"

But i am getting this error when I check my config:
Invalid config for [binary_sensor.template]: [trigger] is an invalid option for [binary_sensor.template]. Check: binary_sensor.template->trigger. (See ?, line ?).

Do you know what I am doing wrong?

Yes; you attempted to change the example I posted.

Compare the Trigger-based Template Binary Sensor example I posted to what you just posted. You discarded the first line and replaced it with something very different. In effect, you attempted to convert it to a legacy-style Template Binary Sensor which not only uses different syntax but doesn’t even support the concept of triggers.