Add scripts for autoconfig system
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
## Использование
|
||||
|
||||
### Базовый запуск
|
||||
|
||||
|
||||
238
can_sniffer/deploy/README.md
Normal file
238
can_sniffer/deploy/README.md
Normal file
@@ -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
|
||||
49
can_sniffer/deploy/can-setup.service
Normal file
49
can_sniffer/deploy/can-setup.service
Normal file
@@ -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
|
||||
24
can_sniffer/deploy/can-sniffer.env
Normal file
24
can_sniffer/deploy/can-sniffer.env
Normal file
@@ -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_<SECTION>__<KEY>
|
||||
|
||||
# Переопределение интерфейсов (через запятую)
|
||||
# CAN_SNIFFER_CAN__INTERFACES="can0,can1"
|
||||
|
||||
# Переопределение PostgreSQL хоста
|
||||
# CAN_SNIFFER_POSTGRESQL__HOST="192.168.1.100"
|
||||
|
||||
# Переопределение уровня логирования
|
||||
# CAN_SNIFFER_LOGGING__LEVEL="DEBUG"
|
||||
55
can_sniffer/deploy/can-sniffer.service
Normal file
55
can_sniffer/deploy/can-sniffer.service
Normal file
@@ -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
|
||||
50
can_sniffer/deploy/config.production.json
Normal file
50
can_sniffer/deploy/config.production.json
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
173
can_sniffer/deploy/diagnose.sh
Normal file
173
can_sniffer/deploy/diagnose.sh
Normal file
@@ -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"
|
||||
198
can_sniffer/deploy/install.sh
Normal file
198
can_sniffer/deploy/install.sh
Normal file
@@ -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!"
|
||||
59
can_sniffer/deploy/uninstall.sh
Normal file
59
can_sniffer/deploy/uninstall.sh
Normal file
@@ -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!"
|
||||
Reference in New Issue
Block a user