Всем привет.
Есть малая механизация, когда вы мотокультиватором типа «Крот» сажаете картошку на 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 cutoffTIMEZONE="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=38899LIGHT_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 fidone# --------------------------------------------# 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 0fi# --------------------------------------------# 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 1fiprintf '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 managingAfter=network.target[Service]ExecStart=/opt/gauss/on_off2.shUser=maxRestart=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=1secOnUnitActiveSec=5minUnit=light.service[Install]WantedBy=multi-user.target
Который начнет запускать ваш таймер каждые 5 минут (выбрать по вкусу).
Далее стандартно systemctl daemon-reload && systemctl enable light.service light.timer && systemctl start light.service light.timer. Скрипт немного флудит в journalctl, дебаг можно убрать.
К сожалению при написании пострадала одна локальная нейросеть, изначальный скрипт, писавшийся руками был ужасен и к публикации не был одобрен.
Всем хорошего урожая
Скрытый текст

ссылка на оригинал статьи https://habr.com/ru/articles/1103312/