Skip to content

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 начинается после достижения целевой температуры.

{ "temp": 60, "ramp": 0, "hold": 1800 }

Логика: держать 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

{
  "unitId": "U1",
  "mode": "PROFILE",
  "stages": [
    { "temp": 50, "ramp": 0,   "hold": 14400 }
  ]
}
Быстрый нагрев до 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 }
  ]
}
Плавный нагрев (10 мин) → 1 час при 65°C → быстрый подъём (5 мин) → 2 часа при 80°C → охлаждение (10 мин) → 1 час при 65°C.

Щадящая сушка нейлона

{
  "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 немедленно прерывает профиль:

{ "unitId": "U1" }

МК переходит в IDLE, нагреватель выключается.

См. также