powerpods/main/proto/uart_messages.proto
simon a0f4a81a55 Add per-slave ESP-NOW OTA progress over UART and fix dashboard updates.
Expose OTA_SLAVE_PROGRESS on the master, track per-slave state during
distribution, run ESP-NOW OTA in a background task so the host can poll
while slaves update, and show master/slave progress in the dashboard
with table layout and faster WebSocket refresh during uploads.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 21:07:46 +02:00

154 lines
3.7 KiB
Protocol Buffer

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;
OTA_START = 16;
OTA_PAYLOAD = 17;
OTA_END = 18;
OTA_STATUS = 19;
OTA_START_ESPNOW = 20;
OTA_SLAVE_PROGRESS = 21;
}
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;
}
}
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;
}
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;
}
message EspNowUnicastTestRequest {
uint32 client_id = 1;
uint32 seq = 2;
}
message EspNowUnicastTestResponse {
bool success = 1;
uint32 seq = 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];
}