Media Pi Agent REST Service для Raspberry Pi.
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.
-
Скачайте пакет
media-pi-agent_<version>_<arch>.debиз GitHub Releases на устройство. -
Установите пакет:
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, если он есть в системе.
- Настройте и зарегистрируйте устройство:
export CORE_API_BASE="https://your-management-server.example"
sudo -E setup-media-pi.shCORE_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 службы для применения конфигурации.
- Проверьте службу:
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.baksetup-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, кроме файла фотографии, используют оболочку:
{
"ok": true,
"data": {}
}Авторизация:
curl -H "Authorization: Bearer <server_key>" http://localhost:8081/api/unitsGET /health- статус сервиса, версия и время. Авторизация не требуется. Если передать корректныйAuthorization: Bearer <server_key>, ответ дополнительно содержитserviceStatusсо статусами воспроизведения и sync-процессов.
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"
}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- выключить устройство.
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-юнитов.
Видео-синхронизация:
GET {core_api_base}/api/devicesyncполучает manifest.- Локальные файлы сравниваются по размеру и SHA256.
- Недостающие или устаревшие файлы загружаются через
GET {core_api_base}/api/devicesync/{id}. - Файл пишется во временный
.tmp, проверяется и атомарно переименовывается. - Файлы в
playlist.destination, отсутствующие в manifest, удаляются.
Плейлист:
GET {core_api_base}/api/devicesync/playlistзагружает активный плейлист.- Файл сохраняется как
{playlist.destination}/playlist.m3u. - При плановой или ручной 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-agentCI собирает 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/