Identify if device is running longer than it should

One of my kids left an outdoor water spigot on (was hooked to a long hose so I didn’t notice immediately) last night.
The well pump is powered through a GE 40A Smart (zwave) switch.
As you can see it’s pretty obvious when the accidental usage started.
How can I monitor abnormalities, in the cleanest/most intuitive way, like this so that I can then turn off the switch and send an alert? I am sure this isn’t an uncommon ask but am not finding what I am looking for or think I am looking for.
Have been meaning to do this since I got the switch but figure this is a good time to get it done. Well 24hours ago would have been better :slight_smile:

Let’s say the maximum time the well pump should run is 15 minutes. Start/stop a 15-minute timer whenever the pump switch turns on/off.

If the timer expires it means the pump has been running for 15 minutes. Use the timer’s finished event as a trigger to turn off the pump switch (and anything else you want to do).

A timer can survive a restart of Home Assistant (provided you enable the feature) which is an important consideration. Other mechanisms in Home Assistant that handle elapsed time (for, delay, wait_template, etc) are reset by a restart.

Let me know if you need help composing the automation to implement my suggestion.

Thanks @123 . So the GE switch actually never gets turned on or off unless for a proposed situation like this. It’s the dumb pressure switch on the well pump that handles all that. The GE switch is just the only way to monitor electric usage and even that won’t be a constant usage even if the water is running wide open due to the pressure tank cause the pump to go on and off.

Your suggestion may still work for this and I am missing it.
I was thinking I’d have to do something like:

if (Current kwh - 1 hour ago kwh) > Y then shut off GE switch and send alert

Where Y is a value I can tweak. Could start aggressively with .5 based on what I am seeing from last night.

We do run portable sprinklers during dry times like this so it’s not unusual for the pump to have ~hour long spikes but even then it would be good to know and ensure a sprinkler isn’t forgotten.

Based on your explanation, I agree you should base it on energy usage.

I could definitely use and appreciate some help with that. At the point where I can modify templates but not create them from scratch yet and feel confident about it.

Found this:

- platform: integration
  name: energy_per_hour
  unit_time: h
  unit_prefix: k
  source: sensor.well_pump_electric_consumption_kwh
  round: 3

Maybe that’s all I need and then use that in an automation?

Edit: nevermind - I don’t think this is it. :thinking:

Any suggestions?
Possible to do without a SQL query?

I have a dual well pump system and have been doing this for a while. I would invert the problem a bit and also improve your system.

  1. Determine how many GPM the pump produces. (Fill pressure tank, disable pump, open faucet remove/measure water until pressure switch triggers, close faucet, enable pump, measure time until pressure switch turns off)
  2. With that data you can now calc daily, hourly, weekly - water usage.

There are four conditions to test for:

  1. Pump Long Run - if the pump runs longer than X minutes, something is wrong (like a blown pipe), and it should fault off. X is something you determine empirically based on measuring your system.
  2. Pump Low Current - if the pumps current drops below Y for more than Z measurements it should fault off. This is indicative of running out of water in the well. Note: pump current is inversely related to water level in well. Less current = Less water in well. Counterintuitive but correct. Hence monitoring the last current measurements of each well cycle - gives you a good indication of ground water availability,
  3. Pump High Current - if the pumps current goes above W for more than V measurements it should fault off. This is indicative of a pump that is starting to fail and needs replacement
  4. Too much water being used per unit time (this is your question.). I’d use a utility meter integration with a timed reset and look for this threshold to be exceeded.

I have a full portable package that does most of this, happy to share if you want To see it.

1 Like

I would think that a trend sensor covers this use case pretty well → Trend - Home Assistant

Use a delay_on for perhaps 90 minutes to cover the sprinkler situation Template - Home Assistant

Then use an alert to notify you Alert - Home Assistant

1 Like

All those conditions sound great and spot on for what I need and situations I hadn’t thought about handling. If you could share that, I’d really appreciate it.

Here it is. I created this as my first HA package, and hence I’m sure there are better ways to do some of the functions. However, since it’s been running rock solid at 2 houses for several years, it’s low on my priority list to update.

The packages need two inputs. One is the current from the well (sensor.well), the other is a 120v voltage reading (sensor.switch_2_voltage). For outputs there is the switch to enable / disable the well (switch.well). These are setup for 1hp well pumps. You may need to adjust the 8.7 constant based on amps your pump draws. My current sensors are CT clamps coming through modbus and I’m able to read them every 3-5 seconds. I don’t know how often your GE device sends this info.

binary_sensor:
  - platform: template
    sensors:
      well_state:
        value_template: >-
          {{ states('sensor.well')|float > 2.0 }}
