API — Дозаторы¶
Управление и мониторинг трёх каналов дозирования. Логика алгоритма — ../dosing-logic.md.
Все эндпоинты используют ch ∈ {0, 1, 2} для адресации канала.
Источник: src/API/Dosator/.
GET /api/dosator/status¶
Текущее состояние всех трёх каналов одним запросом. Опрашивается веб-интерфейсом каждые 2 секунды.
Роль: USER+ (любая авторизация).
Запрос¶
Ответ — 200 OK¶
{
"channels": [
{
"ch": 0,
"proportion": 22,
"window_ms": 2000,
"mode": 0,
"run": true,
"lev": true,
"out": true,
"force": false,
"runtime_s": 38421,
"pump_s": 14203
},
{
"ch": 1,
"proportion": 50,
"window_ms": 2000,
"run": false,
"lev": false,
"out": false,
"force": false,
"runtime_s": 12080,
"pump_s": 6040
},
{
"ch": 2,
"proportion": 0,
"window_ms": 2000,
"run": false,
"lev": true,
"out": false,
"force": false,
"runtime_s": 0,
"pump_s": 0
}
]
}
| Поле | Тип | Описание |
|---|---|---|
ch |
int | Индекс канала (0…2) |
proportion |
int | Текущая пропорция ШИМ (0…99) |
window_ms |
int | Длина окна цикла, мс (100…60000) |
mode |
int | Режим дозирования: 0 пропорциональный, 1 импульсный |
run |
bool | Внешний сигнал «идёт мойка» (digitalRead(pinRun) == HIGH) |
lev |
bool | Датчик уровня концентрата (с антидребезгом 3 тика) |
out |
bool | Канал в состоянии DOSING (активно крутит ШИМ; не мгновенное состояние пина) |
force |
bool | Принудит. режим (forceActive) |
runtime_s |
int | Lifetime RUN-наработка из EEPROM + текущая сессия, секунд |
pump_s |
int | Lifetime время насоса из EEPROM + текущая сессия, секунд |
POST /api/dosator/config¶
Изменить пропорцию, окно цикла и/или режим канала. Записывается в NVS немедленно.
Роль: DUTY+.
Запрос¶
curl -u duty:duty123 -X POST \
-H "Content-Type: application/json" \
-d '{"ch":0,"proportion":25}' \
http://awdc.local/api/dosator/config
Тело¶
{
"ch": 0,
"proportion": 25, // опционально, 0..99
"window_ms": 2000, // опционально, 100..60000
"mode": 0 // опционально, 0 пропорциональный / 1 импульсный
}
Поля тела:
ch(int, обязательно) — индекс канала 0…2.proportion(int) — 0…99 и< window_ms / 20.window_ms(int) — 100…60000.mode(int) —0пропорциональный,1импульсный.enabled(bool) — канал подключён; выключенному не вешается RUN-ISR.
Минимум одно из proportion / window_ms / mode / enabled обязательно — иначе 400.
Выключенный канал (enabled:false): задача простаивает, RUN-прерывание
снимается (висящий вход неподключённого дозатора не наводит ложных
срабатываний), выход держится LOW. В Web UI карточка канала скрыта,
HMI пропускает его при переключении кнопками.
Ответ — 200 OK¶
Ошибки¶
| Код | Тело |
|---|---|
| 400 | {"success":false,"message":"Invalid JSON"} |
| 400 | {"success":false,"message":"ch must be 0..2"} |
| 400 | {"success":false,"message":"proportion must be 0..99"} |
| 400 | {"success":false,"message":"proportion must be < window_ms/20"} |
| 400 | {"success":false,"message":"window_ms must be 100..60000"} |
| 400 | {"success":false,"message":"No valid fields"} |
| 401 | {"error":"Unauthorized"} |
| 403 | {"error":"Forbidden"} |
| 413 | {"success":false,"message":"Body too large"} |
Эффекты¶
- Запись в NVS namespace
dosator: ключиprop_<ch>,window_ms_<ch>. - Событие
DOSING_EVT_PROPORTION_CHANGE→ HMI обновляет дисплей. - Если канал в данный момент DOSING — новая пропорция применяется со следующего тика (20 мс).
POST /api/dosator/dispense¶
Принудительный старт канала. Устанавливает forceActive = true —
дозатор начинает ШИМ-цикл независимо от внешнего RUN-сигнала.
Роль: DUTY+.
Запрос¶
curl -u duty:duty123 -X POST \
-H "Content-Type: application/json" \
-d '{"ch":0}' \
http://awdc.local/api/dosator/dispense
Тело¶
Ответ — 200 OK¶
Ошибки¶
| Код | Тело |
|---|---|
| 400 | {"success":false,"message":"Invalid JSON"} |
| 400 | {"success":false,"message":"ch must be 0..2"} |
| 401 | {"error":"Unauthorized"} |
| 403 | {"error":"Forbidden"} |
| 413 | {"success":false,"message":"Body too large"} |
Замечания¶
- Если
proportion == 0— канал останется IDLE, ничего не польётся. - Если
lev == false(нет концентрата) — пин DOZ остаётся LOW, но канал в DOSING. Это нормально: warmup пропускается, Bresenham обнуляется черезeff=0. - Чтобы понять, реально ли крутится цикл, смотри
outв/api/dosator/status.
POST /api/dosator/stop¶
Принудительная остановка канала. Сбрасывает forceActive = false.
Роль: DUTY+.
Запрос¶
curl -u duty:duty123 -X POST \
-H "Content-Type: application/json" \
-d '{"ch":0}' \
http://awdc.local/api/dosator/stop
Тело¶
Ответ — 200 OK¶
Ошибки¶
Те же коды, что у /dispense.
Замечания¶
- Если канал был в DOSING из-за внешнего RUN (а не force) —
/stopне остановит его. Force-флаг и RUN-сигнал независимы. - Чтобы заглушить «сейчас и навсегда» —
proportion=0через/api/dosator/config.
GET /api/statistics¶
Счётчики наработки по каналам — абсолютные (lifetime) и относительные (с последнего сброса на ТО). Источник — EEPROM (схема v3, две зоны), с аккумуляцией текущей сессии в RAM.
Роль: USER+.
Запрос¶
Ответ — 200 OK¶
{
"channels": [
{"ch": 0, "enabled": true, "runtime_abs_s": 38421, "runtime_rel_s": 5021,
"pump_abs_s": 14203, "pump_rel_s": 1820, "reset_ts": 1779000000, "starts": 12},
{"ch": 1, "enabled": true, "runtime_abs_s": 12080, "runtime_rel_s": 12080,
"pump_abs_s": 6040, "pump_rel_s": 6040, "reset_ts": 0, "starts": 4},
{"ch": 2, "enabled": false, "runtime_abs_s": 0, "runtime_rel_s": 0,
"pump_abs_s": 0, "pump_rel_s": 0, "reset_ts": 0, "starts": 0}
]
}
ch(int) — индекс канала (0…2).enabled(bool) — канал подключён/активен.runtime_abs_s(int) — абсолютная RUN-наработка, секунд (lifetime + текущая сессия).runtime_rel_s(int) — RUN-наработка с последнего сброса на ТО, секунд.pump_abs_s(int) — абсолютное время насоса (outN=HIGH), секунд.pump_rel_s(int) — время насоса с последнего сброса на ТО, секунд.reset_ts(int) — local epoch последнего сброса на ТО;0— сброса не было.starts(int) — запусков DOSING за текущий uptime (RAM, обнуляется reboot).
Относительные счётчики = абсолютные − baseline (снимок на момент ТО).
POST /api/statistics/reset¶
Сброс на ТО одного канала: относительные счётчики (runtime_rel_s,
pump_rel_s) обнуляются, абсолютные — сохраняются. В EEPROM пишется новый
baseline (Zone B) с датой сброса.
Роль: ADMIN.
Запрос¶
curl -u admin:admin123 -X POST \
-H 'Content-Type: application/json' -d '{"ch": 0}' \
http://awdc.local/api/statistics/reset
ch(int) — индекс канала (0…2), обязателен.
Ответ — 200 OK¶
Замечания¶
- Операция неразрушающая для абсолютной наработки — обнуляется только относительный счётчик (через запись baseline в Zone B).
reset_ts— local epoch (UTC + tz_offset);0если время не синхронизировано по NTP.- Полное обнуление абсолютной наработки возможно только форматированием
EEPROM —
POST /api/diag/eeprom/format(защищён паролём администратора).