Категории

Умный уровень воды в бочке для капельного полива

14.10.2025 15:29 | коды из категории: IOT умный дом

У меня на участке стоит большая бочка (куб) с дождевой водой — она питает систему капельного полива через клапан Sonoff SWV. Клапан управляется по Zigbee, работает по расписанию, и всё бы хорошо, но… иногда вода в бочке заканчивается, а полив продолжается. Хотя Sonoff SWV и имеет защиту от сухого хода (до 8 бар, 0.7 МПа), он всё равно — просто клапан: открыл/закрыл. Он не знает, есть ли вода в бочке или нет.

Решил сделать «умный» датчик уровня, который будет:

Цель простая: автоматически отключать полив, если воды мало.

Почему не готовый Zigbee-датчик?

Конечно, сейчас можно купить «умный» ультразвуковой датчик уровня воды с поддержкой Zigbee или Wi-Fi. Например, такие продаются за ~2966 ₽. Но у них есть проблемы:

А у меня уже валялся JSN-SR04T — водонепроницаемый, дешёвый, точный. И ESP-01 — тоже с полки. Решил собрать всё сам. Вышло дешевле, гибче и энергоэффективнее.

Выбор компонентов

Сначала думал использовать ESP32, но он «жирный» для такой простой задачи. В итоге остановился на ESP-01 — дешёвый, маленький, Wi-Fi есть, а больше ничего и не нужно.

Для измерения уровня — водонепроницаемый ультразвуковой датчик JSN-SR04T. Он работает в диапазоне до 5 метров, не боится влаги и конденсата, и отлично подходит для установки сверху в бочку.

Питание — от аккумулятора 18650. Чтобы не сажать батарейку за неделю, добавил таймер TPL5110. Он полностью отключает питание ESP-01 между измерениями. Потребление в простое — десятки наноампер!

Измерение происходит раз в час: ESP-01 просыпается, делает замер, отправляет данные по HTTP или MQTT на Raspberry Pi, подаёт сигнал «DONE» — и TPL5110 снова обесточивает всю схему.

Как это работает

  1. Бочка — кубическая, высотой 100 см. Датчик JSN-SR04T вкручен в крышку сверху, направлен строго вниз.
  2. При старте ESP-01 включает питание датчика (через GPIO + MOSFET), ждёт 50 мс, делает 3 замера, берёт медиану.
  3. Вычисляет уровень: уровень = высота_бочки - расстояние_до_поверхности.
  4. Отправляет данные одним из двух способов:
    • Вариант 1: HTTP POST на PHP-скрипт → запись в MySQL.
    • Вариант 2: Публикация в MQTT-топик → обработка на Raspberry Pi.
  5. WayGuard (мой умный дом) раз в 5 минут опрашивает MySQL или подписывается на MQTT и, если уровень < 15 см — отключает сценарий полива.

Энергопотребление

Благодаря TPL5110, ESP-01 и датчик питаются только ~4–5 секунд в час. Остальное время — полное отключение.

Расчётный срок работы от одного 18650 (3000 мА·ч): более года. На практике — 8–12 месяцев (с учётом зимы, саморазряда и т.п.).

Код для ESP-01

Прошивка написана в Arduino IDE с использованием ESP8266 Core. Ниже — два варианта отправки данных.

Вариант 1: Отправка в MySQL через HTTP (PHP на Raspberry Pi)

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

#define TRIG_PIN 0   // GPIO0 (TX на ESP-01)
#define ECHO_PIN 2   // GPIO2 (RX на ESP-01)
#define DONE_PIN 3   // GPIO3 (если используется, иначе закомментируй)

const char* ssid = "MyWiFi";
const char* password = "password123";

const char* serverURL = "http://192.168.1.100/water-level.php"; // IP Raspberry Pi
const float TANK_HEIGHT = 100.0; // см

void setup() {
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(DONE_PIN, OUTPUT);
  digitalWrite(DONE_PIN, LOW);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(100);

  float level = measureWaterLevel();
  if (level >= 0) {
    sendToMySQL(level);
  }

  // Подтверждение завершения работы для TPL5110
  digitalWrite(DONE_PIN, HIGH);
  delay(100);
}

void loop() {
  // Ничего не делаем — уйдём в выключенный режим через TPL5110
}

float getDistance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  long duration = pulseIn(ECHO_PIN, HIGH, 30000);
  if (duration == 0) return -1;
  return duration * 0.034 / 2;
}

float measureWaterLevel() {
  float distances[3];
  for (int i = 0; i < 3; i++) {
    distances[i] = getDistance();
    delay(50);
  }
  // Простая медиана
  if (distances[0] > distances[1]) swap(distances[0], distances[1]);
  if (distances[1] > distances[2]) swap(distances[1], distances[2]);
  if (distances[0] > distances[1]) swap(distances[0], distances[1]);

  if (distances[1] < 20 || distances[1] > TANK_HEIGHT + 20) return -1;
  return TANK_HEIGHT - distances[1];
}

