Категории

Умная буржуйка 2.0 — отопление, безопасность, автоматика

2025-09-08 22:00:46 | 2040
Умная буржуйка на php, zigbee, mqtt

В 2040 году искусственный интеллект управляет транспортом, климатом и даже выборами. Но настоящие инженеры знают: самое важное — это печка. А если печка умная — ты уже на шаг впереди цивилизации.

Эта статья — о том, как превратить обычную буржуйку в IoT-систему уровня NASA, используя только PHP, MySQL, Zigbee2MQTT, Telegram и сервопривод. Без Home Assistant автоматизаций. Без YAML. Без облаков. Только чистый код, железо, дрова — и немного логики.

А ещё — это система безопасности и автоматического управления. Потому что если печка внезапно потухла — это не всегда «пора подкинуть дров». А если она перегрелась — это уже пожарная опасность. И система должна не только оповестить — но и сама вмешаться.

Что делает эта система?

Архитектура системы

[Датчик температуры Zigbee (Aqara)] → данные → [Zigbee2MQTT → MySQL]
                                                          ↓
                                                 [PHP-скрипт по крону]
                                                          ↓
           ┌──────────────────────────┬────────────────────┴────────────────────┬──────────────────────────┐
           ↓                          ↓                                         ↓                          ↓
[Telegram: "Подкинь дров"]  [Telegram: "Тревога: потухла"]       [Telegram: "ПЕРЕГРЕВ!"]       [MQTT: команда сервоприводу]
           ↓                          ↓                                         ↓                          ↓
      [Ты несёшь дрова]        [Ты проверяешь дымоход]               [Ты бежишь к печке]        [Серва закрывает поддувало]

Шаг 1: Датчик — не на печке, а рядом

Используем Aqara Temperature & Humidity Sensor — он дешёв, надёжен, Zigbee. Но его пластик плавится при 80°C. Поэтому:

Датчик не измеряет температуру печки — он измеряет воздух рядом с печкой. Но этого достаточно, чтобы понять: горит она или нет, перегревается или тухнет.

Шаг 2: Устройство управления — сервопривод на поддувале

Для автоматического управления нужен сервопривод, подключённый к микроконтроллеру (например, ESP32), который работает как Zigbee-устройство.

Пример устройства:

Устройство публикует и принимает команды в MQTT-топике, например:

zigbee2mqtt/servo_damper/set → {"state": "CLOSE"}
zigbee2mqtt/servo_damper → {"state": "OPEN", "position": 90}

При команде CLOSE — серва поворачивается и закрывает поддувало. При OPEN — открывает.

Шаг 3: Логика состояний — 5 режимов работы

Состояние Условие Действие
🔥 Активный нагрев Температура > 70°C Запоминаем максимум — ничего не шлём
🪵 Пора подкинуть дров Температура < 50% от максимума И > 25°C Отправить: «Температура упала до X°C — пора подкинуть дров!»
🚨 Тревога: неожиданное затухание Температура ≤ 25°C И был максимум > 60°C Отправить: «ТРЕВОГА: печка резко потухла — проверьте дымоход!»
⚠️ Предупреждение: перегрев Температура > 90°C Отправить: «Внимание! Температура высокая — X°C. Контролируйте горение.»
🔴 Авария: критический перегрев Температура > 100°C Отправить: «ОПАСНОСТЬ! Температура X°C! Закрываю поддувало!» + отправить MQTT команду на закрытие сервопривода

Шаг 4: База данных — MySQL

-- Данные с датчиков
CREATE TABLE `sensor_data` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `sensor_id` VARCHAR(50),
  `temperature` FLOAT,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Лог уведомлений (чтобы не спамить)
CREATE TABLE `notifications_log` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `type` VARCHAR(50),          -- 'wood', 'alert', 'overheat_warning', 'overheat_emergency'
  `message` TEXT,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Опционально: хранение последнего состояния сервопривода
CREATE TABLE `system_state` (
  `key` VARCHAR(50) PRIMARY KEY,
  `value` TEXT
);

