Skip to content
View in the app

A better way to browse. Learn more.

Power Forum - Renewable Energy Discussion

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Measuring the water level in my Jojo Tanks in HA

Featured Replies

Hi all,

Thought I'd share my journey in creating an accurate water level measuring system for my Jojo tanks.

I've finally managed to find a solution which is about 99.6% accurate. This equates to a water height difference of +-5mm between the actual height in the tank vs what the probe is reading. I'd call this a success 🙃

Some of the other ESP32 + sensor solutions which I've tried and given up on:

  • Waterproof ultrasonic sensor - difficult to implement as the minimum distance between the sensor and the water level is +-20CM if I recall correctly. This meant that I would need to 3D print a cone to raise the ultrasonic sensor and cut a large hole in the Jojo Tank. Plus the issues of condensation on the sensor.
  • Analog water pressure sensor - this was attached to the bottom of the outlet of the tank. The readings were all over the place and I'd see random drops for no apparent reason so I gave up on this.
  • Throw in pressure sensor + ADS1115 A/D Module + voltage regulation - this was probably the longest standing solution that I had in place. The results were very erratic and I'd see random fluctuations for no apparent reason. Landed up having to re-calibrate multiple times - definitely something was wrong.

After advice from others on the Home Assistant Forum, I tried a solution which was suggested by others and it's been spot on and much easier to implment!

Hardware:

Screenshot2024-03-06172258.thumb.png.91db522c90927d267509a5af14ea02f8.png

2 Measurements were taken to calibrate:

  • 1: when the sensor was not inside the tank
  • 2: when the sensor was in the tank and the tank was full (manual float switch had stopped filling).

As seen in the code below:

      float full_voltage = 0.00092; // Voltage at full condition
      float empty_voltage = 0.00042; // Voltage at empty condition

&

      float max_full_reading = 9.2;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4.2;  // Adjust the minimum reading at empty water level

As there are 2 tanks and only 1 sensor, the total volume is multiplied by 2.

Both tank levels equalize when they're full and are thus same.

YAML:

captive_portal:

i2c:
  sda: 21
  scl: 22

sensor:
  - platform: ina219
    address: 0x40
    shunt_resistance: 0.1 ohm
    current:
      name: "INA219 Current"
      id: ina_current
      accuracy_decimals: 5
      filters:
      - multiply: 1000 #convert from Amps to mA
      unit_of_measurement: "mA"
    power:
      name: "INA219 Power"
      accuracy_decimals: 5
    bus_voltage:
      name: "INA219 Bus Voltage"
      accuracy_decimals: 2
    shunt_voltage:
      name: "INA219 Shunt Voltage"
      id: ina219_shunt_voltage
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00092; // Voltage at full condition
      float empty_voltage = 0.00042; // Voltage at empty condition
      float max_height = 1.570; // Adjust the max height as needed

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;

      // Ensure water level is within bounds
      water_level = water_level < 0.0 ? 0.0 : water_level;
      water_level = water_level > max_height ? max_height : water_level;

      ESP_LOGD("custom", "Shunt Voltage: %.5f V", id(ina219_shunt_voltage).state);
      ESP_LOGD("custom", "Water Level: %.5f m", water_level);
      return water_level;


  - platform: template
    name: "Current Full Percentage"
    id: current_full_percentage
    unit_of_measurement: '%'
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float max_full_reading = 9.2;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4.2;  // Adjust the minimum reading at empty water level
      float current_reading = id(ina_current).state;
      
      if (current_reading <= min_empty_reading) {
        return 0.0;
      } else if (current_reading >= max_full_reading) {
        return 100.0;
      } else {
        float current_full_percentage = 100 * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading);
        return current_full_percentage;
      }

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      float tank_radius = 0.71;  // Adjust the tank radius as needed
      float max_height = 1.57;   // Adjust the max height as needed
      float total_volume_single_tank = 3.14159265 * tank_radius * tank_radius * max_height * 1000;
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0);
      float current_volume_single_tank = 3.14159265 * tank_radius * tank_radius * water_level * 1000;
      float total_volume_both_tanks = 2 * current_volume_single_tank;
      return total_volume_both_tanks;

We had a water outage today so I had an opportunity to test the sensor value (height) vs the actual height with a tape measure and I was off by 5mm, so I'll take this as a success.

image.thumb.png.a993f0ccf864a3403f0b97f2323d1d13.png

Screenshot2023-05-24123126.JPG.04512084ea84dbe8db3a4bfa939ec15e.JPG

Hope this is useful to you guys - shout if I can answer any questions :)

  • 5 months later...
  • Author

Added this to the code above which gives a number of days left of water left based on a daily usage of 1100l per day:
 

  - platform: template
    name: "Days of Water Left"
    id: days_of_water_left
    unit_of_measurement: "days"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float total_volume = id(tank_volume).state;
      float daily_usage = 1100.0; // 1100 liters per day
      float days_left = total_volume / daily_usage;
      
      // Cap the maximum days to 5 when tanks are full
      if (days_left > 5.0) {
        return 5.0;
      }
      
      return std::max(0.0f, days_left);

New sensor: sensor.days_of_water_left

image.png.68363a8b1749ac1d192e23237798f324.png

  • 4 months later...

Hi,

 

I like it a lot! I bought all the parts and performed the installation. I am struggling quite a bit. I'm using this in a 10 000L JoJo Tank and am getting confusing readings. Please see the attached screenshots. Below is my code (I did calibrate the readings):

esphome:
  name: jojo-1
  friendly_name: JoJo 1

esp32:
  board: nodemcu-32s
    
# Enable logging
logger:
  
