Skip to content

cheri-hub/dji-python-api

Repository files navigation

DJI AG API

API REST para automação de login e extração de dados de voo do DJI AG SmartFarm.

🔐 Segurança

A API usa X-API-KEY para autenticação. Todos os endpoints (exceto /health) requerem o header:

X-API-KEY: sua_chave_secreta

⚠️ Limitações do DJI

O DJI AG usa WebAssembly para gerar assinaturas de requisição, impossibilitando requisições HTTP diretas. Esta API usa Playwright para automação de browser com contexto persistente.

📋 Funcionalidades

  • ✅ Login automático no DJI Account via Playwright
  • ✅ Sessão persistente (mantém login entre execuções)
  • ✅ Listagem de records de voo
  • ✅ Detalhes de record individual
  • ✅ Extração de dados GPS/telemetria
  • ✅ Exportação GeoJSON
  • ✅ Anti-detecção de automação
  • ✅ Pronto para Docker/VPS

🛠️ Tecnologias

  • Python 3.10+
  • FastAPI - Framework web REST
  • Playwright - Automação de browser
  • Pydantic - Validação de dados
  • Uvicorn - Servidor ASGI

� Como Funciona Tecnicamente

Por que usar automação de browser?

O DJI AG SmartFarm usa WebAssembly (WASM) para gerar assinaturas criptográficas nas requisições. Cada chamada à API do DJI requer um x-signature gerado dinamicamente pelo código WASM rodando no browser. Isso torna impossível fazer requisições HTTP diretas, pois:

  1. O algoritmo de assinatura está ofuscado dentro do binário WASM
  2. A assinatura depende de estado interno do browser (cookies, timestamps, etc.)
  3. Tentativas de engenharia reversa violariam termos de uso

Solução: Usar Playwright para automatizar um browser real que executa o WASM normalmente.

Fluxo de Autenticação

┌─────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  API REST   │────▶│  Playwright      │────▶│  DJI SmartFarm  │
│  (FastAPI)  │     │  (Chromium)      │     │  (WASM + Auth)  │
└─────────────┘     └──────────────────┘     └─────────────────┘
       │                    │                        │
       │  POST /auth/login  │                        │
       │───────────────────▶│   Navega para          │
       │                    │   djiag.com/records    │
       │                    │───────────────────────▶│
       │                    │                        │
       │                    │   Redirect p/ login    │
       │                    │◀───────────────────────│
       │                    │                        │
       │                    │   Preenche email/senha │
       │                    │───────────────────────▶│
       │                    │                        │
       │                    │   Cookies de sessão    │
       │                    │◀───────────────────────│
       │   { success: true }│                        │
       │◀───────────────────│                        │

Browser Profile (Sessão Persistente)

O diretório browser_profile/ armazena o contexto persistente do Chromium:

browser_profile/
├── Default/
│   ├── Cookies           # Cookies de sessão DJI
│   ├── Local Storage/    # Tokens e dados locais
│   ├── Session Storage/  # Dados de sessão
│   ├── Login Data        # Credenciais salvas (criptografadas)
│   └── Preferences       # Configurações do browser
├── Local State           # Estado geral do Chromium
└── ...

Vantagens do contexto persistente:

  • ✅ Mantém sessão entre reinicializações da API
  • ✅ Evita login repetido (cookies válidos são reutilizados)
  • ✅ Preserva configurações anti-CAPTCHA
  • ✅ Reduz suspeita de automação (browser "tem histórico")

Importante para deploy:

  • O browser_profile/ local (Windows/Mac) pode ser copiado para o servidor
  • Evita necessidade de resolver CAPTCHA em ambiente headless
  • Deve ser tratado como dado sensível (contém cookies de autenticação)

Transferência do Browser Profile para Servidor

Se o servidor apresentar CAPTCHA no login (comum em IPs novos):

# 1. No Windows, compactar o profile autenticado
Compress-Archive -Path "browser_profile\*" -DestinationPath "browser_profile.zip"

# 2. Enviar para o servidor
scp browser_profile.zip user@servidor:/opt/djiag-api/

# 3. No servidor, extrair para o volume Docker
docker compose down
unzip browser_profile.zip -d /var/lib/docker/volumes/djiag-api_djiag-browser/_data/
docker compose up -d

Anti-Detecção de Automação

O serviço inclui técnicas para evitar detecção como bot:

# Remove flag de automação do navigator
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });

# Argumentos do Chromium
--disable-blink-features=AutomationControlled
--ignore-default-args=['--enable-automation']

Thread Dedicada para Playwright

Playwright requer que todas as operações sejam executadas na mesma thread onde o browser foi inicializado. A API usa uma arquitetura especial:

