Малая автоматизация

—

от автора

Всем привет.

Есть малая механизация, когда вы мотокультиватором типа «Крот» сажаете картошку на 20 сотках, а есть малая автоматизация, когда вам лень ставить жирный homeassiant и/или приложение от вендора с завязкой на облака и хочется пожить в уютном локалхосте. Сегодня пойдет речь про вторую. И да, важный момент — вы не планировали умный дом и не тянули провода заранее.

Достаточно давно была куплена розетка «Умная розетка Wi-Fi SmartHome 2300W 10А IP20 c заземлением Gauss» в озоне, к сожалению сейчас уже не продается и непонятно продается ли она у вендора. Важно в ней то, что протокол общения там Philips WiZ, он расковырян, много скриптов на гитхабе, оттуда и подчерпнута важная информация.

Сегодня мы делаем включение ее и приборов, подключенных в ней, по закату солнца в конкретной вашей локации. И выключение в 23:00. Для доосвещения рассады дома, что весной, что осенью.
Пререквезиты — любой линукс хост с bash, curl, jq, netcat и доступом в интернет.
Что оставляем за кадром — подключение в ваш локальный LAN, это инструкция из коробки. После подключения доступ в интернет розетке можно заблокировать, она не потеряет адрес и даже валяющаяся на полке в течении полугода сохранит подключение wifi.

Итак, что делает скрипт:

  1. опрашивает по вашему фактическому местоположению когда у вас будет закат, на основании показателей api.sunrise-sunset.org, это бесплатно как минимум для домашнего использования. для бизнеса не изучал, извините.

  2. до заката шлет форсированно выключение розетки, через nc, на случай если случайно нажали кнопку. износа розетки в этом случае не видно, по крайней мере за 3 года.

  3. после заката включает питание на ней, так же через nc

  4. в 23:00 выключает, тк растениям тоже нужно спать

  5. опционально, если у вас 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/