Files
Button/docs/rest-api.md
T
2026-11-02 16:46:20 +03:00

310 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# REST API ButtonTask `/api/v1`
Базовый адрес — тот же, что у веб-конфигуратора (по умолчанию порт 8080). Отдельного процесса нет.
Чтение открыто. Запись требует заголовок `X-Api-Key`. Ключ лежит в `settings.apiKey`, создаётся сам при первом запуске и показывается на вкладке «Безопасность» конфигуратора. Запроса «отдать ключ» в этом API нет: его увидел бы любой в сети. Неверный или пустой ключ — HTTP 401:
```json
{ "ok": false, "error": "unauthorized" }
```
Тело ошибок всегда `{"ok": false, "error": "<код>"}`.
Калибровка в файле хранится как `min` / `max`. В API это `empty_mm` (0%) и `full_mm` (100%). Уровень: `(raw_mm - empty_mm) / (full_mm - empty_mm) * 100`, зажим 0…100, один знак после запятой. Нет границ или они равны — `level_pct` равен `null`.
Байт питания — десятые вольта. `voltage_mv = байт * 100`. Байт `255` — нет данных, тогда `voltage_mv` и `charge_pct` равны `null`. `charge_pct` — оценка остатка двух дешёвых AA по кривой разряда.
`stale_timeout_s` только для чтения: `report_interval_min * 60 * 3`. Для 30 минут это 5400.
## GET /api/v1/health
Авторизация не требуется.
Сводка коллектора, его аптайм, метрики хоста и счётчики датчиков. `ok` и `status: "healthy"` — файл статуса коллектора свежий (не старше 15 секунд). Иначе `status: "degraded"`, HTTP всё равно 200.
```json
{
"ok": true,
"status": "healthy",
"uptime_s": 86400.1,
"version": "1.2.3",
"ts": 1730000000.0,
"collector": {
"available": true,
"sensors_live": 2,
"sensors_stale": 1,
"sensors_total": 3
},
"system": {
"cpu_percent": 12.5,
"memory_used_percent": 41.0,
"load_1m": 0.42
}
}
```
`uptime_s` — секунды с старта процесса коллектора. Если метки старта нет, поле `null`.
## GET /api/v1/sensors
Авторизация не требуется.
Интервал отчёта, таймаут устаревания и карточки известных датчиков. Пустых слотов нет.
```json
{
"report_interval_min": 30,
"stale_timeout_s": 5400,
"sensors": [
{
"mac": "AA:BB:CC:DD:EE:FF",
"name": "Резервуар_1",
"raw_mm": 420,
"level_pct": 63.5,
"voltage_mv": 2800,
"charge_pct": 72,
"age_s": 42,
"state": "live",
"rssi": -67,
"last_seen": 1730000000.0
}
]
}
```
`raw_mm` равен `null`, если датчик не видит цель. `state` — `live` или `stale`.
## GET /api/v1/sensors/{mac}
Авторизация не требуется.
Карточка одного датчика, тот же объект, что элемент `sensors` выше. Неизвестный адрес или кривой MAC — HTTP 404 `sensor_not_found`.
## GET /api/v1/sensors/{mac}/history
Авторизация не требуется.
Параметры:
- `limit` — от 1 до 1000, по умолчанию 100. Иначе HTTP 400 `invalid_limit`.
- `since` — необязательный Unix timestamp, остаются точки с `ts >= since`. Нечисло — HTTP 400 `invalid_since`.
Кольцо на диске `run/sensors-history.json`, не больше 1000 точек на датчик. Ответ от новых к старым. Проценты считаются по текущей калибровке, а не по той, что была в момент замера.
Неизвестный датчик — HTTP 404 `sensor_not_found`. Известный датчик без точек — пустой `entries`.
```json
{
"mac": "AA:BB:CC:DD:EE:FF",
"entries": [
{
"ts": 1730000000.0,
"raw_mm": 420,
"level_pct": 63.5,
"voltage_mv": 2800,
"charge_pct": 72,
"rssi": -67
}
]
}
```
## PUT /api/v1/sensors/{mac}/name
Заголовок `X-Api-Key` обязателен.
```json
{ "name": "Резервуар_1" }
```
Пустая строка сбрасывает имя. `name` не строка — HTTP 400 `invalid_name`. Кривой MAC — HTTP 400 `invalid_mac`.
```json
{ "ok": true, "mac": "AA:BB:CC:DD:EE:FF", "name": "Резервуар_1" }
```
## GET /api/v1/settings
Авторизация не требуется.
```json
{
"report_interval_min": 30,
"stale_timeout_s": 5400
}
```
## PUT /api/v1/settings
Заголовок `X-Api-Key` обязателен.
Принимается только `report_interval_min`, целое от 1 до 65535. Иначе HTTP 400 `invalid_interval`. `stale_timeout_s` записать нельзя.
Ответ — та же пара полей, что у GET.
## GET /api/v1/sensors/{mac}/calibration
Авторизация не требуется.
```json
{ "empty_mm": 1200, "full_mm": 200 }
```
Границ ещё нет — оба поля `null`. Кривой MAC — HTTP 404 `sensor_not_found`.
## PUT /api/v1/sensors/{mac}/calibration
Заголовок `X-Api-Key` обязателен.
```json
{ "empty_mm": 1200, "full_mm": 200 }
```
Оба значения — целые миллиметры от 0 до 65535 и не равны друг другу. Иначе HTTP 400 `invalid_calibration`. Кривой MAC — HTTP 400 `invalid_mac`.
`empty_mm` — показание 0%, `full_mm` — показание 100%. Ответ повторяет записанные границы.
## GET /api/v1/buttons
Авторизация не требуется.
Только идентификатор и подпись. URL и остальные поля кнопки не отдаются.
```json
[
{ "id": "example-1", "label": "Пример" }
]
```
## GET /api/v1/buttons/{id}
Заголовок `X-Api-Key` обязателен.
Полная карточка кнопки: подпись, иконка, действие, тексты ответа, удержание и цвет. Неизвестный id — HTTP 404 `button_not_found`.
```json
{
"id": "example-1",
"label": "Пример",
"iconPath": "cleaner1.png",
"action": {
"type": "http_get",
"url": "http://localhost/btn?bid=01",
"headers": {},
"body": ""
},
"feedback": {
"successText": "Отправлено",
"errorText": "Ошибка",
"pendingText": "...",
"fadeMs": 5000
},
"trigger": { "mode": "hold", "holdMs": 800 },
"color": "#7b007b"
}
```
## POST /api/v1/buttons
Заголовок `X-Api-Key` обязателен.
Создаёт кнопку. Идентификатор назначается сам. Поля те же, что при правке, плюс плоские имена действия: `actionType` (`http_get` или `http_post`), `url`, `headers`, `body`, `timeoutMs` (1000…600000), `successText`, `errorText`, `pendingText`, `fadeMs`, `triggerMode` (`click` или `hold`), `holdMs`, `color`, `iconPath`, `latchReset`, `responseCheck`. Некорректное тело — HTTP 400 `invalid_button` и поле `message` с причиной. Ответ HTTP 201 — созданная карточка.
```json
{
"label": "Пример",
"actionType": "http_get",
"url": "http://localhost/btn?bid=01",
"triggerMode": "hold",
"holdMs": 800,
"color": "#7b007b"
}
```
## PUT /api/v1/buttons/{id}
Заголовок `X-Api-Key` обязателен.
Меняет только переданные поля. Имена полей те же, что у создания. Неизвестный id — HTTP 404 `button_not_found`. Некорректное поле — HTTP 400 `invalid_button`. Ответ — карточка после записи. Экран подхватывает конфиг сам.
## DELETE /api/v1/buttons/{id}
Заголовок `X-Api-Key` обязателен.
Удаляет кнопку. Неизвестный id — HTTP 404 `button_not_found`.
```json
{ "ok": true }
```
## POST /api/v1/buttons/reorder
Заголовок `X-Api-Key` обязателен.
Порядок кнопок на экране. В `order` — идентификаторы спереди назад. Пропущенные остаются в конце в прежнем порядке. `order` не массив строк — HTTP 400 `invalid_order`.
```json
{ "order": ["example-1", "cbd6791cdcb74a58861554b30239c65e"] }
```
Ответ:
```json
{ "ok": true, "order": ["example-1", "cbd6791cdcb74a58861554b30239c65e"] }
```
## GET /api/v1/background
Авторизация не требуется.
```json
{
"type": "gradient",
"color1": "#00007b",
"color2": "#7b007b",
"animated": true,
"imagePath": ""
}
```
`type`: `gradient`, `solid` или `image`.
## PUT /api/v1/background
Заголовок `X-Api-Key` обязателен.
Меняет только переданные поля. Цвет — `#rrggbb`. `animated` — логическое. Иначе HTTP 400 `invalid_background`. Ответ — фон после записи.
```json
{
"type": "gradient",
"color1": "#00007b",
"color2": "#7b007b",
"animated": true
}
```
## POST /api/v1/buttons/{id}/press
Заголовок `X-Api-Key` обязателен.
То же действие, что нажатие на экране, включая защёлку. Тело не нужно.
Ответ HTTP 202 значит, что команда принята экраном, а не что внешний HTTP-запрос кнопки уже завершился:
```json
{ "ok": true, "id": "example-1" }
```
Неизвестный id — HTTP 404 `button_not_found`. Повторная команда, пока экран не забрал предыдущую, заменяет её.
## POST /api/v1/system/reboot
Заголовок `X-Api-Key` обязателен.
Перезагрузка устройства тем же путём, что кнопка в конфигураторе. Ответ уходит до того, как машина погаснет.
```json
{ "ok": true }
```