# Enable Home Assistant API
api:
  encryption:
    key: "uxBTnmmzUw6yiCtJxGYd26Qqoiivswu8GHfUO8Xr+3U="

ota:
  - platform: esphome
    password: "620d601b87d0f7bebb1365ae886fd934"

wifi:
  ssid: 
  password: 
  manual_ip: 
    static_ip: 192.168.0.26
    subnet: 255.255.255.0
    gateway: 192.168.0.254

web_server:
  
captive_portal:

i2c:
  sda: 21
  scl: 22

sensor:
  - platform: ina219
    address: 0x45
    shunt_resistance: 0.1 ohm
    current:
      name: "INA219 Current"
      id: ina_current
      accuracy_decimals: 5
      filters:
      - multiply: 1000 #convert from Amps to mA
      unit_of_measurement: "mA"
    power:
      name: "INA219 Power"
      accuracy_decimals: 5
    bus_voltage:
      name: "INA219 Bus Voltage"
      accuracy_decimals: 2
    shunt_voltage:
      name: "INA219 Shunt Voltage"
      id: ina219_shunt_voltage
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00012; // Voltage at full condition
      float empty_voltage = 0.00004; // Voltage at empty condition
      float max_height = 2.7; // Adjust the max height as needed

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;

      // Ensure water level is within bounds
      water_level = water_level < 0.0 ? 0.0 : water_level;
      water_level = water_level > max_height ? max_height : water_level;

      ESP_LOGD("custom", "Shunt Voltage: %.5f V", id(ina219_shunt_voltage).state);
      ESP_LOGD("custom", "Water Level: %.5f m", water_level);
      return water_level;


  - platform: template
    name: "Current Full Percentage"
    id: current_full_percentage
    unit_of_measurement: '%'
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float max_full_reading = 12;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4;  // Adjust the minimum reading at empty water level
      float current_reading = id(ina_current).state;
      
      if (current_reading <= min_empty_reading) {
        return 0.0;
      } else if (current_reading >= max_full_reading) {
        return 100.0;
      } else {
        float current_full_percentage = 100 * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading);
        return current_full_percentage;
      }

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      float tank_radius = 1.1;  // Adjust the tank radius as needed
      float max_height = 2.7;   // Adjust the max height as needed
      float total_volume_single_tank = 3.14159265 * tank_radius * tank_radius * max_height * 1000;
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0);
      float current_volume_single_tank = 3.14159265 * tank_radius * tank_radius * water_level * 1000;
      return total_volume_single_tank;

 

Can someone kindly please assist?

 

Kind regards,

Robbie

Screenshot 2025-01-17 174607.png

Screenshot 2025-01-17 174649.png

  • Author
31 minutes ago, Robbie3337 said:

Hi,

 

I like it a lot! I bought all the parts and performed the installation. I am struggling quite a bit. I'm using this in a 10 000L JoJo Tank and am getting confusing readings. Please see the attached screenshots. Below is my code (I did calibrate the readings):

esphome:
  name: jojo-1
  friendly_name: JoJo 1

esp32:
  board: nodemcu-32s
    
# Enable logging
logger:
  
# Enable Home Assistant API
api:
  encryption:
    key: "uxBTnmmzUw6yiCtJxGYd26Qqoiivswu8GHfUO8Xr+3U="

ota:
  - platform: esphome
    password: "620d601b87d0f7bebb1365ae886fd934"

wifi:
  ssid: 
  password: 
  manual_ip: 
    static_ip: 192.168.0.26
    subnet: 255.255.255.0
    gateway: 192.168.0.254

web_server:
  
captive_portal:

i2c:
  sda: 21
  scl: 22

sensor:
  - platform: ina219
    address: 0x45
    shunt_resistance: 0.1 ohm
    current:
      name: "INA219 Current"
      id: ina_current
      accuracy_decimals: 5
      filters:
      - multiply: 1000 #convert from Amps to mA
      unit_of_measurement: "mA"
    power:
      name: "INA219 Power"
      accuracy_decimals: 5
    bus_voltage:
      name: "INA219 Bus Voltage"
      accuracy_decimals: 2
    shunt_voltage:
      name: "INA219 Shunt Voltage"
      id: ina219_shunt_voltage
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00012; // Voltage at full condition
      float empty_voltage = 0.00004; // Voltage at empty condition
      float max_height = 2.7; // Adjust the max height as needed

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;

      // Ensure water level is within bounds
      water_level = water_level < 0.0 ? 0.0 : water_level;
      water_level = water_level > max_height ? max_height : water_level;

      ESP_LOGD("custom", "Shunt Voltage: %.5f V", id(ina219_shunt_voltage).state);
      ESP_LOGD("custom", "Water Level: %.5f m", water_level);
      return water_level;


  - platform: template
    name: "Current Full Percentage"
    id: current_full_percentage
    unit_of_measurement: '%'
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float max_full_reading = 12;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4;  // Adjust the minimum reading at empty water level
      float current_reading = id(ina_current).state;
      
      if (current_reading <= min_empty_reading) {
        return 0.0;
      } else if (current_reading >= max_full_reading) {
        return 100.0;
      } else {
        float current_full_percentage = 100 * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading);
        return current_full_percentage;
      }

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      float tank_radius = 1.1;  // Adjust the tank radius as needed
      float max_height = 2.7;   // Adjust the max height as needed
      float total_volume_single_tank = 3.14159265 * tank_radius * tank_radius * max_height * 1000;
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0);
      float current_volume_single_tank = 3.14159265 * tank_radius * tank_radius * water_level * 1000;
      return total_volume_single_tank;

 

Can someone kindly please assist?

 

