Rewrite services
This commit is contained in:
@@ -1,288 +1,32 @@
|
|||||||
# CAN Sniffer Deployment for Raspberry Pi 5
|
# CAN Sniffer - Deployment
|
||||||
|
|
||||||
Автоматическое развёртывание 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 |
|
|
||||||
|
|
||||||
## Установка
|
## Установка
|
||||||
|
|
||||||
### 1. Клонирование репозитория
|
|
||||||
```bash
|
|
||||||
cd /home/pi
|
|
||||||
git clone https://github.com/your-repo/carpibord.git
|
|
||||||
cd carpibord/can_sniffer/deploy
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Запуск установщика
|
|
||||||
```bash
|
```bash
|
||||||
|
cd can_sniffer/deploy
|
||||||
sudo ./install.sh
|
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
|
```bash
|
||||||
# CAN interfaces (для can-setup.service)
|
systemctl start can-sniffer # Запуск
|
||||||
CAN_INTERFACES="can0 can1"
|
systemctl stop can-sniffer # Остановка
|
||||||
CAN_BITRATE=1000000
|
systemctl status can-sniffer # Статус
|
||||||
|
journalctl -u can-sniffer -f # Логи
|
||||||
# Переопределение 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
|
```bash
|
||||||
# Статус интерфейсов
|
./diagnose.sh
|
||||||
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
|
|
||||||
|
|
||||||
# Или перелогиниться для применения группы
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Удаление
|
## Удаление
|
||||||
@@ -290,34 +34,3 @@ sudo systemctl restart can-sniffer
|
|||||||
```bash
|
```bash
|
||||||
sudo ./uninstall.sh
|
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
|
|
||||||
|
|||||||
10
can_sniffer/deploy/can-interfaces
Normal file
10
can_sniffer/deploy/can-interfaces
Normal 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
|
||||||
@@ -1,49 +1,31 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Setup CAN bus interfaces for 2ch CAN HAT
|
Description=Setup CAN interfaces
|
||||||
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
|
After=systemd-modules-load.service
|
||||||
Requires=systemd-modules-load.service
|
Before=can-sniffer.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
RemainAfterExit=yes
|
RemainAfterExit=yes
|
||||||
|
|
||||||
# Настройка CAN интерфейсов
|
# Конфиг CAN интерфейсов
|
||||||
# Bitrate: 1000000 (1Mbps) - стандарт для автомобильной CAN шины
|
EnvironmentFile=/etc/default/can-interfaces
|
||||||
# Можно изменить через /etc/default/can-sniffer
|
|
||||||
|
|
||||||
EnvironmentFile=-/etc/default/can-sniffer
|
ExecStartPre=/bin/sleep 2
|
||||||
ExecStartPre=/usr/bin/sleep 2
|
|
||||||
ExecStart=/bin/bash -c '\
|
ExecStart=/bin/bash -c '\
|
||||||
for iface in ${CAN_INTERFACES:-can0 can1}; do \
|
for iface in ${CAN_INTERFACES:-can0 can1}; do \
|
||||||
if ip link show "$iface" > /dev/null 2>&1; then \
|
if ip link show "$iface" 2>/dev/null; then \
|
||||||
/sbin/ip link set "$iface" down 2>/dev/null || true; \
|
ip link set "$iface" down 2>/dev/null || true; \
|
||||||
/sbin/ip link set "$iface" type can bitrate ${CAN_BITRATE:-1000000}; \
|
ip link set "$iface" type can bitrate ${CAN_BITRATE:-500000}; \
|
||||||
/sbin/ip link set "$iface" up; \
|
ip link set "$iface" up; \
|
||||||
echo "CAN interface $iface configured at ${CAN_BITRATE:-1000000} bps"; \
|
echo "CAN $iface: UP at ${CAN_BITRATE:-500000} bps"; \
|
||||||
else \
|
|
||||||
echo "Warning: CAN interface $iface not found"; \
|
|
||||||
fi; \
|
fi; \
|
||||||
done'
|
done; \
|
||||||
|
exit 0'
|
||||||
|
|
||||||
ExecStop=/bin/bash -c '\
|
ExecStop=/bin/bash -c '\
|
||||||
for iface in ${CAN_INTERFACES:-can0 can1}; do \
|
for iface in ${CAN_INTERFACES:-can0 can1}; do \
|
||||||
if ip link show "$iface" > /dev/null 2>&1; then \
|
ip link set "$iface" down 2>/dev/null || true; \
|
||||||
/sbin/ip link set "$iface" down 2>/dev/null || true; \
|
|
||||||
echo "CAN interface $iface stopped"; \
|
|
||||||
fi; \
|
|
||||||
done'
|
done'
|
||||||
|
|
||||||
# Логирование через journald
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
SyslogIdentifier=can-setup
|
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
@@ -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"
|
|
||||||
@@ -1,62 +1,33 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=CAN Bus Sniffer - Offline-first CAN data collector
|
Description=CAN Bus Sniffer
|
||||||
Documentation=https://github.com/carpibord
|
After=network.target can-setup.service
|
||||||
After=can-setup.service network.target
|
Wants=can-setup.service
|
||||||
Requires=can-setup.service
|
|
||||||
Wants=postgresql.service
|
|
||||||
|
|
||||||
# Restart при падении, но не слишком часто
|
|
||||||
StartLimitIntervalSec=300
|
|
||||||
StartLimitBurst=5
|
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=pi
|
User=root
|
||||||
Group=pi
|
|
||||||
|
|
||||||
# Рабочая директория - где будут создаваться логи и БД
|
|
||||||
WorkingDirectory=/opt/can_sniffer
|
WorkingDirectory=/opt/can_sniffer
|
||||||
|
|
||||||
|
# Только PYTHONUNBUFFERED для вывода логов
|
||||||
Environment=PYTHONUNBUFFERED=1
|
Environment=PYTHONUNBUFFERED=1
|
||||||
Environment=PYTHONPATH=/opt/can_sniffer/src
|
|
||||||
|
|
||||||
# Загрузка переменных окружения для переопределения конфига
|
# Запуск - config.json читается из /opt/can_sniffer/src/
|
||||||
EnvironmentFile=-/etc/default/can-sniffer
|
|
||||||
|
|
||||||
# Запуск через venv
|
|
||||||
ExecStart=/opt/can_sniffer/venv/bin/python /opt/can_sniffer/src/main.py
|
ExecStart=/opt/can_sniffer/venv/bin/python /opt/can_sniffer/src/main.py
|
||||||
|
|
||||||
# Graceful shutdown - отправляем SIGTERM, ждём 30 секунд
|
# Graceful shutdown
|
||||||
# main.py уже обрабатывает SIGTERM через signal handler
|
TimeoutStopSec=15
|
||||||
TimeoutStopSec=30
|
|
||||||
KillSignal=SIGTERM
|
KillSignal=SIGTERM
|
||||||
KillMode=mixed
|
|
||||||
|
|
||||||
# Автоматический рестарт при падении (но не при ручной остановке)
|
# Рестарт при падении
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
|
StartLimitIntervalSec=300
|
||||||
|
StartLimitBurst=5
|
||||||
|
|
||||||
# Логирование через journald
|
# Логи
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
StandardError=journal
|
StandardError=journal
|
||||||
SyslogIdentifier=can-sniffer
|
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]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|||||||
@@ -1,219 +1,57 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# CAN Sniffer Diagnostic Script
|
# CAN Sniffer - Diagnostics
|
||||||
# Проверяет состояние системы и выводит полезную информацию для отладки
|
|
||||||
#
|
#
|
||||||
set -e
|
|
||||||
|
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
NC='\033[0m'
|
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}"; }
|
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 ""
|
||||||
echo -e "${BLUE}║ CAN Sniffer Diagnostic Report ║${NC}"
|
echo "========================================"
|
||||||
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
|
echo " CAN Sniffer Diagnostics"
|
||||||
echo "Date: $(date)"
|
echo "========================================"
|
||||||
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"
|
section "CAN Interfaces"
|
||||||
CAN_FOUND=0
|
|
||||||
for iface in can0 can1; do
|
for iface in can0 can1; do
|
||||||
if ip link show "$iface" &>/dev/null; then
|
if ip link show "$iface" &>/dev/null; then
|
||||||
CAN_FOUND=1
|
STATE=$(ip link show "$iface" | grep -oP '(?<=state )\w+' || echo "?")
|
||||||
STATE=$(ip link show "$iface" | grep -oP '(?<=state )\w+')
|
[[ "$STATE" == "UP" ]] && ok "$iface: UP" || warn "$iface: $STATE"
|
||||||
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
|
else
|
||||||
fail "$iface: NOT FOUND"
|
fail "$iface: NOT FOUND"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ $CAN_FOUND -eq 0 ]]; then
|
section "Services"
|
||||||
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
|
for svc in can-setup can-sniffer; do
|
||||||
if systemctl is-enabled "$svc" &>/dev/null; then
|
if systemctl is-enabled "$svc" &>/dev/null; then
|
||||||
STATUS=$(systemctl is-active "$svc" 2>/dev/null || echo "inactive")
|
STATUS=$(systemctl is-active "$svc" 2>/dev/null || echo "inactive")
|
||||||
if [[ "$STATUS" == "active" ]]; then
|
[[ "$STATUS" == "active" ]] && ok "$svc: active" || warn "$svc: $STATUS"
|
||||||
ok "$svc: $STATUS (enabled)"
|
|
||||||
else
|
else
|
||||||
warn "$svc: $STATUS (enabled)"
|
fail "$svc: not installed"
|
||||||
fi
|
|
||||||
else
|
|
||||||
fail "$svc: not installed or disabled"
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
section "Application Status"
|
section "Files"
|
||||||
INSTALL_DIR="/opt/can_sniffer"
|
INSTALL_DIR="/opt/can_sniffer"
|
||||||
if [[ -d "$INSTALL_DIR" ]]; then
|
[[ -d "$INSTALL_DIR" ]] && ok "Install: $INSTALL_DIR" || fail "Install dir missing"
|
||||||
ok "Installation directory exists: $INSTALL_DIR"
|
[[ -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
|
section "UART"
|
||||||
if [[ -f "$INSTALL_DIR/venv/bin/python" ]]; then
|
[[ -e "/dev/ttyAMA0" ]] && ok "/dev/ttyAMA0" || warn "UART not found"
|
||||||
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
|
section "Process"
|
||||||
if [[ -f "$INSTALL_DIR/src/config.json" ]]; then
|
pgrep -f "can_sniffer.*main.py" > /dev/null && ok "Running" || warn "Not running"
|
||||||
ok "Config file exists"
|
|
||||||
else
|
|
||||||
fail "Config file missing"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check data directory
|
section "Logs (last 5)"
|
||||||
if [[ -d "$INSTALL_DIR/data" ]]; then
|
journalctl -u can-sniffer --no-pager -n 5 2>/dev/null || echo " (no logs)"
|
||||||
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
|
echo ""
|
||||||
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"
|
|
||||||
|
|||||||
@@ -1,233 +1,95 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# CAN Sniffer Installation Script for Raspberry Pi 5
|
# CAN Sniffer - Installation Script
|
||||||
# Устанавливает сервисы автозапуска для can_sniffer
|
|
||||||
#
|
#
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Цвета для вывода
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m'
|
||||||
|
|
||||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
log() { echo -e "${GREEN}[*]${NC} $1"; }
|
||||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
||||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
||||||
|
|
||||||
# Проверка root прав
|
[[ $EUID -ne 0 ]] && error "Запустите с sudo: sudo $0"
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
log_error "Этот скрипт должен запускаться с правами root"
|
|
||||||
echo "Используйте: sudo $0"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Определение директорий
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
INSTALL_DIR="/opt/can_sniffer"
|
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 ""
|
||||||
echo " # For Waveshare 2-CH CAN HAT:"
|
echo "=================================="
|
||||||
echo " dtparam=spi=on"
|
echo " CAN Sniffer Installation"
|
||||||
echo " dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25"
|
echo "=================================="
|
||||||
echo " dtoverlay=mcp2515-can1,oscillator=16000000,interrupt=24"
|
|
||||||
echo ""
|
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
|
# 1. Системные пакеты
|
||||||
if ! grep -q "enable_uart=1" "$CONFIG_TXT"; then
|
log "Установка системных пакетов..."
|
||||||
log_warn "UART not enabled in $CONFIG_TXT"
|
apt-get update -qq
|
||||||
log_warn "For Flipper Zero support, add to $CONFIG_TXT:"
|
apt-get install -y -qq python3 python3-pip python3-venv can-utils
|
||||||
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 отключена
|
# 2. Директории
|
||||||
if grep -q "console=serial0" /boot/firmware/cmdline.txt 2>/dev/null || \
|
log "Создание директорий..."
|
||||||
grep -q "console=ttyAMA0" /boot/firmware/cmdline.txt 2>/dev/null; then
|
mkdir -p "$INSTALL_DIR"/{data,logs}
|
||||||
log_warn "Serial console may be using ttyAMA0!"
|
|
||||||
log_warn "Disable via: sudo raspi-config -> Interface Options -> Serial Port"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# === 3. Создание директорий ===
|
# 3. Копирование проекта
|
||||||
log_info "Creating directories..."
|
log "Копирование файлов..."
|
||||||
|
|
||||||
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/"
|
cp -r "$PROJECT_DIR/src" "$INSTALL_DIR/"
|
||||||
|
|
||||||
# Копируем requirements.txt
|
|
||||||
cp "$PROJECT_DIR/requirements.txt" "$INSTALL_DIR/"
|
cp "$PROJECT_DIR/requirements.txt" "$INSTALL_DIR/"
|
||||||
|
|
||||||
# Копируем production config как основной
|
# Используем production конфиг
|
||||||
cp "$SCRIPT_DIR/config.production.json" "$INSTALL_DIR/src/config.json"
|
cp "$SCRIPT_DIR/config.production.json" "$INSTALL_DIR/src/config.json"
|
||||||
|
|
||||||
# === 5. Создание виртуального окружения ===
|
# 4. Python venv
|
||||||
log_info "Creating Python virtual environment..."
|
log "Создание Python окружения..."
|
||||||
|
|
||||||
if [[ ! -d "$INSTALL_DIR/venv" ]]; then
|
|
||||||
python3 -m venv "$INSTALL_DIR/venv"
|
python3 -m venv "$INSTALL_DIR/venv"
|
||||||
fi
|
"$INSTALL_DIR/venv/bin/pip" install -q --upgrade pip
|
||||||
|
"$INSTALL_DIR/venv/bin/pip" install -q -r "$INSTALL_DIR/requirements.txt"
|
||||||
|
|
||||||
# Устанавливаем зависимости
|
# 5. Права
|
||||||
log_info "Installing Python dependencies..."
|
log "Настройка прав..."
|
||||||
"$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 -R 755 "$INSTALL_DIR"
|
||||||
chmod 700 "$DATA_DIR"
|
chmod 700 "$INSTALL_DIR/data"
|
||||||
chmod 755 "$LOGS_DIR"
|
|
||||||
|
|
||||||
# Добавляем пользователя в группы для доступа к CAN, UART и I2C
|
# 6. Systemd сервисы
|
||||||
usermod -aG dialout "$SERVICE_USER" 2>/dev/null || true
|
log "Установка сервисов..."
|
||||||
usermod -aG plugdev "$SERVICE_USER" 2>/dev/null || true
|
cp "$SCRIPT_DIR/can-sniffer.service" /etc/systemd/system/
|
||||||
usermod -aG i2c "$SERVICE_USER" 2>/dev/null || true
|
cp "$SCRIPT_DIR/can-setup.service" /etc/systemd/system/
|
||||||
usermod -aG gpio "$SERVICE_USER" 2>/dev/null || true
|
|
||||||
|
|
||||||
# === 6.1. Настройка sudoers для shutdown/reboot ===
|
# CAN интерфейсы - отдельный конфиг
|
||||||
log_info "Configuring sudoers for power management..."
|
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
|
systemctl daemon-reload
|
||||||
|
|
||||||
# === 8. Включение сервисов ===
|
|
||||||
log_info "Enabling services..."
|
|
||||||
|
|
||||||
systemctl enable can-setup.service
|
systemctl enable can-setup.service
|
||||||
systemctl enable can-sniffer.service
|
systemctl enable can-sniffer.service
|
||||||
|
|
||||||
# === 9. Итоговая информация ===
|
# Готово
|
||||||
echo ""
|
echo ""
|
||||||
log_info "=== Installation Complete ==="
|
echo "=================================="
|
||||||
|
echo " Установка завершена!"
|
||||||
|
echo "=================================="
|
||||||
echo ""
|
echo ""
|
||||||
echo "Installed components:"
|
echo "Конфиги:"
|
||||||
echo " - CAN Setup Service: $SYSTEMD_DIR/can-setup.service"
|
echo " Приложение: $INSTALL_DIR/src/config.json"
|
||||||
echo " - CAN Sniffer Service: $SYSTEMD_DIR/can-sniffer.service"
|
echo " CAN шина: /etc/default/can-interfaces"
|
||||||
echo " - Environment config: /etc/default/can-sniffer"
|
|
||||||
echo " - Application: $INSTALL_DIR"
|
|
||||||
echo " - Data directory: $DATA_DIR"
|
|
||||||
echo " - Logs directory: $LOGS_DIR"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Configuration:"
|
echo "Команды:"
|
||||||
echo " - Main config: $INSTALL_DIR/src/config.json"
|
echo " systemctl start can-sniffer"
|
||||||
echo " - Edit /etc/default/can-sniffer to override settings"
|
echo " systemctl status can-sniffer"
|
||||||
echo ""
|
echo " journalctl -u can-sniffer -f"
|
||||||
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 ""
|
||||||
|
|
||||||
# Спрашиваем о немедленном запуске
|
read -p "Запустить сейчас? [Y/n] " -n 1 -r
|
||||||
read -p "Start services now? [y/N] " -n 1 -r
|
|
||||||
echo
|
echo
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
|
||||||
log_info "Starting services..."
|
log "Запуск..."
|
||||||
systemctl start can-setup
|
systemctl start can-setup || warn "can-setup: CAN интерфейсы не найдены"
|
||||||
sleep 2
|
|
||||||
systemctl start can-sniffer
|
|
||||||
sleep 1
|
sleep 1
|
||||||
systemctl status can-sniffer --no-pager
|
systemctl start can-sniffer
|
||||||
|
sleep 2
|
||||||
|
systemctl status can-sniffer --no-pager || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log_info "Done!"
|
log "Готово!"
|
||||||
|
|||||||
@@ -1,59 +1,45 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# CAN Sniffer Uninstallation Script
|
# CAN Sniffer - Uninstall Script
|
||||||
#
|
#
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
log() { echo -e "${GREEN}[*]${NC} $1"; }
|
||||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }
|
||||||
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
[[ $EUID -ne 0 ]] && error "Запустите с sudo: sudo $0"
|
||||||
echo -e "${RED}[ERROR]${NC} Run with sudo"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
INSTALL_DIR="/opt/can_sniffer"
|
INSTALL_DIR="/opt/can_sniffer"
|
||||||
SYSTEMD_DIR="/etc/systemd/system"
|
|
||||||
|
|
||||||
log_info "=== CAN Sniffer Uninstallation ==="
|
echo ""
|
||||||
|
echo "=================================="
|
||||||
|
echo " CAN Sniffer Uninstall"
|
||||||
|
echo "=================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
# Остановка сервисов
|
log "Остановка сервисов..."
|
||||||
log_info "Stopping services..."
|
|
||||||
systemctl stop can-sniffer 2>/dev/null || true
|
systemctl stop can-sniffer 2>/dev/null || true
|
||||||
systemctl stop can-setup 2>/dev/null || true
|
systemctl stop can-setup 2>/dev/null || true
|
||||||
|
|
||||||
# Отключение сервисов
|
log "Отключение автозапуска..."
|
||||||
log_info "Disabling services..."
|
|
||||||
systemctl disable can-sniffer 2>/dev/null || true
|
systemctl disable can-sniffer 2>/dev/null || true
|
||||||
systemctl disable can-setup 2>/dev/null || true
|
systemctl disable can-setup 2>/dev/null || true
|
||||||
|
|
||||||
# Удаление systemd файлов
|
log "Удаление systemd файлов..."
|
||||||
log_info "Removing systemd files..."
|
rm -f /etc/systemd/system/can-sniffer.service
|
||||||
rm -f "$SYSTEMD_DIR/can-sniffer.service"
|
rm -f /etc/systemd/system/can-setup.service
|
||||||
rm -f "$SYSTEMD_DIR/can-setup.service"
|
rm -f /etc/default/can-interfaces
|
||||||
rm -f "/etc/default/can-sniffer"
|
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
|
||||||
# Спрашиваем про удаление данных
|
read -p "Удалить приложение ($INSTALL_DIR)? [y/N] " -n 1 -r
|
||||||
echo ""
|
|
||||||
read -p "Remove application data ($INSTALL_DIR/data)? [y/N] " -n 1 -r
|
|
||||||
echo
|
echo
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
log_warn "Removing data directory..."
|
log "Удаление $INSTALL_DIR..."
|
||||||
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"
|
rm -rf "$INSTALL_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log_info "Uninstallation complete!"
|
log "Готово!"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import signal
|
import signal
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from config import config
|
from config import config
|
||||||
|
|||||||
Reference in New Issue
Block a user