Перейти к содержанию

API — Диагностика

Состояние устройства, лог, watchdog, self-test, EEPROM-диагностика.

Источник: src/API/System/, src/api_handlers.cpp.


GET /api/status

Минимальный публичный статус — не требует аутентификации. Использует веб-UI при первом коннекте, чтобы определить IP и режим.

Роль: USER (с allowPublicRead=true — реально без auth).

Запрос

curl http://192.168.4.1/api/status

Ответ — 200 OK

{
  "wifi_mode": "STA",
  "ip": "192.168.100.61",
  "wifi_status": "CONNECTED",
  "ssid": "MyHome",
  "uptime": 38421,
  "version": "0.12.0",
  "dosators": [
    {"ch": 0, "active": false},
    {"ch": 1, "active": false},
    {"ch": 2, "active": false}
  ]
}
Поле Тип Описание
wifi_mode string STA, AP, или AP_STA
ip string IPv4 в текущей роли (AP IP или STA IP)
wifi_status string CONNECTED, CONNECTING, CONNECT_FAILED, AP_MODE
ssid string SSID текущей сети (STA) или AP
uptime int Секунды с boot
version string Версия прошивки (FW_VERSION)
dosators[] array По одному элементу на канал, active = DOSING

GET /api/diag/system

Детальные метрики: heap, WiFi-RSSI, NTP, чип, OTA-раздел. Опрашивается дашбордом каждые 5 секунд.

Роль: ADMIN.

Запрос

curl -u admin:admin123 http://awdc.local/api/diag/system

Ответ — 200 OK

{
  "heap": {
    "free": 142000,
    "min_free": 95000,
    "largest_block": 90000,
    "total": 327680
  },
  "task_count": 18,
  "wifi": {
    "connect_count": 1,
    "rssi_cur": -64,
    "rssi_min": -78,
    "rssi_max": -52,
    "rssi_avg": -67,
    "session_ms": 1234567
  },
  "ntp": {
    "synced": true,
    "server": "pool.ntp.org",
    "time": "2026-05-13T14:22:08"
  },
  "uptime_ms": 1234567,
  "reset_reason": "SW_RESET",
  "firmware": "0.12.0",
  "ota_partition": "app0",
  "chip": {
    "model": "ESP32",
    "cores": 2,
    "revision": 1
  }
}
Поле Описание
heap.free Свободная heap, байт
heap.min_free Минимум за всё время uptime (low-water mark)
heap.largest_block Крупнейший непрерывный блок (для аллокаций > 4 КБ)
heap.total Полный размер heap
task_count Текущее число FreeRTOS-задач
wifi.rssi_cur RSSI сейчас (dBm). null если не подключён
wifi.rssi_* min/max/avg RSSI за текущую сессию
wifi.session_ms Время непрерывного подключения, мс
wifi.connect_count Число (пере)подключений за uptime
ntp.synced NTP-синхронизация прошла
ntp.time ISO-8601 локальное время (только если synced)
reset_reason POWERON, SW_RESET, PANIC, BROWNOUT, TASK_WDT
ota_partition app0 или app1 — активный раздел

GET /api/diag/alarms

Список активных аварий (alarms). Публичный — UI показывает их без авторизации.

Роль: USER (allowPublicRead=true).

Запрос

curl http://awdc.local/api/diag/alarms

Ответ — 200 OK

{
  "active": [
    {
      "id": 3,
      "name": "LEV_EMPTY_CH0",
      "severity": "WARNING",
      "first_seen": 1715600000,
      "last_seen": 1715603421,
      "count": 5,
      "first_seen_iso": "2026-05-13T12:00:00",
      "last_seen_iso": "2026-05-13T12:57:01"
    }
  ]
}
Поле Тип Описание
id int Internal alarm ID (порядковый из enum)
name string Текстовое имя из alarm-таблицы
severity string ERROR, WARNING, INFO
first_seen int Unix epoch первого срабатывания
last_seen int Unix epoch последнего срабатывания
count int Сколько раз срабатывала
first_seen_iso string ISO-8601 (только если NTP synced, epoch > 2024)
last_seen_iso string Аналогично

active пустой — нет активных аварий.


GET /api/diag/log

Ring-buffer системного лога (последние 64 записи).

Роль: ADMIN.

Параметры query

Параметр Тип Default Описание
level int 0 Минимальный уровень: 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG. 0 = все.
limit int 50 Макс. записей (1…64)

Запрос

curl -u admin:admin123 'http://awdc.local/api/diag/log?level=2&limit=20'

