MQTT sensor value is not a number

When I compare the MQTT sensor value, it fails (in the template dev tool) as it is not a number.

Why and what can I do about it? Is it a bug with the MQTT sensor?

{{ (states( 'sensor.octopus_current_price' )) }}

{% if states( 'sensor.octopus_current_price' ) is number %}
a number
{% else %}
not a number
{% endif %}

returns

9.6

not a number

I create the MQTT sensor…

sensor:
  - platform: mqtt
    state_topic: "octopus"
    name: "octopus current price"
    value_template: '{{ (value_json.current_price | round(2)) }}'
    unit_of_measurement: "p/kWh"

The MQTT topic data looks like this

{
  "current_price" : 9.597,
  "next_price" : 9.261,
  "min_price_inc_vat" : 5.733,
  "max_price_inc_vat" : 34.9965,
  "min_blocks" : [ {
    "min Block Price" : 6.62,
    "min Block valid From" : "2020-03-19T22:00:00Z",
    "min_block_size_mins" : 60
  }, {
    "min Block Price" : 6.88,
    "min Block valid From" : "2020-03-19T21:00:00Z",
    "min_block_size_mins" : 120
  } ]
}

I have checked a couple of other MQTT sensors and it is the same.

Try to convert the string to a float first, then round.

'{{ ((value_json.current_price | float) | round(2)) }}'

Doesn’t help.

any state is a string.
you need to convert them yourself.
however, if I get it right python/Jinja allows you to compare them provided they are all similar, i.e

'1' > '0'

is the same as

1 > 0

could you post your code here?

Ah, that explains it :grinning: It is always the little gems that make a big difference.

I tried

{% if states( 'sensor.octopus_current_price' ) < 6 %}

but am now using

{% if states( 'sensor.octopus_current_price' ) | float < 6 %} 

that’s fine. I’ve just tested and you’re good to use just

{% if states( 'sensor.octopus_current_price' ) < '6' %}

amazing :wink:

1 Like

When comparing numbers it’s best to convert them to integers or floats. String comparisons can produce misleading results like this:

As a string comparison, the result is correct but as a numeric comparison it’s not.

yes, because they are not similar (different number of digits).
so string comparison is not a replacement and can only be used in cases like comparing time from sensor.time etc.

The underlying mechanism is a bit more complex than that:

Thanks everyone. It is obvious now - not an easy answer to search for either.

I agree that the documentation doesn’t highlight the fact that an entity’s state is a string value. The one place (that I’ve found) where it’s explained is in the State Object’s documentation and it’s easy to gloss over and underestimate its implications:

Field Description
state.state String representation of the current state of the entity. Example off.
1 Like

Well, as the TS uses states(), it’s natural to check this, and it has it.

Yes but part of (my) confusion / lack of understanding was that the State is a string
image
and an Attribute is a value
image

I can’t complain, it is there in black and white - just missed it.

Every day is a learning day.

We should ask baz123 if it’s natural to check there. :slight_smile:

I know I learned that states are strings after reading many posts here and only later referred to the State Object’s documentation. It took me awhile before I realized a state with a number is actually storing it as a string. Extra confusion was the fact the Numeric State Trigger transparently converts the state to a numeric value when performing its comparison.

What isn’t natural is to see a number and think oh yes, that is a string. I doubt any amount of documentation would have triggered that without reading really carefully.

However, putting some text here might help

image

so make it State (as a string)

I’d have noticed that!

[edit]
A link to the docs on the States page would also help noobs I’d suggest.

well, if you write code it’s worth to pay attention to details unless you fancy constant debugging :wink:
I can tell you a short story about “see a number”:
In Developer tools → States you can see state (or attribute) of your sensor and it shows True. Then you create a template like

{{ states('sensor.test') == True }}

and it never evaluates to True, just because “True”(a string) != True (a boolean). Btu they look the same!

Another great example is attribute duration of a timer - set it to 90000 and check what States show. (Timer converts duration to its string representation so basically you can’t easily use the atribute to find out your timer’s duration if it’s more than 23h59m59s - I consider it as a bug)

All you see is an interpretation of HA’s internals.
So actually your approach

is very sensible, I do the same to make sure my templates works as expected.

could you elaborate?
And do you know that you can edit documentation yourself by clicking Edit on Github at the top right of each page?

1 Like

Totally agree, been writing code since 1988 - started with ADA.

It is just not intuitive when you see a number to think it is a string - mea culpa on that (assumptions…)

I mean the States page in HA UI.

image

The templates page has useful links to the docs - we could have the same on the states page.

I am not suggesting there is any fault, except mine, but on the basis that it seems to be a common (systemic) error, how could that be mitigated?

I also wonder if links to the state information on the templates page might be worthwhile as well.

you tell me… :wink:

yeah, why not?
I bet you can create a new FR on frontend (don’t know when they’ll be able to implement it though…)

1 Like