diff --git a/can_sniffer/deploy/README.md b/can_sniffer/deploy/README.md index 9af0f83..cf195ce 100644 --- a/can_sniffer/deploy/README.md +++ b/can_sniffer/deploy/README.md @@ -1,288 +1,32 @@ -# CAN Sniffer Deployment for Raspberry Pi 5 - -Автоматическое развёртывание CAN Sniffer с systemd на Raspberry Pi 5 с 2-CH CAN HAT. - -## Архитектура - -``` -Boot - │ - ▼ -systemd-modules-load (SPI модули) - │ - ▼ -can-setup.service (OneShot) - │ - ip link set can0 type can bitrate 1000000 - │ - ip link set can0 up - │ - ip link set can1 type can bitrate 1000000 - │ - ip link set can1 up - │ - ▼ -can-sniffer.service - │ - python main.py - │ - Чтение CAN → SQLite → PostgreSQL - │ - ▼ -Running... -``` - -## Требования - -### Hardware -- Raspberry Pi 5 -- 2-CH CAN HAT (MCP2515 или MCP251xFD) -- Flipper Zero (опционально, для мониторинга) - -### Software -- Raspberry Pi OS Bookworm (64-bit recommended) -- Python 3.11+ -- Настроенный overlay для CAN HAT - -## Настройка CAN HAT - -Перед установкой убедитесь, что CAN HAT настроен в `/boot/firmware/config.txt`: - -### Для MCP2515 (стандартный CAN): -```ini -# Enable SPI -dtparam=spi=on - -# Waveshare 2-CH CAN HAT (MCP2515) -dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25 -dtoverlay=mcp2515-can1,oscillator=16000000,interrupt=24 -``` - -### Для MCP251xFD (CAN FD): -```ini -# Enable SPI -dtparam=spi=on - -# Waveshare 2-CH CAN FD HAT (MCP251xFD) -dtoverlay=mcp251xfd,spi0-0,oscillator=40000000,interrupt=25 -dtoverlay=mcp251xfd,spi0-1,oscillator=40000000,interrupt=24 -``` - -После изменения config.txt требуется перезагрузка: -```bash -sudo reboot -``` - -Проверка после перезагрузки: -```bash -ip link show | grep can -# Должны появиться can0 и can1 -``` - -## Настройка UART для Flipper Zero - -Для работы с Flipper Zero через UART (`/dev/ttyAMA0`) необходимо: - -### 1. Отключить serial console -```bash -sudo raspi-config -# Interface Options → Serial Port -# - Login shell over serial: NO -# - Serial port hardware enabled: YES -``` - -### 2. Добавить в `/boot/firmware/config.txt`: -```ini -# Enable UART -enable_uart=1 - -# На RPI5 освобождаем ttyAMA0 от Bluetooth -# Вариант 1: Полностью отключить BT (рекомендуется) -dtoverlay=disable-bt - -# Вариант 2: Переместить BT на mini-UART -# dtoverlay=miniuart-bt -``` - -### 3. Перезагрузить и проверить: -```bash -sudo reboot - -# После перезагрузки -ls -la /dev/ttyAMA0 -# Должен показать устройство - -# Тест чтения (Ctrl+C для выхода) -cat /dev/ttyAMA0 -``` - -### 4. Подключение Flipper Zero -| Flipper Pin | RPI5 Pin | -|-------------|----------| -| TX | GPIO15 (RXD) | -| RX | GPIO14 (TXD) | -| GND | GND | +# CAN Sniffer - Deployment ## Установка -### 1. Клонирование репозитория -```bash -cd /home/pi -git clone https://github.com/your-repo/carpibord.git -cd carpibord/can_sniffer/deploy -``` - -### 2. Запуск установщика ```bash +cd can_sniffer/deploy sudo ./install.sh ``` -Установщик автоматически: -- Проверит зависимости (python3, can-utils) -- Создаст директории `/opt/can_sniffer/{data,logs}` -- Установит Python venv и зависимости -- Скопирует production конфиг -- Установит systemd сервисы -- Включит автозапуск - -### 3. Проверка статуса -```bash -sudo systemctl status can-setup -sudo systemctl status can-sniffer -``` - ## Конфигурация -### Основной конфиг -```bash -sudo nano /opt/can_sniffer/src/config.json -``` +| Файл | Описание | +|------|----------| +| `/opt/can_sniffer/src/config.json` | Основной конфиг приложения | +| `/etc/default/can-interfaces` | Настройки CAN шины (bitrate, интерфейсы) | -### Переопределение через environment -Редактируйте `/etc/default/can-sniffer`: +## Управление ```bash -# CAN interfaces (для can-setup.service) -CAN_INTERFACES="can0 can1" -CAN_BITRATE=1000000 - -# Переопределение config.json (для can-sniffer.service) -CAN_SNIFFER_CAN__INTERFACES="can0,can1" -CAN_SNIFFER_POSTGRESQL__HOST="192.168.1.100" -CAN_SNIFFER_LOGGING__LEVEL="DEBUG" -``` - -После изменений: -```bash -sudo systemctl restart can-sniffer -``` - -## Управление сервисами - -```bash -# Статус -sudo systemctl status can-sniffer -sudo systemctl status can-setup - -# Запуск/остановка -sudo systemctl start can-sniffer -sudo systemctl stop can-sniffer - -# Перезапуск -sudo systemctl restart can-sniffer - -# Просмотр логов -sudo journalctl -u can-sniffer -f -sudo journalctl -u can-sniffer --since "1 hour ago" - -# Логи приложения -tail -f /opt/can_sniffer/logs/can_edge.log +systemctl start can-sniffer # Запуск +systemctl stop can-sniffer # Остановка +systemctl status can-sniffer # Статус +journalctl -u can-sniffer -f # Логи ``` ## Диагностика -### Проверка CAN интерфейсов ```bash -# Статус интерфейсов -ip -details link show can0 -ip -details link show can1 - -# Статистика -ip -s link show can0 - -# Прослушивание (can-utils) -candump can0 can1 -``` - -### Частые проблемы - -#### 1. CAN интерфейсы не появляются -```bash -# Проверить overlay -dmesg | grep -i can -dmesg | grep -i mcp - -# Проверить SPI -ls /dev/spidev* -``` - -#### 2. Ошибка "Network is down" -```bash -# Перезапустить can-setup -sudo systemctl restart can-setup -sudo ip link show can0 -``` - -#### 3. Ошибка доступа к CAN сокету -```bash -# Проверить capabilities в systemd -sudo journalctl -u can-sniffer | grep -i denied - -# Или запустить вручную для теста -sudo /opt/can_sniffer/venv/bin/python /opt/can_sniffer/src/main.py -``` - -#### 4. PostgreSQL недоступен -```bash -# Sniffer работает offline-first, данные сохраняются локально -# Проверить SQLite -ls -la /opt/can_sniffer/data/ - -# Синхронизация произойдёт автоматически когда PostgreSQL станет доступен -``` - -#### 5. Flipper Zero не подключается (нет handshake) - -**Симптомы:** `cat /dev/ttyAMA0` показывает "INIT:flipper", но ACK не отправляется. - -**Проверки:** -```bash -# 1. Проверить что flipper enabled в конфиге -grep -A5 '"flipper"' /opt/can_sniffer/src/config.json -# Должно быть: "enabled": true - -# 2. Проверить что pyserial установлен -/opt/can_sniffer/venv/bin/pip show pyserial - -# 3. Проверить права на UART -ls -la /dev/ttyAMA0 -# crw-rw---- 1 root dialout ... - -# 4. Проверить что пользователь в группе dialout -groups pi -# Должен содержать: dialout - -# 5. Проверить что serial console отключена -sudo dmesg | grep ttyAMA0 -# НЕ должно быть "console [ttyAMA0]" - -# 6. Проверить логи flipper handler -sudo journalctl -u can-sniffer | grep -i flipper -``` - -**Типичные исправления:** -```bash -# Добавить в группу dialout -sudo usermod -aG dialout pi - -# Перезапустить после изменения групп -sudo systemctl restart can-sniffer - -# Или перелогиниться для применения группы +./diagnose.sh ``` ## Удаление @@ -290,34 +34,3 @@ sudo systemctl restart can-sniffer ```bash sudo ./uninstall.sh ``` - -## Структура файлов - -``` -/opt/can_sniffer/ -├── src/ -│ ├── main.py # Entry point -│ ├── config.py # Configuration -│ ├── config.json # Production config -│ └── ... -├── venv/ # Python virtual environment -├── data/ -│ └── can_offline.db # SQLite database -├── logs/ -│ └── can_edge.log # Application logs -└── requirements.txt - -/etc/systemd/system/ -├── can-setup.service # CAN interface setup (OneShot) -└── can-sniffer.service # Main application service - -/etc/default/ -└── can-sniffer # Environment overrides -``` - -## Security Notes - -- Сервис запускается от пользователя `pi` (не root) -- Используется `ProtectSystem=strict` для защиты файловой системы -- Capabilities ограничены `CAP_NET_RAW` и `CAP_NET_ADMIN` для CAN -- Пароль PostgreSQL в config.json - рассмотрите использование secrets diff --git a/can_sniffer/deploy/can-interfaces b/can_sniffer/deploy/can-interfaces new file mode 100644 index 0000000..9afb10e --- /dev/null +++ b/can_sniffer/deploy/can-interfaces @@ -0,0 +1,10 @@ +# /etc/default/can-interfaces +# Настройки CAN интерфейсов для can-setup.service + +# Список интерфейсов (через пробел) +CAN_INTERFACES="can0 can1" + +# Bitrate (бит/с) +# 500000 - стандартный CAN +# 1000000 - High-speed CAN +CAN_BITRATE=500000 diff --git a/can_sniffer/deploy/can-setup.service b/can_sniffer/deploy/can-setup.service index 9d5f259..18b4d6e 100644 --- a/can_sniffer/deploy/can-setup.service +++ b/can_sniffer/deploy/can-setup.service @@ -1,49 +1,31 @@ [Unit] -Description=Setup CAN bus interfaces for 2ch CAN HAT -Documentation=https://github.com/carpibord -After=network-pre.target -Before=network.target -Wants=network-pre.target - -# Ждём пока kernel загрузит модули для CAN HAT -# MCP2515/MCP251xFD появляются после загрузки SPI overlay +Description=Setup CAN interfaces After=systemd-modules-load.service -Requires=systemd-modules-load.service +Before=can-sniffer.service [Service] Type=oneshot RemainAfterExit=yes -# Настройка CAN интерфейсов -# Bitrate: 1000000 (1Mbps) - стандарт для автомобильной CAN шины -# Можно изменить через /etc/default/can-sniffer +# Конфиг CAN интерфейсов +EnvironmentFile=/etc/default/can-interfaces -EnvironmentFile=-/etc/default/can-sniffer -ExecStartPre=/usr/bin/sleep 2 +ExecStartPre=/bin/sleep 2 ExecStart=/bin/bash -c '\ for iface in ${CAN_INTERFACES:-can0 can1}; do \ - if ip link show "$iface" > /dev/null 2>&1; then \ - /sbin/ip link set "$iface" down 2>/dev/null || true; \ - /sbin/ip link set "$iface" type can bitrate ${CAN_BITRATE:-1000000}; \ - /sbin/ip link set "$iface" up; \ - echo "CAN interface $iface configured at ${CAN_BITRATE:-1000000} bps"; \ - else \ - echo "Warning: CAN interface $iface not found"; \ + if ip link show "$iface" 2>/dev/null; then \ + ip link set "$iface" down 2>/dev/null || true; \ + ip link set "$iface" type can bitrate ${CAN_BITRATE:-500000}; \ + ip link set "$iface" up; \ + echo "CAN $iface: UP at ${CAN_BITRATE:-500000} bps"; \ fi; \ - done' + done; \ + exit 0' ExecStop=/bin/bash -c '\ for iface in ${CAN_INTERFACES:-can0 can1}; do \ - if ip link show "$iface" > /dev/null 2>&1; then \ - /sbin/ip link set "$iface" down 2>/dev/null || true; \ - echo "CAN interface $iface stopped"; \ - fi; \ + ip link set "$iface" down 2>/dev/null || true; \ done' -# Логирование через journald -StandardOutput=journal -StandardError=journal -SyslogIdentifier=can-setup - [Install] WantedBy=multi-user.target diff --git a/can_sniffer/deploy/can-sniffer.env b/can_sniffer/deploy/can-sniffer.env deleted file mode 100644 index 6cb6995..0000000 --- a/can_sniffer/deploy/can-sniffer.env +++ /dev/null @@ -1,24 +0,0 @@ -# /etc/default/can-sniffer -# Переменные окружения для can-setup.service и can-sniffer.service - -# === CAN Interface Setup === -# Список интерфейсов через пробел -CAN_INTERFACES="can0 can1" - -# Bitrate (бит/с) - должен совпадать с настройками автомобиля -# 500000 - стандартный CAN -# 1000000 - CAN FD / High-speed CAN -CAN_BITRATE=1000000 - -# === CAN Sniffer Overrides === -# Эти переменные переопределяют config.json -# Формат: CAN_SNIFFER_
__ - -# Переопределение интерфейсов (через запятую) -# CAN_SNIFFER_CAN__INTERFACES="can0,can1" - -# Переопределение PostgreSQL хоста -# CAN_SNIFFER_POSTGRESQL__HOST="192.168.1.100" - -# Переопределение уровня логирования -# CAN_SNIFFER_LOGGING__LEVEL="DEBUG" diff --git a/can_sniffer/deploy/can-sniffer.service b/can_sniffer/deploy/can-sniffer.service index 02cda6f..cee10e1 100644 --- a/can_sniffer/deploy/can-sniffer.service +++ b/can_sniffer/deploy/can-sniffer.service @@ -1,62 +1,33 @@ [Unit] -Description=CAN Bus Sniffer - Offline-first CAN data collector -Documentation=https://github.com/carpibord -After=can-setup.service network.target -Requires=can-setup.service -Wants=postgresql.service - -# Restart при падении, но не слишком часто -StartLimitIntervalSec=300 -StartLimitBurst=5 +Description=CAN Bus Sniffer +After=network.target can-setup.service +Wants=can-setup.service [Service] Type=simple -User=pi -Group=pi - -# Рабочая директория - где будут создаваться логи и БД +User=root WorkingDirectory=/opt/can_sniffer + +# Только PYTHONUNBUFFERED для вывода логов Environment=PYTHONUNBUFFERED=1 -Environment=PYTHONPATH=/opt/can_sniffer/src -# Загрузка переменных окружения для переопределения конфига -EnvironmentFile=-/etc/default/can-sniffer - -# Запуск через venv +# Запуск - config.json читается из /opt/can_sniffer/src/ ExecStart=/opt/can_sniffer/venv/bin/python /opt/can_sniffer/src/main.py -# Graceful shutdown - отправляем SIGTERM, ждём 30 секунд -# main.py уже обрабатывает SIGTERM через signal handler -TimeoutStopSec=30 +# Graceful shutdown +TimeoutStopSec=15 KillSignal=SIGTERM -KillMode=mixed -# Автоматический рестарт при падении (но не при ручной остановке) +# Рестарт при падении Restart=on-failure RestartSec=5 +StartLimitIntervalSec=300 +StartLimitBurst=5 -# Логирование через journald +# Логи StandardOutput=journal StandardError=journal SyslogIdentifier=can-sniffer -# Security hardening (RPI5 совместимо) -# NoNewPrivileges отключен для поддержки sudo (shutdown/reboot) -NoNewPrivileges=no -ProtectSystem=full -ProtectHome=read-only -PrivateTmp=yes -ReadWritePaths=/opt/can_sniffer/data /opt/can_sniffer/logs - -# Разрешаем доступ к CAN сокетам -CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN -AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN - -# Доступ к UART для Flipper Zero (/dev/ttyAMA0) и I2C для UPS -SupplementaryGroups=dialout i2c gpio -DeviceAllow=/dev/ttyAMA0 rw -DeviceAllow=/dev/i2c-1 rw -DeviceAllow=/dev/gpiomem rw - [Install] WantedBy=multi-user.target diff --git a/can_sniffer/deploy/diagnose.sh b/can_sniffer/deploy/diagnose.sh index 434b37e..3ef6df1 100644 --- a/can_sniffer/deploy/diagnose.sh +++ b/can_sniffer/deploy/diagnose.sh @@ -1,219 +1,57 @@ #!/bin/bash # -# CAN Sniffer Diagnostic Script -# Проверяет состояние системы и выводит полезную информацию для отладки +# CAN Sniffer - Diagnostics # -set -e - GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' +ok() { echo -e " ${GREEN}OK${NC} $1"; } +fail() { echo -e " ${RED}FAIL${NC} $1"; } +warn() { echo -e " ${YELLOW}WARN${NC} $1"; } section() { echo -e "\n${BLUE}=== $1 ===${NC}"; } -ok() { echo -e "${GREEN}[OK]${NC} $1"; } -warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } -fail() { echo -e "${RED}[FAIL]${NC} $1"; } -echo -e "${BLUE}╔════════════════════════════════════════╗${NC}" -echo -e "${BLUE}║ CAN Sniffer Diagnostic Report ║${NC}" -echo -e "${BLUE}╚════════════════════════════════════════╝${NC}" -echo "Date: $(date)" -echo "Host: $(hostname)" - -section "System Info" -echo "OS: $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)" -echo "Kernel: $(uname -r)" -echo "Architecture: $(uname -m)" -if [[ -f /proc/device-tree/model ]]; then - echo "Model: $(cat /proc/device-tree/model)" -fi - -section "CAN Kernel Modules" -if lsmod | grep -q "can"; then - lsmod | grep can - ok "CAN modules loaded" -else - fail "No CAN modules loaded" - echo " Try: modprobe can can_raw" -fi - -section "SPI Status" -if ls /dev/spidev* 2>/dev/null; then - ok "SPI devices found" -else - warn "No SPI devices found" - echo " Check: dtparam=spi=on in /boot/firmware/config.txt" -fi +echo "" +echo "========================================" +echo " CAN Sniffer Diagnostics" +echo "========================================" section "CAN Interfaces" -CAN_FOUND=0 for iface in can0 can1; do if ip link show "$iface" &>/dev/null; then - CAN_FOUND=1 - STATE=$(ip link show "$iface" | grep -oP '(?<=state )\w+') - if [[ "$STATE" == "UP" ]]; then - ok "$iface: UP" - else - warn "$iface: $STATE" - fi - # Детали интерфейса - ip -details link show "$iface" 2>/dev/null | grep -E "bitrate|state|mtu" | head -3 | sed 's/^/ /' + STATE=$(ip link show "$iface" | grep -oP '(?<=state )\w+' || echo "?") + [[ "$STATE" == "UP" ]] && ok "$iface: UP" || warn "$iface: $STATE" else fail "$iface: NOT FOUND" fi done -if [[ $CAN_FOUND -eq 0 ]]; then - warn "No CAN interfaces found" - echo " Check CAN HAT overlay in /boot/firmware/config.txt" - echo " Run: dmesg | grep -i mcp" -fi - -section "CAN Statistics" -for iface in can0 can1; do - if ip link show "$iface" &>/dev/null; then - echo "$iface:" - ip -s link show "$iface" 2>/dev/null | grep -E "RX:|TX:|errors" | sed 's/^/ /' - fi -done - -section "Systemd Services" +section "Services" for svc in can-setup can-sniffer; do if systemctl is-enabled "$svc" &>/dev/null; then STATUS=$(systemctl is-active "$svc" 2>/dev/null || echo "inactive") - if [[ "$STATUS" == "active" ]]; then - ok "$svc: $STATUS (enabled)" - else - warn "$svc: $STATUS (enabled)" - fi + [[ "$STATUS" == "active" ]] && ok "$svc: active" || warn "$svc: $STATUS" else - fail "$svc: not installed or disabled" + fail "$svc: not installed" fi done -section "Application Status" +section "Files" INSTALL_DIR="/opt/can_sniffer" -if [[ -d "$INSTALL_DIR" ]]; then - ok "Installation directory exists: $INSTALL_DIR" +[[ -d "$INSTALL_DIR" ]] && ok "Install: $INSTALL_DIR" || fail "Install dir missing" +[[ -f "$INSTALL_DIR/venv/bin/python" ]] && ok "Python venv" || fail "venv missing" +[[ -f "$INSTALL_DIR/src/config.json" ]] && ok "config.json" || fail "config missing" +[[ -f "/etc/default/can-interfaces" ]] && ok "can-interfaces" || warn "can-interfaces missing" - # Check venv - if [[ -f "$INSTALL_DIR/venv/bin/python" ]]; then - ok "Python venv exists" - PYTHON_VERSION=$("$INSTALL_DIR/venv/bin/python" --version 2>&1) - echo " $PYTHON_VERSION" - else - fail "Python venv missing" - fi +section "UART" +[[ -e "/dev/ttyAMA0" ]] && ok "/dev/ttyAMA0" || warn "UART not found" - # Check config - if [[ -f "$INSTALL_DIR/src/config.json" ]]; then - ok "Config file exists" - else - fail "Config file missing" - fi +section "Process" +pgrep -f "can_sniffer.*main.py" > /dev/null && ok "Running" || warn "Not running" - # Check data directory - if [[ -d "$INSTALL_DIR/data" ]]; then - ok "Data directory exists" - if [[ -f "$INSTALL_DIR/data/can_offline.db" ]]; then - DB_SIZE=$(du -h "$INSTALL_DIR/data/can_offline.db" | cut -f1) - echo " SQLite DB size: $DB_SIZE" - fi - else - warn "Data directory missing" - fi +section "Logs (last 5)" +journalctl -u can-sniffer --no-pager -n 5 2>/dev/null || echo " (no logs)" - # Check logs - if [[ -d "$INSTALL_DIR/logs" ]]; then - ok "Logs directory exists" - if [[ -f "$INSTALL_DIR/logs/can_edge.log" ]]; then - LOG_SIZE=$(du -h "$INSTALL_DIR/logs/can_edge.log" | cut -f1) - echo " Log file size: $LOG_SIZE" - fi - fi -else - fail "Installation directory not found: $INSTALL_DIR" -fi - -section "Recent Logs (last 10 lines)" -if systemctl is-active can-sniffer &>/dev/null; then - journalctl -u can-sniffer --no-pager -n 10 2>/dev/null || echo " (no logs available)" -else - echo " Service not running" -fi - -section "Process Check" -if pgrep -f "can_sniffer.*main.py" > /dev/null; then - ok "CAN Sniffer process running" - ps aux | grep "[c]an_sniffer.*main.py" | sed 's/^/ /' -else - warn "CAN Sniffer process not running" -fi - -section "UART / Flipper Zero" -UART_DEV="/dev/ttyAMA0" -if [[ -e "$UART_DEV" ]]; then - ok "UART device exists: $UART_DEV" - ls -la "$UART_DEV" | sed 's/^/ /' - - # Проверить права - if [[ -r "$UART_DEV" ]] && [[ -w "$UART_DEV" ]]; then - ok "UART readable/writable by current user" - else - warn "UART not accessible by current user" - echo " Check: sudo usermod -aG dialout \$USER" - fi - - # Проверить serial console - if dmesg 2>/dev/null | grep -q "console \[ttyAMA0\]"; then - fail "Serial console is using ttyAMA0!" - echo " Disable via: sudo raspi-config -> Interface Options -> Serial Port" - else - ok "Serial console not blocking ttyAMA0" - fi -else - warn "UART device not found: $UART_DEV" - echo " Check /boot/firmware/config.txt: enable_uart=1" -fi - -# Проверить конфиг flipper -if [[ -f "$INSTALL_DIR/src/config.json" ]]; then - FLIPPER_ENABLED=$(grep -A2 '"flipper"' "$INSTALL_DIR/src/config.json" | grep '"enabled"' | grep -oE '(true|false)') - if [[ "$FLIPPER_ENABLED" == "true" ]]; then - ok "Flipper handler enabled in config" - else - warn "Flipper handler DISABLED in config" - fi -fi - -# Проверить pyserial -if [[ -f "$INSTALL_DIR/venv/bin/pip" ]]; then - if "$INSTALL_DIR/venv/bin/pip" show pyserial &>/dev/null; then - ok "pyserial installed" - else - fail "pyserial NOT installed" - echo " Install: $INSTALL_DIR/venv/bin/pip install pyserial" - fi -fi - -section "Network (PostgreSQL target)" -# Извлекаем хост из конфига -if [[ -f "$INSTALL_DIR/src/config.json" ]]; then - PG_HOST=$(grep -oP '"host":\s*"\K[^"]+' "$INSTALL_DIR/src/config.json" | head -1) - PG_PORT=$(grep -oP '"port":\s*\K\d+' "$INSTALL_DIR/src/config.json" | head -1) - if [[ -n "$PG_HOST" ]]; then - echo "PostgreSQL target: $PG_HOST:${PG_PORT:-5432}" - if timeout 2 bash -c "echo >/dev/tcp/$PG_HOST/${PG_PORT:-5432}" 2>/dev/null; then - ok "PostgreSQL port reachable" - else - warn "PostgreSQL port not reachable (offline mode active)" - fi - fi -fi - -section "dmesg CAN/SPI Errors (last 5)" -dmesg | grep -iE "(can|mcp|spi).*error" | tail -5 || echo " (no errors found)" - -echo -e "\n${BLUE}=== Diagnostic Complete ===${NC}\n" +echo "" diff --git a/can_sniffer/deploy/install.sh b/can_sniffer/deploy/install.sh index 6a1a86a..886ee38 100644 --- a/can_sniffer/deploy/install.sh +++ b/can_sniffer/deploy/install.sh @@ -1,233 +1,95 @@ #!/bin/bash # -# CAN Sniffer Installation Script for Raspberry Pi 5 -# Устанавливает сервисы автозапуска для can_sniffer +# CAN Sniffer - Installation Script # set -e -# Цвета для вывода RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' -NC='\033[0m' # No Color +NC='\033[0m' -log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } -log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } -log_error() { echo -e "${RED}[ERROR]${NC} $1"; } +log() { echo -e "${GREEN}[*]${NC} $1"; } +warn() { echo -e "${YELLOW}[!]${NC} $1"; } +error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } -# Проверка root прав -if [[ $EUID -ne 0 ]]; then - log_error "Этот скрипт должен запускаться с правами root" - echo "Используйте: sudo $0" - exit 1 -fi +[[ $EUID -ne 0 ]] && error "Запустите с sudo: sudo $0" -# Определение директорий SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" INSTALL_DIR="/opt/can_sniffer" -DATA_DIR="$INSTALL_DIR/data" -LOGS_DIR="$INSTALL_DIR/logs" -SYSTEMD_DIR="/etc/systemd/system" -log_info "=== CAN Sniffer Installation ===" -log_info "Source: $PROJECT_DIR" -log_info "Target: $INSTALL_DIR" +echo "" +echo "==================================" +echo " CAN Sniffer Installation" +echo "==================================" +echo "" -# === 1. Проверка системных зависимостей === -log_info "Checking system dependencies..." +# 1. Системные пакеты +log "Установка системных пакетов..." +apt-get update -qq +apt-get install -y -qq python3 python3-pip python3-venv can-utils -# Проверка python3 -if ! command -v python3 &> /dev/null; then - log_error "Python3 not found. Installing..." - apt-get update && apt-get install -y python3 python3-pip python3-venv -fi +# 2. Директории +log "Создание директорий..." +mkdir -p "$INSTALL_DIR"/{data,logs} -# Проверка can-utils (для диагностики) -if ! command -v candump &> /dev/null; then - log_warn "can-utils not found. Installing..." - apt-get update && apt-get install -y can-utils -fi - -# === 2. Проверка CAN overlay в config.txt === -log_info "Checking CAN HAT overlay configuration..." - -CONFIG_TXT="/boot/firmware/config.txt" -if [[ ! -f "$CONFIG_TXT" ]]; then - CONFIG_TXT="/boot/config.txt" -fi - -if [[ -f "$CONFIG_TXT" ]]; then - # Проверяем наличие MCP2515 overlay (типичный для 2ch CAN HAT) - if ! grep -q "mcp2515" "$CONFIG_TXT" && ! grep -q "mcp251xfd" "$CONFIG_TXT"; then - log_warn "CAN HAT overlay not found in $CONFIG_TXT" - log_warn "You may need to add overlay for your CAN HAT. Example for MCP2515:" - echo "" - echo " # For Waveshare 2-CH CAN HAT:" - echo " dtparam=spi=on" - echo " dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25" - echo " dtoverlay=mcp2515-can1,oscillator=16000000,interrupt=24" - echo "" - echo " # Or for MCP251xFD (CAN FD):" - echo " dtparam=spi=on" - echo " dtoverlay=mcp251xfd,spi0-0,oscillator=40000000,interrupt=25" - echo " dtoverlay=mcp251xfd,spi0-1,oscillator=40000000,interrupt=24" - echo "" - read -p "Continue installation anyway? [y/N] " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - exit 1 - fi - else - log_info "CAN HAT overlay found in config.txt" - fi - - # Проверяем UART для Flipper Zero - if ! grep -q "enable_uart=1" "$CONFIG_TXT"; then - log_warn "UART not enabled in $CONFIG_TXT" - log_warn "For Flipper Zero support, add to $CONFIG_TXT:" - echo "" - echo " enable_uart=1" - echo " dtoverlay=disable-bt # или dtoverlay=miniuart-bt" - echo "" - else - log_info "UART enabled in config.txt" - fi -fi - -# Проверяем что serial console отключена -if grep -q "console=serial0" /boot/firmware/cmdline.txt 2>/dev/null || \ - grep -q "console=ttyAMA0" /boot/firmware/cmdline.txt 2>/dev/null; then - log_warn "Serial console may be using ttyAMA0!" - log_warn "Disable via: sudo raspi-config -> Interface Options -> Serial Port" -fi - -# === 3. Создание директорий === -log_info "Creating directories..." - -mkdir -p "$INSTALL_DIR" -mkdir -p "$DATA_DIR" -mkdir -p "$LOGS_DIR" - -# === 4. Копирование файлов проекта === -log_info "Copying project files..." - -# Копируем src +# 3. Копирование проекта +log "Копирование файлов..." cp -r "$PROJECT_DIR/src" "$INSTALL_DIR/" - -# Копируем requirements.txt cp "$PROJECT_DIR/requirements.txt" "$INSTALL_DIR/" -# Копируем production config как основной +# Используем production конфиг cp "$SCRIPT_DIR/config.production.json" "$INSTALL_DIR/src/config.json" -# === 5. Создание виртуального окружения === -log_info "Creating Python virtual environment..." +# 4. Python venv +log "Создание Python окружения..." +python3 -m venv "$INSTALL_DIR/venv" +"$INSTALL_DIR/venv/bin/pip" install -q --upgrade pip +"$INSTALL_DIR/venv/bin/pip" install -q -r "$INSTALL_DIR/requirements.txt" -if [[ ! -d "$INSTALL_DIR/venv" ]]; then - python3 -m venv "$INSTALL_DIR/venv" -fi - -# Устанавливаем зависимости -log_info "Installing Python dependencies..." -"$INSTALL_DIR/venv/bin/pip" install --upgrade pip -"$INSTALL_DIR/venv/bin/pip" install -r "$INSTALL_DIR/requirements.txt" - -# === 6. Настройка прав доступа === -log_info "Setting permissions..." - -# Определяем пользователя (pi или текущий sudo user) -if id "pi" &>/dev/null; then - SERVICE_USER="pi" -else - SERVICE_USER="${SUDO_USER:-root}" -fi - -log_info "Service will run as user: $SERVICE_USER" - -chown -R "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR" +# 5. Права +log "Настройка прав..." chmod -R 755 "$INSTALL_DIR" -chmod 700 "$DATA_DIR" -chmod 755 "$LOGS_DIR" +chmod 700 "$INSTALL_DIR/data" -# Добавляем пользователя в группы для доступа к CAN, UART и I2C -usermod -aG dialout "$SERVICE_USER" 2>/dev/null || true -usermod -aG plugdev "$SERVICE_USER" 2>/dev/null || true -usermod -aG i2c "$SERVICE_USER" 2>/dev/null || true -usermod -aG gpio "$SERVICE_USER" 2>/dev/null || true +# 6. Systemd сервисы +log "Установка сервисов..." +cp "$SCRIPT_DIR/can-sniffer.service" /etc/systemd/system/ +cp "$SCRIPT_DIR/can-setup.service" /etc/systemd/system/ -# === 6.1. Настройка sudoers для shutdown/reboot === -log_info "Configuring sudoers for power management..." +# CAN интерфейсы - отдельный конфиг +cp "$SCRIPT_DIR/can-interfaces" /etc/default/can-interfaces -SUDOERS_FILE="/etc/sudoers.d/can-sniffer" -cat > "$SUDOERS_FILE" << EOF -# Allow can_sniffer service user to run power commands without password -$SERVICE_USER ALL=(ALL) NOPASSWD: /sbin/shutdown -$SERVICE_USER ALL=(ALL) NOPASSWD: /sbin/reboot -$SERVICE_USER ALL=(ALL) NOPASSWD: /usr/sbin/shutdown -$SERVICE_USER ALL=(ALL) NOPASSWD: /usr/sbin/reboot -EOF -chmod 440 "$SUDOERS_FILE" -log_info "Sudoers configured for user: $SERVICE_USER" - -# === 7. Установка systemd сервисов === -log_info "Installing systemd services..." - -# Обновляем user в service файле -sed "s/User=pi/User=$SERVICE_USER/g; s/Group=pi/Group=$SERVICE_USER/g" \ - "$SCRIPT_DIR/can-sniffer.service" > "$SYSTEMD_DIR/can-sniffer.service" - -# Копируем can-setup service -cp "$SCRIPT_DIR/can-setup.service" "$SYSTEMD_DIR/" - -# Копируем environment file -cp "$SCRIPT_DIR/can-sniffer.env" "/etc/default/can-sniffer" - -# Перезагрузка systemd systemctl daemon-reload - -# === 8. Включение сервисов === -log_info "Enabling services..." - systemctl enable can-setup.service systemctl enable can-sniffer.service -# === 9. Итоговая информация === +# Готово echo "" -log_info "=== Installation Complete ===" +echo "==================================" +echo " Установка завершена!" +echo "==================================" echo "" -echo "Installed components:" -echo " - CAN Setup Service: $SYSTEMD_DIR/can-setup.service" -echo " - CAN Sniffer Service: $SYSTEMD_DIR/can-sniffer.service" -echo " - Environment config: /etc/default/can-sniffer" -echo " - Application: $INSTALL_DIR" -echo " - Data directory: $DATA_DIR" -echo " - Logs directory: $LOGS_DIR" +echo "Конфиги:" +echo " Приложение: $INSTALL_DIR/src/config.json" +echo " CAN шина: /etc/default/can-interfaces" echo "" -echo "Configuration:" -echo " - Main config: $INSTALL_DIR/src/config.json" -echo " - Edit /etc/default/can-sniffer to override settings" -echo "" -echo "Commands:" -echo " sudo systemctl start can-setup # Start CAN interfaces" -echo " sudo systemctl start can-sniffer # Start sniffer" -echo " sudo systemctl status can-sniffer # Check status" -echo " sudo journalctl -u can-sniffer -f # View logs" -echo "" -echo "To start now (without reboot):" -echo " sudo systemctl start can-setup && sudo systemctl start can-sniffer" +echo "Команды:" +echo " systemctl start can-sniffer" +echo " systemctl status can-sniffer" +echo " journalctl -u can-sniffer -f" echo "" -# Спрашиваем о немедленном запуске -read -p "Start services now? [y/N] " -n 1 -r +read -p "Запустить сейчас? [Y/n] " -n 1 -r echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - log_info "Starting services..." - systemctl start can-setup - sleep 2 - systemctl start can-sniffer +if [[ ! $REPLY =~ ^[Nn]$ ]]; then + log "Запуск..." + systemctl start can-setup || warn "can-setup: CAN интерфейсы не найдены" sleep 1 - systemctl status can-sniffer --no-pager + systemctl start can-sniffer + sleep 2 + systemctl status can-sniffer --no-pager || true fi -log_info "Done!" +log "Готово!" diff --git a/can_sniffer/deploy/uninstall.sh b/can_sniffer/deploy/uninstall.sh index 6643c8e..ab3d8bb 100644 --- a/can_sniffer/deploy/uninstall.sh +++ b/can_sniffer/deploy/uninstall.sh @@ -1,59 +1,45 @@ #!/bin/bash # -# CAN Sniffer Uninstallation Script +# CAN Sniffer - Uninstall Script # set -e RED='\033[0;31m' GREEN='\033[0;32m' -YELLOW='\033[1;33m' NC='\033[0m' -log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } -log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log() { echo -e "${GREEN}[*]${NC} $1"; } +error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } -if [[ $EUID -ne 0 ]]; then - echo -e "${RED}[ERROR]${NC} Run with sudo" - exit 1 -fi +[[ $EUID -ne 0 ]] && error "Запустите с sudo: sudo $0" INSTALL_DIR="/opt/can_sniffer" -SYSTEMD_DIR="/etc/systemd/system" -log_info "=== CAN Sniffer Uninstallation ===" +echo "" +echo "==================================" +echo " CAN Sniffer Uninstall" +echo "==================================" +echo "" -# Остановка сервисов -log_info "Stopping services..." +log "Остановка сервисов..." systemctl stop can-sniffer 2>/dev/null || true systemctl stop can-setup 2>/dev/null || true -# Отключение сервисов -log_info "Disabling services..." +log "Отключение автозапуска..." systemctl disable can-sniffer 2>/dev/null || true systemctl disable can-setup 2>/dev/null || true -# Удаление systemd файлов -log_info "Removing systemd files..." -rm -f "$SYSTEMD_DIR/can-sniffer.service" -rm -f "$SYSTEMD_DIR/can-setup.service" -rm -f "/etc/default/can-sniffer" - +log "Удаление systemd файлов..." +rm -f /etc/systemd/system/can-sniffer.service +rm -f /etc/systemd/system/can-setup.service +rm -f /etc/default/can-interfaces systemctl daemon-reload -# Спрашиваем про удаление данных -echo "" -read -p "Remove application data ($INSTALL_DIR/data)? [y/N] " -n 1 -r +read -p "Удалить приложение ($INSTALL_DIR)? [y/N] " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then - log_warn "Removing data directory..." - rm -rf "$INSTALL_DIR/data" -fi - -read -p "Remove entire installation ($INSTALL_DIR)? [y/N] " -n 1 -r -echo -if [[ $REPLY =~ ^[Yy]$ ]]; then - log_warn "Removing installation directory..." + log "Удаление $INSTALL_DIR..." rm -rf "$INSTALL_DIR" fi -log_info "Uninstallation complete!" +log "Готово!" diff --git a/can_sniffer/src/main.py b/can_sniffer/src/main.py index e900e21..f6c006f 100644 --- a/can_sniffer/src/main.py +++ b/can_sniffer/src/main.py @@ -6,6 +6,7 @@ """ import signal +import subprocess import sys import time from config import config