Conditional lambda error

I have three sensors (1 ultrasonic, 1 luxmeter, 1 hue motion sensor) and script that is supposed to run if values from the sensors are matching a condition specified in a lambda. If they evaluate to true the script is supposed to run. However, ESP is giving some error when compiling. I’ve tried enveloping the “off” in “state.== off” in quotes, and without.

Any ideas about what I’m missing?

sensor:
  - platform: bh1750
    name: "BH1750 Illuminance"
    id: "luxmeter"
    update_interval: 1s

  - platform: ultrasonic
    trigger_pin: GPIO05
    echo_pin: GPIO18
    name: "Ultrasonic Sensor"
    id: "ultra"
    update_interval: 0.2s
    internal: true
    on_value:
      then:
      - if:
          condition:
          - lambda: 'return id(ultra).state < 0.5;'
          then:
            - script.execute: script_light_1
            - delay: 50ms
          else:
      - script.stop: script_light_1

binary_sensor:
  - platform: homeassistant
    name: "hue_motion_1"
    id: "hue_motion_1"
    entity_id: binary_sensor.hue_motion_sensor_1_motion

script:
  - id: script_light_1
    mode: queued
    then:
    - if:
        condition:
        - lambda: 'return id(luxmeter).state < 200 && id(hue_motion_1).state == off;'
        then:
          - switch.turn_on: "green_led_switch_esp32"
          - delay: 15ms
          - switch.turn_off: "green_led_switch_esp32"
          - delay: 425ms

Error:

Compiling /data/esp32-1/.pioenvs/esp32-1/src/main.cpp.o
/config/esphome/esp32-1.yaml: In lambda function:
/config/esphome/esp32-1.yaml:78:63: error: ISO C++ forbids comparison between pointer and integer [-fpermissive]
         - lambda: 'return id(luxmeter).state < 200  && id(hue_motion_1).state == "off";'
                                                               ^~~~~
*** [/data/esp32-1/.pioenvs/esp32-1/src/main.cpp.o] Error 1
========================= [FAILED] Took 26.59 seconds ====

Try replacing id(hue_motion_1).state == off with !id(hue_motion_1).state

The ! is equivalent to checking if it is false (off) in this case

Pointers always trip me up too. The above worked for me but I was also assigning the state to a variable (for other reasons) and checking on the variable so it may be different than your case but worth a try while you wait for a more experienced programmer to respond.

2 Likes

Thanks. It compiles without errors now. However, it doesn’t actually do anything to interrupt the automation. I think it’s somehow having problems reading the state of the motion sensor in this part:

binary_sensor:
  - platform: homeassistant
    name: "hue_motion_1"
    id: "hue_motion_1"
    entity_id: binary_sensor.hue_motion_sensor_1_motion

I don’t really know what pointers are so the error doesn’t really tell me much.

A pointer is a variable that stores the memory address of another variable as its value which is why the comparison between int and pointer was failing. I am guessing that ESPHome converts “off” to 0 (false) so it sees it as an int.

Assuming that my suggestion is correct, have you verified that your states are what you think they should be? I would try to log them so you can see what the values are.

Thanks for the clarification.

How do I output the sensor reading so that I can read in ESPhome flasher/logger?

Outside of Lambda you could use this:

I can’t test this code but I would try this:

script:
  - id: script_light_1
    mode: queued
    logger.log:
      format: "DEBUG LOG: hue_motion_1 state is %d"
      args: ['id(hue_motion_1).state']
    then:
    - if:
        condition:
        - lambda: 'return id(luxmeter).state < 200 && id(hue_motion_1).state == off;'
        then:
          - switch.turn_on: "green_led_switch_esp32"
          - delay: 15ms
          - switch.turn_off: "green_led_switch_esp32"
          - delay: 425ms

If it doesn’t work, you can check out this thread as it has some good pointers (no pun intended):

The thread also talks about specifiers %d in your case which is used for int. If you want to log other values such as a string you would use ‘%s’ as a specifier.

I do a lot of this stuff in Lambda so I never actually tested the logger.log function as above. I typically use something like this in my Lambda:

ESP_LOGD("DEBUG", "Fan Speed Setting: %d" , id(max_fan_speed));

Please note I hack my way through so I have no certainty that I am giving you “state of the art” programming tips… but they have worked for me so I hope they help you out.

1 Like

Thanks. I tried pasting your cod but got an error, so instead, I moved the logger part to the binary sensor itself. Moving it didn’t give me an error but also didn’t actually generate any info in the output

binary_sensor:
  - platform: homeassistant
    name: "hue_motion_1"
    id: "hue_motion_1"
    entity_id: binary_sensor.hue_motion_sensor_1_motion
    on_state:
      logger.log:
        format: "DEBUG LOG: hue_motion_1 state is %d"
        args: ['id(hue_motion_1).state']

