Всем привет.
Есть малая механизация, когда вы мотокультиватором типа «Крот» сажаете картошку на 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, дебаг можно убрать.
К сожалению при написании пострадала одна локальная нейросеть, изначальный скрипт, писавшийся руками был ужасен и к публикации не был одобрен.
Всем хорошего урожая
Скрытый текст


