Refactor code structure for improved readability and maintainability

This commit is contained in:
XupaMisto 2025-11-23 18:15:47 +00:00
parent e5572b2fad
commit d5bbf905a4
8 changed files with 1964 additions and 70 deletions

View File

@ -7,20 +7,19 @@
// inicialização do driver
void led_driver_init(void);
// número de LEDs
int led_get_count(void);
// envia os dados para o anel
void led_show(void);
// limpa todos os LEDs
void led_clear(void);
// define um LED individual
void led_set_pixel(int index, uint8_t r, uint8_t g, uint8_t b);
void led_all_on(uint8_t r, uint8_t g, uint8_t b);
void led_all_off(void);
// spin da sorte
void led_spin_to(uint16_t target, int min_spins, int max_spins, int base_delay_ms);
void led_set_global_brightness(uint8_t level);
#endif

View File

@ -1,4 +1,20 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "mqtt_client.h"
#include "cJSON.h"
// Variáveis globais
extern esp_mqtt_client_handle_t mqtt_client;
extern char topic_resp[64];
extern uint8_t hora_r, hora_g, hora_b;
extern uint8_t min_r, min_g, min_b;
extern uint8_t sec_r, sec_g, sec_b;
extern int clock_speed_ms;
extern bool demo_mode;
extern char current_mode[16];
void mqtt_comandos_handle(cJSON *root);

View File

