Всем привет.
Есть малая механизация, когда вы мотокультиватором типа «Крот» сажаете картошку на 20 сотках, а есть малая автоматизация, когда вам лень ставить жирный homeassiant и/или приложение от вендора с завязкой на облака и хочется пожить в уютном локалхосте. Сегодня пойдет речь про вторую. И да, важный момент — вы не планировали умный дом и не тянули провода заранее.
Достаточно давно была куплена розетка «Умная розетка Wi‑Fi SmartHome 2300W 10А IP20 c заземлением Gauss» в озоне, к сожалению сейчас уже не продается и непонятно продается ли она у вендора. Важно в ней то, что протокол общения там Philips WiZ, он расковырян, много скриптов на гитхабе, оттуда и подчерпнута важная информация.
Сегодня мы делаем включение ее и приборов, подключенных в ней, по закату солнца в конкретной вашей локации. И выключение в 23:00. Для доосвещения рассады дома, что весной, что осенью.
Пререквезиты — любой линукс хост с bash, curl, jq, netcat и доступом в интернет.
Что оставляем за кадром — подключение в ваш локальный LAN, это инструкция из коробки. После подключения доступ в интернет розетке можно заблокировать, она не потеряет адрес и даже валяющаяся на полке в течении полугода сохранит подключение wifi.
Итак, что делает скрипт:
опрашивает по вашему фактическому местоположению когда у вас будет закат, на основании показателей api.sunrise‑sunset.org, это бесплатно как минимум для домашнего использования. для бизнеса не изучал, извините.
до заката шлет форсированно выключение розетки, через nc, на случай если случайно нажали кнопку. износа розетки в этом случае не видно, по крайней мере за 3 года.
после заката включает питание на ней, так же через nc
в 23:00 выключает, тк растениям тоже нужно спать
опционально, если у вас 2-3-4 и более розеток работает по массиву.
Скрытый текст
#!/usr/bin/env bash # # light.sh # # Requires: # - curl # - jq # - GNU date (coreutils) # - netcat / nc # # Run: # ./light.sh # # Print only sunset Unix timestamp: # ./light.sh --print-sunset # set -euo pipefail # -------------------------------------------- # Config # -------------------------------------------- LAT="37.619024" LNG="55.751999" # Use the timezone for both API and 23:00 cutoff TIMEZONE="Europe/Moscow" # Configurable IP addresses. # Add as many as you need. IP_ADDR=( "192.168.1.185" # "192.168.1.186" # "192.168.1.187" ) LIGHT_PORT=38899 LIGHT_ID=1 # -------------------------------------------- # Dependency check # -------------------------------------------- for cmd in curl jq nc date; do if ! command -v "$cmd" >/dev/null 2>&1; then printf 'Missing dependency: %s\n' "$cmd" >&2 exit 1 fi done # -------------------------------------------- # Send UDP command to all configured IPs # -------------------------------------------- send_state() { local state="$1" # true or false local json_state if [[ "$state" == "true" ]]; then json_state="true" else json_state="false" fi for ip in "${IP_ADDR[@]}"; do printf '{"id":%s,"method":"setState","params":{"state":%s}}\n' \ "$LIGHT_ID" "$json_state" | nc -u -w 1 "$ip" "$LIGHT_PORT" || true done } # -------------------------------------------- # Get sunset as Unix epoch seconds # -------------------------------------------- get_sunset_epoch() { # Explicit local date for the API request. # This avoids issues if the API interprets "today" differently. local date_str date_str=$(TZ="$TIMEZONE" date +%Y-%m-%d) local url url="https://api.sunrise-sunset.org/json?lat=${LAT}&lng=${LNG}&date=${date_str}&tzid=${TIMEZONE}&formatted=0" local response response=$(curl -sL --max-time 10 "$url") || return 1 if ! jq -e '.status == "OK"' <<< "$response" >/dev/null; then return 1 fi local sunset_iso sunset_iso=$(jq -r '.results.sunset // ""' <<< "$response") if [[ -z "$sunset_iso" ]]; then return 1 fi # If the API returns only a time like "18:00:00+03:00", # add the local date before conversion. if [[ ! "$sunset_iso" =~ ^[0-9]{4} ]]; then sunset_iso="${date_str} ${sunset_iso}" fi # GNU date supports --date / -d date -d "$sunset_iso" +%s } # -------------------------------------------- # Optional: print only sunset Unix timestamp # -------------------------------------------- if [[ "${1:-}" == "--print-sunset" ]]; then printf '%d\n' "$(get_sunset_epoch)" exit 0 fi # -------------------------------------------- # Main logic # -------------------------------------------- current_epoch=$(date +%s) local_date=$(TZ="$TIMEZONE" date +%Y-%m-%d) cutoff_epoch=$(TZ="$TIMEZONE" date -d "${local_date} 23:00:00" +%s) if ! sunset_epoch=$(get_sunset_epoch); then printf 'ERROR: failed to get sunset from API\n' >&2 exit 1 fi printf 'current_epoch=%d\n' "$current_epoch" printf 'sunset_epoch=%d\n' "$sunset_epoch" printf 'cutoff_23_00=%d\n' "$cutoff_epoch" # Turn ON only if: # current time is AFTER sunset # AND current time is BEFORE 23:00 local time # # Otherwise, turn OFF. if (( current_epoch > sunset_epoch && current_epoch < cutoff_epoch )); then send_state true printf 'light_state=on reason=after_sunset_and_before_23:00\n' else send_state false printf 'light_state=off reason=before_sunset_or_after_23:00\n' fi
Для использования требуется настроить вашу локацию (можно взять из яндекса), адреса розеток, таймзону, остальное по вкусу.
Далее регистрируем сервис в systemd, господам в openwrt и прочей встройке сразу рекомендуется идти в крон:
cat /usr/lib/systemd/system/light.service [Unit] Description=Gauss managing After=network.target [Service] ExecStart=/opt/gauss/on_off2.sh User=max Restart=never [Install] WantedBy=multi-user.target
Собственно /opt/gauss/on_off2.sh место, куда мы положили шелльник.
И регистрируем таймер /etc/systemd/system/light.timer
[Unit] Description=Run light.sh every 5 minute [Timer] OnBootSec=1sec OnUnitActiveSec=5min Unit=light.service [Install] WantedBy=multi-user.target
Который начнет запускать ваш таймер каждые 5 минут (выбрать по вкусу).
Далее стандартно systemctl daemon‑reload && systemctl enable light.service light.timer && systemctl start light.service light.timer. Скрипт немного флудит в journalctl, дебаг можно убрать.
К сожалению при написании пострадала одна локальная нейросеть, изначальный скрипт, писавшийся руками был ужасен и к публикации не был одобрен.
Всем хорошего урожая
Скрытый текст

