Reklama

Chytrý zavlažovací systém ze senzorů a Arduina

Chytrý zavlažovací systém ze senzorů a Arduina - automatické zavlažování zahrady s IoT technologiemi a mobilním ovládáním - návod pro kutily

Automatický zavlažovací systém řízený Arduinem dokáže ušetřit čas, vodu i vaše rostliny. V tomto projektu si postavíme kompletní IoT systém s mobilním ovládáním.

Přehled projektu

Co systém umí

  • Měření vlhkosti půdy na více místech
  • Automatické zavlažování podle nastaveného programu
  • Dálkové ovládání přes WiFi
  • Mobilní aplikaci pro monitoring
  • Záložní ruční ovládání
  • Ochranu proti přelití

Komponenty a cena

Arduino ESP32:           400 Kč
Čidla vlhkosti (5×):     250 Kč
Solenoidové ventily (4×): 800 Kč
Čerpadlo 12V:            300 Kč
Relé moduly (4×):        200 Kč
Napájení 12V/24V:        250 Kč
Hadice a konektory:      400 Kč
Krabička IP65:           150 Kč
Displej OLED:            100 Kč
Různé (rezistory atd.):  150 Kč
------------------------
Celkem:                3000 Kč

Schéma zapojení

Hlavní řídící jednotka (ESP32)

ESP32 piny:
GPIO 2  → LED status
GPIO 4  → Tlačítko START/STOP
GPIO 21 → SDA (I2C displej)  
GPIO 22 → SCL (I2C displej)
GPIO 32 → Čidlo vlhkosti 1
GPIO 33 → Čidlo vlhkosti 2  
GPIO 34 → Čidlo vlhkosti 3
GPIO 35 → Čidlo vlhkosti 4
GPIO 36 → Čidlo vlhkosti 5
GPIO 16 → Relé čerpadlo
GPIO 17 → Relé ventil 1
GPIO 5  → Relé ventil 2
GPIO 18 → Relé ventil 3
GPIO 19 → Relé ventil 4

Napájení

  • ESP32: 5V z USB nebo external
  • Relé moduly: 5V z napájecího zdroje
  • Čerpadlo a ventily: 12V/24V podle typu

Kód pro Arduino IDE

Základní knihovny

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <SSD1306Wire.h>
#include <Preferences.h>

Hlavní kód systému

// Definice pinů
#define PUMP_PIN 16
#define VALVE1_PIN 17
#define VALVE2_PIN 5
#define VALVE3_PIN 18
#define VALVE4_PIN 19

#define MOISTURE1_PIN 32
#define MOISTURE2_PIN 33
#define MOISTURE3_PIN 34
#define MOISTURE4_PIN 35
#define MOISTURE5_PIN 36

#define BUTTON_PIN 4
#define LED_PIN 2

// WiFi konfigurace
const char* ssid = "VasaWiFiSit";
const char* password = "VaseHeslo";

// Webserver na portu 80
WebServer server(80);

// OLED displej 128x64
SSD1306Wire display(0x3c, 21, 22);

// Preferences pro uložení nastavení
Preferences preferences;

// Globální proměnné
struct IrrigationZone {
  int valvePin;
  int moisturePin;
  int moistureThreshold;
  int wateringDuration;
  bool isActive;
  String name;
};

IrrigationZone zones[4] = {
  {VALVE1_PIN, MOISTURE1_PIN, 30, 5000, false, "Rajčata"},
  {VALVE2_PIN, MOISTURE2_PIN, 25, 3000, false, "Salát"},
  {VALVE3_PIN, MOISTURE3_PIN, 35, 7000, false, "Květiny"},
  {VALVE4_PIN, MOISTURE4_PIN, 40, 4000, false, "Bylinky"}
};

bool systemActive = false;
bool manualMode = false;
unsigned long lastCheck = 0;
const unsigned long CHECK_INTERVAL = 30000; // 30 sekund

void setup() {
  Serial.begin(115200);
  
  // Inicializace pinů
  pinMode(PUMP_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  
  for(int i = 0; i < 4; i++) {
    pinMode(zones[i].valvePin, OUTPUT);
    digitalWrite(zones[i].valvePin, LOW);
  }
  digitalWrite(PUMP_PIN, LOW);
  
  // Inicializace displeje
  display.init();
  display.clear();
  display.setFont(ArialMT_Plain_16);
  display.drawString(0, 0, "Zavlažovač");
  display.drawString(0, 20, "Spouštím...");
  display.display();
  
  // Připojení k WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Připojuji k WiFi...");
  }
  
  Serial.println("WiFi připojeno!");
  Serial.print("IP adresa: ");
  Serial.println(WiFi.localIP());
  
  // Inicializace webserveru
  setupWebServer();
  server.begin();
  
  // Načtení uložených nastavení
  loadSettings();
  
  updateDisplay();
}

