Help to convert battery voltage to percentage

Hi all. Fairly new to home assistant. I have a battery entity ‘sensor.water_temp_battery’ that displays the battery in volts. I would like to convert this to a percentage using a template.

I have checked out other posts regarding this but cant get any of the examples to work for me.

1.62v or above should = 100%
1.30v or below should = 0%

I can get the template to show either 100% or 0% but nothing in between. How can I configure the template to show the percentage more acutely? E.g 1.46v = 50%

Thanks!

You could use the compensation integration:

compensation:
  battery_pct:
    source: sensor.your_battery_sensor_here
    unit_of_measurement: "%"
    data_points:
      - [1.62, 100]
      - [1.3, 0]

However this will project values above and below your voltage range if they are input to the integration.

Instead you should use a template sensor:

template:
  - sensor:
      - name: "Battery %"
        unit_of_measurement: "°%"
        device_class: battery
        availability: "{{ states('sensor.your_battery_sensor_here')|is_number }}"
        state: >
          {% set batt_volts = states('sensor.your_battery_sensor_here')|float(0) %}
          {% set batt_pct = 312.5 * batt_volts - 406.25 %} {# calculate percent from the voltage #}
          {% set batt_pct_clamped = ([0, batt_pct, 100]|sort)[1] %} {# clamp the output to a 0-100% range #}
          {{ batt_pct_clamped }}

I’ve expanded my working for clarity. You can simplify it if you wish.

The device class will give a nice changing icon depending on the state of charge.

The availability template will make the output unavailable if your sensor is unavailable (rather than 0 from the float(0) default).

7 Likes

That works perfectly. Thank you for your help!

1 Like

This is a great solution. But how did you come up with the values 312.5 and 406.25?
I would like to do the same for a battery where 3.0V equals 100 % and 2.1V equals 0% and cannot figure out how to adjust the mentioned values.

Okay, just did some Excel trial and error and came up with {% set batt_pct = 111.1 * batt_volts - 233.3 %} for my use case, which are two AAA batteries in series. My device is not functioning properly if the voltage drops under 2.1V, so that is what I want to set as 0%.This works well for my use case.

Excel screenshot how I got to the 2 values in the code (maybe that helps others that aren’t good at math and need to adjust the code to their respective full and empty voltage levels:
excel

Also, I found an error in the unit of measurement which I corrected and then I rounded the end result to a full number, as it was displaying values like 99.99999655 % which do not make sense for this use case. Did it is as follows:

template:
  - sensor:
      - name: "Battery % Your Sensor Name"
        unit_of_measurement: "%"
        device_class: battery
        availability: "{{ states('sensor.your_battery_sensor_here')|is_number }}"
        state: >
          {% set batt_volts = states('sensor.your_battery_sensor_here')|float(0) %}
          {% set batt_pct = 111.11 * batt_volts - 233.33 %} {# calculate percent from the voltage #}
          {% set batt_pct_clamped = ([0, batt_pct, 100]|sort)[1]|round(0) %} {# clamp the output to a 0-100% range and round to full number #}
          {{ batt_pct_clamped }}

Of course this does not represent a correct percentage value of how “full” a battery is, since the voltage does not drop in a linear way for any batteries and especially not for alkaline batteries. But for displaying a roundabout value for a dashboard I like it still better than displaying the voltage.

2 Likes

I’m trying to get this fitted to my situation, which is battery values from 3.3v - 1.5v
Since I’m mathematically challenged and totally clueless where the applied values come from, I hope you can help me. What would be the values for my use case??

1 Like

Just ran across this thread while also trying to do the same thing. Based on the formulas shown above, your numbers should be 55.55 and 83.31. This should get you to about 0.01.

The spreadsheet shown essentially gives you everything you need to plug in, except for the first value, which you just start shoving numbers into to see how close the “0 = ideal” column gets to 0 based on that number and start fine tuning your first value towards 0.

2 Likes

How can I convert this to a 12v battery?

Edit: Actually, I worked out the maths behind this and got it working. Cool formula!

Thanks :slight_smile:

1 Like

I’m not understanding the complexity of the formula here. Is there a reason that the following wouldn’t be sufficient in this case?

Percentage of Charge (%) = [(Current Battery Voltage - Min Voltage) / (Max Voltage - Min Voltage)] * 100


did yo get it verified? seems easier to me…

I’ve code a template macro for computing the m and b factors of a linear equation.

sensor:
  - name: "Water Meter Battery Level"
    unit_of_measurement: "%"
    device_class: battery
    availability: "{{ states('sensor.water_meter_battery_voltage')|is_number }}"
    state: >
      {% set battery_voltage = states('sensor.water_meter_battery_voltage') | float %}
      {% set max_battery_voltage = 3.85 %}
      {% set min_battery_voltage = 3.0 %}

      {% macro battery_percentage(battery_voltage) %}
          {% set m = 100 / (max_battery_voltage - min_battery_voltage) %}
          {% set b = m * min_battery_voltage %}   
          {{([0, m * battery_voltage  - b, 100]|sort)[1] | round(2) }}
      {% endmacro %}

      {{ battery_percentage(battery_voltage) }}

Adding the results of my own battle with the new template format, for future folks, I hate templates; but anyway, your formula is perfectly sufficient, and once plonked into my own take on this issue, it works brilliantly, with no need to wonder what any ‘magic numbers’ are. This is in my templates.yaml.

- sensor:
    - name: "Ruperts Battery %"
      unique_id: ruperts_battery_percentage
      unit_of_measurement: "%"
      device_class: battery
      availability: "{{ states('sensor.ruperts_battery_monitor')|is_number }}"
      state: >
        {% set batt_volts = states('sensor.ruperts_battery_monitor')|float(0) %}
        {% set max_battery_voltage = 12.7 %}
        {% set min_battery_voltage = 10.5 %}
        {% set batt_pct = ((batt_volts - min_battery_voltage) / (max_battery_voltage - min_battery_voltage)) * 100 %} {# calculate percent from the voltage #}
        {% set batt_pct_clamped = ([0, batt_pct, 100]|sort)[1]|round(0) %} {# clamp the output to a 0-100% range #}
        {{ batt_pct_clamped }}

Voltages are for a 12v lead acid car battery, tables found on the internet give various slightly different state of charge v voltage, so your mileage may vary.

My first post on here, so I hope it’s OK.

Edited to add a pair of missing parenthesis on the calculate percentage line, which would probably upset ‘BODMAS’.

1 Like