diff --git a/can_sniffer/README.md b/can_sniffer/README.md index 2980ff8..a7adeea 100644 --- a/can_sniffer/README.md +++ b/can_sniffer/README.md @@ -49,9 +49,11 @@ pip install -r requirements.txt # Проверка доступных интерфейсов ip link show -# Настройка интерфейса (пример) -sudo ip link set can0 type can bitrate 500000 +# Настройка интерфейса (пример для 1Mbps) +sudo ip link set can0 type can bitrate 1000000 sudo ip link set can0 up +sudo ip link set can1 type can bitrate 1000000 +sudo ip link set can1 up ``` ### 4. Конфигурация @@ -82,7 +84,33 @@ sudo ip link set can0 up } ``` -## 🎮 Использование +## Deployment (Raspberry Pi 5) + +Для автоматического запуска на Raspberry Pi 5 с 2-CH CAN HAT используйте скрипты из `deploy/`: + +```bash +# Установка с автозапуском через systemd +cd deploy +sudo ./install.sh +``` + +Установщик автоматически: +- Настроит CAN интерфейсы при загрузке (`can-setup.service`) +- Запустит sniffer как systemd сервис (`can-sniffer.service`) +- Создаст директории для данных и логов в `/opt/can_sniffer/` + +Подробная документация: [deploy/README.md](deploy/README.md) + +```bash +# Управление сервисом +sudo systemctl status can-sniffer +sudo journalctl -u can-sniffer -f + +# Диагностика +sudo ./deploy/diagnose.sh +``` + +## Использование ### Базовый запуск diff --git a/can_sniffer/deploy/README.md b/can_sniffer/deploy/README.md new file mode 100644 index 0000000..c80ac4a --- /dev/null +++ b/can_sniffer/deploy/README.md @@ -0,0 +1,238 @@ +# 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) + +### 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 +``` + +## Установка + +### 1. Клонирование репозитория +```bash +cd /home/pi +git clone https://github.com/your-repo/carpibord.git +cd carpibord/can_sniffer/deploy +``` + +### 2. Запуск установщика +```bash +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 +``` + +### Переопределение через 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 +``` + +## Диагностика + +### Проверка 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 станет доступен +``` + +## Удаление + +```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-setup.service b/can_sniffer/deploy/can-setup.service new file mode 100644 index 0000000..9d5f259 --- /dev/null +++ b/can_sniffer/deploy/can-setup.service @@ -0,0 +1,49 @@ +[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 +After=systemd-modules-load.service +Requires=systemd-modules-load.service + +[Service] +Type=oneshot +RemainAfterExit=yes + +# Настройка CAN интерфейсов +# Bitrate: 1000000 (1Mbps) - стандарт для автомобильной CAN шины +# Можно изменить через /etc/default/can-sniffer + +EnvironmentFile=-/etc/default/can-sniffer +ExecStartPre=/usr/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"; \ + fi; \ + done' + +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; \ + 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 new file mode 100644 index 0000000..6cb6995 --- /dev/null +++ b/can_sniffer/deploy/can-sniffer.env @@ -0,0 +1,24 @@ +# /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 new file mode 100644 index 0000000..64799eb --- /dev/null +++ b/can_sniffer/deploy/can-sniffer.service @@ -0,0 +1,55 @@ +[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 + +[Service] +Type=simple +User=pi +Group=pi + +# Рабочая директория - где будут создаваться логи и БД +WorkingDirectory=/opt/can_sniffer +Environment=PYTHONUNBUFFERED=1 +Environment=PYTHONPATH=/opt/can_sniffer/src + +# Загрузка переменных окружения для переопределения конфига +EnvironmentFile=-/etc/default/can-sniffer + +# Запуск через venv +ExecStart=/opt/can_sniffer/venv/bin/python /opt/can_sniffer/src/main.py + +# Graceful shutdown - отправляем SIGTERM, ждём 30 секунд +# main.py уже обрабатывает SIGTERM через signal handler +TimeoutStopSec=30 +KillSignal=SIGTERM +KillMode=mixed + +# Автоматический рестарт при падении (но не при ручной остановке) +Restart=on-failure +RestartSec=5 + +# Логирование через journald +StandardOutput=journal +StandardError=journal +SyslogIdentifier=can-sniffer + +# Security hardening (RPI5 совместимо) +NoNewPrivileges=yes +ProtectSystem=strict +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 + +[Install] +WantedBy=multi-user.target diff --git a/can_sniffer/deploy/config.production.json b/can_sniffer/deploy/config.production.json new file mode 100644 index 0000000..4427ab7 --- /dev/null +++ b/can_sniffer/deploy/config.production.json @@ -0,0 +1,50 @@ +{ + "can": { + "interfaces": ["can0", "can1"], + "listen_only": true, + "bitrate": 1000000, + "filters": [] + }, + "storage": { + "type": "sqlite", + "database_path": "/opt/can_sniffer/data/can_offline.db", + "wal_mode": true, + "sync_mode": "NORMAL", + "retention_days": 7 + }, + "postgresql": { + "enabled": true, + "host": "100.74.164.1", + "port": 5433, + "database": "carpibord", + "user": "carpibord", + "password": "carpibord", + "batch_size": 10000, + "flush_interval": 5, + "max_retries": 3, + "retry_backoff": 1.0, + "connection_pool_size": 5, + "connection_timeout": 10, + "sync_interval": 30.0 + }, + "flipper": { + "enabled": false, + "device": "/dev/ttyAMA0", + "baudrate": 115200, + "send_interval": 1.0 + }, + "logging": { + "level": "INFO", + "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s", + "file": "/opt/can_sniffer/logs/can_edge.log", + "max_bytes": 10485760, + "backup_count": 5 + }, + "general": { + "buffer_size": 100000, + "batch_size": 10000, + "batch_interval": 0.1, + "max_retries": 3, + "retry_delay": 1.0 + } +} diff --git a/can_sniffer/deploy/diagnose.sh b/can_sniffer/deploy/diagnose.sh new file mode 100644 index 0000000..8b990f3 --- /dev/null +++ b/can_sniffer/deploy/diagnose.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# +# CAN Sniffer Diagnostic Script +# Проверяет состояние системы и выводит полезную информацию для отладки +# +set -e + +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +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 + +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/^/ /' + 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" +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 + else + fail "$svc: not installed or disabled" + fi +done + +section "Application Status" +INSTALL_DIR="/opt/can_sniffer" +if [[ -d "$INSTALL_DIR" ]]; then + ok "Installation directory exists: $INSTALL_DIR" + + # 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 + + # Check config + if [[ -f "$INSTALL_DIR/src/config.json" ]]; then + ok "Config file exists" + else + fail "Config file missing" + fi + + # 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 + + # 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 "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" diff --git a/can_sniffer/deploy/install.sh b/can_sniffer/deploy/install.sh new file mode 100644 index 0000000..b6628d1 --- /dev/null +++ b/can_sniffer/deploy/install.sh @@ -0,0 +1,198 @@ +#!/bin/bash +# +# CAN Sniffer Installation Script for Raspberry Pi 5 +# Устанавливает сервисы автозапуска для can_sniffer +# +set -e + +# Цвета для вывода +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } + +# Проверка root прав +if [[ $EUID -ne 0 ]]; then + log_error "Этот скрипт должен запускаться с правами root" + echo "Используйте: sudo $0" + exit 1 +fi + +# Определение директорий +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" + +# === 1. Проверка системных зависимостей === +log_info "Checking system dependencies..." + +# Проверка 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 + +# Проверка 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 +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 +cp -r "$PROJECT_DIR/src" "$INSTALL_DIR/" + +# Копируем requirements.txt +cp "$PROJECT_DIR/requirements.txt" "$INSTALL_DIR/" + +# Копируем production config как основной +cp "$SCRIPT_DIR/config.production.json" "$INSTALL_DIR/src/config.json" + +# === 5. Создание виртуального окружения === +log_info "Creating Python virtual environment..." + +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" +chmod -R 755 "$INSTALL_DIR" +chmod 700 "$DATA_DIR" +chmod 755 "$LOGS_DIR" + +# Добавляем пользователя в группы для доступа к CAN и UART +usermod -aG dialout "$SERVICE_USER" 2>/dev/null || true +usermod -aG plugdev "$SERVICE_USER" 2>/dev/null || true + +# === 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 "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 "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 "" + +# Спрашиваем о немедленном запуске +read -p "Start services now? [y/N] " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + log_info "Starting services..." + systemctl start can-setup + sleep 2 + systemctl start can-sniffer + sleep 1 + systemctl status can-sniffer --no-pager +fi + +log_info "Done!" diff --git a/can_sniffer/deploy/uninstall.sh b/can_sniffer/deploy/uninstall.sh new file mode 100644 index 0000000..6643c8e --- /dev/null +++ b/can_sniffer/deploy/uninstall.sh @@ -0,0 +1,59 @@ +#!/bin/bash +# +# CAN Sniffer Uninstallation 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"; } + +if [[ $EUID -ne 0 ]]; then + echo -e "${RED}[ERROR]${NC} Run with sudo" + exit 1 +fi + +INSTALL_DIR="/opt/can_sniffer" +SYSTEMD_DIR="/etc/systemd/system" + +log_info "=== CAN Sniffer Uninstallation ===" + +# Остановка сервисов +log_info "Stopping services..." +systemctl stop can-sniffer 2>/dev/null || true +systemctl stop can-setup 2>/dev/null || true + +# Отключение сервисов +log_info "Disabling services..." +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" + +systemctl daemon-reload + +# Спрашиваем про удаление данных +echo "" +read -p "Remove application data ($INSTALL_DIR/data)? [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..." + rm -rf "$INSTALL_DIR" +fi + +log_info "Uninstallation complete!"