void loop() {
  server.handleClient();
  
  // Kontrola tlačítka
  if (digitalRead(BUTTON_PIN) == LOW) {
    delay(50); // debounce
    if (digitalRead(BUTTON_PIN) == LOW) {
      toggleSystem();
      while(digitalRead(BUTTON_PIN) == LOW) delay(10);
    }
  }
  
  // Automatická kontrola vlhkosti
  if (systemActive && !manualMode && 
      (millis() - lastCheck > CHECK_INTERVAL)) {
    checkMoistureAndWater();
    lastCheck = millis();
  }
  
  // Aktualizace displeje každých 5 sekund
  static unsigned long lastDisplayUpdate = 0;
  if (millis() - lastDisplayUpdate > 5000) {
    updateDisplay();
    lastDisplayUpdate = millis();
  }
  
  delay(100);
}

void checkMoistureAndWater() {
  for (int i = 0; i < 4; i++) {
    if (!zones[i].isActive) continue;
    
    int moisture = readMoisture(zones[i].moisturePin);
    Serial.printf("Zóna %d (%s): vlhkost %d%%\n", 
                  i+1, zones[i].name.c_str(), moisture);
    
    if (moisture < zones[i].moistureThreshold) {
      waterZone(i);
    }
  }
}

int readMoisture(int pin) {
  // Čtení analogové hodnoty a převod na procenta
  int rawValue = analogRead(pin);
  // Kalibrace: 4095 = suchá půda (0%), 1500 = mokrá půda (100%)
  int moisture = map(rawValue, 4095, 1500, 0, 100);
  return constrain(moisture, 0, 100);
}

void waterZone(int zoneIndex) {
  Serial.printf("Zavlažuji zónu %d (%s)\n", 
                zoneIndex+1, zones[zoneIndex].name.c_str());
  
  // Zapnout čerpadlo
  digitalWrite(PUMP_PIN, HIGH);
  delay(500); // Počkat na vytvoření tlaku
  
  // Zapnout ventil
  digitalWrite(zones[zoneIndex].valvePin, HIGH);
  
  // Blikat LED během zavlažování
  unsigned long startTime = millis();
  while (millis() - startTime < zones[zoneIndex].wateringDuration) {
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));
    delay(200);
  }
  
  // Vypnout ventil a čerpadlo
  digitalWrite(zones[zoneIndex].valvePin, LOW);
  delay(200);
  digitalWrite(PUMP_PIN, LOW);
  digitalWrite(LED_PIN, LOW);
  
  Serial.printf("Zóna %d zavlažena\n", zoneIndex+1);
}

void setupWebServer() {
  // Hlavní stránka
  server.on("/", handleRoot);
  
  // API endpointy
  server.on("/api/status", handleStatus);
  server.on("/api/water", handleManualWater);
  server.on("/api/settings", handleSettings);
  server.on("/api/toggle", handleToggle);
  
  // CORS hlavičky
  server.enableCORS(true);
}

void handleRoot() {
  String html = getWebInterface();
  server.send(200, "text/html", html);
}

void handleStatus() {
  DynamicJsonDocument doc(1024);
  doc["systemActive"] = systemActive;
  doc["manualMode"] = manualMode;
  doc["ip"] = WiFi.localIP().toString();
  
  JsonArray zonesArray = doc.createNestedArray("zones");
  for (int i = 0; i < 4; i++) {
    JsonObject zone = zonesArray.createNestedObject();
    zone["id"] = i;
    zone["name"] = zones[i].name;
    zone["moisture"] = readMoisture(zones[i].moisturePin);
    zone["threshold"] = zones[i].moistureThreshold;
    zone["active"] = zones[i].isActive;
    zone["duration"] = zones[i].wateringDuration;
  }
  
  String response;
  serializeJson(doc, response);
  server.send(200, "application/json", response);
}

void updateDisplay() {
  display.clear();
  
  // Hlavní stav
  display.setFont(ArialMT_Plain_16);
  String status = systemActive ? "AKTIVNÍ" : "VYPNUTO";
  display.drawString(0, 0, status);
  
  // IP adresa
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 20, WiFi.localIP().toString());
  
  // Vlhkosti
  for (int i = 0; i < 4; i++) {
    int moisture = readMoisture(zones[i].moisturePin);
    String line = zones[i].name + ": " + String(moisture) + "%";
    display.drawString(0, 32 + i*8, line);
  }
  
  display.display();
}

