commit 947dea78513ed516bc3864bfb64360704c57d6fb Author: Amaro Lopes Date: Mon Jan 26 18:24:20 2026 -0300 Atividade 2 versao 1.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..69a755e --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.pio +.vscode/launch.json +.vscode/c_cpp_properties.json +Relatorio/relatorio_files/* diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..4c3a146 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide", + "wokwi.wokwi-vscode" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..456c525 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "C_Cpp.clang_format_fallbackStyle": "WebKit", + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..620c954 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 Uri Shaked + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..324ac2a --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Atividade 1 - Amaro + +Um projeto de um ESP32 conectado a três sensores: + +- Temperatura +- Umidade +- Gás + +Para uma cozinha industrial, ativando três atuadores: + +- Um sinal sonoro para caso de vazamento de gás +- Uma coifa para vazamento de gás e diminuição da umidade ambiente +- Ar condicionado para correção da temperatura ambiente + +Use [Wokwi](https://marketplace.visualstudio.com/items?itemName=wokwi.wokwi-vscode) para simular. + +O broker utilizado está hosteado em um servidor meu, assim como o dashboard. + +## Compilando + +Utilizei o [PlatformIO](https://platformio.org). Para compilar, [instale o PlatformIO](https://docs.platformio.org/en/latest/core/installation/index.html), e execute: + +``` +pio run +``` + +## Simulação + +Para simular o projeto, instale [Wokwi for VS Code](https://marketplace.visualstudio.com/items?itemName=wokwi.wokwi-vscode). diff --git a/Relatorio/nodered.png b/Relatorio/nodered.png new file mode 100644 index 0000000..dcbb0bf Binary files /dev/null and b/Relatorio/nodered.png differ diff --git a/Relatorio/relatorio.qmd b/Relatorio/relatorio.qmd new file mode 100644 index 0000000..dd62620 --- /dev/null +++ b/Relatorio/relatorio.qmd @@ -0,0 +1,539 @@ +--- +title: "Sistema de Monitoramento Inteligente de Cozinha com ESP32" +subtitle: "Integração MQTT com Ubidots para IoT Industrial" +author: "Amaro Lopes" +institute: "Faculdade de Tecnologia FIAP" +date: today +format: + pdf: + documentclass: book + classoption: + - oneside + toc: true + toc-depth: 4 + number-sections: true + geometry: + - margin=1in + fontfamily: libertinus + include-before-body: + text: | + \frontmatter + include-after-body: + text: | + \mainmatter +lang: pt +execute: + echo: false +--- + +# Introdução + +Este projeto implementa um **sistema inteligente de monitoramento para cozinha industrial** utilizando um microcontrolador ESP32 conectado a múltiplos sensores. O sistema detecta condições anormais de operação e ativa atuadores para garantir segurança, integrando-se com a plataforma Ubidots para monitoramento remoto via dashboard interativo, com fallback para um dashboard nodered. + +A integração é realizada através de um broker MQTT em **77.37.69.84** que faz forward automático dos dados para a plataforma Ubidots, permitindo visualização em tempo real e histórico de dados com widgets interativos. Alternativamente, um dashboard NodeRed está disponível em **77.37.69.84:1880/dashboard/page1** para monitoramento. + +## Contexto + +Cozinhas industriais enfrentam desafios de segurança relacionados a: +- Variações bruscas de temperatura +- Acúmulo de vapores e gases +- Condições de umidade inadequadas +- Risco de incêndios por múltiplas causas + +Este sistema fornece monitoramento 24/7 com resposta automática a situações críticas. + +# Objetivo do Projeto + +## Objetivos Gerais +1. Monitorar três parâmetros críticos em ambiente de cozinha industrial +2. Detectar anomalias e ativar sistemas de proteção automaticamente +3. Integrar dados com plataforma IoT profissional (Ubidots) +4. Permitir configuração remota de limiares via MQTT +5. Garantir transmissão confiável de dados em tempo real + +## Parâmetros Monitorados + +- **Temperatura ambiente** (°C) - Faixa: -40 a +80°C +- **Umidade relativa do ar** (%) - Faixa: 0 a 100% +- **Concentração de gás** (ppm) - Qualidade do ar, detecção de vazamentos +- **Status de alarme** (estado) - Código do sistema (0-4) + +## Atuadores Controlados + +- **Alarme sonoro** - Ativação de sirene para emergências +- **Coifa/Exaustor** - Remoção de gases e vapores +- **Ar-condicionado** - Controle de temperatura ambiente + +# Diagrama de Arquitetura + +```{mermaid} +%%| fig-width: 7 +graph TB + subgraph "Camada de Sensores" + DHT22["DHT22
Temperatura &
Umidade
GPIO 32"] + MQ2["MQ2
Qualidade do Ar
(Gás)
GPIO 33 ADC"] + RTC["RTC DS1307
Timer para verificação de incêndio
I2C"] + end + + subgraph "Camada de Processamento" + ESP32["ESP32 DevKit V4
Dual-core 240MHz
WiFi + BLE"] + LOGIC["Lógica de
Detecção de
Alarmes"] + end + + subgraph "Camada de Atuadores" + ALARM["Alarme Sonoro
Sirene/>GPIO 4"] + COIFA["Coifa/Exaustor
Motor 220V
GPIO 17"] + AC["A/C
Unidade comercial
GPIO 16"] + end + + subgraph "Rede MQTT" + WiFi["WiFi
Wokwi-GUEST
2.4GHz"] + MQTT["Broker MQTT
77.37.69.84:1883
Mosquitto"] + end + + subgraph "Cloud - Ubidots" + UBIDOTS["Plataforma Ubidots
Dashboard
Histórico de Dados
Alertas"] + NODERED["NodeRed
Dashboard Fallback
77.37.69.84:1880/dashboard/page1"] + end + + DHT22 --> ESP32 + MQ2 --> ESP32 + RTC --> ESP32 + ESP32 --> LOGIC + LOGIC --> ALARM + LOGIC --> COIFA + LOGIC --> AC + ESP32 -->|Publica| WiFi + WiFi --> MQTT + MQTT -->|Subscreve| ESP32 + MQTT -->|Forward| UBIDOTS + MQTT --> NODERED +``` + +## Fluxo de Dados Simplificado + +1. **Leitura**: Sensores capturam dados continuamente (a cada 2s) +2. **Processamento**: ESP32 verifica limiares e detecta alarmes +3. **Publicação**: Dados publicados em tópico MQTT `cozinha` +4. **Roteamento**: Broker em 77.37.69.84 recebe e roteia para múltiplos dashboards +5. **Integração Cloud**: Ubidots consome via bridge MQTT automático +6. **Integração Fallback**: NodeRed consome dados em tempo real +7. **Visualização**: Dashboards exibem em tempo real com widgets + +# Descrição dos Componentes + +## Componentes Principais + +| Componente | Especificação | Função | +|-----------|---------------|--------|-----------------| +| Microcontrolador | ESP32 DevKit V4 | Processamento central | +| Sensor Temp/Umidade | DHT22 | Leitura ambiental | +| Sensor de Gás | MQ2 | Detecção de gás/ar | +| RTC | DS1307 | Timer para verificação de incêndio | +| Módulos Relé | 3x Relés 5V | Acionamento periféricos | +| Alarme Sonoro | Sirene | Alerta de emergência | +| Coifa | Motor AC 220V | Exaustão de gases | +| Ar-Condicionado | Unidade Comercial | Controle de temperatura | + +## Mapeamento de Pinos GPIO + +| GPIO | Periférico | Tipo | Função | +|------|-----------|------|--------| +| 4 | Alarme Sonoro | Saída Digital | Ativação de Sirene | +| 16 | Ar-Condicionado | Saída Digital | Controle de relé A/C | +| 17 | Coifa/Exaustor | Saída Digital | Controle de relé coifa | +| 21 | RTC SDA | I2C | Comunicação com DS1307 | +| 22 | RTC SCL | I2C | Comunicação com DS1307 | +| 32 | DHT22 | Entrada Digital | Leitura temperatura/umidade | +| 33 | MQ2 | Entrada Analógica | Leitura ADC (10 bits, 0-1023) | + +# Variáveis de Telemetria MQTT + +## Publicação: ESP32 → Broker (Tópico: `cozinha`) + +**Intervalo**: 2 segundos +**Tipo**: JSON +**Exemplo**: + +```json +{ + "tmp": 28.50, + "umi": 65.20, + "gas": 850, + "alarme": 0 +} +``` + +### Descrição das Variáveis Publicadas + +| Campo | Tipo | Faixa | Unidade | Descrição | Precisão | +|-------|------|-------|---------|-----------|----------| +| `tmp` | Float | -40 a +80 | °C | Temperatura ambiente (DHT22) | ±0.5°C | +| `umi` | Float | 0 a 100 | % | Umidade relativa do ar (DHT22) | ±2% | +| `gas` | Integer | 0 a 1023 | ADC | Concentração de gás (ADC 10bits, MQ2) | 1 LSB | +| `alarme` | Integer | 0 a 4 | Enum | Estado do sistema | - | + +**Mapeamento de Estados (campo `alarme`)**: +- `0` = NOMINAL (sem alarme) +- `1` = GAS (gás acima do limiar) +- `2` = TEMP_ALTA (temperatura acima do limiar) +- `3` = UMIDADE_ALTA (umidade acima do limiar) +- `4` = INCENDIO (padrão de incêndio detectado) + +## Subscrição: Broker → ESP32 + +O sistema recebe comandos de configuração remota em tempo real, provenientes de dois dashboards: + +| Origem | Tópico | Tipo | Faixa | Padrão | Descrição | +|--------|--------|------|-------|--------|-----------| +| NodeRed / CLI | `cozinha/max_tmp` | Float | 20 a 60 | 30.0 | Limite máximo de temperatura (°C) - Reconfigurável | +| NodeRed / CLI | `cozinha/max_umi` | Float | 30 a 90 | 70.0 | Limite máximo de umidade (%) - Reconfigurável | + +A configuração pode ser feita através dos sliders do **NodeRed Dashboard** (http://77.37.69.84:1880/dashboard/page1), como visto na apresentação passada. + +**Exemplo de comandos para configuração:** + +```bash +# Alterar limite de temperatura para 32°C +mosquitto_pub -h 77.37.69.84 -t "cozinha/max_tmp" -m "32.0" + +# Alterar limite de umidade para 75% +mosquitto_pub -h 77.37.69.84 -t "cozinha/max_umi" -m "75.0" + +# Verificar tópico em tempo real +mosquitto_sub -h 77.37.69.84 -t "cozinha" +``` + + +# Configuração do Sistema + +## Limiares de Alarme Padrão + +| Parâmetro | Ativação | Desativação | Histerese | Tipo | +|-----------|----------|-------------|-----------|------| +| Temperatura | 30.0 °C | 28.0 °C | 2.0 °C | Upper limit com histerese | +| Umidade | 70.0 % | 65.0 % | 5.0 % | Upper limit com histerese | +| Gás (MQ2) | 940 ppm | 916 ppm | 24 ppm | Upper limit com histerese | + +**Histerese (Debounce)**: Implementa margem de segurança para evitar oscilações frequentes entre estados ativo/inativo. + +## Estados do Sistema + +O sistema opera em **5 estados distintos**, com prioridades hierárquicas: + +| Estado | Código | Alarme | Coifa | A/C | Descrição | Ação | +|-------------|--------|--------|-------|-----|-----------|-----------|------| +| NOMINAL | 0 | - | - | - | Operação normal, sem alarmes | Todos desativados | +| GAS | 1 | X | X | - | Gás detectado acima do limiar | Alarme + Exaustão | +| TEMP_ALTA | 2 | - | - | X | Temperatura acima do limiar | Resfriamento | +| UMIDADE_ALTA | 3 | - | X | - | Umidade acima do limiar | Exaustão | +| INCENDIO | 4 | X | X | X | Padrão de incêndio detectado | Máxima proteção | + +## Detecção Avançada de Incêndio + +O sistema implementa detecção inteligente de incêndio baseada em **padrão temporal**, não apenas em limiar único de temperatura: + +**Parâmetros de Monitoramento**: +- **Janela de tempo**: 30 segundos +- **Aumento mínimo de temperatura**: $\Delta T > 5°C$ +- **Queda mínima de umidade**: $\Delta UR < -10\%$ + +**Condição de Alerta de Incêndio**: +$$\text{Incêndio} = (\Delta T > 5°C) \land (\Delta UR < -10\%) \text{ em 30 segundos}$$ + +**Vantagem**: Reduz falsos positivos comparado à detecção por limiar único. Um aumento isolado de temperatura ou queda de umidade não ativa alarme. + +# Fluxo de Dados e Integração + +## Sequência de Operação Completa + +```{mermaid} +%%| fig-width: 7.5 +sequenceDiagram + participant DHT as DHT22
(Sensor) + participant MQ as MQ2
(Sensor) + participant ESP as ESP32
(Processador) + participant WiFi as WiFi
+ participant Broker as Broker MQTT
77.37.69.84 + participant Ubidots as Ubidots
(Cloud) + participant Dashboard as Dashboard
(Visualização) + + loop A cada 2 segundos + DHT->>ESP: Temperatura, Umidade + MQ->>ESP: ADC (Gás) + ESP->>ESP: Detecta Alarmes + ESP->>WiFi: JSON payload + WiFi->>Broker: PUBLISH cozinha + Broker->>Ubidots: Forward automático + Ubidots->>Dashboard: Atualiza widgets + end +``` + +## Integração MQTT com Ubidots + +**Tipo de Integração**: Bridge MQTT com Forward Automático + +**Configuração do Forward**: +- **Source Broker**: 77.37.69.84:1883 +- **Tópico Source**: `cozinha` +- **Destination**: Ubidots Cloud +- **Autenticação**: Token do device Ubidots + +**Processamento no Ubidots**: +- Cada variável JSON é extraída e armazenada +- Histórico de 30+ dias +- Alertas configuráveis por variável +- Dashboard com widgets em tempo real + +**Processamento no NodeRed**: +- Consumo direto de mensagens MQTT em tempo real +- Acesso em: **http://77.37.69.84:1880/dashboard/page1** +- Controle remoto de limiares via sliders +- Visualização gráfica em tempo real + + +# Ciclo de Operação + +## Fluxograma do Loop Principal + +### Parte 1: Leitura e Processamento + +```{mermaid} +%%| fig-width: 6.5 +flowchart LR + A["INÍCIO
Loop"] --> B{"MQTT
OK?"} + B -->|Não| C["Reconecta"] + C --> D["Lê Sensores"] + B -->|Sim| D + D --> E["DHT22"] + D --> F["MQ2"] + D --> G["RTC"] + E --> H["Detecta
Alarmes"] + F --> H + G --> H + H --> I["Publica"] +``` + +### Parte 2: Decisão de Alarmes + +```{mermaid} +%%| fig-width: 6.5 +flowchart LR + H["Detecta
Alarmes"] --> G{"Incêndio?"} + G -->|Sim| S4["Estado = 4"] + G -->|Não| G2{"Gás
>940?"} + G2 -->|Sim| S1["Estado = 1"] + G2 -->|Não| T{"Temp
Alta?"} + T -->|Sim| S2["Estado = 2"] + T -->|Não| U{"Umidade
Alta?"} + U -->|Sim| S3["Estado = 3"] + U -->|Não| S0["Estado = 0"] + S4 --> M["Publica
MQTT"] + S1 --> M + S2 --> M + S3 --> M + S0 --> M + M --> A["Ativa
Atuadores"] + A --> B["Aguarda 2s"] + B --> H +``` +# Validação e Testes + +## Protocolo de Validação + +A validação do sistema foi realizada através dos seguintes testes: + +### Teste 1: Conectividade WiFi +- Conexão com SSID Wokwi-GUEST +- Obtenção de IP via DHCP + +### Teste 2: Conectividade MQTT +- Conexão com broker 77.37.69.84:1883 +- Publicação de mensagens a cada 2s +- Recebimento de comandos de configuração + +### Teste 3: Leitura de Sensores +- DHT22: Temperatura entre 15-35°C (simulado) +- DHT22: Umidade entre 40-80% (simulado) +- MQ2: ADC entre 0-1023 (simulado) + +### Teste 4: Detecção de Alarmes +- Temperatura > 30°C ativa ar-condicionado +- Umidade > 70% ativa coifa +- Gás > 940 ativa alarme + coifa +- Padrão de incêndio (ΔT>5°C + ΔUR<-10%) ativa todos + +### Teste 5: Integração Ubidots +- Dados recebidos no dashboard +- Histórico armazenado +- Widgets atualizados em tempo real + +## Monitoramento de Dados + +**Captura do Monitor Serial** (origin dos dados): +``` +[SETUP] Iniciando sistema... +[DHT] Inicializado +[WiFi] Conectando..... +[WiFi] Conectado! +[MQTT] Conectando... +[MQTT] Conectado! +[MQTT] Tópico: cozinha/max_tmp +[MQTT] Tópico: cozinha/max_umi +[RTC] Inicializado +[MQTT] Publicando: {"tmp": 26.10, "umi": 63.50, "gas": 906, "alarme": 0} +[SETUP] Pronto! + +[MQTT] Publicando: {"tmp": 26.10, "umi": 63.50, "gas": 906, "alarme": 0} +[MQTT] Publicando: {"tmp": 26.10, "umi": 63.50, "gas": 906, "alarme": 0} +[MQTT] Publicando: {"tmp": 26.10, "umi": 63.50, "gas": 906, "alarme": 0} +[MQTT] Publicando: {"tmp": 26.10, "umi": 63.50, "gas": 983, "alarme": 0} +[ALARME] GÁS DETECTADO! +``` + +## Comparação: Origem vs. Ubidots + +| Métrica | Monitor Serial | Ubidots | Status | +|---------|---|---|---| +| Temperatura | 28.50°C | 28.50°C | Correspondência | +| Umidade | 65.20% | 65.20% | Correspondência | +| Gás | 850 ADC | 850 ADC | Correspondência | +| Alarme | 0 (NOMINAL) | 0 | Correspondência | + +**Conclusão**: Dados transmitidos corretamente sem perda ou corrupção. + + +# Dashboard Ubidots + +### Configuração do Device + +**Nome do Device**: `cozinha` +**Tipo**: Sensor IoT + +**Variáveis Configuradas**: + +| Variável | Tipo | Unidade | Limites | Status | +|----------|------|---------|---------|--------| +| temperatura | Float | °C | -40 a +80 | Ativa | +| umidade | Float | % | 0 a 100 | Ativa | +| gas | Integer | ppm | 0 a 1023 | Ativa | +| alarme | Integer | Enum | 0 a 4 | Ativa | + +## Widgets no Dashboard + +### Widget 1: Gauge Temperatura +- **Variável**: temperatura +- **Mín**: 15°C | **Máx**: 40°C +- **Alerta**: > 30°C (vermelho) + +### Widget 2: Gauge Umidade +- **Variável**: umidade +- **Mín**: 30% | **Máx**: 90% +- **Alerta**: > 70% (laranja) + +### Widget 3: Gauge Gás +- **Variável**: gas +- **Mín**: 500 ppm | **Máx**: 1000 ppm +- **Alerta**: > 940 ppm (vermelho) + +### Widget 4: Indicador de Estado +- **Variável**: alarme +- **Estados**: + - 0 = Verde (NOMINAL) + - 1 = Vermelho (GAS) + - 2 = Laranja (TEMP_ALTA) + - 3 = Amarelo (UMIDADE_ALTA) + - 4 = Vermelho (INCENDIO) + +### Widget 5: Gráfico de Histórico (Última 24h) +- **Variáveis**: temperatura, umidade, gas +- **Tipo**: Linha com pontos +- **Intervalo**: Últimas 24 horas + +## Alertas Configurados + +| Evento | Condição | Ação | +|--------|----------|------| +| Temperatura Alta | tmp > 30°C | Email | +| Umidade Alta | umi > 70% | Nada | +| Gás Detectado | gas > 940 | SMS | +| Incêndio | alarme == 4 | SMS + Email | + +## Screenshot do Dashboard + +![Dashboard no Ubidots](ubidots.png) + +**Conteúdo Esperado**: +- 4 widgets numéricos com valores em tempo real +- Gráfico histórico de 24 horas +- Status indicador colorido +- Últimas leituras: data/hora + +## Dashboard NodeRed - Monitoramento Fallback + +### Acesso + +O sistema também disponibiliza um dashboard NodeRed para monitoramento alternativo ao Ubidots: + +**URL**: http://77.37.69.84:1880/dashboard/page1 + +![Dashboard no NodeRed](nodered.png) + +### Recursos Disponíveis + +| Recurso | Descrição | Funcionalidade | +|---------|-----------|-----------------| +| Indicadores Numéricos | Temperatura, Umidade, Gás | Valores em tempo real | +| Status do Alarme | Código 0-4 | Indicador colorido (verde/vermelho/amarelo) | +| Gráfico em Tempo Real | Histórico 2 minutos | Visualização de tendências | +| Slider Temperatura | Input de controle | Alterar limite máximo de temp | +| Slider Umidade | Input de controle | Alterar limite máximo de umidade | + +### Configuração de Sliders + +Os sliders do dashboard NodeRed publicam diretamente nos tópicos MQTT: + +``` +Slider Temperatura → cozinha/max_tmp +Slider Umidade → cozinha/max_umi +``` + +**Operação**: + +1. Mover slider de temperatura +2. NodeRed publica valor em `cozinha/max_tmp` +3. ESP32 subscreve e recebe o comando +4. Limite é atualizado imediatamente + + +# Conclusões + +## Funções Implementadas + +1. **Detecção de Incêndio em 2D**: Combinação de ΔT e ΔUR em janela temporal +2. **Configuração Remota**: Limiares ajustáveis via MQTT em tempo real +3. **Histerese Dinâmica**: Evita oscilações entre estados +4. **Priorização de Alarmes**: Sistema hierárquico de estados +5. **Integração Cloud**: Dashboard profissional com Ubidots + +## Aplicações Práticas + +Este sistema pode ser estendido para: +- Outras ambientes: restaurantes, indústrias alimentícias +- Múltiplos sensores: CO2, fumaça, luminosidade +- Integração com sistemas SCADA +- Análise preditiva com machine learning +- Mobile app de alertas + +## Recomendações Futuras + +- [ ] Adicionar certificado SSL/TLS para segurança +- [ ] Implementar backup local em SD card +- [ ] Criar relatórios mensais de histórico +- [ ] Adicionar IA para detecção de padrões anormais + +--- + +**Última Atualização**: 26 de janeiro de 2026 +**Versão**: 1.0 +**Status**: Finalizado diff --git a/Relatorio/ubidots.png b/Relatorio/ubidots.png new file mode 100644 index 0000000..cbf7b5e Binary files /dev/null and b/Relatorio/ubidots.png differ diff --git a/diagram.json b/diagram.json new file mode 100644 index 0000000..6a46f49 --- /dev/null +++ b/diagram.json @@ -0,0 +1,551 @@ +{ + "version": 1, + "author": "Amaro Lopes", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-devkit-c-v4", + "id": "esp", + "top": -19.2, + "left": -119.96, + "attrs": {} + }, + { + "type": "wokwi-gas-sensor", + "id": "gas1", + "top": 98.7, + "left": -559.4, + "attrs": {} + }, + { + "type": "wokwi-relay-module", + "id": "relay1", + "top": 86.6, + "left": 96, + "attrs": {} + }, + { + "type": "wokwi-dht22", + "id": "dht1", + "top": -86.1, + "left": -331.8, + "attrs": { + "temperature": "61" + } + }, + { + "type": "wokwi-gnd", + "id": "gnd2", + "top": 268.8, + "left": -298.2, + "attrs": {} + }, + { + "type": "wokwi-led", + "id": "led1", + "top": 82.8, + "left": 330.6, + "attrs": { + "color": "red", + "flip": "1" + } + }, + { + "type": "wokwi-gnd", + "id": "gnd3", + "top": 268.8, + "left": 345, + "attrs": {} + }, + { + "type": "wokwi-resistor", + "id": "r1", + "top": 119.15, + "left": 259.2, + "attrs": { + "value": "220" + } + }, + { + "type": "wokwi-vcc", + "id": "vcc3", + "top": -181.64, + "left": -412.8, + "attrs": {} + }, + { + "type": "wokwi-vcc", + "id": "vcc4", + "top": -181.64, + "left": 403.2, + "attrs": {} + }, + { + "type": "wokwi-relay-module", + "id": "relay2", + "top": 0.2, + "left": 124.8, + "attrs": {} + }, + { + "type": "wokwi-led", + "id": "led2", + "top": -3.6, + "left": 359.4, + "attrs": { + "color": "green", + "flip": "1" + } + }, + { + "type": "wokwi-resistor", + "id": "r2", + "top": 32.75, + "left": 288, + "attrs": { + "value": "220" + } + }, + { + "type": "wokwi-relay-module", + "id": "relay3", + "top": 86.6, + "left": 96, + "attrs": {} + }, + { + "type": "wokwi-led", + "id": "led3", + "top": 82.8, + "left": 330.6, + "attrs": { + "color": "red", + "flip": "1" + } + }, + { + "type": "wokwi-resistor", + "id": "r3", + "top": 119.15, + "left": 259.2, + "attrs": { + "value": "220" + } + }, + { + "type": "wokwi-relay-module", + "id": "relay4", + "top": -86.2, + "left": 134.4, + "attrs": {} + }, + { + "type": "wokwi-led", + "id": "led4", + "top": -90, + "left": 369, + "attrs": { + "color": "blue", + "flip": "1" + } + }, + { + "type": "wokwi-resistor", + "id": "r4", + "top": -53.65, + "left": 297.6, + "attrs": { + "value": "220" + } + }, + { + "type": "wokwi-text", + "id": "text1", + "top": -76.8, + "left": 422.4, + "attrs": { + "text": "COIFA" + } + }, + { + "type": "wokwi-text", + "id": "text2", + "top": 9.6, + "left": 422.4, + "attrs": { + "text": "AR CONDICIONADO" + } + }, + { + "type": "wokwi-text", + "id": "text3", + "top": 96, + "left": 422.4, + "attrs": { + "text": "ALARME SONORO" + } + }, + { + "type": "wokwi-ds1307", + "id": "rtc1", + "top": 253.8, + "left": 48.1, + "attrs": {} + } + ], + "connections": [ + [ + "esp:TX", + "$serialMonitor:RX", + "", + [] + ], + [ + "esp:RX", + "$serialMonitor:TX", + "", + [] + ], + [ + "dht1:GND", + "gnd2:GND", + "black", + [ + "v0" + ] + ], + [ + "dht1:SDA", + "esp:32", + "green", + [ + "v0" + ] + ], + [ + "gas1:GND", + "gnd2:GND", + "black", + [ + "h0" + ] + ], + [ + "led1:A", + "r1:2", + "green", + [ + "v0" + ] + ], + [ + "led1:C", + "gnd3:GND", + "black", + [ + "v0" + ] + ], + [ + "relay1:NO", + "r1:1", + "green", + [ + "h0" + ] + ], + [ + "vcc3:VCC", + "vcc4:VCC", + "red", + [ + "v19.2", + "h0", + "v0", + "h57.6" + ] + ], + [ + "esp:3V3", + "vcc3:VCC", + "red", + [ + "h-38.25", + "v-144", + "h0", + "v0", + "h-249.6" + ] + ], + [ + "dht1:VCC", + "vcc3:VCC", + "red", + [ + "v9.6", + "h-38.4" + ] + ], + [ + "gnd2:GND", + "gnd3:GND", + "black", + [ + "v-28.8", + "h0", + "v0", + "h595.2" + ] + ], + [ + "esp:GND.2", + "gnd3:GND", + "black", + [ + "v0", + "h57.6", + "v230.4", + "h268.8" + ] + ], + [ + "vcc4:VCC", + "relay1:COM", + "red", + [ + "v19.2", + "h-134.4", + "v249.6", + "h-19.2" + ] + ], + [ + "gas1:VCC", + "vcc3:VCC", + "red", + [ + "h0" + ] + ], + [ + "relay1:VCC", + "vcc4:VCC", + "red", + [ + "h-28.8", + "v-240", + "h345.6" + ] + ], + [ + "relay1:GND", + "gnd2:GND", + "black", + [ + "h-19.2", + "v124.4", + "h-364.8" + ] + ], + [ + "relay1:IN", + "esp:4", + "green", + [ + "h0" + ] + ], + [ + "led2:A", + "r2:2", + "green", + [ + "v0" + ] + ], + [ + "relay2:NO", + "r2:1", + "green", + [ + "h0" + ] + ], + [ + "led2:C", + "gnd3:GND", + "black", + [ + "v201.6", + "h-29.2" + ] + ], + [ + "relay2:VCC", + "vcc4:VCC", + "red", + [ + "h-57.6", + "v-153.6", + "h345.6" + ] + ], + [ + "relay2:GND", + "gnd2:GND", + "black", + [ + "h-48", + "v210.8", + "h-240" + ] + ], + [ + "relay2:IN", + "esp:16", + "green", + [ + "h-67.2", + "v76.6" + ] + ], + [ + "led3:A", + "r3:2", + "green", + [ + "v0" + ] + ], + [ + "relay3:NO", + "r3:1", + "green", + [ + "h0" + ] + ], + [ + "led4:A", + "r4:2", + "green", + [ + "v0" + ] + ], + [ + "relay4:NO", + "r4:1", + "green", + [ + "h0" + ] + ], + [ + "led4:C", + "gnd3:GND", + "black", + [ + "v288", + "h-38.8" + ] + ], + [ + "relay4:VCC", + "vcc4:VCC", + "red", + [ + "h-67.2", + "v-67.2", + "h345.6" + ] + ], + [ + "relay4:GND", + "gnd2:GND", + "black", + [ + "h-57.6", + "v297.2", + "h-268.8", + "v0", + "h-96" + ] + ], + [ + "relay4:IN", + "esp:17", + "green", + [ + "h-86.4", + "v-0.2" + ] + ], + [ + "relay2:COM", + "vcc4:VCC", + "red", + [ + "h39.6", + "v-164.6", + "h134.4" + ] + ], + [ + "relay4:COM", + "vcc4:VCC", + "red", + [ + "h30", + "v-78.2", + "h134.4" + ] + ], + [ + "gas1:AOUT", + "esp:33", + "green", + [ + "h230.4", + "v-9.6" + ] + ], + [ + "rtc1:GND", + "esp:CMD", + "black", + [ + "h-192", + "v-96" + ] + ], + [ + "esp:5V", + "rtc1:5V", + "red", + [ + "h-9.45", + "v96" + ] + ], + [ + "rtc1:SCL", + "esp:22", + "green", + [ + "h-38.4", + "v-269" + ] + ], + [ + "rtc1:SDA", + "esp:21", + "green", + [ + "h-48", + "v-230.7" + ] + ] + ], + "dependencies": {} +} \ No newline at end of file diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..a704130 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,15 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32] +platform = espressif32 +framework = arduino +board = esp32dev +lib_deps = hwspeedy/DHT-Sensor, knolleary/PubSubClient, adafruit/RTClib diff --git a/src/esp32-ntp-clock.ino b/src/esp32-ntp-clock.ino new file mode 100644 index 0000000..1fbd9aa --- /dev/null +++ b/src/esp32-ntp-clock.ino @@ -0,0 +1,429 @@ +// ============================================================================ +// Sistema de monitoramento de cozinha com ESP32 +// Monitora temperatura, umidade e gás com detecção avançada de incêndio +// Envia dados via MQTT e controla coifa e ar-condicionado +// ============================================================================ + +// INCLUDES +#include // Sensor DHT22 +#include // MQTT +#include // RTC DS1307 +#include // WiFi + +// ============================================================================ +// DEFINES - Pinos GPIO +// ============================================================================ +#define DHTPIN 32 // Sensor DHT22 (temperatura/umidade) +#define DHTTYPE DHT22 // Tipo sensor DHT +#define MQ2PIN 33 // Sensor MQ2 (qualidade do ar/gás) +#define ALARME_SONORO 4 // Alarme sonoro +#define COIFA 17 // Coifa (exaustor) +#define AR_CONDICIONADO 16 // Ar-condicionado + +// ============================================================================ +// ENUMS +// ============================================================================ +enum statusCozinha { + NOMINAL, // Sem alerta + GAS, // Detecção de gás + TEMP_ALTA, // Temperatura acima do limite + UMIDADE_ALTA, // Umidade acima do limite + INCENDIO // Possível incêndio (padrão: ΔT > 5°C + Δumidade < -10% em 30s) +}; + +// ============================================================================ +// CONSTANTES - Limiares de alarme +// ============================================================================ +const int GAS_ON = 940; // Ativação gás (~1000ppm) +const int GAS_OFF = 916; // Desativação gás (~500ppm) +const float TEMP_ON_DEFAULT = 30.0; // Temperatura máxima padrão (°C) +const float TEMP_HISTERESE = 2.0; // Histerese temperatura +const float UMIDADE_ON_DEFAULT = 70.0; // Umidade máxima padrão (%) +const float UMIDADE_HISTERESE = 5.0; // Histerese umidade + +// Detecção de incêndio +const uint32_t JANELA_TEMPO_INCENDIO = 30; // Janela: 30 segundos +const float DELTA_TEMP_INCENDIO = 5.0; // Aumento mínimo: 5°C +const float DELTA_UMIDADE_INCENDIO = -10.0; // Queda mínima: -10% + +// ============================================================================ +// CONSTANTES - WiFi e MQTT +// ============================================================================ +const char* WIFI_SSID = "Wokwi-GUEST"; +const char* WIFI_PASSWORD = ""; +const char* MQTT_BROKER = "77.37.69.84"; +const int MQTT_PORT = 1883; +const char* MQTT_SUB_TOPICS[] = { "cozinha/max_tmp", "cozinha/max_umi" }; +const char* MQTT_PUB_TOPIC = "cozinha"; +const int MQTT_SUB_COUNT = sizeof(MQTT_SUB_TOPICS) / sizeof(MQTT_SUB_TOPICS[0]); + +// ============================================================================ +// VARIÁVEIS GLOBAIS - Objetos +// ============================================================================ +DHT dht(DHTPIN, DHTTYPE); +RTC_DS1307 RTC; +WiFiClient espClient; +PubSubClient mqtt(espClient); +DateTime now; + +// ============================================================================ +// VARIÁVEIS GLOBAIS - Estado do sistema +// ============================================================================ +int alarmStatus = NOMINAL; +float umidade = 0.0; +float temperatura = 0.0; +int iqAR = 0; + +// Variáveis de configuração (atualizáveis via MQTT) +float TEMP_ON = TEMP_ON_DEFAULT; +float TEMP_OFF = TEMP_ON - TEMP_HISTERESE; +float UMIDADE_ON = UMIDADE_ON_DEFAULT; +float UMIDADE_OFF = UMIDADE_ON - UMIDADE_HISTERESE; + +// Variáveis para detecção de incêndio +float temp_inicio = 0.0; +float umidade_inicio = 0.0; +uint32_t timestamp_inicio = 0; + +// Buffer MQTT +char msg[256]; +char MQTT_CLIENTID[32]; + +// ============================================================================ +// FUNÇÕES AUXILIARES - Callbacks MQTT +// ============================================================================ +void mqttCallback(char* topic, byte* payload, unsigned int length) +{ + Serial.print("[MQTT] Mensagem em ["); + Serial.print(topic); + Serial.println("]"); + + // Copia payload para buffer null-terminated + char buf[64]; + int n = (length < (int)sizeof(buf) - 1) ? length : (int)sizeof(buf) - 1; + memcpy(buf, payload, n); + buf[n] = '\0'; + + Serial.print("[MQTT] payload: "); + Serial.println(buf); + + // Processa tópicos + if (strcmp(topic, "cozinha/max_tmp") == 0) { + float v = atof(buf); + if (!isnan(v)) { + TEMP_ON = v; + TEMP_OFF = TEMP_ON - TEMP_HISTERESE; + Serial.print("[MQTT] TEMP_ON = "); + Serial.println(TEMP_ON); + } + } else if (strcmp(topic, "cozinha/max_umi") == 0) { + float v = atof(buf); + if (!isnan(v)) { + UMIDADE_ON = v; + UMIDADE_OFF = UMIDADE_ON - UMIDADE_HISTERESE; + Serial.print("[MQTT] UMIDADE_ON = "); + Serial.println(UMIDADE_ON); + } + } +} + +// ============================================================================ +// FUNÇÕES AUXILIARES - Conectividade +// ============================================================================ +// Conecta o ESP32 à rede WiFi +void connectWiFi() +{ + Serial.print("[WiFi] Conectando..."); + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + int attempts = 0; + while (WiFi.status() != WL_CONNECTED && attempts < 20) { + delay(500); + Serial.print("."); + attempts++; + } + Serial.println("\r\n[WiFi] Conectado!"); +} + +// Inscreve em tópicos MQTT para receber atualizações de limiares +void mqttSubscribe() +{ + Serial.println("[MQTT] Conectado!"); + for (int i = 0; i < MQTT_SUB_COUNT; ++i) { + if (mqtt.subscribe(MQTT_SUB_TOPICS[i])) { + Serial.print("[MQTT] Tópico: "); + Serial.println(MQTT_SUB_TOPICS[i]); + } + } +} + +// Conecta ao broker MQTT +void connectMQTT() +{ + mqtt.setServer(MQTT_BROKER, MQTT_PORT); + mqtt.setCallback(mqttCallback); + + while (!mqtt.connected()) { + Serial.println("[MQTT] Conectando..."); + if (mqtt.connect(MQTT_CLIENTID)) { + mqttSubscribe(); + break; + } else { + Serial.print("[MQTT] Falha rc="); + Serial.println(mqtt.state()); + delay(2000); + } + } +} + +// ============================================================================ +// FUNÇÕES AUXILIARES - Sensores +// ============================================================================ +// Lê valores de temperatura e umidade do sensor DHT22 +void read_DHT() +{ + umidade = dht.readHumidity(); + temperatura = dht.readTemperature(); + + if (isnan(umidade) || isnan(temperatura)) { + Serial.println("[DHT] Erro na leitura!"); + umidade = 0.0; + temperatura = 0.0; + } +} + +void read_MQ2() +{ + iqAR = analogRead(MQ2PIN); +} + +// ============================================================================ +// FUNÇÕES - Detecção de alarmes +// ============================================================================ +// Detecta padrão de possível incêndio: aumento de temperatura > 5°C + queda de umidade > 10% em 30 segundos +void detect_fire() +{ + // Inicializa janela de monitoramento na primeira chamada + if (temp_inicio == 0.0) { + temp_inicio = temperatura; + umidade_inicio = umidade; + timestamp_inicio = now.secondstime(); + return; + } + + // Calcula tempo decorrido + uint32_t tempo_decorrido = now.secondstime() - timestamp_inicio; + + // Verifica padrão de incêndio a cada 30 segundos + if (tempo_decorrido >= JANELA_TEMPO_INCENDIO) { + float delta_temp = temperatura - temp_inicio; + float delta_umidade = umidade - umidade_inicio; + + // Debug: exibe deltas + Serial.print("[INCENDIO] ΔT: "); + Serial.print(delta_temp); + Serial.print("°C | ΔUmidade: "); + Serial.print(delta_umidade); + Serial.println("%"); + + // Verifica condições críticas + if (delta_temp > DELTA_TEMP_INCENDIO && delta_umidade < DELTA_UMIDADE_INCENDIO) { + Serial.println("[ALERTA] INCÊNDIO DETECTADO!"); + alarmStatus = INCENDIO; + } + + // Reseta janela + temp_inicio = temperatura; + umidade_inicio = umidade; + timestamp_inicio = now.secondstime(); + } +} + +// Verifica qual alarme deve ser ativado baseado nos limites +void check_alarm() +{ + // Atualiza RTC + now = RTC.now(); + + // Detecção de incêndio (máxima prioridade) + detect_fire(); + if (alarmStatus == INCENDIO) { + return; + } + + // Verifica gás + if (alarmStatus == GAS) { + if (iqAR <= GAS_OFF) { + alarmStatus = NOMINAL; + } + } else if (iqAR > GAS_ON) { + alarmStatus = GAS; + return; + } + + // Verifica umidade + if (alarmStatus == UMIDADE_ALTA) { + if (umidade <= UMIDADE_OFF) { + alarmStatus = NOMINAL; + } + } else if (umidade > UMIDADE_ON) { + alarmStatus = UMIDADE_ALTA; + return; + } + + // Verifica temperatura + if (alarmStatus == TEMP_ALTA) { + if (temperatura <= TEMP_OFF) { + alarmStatus = NOMINAL; + } + } else if (temperatura > TEMP_ON) { + alarmStatus = TEMP_ALTA; + return; + } + + // Nenhum alarme ativo + if (alarmStatus != GAS && alarmStatus != UMIDADE_ALTA + && alarmStatus != TEMP_ALTA) { + alarmStatus = NOMINAL; + } +} + +// ============================================================================ +// FUNÇÕES - Leitura e publicação +// ============================================================================ +// Realiza leitura de todos os sensores e publica dados via MQTT +void leitura_sensores() +{ + read_DHT(); + read_MQ2(); + + // Formata e publica via MQTT + snprintf(msg, sizeof(msg), + "{\"tmp\": %.2f, \"umi\": %.2f, \"gas\": %d, \"alarme\": %d}", + temperatura, umidade, iqAR, alarmStatus); + Serial.print("[MQTT] Publicando: "); + Serial.println(msg); + mqtt.publish(MQTT_PUB_TOPIC, msg); + + // Verifica alarmes + check_alarm(); +} + +// Processa ativação de periféricos baseado no alarme +void processa_alarme() +{ + // Desativa todos antes de processar + digitalWrite(ALARME_SONORO, LOW); + digitalWrite(COIFA, LOW); + digitalWrite(AR_CONDICIONADO, LOW); + + if (alarmStatus == NOMINAL) { + return; + } + + // Ativa periféricos conforme alarme + switch (alarmStatus) { + case INCENDIO: + digitalWrite(ALARME_SONORO, HIGH); + digitalWrite(COIFA, HIGH); + digitalWrite(AR_CONDICIONADO, HIGH); + Serial.println("[ALARME] INCÊNDIO!"); + break; + case GAS: + digitalWrite(ALARME_SONORO, HIGH); + digitalWrite(COIFA, HIGH); + Serial.println("[ALARME] GÁS DETECTADO!"); + break; + case UMIDADE_ALTA: + digitalWrite(COIFA, HIGH); + Serial.println("[ALARME] UMIDADE ALTA!"); + break; + case TEMP_ALTA: + digitalWrite(AR_CONDICIONADO, HIGH); + Serial.println("[ALARME] TEMPERATURA ALTA!"); + break; + default: + break; + } +} + +// ============================================================================ +// FUNÇÕES - Inicialização +// ============================================================================ +void rtc_setup() +{ + if (!RTC.begin()) { + Serial.println("[RTC] Erro: não encontrado!"); + while (1) + delay(1000); + } + Serial.println("[RTC] Inicializado"); +} + +// Inicializa o ESP32 e configura os periféricos +void setup() +{ + Serial.begin(115200); + delay(100); + + Serial.println("\n[SETUP] Iniciando sistema..."); + + // Inicializa DHT + dht.begin(); + Serial.println("[DHT] Inicializado"); + + // Gera ID único MQTT + snprintf(MQTT_CLIENTID, sizeof(MQTT_CLIENTID), "esp32_%08X", + (uint32_t)(ESP.getEfuseMac() & 0xFFFFFFFF)); + + // Configura ADC + analogReadResolution(10); + + // Configura pinos + pinMode(ALARME_SONORO, OUTPUT); + pinMode(COIFA, OUTPUT); + pinMode(AR_CONDICIONADO, OUTPUT); + pinMode(MQ2PIN, INPUT); + pinMode(DHTPIN, INPUT); + + // Desativa todos os atuadores + digitalWrite(ALARME_SONORO, LOW); + digitalWrite(COIFA, LOW); + digitalWrite(AR_CONDICIONADO, LOW); + + // Conecta + connectWiFi(); + connectMQTT(); + rtc_setup(); + + // Primeira leitura + now = RTC.now(); + leitura_sensores(); + + Serial.println("[SETUP] Pronto!\n"); +} + +// ============================================================================ +// LOOP PRINCIPAL +// ============================================================================ +// Loop principal - executa continuamente +void loop() +{ + // Verifica MQTT + if (!mqtt.connected()) { + connectMQTT(); + } + mqtt.loop(); + + // Lê sensores + leitura_sensores(); + + // Processa alarme + processa_alarme(); + + // Aguarda 2 segundos + unsigned long start = millis(); + while (millis() - start < 2000UL) { + mqtt.loop(); + delay(10); + } +} \ No newline at end of file diff --git a/wokwi.toml b/wokwi.toml new file mode 100644 index 0000000..0115800 --- /dev/null +++ b/wokwi.toml @@ -0,0 +1,4 @@ +[wokwi] +version = 1 +elf = ".pio/build/esp32/firmware.elf" +firmware = ".pio/build/esp32/firmware.bin"