Таймер в розетке включает свет в курятнике в 18:00 — и весь декабрь птицы сидят в темноте до включения, потому что солнце там садится в 16:00, а в июне лишние два часа горения при том, что на улице ещё светло. Жёсткое расписание из урока про свет по часам честно держит назначенные минуты, но никуда не уезжает вместе с сезоном: разница между декабрём и июнем в средней полосе — одиннадцать часов светового дня. Выход — привязать триггер не к настенным часам, а к солнцу: включать свет за полчаса до заката, запускать полив через полчаса после рассвета. Здесь считаю момент заката и рассвета арифметикой на RTC-дате и разбираю все места, где солнечные формулы кусаются.
Что понадобится на входе: координаты точки — широта и долгота, дата с RTC и часовой пояс. Всё. Никаких датчиков освещённости и антенн: солнечное движение вычисляется из календаря с точностью в пару минут, и этого хватает для полива и света. Для автоматики с датчиком почвы связка получается двухслойной — урок про автополив по почве отвечает «можно ли поливать», а солнечная арифметика отвечает «не рано ли ещё».
Что нужно солнцу: точка на карте и дата
Формулы восхода и заката — это астрономия в упаковке для микроконтроллеров: по дате считается склонение солнца и уравнение времени, по координатам — часовой угол, и на выходе два момента суток. Граница события тоже определена не на глазок: восходом считают момент, когда верхний край диска показывается над горизонтом с учётом изгиба лучей в атмосфере, — отсюда стандартный угол солнца минус 0,833 градуса, где сложены рефракция и полудиаметр диска. Если суммировать грубо: рефракция поднимает картинку примерно на полградуса, диск добавляет ещё четверть — и вот готов эталонный угол, который зашит во все калькуляторы.
Руками формулу писать не надо — есть готовые библиотеки. SolarCalculator выдаёт восход, закат, солнечный полдень, сумерки и уравнение времени; Dusk2Dawn — порт онлайнового калькулятора NOAA, у которого часовой пояс передаётся в минутах. Мой совет по запуску любой из них один и тот же: возьмите одну дату и свои координаты, вбейте их в онлайн-калькулятор NOAA и сравните с выводом скетча. Расхождение в минуту — норма для округлённых формул; расхождение в часы почти всегда означает перепутанный знак долготы или пояс, и ловить это на стенде дешевле, чем на живом курятнике.
Про координаты — сразу две грабли. Первая: западная долгота в этих библиотеках отрицательная, и Москва с её 37,6 градуса восточной идёт со знаком плюс, а Лондон с 0,1 градуса западной — уже минус. Вторая: широта выше 66,5 градуса упирается в полярный день и полярную ночь — бывают даты, когда солнце не садится или не встаёт вовсе, и библиотека вернёт вместо времени служебную пометку. Проверяйте, что возвращает функция, прежде чем скармливать число планировщику: пометка, превращённая в минуты, даёт расписание из области фантастики.
#include <Wire.h>#include <RTClib.h>#include <SunSet.h> // библиотека солнечных расчётов RTC_DS3231 rtc;SunSet sol;const int RELE = 7; // модуль реле на светconst double SHIROTA = 55.75; // Москваconst double DOLGOTA = 37.62;const int PoyaS = 3; // часовой пояс UTC+3 int denZapisi = -1; // день, для которого уже считали закатint zakatMin = 0;int voshodMin = 0; int minutSutok(DateTime t) { return t.hour() * 60 + t.minute();} void pereschitat(DateTime now) { sol.setCurrentDate(now.year(), now.month(), now.day()); double zakatChasy = sol.calcSunset(); // часы с дробью double voshodChasy = sol.calcSunrise(); zakatMin = int(zakatChasy * 60.0); voshodMin = int(voshodChasy * 60.0); Serial.print("[СОЛНЦЕ] voshod "); Serial.print(voshodMin / 60); Serial.print(":"); Serial.print(voshodMin % 60); Serial.print(" zahod "); Serial.print(zakatMin / 60); Serial.print(":"); Serial.println(zakatMin % 60);} void setup() { Serial.begin(9600); pinMode(RELE, OUTPUT); if (rtc.begin() == false) { while (1) {} } sol.setPosition(SHIROTA, DOLGOTA, PoyaS); pereschitat(rtc.now());} void loop() { DateTime now = rtc.now(); if (now.day() != denZapisi) { // новый день - новая арифметика denZapisi = now.day(); pereschitat(now); } int m = minutSutok(now); int vklyuchenie = zakatMin - 30; // свет за полчаса до заката bool svetOn = (m >= vklyuchenie || m < voshodMin); digitalWrite(RELE, svetOn ? HIGH : LOW); // реле модульное: LOW - включено у многих плат delay(1000);}Сумерки, полив и границы применимости
Для света в курятнике закат — не всегда то, что нужно. Курицы садятся на насест в сумерках, а гражданские сумерки — это солнце на шести градусах под горизонтом, ещё минут тридцать-сорок после видимого заката. Библиотеки умеют этот уровень: у SolarCalculator сумерки считаются отдельным вызовом, в ручной арифметике угол просто меняют с 0,833 на 6 градусов. Мой рабочий вариант — закат минус двадцать-тридцать минут: свет успевает разгореться до темноты, и птицы не сидят в полутьме. Для полива логика зеркальная: рассвет плюс полчаса — вода идёт по холодной траве, испарение минимально, а у листьев есть день, чтобы высохнуть до ночной сырости.
Часовой пояс и перевод стрелок — второй слой аккуратности. Пока RTC живёт локальным временем, скетчу пояс знать незачем: закат сам переползёт на час в нужную дату, потому что дата в формуле сменится, — механику сезонных сдвигов я разбирал в уроке про летнее время. Но если вы держите в чипе UTC, как любят логгеры, — пояс придётся передать в библиотеку, и границу его действия в странах со сдвигом придётся держать в скетче. И про точность: на восьмибитных платах тип double — это четыре байта, то есть семь значащих цифр, — для минутной точности заката запас огромен, но не ждите от скетча секунд: сама модель атмосферы гуляет на минуту-две от погоды.
Полюс формулы — за полярным кругом. Если проект едет в Мурманск или Норильск, добавьте ветку: сервисное значение из библиотеки — сигнал уйти в резервное расписание по часам, как в уроке про неделю расписаний. У меня этот fallback выглядит скучно: не считалось — работаем по жёсткому графику и печатаем в журнал пометку. Комбинация «солнце в обычные дни, график в крайние» покрывает всю страну, а заодно страхует от лжи формулы в горах, где настоящий горизонт ниже математического.
В модели видно главное свойство солнечного триггера: включение само уезжает по сезонам — в декабре свет встаёт рано днём, в июне под полночь, и ни одна строка расписания при этом не правится. Точность таблицы — минутная и честно округлённая: настоящая библиотека на плате считает по формулам и уходит от таблицы на единицы минут. Кнопка ручного обхода — тот же контракт, что и в расписаниях: автоматика автоматикой, а человек должен уметь включить свет прямо сейчас, без выключателей питания.
На плате скетч из code-блока пересчитывает солнце раз в сутки по смене дня — этого достаточно: закат не гуляет внутри суток. Реле света берите модульное с оптопарой и следите за током катушки: пара десятков миллиампер пин не тянет, потому и транзистор внутри модуля, а про подключение нагрузки 220 В собран отдельный урок про модуль реле. Планировщик вокруг окна света живёт на millis — базовая механика без блокирующих пауз собрана в уроке про millis вместо delay.
Откуда взять координаты: откройте карту на телефоне, нажмите долгим тапом точку щитка и перепишите два числа из всплывашки — четыре знака после запятой хватает с запасом, потому что смена четвёртого знака сдвигает закат меньше чем на секунду. Широта вашего места подскажет и амплитуду сезона: на юге страны день гуляет от девяти до пятнадцати часов, в Петербурге — от пяти с половиной до восемнадцати с половиной, и таблица из симулятора для широты 55,75 показывает середину этой вилки. Смотрите на свою широту честно, а не по московским привычкам.
| Триггер света | Что даёт | Где подводит |
|---|---|---|
| Часы по расписанию | стабильные минуты круглый год | декабрь и июнь различаются на 11 часов дня |
| Закат минус 30 минут | свет ровно к темноте в любой сезон | нужны координаты и дата |
| Сумерки минус 6 градусов | включение в полутьму, комфорт птицам | позднее видимого заката на полчаса |
| Фоторезистор на A1 | реагирует на реальную тьму | фары машин и тучи дают ложные сработки |
Куда расширять. Полив получает второй слой условий: солнечное окно отвечает «рано ли», датчик почвы — «нужно ли», а флаги уже отработанного полива живут в расписании на неделю. Дальше по желанию — дневная статистика длины дня для теплицы: те же два числа в журнал, и через месяц вы видите кривую сезона, не выходя из гаража.
- 1. Что зашито в стандартный угол восхода минус 0,833 градуса?
- 2. Какой минимальный набор входов нужен солнечной формуле?
- 3. Что вернёт библиотека в полярный день за полярным кругом?
- 4. Почему для света в курятнике я беру закат минус 20-30 минут?
- 5. Хватит ли точности тип double на Uno для минутного заката?
- Солнечный триггер — это координаты, дата и пояс: датчиков освещённости не нужно
- Стандартный угол восхода минус 0,833 градуса — рефракция плюс полудиаметр диска
- Западная долгота отрицательная: перепутанный знак сдвигает закат на часы
- За 66,5 широты бывают даты без заката — проверяйте пометку и держите fallback
- Для света беру закат минус 30 минут, для полива — рассвет плюс 30
Частые вопросы по теме урока
- Что зашито в стандартный угол восхода минус 0,833 градуса?
- Восходом считают момент, когда верхний край диска виден над горизонтом с учётом изгиба лучей: полградуса даёт рефракция, ещё четверть — сам диск. Сумма и есть 0,833 градуса. Рефракция атмосферы и полудиаметр солнечного диска
- Какой минимальный набор входов нужен солнечной формуле?
- Солнечное движение вычисляется из календаря и точки на карте: широта, долгота, дата, пояс. Датчиков не нужно — погрешность результата и так минутная. Широта, долгота, дата и часовой пояс
- Что вернёт библиотека в полярный день за полярным кругом?
- В даты, когда солнце не садится или не встаёт, честного результата нет — библиотека возвращает служебное значение. Его надо проверять и уходить в резервное расписание, а не скармливать планировщику. Служебную пометку вместо времени
- Почему для света в курятнике я беру закат минус 20-30 минут?
- Курицы садятся в сумерках, до полной темноты — десятки минут. Запас в полчаса до заката даёт готовый световой режим к моменту, когда птицам он нужен. Чтобы свет разгорелся до темноты, пока птицы в сумерках идут на насест
- Хватит ли точности тип double на Uno для минутного заката?
- На восьмибитных платах double занимает 4 байта — семь значащих цифр. Для результата с точностью в минуты этого с огромным запасом, а секунд от модели всё равно ждать не стоит. Да: double на AVR — 4 байта, семи значащих цифр хватает с запасом