┌─────────────────┐     ┌─────────────────────┐
│  FastAPI        │     │  PlaywrightThread   │
│  (async/await)  │────▶│  (thread dedicada)  │
│                 │     │                     │
│  - Recebe HTTP  │     │  - Controla browser │
│  - Valida API   │     │  - Executa ações    │
│  - Retorna JSON │     │  - Mantém contexto  │
└─────────────────┘     └─────────────────────┘

Isso garante:

  • Compatibilidade com FastAPI assíncrono
  • Estabilidade do browser (sem race conditions)
  • Reutilização da mesma instância do browser

�📦 Instalação Local

1. Clone e configure o ambiente

git clone <seu-repositorio>
cd djiag-api

# Criar ambiente virtual
python -m venv venv

# Windows
venv\Scripts\activate

# Linux/Mac
source venv/bin/activate

# Instalar dependências
pip install -r requirements.txt

# Instalar browser do Playwright
playwright install chromium

2. Configure as variáveis de ambiente

cp .env.example .env

Edite o .env:

# Credenciais DJI (obrigatório)
DJI_USERNAME=seu_email@exemplo.com
DJI_PASSWORD=sua_senha

# Segurança API (obrigatório)
API_KEY=sua_chave_secreta

# Configurações
API_HOST=0.0.0.0
API_PORT=8000
API_PREFIX=/api
BROWSER_HEADLESS=false

3. Inicie o servidor

python -m src.main

🐳 Docker

# Copiar e configurar .env
cp .env.example .env
nano .env

# Iniciar
docker compose up -d --build

# Ver logs
docker compose logs -f

Veja DEPLOY.md para instruções completas de deploy em VPS.

📡 Endpoints

Método Endpoint Auth Descrição
GET /api/health Health check
POST /api/auth/login Login no DJI AG
GET /api/auth/status Status da autenticação
GET /api/records Listar records
GET /api/records/{id} Detalhes de um record
GET /api/records/{id}/flight-data Dados de voo (GPS/telemetria)
GET /api/records/{id}/geojson GeoJSON (resposta JSON)
GET /api/records/{id}/geojson/download GeoJSON (download arquivo)

Swagger UI: http://localhost:8000/api/docs

🚀 Exemplos de Uso

cURL

# Health check (sem autenticação)
curl http://localhost:8000/api/health

# Login
curl -X POST http://localhost:8000/api/auth/login \
  -H "X-API-KEY: sua_api_key"

# Listar records
curl http://localhost:8000/api/records \
  -H "X-API-KEY: sua_api_key"

# Obter GeoJSON
curl http://localhost:8000/api/records/ABC123/geojson \
  -H "X-API-KEY: sua_api_key"

# Download GeoJSON como arquivo
curl -O http://localhost:8000/api/records/ABC123/geojson/download \
  -H "X-API-KEY: sua_api_key"

Python

import requests

BASE_URL = "http://localhost:8000/api"
HEADERS = {"X-API-KEY": "sua_api_key"}

# Login
response = requests.post(f"{BASE_URL}/auth/login", headers=HEADERS)
print(response.json())

# Listar records
response = requests.get(f"{BASE_URL}/records", headers=HEADERS)
records = response.json()

# Obter GeoJSON de um record
record_id = records["items"][0]["id"]
response = requests.get(f"{BASE_URL}/records/{record_id}/geojson", headers=HEADERS)
geojson = response.json()

PowerShell

$headers = @{ "X-API-KEY" = "sua_api_key" }

# Login
Invoke-RestMethod -Uri "http://localhost:8000/api/auth/login" -Method POST -Headers $headers

# Listar records
Invoke-RestMethod -Uri "http://localhost:8000/api/records" -Headers $headers

🏗️ Estrutura do Projeto

djiag-api/
├── src/
│   ├── application/          # Casos de uso
│   ├── domain/               # Entidades e interfaces
│   ├── infrastructure/       # Implementações (browser, config)
│   │   ├── config/
│   │   ├── repositories/
│   │   └── services/
│   ├── presentation/         # API (rotas, dependencies)
│   │   └── routes/
│   └── main.py
├── prototipo/                # Scripts de desenvolvimento
├── downloads/                # Downloads salvos
├── browser_profile/          # Sessão persistente do browser
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
├── .env.example
├── DEPLOY.md
└── README.md

⚠️ Troubleshooting

Login falha ou timeout

  • Verifique credenciais no .env
  • Se aparecer CAPTCHA, complete manualmente (browser abrirá)
  • Configure BROWSER_HEADLESS=false para ver o browser

GeoJSON trava o Swagger

  • Use o endpoint /geojson/download para arquivos grandes
  • O download retorna arquivo ao invés de renderizar no Swagger

Erro no Docker

  • Verifique se shm_size: 2gb está no docker-compose
  • Playwright precisa de memória compartilhada

Browser não abre

  • Verifique se Playwright está instalado: playwright install chromium
  • No Docker, sempre use BROWSER_HEADLESS=true

📄 Licença

Este projeto é para uso pessoal e educacional. Respeite os Termos de Serviço do DJI.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages