GUIA OPERACIONAL · API V1

Documentação do Valkyris

Tudo o que você precisa para instalar o servidor, preparar câmeras e iluminação, conectar o Android e integrar a API.

Documentação sempre atualizada OpenAPI 3.1
01

Começar

O instalador baixa artefatos da release, gera os segredos locais e o certificado TLS, prepara o Compose e inicia Valkyris e MediaMTX.

curl -fsSL https://valkyris.vercel.app/install.sh | sh

Requisitos

  • ✓Linux em amd64 ou arm64
  • ✓Docker Engine com Docker Compose v2
  • ✓Android 8.0 (SDK 26) ou mais recente
  • ✓Câmera ONVIF Profile S com RTSP
  • ✓Servidor, celular e câmera acessíveis por LAN ou VPN

Mantenha as portas ONVIF e RTSP acessíveis apenas na rede privada. Para acesso externo, conecte o celular por VPN; não publique a câmera na internet.

02

Arquitetura

CâmeraONVIF · RTSP
→
MediaMTXWebRTC · buffer · Opus
→
Go + SQLiteregras · eventos
→
AndroidCompose · push

O backend é o limite de segurança. O app nunca recebe a senha da câmera nem segredos de adaptadores locais. Câmeras passam pelo MediaMTX; a iluminação usa uma fronteira de driver independente de fabricante. Credenciais ficam cifradas com AES-256-GCM; tokens são persistidos somente como hash.

03

Preparar a câmera

  1. 1
    Conecte ao Wi-Fi

    Na TC40, use o Tapo uma vez para concluir a configuração inicial.

  2. 2
    Crie a Camera Account

    Use uma credencial exclusiva nas configurações avançadas. Não é a senha da sua conta TP-Link.

  3. 3
    Confirme a rede local

    O servidor precisa alcançar a câmera pelas portas ONVIF e RTSP na rede privada.

  4. 4
    Cadastre no app

    Informe nome, ícone, IP, usuário e senha. O RTSP principal da Tapo é montado automaticamente; use o campo avançado apenas para sobrescrever.

O cadastro é persistido imediatamente. A tela da câmera acompanha queued, probing, stream, ready ou failed em tempo real, e o último erro sanitizado permanece salvo para diagnóstico.

Iluminação inteligente

O modelo comum de energia, brilho, temperatura do branco e RGB permanece no aplicativo e no painel, mas o núcleo não inclui integração proprietária com contas de fabricante. Adaptadores locais padronizados podem ser adicionados atrás da fronteira de driver sem redesenhar as interfaces.

Registros antigos não são apagados automaticamente durante essa transição. Um administrador ainda pode removê-los pelo aplicativo.

04

Android

Instale o APK da release mais recente. No primeiro acesso, informe a URL HTTPS pela qual o celular alcança o servidor e crie a conta com usuário e senha. O primeiro dispositivo vira administrador.

Outros celulares

Em Ajustes, o administrador cria um convite temporário e de uso único. O QR é montado dentro do app com a URL já conhecida; o backend não possui página pública de pareamento.

Notificações nativas

O APK usa Firebase Cloud Messaging diretamente e não exige aplicativo auxiliar. Após o login, o token deste celular é registrado automaticamente; o Android recebe um payload mínimo cifrado e o Valkyris cria a notificação ou o alarme nativo.

  1. 1
    Configure o APK

    Adicione com.ferforastieri.valkyris ao projeto Firebase, baixe google-services.json e grave seu base64 no secret FIREBASE_ANDROID_CONFIG_BASE64 do GitHub.

  2. 2
    Configure o servidor

    Gere uma chave JSON em Configurações do projeto → Contas de serviço. No sheet de alertas do app, envie esse JSON: ele é validado e cifrado no SQLite do seu servidor.

  3. 3
    Conceda a permissão

    Abra o APK da nova release, faça login e permita notificações. O registro no FCM acontece automaticamente.

A API aceita a mesma configuração para integrações administrativas em PUT /api/v1/settings/push, usando serviceAccountBase64. A conta nunca é retornada pela API.

Painel web no seu servidor

Abra /app/ na URL HTTPS da instalação e use seu usuário e senha. O painel consulta câmeras ao vivo, controla as lâmpadas cadastradas, exibe eventos, família, percursos e informações do servidor. Cadastro e configuração dos dispositivos continuam no Android.

A sessão usa cookie Secure, HttpOnly e SameSite=Strict, válido por 30 dias e renovado durante o uso. Sair ou trocar a senha revoga a sessão. O painel vem na imagem Docker e não exige Node nem deploy na Vercel. Dados são consultados a cada 15 segundos com a aba visível.

WebRTC · Cloudflare Tunnel

Android e painel usam os mesmos endpoints WHEP. O túnel leva HTTPS e a negociação, mas áudio e vídeo precisam alcançar o MediaMTX por ICE. Libere 8189 UDP/TCP na rede privada e configure VALKYRIS_WEBRTC_HOSTS com endereços LAN/VPN alcançáveis. O domínio do túnel não é endereço de mídia. STUN pode auxiliar conexão direta; NAT restritivo exige VPN, rota pública de mídia ou TURN configurado.

