Wait_until: wont compile

I have this…

            - wait_until: 
                condition:
                  lambda: |-
                    return 'id(fish_food_hopper).state <= id(post_dose_weight).state';

… and it passes validation.

But on installing I get a compilation error:

Compiling /data/feeder/.pioenvs/feeder/src/main.cpp.o
/config/esphome/feeder.yaml:288:14: warning: character constant too long for its type
                     return 'id(fish_food_hopper).state <= id(post_dose_weight).state';

What is it trying to tell me?

Try it without the quotes:

            - wait_until: 
                condition:
                  lambda: |-
                    return id(fish_food_hopper).state <= id(post_dose_weight).state;

Or use quotes around everything when it is on a single line:

            - wait_until: 
                condition:
                  lambda: 'return id(fish_food_hopper).state <= id(post_dose_weight).state;'

Thanks, Tom.

Still the same with both of those options :confused:

Or, I should add, a myriad of other, probably longshot, syntax options.

I’m not sure where to go from here.

Does the lambda seem correct?

I’m getting the same result using while: then:.

Is it the types of fish_food_hopper and post_dose_weight that are causing the problem?

sensor:
  - platform: hx711
    name: "Fish food hopper"
    id: fish_food_hopper
    dout_pin: 27
    clk_pin: 26
    filters:
      - calibrate_linear:   
        - 9800 -> 0    
        - 435000 -> 5.0
      - sliding_window_moving_average:    
          window_size: 5    
          send_every: 5
    update_interval: 2s
    unit_of_measurement: gm
    accuracy_decimals: 1

and:

globals:
  - id: post_dose_weight
    type: int
    restore_value: yes

Some progress in that I now have a different error.

What is…

Condition must consist of key-value mapping! Got return id(pre_dose_weight).state <= id(post_dose_weight).state;.
                condition: !lambda |-
                  return id(pre_dose_weight).state <= id(post_dose_weight).state; [source /config/esphome/feeder.yaml:287]

…trying to tell me?

I now have in my code:

            - wait_until: 
                condition:
                  !lambda
                    'return id(pre_dose_weight).state <= id(post_dose_weight).state;'

Don’t quote multi line lambdas. Only quote the whole line when it’s a single line lambda like my example above and just like jinja in Home Assistant.

Try asking on the ESPHome Discord, lots of expert helpers there: https://discord.gg/mdT9Kr9V

1 Like

It would probably help, if you’d post your whole code. :slight_smile: To see what’s wrong, it is at least necessary to post the parts around the error. Eg. if you forget a “;” at the end of statement, the error normally is set in the next line after… :wink:

1 Like

Again, thank you both for the help. I appreciate it.

Here’s the whole thing. There’s some cruft and test code in there. I was at it until the early hours.

It was all looking good and working until I started to add the wait_until:.

esphome:
  name: feeder
  platform: ESP32
  board: esp32dev
  platformio_options:
    board_build.f_cpu: 80000000L

# Notes
# 5000g maximum tared weight
# 500g minimum weight
# 2 gms per second feed rate

  on_boot:
    then:
      # read the RTC time once when the system boots
      - ds1307.read_time:
      - if:
          condition:
            sun.is_above_horizon:
          then:
            - binary_sensor.template.publish:
                id: fish_feeder_sun_is_up
                state: ON
          else:
            - binary_sensor.template.publish:
                id: fish_feeder_sun_is_up
                state: OFF
      

api:

i2c: 
  sda: 19
  scl: 18

dallas:
  - pin: GPIO23
    update_interval: 60s

sun:
  latitude: !secret latitude
  longitude: !secret longitude
  on_sunrise:
    - then:
      - binary_sensor.template.publish:
          id: fish_feeder_sun_is_up
          state: ON
  on_sunset:
    - then:
      - binary_sensor.template.publish:
          id: fish_feeder_sun_is_up
          state: OFF

logger:

web_server:
  port: 80
  auth:
    username: admin
    password: !secret OTA_password
    
ota:
  password: !secret OTA_password

wifi:
  ssid: !secret dryderdale_wifi_SSID
  password: !secret dryderdale_wifi_password
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Feeder Fallback Hotspot"
    password: !secret OTA_password
  power_save_mode: none
  
captive_portal:

globals:
  - id: feed_amount_timer_variable
    type: int
    restore_value: no
    initial_value: '5'

  - id: feeds_per_day_variable
    type: int
    restore_value: no
    initial_value: '5'

  - id: water_pre_dispense_time_variable
    type: int
    restore_value: yes
    initial_value: '5'

  - id: water_post_dispense_time_variable
    type: int
    restore_value: yes
    initial_value: '5'
  
  - id: current_hopper_weight
    type: int

  
  - id: pre_dose_weight
    type: int
    restore_value: yes

  - id: post_dose_weight
    type: int
    restore_value: yes