void sendToMySQL(float level) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin(serverURL);
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    String payload = "device=barrel_1&level=" + String(level);
    int httpResponseCode = http.POST(payload);
    http.end();
  }
}

Вариант 2: Отправка по MQTT

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define TRIG_PIN 0
#define ECHO_PIN 2
#define DONE_PIN 3

const char* ssid = "MyWiFi";
const char* password = "password123";
const char* mqtt_server = "192.168.1.100"; // IP Raspberry Pi с Mosquitto
const int mqtt_port = 1883;

WiFiClient espClient;
PubSubClient client(espClient);

const float TANK_HEIGHT = 100.0;

void setup() {
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(DONE_PIN, OUTPUT);
  digitalWrite(DONE_PIN, LOW);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) delay(100);

  client.setServer(mqtt_server, mqtt_port);
  while (!client.connected()) {
    client.connect("water_sensor_barrel");
    delay(500);
  }

  float level = measureWaterLevel();
  if (level >= 0) {
    String msg = String(level);
    client.publish("sensors/water/barrel_1", msg.c_str());
  }

  digitalWrite(DONE_PIN, HIGH);
  delay(100);
}

void loop() {
  // Ничего
}

// Функции measureWaterLevel() и getDistance() — такие же, как в варианте 1
// (скопируй их сюда)

Серверная часть (Raspberry Pi)

WayGuard подключается к той же MySQL или подписывается на MQTT — и принимает решение: включать полив или нет.

Что дальше?

Пока минимальная версия работает. В планах:

Но даже сейчас система спасает мой сад от «сухого полива» — и я спокоен, уезжая на неделю.

Вывод

Простой, дешёвый и энергоэффективный IoT-датчик уровня воды — это реально. ESP-01 + JSN-SR04T + TPL5110 + Raspberry Pi — отличный тандем для автономных задач на даче. Главное — не перестраховываться: не нужен ESP32, если хватает ESP-01. Иногда «меньше — лучше».

Простой и безопасный (насколько возможно для локального IoT) PHP-скрипт water-level.php, который принимает данные от ESP-01 и сохраняет их в MySQL.
📁 Требования на Raspberry Pi:


🔧 1. Создай базу и таблицу в MySQL
Подключись к MySQL (например, через mysql -u root -p) и выполни:

CREATE DATABASE iot_sensors;
USE iot_sensors;

CREATE TABLE water_levels (
    id INT AUTO_INCREMENT PRIMARY KEY,
    device VARCHAR(50) NOT NULL,
    level_cm FLOAT NOT NULL,
    recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

📄 2. Файл water-level.php (положи в /var/www/html/)

<?php
// water-level.php — приём данных с датчика уровня воды

// Настройки БД
$host = 'localhost';
$db   = 'iot_sensors';
$user = 'iot_user';      // лучше не root!
$pass = 'strong_password';
$charset = 'utf8mb4';

// Проверка метода
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    die('Method Not Allowed');
}

// Обязательные параметры
$device = $_POST['device'] ?? null;
$level  = $_POST['level']  ?? null;

if (!$device || !is_numeric($level)) {
    http_response_code(400);
    die('Bad Request: missing or invalid data');
}

// Очистка входных данных
$device = substr(trim($device), 0, 50); // макс. 50 символов
$level = floatval($level);

// Защита: уровень не может быть отрицательным или больше 200 см
if ($level < 0 || $level > 200) {
    http_response_code(400);
    die('Invalid level value');
}

// Подключение к БД
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false,
];

try {
    $pdo = new PDO($dsn, $user, $pass, $options);

    $stmt = $pdo->prepare("INSERT INTO water_levels (device, level_cm) VALUES (?, ?)");
    $stmt->execute([$device, $level]);

    // Успех
    http_response_code(200);
    echo "OK: Level saved for $device = $level cm";

} catch (PDOException $e) {
    error_log("DB Error: " . $e->getMessage());
    http_response_code(500);
    die('Internal Server Error');
}
?>

🔐 3. (Опционально) Создай отдельного пользователя в MySQL
Не используй root! Выполни в MySQL:


CREATE USER 'iot_user'@'localhost' IDENTIFIED BY 'strong_password';
GRANT INSERT ON iot_sensors.water_levels TO 'iot_user'@'localhost';
FLUSH PRIVILEGES;
🧪 4. Проверка работы
С терминала Raspberry Pi или другого компьютера в сети:

curl -X POST http://192.168.1.100/water-level.php \
  -d "device=test_barrel&level=85.3"

Теги: #MySQL #IoT #полив #дача #умный_дом #wifi #tpl5110 #энергосбережение #18650 #уровень_воды #esp01 #jsn_sr04t #бочка #wayguard #сон #ультразвук #датчик_уровня

Комментарии

Пока нет комментариев. Будьте первым!

Оставить комментарий

← Назад к списку

Важно: Блог-эксперимент

Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.

Посетителей сегодня: 0


Кто я | Контакты и регион

© Digital Specialist | Не являемся сотрудниками Google, Яндекса и NASA