Slim Irrigatiesysteem
🌱 Slim Irrigatiesysteem met ESPHome, KC868‑A6 en Dynamische Energieprijzen
Water geven is niet moeilijk — maar het efficiënt, energiezuinig en volledig geautomatiseerd doen, dat is een ander verhaal. In dit project bouwde ik een compleet irrigatiesysteem op basis van:
- ESPHome
- Kincony KC868‑A6
- Home Assistant
- Dynamische energieprijzen via cheapest_energy_hours.jinja (TheFes)
Het resultaat is een systeem dat:
- vijf irrigatiezones aanstuurt
- een pomp schakelt
- lokaal bedienbaar is via hardware‑knoppen
- volledig integreert met Home Assistant
- automatisch draait op de goedkoopste uren van de dag
- en zelfs na een reboot weet wanneer elke zone voor het laatst actief was
- irrigatie duur wordt in de ESP geregeld, zodat een zone niet per ongeluk aan blijft als Home Assistant in de tussentijd herstart
🔧 Hardware: Kincony KC868‑A6
De KC868‑A6 is een veelzijdige controller die ideaal is voor irrigatieprojecten.
| Eigenschap | Beschrijving |
|---|---|
| MCU | ESP32 (WiFi + Bluetooth) |
| Relais | 6 kanalen, 10A, optisch geïsoleerd |
| Ingangen | 6 digitale ingangen (PCF8574) |
| Uitgangen | 8 digitale uitgangen (PCF8574) |
| I²C‑bus | Voor displays, sensoren, uitbreidingen |
| Voeding | 12V input, interne 5V/3.3V conversie |
| Extra’s | RS485, IR, RF, uitbreidingsheaders |
Meer info:
KC868‑A6 hardware details
💧 Irrigatiecontroller met ESPHome
De configuratie bevat:
- 5 irrigatiezones
- pompbeveiliging
- OLED‑display
- lokale bediening via knoppen
- persistent “last run” geheugen
- Home Assistant integratie
⚡ Slimme automatisering: irrigeren op de goedkoopste uren
Met dynamische energieprijzen is het zonde om de pomp te laten draaien op dure uren. Daarom gebruik ik de cheapest_energy_hours.jinja template van TheFes.
Repo:
https://github.com/TheFes/cheapest-energy-hours
🧠 template sensor: “energy low 1 hour daytime”
# template sensor
- trigger:
- platform: time
at:
- "8:00"
# - "14:16"
- platform: homeassistant
event: start
# - platform: state
# entity_id:
# - binary_sensor.dishwasher_door
# - binary_sensor.dishwasher_remote_active
sensor:
- unique_id: f8853830-bf81-46d4-85a9-379c25c37c23
name: Vijver bijvullen Start Time
device_class: timestamp
state: >
{%- set sensor = 'zonneplan' -%}
{% from "cheapest_energy_hours.jinja" import cheapest_energy_hours %}
{{ cheapest_energy_hours(sensor=sensor, hours=1, start='8:00', end='17:00', include_tomorrow=false) }}
🧠 Automation: “Vijver bijvullen op goedkoopste uur”
alias: Lowest price vijver bijvullen
triggers:
- trigger: time
at: sensor.vijver_bijvullen_start_time
conditions:
- condition: template
value_template: >
{{
states('sensor.irrigation_vijver_laatst_gestart') not in ['unknown','unavailable','','Nog nooit']
and
(now() - (states('sensor.irrigation_vijver_laatst_gestart') | as_datetime | as_local)).total_seconds() > 18 * 3600
}}
- condition: numeric_state
entity_id: sensor.cmx_temp
above: 5
actions:
- action: number.set_value
target:
entity_id: number.irrigation_vijver
data:
value: "7"
- action: switch.turn_on
target:
entity_id: switch.vijver
mode: single
📄 Volledige ESPHome‑configuratie
Hieronder staat de volledige YAML‑configuratie van het irrigatiesysteem.
# https://www.kincony.com/kc868-a6-hardware-design-details.html
# https://www.kincony.com/forum/showthread.php?tid=1963
# Based on ESPHome Sprinkler Controller - https://esphome.io/components/sprinkler.html
# https://community.home-assistant.io/t/sprinkler-automation-with-esphome-a-complete-project/565077
# Change Log
# 2023 01 XX
# Initial version
# 2023 04 09 V03
# fix run duration to seconds
# 2023 04 22 V04
# fix GPIO order to match relay 1- 4
# added % at the lambda return for progress sensor return value
# 2023 04 25 V05
# added nodemcu as sensor to display in HA ui
# added includes for api key en ota password
# 2023 05 07 V06
# added a NTC temp sensor to watch the enclosure temperature
# 2023 05 10 V07
# addjusted settings reference voltage to adjust to actual temp (default 3.3)
# 2023 06 06 V08
# adjusted settings for valves corresponding to switches
# added repeat function
# 2024 04 04 V09
# Corrected the value of KEY ESPHOME_PROJECT_VERSION due to compiling error esphome v2024.3.1
# initializer-string for 'char [30]' is too long
# changed 2023 06 06 V08 to 20240404_V09
# removed the text "Irrigation Controller.,"
# 20260312_V01Peterpc
# Wanneer laatst actief toegevoegd.
# 20260314_V01Peterpc
# Bij reboot laatst actief weer naar HA sturen.
# 20260331_V06Peterpc
# sprinkler tijden bij reboot terug zetten naar bewaarde waarden in flash.
# laatst gestart waarde bij install op huidige tijd zetten in plaats van unknown
###############################################################
# KC868-A6 HARDWARE MAP — Irrigation Controller Reference
#
# I2C BUS (ESSENTIEEL — HARD-WIRED):
# SDA = GPIO4
# SCL = GPIO15
#
# I2C DEVICES:
# PCF8574 OUT → 0x24 (Relays)
# PCF8574 IN → 0x22 (Buttons)
# SSD1306 OLED → 0x3C (Display)
#
# PCF8574 OUT (0x24) — RELAYS:
# Pin 0 → Relay 1 → Zone 1
# Pin 1 → Relay 2 → Zone 2
# Pin 2 → Relay 3 → Zone 3
# Pin 3 → Relay 4 → Zone 4
# Pin 4 → Relay 5 → Zone 5
# Pin 5 → Relay 6 → Pump
# Pin 6 → Relay 7 → Free
# Pin 7 → Relay 8 → Free
#
# PCF8574 IN (0x22) — BUTTONS:
# Pin 0 → Button 1 → Start Zone 1
# Pin 1 → Button 2 → Start Zone 2
# Pin 2 → Button 3 → Start Zone 3
# Pin 3 → Button 4 → Start Zone 4
# Pin 4 → Button 5 → Start Zone 5
# Pin 5 → Button 6 → Shutdown All
# Pin 6 → Free
# Pin 7 → Free
#
# DISPLAY (SSD1306 128x64):
# I2C Address: 0x3C
# Shared bus with both PCF8574 chips
#
# POWER:
# ESP32 → 5V input → onboard regulator → 3.3V logic
# Relays → 5V
# PCF8574 → 3.3V
# Display → 3.3V
#
# NOTE:
# - I2C pins MUST be SDA=4, SCL=15 for KC868-A6.
# - Wrong pins = no relays, no buttons, no display.
# - This map is hardware-accurate for your irrigation setup.
###############################################################
###############################################
# V06-FULL-CLEAN — Irrigation Controller
# Universeel, persistent, substitutions-driven
###############################################
################################################################################
# WAARSCHUWING: #
# Bij een firmware-installatie worden alle opgeslagen waarden #
# (globals, sprinkler settings, durations) teruggezet naar deze defaults. #
# Pas deze waarden hier aan als je andere standaardtijden wilt. #
################################################################################
substitutions:
friendly_name: "Irrigation Controller"
zone_1_name: Voortuin
zone_1_last_run_id: voortuin_last_run
zone_1_valve_id: zone1_duration
default_zone_1_duration: "30"
zone_2_name: Achtertuin
zone_2_last_run_id: achtertuin_last_run
zone_2_valve_id: zone2_duration
default_zone_2_duration: "3"
zone_3_name: Serre
zone_3_last_run_id: serre_last_run
zone_3_valve_id: zone3_duration
default_zone_3_duration: "3"
zone_4_name: Vijver
zone_4_last_run_id: vijver_last_run
zone_4_valve_id: zone4_duration
default_zone_4_duration: "5"
zone_5_name: Spare
zone_5_last_run_id: zone5_last_run
zone_5_valve_id: zone5_duration
default_zone_5_duration: "15"
# hieronder niets meer aanpassen!
software_version: 20260331_V06_FULL_CLEAN
sensor_update_frequency: 1s
log_level: debug
esphome_name: irrigation
esphome_platform: ESP32
esphome_board: esp32dev
esphome_comment: Five Valve Irrigation Controller
esphome_project_name: jaya.IrrigationController
esphome_project_version: ${software_version}
devicename: irrigation_controller
upper_devicename: "Irrigation Controller"
uom: Min
###############################################
# ESPHome Core
# Define Project Details and ESP Board Type
###############################################
esphome:
name: ${esphome_name}
comment: ${esphome_comment}
project:
name: ${esphome_project_name}
version: ${esphome_project_version}
on_boot:
priority: -100
then:
# Reset status
- text_sensor.template.publish:
id: valve_status
state: "Idle"
# Convert seconds → minutes
- sprinkler.set_multiplier:
id: ${devicename}
multiplier: 60
# Restore persistent durations into sprinkler
- lambda: |-
id(${devicename}).set_valve_run_duration(0, id(dur_0));
id(${devicename}).set_valve_run_duration(1, id(dur_1));
id(${devicename}).set_valve_run_duration(2, id(dur_2));
id(${devicename}).set_valve_run_duration(3, id(dur_3));
id(${devicename}).set_valve_run_duration(4, id(dur_4));
# --- Last-run timestamps initialiseren ---
- lambda: |-
auto now = id(homeassistant_time).now();
if (now.is_valid()) {
std::string ts = now.strftime("%Y-%m-%d %H:%M:%S");
if (id(zone1_last_run_global).empty())
id(zone1_last_run_global) = ts;
if (id(zone2_last_run_global).empty())
id(zone2_last_run_global) = ts;
if (id(zone3_last_run_global).empty())
id(zone3_last_run_global) = ts;
if (id(zone4_last_run_global).empty())
id(zone4_last_run_global) = ts;
if (id(zone5_last_run_global).empty())
id(zone5_last_run_global) = ts;
}
# --- Last-run sensors publiceren ---
- text_sensor.template.publish:
id: ${zone_1_last_run_id}
state: !lambda 'return id(zone1_last_run_global);'
- text_sensor.template.publish:
id: ${zone_2_last_run_id}
state: !lambda 'return id(zone2_last_run_global);'
- text_sensor.template.publish:
id: ${zone_3_last_run_id}
state: !lambda 'return id(zone3_last_run_global);'
- text_sensor.template.publish:
id: ${zone_4_last_run_id}
state: !lambda 'return id(zone4_last_run_global);'
- text_sensor.template.publish:
id: ${zone_5_last_run_id}
state: !lambda 'return id(zone5_last_run_global);'
###############################################
# ESP32 Hardware
###############################################
esp32:
board: ${esphome_board}
framework:
type: esp-idf
###############################################
# WiFi
###############################################
wifi:
ssid: !secret wifi_ssid24
password: !secret wifi_password
ap:
ssid: "${esphome_name} Fallback Hotspot"
password: !secret esphome_ap_password
logger:
level: ${log_level}
<<: !include common/ota.yaml
# Enable Web server.
web_server:
port: 80
###############################################
# Time Sync + Auto Restart
###############################################
time:
- platform: homeassistant
id: homeassistant_time
###############################################
# restart device at 4 at night so if a wifi
# problem is there it will solve
###############################################
on_time:
- seconds: 0
minutes: 0
hours: 4
days_of_week: MON-SUN
then:
- switch.toggle: restartit
###############################################
# Enable Home Assistant API
###############################################
api:
encryption:
key: !secret encryption_key
reboot_timeout: 0s
###############################################
# GLOBALS — Persistent Durations + Last Run to flash
###############################################
globals:
# Last run text sensors
- id: zone1_last_run_global
type: std::string
restore_value: true
initial_value: "\"Nog nooit\""
- id: zone2_last_run_global
type: std::string
restore_value: true
initial_value: "\"Nog nooit\""
- id: zone3_last_run_global
type: std::string
restore_value: true
initial_value: "\"Nog nooit\""
- id: zone4_last_run_global
type: std::string
restore_value: true
initial_value: "\"Nog nooit\""
- id: zone5_last_run_global
type: std::string
restore_value: true
initial_value: "\"Nog nooit\""
# Persistent run durations (G1)
- id: dur_0
type: int
restore_value: true
initial_value: ${default_zone_1_duration}
- id: dur_1
type: int
restore_value: true
initial_value: ${default_zone_2_duration}
- id: dur_2
type: int
restore_value: true
initial_value: ${default_zone_3_duration}
- id: dur_3
type: int
restore_value: true
initial_value: ${default_zone_4_duration}
- id: dur_4
type: int
restore_value: true
initial_value: ${default_zone_5_duration}
###############################################
# TEXT SENSORS — General Info + Last Run
###############################################
text_sensor:
- platform: version
name: "${esphome_name} ESPHome Version"
hide_timestamp: false
- platform: wifi_info
ip_address:
name: "${esphome_name} IP"
ssid:
name: "${esphome_name} SSID"
bssid:
name: "${esphome_name} BSSID"
###############################################
# Time Remaining (dynamic)
###############################################
- platform: template
id: time_remaining
name: "${upper_devicename} Time Remaining"
update_interval: ${sensor_update_frequency}
icon: "mdi:timer-sand"
lambda: |-
int seconds = round(id(${devicename}).time_remaining_active_valve().value_or(0));
int days = seconds / 86400;
seconds %= 86400;
int hours = seconds / 3600;
seconds %= 3600;
int minutes = seconds / 60;
seconds %= 60;
std::string result;
if (days > 0) result += std::to_string(days) + "d ";
if (hours > 0) result += std::to_string(hours) + "h ";
if (minutes > 0) result += std::to_string(minutes) + "m ";
result += std::to_string(seconds) + "s";
return result;
###############################################
# Progress %
###############################################
- platform: template
id: progress_percent
name: "${upper_devicename} Progress %"
update_interval: ${sensor_update_frequency}
icon: "mdi:progress-clock"
lambda: |-
int valve = id(${devicename}).active_valve().value_or(0);
int total = id(${devicename}).valve_run_duration_adjusted(valve);
int remaining = id(${devicename}).time_remaining_active_valve().value_or(0);
if (total == 0) return std::string("0%");
int pct = round((total - remaining) * 100 / total);
return std::to_string(pct) + "%";
###############################################
# Valve Status
###############################################
- platform: template
id: valve_status
name: "${upper_devicename} Status"
update_interval: never
icon: "mdi:information-variant"
###############################################
# Board Type
###############################################
- platform: template
id: espboard_type
icon: "mdi:developer-board"
name: "${esphome_name} ESPBoard"
lambda: |-
return esphome::optional(std::string("${esphome_board}"));
###############################################
# Last Run Sensors (dynamic via substitutions)
###############################################
- platform: template
id: ${zone_1_last_run_id}
name: "${zone_1_name} Laatst Gestart"
icon: "mdi:clock-start"
update_interval: never
lambda: |-
return id(zone1_last_run_global);
- platform: template
id: ${zone_2_last_run_id}
name: "${zone_2_name} Laatst Gestart"
icon: "mdi:clock-start"
update_interval: never
lambda: |-
return id(zone2_last_run_global);
- platform: template
id: ${zone_3_last_run_id}
name: "${zone_3_name} Laatst Gestart"
icon: "mdi:clock-start"
update_interval: never
lambda: |-
return id(zone3_last_run_global);
- platform: template
id: ${zone_4_last_run_id}
name: "${zone_4_name} Laatst Gestart"
icon: "mdi:clock-start"
update_interval: never
lambda: |-
return id(zone4_last_run_global);
- platform: template
id: ${zone_5_last_run_id}
name: "${zone_5_name} Laatst Gestart"
icon: "mdi:clock-start"
update_interval: never
lambda: |-
return id(zone5_last_run_global);
###############################################
# SENSORS — Uptime + WiFi Signal
###############################################
sensor:
- platform: uptime
name: "${upper_devicename} Uptime"
- platform: wifi_signal
name: "${upper_devicename} WiFi Signal"
update_interval: 60s
###############################################
# NUMBER ENTITIES — Persistent Run Durations
###############################################
number:
###############################################
# Zone 1 — ${zone_1_name}
###############################################
- platform: template
id: ${zone_1_valve_id}
name: "${zone_1_name}"
min_value: 1
max_value: 60
step: 1
unit_of_measurement: ${uom}
icon: "mdi:timer-outline"
mode: box
lambda: |-
return float(id(dur_0));
set_action:
- lambda: |-
id(dur_0) = int(x);
id(${devicename}).set_valve_run_duration(0, id(dur_0));
###############################################
# Zone 2 — ${zone_2_name}
###############################################
- platform: template
id: ${zone_2_valve_id}
name: "${zone_2_name}"
min_value: 1
max_value: 60
step: 1
unit_of_measurement: ${uom}
icon: "mdi:timer-outline"
mode: box
lambda: |-
return float(id(dur_1));
set_action:
- lambda: |-
id(dur_1) = int(x);
id(${devicename}).set_valve_run_duration(1, id(dur_1));
###############################################
# Zone 3 — ${zone_3_name}
###############################################
- platform: template
id: ${zone_3_valve_id}
name: "${zone_3_name}"
min_value: 1
max_value: 60
step: 1
unit_of_measurement: ${uom}
icon: "mdi:timer-outline"
mode: box
lambda: |-
return float(id(dur_2));
set_action:
- lambda: |-
id(dur_2) = int(x);
id(${devicename}).set_valve_run_duration(2, id(dur_2));
###############################################
# Zone 4 — ${zone_4_name}
###############################################
- platform: template
id: ${zone_4_valve_id}
name: "${zone_4_name}"
min_value: 1
max_value: 60
step: 1
unit_of_measurement: ${uom}
icon: "mdi:timer-outline"
mode: box
lambda: |-
return float(id(dur_3));
set_action:
- lambda: |-
id(dur_3) = int(x);
id(${devicename}).set_valve_run_duration(3, id(dur_3));
###############################################
# Zone 5 — ${zone_5_name}
###############################################
- platform: template
id: ${zone_5_valve_id}
name: "${zone_5_name}"
min_value: 1
max_value: 60
step: 1
unit_of_measurement: ${uom}
icon: "mdi:timer-outline"
mode: box
lambda: |-
return float(id(dur_4));
set_action:
- lambda: |-
id(dur_4) = int(x);
id(${devicename}).set_valve_run_duration(4, id(dur_4));
###############################################
# Repeat Cycles
###############################################
- platform: template
id: sprinkler_ctrlr_repeat_cycles
name: "Sprinkler Repeat Cycles"
min_value: 0
max_value: 4
step: 1
mode: box
icon: "mdi:water-sync"
lambda: |-
return id(${devicename}).repeat();
set_action:
- sprinkler.set_repeat:
id: ${devicename}
repeat: !lambda 'return x;'
###############################################
# SPRINKLER CONTROLLER — Persistent + Clean
###############################################
sprinkler:
- id: ${devicename}
pump_start_pump_delay: 3s
pump_stop_valve_delay: 3s
main_switch:
name: "Start-Stop-Resume"
id: main_switch
auto_advance_switch: "Auto Advance"
valve_open_delay: 2s
repeat_number: "Repeat"
###############################################
# Valves — Dynamic via substitutions
###############################################
valves:
- valve_switch: ${zone_1_name}
enable_switch: "Enable ${zone_1_name}"
pump_switch_id: sprinkler_pump_sw
run_duration: 60s
valve_switch_id: ${devicename}_1
- valve_switch: ${zone_2_name}
enable_switch: "Enable ${zone_2_name}"
pump_switch_id: sprinkler_pump_sw
run_duration: 60s
valve_switch_id: ${devicename}_2
- valve_switch: ${zone_3_name}
enable_switch: "Enable ${zone_3_name}"
pump_switch_id: sprinkler_pump_sw
run_duration: 60s
valve_switch_id: ${devicename}_3
- valve_switch: ${zone_4_name}
enable_switch: "Enable ${zone_4_name}"
pump_switch_id: sprinkler_pump_sw
run_duration: 60s
valve_switch_id: ${devicename}_4
- valve_switch: ${zone_5_name}
enable_switch: "Enable ${zone_5_name}"
pump_switch_id: sprinkler_pump_sw
run_duration: 60s
valve_switch_id: ${devicename}_5
###############################################
# BUTTONS — Pause
###############################################
button:
- platform: template
id: sprinkler_pause
name: "Pause"
icon: "mdi:pause"
on_press:
then:
- text_sensor.template.publish:
id: valve_status
state: "Paused"
- sprinkler.pause: ${devicename}
###############################################
# PCF8574 I/O Expanders
###############################################
pcf8574:
- id: pcf8574_hub_out_1
address: 0x24
- id: pcf8574_hub_in_1
address: 0x22
###############################################
# SWITCHES — Restart Device
###############################################
switch:
- platform: restart
name: "Restart ${devicename}"
id: restartit
###############################################
# RELAY OUTPUTS — Hidden Valve Controls
# All dynamic via substitutions
###############################################
###############################################
# Zone 1 Relay
###############################################
- platform: gpio
id: ${devicename}_1
name: "Relay Zone 1"
internal: true
restore_mode: RESTORE_DEFAULT_OFF
pin:
pcf8574: pcf8574_hub_out_1
number: 0
mode: OUTPUT
inverted: true
on_turn_on:
- lambda: |-
auto now = id(homeassistant_time).now();
if (now.is_valid()) {
id(zone1_last_run_global) = now.strftime("%Y-%m-%d %H:%M:%S");
} else {
id(zone1_last_run_global) = "Unknown";
}
- text_sensor.template.publish:
id: ${zone_1_last_run_id}
state: !lambda 'return id(zone1_last_run_global);'
- text_sensor.template.publish:
id: valve_status
state: "${zone_1_name} Active"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Idle"
###############################################
# Zone 2 Relay
###############################################
- platform: gpio
id: ${devicename}_2
name: "Relay Zone 2"
internal: true
restore_mode: RESTORE_DEFAULT_OFF
pin:
pcf8574: pcf8574_hub_out_1
number: 1
mode: OUTPUT
inverted: true
on_turn_on:
- lambda: |-
auto now = id(homeassistant_time).now();
if (now.is_valid()) {
id(zone2_last_run_global) = now.strftime("%Y-%m-%d %H:%M:%S");
} else {
id(zone2_last_run_global) = "Unknown";
}
- text_sensor.template.publish:
id: ${zone_2_last_run_id}
state: !lambda 'return id(zone2_last_run_global);'
- text_sensor.template.publish:
id: valve_status
state: "${zone_2_name} Active"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Idle"
###############################################
# Zone 3 Relay
###############################################
- platform: gpio
id: ${devicename}_3
name: "Relay Zone 3"
internal: true
restore_mode: RESTORE_DEFAULT_OFF
pin:
pcf8574: pcf8574_hub_out_1
number: 2
mode: OUTPUT
inverted: true
on_turn_on:
- lambda: |-
auto now = id(homeassistant_time).now();
if (now.is_valid()) {
id(zone3_last_run_global) = now.strftime("%Y-%m-%d %H:%M:%S");
} else {
id(zone3_last_run_global) = "Unknown";
}
- text_sensor.template.publish:
id: ${zone_3_last_run_id}
state: !lambda 'return id(zone3_last_run_global);'
- text_sensor.template.publish:
id: valve_status
state: "${zone_3_name} Active"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Idle"
###############################################
# Zone 4 Relay
###############################################
- platform: gpio
id: ${devicename}_4
name: "Relay Zone 4"
internal: true
restore_mode: RESTORE_DEFAULT_OFF
pin:
pcf8574: pcf8574_hub_out_1
number: 3
mode: OUTPUT
inverted: true
on_turn_on:
- lambda: |-
auto now = id(homeassistant_time).now();
if (now.is_valid()) {
id(zone4_last_run_global) = now.strftime("%Y-%m-%d %H:%M:%S");
} else {
id(zone4_last_run_global) = "Unknown";
}
- text_sensor.template.publish:
id: ${zone_4_last_run_id}
state: !lambda 'return id(zone4_last_run_global);'
- text_sensor.template.publish:
id: valve_status
state: "${zone_4_name} Active"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Idle"
###############################################
# Zone 5 Relay
###############################################
- platform: gpio
id: ${devicename}_5
name: "Relay Zone 5"
internal: true
restore_mode: RESTORE_DEFAULT_OFF
pin:
pcf8574: pcf8574_hub_out_1
number: 4
mode: OUTPUT
inverted: true
on_turn_on:
- lambda: |-
auto now = id(homeassistant_time).now();
if (now.is_valid()) {
id(zone5_last_run_global) = now.strftime("%Y-%m-%d %H:%M:%S");
} else {
id(zone5_last_run_global) = "Unknown";
}
- text_sensor.template.publish:
id: ${zone_5_last_run_id}
state: !lambda 'return id(zone5_last_run_global);'
- text_sensor.template.publish:
id: valve_status
state: "${zone_5_name} Active"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Idle"
###############################################
# Pump Relay
###############################################
- platform: gpio
id: sprinkler_pump_sw
name: "Sprinkler Pump"
internal: true
restore_mode: RESTORE_DEFAULT_OFF
pin:
pcf8574: pcf8574_hub_out_1
number: 5
mode: OUTPUT
inverted: true
on_turn_on:
- text_sensor.template.publish:
id: valve_status
state: "Pump Active"
on_turn_off:
- text_sensor.template.publish:
id: valve_status
state: "Idle"
###############################################
# BINARY SENSORS — Local Manual Inputs
###############################################
binary_sensor:
- platform: homeassistant
id: prevent_deep_sleep
name: "${upper_devicename} Prevent Deep Sleep"
entity_id: input_boolean.prevent_deep_sleep
###############################################
# Local Button 1 → Start Zone 1
###############################################
- platform: gpio
name: "a6-input1"
internal: true
pin:
pcf8574: pcf8574_hub_in_1
number: 0
mode: INPUT
inverted: true
on_press:
- sprinkler.start_single_valve:
id: ${devicename}
valve_number: 0
###############################################
# Local Button 2 → Start Zone 2
###############################################
- platform: gpio
name: "a6-input2"
internal: true
pin:
pcf8574: pcf8574_hub_in_1
number: 1
mode: INPUT
inverted: true
on_press:
- sprinkler.start_single_valve:
id: ${devicename}
valve_number: 1
###############################################
# Local Button 3 → Start Zone 3
###############################################
- platform: gpio
name: "a6-input3"
internal: true
pin:
pcf8574: pcf8574_hub_in_1
number: 2
mode: INPUT
inverted: true
on_press:
- sprinkler.start_single_valve:
id: ${devicename}
valve_number: 2
###############################################
# Local Button 4 → Start Zone 4
###############################################
- platform: gpio
name: "a6-input4"
internal: true
pin:
pcf8574: pcf8574_hub_in_1
number: 3
mode: INPUT
inverted: true
on_press:
- sprinkler.start_single_valve:
id: ${devicename}
valve_number: 3
###############################################
# Local Button 5 → Start Zone 5
###############################################
- platform: gpio
name: "a6-input5"
internal: true
pin:
pcf8574: pcf8574_hub_in_1
number: 4
mode: INPUT
inverted: true
on_press:
- sprinkler.start_single_valve:
id: ${devicename}
valve_number: 4
###############################################
# Local Button 6 → Shutdown All
###############################################
- platform: gpio
name: "a6-input6"
internal: true
pin:
pcf8574: pcf8574_hub_in_1
number: 5
mode: INPUT
inverted: true
on_press:
- sprinkler.shutdown: ${devicename}
###############################################
# I2C BUS
###############################################
i2c:
sda: 4
scl: 15
scan: true
id: bus_a
###############################################
# FONTS
###############################################
font:
- file: "common/fonts/Roboto-Regular.ttf"
id: font_small
size: 12
- file: "common/fonts/Roboto-Regular.ttf"
id: font_medium
size: 16
- file: "common/fonts/Roboto-Regular.ttf"
id: font_large
size: 20
###############################################
# DISPLAY — SSD1306 128x64
###############################################
display:
- platform: ssd1306_i2c
model: "SSD1306 128x64"
id: irrigation_display
address: 0x3C
rotation: 0
lambda: |-
// Tijd bovenaan
auto now = id(homeassistant_time).now();
if (now.is_valid()) {
it.strftime(0, 0, id(font_medium), "%H:%M:%S", now);
} else {
it.printf(0, 0, id(font_medium), "--:--:--");
}
// Active valve
auto active = id(${devicename}).active_valve().value_or(-1);
if (active >= 0) {
std::string zone_name;
if (active == 0) zone_name = "${zone_1_name}";
if (active == 1) zone_name = "${zone_2_name}";
if (active == 2) zone_name = "${zone_3_name}";
if (active == 3) zone_name = "${zone_4_name}";
if (active == 4) zone_name = "${zone_5_name}";
it.printf(0, 18, id(font_small), "Active: %s", zone_name.c_str());
} else {
it.printf(0, 18, id(font_small), "Active: None");
}
// Time remaining
it.printf(0, 32, id(font_small), "Remaining: %s",
id(time_remaining).state.c_str());
// Progress %
it.printf(0, 46, id(font_small), "Progress: %s",
id(progress_percent).state.c_str());
# -----------------------------end---------------------------------------------------
🎯 Conclusie
Dit project combineert krachtige hardware, flexibele software en slimme automatisering. Het resultaat is een irrigatiesysteem dat volledig autonoom werkt, energie bespaart en perfect integreert in een moderne smart home‑omgeving.
![]()










