deploy examples

This commit is contained in:
awe
2026-10-22 12:57:33 +03:00
parent 09a2aa7932
commit 5826c4ff67
10 changed files with 357 additions and 13 deletions
@@ -0,0 +1,53 @@
# systemd-службы сетевого моста
Автозапуск `tools/bridge.py` как служб: `cart-bridge-tx` (отправитель, рядом с
пультом) и `cart-bridge-rx` (приёмник, рядом с тележкой). На каждой машине
включается ровно одна роль.
## Установка
На машине-отправителе:
```sh
sudo ./install-bridge.sh tx
```
На машине-приёмнике:
```sh
sudo ./install-bridge.sh rx
```
Установщик подставляет в юнит реальные пути (python из `.venv` проекта, если
есть, иначе системный `python3`; `bridge.py`; рабочий каталог) и пользователя
(того, кто вызвал `sudo`). Юниты кладутся в `/etc/systemd/system/`, конфиги —
в `/etc/cart-bridge/{tx,rx}.env` (создаются из примеров, существующие не
перезаписываются). Без аргумента (`none`) — только установка, без включения.
Интерпретатор можно задать явно: `sudo PYTHON=/usr/bin/python3 ./install-bridge.sh rx`.
В выбранном python должен быть `pyserial`.
## Настройка
Отредактировать конфиг под свою сеть и ключ:
```sh
sudoedit /etc/cart-bridge/tx.env # peer = адрес приёмника, общий ключ
sudoedit /etc/cart-bridge/rx.env # bind, тот же ключ
sudo systemctl restart cart-bridge-tx # применить
```
Ключ `CART_BRIDGE_KEY` на обеих сторонах должен совпадать (HMAC-аутентификация
пакетов; обязателен для интернета).
## Эксплуатация
```sh
systemctl status cart-bridge-tx
journalctl -u cart-bridge-tx -f # логи; на отправителе видно «приёмник отвечает/НЕ отвечает»
sudo systemctl restart cart-bridge-tx
sudo systemctl disable --now cart-bridge-tx
```
Служба перезапускается при падении (`Restart=always`). Доступ к USB-порту STM
даётся группами `dialout`/`plugdev` (прописаны в юните).
@@ -0,0 +1,19 @@
# Конфигурация службы приёмника (cart-bridge-rx). Копируется в
# /etc/cart-bridge/rx.env установщиком. Переменные читает tools/bridge.py.
# Локальный UDP-адрес для приёма HOST:PORT.
CART_BRIDGE_BIND=0.0.0.0:5005
# Общий ключ HMAC (ОБЯЗАТЕЛЕН для интернета). Должен совпадать с отправителем.
CART_BRIDGE_KEY=change-me-shared-secret
# Необязательно: принимать пакеты только с этого адреса отправителя (фильтр по
# хосту). Для интернета за NAT обычно оставляют пустым и полагаются на HMAC.
#CART_BRIDGE_PEER=10.0.0.1
# Необязательно: путь к порту или подстрока product/serial. По умолчанию порт
# ищется по USB product string CART-RX.
#CART_BRIDGE_DEVICE=CART-RX
# Необязательно: уровень логов (DEBUG/INFO/WARNING).
#CART_BRIDGE_LOG_LEVEL=INFO
@@ -0,0 +1,18 @@
[Unit]
Description=Cart bridge receiver (role rx): сеть -> USB тележки
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
Type=simple
User=@USER@
SupplementaryGroups=dialout plugdev
EnvironmentFile=/etc/cart-bridge/rx.env
WorkingDirectory=@WORKDIR@
ExecStart=@PYTHON@ @BRIDGE@ --role rx
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
@@ -0,0 +1,15 @@
# Конфигурация службы отправителя (cart-bridge-tx). Копируется в
# /etc/cart-bridge/tx.env установщиком. Переменные читает tools/bridge.py.
# Адрес приёмника HOST:PORT — куда слать управление.
CART_BRIDGE_PEER=10.0.0.2:5005
# Общий ключ HMAC (ОБЯЗАТЕЛЕН для интернета). Должен совпадать с приёмником.
CART_BRIDGE_KEY=change-me-shared-secret
# Необязательно: путь к порту или подстрока product/serial. По умолчанию порт
# ищется по USB product string CART-TX.
#CART_BRIDGE_DEVICE=CART-TX
# Необязательно: уровень логов (DEBUG/INFO/WARNING).
#CART_BRIDGE_LOG_LEVEL=INFO
@@ -0,0 +1,20 @@
[Unit]
Description=Cart bridge sender (role tx): пульт USB -> сеть
After=network-online.target
Wants=network-online.target
# не упираться в лимит перезапусков при флапе сети/USB
StartLimitIntervalSec=0
[Service]
Type=simple
User=@USER@
# доступ к последовательному порту STM (dialout) и к USB-дескрипторам (plugdev)
SupplementaryGroups=dialout plugdev
EnvironmentFile=/etc/cart-bridge/tx.env
WorkingDirectory=@WORKDIR@
ExecStart=@PYTHON@ @BRIDGE@ --role tx
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# Установка systemd-служб сетевого моста тележки.
#
# sudo ./install-bridge.sh [tx|rx|both|none]
#
# Аргумент выбирает, какую службу включить и запустить на ЭТОЙ машине
# (tx — рядом с пультом, rx — рядом с тележкой). Без аргумента юниты только
# ставятся, но не включаются. Файлы юнитов и шаблоны конфигов берутся из этого
# каталога; пути к python и bridge.py подставляются автоматически.
set -euo pipefail
SELF="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TOOLS="$(cd "$SELF/../tools" && pwd)"
REPO="$(cd "$SELF/../../.." && pwd)"
BRIDGE="$TOOLS/bridge.py"
WORKDIR="$TOOLS"
ENABLE="${1:-none}"
case "$ENABLE" in tx|rx|both|none) ;; *) echo "аргумент: tx|rx|both|none" >&2; exit 2;; esac
if [ "$(id -u)" -ne 0 ]; then
echo "нужны права root — перезапускаюсь через sudo"
exec sudo -E PYTHON="${PYTHON:-}" bash "$0" "$ENABLE"
fi
TARGET_USER="${SUDO_USER:-root}"
# интерпретатор: venv проекта, если есть, иначе системный python3
PYTHON="${PYTHON:-}"
if [ -z "$PYTHON" ]; then
if [ -x "$REPO/.venv/bin/python" ]; then
PYTHON="$REPO/.venv/bin/python"
else
PYTHON="$(command -v python3)"
fi
fi
echo "python : $PYTHON"
echo "bridge : $BRIDGE"
echo "user : $TARGET_USER"
if ! "$PYTHON" -c 'import serial' 2>/dev/null; then
echo "ВНИМАНИЕ: в $PYTHON нет pyserial — поставь: $PYTHON -m pip install pyserial" >&2
fi
gen_unit() { # <role>
local role="$1"
sed -e "s|@PYTHON@|$PYTHON|g" -e "s|@BRIDGE@|$BRIDGE|g" \
-e "s|@WORKDIR@|$WORKDIR|g" -e "s|@USER@|$TARGET_USER|g" \
"$SELF/cart-bridge-$role.service" > "/etc/systemd/system/cart-bridge-$role.service"
echo "установлен юнит /etc/systemd/system/cart-bridge-$role.service"
}
install -d -m 755 /etc/cart-bridge
for role in tx rx; do
gen_unit "$role"
conf="/etc/cart-bridge/$role.env"
if [ ! -e "$conf" ]; then
install -m 600 "$SELF/cart-bridge-$role.env.example" "$conf"
echo "создан конфиг $conf (ОТРЕДАКТИРУЙ: peer/bind и ключ)"
else
echo "конфиг $conf уже есть — не трогаю"
fi
done
systemctl daemon-reload
enable_one() { # <role>
systemctl enable --now "cart-bridge-$1.service"
echo "включена и запущена cart-bridge-$1.service"
}
case "$ENABLE" in
tx) enable_one tx ;;
rx) enable_one rx ;;
both) enable_one tx; enable_one rx ;;
none) echo "юниты установлены, не включены. Включить: systemctl enable --now cart-bridge-tx (или -rx)";;
esac
echo "готово. Логи: journalctl -u cart-bridge-tx -f (или -rx)"