Rewrite services

This commit is contained in:
2026-01-28 00:06:40 +03:00
parent 8b10cb1d9f
commit 042a44ffb7
9 changed files with 146 additions and 807 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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_<SECTION>__<KEY>
# Переопределение интерфейсов (через запятую)
# CAN_SNIFFER_CAN__INTERFACES="can0,can1"
# Переопределение PostgreSQL хоста
# CAN_SNIFFER_POSTGRESQL__HOST="192.168.1.100"
# Переопределение уровня логирования
# CAN_SNIFFER_LOGGING__LEVEL="DEBUG"

View File

@@ -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

View File

@@ -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 ""

View File

@@ -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 "Готово!"

View File

@@ -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 "Готово!"

View File

@@ -6,6 +6,7 @@
"""
import signal
import subprocess
import sys
import time
from config import config