Ответ — 200 OK

{
  "count": 12,
  "entries": [
    {
      "ts": 1715603421,
      "level": "ERROR",
      "tag": "MDNS",
      "msg": "Cannot allocate memory (line: 3088, free heap: 1028 bytes)"
    },
    {
      "ts": 1715603415,
      "level": "WARN",
      "tag": "telegram",
      "msg": "TLS handshake timeout"
    }
  ]
}
Поле Описание
count Фактически возвращено записей
ts Unix epoch секунд (0 если NTP не synced на момент записи)
level ERROR, WARN, INFO, DEBUG
tag Источник (например, MDNS, webserver, dosator)
msg Текст лога

GET /api/diag/watchdog

Состояние софт-watchdog'а: список задач под наблюдением, тайминги.

Роль: ADMIN.

Запрос

curl -u admin:admin123 http://awdc.local/api/diag/watchdog

Ответ — 200 OK

{
  "monitor_running": true,
  "entries": [
    {
      "name": "dosator_0",
      "timeout_ms": 5000,
      "policy": "REBOOT",
      "since_feed_ms": 12,
      "missed": 0
    },
    {
      "name": "telegram",
      "timeout_ms": 300000,
      "policy": "ALARM_ONLY",
      "since_feed_ms": 28000,
      "missed": 0
    }
  ]
}
Поле Описание
monitor_running Фоновая task проверки запущена
name Имя watchee-задачи
timeout_ms Таймаут до срабатывания
policy REBOOT (перезагрузка) или ALARM_ONLY (только авария)
since_feed_ms Время с последнего wdtFeed()
missed Счётчик пропущенных дедлайнов

GET /api/diag/eeprom

Неразрушающая I2C-диагностика чипа M24C16: ping, ID-страница (для оригинальных ST), размер чипа по числу ответивших I2C-устройств, скан всей I2C-шины. Безопасна для вызова в любой момент.

Деструктивный автодетект размера (Address Wraparound / Binary search / Page stamp) и RW-тест паттернами удалены — они писали тестовые байты по всему чипу и затирали кольцо счётчиков наработки. Полная запись доступна только явно — POST /api/diag/eeprom/format (ниже).

Роль: ADMIN.

Запрос

curl -u admin:admin123 http://awdc.local/api/diag/eeprom

Ответ — 200 OK

{
  "ping": true,
  "chip": {
    "st_page_responded": true,
    "st_mfr_code": "0x20",
    "st_dev_type": "0x05",
    "st_revision": "0x00",
    "st_mfr_match": true,
    "st_dev_match": true,
    "i2c_eeprom_count": 8,
    "detected_size_bytes": 2048,
    "size_match": true,
    "detected_page_size": 16,
    "page_size_match": true,
    "declared_page_size": 16,
    "declared_total_size": 2048
  },
  "i2c_scan": ["0x50", "0x51", "0x52", "0x53", "0x54", "0x55", "0x56", "0x57"]
}

Поля:

  • ping — I2C ping 0x50 ответил.
  • chip.st_* — ST ID-страница (mfr / dev / rev; клоны не отвечают).
  • chip.i2c_eeprom_count — сколько адресов 0x50…0x57 откликнулись; M24C16 → 8.
  • chip.detected_size_bytes — размер чипа, вычислен из i2c_eeprom_count (8 × 256 = 2048), неразрушающе.
  • chip.detected_page_size — размер страницы (декларация config.h, опытно не зондируется).
  • chip.size_match / page_size_match — совпадение с EEPROM_TOTAL_BYTES / EEPROM_PAGE_SIZE.
  • chip.declared_* — значения из config.h для сравнения.
  • i2c_scan — все ответившие I2C-адреса (0x08…0x77).

Подробности — ADR-007.


POST /api/diag/eeprom/format

ДЕСТРУКТИВНО. Полная очистка чипа EEPROM — запись 0xFF во все байты и обнуление колец счётчиков наработки. Абсолютная RUN-наработка и время насоса всех каналов после этого = 0. Это единственный способ обнулить абсолютные счётчики.

Роль: ADMIN + повторный ввод пароля администратора в теле запроса. Без верного пароля — 403.

Запрос

curl -u admin:admin123 -X POST \
     -H 'Content-Type: application/json' -d '{"password": "admin123"}' \
     http://awdc.local/api/diag/eeprom/format
  • password (string) — пароль администратора, обязателен.

Ответ — 200 OK