Kind regards,

Robbie

Screenshot 2025-01-17 174607.png

Screenshot 2025-01-17 174649.png

So 3 things that I noticed when compared to my code:

- your ina219 address is  0x45 - mine is 0x40
- I also noticed that your calibration numbers seem very low - perhaps adjust the point above and below and try take new calibrations.
- the float max_height is only 1 decimal place - perhaps make this 3

Here's my code in case :

captive_portal:

i2c:
  sda: 21
  scl: 22

sensor:
  - platform: ina219
    address: 0x40
    shunt_resistance: 0.1 ohm
    current:
      name: "INA219 Current"
      id: ina_current
      accuracy_decimals: 5
      filters:
      - multiply: 1000 #convert from Amps to mA
      unit_of_measurement: "mA"
    power:
      name: "INA219 Power"
      accuracy_decimals: 5
    bus_voltage:
      name: "INA219 Bus Voltage"
      accuracy_decimals: 2
    shunt_voltage:
      name: "INA219 Shunt Voltage"
      id: ina219_shunt_voltage
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00092; // Voltage at full condition
      float empty_voltage = 0.00042; // Voltage at empty condition
      float max_height = 1.570; // Adjust the max height as needed

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;

      // Ensure water level is within bounds
      water_level = std::max(0.0f, std::min(water_level, max_height));

      ESP_LOGD("custom", "Shunt Voltage: %.5f V", shunt_voltage);
      ESP_LOGD("custom", "Water Level: %.5f m", water_level);
      return water_level;

  - platform: template
    name: "Current Full Percentage"
    id: current_full_percentage
    unit_of_measurement: '%'
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float max_full_reading = 9.2;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4.2;  // Adjust the minimum reading at empty water level
      float current_reading = id(ina_current).state;
      
      float current_full_percentage = 100.0f * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading);
      return std::max(0.0f, std::min(current_full_percentage, 100.0f));

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      constexpr float tank_radius = 0.71;  // Adjust the tank radius as needed
      constexpr float max_height = 1.57;   // Adjust the max height as needed
      constexpr float pi = 3.14159265f;
      constexpr float total_volume_single_tank = pi * tank_radius * tank_radius * max_height * 1000;
      
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0f);
      float current_volume_single_tank = pi * tank_radius * tank_radius * water_level * 1000;
      float total_volume_both_tanks = 2 * current_volume_single_tank;
      
      return total_volume_both_tanks;

  - platform: template
    name: "Days of Water Left"
    id: days_of_water_left
    unit_of_measurement: "days"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float total_volume = id(tank_volume).state;
      float daily_usage = 1100.0; // 1100 liters per day
      float days_left = total_volume / daily_usage;
      
      // Cap the maximum days to 5 when tanks are full
      if (days_left > 5.0) {
        return 5.0;
      }
      
      return std::max(0.0f, days_left);

  - platform: template
    name: "Daily Water Consumption Rate"
    id: daily_water_consumption
    unit_of_measurement: "L/day"
    accuracy_decimals: 1
    update_interval: 3600s  # Update hourly
    lambda: |-
      static float last_volume = id(tank_volume).state;
      static unsigned long last_update = 0;
      float current_volume = id(tank_volume).state;
      unsigned long current_time = millis();
      float consumption_rate = 0;
      
      if (last_update > 0) {
        float volume_change = last_volume - current_volume;
        float days_elapsed = (current_time - last_update) / (1000.0 * 60 * 60 * 24);
        consumption_rate = volume_change / days_elapsed;
      }
      
      last_volume = current_volume;
      last_update = current_time;
      
      return std::max(0.0f, consumption_rate);

  - platform: template
    name: "Tank Refill Rate"
    id: tank_refill_rate
    unit_of_measurement: "L/hour"
    accuracy_decimals: 1
    update_interval: 300s  # Update every 5 minutes
    lambda: |-
      static float last_volume = id(tank_volume).state;
      static unsigned long last_update = 0;
      float current_volume = id(tank_volume).state;
      unsigned long current_time = millis();
      float refill_rate = 0;
      
      if (last_update > 0 && current_volume > last_volume) {
        float volume_change = current_volume - last_volume;
        float hours_elapsed = (current_time - last_update) / (1000.0 * 60 * 60);
        refill_rate = volume_change / hours_elapsed;
      }
      
      last_volume = current_volume;
      last_update = current_time;
      
      return refill_rate;

  - platform: template
    name: "Time to Empty"
    id: time_to_empty
    unit_of_measurement: "hours"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float current_volume = id(tank_volume).state;
      float consumption_rate = id(daily_water_consumption).state / 24.0;  // L/hour
      
      if (consumption_rate > 0) {
        return current_volume / consumption_rate;
      } else {
        return 0;  // Avoid division by zero
      }

  - platform: template
    name: "Time to Full"
    id: time_to_full
    unit_of_measurement: "hours"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float current_volume = id(tank_volume).state;
      float max_volume = 4973.0;  // Maximum volume of both tanks
      float refill_rate = id(tank_refill_rate).state;
      
      if (refill_rate > 0) {
        return (max_volume - current_volume) / refill_rate;
      } else {
        return 0;  // Not currently filling
      }

  - platform: template
    name: "Water Usage Efficiency"
    id: water_usage_efficiency
    unit_of_measurement: "%"
    accuracy_decimals: 1
    update_interval: 3600s  # Update hourly
    lambda: |-
      float actual_consumption = id(daily_water_consumption).state;
      float expected_consumption = 1100.0;  // Expected daily usage
      
      if (expected_consumption > 0) {
        float efficiency = (expected_consumption - actual_consumption) / expected_consumption * 100;
        return std::min(100.0f, std::max(0.0f, efficiency));
      } else {
        return 0;
      }

  - platform: template
    name: "Water Self-Sufficiency Duration"
    id: water_self_sufficiency
    unit_of_measurement: "days"
    accuracy_decimals: 1
    lambda: |-
      float total_volume = id(tank_volume).state;
      float actual_consumption = id(daily_water_consumption).state;
      
      if (actual_consumption > 0) {
        return total_volume / actual_consumption;
      } else {
        return id(days_of_water_left).state;  // Fallback to the standard calculation
      }

 

