System nawadniania oparty o esp32 i przekaźniki

Zgadza się: “Czujnik jest wyposażony w higroskopijne pierścienie, które pęcznieją przez nasiąkanie. W ten sposób obwód elektryczny jest rozpinany a system nawadniania do czasu wyschnięcia pierścieni pozostaje nieaktywny. Wiele ustawień wysokości opadu 5 - 20 mm, szybkie i proste ustawianie poprzez obrót pokrętła”.

Znalazłem winowajcę “słabego połączenia” - to nie była wina WiFi - chociaż one też słabe, ale jak dałem w kodzie aktualizację sensorów co 1s, to chyba esp nie wyrabiało z ilością danych do obrobienia i się wysypywało (resetowało), zmieniłem na 3s i teraz pracuje stabilnie - chciałem jedną aby płynnie zmiany pokazywało ale jak widać nie da się.

Nie zauważyłem tego wcześniej w kodzie, jak dla mnie to nawet 3s jest abstrakcją. W żadnym środowisku zmiany temperatury i wilgotności nie zachodzą tak szybko. Moim zdaniem 60s to w zupełności wystarczający interwał.

Temperatura i wilgotność idzie wolno, fajnie też online podglądać czas do końca jak liczy w sekundach ale bez tego da się żyć - natomiast ciśnienie w zbiorniku hydrofobowym już zmienia się szybko, a że byłem zmuszony wprowadzić zmiany w pętlach nawadniania (zastąpić jedna sekcję dwoma sąsiadującymi bo robiąc kostkę uszkodzili jedna rurę idącą od rozdzielacza - niestety uszkodzenie pod kostką) i na podstawie zbyt niskiego ciśnienia pauzować podlewanie i czekać na wzrost ciśnienia - sekcja wylewa więcej wody niż pompa + 100l zbiornik może wydać i dlatego taki zabieg - finalnie taniej niż rozbierać kostkę a się sprawdza.

Czasem zachodzą naprawdę szybko (mam na myśli sytuacje związane z gwałtownymi burzami, niestety przykładu chyba już nie znajdę w gęstych danych), ale bez przesady.
Do potrzeb gęstej wizualizacji wystarczają 4 pomiary na minutę, ale w przypadku rozwiązań DIY koniecznie się trzeba kierować możliwościami użytych czujników (a jest wiele takich które nie mogą raportować aż tak często).

Wybrałem dzień, kiedy był znaczny spadek temperatury, więc może to była burza albo deszcz,4 pomiary na minutę (to akurat czujnik BLE) i wygląda to tak

W sumie jakbym zamiast automatyzacji w HA ukrył w kodzie esphome “naciśnięcie” pauzy przy ciśnieniu niższym niż 2,4bar i wznowienia przy wyższym niż 3,5 - jak spada do 2,1 to chowają się zraszacze, a przy 2,2 zaczyna słabo lecieć (bo w zbiornik już wtedy pusty). to mógłbym rzadziej odczytywać - spróbuje :slight_smile:

W sumie automatyzację możesz zapisywać w samym kodzie ESPHome. Uniezależniasz się wtedy bardziej i omijasz pośrednika.

Właśnie dodałem to do kodu - nie wiem tylko czy jak mam ustawiony update_interval dla zmiennej water pressure na 3s to jak zmienię na np. 10s to ten fragment kogu i tak się wykona prawidłowo bo zmienna water pressure będzie miała wartość aktualizowaną w kodzie esp ale nie publikowaną czy jednak nie - muszę to przetestować ale z racji “testów na produkcji” nie mogę za dużo testować bo już przelałem trawnik :wink:

substitutions:
### Modify only the following 6 lines.
  zone_1_name: 1.Trawnik 1
  zone_2_name: 2.Trawnik 2
  zone_3_name: 3.Trawnik 3
  zone_4_name: 4.Trawnik 4
  zone_5_name: 5.Trawnik 5
  zone_6_name: 6.Trawnik 6
  zone_7_name: 7.Kroplownica
  software_version: V1.2
  sensor_update_frequency: 5s
  log_level: very_verbose # Enable levels logging https://esphome.io/components/logger.html
  # none, error, warn, info, debug (default), verbose, very_verbose
##############################################
#  DO NOT CHANGE ANYTHING BELOW THIS LINE  ###
##############################################
  zone_1_valve_id: valve_0
  zone_2_valve_id: valve_1
  zone_3_valve_id: valve_2
  zone_4_valve_id: valve_3
  zone_5_value_id: value_4
  zone_6_value_id: value_5
  zone_7_value_id: value_6

  esphome_platform: ESP32
  esphome_board: esp32
  esphome_comment: Irrigation Control
  esphome_project_name: dar3k.Irrigation Control
  esphome_project_version: Irrigation Controller, $software_version
  devicename: irrigation_controller
  upper_devicename: "Irrigation Controller"
  uom: Min # this overrides the uom in sprinkler -> run_duration 

#Define Project Deatils and ESP Board Type
esphome:
  name: podlewanie
  friendly_name: "Irrigation Controller"
  comment: Irrigation Control
  project:
    name: dar3k.irrigation_control
    version: "V1.1"
  on_boot:
    priority: -100
    then:
      # Set default state for Valve Status
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
      # Set multiplier to 60, convert seconds to minutes
      - sprinkler.set_multiplier:
          id: $devicename
          multiplier: 60
esp32:
  board: esp32dev

debug:
  update_interval: 60s

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  power_save_mode: none
  output_power: 8.5dB
logger:

# Enable Web server.
web_server:
  port: 80

# Sync time with Home Assistant.
time:
  - platform: homeassistant
    id: homeassistant_time
    
api:
  encryption:
    key: "LjHIyJtf6N8iHqE6ev8j6XmUlzsvKt8AGdnyeguckLE="

ota:
  - platform: esphome
    password: "cfaa0c792a4c710253d485add7d61c37"

  
###############################################
# Text sensors with general information.
###############################################
text_sensor:
  - platform: wifi_info
    ip_address:
      name: "$upper_devicename IP"
      
# Expose Time Remaining as a sensor.
  - 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 / (24 * 3600);
      seconds = seconds % (24 * 3600);
      int hours = seconds / 3600;
      seconds = seconds % 3600;
      int minutes = seconds /  60;
      seconds = seconds % 60;
        return {
          ((days ? String(days) + "d " : "") + 
          (hours ? String(hours) + "h " : "") +
          (minutes ? String(minutes) + "m " : "") +
          (String(seconds) + "s")).c_str()};


  # Expose Progress Percent as a sensor.
  - platform: template
    id: progress_percent
    name: $upper_devicename Progress %
    update_interval: $sensor_update_frequency
    icon: "mdi:progress-clock"
    lambda: |-
      int progress_percent = round(((id($devicename).valve_run_duration_adjusted(id($devicename).active_valve().value_or(0)) - id($devicename).time_remaining_active_valve().value_or(0)) * 100 / id($devicename).valve_run_duration_adjusted(id($devicename).active_valve().value_or(0))));
      std::string progress_percent_as_string = std::to_string(progress_percent);
      return progress_percent_as_string +"%";

  # Expose Valve Status as a sensor.
  - platform: template
    id: valve_status
    name: $upper_devicename Status
    update_interval: never
    icon: "mdi:information-variant"
sensor:
  # Uptime sensor.
  - platform: uptime
    name: $upper_devicename Uptime
  # WiFi Signal sensor.
  - platform: wifi_signal
    name: $upper_devicename WiFi Signal
    update_interval: 60s
  - platform: dht
    pin: 4
    temperature:
      name: "Temperatura"
      id: temperature_sensor 
    humidity:
      name: "Wilgotnosc"
      id: humidity_sensor
    update_interval: 90s
  - platform: adc
    id: water_pressure_raw
    pin: A6
    attenuation: 11db
    update_interval: 500ms
  - platform: template
    id: water_pressure
    name: "Water pressure"
    unit_of_measurement: "bar"
    lambda: |-
      static float values[5];
      static uint8_t index = 0;
      static float readings[10];
      readings[index++] = id(water_pressure_raw).state;
      if (index >= 10) index = 0;

      float sum = 0;
      for (uint8_t i = 0; i < 10; i++) {
        sum += readings[i];
      }
      return (sum / 10.0) * 3.0303 - 0.5;
    update_interval: 3s

  - platform: template
    id: water_pressure_internal
    internal: true
    lambda: |-
      return id(water_pressure_raw).state * 3.0303 - 0.5;
    update_interval: 500ms
  - platform: debug
    loop_time:
      name: "Loop Time"


