Skip to content

UART протокол iDryer (MCU ↔ LINK)

Разработчик продукта: зачем этот файл и порядок чтения — 00-for-product-developers.md.

Версия протокола: 1
Физика: 115200 бод, 8N1, SOF: 0xAA
Роли: MCU (контроллер, напр. RP2040) и LINK (сетевой мост, ESP32). Источник правды: src/uart/uart_protocol.h.

Кадр

[SOF][VER][FLAGS][KIND][SEQ][LEN][PAYLOAD][CRClo][CRChi]
 1     1     1      1     1     1    0-200      2 bytes
| Поле | Описание | |-------|----------| | 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 == 64ProfilePayload (профильная сушка с 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

  1. Backend→Device: MQTT set / invoke → UART ConfigPush → MCU применяет → delta в MQTT
  2. Device→Backend: MQTT get_config → UART GetConfig → полный 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 не реализована (заглушка)

См. также