508 lines
18 KiB
Markdown
508 lines
18 KiB
Markdown
# GPIO Monitor Dashboard for Raspberry Pi
|
||
|
||
Реалтайм мониторинг параллельной GPIO-шины Raspberry Pi через C + Go + Web Dashboard.
|
||
|
||
Проект читает входящие сигналы с GPIO-пинов Raspberry Pi по прерыванию, передаёт данные через FIFO pipe в Go-сервер и отображает всё в браузере в реальном времени с возможностью просмотра исторических данных.
|
||
|
||
---
|
||
|
||
## Возможности
|
||
|
||
✅ Захват данных по GPIO interrupt (C + WiringPi)
|
||
✅ FIFO pipe, а также stdin/stdout между C + WiringPi и Go Service
|
||
✅ Реализация кольцевого буфера чтения
|
||
✅ HTTP API + Web Dashboard
|
||
✅ **Автоматическая ротация** лог-файлов
|
||
✅ **Retention** (автоматическая очистка старых логов)
|
||
✅ **Watchdog** мониторинг активности
|
||
✅ **MJPEG камера** через go2rtc
|
||
✅ TypeScript фронтенд
|
||
✅ Работа через Wi-Fi Access Point
|
||
|
||
---
|
||
|
||
## Архитектура
|
||
|
||
```text
|
||
GPIO BUS (8 bit)
|
||
↓
|
||
gpio-interrupt.c (C + WiringPi)
|
||
↓ stdout
|
||
FIFO pipe (/tmp/gpio_pipe)
|
||
↓
|
||
Go Server (gpio-monitor-server)
|
||
├── RingBuffer (RAM)
|
||
├── Data Logger (бинарные .bin файлы)
|
||
├── Human Logger (текстовые логи)
|
||
├── Event Logger (события системы)
|
||
├── Watchdog (мониторинг)
|
||
└── Retention (очистка старых логов)
|
||
↓
|
||
HTTP API (:8080)
|
||
├── /api/health - статус сервера
|
||
├── /api/latest - последние данные
|
||
├── /api/history - история (последние 100)
|
||
├── /api/stream - статус камеры
|
||
├── /api/cam - MJPEG поток
|
||
├── /api/log/files - список лог-файлов
|
||
├── /api/log/data - данные из лог-файла
|
||
└── /api/log/events - события системы
|
||
↓
|
||
Web Dashboard (Embedded)
|
||
├── index.html
|
||
├── dashboard.html (главная)
|
||
├── logs.html (просмотр логов)
|
||
├── css/style.css
|
||
├── js/*.ts (TypeScript исходники)
|
||
└── dist/*.js (скомпилированный JS)
|
||
```
|
||
|
||
---
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
.
|
||
├── build/
|
||
│ └── gpio-monitor-server # Скомпилированный бинарник
|
||
├── build.sh # Скрипт сборки (Go + TypeScript)
|
||
├── cmd/server/
|
||
│ ├── main.go # Go HTTP сервер
|
||
│ └── web/ # Веб-интерфейс
|
||
│ ├── css/style.css
|
||
│ ├── dist/ # Скомпилированный JS
|
||
│ │ ├── app.js
|
||
│ │ ├── chart.js
|
||
│ │ ├── data.js
|
||
│ │ └── ...
|
||
│ ├── js/ # TypeScript исходники
|
||
│ │ ├── app.ts
|
||
│ │ ├── chart.ts
|
||
│ │ ├── data.ts
|
||
│ │ └── ...
|
||
│ ├── dashboard.html
|
||
│ ├── index.html
|
||
│ ├── logs.html
|
||
│ ├── favicon.png
|
||
│ ├── package.json
|
||
│ ├── tsconfig.json
|
||
│ └── README.md
|
||
├── internal/
|
||
│ ├── adapter/buffer.go # RingBuffer
|
||
│ ├── logger/ # Система логирования
|
||
│ │ ├── config.go
|
||
│ │ ├── data_logger.go # Бинарные логи
|
||
│ │ ├── event_logger.go # События
|
||
│ │ ├── human_logger.go # Человекочитаемые логи
|
||
│ │ ├── monitor.go # Watchdog
|
||
│ │ ├── parser.go # Парсер данных GPIO
|
||
│ │ ├── paths.go # Пути к файлам
|
||
│ │ ├── retention.go # Очистка старых логов
|
||
│ │ └── rotation.go # Ротация файлов
|
||
│ └── pipe/reader.go # Чтение из FIFO pipe
|
||
├── scripts/
|
||
│ ├── monitor-gpio.service # Systemd сервис
|
||
│ ├── monitor-gpio.socket # Systemd socket
|
||
│ ├── go2rtc # Бинарник go2rtc
|
||
│ ├── go2rtc.yaml # Конфиг go2rtc
|
||
│ ├── view_logs.sh # Скрипт просмотра логов
|
||
│ ├── emulator.py # Эмулятор GPIO
|
||
│ └── imi_wire.py # IMI Wire эмулятор
|
||
├── SDR/ # SDR компоненты
|
||
│ ├── common.c/h
|
||
│ ├── reciever.c
|
||
│ ├── transmitter.c
|
||
│ └── makefile
|
||
├── go.mod
|
||
├── start-server.sh
|
||
└── README.md
|
||
```
|
||
|
||
## GPIO пины
|
||
|
||
```
|
||
WR/STROBE = GPIO27
|
||
|
||
DATA BUS:
|
||
D0 = GPIO21
|
||
D1 = GPIO7
|
||
D2 = GPIO6
|
||
D3 = GPIO5
|
||
D4 = GPIO25
|
||
D5 = GPIO24
|
||
D6 = GPIO23
|
||
D7 = GPIO22
|
||
```
|
||
|
||
---
|
||
|
||
## Установка
|
||
|
||
### 1. Установка зависимостей
|
||
|
||
```bash
|
||
sudo apt update
|
||
sudo apt install -y golang git build-essential wiringpi nodejs npm alsa-utils
|
||
```
|
||
|
||
> `alsa-utils` нужен для монитора уровня звука (использует `arecord`). Проверить, что микрофон виден системе:
|
||
> ```bash
|
||
> arecord -l
|
||
> # **** List of CAPTURE Hardware Devices ****
|
||
> # card 3: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]
|
||
> ```
|
||
> Если список пуст — микрофон не подключён или не определился, монитор звука будет отдавать `sound_level: 0`.
|
||
|
||
### 2. Клонирование и сборка
|
||
|
||
```bash
|
||
git clone <your-repo>
|
||
cd ~/work/golang
|
||
|
||
# Полная подготовка окружения (проверка Node.js, скачивание Go-модулей и npm-пакетов)
|
||
make init
|
||
```
|
||
|
||
### 3. Сборка проекта
|
||
``` Bash
|
||
# Скомпилируйте TypeScript-фронтенд и Go-сервер одной командой:
|
||
make build
|
||
```
|
||
|
||
### 4. Настройка systemd сервиса
|
||
|
||
Для постоянной работы сервера в фоновом режиме настройте систему инициализации. Поскольку сервер пишет логи в защищенную директорию /var/log/, его запуск и управление осуществляются через systemctl с правами администратора
|
||
|
||
```bash
|
||
# Копировать сервисные файлы
|
||
sudo cp scripts/monitor-gpio.service /etc/systemd/system/
|
||
sudo cp scripts/monitor-gpio.socket /etc/systemd/system/
|
||
|
||
# Перезагрузить systemd
|
||
sudo systemctl daemon-reload
|
||
|
||
# Включить автозапуск
|
||
sudo systemctl enable monitor-gpio.socket
|
||
sudo systemctl enable monitor-gpio.service
|
||
|
||
# Запустить сервис
|
||
sudo systemctl start monitor-gpio.service
|
||
```
|
||
|
||
### 4. Проверка статуса
|
||
|
||
```bash
|
||
sudo systemctl status monitor-gpio.service
|
||
journalctl -u monitor-gpio.service -f
|
||
```
|
||
|
||
---
|
||
|
||
## Настройка firewall (nftables)
|
||
|
||
**Важно:** На Raspberry Pi OS Bookworm по умолчанию активен nftables, который блокирует все входящие порты, кроме SSH (22).
|
||
|
||
### Разрешить порт 8080:
|
||
|
||
```bash
|
||
# Добавить правило для порта 8080
|
||
sudo nft add rule inet filter input tcp dport 8080 accept
|
||
|
||
# Проверить правила
|
||
sudo nft list ruleset
|
||
|
||
# Сохранить правила (для сохранения после перезагрузки)
|
||
sudo nft list ruleset | sudo tee /etc/nftables.conf > /dev/null
|
||
sudo systemctl enable nftables
|
||
sudo systemctl restart nftables
|
||
```
|
||
|
||
### Для доступа только с локальной сети:
|
||
|
||
```bash
|
||
# Разрешить только с сети 10.1.1.0/24
|
||
sudo nft add rule inet filter input ip saddr 10.1.1.0/24 tcp dport 8080 accept
|
||
|
||
# Или только с конкретного IP
|
||
sudo nft add rule inet filter input ip saddr 192.168.1.100 tcp dport 8080 accept
|
||
```
|
||
|
||
### Для доступа через Wi-Fi AP:
|
||
|
||
```bash
|
||
# Разрешить с Wi-Fi сети (192.168.77.0/24)
|
||
sudo nft add rule inet filter input iifname "wlan0" tcp dport 8080 accept
|
||
```
|
||
|
||
---
|
||
|
||
## Запуск
|
||
|
||
### Ручной запуск
|
||
|
||
```bash
|
||
./build/gpio-monitor-server \
|
||
-pipe /tmp/gpio_pipe \
|
||
-retention-hours=72 \
|
||
-retention-mb=2000 \
|
||
-retention-interval=60 \
|
||
-rotation-check-interval=1 \
|
||
-buffer-size=10240 \
|
||
-human-log-interval=5
|
||
```
|
||
|
||
### Параметры командной строки
|
||
|
||
| Параметр | По умолчанию | Описание |
|
||
|----------|------------------|--------------------|
|
||
| `-pipe` | `/tmp/gpio_pipe` | Путь к FIFO pipe |
|
||
| `-port` | `:8080` | Порт веб-сервера |
|
||
| `-retention-hours` | `48` | Часы хранения логов (0 = отключено) |
|
||
| `-retention-mb` | `5000` | Максимальный размер логов в MB |
|
||
| `-retention-interval` | `15` | Интервал проверки retention (мин) |
|
||
| `-rotation-check-interval` | `1` | Интервал проверки ротации (мин)|
|
||
| `-buffer-size` | `10240`| Размер кольцевого буфера |
|
||
| `-human-log-interval` | `5` | Интервал записи human-логов (сек) |
|
||
| `-alert-cooldown` | `10` | Задержка между алертами (сек) |
|
||
| `-camera-url` | `http://127.0.0.1:1984/api/stream.mjpeg?src=cam_mjpeg` | URL MJPEG камеры |
|
||
|
||
---
|
||
|
||
## Ротация и хранение логов (Retention)
|
||
|
||
Бинарные данные GPIO пишутся в почасовые файлы вида `gpio-YYYY-MM-DD-HH.bin`
|
||
в директории `internal/logger` (`GetDataLogsDir()`). За это отвечают два
|
||
независимых механизма:
|
||
|
||
- **Ротация** (`internal/logger/rotation.go`) — каждую минуту (`-rotation-check-interval`)
|
||
проверяет текущий час и, если он изменился, закрывает старый `.bin`-файл и
|
||
открывает новый. Ротация только создаёт новые файлы, старые она не трогает.
|
||
- **Retention** (`internal/logger/retention.go`) — раз в `-retention-interval`
|
||
минут (плюс один прогон через минуту после старта) удаляет лишние файлы по
|
||
двум независимым лимитам: возрасту (`-retention-hours`) и суммарному размеру
|
||
(`-retention-mb`). Любой из лимитов можно отключить, выставив `0`.
|
||
|
||
### Как работает удаление (FIFO)
|
||
|
||
Очистка идёт по правилам:
|
||
|
||
1. Все `gpio-*.bin` сортируются от самого старого к самому новому (FIFO-порядок).
|
||
2. Файлы удаляются строго с "старого" конца списка, по одному, пока выполняются
|
||
оба условия:
|
||
- файл старше порога **и по времени в имени файла, и по реальному времени
|
||
последней записи (ModTime)** — если файл был записан недавно, но у него
|
||
"старое" имя (или наоборот), он не считается кандидатом на удаление;
|
||
- файлов в директории больше `minKeepFiles` (сейчас — 2).
|
||
3. Как только встречается первый файл, который не удовлетворяет условиям,
|
||
очистка останавливается — все файлы правее (более новые) заведомо тоже
|
||
не подходят под удаление.
|
||
|
||
Итог: Очистка по размеру (`cleanBySize`): удаляет самые старые файлы,
|
||
пока суммарный объём превышает `-retention-mb`, но тоже не опускается ниже
|
||
`minKeepFiles`.
|
||
|
||
Дополнительная защита — при разборе имени файла (`parseFilenameTime`) любая
|
||
ошибка парсинга (битое или неожиданное имя) не считается "нулевым/древним"
|
||
временем, а приводит к откату на реальный `ModTime` файла с диска, чтобы
|
||
повреждённое или нестандартное имя не привело к ошибочному удалению.
|
||
|
||
---
|
||
|
||
## Dashboard
|
||
|
||
Открывайте в браузере:
|
||
|
||
- **Через Ethernet:** `http://10.1.1.33:8080` (или ваш IP)
|
||
- **Через Wi-Fi AP:** `http://192.168.77.1:8080`
|
||
- **Локально:** `http://localhost:8080`
|
||
|
||
### Страницы
|
||
|
||
- `http://<IP>:8080/` - Перенаправление на dashboard
|
||
- `http://<IP>:8080/dashboard.html` - Главная панель мониторинга
|
||
- `http://<IP>:8080/logs.html` - Просмотр исторических логов
|
||
|
||
---
|
||
|
||
## API
|
||
|
||
### Основные эндпоинты
|
||
|
||
```bash
|
||
GET /api/health
|
||
# Статус сервера, uptime, статистика, sound_level (0-100, уровень с микрофона)
|
||
|
||
GET /api/latest
|
||
# Последние данные и история (10 записей)
|
||
|
||
GET /api/history
|
||
# Последние 100 записей
|
||
|
||
GET /api/stream
|
||
# Статус камеры
|
||
|
||
GET /api/cam
|
||
# MJPEG поток камеры (прокси на go2rtc)
|
||
```
|
||
|
||
### Работа с логами
|
||
|
||
```bash
|
||
GET /api/log/files
|
||
# Список доступных лог-файлов
|
||
|
||
GET /api/log/data?file=gpio-2026-06-17-11.bin
|
||
# Данные из конкретного бинарного лога
|
||
|
||
GET /api/log/events?limit=100
|
||
# Последние события системы
|
||
```
|
||
|
||
---
|
||
|
||
## Диагностика проблем
|
||
|
||
### Если Dashboard не открывается:
|
||
|
||
1. **Проверьте, что сервер запущен:**
|
||
```bash
|
||
ps aux | grep gpio-monitor-server
|
||
sudo systemctl status monitor-gpio.service
|
||
```
|
||
|
||
2. **Проверьте firewall:**
|
||
```bash
|
||
sudo nft list ruleset | grep 8080
|
||
```
|
||
|
||
3. **Проверьте, на каком интерфейсе слушает сервер:**
|
||
```bash
|
||
sudo ss -tlnp | grep 8080
|
||
# Должно быть *:8080 или 0.0.0.0:8080
|
||
```
|
||
|
||
4. **Проверьте маршрутизацию:**
|
||
```bash
|
||
ip route show
|
||
```
|
||
|
||
5. **Посмотрите логи:**
|
||
```bash
|
||
sudo journalctl -u monitor-gpio.service -f
|
||
tail -f /home/user/logs/gpio-events.log
|
||
tail -f /home/user/logs/gpio-human.log
|
||
```
|
||
|
||
6. **Проверьте наличие pipe:**
|
||
```bash
|
||
ls -la /tmp/gpio_pipe
|
||
```
|
||
|
||
### Если индикатор "🔊 ЗВУК" на dashboard не реагирует на микрофон:
|
||
|
||
1. **Проверьте, что arecord установлен и видит микрофон:**
|
||
```bash
|
||
which arecord
|
||
arecord -l
|
||
```
|
||
|
||
2. **Проверьте лог сервера при запуске** — если микрофон не найден, будет строка:
|
||
```
|
||
Аудио-монитор не запущен (микрофон недоступен?): ...
|
||
```
|
||
|
||
3. **Проверьте права доступа к аудио-устройству** (сервис должен работать от пользователя из группы `audio`):
|
||
```bash
|
||
groups <user>
|
||
sudo usermod -aG audio <user>
|
||
```
|
||
|
||
---
|
||
|
||
## Wi-Fi режим Raspberry Pi
|
||
|
||
SSID: `fix_me`
|
||
IP: `192.168.77.1`
|
||
|
||
Подключение: `ssh user@192.168.77.1`
|
||
|
||
---
|
||
|
||
|
||
### Запуск Go сервера в режиме разработки:
|
||
|
||
```bash
|
||
go run cmd/server/main.go \
|
||
-pipe /tmp/gpio_pipe \
|
||
-retention-hours=1 \
|
||
-human-log-interval=1
|
||
```
|
||
|
||
### Эмуляция GPIO сигналов:
|
||
|
||
```bash
|
||
python3 scripts/emulator.py
|
||
```
|
||
|
||
### Просмотр логов:
|
||
|
||
```bash
|
||
./scripts/view_logs.sh
|
||
```
|
||
|
||
---
|
||
|
||
## Камера (go2rtc)
|
||
|
||
Для работы камеры установите go2rtc:
|
||
|
||
```bash
|
||
# Запуск go2rtc
|
||
./scripts/go2rtc -config scripts/go2rtc.yaml
|
||
```
|
||
|
||
Камера будет доступна по адресу:
|
||
- MJPEG поток: `http://<IP>:1984/api/stream.mjpeg?src=cam_mjpeg`
|
||
- Встроенный интерфейс: `http://<IP>:1984`
|
||
|
||
---
|
||
|
||
## Сборка и управление DEB-пакетом
|
||
|
||
В проект добавлена возможность сборки нативного `.deb` пакета для Raspberry Pi OS. Пакет автоматически упаковывает скомпилированный Go-сервер, собранный TypeScript-фронтенд, скрипты логов, конфигурационные файлы и systemd-сервисы.
|
||
|
||
|
||
Сборка пакета выполняется одной командой. **Запуск от обычного пользователя (без sudo):**
|
||
|
||
```bash
|
||
make deb
|
||
```
|
||
|
||
После завершения файл пакета будет доступен по пути: ./build/gpio-monitor-server.deb
|
||
|
||
Установка собранного пакета
|
||
После того как пакет собран, его можно установить в систему с помощью менеджера пакетов apt (он автоматически подтянет системные зависимости, если они требуются):
|
||
|
||
```Bash
|
||
cd ./build
|
||
sudo dpkg -i gpio-monitor-server_1.0.0-1_arm64.deb
|
||
```
|
||
|
||
Полезные команды для работы с пакетом
|
||
В Makefile предусмотрены дополнительные команды для проверки и очистки пакета перед деплоем:
|
||
|
||
Просмотр информации о пакете (версия, архитектура, зависимости, описание):
|
||
```Bash
|
||
# Просмотр содержимого пакета, список файлов и папок:
|
||
make deb-info
|
||
```
|
||
```Bash
|
||
# Очистка временных файлов сборки пакета:
|
||
make deb-contents
|
||
```
|
||
```Bash
|
||
make deb-clean
|
||
sudo apt purge gpio-monitor-server
|
||
```
|
||
|
||
--- |