sensor:
  - platform: template
    sensors:
      well_last:
        unit_of_measurement: Amp
        value_template: >-
          {{ states('input_number.well_last') }}
        device_class: current
      well_last_resistance:
        unit_of_measurement: Ohm
        value_template: >-
          {{ states('input_number.well_last_resistance') }}
      well_last_duration:
        unit_of_measurement: sec
        value_template: >-
          {{ states('input_number.well_last_duration_i') }}
      well_cycles:
        value_template: >-
          {{ states('input_number.well_cycle') }}
      well_watts:
        unit_of_measurement: W
        value_template: >-
          {{ (states('sensor.well')|float(0) * states('sensor.switch_2_voltage')|float(0) * 2.0)|int(0) }}
        device_class: power
      well_resistance:
        value_template: >-
          {% if states('sensor.well')| float(0) > 8.9 -%}
          {{  ((states('sensor.switch_2_voltage')|float(0) * 2.0)  /  states('sensor.well')|float(0))| round(2) }}
          {%- else -%}
          0.0
          {%- endif %}
        unit_of_measurement: Ohm
      well_run_volume:
        unit_of_measurement: G
        value_template: >-
          {{ states('input_number.well_run_counter')|float * states('input_number.well_gpm')|float }}
input_text:
  well_fault:
  well_status:

input_number:
  well_last:
    name: well_last_i
    min: 0.0
    max: 20.0
    step: 0.001
    mode: box
  well_last_resistance:
    name: well_last_resistance
    min: 0.0
    max: 100.0
    step: 0.001
    mode: box
  well_cycle:
    name: well_cycle_i
    min: 0
    max: 999999
    step: 1
    mode: box
  well_low_count:
    min: 0
    max: 999999
    step: 1
    mode: box
  well_high_count:
    min: 0
    max: 999999
    step: 1
    mode: box
  well_run_counter:
    min: 0
    max: 999999
    step: 1
    mode: box
  well_last_duration_i:
    min: 0
    max: 999999
    step: 1
    mode: box
  well_last_volume:
    min: 0
    max: 999999
    step: 1
    mode: box
    unit_of_measurement: G
  well_day_running_volume:
    min: 0
    max: 999999
    step: 1
    mode: box
    unit_of_measurement: G
  well_day_total_volume:
    min: 0
    max: 999999
    step: 1
    mode: box
    unit_of_measurement: G

  well_low_current:
    min: 0
    max: 20
    step: 0.01
    mode: box
    unit_of_measurement: Amp
  well_high_current:
    min: 0
    max: 20
    step: 0.01
    mode: box
    unit_of_measurement: Amp
  well_run_limit:
    min: 0
    max: 40
    step: 1.0
    mode: box
    unit_of_measurement: Min
  well_gpm:
    min: 0
    max: 10
    step: 0.01
    mode: box
    unit_of_measurement: GPM

input_boolean:
  well_fault:

input_datetime:
  well_last_run:
    has_date: true
    has_time: true

alert:
  well_fault:
    name:  well_fault
    message: well_fault: {{ states("input_text.well_fault") }} status: {{ states("input_text.well_status") }}'
    done_message: "well_fault cleared"
    entity_id: input_boolean.well_fault
    state: "on"
    repeat:
      - 1
      - 60
    can_acknowledge: true
    skip_first: true
    notifiers:
      - sms_notifiers_all

recorder:
  include:
    entities:
      - sensor.well_last
      - sensor.well_last_resistance
      - sensor.well_last_duration
      - sensor.well_cycles
      - sensor.well_watts
      - sensor.well_resistance
      - binary_sensor.well_state
      - input_text.well_fault
      - input_text.well_status
      - input_number.well_low_current
      - input_number.well_high_current
      - input_number.well_high_count
      - input_number.well_low_count
      - input_number.well_run_limit
      - input_number.well_run_counter
      - input_number.well_gpm
      - input_number.well_last_volume
      - input_number.well_day_running_volume
      - input_number.well_day_total_volume
      - input_boolean.well_fault
      - input_datetime.well_last_run
      - switch.well
      - alert.well_fault

####################################################################################################################################
#   Name:    well Detect Turn Off
#   Purpose: Detects the well turning off by the current falling below a threshold.  It then
#            copies the current, run duration for the final run information and resets the time counter, over/under current counters
#   Open Items:
####################################################################################################################################
- id: well Detect Turn Off
  alias: well Detect Turn Off
  trigger:
    - platform: state
      entity_id: sensor.well
  condition:
    condition: and
    conditions:
      - condition: template
        value_template: "{{ trigger.to_state.state|float(100) < 8.9 }}"
      - condition: template
        value_template: "{{ trigger.from_state.state|float(0) > 8.9 }}"
  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.well_last
        value: "{{ trigger.from_state.state|float(0) }}"
    - service: input_number.set_value
      data_template:
        entity_id: input_number.well_last_resistance
        value: "{{ ((states('sensor.switch_2_voltage')|float(0) * 2.0) / trigger.from_state.state|float(0)) | round(2) }}"
    - service: input_number.increment
      data_template:
        entity_id: input_number.well_cycle
    - service: input_number.set_value
      data:
        entity_id: input_number.well_run_counter
        value: 0
    - service: input_number.set_value
      data:
        entity_id: input_number.well_low_count
        value: 0
    - service: input_number.set_value
      data:
        entity_id: input_number.well_high_count
        value: 0

