Last active
May 15, 2025 21:51
-
-
Save pavax/7db3cd531fd94854c609c8274d4b8136 to your computer and use it in GitHub Desktop.
ESPHome Config for Plant Watering
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| substitutions: | |
| friendly_name: "Smart Plant Watering 2" | |
| name: "smart-plant-watering-2" | |
| initial_sleep_duration_minutes: "60" # For how long (minutes) should the node sleep | |
| initial_rewatering_wait_time_minutes: "240" # Time (minutes) to wait before watering the plant again | |
| initial_min_moisture_level: "15" # Threshold that defines when to water a plant | |
| initial_max_watering_time_seconds: "10" # How long should the watering process run (seconds) | |
| initial_max_running_time_minutes: "5" # Max time (minutes) for the node to stay awake | |
| battery_max: "4.1" # Battery voltage indicating 100% | |
| battery_min: "3.3" # Battery voltage indicating 0% | |
| uptime_update_interval: 60s | |
| esp32: | |
| board: lolin_c3_mini | |
| framework: | |
| type: esp-idf | |
| wifi: | |
| ssid: !secret wifi_ssid | |
| password: !secret wifi_password | |
| fast_connect: true | |
| output_power: 8.5dB | |
| esphome: | |
| name: ${name} | |
| friendly_name: ${friendly_name} | |
| on_boot: | |
| - priority: 600 | |
| then: | |
| - script.execute: measure_battery | |
| - light.turn_on: | |
| id: status_led | |
| brightness: 30% | |
| transition_length: 0s | |
| blue: 1 | |
| red: 1 | |
| green: 1 | |
| - delay: 2s | |
| - script.execute: led_status_light | |
| - priority: -100 | |
| then: | |
| - lambda: "id(has_booted) = true;" | |
| on_shutdown: | |
| - priority: -200.0 | |
| then: | |
| - light.turn_off: | |
| id: status_led | |
| transition_length: 0s | |
| - switch.turn_off: external_modules | |
| - component.update: uptime_seconds | |
| #- component.update: uptime_text_sensor | |
| - logger.log: | |
| level: INFO | |
| format: "Going to sleep - Good Night!🌛" | |
| logger: | |
| level: DEBUG | |
| globals: | |
| - id: plant1_status | |
| type: std::string | |
| restore_value: no | |
| initial_value: '"unknown"' | |
| - id: plant2_status | |
| type: std::string | |
| restore_value: no | |
| initial_value: '"unknown"' | |
| - id: plant3_status | |
| type: std::string | |
| restore_value: no | |
| initial_value: '"unknown"' | |
| - id: plant4_status | |
| type: std::string | |
| restore_value: no | |
| initial_value: '"unknown"' | |
| - id: plant5_status | |
| type: std::string | |
| restore_value: no | |
| initial_value: '"unknown"' | |
| - id: plant1_last_watered | |
| type: unsigned long | |
| restore_value: yes | |
| initial_value: "0" | |
| - id: plant2_last_watered | |
| type: unsigned long | |
| restore_value: yes | |
| initial_value: "0" | |
| - id: plant3_last_watered | |
| type: unsigned long | |
| restore_value: yes | |
| initial_value: "0" | |
| - id: plant4_last_watered | |
| type: unsigned long | |
| restore_value: yes | |
| initial_value: "0" | |
| - id: plant5_last_watered | |
| type: unsigned long | |
| restore_value: yes | |
| initial_value: "0" | |
| - id: has_booted | |
| type: bool | |
| restore_value: no | |
| initial_value: "false" | |
| - id: all_plants_scanned | |
| type: bool | |
| restore_value: no | |
| initial_value: "false" | |
| - id: elapsed_watering_time | |
| type: int | |
| restore_value: no | |
| initial_value: "0" | |
| interval: | |
| - interval: 2sec | |
| id: "stop_scanning_interval" | |
| startup_delay: 5sec | |
| then: | |
| - if: | |
| condition: | |
| - and: | |
| - lambda: "return !isnan(id(plant1_sensor_moisture).state);" | |
| - lambda: "return !isnan(id(plant2_sensor_moisture).state);" | |
| - lambda: "return !isnan(id(plant3_sensor_moisture).state);" | |
| - lambda: "return !isnan(id(plant4_sensor_moisture).state);" | |
| - lambda: "return !isnan(id(plant5_sensor_moisture).state);" | |
| then: | |
| - lambda: |- | |
| static bool executed = false; | |
| if (!executed) { | |
| ESP_LOGI("main", "Stop BLE Scanning since all plants moisture levels have been fetched."); | |
| id(all_plants_scanned) = true; | |
| id(ble_tracker).stop_scan(); | |
| id(led_status_light).execute(); | |
| executed = true; | |
| } | |
| - interval: 5s | |
| id: "max_running_time_reached_interval" | |
| startup_delay: 60s | |
| then: | |
| - if: | |
| condition: | |
| - and: | |
| - lambda: "return id(uptime_seconds).state >= (id(max_running_time_minutes).state * 60);" | |
| - not: | |
| - script.is_running: watering_process | |
| then: | |
| - logger.log: | |
| level: WARN | |
| format: "Max running time reached: %0.0fs of max. %0.0fs" | |
| args: | |
| - id(uptime_seconds).state | |
| - id(max_running_time_minutes).state * 60 | |
| - script.execute: prepare_shutdown | |
| - interval: 5sec | |
| id: "duty_done_interval" | |
| startup_delay: 20s | |
| then: | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant1_status) == std::string("ok") || id(plant1_status) == std::string("watered") || id(plant1_status) == std::string("recently_watered") || id(plant1_status) == std::string("watering_canceled");' | |
| - lambda: 'return id(plant2_status) == std::string("ok") || id(plant2_status) == std::string("watered") || id(plant2_status) == std::string("recently_watered") || id(plant2_status) == std::string("watering_canceled");' | |
| - lambda: 'return id(plant3_status) == std::string("ok") || id(plant3_status) == std::string("watered") || id(plant3_status) == std::string("recently_watered") || id(plant3_status) == std::string("watering_canceled");' | |
| - lambda: 'return id(plant4_status) == std::string("ok") || id(plant4_status) == std::string("watered") || id(plant4_status) == std::string("recently_watered") || id(plant4_status) == std::string("watering_canceled");' | |
| - lambda: 'return id(plant5_status) == std::string("ok") || id(plant5_status) == std::string("watered") || id(plant5_status) == std::string("recently_watered") || id(plant5_status) == std::string("watering_canceled");' | |
| - lambda: "return id(all_plants_scanned);" | |
| then: | |
| - esp32_ble_tracker.stop_scan | |
| - if: | |
| condition: | |
| switch.is_off: prevent_deep_sleep_switch | |
| then: | |
| - logger.log: | |
| level: INFO | |
| format: "Everything is done - Prepare Deep Sleep!" | |
| - script.execute: prepare_shutdown | |
| light: | |
| - platform: esp32_rmt_led_strip | |
| id: status_led | |
| rgb_order: GRB | |
| pin: GPIO7 | |
| num_leds: 30 | |
| #rmt_channel: 0 | |
| chipset: ws2812 | |
| name: "Onboard RGB" | |
| effects: | |
| - pulse: | |
| name: "Pulse" | |
| transition_length: 500ms | |
| update_interval: 500ms | |
| - pulse: | |
| name: "Breathing" | |
| transition_length: 2000ms | |
| update_interval: 2000ms | |
| min_brightness: 20% | |
| max_brightness: 100% | |
| # platform: neopixelbus | |
| # id: status_led | |
| # type: GRB | |
| # pin: GPIO7 | |
| # num_leds: 1 | |
| # name: "Onboard RGB" | |
| # variant: ws2812 | |
| # effects: | |
| # - pulse: | |
| # name: "Pulse" | |
| # transition_length: 500ms | |
| # update_interval: 500ms | |
| # - pulse: | |
| # name: "Breathing" | |
| # transition_length: 2000ms | |
| # update_interval: 2000ms | |
| # min_brightness: 20% | |
| # max_brightness: 100% | |
| output: | |
| - platform: gpio | |
| id: battery_gnd | |
| pin: | |
| number: GPIO2 | |
| inverted: true | |
| mode: | |
| output: true | |
| pullup: false | |
| pulldown: false | |
| ignore_strapping_warning: true | |
| binary_sensor: | |
| - platform: status | |
| name: "Status" | |
| - platform: gpio | |
| id: water_tank_empty | |
| name: "Water Tank" | |
| icon: "mdi:bucket" | |
| # ON means problem detected (tank is empty) whereas OFF means no problem (tank is full). | |
| device_class: problem | |
| pin: | |
| number: GPIO1 | |
| inverted: false | |
| mode: | |
| input: true | |
| pullup: true | |
| filters: | |
| - delayed_on: 250ms | |
| - delayed_off: 250ms | |
| on_release: | |
| then: | |
| - script.execute: led_status_light | |
| on_press: | |
| then: | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: "all" | |
| state: "OFF" | |
| use_internal: false | |
| - script.execute: led_status_light | |
| sensor: | |
| - platform: adc | |
| pin: GPIO3 | |
| name: "Battery Voltage" | |
| id: battery_voltage | |
| icon: "mdi:flash" | |
| attenuation: 12db | |
| accuracy_decimals: 2 | |
| update_interval: never | |
| filters: | |
| - median: | |
| window_size: 5 | |
| send_every: 5 | |
| send_first_at: 1 | |
| - multiply: 2.0 | |
| - round: 2 | |
| - platform: copy | |
| source_id: battery_voltage | |
| unit_of_measurement: "%" | |
| icon: "mdi:battery" | |
| name: "Battery Percentage" | |
| accuracy_decimals: 0 | |
| filters: | |
| - lambda: |- | |
| const float max_voltage = ${battery_max}; | |
| const float min_voltage = ${battery_min}; | |
| float battery_percentage = (x - min_voltage) / (max_voltage - min_voltage) * 100.0; | |
| return battery_percentage > 100.0 ? 100.0 : (battery_percentage < 0.0 ? 0.0 : battery_percentage); | |
| - round: 0 | |
| - platform: uptime | |
| id: uptime_seconds | |
| type: seconds | |
| name: Uptime Seconds | |
| update_interval: ${uptime_update_interval} | |
| - platform: xiaomi_hhccjcy01 | |
| mac_address: "C4:7C:8D:65:FD:DF" | |
| moisture: | |
| name: "Plant 1 Soil Moisture" | |
| id: plant1_sensor_moisture | |
| on_value: | |
| then: | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant1_status) == std::string("unknown");' | |
| - lambda: "return x <= id(plant_1_min_moisture_level).state;" | |
| then: | |
| - logger.log: | |
| level: WARN | |
| format: "Plant 1: Soil dry - Schedule watering!" | |
| - globals.set: | |
| id: plant1_status | |
| value: '"needs_water"' | |
| - script.execute: | |
| id: schedule_watering | |
| relay_id: !lambda "return id(plant1_relay).state;" | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant1_status) == std::string("unknown");' | |
| - lambda: "return x > id(plant_1_min_moisture_level).state;" | |
| then: | |
| - globals.set: | |
| id: plant1_status | |
| value: '"ok"' | |
| - component.update: plant1_status_sensor | |
| - platform: xiaomi_hhccjcy01 | |
| mac_address: "C4:7C:8D:6B:A8:3C" | |
| moisture: | |
| name: "Plant 2 Soil Moisture" | |
| id: plant2_sensor_moisture | |
| on_value: | |
| then: | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant2_status) == std::string("unknown");' | |
| - lambda: "return x <= id(plant_2_min_moisture_level).state;" | |
| then: | |
| - logger.log: | |
| level: WARN | |
| format: "Plant 2: Soil dry - Schedule watering!" | |
| - globals.set: | |
| id: plant2_status | |
| value: '"needs_water"' | |
| - script.execute: | |
| id: schedule_watering | |
| relay_id: !lambda "return id(plant2_relay).state;" | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant2_status) == std::string("unknown");' | |
| - lambda: "return x > id(plant_2_min_moisture_level).state;" | |
| then: | |
| - globals.set: | |
| id: plant2_status | |
| value: '"ok"' | |
| - component.update: plant2_status_sensor | |
| - platform: xiaomi_hhccjcy01 | |
| mac_address: "C4:7C:8D:6B:8E:EE" | |
| moisture: | |
| name: "Plant 3 Soil Moisture" | |
| id: plant3_sensor_moisture | |
| on_value: | |
| then: | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant3_status) == std::string("unknown");' | |
| - lambda: "return x <= id(plant_3_min_moisture_level).state;" | |
| then: | |
| - logger.log: | |
| level: WARN | |
| format: "Plant 3: Soil dry - Schedule watering!" | |
| - globals.set: | |
| id: plant3_status | |
| value: '"needs_water"' | |
| - script.execute: | |
| id: schedule_watering | |
| relay_id: !lambda "return id(plant3_relay).state;" | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant3_status) == std::string("unknown");' | |
| - lambda: "return x > id(plant_3_min_moisture_level).state;" | |
| then: | |
| - globals.set: | |
| id: plant3_status | |
| value: '"ok"' | |
| - component.update: plant3_status_sensor | |
| - platform: xiaomi_hhccjcy01 | |
| mac_address: "C4:7C:8D:6B:96:05" | |
| moisture: | |
| name: "Plant 4 Soil Moisture" | |
| id: plant4_sensor_moisture | |
| on_value: | |
| then: | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant4_status) == std::string("unknown");' | |
| - lambda: "return x <= id(plant_4_min_moisture_level).state;" | |
| then: | |
| - logger.log: | |
| level: WARN | |
| format: "Plant 4: Soil dry - Schedule watering!" | |
| - globals.set: | |
| id: plant4_status | |
| value: '"needs_water"' | |
| - script.execute: | |
| id: schedule_watering | |
| relay_id: !lambda "return id(plant4_relay).state;" | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant4_status) == std::string("unknown");' | |
| - lambda: "return x > id(plant_4_min_moisture_level).state;" | |
| then: | |
| - globals.set: | |
| id: plant4_status | |
| value: '"ok"' | |
| - component.update: plant4_status_sensor | |
| - platform: xiaomi_hhccjcy01 | |
| mac_address: "80:EA:CA:88:B8:DF" | |
| moisture: | |
| name: "Plant 5 Soil Moisture" | |
| id: plant5_sensor_moisture | |
| on_value: | |
| then: | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant5_status) == std::string("unknown");' | |
| - lambda: "return x <= id(plant_5_min_moisture_level).state;" | |
| then: | |
| - logger.log: | |
| level: WARN | |
| format: "Plant 5: Soil dry - Schedule watering!" | |
| - globals.set: | |
| id: plant5_status | |
| value: '"needs_water"' | |
| - script.execute: | |
| id: schedule_watering | |
| relay_id: !lambda "return id(plant5_relay).state;" | |
| - if: | |
| condition: | |
| and: | |
| - lambda: 'return id(plant5_status) == std::string("unknown");' | |
| - lambda: "return x > id(plant_5_min_moisture_level).state;" | |
| then: | |
| - globals.set: | |
| id: plant5_status | |
| value: '"ok"' | |
| - component.update: plant5_status_sensor | |
| - platform: template | |
| name: "Plant 1 Last Watered Timestamp" | |
| id: plant1_last_watered_timestamp_sensor | |
| icon: "mdi:clock-time-eight-outline" | |
| unit_of_measurement: "s" | |
| accuracy_decimals: 0 | |
| entity_category: diagnostic | |
| update_interval: never | |
| lambda: return id(plant1_last_watered); | |
| - platform: template | |
| name: "Plant 2 Last Watered Timestamp" | |
| id: plant2_last_watered_timestamp_sensor | |
| icon: "mdi:clock-time-eight-outline" | |
| unit_of_measurement: "s" | |
| accuracy_decimals: 0 | |
| entity_category: diagnostic | |
| update_interval: never | |
| lambda: return id(plant2_last_watered); | |
| - platform: template | |
| name: "Plant 3 Last Watered Timestamp" | |
| id: plant3_last_watered_timestamp_sensor | |
| icon: "mdi:clock-time-eight-outline" | |
| unit_of_measurement: "s" | |
| accuracy_decimals: 0 | |
| entity_category: diagnostic | |
| update_interval: never | |
| lambda: return id(plant3_last_watered); | |
| - platform: template | |
| name: "Plant 4 Last Watered Timestamp" | |
| id: plant4_last_watered_timestamp_sensor | |
| unit_of_measurement: "s" | |
| accuracy_decimals: 0 | |
| entity_category: diagnostic | |
| update_interval: never | |
| lambda: return id(plant4_last_watered); | |
| - platform: template | |
| name: "Plant 5 Last Watered Timestamp" | |
| id: plant5_last_watered_timestamp_sensor | |
| unit_of_measurement: "s" | |
| accuracy_decimals: 0 | |
| entity_category: diagnostic | |
| update_interval: never | |
| lambda: return id(plant5_last_watered); | |
| text_sensor: | |
| # - platform: wifi_info | |
| # ip_address: | |
| # name: "IP Address" | |
| # ssid: | |
| # name: "SSID" | |
| # - platform: version | |
| # name: "ESPHome Version" | |
| # - platform: uptime | |
| # id: uptime_text_sensor | |
| # name: Uptime | |
| # update_interval: ${uptime_update_interval} | |
| - platform: template | |
| id: plant1_status_sensor | |
| name: "Plant-1 Status" | |
| update_interval: never | |
| icon: "mdi:flower" | |
| lambda: return id(plant1_status); | |
| - platform: template | |
| id: plant2_status_sensor | |
| name: "Plant-2 Status" | |
| update_interval: never | |
| icon: "mdi:flower" | |
| lambda: return id(plant2_status); | |
| - platform: template | |
| id: plant3_status_sensor | |
| name: "Plant-3 Status" | |
| update_interval: never | |
| icon: "mdi:flower" | |
| lambda: return id(plant3_status); | |
| - platform: template | |
| id: plant4_status_sensor | |
| name: "Plant-4 Status" | |
| update_interval: never | |
| icon: "mdi:flower" | |
| lambda: return id(plant4_status); | |
| - platform: template | |
| id: plant5_status_sensor | |
| name: "Plant-5 Status" | |
| update_interval: never | |
| icon: "mdi:flower" | |
| lambda: return id(plant5_status); | |
| switch: | |
| - platform: template | |
| name: "Relay 1" | |
| id: relay1 | |
| lambda: "return id(watering_process_relay1).is_running();" | |
| icon: "mdi:water-pump" | |
| turn_on_action: | |
| - if: | |
| condition: | |
| and: | |
| - binary_sensor.is_off: water_tank_empty | |
| - lambda: "return id(has_booted);" | |
| - not: | |
| - script.is_running: watering_process | |
| then: | |
| - script.execute: | |
| id: watering_process_relay1 | |
| turn_off_action: | |
| - switch.turn_off: relay1_internal | |
| - if: | |
| condition: | |
| - script.is_running: watering_process_relay1 | |
| then: | |
| - script.execute: | |
| id: update_plants_state | |
| relay_id: "relay1" | |
| newState: "watering_canceled" | |
| update_timestamp: false | |
| - script.execute: | |
| id: stop_watering_scripts | |
| - script.execute: led_status_light | |
| - platform: template | |
| name: "Relay 2" | |
| id: relay2 | |
| lambda: "return id(watering_process_relay2).is_running();" | |
| icon: "mdi:water-pump" | |
| turn_on_action: | |
| - if: | |
| condition: | |
| and: | |
| - binary_sensor.is_off: water_tank_empty | |
| - lambda: "return id(has_booted);" | |
| - not: | |
| - script.is_running: watering_process | |
| then: | |
| - script.execute: | |
| id: watering_process_relay2 | |
| turn_off_action: | |
| - switch.turn_off: relay2_internal | |
| - if: | |
| condition: | |
| - script.is_running: watering_process_relay2 | |
| then: | |
| - script.execute: | |
| id: update_plants_state | |
| relay_id: "relay2" | |
| newState: "watering_canceled" | |
| update_timestamp: false | |
| - script.execute: | |
| id: stop_watering_scripts | |
| - script.execute: led_status_light | |
| - platform: template | |
| name: "Relay 3" | |
| id: relay3 | |
| lambda: "return id(watering_process_relay3).is_running();" | |
| icon: "mdi:water-pump" | |
| turn_on_action: | |
| - if: | |
| condition: | |
| and: | |
| - binary_sensor.is_off: water_tank_empty | |
| - lambda: "return id(has_booted);" | |
| - not: | |
| - script.is_running: watering_process | |
| then: | |
| - script.execute: | |
| id: watering_process_relay3 | |
| turn_off_action: | |
| - switch.turn_off: relay3_internal | |
| - if: | |
| condition: | |
| - script.is_running: watering_process_relay3 | |
| then: | |
| - script.execute: | |
| id: update_plants_state | |
| relay_id: "relay3" | |
| newState: "watering_canceled" | |
| update_timestamp: false | |
| - script.execute: | |
| id: stop_watering_scripts | |
| - script.execute: led_status_light | |
| - platform: template | |
| name: "Relay 4" | |
| id: relay4 | |
| lambda: "return id(watering_process_relay4).is_running();" | |
| icon: "mdi:water-pump" | |
| turn_on_action: | |
| - if: | |
| condition: | |
| and: | |
| - binary_sensor.is_off: water_tank_empty | |
| - lambda: "return id(has_booted);" | |
| - not: | |
| - script.is_running: watering_process | |
| then: | |
| - script.execute: | |
| id: watering_process_relay4 | |
| turn_off_action: | |
| - switch.turn_off: relay4_internal | |
| - if: | |
| condition: | |
| - script.is_running: watering_process_relay4 | |
| then: | |
| - script.execute: | |
| id: update_plants_state | |
| relay_id: "relay4" | |
| newState: "watering_canceled" | |
| update_timestamp: false | |
| - script.execute: | |
| id: stop_watering_scripts | |
| - script.execute: led_status_light | |
| - platform: gpio | |
| name: "Relay 1 (Internal)" | |
| id: relay1_internal | |
| restore_mode: ALWAYS_OFF | |
| pin: GPIO4 | |
| inverted: true | |
| interlock: [relay2_internal, relay3_internal, relay4_internal] | |
| internal: true | |
| - platform: gpio | |
| name: "Relay 2 (internal)" | |
| id: relay2_internal | |
| restore_mode: ALWAYS_OFF | |
| pin: | |
| number: GPIO8 | |
| ignore_strapping_warning: true | |
| inverted: true | |
| interlock: [relay1_internal, relay3_internal, relay4_internal] | |
| internal: true | |
| - platform: gpio | |
| name: "Relay 3 (internal)" | |
| id: relay3_internal | |
| restore_mode: ALWAYS_OFF | |
| pin: GPIO6 | |
| inverted: true | |
| interlock: [relay1_internal, relay2_internal, relay4_internal] | |
| internal: true | |
| - platform: gpio | |
| name: "Relay 4 (internal)" | |
| id: relay4_internal | |
| restore_mode: ALWAYS_OFF | |
| pin: GPIO10 | |
| inverted: true | |
| interlock: [relay1_internal, relay2_internal, relay3_internal] | |
| internal: true | |
| - platform: gpio | |
| name: "Power external modules" | |
| id: external_modules | |
| restore_mode: ALWAYS_OFF | |
| pin: | |
| number: GPIO5 | |
| inverted: false | |
| on_turn_off: | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: "all" | |
| state: "OFF" | |
| use_internal: false | |
| - platform: template | |
| id: prevent_deep_sleep_switch | |
| name: "Prevent Deep Sleep" | |
| restore_mode: RESTORE_DEFAULT_OFF | |
| optimistic: true | |
| entity_category: config | |
| icon: "mdi:sleep-off" | |
| on_turn_on: | |
| then: | |
| - deep_sleep.prevent: sleep_control | |
| on_turn_off: | |
| then: | |
| - deep_sleep.allow: sleep_control | |
| number: | |
| # | |
| # Relay 1 Configuration | |
| # | |
| - platform: template | |
| name: "Relay1 Watering Time Total" | |
| id: relay1_watering_time_total | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 90 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: ${initial_max_watering_time_seconds} | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 1 Watering Pulse Time (ON)" | |
| id: relay1_watering_pulse_time_on | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 1 Watering Pulse Time (OFF)" | |
| id: relay1_watering_pulse_time_off | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| # | |
| # Relay 2 Configuration | |
| # | |
| - platform: template | |
| name: "Relay2 Watering Time Total" | |
| id: relay2_watering_time_total | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 90 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: ${initial_max_watering_time_seconds} | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 2 Watering Pulse Time (ON)" | |
| id: relay2_watering_pulse_time_on | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 2 Watering Pulse Time (OFF)" | |
| id: relay2_watering_pulse_time_off | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| # | |
| # Relay 3 Configuration | |
| # | |
| - platform: template | |
| name: "Relay3 Watering Time Total" | |
| id: relay3_watering_time_total | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 90 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: ${initial_max_watering_time_seconds} | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 3 Watering Pulse Time (ON)" | |
| id: relay3_watering_pulse_time_on | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 3 Watering Pulse Time (OFF)" | |
| id: relay3_watering_pulse_time_off | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| # | |
| # Relay 4 Configuration | |
| # | |
| - platform: template | |
| name: "Relay 4 Watering Time Total" | |
| id: relay4_watering_time_total | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 90 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: ${initial_max_watering_time_seconds} | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 4 Watering Pulse Time (ON)" | |
| id: relay4_watering_pulse_time_on | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| - platform: template | |
| name: "Relay 4 Watering Pulse Time (OFF)" | |
| id: relay4_watering_pulse_time_off | |
| unit_of_measurement: "sec" | |
| entity_category: config | |
| min_value: 0 | |
| max_value: 120 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: 0 | |
| restore_value: yes | |
| # | |
| # System Configuration | |
| # | |
| - platform: template | |
| name: "Sleep Duration" | |
| id: sleep_duration_minutes | |
| unit_of_measurement: "min" | |
| entity_category: config | |
| min_value: 1 | |
| max_value: 1440 | |
| step: 5 | |
| optimistic: true | |
| mode: box | |
| initial_value: ${initial_sleep_duration_minutes} | |
| restore_value: yes | |
| - platform: template | |
| name: "Max Running Time" | |
| id: max_running_time_minutes | |
| unit_of_measurement: "min" | |
| entity_category: config | |
| min_value: 1 | |
| max_value: 15 | |
| step: 1 | |
| optimistic: true | |
| mode: box | |
| initial_value: ${initial_max_running_time_minutes} | |
| restore_value: yes | |
| - platform: template | |
| name: "Re-watering wait time" | |
| id: rewatering_wait_time_minutes | |
| entity_category: config | |
| unit_of_measurement: "min" | |
| min_value: 0 | |
| max_value: 10080 | |
| step: 10 | |
| optimistic: true | |
| mode: box | |
| initial_value: ${initial_rewatering_wait_time_minutes} | |
| restore_value: yes | |
| # | |
| # Plants Configuration | |
| # | |
| - platform: template | |
| name: "Plant 1 min. Moisture Level" | |
| id: plant_1_min_moisture_level | |
| entity_category: config | |
| unit_of_measurement: "%" | |
| min_value: 0 | |
| max_value: 100 | |
| step: 1 | |
| optimistic: true | |
| initial_value: ${initial_min_moisture_level} | |
| restore_value: yes | |
| - platform: template | |
| name: "Plant 2 min. Moisture Level" | |
| id: plant_2_min_moisture_level | |
| entity_category: config | |
| unit_of_measurement: "%" | |
| min_value: 0 | |
| max_value: 100 | |
| step: 1 | |
| optimistic: true | |
| initial_value: ${initial_min_moisture_level} | |
| restore_value: yes | |
| - platform: template | |
| name: "Plant 3 min. Moisture Level" | |
| id: plant_3_min_moisture_level | |
| entity_category: config | |
| unit_of_measurement: "%" | |
| min_value: 0 | |
| max_value: 100 | |
| step: 1 | |
| optimistic: true | |
| initial_value: ${initial_min_moisture_level} | |
| restore_value: yes | |
| - platform: template | |
| name: "Plant 4 min. Moisture Level" | |
| id: plant_4_min_moisture_level | |
| entity_category: config | |
| unit_of_measurement: "%" | |
| min_value: 0 | |
| max_value: 100 | |
| step: 1 | |
| optimistic: true | |
| initial_value: ${initial_min_moisture_level} | |
| restore_value: yes | |
| - platform: template | |
| name: "Plant 5 min. Moisture Level" | |
| id: plant_5_min_moisture_level | |
| entity_category: config | |
| unit_of_measurement: "%" | |
| min_value: 0 | |
| max_value: 100 | |
| step: 1 | |
| optimistic: true | |
| initial_value: ${initial_min_moisture_level} | |
| restore_value: yes | |
| select: | |
| - platform: template | |
| name: "Plant-1" | |
| id: plant1_relay | |
| options: | |
| - "relay1" | |
| - "relay2" | |
| - "relay3" | |
| - "relay4" | |
| entity_category: config | |
| initial_option: "relay1" | |
| restore_value: yes | |
| optimistic: true | |
| - platform: template | |
| name: "Plant-2" | |
| id: plant2_relay | |
| options: | |
| - "relay1" | |
| - "relay2" | |
| - "relay3" | |
| - "relay4" | |
| entity_category: config | |
| initial_option: "relay1" | |
| restore_value: yes | |
| optimistic: true | |
| - platform: template | |
| name: "Plant-3" | |
| id: plant3_relay | |
| options: | |
| - "relay1" | |
| - "relay2" | |
| - "relay3" | |
| - "relay4" | |
| entity_category: config | |
| initial_option: "relay1" | |
| restore_value: yes | |
| optimistic: true | |
| - platform: template | |
| name: "Plant-4" | |
| id: plant4_relay | |
| options: | |
| - "relay1" | |
| - "relay2" | |
| - "relay3" | |
| - "relay4" | |
| entity_category: config | |
| initial_option: "relay2" | |
| restore_value: yes | |
| optimistic: true | |
| - platform: template | |
| name: "Plant-5" | |
| id: plant5_relay | |
| options: | |
| - "relay1" | |
| - "relay2" | |
| - "relay3" | |
| - "relay4" | |
| entity_category: config | |
| initial_option: "relay2" | |
| restore_value: yes | |
| optimistic: true | |
| ota: | |
| platform: esphome | |
| password: !secret api_password | |
| on_begin: | |
| then: | |
| - deep_sleep.prevent: sleep_control | |
| on_end: | |
| then: | |
| - deep_sleep.allow: sleep_control | |
| on_error: | |
| then: | |
| - deep_sleep.allow: sleep_control | |
| api: | |
| id: api_id | |
| encryption: | |
| key: !secret encryption_key | |
| on_client_connected: | |
| - script.execute: led_status_light | |
| - esp32_ble_tracker.start_scan: | |
| continuous: true | |
| - component.update: plant1_last_watered_timestamp_sensor | |
| - component.update: plant2_last_watered_timestamp_sensor | |
| - component.update: plant3_last_watered_timestamp_sensor | |
| - component.update: plant4_last_watered_timestamp_sensor | |
| - component.update: plant5_last_watered_timestamp_sensor | |
| on_client_disconnected: | |
| - script.execute: led_status_light | |
| - esp32_ble_tracker.stop_scan: | |
| mqtt: | |
| broker: !secret mqtt_broker | |
| username: !secret mqtt_username | |
| password: !secret mqtt_password | |
| discovery: false | |
| topic_prefix: null | |
| on_message: | |
| - topic: ${name}/schedule-watering | |
| qos: 1 | |
| payload: "plant1" | |
| then: | |
| - script.execute: | |
| id: schedule_watering | |
| relay_id: !lambda "return id(plant1_relay).state;" | |
| - mqtt.publish: | |
| topic: ${name}/schedule-watering | |
| payload: "ACK" | |
| retain: true | |
| - topic: ${name}/schedule-watering | |
| qos: 1 | |
| payload: "plant4" | |
| then: | |
| - script.execute: | |
| id: schedule_watering | |
| relay_id: !lambda "return id(plant4_relay).state;" | |
| - mqtt.publish: | |
| topic: ${name}/schedule-watering | |
| payload: "ACK" | |
| retain: true | |
| - topic: ${name}/deep-sleep | |
| qos: 1 | |
| payload: "ON" | |
| then: | |
| - switch.turn_off: prevent_deep_sleep_switch | |
| - mqtt.publish: | |
| topic: ${name}/deep-sleep | |
| payload: "ACK" | |
| retain: true | |
| - topic: ${name}/deep-sleep | |
| qos: 1 | |
| payload: "OFF" | |
| then: | |
| - switch.turn_on: prevent_deep_sleep_switch | |
| - mqtt.publish: | |
| topic: ${name}/deep-sleep | |
| payload: "ACK" | |
| retain: true | |
| deep_sleep: | |
| id: sleep_control | |
| esp32_ble_tracker: | |
| id: ble_tracker | |
| scan_parameters: | |
| # When using this component on single core chips such as the ESP32-C3 both WiFi and ble_tracker must run on the same core, | |
| # and this has been known to cause issues when connecting to WiFi. A work-around for this is to enable the tracker only after | |
| # the native API is connected. | |
| continuous: false | |
| active: false | |
| interval: 300ms | |
| window: 300ms | |
| script: | |
| - id: measure_battery | |
| mode: single | |
| then: | |
| - output.turn_on: battery_gnd | |
| - repeat: | |
| count: 20 | |
| then: | |
| - delay: 25ms | |
| - component.update: battery_voltage | |
| - output.turn_off: battery_gnd | |
| - id: set_relay_state | |
| mode: restart | |
| parameters: | |
| relay_id: string | |
| state: string | |
| use_internal: bool | |
| then: | |
| - lambda: |- | |
| std::map<std::string, switch_::Switch*> relays = { | |
| {"relay1", use_internal ? static_cast<switch_::Switch*>(id(relay1_internal)) : static_cast<switch_::Switch*>(id(relay1))}, | |
| {"relay2", use_internal ? static_cast<switch_::Switch*>(id(relay2_internal)) : static_cast<switch_::Switch*>(id(relay2))}, | |
| {"relay3", use_internal ? static_cast<switch_::Switch*>(id(relay3_internal)) : static_cast<switch_::Switch*>(id(relay3))}, | |
| {"relay4", use_internal ? static_cast<switch_::Switch*>(id(relay4_internal)) : static_cast<switch_::Switch*>(id(relay4))} | |
| }; | |
| bool handled = false; | |
| if (relay_id == "all") { | |
| handled = true; | |
| for (auto& [name, relay] : relays) { | |
| if (state == "on" || state == "ON") { | |
| if (!relay->state) relay->turn_on(); | |
| } else if (state == "off" || state == "OFF") { | |
| if (relay->state) relay->turn_off(); | |
| } | |
| } | |
| } else { | |
| auto relay_it = relays.find(relay_id); | |
| if (relay_it != relays.end()) { | |
| handled = true; | |
| switch_::Switch* relay = relay_it->second; | |
| if (( state == "on" || state == "ON" ) && !relay->state) { | |
| relay->turn_on(); | |
| } else if ((state == "off" || state == "OFF" ) && relay->state) { | |
| relay->turn_off(); | |
| } | |
| } | |
| } | |
| if (!handled) { | |
| ESP_LOGW("set_relay_state", "Unknown relay_id: %s", relay_id.c_str()); | |
| } | |
| - id: prepare_shutdown | |
| mode: single | |
| then: | |
| - light.turn_off: | |
| id: status_led | |
| transition_length: 0s | |
| - component.update: uptime_seconds | |
| #- component.update: uptime_text_sensor | |
| - delay: 2s | |
| - deep_sleep.allow: sleep_control | |
| - deep_sleep.enter: | |
| id: sleep_control | |
| sleep_duration: !lambda "return id(sleep_duration_minutes).state * 1000 * 60;" | |
| - id: led_status_light | |
| mode: restart | |
| then: | |
| - delay: 100ms | |
| - lambda: |- | |
| // Only proceed if status_led is currently on | |
| //if (!id(status_led).current_values.is_on()) { | |
| // return; | |
| //} | |
| // Tank Empty -> Red | |
| if (id(water_tank_empty).state) { | |
| id(status_led).turn_on() | |
| .set_effect("Pulse") | |
| .set_red(1.0) | |
| .set_green(0.0) | |
| .set_blue(0.0) | |
| .set_brightness(1.0) | |
| .perform(); | |
| return; | |
| } | |
| // Not Connected -> Magenta | |
| if (!id(api_id).is_connected()) { | |
| id(status_led).turn_on() | |
| .set_effect("Pulse") | |
| .set_red(1.0) | |
| .set_green(0.0) | |
| .set_blue(1.0) | |
| .set_brightness(1.0) | |
| .perform(); | |
| return; | |
| } | |
| // watering process is running -> yellow | |
| if (id(watering_process).is_running()) { | |
| id(status_led).turn_on() | |
| .set_effect("Breathing") | |
| .set_red(1.0) | |
| .set_green(1.0) | |
| .set_blue(0.0) | |
| .set_brightness(1.0) | |
| .perform(); | |
| return; | |
| } | |
| // All Plants Scanned -> Cyan | |
| if (id(all_plants_scanned)){ | |
| id(status_led).turn_on() | |
| .set_effect("Breathing") | |
| .set_red(0.0) | |
| .set_green(1.0) | |
| .set_blue(0.8) | |
| .set_brightness(1.0) | |
| .perform(); | |
| return; | |
| } | |
| // OK -> Blue | |
| id(status_led).turn_on() | |
| .set_effect("Breathing") | |
| .set_red(0.0) | |
| .set_green(0.0) | |
| .set_blue(1.0) | |
| .set_brightness(1.0) | |
| .perform(); | |
| - id: update_plants_state | |
| mode: queued | |
| parameters: | |
| relay_id: string | |
| newState: string | |
| update_timestamp: boolean | |
| then: | |
| - lambda: |- | |
| time_t now = id(esptime).now().timestamp; | |
| std::map<std::string, std::tuple<std::string*, template_::TemplateTextSensor*, unsigned long*, template_::TemplateSensor*>> plant_map = { | |
| {id(plant1_relay).state, std::make_tuple( &id(plant1_status), id(plant1_status_sensor), &id(plant1_last_watered), id(plant1_last_watered_timestamp_sensor) )}, | |
| {id(plant2_relay).state, std::make_tuple( &id(plant2_status), id(plant2_status_sensor), &id(plant2_last_watered), id(plant2_last_watered_timestamp_sensor) )}, | |
| {id(plant3_relay).state, std::make_tuple( &id(plant3_status), id(plant3_status_sensor), &id(plant3_last_watered), id(plant3_last_watered_timestamp_sensor) )}, | |
| {id(plant4_relay).state, std::make_tuple( &id(plant4_status), id(plant4_status_sensor), &id(plant4_last_watered), id(plant4_last_watered_timestamp_sensor) )}, | |
| {id(plant5_relay).state, std::make_tuple( &id(plant5_status), id(plant5_status_sensor), &id(plant5_last_watered), id(plant5_last_watered_timestamp_sensor) )} | |
| }; | |
| bool handled = false; | |
| for (auto& [plantRelayId, plant_data] : plant_map) { | |
| if (plantRelayId == relay_id) { | |
| handled = true; | |
| // Update status | |
| *std::get<0>(plant_data) = newState; | |
| std::get<1>(plant_data)->publish_state(newState); | |
| // Conditionally update timestamp | |
| if (update_timestamp) { | |
| *std::get<2>(plant_data) = now; | |
| std::get<3>(plant_data)->publish_state(now); | |
| } | |
| } | |
| } | |
| if (!handled) { | |
| ESP_LOGW("update_plants_state", "Unknown relay_id: %s", relay_id.c_str()); | |
| } | |
| - id: schedule_watering | |
| parameters: | |
| relay_id: string | |
| mode: queued | |
| max_runs: 5 | |
| then: | |
| - logger.log: | |
| level: INFO | |
| tag: schedule_watering | |
| format: "%s: Schedule watering process" | |
| args: | |
| - relay_id.c_str() | |
| - wait_until: | |
| - lambda: "return id(has_booted) = true;" | |
| - wait_until: | |
| condition: | |
| - not: | |
| - script.is_running: watering_process | |
| - if: | |
| condition: | |
| lambda: |- | |
| time_t now = id(esptime).now().timestamp; | |
| int rewateringWaitTime = id(rewatering_wait_time_minutes).state * 60; | |
| std::map<std::string, time_t> plant_last_watered_map = { | |
| { id(plant1_relay).state, static_cast<time_t>(id(plant1_last_watered)) }, | |
| { id(plant2_relay).state, static_cast<time_t>(id(plant2_last_watered)) }, | |
| { id(plant3_relay).state, static_cast<time_t>(id(plant3_last_watered)) }, | |
| { id(plant4_relay).state, static_cast<time_t>(id(plant4_last_watered)) }, | |
| { id(plant5_relay).state, static_cast<time_t>(id(plant5_last_watered)) }, | |
| }; | |
| auto it = plant_last_watered_map.find(relay_id); | |
| time_t last_watered = (it != plant_last_watered_map.end()) ? it->second : 0; | |
| return (now - last_watered) >= rewateringWaitTime; | |
| then: | |
| - wait_until: | |
| binary_sensor.is_off: water_tank_empty | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: !lambda "return relay_id;" | |
| state: "ON" | |
| use_internal: false | |
| else: | |
| - logger.log: | |
| level: WARN | |
| tag: schedule_watering | |
| format: "%s was watered recently (last watered < %d min ago)" | |
| args: | |
| - relay_id.c_str() | |
| - int(id(rewatering_wait_time_minutes).state) | |
| - script.execute: | |
| id: update_plants_state | |
| relay_id: !lambda "return relay_id;" | |
| newState: "recently_watered" | |
| update_timestamp: false | |
| - id: watering_process_relay1 | |
| mode: single | |
| then: | |
| - script.execute: | |
| id: watering_process | |
| relay_id: "relay1" | |
| - script.execute: led_status_light | |
| - script.wait: watering_process | |
| - script.execute: led_status_light | |
| - id: watering_process_relay2 | |
| mode: single | |
| then: | |
| - script.execute: | |
| id: watering_process | |
| relay_id: "relay2" | |
| - script.execute: led_status_light | |
| - script.wait: watering_process | |
| - script.execute: led_status_light | |
| - id: watering_process_relay3 | |
| mode: single | |
| then: | |
| - script.execute: | |
| id: watering_process | |
| relay_id: "relay3" | |
| - script.execute: led_status_light | |
| - script.wait: watering_process | |
| - script.execute: led_status_light | |
| - id: watering_process_relay4 | |
| mode: single | |
| then: | |
| - script.execute: | |
| id: watering_process | |
| relay_id: "relay4" | |
| - script.execute: led_status_light | |
| - script.wait: watering_process | |
| - script.execute: led_status_light | |
| - id: watering_process | |
| parameters: | |
| relay_id: string | |
| mode: single | |
| then: | |
| - logger.log: | |
| level: INFO | |
| tag: watering_process | |
| format: "%s: Start watering process" | |
| args: | |
| - relay_id.c_str() | |
| - switch.turn_on: external_modules | |
| - script.execute: | |
| id: update_plants_state | |
| relay_id: !lambda "return relay_id;" | |
| newState: "watering" | |
| update_timestamp: false | |
| - lambda: |- | |
| std::map<std::string, std::tuple<float, float, float>> relay_params = { | |
| {"relay1", std::make_tuple(id(relay1_watering_pulse_time_on).state, id(relay1_watering_pulse_time_off).state, id(relay1_watering_time_total).state)}, | |
| {"relay2", std::make_tuple(id(relay2_watering_pulse_time_on).state, id(relay2_watering_pulse_time_off).state, id(relay2_watering_time_total).state)}, | |
| {"relay3", std::make_tuple(id(relay3_watering_pulse_time_on).state, id(relay3_watering_pulse_time_off).state, id(relay3_watering_time_total).state)}, | |
| {"relay4", std::make_tuple(id(relay4_watering_pulse_time_on).state, id(relay4_watering_pulse_time_off).state, id(relay4_watering_time_total).state)} | |
| }; | |
| auto it = relay_params.find(relay_id); | |
| if (it != relay_params.end()) { | |
| float pulse_on = std::get<0>(it->second); | |
| float pulse_off = std::get<1>(it->second); | |
| float total = std::get<2>(it->second); | |
| if (pulse_on > 0 && pulse_off > 0) { | |
| id(pulsed_watering)->execute(relay_id, pulse_on, pulse_off, total); | |
| } else { | |
| id(continous_watering)->execute(relay_id, total); | |
| } | |
| } else { | |
| ESP_LOGW("watering_process", "Unknown relay_id: %s", relay_id.c_str()); | |
| } | |
| - script.wait: continous_watering | |
| - script.wait: pulsed_watering | |
| - script.execute: | |
| id: update_plants_state | |
| relay_id: !lambda "return relay_id;" | |
| newState: "watered" | |
| update_timestamp: true | |
| - id: pulsed_watering | |
| mode: single | |
| parameters: | |
| relay_id: string | |
| pulse_time_on: float | |
| pulse_time_off: float | |
| total_time: float | |
| then: | |
| - logger.log: | |
| level: INFO | |
| tag: pulsed_watering | |
| format: "%s: Use watering pulse with ON: %0.0fs - OFF: %0.0fs - Total: %0.0fs" | |
| args: | |
| - relay_id.c_str() | |
| - pulse_time_on | |
| - pulse_time_off | |
| - total_time | |
| - lambda: "id(elapsed_watering_time) = 0;" | |
| - while: | |
| condition: | |
| - lambda: "return ( total_time * 1000 ) > id(elapsed_watering_time);" | |
| then: | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: !lambda "return relay_id;" | |
| state: "ON" | |
| use_internal: true | |
| - delay: !lambda "return pulse_time_on * 1000;" | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: !lambda "return relay_id;" | |
| state: "OFF" | |
| use_internal: true | |
| - lambda: "id(elapsed_watering_time) += pulse_time_on * 1000;" | |
| - if: | |
| condition: | |
| lambda: "return total_time * 1000 > id(elapsed_watering_time);" | |
| then: | |
| - delay: !lambda "return pulse_time_off * 1000;" | |
| - logger.log: | |
| level: INFO | |
| tag: pulsed_watering | |
| format: "%s: Total watering time reached." | |
| args: | |
| - relay_id.c_str() | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: !lambda "return relay_id;" | |
| state: "OFF" | |
| use_internal: true | |
| - id: continous_watering | |
| mode: single | |
| parameters: | |
| relay_id: string | |
| total_time: float | |
| then: | |
| - logger.log: | |
| level: INFO | |
| tag: continous_watering | |
| format: "%s: Use continous watering for %0.0fs" | |
| args: | |
| - relay_id.c_str() | |
| - total_time | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: !lambda "return relay_id;" | |
| state: "ON" | |
| use_internal: true | |
| - delay: !lambda "return total_time * 1000;" | |
| - logger.log: | |
| level: INFO | |
| tag: continous_watering | |
| format: "%s: Total watering time reached." | |
| args: | |
| - relay_id.c_str() | |
| - script.execute: | |
| id: set_relay_state | |
| relay_id: !lambda "return relay_id;" | |
| state: "OFF" | |
| use_internal: true | |
| - id: stop_watering_scripts | |
| mode: single | |
| then: | |
| - script.stop: watering_process | |
| - script.stop: pulsed_watering | |
| - script.stop: continous_watering | |
| button: | |
| - platform: restart | |
| name: "Restart" | |
| - platform: shutdown | |
| name: "Shutdown" | |
| time: | |
| - platform: sntp | |
| id: esptime | |
| servers: | |
| - 0.pool.ntp.org | |
| - 1.pool.ntp.org | |
| - 2.pool.ntp.org |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment