В 2040 году искусственный интеллект управляет транспортом, климатом и даже выборами. Но настоящие инженеры знают: самое важное — это печка. А если печка умная — ты уже на шаг впереди цивилизации.
Эта статья — о том, как превратить обычную буржуйку в IoT-систему уровня NASA, используя только PHP, MySQL, Zigbee2MQTT, Telegram и сервопривод. Без Home Assistant автоматизаций. Без YAML. Без облаков. Только чистый код, железо, дрова — и немного логики.
А ещё — это система безопасности и автоматического управления. Потому что если печка внезапно потухла — это не всегда «пора подкинуть дров». А если она перегрелась — это уже пожарная опасность. И система должна не только оповестить — но и сама вмешаться.
[Датчик температуры Zigbee (Aqara)] → данные → [Zigbee2MQTT → MySQL]
↓
[PHP-скрипт по крону]
↓
┌──────────────────────────┬────────────────────┴────────────────────┬──────────────────────────┐
↓ ↓ ↓ ↓
[Telegram: "Подкинь дров"] [Telegram: "Тревога: потухла"] [Telegram: "ПЕРЕГРЕВ!"] [MQTT: команда сервоприводу]
↓ ↓ ↓ ↓
[Ты несёшь дрова] [Ты проверяешь дымоход] [Ты бежишь к печке] [Серва закрывает поддувало]
Используем Aqara Temperature & Humidity Sensor — он дешёв, надёжен, Zigbee. Но его пластик плавится при 80°C. Поэтому:
Датчик не измеряет температуру печки — он измеряет воздух рядом с печкой. Но этого достаточно, чтобы понять: горит она или нет, перегревается или тухнет.
Для автоматического управления нужен сервопривод, подключённый к микроконтроллеру (например, ESP32), который работает как Zigbee-устройство.
Пример устройства:
cover или switchУстройство публикует и принимает команды в MQTT-топике, например:
zigbee2mqtt/servo_damper/set → {"state": "CLOSE"}
zigbee2mqtt/servo_damper → {"state": "OPEN", "position": 90}
При команде CLOSE — серва поворачивается и закрывает поддувало. При OPEN — открывает.
| Состояние | Условие | Действие |
|---|---|---|
| 🔥 Активный нагрев | Температура > 70°C | Запоминаем максимум — ничего не шлём |
| 🪵 Пора подкинуть дров | Температура < 50% от максимума И > 25°C | Отправить: «Температура упала до X°C — пора подкинуть дров!» |
| 🚨 Тревога: неожиданное затухание | Температура ≤ 25°C И был максимум > 60°C | Отправить: «ТРЕВОГА: печка резко потухла — проверьте дымоход!» |
| ⚠️ Предупреждение: перегрев | Температура > 90°C | Отправить: «Внимание! Температура высокая — X°C. Контролируйте горение.» |
| 🔴 Авария: критический перегрев | Температура > 100°C | Отправить: «ОПАСНОСТЬ! Температура X°C! Закрываю поддувало!» + отправить MQTT команду на закрытие сервопривода |
-- Данные с датчиков 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 );
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));
}
}
?>
*/2 * * * * /usr/bin/php /var/www/burzhuika/burzhuika_check.php >> /var/log/burzhuika.log 2>&1
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 "💤 Всё в норме";
?>
Ты сделал не просто «умную печку» — ты создал гибридную систему отопления, безопасности и автоматики, которая:
Это не «умный дом». Это — умный выживальщик с функцией автопилота.
🪵 Подкинь дров. 🚨 Проверь дымоход. 🔥 Закрой поддувало. 💡 Ты — инженер будущего.
Блог только запустил, все статьи генерирую через нейросеть т.к. лень, возможны ошибки. Просто чтобы вы знали и не запускали ядерный реактор по моим статьям ))
Если у вас есть вопросы, или Нашли неточность? пишите в коментах — вместе поправим и сделаем статью более качественной. Я лично объясню нюансы из практики.
Комментарии
Пока нет комментариев. Будьте первым!