####################################################################################################################################
#   Name:    well calculate run duration in seconds
#   Purpose: Calculates the last run time in seconds
#   Open Items:
####################################################################################################################################
- id: well calculate run duration in seconds
  alias: well calculate run duration in seconds
  trigger:
    - platform: state
      entity_id: binary_sensor.well_state
      to: "off"
      from: "on"
  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.well_last_duration_i
        value: "{{ as_timestamp(now())|int(0) - as_timestamp(trigger.from_state.last_changed)|int(0) }}"
    - service: input_number.set_value
      data_template:
        entity_id: input_number.well_last_volume
        value: '{{ (as_timestamp(now())|int(0) - as_timestamp(trigger.from_state.last_changed)|int(0))|float(0) * states("input_number.well_gpm")|float(0) / 60.0 }}'
    - service: input_number.set_value
      data_template:
        entity_id: input_number.well_day_running_volume
        value: '{{ (((as_timestamp(now())|int(0) - as_timestamp(trigger.from_state.last_changed)|int(0))|float(0) * states("input_number.well_gpm")|float(0)) / 60.0) + states("input_number.well_day_running_volume")|float(0) }}'

####################################################################################################################################
#   Name:    well capture well start time
#   Purpose: Calculates the last run time in seconds
#   Open Items:
####################################################################################################################################
- id: well capture well start time
  alias: well capture well start time
  trigger:
    - platform: state
      entity_id: binary_sensor.well_state
      to: "on"
      from: "off"
  action:
    - service: input_datetime.set_datetime
      data_template:
        entity_id: input_datetime.well_last_run
        datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
    - service: input_datetime.set_datetime
      data_template:
        entity_id: input_datetime.well_last_run
        datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"

####################################################################################################################################
#   Name:    well Count Low Current
#   Purpose: Determine if the current is below the threshold and if so increments the low current counter
#   Open Items:
####################################################################################################################################
- id: well Count Low Current
  alias: well Count Low Current
  trigger:
    - platform: state
      entity_id: sensor.well
  condition: '{{ states("sensor.well")|float(0) > 2.0 and states("sensor.well")|float(100) <= states("input_number.well_low_current")|float(0) }}'
  action:
    - service: input_number.increment
      data_template:
        entity_id: input_number.well_low_count

####################################################################################################################################
#   Name:    well Count High Current
#   Purpose: Determine if the current is above the threshold and if so increments the high current counter
#   Open Items:
####################################################################################################################################
- id: well Count High Current
  alias: well Count High Current
  trigger:
    - platform: state
      entity_id: sensor.well
  condition: '{{ states("sensor.well")|float(0) >= states("input_number.well_high_current") |float(100)}}'
  action:
    - service: input_number.increment
      target:
        entity_id: input_number.well_high_count

####################################################################################################################################
#   Name:    well run duration
#   Purpose: When the well is running increment the run counter every minute
#   Open Items:
####################################################################################################################################
- id: well run duration
  alias: well run duration
  trigger:
    - platform: time_pattern
      minutes: "/1"
  condition: "{{ states('sensor.well')|float(0) > 2.0 }}"
  action:
    - service: input_number.increment
      target:
        entity_id: input_number.well_run_counter

####################################################################################################################################
#   Name:    well Low Current Fault
#   Purpose: If the low current counter exceeds the threshold FAULT the pump
#   Open Items:
####################################################################################################################################
- id: well Low Current Fault
  alias: well Low Current Fault
  trigger:
    - platform: numeric_state
      entity_id: input_number.well_low_count
      above: 1
  action:
    - service: input_text.set_value
      data_template:
        entity_id: input_text.well_fault
        value: "{{ 'low current: ' +  states('sensor.well') + ' Amps' }}"
    - service: input_boolean.turn_on
      target:
        entity_id: input_boolean.well_fault

####################################################################################################################################
#   Name:    well High Current Fault
#   Purpose: If the high current counter exceeds the threshold FAULT the pump
#   Open Items:
####################################################################################################################################
- id: well High Current Fault
  alias: well High Current Fault
  trigger:
    - platform: numeric_state
      entity_id: input_number.well_high_count
      above: 3
  action:
    - service: input_text.set_value
      data_template:
        entity_id: input_text.well_fault
        value: "{{ 'high current: ' +  states('sensor.well') + ' Amps' }}"
    - service: input_boolean.turn_on
      target:
        entity_id: input_boolean.well_fault

