Atividade 2 versao 1.0
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.pio
|
||||
.vscode/launch.json
|
||||
.vscode/c_cpp_properties.json
|
||||
Relatorio/relatorio_files/*
|
||||
11
.vscode/extensions.json
vendored
Normal file
11
.vscode/extensions.json
vendored
Normal file
@@ -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"
|
||||
]
|
||||
}
|
||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"C_Cpp.clang_format_fallbackStyle": "WebKit",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -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.
|
||||
29
README.md
Normal file
29
README.md
Normal file
@@ -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).
|
||||
BIN
Relatorio/nodered.png
Normal file
BIN
Relatorio/nodered.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
539
Relatorio/relatorio.qmd
Normal file
539
Relatorio/relatorio.qmd
Normal file
@@ -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["<b>DHT22</b><br/>Temperatura &<br/>Umidade<br/>GPIO 32"]
|
||||
MQ2["<b>MQ2</b><br/>Qualidade do Ar<br/>(Gás)<br/>GPIO 33 ADC"]
|
||||
RTC["<b>RTC DS1307</b><br/>Timer para verificação de incêndio<br/>I2C"]
|
||||
end
|
||||
|
||||
subgraph "Camada de Processamento"
|
||||
ESP32["<b>ESP32 DevKit V4</b><br/>Dual-core 240MHz<br/>WiFi + BLE"]
|
||||
LOGIC["Lógica de<br/>Detecção de<br/>Alarmes"]
|
||||
end
|
||||
|
||||
subgraph "Camada de Atuadores"
|
||||
ALARM["<b>Alarme Sonoro</b><br/>Sirene/>GPIO 4"]
|
||||
COIFA["<b>Coifa/Exaustor</b><br/>Motor 220V<br/>GPIO 17"]
|
||||
AC["<b>A/C</b><br/>Unidade comercial<br/>GPIO 16"]
|
||||
end
|
||||
|
||||
subgraph "Rede MQTT"
|
||||
WiFi["<b>WiFi</b><br/>Wokwi-GUEST<br/>2.4GHz"]
|
||||
MQTT["<b>Broker MQTT</b><br/>77.37.69.84:1883<br/>Mosquitto"]
|
||||
end
|
||||
|
||||
subgraph "Cloud - Ubidots"
|
||||
UBIDOTS["<b>Plataforma Ubidots</b><br/>Dashboard<br/>Histórico de Dados<br/>Alertas"]
|
||||
NODERED["<b>NodeRed</b><br/>Dashboard Fallback<br/>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<br/>(Sensor)
|
||||
participant MQ as MQ2<br/>(Sensor)
|
||||
participant ESP as ESP32<br/>(Processador)
|
||||
participant WiFi as WiFi<br/>
|
||||
participant Broker as Broker MQTT<br/>77.37.69.84
|
||||
participant Ubidots as Ubidots<br/>(Cloud)
|
||||
participant Dashboard as Dashboard<br/>(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<br/>Loop"] --> B{"MQTT<br/>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<br/>Alarmes"]
|
||||
F --> H
|
||||
G --> H
|
||||
H --> I["Publica"]
|
||||
```
|
||||
|
||||
### Parte 2: Decisão de Alarmes
|
||||
|
||||
```{mermaid}
|
||||
%%| fig-width: 6.5
|
||||
flowchart LR
|
||||
H["Detecta<br/>Alarmes"] --> G{"Incêndio?"}
|
||||
G -->|Sim| S4["Estado = 4"]
|
||||
G -->|Não| G2{"Gás<br>>940?"}
|
||||
G2 -->|Sim| S1["Estado = 1"]
|
||||
G2 -->|Não| T{"Temp<br/>Alta?"}
|
||||
T -->|Sim| S2["Estado = 2"]
|
||||
T -->|Não| U{"Umidade<br/>Alta?"}
|
||||
U -->|Sim| S3["Estado = 3"]
|
||||
U -->|Não| S0["Estado = 0"]
|
||||
S4 --> M["Publica<br/>MQTT"]
|
||||
S1 --> M
|
||||
S2 --> M
|
||||
S3 --> M
|
||||
S0 --> M
|
||||
M --> A["Ativa<br/>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
|
||||
|
||||

|
||||
|
||||
**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
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
BIN
Relatorio/ubidots.png
Normal file
BIN
Relatorio/ubidots.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
551
diagram.json
Normal file
551
diagram.json
Normal file
@@ -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": {}
|
||||
}
|
||||
15
platformio.ini
Normal file
15
platformio.ini
Normal file
@@ -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
|
||||
429
src/esp32-ntp-clock.ino
Normal file
429
src/esp32-ntp-clock.ino
Normal file
@@ -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 <DHT.h> // Sensor DHT22
|
||||
#include <PubSubClient.h> // MQTT
|
||||
#include <RTClib.h> // RTC DS1307
|
||||
#include <WiFi.h> // 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);
|
||||
}
|
||||
}
|
||||
4
wokwi.toml
Normal file
4
wokwi.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[wokwi]
|
||||
version = 1
|
||||
elf = ".pio/build/esp32/firmware.elf"
|
||||
firmware = ".pio/build/esp32/firmware.bin"
|
||||
Reference in New Issue
Block a user