Edited by Muttley
typo

14 hours ago, Muttley said:

So 3 things that I noticed when compared to my code:

- your ina219 address is  0x45 - mine is 0x40
- I also noticed that your calibration numbers seem very low - perhaps adjust the point above and below and try take new calibrations.
- the float max_height is only 1 decimal place - perhaps make this 3

Here's my code in case :

captive_portal:

i2c:
  sda: 21
  scl: 22

sensor:
  - platform: ina219
    address: 0x40
    shunt_resistance: 0.1 ohm
    current:
      name: "INA219 Current"
      id: ina_current
      accuracy_decimals: 5
      filters:
      - multiply: 1000 #convert from Amps to mA
      unit_of_measurement: "mA"
    power:
      name: "INA219 Power"
      accuracy_decimals: 5
    bus_voltage:
      name: "INA219 Bus Voltage"
      accuracy_decimals: 2
    shunt_voltage:
      name: "INA219 Shunt Voltage"
      id: ina219_shunt_voltage
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00092; // Voltage at full condition
      float empty_voltage = 0.00042; // Voltage at empty condition
      float max_height = 1.570; // Adjust the max height as needed

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;

      // Ensure water level is within bounds
      water_level = std::max(0.0f, std::min(water_level, max_height));

      ESP_LOGD("custom", "Shunt Voltage: %.5f V", shunt_voltage);
      ESP_LOGD("custom", "Water Level: %.5f m", water_level);
      return water_level;

  - platform: template
    name: "Current Full Percentage"
    id: current_full_percentage
    unit_of_measurement: '%'
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float max_full_reading = 9.2;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4.2;  // Adjust the minimum reading at empty water level
      float current_reading = id(ina_current).state;
      
      float current_full_percentage = 100.0f * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading);
      return std::max(0.0f, std::min(current_full_percentage, 100.0f));

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      constexpr float tank_radius = 0.71;  // Adjust the tank radius as needed
      constexpr float max_height = 1.57;   // Adjust the max height as needed
      constexpr float pi = 3.14159265f;
      constexpr float total_volume_single_tank = pi * tank_radius * tank_radius * max_height * 1000;
      
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0f);
      float current_volume_single_tank = pi * tank_radius * tank_radius * water_level * 1000;
      float total_volume_both_tanks = 2 * current_volume_single_tank;
      
      return total_volume_both_tanks;

  - platform: template
    name: "Days of Water Left"
    id: days_of_water_left
    unit_of_measurement: "days"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float total_volume = id(tank_volume).state;
      float daily_usage = 1100.0; // 1100 liters per day
      float days_left = total_volume / daily_usage;
      
      // Cap the maximum days to 5 when tanks are full
      if (days_left > 5.0) {
        return 5.0;
      }
      
      return std::max(0.0f, days_left);

  - platform: template
    name: "Daily Water Consumption Rate"
    id: daily_water_consumption
    unit_of_measurement: "L/day"
    accuracy_decimals: 1
    update_interval: 3600s  # Update hourly
    lambda: |-
      static float last_volume = id(tank_volume).state;
      static unsigned long last_update = 0;
      float current_volume = id(tank_volume).state;
      unsigned long current_time = millis();
      float consumption_rate = 0;
      
      if (last_update > 0) {
        float volume_change = last_volume - current_volume;
        float days_elapsed = (current_time - last_update) / (1000.0 * 60 * 60 * 24);
        consumption_rate = volume_change / days_elapsed;
      }
      
      last_volume = current_volume;
      last_update = current_time;
      
      return std::max(0.0f, consumption_rate);

  - platform: template
    name: "Tank Refill Rate"
    id: tank_refill_rate
    unit_of_measurement: "L/hour"
    accuracy_decimals: 1
    update_interval: 300s  # Update every 5 minutes
    lambda: |-
      static float last_volume = id(tank_volume).state;
      static unsigned long last_update = 0;
      float current_volume = id(tank_volume).state;
      unsigned long current_time = millis();
      float refill_rate = 0;
      
      if (last_update > 0 && current_volume > last_volume) {
        float volume_change = current_volume - last_volume;
        float hours_elapsed = (current_time - last_update) / (1000.0 * 60 * 60);
        refill_rate = volume_change / hours_elapsed;
      }
      
      last_volume = current_volume;
      last_update = current_time;
      
      return refill_rate;

  - platform: template
    name: "Time to Empty"
    id: time_to_empty
    unit_of_measurement: "hours"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float current_volume = id(tank_volume).state;
      float consumption_rate = id(daily_water_consumption).state / 24.0;  // L/hour
      
      if (consumption_rate > 0) {
        return current_volume / consumption_rate;
      } else {
        return 0;  // Avoid division by zero
      }

  - platform: template
    name: "Time to Full"
    id: time_to_full
    unit_of_measurement: "hours"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float current_volume = id(tank_volume).state;
      float max_volume = 4973.0;  // Maximum volume of both tanks
      float refill_rate = id(tank_refill_rate).state;
      
      if (refill_rate > 0) {
        return (max_volume - current_volume) / refill_rate;
      } else {
        return 0;  // Not currently filling
      }

  - platform: template
    name: "Water Usage Efficiency"
    id: water_usage_efficiency
    unit_of_measurement: "%"
    accuracy_decimals: 1
    update_interval: 3600s  # Update hourly
    lambda: |-
      float actual_consumption = id(daily_water_consumption).state;
      float expected_consumption = 1100.0;  // Expected daily usage
      
      if (expected_consumption > 0) {
        float efficiency = (expected_consumption - actual_consumption) / expected_consumption * 100;
        return std::min(100.0f, std::max(0.0f, efficiency));
      } else {
        return 0;
      }

  - platform: template
    name: "Water Self-Sufficiency Duration"
    id: water_self_sufficiency
    unit_of_measurement: "days"
    accuracy_decimals: 1
    lambda: |-
      float total_volume = id(tank_volume).state;
      float actual_consumption = id(daily_water_consumption).state;
      
      if (actual_consumption > 0) {
        return total_volume / actual_consumption;
      } else {
        return id(days_of_water_left).state;  // Fallback to the standard calculation
      }

 

