Sistema de monitoramento em tempo real de máquinas industriais de dobra de tubos (P31–P38), desenvolvido para a Trento Indústria. Integra a leitura de inspeções do PolyWorks, o cálculo e envio de correções LRA às máquinas via TCP, a publicação de medições na API do ERP e dois painéis de acompanhamento (GUI local e web).
┌──────────────────────────┐
PolyWorks exporta │ main.py │ orquestra as threads
*_maquina.json │ (ponto de entrada) │ e o encerramento
*_sistema.json └────────────┬─────────────┘
│ │
▼ ▼
┌───────────────────────────────────────────────────────────────────┐
│ pacote integracao/ │
│ │
│ processamento/ servicos/ │
│ ┌─────────────────────┐ ┌──────────────────────┐ │
│ │ monitor (watchdog) │ │ servidor_socket (TCP)│◄──────┼── Máquinas
│ │ └─► fila ─► worker│ │ servidor_web (Flask) │◄──────┼── Navegadores
│ │ pipeline │──────────►│ api_erp (HTTP) │──────►┼── ERP
│ │ ├─ lra │ │ reenvio_erp (outbox) │──────►┼── ERP (retry)
│ │ ├─ extracao │ │ mdns (Zeroconf) │ │
│ │ └─ util │ └──────────┬───────────┘ │
│ └─────────┬───────────┘ │ │
│ │ dados/ │ │
│ └────────────► gerenciador ◄───────┘ │
│ │ │
│ banco (SQLite) │
│ ▲ │
│ gui/painel (ttkbootstrap) │
└───────────────────────────────────────────────────────────────────┘
O PolyWorks exporta dois tipos de arquivo para o diretório monitorado (ROOT_DIRECTORY). O watchdog aplica um debounce de 1 s (aguarda o arquivo terminar de ser gravado) e o coloca na fila de processamento:
| Arquivo | O que acontece |
|---|---|
<maquina>_maquina.json |
O bloco LRA_CORRECTION é interpretado, os ajustes de correção são calculados e enviados à máquina conectada via socket TCP. O resultado (mesmo vazio) é salvo no estado da máquina e no histórico LRA — inclusive descartes por limite de segurança, com o motivo. |
<maquina>_sistema.json |
O bloco DIMENSIONAL é extraído e: ① o estado da máquina é atualizado (painéis); ② as medições são publicadas na API do ERP via outbox (ver abaixo); ③ um snapshot de BI é gravado (bloco JSON legado + tabelas normalizadas inspecoes/medicoes, com setpoints da máquina solicitados via socket). |
Após o processamento bem-sucedido, o arquivo é arquivado em ROOT_DIRECTORY/processados/AAAA-MM/ (configurável por ARQUIVAR_PROCESSADOS) — para reprocessar, basta movê-lo de volta.
Cada envio de medições é gravado no banco como pendente ANTES de tentar a API — indisponibilidade do ERP atrasa a medição, nunca a perde. Se a primeira tentativa falha, a thread ReenvioERP reprocessa os pendentes com backoff exponencial (configurável via API_RETRY_*) até um máximo de tentativas; depois disso o envio é marcado como falha definitiva (mas nunca apagado). Os painéis mostram o status de cada envio: ✔ enviado, ⏳ pendente, ✖ falha.
- Dobras (GRAU_N) — corrige quando
|desvio| > tolerância; ajuste =-desvio. - Giros (TOMBO_N) — corrige quando
|desvio| > tolerância/2; ajuste =-desvio. - Pernas (TAMANHO_N / UNIDADE_M) — correção acumulativa: cada perna soma o desvio acumulado da anterior e a influência do grau vizinho (fator
grau_influencia_perna). A regra muda conforme o campoProduçãodo arquivo (Normal/ invertida). - Limites de segurança (
LRA_LIMITS) — dobra ou giro acima do limite descarta o envio inteiro (leitura anômala); perna acima do limite é descartada individualmente.
Sist Integração/
│
├── main.py # Ponto de entrada — só orquestra threads
├── main.spec # Build PyInstaller
├── pyproject.toml # Config do pytest e do ruff (lint)
├── requirements.txt
├── requirements-dev.txt # Dependências de desenvolvimento (pytest, ruff)
├── .env.example # Modelo de configuração (copiar para .env)
├── .github/workflows/tests.yml # CI: lint + testes a cada push
│
├── integracao/ # ── Pacote principal ──
│ ├── config.py # TODAS as configurações (lê o .env)
│ ├── estado.py # shutdown_event global
│ ├── logs.py # Logging diário + expurgo (LOG_RETENCAO_DIAS)
│ ├── recursos.py # Caminhos de recursos (dev × PyInstaller)
│ ├── tempo.py # Timestamps ISO 8601 com offset de fuso
│ │
│ ├── processamento/
│ │ ├── monitor.py # Watchdog + debounce + fila + workers
│ │ ├── pipeline.py # Roteia cada arquivo para seu fluxo
│ │ ├── leitor_json.py # Leitura resiliente (utf-8/latin1/cp1252)
│ │ ├── extracao.py # Extração do bloco DIMENSIONAL
│ │ ├── util.py # Tolerâncias + achatamento de medições
│ │ └── lra.py # Classificação e cálculo das correções LRA
│ │
│ ├── servicos/
│ │ ├── servidor_socket.py # Servidor TCP das máquinas (porta 6789)
│ │ ├── servidor_web.py # Painel web Flask/waitress (porta 80)
│ │ ├── api_erp.py # Cliente HTTP da API do ERP (com retry)
│ │ ├── reenvio_erp.py # Outbox: reenvio resiliente ao ERP
│ │ └── mdns.py # Anúncio Zeroconf (http://monitoramento.local)
│ │
│ ├── dados/
│ │ ├── banco.py # SQLite: migrações versionadas e SQL
│ │ └── gerenciador.py # Fachada de acesso a dados
│ │
│ └── gui/
│ └── painel.py # Painel local (Tkinter + ttkbootstrap)
│
├── scripts/ # ── Utilitários independentes ──
│ └── analise_variacao.py # Exporta histórico de inspeções para Excel
│
├── tests/ # Testes pytest (cálculo LRA, util, extração)
│ └── fixtures/ # JSONs de exemplo
│
├── templates/ # Páginas do painel web
│ ├── index.html
│ └── maquina.html
│
├── static/
│ └── chart.umd.min.js # Chart.js local (rede isolada, sem CDN)
│
└── assets/
└── icone.ico
Regra de dependência entre camadas: gui/servicos/processamento → dados/gerenciador → dados/banco. Nenhum módulo acessa o SQLite diretamente, e toda configuração vem de integracao/config.py.
- Python 3.10+
- Windows (a GUI usa Tkinter/ttkbootstrap; caminhos padrão em
D:\Documentos\)
pip install -r requirements.txt# Copie o modelo e preencha com os valores reais
copy .env.example .env
notepad .envVariáveis principais (todas documentadas no .env.example):
| Variável | Uso |
|---|---|
ROOT_DIRECTORY |
Diretório monitorado (exportação do PolyWorks) |
LOG_DIRECTORY |
Diretório dos logs diários |
LOG_RETENCAO_DIAS |
Retenção dos logs em dias (padrão 60; 0 desativa o expurgo) |
DB_PATH |
Caminho do banco SQLite (padrão machines_data.db) |
API_URL / API_TOKEN / API_HEADER_NAME / API_HEADER_1 |
Credenciais da API do ERP |
API_RETRY_* |
Reenvio ao ERP: máx. de tentativas, backoff e frequência da varredura |
ARQUIVAR_PROCESSADOS |
Move JSONs processados para processados/AAAA-MM/ (padrão true) |
LRA_*_MAX |
Limites de segurança do cálculo LRA (padrão 5.0) |
SOCKET_PORT / WEB_PORT / MDNS_NAME |
Portas e nome de rede |
python main.pyA porta 80 (painel web) pode exigir execução como administrador no Windows.
💡 Migração automática do banco: na inicialização, as migrações de schema pendentes são aplicadas automaticamente (tabela
schema_version). Bancos de versões antigas são atualizados sem perder dados — não é preciso rodar nenhum script.
pyinstaller main.spec
# saída: dist/Sistema de Integração.exeO .env deve ficar ao lado do executável em produção.
| Rota | Descrição |
|---|---|
/ |
Seleção de máquina, com indicador de conexão 🟢/🔴 por máquina |
/maquina/<id> |
Painel da máquina: estado atual, últimos envios (✔/⏳/✖), badge de conexão e gráfico de tendência de desvio por cota (atualiza a cada 5 s) |
/api/maquina/<id> |
JSON com o estado atual da máquina |
/api/maquina/<id>/ultimos-envios |
Últimos 3 envios à API do ERP (com status) |
/api/maquina/<id>/cotas |
Nomes das cotas já medidas (seletor do gráfico) |
/api/maquina/<id>/medicoes?cota=<nome>&limite=N |
Série temporal de uma cota (timestamp, medida, desvio, tolerância) |
/api/dados-inspecao |
Histórico de snapshots (BI), paginado: machine_id, de, ate, limite (padrão 500, máx 2000), offset |
/api/status |
Diagnóstico: máquinas conectadas, métricas do pipeline, fila e último envio ao ERP por máquina |
O painel é servido pelo waitress (servidor WSGI de produção) e funciona 100% offline — o Chart.js do gráfico de tendência é embarcado em static/, sem CDN. Com o mDNS ativo, fica acessível em http://monitoramento.local na rede.
Mensagens JSON delimitadas por \n sobre TCP (porta 6789):
- Ao conectar, a máquina envia seu nome (ex.:
P31) como primeira mensagem; - O servidor envia correções LRA como
{"dobra_1": -0.35, "unidade_2": 1.2, ...}; - O servidor pode solicitar
{"command": "GET_SETPOINTS"}e a máquina responde{"response_to": "GET_SETPOINTS", "data": {...}}; - Qualquer outro JSON da máquina é tratado como feedback e salvo no banco (
machine_id,valores_lidos,valores_atualizados).
O banco roda em modo WAL (leituras concorrentes com a escrita) e o schema é versionado: a tabela schema_version registra as migrações aplicadas, e a inicialização atualiza bancos antigos automaticamente.
| Tabela | Conteúdo |
|---|---|
machine_state |
Estado ATUAL de cada máquina (1 linha por máquina, sobrescrita) |
dados_inspecao |
Snapshots de BI em JSON (legado — mantido por compatibilidade) |
inspecoes + medicoes |
Medições normalizadas: uma linha por cota, com medida/desvio/tolerância/setpoint — base das séries e gráficos |
historico_api |
Cada envio ao ERP, com resultado (sucesso/status/latência) e controle de reenvio (outbox) |
historico_lra |
Cada cálculo LRA, inclusive descartes por limite com o motivo |
historico_feedback |
Todos os feedbacks recebidos das máquinas |
eventos_conexao |
Conexões/desconexões das máquinas (auditoria de disponibilidade) |
schema_version |
Migrações de schema já aplicadas |
A maioria dos registros carrega arquivo_origem — o nome do JSON do PolyWorks que o gerou (rastreabilidade).
| Pacote | Uso |
|---|---|
flask |
Painel web |
waitress |
Servidor WSGI de produção do painel web |
ttkbootstrap |
Interface gráfica |
watchdog |
Monitoramento do diretório de exportação |
zeroconf |
Descoberta mDNS na rede |
requests |
Cliente da API do ERP |
python-dotenv |
Carregamento do .env |
pandas + openpyxl |
Somente scripts/analise_variacao.py (exportação Excel) |
# Exporta o histórico de inspeções para Excel (consome a API paginada do painel)
python scripts/analise_variacao.py # BACKEND_IP configurável via .envO cálculo LRA (regras de correção, efeitos acumulativos e limites de segurança) é coberto por testes:
pip install -r requirements-dev.txt
pytest # testes
ruff check . # lintO workflow em .github/workflows/tests.yml roda lint e testes a cada push/PR.
- Tokens e credenciais são lidos exclusivamente do
.env/ variáveis de ambiente; - O
.envé ignorado pelo git — nunca coloque credenciais em código ou commits; - Consulte
.env.examplepara a lista completa de variáveis.
- Crie uma branch:
git checkout -b feature/nome-da-feature - Faça commits semânticos (
feat:,fix:,docs:,chore:…) - Abra um Pull Request
Uso interno — Trento Indústria.