Комментарии (7)

BigBrother
03.11.2026 17:04Зачем вообще здесь обращаться к какому-то забугорному серверу, чтобы только узнать время захода солнца? Это уже не совсем локалхост. В наше неспокойное время блокировок всего и всех.
Проще забить в локальный файлик. Тем более точное время здесь не слишком актуально. Думаю, достаточно будет даже подекадно внести: растениям это не повредит.
max9 Автор
03.11.2026 17:04есть опция, да, либо забить в файлик, либо лучше по фактическому освещению включать свет, но там надо думать рокет-сайнс по вариантам
сутра темно - включаем на весь день
пришла туча летом/зимой не алармить и не зажигать свет на 20 минут, лампочка быстро кончится от переходных процессов
отличать аларм п2 от заката
у меня даже валялась esp с датчиком освещения и снятыми показателями освещенности, чтобы написать, но не дошли руки

Lizdroz
03.11.2026 17:04Рокет-сайнс начинается там, где хочется учесть все возможные краевые сценарии)
А почему бы просто не купить таймер-розетку за триста рублей в строительном магазине?

Lizdroz
03.11.2026 17:04Решение интересное, но скрипт выглядит немного перегруженным для такой простой задачи. Вместо запросов к внешним API можно было просто поставить локальный cron с хардкодными таймингами по сезонам. Для рассады минутная точность заката не нужна
MarkCraft_Dev
Интересный подход с
ncнапрямую к розетке, без облаков. А насколько стабильно держится TCP-соединение? У меня был опыт с Wi-Fi устройствами (правда, не Gauss), так они иногда отваливались от сети, если роутер перезагружался. Приходилось ли вам добавлять какие-то проверкиpingперед отправкой команды, или она и так годами работает без сбоев?max9 Автор
там только udp, ничего не надо ни пингов ничего. улетело и улетело. имекнно поэтому в цикле скрипта вечная отправка
MarkCraft_Dev
А, так вот почему цикл вечный! Логично, UDP же не гарантирует доставку, поэтому проще «кричать» в сеть, пока не дойдет. Спасибо за разъяснение, буду знать