Thank you so much for your swift reply!

Regarding the ina219 sensor - I could not find the one that you linked in stock, so I bought this one instead. According to this wiki, I matched the address with the DIP switch configuration.
I added a "0" after the "2.7" Yesterday after your reply, and I think that was the problem. I'm still monitoring, but it looks positive, thank you!
I'm busy draining the tank to recalibrate everything. I will keep you posted.

Do you maybe know why my "Tank Volume" and "Current Full Percentage" aren't showing any data?

 

Again, thank you so much!

 

 

Screenshot 2025-01-18 124032.png

Screenshot 2025-01-18 124052.png

  • Author
7 hours ago, Robbie3337 said:

Thank you so much for your swift reply!

Regarding the ina219 sensor - I could not find the one that you linked in stock, so I bought this one instead. According to this wiki, I matched the address with the DIP switch configuration.
I added a "0" after the "2.7" Yesterday after your reply, and I think that was the problem. I'm still monitoring, but it looks positive, thank you!
I'm busy draining the tank to recalibrate everything. I will keep you posted.

Do you maybe know why my "Tank Volume" and "Current Full Percentage" aren't showing any data?

 

Again, thank you so much!

 

 

Screenshot 2025-01-18 124032.png

Screenshot 2025-01-18 124052.png

No worries - glad you got sorted, I'm sure your INA219 is good!
NB: no need to drain the tank - just pull out the probe and take it a reading. Because it's only 2 calibrations points, full and empty and thus you can just take an empty reading with the probe out the tank and one when it's full, ie: at the bottom of the tank when it's full.

Regarding the missing values, I forgot to mention that you'll need to add in a template sensor to your configuration.yaml file:

template:
  - sensor:
      - name: "Water Tank Level"
        unique_id: water_tank_level
        state: >
          {% set current = states('sensor.ina219_current') | float(default=0) %}
          {% set height = ((current * 5.0663) - 24.86) | round(2) %}
          {% if 0.000 <= height <= 72.000 %}
            {{ height }}
          {% else %}
            unknown
          {% endif %}

I completely forgot the logic for the above ^ so just use claude.ai - share your esp32 code with it and this and ask it to make the necessary changes.
Or even ask it to explain the above to you. 🙃

Oh and also, chances are that your Jojo tank holds more than 10 000L!

 

Edited by Muttley
added extra info

13 hours ago, Muttley said:

No worries - glad you got sorted, I'm sure your INA219 is good!
NB: no need to drain the tank - just pull out the probe and take it a reading. Because it's only 2 calibrations points, full and empty and thus you can just take an empty reading with the probe out the tank and one when it's full, ie: at the bottom of the tank when it's full.

Regarding the missing values, I forgot to mention that you'll need to add in a template sensor to your configuration.yaml file:

template:
  - sensor:
      - name: "Water Tank Level"
        unique_id: water_tank_level
        state: >
          {% set current = states('sensor.ina219_current') | float(default=0) %}
          {% set height = ((current * 5.0663) - 24.86) | round(2) %}
          {% if 0.000 <= height <= 72.000 %}
            {{ height }}
          {% else %}
            unknown
          {% endif %}

I completely forgot the logic for the above ^ so just use claude.ai - share your esp32 code with it and this and ask it to make the necessary changes.
Or even ask it to explain the above to you. 🙃

Oh and also, chances are that your Jojo tank holds more than 10 000L!

 

Thanks!

 

I'll test and report back.

  • Author
6 hours ago, Robbie3337 said:

Thanks!

 

I'll test and report back.

The joys of open source software 🤨
Turns out, I had a look at my dashboard a few moments ago and both Volume and Percentage we're missing yet I did absolutely nothing - no fiddling, I promise 🙃

Updated my ESP32 to the latest version and boom... everything was back. Maybe this is part of the issue you're having.

On 2025/01/19 at 3:56 PM, Muttley said:

The joys of open source software 🤨
Turns out, I had a look at my dashboard a few moments ago and both Volume and Percentage we're missing yet I did absolutely nothing - no fiddling, I promise 🙃

Updated my ESP32 to the latest version and boom... everything was back. Maybe this is part of the issue you're having.

Haha, you said it 🤣

I honestly hoped it was my problem, but sadly after updating, it did not work. It's as if the tank volume is just static.

