В моей кладовке стоит шкафчик с роутером, коммутатором и NAS — домовая серверная размером с тумбочку. Июльская волна жары закончилась тем, что NAS сам отключил диски: SMART показал пятьдесят один градус на пластине при потолке около сорока пяти. Железо молчало до последнего и спаслось собственной страховкой, а я в этот момент сидел в той же квартире в трёх метрах и ничего не знал. Вывод после того июля: датчик в шкафу без сигнала — это дневник, а не охрана; смотреть Serial раз в час никто не будет, сигнал должен приходить сам и по нарастающей.
По нарастающей — потому что сирена на первом же превышении приучает к звуку быстрее, чем хочется признать. Порог тревоги сразу на сорока градусах означает, что весь летний сезон вы будете жить с включённым звуком на каждый тёплый день, и однажды не отличите его от настоящего пожара. Отсюда три ступени с разными голосами: сначала что-то деликатное, потом громкое, потом силовое.
В этом уроке соберём полный контур: DHT22 на пине 2, светодиод статуса на пине 12, зуммер на пине 8, кнопка сброса на пине 3, реле на пине 7 — и логику, в которой каждая ступень включается по своему порогу, гасится по своему условию и пишет в Serial строку с millis-меткой. Отдельно разберём кнопку: без неё тревога орёт без тишины, с наивной кнопкой — тревогу глушат насовсем, и обе крайности хуже третьей ступени.
Три ступени вместо одной сирены
Ступень первая, предупреждение: температура выше 38 °C. Светодиод статуса перестаёт дышать и начинает мигать с частотой два герца, в лог идёт строка WARN. Звука нет — в шкафчике, который стоит в жилой квартире, постоянное жужжание на плюс-минус два градуса выше нормы наказывает слух за пустяк. Предупреждение должно быть заметным вблизи и незаметным из другой комнаты: подошёл, взглянул, понял, что летом надо бы приоткрыть дверцу.
Ступень вторая, тревога: выше 40 °C. Зуммер на tone(8, 2000) — двухкилогерцовая нота, которую слышно из коридора через закрытую дверь. Кнопка на пине 3 глушит звук, но не диагноз: если температура всё ещё за сорока, через тридцать секунд зуммер включится снова. Так кнопка работает как «я услышал, я занимаюсь», а не как «замолчи навсегда» — это флаг ack и вся разница между тревогой и шумом. Сброс происходит и сам, когда воздух остыл ниже 39,5: гистерезис в полградуса на каждой ступени, потому что шум DHT22 в две-четыре десятых иначе заставит порог дребезжать.
Ступень третья, силовая: выше 45 °C — потолок, на котором диски уже деградируют, а блоки питания уходят в защиту. Реле обесточивает розетку шкафа. Это линия последняя и страшная: вместе с питанием пропадают и данные, поэтому её условие должно быть не «мне не нравится температура», а «дальше железо погибает само». Пока зуммер орёт, у вас есть минуты доехать до кладовки и выключить руками; реле — на случай, когда вас нет неделями.
Скетч: флаг ack, метки времени и честная ступень ШИМ
#include <DHT.h> DHT dht(2, DHT22); const int PIN_LED = 12; // на живой Uno ШИМ тут нет — см. заметку нижеconst int PIN_BUZZER = 8;const int PIN_BTN = 3; // кнопка на GND, INPUT_PULLUPconst int PIN_RELAY = 7; const float T_WARN = 38.0;const float T_ALARM = 40.0;const float T_CUT = 45.0;const float T_HYST = 0.5; bool warn = false;bool alarm = false;bool cut = false;bool acked = false; // «тревогу услышали»unsigned long lastPoll = 0;unsigned long lastRepeat = 0; // повтор тревоги после ackunsigned long lastBlink = 0;unsigned long lastBeat = 0;int beat = 0; void setup() { Serial.begin(9600); pinMode(PIN_LED, OUTPUT); pinMode(PIN_BUZZER, OUTPUT); pinMode(PIN_BTN, INPUT_PULLUP); pinMode(PIN_RELAY, OUTPUT); digitalWrite(PIN_RELAY, HIGH); // реле-модуль активен LOW: питание включено dht.begin();} void logEvent(const char *what) { Serial.print(millis() / 1000); Serial.print(" s: "); Serial.print(what); Serial.print(" t="); Serial.println(dht.readTemperature(), 1);} void loop() { if (millis() - lastPoll < 2000) return; lastPoll = millis(); float t = dht.readTemperature(); if (isnan(t)) { logEvent("SENSOR chtenie sorvalos"); return; // сбой чтения — не тревога } // Ступени с гистерезисом if (!warn && t > T_WARN + T_HYST) { warn = true; logEvent("WARN"); } if (warn && t < T_WARN - T_HYST) { warn = false; logEvent("WARN off"); } if (!alarm && t > T_ALARM + T_HYST) { alarm = true; acked = false; lastRepeat = millis(); logEvent("ALARM"); } if (alarm && t < T_ALARM - T_HYST) { alarm = false; acked = false; noTone(PIN_BUZZER); logEvent("ALARM off"); } if (!cut && t > T_CUT) { cut = true; digitalWrite(PIN_RELAY, LOW); logEvent("CUT rele obestochilo shkaf"); } // Кнопка сброса: глушит зуммер на 30 секунд, не навсегда if (digitalRead(PIN_BTN) == LOW && alarm && !acked) { acked = true; lastRepeat = millis(); noTone(PIN_BUZZER); logEvent("ACK zvuk sbroshen knopkoi"); delay(150); // пауза от дребезга } if (alarm && acked && millis() - lastRepeat > 30000UL) { acked = false; // жарко по-прежнему — тревога возвращается logEvent("ALARM povtor posle ack"); } // Зуммер: звучит только при непогашенной тревоге if (alarm && !acked && !cut) tone(PIN_BUZZER, 2000); // Светодиод: дыхание ШИМ в норме, мигание 2 Гц при предупреждении, ровно при тревоге if (alarm || cut) { analogWrite(PIN_LED, 255); } else if (warn) { if (millis() - lastBlink > 250) { lastBlink = millis(); beat = !beat; } digitalWrite(PIN_LED, beat); } else { int glow = (millis() % 4000) / 16; // 0..250 if (glow > 125) glow = 250 - glow; // пила вверх-вниз analogWrite(PIN_LED, glow); }}Центр скетча — флаг ack. Тревога без кнопки орёт без тишины: через час двухкилогерцовая нота из кладовки становится фоном, к которому привыкают за неделю, и настоящий сигнал тонет в привычке. Кнопка без флага — другая крайность: приглушил и забыл, а температура держится на сорока двух. Формула посередине: ack глушит ровно на тридцать секунд и пишет в лог отдельной строкой — серия ALARM, ACK, ALARM povtor в логе показывает честную картину «жарко, меня уведомили, я знаю, жарко продолжается» без единого лишнего децибела.
Лог событий построен на одной функции logEvent с меткой millis()/1000 — секунды от старта платы. Метки нужны не для красоты: утренний просмотр лога без них не отвечает на главный вопрос «как быстро всё развивалось». Два часа между WARN и ALARM — летний нагрев, работа вентиляции; десять секунд между ALARM и CUT — задымление или коротыш, и реагировать надо по-разному. Философию разнесения логики и отладочной печати я разбирал в уроке про отладку через Serial, а таймерную базу без блокировки — в уроке про millis вместо delay.
Две вещи в скетче сделаны назло наивным версиям. Сбой чтения не превращается в тревогу: isnan-ветка пишет в лог строку SENSOR и пропускает такт — одиночный nan не сирена, а упорные nan ищут проводами по чек-листу диагностики nan. Реле-модуль у меня активен низким уровнем, поэтому питание в норме держится HIGH: скетч, который пишет в реле «прямыми» значениями, при старте платы, пока пины ещё плавают, успевает обесточить шкаф на полсекунды — перепроверьте полярность своего модуля, прежде чем вешать на него розетку.
Симулятор даёт прожить весь сценарий за минуту, чего летом не дождёшься и за сутки. Проследите два маршрута: быстрый, когда вы дожимаете ползунок до сорока пяти и смотрите, как ступени накатывают волнами по логу, и правильный, когда после первого ALARM вы сбрасываете звук кнопкой, а температуру снижаете на полградуса за раз — тогда в логе останется один ALARM и один ALARM off, и именно так выглядит шкаф, охрана которого работает, а не паникует.
Реле третьей ступени в моём шкафчике разрывает фазу обычной розетки, в которую воткнут удлинитель с NAS и свитчем. Но стоит сказать честно: обесточивание — редко лучший ответ для хранилища данных. Резкое снятие питания для диска — та же травма, что перегрев; если устройство умеет корректно гаситься само, реле должно резать только то, что режется безопасно. Вентилятор вытяжки на этом же реле при пороге пониже — более мягкий вариант, он разобран в уроке про вытяжку по DHT.
| Ступень | Условие | Что делает | Как гасится |
|---|---|---|---|
| Норма | t до 38 °C | светодиод дышит ШИМ, лог молчит | — |
| Предупреждение | t выше 38 °C | LED мигает 2 Гц, строка WARN | само при остывании ниже 37,5 |
| Тревога | t выше 40 °C | tone(8, 2000) непрерывно, строка ALARM | кнопка — на 30 секунд; остывание ниже 39,5 — полностью |
| Обесточивание | t выше 45 °C | реле режет питание розетки, строка CUT | только вручную, после разбора |
Обслуживание охраны и что дальше
Охрана, которая не проверяется, — заглушка. Раз в сезон я жму на плате тест: при старте скетч коротко пикает зуммером, мигает светодиодом и щёлкает реле — три секунды, за которые видно, что все три голоса живы. Тест при старте стоит двух строк в setup и экономит тот день, когда зуммер умер полгода назад, а вы узнаёте об этом из отчёта SMART, как в самом начале этой истории. Пороги по сезонам разные: летом тридцать восемь наступает само, зимой шкафчик не греется вовсе, — поэтому константы стоит вынести в энергонезависимую память и крутить кнопками без ноутбука, как разобрано в уроке про пороги в EEPROM.
И про этаж выше: Serial-лог — уже половина мониторинга, вторая половина — доставка его вам. Wifi-модуль, MQTT, уведомления на телефон — всё это навешивается на те же события WARN/ALARM/CUT, потому что логика уже разделена на ступени. Реле при этом оставайтесь локальной линией: сеть падает вместе с роутером, а реле на пине 7 живёт при любой погоде на улице. Сами голоса тревоги — частоты, ритмы, различение на слух причин — разобраны в уроке про зуммер и пороги, там же про резистор в разрыве зуммера.
Формула, с которой я уезжал от того июльского инцидента: данные без сигнала — дневник, сигнал без эскалации — паника, эскалация без кнопки — пытка. Три ступени с разными голосами, флаг ack, лог с метками — и шкафчик из кладовки превращается в систему, о которой вы вспоминаете раз в сезон, на тесте при старте.
- 1. Что именно делает кнопка при активной тревоге?
- 2. Почему первая ступень — светодиод, а не зуммер?
- 3. Тревога сработала на 40,3 °C, вы нажали кнопку, температура держится 41. Что произойдёт дальше?
- 4. analogWrite(12, 64) на настоящей Arduino Uno — что получится на светодиоде?
- 5. Датчик вернул nan при том, что минуту назад была активна тревога. Как правильно?
- Три ступени с разными голосами: LED-мигание на 38, tone(8, 2000) на 40, реле на 45 — предупреждение не должно наказывать слухом.
- Кнопка с флагом ack глушит зуммер на 30 секунд; жара осталась — тревога возвращается. Всё пишется в лог.
- Serial-лог с меткой millis()/1000: без меток не видно, как быстро развивалось событие.
- nan — не тревога: пропуск такта и строка SENSOR; реле проверьте на полярность активности, пока пины плавают при старте.
- На живой Uno ШИМ есть на 3, 5, 6, 9, 10, 11 — светодиод-дыхание переносите на пин 9, мигание работает на любом.
Частые вопросы по теме урока
- Что именно делает кнопка при активной тревоге?
- Флаг ack глушит звук на тридцать секунд и пишет ACK в лог. Температура за порогом — зуммер вернётся. Сброс навсегда превращает охрану в декорацию. Глушит зуммер на 30 секунд; если жара осталась — тревога повторяется
- Почему первая ступень — светодиод, а не зуммер?
- Порог предупреждения будет нарушаться весь жаркий сезон. Постоянный писк на пустяке приучает не реагировать — и однажды промолчите настоящую тревогу. Предупреждение о плюс-минус двух градусах не должно наказывать слухом весь сезон
- Тревога сработала на 40,3 °C, вы нажали кнопку, температура держится 41. Что произойдёт дальше?
- Ack глушит звук на 30 секунд. Причина не ушла — значит строка povtor появится в логе, и зуммер вернётся. Так кнопка означает «я услышал», а не «замолчи». Зуммер включится снова примерно через 30 секунд
- analogWrite(12, 64) на настоящей Arduino Uno — что получится на светодиоде?
- ШИМ на Uno живёт на пинах 3, 5, 6, 9, 10, 11. analogWrite на остальных пинах вырождается в обычный уровень. Симулятор рисует дыхание на 12 честно — на живой плате переносите светодиод на пин 9. Постоянный низкий уровень без регулировки: аппаратного ШИМ на пине 12 нет
- Датчик вернул nan при том, что минуту назад была активна тревога. Как правильно?
- nan — отсутствие данных, а не их значение. Лог строкой SENSOR сохраняет след, упорные сбои ищут проводами по чек-листу диагностики, но сирену одиночный nan не поднимает. Пропустить такт и записать в лог строку SENSOR: сбой чтения — не тревога