Fix MQTT heartbeat + clock MQTT-only + payload cleanup
This commit is contained in:
parent
a26b421d75
commit
e8618ab6aa
46
main/certs.h
46
main/certs.h
@ -2,33 +2,21 @@
|
|||||||
|
|
||||||
static const char ca_cert_pem[] =
|
static const char ca_cert_pem[] =
|
||||||
"-----BEGIN CERTIFICATE-----\n"
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n"
|
"MIIDHDCCAgSgAwIBAgIUUDkqyQzHgZpOxeCBy0YGWwDZWRkwDQYJKoZIhvcNAQEL\n"
|
||||||
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n"
|
"BQAwIDEeMBwGA1UEAwwVbXF0dC54dXBhcy5teXdpcmUub3JnMB4XDTI2MDIxNDE4\n"
|
||||||
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n"
|
"MjcyMVoXDTI3MDIxNDE4MjcyMVowIDEeMBwGA1UEAwwVbXF0dC54dXBhcy5teXdp\n"
|
||||||
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n"
|
"cmUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnRpx59na551D\n"
|
||||||
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n"
|
"v9HNX56vZdhBpt+MM9vL/TiyNupnuStH7hoNDMYXGva4YSbsHNZknHN0h6Aq08jG\n"
|
||||||
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n"
|
"oDHoJyWr3Cn4ftqb616V499hJmodFFyyk8zR952On32PV7ds95TTIloXe1ptMs0Y\n"
|
||||||
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n"
|
"Pxsr1U1x3M0FNpGazHJEXj7ANQjLcx6ou0FCsgLiqHQ0z6OCMYk9Pl/bvFd4As3R\n"
|
||||||
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n"
|
"QnL0aWV938QjJ1RFdASgW81xONuxntoJiKQNl9mBTGHF7UGFsHckz4lxNohrmDgs\n"
|
||||||
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n"
|
"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\n"
|
|
||||||
"-----END CERTIFICATE-----\n";
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|||||||
@ -1,23 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "mqtt_client.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern esp_mqtt_client_handle_t mqtt_client;
|
|
||||||
|
|
||||||
// Exportar os tópicos MQTT (antes eram static!)
|
|
||||||
extern char topic_status[64];
|
|
||||||
extern char topic_cmd[64];
|
|
||||||
extern char topic_resp[64];
|
|
||||||
extern char topic_lwt[64];
|
|
||||||
|
|
||||||
// Opcional: loop placeholder
|
|
||||||
static inline void mqtt_handler_loop(void) {}
|
|
||||||
|
|
||||||
void mqtt_handler_start(void);
|
void mqtt_handler_start(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -87,20 +87,12 @@ void led_clock_animation(void)
|
|||||||
struct tm t;
|
struct tm t;
|
||||||
localtime_r(&now, &t);
|
localtime_r(&now, &t);
|
||||||
|
|
||||||
int h = t.tm_hour;
|
|
||||||
int m = t.tm_min;
|
|
||||||
int s = t.tm_sec;
|
int s = t.tm_sec;
|
||||||
|
|
||||||
// Mostrar HHMM no display (14-seg)
|
led_clear();
|
||||||
|
|
||||||
display_set_time_top(h, m);
|
|
||||||
|
|
||||||
// LED dos segundos em azul
|
|
||||||
led_clear(); // APAGA TUDO
|
|
||||||
|
|
||||||
int pos = s % LED_COUNT; // 0..59 ou 0..63
|
int pos = s % LED_COUNT;
|
||||||
|
led_set_pixel(pos, 0, 0, 60);
|
||||||
led_set_pixel(pos, 0, 0, 60); // azul forte
|
|
||||||
led_show();
|
led_show();
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(200));
|
vTaskDelay(pdMS_TO_TICKS(200));
|
||||||
|
|||||||
237
main/main.c
237
main/main.c
@ -1,21 +1,16 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "esp_rom_sys.h"
|
|
||||||
#include "esp_task_wdt.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_system.h"
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "esp_event.h"
|
|
||||||
#include "esp_netif.h"
|
|
||||||
#include "esp_sntp.h"
|
|
||||||
|
|
||||||
#include "eeprom_virtual.h"
|
#include "eeprom_virtual.h"
|
||||||
#include "eeprom_tls.h"
|
|
||||||
#include "eeprom_animacao.h"
|
#include "eeprom_animacao.h"
|
||||||
|
|
||||||
#include "wifi_config_portal.h"
|
#include "wifi_config_portal.h"
|
||||||
@ -23,245 +18,102 @@
|
|||||||
|
|
||||||
#include "led_driver.h"
|
#include "led_driver.h"
|
||||||
#include "led_effects.h"
|
#include "led_effects.h"
|
||||||
|
|
||||||
#include "creditos.h"
|
|
||||||
#include "led_task.h"
|
#include "led_task.h"
|
||||||
|
#include "creditos.h"
|
||||||
|
|
||||||
#include "driver/i2c.h"
|
#include "driver/i2c.h"
|
||||||
#include "i2c_helper.h"
|
#include "i2c_helper.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include "net_weather.h"
|
|
||||||
#include "buzzer.h"
|
#include "buzzer.h"
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
esp_err_t i2c_init(void);
|
|
||||||
esp_err_t display_init(void);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool modo_bloqueado = false; // definição oficial
|
|
||||||
|
|
||||||
#define SDA_PIN 21
|
|
||||||
#define SCL_PIN 22
|
|
||||||
#define I2C_PORT I2C_NUM_0
|
|
||||||
|
|
||||||
static const char *TAG = "APP";
|
static const char *TAG = "APP";
|
||||||
static uint32_t segundos = 0;
|
void i2c_scan(void);
|
||||||
|
volatile bool hora_vem_do_mqtt = false;
|
||||||
|
bool modo_bloqueado = false;
|
||||||
static bool wifi_ready = false;
|
static bool wifi_ready = false;
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// CONTADORES
|
||||||
|
// ======================================================
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int total_creditos;
|
int total_creditos;
|
||||||
int total_saidas;
|
int total_saidas;
|
||||||
} contadores_t;
|
} contadores_t;
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// SEGUNDOS (simples, local)
|
||||||
|
// ======================================================
|
||||||
|
static uint32_t segundos = 0;
|
||||||
|
|
||||||
static void weather_task(void *arg)
|
static void segundos_task(void *pv)
|
||||||
{
|
{
|
||||||
float temp;
|
|
||||||
|
|
||||||
ESP_LOGI("WEATHER", "🌡️ weather_task arrancou");
|
|
||||||
|
|
||||||
// 🔥 leitura IMEDIATA (antes do delay)
|
|
||||||
ESP_LOGI("WEATHER", "🌐 a pedir temperatura (primeira vez)");
|
|
||||||
|
|
||||||
if (net_weather_update(&temp)) {
|
|
||||||
ESP_LOGI("WEATHER", "🌡️ temperatura recebida: %.1f", temp);
|
|
||||||
display_temperature_bottom(temp);
|
|
||||||
} else {
|
|
||||||
ESP_LOGE("WEATHER", "❌ net_weather_update falhou");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(15 * 60 * 1000));
|
|
||||||
|
|
||||||
ESP_LOGI("WEATHER", "🌐 a pedir temperatura (loop)");
|
|
||||||
|
|
||||||
if (net_weather_update(&temp)) {
|
|
||||||
ESP_LOGI("WEATHER", "🌡️ temperatura recebida: %.1f", temp);
|
|
||||||
display_temperature_bottom(temp);
|
|
||||||
} else {
|
|
||||||
ESP_LOGE("WEATHER", "❌ net_weather_update falhou");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================
|
|
||||||
// Task contador simples
|
|
||||||
// ============================
|
|
||||||
void segundos_task(void *pv) {
|
|
||||||
while (1) {
|
while (1) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
segundos++;
|
segundos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t get_segundos(void) {
|
uint32_t get_segundos(void)
|
||||||
|
{
|
||||||
return segundos;
|
return segundos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
// ============================
|
// WIFI OK CALLBACK
|
||||||
// Callback Wi-Fi pronto
|
// ======================================================
|
||||||
// ============================
|
static void on_wifi_connected(void)
|
||||||
static void on_wifi_connected(void) {
|
{
|
||||||
wifi_ready = true;
|
wifi_ready = true;
|
||||||
|
|
||||||
ESP_LOGI(TAG, "✅ Wi-Fi conectado — iniciando MQTT...");
|
ESP_LOGI(TAG, "✅ Wi-Fi conectado — iniciando MQTT...");
|
||||||
mqtt_handler_start();
|
mqtt_handler_start();
|
||||||
|
|
||||||
ESP_LOGI(TAG, "🕒 SNTP...");
|
|
||||||
esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
|
||||||
esp_sntp_setservername(0, "pool.ntp.org");
|
|
||||||
esp_sntp_init();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "💡 Inicializando driver LED...");
|
ESP_LOGI(TAG, "💡 Inicializando driver LED...");
|
||||||
led_driver_init();
|
led_driver_init();
|
||||||
|
|
||||||
ESP_LOGI(TAG, "🎬 Iniciando tasks LED e Créditos...");
|
ESP_LOGI(TAG, "🎬 Iniciando tasks LED e Créditos...");
|
||||||
xTaskCreate(led_task, "led_task", 8192, NULL, 5, NULL);
|
// xTaskCreate(led_task, "led_task", 8192, NULL, 5, NULL);
|
||||||
xTaskCreate(creditos_task, "creditos_task", 8192, NULL, 5, NULL);
|
// xTaskCreate(creditos_task, "creditos_task", 8192, NULL, 5, NULL);
|
||||||
|
|
||||||
// 🌡️ TASK DO TEMPO (AQUI!)
|
|
||||||
ESP_LOGI(TAG, "🌡️ Iniciando task de temperatura (Open-Meteo)");
|
|
||||||
xTaskCreate(weather_task, "weather_task", 4096, NULL, 4, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
// ============================
|
// MAIN
|
||||||
// Stack Overflow Handler
|
// ======================================================
|
||||||
// ============================
|
void app_main(void)
|
||||||
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
|
||||||
{
|
{
|
||||||
esp_rom_printf("\n🧨 Stack overflow em %s!\n", pcTaskName);
|
|
||||||
esp_task_wdt_reset();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
esp_restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Configuração básica do I2C
|
|
||||||
i2c_config_t cfg = {
|
|
||||||
.mode = I2C_MODE_MASTER,
|
|
||||||
.sda_io_num = SDA_PIN,
|
|
||||||
.scl_io_num = SCL_PIN,
|
|
||||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
|
||||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
|
||||||
.master.clk_speed = 100000
|
|
||||||
};
|
|
||||||
|
|
||||||
void ht16_init()
|
|
||||||
{
|
|
||||||
uint8_t cmd1 = 0x21; // liga oscilador
|
|
||||||
i2c_master_write_to_device(I2C_PORT, 0x70, &cmd1, 1, 10 / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
uint8_t cmd2 = 0x81; // display ON, sem piscar
|
|
||||||
i2c_master_write_to_device(I2C_PORT, 0x70, &cmd2, 1, 10 / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
uint8_t cmd3 = 0xEF; // brilho máximo
|
|
||||||
i2c_master_write_to_device(I2C_PORT, 0x70, &cmd3, 1, 10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ht16_test()
|
|
||||||
{
|
|
||||||
uint8_t buf[17] = {0};
|
|
||||||
buf[0] = 0x00; // endereço inicial
|
|
||||||
|
|
||||||
buf[7] = 0b0111111; // acende apenas o dígito 0
|
|
||||||
// (que mostra um "0" bonitinho)
|
|
||||||
|
|
||||||
|
|
||||||
// Os outros dígitos ficam a 0 = apagados
|
|
||||||
|
|
||||||
i2c_master_write_to_device(I2C_PORT, 0x70, buf, sizeof(buf), 20 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
//************************************************************** */
|
|
||||||
void i2c_scan(void)
|
|
||||||
{
|
|
||||||
printf("\n--- A fazer scan ao I2C ---\n");
|
|
||||||
|
|
||||||
int found = 0;
|
|
||||||
|
|
||||||
for (uint8_t addr = 1; addr < 0x7F; addr++) {
|
|
||||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
|
||||||
i2c_master_start(cmd);
|
|
||||||
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
|
|
||||||
i2c_master_stop(cmd);
|
|
||||||
|
|
||||||
esp_err_t r = i2c_master_cmd_begin(I2C_PORT, cmd, pdMS_TO_TICKS(50));
|
|
||||||
i2c_cmd_link_delete(cmd);
|
|
||||||
|
|
||||||
if (r == ESP_OK) {
|
|
||||||
printf("✅ I2C encontrado: 0x%02X\n", addr);
|
|
||||||
found++;
|
|
||||||
} else if (r == ESP_ERR_TIMEOUT) {
|
|
||||||
printf("⏱️ TIMEOUT no addr 0x%02X (bus preso?)\n", addr);
|
|
||||||
break; // não vale a pena continuar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
printf("❌ Nenhum dispositivo I2C encontrado\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ============================
|
|
||||||
// MAIN
|
|
||||||
// ============================
|
|
||||||
void app_main(void) {
|
|
||||||
|
|
||||||
// -------- EEPROM virtual --------
|
// -------- EEPROM virtual --------
|
||||||
eeprom_virtual_init();
|
eeprom_virtual_init();
|
||||||
|
|
||||||
contadores_t contadores = {100, 25};
|
contadores_t contadores = {100, 25};
|
||||||
eeprom_virtual_write_bin("contadores", &contadores, sizeof(contadores));
|
eeprom_virtual_write_bin("contadores", &contadores, sizeof(contadores));
|
||||||
ESP_LOGI("EEPROM", "💾 Gravado: total_creditos=%d, total_saidas=%d",
|
|
||||||
contadores.total_creditos, contadores.total_saidas);
|
|
||||||
|
|
||||||
contadores_t lidos = {0};
|
contadores_t lidos = {0};
|
||||||
size_t len = sizeof(lidos);
|
size_t len = sizeof(lidos);
|
||||||
if (eeprom_virtual_read_bin("contadores", &lidos, &len) == ESP_OK) {
|
if (eeprom_virtual_read_bin("contadores", &lidos, &len) == ESP_OK) {
|
||||||
ESP_LOGI("EEPROM", "📖 Lido: total_creditos=%d, total_saidas=%d",
|
ESP_LOGI("EEPROM", "📖 Lido: creditos=%d saidas=%d",
|
||||||
lidos.total_creditos, lidos.total_saidas);
|
lidos.total_creditos, lidos.total_saidas);
|
||||||
} else {
|
|
||||||
ESP_LOGW("EEPROM", "⚠️ Falha ao ler dados!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------- NVS normal --------
|
// -------- NVS --------
|
||||||
ESP_ERROR_CHECK(nvs_flash_init());
|
ESP_ERROR_CHECK(nvs_flash_init());
|
||||||
|
|
||||||
|
// -------- Animação --------
|
||||||
animacao_load();
|
animacao_load();
|
||||||
ESP_LOGI("ANIM", "🎨 Animação carregada = %u", animacao);
|
ESP_LOGI("ANIM", "🎨 Animação carregada = %u", animacao);
|
||||||
|
|
||||||
|
// -------- I2C --------
|
||||||
|
if (i2c_init() == ESP_OK) {
|
||||||
// 1) Inicializa I2C (não aborta)
|
// i2c_scan();
|
||||||
esp_err_t ei = i2c_init();
|
|
||||||
if (ei != ESP_OK) {
|
|
||||||
printf("i2c_init falhou: %s\n", esp_err_to_name(ei));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Scan I2C (ver o que existe no barramento)
|
|
||||||
i2c_scan();
|
|
||||||
|
|
||||||
// 3) Inicializa displays SEM abortar (para não rebootar em loop)
|
|
||||||
esp_err_t ed = display_init();
|
esp_err_t ed = display_init();
|
||||||
printf("display_init = %s\n", esp_err_to_name(ed));
|
ESP_LOGI(TAG, "display_init = %s", esp_err_to_name(ed));
|
||||||
|
|
||||||
// 4) Teste simples no display (se existir)
|
|
||||||
display_text_top("INIT");
|
display_text_top("INIT");
|
||||||
|
|
||||||
// 🔔 6) buzzer (AQUI!)
|
// -------- Buzzer --------
|
||||||
buzzer_init();
|
buzzer_init();
|
||||||
buzzer_beep(500);
|
buzzer_beep(300);
|
||||||
|
|
||||||
|
|
||||||
// -------- Wi-Fi --------
|
// -------- Wi-Fi --------
|
||||||
wifi_config_t cfg;
|
wifi_config_t cfg;
|
||||||
@ -269,21 +121,22 @@ void app_main(void) {
|
|||||||
|
|
||||||
if (esp_wifi_get_config(WIFI_IF_STA, &cfg) == ESP_OK) {
|
if (esp_wifi_get_config(WIFI_IF_STA, &cfg) == ESP_OK) {
|
||||||
if (strlen((char *)cfg.sta.ssid) > 0) {
|
if (strlen((char *)cfg.sta.ssid) > 0) {
|
||||||
ESP_LOGI(TAG, "📂 Credenciais no NVS: SSID=%s", cfg.sta.ssid);
|
ESP_LOGI(TAG, "📂 Credenciais encontradas: %s", cfg.sta.ssid);
|
||||||
have_creds = true;
|
have_creds = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wifi_config_portal_init(on_wifi_connected, have_creds);
|
wifi_config_portal_init(on_wifi_connected, have_creds);
|
||||||
|
|
||||||
// -------- Criar tasks iniciais --------
|
// -------- Tasks base --------
|
||||||
xTaskCreate(segundos_task, "segundos_task", 4096, NULL, 5, NULL);
|
xTaskCreate(segundos_task, "segundos_task", 4096, NULL, 5, NULL);
|
||||||
|
|
||||||
// -------- Loop principal --------
|
// -------- Loop principal --------
|
||||||
|
// Tudo é event-driven (MQTT, UI, etc.)
|
||||||
while (1) {
|
while (1) {
|
||||||
if (wifi_ready) {
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
mqtt_handler_loop();
|
|
||||||
}
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,215 +1,272 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "esp_log.h"
|
#include <stdio.h>
|
||||||
#include "mqtt_client.h"
|
|
||||||
#include "esp_system.h"
|
|
||||||
#include "esp_mac.h"
|
|
||||||
#include "esp_netif.h"
|
|
||||||
#include "cJSON.h"
|
|
||||||
#include "certs.h"
|
#include "certs.h"
|
||||||
#include "mqtt_comandos.h"
|
|
||||||
#include "led_driver.h"
|
#include "esp_log.h"
|
||||||
#include "esp_timer.h"
|
#include "esp_system.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
#include "eeprom_virtual.h"
|
#include "mqtt_client.h"
|
||||||
#include "ui.h"
|
#include "esp_mac.h"
|
||||||
|
|
||||||
|
#include "cJSON.h"
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
#include "mqtt_handler.h"
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
static const char *TAG = "MQTT";
|
static const char *TAG = "MQTT";
|
||||||
|
|
||||||
// -------- CONFIG --------
|
// MQTT CONFIG
|
||||||
#define BROKER_HOST "mqtt.xupas.mywire.org"
|
#define BROKER_HOST "mqtt.xupas.mywire.org"
|
||||||
#define BROKER_PORT_TLS 8883
|
#define BROKER_PORT 8883
|
||||||
#define BROKER_PORT_TCP 1883
|
#define MQTT_USER "xupa"
|
||||||
#define MQTT_USER "xupa"
|
#define MQTT_PASS "xupa"
|
||||||
#define MQTT_PASS "xupa"
|
|
||||||
|
|
||||||
esp_mqtt_client_handle_t mqtt_client = NULL;
|
// ======================================================
|
||||||
static esp_timer_handle_t mqtt_watchdog = NULL;
|
static esp_mqtt_client_handle_t mqtt_client = NULL;
|
||||||
static bool mqtt_connected = false;
|
static bool mqtt_connected = false;
|
||||||
|
|
||||||
char topic_status[64];
|
static char topic_cmd[64];
|
||||||
char topic_cmd[64];
|
static char topic_status[64];
|
||||||
char topic_resp[64];
|
|
||||||
char topic_lwt[64];
|
// TASK HANDLES
|
||||||
|
static TaskHandle_t status_task_handle = NULL;
|
||||||
|
static TaskHandle_t mqtt_clock_handle = NULL;
|
||||||
|
|
||||||
|
// RELÓGIO MQTT
|
||||||
|
static int clock_h = 0;
|
||||||
|
static int clock_m = 0;
|
||||||
|
static bool clock_valid = false;
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
// HEARTBEAT / STATUS
|
// HEARTBEAT TASK
|
||||||
// ======================================================
|
// ======================================================
|
||||||
static void send_status(void) {
|
static void status_task(void *pv)
|
||||||
if (!mqtt_client || !mqtt_connected) return;
|
{
|
||||||
|
while (1) {
|
||||||
|
|
||||||
char buf[160];
|
if (mqtt_connected) {
|
||||||
snprintf(buf, sizeof(buf),
|
|
||||||
"{\"uptime\":%lu,\"heap\":%lu}",
|
|
||||||
(unsigned long)(esp_log_timestamp() / 1000),
|
|
||||||
(unsigned long)esp_get_free_heap_size());
|
|
||||||
|
|
||||||
esp_mqtt_client_publish(mqtt_client, topic_status, buf, 0, 1, false);
|
char msg[128];
|
||||||
ESP_LOGI(TAG, "📤 STATUS -> %s", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================================================
|
snprintf(msg, sizeof(msg),
|
||||||
// WATCHDOG CALLBACK
|
"{\"status\":\"online\"}");
|
||||||
// ======================================================
|
|
||||||
static void mqtt_watchdog_cb(void *arg) {
|
esp_mqtt_client_publish(mqtt_client,
|
||||||
if (!mqtt_connected) {
|
topic_status,
|
||||||
ESP_LOGE(TAG, "⏱️ 2 minutos sem MQTT, reiniciando ESP...");
|
msg,
|
||||||
esp_restart();
|
0,
|
||||||
|
1,
|
||||||
|
0);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "💓 Heartbeat enviado");
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
// EVENT HANDLER
|
// CLOCK TASK (só MQTT controla)
|
||||||
// ======================================================
|
// ======================================================
|
||||||
static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
|
static void mqtt_clock_task(void *pv)
|
||||||
int32_t event_id, void *event_data) {
|
{
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
if (clock_valid) {
|
||||||
|
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(60000)); // 1 minuto
|
||||||
|
|
||||||
|
clock_m++;
|
||||||
|
|
||||||
|
if (clock_m >= 60) {
|
||||||
|
clock_m = 0;
|
||||||
|
clock_h++;
|
||||||
|
|
||||||
|
if (clock_h >= 24)
|
||||||
|
clock_h = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
display_set_time_top(clock_h, clock_m);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "🕒 Hora interna: %02d:%02d",
|
||||||
|
clock_h, clock_m);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// MQTT EVENT HANDLER
|
||||||
|
// ======================================================
|
||||||
|
static void mqtt_event_handler(void *arg,
|
||||||
|
esp_event_base_t base,
|
||||||
|
int32_t event_id,
|
||||||
|
void *event_data)
|
||||||
|
{
|
||||||
esp_mqtt_event_handle_t event = event_data;
|
esp_mqtt_event_handle_t event = event_data;
|
||||||
|
|
||||||
switch (event->event_id) {
|
switch (event->event_id) {
|
||||||
case MQTT_EVENT_CONNECTED:
|
|
||||||
mqtt_connected = true;
|
|
||||||
|
|
||||||
// LED verde no pixel 0
|
// ------------------------------
|
||||||
led_set_pixel(0, 0, 50, 0);
|
case MQTT_EVENT_CONNECTED:
|
||||||
led_show();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "✅ MQTT conectado");
|
mqtt_connected = true;
|
||||||
esp_mqtt_client_publish(mqtt_client, topic_status, "online", 0, 1, 0);
|
ESP_LOGI(TAG, "✅ MQTT conectado");
|
||||||
// esp_mqtt_client_publish(mqtt_client, topic_status, "online", 0, 1, true);
|
|
||||||
esp_mqtt_client_subscribe(mqtt_client, topic_cmd, 1);
|
|
||||||
send_status();
|
|
||||||
|
|
||||||
if (mqtt_watchdog) esp_timer_stop(mqtt_watchdog);
|
// ONLINE retain
|
||||||
break;
|
esp_mqtt_client_publish(mqtt_client,
|
||||||
|
topic_status,
|
||||||
|
"{\"status\":\"online\"}",
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1);
|
||||||
|
|
||||||
case MQTT_EVENT_DISCONNECTED:
|
esp_mqtt_client_subscribe(mqtt_client, topic_cmd, 1);
|
||||||
mqtt_connected = false;
|
esp_mqtt_client_subscribe(mqtt_client, "time/now", 1);
|
||||||
|
|
||||||
// LED vermelho no pixel 0
|
// heartbeat (1x)
|
||||||
led_set_pixel(0, 50, 0, 0);
|
if (status_task_handle == NULL) {
|
||||||
led_show();
|
xTaskCreate(status_task,
|
||||||
|
"status_task",
|
||||||
|
4096,
|
||||||
|
NULL,
|
||||||
|
5,
|
||||||
|
&status_task_handle);
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGW(TAG, "⚠️ MQTT desconectado");
|
// clock (1x)
|
||||||
if (mqtt_watchdog) esp_timer_start_periodic(mqtt_watchdog, 120000000);
|
if (mqtt_clock_handle == NULL) {
|
||||||
break;
|
xTaskCreate(mqtt_clock_task,
|
||||||
|
"mqtt_clock",
|
||||||
|
4096,
|
||||||
|
NULL,
|
||||||
|
5,
|
||||||
|
&mqtt_clock_handle);
|
||||||
|
}
|
||||||
|
|
||||||
case MQTT_EVENT_DATA: {
|
break;
|
||||||
// Copia o payload para um buffer legível
|
|
||||||
char json_clean[256];
|
|
||||||
int len = event->data_len;
|
|
||||||
|
|
||||||
if (len >= sizeof(json_clean)) len = sizeof(json_clean) - 1;
|
// ------------------------------
|
||||||
memcpy(json_clean, event->data, len);
|
case MQTT_EVENT_DISCONNECTED:
|
||||||
json_clean[len] = 0; // NULL terminate
|
mqtt_connected = false;
|
||||||
|
ESP_LOGW(TAG, "⚠️ MQTT desconectado");
|
||||||
|
break;
|
||||||
|
|
||||||
// Remove quebras de linha
|
// ------------------------------
|
||||||
for (int i = 0; json_clean[i]; i++) {
|
case MQTT_EVENT_DATA:
|
||||||
if (json_clean[i] == '\r' || json_clean[i] == '\n')
|
{
|
||||||
json_clean[i] = ' ';
|
esp_mqtt_event_handle_t e = event;
|
||||||
}
|
|
||||||
|
|
||||||
// Mostrar tópico + JSON limpo
|
// 🔥 Ignorar fragmentos parciais
|
||||||
ESP_LOGI(TAG, "📩 [%.*s] %s",
|
if (e->current_data_offset != 0) {
|
||||||
event->topic_len, event->topic,
|
ESP_LOGW(TAG, "Fragmento ignorado");
|
||||||
json_clean);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔥 Ignorar payload vazio
|
||||||
|
if (e->data_len == 0) {
|
||||||
|
ESP_LOGW(TAG, "Payload vazio ignorado");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char topic[64];
|
||||||
|
char payload[256];
|
||||||
|
|
||||||
|
int tlen = e->topic_len;
|
||||||
|
int plen = e->data_len;
|
||||||
|
|
||||||
|
if (tlen >= sizeof(topic)) tlen = sizeof(topic) - 1;
|
||||||
|
if (plen >= sizeof(payload)) plen = sizeof(payload) - 1;
|
||||||
|
|
||||||
|
memcpy(topic, e->topic, tlen);
|
||||||
|
topic[tlen] = 0;
|
||||||
|
|
||||||
|
memcpy(payload, e->data, plen);
|
||||||
|
payload[plen] = 0;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "📩 [%s] %s", topic, payload);
|
||||||
|
|
||||||
|
// -------- TIME --------
|
||||||
|
if (strcmp(topic, "time/now") == 0) {
|
||||||
|
|
||||||
|
cJSON *root = cJSON_Parse(payload);
|
||||||
|
if (!root) return;
|
||||||
|
|
||||||
|
cJSON *h = cJSON_GetObjectItem(root, "h");
|
||||||
|
cJSON *m = cJSON_GetObjectItem(root, "m");
|
||||||
|
|
||||||
|
if (cJSON_IsNumber(h) && cJSON_IsNumber(m)) {
|
||||||
|
|
||||||
|
clock_h = h->valueint;
|
||||||
|
clock_m = m->valueint;
|
||||||
|
clock_valid = true;
|
||||||
|
|
||||||
|
display_set_time_top(clock_h, clock_m);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "⏰ Hora MQTT: %02d:%02d",
|
||||||
|
clock_h, clock_m);
|
||||||
|
}
|
||||||
|
|
||||||
// JSON parse
|
|
||||||
cJSON *root = cJSON_Parse(json_clean);
|
|
||||||
if (root) {
|
|
||||||
mqtt_comandos_handle(root);
|
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
} else {
|
return;
|
||||||
ESP_LOGE(TAG, "❌ JSON inválido");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case MQTT_EVENT_ERROR:
|
|
||||||
ESP_LOGE(TAG, "❌ Erro MQTT");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ======================================================
|
|
||||||
// HEARTBEAT TASK
|
|
||||||
// ======================================================
|
|
||||||
static void mqtt_heartbeat_task(void *arg) {
|
|
||||||
while (1) {
|
|
||||||
send_status();
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(30000)); // envia status a cada 30s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======================================================
|
|
||||||
// START / CONFIG
|
|
||||||
// ======================================================
|
|
||||||
void mqtt_handler_start(void) {
|
|
||||||
esp_mqtt_client_config_t mqtt_cfg = {0};
|
|
||||||
|
|
||||||
// -------- IDENTIFICADOR AUTOMÁTICO --------
|
|
||||||
char device_id[16];
|
|
||||||
uint8_t mac[6];
|
|
||||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
|
||||||
snprintf(device_id, sizeof(device_id), "esp_%02X%02X%02X", mac[3], mac[4], mac[5]);
|
|
||||||
|
|
||||||
esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
|
||||||
if (netif) esp_netif_set_hostname(netif, device_id);
|
|
||||||
ESP_LOGI(TAG, "🆔 ID do dispositivo: %s", device_id);
|
|
||||||
|
|
||||||
snprintf(topic_status, sizeof(topic_status), "esp/%s/status", device_id);
|
|
||||||
snprintf(topic_cmd, sizeof(topic_cmd), "esp/%s/cmd", device_id);
|
|
||||||
snprintf(topic_resp, sizeof(topic_resp), "esp/%s/resp", device_id);
|
|
||||||
snprintf(topic_lwt, sizeof(topic_lwt), "esp/%s/lwt", device_id);
|
|
||||||
|
|
||||||
mqtt_cfg.credentials.client_id = device_id;
|
|
||||||
mqtt_cfg.credentials.username = MQTT_USER;
|
|
||||||
mqtt_cfg.credentials.authentication.password = MQTT_PASS;
|
|
||||||
// ======================================================
|
|
||||||
// MQTT TLS — usa SEMPRE o certificado embutido
|
|
||||||
// ======================================================
|
|
||||||
mqtt_cfg.broker.address.hostname = BROKER_HOST;
|
|
||||||
mqtt_cfg.broker.address.port = BROKER_PORT_TLS;
|
|
||||||
mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_SSL;
|
|
||||||
|
|
||||||
// Certificado raiz (ISRG Root X1)
|
|
||||||
mqtt_cfg.broker.verification.certificate = ca_cert_pem;
|
|
||||||
ESP_LOGI(TAG, "🔐 TLS ativo (cert embutido, EEPROM ignorada)");
|
|
||||||
|
|
||||||
// -------- LWT --------
|
|
||||||
mqtt_cfg.session.last_will.topic = topic_lwt;
|
|
||||||
mqtt_cfg.session.last_will.msg = "offline";
|
|
||||||
mqtt_cfg.session.last_will.qos = 1;
|
|
||||||
mqtt_cfg.session.last_will.retain = false;
|
|
||||||
|
|
||||||
// ======================================================
|
|
||||||
// INICIALIZAÇÃO DO CLIENTE MQTT (TLS OBRIGATÓRIO)
|
|
||||||
// ======================================================
|
|
||||||
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
|
|
||||||
if (mqtt_client == NULL) {
|
|
||||||
ESP_LOGE(TAG, "❌ Falha a inicializar MQTT (TLS). Abortado.");
|
|
||||||
return; // Nem vale a pena continuar, sem MQTT não há vida
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
|
|
||||||
esp_mqtt_client_start(mqtt_client);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "🚀 MQTT inicializado em %s:%lu (TLS)",
|
|
||||||
mqtt_cfg.broker.address.hostname,
|
|
||||||
(unsigned long)mqtt_cfg.broker.address.port);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// -------- WATCHDOG MQTT --------
|
default:
|
||||||
const esp_timer_create_args_t wd_args = {
|
break;
|
||||||
.callback = &mqtt_watchdog_cb,
|
}
|
||||||
.name = "mqtt_watchdog"
|
}
|
||||||
};
|
|
||||||
esp_timer_create(&wd_args, &mqtt_watchdog);
|
// ======================================================
|
||||||
|
// START MQTT
|
||||||
// -------- HEARTBEAT TASK --------
|
// ======================================================
|
||||||
xTaskCreate(mqtt_heartbeat_task, "mqtt_heartbeat", 12288, NULL, 5, NULL);
|
void mqtt_handler_start(void)
|
||||||
|
{
|
||||||
|
esp_mqtt_client_config_t cfg = {0};
|
||||||
|
|
||||||
|
uint8_t mac[6];
|
||||||
|
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
||||||
|
|
||||||
|
char client_id[16];
|
||||||
|
snprintf(client_id, sizeof(client_id),
|
||||||
|
"esp_%02X%02X%02X",
|
||||||
|
mac[3], mac[4], mac[5]);
|
||||||
|
|
||||||
|
snprintf(topic_cmd, sizeof(topic_cmd),
|
||||||
|
"esp/%s/cmd", client_id);
|
||||||
|
|
||||||
|
snprintf(topic_status, sizeof(topic_status),
|
||||||
|
"esp/%s/status", client_id);
|
||||||
|
|
||||||
|
cfg.broker.address.hostname = BROKER_HOST;
|
||||||
|
cfg.broker.address.port = BROKER_PORT;
|
||||||
|
cfg.credentials.username = MQTT_USER;
|
||||||
|
cfg.credentials.authentication.password = MQTT_PASS;
|
||||||
|
cfg.credentials.client_id = client_id;
|
||||||
|
cfg.broker.address.transport = MQTT_TRANSPORT_OVER_SSL;
|
||||||
|
cfg.broker.verification.certificate = ca_cert_pem;
|
||||||
|
|
||||||
|
// Last will
|
||||||
|
cfg.session.last_will.topic = topic_status;
|
||||||
|
cfg.session.last_will.msg = "{\"status\":\"offline\"}";
|
||||||
|
cfg.session.last_will.qos = 1;
|
||||||
|
cfg.session.last_will.retain = 1;
|
||||||
|
|
||||||
|
mqtt_client = esp_mqtt_client_init(&cfg);
|
||||||
|
esp_mqtt_client_register_event(
|
||||||
|
mqtt_client, ESP_EVENT_ANY_ID,
|
||||||
|
mqtt_event_handler, NULL);
|
||||||
|
|
||||||
|
esp_mqtt_client_start(mqtt_client);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "🚀 MQTT iniciado como %s", client_id);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user