3 Things bothering me are:

  1. My calibration value outside of the tank is indeed 0.00004V - I bought the one from DIY Electronics. I have attached a spreadsheet (history (9).csv) of the reading last year when I first connected the device.
  2. After copying your new code and adding the template sensor in the "configuration.yaml" - I still cannot get the Tank Volume & Current Full % to work.
    In the Developer Tools, I get an "unknown" output when testing the code for the template sensor. I attached the sensor ID I have as well as the states that Home Assistant is reading.
  3. The "Shunt Voltage" graph seemed to work fine, but after all the fiddling, it seems like I'm back to square one. Please see the "Correct" and "Incorrect" graph screenshots attached.

I'm sorry to trouble you so much!

I do appreciate your help though.

Template Editor Error.png

Ina219 Sensor ID.png

Ina219 States.png

Ina219 Incorrect Graph.png

Ina219 Correct Graph.jpg

history (9).csv

  • Author
1 hour ago, Robbie3337 said:

Haha, you said it 🤣

I honestly hoped it was my problem, but sadly after updating, it did not work. It's as if the tank volume is just static.

3 Things bothering me are:

  1. My calibration value outside of the tank is indeed 0.00004V - I bought the one from DIY Electronics. I have attached a spreadsheet (history (9).csv) of the reading last year when I first connected the device.
  2. After copying your new code and adding the template sensor in the "configuration.yaml" - I still cannot get the Tank Volume & Current Full % to work.
    In the Developer Tools, I get an "unknown" output when testing the code for the template sensor. I attached the sensor ID I have as well as the states that Home Assistant is reading.
  3. The "Shunt Voltage" graph seemed to work fine, but after all the fiddling, it seems like I'm back to square one. Please see the "Correct" and "Incorrect" graph screenshots attached.

I'm sorry to trouble you so much!

I do appreciate your help though.

Template Editor Error.png

Ina219 Sensor ID.png

Ina219 States.png

Ina219 Incorrect Graph.png

Ina219 Correct Graph.jpg

history (9).csv 103 B · 0 downloads

They said it'll be simple :D

Ok so a few more things come to mind:

When I had the issue yesterday, I noticed that I was not getting any values for INA219 Power (W) or and Values for INA219 Current (mA). We need these values to get the tank volume and the tank %. The way that I got this to work was a simple reboot of the 24V power supply which powers the INA219 and the probe. I then started to get W and mA data coming in.

Your example from above is showing the exact same scenario as I had:

image.png.08212a8f618895c3e8f5b6c1ca1edf78.png

I think the above is step 1 in troubleshooting but I also noticed a few other things:


I also noticed a few more things in your esphome code which I've updated based on your original figures shared and adjusted for a single tank like yours:
 

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      constexpr float tank_radius = 1.10;  // Adjust the tank radius as needed
      constexpr float max_height = 2.70;   // Adjust the max height as needed
      constexpr float pi = 3.14159265f;
      constexpr float total_volume = pi * tank_radius * tank_radius * max_height * 1000;
      
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0f);
      float current_volume = pi * tank_radius * tank_radius * water_level * 1000;
      
      return current_volume;

Your max height seems quite low compared to what it's listed on the Jojo Website - they state that the height is 3150mm and you're only accounting for a height of 2700mm. Did you put a tape measure into the tank to the bottom with water inside to check?

I think try the above steps and lets see what it comes up with.

You may also need to reboot the ESP32 - I think the sequence I use is: power off probe, power of ESP32, power on probe, power on ESP32.

 

On 2025/01/20 at 8:55 PM, Muttley said:

They said it'll be simple :D

Ok so a few more things come to mind:

When I had the issue yesterday, I noticed that I was not getting any values for INA219 Power (W) or and Values for INA219 Current (mA). We need these values to get the tank volume and the tank %. The way that I got this to work was a simple reboot of the 24V power supply which powers the INA219 and the probe. I then started to get W and mA data coming in.

Your example from above is showing the exact same scenario as I had:

image.png.08212a8f618895c3e8f5b6c1ca1edf78.png

I think the above is step 1 in troubleshooting but I also noticed a few other things:


I also noticed a few more things in your esphome code which I've updated based on your original figures shared and adjusted for a single tank like yours:
 

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      constexpr float tank_radius = 1.10;  // Adjust the tank radius as needed
      constexpr float max_height = 2.70;   // Adjust the max height as needed
      constexpr float pi = 3.14159265f;
      constexpr float total_volume = pi * tank_radius * tank_radius * max_height * 1000;
      
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0f);
      float current_volume = pi * tank_radius * tank_radius * water_level * 1000;
      
      return current_volume;

Your max height seems quite low compared to what it's listed on the Jojo Website - they state that the height is 3150mm and you're only accounting for a height of 2700mm. Did you put a tape measure into the tank to the bottom with water inside to check?

I think try the above steps and lets see what it comes up with.

You may also need to reboot the ESP32 - I think the sequence I use is: power off probe, power of ESP32, power on probe, power on ESP32.

 

Haha yes they did 🤣

I did a reboot on my side and my power and current values were restored the same as yours, thanks! It happened twice since your reply, so the second time I added a button to reboot the ESP32 to be able to reboot it remotely which also works.

It seems like the jaggered graph is a result of whenever the current and power values go down to 0 or unavailable, because when I reboot the ESP, then the graph begins to normalize after the values restored.

The reason I used 2700mm as the height is due to the spec sheet. It seems that the overflow level is at that level. Please see the picture attached.

Why do you think that my probe reading outside of the tank has an extra "0" compared to yours?

After making the change as per your recommendation in the "Tank Volume" template section in the code, I still cannot get the "Current Full %" and "Tank Volume" readings to work. It just stays at a constant level.

I asked claude.ai to adapt the template sensor code to my existing ESPHome code and this is what it came up with:

