adiciona podômetro e telinha

This commit is contained in:
2026-02-12 16:04:06 -03:00
parent 203a4a006d
commit b7419154aa
3 changed files with 404 additions and 328 deletions

View File

@@ -3,186 +3,74 @@
"author": "Amaro Lopes", "author": "Amaro Lopes",
"editor": "wokwi", "editor": "wokwi",
"parts": [ "parts": [
{ { "type": "board-esp32-devkit-c-v4", "id": "esp", "top": 0, "left": 0, "attrs": {} },
"type": "board-esp32-devkit-c-v4", { "type": "chip-heartrate", "id": "chip1", "top": -114.18, "left": -148.8, "attrs": {} },
"id": "esp",
"top": 0,
"left": 0,
"attrs": {}
},
{
"type": "chip-heartrate",
"id": "chip1",
"top": -114.18,
"left": -148.8,
"attrs": {}
},
{ {
"type": "wokwi-resistor", "type": "wokwi-resistor",
"id": "r1", "id": "r1",
"top": -33.6, "top": -33.6,
"left": -67.75, "left": -67.75,
"rotate": 90, "rotate": 90,
"attrs": { "attrs": { "value": "1000" }
"value": "1000" },
} { "type": "wokwi-slide-switch", "id": "sw1", "top": -130, "left": 127.9, "attrs": {} },
{ "type": "wokwi-mpu6050", "id": "imu1", "top": 167.02, "left": 175.12, "attrs": {} },
{ "type": "wokwi-led", "id": "led1", "top": -32.4, "left": 167, "attrs": { "color": "red" } },
{
"type": "wokwi-text",
"id": "text1",
"top": -163.2,
"left": 67.2,
"attrs": { "text": "devagar" }
}, },
{ {
"type": "wokwi-slide-switch", "type": "wokwi-text",
"id": "sw1", "id": "text2",
"top": -130, "top": -163.2,
"left": 127.9, "left": 153.6,
"attrs": {} "attrs": { "text": "rápido" }
}, },
{ {
"type": "wokwi-mpu6050", "type": "board-ssd1306",
"id": "imu1", "id": "oled1",
"top": 99.82, "top": 99.14,
"left": -199.28, "left": 288.23,
"attrs": {} "attrs": { "i2cAddress": "0x3c" }
}, },
{ {
"type": "wokwi-led", "type": "wokwi-pushbutton",
"id": "led1", "id": "btn1",
"top": -32.4, "top": 111.8,
"left": 167, "left": -144,
"attrs": { "attrs": { "color": "green", "xray": "1" }
"color": "red" },
} { "type": "wokwi-vcc", "id": "vcc1", "top": -37.64, "left": 326.4, "attrs": {} },
} { "type": "wokwi-vcc", "id": "vcc2", "top": -37.64, "left": -230.4, "attrs": {} }
], ],
"connections": [ "connections": [
[ [ "esp:TX", "$serialMonitor:RX", "", [] ],
"esp:TX", [ "esp:RX", "$serialMonitor:TX", "", [] ],
"$serialMonitor:RX", [ "esp:3V3", "chip1:VCC", "red", [ "h-187.01", "v-134.4" ] ],
"", [ "chip1:GND", "esp:GND.2", "black", [ "v28.8", "h297.6", "v96" ] ],
[] [ "r1:1", "chip1:BTN", "red", [ "h0" ] ],
], [ "esp:35", "chip1:OUT", "green", [ "h-23.81", "v-182.4" ] ],
[ [ "sw1:1", "chip1:BTN", "green", [ "v0" ] ],
"esp:RX", [ "sw1:2", "sw1:3", "black", [ "v0" ] ],
"$serialMonitor:TX", [ "sw1:3", "esp:GND.2", "black", [ "v0" ] ],
"", [ "imu1:SDA", "esp:21", "green", [ "v0" ] ],
[] [ "esp:GND.2", "led1:C", "black", [ "h81.24" ] ],
], [ "esp:17", "led1:A", "green", [ "h0" ] ],
[ [ "oled1:GND", "esp:GND.2", "black", [ "v0" ] ],
"esp:3V3", [ "oled1:SCL", "esp:22", "green", [ "v0" ] ],
"chip1:VCC", [ "esp:21", "oled1:SDA", "green", [ "h254.44" ] ],
"green", [ "esp:3V3", "r1:2", "red", [ "h0" ] ],
[ [ "oled1:VCC", "vcc1:VCC", "red", [ "v0" ] ],
"h-187.01", [ "vcc2:VCC", "esp:3V3", "red", [ "v0" ] ],
"v-134.4" [ "imu1:SCL", "esp:22", "green", [ "v0" ] ],
] [ "imu1:GND", "esp:GND.2", "black", [ "v0" ] ],
], [ "imu1:VCC", "vcc1:VCC", "red", [ "v-153.6", "h86.48" ] ],
[ [ "btn1:1.r", "esp:25", "green", [ "v0" ] ],
"chip1:GND", [ "esp:GND.1", "btn1:2.r", "black", [ "h0" ] ]
"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": {} "dependencies": {}
} }

View File

@@ -16,3 +16,4 @@ lib_deps =
hwspeedy/DHT-Sensor hwspeedy/DHT-Sensor
knolleary/PubSubClient knolleary/PubSubClient
adafruit/Adafruit MPU6050@^2.2.8 adafruit/Adafruit MPU6050@^2.2.8
arduinogetstarted/ezButton

View File

@@ -1,52 +1,88 @@
// ============================================================================ // ============================================================================
// Sistema de monitoramento de cozinha com ESP32 // Monitor de Repetições e Passos com ESP32
// Monitora temperatura, umidade e gás com detecção avançada de incêndio // Monitora aceleração (MPU6050), frequência cardíaca (sensor de pulso)
// Envia dados via MQTT e controla coifa e ar-condicionado // Exibe dados em OLED, envia via MQTT
// Modo Repetição: detecta exercícios com análise de tempo e intensidade
// Modo Pedômetro: conta passos baseado em aceleração
// ============================================================================ // ============================================================================
// ============================================================================
// INCLUDES // INCLUDES
// ============================================================================
// Comunicação e rede
#include <WiFi.h>
#include <PubSubClient.h>
// Sensores e I2C
#include <Wire.h>
#include <Adafruit_MPU6050.h> #include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h> #include <Adafruit_Sensor.h>
#include <PubSubClient.h> // MQTT
#include <WiFi.h> // WiFi // Display
#include <Wire.h> #include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Interface
#include <ezButton.h>
// ============================================================================ // ============================================================================
// DEFINES - Pinos GPIO // CONFIGURAÇÃO - Pinos GPIO
// ============================================================================ // ============================================================================
#define PULSE_PIN 35 // Pin for the pulse sensor #define PULSE_PIN 35
#define LED_PIN 17 // Pin for the LED #define LED_PIN 17
#define MODE_BUTTON_PIN 25
// ============================================================================ // ============================================================================
// DEFINES - Configurações estáticas // CONFIGURAÇÃO - Display OLED SSD1306
// ============================================================================ // ============================================================================
#define SAMPLE_PERIOD_MS 10 // 100 Hz #define SCREEN_WIDTH 128 // Largura em pixels
#define FILTER_ALPHA 0.9 #define SCREEN_HEIGHT 64 // Altura em pixels
#define OLED_RESET -1 // Pin de reset (compartilhado)
#define SCREEN_ADDRESS 0x3C // Endereço I2C do display
#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 // CONFIGURAÇÃO - Algoritmo de Detecção de Repetições
// ============================================================================
#define SAMPLE_PERIOD_MS 10 // Período de amostragem em ms (100 Hz)
#define FILTER_ALPHA 0.9 // Fator de filtro exponencial (0-1)
#define ACCEL_REST_THRESHOLD 0.3 // Aceleração < 0.3 m/s² = repouso
#define ACCEL_ACTIVE_THRESHOLD 0.8// Aceleração > 0.8 m/s² = movimento ativo
#define MIN_PEAK_AMPLITUDE 1.5 // Amplitude mínima do pico em m/s²
#define MIN_REP_TIME 800 // Tempo mínimo de repetição em ms
#define MAX_REP_TIME 5000 // Tempo máximo de repetição em ms
// ============================================================================
// CONFIGURAÇÃO - Pedômetro
// ============================================================================
#define STEP_ACCEL_THRESHOLD 0.8 // Limiar de aceleração para passo
#define STEP_DEBOUNCE_MS 200 // Tempo mínimo entre passos
#define BUTTON_DEBOUNCE_MS 50 // Debounce do botão
#define PEDOMETER_IDLE_TIMEOUT_MS 30000 // Timeout de inatividade (ms)
#define DISPLAY_UPDATE_INTERVAL_MS 100 // Limita display a 10 FPS
// ============================================================================
// CONFIGURAÇÃO - WiFi e MQTT
// ============================================================================
#define WIFI_SSID "Wokwi-GUEST" // SSID da rede WiFi
#define WIFI_PASSWORD "" // Senha da rede WiFi
#define MQTT_BROKER "77.37.69.84" // Endereço do broker MQTT
#define MQTT_PORT 1883 // Porta MQTT padrão
#define MQTT_RECONNECT_INTERVAL_MS 5000 // Intervalo de reconexão
// ============================================================================
// ENUMS - Estados do Sistema
// ============================================================================ // ============================================================================
enum EstadoRepeticao { enum EstadoRepeticao {
OCIOSO, OCIOSO,
DESCANSO,
SUBINDO, SUBINDO,
DESCENDO DESCENDO,
DESCANSO
}; };
// ============================================================================ // ============================================================================
// CONSTANTES - WiFi e MQTT // CONSTANTES - 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[] = { const char* MQTT_SUB_TOPICS[] = {
"academia/reps", "academia/reps",
"academia/sets", "academia/sets",
@@ -56,203 +92,330 @@ const char* MQTT_PUB_TOPIC = "academia";
const int MQTT_SUB_COUNT = sizeof(MQTT_SUB_TOPICS) / sizeof(MQTT_SUB_TOPICS[0]); const int MQTT_SUB_COUNT = sizeof(MQTT_SUB_TOPICS) / sizeof(MQTT_SUB_TOPICS[0]);
// ============================================================================ // ============================================================================
// VARIÁVEIS GLOBAIS - Objetos // OBJETOS GLOBAIS
// ============================================================================ // ============================================================================
WiFiClient espClient; WiFiClient espClient;
PubSubClient mqtt(espClient); PubSubClient mqtt(espClient);
Adafruit_MPU6050 mpu; Adafruit_MPU6050 mpu;
sensors_event_t event; sensors_event_t event;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
ezButton button(MODE_BUTTON_PIN);
// ============================================================================ // ============================================================================
// VARIÁVEIS GLOBAIS - Estado do sistema // VARIÁVEIS GLOBAIS - Estado Atual do Sistema
// ============================================================================ // ============================================================================
EstadoRepeticao estado = OCIOSO; EstadoRepeticao estado = OCIOSO;
bool pedometroAtivo = false;
unsigned long ultimaAmostra = 0; // ============================================================================
// VARIÁVEIS GLOBAIS - Leitura e Processamento de Sensores
unsigned long t_inicio = 0; // ============================================================================
unsigned long t_pico = 0; // Aceleração (MPU6050)
unsigned long t_fim = 0;
unsigned long t_descanso = 30;
float aceleracaoFiltrada = 1.0; float aceleracaoFiltrada = 1.0;
float aceleracaoAnterior = 1.0; float aceleracaoAnterior = 1.0;
float aceleracaoPico = 0; float aceleracaoPico = 0;
unsigned long ultimaAmostra = 0;
// Frequência cardíaca (sensor de pulso)
int frequenciaCardiacaAtual = 0;
// ============================================================================
// VARIÁVEIS GLOBAIS - Detecção de Repetições
// ============================================================================
unsigned long tInicio = 0;
unsigned long tPico = 0;
unsigned long tFim = 0;
unsigned long tDescanso = 30;
int repeticoes = 0; int repeticoes = 0;
int max_reps = 0; int maxRepeticoes = 0;
int set = 0; int serie = 0;
int sets = 0; int series = 0;
// Frequência cardíaca (atual e agregados por repetição) // Agregação de frequência cardíaca por repetição
int frequenciaCardiacaAtual = 0;
unsigned long somaFrequenciaCardiaca = 0; unsigned long somaFrequenciaCardiaca = 0;
unsigned int contagemFrequenciaCardiaca = 0; unsigned int contagemFrequenciaCardiaca = 0;
// MQTT reconnect control // ============================================================================
unsigned long ultimoMqttAttempt = 0; // VARIÁVEIS GLOBAIS - Pedômetro
const unsigned long MQTT_RECONNECT_INTERVAL_MS = 5000; // ============================================================================
long totalPassos = 0;
unsigned long ultimoTempoPassso = 0;
unsigned long ultimaAtividadePedometro = 0;
// Buffer MQTT // ============================================================================
// VARIÁVEIS GLOBAIS - Comunicação MQTT
// ============================================================================
char msg[256]; char msg[256];
char MQTT_CLIENTID[32]; char MQTT_CLIENTID[32];
unsigned long ultimoMqttAttempt = 0;
unsigned long ultimoDisplayUpdate = 0;
// ============================================================================ // ============================================================================
// FUNÇÕES AUXILIARES - Callbacks MQTT // COMUNICAÇÃO - MQTT
// ============================================================================ // ============================================================================
void mqttCallback(char* topic, byte* payload, unsigned int length) 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]; char buf[64];
int n = (length < (int)sizeof(buf) - 1) ? length : (int)sizeof(buf) - 1; int n = (length < (int)sizeof(buf) - 1) ? length : (int)sizeof(buf) - 1;
memcpy(buf, payload, n); memcpy(buf, payload, n);
buf[n] = '\0'; buf[n] = '\0';
Serial.print("[MQTT] payload: ");
Serial.println(buf);
// Processa tópicos
if (strcmp(topic, "academia/reps") == 0) { if (strcmp(topic, "academia/reps") == 0) {
int v = atoi(buf); int valor = atoi(buf);
if (!isnan(v)) { if (!isnan(valor)) {
Serial.print("[MQTT] reps = "); maxRepeticoes = valor;
Serial.println(v);
max_reps = v;
} }
} else if (strcmp(topic, "academia/sets") == 0) { } else if (strcmp(topic, "academia/sets") == 0) {
int v = atoi(buf); int valor = atoi(buf);
if (!isnan(v)) { if (!isnan(valor)) {
Serial.print("[MQTT] sets = "); series = valor;
Serial.println(v);
sets = v;
} }
} else if (strcmp(topic, "academia/t_descanso") == 0) { } else if (strcmp(topic, "academia/t_descanso") == 0) {
int v = atoi(buf); int valor = atoi(buf);
if (!isnan(v)) { if (!isnan(valor)) {
Serial.print("[MQTT] t_descanso = "); tDescanso = valor;
Serial.println(v);
t_descanso = v;
} }
} }
} }
// ============================================================================ // ============================================================================
// FUNÇÕES AUXILIARES - Conectividade // CONECTIVIDADE - WiFi e MQTT
// ============================================================================ // ============================================================================
// Conecta o ESP32 à rede WiFi
void connectWiFi() void connectWiFi()
{ {
Serial.print("[WiFi] Conectando...");
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
int attempts = 0; int tentativas = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) { while (WiFi.status() != WL_CONNECTED && tentativas < 20) {
delay(500); delay(500);
Serial.print("."); tentativas++;
attempts++;
} }
Serial.println("\r\n[WiFi] Conectado!");
} }
// Inscreve em tópicos MQTT para receber atualizações de limiares
void mqttSubscribe() void mqttSubscribe()
{ {
Serial.println("[MQTT] Conectado!");
for (int i = 0; i < MQTT_SUB_COUNT; ++i) { for (int i = 0; i < MQTT_SUB_COUNT; ++i) {
if (mqtt.subscribe(MQTT_SUB_TOPICS[i])) { mqtt.subscribe(MQTT_SUB_TOPICS[i]);
Serial.print("[MQTT] Tópico: ");
Serial.println(MQTT_SUB_TOPICS[i]);
}
} }
} }
// Conecta ao broker MQTT
void connectMQTT() void connectMQTT()
{ {
mqtt.setServer(MQTT_BROKER, MQTT_PORT); mqtt.setServer(MQTT_BROKER, MQTT_PORT);
mqtt.setCallback(mqttCallback); mqtt.setCallback(mqttCallback);
while (!mqtt.connected()) { while (!mqtt.connected()) {
Serial.println("[MQTT] Conectando...");
if (mqtt.connect(MQTT_CLIENTID)) { if (mqtt.connect(MQTT_CLIENTID)) {
mqttSubscribe(); mqttSubscribe();
break; break;
} else { } else {
Serial.print("[MQTT] Falha rc=");
Serial.println(mqtt.state());
delay(2000); delay(2000);
} }
} }
} }
// ============================================================================ // ============================================================================
// FUNÇÕES AUXILIARES - Sensores // INTERFACE - Display OLED
// ============================================================================ // ============================================================================
// Lê valores de aceleração do sensor MPU
void displayRepetitionStatus()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Modo Repeticao");
display.setTextSize(2);
display.setCursor(0, 15);
display.print("Reps: ");
display.println(repeticoes);
display.setCursor(0, 35);
display.print("Set: ");
display.print(serie);
display.print("/");
display.println(series);
display.setTextSize(1);
display.setCursor(0, 55);
display.print("FC: ");
display.print(frequenciaCardiacaAtual);
display.println(" bpm");
display.display();
}
void displayPedometerStatus()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Modo Pedometro");
display.setTextSize(2);
display.setCursor(0, 20);
display.print("Passos: ");
display.println(totalPassos);
display.setTextSize(1);
display.setCursor(0, 55);
display.print("FC: ");
display.print(frequenciaCardiacaAtual);
display.println(" bpm");
display.display();
}
void displayRestTimer()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("DESCANSO");
unsigned long tempoDecorrido = (millis() - tFim) / 1000;
long tempoRestante = tDescanso - tempoDecorrido;
display.setTextSize(2);
display.setCursor(0, 20);
if (tempoRestante > 0) {
display.print("Restam: ");
display.println(tempoRestante);
} else {
display.println("PRONTO!");
}
display.setTextSize(1);
display.setCursor(0, 55);
display.print("FC: ");
display.print(frequenciaCardiacaAtual);
display.println(" bpm");
display.display();
}
void displayPedometerIdleScreen()
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Pedometro OCIOSO");
display.setTextSize(2);
display.setCursor(0, 25);
display.println("Aguardando...");
display.setTextSize(1);
display.setCursor(0, 55);
display.print("FC: ");
display.print(frequenciaCardiacaAtual);
display.println(" bpm");
display.display();
}
// ============================================================================
// SENSORES - Leitura e Processamento
// ============================================================================
void amostraMPU() void amostraMPU()
{ {
sensors_event_t a, g, temp; sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp); mpu.getEvent(&a, &g, &temp);
float magnitudeAceleracao = sqrt( float magnitudeAceleracao = sqrt(
a.acceleration.x * a.acceleration.x a.acceleration.x * a.acceleration.x +
+ a.acceleration.y * a.acceleration.y a.acceleration.y * a.acceleration.y +
+ a.acceleration.z * a.acceleration.z); a.acceleration.z * a.acceleration.z
);
float aceleracaoCorrigida = magnitudeAceleracao - 9.81; float aceleracaoCorrigida = magnitudeAceleracao - 9.81;
aceleracaoFiltrada = FILTER_ALPHA * aceleracaoFiltrada +
(1.0 - FILTER_ALPHA) * aceleracaoCorrigida;
aceleracaoFiltrada = FILTER_ALPHA * aceleracaoFiltrada + (1.0 - FILTER_ALPHA) * aceleracaoCorrigida; if (abs(aceleracaoFiltrada) > 0.1) {
ultimaAtividadePedometro = millis();
}
detectarRepeticao(aceleracaoFiltrada); if (!pedometroAtivo) {
detectarRepeticao(aceleracaoFiltrada);
} else {
detectaPasso(aceleracaoFiltrada);
}
}
void detectaPasso(float aceleracaoAtual)
{
unsigned long tempoAtual = millis();
if ((tempoAtual - ultimoTempoPassso) > STEP_DEBOUNCE_MS) {
if (aceleracaoAtual > STEP_ACCEL_THRESHOLD &&
aceleracaoAnterior < STEP_ACCEL_THRESHOLD) {
totalPassos++;
ultimoTempoPassso = tempoAtual;
ultimaAtividadePedometro = tempoAtual;
snprintf(msg, sizeof(msg),
"{\"passos\": %ld, \"fc\": %d}",
totalPassos, frequenciaCardiacaAtual);
mqtt.publish(MQTT_PUB_TOPIC, msg);
}
}
aceleracaoAnterior = aceleracaoAtual;
} }
// ============================================================================ // ============================================================================
// FUNÇÕES - Detecção de alarmes // DETECÇÃO - Repetições
// ============================================================================ // ============================================================================
// Verifica qual alarme deve ser ativado baseado nos limites
void detectarRepeticao(float sinal) void detectarRepeticao(float sinal)
{ {
unsigned long agora = millis(); unsigned long agora = millis();
switch (estado) { switch (estado) {
case OCIOSO: case OCIOSO:
if (sinal > TH_START) { if (sinal > ACCEL_ACTIVE_THRESHOLD) {
t_inicio = agora; tInicio = agora;
aceleracaoPico = sinal; aceleracaoPico = sinal;
estado = SUBINDO; estado = SUBINDO;
// Inicia acumulação de frequência cardíaca para esta repetição
somaFrequenciaCardiaca = 0; somaFrequenciaCardiaca = 0;
contagemFrequenciaCardiaca = 0; contagemFrequenciaCardiaca = 0;
digitalWrite(LED_PIN, HIGH);
} }
break; break;
case SUBINDO: case SUBINDO:
if (sinal > aceleracaoPico) if (sinal > aceleracaoPico) {
aceleracaoPico = sinal; aceleracaoPico = sinal;
}
if (sinal < aceleracaoAnterior) { if (sinal < aceleracaoAnterior) {
t_pico = agora; tPico = agora;
estado = DESCENDO; estado = DESCENDO;
} }
break; break;
case DESCENDO: case DESCENDO:
if (sinal < TH_END) { if (sinal < ACCEL_REST_THRESHOLD) {
t_fim = agora; tFim = agora;
analisarRepeticao(); analisarRepeticao();
verificarSerie(); verificarSerie();
digitalWrite(LED_PIN, LOW);
} }
break; break;
case DESCANSO:
break;
} }
// Se estamos no meio de uma repetição, acumula a frequência cardíaca atual if (estado != OCIOSO && estado != DESCANSO) {
if (estado != OCIOSO) {
somaFrequenciaCardiaca += (unsigned long)frequenciaCardiacaAtual; somaFrequenciaCardiaca += (unsigned long)frequenciaCardiacaAtual;
contagemFrequenciaCardiaca++; contagemFrequenciaCardiaca++;
} }
@@ -262,52 +425,39 @@ void detectarRepeticao(float sinal)
void analisarRepeticao() void analisarRepeticao()
{ {
unsigned long tempoTotal = t_fim - t_inicio; unsigned long tempoTotal = tFim - tInicio;
unsigned long tempoSubida = t_pico - t_inicio; unsigned long tempoSubida = tPico - tInicio;
unsigned long tempoDescida = t_fim - t_pico; unsigned long tempoDescida = tFim - tPico;
bool invalida = false;
bool ruim = false;
Serial.print("Total: ");
Serial.print(tempoTotal);
Serial.print(" ms");
if (aceleracaoPico < MIN_PEAK_AMPLITUDE) { if (aceleracaoPico < MIN_PEAK_AMPLITUDE) {
Serial.print(" | Repetição parcial"); invalida = true;
ruim = true; Serial.print(" Repetição parcial ");
} }
if (tempoTotal < MIN_REP_TIME) { if (tempoTotal < MIN_REP_TIME) {
Serial.print(" | Muito rápido"); invalida = true;
ruim = true; Serial.print(" Rápido demais ");
} }
if (tempoTotal > MAX_REP_TIME) { if (tempoTotal > MAX_REP_TIME) {
Serial.print(" | Muito lento"); invalida = true;
ruim = true; Serial.print(" Lento demais ");
} }
if (tempoDescida < tempoSubida * 0.6) { if (tempoDescida < tempoSubida * 0.6) {
Serial.print(" | Deixando cair o peso"); invalida = true;
ruim = true; Serial.print(" Deixando o peso cair ");
} }
if (!ruim) { if (!invalida) {
Serial.print(" | Boa repetição");
repeticoes++; 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; unsigned int fcMedia = 0;
if (contagemFrequenciaCardiaca > 0) { if (contagemFrequenciaCardiaca > 0) {
fcMedia = (unsigned int)(somaFrequenciaCardiaca / contagemFrequenciaCardiaca); fcMedia = (unsigned int)(somaFrequenciaCardiaca / contagemFrequenciaCardiaca);
Serial.print(" | FC média: ");
Serial.print(fcMedia);
Serial.print(" bpm");
} }
// Zera agregados após uso
somaFrequenciaCardiaca = 0; somaFrequenciaCardiaca = 0;
contagemFrequenciaCardiaca = 0; contagemFrequenciaCardiaca = 0;
@@ -316,21 +466,19 @@ void analisarRepeticao()
fcMedia, tempoTotal, tempoSubida, tempoDescida); fcMedia, tempoTotal, tempoSubida, tempoDescida);
mqtt.publish(MQTT_PUB_TOPIC, msg); mqtt.publish(MQTT_PUB_TOPIC, msg);
Serial.println(); Serial.println();
} }
void verificarSerie() void verificarSerie()
{ {
if (repeticoes >= max_reps && max_reps > 0) { if (repeticoes >= maxRepeticoes && maxRepeticoes > 0) {
Serial.println("[SÉRIE] Série finalizada, iniciando descanso...");
repeticoes = 0; repeticoes = 0;
estado = DESCANSO; estado = DESCANSO;
set++;
digitalWrite(LED_PIN, HIGH); digitalWrite(LED_PIN, HIGH);
if (set >= sets && sets > 0) { serie++;
Serial.println("[TREINO] Treino finalizado, parabéns!");
set = 0; if (serie >= series && series > 0) {
serie = 0;
} }
} else { } else {
estado = OCIOSO; estado = OCIOSO;
@@ -338,42 +486,45 @@ void verificarSerie()
} }
// ============================================================================ // ============================================================================
// FUNÇÕES - Inicialização // INICIALIZAÇÃO
// ============================================================================ // ============================================================================
// Inicializa o ESP32 e configura os periféricos
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(115200);
delay(100); delay(100);
Serial.println("\n[SETUP] Iniciando sistema...");
// Gera ID único MQTT
snprintf(MQTT_CLIENTID, sizeof(MQTT_CLIENTID), "esp32_%08X", snprintf(MQTT_CLIENTID, sizeof(MQTT_CLIENTID), "esp32_%08X",
(uint32_t)(ESP.getEfuseMac() & 0xFFFFFFFF)); (uint32_t)(ESP.getEfuseMac() & 0xFFFFFFFF));
// Conecta Wire.begin();
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
for (;;);
}
connectWiFi(); connectWiFi();
connectMQTT(); connectMQTT();
while (!mpu.begin()) { while (!mpu.begin()) {
Serial.println("MPU6050 not connected!");
delay(1000); delay(1000);
} }
mpu.setAccelerometerRange(MPU6050_RANGE_4_G); mpu.setAccelerometerRange(MPU6050_RANGE_4_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG); mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
Serial.println("MPU6050 ready!");
pinMode(LED_PIN, OUTPUT); pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); digitalWrite(LED_PIN, LOW);
Serial.println("[SETUP] Pronto!\n");
pinMode(MODE_BUTTON_PIN, INPUT_PULLUP);
button.setDebounceTime(BUTTON_DEBOUNCE_MS);
} }
// ============================================================================ // ============================================================================
// LOOP PRINCIPAL // LOOP PRINCIPAL
// ============================================================================ // ============================================================================
// Loop principal - executa continuamente
void loop() void loop()
{ {
if (!mqtt.connected()) { if (!mqtt.connected()) {
@@ -381,22 +532,58 @@ void loop()
} }
mqtt.loop(); mqtt.loop();
if (millis() - ultimaAmostra >= SAMPLE_PERIOD_MS && estado != DESCANSO) { button.loop();
// Verifica MQTT
if (button.isPressed()) {
pedometroAtivo = !pedometroAtivo;
if (pedometroAtivo) {
totalPassos = 0;
ultimoTempoPassso = 0;
aceleracaoAnterior = 1.0;
ultimaAtividadePedometro = millis();
} else {
estado = OCIOSO;
repeticoes = 0;
serie = 0;
aceleracaoAnterior = 1.0;
somaFrequenciaCardiaca = 0;
contagemFrequenciaCardiaca = 0;
}
display.clearDisplay();
display.display();
}
if (millis() - ultimaAmostra >= SAMPLE_PERIOD_MS) {
int16_t valorPulso = analogRead(PULSE_PIN); int16_t valorPulso = analogRead(PULSE_PIN);
// Converter valorPulso para tensão
float tensao = valorPulso * (5.0 / 4095.0); float tensao = valorPulso * (5.0 / 4095.0);
// Atualiza frequência cardíaca atual (valor usado nas acumulações)
frequenciaCardiacaAtual = (int)((tensao / 3.3) * 675); frequenciaCardiacaAtual = (int)((tensao / 3.3) * 675);
ultimaAmostra += SAMPLE_PERIOD_MS;
amostraMPU(); amostraMPU();
} else if (millis() - t_fim >= t_descanso * 100 && estado == DESCANSO) { ultimaAmostra += SAMPLE_PERIOD_MS;
}
// Atualizar display apenas a cada DISPLAY_UPDATE_INTERVAL_MS (100ms = 10 FPS)
if (millis() - ultimoDisplayUpdate >= DISPLAY_UPDATE_INTERVAL_MS) {
ultimoDisplayUpdate = millis();
if (estado == DESCANSO) {
displayRestTimer();
} else if (pedometroAtivo &&
(millis() - ultimaAtividadePedometro > PEDOMETER_IDLE_TIMEOUT_MS)) {
displayPedometerIdleScreen();
} else {
if (pedometroAtivo) {
displayPedometerStatus();
} else {
displayRepetitionStatus();
}
}
}
if (estado == DESCANSO && millis() - tFim >= tDescanso * 1000) {
estado = OCIOSO; estado = OCIOSO;
digitalWrite(LED_PIN, LOW); digitalWrite(LED_PIN, LOW);
Serial.println("[DESCANSO] Descanso finalizado, pronto para próxima série.");
} }
} }