Add tank percentage to Mopeka Integration

Mopeka integration

Template sensor calc for 500 gallon tank based on xls calc found in the included link. Just converted to HA format with some math reduction. Hopefully save others some time. I have only spot checked at my current level. App reads 49% and this calced to 48.74%. If your horizontal tank is different use the xls sheet and copy over the new needed constants.

template:
  - sensor:
     - name: propane_house_tank_percentage
        unit_of_measurement: "%"
        state: >
          {% set h = (states('sensor.propane_house_tank_level') | float - 0.25) / 12 %}
          {# vp = in propane - bottom thick / 12(conv ft) #}
          {% set vp= (pi * h ** 2/3) * (4.625 - h) + 6.8333*(2.37673611*acos((1.54166-h)/1.54166)-(1.54166-h)*sqrt(3.08333*h-h**2)) %}
          {# propane volume = reduction with h calc from https://github.com/home-assistant/core/issues/87122 #}
          {% set vt = 66.37099 %}
          {{ ((vp / vt) * 100) | round(2) }}
2 Likes

Has anyone been able to convert this into a cubic meter for usage in the energy dashboard?

1 Like

For others searching this thread a 30lb vertical tank: min is 1.5in and max is 15in and the multiplier for this sensor is 7.4074.

Also, after filling a tank this sensor formula can result in a percentage greater than 100%. To fix, add the min filter using brackets around the array as shown below.

{{ [ ((states('sensor.propane_tank_level') | float(1.5) - 1.5) * 7.4074) | round(0), 100] | min }}

Does anyone take the tank temperature into account when calculating the percentage? The apparent volume of propane changes with temperature swings so just using a constant will work as long as your temp is stable, but where I live we can have a 40 degree F swing between low and high temps. Iā€™ve looked for the formula but havenā€™t had much luck in anything that works.

Terry

2 Likes

Iā€™m curious about this also. Without taking temperature into account, I canā€™t properly determine consumption due to the swings you mention.

I donā€™t think youā€™ll ever be able to use one of these sensors and get a reliable consumption value (unless youā€™re using a LOT of propane). I also donā€™t think itā€™s simply due to temperature swings, as I see a reasonable bit of noise and general variation in the values all the time. But for having a pretty accurate value of fill level, it works fantastic.

the reading variation can be softened using trend or filter sensors for the most part. still, the fill percentage varies too much each day w/ temperature that filtering/trending wonā€™t work. iā€™m tempted to figure out a way to keep estimate consumption between peaks, since i rarely see a peak exceeding a previous one. check it out percentage vs temp

Using the constant appears to match the Mopeka app throughout the usage of the tank. That is likely what most users would expect to see when checking their custom sensor and close enough for me even though it fluctuates slightly with temperature as Iā€™m really only concerned with when Iā€™m nearly out of propane and need to take action.

Seems like you might be able to use a derivative sensor to determine your consumption rate with a few different values in the ā€œTime Windowā€ field to see what smooths it out best. Using the ā€œtank percentageā€ sensor as I have in my screenshot would show you x% / hour consumption.

I imagine you are looking to take it a step further and estimate ā€œhow much time until I run out of propane?ā€ For that, there are several different forums posts on battery consumption rates and energy remaining (usually for solar batteries) that seem like they could be modified to work for propane.

For those looking to create one through the GUI:
Settings ā†’ Devices & Services ā†’ Helpers ā†’ Create Helper ā†’ Derivative sensor

1 Like

I was pretty unhappy with the rudimentary calculations for vertical tanks provided above, so I threw together this customizable template (These are numbers for a 20lb tank, but can be adjusted for any dimension tank you want) for vertical tanks:

{# User supplied variables. Use the same units that the mopeka sensor is configured to report.
     I use mm by default (better resolution from the sensor #}
{% set side_length = 203.0 %}
{% set tank_diameter = 304.0 %}
{% set wall_thickness = 3.175 %}

{% set measured_fill_depth = states('sensor.propane_tank_level') | float - wall_thickness%}

{% set R_tank = tank_diameter / 2 %}
{% set H_tank = side_length + R_tank %}

{# A 2:1 Ellipsoid has a c value that is half of its a/b values. A and B are the radius of the tank #}
{% set E_a = R_tank %}
{% set E_b = R_tank %}
{% set E_c = R_tank / 2 %}

{# Vertical tanks are a cylinder capped on either end with half of a 2:1 ellipsoid https://www.vcalc.com/wiki/vCalc/Ellipsoid-Volume #}
{# Calculate max tank volume in mm^3 #}
{% set hemi_ellipsoid_volume = 2 / 3 * pi * E_a * E_b * E_c %}
{% set cylinder_volume = side_length * pi * R_tank**2 %}
{% set max_volume = 2 * hemi_ellipsoid_volume + cylinder_volume %}

{# Fill volume is dependent on which region of the tank the level is in. #}
{#   Create a piecewise function which regions for bottom ellipsoid, middle cylinder, or top ellipsoid #}
{% if 0 <= measured_fill_depth and measured_fill_depth <= E_c %}
  {# The region where the fill level is in the bottom ellipsoid can be calculated using the volume 
     for an elipsoidal cap. https://www.vcalc.com/wiki/ellipsoid-cap-volume #}
  {% set measured_fill_volume = pi * E_a * E_b * ((2/3 * E_c) - E_c + measured_fill_depth + ((E_c - measured_fill_depth)**3/(3 * E_c**2))) %}
{% elif E_c <= measured_fill_depth and measured_fill_depth <= E_c + side_length %}
  {# The region where the fill level is in the middle cylinder can be calculated using the volume 
     of the bottom ellipsoid plus the filled volume of the cylinder #}
  {% set measured_fill_volume = hemi_ellipsoid_volume + (measured_fill_depth - E_c) * pi * R_tank**2 %}
{% elif E_c + side_length <= measured_fill_depth and measured_fill_depth <= H_tank %}
  {# The region where the fill level is in the top ellipsoid can be calculated by subtracting the volume 
     of an elipsoidal cap that has a height of the height of the tank minus the fill level. 
     https://www.vcalc.com/wiki/ellipsoid-cap-volume #}
  {% set measured_fill_volume = max_volume - (pi * E_a * E_b * ((2/3 * E_c) - E_c + H_tank - measured_fill_depth + ((E_c - H_tank + measured_fill_depth)**3/(3 * E_c**2)))) %}
{% else %}
  {# All other ranges are invalid, set measured_fill_volume to a value that will result in the template returning -1 #}
  {% set measured_fill_volume = -max_volume / 100 %}
{% endif %}

{{ (100 * measured_fill_volume / max_volume) | round(1) }}

I also created a similar configurable template for horizontal tanks.These are numbers for a 500 gal tank, but can be adjusted for any dimension tank you want:

{# User supplied variables. Use the same units that the mopeka sensor is configured to report.
     I use mm by default (better resolution from the sensor #}
{% set overall_length = 3022.6 %}
{% set overall_tank_diameter = 952.5 %}
{% set wall_thickness = 6.35 %}

{% set internal_tank_diameter = overall_tank_diameter - 2 * wall_thickness %}
{% set side_length = overall_length - overall_tank_diameter %}

{% set measured_fill_depth = states('sensor.propane_tank_level') | float - wall_thickness %}

{% set R_tank = internal_tank_diameter / 2 %}

{# Horizontal tanks are a cylinder capped on either end with hemispheres #}
{# calculate max tank volume in mm^3 #}
{% set spherical_volume = 4 / 3 * pi * R_tank**3 %}
{% set cylinder_volume = side_length * pi * R_tank**2 %}
{% set max_volume = spherical_volume + cylinder_volume %}

{# Calculate the volume of a spherical cap of height equal to the fill level: https://www.vcalc.com/wiki/Volume-of-a-Sphere-Cap #}
{% set fill_spherical_volume = pi / 3 * measured_fill_depth**2 * (3 * R_tank - measured_fill_depth) %}
{# Calculate the volume of a partial horizontal cylinder: https://www.vcalc.com/wiki/volume-of-horizontal-cylinder #}
{% set fill_cylinder_volume = side_length * (R_tank**2 * acos((R_tank - measured_fill_depth) / R_tank) - (R_tank - measured_fill_depth) * sqrt(2 * R_tank * measured_fill_depth - measured_fill_depth**2)) %}

{% set measured_fill_volume = fill_spherical_volume + fill_cylinder_volume %}

{{ (100 * measured_fill_volume / max_volume) | round(2) }}

Just make sure you enter your user dimensions in the same unit as your sensor is configured or it will not work correctly.

2 Likes

iā€™ll try this, but anytime iā€™ve used a derivative sensor (like electrical energy), if thereā€™s a decrease in the data, then the subsequent increase will make the sensor go nuts. like double the consumption. hope this makes sense the way iā€™m explaining.

i did a quick implementation. your measurements are same as mine with a x25.4 to convert from mm to in (like the sensor). my calculation is much simpler:

{% set full_height = 90 %}
{{ (states('sensor.house_gas_tank_monitor_tank_level')|float(0) / (full_height|float(0) / 2.54) * 100) | round(1) }}

i derived the ā€œ90ā€ from the sensor when the fill was 58% at 20.7" (20.7/58%x2.54=90ish)

i think your method is a lot more precise for volume and note a delta of ~5.5% between mine and your method. iā€™ll keep monitoring. thanks for thisā€¦

Yeah, mine is going to be the exact fill volume.

The linear level based approach described (which is basically assuming that your tank is a rectangle. will become more inaccurate the further you get from the mid level of the tank (Iā€™m assuming youā€™re referring to a horizontal tank and not a vertical tank. Vertical tanks are a whole different beast)

You can see the effects of this by substituting static values in for your measured fill level. At 50% fill the two methods will be the same, but at 25% fill level your approach will be ~7% higher than the actual fill percentage and at 75% fill level it will be 7% lower.

1 Like

not sure where I am going wrong hereā€¦ I am getting a very ā€œoffā€ percentage.
I put your code into a template sensor. Please correct me where I am wrongā€¦

homeassistant:/config/entities/templates/mopeka# cat house_500gal_2.yaml


- sensor:
  - name: "House 500gal Tank Percentage 2"
    unit_of_measurement: "%"
    state: >
      {# User supplied variables. Use the same units that the mopeka sensor is configured to report. #}
      {# I use mm by default (better resolution from the sensor #}
      {% set overall_length = 3022.6 %}
      {% set overall_tank_diameter = 952.5 %}
      {% set wall_thickness = 6.35 %}
      {% set internal_tank_diameter = overall_tank_diameter - 2 * wall_thickness %}
      {% set side_length = overall_length - overall_tank_diameter %}
      {% set measured_fill_depth = states('sensor.house_500gal_tank_level') | float - wall_thickness %}
      {% set R_tank = internal_tank_diameter / 2 %}

      {# Horizontal tanks are a cylinder capped on either end with hemispheres #}
      {# calculate max tank volume in mm^3 #}
      {% set spherical_volume = 4 / 3 * pi * R_tank**3 %}
      {% set cylinder_volume = side_length * pi * R_tank**2 %}
      {% set max_volume = spherical_volume + cylinder_volume %}

      {# Calculate the volume of a spherical cap of height equal to the fill level: https://www.vcalc.com/wiki/Volume-of-a-Sphere-Cap #}
      {% set fill_spherical_volume = pi / 3 * measured_fill_depth**2 * (3 * R_tank - measured_fill_depth) %}

      {# Calculate the volume of a partial horizontal cylinder: https://www.vcalc.com/wiki/volume-of-horizontal-cylinder #}
      {% set fill_cylinder_volume = side_length * (R_tank**2 * acos((R_tank - measured_fill_depth) / R_tank) - (R_tank - measured_fill_depth) * sqrt(2 * R_tank * measured_fill_depth - measured_fill_depth**2)) %}
      {% set measured_fill_volume = fill_spherical_volume + fill_cylinder_volume %}
      {{ (100 * measured_fill_volume / max_volume) | round(2) }}

ā€¦and if I use this formula, I get something much closer

homeassistant:/config/entities/templates/mopeka# cat house_500gal.yaml

- sensor:
  - name: "House 500gal Tank Percentage 1"
    unit_of_measurement: "%"
    state: >
      {% set h = (states('sensor.house_500gal_tank_level') | float - 0.25) / 12 %}

      {# vp = in propane - bottom thick / 12(conv ft) #}
      {% set vp= (pi * h ** 2/3) * (4.625 - h) + 6.8333*(2.37673611*acos((1.54166-h)/1.54166)-(1.54166-h)*sqrt(3.08333*h-h**2)) %}

      {# propane volume = reduction with h calc from https://github.com/home-assistant/core/issues/87122 #}
      {% set vt = 66.37099 %}
      {{ ((vp / vt) * 100) | round(2) }}

How would you format a template sensor for the Mopeka Pro Universals that can measure things other than propane? For instance I have a 6 gallon marine fuel tank that is hooked up to my diesel heater. Using the Mopeka app I can set the tank to be ā€œArbitraryā€ and just input the fuel height at the full mark. For me this is 7in when full. Works great in the app, but how do I translate this to HA?

Could anyone provide the calculation for a 250 gallon horizontal tank, please?

Iā€™ve running both sensors for about 3 weeks. i agree that your calculations should be more accurate - makes sense. 3 weeks ago i was reading 43% (my quick method) vs 37% (your more precise method). this is consistent in approach that 7-8% discrepancy you mention. 3 weeks later the readings are 31% vs 23%. but whatā€™s interesting is that 31% is close to the mechanical pressure dial, which is reading ~30%. any idea why? or is the dial just an artifact of the pressure and doesnā€™t really reflect the actual volume? in any case, i was instructed to call for a fill at ~25%. iā€™m getting close to that.

check out this table:
image

then you can modify @jrhelbert 's post above (the horizontal tank equation) with the appropriate size for a 250gal

1 Like

Thanks so much to both of youā€¦ this worked great! In case it might help someone else, hereā€™s the template sensor state for a 250 gallon horizontal tank when Mopeka reports depth in inches. Just make sure you change sensor.propane_tank_level to whatever entity that it will listen to for readings:

{# Set three user supplied variables. Use the same units that the mopeka sensor is configured to report.
     I am using inches here #}
{% set overall_length = 94.00 %}
{% set overall_tank_diameter = 30.00 %}
{% set wall_thickness = 0.25 %}

{% set internal_tank_diameter = overall_tank_diameter - 2 * wall_thickness %}
{% set side_length = overall_length - overall_tank_diameter %}

{% set measured_fill_depth = states('sensor.propane_tank_level') | float - wall_thickness %}

{% set R_tank = internal_tank_diameter / 2 %}

{# Horizontal tanks are a cylinder capped on either end with hemispheres #}
{# calculate max tank volume in mm^3 #}
{% set spherical_volume = 4 / 3 * pi * R_tank**3 %}
{% set cylinder_volume = side_length * pi * R_tank**2 %}
{% set max_volume = spherical_volume + cylinder_volume %}

{# Calculate the volume of a spherical cap of height equal to the fill level: https://www.vcalc.com/wiki/Volume-of-a-Sphere-Cap #}
{% set fill_spherical_volume = pi / 3 * measured_fill_depth**2 * (3 * R_tank - measured_fill_depth) %}
{# Calculate the volume of a partial horizontal cylinder: https://www.vcalc.com/wiki/volume-of-horizontal-cylinder #}
{% set fill_cylinder_volume = side_length * (R_tank**2 * acos((R_tank - measured_fill_depth) / R_tank) - (R_tank - measured_fill_depth) * sqrt(2 * R_tank * measured_fill_depth - measured_fill_depth**2)) %}

{% set measured_fill_volume = fill_spherical_volume + fill_cylinder_volume %}

{{ (100 * measured_fill_volume / max_volume) | round(2) }}