template:
  - sensor:
      - name: "Water Level Template"
        unique_id: water_level_template
        unit_of_measurement: "m"
        state: >
          {% set current = states('sensor.jojo_1_ina219_current') | float(default=0) %}
          {% set height = ((current - 4) / (12 - 4) * 2.70) | round(3) %}
          {% if 0.000 <= height <= 2.700 %}
            {{ height }}
          {% else %}
            unknown
          {% endif %}

Does it look fine?


Here is my latest ESPHome configuration:

web_server:
  
captive_portal:

button:
  - platform: restart
    name: "JoJo1 Restart"

i2c:
  sda: 21
  scl: 22

sensor:
  - platform: ina219
    address: 0x45
    shunt_resistance: 0.1 ohm
    current:
      name: "INA219 Current"
      id: ina_current
      accuracy_decimals: 5
      filters:
      - multiply: 1000 #convert from Amps to mA
      unit_of_measurement: "mA"
    power:
      name: "INA219 Power"
      accuracy_decimals: 5
    bus_voltage:
      name: "INA219 Bus Voltage"
      accuracy_decimals: 2
    shunt_voltage:
      name: "INA219 Shunt Voltage"
      id: ina219_shunt_voltage
      accuracy_decimals: 5
    max_voltage: 32.0V
    max_current: 400mA
    update_interval: 10s

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00012; // Voltage at full condition
      float empty_voltage = 0.00004; // Voltage at empty condition
      float max_height = 2.70; // Adjust the max height as needed

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;

      // Ensure water level is within bounds
      water_level = water_level < 0.0 ? 0.0 : water_level;
      water_level = water_level > max_height ? max_height : water_level;

      ESP_LOGD("custom", "Shunt Voltage: %.5f V", id(ina219_shunt_voltage).state);
      ESP_LOGD("custom", "Water Level: %.5f m", water_level);
      return water_level;


  - platform: template
    name: "Current Full Percentage"
    id: current_full_percentage
    unit_of_measurement: '%'
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      float max_full_reading = 12;  // Adjust the maximum reading at full water level
      float min_empty_reading = 4;  // Adjust the minimum reading at empty water level
      float current_reading = id(ina_current).state;
      
      if (current_reading <= min_empty_reading) {
        return 0.0;
      } else if (current_reading >= max_full_reading) {
        return 100.0;
      } else {
        float current_full_percentage = 100 * (current_reading - min_empty_reading) / (max_full_reading - min_empty_reading);
        return current_full_percentage;
      }

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      constexpr float tank_radius = 1.10;  // Adjust the tank radius as needed
      constexpr float max_height = 2.70;   // Adjust the max height as needed
      constexpr float pi = 3.14159265f;
      constexpr float total_volume = pi * tank_radius * tank_radius * max_height * 1000;
      
      float percentage_full = id(current_full_percentage).state;
      float water_level = max_height * (percentage_full / 100.0f);
      float current_volume = pi * tank_radius * tank_radius * water_level * 1000;
      
      return current_volume;

 

Please let me know if you need any additional information

 

Thanks! 😁

JoJo Tank Specs.png

Jaggered Graph.png

  • Author

Hey,

At least we've still got our humour, but we'll get this right eventually :D

So I think we should go back to basics here - I've previously tried using some DF Robot Components and I find them to be at times over engineered and just caused frustration and total randomness in terms of the data.
EG: I purchased one of their ADS1115 modules and got terrible data - purchased a generic one and it was perfect.

Can I suggest you purchase another INA219, which is like mine from PiShop or Communica ? I think this will remove any additional "calibration" etc that the DF Robot requires and we can use most of my code which works most of the time 🤣

Once this is sorted, we can dive into the code and see where's we're at - I still think that your mV reading is too low but I suspect the suggestion above will fix this.

I think it's good to have a bit of humour while we struggle with these wonderful devices. It helps taking the focus off of the frustration a bit. But yes, I definitely agree. We will get this right eventually 😂

Thanks for the tip on the DF Robot sensor! I will buy the generic INA219 as per one of your links. I agree with your approach to diagnosing the issue.

It will probably only arrive early next week, so I will post back when the new INA219 has been installed.

Thanks again!

  • Author
1 minute ago, Robbie3337 said:

I think it's good to have a bit of humour while we struggle with these wonderful devices. It helps taking the focus off of the frustration a bit. But yes, I definitely agree. We will get this right eventually 😂

Thanks for the tip on the DF Robot sensor! I will buy the generic INA219 as per one of your links. I agree with your approach to diagnosing the issue.

It will probably only arrive early next week, so I will post back when the new INA219 has been installed.

Thanks again!

We apologise for the frustation caused, please continue to hold while we wait for your parts to arrive :D

Let me know when the INA219 arrives and the struggle shall continue 🤓

  • 3 weeks later...

Hi Muttley and Robbie

I'll be attempting this project over the weekend, as the ultrasonic sensors are proving to be absolute rubbish inside the tanks.

I have 2x ECO Slimline 2220lt tanks, but will initially only use the DF Robot solution in one tank. Problem with these slimline tanks are that they have two cylinders, which join together towards the top, so I'm not sure on which formula to use in the yaml file. Do you guys perhaps have any ideas?

  • Author
1 hour ago, stormjp said:

Hi Muttley and Robbie

I'll be attempting this project over the weekend, as the ultrasonic sensors are proving to be absolute rubbish inside the tanks.

I have 2x ECO Slimline 2220lt tanks, but will initially only use the DF Robot solution in one tank. Problem with these slimline tanks are that they have two cylinders, which join together towards the top, so I'm not sure on which formula to use in the yaml file. Do you guys perhaps have any ideas?