O player não substitui WebRTC por imagem ou HLS. A espera ICE de oito segundos não encerra a conexão Android quando já existem candidatos utilizáveis. Um HTTP 201 na negociação não comprova reprodução: verifique frames recebidos.

Localização, eventos e movimento

O Android integra fontes de localização com Fused Location Provider. Uma entrada ou saída exige três leituras por pelo menos dois minutos, além da margem de precisão. Leitura inconclusiva ou retorno cancela a confirmação. O servidor pede amostras enquanto há confirmação pendente, sem preencher o histórico com pontos estacionários.

Alertas mostram pessoa e área, e não são enviados ao próprio usuário que se deslocou. O histórico tem pontos numerados, horário e precisão; os mapas aproximam pessoas próximas. A precisão é estimada, e falta de rede ou sinal pode adiar alertas. Instale o APK atualizado em cada celular.

Nas regras da câmera, movimento persistente permite selecionar uma região da imagem, duração, sensibilidade e dias/horários, inclusive 22:00–06:00. Mantenha a câmera fixa e redesenhe a região após mover PTZ. A análise detecta movimento na região, não identifica o bebê, postura, respiração ou perigo médico; não substitui supervisão.

Eventos são separados em localização, áudio e câmera. Detalhes mostram pessoa/área e posição quando disponíveis; clipes indicam se estão processando, prontos ou indisponíveis.

05

Configuração

VALKYRIS_WEBRTC_HOSTSIP LAN/VPNEndereços de mídia anunciados, separados por vírgula.
VALKYRIS_WEB_DIR/opt/valkyris/webBuild estático do painel no backend.
VALKYRIS_LISTEN:8443Endereço interno do serviço HTTPS.
VALKYRIS_DATA_DIR/dataVolume persistente.
VALKYRIS_DATABASE/data/valkyris.dbSQLite.
VALKYRIS_TLS_CERT/data/tls/server.crtCertificado TLS.
VALKYRIS_TLS_KEY/data/tls/server.keyChave TLS.
VALKYRIS_MASTER_KEY_FILE/data/secrets/master.keyChave mestra de criptografia.
VALKYRIS_MEDIA_APIhttp://mediamtx:9997API interna do MediaMTX.
VALKYRIS_MEDIA_RTSPrtsp://mediamtx:8554Stream interno para monitoramento e detectores.
VALKYRIS_MEDIA_WEBRTChttp://mediamtx:8889Origem WHEP interna; a mídia WebRTC segue direto ao celular após ICE.
VALKYRIS_MEDIA_PLAYBACKhttp://mediamtx:9996API interna para gerar clipes recentes.
VALKYRIS_RELEASE_APIapi.github.com/…/releases/latestRelease estável consultada.
VALKYRIS_FIREBASE_CREDENTIALS_FILE/data/secrets/firebase-service-account.jsonAlternativa legada: arquivo de conta de serviço FCM. O app usa o armazenamento cifrado do SQLite.

O arquivo mediamtx.yml deve existir como arquivo antes de subir o Compose.

06

API HTTP

Bearer no Android e integrações; o painel usa cookie HttpOnly e X-Valkyris-Viewer: 1. Rotas públicas dispensam sessão. A base é /api/v1. Respostas JSON usam o envelope success, message e data; erros usam success, message e error.

curl -k https://SEU_SERVIDOR:8443/api/v1/cameras \ -H 'Authorization: Bearer SEU_TOKEN'

Referência de endpoints

OpenAPI YAML
GET/healthPúblico

Saúde do servidor.

GET/openapi.yamlPúblico

Contrato OpenAPI 3.1 servido pelo backend.

GET/api/v1/auth/statusPúblico

Informa se o primeiro administrador já existe.

POST/api/v1/admin/bootstrapPúblico

Cria a conta com usuário e senha e o primeiro administrador, uma única vez.

POST/api/v1/loginPúblico

Autentica uma conta pessoal sem recriar o perfil.

POST/api/v1/pairPúblico

Consome um convite de uso único.

POST/api/v1/pairing-sessionsAdmin

Cria um convite temporário para outro celular.

GET · POST/api/v1/camerasAutenticado

Lista câmeras ou inicia o cadastro assíncrono.

PUT · DELETE/api/v1/cameras/{id}Autenticado

Edita ou remove uma câmera; uma mudança de conexão reinicia sua configuração.

GET/api/v1/camera-operations/{id}Autenticado

Acompanha a descoberta ONVIF e a configuração de mídia.

POST/api/v1/cameras/{id}/ptzAutenticado

Move, para ou aplica zoom quando suportado.

GET/api/v1/lightsAutenticado

Lista a iluminação fornecida pelo adaptador local instalado.

GET · DELETE/api/v1/lights/{id}Autenticado / Admin ao remover

Consulta ou remove uma iluminação.

PUT/api/v1/lights/{id}/stateAutenticado