I got some help from the people over at Reddit which solved the conditional lambda issue by switching to this:

id(hue_motion_1).state == false;'

or similar to your suggestion (what :

!id(hue_motion_1).state == false;'

However. The script is either unaffected, or doesn’t execute at all irrespective of motion or not. I think the logging function could provide valuable insight here if I can solve it.

Your condition will only be true if the luxmeter state is under 200 AND there is no motion. Is that what you want?

Did the log entries confirm the value of the luxmeter and motion are what you expect?

That is precisely what I want. I just tested with the motion on and off. So one scenario was just triggering motion while the luxmeter is covered (and well below 200 lx). Will ESP automatically update the state of the motion sensor or do I have somehow have to force a regular update?

The log entries unfortunately don’t show anything for the motion. For the luxmeter and ultrasonic sensor it shows reading normally.

That reminds me… I would avoid using a motion sensor that is not directly connected to the ESP as I see it as a significant point of failure. I would want the ESP to keep working regardless of what is going on with HA or the connection between the two. Anyhow, while I have not tried to do it, I don’t see why it would not work.

It sounds like the script is not running or is stopped too soon. Looking at the code it appears you call the script when the Ultrasonic sensor detects a value under 0.5 (meters right?) and then stop the script immediately after the if.

I just noticed a likely error… the script.stop in your code executes every time right after the if but given you have an else: just above it I’d say your indentation is incorrect. I added 6 spaces to align it where it should be if meant to run only when the “ultra” condition if false. Do you even need to stop the script? I thought stopping the script was only necessary when it did something that took a long time, and may therefore need to be stopped, which does not appear to be your case.

  - platform: ultrasonic
    trigger_pin: GPIO05
    echo_pin: GPIO18
    name: "Ultrasonic Sensor"
    id: "ultra"
    update_interval: 0.2s
    internal: true
    on_value:
      then:
      - if:
          condition:
          - lambda: 'return id(ultra).state < 0.5;'
          then:
            - script.execute: script_light_1
            - delay: 50ms
          else:
            - script.stop: script_light_1
1 Like

Thanks very much for your help. If I don’t have the stop script it just keeps looping even when the conditions are false, for some reason. However, I did something similar to what you did but moved the stop script to the script itself.

  - platform: ultrasonic
    trigger_pin: GPIO05
    echo_pin: GPIO18
    name: "Ultrasonic Sensor"
    id: "ultra"
    update_interval: 0.2s
    internal: true
    on_value:
      then:
      - if:
          condition:
          - lambda: 'return id(ultra).state < 0.5 && id(esp32_test_mqtt).state == "OFF";'
          then:
            - script.execute: script_light_1
            - delay: 50ms
          else:

script:
  - id: script_light_1
    mode: queued
    then:
    - if:
        condition:
        - lambda: 'return id(luxmeter).state < 200;'
        then:
          - switch.turn_on: "green_led_switch_esp32"
          - delay: 15ms
          - switch.turn_off: "green_led_switch_esp32"
          - delay: 875ms
          - script.stop: script_light_1

After a long and arduous day of ripping my hair out, I think we zeroed in on the main problem almost at the same time. Direct connection (i.e. API).

My HUE is located on the same net as the ESP, but different from the RBPi. I run almost everything else over MQTT, but I realised just now that my HUE doesn’t. Tomorrow I will attempt to set up Zigbee2MQTT.

Until then, I setup an experiment using mqtt subscribe in order to test my hypothesis ;

  - platform: gpio
    id: "esp32_transistor_25"
    name: "esp32_transistor_25" 
    pin: GPIO25

(this is connected to a led diode so that I can confirm that the circuit is closed)

  - platform: mqtt_subscribe
    name: "Test MQTT"
    id: esp32_test_mqtt
    topic: esp32/switch/esp32_transistor_25/state

(I use this to get a non-numeric state value to test validity of the == “OFF” expression)

    on_value:
      then:
      - if:
          condition:
          - lambda: 'return id(ultra).state < 0.5 && id(esp32_test_mqtt).state == "OFF";'
          then:
            - script.execute: script_light_1
            - delay: 50ms
          else:

Method:

  1. Blocked the luxmeter
  2. Ensured that ultrasonic distance < 0.5
  3. Manually switched on the esp32_transistor_25 in order to push a state change

Result: It indeed evaluated the expression "== “OFF” as false and stopped the script from running! (Switching off the esp32_transistor_25 allowed the script to resume and it ran just fine).

1 Like

This may only be cosmetic but I would remove the else: given there is no code beneath it.

Hopefully your latest findings will lead you to a solution!

1 Like

Good suggestion, I did that.

I can also confirm that the problem very likely is due to not have the API connection. I’ve created an automation that switches on a switch over in the same ESP as the ultra/lux sensor over MQTT when the motion detects motion and it correctly stops the script from running.

Thanks for all your help.

1 Like