String getWebInterface() {
  return R"(
<!DOCTYPE html>
<html>
<head>
    <title>Chytrý zavlažovač</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        body { font-family: Arial; margin: 20px; }
        .zone { border: 1px solid #ccc; margin: 10px 0; padding: 15px; }
        .button { background: #4CAF50; color: white; padding: 10px 20px; 
                 border: none; cursor: pointer; margin: 5px; }
        .button:hover { background: #45a049; }
        .status { font-size: 18px; margin: 10px 0; }
        .moisture { font-size: 16px; font-weight: bold; }
    </style>
</head>
<body>
    <h1>🌱 Chytrý zavlažovací systém</h1>
    
    <div class="status" id="systemStatus">Načítám...</div>
    <button class="button" onclick="toggleSystem()">Zapnout/Vypnout</button>
    
    <h2>Zóny zavlažování</h2>
    <div id="zones"></div>
    
    <script>
        function updateStatus() {
            fetch('/api/status')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('systemStatus').innerHTML = 
                        'Systém: ' + (data.systemActive ? 'AKTIVNÍ' : 'VYPNUTÝ');
                    
                    let zonesHTML = '';
                    data.zones.forEach(zone => {
                        zonesHTML += `
                            <div class="zone">
                                <h3>${zone.name}</h3>
                                <div class="moisture">Vlhkost: ${zone.moisture}%</div>
                                <div>Práh: ${zone.threshold}%</div>
                                <div>Doba: ${zone.duration/1000}s</div>
                                <button class="button" onclick="waterZone(${zone.id})">
                                    Zavlažit nyní
                                </button>
                            </div>
                        `;
                    });
                    document.getElementById('zones').innerHTML = zonesHTML;
                });
        }
        
        function toggleSystem() {
            fetch('/api/toggle', {method: 'POST'})
                .then(() => updateStatus());
        }
        
        function waterZone(zoneId) {
            fetch('/api/water', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({zone: zoneId})
            }).then(() => alert('Zavlažování spuštěno!'));
        }
        
        // Aktualizace každých 5 sekund
        setInterval(updateStatus, 5000);
        updateStatus();
    </script>
</body>
</html>
  )";
}

Instalace a nastavení

Příprava hardwaru

  1. Sestavení řídící skříňky

    • Umístění ESP32 do voděodolné krabičky
    • Instalace displeje na víko
    • Průchodky pro kabely
  2. Pokládka senzorů

    • Umístění čidel vlhkosti 10-15 cm pod povrch
    • Ochrana před přímým kontaktem s vodou
    • Kalibrace podle typu půdy
  3. Instalace ventilů

    • Umístění za hlavní uzávěr vody
    • Kontrola průtoku a tlaku
    • Test všech spojů

Software a konfigurace

// WiFi nastavení v kódu
const char* ssid = "VasaWiFiSit";  
const char* password = "VaseHeslo";

// Kalibrace čidel vlhkosti
const int DRY_VALUE = 4095;    // suchá půda
const int WET_VALUE = 1500;    // mokrá půda

Mobilní aplikace (volitelně)

React Native aplikace

Pro pokročilé uživatele je možné vytvořit mobilní aplikaci:

// Základní API volání
const API_BASE = 'http://192.168.1.100';

const getStatus = async () => {
  const response = await fetch(`${API_BASE}/api/status`);
  return response.json();
};

const waterZone = async (zoneId) => {
  await fetch(`${API_BASE}/api/water`, {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({zone: zoneId})
  });
};

Rozšíření systému

Pokročilé funkce

  • Meteorologická data: Integrace s weather API
  • Kamerový monitoring: ESP32-CAM pro sledování rostlin
  • Dešťový senzor: Vypnutí při dešti
  • Flowmetr: Měření spotřeby vody
  • Solární napájení: Nezávislé napájení systému

Integrace s chytrou domácností

// MQTT pro Home Assistant
#include <PubSubClient.h>

WiFiClient espClient;
PubSubClient client(espClient);

void publishToHA(String topic, String payload) {
  client.publish(("homeassistant/sensor/irrigation/" + topic).c_str(), 
                 payload.c_str());
}

Údržba a řešení problémů

Pravidelná údržba

  • Týdně: Kontrola funkčnosti čidel
  • Měsíčně: Čištění filtrů ventilů
  • Sezónně: Kalibrace senzorů vlhkosti
  • Ročně: Výměna těsnění

Časté problémy

Falešné čtení vlhkosti ✅ Čištění elektrod senzorů

Nefunkční ventily
✅ Kontrola napájení a průchodnosti

WiFi výpadky ✅ Implementace offline režimu

Náklady vs. komerční řešení

Srovnání s komerčními systémy

DIY Arduino systém:      3 000 Kč
Komerční systém (basic): 15 000 Kč  
Profesionální instalace: 35 000 Kč

Úspora:                  80-90%

ROI (návratnost investice)

  • Úspora vody: 30-50%
  • Úspora času: 2-3 hodiny týdně
  • Lepší růst rostlin: nezaměřitelné
  • Návratnost: 1-2 sezóny

Chytrý zavlažovací systém na bázi Arduina je ideální projekt pro kutily, kteří chtějí kombinovat elektroniku s praktickou aplikací. Systém lze postupně rozšiřovat a přizpůsobovat konkrétním potřebám.

Tip pro začátečníky: Začněte s jednou zónou a postupně přidávejte další podle zkušeností a potřeb.

Reklama