String to int stoi conversion - catch error

I’ve been trying to work out why my NSPanel ESP32 is crashing into a boot loop every so often. I realised it was happening whenever a Home Assistant MQTT sensor glitched and started reporting status ‘unavailable’, so I looked at my code and I think it’s due to me trying to convert the string value to an int, as the sensor normally reports a battery level. The code is:

  - platform: homeassistant
    id: lock_1_batt
    entity_id: sensor.front_door_lock_battery
    on_value:
      then:
        - wait_until:
            switch.is_on: nextion_init
        - lambda: |-
            int symbol = 26;
            int batt = stoi(id(lock_1_batt).state);
            ESP_LOGD("batt_test", "The value of battery is: %i", batt);
            if (batt <= 20) {
              symbol=25;
            } else if (batt <= 40) {
              symbol=24;
            } else if (batt <= 60) {
              symbol=23;
            } else if (batt <= 80) {
              symbol=22;
            } else if (batt <= 100) {
              symbol=21;
            } else {
              symbol=26;
            }
            id(disp1).send_command_printf("Home.lock1batt.pic=%i", symbol);

So I think the offending line is int batt = stoi(id(lock_1_batt).state); which would throw an error if there is no valid integer conversion. Accorinding to the CPP reference stoi throws an error of type [std::invalid_argument] if no conversion can be performed. How do I test for this error and gracefully handle it? I’m a CPP novice so I can only hack things together!

Thanks!

You could test and see if you can use isdigit() in a similar manner to the example on this page.

Checking the first character and only converting the string if it passes this test may be enough for your usecase.

https://cplusplus.com/reference/cctype/isdigit/

Thanks, that would certainly work but is there no easy way just to try/catch the conversion error so it would cover all error cases?

I don’t know.

But I noticed stoi() actually strips trailing letters so it may handle cases more robustly than you think.

I’m just a cpp beginner though.

Well I learned something else today, Exception Handling is disabled by default in ESPHome so you can’t use a try/catch method anyway.

Your method would work but involves converting the state string to a Char array first, which is a bit wasteful. In the end I’ve just added a test to make sure the string isn’t “unavailable” or “unknown” before attempting the conversion.

1 Like

Could you share the solution when you’re ready please?

Nothing fancy just:

            if (id(lock_1_batt).state == "unavailable" || id(lock_1_batt).state == "unknown"){
              ESP_LOGD("batt_test", "The value of battery is unavailable");
              symbol = 26;
            } else {
              int batt = stoi(id(lock_1_batt).state);
              ESP_LOGD("batt_test", "The value of battery is: %i", batt);
              if (batt <= 20) {
                symbol=25;
              } else if (batt <= 40) {
                symbol=24;
              } else if (batt <= 60) {
                symbol=23;
              } else if (batt <= 80) {
                symbol=22;
              } else if (batt <= 100) {
                symbol=21;
              } else {
                symbol=26;
              }
            }
1 Like