Profile Mode (Профильная многоэтапная сушка)¶
Режим профильной сушки позволяет задать последовательность температурных этапов с контролем скорости перехода между ними.
Команда запуска¶
Topic: idryer/{serial}/commands/profile
QoS: 1
{
"unitId": "U1",
"mode": "PROFILE",
"stages": [
{ "temp": 60, "ramp": 300, "hold": 1800 },
{ "temp": 100, "ramp": 600, "hold": 6000 },
{ "temp": 70, "ramp": 600, "hold": 12000 }
],
"startStage": 0,
"timestamp": "2025-12-08T12:00:00Z"
}
Поля команды¶
Парсер на стороне LINK (CommandHandler::handleProfile) использует unitId, stages, startStage (по умолчанию 0). Поля mode и timestamp в примере ниже не читаются обработчиком профиля; timestamp в корне JSON может обрабатываться общим механизмом синхронизации времени для любых MQTT-команд, если задан callback.
| Поле | Тип | Обязательно для LINK | Описание |
|---|---|---|---|
unitId |
string | да | ID камеры (U1, U2, U3, U4) |
mode |
string | нет (игнорируется) | Для документации бэкенда; можно передавать "PROFILE" |
stages |
array | да | Массив температурных этапов (до 10) |
startStage |
number | нет | Индекс этапа для старта (0-based), по умолчанию 0 |
timestamp |
string | нет | Опционально для time sync (см. выше) |
Поля stages[]¶
| Поле | Тип | Ед. изм. | Описание |
|---|---|---|---|
temp |
number | °C | Целевая температура этапа |
ramp |
number | секунды | Время разгона до целевой температуры |
hold |
number | секунды | Время удержания целевой температуры |
Особые значения¶
ramp = 0 (быстрый нагрев)¶
Когда ramp: 0, МК греет на максимальной мощности до достижения temp.
Отсчёт hold начинается после достижения целевой температуры.
Логика: держать 30 минут при 60°C, а не 30 минут включая разогрев.
Логика работы на МК¶
Переменные состояния¶
struct ProfileState {
uint8_t currentStage; // Индекс текущего этапа (0-based)
uint8_t totalStages; // Общее количество этапов
float prevTemp; // Температура в начале этапа
uint32_t stageStartTime; // Время начала этапа (мс)
uint32_t holdStartTime; // Время начала удержания (мс)
bool inRamp; // true = рампа, false = удержание
};
Автомат состояний¶
┌─────────────────────────────────────────────────────────────┐
│ PROFILE MODE │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ достигли temp ┌─────────┐ │
│ │ RAMP │ ─────────────────► │ HOLD │ │
│ │ │ или ramp=0 и │ │ │
│ │ │ temp достигнута │ │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ │ stageTime >= ramp │ holdTime >= hold │
│ │ (если ramp > 0) │ │
│ ▼ ▼ │
│ переход к HOLD следующий этап │
│ или завершение │
│ │
└─────────────────────────────────────────────────────────────┘
Псевдокод¶
void profileTick(uint32_t now) {
Stage* stage = &stages[currentStage];
uint32_t stageTime = now - stageStartTime;
if (inRamp) {
if (stage->ramp == 0) {
// Быстрый нагрев: греем на максимуме
targetTemp = stage->temp;
heaterPower = MAX_POWER;
// Переход к HOLD когда достигли температуры
if (currentTemp >= stage->temp - HYSTERESIS) {
inRamp = false;
holdStartTime = now;
}
} else {
// Линейная рампа
if (stageTime < stage->ramp * 1000) {
float progress = (float)stageTime / (stage->ramp * 1000);
targetTemp = prevTemp + (stage->temp - prevTemp) * progress;
} else {
// Рампа завершена, переход к HOLD
targetTemp = stage->temp;
inRamp = false;
holdStartTime = now;
}
}
} else {
// Режим HOLD
targetTemp = stage->temp;
uint32_t holdTime = now - holdStartTime;
if (holdTime >= stage->hold * 1000) {
// Этап завершён
if (currentStage + 1 < totalStages) {
// Следующий этап
prevTemp = currentTemp;
currentStage++;
stageStartTime = now;
inRamp = true;
} else {
// Профиль завершён
setMode(IDLE);
}
}
}
// PID регулятор
heaterPower = pidCompute(targetTemp, currentTemp);
}
Примеры профилей¶
Стандартная сушка PLA¶
Быстрый нагрев до 50°C, держать 4 часа.Интенсивная сушка ABS¶
{
"unitId": "U1",
"mode": "PROFILE",
"stages": [
{ "temp": 65, "ramp": 600, "hold": 3600 },
{ "temp": 80, "ramp": 300, "hold": 7200 },
{ "temp": 65, "ramp": 600, "hold": 3600 }
]
}
Щадящая сушка нейлона¶
{
"unitId": "U1",
"mode": "PROFILE",
"stages": [
{ "temp": 40, "ramp": 1200, "hold": 7200 },
{ "temp": 70, "ramp": 1800, "hold": 28800 },
{ "temp": 50, "ramp": 1200, "hold": 3600 }
]
}
Status телеметрия¶
При работе в режиме PROFILE устройство отправляет расширенный статус:
{
"units": [
{
"unitId": "U1",
"mode": "PROFILE",
"sessionNum": 42,
"target": { "temperature": 80.0 },
"totalElapsed": 4200,
"totalRemaining": 10200,
"currentStage": 1,
"totalStages": 3,
"stageElapsed": 600,
"stageRemaining": 7200,
"stagePhase": "HOLD"
}
],
"timestamp": "..."
}
| Поле | Описание |
|---|---|
currentStage |
Индекс текущего этапа (0-based) |
totalStages |
Общее количество этапов |
stageElapsed |
Секунды с начала текущего этапа |
stageRemaining |
Секунды до конца текущего этапа |
stagePhase |
"RAMP" или "HOLD" |
UART передача на MCU¶
Единственный нормативный формат для прошивки — кадр MessageKind::Command (0x20) с payload 64 байта (ProfilePayload: до 10 этапов по 6 байт, поля unitId, totalStages, startStage, массив стадий). См. раздел ProfilePayload внутри Command (0x20) в 02-binary-format.md. Дискриминация: длина 13 байт → обычный CommandPayload, 64 байта → профиль.
Прерывание профиля¶
Команда stop немедленно прерывает профиль:
МК переходит в IDLE, нагреватель выключается.
См. также¶
- 01-mqtt.md — MQTT топики и команды
- Основные потоки — конфигурация и Hello/info