number:
  - platform: template
    id: water_pressure_threshold_low
    name: "Water Pressure Threshold Low"
    unit_of_measurement: bar
    optimistic: true
    mode: box 
    min_value: 2.00
    max_value: 2.95
    initial_value: 2.8
    step: 0.01
  - platform: template
    id: water_pressure_threshold_high
    name: "Water Pressure Threshold High"
    unit_of_measurement: bar
    optimistic: true
    mode: box 
    min_value: 3.00
    max_value: 3.80
    initial_value: 3.6
    step: 0.01
  - platform: template
    id: zone_1_valve_id
    name: $zone_1_name
    min_value: 1
    max_value: 15
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(0);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 0
          run_duration: !lambda 'return x;'
  - platform: template
    id: zone_2_valve_id
    name: $zone_2_name
    min_value: 1
    max_value: 15
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(1);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 1
          run_duration: !lambda 'return x;'
  - platform: template
    id: zone_3_valve_id
    name: $zone_3_name
    min_value: 1
    max_value: 15
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(2);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 2
          run_duration: !lambda 'return x;'
  - platform: template
    id: zone_4_valve_id
    name: $zone_4_name
    min_value: 1
    max_value: 20
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(3);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 3
          run_duration: !lambda 'return x;'
  - platform: template
    id: zone_5_valve_id
    name: $zone_5_name
    min_value: 1
    max_value: 15
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(4);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 4
          run_duration: !lambda 'return x;'        
  - platform: template
    id: zone_6_valve_id
    name: $zone_6_name
    min_value: 1
    max_value: 15
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(5);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 5
          run_duration: !lambda 'return x;'
  - platform: template
    id: zone_7_valve_id
    name: $zone_7_name
    min_value: 1
    max_value: 30
    step: 1
    unit_of_measurement: $uom
    icon: "mdi:timer-outline"
    mode: box # Defines how the number should be displayed in the UI
    lambda: "return id($devicename).valve_run_duration(6);"
    set_action:
      - sprinkler.set_valve_run_duration:
          id: $devicename
          valve_number: 6
          run_duration: !lambda 'return x;'
###############################################
# Main Sprinkler Controller
###############################################
sprinkler:
  - id: $devicename
    main_switch:
      name: "Start/Stop/Resume"
      id: main_switch
    auto_advance_switch: "Auto Advance"
    valve_open_delay: 1s
    valves:
      - valve_switch: $zone_1_name
        enable_switch: Enable_$zone_1_name
        run_duration: 3s
        valve_switch_id: ${devicename}_1
      - valve_switch: $zone_2_name
        enable_switch: Enable_$zone_2_name
        run_duration: 3s
        valve_switch_id: ${devicename}_2
      - valve_switch: $zone_3_name
        enable_switch: Enable_$zone_3_name
        run_duration: 3s
        valve_switch_id: ${devicename}_3
      - valve_switch: $zone_4_name
        enable_switch: Enable_$zone_4_name
        run_duration: 10s
        valve_switch_id: ${devicename}_4
      - valve_switch: $zone_5_name
        enable_switch: Enable_$zone_5_name
        run_duration: 4s
        valve_switch_id: ${devicename}_5  
      - valve_switch: $zone_6_name
        enable_switch: Enable_$zone_6_name
        run_duration: 4s
        valve_switch_id: ${devicename}_6
      - valve_switch: $zone_7_name
        enable_switch: Enable_$zone_7_name
        run_duration: 15s
        valve_switch_id: ${devicename}_7
button:
  - platform: template
    id: sprinkler_pause
    name: "Pauza"
    icon: "mdi:pause"
    on_press:
      then:
        - text_sensor.template.publish:
            id: valve_status
            state: "Paused"
        - sprinkler.pause: $devicename


####################################################
# Switch Control to restart the irrigation system.   
####################################################
switch:
  - platform: restart
    name: "Restart $devicename"


####################################################
# Hidden I/O  Switches to control irrigation valve relays
####################################################
  - platform: gpio
    name: Relay Board Pin IN1
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_1
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_1_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO32 
    inverted: false
  - platform: gpio
    name: Relay Board Pin IN2
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_2
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_2_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO33
    inverted: false
  - platform: gpio
    name: Relay Board Pin IN3
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_3
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_3_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO25
    inverted: false
  - platform: gpio
    name: Relay Board Pin IN4
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_4
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_4_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO26
    inverted: false
  - platform: gpio
    name: Relay Board Pin IN5
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_5
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_5_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO27
    inverted: false  
  - platform: gpio
    name: Relay Board Pin IN6
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_6
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_6_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO14
    inverted: false
  - platform: gpio
    name: Relay Board Pin IN7
    restore_mode: RESTORE_DEFAULT_OFF # Prevents GPIO pin from going high during boot
    internal: true # Prevents GPIO switch NAME from showing up in Home Assistant
    id: ${devicename}_7
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "$zone_7_name Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
    pin: GPIO12
    inverted: false
  - platform: gpio
    pin: GPIO13
    name: Przekaznik
    id: Przekaznik
