Skip to content

Instantly share code, notes, and snippets.

@pavax
Last active May 1, 2025 23:17
Show Gist options
  • Save pavax/7db3cd531fd94854c609c8274d4b8136 to your computer and use it in GitHub Desktop.
Save pavax/7db3cd531fd94854c609c8274d4b8136 to your computer and use it in GitHub Desktop.
ESPHome Config for Plant Watering
substitutions:
friendly_name: "Smart Plant Watering 2"
name: "smart-plant-watering-2"
initial_sleep_duration_minutes: "120" # For how long (minutes) should the MCU sleep
initial_watering_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 MCU 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: arduino
packages:
device_base: !include common/device_base.yaml
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
output_power: 8.5dB
esphome:
on_boot:
- priority: 600
then:
- delay: 1s
- script.execute: led_status_light
- priority: -100
then:
- script.execute: measure_battery
- script.wait: measure_battery
- lambda: "id(has_booted) = true;"
on_shutdown:
- priority: -100.0
then:
- switch.turn_off: external_modules
- component.update: uptime_seconds
- component.update: uptime_text_sensor
- logger.log:
level: INFO
format: "Going to sleep - Good Night!🌛"
safe_mode:
disabled: true
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: 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: has_booted
type: bool
restore_value: no
initial_value: "false"
deep_sleep:
id: sleep_control
esp32_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
#web_server:
# port: 80
interval:
- interval: 5s
startup_delay: 60s
then:
- if:
condition:
- and:
- lambda: "return id(uptime_seconds).state >= (id(max_running_time_minutes).state * 60);"
- switch.is_off: relay1
- switch.is_off: relay2
- switch.is_off: relay3
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
- light.turn_off:
id: status_led
transition_length: 0s
- delay: 2s
- deep_sleep.allow: sleep_control
- deep_sleep.enter:
id: sleep_control
sleep_duration: !lambda "return id(sleep_duration_minutes).state * 1000 * 60;"
- interval: 5sec
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("already_watered");'
- lambda: 'return id(plant2_status) == std::string("ok") || id(plant2_status) == std::string("watered") || id(plant2_status) == std::string("already_watered");'
- lambda: 'return id(plant3_status) == std::string("ok") || id(plant3_status) == std::string("watered") || id(plant3_status) == std::string("already_watered");'
then:
- esp32_ble_tracker.stop_scan
- if:
condition:
switch.is_off: prevent_deep_sleep_switch
then:
- logger.log:
level: INFO
format: "All plants are either ok or have been watered."
- light.turn_off:
id: status_led
transition_length: 0s
- delay: 2s
- deep_sleep.enter:
id: sleep_control
sleep_duration: !lambda "return id(sleep_duration_minutes).state * 1000 * 60;"
light:
- platform: neopixelbus
id: status_led
type: GRB
pin: GPIO7
num_leds: 1
name: "Onboard RGB"
variant: ws2812
effects:
- pulse:
name: "Pulse"
transition_length: 700ms
update_interval: 700ms
output:
- platform: gpio
id: battery_gnd
pin:
number: GPIO2
inverted: true
mode:
output: true
pullup: false
pulldown: false
binary_sensor:
- platform: gpio
id: water_tank_empty
name: "Water Tank"
# 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
- logger.log:
level: DEBUG
format: "Wasserstand OK"
on_press:
then:
- script.execute: led_status_light
- logger.log:
level: DEBUG
format: "Wasserstand niedrig"
- lambda: |-
if (id(relay1).state) {
id(relay1).turn_off();
}
if (id(relay2).state) {
id(relay2).turn_off();
}
if (id(relay3).state) {
id(relay3).turn_off();
}
sensor:
- platform: adc
pin: GPIO3
name: "Battery Voltage"
id: battery_voltage
icon: "mdi:flash"
attenuation: 11db
accuracy_decimals: 2
update_interval: never
filters:
- 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"
on_value:
then:
- logger.log:
level: DEBUG
format: "Plant 1: Moisture received: %.1f"
args: [x]
- 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:
- logger.log:
level: INFO
format: "Plant 1: Soil moisture OK — no watering needed."
- 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"
on_value:
then:
- logger.log:
level: INFO
format: "Plant 2: Moisture received: %.1f"
args: [x]
- 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:
- logger.log:
level: INFO
format: "Plant 2: Soil moisture OK — no watering needed."
- 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"
on_value:
then:
- logger.log:
level: INFO
format: "Plant 3: Moisture received: %.1f"
args: [x]
- 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:
- logger.log:
level: INFO
format: "Plant 3: Soil moisture OK — no watering needed."
- globals.set:
id: plant3_status
value: '"ok"'
- component.update: plant3_status_sensor
- platform: template
name: "Wakeup Cause"
accuracy_decimals: 0
entity_category: diagnostic
lambda: return esp_sleep_get_wakeup_cause();
- platform: template
name: "Plant 1 Last Watered Timestamp"
id: plant1_last_watered_timestamp_sensor
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
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
unit_of_measurement: "s"
accuracy_decimals: 0
entity_category: diagnostic
update_interval: never
lambda: |-
return id(plant3_last_watered);
text_sensor:
- id: !extend uptime_text_sensor
update_interval: ${uptime_update_interval}
- platform: template
id: plant1_status_sensor
name: "Plant-1 Status"
update_interval: never
lambda: return id(plant1_status);
- platform: template
id: plant2_status_sensor
name: "Plant-2 Status"
update_interval: never
lambda: return id(plant2_status);
- platform: template
id: plant3_status_sensor
name: "Plant-3 Status"
update_interval: never
lambda: return id(plant3_status);
- platform: template
name: "Plant 1 Last Watered"
id: plant1_last_watered_text_sensor
entity_category: diagnostic
update_interval: never
lambda: |-
if (id(plant1_last_watered) == 0) {
return std::string("Never");
} else {
time_t last_time = id(plant1_last_watered);
struct tm *timeinfo = localtime(&last_time);
char buffer[30];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
return std::string(buffer);
}
- platform: template
name: "Plant 2 Last Watered"
id: plant2_last_watered_text_sensor
entity_category: diagnostic
update_interval: never
lambda: |-
if (id(plant2_last_watered) == 0) {
return std::string("Never");
} else {
time_t last_time = id(plant2_last_watered);
struct tm *timeinfo = localtime(&last_time);
char buffer[30];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
return std::string(buffer);
}
- platform: template
name: "Plant 3 Last Watered"
id: plant3_last_watered_text_sensor
entity_category: diagnostic
update_interval: never
lambda: |-
if (id(plant3_last_watered) == 0) {
return std::string("Never");
} else {
time_t last_time = id(plant3_last_watered);
struct tm *timeinfo = localtime(&last_time);
char buffer[30];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
return std::string(buffer);
}
switch:
- platform: template
name: "Relay 1"
id: relay1
lambda: "return id(relay1_internal).state;"
turn_on_action:
- if:
condition:
and:
- binary_sensor.is_off: water_tank_empty
- lambda: "return id(has_booted);"
then:
- switch.turn_on: external_modules
- switch.turn_on: relay1_internal
- script.execute:
id: update_plants_state
relay_id: "relay1"
newState: "watering"
- script.execute:
id: relay_timer_script
relay_id: "relay1"
else:
- logger.log:
level: WARN
format: "Blocking relay1 activation!"
turn_off_action:
- switch.turn_off: relay1_internal
- script.stop: relay_timer_script
- if:
condition:
- lambda: "return id(has_booted);"
then:
- script.execute:
id: mark_plants_as_watered
relay_id: "relay1"
- platform: template
name: "Relay 2"
id: relay2
lambda: "return id(relay2_internal).state;"
turn_on_action:
- if:
condition:
and:
- binary_sensor.is_off: water_tank_empty
- lambda: "return id(has_booted);"
then:
- switch.turn_on: external_modules
- switch.turn_on: relay2_internal
- script.execute:
id: update_plants_state
relay_id: "relay2"
newState: "watering"
- script.execute:
id: relay_timer_script
relay_id: "relay2"
else:
- logger.log:
level: WARN
format: "Blocking relay2 activation!"
turn_off_action:
- switch.turn_off: relay2_internal
- script.stop: relay_timer_script
- if:
condition:
- lambda: "return id(has_booted);"
then:
- script.execute:
id: mark_plants_as_watered
relay_id: "relay2"
- platform: template
name: "Relay 3"
id: relay3
lambda: "return id(relay3_internal).state;"
turn_on_action:
- if:
condition:
and:
- binary_sensor.is_off: water_tank_empty
- lambda: "return id(has_booted);"
then:
- switch.turn_on: external_modules
- switch.turn_on: relay3_internal
- script.execute:
id: update_plants_state
relay_id: "relay3"
newState: "watering"
- script.execute:
id: relay_timer_script
relay_id: "relay3"
else:
- logger.log:
level: WARN
format: "Blocking relay3 activation!"
turn_off_action:
- switch.turn_off: relay3_internal
- script.stop: relay_timer_script
- if:
condition:
- lambda: "return id(has_booted);"
then:
- script.execute:
id: mark_plants_as_watered
relay_id: "relay3"
- platform: gpio
name: "Relay 1 (Internal)"
id: relay1_internal
restore_mode: ALWAYS_OFF
pin: GPIO4
inverted: true
interlock: [relay2_internal, relay3_internal]
internal: true
- platform: gpio
name: "Relay 2 (internal)"
id: relay2_internal
restore_mode: ALWAYS_OFF
pin: GPIO8
inverted: true
interlock: [relay1_internal, relay3_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]
internal: true
- platform: gpio
name: "Power external modules"
id: external_modules
restore_mode: ALWAYS_OFF
pin:
number: GPIO5
inverted: false
on_turn_off:
- lambda: |-
if (id(relay1).state) {
id(relay1).turn_off();
}
if (id(relay2).state) {
id(relay2).turn_off();
}
if (id(relay3).state) {
id(relay3).turn_off();
}
- platform: template
name: "Prevent Deep Sleep"
id: prevent_deep_sleep_switch
restore_mode: ALWAYS_OFF
optimistic: true
entity_category: config
turn_on_action:
- deep_sleep.prevent: sleep_control
turn_off_action:
- deep_sleep.allow: sleep_control
number:
- 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: "Max Watering Time"
id: max_watering_time
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: "Watering wait time duration"
id: watering_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_watering_wait_time_minutes}
restore_value: yes
- 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
select:
- platform: template
name: "Plant-1"
id: plant1_relay
options:
- "relay1"
- "relay2"
- "relay3"
entity_category: config
initial_option: "relay1"
restore_value: yes
optimistic: true
- platform: template
name: "Plant-2"
id: plant2_relay
options:
- "relay1"
- "relay2"
- "relay3"
entity_category: config
initial_option: "relay2"
restore_value: yes
optimistic: true
- platform: template
name: "Plant-3"
id: plant3_relay
options:
- "relay1"
- "relay2"
- "relay3"
entity_category: config
initial_option: "relay3"
restore_value: yes
optimistic: true
api:
on_client_connected:
- script.execute: led_status_light
- component.update: plant1_last_watered_timestamp_sensor
- component.update: plant2_last_watered_timestamp_sensor
- component.update: plant3_last_watered_timestamp_sensor
- component.update: plant1_last_watered_text_sensor
- component.update: plant2_last_watered_text_sensor
- component.update: plant3_last_watered_text_sensor
- esp32_ble_tracker.start_scan:
continuous: true
on_client_disconnected:
- script.execute: led_status_light
- esp32_ble_tracker.stop_scan:
services:
- service: watering_service
variables:
relay_id: string
then:
- script.execute:
id: schedule_watering
relay_id: !lambda |-
return relay_id;
script:
- id: measure_battery
mode: single
then:
- output.turn_on: battery_gnd
- delay: 1s
- component.update: battery_voltage
- delay: 1s
- output.turn_off: battery_gnd
- id: led_status_light
mode: restart
then:
- lambda: |-
// 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(0.8)
.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(0.3)
.perform();
return;
}
// OK -> Blue
id(status_led).turn_on()
.set_effect("none")
.set_red(0.0)
.set_green(0.0)
.set_blue(1.0)
.set_brightness(0.3)
.perform();
- delay: 1s
- id: update_plants_state
mode: queued
parameters:
relay_id: string
newState: string
then:
- lambda: |-
std::string plant1RelayId = id(plant1_relay).state;
std::string plant2RelayId = id(plant2_relay).state;
std::string plant3RelayId = id(plant3_relay).state;
boolean foundAMatch = false;
if (plant1RelayId == relay_id){
id(plant1_status) = newState;
id(plant1_status_sensor).update();
foundAMatch = true;
}
if (plant2RelayId == relay_id){
id(plant2_status) = newState;
id(plant2_status_sensor).update();
foundAMatch = true;
}
if (plant3RelayId == relay_id){
id(plant3_status) = newState;
id(plant3_status_sensor).update();
foundAMatch = true;
}
if (!foundAMatch){
ESP_LOGW("plant_status_watering", "No Plant configured for: %s", relay_id.c_str());
return;
}
- id: mark_plants_as_watered
mode: queued
parameters:
relay_id: string
then:
- lambda: |-
time_t now = id(esptime).now().timestamp;
std::string watered_state = std::string("watered");
std::string plant1RelayId = id(plant1_relay).state;
std::string plant2RelayId = id(plant2_relay).state;
std::string plant3RelayId = id(plant3_relay).state;
boolean foundAMatch = false;
if (plant1RelayId == relay_id){
id(plant1_status) = watered_state;
id(plant1_last_watered) = now;
id(plant1_status_sensor).update();
id(plant1_last_watered_text_sensor).update();
id(plant1_last_watered_timestamp_sensor).update();
foundAMatch = true;
}
if (plant2RelayId == relay_id){
id(plant2_status) = watered_state;
id(plant2_last_watered) = now;
id(plant2_status_sensor).update();
id(plant2_last_watered_text_sensor).update();
id(plant2_last_watered_timestamp_sensor).update();
foundAMatch = true;
}
if (plant3RelayId == relay_id){
id(plant3_status) = watered_state;
id(plant3_last_watered) = now;
id(plant3_status_sensor).update();
id(plant3_last_watered_text_sensor).update();
id(plant3_last_watered_timestamp_sensor).update();
foundAMatch = true;
}
if (!foundAMatch){
ESP_LOGW("mark_plants_as_watered", "No Plant configured for: %s", relay_id.c_str());
return;
}
- id: schedule_watering
parameters:
relay_id: string
mode: queued
max_runs: 4
then:
- logger.log:
level: INFO
tag: schedule_watering
format: "%s: Schedule watering process"
args:
- relay_id.c_str()
- logger.log:
level: INFO
tag: schedule_watering
format: "%s: Wait for system has booted"
args:
- relay_id.c_str()
- wait_until:
- lambda: "return id(has_booted) = true;"
- logger.log:
level: INFO
tag: schedule_watering
format: "%s: Wait for all relays to finish"
args:
- relay_id.c_str()
- wait_until:
condition:
and:
- switch.is_off: relay1
- switch.is_off: relay2
- switch.is_off: relay3
- logger.log:
level: INFO
tag: schedule_watering
format: "%s: All other relays are off, proceeding with watering process"
args:
- relay_id.c_str()
- if:
condition:
lambda: |-
time_t now = id(esptime).now().timestamp;
int minWateringWaitTime = id(watering_wait_time_minutes).state * 60;
time_t last_watered = 0;
std::vector<std::string> plant_relays = {
id(plant1_relay).state,
id(plant2_relay).state,
id(plant3_relay).state
};
std::vector<time_t> plant_last_watered = {
static_cast<time_t>(id(plant1_last_watered)),
static_cast<time_t>(id(plant2_last_watered)),
static_cast<time_t>(id(plant3_last_watered))
};
for (size_t i = 0; i < plant_relays.size(); i++) {
if (plant_relays[i] == relay_id && plant_last_watered[i] > last_watered) {
last_watered = plant_last_watered[i];
}
}
return (now - last_watered) >= minWateringWaitTime;
then:
- logger.log:
level: INFO
tag: schedule_watering
format: "%s: Wait for water tank"
args:
- relay_id.c_str()
- wait_until:
binary_sensor.is_off: water_tank_empty
- logger.log:
level: INFO
tag: schedule_watering
format: "%s: Water tank ready"
args:
- relay_id.c_str()
- lambda: |-
if (relay_id == "relay1") {
id(relay1).turn_on();
} else if (relay_id == "relay2") {
id(relay2).turn_on();
} else if (relay_id == "relay3") {
id(relay3).turn_on();
} else {
ESP_LOGE("schedule_watering", "Unknown relay_id: %s", relay_id.c_str());
}
else:
- logger.log:
level: WARN
tag: schedule_watering
format: "%s was watered too recently (last watered < %d min ago)"
args:
- relay_id.c_str()
- int(id(watering_wait_time_minutes).state)
- lambda: |-
std::string already_watered_state = std::string("already_watered");
std::string plant1RelayId = id(plant1_relay).state;
std::string plant2RelayId = id(plant2_relay).state;
std::string plant3RelayId = id(plant3_relay).state;
boolean foundAMatch = false;
if (plant1RelayId == relay_id){
foundAMatch = true;
id(plant1_status) = already_watered_state;
id(plant1_status_sensor).update();
}
if (plant2RelayId == relay_id){
foundAMatch = true;
id(plant2_status) = already_watered_state;
id(plant2_status_sensor).update();
}
if (plant3RelayId == relay_id){
foundAMatch = true;
id(plant3_status) = already_watered_state;
id(plant3_status_sensor).update();
}
if (!foundAMatch){
ESP_LOGW("schedule_watering", "No plant configured for: %s", relay_id.c_str());
}
- id: relay_timer_script
parameters:
relay_id: string
mode: restart
then:
- logger.log:
level: INFO
tag: relay_timer_script
format: "Start watering using: %s"
args:
- relay_id.c_str()
- delay: !lambda "return id(max_watering_time).state * 1000;"
- logger.log:
level: INFO
tag: relay_timer_script
format: "Max Watering time reached. Turn off %s"
args:
- relay_id.c_str()
- lambda: |-
if (relay_id == "relay1") {
id(relay1).turn_off();
} else if (relay_id == "relay2") {
id(relay2).turn_off();
} else if (relay_id == "relay3") {
id(relay3).turn_off();
} else {
ESP_LOGE("relay_timer_script", "Unknown relay_id: %s", relay_id.c_str());
}
ota:
on_begin:
then:
- logger.log: "OTA started — prevent deep-sleep!"
- deep_sleep.prevent: sleep_control
on_end:
then:
- logger.log: "OTA ended — allow deep-sleep!"
- deep_sleep.allow: sleep_control
on_error:
then:
- logger.log: "OTA failed — allow deep-sleep!"
- deep_sleep.allow: sleep_control
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