Versao 1.0
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.pio
|
||||
.vscode/launch.json
|
||||
.vscode/c_cpp_properties.json
|
||||
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.
|
||||
17
README.md
Normal file
17
README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# ESP32 NTP Clock
|
||||
|
||||
A simple clock that displays the time and date on an LCD1602 display. The time is synced via NTP.
|
||||
|
||||
Use [Wokwi](https://marketplace.visualstudio.com/items?itemName=wokwi.wokwi-vscode) to simulate this project.
|
||||
|
||||
## Building
|
||||
|
||||
This is a [PlatformIO](https://platformio.org) project. To build it, [install PlatformIO](https://docs.platformio.org/en/latest/core/installation/index.html), and then run the following command:
|
||||
|
||||
```
|
||||
pio run
|
||||
```
|
||||
|
||||
## Simulate the project
|
||||
|
||||
To simulate this project, install [Wokwi for VS Code](https://marketplace.visualstudio.com/items?itemName=wokwi.wokwi-vscode). Open the project directory in Visual Studio Code, press **F1** and select "Wokwi: Start Simulator".
|
||||
139
diagram.json
Normal file
139
diagram.json
Normal file
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"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": "21" }
|
||||
},
|
||||
{ "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" }
|
||||
}
|
||||
],
|
||||
"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" ] ]
|
||||
],
|
||||
"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
|
||||
239
src/esp32-ntp-clock.ino
Normal file
239
src/esp32-ntp-clock.ino
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <DHT.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#define DHTPIN 32
|
||||
#define DHTTYPE DHT22
|
||||
#define MQ2PIN 33
|
||||
#define ALARME_SONORO 4
|
||||
#define COIFA 17
|
||||
#define AR_CONDICIONADO 16
|
||||
|
||||
DHT dht(DHTPIN, DHTTYPE);
|
||||
|
||||
enum statusCozinha {
|
||||
NOMINAL,
|
||||
GAS,
|
||||
TEMP_ALTA,
|
||||
UMIDADE_ALTA
|
||||
};
|
||||
|
||||
int alarmStatus = NOMINAL;
|
||||
float umidade = 0;
|
||||
float temperatura = 0;
|
||||
int iqAR = 0;
|
||||
|
||||
const int GAS_ON = 940; // 1000ppm
|
||||
const int GAS_OFF = 916; // 500ppm
|
||||
float UMIDADE_ON = 70.0;
|
||||
float UMIDADE_OFF = UMIDADE_ON - 5;
|
||||
float TEMP_ON = 30.0;
|
||||
float TEMP_OFF = TEMP_ON - 2;
|
||||
|
||||
const char* WIFI_SSID = "Wokwi-GUEST";
|
||||
const char* WIFI_PASSWORD = "";
|
||||
const char* MQTT_BROKER = "77.37.69.84";
|
||||
const int MQTT_PORT = 1883;
|
||||
char MQTT_CLIENTID[32] = { 0 };
|
||||
const char* MQTT_SUB_TOPICS[] = { "cozinha/max_tmp", "cozinha/max_umi" };
|
||||
const char* MQTT_PUB_TOPIC = "cozinha";
|
||||
char msg[255];
|
||||
|
||||
const int MQTT_SUB_COUNT = sizeof(MQTT_SUB_TOPICS) / sizeof(MQTT_SUB_TOPICS[0]);
|
||||
|
||||
void mqttCallback(char* topic, byte* payload, unsigned int length)
|
||||
{
|
||||
Serial.print("[MQTT] Mensagem em [");
|
||||
Serial.print(topic);
|
||||
Serial.println("]");
|
||||
|
||||
char buf[64];
|
||||
int n = (length < (sizeof(buf) - 1)) ? length : (sizeof(buf) - 1);
|
||||
memcpy(buf, payload, n);
|
||||
buf[n] = '\0';
|
||||
|
||||
// show payload for debugging
|
||||
Serial.print("[MQTT] payload: ");
|
||||
Serial.println(buf);
|
||||
|
||||
if (strcmp(topic, "cozinha/max_tmp") == 0) {
|
||||
float v = atof(buf);
|
||||
if (!isnan(v)) {
|
||||
TEMP_ON = v;
|
||||
TEMP_OFF = TEMP_ON - 2;
|
||||
Serial.print("[MQTT] TEMP_ON definido para ");
|
||||
Serial.println(TEMP_ON);
|
||||
} else {
|
||||
Serial.println("[MQTT] Temperatura inválida");
|
||||
}
|
||||
} else if (strcmp(topic, "cozinha/max_umi") == 0) {
|
||||
float v = atof(buf);
|
||||
if (!isnan(v)) {
|
||||
UMIDADE_ON = v;
|
||||
UMIDADE_OFF = UMIDADE_ON - 5;
|
||||
Serial.print("[MQTT] UMIDADE_ON definido para ");
|
||||
Serial.println(UMIDADE_ON);
|
||||
} else {
|
||||
Serial.println("[MQTT] Umidade inválida");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WiFiClient espClient;
|
||||
PubSubClient mqtt(espClient);
|
||||
|
||||
void connectWiFi()
|
||||
{
|
||||
Serial.print("[WiFi] Conectando...");
|
||||
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
Serial.print(".");
|
||||
}
|
||||
Serial.println("\r\n[WiFi] Conectado!");
|
||||
}
|
||||
|
||||
void connectMQTT()
|
||||
{
|
||||
mqtt.setServer(MQTT_BROKER, MQTT_PORT);
|
||||
mqtt.setCallback(mqttCallback);
|
||||
while (!mqtt.connected()) {
|
||||
Serial.println("[MQTT] Conectando...");
|
||||
if (mqtt.connect(MQTT_CLIENTID)) {
|
||||
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 assinado: ");
|
||||
Serial.println(MQTT_SUB_TOPICS[i]);
|
||||
} else {
|
||||
Serial.print("[MQTT] Assinatura falhou: ");
|
||||
Serial.println(MQTT_SUB_TOPICS[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
Serial.print(" ERRO! (rc=");
|
||||
Serial.print(mqtt.state());
|
||||
Serial.println("). Tentando novamente em 2s...");
|
||||
delay(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void read_DHT()
|
||||
{
|
||||
umidade = dht.readHumidity();
|
||||
temperatura = dht.readTemperature();
|
||||
if (isnan(umidade) || isnan(temperatura)) {
|
||||
Serial.println("Erro na leitura");
|
||||
}
|
||||
}
|
||||
|
||||
void check_alarm()
|
||||
{
|
||||
if (alarmStatus == GAS) {
|
||||
if (iqAR > GAS_OFF)
|
||||
return;
|
||||
} else {
|
||||
if (iqAR > GAS_ON) {
|
||||
alarmStatus = GAS;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (alarmStatus == UMIDADE_ALTA) {
|
||||
if (umidade > UMIDADE_OFF)
|
||||
return;
|
||||
} else {
|
||||
if (umidade > UMIDADE_ON) {
|
||||
alarmStatus = UMIDADE_ALTA;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (alarmStatus == TEMP_ALTA) {
|
||||
if (temperatura > TEMP_OFF)
|
||||
return;
|
||||
} else {
|
||||
if (temperatura > TEMP_ON) {
|
||||
alarmStatus = TEMP_ALTA;
|
||||
return;
|
||||
}
|
||||
}
|
||||
alarmStatus = NOMINAL;
|
||||
}
|
||||
|
||||
void refresh_sensors()
|
||||
{
|
||||
read_DHT();
|
||||
iqAR = analogRead(MQ2PIN);
|
||||
|
||||
sprintf(msg, "{\"tmp\": %3.2f, \"umi\": %3.2f, \"gas\": %d}", temperatura, umidade, iqAR);
|
||||
mqtt.publish(MQTT_PUB_TOPIC, msg);
|
||||
|
||||
check_alarm();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
dht.begin();
|
||||
Serial.println("DHT iniciado");
|
||||
|
||||
snprintf(MQTT_CLIENTID, sizeof(MQTT_CLIENTID), "esp32_%08X", (uint32_t)(ESP.getEfuseMac() & 0xFFFFFFFF));
|
||||
|
||||
analogReadResolution(10);
|
||||
|
||||
pinMode(ALARME_SONORO, OUTPUT);
|
||||
pinMode(COIFA, OUTPUT);
|
||||
pinMode(AR_CONDICIONADO, OUTPUT);
|
||||
pinMode(MQ2PIN, INPUT);
|
||||
pinMode(DHTPIN, INPUT);
|
||||
|
||||
digitalWrite(ALARME_SONORO, LOW);
|
||||
digitalWrite(COIFA, LOW);
|
||||
digitalWrite(AR_CONDICIONADO, LOW);
|
||||
|
||||
connectWiFi();
|
||||
connectMQTT();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!mqtt.connected()) {
|
||||
connectMQTT();
|
||||
}
|
||||
mqtt.loop();
|
||||
|
||||
digitalWrite(ALARME_SONORO, LOW);
|
||||
digitalWrite(COIFA, LOW);
|
||||
digitalWrite(AR_CONDICIONADO, LOW);
|
||||
refresh_sensors();
|
||||
int alarmCounter = 0;
|
||||
|
||||
unsigned long start = millis();
|
||||
while (millis() - start < 2000UL) {
|
||||
mqtt.loop();
|
||||
delay(10);
|
||||
}
|
||||
while (alarmStatus != NOMINAL) {
|
||||
switch (alarmStatus) {
|
||||
case GAS:
|
||||
digitalWrite(ALARME_SONORO, HIGH);
|
||||
case UMIDADE_ALTA:
|
||||
digitalWrite(COIFA, HIGH);
|
||||
break;
|
||||
case TEMP_ALTA:
|
||||
digitalWrite(AR_CONDICIONADO, HIGH);
|
||||
break;
|
||||
default:
|
||||
Serial.println("STATUS DESCONHECIDO");
|
||||
}
|
||||
alarmCounter++;
|
||||
delay(500);
|
||||
if (alarmCounter > 5) {
|
||||
refresh_sensors();
|
||||
alarmCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
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