How can I return 0 if value is nan/null/unknown in lambda?

I have a light I want to control from ESP-Home with a rotary encoder.
The idea is if the light is off then it should do light turn on with brightness 10 ( one step).

sensor:
  - platform: homeassistant
    id: david_brightness
    entity_id: light.davids_lampa
    attribute: brightness


  - platform: rotary_encoder
    name: "Brightness Encoder"
    id: brightness_encoder
    pin_a: GPIO5
    pin_b: GPIO6
    internal: true
    on_value:
      - lambda: |-
            // Calculate change from last position
            int current = (int)x;
            int delta = current - id(last_encoder_value);
            id(last_encoder_value) = current;
            
            // Adjust brightness (step of 10 per click)
            ESP_LOGI("encoder", "David brightness %.0f", id(david_brightness).state);
            int david = 0;
            if (id(david_brightness).state == nan) {
              david = 0;
            } else {
              david = (int)id(david_brightness).state; 
            }
            ESP_LOGI("encoder", "David %d", david);
            float new_brightness = david + (delta * 10);
            
            // Clamp to valid range
            if (new_brightness < 0) new_brightness = 0;
            if (new_brightness > 255) new_brightness = 255;

with the above I get this:

/config/esphome/david-sang.yaml: In lambda function:
/config/esphome/david-sang.yaml:221:35: error: invalid operands of types 'float' and 'double(const char*)' to binary 'operator=='
  221 |             if (id(david_brightness).state == nan) {
      |             ~~~~~~~~~~~~~~~~~~~~~ ^~ ~~~
      |                             |        |
      |                             float    double(const char*)
*** [.pioenvs/david-sang/src/main.cpp.o] Error 1

I have also tried == NULL and if (std::isnan(id(david_brightness).state)).
What is the correct way to make the rotary encoder to send 10 as brightness when the light is off.
Using isnan results in it sending 255.

If isnan is correct way, but I’m not sure how the values go here. Where are you turning the light on ?
I think you should check if david_brightness isnan and if delta>0 then set new_brightness to 10 and turn light on.

I believe from my testing that isnan returns false and with the code I had it then read the value of Davids lampa brightness and placed that as the variable David.
I believe that then was (somehow) interpreted as 255.
I honestly have no clue how that has happened.

The current code I have now does not compile but I can change it to something where it can compile with some debug prints so that I can show you the values of the variables.
Give me a few minutes.

So this is the complete code that is not installed with a few debug prints.

sensor:
  - platform: homeassistant
    id: david_brightness
    entity_id: light.davids_lampa
    attribute: brightness


  - platform: rotary_encoder
    name: "Brightness Encoder"
    id: brightness_encoder
    pin_a: GPIO5
    pin_b: GPIO6
    internal: true
    on_value:
      - lambda: |-
            HomeassistantActionRequest svc;
            svc.service = StringRef("light.turn_on");
            svc.data.init(2); 
            auto &kv1 = svc.data.emplace_back();
            kv1.key = StringRef("entity_id");
            kv1.value = StringRef("light.davids_lampa");
            auto &kv2 = svc.data.emplace_back();
            kv2.key = StringRef("brightness");


            // Calculate change from last position
            int current = (int)x;
            int delta = current - id(last_encoder_value);
            id(last_encoder_value) = current;
            
            // Adjust brightness (step of 10 per click)
            ESP_LOGI("encoder", "David brightness as float %.0f", id(david_brightness).state);
            ESP_LOGI("encoder", "David brightness as string %s", id(david_brightness).state);
            int david = 0;
            if (std::isnan(id(david_brightness).state)) {
              david = 0;
            } else {
              david = (int)id(david_brightness).state; 
            }
            ESP_LOGI("encoder", "Variable david after IF %d", david);
            float new_brightness = david + (delta * 10);
            
            // Clamp to valid range
            if (new_brightness < 0) new_brightness = 0;
            if (new_brightness > 255) new_brightness = 255;
            ESP_LOGI("encoder", "Variable david after 'clamp' %d", david);
            
            // Update brightness
            if (new_brightness != id(david_brightness).state) {
              static char brightness_buffer[10]; 
              sprintf(brightness_buffer, "%d", (int)new_brightness);
              kv2.value = esphome::StringRef(brightness_buffer);

              
              global_api_server->send_homeassistant_action(svc);
              ESP_LOGI("encoder", "Brightness adjusted to %.0f", new_brightness);
            }

I’m aware people does not like that method of turning on a light, but it works for now and I do not intend to update the ESP version of the code.

The light is turned off and I rotate the encoder one step to turn on, that gives:

[18:01:40][D][sensor:118]: 'Brightness Encoder' >> 35 steps
[18:01:40][I][encoder:219]: David brightness nan
[18:01:40][I][encoder:226]: David 2147483647
[18:01:40][I][encoder:242]: Brightness adjusted to 0
[18:01:42][D][sensor:118]: 'Brightness Encoder' >> 36 steps
[18:01:42][I][encoder:219]: David brightness nan
[18:01:42][I][encoder:226]: David 2147483647
[18:01:42][I][encoder:242]: Brightness adjusted to 0

And that makes me clueless… it’s not the correct debug prints.
I don’t understand this. And it doesn’t even turn on the light anymore…
It seems as if the device reboots when I use the rotary encoder.

Here we go…

I twisted some more back and forth and now this happened in the log:

[18:07:04][D][sensor:118]: 'Brightness Encoder' >> 46 steps
[18:07:04][I][encoder:219]: David brightness nan
[18:07:04][I][encoder:226]: David 2147483647
[18:07:04][I][encoder:242]: Brightness adjusted to 0
[18:07:04][D][sensor:118]: 'Brightness Encoder' >> 47 steps
[18:07:04][I][encoder:219]: David brightness nan
[18:07:04][I][encoder:226]: David 2147483647
[18:07:04][I][encoder:242]: Brightness adjusted to 0
[18:07:04][D][sensor:118]: 'Brightness Encoder' >> 48 steps
[18:07:04][I][encoder:219]: David brightness nan
[18:07:04][I][encoder:226]: David 2147483647
[18:07:04][I][encoder:242]: Brightness adjusted to 0
[18:07:05][D][sensor:118]: 'Brightness Encoder' >> 47 steps
[18:07:05][I][encoder:219]: David brightness nan
[18:07:05][I][encoder:226]: David 2147483647
[18:07:05][I][encoder:242]: Brightness adjusted to 255
[18:07:05][D][homeassistant.sensor:021]: 'light.davids_lampa::brightness': Got attribute state 254.00
[18:07:05][D][sensor:118]: 'david_brightness' >> 254.0 
[18:07:05][D][sensor:118]: 'Brightness Encoder' >> 46 steps
[18:07:05][I][encoder:219]: David brightness 254
[18:07:05][I][encoder:226]: David 254
[18:07:05][I][encoder:242]: Brightness adjusted to 244
[18:07:05][D][homeassistant.sensor:021]: 'light.davids_lampa::brightness': Got attribute state 244.00
[18:07:05][D][sensor:118]: 'david_brightness' >> 244.0 
[18:07:05][D][sensor:118]: 'Brightness Encoder' >> 47 steps
[18:07:05][I][encoder:219]: David brightness 244
[18:07:05][I][encoder:226]: David 244
[18:07:05][I][encoder:242]: Brightness adjusted to 254
[18:07:05][D][homeassistant.sensor:021]: 'light.davids_lampa::brightness': Got attribute state 254.00
[18:07:05][D][sensor:118]: 'david_brightness' >> 254.0 

I figured it out.
The rotary encoder value started at what it saved to the EEPROM.

When I added restore_mode: ALWAYS_ZERO then it would use 0 and compare that against the last_encoder_value which also has initial value 0.
That means it does a small step as it should.