first commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
10
.vscode/extensions.json
vendored
Normal file
10
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
19
chips/heartrate.chip.json
Normal file
19
chips/heartrate.chip.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "heartrate",
|
||||
"author": "Amaro Lopes",
|
||||
"pins": [
|
||||
"VCC",
|
||||
"GND",
|
||||
"BTN",
|
||||
"OUT"
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"id": "pulseValue",
|
||||
"label": "Heart Rate",
|
||||
"type": "slider",
|
||||
"min": 40,
|
||||
"max": 200
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
chips/heartrate.chip.wasm
Executable file
BIN
chips/heartrate.chip.wasm
Executable file
Binary file not shown.
188
diagram.json
Normal file
188
diagram.json
Normal file
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"version": 1,
|
||||
"author": "Amaro Lopes",
|
||||
"editor": "wokwi",
|
||||
"parts": [
|
||||
{
|
||||
"type": "board-esp32-devkit-c-v4",
|
||||
"id": "esp",
|
||||
"top": 0,
|
||||
"left": 0,
|
||||
"attrs": {}
|
||||
},
|
||||
{
|
||||
"type": "chip-heartrate",
|
||||
"id": "chip1",
|
||||
"top": -114.18,
|
||||
"left": -148.8,
|
||||
"attrs": {}
|
||||
},
|
||||
{
|
||||
"type": "wokwi-resistor",
|
||||
"id": "r1",
|
||||
"top": -33.6,
|
||||
"left": -67.75,
|
||||
"rotate": 90,
|
||||
"attrs": {
|
||||
"value": "1000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wokwi-slide-switch",
|
||||
"id": "sw1",
|
||||
"top": -130,
|
||||
"left": 127.9,
|
||||
"attrs": {}
|
||||
},
|
||||
{
|
||||
"type": "wokwi-mpu6050",
|
||||
"id": "imu1",
|
||||
"top": 99.82,
|
||||
"left": -199.28,
|
||||
"attrs": {}
|
||||
},
|
||||
{
|
||||
"type": "wokwi-led",
|
||||
"id": "led1",
|
||||
"top": -32.4,
|
||||
"left": 167,
|
||||
"attrs": {
|
||||
"color": "red"
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
[
|
||||
"esp:TX",
|
||||
"$serialMonitor:RX",
|
||||
"",
|
||||
[]
|
||||
],
|
||||
[
|
||||
"esp:RX",
|
||||
"$serialMonitor:TX",
|
||||
"",
|
||||
[]
|
||||
],
|
||||
[
|
||||
"esp:3V3",
|
||||
"chip1:VCC",
|
||||
"green",
|
||||
[
|
||||
"h-187.01",
|
||||
"v-134.4"
|
||||
]
|
||||
],
|
||||
[
|
||||
"chip1:GND",
|
||||
"esp:GND.2",
|
||||
"black",
|
||||
[
|
||||
"v28.8",
|
||||
"h244.76"
|
||||
]
|
||||
],
|
||||
[
|
||||
"r1:1",
|
||||
"chip1:BTN",
|
||||
"green",
|
||||
[
|
||||
"h0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"r1:2",
|
||||
"esp:3V3",
|
||||
"green",
|
||||
[
|
||||
"h0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"esp:35",
|
||||
"chip1:OUT",
|
||||
"green",
|
||||
[
|
||||
"h-23.81",
|
||||
"v-182.4"
|
||||
]
|
||||
],
|
||||
[
|
||||
"sw1:1",
|
||||
"chip1:BTN",
|
||||
"green",
|
||||
[
|
||||
"v0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"sw1:2",
|
||||
"sw1:3",
|
||||
"black",
|
||||
[
|
||||
"v0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"sw1:3",
|
||||
"esp:GND.2",
|
||||
"black",
|
||||
[
|
||||
"v0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"imu1:VCC",
|
||||
"esp:3V3",
|
||||
"red",
|
||||
[
|
||||
"v0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"imu1:GND",
|
||||
"esp:GND.2",
|
||||
"black",
|
||||
[
|
||||
"v-134.4",
|
||||
"h28.88"
|
||||
]
|
||||
],
|
||||
[
|
||||
"imu1:SCL",
|
||||
"esp:22",
|
||||
"green",
|
||||
[
|
||||
"v9.6",
|
||||
"h268.88",
|
||||
"v-67.2"
|
||||
]
|
||||
],
|
||||
[
|
||||
"imu1:SDA",
|
||||
"esp:21",
|
||||
"green",
|
||||
[
|
||||
"v0"
|
||||
]
|
||||
],
|
||||
[
|
||||
"esp:GND.2",
|
||||
"led1:C",
|
||||
"black",
|
||||
[
|
||||
"v-19.2",
|
||||
"h-4.76"
|
||||
]
|
||||
],
|
||||
[
|
||||
"esp:17",
|
||||
"led1:A",
|
||||
"green",
|
||||
[
|
||||
"h0"
|
||||
]
|
||||
]
|
||||
],
|
||||
"dependencies": {}
|
||||
}
|
||||
18
platformio.ini
Normal file
18
platformio.ini
Normal file
@@ -0,0 +1,18 @@
|
||||
; 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/Adafruit MPU6050@^2.2.8
|
||||
402
src/main.ino
Normal file
402
src/main.ino
Normal file
@@ -0,0 +1,402 @@
|
||||
// ============================================================================
|
||||
// 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 <Adafruit_MPU6050.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <PubSubClient.h> // MQTT
|
||||
#include <WiFi.h> // WiFi
|
||||
#include <Wire.h>
|
||||
|
||||
// ============================================================================
|
||||
// DEFINES - Pinos GPIO
|
||||
// ============================================================================
|
||||
#define PULSE_PIN 35 // Pin for the pulse sensor
|
||||
#define LED_PIN 17 // Pin for the LED
|
||||
|
||||
// ============================================================================
|
||||
// DEFINES - Configurações estáticas
|
||||
// ============================================================================
|
||||
#define SAMPLE_PERIOD_MS 10 // 100 Hz
|
||||
#define FILTER_ALPHA 0.9
|
||||
|
||||
#define TH_START 1.15
|
||||
#define TH_END 1.05
|
||||
|
||||
#define MIN_PEAK_AMPLITUDE 1.5
|
||||
|
||||
#define MIN_REP_TIME 800
|
||||
#define MAX_REP_TIME 5000
|
||||
// ============================================================================
|
||||
// ENUMS
|
||||
// ============================================================================
|
||||
enum EstadoRepeticao {
|
||||
OCIOSO,
|
||||
DESCANSO,
|
||||
SUBINDO,
|
||||
DESCENDO
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 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[] = {
|
||||
"academia/reps",
|
||||
"academia/sets",
|
||||
"academia/t_descanso"
|
||||
};
|
||||
const char* MQTT_PUB_TOPIC = "academia";
|
||||
const int MQTT_SUB_COUNT = sizeof(MQTT_SUB_TOPICS) / sizeof(MQTT_SUB_TOPICS[0]);
|
||||
|
||||
// ============================================================================
|
||||
// VARIÁVEIS GLOBAIS - Objetos
|
||||
// ============================================================================
|
||||
WiFiClient espClient;
|
||||
PubSubClient mqtt(espClient);
|
||||
Adafruit_MPU6050 mpu;
|
||||
sensors_event_t event;
|
||||
|
||||
// ============================================================================
|
||||
// VARIÁVEIS GLOBAIS - Estado do sistema
|
||||
// ============================================================================
|
||||
|
||||
EstadoRepeticao estado = OCIOSO;
|
||||
|
||||
unsigned long ultimaAmostra = 0;
|
||||
|
||||
unsigned long t_inicio = 0;
|
||||
unsigned long t_pico = 0;
|
||||
unsigned long t_fim = 0;
|
||||
unsigned long t_descanso = 30;
|
||||
|
||||
float aceleracaoFiltrada = 1.0;
|
||||
float aceleracaoAnterior = 1.0;
|
||||
float aceleracaoPico = 0;
|
||||
|
||||
int repeticoes = 0;
|
||||
int max_reps = 0;
|
||||
int set = 0;
|
||||
int sets = 0;
|
||||
|
||||
// Frequência cardíaca (atual e agregados por repetição)
|
||||
int frequenciaCardiacaAtual = 0;
|
||||
unsigned long somaFrequenciaCardiaca = 0;
|
||||
unsigned int contagemFrequenciaCardiaca = 0;
|
||||
|
||||
// MQTT reconnect control
|
||||
unsigned long ultimoMqttAttempt = 0;
|
||||
const unsigned long MQTT_RECONNECT_INTERVAL_MS = 5000;
|
||||
|
||||
// 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, "academia/reps") == 0) {
|
||||
int v = atoi(buf);
|
||||
if (!isnan(v)) {
|
||||
Serial.print("[MQTT] reps = ");
|
||||
Serial.println(v);
|
||||
max_reps = v;
|
||||
}
|
||||
} else if (strcmp(topic, "academia/sets") == 0) {
|
||||
int v = atoi(buf);
|
||||
if (!isnan(v)) {
|
||||
Serial.print("[MQTT] sets = ");
|
||||
Serial.println(v);
|
||||
sets = v;
|
||||
}
|
||||
} else if (strcmp(topic, "academia/t_descanso") == 0) {
|
||||
int v = atoi(buf);
|
||||
if (!isnan(v)) {
|
||||
Serial.print("[MQTT] t_descanso = ");
|
||||
Serial.println(v);
|
||||
t_descanso = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 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 aceleração do sensor MPU
|
||||
void amostraMPU()
|
||||
{
|
||||
sensors_event_t a, g, temp;
|
||||
mpu.getEvent(&a, &g, &temp);
|
||||
|
||||
float magnitudeAceleracao = sqrt(
|
||||
a.acceleration.x * a.acceleration.x
|
||||
+ a.acceleration.y * a.acceleration.y
|
||||
+ a.acceleration.z * a.acceleration.z);
|
||||
|
||||
float aceleracaoCorrigida = magnitudeAceleracao - 9.81;
|
||||
|
||||
aceleracaoFiltrada = FILTER_ALPHA * aceleracaoFiltrada + (1.0 - FILTER_ALPHA) * aceleracaoCorrigida;
|
||||
|
||||
detectarRepeticao(aceleracaoFiltrada);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES - Detecção de alarmes
|
||||
// ============================================================================
|
||||
// Verifica qual alarme deve ser ativado baseado nos limites
|
||||
void detectarRepeticao(float sinal)
|
||||
{
|
||||
unsigned long agora = millis();
|
||||
|
||||
switch (estado) {
|
||||
|
||||
case OCIOSO:
|
||||
if (sinal > TH_START) {
|
||||
t_inicio = agora;
|
||||
aceleracaoPico = sinal;
|
||||
estado = SUBINDO;
|
||||
// Inicia acumulação de frequência cardíaca para esta repetição
|
||||
somaFrequenciaCardiaca = 0;
|
||||
contagemFrequenciaCardiaca = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUBINDO:
|
||||
if (sinal > aceleracaoPico)
|
||||
aceleracaoPico = sinal;
|
||||
|
||||
if (sinal < aceleracaoAnterior) {
|
||||
t_pico = agora;
|
||||
estado = DESCENDO;
|
||||
}
|
||||
break;
|
||||
|
||||
case DESCENDO:
|
||||
if (sinal < TH_END) {
|
||||
t_fim = agora;
|
||||
|
||||
analisarRepeticao();
|
||||
verificarSerie();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Se estamos no meio de uma repetição, acumula a frequência cardíaca atual
|
||||
if (estado != OCIOSO) {
|
||||
somaFrequenciaCardiaca += (unsigned long)frequenciaCardiacaAtual;
|
||||
contagemFrequenciaCardiaca++;
|
||||
}
|
||||
|
||||
aceleracaoAnterior = sinal;
|
||||
}
|
||||
|
||||
void analisarRepeticao()
|
||||
{
|
||||
unsigned long tempoTotal = t_fim - t_inicio;
|
||||
unsigned long tempoSubida = t_pico - t_inicio;
|
||||
unsigned long tempoDescida = t_fim - t_pico;
|
||||
|
||||
bool ruim = false;
|
||||
|
||||
Serial.print("Total: ");
|
||||
Serial.print(tempoTotal);
|
||||
Serial.print(" ms");
|
||||
|
||||
if (aceleracaoPico < MIN_PEAK_AMPLITUDE) {
|
||||
Serial.print(" | Repetição parcial");
|
||||
ruim = true;
|
||||
}
|
||||
|
||||
if (tempoTotal < MIN_REP_TIME) {
|
||||
Serial.print(" | Muito rápido");
|
||||
ruim = true;
|
||||
}
|
||||
|
||||
if (tempoTotal > MAX_REP_TIME) {
|
||||
Serial.print(" | Muito lento");
|
||||
ruim = true;
|
||||
}
|
||||
|
||||
if (tempoDescida < tempoSubida * 0.6) {
|
||||
Serial.print(" | Deixando cair o peso");
|
||||
ruim = true;
|
||||
}
|
||||
|
||||
if (!ruim) {
|
||||
Serial.print(" | Boa repetição");
|
||||
repeticoes++;
|
||||
Serial.print(" | Repetição ");
|
||||
Serial.print(repeticoes);
|
||||
}
|
||||
// Calcula e mostra frequência cardíaca média durante a repetição
|
||||
unsigned int fcMedia = 0;
|
||||
if (contagemFrequenciaCardiaca > 0) {
|
||||
fcMedia = (unsigned int)(somaFrequenciaCardiaca / contagemFrequenciaCardiaca);
|
||||
Serial.print(" | FC média: ");
|
||||
Serial.print(fcMedia);
|
||||
Serial.print(" bpm");
|
||||
}
|
||||
|
||||
// Zera agregados após uso
|
||||
somaFrequenciaCardiaca = 0;
|
||||
contagemFrequenciaCardiaca = 0;
|
||||
|
||||
snprintf(msg, sizeof(msg),
|
||||
"{\"fcm\": %d, \"reptime\": %d, \"timeup\": %d, \"timedown\": %d}",
|
||||
fcMedia, tempoTotal, tempoSubida, tempoDescida);
|
||||
|
||||
mqtt.publish(MQTT_PUB_TOPIC, msg);
|
||||
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void verificarSerie()
|
||||
{
|
||||
if (repeticoes >= max_reps && max_reps > 0) {
|
||||
Serial.println("[SÉRIE] Série finalizada, iniciando descanso...");
|
||||
repeticoes = 0;
|
||||
estado = DESCANSO;
|
||||
set++;
|
||||
digitalWrite(LED_PIN, HIGH);
|
||||
if (set >= sets && sets > 0) {
|
||||
Serial.println("[TREINO] Treino finalizado, parabéns!");
|
||||
set = 0;
|
||||
}
|
||||
} else {
|
||||
estado = OCIOSO;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FUNÇÕES - Inicialização
|
||||
// ============================================================================
|
||||
// Inicializa o ESP32 e configura os periféricos
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
delay(100);
|
||||
|
||||
Serial.println("\n[SETUP] Iniciando sistema...");
|
||||
|
||||
// Gera ID único MQTT
|
||||
snprintf(MQTT_CLIENTID, sizeof(MQTT_CLIENTID), "esp32_%08X",
|
||||
(uint32_t)(ESP.getEfuseMac() & 0xFFFFFFFF));
|
||||
|
||||
// Conecta
|
||||
connectWiFi();
|
||||
connectMQTT();
|
||||
|
||||
while (!mpu.begin()) {
|
||||
Serial.println("MPU6050 not connected!");
|
||||
delay(1000);
|
||||
}
|
||||
mpu.setAccelerometerRange(MPU6050_RANGE_4_G);
|
||||
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
|
||||
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
|
||||
Serial.println("MPU6050 ready!");
|
||||
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
Serial.println("[SETUP] Pronto!\n");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LOOP PRINCIPAL
|
||||
// ============================================================================
|
||||
// Loop principal - executa continuamente
|
||||
void loop()
|
||||
{
|
||||
if (!mqtt.connected()) {
|
||||
connectMQTT();
|
||||
}
|
||||
mqtt.loop();
|
||||
|
||||
if (millis() - ultimaAmostra >= SAMPLE_PERIOD_MS && estado != DESCANSO) {
|
||||
// Verifica MQTT
|
||||
|
||||
int16_t valorPulso = analogRead(PULSE_PIN);
|
||||
|
||||
// Converter valorPulso para tensão
|
||||
float tensao = valorPulso * (5.0 / 4095.0);
|
||||
|
||||
// Atualiza frequência cardíaca atual (valor usado nas acumulações)
|
||||
frequenciaCardiacaAtual = (int)((tensao / 3.3) * 675);
|
||||
|
||||
ultimaAmostra += SAMPLE_PERIOD_MS;
|
||||
amostraMPU();
|
||||
} else if (millis() - t_fim >= t_descanso * 100 && estado == DESCANSO) {
|
||||
estado = OCIOSO;
|
||||
digitalWrite(LED_PIN, LOW);
|
||||
Serial.println("[DESCANSO] Descanso finalizado, pronto para próxima série.");
|
||||
}
|
||||
}
|
||||
13
wokwi.toml
Normal file
13
wokwi.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
# Wokwi Configuration File
|
||||
# Reference: https://docs.wokwi.com/vscode/project-config
|
||||
[wokwi]
|
||||
version = 1
|
||||
firmware = '.pio/build/esp32/firmware.bin'
|
||||
elf = '.pio/build/esp32/firmware.elf'
|
||||
|
||||
[[chip]]
|
||||
name = 'heartrate'
|
||||
binary = 'chips/heartrate.chip.wasm'
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user