UART протокол iDryer (MCU ↔ LINK)¶
Разработчик продукта: зачем этот файл и порядок чтения — 00-for-product-developers.md.
Версия протокола: 1
Физика: 115200 бод, 8N1, SOF: 0xAA
Роли: MCU (контроллер, напр. RP2040) и LINK (сетевой мост, ESP32). Источник правды: src/uart/uart_protocol.h.
Кадр¶
| Поле | Описание | |-------|----------| |VER | Всегда 1. Иное значение генерирует Error с InvalidPayload. |
| FLAGS | bit0 ACK_REQUIRED, bit1 IS_ACK, bit2 ERROR, bit3 FRAGMENTED, bit4 LAST_FRAGMENT. |
| SEQ | Циклический счётчик (0..255). Для ACK фреймов равен номеру подтверждаемого кадра. |
| LEN | 0–200 (MAX_PAYLOAD_SIZE). |
| CRC | CRC16-CCITT, poly 0x1021, init 0xFFFF, little-endian. |
ACK/Retry: 700ms × 3 попытки, затем Error{Timeout}
Тайминги: Heartbeat 5с, Telemetry 1с (активный) / 15с (IDLE)
Типы сообщений¶
| Код | Имя | Направление | Статус |
|---|---|---|---|
0x01 |
Hello | MCU→LINK (ответ на триггер LINK) | Используется |
0x02 |
HelloAck | LINK→MCU | Используется |
0x10 |
Telemetry | MCU→LINK | Используется |
0x11 |
TelemetryAck | LINK→MCU | Используется |
0x12 |
Weights | MCU→LINK | Используется |
0x13 |
Status | MCU→LINK | Используется |
0x14 |
Rfid | MCU→LINK | Используется |
0x1A |
RfidReadData | MCU→LINK | Не интегрировано |
0x1B |
RfidWriteData | LINK→MCU | Не интегрировано |
0x20 |
Command | LINK→MCU | Используется (см. ниже два формата payload) |
0x21 |
CommandAck | MCU→LINK | Используется |
0x30 |
ConfigPush | Обе стороны | Используется |
0x31 |
ConfigAck | Обе стороны | Используется |
0x40 |
Heartbeat | Обе стороны | Используется |
0x50 |
Error | Обе стороны | Используется |
0x60 |
Log | Диагностика | Используется |
0x70 |
ClaimStart | MCU→LINK | Используется |
0x71 |
ClaimStatus | LINK→MCU | Используется |
0x72 |
ClaimComplete | LINK→MCU | Используется |
0x73 |
WsEnable | MCU→LINK | Используется |
0x74 |
WsStatus | LINK→MCU | Используется |
0x75 |
WsResetClients | MCU→LINK | Используется |
0x76 |
WsStatusRequest | MCU→LINK | Используется |
Кадр 0x20 Command: при payloadLength == 13 это CommandPayload; при payloadLength == 64 — ProfilePayload (профильная сушка с MQTT commands/profile). Разбор в uart_bridge.cpp.
Ключевые Payloadы¶
HelloPayload: role (1=MCU, 0xFF=request), firmwareVersion, unitsCount, units[] (topology), mcuSerial
TelemetryPayload: count, units[] (unitId, temperatureC10, humidityPct10, heaterPowerPct, fanOn)
StatusPayload: count, units[] (unitId, mode, sessionNum, targets, timers), uptime
CommandPayload (13 B): command, targetState, unitId, arg0/arg1 (Start: temp×10, минуты или для Storage — влажность в arg1)
ProfilePayload (64 B): в том же MessageKind::Command, см. 02-binary-format.md
ConfigChunk: transferId, totalSize, chunkIndex, data[194] (JSON фрагменты)
Remote Config (ConfigPush)¶
MCU и LINK имеют общую структуру меню (menu_meta.h). По UART передаются только значения.
Форматы:
- MCU→LINK: полный конфиг {"v":8,"units":3,"menu":[...]} или delta {"d":{"3":[55,60,55]}}
- LINK→MCU: команда {"cmd":"set","id":3,"unit":0,"val":55} или {"cmd":"invoke","id":5}
Фрагментация: 194 байта на фрагмент, флаги FRAGMENTED/LAST_FRAGMENT
HeartbeatPayload: uptimeSeconds; wifiRssiDbm (при LINK→MCU — RSSI WiFi; при MCU→LINK — значение задаёт прошивка MCU, часто температура); errorsSinceBoot (uint16, счётчик отправителя кадра с момента старта); cloudState (0–7, только байт в кадре LINK→MCU: Idle→Online). Референсный Link в исходящем heartbeat заполняет errorsSinceBoot счётчиком сбоев UART/ACK на стороне ESP, а не счётчиком ошибок EEPROM MCU; поле из входящего heartbeat не пробрасывается в MQTT. Подробнее: 02-binary-format.md (раздел Heartbeat).
LogPayload (MCU→LINK): severity, source, event, message, unitId — см. 02-binary-format.md (раздел Log).
ClaimStatusPayload: status, pin[9], expiresAt, remainingSeconds
WsStatusPayload: state, pin, pairedCount, maxClients
Подробные структуры см. 02-binary-format.md
Основные сценарии¶
Hello Handshake¶
- MCU отправляет Hello (role=1) с топологией
- LINK отвечает HelloAck (IP, SSID)
- LINK может запросить Hello триггером (role=0xFF)
Версионирование¶
MCU проверяет MAJOR версию firmware LINK. При несовпадении remote config блокируется, telemetry работает.
Remote Config¶
- Backend→Device: MQTT
set/invoke→ UARTConfigPush→ MCU применяет → delta в MQTT - Device→Backend: MQTT
get_config→ UARTGetConfig→ полный JSON в MQTT
Claiming¶
MCU→ClaimStart → LINK делает HTTP provision/register → ClaimStatus с PIN → ClaimComplete
Профильная сушка¶
Backend→MQTT commands/profile → LINK формирует ProfilePayload → UART кадр Command (64 байта). См. 07-profile-mode.
Ограничения¶
- RFID OpenPrintTag (
RfidReadData/RfidWriteData) не интегрировано - MQTT команда
write_rfidна стороне LINK не реализована (заглушка)
См. также¶
- Бинарный формат — детальные структуры payload
- Руководство по интеграции — compatibility contract
- MQTT API — топики и команды