Add LED ring control per client and broadcast over REST and WebSocket.
Solid color mode fills all ring LEDs; master routes UART commands to slaves via ESPNOW_LED_RING. goTool exposes POST /api/led-ring, WebSocket set_led_ring, and a dashboard LED panel with master/slave/all targets. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include "bosch456.h"
|
||||
#include "client_registry.h"
|
||||
#include "esp_now_comm.h"
|
||||
#include "cmd_led_ring.h"
|
||||
#include "led_ring.h"
|
||||
#include "ota_espnow.h"
|
||||
#include "pod_reboot.h"
|
||||
@@ -209,6 +210,30 @@ static esp_err_t send_find_me(const uint8_t *dest_mac, uint32_t client_id) {
|
||||
return send_message(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_led_ring(const uint8_t *dest_mac, uint32_t client_id,
|
||||
const alox_LedRingProgressRequest *req) {
|
||||
if (req == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
|
||||
msg.type = alox_EspNowMessageType_ESPNOW_LED_RING;
|
||||
msg.which_payload = alox_EspNowMessage_led_ring_tag;
|
||||
msg.payload.led_ring.client_id = client_id;
|
||||
msg.payload.led_ring.mode = req->mode;
|
||||
msg.payload.led_ring.progress = req->progress;
|
||||
msg.payload.led_ring.digit = req->digit;
|
||||
msg.payload.led_ring.r = req->r;
|
||||
msg.payload.led_ring.g = req->g;
|
||||
msg.payload.led_ring.b = req->b;
|
||||
msg.payload.led_ring.intensity = req->intensity;
|
||||
msg.payload.led_ring.blink_ms = req->blink_ms;
|
||||
msg.payload.led_ring.blink_count = req->blink_count;
|
||||
|
||||
return send_message(dest_mac, &msg);
|
||||
}
|
||||
|
||||
static esp_err_t send_restart(const uint8_t *dest_mac, uint32_t client_id) {
|
||||
alox_EspNowMessage msg = alox_EspNowMessage_init_zero;
|
||||
|
||||
@@ -347,6 +372,26 @@ esp_err_t esp_now_comm_send_find_me(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_now_comm_send_led_ring(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t client_id,
|
||||
const alox_LedRingProgressRequest *req) {
|
||||
if (mac == NULL || !s_config.master || req == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
char mac_str[18];
|
||||
mac_to_str(mac, mac_str, sizeof(mac_str));
|
||||
esp_err_t err = send_led_ring(mac, client_id, req);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "unicast LED_RING mode %lu to %s client_id=%lu",
|
||||
(unsigned long)req->mode, mac_str, (unsigned long)client_id);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "unicast LED_RING to %s failed: %s", mac_str,
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t esp_now_comm_send_unicast_test(const uint8_t mac[CLIENT_MAC_LEN],
|
||||
uint32_t seq) {
|
||||
if (mac == NULL || !s_config.master) {
|
||||
@@ -454,6 +499,36 @@ static void handle_slave_restart(const uint8_t *master_mac,
|
||||
pod_schedule_restart();
|
||||
}
|
||||
|
||||
static void handle_slave_led_ring(const uint8_t *master_mac,
|
||||
const alox_EspNowLedRing *msg) {
|
||||
uint32_t my_id = s_own_mac[5];
|
||||
|
||||
if (msg->client_id != 0 && msg->client_id != my_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_slave_joined && !mac_equal(master_mac, s_master_mac)) {
|
||||
return;
|
||||
}
|
||||
|
||||
alox_LedRingProgressRequest req = alox_LedRingProgressRequest_init_zero;
|
||||
req.mode = msg->mode;
|
||||
req.progress = msg->progress;
|
||||
req.digit = msg->digit;
|
||||
req.r = msg->r;
|
||||
req.g = msg->g;
|
||||
req.b = msg->b;
|
||||
req.intensity = msg->intensity;
|
||||
req.blink_ms = msg->blink_ms;
|
||||
req.blink_count = msg->blink_count;
|
||||
|
||||
char mac_str[18];
|
||||
mac_to_str(master_mac, mac_str, sizeof(mac_str));
|
||||
ESP_LOGI(TAG, "LED_RING mode %lu from master %s (id=%lu)",
|
||||
(unsigned long)req.mode, mac_str, (unsigned long)my_id);
|
||||
cmd_led_ring_apply(&req);
|
||||
}
|
||||
|
||||
static void handle_slave_find_me(const uint8_t *master_mac,
|
||||
const alox_EspNowFindMe *req) {
|
||||
uint32_t my_id = s_own_mac[5];
|
||||
@@ -704,6 +779,12 @@ static void espnow_recv_cb(const esp_now_recv_info_t *info, const uint8_t *data,
|
||||
}
|
||||
handle_slave_accel_stream(info->src_addr, &msg.payload.accel_stream);
|
||||
break;
|
||||
case alox_EspNowMessage_led_ring_tag:
|
||||
if (!s_slave_joined || !mac_equal(info->src_addr, s_master_mac)) {
|
||||
break;
|
||||
}
|
||||
handle_slave_led_ring(info->src_addr, &msg.payload.led_ring);
|
||||
break;
|
||||
case alox_EspNowMessage_find_me_tag:
|
||||
if (!s_slave_joined || !mac_equal(info->src_addr, s_master_mac)) {
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user