####################################################################################################################################
#   Name:    well Long Run Fault
#   Purpose: If the high current counter exceeds the threshold FAULT the pump
#   Open Items:
#   Updates
#   - 2021-03-31 - make the run counter configurable
####################################################################################################################################
- id: well Long Run Fault
  alias: well Long Run Fault
  trigger:
    - platform: state
      entity_id: input_number.well_run_counter
  condition: "{{ states('input_number.well_run_counter')|int(0) > states('input_number.well_run_limit')|int(0) }}"
  action:
    - service: input_text.set_value
      data_template:
        entity_id: input_text.well_fault
        value: "{{ 'duration: ' +  states('input_number.well_run_counter') + ' Minutes' }}"
    - service: input_boolean.turn_on
      target:
        entity_id: input_boolean.well_fault

####################################################################################################################################
#   Name:    well fault occurred
#   Purpose: Turn off pump in case of fault
#   Open Items:
####################################################################################################################################
- id: well fault occurred
  alias: well fault occurred
  trigger:
    - platform: state
      entity_id: input_boolean.well_fault
      to: "on"
  condition: "{{ states('input_boolean.well_control') == 'on' }}"
  action:
    - service: input_text.set_value
      data_template:
        entity_id: input_text.well_status
        value: "{{ 'off:fault' }}"
    - service: switch.turn_off
      data_template:
        entity_id: switch.well

####################################################################################################################################
#   Name:    well fault cleared
#   Purpose: clear fault message
#   Open Items:
####################################################################################################################################
- id: well fault cleared
  alias: well fault cleared
  trigger:
    - platform: state
      entity_id: input_boolean.well_fault
      to: "off"
  action:
    - service: input_text.set_value
      data_template:
        entity_id: input_text.well_fault
        value: "{{ 'Clear' }}"

####################################################################################################################################
#   Name:    well fault cleared
#   Purpose: clear fault message
#   Open Items:
####################################################################################################################################
- id: well turned on fault active
  alias: well turned on fault active
  trigger:
    - platform: state
      entity_id: switch.well
      to: "on"
  condition: "{{ states('input_boolean.well_control') == 'on' and states('input_boolean.well_fault') == 'on' }}"
  action:
    - service: switch.turn_off
      target:
        entity_id: switch.well
    - service: input_text.set_value
      data_template:
        entity_id: input_text.well_status
        value: "{{ 'off:existing fault' }}"

####################################################################################################################################
#   Name:    well day stats rollover
#   Purpose: At the end of the day calculate the final days statistics for storage in variables
#   Open Items:
####################################################################################################################################
- id: well day stats rollover
  alias: well day stats rolloever
  trigger:
    - platform: time
      at: "00:00:00"
  action:
    - service: input_number.set_value
      data_template:
        entity_id: input_number.well_day_total_volume
        value: '{{ states("input_number.well_day_running_volume")|float(0) }}'
    - service: input_number.set_value
      data_template:
        entity_id: input_number.well_day_running_volume
        value: "{{ 0.0 }}"

sensor:
  - platform: template
    sensors:
      wellcycles:
        value_template: >-
          {{ states('sensor.well_cycles')|int  }}
      total_gallons_today:
        unit_of_measurement: G
        value_template: >-
          {{ states('input_number.well_day_running_volume')| round(0) | int }}
      total_gallons_yesterday:
        unit_of_measurement: G
        value_template: >-
          {{ states('input_number.well_day_total_volume')| round(0)| int }}
input_boolean:
  well_control:

recorder:
  include:
    entities:
      - input_boolean.well_control
      - sensor.wellcycles
      - sensor.total_gallons_today
      - sensor.total_gallons_yesterday

Here what the run time screens looks like. Sprinklers ran used a lot of water.

Here’s where I set the empirically derived limits.

1 Like

Thanks a lot! This looks great.

Hello,

This looks terrific, something that I can really use, but I don’t know how. I’m new to Home Assistant and have been trying to figure out how to use these 3 files you provided but I’ve had no luck.

I created a packages folder and dropped these 3 files in (do they need specific names?). I updated my configuration.yaml to include the package folder under homeassistant: It seems to see them but then gives me errors about things like “expected a dictionary for dictionary value @ data[‘packages’][‘automations’]” If I try to view my automations.yaml file (I assumed your big file was automations, maybe not?) within the Studio Code server it tells me “Incorrect type. Expected “object”.yaml-schema: http://schemas.home-assistant.io/integration-homeassistant-packages

I must be missing something but I don’t know what. Can you please give me some guidance? Thanks.