Good luck on the weekend project - it seems it's going to be slightly different to my setup due to the joined cylinders but I plugged my code into Claude.ai and asked it to provide instructions and described your tank as best as possible. I think it's going to be a bit of a trial and error - here's the code and instructions:

 

# Configuration for dual connected cylindrical water tanks
# This configuration assumes two tanks connected at approximately 75% height

esphome:
  name: tankvolume

# [Previous WiFi, API, and basic configuration remains the same]

sensor:
  # INA219 sensor configuration remains the same as it's a single probe
  - platform: ina219
    # [Previous INA219 configuration remains unchanged]

  - platform: template
    name: "Water Level"
    id: water_level
    unit_of_measurement: 'm'
    accuracy_decimals: 3
    update_interval: 60s
    lambda: |-
      # CALIBRATION INSTRUCTIONS:
      # 1. Measure and record the shunt voltage when tanks are empty
      # 2. Measure and record the shunt voltage when tanks are full
      # 3. Update these values below:
      float shunt_voltage = id(ina219_shunt_voltage).state;
      float full_voltage = 0.00092;  // UPDATE: Measure and set your full tank voltage
      float empty_voltage = 0.00042; // UPDATE: Measure and set your empty tank voltage
      float max_height = 1.570;      // UPDATE: Set your tank height in meters

      // Calculate water level based on calibration
      float slope = (max_height - 0.0) / (full_voltage - empty_voltage);
      float intercept = max_height - slope * full_voltage;
      float water_level = slope * shunt_voltage + intercept;
      
      return std::max(0.0f, std::min(water_level, max_height));

  - platform: template
    name: "Tank Volume"
    id: tank_volume
    unit_of_measurement: "litres"
    lambda: |-
      // TANK CONFIGURATION PARAMETERS
      // UPDATE THESE VALUES:
      constexpr float tank_radius = 0.71;        // Set your tank radius in meters
      constexpr float tank_height = 1.57;        // Set total tank height
      constexpr float connection_height = 1.18;   // Set height of connection (75% of total height)
      constexpr float pi = 3.14159265f;
      
      float water_level = id(water_level).state;
      float total_volume = 0.0f;
      
      if (water_level <= connection_height) {
        // Below connection: Calculate as two separate cylinders
        total_volume = 2 * (pi * tank_radius * tank_radius * water_level * 1000);
      } else {
        // Above connection: Calculate as combined volume
        // First, volume up to connection
        float lower_volume = 2 * (pi * tank_radius * tank_radius * connection_height * 1000);
        // Then add combined volume above connection
        float upper_volume = pi * tank_radius * tank_radius * (water_level - connection_height) * 2000;
        total_volume = lower_volume + upper_volume;
      }
      
      return total_volume;

  # [Rest of the sensors remain largely the same, but update these values:]
  
  - platform: template
    name: "Days of Water Left"
    id: days_of_water_left
    unit_of_measurement: "days"
    lambda: |-
      float total_volume = id(tank_volume).state;
      float daily_usage = 1100.0; // UPDATE: Set your expected daily usage in liters
      float days_left = total_volume / daily_usage;
      
      // UPDATE: Adjust maximum days based on your total capacity
      if (days_left > 7.0) {  // Change based on your maximum capacity
        return 7.0;
      }
      
      return std::max(0.0f, days_left);

  - platform: template
    name: "Time to Full"
    id: time_to_full
    unit_of_measurement: "hours"
    lambda: |-
      float current_volume = id(tank_volume).state;
      // UPDATE: Calculate your maximum volume based on your tank dimensions
      float max_volume = 2 * (pi * 0.71 * 0.71 * 1.57 * 1000);  // Update with your dimensions
      float refill_rate = id(tank_refill_rate).state;
      
      if (refill_rate > 0) {
        return (max_volume - current_volume) / refill_rate;
      } else {
        return 0;
      }

Here are the key steps for the user to implement this configuration:

  1. Physical Measurements Needed:
    • Measure the radius of both tanks
    • Measure the total height of the tanks
    • Measure the height where the tanks are connected (approximately 75% of total height)
  2. Calibration Steps:
    • Install the INA219 sensor and connect it to the ESP32
    • With tanks empty, note the shunt voltage reading
    • With tanks full, note the shunt voltage reading
    • Update these values in the "Water Level" sensor configuration
  3. Key Configuration Updates:
    • In the Tank Volume sensor:
      • Update tank_radius with your measured radius
      • Update tank_height with your total tank height
      • Update connection_height with the height where tanks are connected
  4. Usage Configuration:
    • Update daily_usage in the "Days of Water Left" sensor with your expected daily water usage
    • Adjust the maximum days cap based on your total tank capacity

The main difference in this configuration compared to your original is the volume calculation that accounts for the connected tanks. When the water level is:

  • Below the connection: It calculates volume as two separate cylinders
  • Above the connection: It calculates the combined volume, treating the space above the connection as one larger cylinder

Hi Muttley

 

Thank you for this - Claude and I are still struggling with each other, maybe because of my very Afrikaans-like English.

 

I've gone through the schematics and cannot figure out the reason for DC-DC voltage regulator, as both the INA219 and the DF Robot can accept 24V input? What voltage setting do you use on the 'out' on the DC-DC voltage regulator then?

The 24V power supply I got have two DC outputs, so I'll use a buck converter to power the ESP32 from there, but can I not connect the INA219 and DF Robot directly to the 24V power supply?

I'm a little confused

And also, can you cut the cable and tube on the DF Robot shorter, or should it remain at the full 5m length?

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.