303 lines
9.9 KiB
C
303 lines
9.9 KiB
C
#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 "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
|
|
#include "led_driver.h"
|
|
#include "led_effects.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];
|
|
|
|
// Configuração de modos / relógio
|
|
bool demo_mode = false;
|
|
char current_mode[16] = "IDLE";
|
|
|
|
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)) {
|
|
ESP_LOGW(TAG, "⚠️ Comando inválido (sem 'cmd')");
|
|
return;
|
|
}
|
|
|
|
const char *c = cmd->valuestring;
|
|
ESP_LOGI(TAG, "📩 CMD: %s", c);
|
|
|
|
// ======================================================
|
|
// COMANDOS BÁSICOS
|
|
// ======================================================
|
|
|
|
if (strcmp(c, "LED_ON") == 0) {
|
|
led_all_on(50, 50, 50);
|
|
}
|
|
|
|
else if (strcmp(c, "LED_OFF") == 0) {
|
|
led_all_off();
|
|
}
|
|
|
|
else if (strcmp(c, "CLEAR") == 0) {
|
|
led_all_off();
|
|
}
|
|
|
|
else if (strcmp(c, "SPIN") == 0) {
|
|
int n = led_get_count();
|
|
if (n <= 0) return;
|
|
uint16_t p = esp_random() % n;
|
|
led_spin_to(p, 2, 12, 80);
|
|
}
|
|
|
|
else if (strcmp(c, "JACKPOT") == 0) {
|
|
led_jackpot_animation(); // anima 1 vez
|
|
}
|
|
|
|
else if (strcmp(c, "REBOOT") == 0) {
|
|
ESP_LOGW(TAG, "🔁 REBOOT pedido via MQTT");
|
|
vTaskDelay(pdMS_TO_TICKS(200));
|
|
esp_restart();
|
|
}
|
|
|
|
else if (strcmp(c, "STATUS") == 0) {
|
|
char resp[160];
|
|
snprintf(resp, sizeof(resp),
|
|
"{\"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_ANIM (0/1/2...)
|
|
// ======================================================
|
|
else if (strcmp(c, "SET_ANIM") == 0) {
|
|
cJSON *v = cJSON_GetObjectItem(root, "value");
|
|
if (!cJSON_IsNumber(v)) {
|
|
ESP_LOGW(TAG, "❌ SET_ANIM sem valor numérico");
|
|
return;
|
|
}
|
|
|
|
uint8_t novo = v->valueint;
|
|
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);
|
|
}
|
|
|
|
// ======================================================
|
|
// SET_COLOR (todos os LEDs)
|
|
// ======================================================
|
|
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");
|
|
|
|
if (!cJSON_IsNumber(r) || !cJSON_IsNumber(g) || !cJSON_IsNumber(b)) {
|
|
ESP_LOGW(TAG, "❌ SET_COLOR sem r/g/b");
|
|
return;
|
|
}
|
|
|
|
int n = led_get_count();
|
|
for (int i = 0; i < n; i++) {
|
|
led_set_pixel(i, r->valueint, g->valueint, b->valueint);
|
|
}
|
|
led_show();
|
|
}
|
|
|
|
// ======================================================
|
|
// 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;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
// ======================================================
|
|
// 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);
|
|
|
|
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);
|
|
}
|
|
}
|