powerpods/main/proto/uart_messages.proto
simon eb67a46158 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>
2026-05-29 19:24:55 +02:00

261 lines
6.8 KiB
Protocol Buffer
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

syntax = "proto3";
import "nanopb.proto";
package alox;
enum MessageType {
UNKNOWN = 0;
ACK = 1;
ECHO = 2;
VERSION = 3;
CLIENT_INFO = 4;
CLIENT_INPUT = 5;
ACCEL_DEADZONE = 6;
ESPNOW_UNICAST_TEST = 7;
LED_RING = 8;
OTA_START = 16;
OTA_PAYLOAD = 17;
OTA_END = 18;
OTA_STATUS = 19;
OTA_START_ESPNOW = 20;
OTA_SLAVE_PROGRESS = 21;
FIND_ME = 22;
RESTART = 23;
ACCEL_SNAPSHOT = 24;
ACCEL_STREAM = 25;
}
message UartMessage {
MessageType type = 1;
oneof payload {
Ack ack_payload = 2;
EchoPayload echo_payload = 3;
VersionResponse version_response = 4;
ClientInfoResponse client_info_response = 5;
ClientInputResponse client_input_response = 6;
OtaStartPayload ota_start = 7;
OtaPayload ota_payload = 8;
OtaEndPayload ota_end = 9;
OtaStatusPayload ota_status = 10;
AccelDeadzoneRequest accel_deadzone_request = 11;
AccelDeadzoneResponse accel_deadzone_response = 12;
EspNowUnicastTestRequest espnow_unicast_test_request = 13;
EspNowUnicastTestResponse espnow_unicast_test_response = 14;
OtaSlaveProgressRequest ota_slave_progress_request = 15;
OtaSlaveProgressResponse ota_slave_progress_response = 16;
LedRingProgressRequest led_ring_progress_request = 17;
LedRingProgressResponse led_ring_progress_response = 18;
EspNowFindMeRequest espnow_find_me_request = 19;
EspNowFindMeResponse espnow_find_me_response = 20;
RestartRequest restart_request = 21;
RestartResponse restart_response = 22;
AccelSnapshotRequest accel_snapshot_request = 23;
AccelSnapshotResponse accel_snapshot_response = 24;
AccelStreamRequest accel_stream_request = 25;
AccelStreamResponse accel_stream_response = 26;
}
}
message Ack {}
message EchoPayload {
bytes data = 1;
}
message VersionResponse {
uint32 version = 1;
string git_hash = 2;
/** Active OTA app partition label, e.g. "ota_0" or "ota_1". */
string running_partition = 3;
}
message ClientInfo {
uint32 id = 1;
bool available = 2;
bool used = 3;
bytes mac = 4;
uint32 last_ping = 5;
uint32 last_success_ping = 6;
uint32 version = 7;
/** Master: ESP-NOW accel stream enabled for this slave. */
bool accel_stream_enabled = 8;
}
message ClientInfoResponse {
repeated ClientInfo clients = 1;
}
message ClientInput {
uint32 id = 1;
float lage_x = 2;
float lage_y = 3;
uint32 bitmask = 4;
}
message ClientInputResponse {
repeated ClientInput clients = 1;
}
// write=false: read deadzone; write=true: apply deadzone (LSB per axis, raw accel units).
// client_id 0 = local BMA456 on this node; >0 = slave id on master; ignored on slave.
// all_clients = true (master only): push deadzone to every registered slave via ESP-NOW.
message AccelDeadzoneRequest {
bool write = 1;
uint32 deadzone = 2;
uint32 client_id = 3;
bool all_clients = 4;
}
message AccelDeadzoneResponse {
uint32 deadzone = 1;
uint32 client_id = 2;
bool success = 3;
uint32 slaves_updated = 4;
}
// Host → master: enable/disable slave accel ESP-NOW stream (~16 ms per slave).
// write=false: read; write=true: apply. client_id 0 invalid for write (use >0 or all_clients).
message AccelStreamRequest {
bool write = 1;
bool enable = 2;
uint32 client_id = 3;
bool all_clients = 4;
}
message AccelStreamResponse {
bool enabled = 1;
uint32 client_id = 2;
bool success = 3;
uint32 slaves_updated = 4;
}
// Host → master: read cached accel samples from slaves (only while stream enabled).
// client_id 0 = all registered slaves; otherwise one slave.
message AccelSnapshotRequest {
uint32 client_id = 1;
}
message AccelSample {
uint32 client_id = 1;
bool valid = 2;
sint32 x = 3;
sint32 y = 4;
sint32 z = 5;
/** Milliseconds since last ESP-NOW sample from this slave. */
uint32 age_ms = 6;
}
message AccelSnapshotResponse {
repeated AccelSample samples = 1 [(nanopb).max_count = 16];
}
message EspNowUnicastTestRequest {
uint32 client_id = 1;
uint32 seq = 2;
}
message EspNowUnicastTestResponse {
bool success = 1;
uint32 seq = 2;
}
// Host → master: LED ring on master (client_id=0) and/or slaves via ESP-NOW.
// mode: 0=clear, 1=progress (0100 %), 2=digit (010), 3=blink, 4=find-me, 5=all LEDs solid color.
message LedRingProgressRequest {
uint32 mode = 1;
/** 0100: fraction of ring LEDs to light (mode=progress) */
uint32 progress = 2;
/** 010 (mode=digit) */
uint32 digit = 3;
uint32 r = 4;
uint32 g = 5;
uint32 b = 6;
/** 0255 brightness scale; 0 = firmware default (~5 %) */
uint32 intensity = 7;
/** Pulse length in ms (mode=blink, default 350) */
uint32 blink_ms = 8;
/** Number of pulses (mode=blink, default 1) */
uint32 blink_count = 9;
/** 0 = master ring only; >0 = one slave; ignored when all_clients */
uint32 client_id = 10;
/** Broadcast to all registered slaves (and optionally master unless slaves_only) */
bool all_clients = 11;
/** With all_clients: do not change master ring */
bool slaves_only = 12;
}
message LedRingProgressResponse {
bool success = 1;
uint32 mode = 2;
uint32 progress = 3;
uint32 digit = 4;
uint32 client_id = 5;
uint32 slaves_updated = 6;
}
/** Host → master: find-me on local ring (client_id=0) or ESP-NOW unicast to one slave. */
message EspNowFindMeRequest {
uint32 client_id = 1;
}
message EspNowFindMeResponse {
bool success = 1;
uint32 client_id = 2;
}
/** Host → master: restart local node (client_id=0) or ESP-NOW unicast to one slave. */
message RestartRequest {
uint32 client_id = 1;
}
message RestartResponse {
bool success = 1;
uint32 client_id = 2;
}
// Host → device: begin UART OTA (erase inactive OTA slot; device replies OTA_STATUS).
message OtaStartPayload {
uint32 total_size = 1;
}
// Host → device: firmware chunk (up to 200 bytes); device buffers 4 KiB before flash write.
message OtaPayload {
uint32 seq = 1;
bytes data = 2 [(nanopb).max_size = 200];
}
// Host → device: no more payload; device flushes buffer and finalizes OTA.
message OtaEndPayload {}
// Device → host status (also used as ACK after each 4 KiB written).
// status: 1=preparing, 2=ready, 3=block_ack, 4=success, 5=failed, 6=distributing
message OtaStatusPayload {
uint32 status = 1;
uint32 bytes_written = 2;
uint32 target_slot = 3;
uint32 error = 4;
}
// Host → master: query ESP-NOW slave OTA progress (client_id 0 = all slaves in session).
message OtaSlaveProgressRequest {
uint32 client_id = 1;
}
message OtaSlaveProgressEntry {
uint32 client_id = 1;
uint32 bytes_written = 2;
uint32 total_bytes = 3;
/** 0=idle, 1=preparing, 2=ready, 3=distributing, 4=success, 5=failed */
uint32 status = 4;
uint32 error = 5;
}
message OtaSlaveProgressResponse {
bool active = 1;
uint32 total_bytes = 2;
uint32 aggregate_bytes = 3;
uint32 slave_count = 4;
repeated OtaSlaveProgressEntry slaves = 5 [(nanopb).max_count = 16];
}