Мониторинг Умного Дома и его окружения телефоном без интернета. Android, Termux и открытая система автоматизации

от автора

В этой публикации рассмотрим контроль открытой системы «Умный дом» независимым от системы устройством — простым смартфоном, используя функции, для которых и изначально создавался  мобильный телефон: звонки и SMS.  

В статье осуществим возможность контроля как системы домашней автоматизации (в моем случае Majordomo), так и отдельных элементов экосистемы и окружения умного дома. Основная идея статьи — контроль и отправка оповещений через мобильную сеть, без использования интернета. Алгоритм простой, в случае проблемы выполняем следующее: SMS -> повторный SMS -> звонок через мобильную сеть.

Статья является продолжением предыдущей Не совсем умный дом на телефоне. Termux, zigbee/zigbee2mqtt и Android У меня уже установлен Termux и его дополнения (из одного источника).   

Начнём с простого — команду ping, думаю большинство знает и использует. Немного усложним её условиями вывода информации о статусе. Проверим одной командой в терминале доступность роутера:

ping -c 1 -W 1 192.168.1.1 &>/dev/null && echo "СТАТУС: Роутер в сети! Можно работать." || echo "СТАТУС: Роутер НЕ ОТВЕЧАЕТ!"

Преобразуем команду в небольшой скрипт проверки доступности роутера, сервера системы домашней автоматизации (я использую MajorDoMo), немного изменив команду и условия — проверяем не только роутер, но и доступность сети Internet (в качестве примера используя IP адрес DNS Google):

nano step1_ping.sh

#!/bin/bashSERVER_IP="192.168.1.123"ROUTER_IP="192.168.1.1"INTERNET_IP="8.8.8.8"echo "Проверяем связь с сервером $SERVER_IP..."# -c 1 (один пакет), -W 1 (время ожидания 1 секунда)if ping -c 1 -W 1 "$SERVER_IP" &>/dev/null; then    echo "СТАТУС: Сервер в сети!"else    echo "СТАТУС: Сервер УД НЕ ОТВЕЧАЕТ!"fiecho "Проверяем связь с роутером $ROUTER_IP..."if ping -c 1 -W 1 "$ROUTER_IP" &>/dev/null; then    echo "СТАТУС: Роутер в сети!"else    echo "СТАТУС: Роутер НЕ ОТВЕЧАЕТ!"fiecho "Проверяем связь с Интернетом $INTERNET_IP..."if ping -c 1 -W 1 "$INTERNET_IP" &>/dev/null; then    echo "СТАТУС: Интернет доступен!"else    echo "СТАТУС: Нет доступа к Интернету!"fi

Дальше, как обычно, сохраняем (Ctrl+O, затем Enter, для выхода Ctrl+X) и делаем скрипт исполняемым и запускаем его для проверки (прерывание программы — CTRL+C).

chmod +x step1_ping.sh./step1_ping.sh  

Проверка портов сервисов УД

Перед началом установим утилиты nc (netcat) и curl в Termux, если они ещё не установлены:

pkg install netcat-openbsd curl -y

В разных системах домашней автоматизации открыты разные порты, но есть несколько стандартных, которые встречаются довольно часто:

  • 22 — SSH,

  • 80 — HTTP (веб-интерфейс системы автоматизации ),

  • 1883 — MQTT-брокер,

  • 8080 — веб-интерфейс Zigbee2MQTT (по умолчанию).

Для проверки возьмём два сервиса: порт 80 (MajorDoMo) и порт 8080 (Zigbee2MQTT). Ниже — два варианта скрипта: простой (через nc) и более глубокий (через curl).

Вариант 1: быстрая проверка доступности портов через nc

Создадим ещё один скрипт и вставим содержимое:

nano step2_ports.sh

#!/bin/bashSERVER_IP="192.168.1.123"# Массив портов для проверки: "ПОРТ:ОПИСАНИЕ"SERVICES=(    "80:MajorDoMo Web"    "8080:Zigbee2MQTT Web")echo "Проверяем работу сервисов на $SERVER_IP..."for item in "${SERVICES[@]}"; do    # Разделяем порт и описание по символу ":"    PORT="${item%%:*}"    NAME="${item#*:}"    # nc -z: режим сканирования, -w 1: таймаут 1 секунда    if nc -zv -w 1 "$SERVER_IP" "$PORT" &>/dev/null; then        echo "  [ OK ] $NAME (порт $PORT) работает."    else        echo "  [FAIL] $NAME (порт $PORT) НЕ ОТВЕЧАЕТ!"    fidone

Вариант 2: глубокая проверка HTTP-сервисов через curl

Этот вариант не просто проверяет, «открыт ли порт», а смотрит, отдаёт ли сервис корректную страницу (HTTP-код 200). Создадим отдельный скрипт (или перезапишем тот же файл — на выбор):

#!/bin/bashSERVER_IP="192.168.1.123"echo "=== Глубокая проверка веб-сервисов ==="# Функция для проверки HTTP-кодаcheck_http() {    local url=$1    local name=$2    # --silent: скрыть прогресс-бар    # --output /dev/null: не сохранять тело страницы    # --write-out "%{http_code}": вывести только HTTP-код    # --max-time 3: ограничить ожидание 3 секундами    STATUS_CODE=$(curl --silent --output /dev/null --write-out "%{http_code}" --max-time 3 "$url")    if [ "$STATUS_CODE" -eq 200 ]; then        echo "  [ OK ] $name отдаёт страницу (Код: 200)"    elif [ "$STATUS_CODE" = "000" ]; then        # 000 — curl не смог соединиться (таймаут, хост недоступен и т.п.)        echo "  [FAIL] $name ВООБЩЕ НЕ ОТВЕЧАЕТ (Таймаут или сервис выключен)"    else        echo "  [WARN] $name доступен, но вернул ошибку сервера (Код: $STATUS_CODE)"    fi}# Проверяем MajorDoMo (порт 80)check_http "http://$SERVER_IP:80" "MajorDoMo Web"# Проверяем Zigbee2MQTT (порт 8080)check_http "http://$SERVER_IP:8080" "Zigbee2MQTT Web"

В ответе практически то же самое, но сам алгоритм проверки, несколько другой. Перейдём к проверке главной функции смартфона.

Взаимодействие с мобильной сетью (Звонки и SMS)

Теперь начнём тестировать основную функцию смартфона в этой публикации: отправке SMS и совершение звонков. Именно эти каналы станут нашими «резервными» оповещениями, когда интернет недоступен, а мобильная сеть остаётся рабочей. Чтобы Termux мог отправлять SMS или делать звонки  понадобится официальное дополнение Termux:API. Оно связывает консоль Linux с функциями Android, не только телефония, но и другие функции смартфона.

Предварительная подготовка (выполняется один раз)

Убеждаемся, что на телефоне установлено приложение дополнение  Termux:API (из того же источника, откуда скачивали сам Termux — например, F-Droid). Запускаем его на телефоне один раз и предоставляем необходимые разрешения.

Устанавливаем пакет утилит командной строки внутри Termux:

pkg install termux-api -y

Тестирование SMS и звонка

Напишем небольшой скрипт, который проверит, работают ли команды связи на устройстве. Будем использовать две основные команды: termux-sms-send и termux-telephony-call.

Вставим в него код ниже. Заменяем +XXXXXXXXXXX на свой номер телефона:

#!/bin/bash# Указываем номер телефона, на который будем звонить, в международном форматеMY_NUMBER="+XXXXXXXXXXX"echo "=== Тест мобильных функций ==="# 1. Проверка отправки SMSecho "Пробуем отправить тестовое SMS..."termux-sms-send -n "$MY_NUMBER" "Termux: Тест связи. Сервер Умного Дома ок!"echo "Запрос на SMS отправлен. Проверьте входящие сообщения."echo "-----------------------------------"# 2. Проверка звонкаecho "Внимание! Сейчас телефон совершит тестовый вызов на $MY_NUMBER"echo "Вы можете сразу сбросить его."read -p "Нажмите Enter для начала звонка..."termux-telephony-call "$MY_NUMBER"

!!! При первом звонке и отправке SMS сообщения Android запросит разрешения для приложения Termux для звонков и SMS – обязательно выдаем их, без разрешений — не заработает.

Финал

Скомбинировав предыдущие действия и объединив их вместе в один скрипт, получаем финальную версию — готовый мониторинг, который работает в цикле и оповещает через мобильную сеть.

Логика работы

