ESPHome water level sensor

Thanks @ronsum. I like how you have all your calculation are at the sensor output level in ESP home. I might use that idea and some of your code.

But what I find different is my voltage and level percentage calculation increases with temperature which is counter-intuitive I would have thought the hydrostatic pressure would decrease with increase in temperature as the density decreases or stay the same due to an equivalent increase in fluid height due to volume expansion in a fixed container volume. Note my tank is a vented non pressurised tank.

Do you think my volume expansion and hence fluid height increase greater than any density reduction hence I am seeing an increase in level/hydrostatic pressure?

I should probably say that I only have a layman’s understanding of the physics and electronics involved, all based on a few google searches regarding temperature and [water density, water volume, and pressure sensors]. Luckily I added a BMP280 sensor (thinking I may need to compensate for barometric pressure). When I noticed the unexpected fluctuations, I added the BMP280’s data to Grafana and was first able to realize the issue and then gather the data to write the compensation in firmware.

What you described seems to be in sync with the thermal effects on water. My readings weren’t, which lead me to believe that it was the sensor being affected. Either way, if you’re experiencing fluctuations that seem to coincide with the sun, it is likely a temperature issue.

As your sensor is the drop-in type (same temp as water) and the readings seem in sync with thermal effects on water, I suspect you need to monitor the water temperature in your tank. Having my sensor and other electronics all external and housed in the same environment allowed me to use the BMP280 sensor. I can’t recommend any particular in-tank water temperature sensor.

Add a temperature sensor internally (in tank) or externally (at microcontroller), and collect data on a fixed volume of water over a few days. Once you add temperature to your graph, you can verify if a spike in pressure corelates to a spike in temperature, and by how much.

The links up top should help understand the physics.

This is my tank and sensor setup:



3 Likes

I have a very similar setup (almost exact!). How do you compensate for the pump suction pressure at the sensor when it comes on? Does this affect the reading (albeit instantaneous).

Pump suction does cause a momentary downward spike. It causes the live reading to be inaccurate, and at the same time has the benefit of showing pump usage :man_shrugging:. I wanted to rectify this physically, but that would require emptying a tank.

I used the median and exponential_moving_average filters, applying the exponential_moving_average twice. I had to experiment quite a bit and can’t say if my method is optimal… but resolution and update frequency are acceptable for my application, especially when compared to an ultrasonic sensor.

This is the last 30 days of my ultrasonic sensor vs pressure transducer:

@ronsum Seems we have an almost identical setup. Here is what my sensor mounted looks like. Also I have been comparing my ultrasonic sensor with the pressure transducer just as you have. The difference would be the offset for the “dead space” on the ultrasonic sensor that I haven’t accounted for.

I also had to apply some filtering due to pump suction. My aim is to remove the ultrasonic sensor completely and just use the pressure transducer. I also included a screenshot of WASA water pressure (because Freeport na :D)

image

Hi @ronsum see below description for my liquid level sensor it says it has built in temperature compensation. Which makes me wonder if the temperature issue is related to the pressure sensor or the node mcu chip and power supply heating up with ambient temperature going up. I am wondering whether the temperature compensation should be be based on ambient temperature or water temperature.

“This throw-in type liquid level transmitter adopts high-performance pressure sensing chip, with advanced circuit processing and temperature compensation technology. The level transmitter receives different pressures at different depths of liquid, which can be converted into corresponding current signals and output through the sensor. In this way, the depth of liquid can be measured.”

Can you share your ESPHOME yaml and circuit diagram/device wiring for this set-up?

I have a throw in level sensor from dfrobot that is temperature compensated. I also have a DS18B20 temperature sensor now installed in the IP67 enclosure that houses the power supply, nodemcu and the analog current voltage converter. There seems to be a close correlation between the ambient temperature in the enclosure and the voltage reading- see below. Can someone please help with the temperature compensation formula in esphome. See attached temperature vs voltage curve.

esphome config:
#Dallas DS18B20 Temp sensor
dallas:

  • pin: GPIO5
    update_interval: 1s

Internal Voltage Reading

sensor:

  • platform: adc
    pin: A0
    id: tank_raw_voltage
    update_interval: 1s
    accuracy_decimals: 3
    filters:
    • multiply: 3.3
    • delta : 0.002
      on_value:
      then:
      • lambda: id(tank_voltage).publish_state(x);
      • lambda: id(tank_percent).publish_state(x);
      • lambda: id(tank_volume).publish_state(x);

Temperature Reading

  • platform: dallas
    id: enclosure_temp
    address: xxxxxxxxxxxx
    name: “Sensor Enclosure Temperature”
    resolution: 12
    unit_of_measurement: “°C”
    icon: “mdi:thermometer”
    device_class: “temperature”
    state_class: “measurement”
    accuracy_decimals: 1
    filters:
    • median:
    • exponential_moving_average:
      alpha: 0.2
      send_every: 15

Exposed Voltage Reading

  • platform: template
    id: tank_voltage
    name: “Water Tank Voltage”
    device_class: voltage
    accuracy_decimals: 3
    filters:
    • median:
    • exponential_moving_average:
      alpha: 0.2
      send_every: 15

Exposed Tank Percentage

  • platform: template
    name: “Water Tank Level %”
    id: tank_percent
    update_interval: 1s
    accuracy_decimals: 0
    device_class: “”
    unit_of_measurement: “%”
    icon: “mdi:water-well”
    filters:
    • median:
    • exponential_moving_average:
      alpha: 0.2
      send_every: 15
    • calibrate_linear:
      • 0.231 → 0.0
      • 0.926 → 100.0

Exposed Tank Volume

  • platform: template
    name: “Water Tank Volume”
    id: tank_volume
    update_interval: 1s
    accuracy_decimals: 0
    device_class: “”
    unit_of_measurement: “L”
    icon: “mdi:water-well”
    filters:
    • median:
    • exponential_moving_average:
      alpha: 0.2
      send_every: 15
    • calibrate_linear:
      • 0.231 → 0.0
      • 0.926 → 5000
1 Like

The relevant sections in my yaml look like this:

i2c:
  sda: 21
  scl: 22

sensor:
  - platform: ina219
    address: 0x40
    shunt_resistance: 0.1 ohm
    current:
      name: "fonteneA"
      accuracy_decimals: 5
    power:
      name: "fonteneW"
      accuracy_decimals: 5
    bus_voltage:
      name: "fonteneV"
      accuracy_decimals: 2
    shunt_voltage:
      name: "fonteneV2"
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

2 Likes

Thank you. Why do you use max_current: 400mA if the throw in sensor works in 4-20mA range? or is that just a setting for the ina219?

That’s for the INA219. It defaults to max. 3.2A and a precision of 0.8mA. Setting it to max 400mA gives a precision of 0.1mA.

2 Likes

Ahh I see. Thanks for the clarification. This is my first time using the INA219 and still learning the settings for it.

Hello to all
I try to do the same but i receive always ov on the esp, i have make this


and i use the code in this post to make this one

esphome:
  name: water-level
  platform: ESP32
  board: esp-wrover-kit

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  password: "3819628eb5eee80ad86c901f2838e6ec"



ethernet:
  type: LAN8720
  mdc_pin: GPIO23
  mdio_pin: GPIO18
  clk_mode: GPIO0_IN
  phy_addr: 1
  power_pin: GPIO16

  # Optional manual IP
  manual_ip:
    static_ip: 10.0.0.235
    gateway: 10.0.0.1
    subnet: 255.255.255.0

  # Enable fallback hotspot (captive portal) in case wifi connection fails

dallas:
  - pin: GPIO14

