|
|
||
|---|---|---|
| .gitea/workflows | ||
| app | ||
| infra | ||
| .env.example | ||
| .gitignore | ||
| backfill.py | ||
| debug_wifeed.py | ||
| deploy.sh | ||
| docker-compose.prod.yml | ||
| README.md | ||
| requirements.txt | ||
| test_transform_load.py | ||
📡 WiFi ETL Pipeline
🚧 Em construção 🚧 Este projeto está em desenvolvimento. Este primeiro commit contém a estrutura base do pipeline ETL.
🧠 Visão Geral
Este projeto tem como objetivo realizar a ingestão periódica de dados de duas APIs distintas:
- API de Autenticação (WiFeed) → Nome, CPF, sexo, MAC
- API do Access Point (Ruijie) → MAC, tempo conectado, AP
Os dados serão cruzados pelo MAC Address e persistidos em um banco PostgreSQL para análise e consulta.
⚙️ Arquitetura
flowchart TD
A["Cron (Docker)\na cada 5 minutos"]
B["Python ETL Script"]
C["API Autenticação\nnome, cpf, sexo, MAC"]
D["API do AP\nMAC, tempo, AP"]
E["Transform\nmerge pelo MAC"]
F["PostgreSQL\nusers + sessions"]
A --> B
B --> C
B --> D
C --> E
D --> E
E --> F
Fluxo
- Execução automática a cada 5 minutos (cron via Docker)
- Extração dos dados das APIs
- Transformação (merge pelo MAC + normalização)
- Carga no banco PostgreSQL
🏗️ Estrutura do Projeto
app/
├── core/ # Configurações e conexão com banco
│ ├── config.py
│ └── db.py
│
├── extractor/ # Extração das APIs externas
│ ├── ruijie.py
│ └── wifeed.py
│
├── transform/ # Regras de transformação
│ └── merge_mac.py
│
├── load/ # Persistência no banco
│ └── load_database.py
│
└── main.py # Orquestrador do pipeline
infra/
├── Dockerfile
├── docker-compose.yml
└── crontab
.env.example
requirements.txt
README.md
🚀 Como executar
⚠️ Observação: o projeto ainda está em fase inicial e algumas partes podem não estar totalmente implementadas.
1. Clonar o repositório
git clone <seu-repo>
cd wifi-etl
2. Configurar variáveis de ambiente
Crie um .env baseado no exemplo:
cp .env.example .env
Preencha com suas credenciais (WiFeed já inclusa no .env):
# PostgreSQL
DB_HOST=localhost
DB_PORT=5432
DB_NAME=wifi_etl
DB_USER=postgres
DB_PASSWORD=sua_senha
# Ruijie (AP)
RUIJIE_BASE_URL=https://cloud-eu.ruijienetworks.com
RUIJIE_APPID=seu_appid
RUIJIE_SECRET=seu_secret
RUIJIE_ACCESS_TOKEN=
RUIJIE_GROUP_ID=9290679
# WiFeed (autenticação usuários)
WIFEED_BASE_URL=https://api.wifeed.com.br
WIFEED_CLIENT_ID=60e40ee2-f39f-4556-8a22-840a2e3fa686
WIFEED_CLIENT_SECRET=dRpd6FB2hjbyvcA
LOG_LEVEL=INFO
3. Modo Desenvolvedor (local)
# a) Crie venv
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/Mac
# b) Instale deps
pip install -r requirements.txt
# c) Suba PostgreSQL (Docker)
docker run -d --name wifi-db \
-e POSTGRES_PASSWORD=$DB_PASSWORD \
-e POSTGRES_DB=$DB_NAME \
-p 5432:5432 postgres:15-alpine
# d) Crie o schema
docker exec -i wifi-db psql -U postgres -d wifi_etl < infra/init.sql
# e) Rode o ETL (uma vez)
python app/main.py
# f) (Opcional) Agende localmente
# crontab -e
# */5 * * * * cd /caminho/wifi-etl && /usr/bin/python3 main.py >> /var/log/wifi-etl.log 2>&1
4. Modo Produção (Docker Compose)
# Build e sobe Postgres + ETL (ambiente dev completo)
docker-compose up --build -d
# Logs
docker-compose logs -f etl
# Executa manualmente (debug)
docker-compose exec etl python /app/main.py
5. Deploy Automático (CI/CD)
Ao fazer git push na branch main, o workflow .gitea/workflows/deploy.yml dispara automaticamente:
- Builda imagem Docker (
wifi-etl:<commit-sha>) - Salva como artifact (backup)
- Deploy via SSH no servidor de produção configurado
Configurar Secrets no Gitea
Acesse Settings → Secrets do repositório e adicione:
| Nome | Descrição |
|---|---|
SSH_PRIVATE_KEY |
Chave privada SSH para acesso ao servidor |
SSH_HOST |
IP/hostname do servidor prod (ex: etl.prod.example.com) |
SSH_USER |
Usuário SSH (ex: deploy) |
REGISTRY |
(opcional) Registry Docker (ex: ghcr.io/seu-user) |
REGISTRY_USERNAME |
(opcional) Username do registry |
REGISTRY_PASSWORD |
(opcional) Token/Password do registry |
Variáveis de Ambiente no Servidor
No servidor de produção, crie /opt/wifi-etl/.env com mesmas variáveis do .env local (ou use docker-compose override).
# No servidor (primeira vez)
mkdir -p /opt/wifi-etl
# Copie arquivos: docker-compose.prod.yml + .env (via scp)
# Deploy manual (força rebuild)
./deploy.sh prod
6. Consultas Úteis
-- Sessões com dados do usuário
SELECT u.name, u.cpf, s.access_point_name,
s.online_time, s.offline_time,
EXTRACT(EPOCH FROM (s.offline_time - s.online_time))/60 AS mins
FROM sessions s
JOIN users u ON u.mac_address = s.mac_address
ORDER BY s.online_time DESC
LIMIT 20;
-- Sessões por prédio (último dia)
SELECT building_name, COUNT(*) AS total_sessions,
SUM(active_time_ms)/60000 AS total_minutes
FROM sessions
WHERE online_time >= NOW() - INTERVAL '1 day'
GROUP BY building_name;
-- Usuários únicos (ontem)
SELECT COUNT(DISTINCT mac_address) AS usuarios_unicos
FROM sessions
WHERE online_time::date = CURRENT_DATE - 1;
📊 Modelo de Dados
users
id (PK)
mac_address (UNIQUE, normalized)
name, cpf, gender, email, birthdate
client_id (WiFeed), host_type, local_name
created_at, updated_at
sessions
id (PK)
mac_address (FK → users)
access_point_name, building_name, band, channel
rssi, user_ip, bytes_up/down/total
online_time (TIMESTAMP), offline_time (TIMESTAMP)
active_time_ms
created_at
UNIQUE (mac_address, online_time) ← idempotência
watermarks
source (PK) -- 'ruijie' | 'wifeed'
last_value -- epoch ms (Ruijie) | 'YYYY-MM-DD' (WiFeed)
last_run_at -- timestamp da última extração
🔒 Segurança
- Credenciais: apenas no
.env(nunca commitar) - DB em VM separada:
docker-compose.prod.ymlsó sobe ETL;DB_HOSTaponta para IP externo - Watermarks: evitam vazamento de dados históricos acidental
- Idempotência: constraint única impede duplicatas mesmo em retry
🐛 Troubleshooting
| Problema | Solução |
|---|---|
psycopg2 erro ao conectar |
Verifique DB_HOST, DB_PORT, firewall |
| Token Ruijie 401 | Rode get_access_token() manual ou atualize RUIJIE_ACCESS_TOKEN |
| Watermark não avança | Verifique onlineTime dos registros (deve ser > watermark anterior) |
| MAC não normaliza | Logs Warn — verifique formato de entrada (Cisco vs colon) |
| Docker build lento | Use --no-cache se mudar dependências; senão cache funciona |
📌 Roadmap
- Schema mínimo + watermarks
- Extractor Ruijie com paginação + watermark
- Extractor WiFeed (report/access)
- Transform: normalize_mac + mapeamento campos
- Load: upsert users + insert sessions idempotente
- Docker + cron
- CI/CD (push → deploy)
- Retry com backoff nas APIs
- Testes unitários (pytest)
📝 Licença
Proprietário — Sothis