Проверка выполняется каждые 30 секунд (интервал задаётся переменной INTERVAL). Мониторятся четыре цели:

1.    Сервер умного дома — по пингу. Если сервер не отвечает, проверка веб‑сервисов (MajorDoMo, Zigbee2MQTT) пропускается, а их локальные счётчики сбрасываются, чтобы избежать спама параллельных уведомлений.

2.    Роутер — по пингу.

3.    Доступность интернета — по пингу (в примере используем DNS Google 8.8.8.8).

4.    Веб‑сервисы (MajorDoMo на порту 80 и Zigbee2MQTT на порту 8080) — через HTTP‑запрос с проверкой кода ответа. Проверяются только если сервер доступен по пингу.

Эскалация оповещений

Для каждой цели ведётся отдельный счётчик ошибок подряд. Алгоритм эскалации одинаковый для всех: 2 ошибки подряд время обнаружения около минуты отправляется первое SMS сообщение; 4 ошибки подряд, ещё через минуту — второе сообщение; и наконец после трёх минут и 6 ошибок поступает «пустой» звонок.

При восстановлении связи отправляется SMS с текстом «OK: … ВОССТАНОВЛЕНА», но только если до этого уже было отправлено хотя бы одно уведомление об аварии, сделано, чтобы не спамить при кратковременных колебаниях связи.