time:
  - platform: ds1307
    # repeated synchronization is not necessary unless the external RTC
    # is much more accurate than the internal clock
    update_interval: never
  - platform: homeassistant
    # instead try to synchronize via network repeatedly ...
    on_time_sync:
      then:
        # ... and update the RTC when the synchronization was successful
        ds1307.write_time:
    # on_time:
    #   # Every hour when sun is up
    #   - seconds: 0
    #     minutes: 0
    #     then:
    #       - if:
    #           condition:
    #             and:
    #               - sun.is_above_horizon:
    #               - binary_sensor.is_off: disable_fish_feed
    #           then:
    #             - script.execute: dispense_food

sensor:
  - platform: hx711
    name: "Fish food hopper"
    id: fish_food_hopper
    dout_pin: 27
    clk_pin: 26
    filters:
      - calibrate_linear:   
        - 9800 -> 0    
        - 435000 -> 5.0
      - sliding_window_moving_average:    
          window_size: 5    
          send_every: 5
    update_interval: 2s
    unit_of_measurement: gm
    accuracy_decimals: 1
    on_value:
      then:
        - globals.set:
            id: current_hopper_weight
            value: !lambda 'return x;'
  
  - platform: homeassistant
    name: "Fish feed amount"
    entity_id: input_number.fish_feed_amount #defined in homeassistant
    id: fish_feed_amount
    on_value:
      then:
        - globals.set:
            id: feed_amount_timer_variable
            value: !lambda 'return x;'
  
  - platform: homeassistant
    name: "Feeds per day"
    entity_id: input_number.feeds_per_day #defined in homeassistant
    id: feeds_per_day
    on_value:
      then:
        - globals.set:
            id: feeds_per_day_variable
            value: !lambda 'return x;'

  - platform: homeassistant
    name: "Water Pre Dispense Time"
    entity_id: input_number.water_pre_dispense_time #defined in homeassistant
    id: water_pre_dispense_time
    on_value:
      then:
        - globals.set:
            id: water_pre_dispense_time_variable
            value: !lambda 'return x;'

  - platform: homeassistant
    name: "Water Post Dispense Time"
    entity_id: input_number.water_post_dispense_time_HA #defined in homeassistant
    id: water_post_dispense_time
    on_value:
      then:
        - globals.set:
            id: water_post_dispense_time_variable
            value: !lambda 'return x;'

  - platform: homeassistant
    name: "Water temperature"
    entity_id: sensor.pond_water_temperature #defined in homeassistant
    id: water_temperature

  - platform: dallas
    address: 0x0301192A83D1AC28
    name: "Feeder Water Temperature"
    id: feeder_water_temperature
    icon: mdi:temperature-celsius

text_sensor:
  - platform: sun
    name: Sun Next Sunrise
    type: sunrise
  - platform: sun
    name: Sun Next Sunset
    type: sunset

binary_sensor:
  - platform: gpio
    pin: 
      number: 17
      mode: INPUT_PULLUP
    name: "Manual Fish Feed"
    id: manual_fish_feed
    filters:
      - invert:
    on_press:
      then:
        - script.execute: dispense_food
        # - switch.turn_on: fish_feed_motor
    # on_release:
    #   then:
    #     script.execute: dispense_food

  - platform: gpio
    pin: 
      number: 16
      mode: INPUT_PULLUP
    name: "Disable Fish Feed"
    id: disable_fish_feed
    filters:
      - invert:

  - platform: template
    name: "Fish feeder sun is up"
    id: fish_feeder_sun_is_up

  - platform: homeassistant
    name: "Disable fish feeding"
    entity_id: input_boolean.disable_fish_feeder #defined in homeassistant
    id: disable_fish_feeding

  - platform: homeassistant
    name: "Manual feed"
    entity_id: input_boolean.manually_feed_fish #defined in homeassistant
    id: manual_fish_feeding
    on_press:
      then:
        - script.execute: dispense_food
        - delay: 1s
        - homeassistant.service:
            service: input_boolean.turn_off
            data:
              entity_id: input_boolean.manually_feed_fish


switch:
  - platform: restart
    name: "Restart fish feeder control"
    id: restart_fish_feeder_control

  - platform: gpio
    pin: 21
    name: "Fish Feed Motor"
    id: fish_feed_motor
    inverted: false
    restore_mode: RESTORE_DEFAULT_OFF

script:
  - id: dispense_food
    then:
      - if:
          condition:
              - binary_sensor.is_off: disable_fish_feeding
          then:
            - globals.set:
                id: pre_dose_weight
                value: current_hopper_weight
            - globals.set:
                id: post_dose_weight
                value: !lambda return 'id(pre_dose_weight).state - id(fish_feed_amount).state;'
            - homeassistant.service:
                service: switch.turn_on
                data:
                  entity_id: switch.water_fill_valve
            - delay: !lambda 'return id(water_pre_dispense_time_variable) * 1000;'
            - switch.turn_on: fish_feed_motor
            - wait_until: 
                condition:
                  lambda: |-
                    return id(current_hopper_weight).state <= id(post_dose_weight).state; 
            # - delay: !lambda 'return id(feed_amount_timer_variable) * 1000 /2;'
            - switch.turn_off: fish_feed_motor
            - delay: !lambda 'return id(water_post_dispense_time_variable) * 1000;'
            - homeassistant.service:
                service: switch.turn_off
                data:
                  entity_id: switch.water_fill_valve
1 Like

Getting back to where I was originally, I have:

            - wait_until:
                condition:
                  lambda: 'return id(fish_food_hopper).state <= id(post_dose_weight).state;'

And this creates the following error:

/config/esphome/feeder.yaml: In lambda function:
/config/esphome/feeder.yaml:296:67: error: request for member 'state' in 'post_dose_weight->esphome::globals::GlobalsComponent<T>::value<int>()', which is of non-class type 'int'
                   lambda: 'return id(fish_food_hopper).state <= id(post_dose_weight).state;'
                                                                   ^
In file included from src/esphome/core/application.h:8:0,
                 from src/esphome/components/api/api_connection.h:4,
                 from src/esphome.h:2,
                 from src/main.cpp:3:
src/esphome/core/helpers.h: In instantiation of 'esphome::TemplatableValue<T, X>::TemplatableValue(F) [with F = esphome::globals::GlobalsComponent<int>*; typename std::enable_if<(! esphome::is_callable<F, X ...>::value), int>::type <anonymous> = 0; T = int; X = {}]':
src/esphome/components/globals/globals_component.h:60:3:   required from 'void esphome::globals::GlobalVarSetAction<C, Ts>::set_value(V) [with V = esphome::globals::GlobalsComponent<int>*; C = esphome::globals::GlobalsComponent<int>; Ts = {}]'
/config/esphome/feeder.yaml:198:64:   required from here
src/esphome/core/helpers.h:239:57: error: invalid conversion from 'esphome::globals::GlobalsComponent<int>*' to 'int' [-fpermissive]
   TemplatableValue(F value) : type_(VALUE), value_(value) {}

It’s the “which is of non-class type 'int” and “invalid conversion” parts that has me think that this is not just a formatting issue.

Does the problem lie with my sensor and globals declarations maybe?

The fish_food_hopper sensor has accuracy_decimals: 1, which suggests it is of type float, whereas the globals are of type int. I have tried them as float with same result though. The sensor doesn’t support changing type.

EDIT:

Removing accuracy_decimals: 1, according to the docs, causes the sensor to return int.

With this, and globals set to int, I now get this error:

invalid conversion from 'esphome::globals::GlobalsComponent<int>*' to 'int' [-fpermissive], which further suggests to me that it’s a mismatched type or similar. Just not sure how to fix it.

Having painstakingly commented out each line of code, one by one, and compiled each time, I’ve narrowed it down to the commented out items in the script below.

I think I’m at the end of my current capabilities!

Any suggestions welcome.

script:
  - id: dispense_food
    then:
      - if:
          condition:
              - binary_sensor.is_off: disable_fish_feeding
          then:
            # - globals.set:
            #     id: pre_dose_weight
            #     value: current_hopper_weight
            # - globals.set:
            #     id: post_dose_weight
            #     value: !lambda 'return id(pre_dose_weight).state - id(fish_feed_amount).state;'
            - homeassistant.service:
                service: switch.turn_on
                data:
                  entity_id: switch.water_fill_valve
            - delay: !lambda 'return id(water_pre_dispense_time_variable) * 1000;'
            - switch.turn_on: fish_feed_motor
            # - wait_until:
            #     condition:
            #       lambda: 'return id(fish_food_hopper).state <= 0;' #  id(post_dose_weight).state;'
            - delay: !lambda 'return id(feed_amount_timer_variable) * 500;'
            - switch.turn_off: fish_feed_motor
            - delay: !lambda 'return id(water_post_dispense_time_variable) * 1000;'
            - homeassistant.service:
                service: switch.turn_off
                data:
                  entity_id: switch.water_fill_valve

Discord sorted it out!

the .state is not required for the globals, just the sensor.

Thanks all for your help.

2 Likes