Pular para conteúdo

Arquitetura

Visão geral

O sistema é dividido em três camadas:

  1. Edge — ESP32 com sensores (ZMPT101B + SCT-013-100) calcula Vrms, Irms, Watts, fator de potência e kWh e publica via MQTT.
  2. Broker — HiveMQ Cloud (MQTTS, porta 8883) roteia as mensagens.
  3. Cloud — aplicação Django recebe a telemetria, persiste no PostgreSQL e entrega dashboards, previsões e o assistente WhatsApp.
ESP32 → HiveMQ Cloud (MQTTS) → Django Subscriber → PostgreSQL/TimescaleDB
                                        ↓
                               Views CBV + Templates (web)
                               REST API — DRF (app Flet)
                               Webhook Evolution API (WhatsApp)

Apps Django

App Responsabilidade
core BaseModel com timestamps, configuração central, site público
accounts Modelo de usuário customizado, autenticação por e-mail
meters Cadastro e status dos medidores IoT
telemetry Ingestão MQTT e armazenamento das leituras
tariffs Tarifas da ANEEL e cálculo de custo estimado
dashboard Agregações e gráficos de consumo
analytics Previsão de fatura (forecasting) e desagregação de cargas (NILM, com classificador por usuário + calibração manual)
assistant Chatbot WhatsApp (Evolution API) e chat web, ambos via LangChain/RAG
api Endpoints REST para o app Flet

O app Flet (flet_app/) é um projeto Python separado; não é uma app Django.


Stack técnica

Camada Tecnologia
Linguagem Python 3.11
Framework web Django 5.x (MVT, sem SPA)
Templates Django Template Language
Estilização web TailwindCSS 3.x (darkMode: 'class')
Gráficos web Chart.js
REST API Django REST Framework
Autenticação da API Token (DRF TokenAuthentication)
App mobile Flet (Python) — build Android/iOS
Banco de dados PostgreSQL 16 + extensão TimescaleDB
Driver do banco psycopg (psycopg2-binary)
Cliente MQTT paho-mqtt (management command)
Variáveis de ambiente python-decouple
IA — Forecasting scikit-learn / statsmodels
IA — NILM scikit-learn
API de clima Open-Meteo (variável exógena do forecasting)
Assistente LangChain (RAG) + Evolution API

Fluxo de dados

ESP32 publica telemetria (a cada 5s)
    → HiveMQ Cloud (MQTTS 8883)
        → management command run_mqtt_subscriber (paho-mqtt)
            → service layer (telemetry/services.py)
                → TelemetryReading salvo no PostgreSQL/TimescaleDB

ESP32 publica status (LWT / boot)
    → management command run_mqtt_subscriber
        → atualiza Meter.is_online + cria DeviceStatusEvent

Dashboard web
    → lê TelemetryReading + BillForecast + LoadDisaggregation
    → renderiza via CBV + DTL + Chart.js

App Flet
    → autenticação: POST /api/auth/token/
    → lê dados: GET /api/meters/, /api/meters/{id}/readings/, etc.

WhatsApp
    → usuário mensagem → Evolution API → webhook Django (assistant app)
        → LangChain RAG consulta telemetria e estimativas
        → resposta em linguagem natural enviada de volta

Chat web (botão flutuante na seção Assistente)
    → usuário digita → POST /assistant/chat/ (WebChatView)
        → mesmo pipeline RAG (build_user_context + LangChain)
        → resposta retornada como JSON (sem envio WhatsApp)
        → mensagem persistida com source='web'

Alertas proativos (ver docs/alertas.md)
    → signals (BillForecast, TelemetryReading) + NILM + sync_white_tariff
        → send_proactive_alert (assistant/services.py)
            → WhatsApp (se o usuário já conversou com o bot)
            → AssistantMessage(is_proactive_alert=True)
                → card "Último alerta" no dashboard + histórico do assistente

Banco de dados por ambiente

Ambiente Imagem Observação
Desenvolvimento local timescale/timescaledb:latest-pg16 Hypertable + agregação contínua ativos
Produção (IONOS VPS) postgres:16-alpine Migrations TimescaleDB condicionais — ignoradas quando a extensão não está presente

A tabela TelemetryReading é uma hypertable particionada por measured_at quando o TimescaleDB está disponível. As migrations 0002_hypertable e 0003_continuous_aggregates verificam a existência da função create_hypertable antes de executar, tornando o banco intercambiável.


Deploy em produção (Docker)

O sistema roda containerizado via docker-compose.prod.yml em energiasm.online:

nginx:alpine  →  energia-web (Gunicorn, 4 workers)  →  postgres:16-alpine
                 energia-mqtt_subscriber (management command, PYTHONUNBUFFERED=1)
                 evolution-api:8080 (evoapicloud/evolution-api:latest)

Serviços:

Serviço Função
db PostgreSQL 16-alpine — bancos energia_db e evolution_api
web Django + Gunicorn, 4 workers
mqtt_subscriber Management command run_mqtt_subscriber (reconecta recriando mqtt.Client)
nginx Reverse proxy + SSL Let's Encrypt + /media/
evolution-api Gateway WhatsApp, instância energiabot

Dockerfile: multi-stage build — gcc/libpq-dev apenas no stage builder; runtime usa só libpq5. Reduz a imagem final em ~200 MB.

requirements.prod.txt: versão de produção sem flet, flake8, black, isort e outras ferramentas de desenvolvimento.

Guia completo: docs/DEPLOY.md.