Liga, desliga e altera brilho, branco ou cor.

GET/api/v1/cameras/{id}/snapshotAutenticado

Retorna um frame JPEG do stream local atual.

GET/api/v1/cameras/{id}/recordingAutenticado

Baixa os últimos 10 segundos do buffer em MP4.

POST · PATCH · DELETE/api/v1/cameras/{id}/live/webrtc/whepAutenticado

Negocia e encerra o stream WebRTC autenticado.

GET/api/v1/detectorsAutenticado

Lista os tipos normalizados de detecção.

GET · POST/api/v1/rulesAutenticado

Lista ou cria regras de automação.

PUT · DELETE/api/v1/rules/{id}Autenticado

Edita ou remove uma regra.

GET/api/v1/usersAutenticado

Lista os perfis da família vinculados aos dispositivos pareados.

GET/api/v1/users/{id}/historyAutenticado

Retorna o histórico de localização de um usuário.

POST/api/v1/me/locationAutenticado

Registra a localização do usuário vinculado ao dispositivo atual.

GET · POST/api/v1/placesAutenticado / Admin ao alterar

Lista áreas ou cria uma área de alerta.

PUT · DELETE/api/v1/places/{id}Admin

Edita ou remove uma área.

GET · PUT/api/v1/meAutenticado

Consulta ou atualiza o perfil do próprio dispositivo.

POST/api/v1/me/passwordUsuário

Altera a própria senha e revoga as outras sessões.

GET · DELETE/api/v1/viewer-sessionSessão web

Restaura ou revoga a sessão do painel.

GET/api/v1/eventsAutenticado

Lista eventos recentes.

GET/api/v1/events/{id}Autenticado

Retorna metadados de um evento.

POST/api/v1/events/{id}/acknowledgeAutenticado

Reconhece o evento e interrompe o alarme.

POST/api/v1/events/acknowledge-allAutenticado

Reconhece todos os eventos pendentes.

GET/api/v1/events/{id}/snapshotAutenticado

Retorna o JPEG preservado no evento.

GET/api/v1/events/{id}/clipAutenticado

Transmite o clipe MP4 do evento.

POST/api/v1/devices/pushAutenticado

Registra o token FCM e o segredo do payload cifrado.

GET · PUT/api/v1/settings/pushAdmin ao alterar

Consulta a configuração FCM ou envia a conta de serviço Base64, cifrada no SQLite.

GET · PUT/api/v1/settings/retentionAdmin ao alterar

Lê ou altera os limites de retenção.

POST/api/v1/detectionsAutenticado

Recebe uma detecção normalizada de integração local.

GET/api/v1/system/updateAutenticado

Consulta a release e o link do APK, sem executar atualizações.

GET/api/v1/realtimeAutenticado

WebSocket para mudanças de câmeras, iluminação e eventos.

07

Atualizações

Quando uma release estável mais nova existir, o app e o web exibem um toast, sem atualizar automaticamente. Nas configurações do app, o usuário pode iniciar o download do APK assinado do GitHub; o Android solicita confirmação para instalar.

SQLite, clipes e snapshots permanecem no volume valkyris-data. A API apenas consulta versões; não executa atualizações do servidor.

Na série 2.x, a API permanece /api/v1 e a migração preserva dados. Execute o instalador novamente no host para atualizar o backend, o web, Compose e MediaMTX. O APK precisa ser instalado em cada celular com confirmação do Android. A consulta de releases tem cache de até 15 minutos.

08

Segurança e backup

A API limita por minuto: 3000 requisições globais e 1200 por endereço; autenticação tem 30 globais e 10 por endereço; snapshots/gravações têm 60 por sessão/endereço, e abertura WHEP tem 12. Respostas 429 incluem Retry-After. O backend não confia em X-Forwarded-For ou CF-Connecting-IP do cliente; usuários de um proxy compartilham o orçamento. Os contadores são locais ao processo.

Para backup, use a API de backup SQLite ou pare a stack antes de copiar o volume. Preserve banco, WAL quando aplicável, chave mestra, certificados, mídia, .env, Compose e mediamtx.yml. Copiar apenas o .db em execução pode gerar backup incompleto.

  • Não encaminhe 554, 2020, 8888 ou 9997 no roteador.
  • Use TLS confiável por proxy reverso ou instale a CA privada no celular.
  • Use Tailscale, WireGuard ou outra VPN para acesso fora de casa.
  • Faça backup do volume valkyris-data e do .env juntos, com acesso restrito.
09

Diagnóstico

docker compose ps docker compose logs --tail=200 valkyris docker compose logs --tail=200 mediamtx curl -k https://localhost:8443/health
setup failed

Abra a câmera no app: a etapa e o erro persistido indicam se a falha ocorreu no ONVIF ou no stream.

EOFException

Verifique primeiro se MediaMTX está saudável e se mediamtx.yml foi montado como arquivo.

Sem preview

Confira snapshot, perfil ONVIF escolhido e conectividade RTSP entre o host e a câmera.