Using ESPhome to build a water flow rate meter

@donparlor you are most welcome. If you look elsewhere in this thread, I also described how you can use Home Assistant to log the total volume of water per day/week/month/year, which is very useful for long term record keeping, if you are into that sort of data analysis.

I would like to join @Pensee in asking to see your YAML if you don’t mind; it is always very interesting to me to see how other people solve problems. I learn most that way.

1 Like

Hello Stéphane,

There is a lot of coding behind this, i’ll try to write it all down.

  • Instant water debit (in ESPHome)
sensor:
  - platform: pulse_counter
    pin:
      number: 4
      mode:
        input: true
        pullup: true
    unit_of_measurement: 'L/min'
    accuracy_decimals: 2
    id: water_usage
    name: "Débit d'eau instantané"
    update_interval: 5s
    filters:
      - lambda: return (x / 396); # 396 = 6,6 * 60
  • Total volume in cubic meters (in ESPHome)
sensor:
  - platform: integration
    name: "Eau total en M3"
    unit_of_measurement: 'm³'
    accuracy_decimals: 2
    sensor: water_usage
    time_unit: min
    filters:
        - lambda: return (x / 1000);
  • Total volume in liters (in ESPHome)
sensor:
  - platform: integration
    name: "Utilisation d'eau total"
    unit_of_measurement: 'L'
    accuracy_decimals: 2
     sensor: water_usage
     time_unit: min
  • Duration of the last water usage (in configuration.yaml)
sensor:
  - platform: template
    sensors:
        duree_ecoulement_eau_principale:
          friendly_name: Durée d'écoulement de l'eau principale
          unit_of_measurement: "sec"
          value_template: >
            {% set t = this.state if states('input_boolean.eau_principale_on_off') == 'off' else now().timestamp() - states.input_boolean.eau_principale_on_off.last_changed.timestamp() %}
            {{ t | round(2, 'common') }}
  • Volume of the last water usage (in configuration.yaml)
sensor:
  - platform: template
    sensors:
        volume_derniere_utilisation:
          friendly_name: Volume d'eau utilisé
          unit_of_measurement: 'L'
          value_template: >
            {{ (states('sensor.utilisation_d_eau_total') | float - states('input_number.volume_de_depart_debit') | float) | round(2, 'common') }}
  • Cost of the last shower (in configuration.yaml)
sensor:
  - platform: template
    sensors:
        cout_de_la_derniere_douche:
          friendly_name: Coût de la dernière douche
          unit_of_measurement: '$'
          value_template: >
            {{ (states('sensor.volume_derniere_utilisation') | float * 0.01 | float) | round(2, 'common') }}

As you can see, there are some input booleans to calculate some values. If you have more questions, let me know.

12 Likes

@donparlor
Thank you so much for that,you save me great amount of time.

1 Like

hi
what is this? cant find this sensor in your code(
this is switch for pump or something else?

This is a boolean that is triggered by a template sensor with an automation:

Here is the boolean:

Here is the template sensor in configuration.yaml

template:
  - sensor:
    - name: Durée de la dernière douche
      state:  >
        {% set current_liters = states('sensor.debit_d_eau_instantane') | float(0) %}
        {% if current_liters  > 0 %}
          {{ this.state | float(0) + current_liters  if this.state is defined else 0 }}
        {% else %}
          off
        {% endif %}

And here is the automation that triggers the boolean:

alias: Douche / Eau principale (ON/OFF)
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.duree_de_la_derniere_douche
    id: Trigger-ON
    from: "off"
  - platform: state
    entity_id:
      - sensor.duree_de_la_derniere_douche
    to: "off"
    id: Trigger-OFF
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: Trigger-ON
        sequence:
          - service: input_boolean.turn_on
            data: {}
            target:
              entity_id: input_boolean.eau_principale_on_off
      - conditions:
          - condition: trigger
            id: Trigger-OFF
        sequence:
          - service: input_boolean.turn_off
            data: {}
            target:
              entity_id: input_boolean.eau_principale_on_off
    default: []
mode: single

I should also mention that to calculate the volume of the last water usage, I also created an input_number value that is triggered when water flow is detected

Here the input_number:

Before creating the automation storing the initial volume of water when flow is detected, you need to create a binary_sensor that will be used to trigger that action of storing the initial value.

Here is the code for the binary sensor named binary_sensor.debit_d_eau_on_off (in configuration.yaml)

template:
  - binary_sensor:
    - name: Débit d'eau (ON/OFF)
      state: "{{ states('sensor.debit_d_eau_instantane') | float(0) > 0 }}"

Here is the automation storing the initial value when water flow is detected:

alias: Douche / Définir le volume de départ
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.debit_d_eau_on_off
    to: "on"
    from: "off"
condition: []
action:
  - service: input_number.set_value
    data:
      value: "{{ states('sensor.utilisation_d_eau_total') }}"
    target:
      entity_id: input_number.volume_de_depart_debit
mode: single
2 Likes

I got a problem getting this to work! What is it I do wrong. I had to cut up my config file with mqtt changed this last update so I used !include_dir_merge_list.
This i did for the template sensors too in this example, but now the sensors are not being seen in HA what I have or done is this!?

in configuration i put: template: !include_dir_merge_list templates/
I made a directory named “templates” in my config dir

then I grabbed donparlor his examples :slight_smile: only way for me to get things running>>>>

for instance.

template:
  - sensor:
    - name: Durée de la dernière douche
      state:  >
        {% set current_liters = states('sensor.debit_d_eau_instantane') | float(0) %}
        {% if current_liters  > 0 %}
          {{ this.state | float(0) + current_liters  if this.state is defined else 0 }}
        {% else %}
          off
        {% endif %}

and i made a yaml file in my templates dir named “water verbruik laatst”
then I rewrote the code to get no errors into this

sensor:
-   name: waterverbruik per keer
    unique_id: '8775758200'
    state:  >
        {% set current_liters = states('sensor.waterverbruik_in_liters') | float(0) %}
        {% if current_liters  > 0 %}
          {{ this.state | float(0) + current_liters  if this.state is defined else 0 }}
        {% else %}
          off
        {% endif %}

But that was it, in my states I do not find the sensors back, HA does not see them. SO please where did I make the error, what do I not see?!

Hello, I am a French beginner, I found your interface very interesting.
I lack knowledge but I am continually learning.

I hope you can help me because I can’t find a solution despite the time spent.

“Durée de la dernière utilisation” remains deactivated.
I think I’m not using the right sensor.

1

The first three sensors below are not visible in HA, why?


# Loads default set of integrations. Do not remove.
default_config:

- platform: template
  sensor:
      duree_ecoulement_eau_principale:
        friendly_name: Durée d'écoulement de l'eau principale
        unit_of_measurement: "sec"
        value_template: >
          {% set t = this.state if states('input_boolean.eau_principale_on_off') == 'off' else now().timestamp() - states.input_boolean.eau_principale_on_off.last_changed.timestamp() %}
          {{ t | round(2, 'common') }}
          
          
- platform: template
  sensor:
      volume_derniere_utilisation:
        friendly_name: Volume d'eau utilisé
        unit_of_measurement: 'L'
        value_template: >
          {{ (states('sensor.utilisation_d_eau_total') | float - states('input_number.volume_de_depart_debit') | float) | round(2, 'common') }}
            
            
- platform: template
  sensor:
      cout_de_la_derniere_douche:
        friendly_name: Coût de la dernière douche
        unit_of_measurement: '$'
        value_template: >
          {{ (states('sensor.volume_derniere_utilisation') | float * 0.01 | float) | round(2, 'common') }}

- platform: template
  sensor:
    Durée de la dernière douche:
      state:  >
        {% set current_liters = states('sensor.debit_d_eau_instantane') | float(0) %}
        {% if current_liters  > 0 %}
          {{ this.state | float(0) + current_liters  if this.state is defined else 0 }}
        {% else %}
          off
        {% endif %}

Also here is my code in automation.

### automation eau principale

  - alias: Douche / Eau principale (ON/OFF)
    description: "Douche /eau principale (ON/OFF)"
    trigger:
      - platform: state
        entity_id:
          - sensor.duree_de_la_derniere_douche
        id: Trigger-ON
        from: "off"
      - platform: state
        entity_id:
          - sensor.duree_de_la_derniere_douche
        to: "off"
        id: Trigger-OFF
    condition: []
    action:
      - choose:
          - conditions:
              - condition: trigger
                id: Trigger-ON
            sequence:
              - service: input_boolean.turn_on
                data: {}
                target:
                  entity_id: input_boolean.eau_principale_on_off
          - conditions:
              - condition: trigger
                id: Trigger-OFF
            sequence:
              - service: input_boolean.turn_off
                data: {}
                target:
                  entity_id: input_boolean.eau_principale_on_off
        default: []
    mode: single

### automation eau principale

### automation volume de départ

  - alias: Douche / Définir le volume de départ
    description: "Douche / Définir le volume de départ"
    trigger:
      - platform: state
        entity_id:
          - binary_sensor.debit_d_eau_on_off
        to: "on"
        from: "off"
    condition: []
    action:
      - service: input_number.set_value
        data:
          value: "{{ states('sensor.utilisation_d_eau_total') }}"
        target:
          entity_id: input_number.volume_de_depart_debit
    mode: single

### automation volume de départ

I hope not to bother asking for this help. I am blocked by my knowledge. Thanks a lot.

Hello Patrice!

Congratulation for reaching this far re-creating this setup. We could continue un French from here but I’ll keep it in english for the community. In this post I said I created an Input_Number: Using ESPhome to build a water flow rate meter - #166 by donparlor

This boolean tells Home Assistant that water flow is ON or OFF. If you need help creating an Input Boolean, look at this tutorial: Input Boolean - Home Assistant

Durée de la dernière utilisation (Duration of the last water usage) refers to that boolean so it can calculate time properly. Let me know if you created that boolean, I’ll dig further into your code after you answered. I need some sleep here, it’s 2h52 AM! :sweat_smile:

1 Like

Hello Vincent. I am happy to have a return from you, I hope the night was good :innocent: , and it is normal to continue our exchanges in English for the community. :relaxed:

I have created both inputs. Maybe they are misconfigured ?

For the input_number, I don’t have the same configuration possibilities.

Thank you again for your help.

Hello, sorry to ask, but I’m still interested if you have any idea regarding my problem. Thanks

Hello Patrice,

Sorry for the delay, very busy this week. I think I forgot to mention about a binary sensor in my YAML file that I didn’t mention. This template binary sensor triggers the automation which input volume, its name is binary_sensor.debit_d_eau_on_off. This is probably why sensor.duree_de_la_derniere_douche with friendly name Durée de la dernière utilisation (Duration of the last water usage) is not working.

Here is the code for the binary sensor named binary_sensor.debit_d_eau_on_off (in configuration.yaml)

template:
  - binary_sensor:
    - name: Débit d'eau (ON/OFF)
      state: "{{ states('sensor.debit_d_eau_instantane') | float(0) > 0 }}"

After creating that binary_sensor, make sure to double-check the automation storing the initial value when water flow is detected:

alias: Douche / Définir le volume de départ
description: ""
trigger:
  - platform: state
    entity_id:
      - binary_sensor.debit_d_eau_on_off
    to: "on"
    from: "off"
condition: []
action:
  - service: input_number.set_value
    data:
      value: "{{ states('sensor.utilisation_d_eau_total') }}"
    target:
      entity_id: input_number.volume_de_depart_debit
mode: single

Let me know if that works for you.

Good luck!

PS: I will add this binary_sensor to my post above so there is not missing anything.

1 Like

Hello, no worries, thank you for taking the time to answer me today.
I added the binary_sensor.
I have the information that appears but only indicates the enabled/disabled state.
I don’t have the time that appears.
Here is a screenshot.

What do you think ? Thanks a lot.

Hi you, What kind of sensor are you using? if i use YFS201 how will the configuration change? can i see your wiring diagram? Thank you very much.

1 Like

The value being displayed at Durée de la dernière utilisation (Duration of the last water usage) comes from sensor.duree_ecoulement_eau_principale

- platform: template
    sensors:
        duree_ecoulement_eau_principale:
          friendly_name: Durée d'écoulement de l'eau principale
          unit_of_measurement: "sec"
          value_template: >
            {% set t = this.state if states('input_boolean.eau_principale_on_off') == 'off' else now().timestamp() - states.input_boolean.eau_principale_on_off.last_changed.timestamp() %}
            {{ t | round(2, 'common') }}

You are displaying Débit d’eau (ON/OFF).

Try to change the sensor from where this value is displayed.

I simply use a NPT YF-B5 sensor

But basically, this setup can work with most if not any flow sensor. The only thing that change is the first sensor in ESPHome that calculate the rotation of the flow sensor.

Instant water debit (in ESPHome)

sensor:
  - platform: pulse_counter
    pin:
      number: 4
      mode:
        input: true
        pullup: true
    unit_of_measurement: 'L/min'
    accuracy_decimals: 2
    id: water_usage
    name: "Débit d'eau instantané"
    update_interval: 5s
    filters:
      - lambda: return (x / 396); # 396 = 6,6 * 60

It’s just a matter of adjusting the lambda to your flow sensor:

filters:
      - lambda: return (x / 396); # 396 = 6,6 * 60

YF-B5 is:

396 = 6,6 * 60

For YF-S201, the flow rate pulse characteristics goes as follow: Frequency (Hz) = 7.5 * Flow rate (L/min)
So the lambda should be

filters:
      - lambda: return (x / 450); # 450 = 7,5 * 60

Then you first sensor in ESPHome will be:

sensor:
  - platform: pulse_counter
    pin:
      number: 4 #Change according to the pin where you connected your flow sensor on ESP32 board
      mode:
        input: true
        pullup: true
    unit_of_measurement: 'L/min'
    accuracy_decimals: 2
    id: water_usage
    name: "Débit d'eau instantané" #Choose name according to your display language
    update_interval: 5s
    filters:
      - lambda: return (x / 450); # 450 = 7,5 * 60
6 Likes

Hello, I wanted to put this sensor, but it does not appear.


I don’t understand if I made a mistake. Thank you

And if you go in your Development tools tab, can you find it?
Look what I can see when I search for it:

Curiously, there is nothing with “duree_ec….”

And very basic question but I must ask: Did you restart your HA after adding those lines in your configuration.yaml ?