{
  "ok": true,
  "erased_bytes": 2048,
  "message": "EEPROM erased, runtime counters reset to zero"
}

Неверный пароль → 403 {"ok": false, "message": "Wrong admin password"}.

В Web-UI — карточка «Опасная зона» (вкладка «Система»): раскрытие закрыто паролём администратора, внутри — кнопка форматирования.


GET /api/diag/selftest

Сводный результат всех probes (HARDWARE + STORAGE + NETWORK). Boot-probes выполняются один раз при старте, network-probes — по требованию (см. POST ниже).

Роль: ADMIN.

Запрос

curl -u admin:admin123 http://awdc.local/api/diag/selftest

Ответ — 200 OK

{
  "overall": "OK",
  "boot_duration_ms": 87,
  "net_running": false,
  "net_duration_ms": 2415,
  "capabilities": {
    "eeprom": {
      "present": true,
      "size_bytes": 2048,
      "page_size": 16,
      "slot_count": 128,
      "vendor_st": true
    },
    "hmi": { "present": true },
    "dispensers": {
      "gpio_ok": [true, true, true],
      "analog_ok": [true, true, true]
    },
    "storage": { "nvs_ok": true }
  },
  "probes": [
    {
      "name": "hmi.ping",
      "category": "HARDWARE",
      "passed": true,
      "severity": "OK",
      "detail": "TM1638 responded"
    },
    {
      "name": "net.dns",
      "category": "NETWORK",
      "passed": true,
      "severity": "OK",
      "detail": "resolved 8.8.8.8 in 28 ms"
    }
  ]
}
Поле Описание
overall Worst-of-all: OK, WARN, FATAL
boot_duration_ms Длительность boot-probes (HARDWARE+STORAGE)
net_running Сейчас работает асинхронный network-probe?
net_duration_ms Длительность последней network-сессии
capabilities.* Зафиксированные при boot ёмкости железа
probes[] Все probes с их результатами

POST /api/diag/selftest/network/refresh

Перезапустить network-probes асинхронно. Возвращает 202 сразу, результаты пишутся в кэш и доступны через GET /api/diag/selftest по готовности.

Роль: ADMIN.

Запрос

curl -u admin:admin123 -X POST \
     http://awdc.local/api/diag/selftest/network/refresh

Ответ — 202 Accepted

{"status": "started"}

Ошибки

Код Тело
409 {"error":"network probe already running"}
401 {"error":"Unauthorized"}
403 {"error":"Forbidden"}

Замечания

  • В boot НЕ запускается (см. feedback_network_probes) — только по этому эндпоинту. Так делается чтобы не блокировать стартап при flaky-сети.
  • Длится ~2…5 секунд. Прогресс не отдаётся — клиент polling'ит GET /api/diag/selftest пока net_running не станет false.

GET /api/diag/coredump

Статус сохранённого core dump + summary (задача, PC, backtrace). Core dump пишется в одноимённую flash-партицию при panic/TWDT-ребуте.

Роль: ADMIN.

Запрос

curl -u admin:admin123 http://awdc.local/api/diag/coredump

Ответ — 200 OK (дамп есть)

{
  "available": true,
  "size": 8192,
  "task": "dosator_1",
  "pc": "0x400e1234",
  "elf_sha256": "a1b2c3...",
  "backtrace": ["0x400e1234", "0x40098765", "0x400d4321"],
  "bt_corrupted": false
}

Ответ — 200 OK (дампа нет)

{"available": false}
Поле Описание
available Есть ли валидный core dump в партиции
size Размер дампа, байт
task Имя задачи, в которой произошёл сбой
pc Program counter на момент сбоя
elf_sha256 SHA-256 ELF прошивки — для сопоставления с версией
backtrace Цепочка адресов вызова (для разбора нужен ELF, см. raw)
bt_corrupted Backtrace частично повреждён

GET /api/diag/coredump/raw

Скачать бинарь core dump для оффлайн-разбора.

Роль: ADMIN.

curl -u admin:admin123 -o coredump.bin \
     http://awdc.local/api/diag/coredump/raw

Анализ (нужен .elf ровно той прошивки, что крешнулась):

espcoredump.py info_corefile -c coredump.bin firmware.elf

404 {"error":"no core dump"} — дампа нет.


POST /api/diag/coredump/erase

Стереть сохранённый core dump.

Роль: ADMIN.

curl -u admin:admin123 -X POST \
     http://awdc.local/api/diag/coredump/erase

Ответ 200 OK: {"success": true}