binary_sensor:
  - platform: gpio
    pin:
      number: GPIO0
      inverted: true
    name: "Przycisk"
    on_press:
      then:
        - switch.toggle: main_switch
  - platform: gpio
    pin:
      number: GPIO15
      mode: 
        input: true
        pullup: true
    id: czujnik_deszczu
    name: "Czujnik deszczu"
    filters:
      - delayed_on: 100ms
      - delayed_off: 100ms
  - platform: template
    id: water_pressure_low
    name: "Water Pressure Low"
    lambda: |-
      if (id(valve_status).state != "Idle" && id(water_pressure_internal).state < id(water_pressure_threshold_low).state) {
        return true;
      } else {
        return false;
      }
    filters:
      - delayed_on_off: 500ms
    on_state:
      - if:
          condition:
            binary_sensor.is_on: water_pressure_low
          then:
            - text_sensor.template.publish:
                id: valve_status
                state: "Paused"
            - sprinkler.pause: $devicename
            - text_sensor.template.publish:
                id: valve_status
                state: "Paused"
            - sprinkler.pause: $devicename
  - platform: template
    id: water_pressure_high
    name: "Water Pressure High"
    lambda: |-
      if (id(valve_status).state == "Paused" && id(water_pressure_internal).state > id(water_pressure_threshold_high).state) {
        return true;
      } else {
        return false;
      }
    filters:
      - delayed_on_off: 500ms
    on_state:
      - if:
          condition:
            binary_sensor.is_on: water_pressure_high
          then:
            - switch.toggle: main_switch
1 polubienie

Takie wyrwane z kontekstu fragmenty kody nie pomagają innym, trzeba się dodatkowo zastanawiać co autor miał na myśli.

Wystarczy go wkleić na sam koniec kodu wyżej a zwracanie wartości true / false od razu sugeruje że to binary sensor - dlatego nie wkleiłem całości bo po co dwa razy to samo?

Hmm, żeby czytający złapał orient?

1 polubienie

Hej, a mam pytanie, czy wszystko będzie działało “lokalnie”, jeżeli modul utraci łączność z HA?

U mnie działa - utraci połączenie to wykonuje dalej program, a jak nie ma połączenia to daje się też odpalić z przycisku - jakbyś chciał to nawet przy użyciu wejść wyjść dałoby się dodać przyciski do uruchamiania każdej sekcji osobno.

1 polubienie

Dziękuję za rzeczową odpowiedź!
to dziś może coś skleje na kc868

Polecam chatgpt bardzo pomocny “w sklejeniu” zmian w kodzie :blush:

mam jeszcze pytanie, w jaki sposób wykorzystujesz sensor deszczu? widzę ze cztasz go po GPIO15 ale nie widzę, aby był gdzies wykorzystywany w kodzie. masz jakieś automatyzacje skonfigurowane? podzielisz się yaml?

Taką automatyzacją:

alias: Podlewanie wyłącz - czunik deszczu
description: ""
mode: single
triggers:
  - entity_id:
      - binary_sensor.czujnik_deszczu
    from: "off"
    to: "on"
    for:
      hours: 0
      minutes: 1
      seconds: 0
    trigger: state
conditions: []
actions:
  - metadata: {}
    data: {}
    target:
      entity_id:
        - switch.enable_1_trawnik_1
        - switch.enable_2_trawnik_2
        - switch.enable_3_trawnik_3
        - switch.enable_4_trawnik_4
        - switch.enable_5_trawnik_5
        - switch.enable_6_trawnik_6
        - switch.enable_7_kroplownica
    action: switch.turn_off

Można to zrobić w kodzie esp tak samo, jak automatyzację nawadniania ale w planie mam używanie do sterowania tego GitHub - jeroenterheerdt/HAsmartirrigation: Smart Irrigation custom component for Home Assistant

thx. ja właśnie obczajam to:
GitHub - petergridge/Irrigation-V5: Irrigation custom component for Home Assistant

To co wyżej dałem, działa genialnie! tego szukałem. szkoda, że nie idzie tego zaimplementować lokalnie w ESP. PS. aby prawidłowo działał należy deczko kod zmienić w zakresie “sprinkler”
natomiast GitHub - jeroenterheerdt/HAsmartirrigation: Smart Irrigation custom component for Home Assistant nie steruje sam w sobie zaworami a przelicza parowanie i zaciąga pogodynke.

To jak już coś zmieniłeś i ulepszyłeś to jeżeli to możliwe to sugeruję się dzielić z innymi użytkownikami forum :wink:

A co do Smart irrigation to wiem dlatego automatyzację dot. nawadniania zostawiłem w HA a nie w esp tak aby móc na podstawie pogody odpowiednio “dawkować” wodę - ale to czeka aktualnie na wolną chwilę aby się tym zająć.