How can I track water softener schedule (using ESPHome and Ultrasonic)

I am monitoring my salt level for my water softener using ESPHome and an ultrasonic sensor. I see about a 1-inch drop from the sensor whenever the softener recharges. How can I keep track of the dates/times that it drops 1in within 1 hour? I want to predict when to add salt and know the last time the system recharged.

The two circled events are what I would like to capture. Both indicate the salt level dropped do to a recharge.

1 Like

I’m not sure but here are some ideas.

I think you need to start layering up the right filters in working towards a “pulse counter”. I would visualise the data a lot while doing this (like you’ve done). I like Grafana for this kind of thing.

I would start adding a series of chained copy sensors.

I would start with a moving median filter of window size 3 or 5 to clean up the noise.

Then I’d see what a delta sensor or filter looks chained onto that.

I’m not quite sure where to take it after that step yet.

Possibly a throttle filter or something to try to discretise it further. You basically want to process it to look like a very square stepped signal.

I tried to make my softener a little bit more smart as well. I built a distance sensor based on ESPHome e a VL53L0X fixed with double-sided tape to the side of the salt container. It works quire realiabily.

To help keeping track of the softener phase I added a derivative helper based on the measured distance with the following options:

This helper represents the speed and the direction of the delta with respect to the time:

Then I implemented the state-machine of the softener with a dropbox helper like this:

Finally, with a few automations I added the transitions between states:

alias: Addolcitore backwash-idle
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.addolcitore_derivata
    below: 0.1
condition:
  - condition: state
    entity_id: input_select.addolcitore_status
    state: Back Wash
action:
  - service: input_select.select_option
    metadata: {}
    data:
      option: Idle
    target:
      entity_id: input_select.addolcitore_status
mode: single
alias: Addolcitore brine-rinse
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.addolcitore_derivata
    above: -1
condition:
  - condition: state
    entity_id: input_select.addolcitore_status
    state: Brine
action:
  - service: input_select.select_option
    metadata: {}
    data:
      option: Rinse
    target:
      entity_id: input_select.addolcitore_status
mode: single
alias: Addolcitore idle-brine
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.addolcitore_derivata
    below: -0.5
condition:
  - condition: state
    entity_id: input_select.addolcitore_status
    state: Idle
action:
  - service: input_select.select_option
    metadata: {}
    data:
      option: Brine
    target:
      entity_id: input_select.addolcitore_status
mode: single
alias: Addolcitore rinse-backwash
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.addolcitore_derivata
    below: 0.5
condition:
  - condition: state
    entity_id: input_select.addolcitore_status
    state: Rinse
action:
  - service: input_select.select_option
    metadata: {}
    data:
      option: Back Wash
    target:
      entity_id: input_select.addolcitore_status
mode: single

Now the softener status is correctly identified during the regeneration process:

I think it should be possible to store the date at each cycle and even estimate the next one comparing the elapsed time with respect to the previous one.

This is still a work in progress, so some improvements will need to be implemented.