Шаг 5: PHP-скрипт — мозг системы (burzhuika_check.php)

connect_error) {
    die("Ошибка подключения к БД: " . $mysqli->connect_error);
}

// 1. Получить последнюю температуру
$stmt = $mysqli->prepare("
    SELECT temperature FROM sensor_data 
    WHERE sensor_id = ? 
    ORDER BY created_at DESC LIMIT 1
");
$stmt->bind_param("s", $sensor_name);
$stmt->execute();
$result = $stmt->get_result();
$current_temp = $result->fetch_assoc()['temperature'] ?? null;

if ($current_temp === null) {
    die("Нет данных от датчика.\n");
}

// 2. Получить максимальную температуру за последние 12 часов
$stmt = $mysqli->prepare("
    SELECT MAX(temperature) as max_temp FROM sensor_data 
    WHERE sensor_id = ? 
    AND created_at > NOW() - INTERVAL 12 HOUR
");
$stmt->bind_param("s", $sensor_name);
$stmt->execute();
$result = $stmt->get_result();
$max_temp = $result->fetch_assoc()['max_temp'] ?? 20;

// 3. Если максимум слишком низкий — выходим (ещё не топили)
if ($max_temp < 40) {
    echo "Максимум слишком низкий ($max_temp°C) — игнорируем.\n";
    exit;
}

// 4. Рассчитываем порог "пора дров"
$threshold_wood = $max_temp * ($min_percent_threshold / 100);

// 5. Проверяем состояние — в порядке приоритета (сначала авария!)

// СЛУЧАЙ 1: Аварийный перегрев (>100°C)
if ($current_temp > $overheat_emergency) {
    if (!notificationSentRecently($mysqli, 'overheat_emergency', 0.5)) { // каждые 30 минут
        $message = "🔴 ОПАСНОСТЬ! Температура: " . round($current_temp, 1) . "°C! Закрываю поддувало!";
        sendTelegram($telegram_bot_token, $telegram_chat_id, $message);
        logNotification($mysqli, 'overheat_emergency', $message);
        sendMQTTCommand($mqtt_host, $mqtt_port, $servo_device_topic, '{"state": "CLOSE"}');
        echo "АВАРИЯ: $message + команда CLOSE отправлена\n";
    } else {
        echo "Авария уже отправлялась — пропускаем.\n";
    }
}

// СЛУЧАЙ 2: Предупреждение о перегреве (>90°C)
else if ($current_temp > $overheat_warning) {
    if (!notificationSentRecently($mysqli, 'overheat_warning', 1)) {
        $message = "⚠️ Внимание! Температура высокая: " . round($current_temp, 1) . "°C. Контролируйте горение.";
        sendTelegram($telegram_bot_token, $telegram_chat_id, $message);
        logNotification($mysqli, 'overheat_warning', $message);
        echo "Предупреждение: $message\n";
    } else {
        echo "Предупреждение уже отправлялось — пропускаем.\n";
    }
}

// СЛУЧАЙ 3: Пора подкинуть дров
else if ($current_temp < $threshold_wood && $current_temp > $threshold_cold) {
    if (!notificationSentRecently($mysqli, 'wood', $cooldown_hours)) {
        $message = "🪵 Температура упала до " . round($current_temp, 1) . "°C (порог: " . round($threshold_wood, 1) . "°C). Пора подкинуть дров!";
        sendTelegram($telegram_bot_token, $telegram_chat_id, $message);
        logNotification($mysqli, 'wood', $message);
        echo "Отправлено: $message\n";
    } else {
        echo "Уведомление 'дров' уже отправлялось — пропускаем.\n";
    }
}

// СЛУЧАЙ 4: Тревога — печка резко потухла
else if ($current_temp <= $threshold_cold && $max_temp >= $min_max_for_alert) {
    if (!notificationSentRecently($mysqli, 'alert', 1)) {
        $message = "🚨 ТРЕВОГА: печка резко потухла! Температура: " . round($current_temp, 1) . "°C. Максимум был: " . round($max_temp, 1) . "°C. Проверьте дымоход и тягу!";
        sendTelegram($telegram_bot_token, $telegram_chat_id, $message);
        logNotification($mysqli, 'alert', $message);
        echo "Отправлено: $message\n";
    } else {
        echo "Тревога уже отправлялась — пропускаем.\n";
    }
}

// СЛУЧАЙ 5: Всё в норме
else {
    echo "Температура в норме: " . round($current_temp, 1) . "°C\n";
}

$mysqli->close();

// ============ ФУНКЦИИ ============

function notificationSentRecently($mysqli, $type, $hours) {
    $stmt = $mysqli->prepare("
        SELECT COUNT(*) as cnt FROM notifications_log 
        WHERE type = ? AND created_at > NOW() - INTERVAL ? HOUR
    ");
    $stmt->bind_param("si", $type, $hours);
    $stmt->execute();
    return $stmt->get_result()->fetch_assoc()['cnt'] > 0;
}

function sendTelegram($token, $chat_id, $message) {
    $url = "https://api.telegram.org/bot$token/sendMessage?chat_id=$chat_id&text=" . urlencode($message);
    file_get_contents($url);
}

function logNotification($mysqli, $type, $message) {
    $stmt = $mysqli->prepare("INSERT INTO notifications_log (type, message) VALUES (?, ?)");
    $stmt->bind_param("ss", $type, $message);
    $stmt->execute();
}

function sendMQTTCommand($host, $port, $topic, $payload) {
    // Простая отправка через shell + mosquitto_pub (установи mosquitto-clients)
    $cmd = "mosquitto_pub -h $host -p $port -t '$topic' -m '$payload' 2>&1";
    exec($cmd, $output, $return_var);
    if ($return_var !== 0) {
        error_log("MQTT Error: " . implode("\n", $output));
    }
}

?>

Шаг 6: Крон — запуск каждые 2 минуты

*/2 * * * * /usr/bin/php /var/www/burzhuika/burzhuika_check.php >> /var/log/burzhuika.log 2>&1

Шаг 7: Веб-интерфейс статуса (status.php)

prepare("SELECT temperature FROM sensor_data WHERE sensor_id = ? ORDER BY created_at DESC LIMIT 1");
$stmt->bind_param("s", $sensor_name);
$stmt->execute();
$current_temp = $stmt->get_result()->fetch_assoc()['temperature'] ?? 'Нет данных';

$stmt = $mysqli->prepare("SELECT MAX(temperature) as max_temp FROM sensor_data WHERE sensor_id = ? AND created_at > NOW() - INTERVAL 12 HOUR");
$stmt->bind_param("s", $sensor_name);
$stmt->execute();
$max_temp = $stmt->get_result()->fetch_assoc()['max_temp'] ?? 20;
?>



Статус буржуйки

🔥 Умная буржуйка 2.0 — статус

Текущая температура: °C

Максимум за 12 ч: °C

Порог "дров": °C

Состояние: 100) echo "🔴 АВАРИЯ: перегрев!"; else if ($current_temp > 90) echo "⚠️ Предупреждение: перегрев"; else if ($current_temp >= 70) echo "🔥 Активный нагрев"; else if ($current_temp < ($max_temp * 0.5) && $current_temp > 25) echo "🪵 Пора подкинуть дров"; else if ($current_temp <= 25 && $max_temp >= 60) echo "🚨 ТРЕВОГА: проверьте дымоход!"; else echo "💤 Всё в норме"; ?>

Заключение

Ты сделал не просто «умную печку» — ты создал гибридную систему отопления, безопасности и автоматики, которая:

Это не «умный дом». Это — умный выживальщик с функцией автопилота.

🪵 Подкинь дров. 🚨 Проверь дымоход. 🔥 Закрой поддувало. 💡 Ты — инженер будущего.

Комментарии

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

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

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

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

Внимание: Cтатьи здесь сгенерированны через нейросеть, не правил ошибки, да и не до этого пока. Блог только запустил. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
НО!
Каждый кейс я делал минимум один раз. Сервера стоят, клиенты довольны, дата-центры не горят.

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

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


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