Skip to content

sw-consulting/media-pi.device

Repository files navigation

media-pi.device

Media Pi Agent REST Service для Raspberry Pi.

Build & Package Media Pi Agent Lint codecov

Описание

media-pi-agent - это HTTP-сервис для устройства Media Pi. Он запускается как systemd-служба и предоставляет API для:

  • управления разрешенными systemd-юнитами через D-Bus;
  • запуска и остановки воспроизведения play.video.service;
  • синхронизации плейлиста и медиафайлов с core API;
  • настройки расписаний синхронизации и нерабочего времени;
  • захвата и отправки фотографий с видеоустройства;
  • перезагрузки конфигурации, reboot и shutdown устройства.

Все API-методы, кроме /health, требуют Bearer-токен из server_key в /etc/media-pi-agent/agent.yaml.

Установка

  1. Скачайте пакет media-pi-agent_<version>_<arch>.deb из GitHub Releases на устройство.

  2. Установите пакет:

sudo apt-get update
sudo apt install ./media-pi-agent_<version>_<arch>.deb

Альтернативно:

sudo dpkg -i ./media-pi-agent_<version>_<arch>.deb
sudo apt-get update
sudo apt-get install -f -y

Пакет устанавливает бинарник, systemd unit, конфигурацию, polkit-правило и зависимости: dbus, policykit-1, systemd, curl, jq, ffmpeg.

Пакет создает системную группу media-pi и выдает ей read/write-доступ к каталогам данных и конфигурации: /etc/media-pi-agent, /opt/media-pi, /opt/media-pi-agent и /var/media-pi, если эти пути существуют. Привилегированные системные файлы /etc/systemd/system/media-pi-agent.service и /etc/polkit-1/localauthority/50-local.d/media-pi-agent.pkla остаются под управлением root и доступны группе media-pi только на чтение. Пользователь pi добавляется в группу media-pi, если он есть в системе.

  1. Настройте и зарегистрируйте устройство:
export CORE_API_BASE="https://your-management-server.example"
sudo -E setup-media-pi.sh

CORE_API_BASE должен указывать на URL media-pi core API. Если переменная не задана, setup-скрипт использует значение по умолчанию из setup/setup-media-pi.sh.

Скрипт:

  • генерирует /etc/media-pi-agent/agent.yaml и новый server_key;
  • создает группу media-pi, добавляет в нее пользователя pi, если он есть, и восстанавливает group read/write-доступ к каталогам данных и конфигурации Media Pi (системные файлы /etc/systemd и /etc/polkit-1 доступны группе только на чтение);
  • регистрирует устройство в ${CORE_API_BASE}/api/devices/register;
  • best-effort отключает motion.service, если он установлен;
  • включает и запускает media-pi-agent.service;
  • проверяет /health;
  • после загрузки и миграции конфигурации best-effort отключает старые playlist.upload.service, playlist.upload.timer, video.upload.service и video.upload.timer;
  • выполняет reload или restart службы для применения конфигурации.
  1. Проверьте службу:
sudo systemctl status media-pi-agent
curl http://localhost:8081/health

Обновление

Установите новый .deb. При upgrade пакет остановит службу перед заменой файлов и запустит ее обратно, если служба была включена:

sudo apt install ./media-pi-agent_<new-version>_<arch>.deb

Файлы /etc/media-pi-agent/agent.yaml, /etc/systemd/system/media-pi-agent.service и polkit-конфигурация помечены как conffiles. Если они были изменены локально, dpkg может предложить сохранить текущую версию или заменить ее версией из пакета.

При установке или обновлении пакет best-effort отключает motion.service, если он установлен.

При обновлении старая группа svc-ops переименовывается в media-pi, если группа media-pi еще не существует. Если обе группы уже есть, участники svc-ops добавляются в media-pi best-effort.

Перед обновлением можно сохранить резервную копию:

sudo cp /etc/media-pi-agent/agent.yaml /root/agent.yaml.bak

setup-media-pi.sh нужен для первичной настройки и повторной регистрации. После обычного обновления запускать его не требуется.

Конфигурация

Основной файл конфигурации: /etc/media-pi-agent/agent.yaml.

Для локальных тестов и нестандартного запуска путь можно переопределить переменной MEDIA_PI_AGENT_CONFIG.

Пример:

allowed_units:
  - mnt-usb.mount
  - mnt-ya.disk.mount
  - mnt-ya.disk.automount
  - play.video.service

server_key: "generated-key"
listen_addr: "0.0.0.0:8081"
media_pi_service_user: "pi"
core_api_base: "https://vezyn.fvds.ru"
max_parallel_downloads: 3

playlist:
  destination: "/var/media-pi"

screenshot:
  timers:
    - "00:00:30"
    - "00:30:00"
  resend_limit: 5
  input: "/dev/video0"
  path_template: "/var/media-pi/screenshots/cam_$(date +%F_%H-%M-%S).jpg"

schedule:
  playlist:
    - "10:30"
    - "14:45"
  video:
    - "02:00"
  rest:
    - start: "22:00"
      stop: "08:00"

audio:
  output: "hdmi"

Параметры:

  • allowed_units - systemd-юниты, которыми разрешено управлять через /api/units/*.
  • server_key - Bearer-токен для входящих API-запросов и идентификатор устройства для запросов к core API.
  • listen_addr - адрес HTTP-сервера, по умолчанию 0.0.0.0:8081.
  • media_pi_service_user - пользователь для crontab-операций, по умолчанию pi.
  • core_api_base - базовый URL core API, используемый для регистрации, синхронизации и отправки фотографий.
  • max_parallel_downloads - зарезервировано для будущей параллельной загрузки, по умолчанию 3.
  • playlist.destination - директория для playlist.m3u и медиафайлов, по умолчанию /var/media-pi.
  • schedule.playlist - времена загрузки плейлиста в формате HH:MM; после успешной плановой загрузки агент перезапускает play.video.service.
  • schedule.video - времена синхронизации медиафайлов в формате HH:MM.
  • schedule.rest - интервалы нерабочего времени; агент управляет остановкой и запуском play.video.service.
  • audio.output - аудиовыход, hdmi или jack.
  • screenshot.timers - интервалы фотоотчёта после каждого запуска плейлиста в формате HH:mm:ss от 00:00:00 до 23:59:59; пустой список отключает автоматический фотоотчёт.
  • screenshot.resend_limit - сколько старых неотправленных фотографий повторно отправлять за один цикл.
  • screenshot.input - видеоустройство для ffmpeg, по умолчанию /dev/video0.
  • screenshot.path_template - шаблон локального пути для временного файла фотографии.

ffmpeg берется из PATH. При необходимости путь можно переопределить через FFMPEG_PATH.

API

Все ответы API, кроме файла фотографии, используют оболочку:

{
  "ok": true,
  "data": {}
}

Авторизация:

curl -H "Authorization: Bearer <server_key>" http://localhost:8081/api/units

Health

  • GET /health - статус сервиса, версия и время. Авторизация не требуется. Если передать корректный Authorization: Bearer <server_key>, ответ дополнительно содержит serviceStatus со статусами воспроизведения и sync-процессов.

Systemd units

  • GET /api/units - список разрешенных юнитов и их состояние.
  • GET /api/units/status?unit=<unit> - состояние одного разрешенного юнита.
  • POST /api/units/start - запустить юнит.
  • POST /api/units/stop - остановить юнит.
  • POST /api/units/restart - перезапустить юнит.
  • POST /api/units/enable - включить юнит.
  • POST /api/units/disable - отключить юнит.

Тело запроса для unit action:

{
  "unit": "play.video.service"
}

Menu

  • GET /api/menu - список доступных menu-действий.
  • POST /api/menu/playback/stop - остановить play.video.service.
  • POST /api/menu/playback/start - запустить play.video.service.
  • GET /api/menu/service/status - статусы воспроизведения и sync-процессов.
  • GET /api/menu/configuration/get - получить настройки плейлиста, расписания, аудио и фотографии.
  • PUT /api/menu/configuration/update - обновить настройки.
  • POST /api/menu/playlist/start-upload - загрузить playlist.m3u из core API и перезапустить воспроизведение.
  • POST /api/menu/playlist/stop-upload - отменить текущую синхронизацию.
  • POST /api/menu/video/start-upload - синхронизировать медиафайлы из core API.
  • POST /api/menu/video/stop-upload - отменить текущую синхронизацию.
  • GET /api/menu/screenshot/take - сделать фотографию немедленно и вернуть файл в ответе.
  • POST /api/menu/system/reload - выполнить systemctl daemon-reload.
  • POST /api/menu/system/reboot - перезагрузить устройство.
  • POST /api/menu/system/shutdown - выключить устройство.

Reload

  • POST /internal/reload - перезагрузить /etc/media-pi-agent/agent.yaml без restart процесса. Метод требует Bearer-токен.

Обычно reload выполняется через systemd:

sudo systemctl reload media-pi-agent || sudo systemctl restart media-pi-agent

Синхронизация файлов

Агент синхронизирует файлы напрямую с core API, без отдельных playlist.upload.* и video.upload.* systemd-юнитов.

Видео-синхронизация:

  1. GET {core_api_base}/api/devicesync получает manifest.
  2. Локальные файлы сравниваются по размеру и SHA256.
  3. Недостающие или устаревшие файлы загружаются через GET {core_api_base}/api/devicesync/{id}.
  4. Файл пишется во временный .tmp, проверяется и атомарно переименовывается.
  5. Файлы в playlist.destination, отсутствующие в manifest, удаляются.

Плейлист:

  1. GET {core_api_base}/api/devicesync/playlist загружает активный плейлист.
  2. Файл сохраняется как {playlist.destination}/playlist.m3u.
  3. При плановой или ручной playlist-синхронизации агент перезапускает play.video.service.

Запросы к core API используют заголовок:

X-Device-Id: <server_key>

Статус последней видео-синхронизации хранится в памяти и best-effort записывается в /var/media-pi/sync/sync-status.json.

Фотографии

Если screenshot.timers содержит интервалы, агент после каждого запуска плейлиста отменяет ранее запланированные фотографии и планирует новые снимки относительно этого запуска. Захват выполняется через ffmpeg:

ffmpeg -loglevel error -y -i /dev/video0 -frames:v 1 <output>

После успешного захвата файл отправляется в:

POST {core_api_base}/api/devicesync/screenshot

Файл отправляется как multipart form field file, с заголовком X-Device-Id: <server_key>. После успешной отправки локальный файл удаляется. Если отправка не удалась, файл остается в директории фотографий и будет повторно отправлен следующим снимком, с учетом screenshot.resend_limit.

GET /api/menu/screenshot/take делает снимок вручную и возвращает файл клиенту; этот метод не отправляет файл в core API.

Миграция со старых версий

При первичном создании конфигурации агент пытается перенести отсутствующие настройки из старых systemd/crontab-файлов, если существующей конфигурации агента еще нет:

  • пути playlist upload из playlist.upload.service;
  • времена playlist/video из старых timer-файлов;
  • интервалы rest из crontab пользователя media_pi_service_user;
  • audio output из /etc/asound.conf.

После миграции конфигурации setup-скрипт best-effort отключает старые playlist.upload.service, playlist.upload.timer, video.upload.service и video.upload.timer. Debian-пакет также best-effort отключает эти unit'ы при первичной установке и при обновлении, не удаляя unit-файлы, которые нужны для миграции.

Разработка

Требуется Go 1.25.1.

Запуск тестов:

go test ./...

Запуск тестов с race detector и coverage:

go test -race -v ./... -coverprofile=coverage.out -covermode=atomic

Интеграционные тесты:

go test -race -v -tags=integration ./...

Локальный запуск с тестовой конфигурацией:

go run ./cmd/media-pi setup ./agent.local.yaml
MEDIA_PI_AGENT_CONFIG=./agent.local.yaml go run ./cmd/media-pi

Сборка бинарника:

go build -trimpath -buildvcs=false -o build/media-pi-agent ./cmd/media-pi

Сборка ARM-пакета из готового бинарника:

./packaging/mkdeb.sh arm64 0.1.0 dist/arm64/media-pi-agent
./packaging/mkdeb.sh armhf 0.1.0 dist/armhf/media-pi-agent

CI собирает armhf и arm64, запускает unit/integration tests, публикует .deb в GitHub Release для тегов v*.

Устранение неполадок

Проверка службы:

sudo systemctl status media-pi-agent
sudo journalctl -u media-pi-agent -f
curl http://localhost:8081/health

Проверка конфигурации:

sudo cat /etc/media-pi-agent/agent.yaml
sudo systemctl reload media-pi-agent || sudo systemctl restart media-pi-agent

Проверка регистрации:

echo "$CORE_API_BASE"
curl -I "$CORE_API_BASE/api/status/status"

Проверка rest-расписания:

sudo crontab -u pi -l

Замените pi на значение media_pi_service_user, если оно отличается.

Удаление

Удалить пакет с конфигурацией:

sudo apt remove --purge media-pi-agent

Удалить пакет, сохранив conffiles:

sudo apt remove media-pi-agent

Через dpkg:

sudo dpkg -r media-pi-agent

При необходимости удалить конфигурацию вручную:

sudo rm -rf /etc/media-pi-agent/

About

Media Pi Device Scripts

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors