home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
71.41k stars 29.9k forks source link

Value returned from template is not a number #880

Closed carmolim closed 8 years ago

carmolim commented 8 years ago

Hello, I'm getting the following error:

16-01-10 18:56:40 homeassistant.components.automation.numeric_state: Value returned from template is not a number: 23.84

I think the automation that is causing this is that one:

 automation:
   - alias: Bellow 20 test
      trigger:
        platform: numeric_state
        entity_id: sensor.augustos_room_temperature
        below: 20
      condition:
        platform: state
        entity_id: switch.notifications
        state: 'on'
      action:
        service: notify.me
        data:
          message: >
            {{ states( 'sensor.augustos_room_temperature' ) }}ºC     

What is causing this error?

philipbl commented 8 years ago

The error is coming from the trigger part of the automation rule. It is trying to convert the state of sensor.augustos_room_temperature into a float (see here).

I am not sure why this error would occur if the state is 23.84. float(23.84) or float("23.84") clearly work in Python. float takes care of trimming off whitespace as well so something like float("23.84 \n") would not be a problem.

Maybe there is a hidden character in the value? Something like "23.84 \0". You wouldn't see anything when you print out the value in the error message, but converting it to a float fails.

carmolim commented 8 years ago

Thanks for the insight @philipbl those values are been sent from my SparkCore by this function:

void formatAndPublish( String topic, String value )
{
    if ( client.isConnected() )
    {
        byte bytebuffer[ value.length() + 1 ];
        value.getBytes( bytebuffer, value.length() + 1 );
        client.publish( topic, bytebuffer, value.length() + 1, true );
    }
}

There is a way to "see" this supposed hidden character?

Thanks!

carmolim commented 8 years ago

100% sure the problem is the "\0" at the end of the string, juste looked in the Strings documentation from Arduino, now, lets find out what is the best way to fix it.

carmolim commented 8 years ago

Now I'm a little bit confused... In the blog post using the ESP8266 the the code looks like this:

client.publish(temperature_topic, String(temp).c_str(), true);

I looked up the .c_str() function and I found this:

"Returns a pointer to an array that contains a null-terminated sequence of characters (i.e., a C-string) representing the current value of the string object. This array includes the same sequence of characters that make up the value of the string object plus an additional terminating null-character ('\0') at the end."

And now? The example is wrong? Or the problem isn't the "\0" at the end of the string?

philipbl commented 8 years ago

A null character (\0) isn't necessarily a bad thing. You need it if you have an array of chars, as the Strings documentation mentions. You just have to be careful when you should manually add it and when you shouldn't. I just used it as an example of a character that could mess up the conversion from string to float in Python but would be invisible.

Putting all that aside, the code that you posted seems to have a slight problem and I think that could be causing the error. You are adding one to the length of the value. This means when you copy the bytes from the string into the buffer (getBytes), you are copying an extra byte that you shouldn't be copying. That could cause problems when home assistant receives the value and tries to convert it into a float.

I think the code should be more like this:

void formatAndPublish( String topic, String value )
{
    if ( client.isConnected() )
    {
        byte bytebuffer[ value.length() ];
        value.getBytes( bytebuffer, value.length() );
        client.publish( topic, bytebuffer, value.length(), true );
    }
}

But better yet, I think you could do something like this:

void formatAndPublish( String topic, String value )
{
    if ( client.isConnected() )
    {
        client.publish( topic, value.c_str(), value.length(), true );
    }
}

To figure out if this is what is actually happening, you could print out the value of each character of the problem value. Something like this could be added to the error handling on line 102 of numeric_state.py:

for c in value:
    print(c, "=", ord(c))

I'm hoping you will see something like this:

2 = 50
3 = 51
. = 46
8 = 56
4 = 52
 = 0

Otherwise, I am not sure what is going on.

carmolim commented 8 years ago

After reading the documentation I understood the purpose of the null character. I'll try to review my code, but I remember that I had to add the +1 because the value I was getting on Home Assistant was missing a digit. But looking again, I thing I don't need the +1 in this line:

client.publish( topic, bytebuffer, value.length() + 1, true );

When I get back home I'll do some tests.

Thanks!

carmolim commented 8 years ago

I just add the code you suggest:

for c in value:
    print(c, "=", ord(c))

And I got this:

INFO:homeassistant.core:Bus:Handling <Event MQTT_MESSAGE_RECEIVED[L]: qos=0, payload=3170.60, topic=home/room/augusto/luminosity>
2 = 50
4 = 52
. = 46
8 = 56
1 = 49
 = 0
WARNING:homeassistant.components.automation.numeric_state:Value returned from template is not a number: 24.81

Than I removed the + 1 ending up with:

client.publish( topic, bytebuffer, value.length(), true );

And no more erros... \o/

The code you sent:

void formatAndPublish( String topic, String value )
{
    if ( client.isConnected() )
    {
        client.publish( topic, value.c_str(), value.length(), true );
    }
}

Ins't working yet, getting some errors when compelling to the SparkCore, but when I find out a better solution I'll post here.

Thanks again!