sensor:
  - platform: adc
    pin: GPIO39
    name: "water level voltage"
    id: watertank_voltage    
    accuracy_decimals: 3
    update_interval: 1s #the delta filter will ensure it only sends values when something changes. 
    filters:
      - sliding_window_moving_average:
          window_size: 10 #creates a moving average of the last 10 values
          send_every: 1 #sends the moving average at every measurement (but only if it passes the delta filter below)) 
          send_first_at: 1 #after startup immediately start sending the result rather than wait for the first 10 measurements
      - delta : 0.0015 #only send the result if the voltage difference with the last sent result is higher than this
        ## Exposed Voltage Reading
  - platform: template
    name: "Water Level Sensor usable CM" #first X cm are below pump inlet and thus unuseable.
    id: watertank_cm
    icon: 'mdi:water-well'
    unit_of_measurement: 'cm'
    lambda: |-
        return id(watertank_voltage).state;
    update_interval: 1s #the delta filter will ensure it only sends values when something changes. 
    filters:
      - calibrate_linear:
          # Measured value of X volt maps to y cm
          - 0.0 -> 0
          - 2.5 -> 100.0
      - delta : 0.001 #only send the result if the difference with the last sent result is higher than this
  - platform: template
    name: "Water Level Sensor usable %"
    id: watertank_percent
    icon: 'mdi:water-well'
    unit_of_measurement: '%'
    lambda: |-
        return id(watertank_cm).state / 165.0 * 100; 
      #divide by max water level height to get a percentage
    update_interval: 1s #the delta filter will ensure it only sends values when something changes. 
    filters:
      - delta : 0.001 #only send the result if the difference with the last sent result is higher than this
  - platform: template
    name: "Water Level Sensor usable liters"
    id: watertank_liter
    icon: 'mdi:water-well'
    unit_of_measurement: 'l'
    lambda: |-
        return id(watertank_cm).state / 100 * 1 * 1 * 3 * 1000.0;
      #height (meters) times Largeur times Lenght times nombers of tanks times 1000 gives liters.
    update_interval: 1s #the delta filter will ensure it only sends values when something changes. 
    filters:
      - delta : 0.001 #only send the result if the difference with the last sent result is higher than this

  - platform: dht
    pin: GPIO4
    temperature:
      name: "Cabane Temperature"
    humidity:
      name: "Cabane Humidity"
    update_interval: 60s      

  - platform: dallas
    address: 0x843C01B556471B28
    name: "watertank Temperature"

Have you an idea ???
Thanks a lot

1 Like

Hi @aherbjornsen with your setup using esp32, ina219 and TL-136 sensor do you see an drift in the TL-136 values based on ambient temperature?

I am using a TL-136 with an ESP8266 and analog current to voltage converter but the output voltage drifts with ambient temperature making the readings unusable.

@rybackisback I don’t really have much data with variable ambient temperature. I see from old graphs that I had it outdooors for a single day when the temperature varied between 14 and 28 degrees without seeing that reflect on my readings.

Thanks @aherbjornsen. Are you please able to share your wiring diagram. Ive never used an INA219 before.

Sorry. Don’t have a diagram. I just used examples I found on the net.
It is extremely simple, you connect the INA219 to your ESP32, And then you you hook up the TL-136 to the other side of the INA219.
I used a 24V PSU to drive both the TL-136 and a USB-charger that powered the ESP32.

1 Like

Did you connect ground from the ESP32 to the Vin+ or Vin- on the INA219 with or without a pull up resistor?

EDIT
Disregard the above. Grounding the ESP to the INA219 across Vin causes a short. I might need a pullup resistor across the SCA and SCL if needed. I’ll be testing the TL-136 in my water tank this weekend to see what I get for current measurements and water height. I shared my wiring diagram in a post below.

Here is how I have it wired up:

I am using a M5 Atom Lite which is an ESP32 Pico which is different than the ESP in the diagram above (I haven’t found a Atom Lite item for fritzing yet) but gives you the same idea on how to wire it.:

2 Likes

Hi @kimocal thanks for that. I managed to figure out the wiring myelf. So I changed my setup to now include ADS1115 (analog to digital converter) to combat the fluctuations of the sensor reading with temperature since my setup is setup outdoors in an ip67 enclosure. But I am still getting sensor readings drift with ambient temperature with no water being added or removed from the tank. Do you see that with an INA219 setup?