↩️ Назад

Категории

Упрощаю умный дом на распбери пи - email уведомлений через Cron + MySQL

06.05.2026 | Статья из категории: IOT умный дом

🤔 Вступление. Как я запарился и забил на "модные" интерфейсы

Написал я веб-интерфейс для правил автоматизации. С вечным циклом PHP, MQTT-подписками, подтверждениями, задержками, AJAX-панелями, цветными кнопочками... Красиво, модно, молодёжно.

И всё это ради того, чтобы один раз в полчаса проверить, не засох ли можжевельник. Ну и чтобы при движении письмо приходило, когда никого дома нет.

А по факту: никто эти интерфейсы не открывает. Комментариев никто не пишет, логи никто не смотрит. Зачем тогда всё это?

Правильное решение оказалось проще: всё, что нужно, уже лежит в базе данных — таблица sensor_data хранит историю всех датчиков. Осталось только настроить пару скриптов и добавить их в крон.

✅ Почему Cron + MySQL — это круто

📝 Подготовка. Таблица для истории отправок

CREATE TABLE IF NOT EXISTS email_history (
    id INT AUTO_INCREMENT PRIMARY KEY,
    rule_name VARCHAR(100),
    trigger_value VARCHAR(50),
    sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY unique_daily (rule_name, DATE(sent_at))
);

1️⃣ Скрипт для датчика движения (проверка раз в 30 минут)

Файл: /var/www/html/cron_motion_email.php

<?php
$pdo = new PDO("mysql:host=127.0.0.1;dbname=iot_db;charset=utf8mb4", "user", "123456");

$motionTopic = 'zigbee2mqtt/motion_sensor/presence';
$emailTo = '9447333@gmail.com';
$checkMinutes = 30;

// Было ли движение за последние 30 минут
$stmt = $pdo->prepare("
    SELECT COUNT(*) as cnt FROM sensor_data 
    WHERE topic = ? AND value = '1'
    AND timestamp > DATE_SUB(NOW(), INTERVAL ? MINUTE)
");
$stmt->execute([$motionTopic, $checkMinutes]);
$motion = $stmt->fetch();

// Проверяем, не отправляли ли уже сегодня
$stmt = $pdo->prepare("
    SELECT COUNT(*) as sent FROM email_history 
    WHERE rule_name = 'motion' AND DATE(sent_at) = CURDATE()
");
$stmt->execute();
$sent = $stmt->fetch();

if ($motion['cnt'] > 0 && $sent['sent'] == 0) {
    $subject = "📡 Обнаружено движение";
    $message = "За последние $checkMinutes минут было {$motion['cnt']} срабатываний\n";
    $message .= "Время: " . date('Y-m-d H:i:s');
    mail($emailTo, $subject, $message, "From: it@logoakademia.ru\r\n");
    
    $pdo->prepare("INSERT INTO email_history (rule_name) VALUES ('motion')")->execute();
    echo date('Y-m-d H:i:s') . " - Email о движении отправлен\n";
}

2️⃣ Скрипт для можжевельника (влажность почвы, раз в час)

Файл: /var/www/html/cron_water_email.php

<?php
$pdo = new PDO("mysql:host=127.0.0.1;dbname=iot_db;charset=utf8mb4", "user", "123456");

$moistureTopic = 'sensors/soil_moisture';
$emailTo = '9447333@gmail.com';
$dryThreshold = 30;

// Последнее значение влажности
$stmt = $pdo->prepare("
    SELECT value, timestamp FROM sensor_data 
    WHERE topic = ? ORDER BY timestamp DESC LIMIT 1
");
$stmt->execute([$moistureTopic]);
$sensor = $stmt->fetch();

if (!$sensor) exit("Нет данных\n");

// Проверяем, не отправляли ли сегодня
$stmt = $pdo->prepare("
    SELECT COUNT(*) as sent FROM email_history 
    WHERE rule_name = 'watering' AND DATE(sent_at) = CURDATE()
");
$stmt->execute();
$sent = $stmt->fetch();

if ($sensor['value'] < $dryThreshold && $sent['sent'] == 0) {
    $subject = "💧 Нужно полить можжевельник!";
    $message = "Влажность почвы: {$sensor['value']}%\n";
    $message .= "Время замера: {$sensor['timestamp']}\n";
    $message .= "Порог: ниже $dryThreshold%";
    
    mail($emailTo, $subject, $message, "From: it@logoakademia.ru\r\n");
    
    $pdo->prepare("INSERT INTO email_history (rule_name, trigger_value) VALUES ('watering', {$sensor['value']})")->execute();
    echo date('Y-m-d H:i:s') . " - Письмо о поливе отправлено\n";
}

3️⃣ Добавляем в Cron

# Редактируем crontab
sudo crontab -e

# Добавляем строки:
*/30 * * * * /usr/bin/php /var/www/html/cron_motion_email.php >> /var/log/motion.log 2>&1
0 * * * * /usr/bin/php /var/www/html/cron_water_email.php >> /var/log/water.log 2>&1

⏱️ А что насчёт точности крона?

Крон — не для секунд. Минимальный интервал — 1 минута.

ИнтервалТочностьНагрузкаДля каких задач
1 минута± несколько секундНизкаяДвижение, протечка, дым
5 минут± 5-10 секОчень низкаяТемпература, влажность
30 минут± 30 секМинимальнаяПолив, уведомления раз в полчаса
1 час± 1 минутаНичтожнаяДневная статистика, отчёты

Нагрузка: один PHP-скрипт с простым SELECT-запросом выполняется за 0.01-0.05 секунды. Даже 10 таких скриптов в минуту — это 0.5 секунды работы в минуту, или 0.8% нагрузки на одно ядро. Для Raspberry Pi — вообще копейки.

🎯 Дополнительные идеи для скриптов

📌 Итог. Мои мысли

Не усложняйте там, где можно просто. Интерфейсы и свистоперделки — это круто для портфолио. Но для себя, для дома, для души — лучше надёжные скрипты в кроне, которые работают годами без присмотра.

Все данные уже есть в базе. Не нужно городить вечные циклы, подписываться на MQTT, обрабатывать подтверждения. Просто берём sensor_data, проверяем историю, отправляем письмо, запоминаем в email_history.

🌱 Можжевельник скажет спасибо. А комментарии — ну их.


P.S. Если что-то пойдёт не так — логи всегда под рукой: /var/log/motion.log и /var/log/water.log




Категории:

Категории

Комментарии

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

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

← Назад к списку статей

Посетителей сегодня: 0
о блоге | карта блога | 📡 Подписаться на RSS

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