ESPHome String to Float (Home Assistant Sensor)

I’ve been playing with creating a parking sensor with a simple RGB led as an indicator for proximity to the “ideal” parking distance.

I’m storing the distance as a global variable in the ESPHome code upon a long button press, which is great, except for when the device would restart. I don’t want to hard code the right distance in, though that would be a lot simpler.

I want to retain that custom distance between reboots, which is the main goal here.

If there’s a way to do that within the ESPHome code without hardcoding it, that’d be awesome and you don’t need to read any farther.

However, the only way I’ve imagined having a source of that retained info, is to pull the number from an input_boolean within Home Assistant–and having the button press on the device set a new input_boolean value within Home Assistant. That way, Home Assistant will have an active value for the parking sensor if the parking sensor reboots… obviously the failing here is if both devices restart.

My question is how to convert the platform: homeassistant sensor value, which comes in as a string (shown as nan in the console), to a float value. I’ve tried a few solutions and Googled a bunch–even going so far as looking into how I’d write a C++ custom component, which is way over my head.

Here’s the code for the sensors that I’m trying to play with–a “${device_name}_hass_target” sensor that is the imported string and a “${device_name}_target” that is a float value–either being set by the global value or in the case of the global value being the initial value (0), then relying on the “${device_name}_hass_target” to provide that value.

  - platform: homeassistant
    # https://esphome.io/components/sensor/homeassistant.html
    id: ${device_name}_hass_target
    entity_id: input_number.${device_name}_target
  - platform: template
    # https://esphome.io/components/sensor/template.html
    name: ${device_name}_target
    id: ${device_name}_target
    unit_of_measurement: "in"
    icon: "mdi:target"
    lambda: |-
      if (id(${device_name}_target_global) == 0) {
        float hassTarget = std::stof(id(${device_name}_hass_target).state); # also tried "std::stof" here too... 
        id(${device_name}_target_global) = hassTarget;
        return hassTarget;
      } else {
        return id(${device_name}_target_global);
      }

When I try using this method of C++ code to convert the string to a float, I get this error:

src/main.cpp: In lambda function:
src/main.cpp:913:44: error: 'stof' is not a member of 'std'
         garage_01_target_global->value() = std::stof(garage_01_hass_target->state);
                                            ^
*** [.pioenvs/garage_01/src/main.cpp.o] Error 1

And this error if I just use “float hassTarget = stof(id(${device_name}_hass_target).state);”

src/main.cpp: In lambda function:
src/main.cpp:913:77: error: 'stof' was not declared in this scope
         garage_01_target_global->value() = stof(garage_01_hass_target->state);
                                                                             ^
*** [.pioenvs/garage_01/src/main.cpp.o] Error 1

Tonight while trying to figure out how to round a sensor value to 1 decimal place I discovered where many of the lambda functions are defined: https://esphome.io/api/helpers_8cpp_source.html

There’s a function called parse_float that help with with your float conversions…

Don’t know if there’s away to store anything between reboots… There’s also a namespace doc, but didn’t see anything in there about it either (just looked for save/store), my guess is it’s not possible.

1 Like

Hey, thanks for the response! This was so long ago that I don’t think I can recall if I tried that method or not, but maybe I’ll give it a shot! Saving the value between reboots would definitely be awesome, but I’ve pretty much given up hope on it.

For now, the ultrasonic sensor + RGB led + light sensor + esp8266 setup that’s in the garage has performed admirably for the past six months after I simply set a fixed value in the code for the parking distance.

Cheers!

Further digging around it looks like restore_value from globals can do state across reboots:

 # Example configuration entry
 globals:
   - id: my_global_int
     type: int
     restore_value: yes
     initial_value: '0'

Thanks for the response.

I thought I had tried doing that before, but the ‘restore_value’ was simply pointing it to the ‘0’ of the initial declaration, not the new value that was being set during operation (in this case, an ultrasonic distance measure that had been inputted before reboot). Do you know if this means it’ll retain whatever the last known value is, or that it’ll simply restore the value to the ‘initial_value’ (0 in this case)?

Did you get how to round to 1 decimal place within a lambda function? Thanks!

Unfortunately I don’t think I ever figured it out–I’ve not learned C++ and only stumble through modifying things that others have done. |

If I look around, it seems like when you get the error that I was ("‘stof’ is not a member of ‘std’") it indicates you’re not using newerer C++11 functions. Maybe you can use the following flag to tell the compiler to use C++11?

-std=c++11

If you figure something out, let me know!

This filter rounds to 2 decimal places: - lambda: return (round(x*100.0))/100.0;