на даче задумал теплицу, а теплица без полива как вобла без пива ) короч полив определяет когда влажность повышена, дождь, влажность почвы, уровень в баке, температура воздуха
Код для умного полива. по температуре воздуха, по влажности воздуха, влажность почвы и увроень в баке на электромеханическом кране для капельного полива
#include <LiquidCrystal_I2C.h>
#include <Adafruit_Sensor.h>
#include <HTU21D.h>
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
// Датчики и пины
HTU21D sensor; // Датчик температуры/влажности
int zemlyaPin = A3; // Пин датчика влажности почвы
#define nasos 10 // Пин управления насосом
#define gerkon 7 // Пин поплавкового датчика
// Пины для крана
#define valveOpenPin 12 // Реле открытия крана
#define valveClosePin 11 // Реле закрытия крана
// Переменные состояния
int zemlya = 0; // Значение датчика почвы
int suhota_zemli = 0; // Счетчик сухости почвы
int voda_bochka = 0; // Счетчик уровня воды
int temper = 0; // Счетчик температуры
int vlazh = 0; // Счетчик влажности
int kolvo = 0; // Счетчик поливов
int nasosok = 1; // Состояние насоса
int gerkon_triger = 0; // Триггер поплавкового датчика
int displayPage = 0; // Страница дисплея
int tttt = 1; // Флаг отладки
// Временные метки
tmElements_t lastTempCheck; // Время последней проверки температуры
tmElements_t lastPolivStart; // Время начала полива
tmElements_t lastDisplayUpdate; // Время обновления дисплея
unsigned long polivDuration = 2000000; // Продолжительность полива в мс (например, 3.5 минуты)
unsigned long polivStartTime = 0; // Время начала полива часы
bool isPolivRunning = false; // Флаг: идёт ли полив?
// Константы
const byte POLIV_HOUR = 20; // Час автоматического полива
const int VALVE_TIME = 11000; // Время открытия/закрытия крана (10 сек)
// Инициализация LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Перечисление состояний крана
enum ValveState {
VALVE_IDLE,
VALVE_OPENING,
VALVE_CLOSING
};
ValveState valveStatus = VALVE_IDLE;
unsigned long valveStartTime = 0;
// Функция вывода времени на дисплей
void printTime(int hours, int minutes) {
if (hours < 10) lcd.print("0");
lcd.print(hours);
lcd.print(":");
if (minutes < 10) lcd.print("0");
lcd.print(minutes);
}
void setup() {
Serial.begin(9600);
while (!Serial); // Ожидание инициализации Serial
// Инициализация датчиков
sensor.begin();
// Настройка дисплея
lcd.init();
lcd.backlight();
// Настройка пинов
pinMode(gerkon, INPUT);
pinMode(nasos, OUTPUT);
pinMode(valveOpenPin, OUTPUT);
pinMode(valveClosePin, OUTPUT);
digitalWrite(nasos, HIGH); // Насос выключен
digitalWrite(valveOpenPin, HIGH); // Выключить реле открытия
digitalWrite(valveClosePin, HIGH); // Выключить реле закрытия
// Инициализация времени
if (RTC.read(lastTempCheck)) {
lastPolivStart = lastDisplayUpdate = lastTempCheck;
}
}
void openValve() {
if (valveStatus != VALVE_IDLE) return;
valveStatus = VALVE_OPENING;
valveStartTime = millis();
digitalWrite(valveOpenPin, LOW); // Включаем открытие
digitalWrite(valveClosePin, HIGH); // Убедиться, что закрыто
Serial.println("Кран: Открываем...");
}
void closeValve() {
if (valveStatus != VALVE_IDLE) return;
valveStatus = VALVE_CLOSING;
valveStartTime = millis();
digitalWrite(valveClosePin, LOW); // Включаем закрытие
digitalWrite(valveOpenPin, HIGH); // Убедиться, что открыто
Serial.println("Кран: Закрываем...");
}
void loop() {
tmElements_t tm;
if (RTC.read(tm)) {
zemlya = analogRead(zemlyaPin); // Чтение датчика почвы
int buttonState = digitalRead(gerkon); // Чтение поплавкового датчика
// Обработка состояния крана
switch (valveStatus) {
case VALVE_OPENING:
if (millis() - valveStartTime >= VALVE_TIME) {
digitalWrite(valveOpenPin, HIGH);
valveStatus = VALVE_IDLE;
Serial.println("Кран: Открыт.");
}
break;
case VALVE_CLOSING:
if (millis() - valveStartTime >= VALVE_TIME) {
digitalWrite(valveClosePin, HIGH);
valveStatus = VALVE_IDLE;
Serial.println("Кран: Закрыт.");
}
break;
default:
break;
}
// Проверка условий каждую минуту в час полива
if (tm.Hour == POLIV_HOUR && tm.Minute != lastTempCheck.Minute) {
lastTempCheck = tm;
// Чтение температуры и влажности
if (sensor.measure()) {
float temperature = sensor.getTemperature();
float humidity = sensor.getHumidity();
// Обновление счетчиков
if (temperature > 18) temper++;
if (humidity > 70) vlazh++;
}
// Обновление состояния почвы и бака
if (zemlya > 260) suhota_zemli++; else suhota_zemli--;
if (buttonState == 1) voda_bochka++; else voda_bochka--;
}
// Сброс счетчиков в 10:00
if (tm.Hour == 10 && tm.Minute == 0) {
nasosok = 1;
vlazh = temper = kolvo = 0;
}
// Логика включения полива
if (tm.Hour == POLIV_HOUR && nasosok == 1) {
if (temper > 10 && vlazh < 10 && voda_bochka > 10 && suhota_zemli > 10 && tm.Minute < 48 ) {
openValve();
delay(1000); // короткая пауза, чтобы кран успел открыться
digitalWrite(nasos, LOW); // Включаем насос
nasosok = 2;
isPolivRunning = true;
polivStartTime = millis(); // Запоминаем время старта
lastPolivStart = tm;
}
}
// Выключение насоса через 10 минут
if (isPolivRunning && (millis() - polivStartTime >= polivDuration)) {
digitalWrite(nasos, HIGH); // Выключаем насос
closeValve(); // Закрываем кран
nasosok = 3;
isPolivRunning = false;
kolvo++;
}
// Обновление дисплея каждые 3 секунды
if (tm.Second % 3 == 0 && tm.Second != lastDisplayUpdate.Second) {
lastDisplayUpdate = tm;
displayPage = (displayPage + 1) % 4;
lcd.clear();
switch (displayPage) {
case 0: // Основная информация
lcd.setCursor(0, 0);
lcd.print("bochka:");
lcd.print(buttonState);
lcd.setCursor(10, 0);
printTime(tm.Hour, tm.Minute);
lcd.setCursor(0, 1);
lcd.print(zemlya < 260 ? "Vlazhno:" : "Suho:");
lcd.print(zemlya);
break;
case 1: // Показания датчиков
if (sensor.measure()) {
float t = sensor.getTemperature();
float h = sensor.getHumidity();
lcd.setCursor(0, 0);
lcd.print("T:"); lcd.print(t,1); lcd.print("C H:"); lcd.print(h,1); lcd.print("%");
} else {
lcd.print("error_datchik!");
}
lcd.setCursor(0, 1);
lcd.print("Polivov:"); lcd.print(kolvo);
break;
case 2: // Состояние системы
lcd.setCursor(0, 0);
lcd.print("Nasos:");
lcd.print(nasosok == 1 ? "Gotov" : nasosok == 2 ? "Navlivaet" : "Nalito");
lcd.setCursor(0, 1);
lcd.print("Kran: ");
if (valveStatus == VALVE_OPENING) lcd.print("Otkryvayetsya");
else if (valveStatus == VALVE_CLOSING) lcd.print("Zakryvaetsya");
else lcd.print("OK");
break;
case 3: // Счетчики + обратный отсчёт
lcd.setCursor(0, 0);
lcd.print("Temp:"); lcd.print(temper);
lcd.setCursor(0, 1);
lcd.print("Vlazh:"); lcd.print(vlazh);
if (isPolivRunning) {
unsigned long elapsed = millis() - polivStartTime;
int remainingSec = (polivDuration - elapsed) / 1000;
lcd.setCursor(9, 0);
lcd.print("s:");
int minutes = remainingSec / 60;
int seconds = remainingSec % 60;
if (minutes < 10) lcd.print("0");
lcd.print(minutes);
lcd.print(":");
if (seconds < 10) lcd.print("0");
lcd.print(seconds);
} else {
lcd.setCursor(9, 2);
lcd.print("errrr");
}
break;
}
}
}
delay(200);
}
Вот тут еще есть старые коды, походу метеостанцию делал с поливов. не проверял просто сохранил тут. может че полезное
Описание системы
Эта метеостанция с элементами умной теплицы включает:
Мониторинг окружающей среды:
Температура и влажность (HTU21D)
Атмосферное давление (BMP180)
Уровень CO2 (PWM датчик)
Концентрация вредных газов (CO, NH3, NO2) с помощью MICS6814
Уровень формальдегида (ZE08)
Система управления поливом:
Автоматический полив по расписанию (6:00 и 21:00)
Дополнительный ночной полив насосом (1:00)
Защита от полива при высокой влажности или низкой температуре
Управление кранами и насосом через реле
Интерфейс и безопасность:
LCD дисплей для отображения данных
Кнопочное управление
Звуковая сигнализация при обнаружении опасных уровней газов
Логика работы:
Автоматическое управление поливом по времени
Защита растений от перелива
Мониторинг качества воздуха
Визуализация всех параметров на дисплее
Система предназначена для автоматического контроля условий в теплице или оранжерее с возможностью ручного управления через кнопки.
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <LiquidCrystal_I2C.h>
#include "SparkFunHTU21D.h" // Датчик температуры и влажности
#include "SFE_BMP180.h" // Датчик давления
#include <MICS6814.h> // Мультигазовый датчик
#include <SoftwareSerial.h>
// Определение пинов
#define relayDOWN 3 // Реле для опускания (закрытия) крана
#define relayUP 4 // Реле для поднятия (открытия) крана
#define relayNASOS 7 // Реле насоса полива
#define pwmPin 6 // Пин датчика CO2 (PWM)
#define buttonPin A6 // Пин кнопки
#define buzzPin 5 // Пин пищалки
// Датчики газа
#define PIN_CO A2 // Пин датчика CO
#define PIN_NO2 A3 // Пин датчика NO2
#define PIN_NH3 A1 // Пин датчика NH3
// Настройки для формальдегидного датчика
#define MAXLENGTH 9
#define VREF 5.0 // опорное напряжение для аналоговых датчиков
SoftwareSerial mySerial(10, 11); // RX, TX для датчика формальдегида
// Объекты датчиков
HTU21D myHumidity; // Датчик влажности и температуры
SFE_BMP180 pressure; // Датчик давления
MICS6814 gas(PIN_CO, PIN_NO2, PIN_NH3); // Мультигазовый датчик
LiquidCrystal_I2C lcd(0x27,16,2); // LCD дисплей I2C
// Переменные для датчика CO2
int prevVal = LOW;
long th, tl, h, l, ppm;
// Переменные для управления системой
int value = 25;
long prev_gaz = 0;
long prev_upbut = 0;
long prev_poliv = 0;
long prev_buzz = 0;
// Флаги состояний
int trig_up = 0;
int trig_down = 0;
int trig_center = 0;
int poliv = 0;
int button = 0;
int gaz = 0;
int sensorValue = 0;
int prev_pump = 0;
int prevrain = 0;
int rain_triger = 0;
int polivkapel_trig = 0;
int polivnasos_trig = 0;
int val = 0;
int davlenie = 0;
int poliv_val = 0;
int kol_vo = 0;
int fff = 0;
// Тайминги
long nasos_time = 30000;
int KRANdelay = 12000;
unsigned long NASOSdelay = 0;
unsigned long relayUPdelay = 0;
unsigned long relayDOWNdelay = 0;
long KRANtrig = 0;
long NASOStrig = 0;
long pressuredelay = 0;
long poliv_off = 0;
void setup() {
Serial.begin(9600);
mySerial.begin(9600); // Для датчика формальдегида
// Настройка пина датчика CO2
pinMode(pwmPin, INPUT);
// Инициализация LCD
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("kalibrovka");
// Инициализация датчиков
myHumidity.begin();
pressure.begin();
gas.calibrate();
// Настройка пинов
pinMode(buzzPin, OUTPUT);
pinMode(buttonPin, INPUT);
pinMode(relayDOWN, OUTPUT);
pinMode(relayUP, OUTPUT);
pinMode(relayNASOS, OUTPUT);
// Начальные состояния реле
digitalWrite(relayDOWN, HIGH);
digitalWrite(relayUP, HIGH);
digitalWrite(relayNASOS, HIGH);
delay(200);
lcd.clear();
}
void loop() {
// Измерение CO2
measureCO2();
// Измерение формальдегида
ze08_PPM();
// Обработка кнопок
handleButtons();
// Измерение давления
measurePressure();
// Чтение температуры и влажности
int humd = myHumidity.readHumidity();
int temp = myHumidity.readTemperature();
// Управление поливом по времени
controlWateringSystem(temp, humd);
// Чтение показаний газовых датчиков
int COCO = gas.measure(CO);
int NHH = gas.measure(NH3);
int NOO = gas.measure(NO2);
// Отображение данных на LCD
updateDisplay(temp, humd, davlenie, COCO, NHH, NOO, ppm);
// Проверка на опасные уровни газов
checkGasLevels(COCO, NHH, NOO, ppm);
// Управление звуковым сигналом
controlBuzzer();
}
// Функция измерения CO2
void measureCO2() {
long tt = millis();
int myVal = digitalRead(pwmPin);
if (myVal == HIGH) {
if (myVal != prevVal) {
h = tt;
tl = h - l;
prevVal = myVal;
}
} else {
if (myVal != prevVal) {
l = tt;
th = l - h;
prevVal = myVal;
ppm = 5000 * (th - 2) / (th + tl - 4);
fff = ppm;
}
}
// Фильтрация неверных значений CO2
if (!(fff > 1650 && fff < 1680) && fff != 1480 && fff != 2037 &&
!(fff > 1240 && fff < 1250) && fff != 199 && fff != 262 && fff != 970) {
lcd.setCursor(6, 1);
lcd.print(":" + String(ppm) + "*");
}
}
// Функция обработки кнопок
void handleButtons() {
int btnValue = analogRead(buttonPin);
if (btnValue < 700 && btnValue > 500 && millis() - prev_upbut > 2000) {
prev_upbut = millis();
trig_center = (trig_center + 1) % 5; // Циклическое изменение от 0 до 4
}
if (btnValue < 1050 && btnValue > 1000 && millis() - prev_upbut > 2000) {
prev_upbut = millis();
trig_up = (trig_up + 1) % 4; // Циклическое изменение от 0 до 3
}
if (btnValue < 280 && btnValue > 310 && millis() - prev_upbut > 2000) {
prev_upbut = millis();
trig_down = (trig_down + 1) % 4; // Циклическое изменение от 0 до 3
}
}
// Функция измерения давления
void measurePressure() {
char status;
double T, P, p0, a;
status = pressure.startTemperature();
if (status != 0) {
delay(status);
status = pressure.getTemperature(T);
if (status != 0) {
status = pressure.startPressure(3);
if (status != 0) {
delay(status);
status = pressure.getPressure(P, T);
if (status != 0) {
p0 = pressure.sealevel(P, ALTITUDE);
davlenie = P;
}
}
}
}
}
// Функция управления системой полива
void controlWateringSystem(int temp, int humd) {
tmElements_t tm;
if (RTC.read(tm)) {
// Утренний полив (6 часов)
if (tm.Hour == 6 && polivkapel_trig == 0 && poliv_off == 0) {
polivkapel_trig = 1;
digitalWrite(relayUP, LOW); // Открыть кран
relayUPdelay = millis();
}
// Закрытие крана после 12 секунд
if (millis() - relayUPdelay > 12000 && polivkapel_trig == 1) {
digitalWrite(relayUP, HIGH);
polivkapel_trig = 2;
}
// Вечерний полив (21 час)
if (tm.Hour == 21 && polivkapel_trig == 3) {
polivkapel_trig = 4;
digitalWrite(relayDOWN, LOW); // Закрыть кран
relayDOWNdelay = millis();
}
// Завершение закрытия крана
if (millis() - relayDOWNdelay > 12000 && polivkapel_trig == 4) {
digitalWrite(relayDOWN, HIGH);
polivkapel_trig = 5;
}
// Ночной полив насосом (1 час)
if (tm.Hour == 1 && polivnasos_trig == 0) {
polivnasos_trig = 1;
digitalWrite(relayNASOS, LOW); // Включить насос
NASOSdelay = millis();
}
// Выключение насоса через 100 секунд
if (millis() - NASOSdelay > 100000 && polivnasos_trig == 1) {
digitalWrite(relayNASOS, HIGH);
polivnasos_trig = 2;
}
// Сброс триггеров в 3 часа ночи
if (tm.Hour == 3) {
polivnasos_trig = 0;
polivkapel_trig = 0;
}
// Закрытие крана при высокой влажности или низкой температуре
if ((humd > 70 || temp < 15) && polivkapel_trig == 2) {
polivkapel_trig = 3;
}
// Общий сброс при неблагоприятных условиях
if (humd > 70 || temp < 15) {
poliv_off = 1;
} else {
poliv_off = 0;
}
}
}
// Функция обновления дисплея
void updateDisplay(int temp, int humd, int press, int CO, int NH3, int NO2, int co2) {
lcd.setCursor(0, 0);
lcd.print(temp);
lcd.print(":");
lcd.print(humd);
lcd.print(":");
lcd.print(int(press * 0.75)); // Преобразование в мм рт.ст.
lcd.setCursor(0, 1);
lcd.print(CO);
lcd.print(":");
lcd.print(NH3);
lcd.print(":");
lcd.print(NO2);
}
// Функция проверки уровня газов
void checkGasLevels(int CO, int NH3, int NO2, int co2) {
if (CO > 50 || NH3 > 2 || NO2 > 2 || co2 > 2000) {
gaz = 1;
}
// Сброс тревоги через 20 секунд
if (millis() - prev_gaz > 20000 && gaz == 1) {
prev_gaz = millis();
gaz = 0;
}
}
// Функция управления звуковым сигналом
void controlBuzzer() {
if (millis() - prev_buzz > 5000 && gaz == 1) {
prev_buzz = millis();
digitalWrite(buzzPin, HIGH);
delay(200);
digitalWrite(buzzPin, LOW);
}
}
// Функции для работы с датчиком формальдегида
byte checkSum(byte array[], byte length) {
byte sum = 0;
for (int i = 1; i < length - 1; i++) {
sum += array[i];
}
return (~sum) + 1;
}
boolean available1() {
while (mySerial.available()) {
for (byte index = 0; index < MAXLENGTH - 1; index++) {
receivedCommandStack[index] = receivedCommandStack[index + 1];
}
receivedCommandStack[MAXLENGTH - 1] = mySerial.read();
byte sumNum = checkSum(receivedCommandStack, MAXLENGTH);
if ((receivedCommandStack[0] == 0xFF) && (receivedCommandStack[1] == 0x17) &&
(receivedCommandStack[2] == 0x04) && (receivedCommandStack[MAXLENGTH - 1] == sumNum)) {
receivedFlag = 1;
return true;
}
}
return false;
}
float ze08_PPM() {
if (available1()) {
receivedFlag = 0;
float ppb = (unsigned int)(receivedCommandStack[4] * 256) + receivedCommandStack[5];
float ppmf = ppb / 1000;
delay(1000);
lcd.setCursor(9, 0);
lcd.print(":");
lcd.print(ppmf);
return ppmf;
}
return 0;
}
Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.
Комментарии
Пока нет комментариев. Будьте первым!