Add tank percentage to Mopeka Integration

Jerome, this looks like a work of art and I would love to use it for a 30lb propane tank, but unfortunately, to me, it’s like trying to read Chinese. LOL

I spent about 2 hours trying to figure out what to do with this and I’m officially lost. Can you please point me in the right direction? Does this code go in the configuration.yaml file? I saw another user put this in /config/entities/templates/mopeka/filename.yaml, but I don’t have an entities folder and all those other folders after it.

I tried the simple version posted up above in my configuration.yaml file and variations of it and cannot even get it to work (that is my actual sensor entity name):

template:
  - sensor:
      gas_level_percent:
        friendly_name: Propane Percentage
        value_template: "{{ ((states('sensor.propane_tank_1_tank_level') | float(2.0) - 2.0) * 11.77) | round(0) }}"
        unit_of_measurement: "%"
        icon: mdi:propane-tank

Again, I would like YOUR code to work for a 30lb propane tank. I also have the Mopeka H20 sensors on 3 rectangular water tanks with varying sizes that I’d like to get working as well, but that’s another topic.

Any help would be appreciated!

template:
   - sensor:
        gas_level_percent:
          friendly_name: Gas Level Percent
          unit_of_measurement: "%"
          value_template: "
          {% set min_l = 5 %}
          {% set max_l = 96 %}
          {% set current_l = states('sensor.gas_tank_level') | float %}
          {% set percentage = ((current_l - min_l) / (max_l - min_l)) * 100 %}
          {{ min(percentage | round(0),100) }}"

For 100lb tank, numbers in cm. Change min and max for other sizes.

5cm min = min value, empty
96cm max = max value, full

1 Like

Thanks for this, but for some reason I can’t get Home Assistant to see the below entity. This is true even when I list all entities. Any suggestions?

- platform: template
    name: 'DS2 Propane Tank Percentage'
    unique_id: sensor.propane_ds_pct
    state: >
        {% set side_length = 203.0 %}
        {% set tank_diameter = 304.0 %}
        {% set wall_thickness = 3.175 %}

        {% set measured_fill_depth = states('sensor.pro_check_192a_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 mi>
             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) }}

    unit_of_measurement: "%"
    icon: mdi:propane-tank

here’s mine. maybe you can adapt to your setup:

template:
  - sensor:
    - name: House Gas Tank Percent 2
      unique_id: sensor.house_gas_tank_percent_2
      unit_of_measurement: '%'
      state_class: measurement
      state: >
        {% 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_gas_tank_monitor_tank_level')|float(0) * 25.4 - 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 wanted to provide a small update to this thread in regards to using the Mopeka Pro Universal sensors to measure commodities other than propane (Diesel, gas, water, etc).

Currently the native HA integration, as well as the ESPHome integration do not support using these sensors for anything other than propane measurements. There’s also no way to configure these sensors in either integration to show tank percentages by default, or adjust tank sizes and orientations (ESPHome has a few presets to pick from). This leads to having to do quite a lot of yaml configuration with template sensors, which just seems like a lot of work to get an accurate measurement of a given liquid.

However I’ve found a solution for my specific setup so I can configure these sensors for various commodities, and set all the parameters of the sensors to give accurate measurements.

My setup consists of an off-grid solar system based on Victron gear that all communicates back to the Cerbo GX for remote management. Luckily the Cerbo GX supports the Mopeka sensors natively and allows for a wide range of settings to be configured all from the web ui for each connected sensor.

mopeka3
mopeka2
mopeka1

Once you’ve configured your sensors on the Cerbo GX, you can expose them through MQTT to Home Assistant. There’s many different MQTT topics that can be exposed for these sensor so you can pick and choose exactly what you’d like to see in HA.


Below is an example sensor to show the tank percentage. No fancy calculations needed.

* name: "Cerbo Gas Percent"
state_topic: "victron/N/VRM_ID/tank/20/Level"
unique_id: "cerbo_gas_percent"
device_class: energy
value_template: '{{ value_json.value | round(0) }}'
unit_of_measurement: "%"
icon: mdi:propane-tank

I hope this eventually helps out others who were trying to use these sensors in their RVs or vans and has a Cerbo GX to integrate them with. I hope that the Mopeka HA integration eventually gets updated to allow more configuration as the Cerbo GX gives us. Perhaps someone who is interested can take a look at the VenusOS source code and reverse engineer something for the HA integration. I’m not sure how much of their code is open, but I have been able to find this repo…

1 Like

Another update!

I just noticed that the issue on GitHub regarding the inclusion of additional commodities has been closed because support has been added for inclusion into ha core!

It looks like we’ll finally be getting some more options for what liquids we can measure!

I implemented the other medium types (including fluids and air) in the Mopeka integration. Essentially medium types like water, oil, and air, have various coefficients when measured with ultrasonic sensors. The integration will now give accurate readings for types other than propane.

Bottom up sensors measure through the tank bottom to the fluid surface.

Top down sensors measure air to the fluid surface so the calculation of the fluid height (or percentage) must take into account the air gap from the top of the tank and then the depth of the tank (depth of tank from sensor to tank bottom - measured air gap = depth of fluid).

Now we just need a way to convert to percentages easily within the integration. It still measures in inches.

Tough crowd here :sweat_smile:.

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.

Used to have a percentage working… unsure if recent updates to HA has introduced more complexity to this?

It no longer will render the percentage for me.
Anyone notice this too?