Tough crowd here .
Providing accurate inches for any medium is the obvious first step. When I get some spare cycles I may invest some effort for tank calculations. In the meantime…
For standard vertical BBQ propane tanks in various sizes the percentage is trivial since the tanks are nearly symmetrical. If the sensor measures a nymber of inches at x% in the app then everything else is a ratio to that. so if 11.7"/100% then 5.85"=50%. Any reading at any level will do the trick.
# BBQ Tank Level Percentage
- name: "BBQ Tank Level Percentage"
unique_id: sensor.bbq_tank_level_percentage
unit_of_measurement: "%"
state: >
{% set height = states('sensor.repeater_bbq_tank_level') %}
{% if height is match("^-?\\d+(\\.\\d+)?$") %}
{% set height = height | float %}
{% set reference_height = 11.7 %}
{% set reference_percent = 100 %}
{% set percentage = (height / reference_height * reference_percent) | round(1) %}
{{ [0, [100, percentage] | min] | max }}
{% else %}
-1
{% endif %}
attributes:
friendly_name: "BBQ Tank Level Percentage"
icon: mdi:gas-cylinder
For horizontal tanks, like with propane house tanks, it’s a bit more involved, especially since the tank probably is not just a cylinder but has elliptical ends so there is more fluid near the center both with regard to the circumference of the tank and the ends of the cylinder. Still the shape volume can be calculated. Reference measurements may be more accurate since the supplier full does not generally mean full to the top.
Even more involved if you have a top down horizontal leg tank with indentions, legs, etc. Here again, full is not full to the top since there is an overflow and empty is not empty to the bottom since the outflow is not at the bottom of the tank. I have a 520 gallon water tank with a TD40 top down sensor where the tank has markings on the side with gallon increments. This calculation is an extrapolation which is what the Mopeka app offers. One can also do this in a template, for example the points contain inches of water and gallons like this:
- sensor:
- name: "Hill Tank Gallons Remaining"
unique_id: sensor.hill_tank_gallons_remaining
unit_of_measurement: "gallons"
state: >
{% set air_distance = states('sensor.repeater_hill_tank_520_gallon_tank_level') %}
{% if air_distance is match("^-?\\d+(\\.\\d+)?$") %}
{% set air_distance = air_distance | float %}
{% set water_depth = 48 - air_distance %}
{% set points = [(1.5, 0), (12.5, 100), (20.5, 200), (27.5, 300), (35.5, 400), (44.5, 500), (46.5, 520)] %}
{% set gallons = namespace(value=0) %}
{% for i in range(points | length - 1) %}
{% set x1, y1 = points[i] %}
{% set x2, y2 = points[i+1] %}
{% if water_depth >= x1 and water_depth <= x2 %}
{% set gallons.value = y1 + (water_depth - x1) * (y2 - y1) / (x2 - x1) %}
{% break %}
{% endif %}
{% endfor %}
{{ gallons.value | round(1) }}
{% else %}
-1
{% endif %}
While i used the markings on the side of the tank I adjusted the points (inches, gallons) so that the readings met my requirements for real usage.