Tag: KC868-A6

Slim Irrigatiesysteem

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: "irrigatie: Lowest price vijver bijvullen"
description: ""
triggers:
  - trigger: time
    at: sensor.vijver_bijvullen_start_time
  - value_template: "{{ states('sensor.zonneplan_cheapest_time') == now().strftime('%H:%M') }}"
    trigger: template
    enabled: false
conditions:
  - condition: and
    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:
  - choose:
      - conditions:
          - condition: state
            entity_id: switch.irrigation_serre_switch
            state:
              - "on"
        sequence:
          - wait_for_trigger:
              - entity_id:
                  - switch.irrigation_serre_switch
                to:
                  - "off"
                trigger: state
            continue_on_timeout: false
          - delay:
              hours: 0
              minutes: 0
              seconds: 30
              milliseconds: 0
  - action: number.set_value
    target:
      entity_id: number.irrigation_vijver
    data:
      value: "5"
  - action: switch.turn_on
    target:
      entity_id: switch.irrigation_vijver_switch
    data: {}
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
# 20260401_V01Peterpc
  # de switch in HA gaat bij inschakelen via HA aan, even uit en weer aan, omdat het de status van de valve switch in de esp bij houdt.
  # dat is niet handig als je die in een automation als trigger wil gebruiken.
  # daarom is er een HA switch toegevoegd, die aan blijft en een status sensor voor de zone.
  # de valve switch is ook nog zichtbaar met zijn aan, uit, aan eigenschap, omdat je die niet op internal kan zetten in ESPHome.  
###############################################################
# 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: 20260401_V01Peterpc
  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

###############################################
# SWITCHES voor valves
###############################################

switch:
  - platform: template
    name: "${zone_1_name} switch"
    id: zone_1_switch
    #internal: true
    optimistic: true
    restore_mode: DISABLED
    turn_on_action:
      - sprinkler.start_single_valve:
          id: ${devicename}
          valve_number: 0
    turn_off_action:
      - sprinkler.shutdown:
          id: ${devicename}

  - platform: template
    name: "${zone_2_name} switch"
    id: zone_2_switch
    #internal: true
    optimistic: true
    restore_mode: DISABLED
    turn_on_action:
      - sprinkler.start_single_valve:
          id: ${devicename}
          valve_number: 1
    turn_off_action:
      - sprinkler.shutdown:
          id: ${devicename}

  - platform: template
    name: "${zone_3_name} switch"
    id: zone_3_switch
    #internal: true
    optimistic: true
    restore_mode: DISABLED
    turn_on_action:
      - sprinkler.start_single_valve:
          id: ${devicename}
          valve_number: 2
    turn_off_action:
      - sprinkler.shutdown:
          id: ${devicename}

  - platform: template
    name: "${zone_4_name} switch"
    id: zone_4_switch
    #internal: true
    optimistic: true
    restore_mode: DISABLED
    turn_on_action:
      - sprinkler.start_single_valve:
          id: ${devicename}
          valve_number: 3
    turn_off_action:
      - sprinkler.shutdown:
          id: ${devicename}

  - platform: template
    name: "${zone_5_name} switch"
    id: zone_5_switch
    #internal: true
    optimistic: true
    restore_mode: DISABLED
    turn_on_action:
      - sprinkler.start_single_valve:
          id: ${devicename}
          valve_number: 4
    turn_off_action:
      - sprinkler.shutdown:
          id: ${devicename}

###############################################
# SWITCHES — Restart Device
###############################################

  - platform: restart
    name: "Restart ${devicename}"
    id: restartit



###############################################
# RELAY OUTPUTS — Hidden Valve Controls
# All dynamic via substitutions
###############################################

  ###############################################
  # Zone 1 Relay
  ###############################################
  - platform: gpio
    id: ${devicename}_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");
          }
      - 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
    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");
          }
      - 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
    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");
          }
      - 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
    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");
          }
      - 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
    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");
          }
      - 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"

###############################################
# 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


###############################################
# 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}

###############################################
# status‑sensor voor de zone
###############################################

  - platform: template
    id: zone_1_active
    name: "${zone_1_name} Actief"
    device_class: running
    lambda: |-
      return id(${devicename}_1).state;
    #update_interval: 1s
  - platform: template
    id: zone_2_active
    name: "${zone_2_name} Actief"
    device_class: running
    lambda: |-
      return id(${devicename}_2).state;
    #update_interval: 1s
  - platform: template
    id: zone_3_active
    name: "${zone_3_name} Actief"
    device_class: running
    lambda: |-
      return id(${devicename}_3).state;
    #update_interval: 1s
  - platform: template
    id: zone_4_active
    name: "${zone_4_name} Actief"
    device_class: running
    lambda: |-
      return id(${devicename}_4).state;
    #update_interval: 1s
  - platform: template
    id: zone_5_active
    name: "${zone_5_name} Actief"
    device_class: running
    lambda: |-
      return id(${devicename}_5).state;
    #update_interval: 1s

###############################################
# 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---------------------------------------------------

📄 automation:alle 5 zones automatisch UIT

Hij werkt op basis van:
sensor.irrigation_controller_time_remaining
zodra die 0 seconden bereikt
zet hij alle stateless zone‑switches uit


alias: "Irrigatie : Zet zones uit wanneer sproeien klaar is"
description: ""
triggers:
  - trigger: state
    entity_id:
      - binary_sensor.irrigation_voortuin_actief
    to:
      - "off"
    for:
      hours: 0
      minutes: 0
      seconds: 30
    from:
      - "on"
    id: voortuin
  - trigger: state
    entity_id:
      - binary_sensor.irrigation_achtertuin_actief
    to:
      - "off"
    for:
      hours: 0
      minutes: 0
      seconds: 30
    from:
      - "on"
    id: achtertuin
  - trigger: state
    entity_id:
      - binary_sensor.irrigation_serre_actief
    to:
      - "off"
    for:
      hours: 0
      minutes: 0
      seconds: 30
    from:
      - "on"
    id: serre
  - trigger: state
    entity_id:
      - binary_sensor.irrigation_vijver_actief
    to:
      - "off"
    for:
      hours: 0
      minutes: 0
      seconds: 30
    from:
      - "on"
    id: vijver
  - trigger: state
    entity_id:
      - binary_sensor.irrigation_spare_actief
    to:
      - "off"
    for:
      hours: 0
      minutes: 0
      seconds: 30
    from:
      - "on"
    id: spare
conditions: []
actions:
  - if:
      - condition: trigger
        id:
          - voortuin
    then:
      - target:
          entity_id:
            - switch.irrigation_voortuin_switch
        action: switch.turn_off
        data: {}
    alias: voortuin
  - if:
      - condition: trigger
        id:
          - achtertuin
    then:
      - target:
          entity_id:
            - switch.irrigation_achtertuin_switch
        action: switch.turn_off
        data: {}
    alias: achtertuin
  - alias: serre
    if:
      - condition: trigger
        id:
          - serre
    then:
      - target:
          entity_id:
            - switch.irrigation_serre_switch
        action: switch.turn_off
        data: {}
  - if:
      - condition: trigger
        id:
          - vijver
    then:
      - target:
          entity_id:
            - switch.irrigation_vijver_switch
        action: switch.turn_off
        data: {}
    alias: vijver
  - if:
      - condition: trigger
        id:
          - spare
    then:
      - target:
          entity_id: switch.irrigation_spare_switch
        action: switch.turn_off
        data: {}
    alias: spare
mode: restart



🎯 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.

Loading

Translate »