MQTT value template to catch NULL

I have an MQTT topic that can reports a state that sometimes is an number and other times is a null value. How do I build a value template to perform the proper calculation if its a number but allow for the null when present?

For example the below works fine when the value is a number, however when the value flips to “null” I receive the log error “Exception in message_received when handling msg”

#Victron SmartShunt Runtime Remaining
  - unique_id: victron_shunt_battery_timetogo
    name: Battery Runtime Remaining
    device_class: ENERGY_STORAGE
    unit_of_measurement: 'kWh'
    state_topic: "venus-home/N/serial#/battery/288/TimeToGo"
    value_template: "{{(value_json.value / 3600) | round(0) }}"
    icon: mdi:battery

What value do you want the MQTT Sensor to report when value_json.value isn’t a number?

To clarify, is the received payload always in JSON format and the value key sometimes contains a number and sometimes contains nothing? Post an example or two of the payload.

Preferably I would love for it to just ignore it until it returns back to a number and it can be calculated. Watching MQTT explorer its consistently a number with a NULL thrown in every now and then.

TimeToGo = {“value”: 863999.9375}
TimeToGo = {“value”: null}

Try this:

    value_template: >
      {% set v = states('sensor.battery_runtime_remaining') | default(0) %}
      {{ (value_json.value / 3600) | round(0) if value_json.value | is_number else v }}

It reports the newly received value only if it’s a number, otherwise it reports the sensor’s existing value (it reports zero if the sensor has no existing value).


EDIT

Correction. Removed errant double-quotes character.

Got the following error in the logs, the value “50” was correct and matches the source.

Exception raised when updating state of sensor.battery_time_remaining, topic: 'venus-home/N/b827eb39dc65/battery/288/TimeToGo' with payload: b'{"value": 179579.984375}'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 579, in state
    numerical_value = int(value)
ValueError: invalid literal for int() with base 10: '50"'

The problem is due to a silly little typo I made in the template I posted above. :man_facepalming:t3:

There’s a double-quotes character at the end of the second line. Remove it because it shouldn’t be there (it’s a leftover from when I copy-pasted your original template). Its presence is causing the error.

After you remove it, ensure you execute Developer Tools > YAML > Reload Template Entities. The next payload received by the sensor will be stored without the double-quotes character.


NOTE

I have already corrected the example posted above and removed the double-quotes character.

Ah man I thought I fixed it and got excited making it more complicated than it needed to be with the below! Yours works and less code is always better :slight_smile: appreciate the help

        value_template: >
            {% set v = states('sensor.battery_runtime_remaining') | default(0) %}
            {% if value_json.value | is_number %}
              {{ (value_json.value / 3600) | round(0) }}
            {% else %}
              v
            {% endif %}

If you want slightly less code, you can write it like this:

    value_template: >
      {{ (value_json.value / 3600) | round(0) if value_json.value | is_number
        else states('sensor.battery_runtime_remaining') | default(0) }}
1 Like

** NOTE: There wasn’t a “reload template entities” in dev tools yaml, but after reloading all yaml I think it is working. Disregard below.

well biscuits. Still erroring when the value returned is null.

Exception raised when updating state of sensor.battery_time_remaining, topic: 'venus-home/N/serial#/battery/288/TimeToGo' with payload: b'{"value": null}'
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 579, in state
    numerical_value = int(value)
ValueError: invalid literal for int() with base 10: 'unknown'

Null or unknown? The error message is reporting unknown isn’t an integer value.

As an experiment, let’s see how this behaves:

    value_template: >
      {{ (value_json.value | float(0) / 3600) | round(0) if value_json.value | is_number
        else states('sensor.battery_runtime_remaining') | float(0) }}

Attached the reloading options I have in dev tools page. The template is working fine UNLESS I reload HA while the battery is fully charged or charging. When ever the battery is fully charged and not draining is when the MQTT value is being sent as “null”. I noticed on another users example they were showing the state as “charging”, is there a way to build the template to show the time remaining OR the value “charging” ?

Not sure why Template Entities doesn’t appear on the reloading page. I would expect that if you didn’t have any Template entities defined but you do.

Your Template Sensor employs the unit_of_measurement option which (as of version 2023.5.0) demands that the entity’s value is numeric. Therefore you can’t have the template produce a non-numeric value like “charging”.

Did you get a chance to test the latest template I had proposed?

Its not a historically important value, is it possible to use a different template that can display a numerical number or a string?

I have the updated value template you sent loaded, after the sensor got its first numerical value its working fine, showing 0 when the value returned is “null” and showing the actual numerical value when present.

Yes, the template can be designed to report whatever you want but it’s the presence of other options, such as unit_of_measurement, that determines if the overall Template Sensor will work properly or generate error messages.

Glad to hear the revised template works properly.

Did some more digging and found the following sensor configuration in a setup guide, going to give it a try and see how it functions. Appreciate the help and education Taras!

  # Estimated Time until battery is empty based on current load.
  # These calculations were copied from victrons code to mimic how they display it
  - name: "Battery Remaining"
    icon: mdi:timer-sand
    state_topic: "victron/N/your-venus-id/system/0/Dc/Battery/TimeToGo"
    value_template: >
      {% if value == '{"value": null}' %}
        ∞
      {% else %}

        {% set seconds = value_json.value | round(0) | int %}
        {% set days = (seconds / 86400) | round(0, 'floor') | int %}
        {% set hours = ((seconds - days * 86400) / 3600) | round(0, 'floor') | int %}
        {% set minutes = ((seconds - hours * 3600) / 60) | round(0, 'floor') | int %}

        {% if 2 > days >= 1 %}
          {{days}} Day
        {% elif days >= 2 %}
          {{days}} Days
        {% elif hours > 0 %}
          {{hours}} Hours
        {% elif minutes > 0 %}
          {{minutes}} Minutes
        {% else %}
          ∞
        {% endif %}
      {% endif %}
1 Like

You may also wish to consider using relative_time to display elapsed time.

Reference: Templating

1 Like

I can’t get this to work anymore… Been testing also with the Developer tools and it does not like the null…