#!/bin/bash# --- НАСТРОЙКИ ---SERVER_IP="192.168.1.123"ROUTER_IP="192.168.1.1"WAN_IP="8.8.8.8"MY_NUMBER="+XXXXXXXXXXXX" # Ваш номер телефонаINTERVAL=30               # Интервал опроса в секундах# --- СЧЕТЧИКИ ОШИБОК (0 - всё ок) ---err_server=0err_router=0err_wan=0err_md=0      # Для MajorDoMoerr_z2m=0     # Для Zigbee2MQTT# --- СТАТУСЫ УВЕДОМЛЕНИЙ (0-нет, 1-СМС1, 2-СМС2, 3-Звонок) ---alert_server=0alert_router=0alert_wan=0alert_md=0alert_z2m=0# Функция для проверки пинга (0 - ок, 1 - упал)check_ping() {    ping -c 1 -W 1 "$1" &>/dev/null    return $?}# Функция для проверки HTTP статуса (0 - ок (200), 1 - упал/ошибка)check_http_status() {    local url="$1"    # Запрашиваем только код ответа, таймаут 2 секунды    local code=$(curl --silent --output /dev/null --write-out "%{http_code}" --max-time 2 "$url")    if [ "$code" -eq 200 ]; then        return 0    else        return 1    fi}# Функция обработки логики эскалации# Аргументы: $1-имя для переменной, $2-имя для текста СМС, $3-текущий счетчик, $4-статус алертаprocess_incident() {    local var_name="$1"    local text_name="$2"    local count=$3    local alert_status=$4        # 2 ошибки подряд = 1 минута аварии    if [ $count -eq 2 ] && [ $alert_status -eq 0 ]; then        termux-sms-send -n "$MY_NUMBER" "ALERT: Проблема с [$text_name] (уже 1 минута)!"        eval "alert_${var_name}=1"        echo "[СМС] Отправлено первое уведомление для $text_name"            # 4 ошибки подряд = около 2 минут аварии    elif [ $count -eq 4 ] && [ $alert_status -eq 1 ]; then        termux-sms-send -n "$MY_NUMBER" "ALERT: [$text_name] ВСЕ ЕЩЕ ЛЕЖИТ (уже 2 минуты)!"        eval "alert_${var_name}=2"        echo "[СМС] Отправлено второе уведомление для $text_name"            # 6 ошибок подряд = около 3 минуты аварии    elif [ $count -eq 6 ] && [ $alert_status -eq 2 ]; then        echo "[ЗВОНОК] Инициирую экстренный вызов по причине: $text_name"        termux-telephony-call "$MY_NUMBER"        eval "alert_${var_name}=3"    fi}echo "=== Запуск расширенного мониторинга УД (Интервал: ${INTERVAL}с) ==="while true; do    echo "--- Проверка $(date '+%H:%M:%S') ---"    # 1. ПРОВЕРКА СЕРВЕРА (ПИНГ)    if check_ping "$SERVER_IP"; then        if [ $err_server -gt 0 ]; then            [ $alert_server -gt 0 ] && termux-sms-send -n "$MY_NUMBER" "OK: Связь с сервером $SERVER_IP ВОССТАНОВЛЕНА."            echo "✅ Сервер снова в сети."            err_server=0; alert_server=0        fi                # --- СЕРВИСЫ ПРОВЕРЯЕМ ТОЛЬКО ЕСЛИ САМ СЕРВЕР ПИНГУЕТСЯ ---                # 1.1 ПРОВЕРКА MAJORDOMO (PORT 80)        if check_http_status "http://$SERVER_IP:80"; then            if [ $err_md -gt 0 ]; then                [ $alert_md -gt 0 ] && termux-sms-send -n "$MY_NUMBER" "OK: Сервис MajorDoMo (порт 80) восстановил работу."                echo "✅ MajorDoMo Web [OK]"                err_md=0; alert_md=0            fi        else            ((err_md++))            echo "❌ MajorDoMo Web упал. Ошибок подряд: $err_md"            process_incident "md" "MajorDoMo Web" $err_md $alert_md        fi        # 1.2 ПРОВЕРКА ZIGBEE2MQTT (PORT 8080)        if check_http_status "http://$SERVER_IP:8080"; then            if [ $err_z2m -gt 0 ]; then                [ $alert_z2m -gt 0 ] && termux-sms-send -n "$MY_NUMBER" "OK: Сервис Zigbee2MQTT (порт 8080) восстановил работу."                echo "✅ Zigbee2MQTT Web [OK]"                err_z2m=0; alert_z2m=0            fi        else            ((err_z2m++))            echo "❌ Zigbee2MQTT Web упал. Ошибок подряд: $err_z2m"            process_incident "z2m" "Zigbee2MQTT Web" $err_z2m $alert_z2m        fi    else        ((err_server++))        echo "❌ Сервер полностью недоступен по пингу. Ошибок подряд: $err_server"        process_incident "server" "Сервер УД (Ping)" $err_server $alert_server                # Если сам сервер лежит, сбрасываем локальные счетчики веб-сервисов,         # чтобы они не генерировали лишний спам параллельно с аварией сервера.        err_md=0; err_z2m=0    fi    # 2. ПРОВЕРКА РОУТЕРА    if check_ping "$ROUTER_IP"; then        if [ $err_router -gt 0 ]; then            [ $alert_router -gt 0 ] && termux-sms-send -n "$MY_NUMBER" "OK: Связь с роутером $ROUTER_IP ВОССТАНОВЛЕНА."            echo "✅ Роутер снова в сети."            err_router=0; alert_router=0        fi    else        ((err_router++))        echo "❌ Роутер упал. Ошибок подряд: $err_router"        process_incident "router" "Роутер" $err_router $alert_router    fi    # 3. ПРОВЕРКА ИНТЕРНЕТА    if check_ping "$WAN_IP"; then        if [ $err_wan -gt 0 ]; then            [ $alert_wan -gt 0 ] && termux-sms-send -n "$MY_NUMBER" "OK: Доступ в Интернет ВОССТАНОВЛЕН."            echo "✅ Интернет снова доступен."            err_wan=0; alert_wan=0        fi    else        ((err_wan++))        echo "❌ Интернет упал. Ошибок подряд: $err_wan"        process_incident "wan" "Интернет" $err_wan $alert_wan    fi    sleep $INTERVALdone

Дальнейшие шаги

Дальнейшие действия — по усмотрению. В зависимости от производителя и версии Android можно и нужно:

  • Включить Termux в автозагрузку. Для теста использовал три смартфона Xiaomi с Android 10, 13 (основной на котором всё тестировалось) и 16 это работало по-разному: на 13-й версии запустить при старте телефона никак не удавалось, обошёл через MacroDroid.

  • Отключить энергосбережение для Termux. В настройках смартфона — режим без ограничений, иначе система рано или поздно «убьёт» фоновый процесс. Так же можно организовать и питание с контролем заряда/разряда телефона.

  • Добавить скрипт в автозапуск Termux. Способов несколько — например, через .bashrc или Termux:Boot.

  • Доработать под свои нужды: ночной режим, логирование, дополнительные проверки — всё на ваше усмотрение.

Эта статья — не исчерпывающее руководство, а всего лишь старт и направление действий.

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