@ -21,6 +21,15 @@ static rmt_transmit_config_t tx_config = {
.loop_count = 0
};
static uint8_t global_brightness = 255;
void led_set_global_brightness(uint8_t level)
{
global_brightness = level;
}
void led_driver_init(void)
{
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
@ -72,21 +81,29 @@ static void hw_update(void)
{
uint8_t buf[LED_COUNT * 3];
// MOST common format is GRB
// Previne divisão por zero
uint8_t br = (global_brightness == 0) ? 1 : global_brightness;
for (int i = 0; i < LED_COUNT; i++) {
buf[i*3 + 0] = leds[i].g;
buf[i*3 + 1] = leds[i].r;
buf[i*3 + 2] = leds[i].b;
// Escala (r,g,b) com brilho global (0..255)
uint8_t r = (leds[i].r * br) >> 8;
uint8_t g = (leds[i].g * br) >> 8;
uint8_t b = (leds[i].b * br) >> 8;
// GRB
buf[i*3 + 0] = g;
buf[i*3 + 1] = r;
buf[i*3 + 2] = b;
}
ESP_ERROR_CHECK(rmt_transmit(rmt_chan, encoder, buf, sizeof(buf), &tx_config));
rmt_tx_wait_all_done(rmt_chan, -1);
// Reset time > 50us
esp_rom_delay_us(60);
esp_rom_delay_us(60); // reset 60us
}
void led_show(void)
{
hw_update();

View File

@ -4,6 +4,8 @@
#include "freertos/task.h"
#include <stdlib.h>
#include <time.h>
#include "mqtt_comandos.h"
void led_all_on(uint8_t r, uint8_t g, uint8_t b)
{

View File

@ -1,23 +1,38 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_log.h"
#include "esp_system.h"
#include "esp_random.h"
#include "mqtt_client.h"
#include "cJSON.h"
#include "esp_random.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "led_driver.h"
#include "led_effects.h"
#include "creditos.h"
#include "eeprom_animacao.h"
#include "eeprom_animacao.h" // animacao / animacao_save()
static const char *TAG = "MQTT_CMD";
extern esp_mqtt_client_handle_t mqtt_client;
extern char topic_resp[64];
// Estes tópicos vêm do mqtt_handler.c
extern char topic_resp[];
// Configuração de modos / relógio
bool demo_mode = false;
char current_mode[16] = "IDLE";
void mqtt_comandos_handle(cJSON *root)
uint8_t hora_r = 10, hora_g = 40, hora_b = 10;
uint8_t min_r = 10, min_g = 10, min_b = 60;
uint8_t sec_r = 5, sec_g = 5, sec_b = 5;
int clock_speed_ms = 150; // usado no led_clock_animation()
void mqtt_comandos_handle(cJSON *root)
{
cJSON *cmd = cJSON_GetObjectItem(root, "cmd");
if (!cJSON_IsString(cmd)) {
@ -29,8 +44,9 @@ void mqtt_comandos_handle(cJSON *root)
ESP_LOGI(TAG, "📩 CMD: %s", c);
// ======================================================
// LED ON / OFF
// COMANDOS BÁSICOS
// ======================================================
if (strcmp(c, "LED_ON") == 0) {
led_all_on(50, 50, 50);
}
@ -39,43 +55,40 @@ void mqtt_comandos_handle(cJSON *root)
led_all_off();
}
// ======================================================
// SPIN
// ======================================================
else if (strcmp(c, "CLEAR") == 0) {
led_all_off();
}
else if (strcmp(c, "SPIN") == 0) {
uint16_t p = esp_random() % led_get_count();
int n = led_get_count();
if (n <= 0) return;
uint16_t p = esp_random() % n;
led_spin_to(p, 2, 12, 80);
}
// ======================================================
// JACKPOT
// ======================================================
else if (strcmp(c, "JACKPOT") == 0) {
led_jackpot_animation();
led_jackpot_animation(); // anima 1 vez
}
// ======================================================
// DAR CRÉDITO
// ======================================================
else if (strcmp(c, "CREDITO") == 0) {
creditos_dar();
else if (strcmp(c, "REBOOT") == 0) {
ESP_LOGW(TAG, "🔁 REBOOT pedido via MQTT");
vTaskDelay(pdMS_TO_TICKS(200));
esp_restart();
}
// ======================================================
// ESTADO DO SISTEMA
// ======================================================
else if (strcmp(c, "STATUS") == 0) {
char resp[128];
char resp[160];
snprintf(resp, sizeof(resp),
"{\"status\":\"ok\",\"heap\":%lu,\"anim\":%u}",
(unsigned long)esp_get_free_heap_size(),
animacao);
esp_mqtt_client_publish(mqtt_client, topic_resp, resp, 0, 1, false);
"{\"uptime\":%lu,\"heap\":%lu}",
(unsigned long)(esp_log_timestamp()/1000),
(unsigned long)esp_get_free_heap_size());
esp_mqtt_client_publish(mqtt_client, topic_resp,
resp, 0, 1, false);
ESP_LOGI(TAG, "📤 STATUS -> %s", resp);
}
// ======================================================
// SET ANIMAÇÃO (NVS)
// SET_ANIM (0/1/2...)
// ======================================================
else if (strcmp(c, "SET_ANIM") == 0) {
cJSON *v = cJSON_GetObjectItem(root, "value");
@ -85,45 +98,197 @@ void mqtt_comandos_handle(cJSON *root)
}
uint8_t novo = v->valueint;
animacao_save(novo); // GRAVA NA NVS
animacao_save(novo); // grava em NVS
animacao = novo; // atualiza RAM
ESP_LOGI(TAG, "🎨 Animação alterada para %u", novo);
char resp[64];
snprintf(resp, sizeof(resp), "{\"anim\":%u}", novo);
esp_mqtt_client_publish(mqtt_client, topic_resp, resp, 0, 1, false);
esp_mqtt_client_publish(mqtt_client, topic_resp,
resp, 0, 1, false);
}
// ======================================================
// REBOOT
// SET_COLOR (todos os LEDs)
// ======================================================
else if (strcmp(c, "REBOOT") == 0) {
else if (strcmp(c, "SET_COLOR") == 0) {
cJSON *r = cJSON_GetObjectItem(root, "r");
cJSON *g = cJSON_GetObjectItem(root, "g");
cJSON *b = cJSON_GetObjectItem(root, "b");
ESP_LOGW(TAG, "♻️ Reinício seguro agendado...");
if (!cJSON_IsNumber(r) || !cJSON_IsNumber(g) || !cJSON_IsNumber(b)) {
ESP_LOGW(TAG, "❌ SET_COLOR sem r/g/b");
return;
}
// callback C normal
void reboot_cb(void *arg) {
esp_restart();
int n = led_get_count();
for (int i = 0; i < n; i++) {
led_set_pixel(i, r->valueint, g->valueint, b->valueint);
}
led_show();
}
// criar timer
esp_timer_handle_t reboot_timer;
const esp_timer_create_args_t args = {
.callback = reboot_cb,
.arg = NULL,
.name = "reboot_safe"
};
// ======================================================
// SET_BRIGHT (brilho global)
// ======================================================
else if (strcmp(c, "SET_BRIGHT") == 0) {
cJSON *v = cJSON_GetObjectItem(root, "value");
if (!cJSON_IsNumber(v)) {
ESP_LOGW(TAG, "❌ SET_BRIGHT sem 'value'");
return;
}
esp_timer_create(&args, &reboot_timer);
esp_timer_start_once(reboot_timer, 200000); // 200 ms
return; // evita continuar dentro do handler
uint8_t level = v->valueint;
led_set_global_brightness(level);
ESP_LOGI(TAG, "💡 Brilho global = %u", level);
}
// ======================================================
// LED_PIXEL (1 LED)
// ======================================================
else if (strcmp(c, "LED_PIXEL") == 0) {
cJSON *n = cJSON_GetObjectItem(root, "n");
cJSON *r = cJSON_GetObjectItem(root, "r");
cJSON *g = cJSON_GetObjectItem(root, "g");
cJSON *b = cJSON_GetObjectItem(root, "b");
if (!cJSON_IsNumber(n) || !cJSON_IsNumber(r) ||
!cJSON_IsNumber(g) || !cJSON_IsNumber(b)) {
ESP_LOGW(TAG, "❌ LED_PIXEL sem n/r/g/b");
return;
}
led_set_pixel(n->valueint, r->valueint, g->valueint, b->valueint);
led_show();
}
// ======================================================
// COMANDO DESCONHECIDO
// DEMO_ON / DEMO_OFF
// ======================================================
else if (strcmp(c, "DEMO_ON") == 0) {
demo_mode = true;
strncpy(current_mode, "DEMO", sizeof(current_mode));
current_mode[sizeof(current_mode)-1] = '\0';
ESP_LOGI(TAG, "▶ Demo ON");
}
else if (strcmp(c, "DEMO_OFF") == 0) {
demo_mode = false;
strncpy(current_mode, "NORMAL", sizeof(current_mode));
current_mode[sizeof(current_mode)-1] = '\0';
ESP_LOGI(TAG, "⏹ Demo OFF");
}
// ======================================================
// SET_MODE (string)
// ======================================================
else if (strcmp(c, "SET_MODE") == 0) {
cJSON *v = cJSON_GetObjectItem(root, "value");
if (!cJSON_IsString(v)) {
ESP_LOGW(TAG, "❌ SET_MODE sem 'value' string");
return;
}
strncpy(current_mode, v->valuestring, sizeof(current_mode));
current_mode[sizeof(current_mode)-1] = '\0';
ESP_LOGI(TAG, "🎛 Mode = %s", current_mode);
}
// ======================================================
// GET_INFO
// ======================================================
else if (strcmp(c, "GET_INFO") == 0) {
char resp[256];
snprintf(resp, sizeof(resp),
"{\"uptime\":%lu,"
"\"heap\":%lu,"
"\"anim\":%u,"
"\"mode\":\"%s\"}",
(unsigned long)(esp_log_timestamp()/1000),
(unsigned long)esp_get_free_heap_size(),
animacao,
current_mode
);
esp_mqtt_client_publish(mqtt_client, topic_resp,
resp, 0, 1, false);
ESP_LOGI(TAG, "📤 INFO -> %s", resp);
}
// ======================================================
// SET_HOUR_COLOR / SET_MIN_COLOR / SET_SEC_COLOR
// ======================================================
else if (strcmp(c, "SET_HOUR_COLOR") == 0) {
cJSON *r = cJSON_GetObjectItem(root, "r");
cJSON *g = cJSON_GetObjectItem(root, "g");
cJSON *b = cJSON_GetObjectItem(root, "b");
if (!cJSON_IsNumber(r) || !cJSON_IsNumber(g) || !cJSON_IsNumber(b)) return;
hora_r = r->valueint;
hora_g = g->valueint;
hora_b = b->valueint;
ESP_LOGI(TAG, "⏰ Cor HORAS = (%u,%u,%u)", hora_r, hora_g, hora_b);
}
else if (strcmp(c, "SET_MIN_COLOR") == 0) {
cJSON *r = cJSON_GetObjectItem(root, "r");
cJSON *g = cJSON_GetObjectItem(root, "g");
cJSON *b = cJSON_GetObjectItem(root, "b");
if (!cJSON_IsNumber(r) || !cJSON_IsNumber(g) || !cJSON_IsNumber(b)) return;
min_r = r->valueint;
min_g = g->valueint;
min_b = b->valueint;
ESP_LOGI(TAG, "⏰ Cor MIN = (%u,%u,%u)", min_r, min_g, min_b);
}
else if (strcmp(c, "SET_SEC_COLOR") == 0) {
cJSON *r = cJSON_GetObjectItem(root, "r");
cJSON *g = cJSON_GetObjectItem(root, "g");
cJSON *b = cJSON_GetObjectItem(root, "b");
if (!cJSON_IsNumber(r) || !cJSON_IsNumber(g) || !cJSON_IsNumber(b)) return;
sec_r = r->valueint;
sec_g = g->valueint;
sec_b = b->valueint;
ESP_LOGI(TAG, "⏰ Cor SEC = (%u,%u,%u)", sec_r, sec_g, sec_b);
}
// ======================================================
// SET_CLOCK_SPEED (ms)
// ======================================================
else if (strcmp(c, "SET_CLOCK_SPEED") == 0) {
cJSON *v = cJSON_GetObjectItem(root, "ms");
if (!cJSON_IsNumber(v)) {
ESP_LOGW(TAG, "❌ SET_CLOCK_SPEED sem 'ms'");
return;
}
clock_speed_ms = v->valueint;
ESP_LOGI(TAG, "⏰ Clock speed = %d ms", clock_speed_ms);
}
// ======================================================
// TEST_RING
// ======================================================
else if (strcmp(c, "TEST_RING") == 0) {
int n = led_get_count();
if (n <= 0) return;
ESP_LOGI(TAG, "🔍 TEST_RING: %d LEDs", n);
for (int i = 0; i < n; i++) {
led_clear();
led_set_pixel(i, 0, 50, 0);
led_show();
vTaskDelay(pdMS_TO_TICKS(80));
}
led_all_off();
}
// ======================================================
// COMANDO DESCONHECIDO
// ======================================================
else {
ESP_LOGW(TAG, "⚠️ Comando desconhecido: %s", c);
@ -131,7 +296,7 @@ void mqtt_comandos_handle(cJSON *root)
char resp[128];
snprintf(resp, sizeof(resp),
"{\"error\":\"unknown_cmd\",\"cmd\":\"%s\"}", c);
esp_mqtt_client_publish(mqtt_client, topic_resp, resp, 0, 1, false);
esp_mqtt_client_publish(mqtt_client, topic_resp,
resp, 0, 1, false);
}
}

47
main/notas.txt Normal file
View File

@ -0,0 +1,47 @@
{"cmd":"STATUS"} // pede o estado: uptime + heap
{"cmd":"LED_ON"} // liga todos os LEDs (branco fraco)
{"cmd":"LED_OFF"} // desliga tudo
{"cmd":"SPIN"} // rotação rápida até posição aleatória
{"cmd":"JACKPOT"} // animação jackpot (flash + arco-íris)
{"cmd":"REBOOT"} // reinicia o ESP
{"cmd":"SET_ANIM","value":0} // animação idle (pontinho azul)
{"cmd":"SET_ANIM","value":1} // relógio (horas/minutos/segundos)
{"cmd":"SET_ANIM","value":2} // jackpot em loop
{"cmd":"STATUS"} // estado: uptime + heap
{"cmd":"LED_ON"} // liga tudo
{"cmd":"LED_OFF"} // desliga tudo
{"cmd":"CLEAR"} // igual ao LED_OFF mas sem ser idiota
{"cmd":"SPIN"} // spin aleatório
{"cmd":"JACKPOT"} // animação jackpot
{"cmd":"REBOOT"} // reinicia o ESP
{"cmd":"SET_ANIM","value":X} // animação permanente (0,1,2...)
{"cmd":"SET_COLOR","r":X,"g":Y,"b":Z} // cor estática
{"cmd":"SET_BRIGHT","value":X"} // brilho global
{"cmd":"LED_PIXEL","n":i,"r":X,"g":Y,"b":Z} // LED individual
{"cmd":"DEMO_ON"} // liga demo
{"cmd":"DEMO_OFF"} // desliga demo
{"cmd":"SET_MODE","value":"RELOGIO"} // modos gerais (STRING)
{"cmd":"GET_INFO"} // resposta JSON completa
{"cmd":"SET_HOUR_COLOR","r":X,"g":Y,"b":Z} // ponteiro horas
{"cmd":"SET_MIN_COLOR","r":X,"g":Y,"b":Z} // ponteiro minutos
{"cmd":"SET_SEC_COLOR","r":X,"g":Y,"b":Z} // ponteiro segundos
{"cmd":"SET_CLOCK_SPEED","ms":X} // velocidade do relógio (delay)
{"cmd":"TEST_RING"} // acender LED a LED
esp/esp_BBC9A4/cmd // onde envias os comandos
esp/esp_BBC9A4/resp // respostas aos comandos
esp/esp_BBC9A4/status // heartbeat 30s
esp/esp_BBC9A4/lwt // "offline" caso morra

View File

@ -317,14 +317,14 @@ CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
CONFIG_ESPTOOLPY_FLASHFREQ="40m"
# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set
# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set
CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
# CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE is not set
CONFIG_ESPTOOLPY_BEFORE_RESET=y
# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
@ -338,12 +338,12 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
#
# Partition Table
#
CONFIG_PARTITION_TABLE_SINGLE_APP=y
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
# CONFIG_PARTITION_TABLE_CUSTOM is not set
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table

1648
sdkconfig.old Normal file

File diff suppressed because it is too large Load Diff