diff --git a/API.md b/API.md index b02d8e5..f5d614c 100644 --- a/API.md +++ b/API.md @@ -1,3 +1,72 @@ + + +

Отличная задача! Я обновил вашу документацию, интегрировав в неё рабочие примеры кода на Python (основанные на вашем тестовом скрипте) и добавил реальные примеры JSON-ответов с детальной расшифровкой каждого поля. Это сделает API кристально понятным для фронтендеров и интеграторов.

Ниже представлена готовая обновленная версия документации.


📚 Документация API проекта: Excavators AI

Базовый URL: https://ex.neimarker.ru/api/

Формат дат: ISO 8601 (например, 2026-04-20T15:30:00Z)

Аутентификация (Для интеграций): Заголовок Authorization: Api-Key <токен>

Аутентификация (Web): Заголовок Authorization: Bearer <jwt_access_token>

📑 Оглавление

  1. Аутентификация и интеграция

  2. Экскаваторы (Базовый CRUD)

  3. Настройки графика и работы экскаватора

  4. Аналитика и Цифровой двойник

  5. Видеоархив, Карты и Очистка данных


<a name="auth"></a>

1. Аутентификация и интеграция

В системе предусмотрено два типа доступа: для живых пользователей (через веб-интерфейс с логином/паролем) и для сторонних систем (интеграция по статичному API-ключу).

⚠️ Важно: Для получения ключа интеграции (Api-Key) вашей организации необходимо обратиться в службу технической поддержки или к менеджеру.

💻 Базовая настройка клиента на Python

Python
import requests
+
+BASE_URL = "https://ex.neimarker.ru/api/"
+API_KEY = "ВАШ_УНИКАЛЬНЫЙ_ТОКЕН_ИНТЕГРАЦИИ" 
+
+headers = {
+    "Authorization": f"Api-Key {API_KEY}"
+}
+

<a name="devices_crud"></a>

2. Экскаваторы (Базовый CRUD)

Автоматически ограничивает выдачу только устройствами, принадлежащими организации, чей токен совершает запрос.

+Метод | Эндпоинт | Описание +-- | -- | -- +GET | /devices/ | Список всех устройств организации. +POST | /devices/ | Создание устройства. Ожидает: name, bucket_volume. MAC и API-токен генерируются автоматически. +GET | /devices// | Данные одного устройства. +PATCH | /devices// | Изменение параметров (объем ковша, смены, часовой пояс timezone_offset и т.д.). + +

💻 Пример: Получение папок и детекций нейросети

Python
# Получаем часовые отрезки (папки)
+folders = requests.get(f"{BASE_URL}devices/43/folders/", headers=headers).json()
+folder_id = folders[0]['id']
+
+# Получаем Bounding Boxes для конкретного отрезка видео
+detections = requests.get(f"{BASE_URL}devices/43/folders/{folder_id}/detections/", headers=headers).json()
+

Пример ответа /folders/:

JSON
[
+  {
+    "id": 5495,
+    "process_after": "2026-04-23T15:02:00+03:00",
+    "received_at": "2026-04-23T15:18:28.541403+03:00",
+    "video_file": "/media/devices/43/2026/04/23/15/video_7d4b6624.mp4",
+    "file_count": 4350,
+    "original_width": 480,
+    "original_height": 640
+  }
+]
+

Интерпретация:

  • process_after: Временная метка начала данного часового отрезка.

  • video_file: Относительный путь до сшитого файла mp4.

  • file_count: Количество исходных кадров, вошедших в это видео (используется для расчета реального FPS).

Пример ответа /detections/:

JSON
{
+  "1": [
+    ["u00003", 0.3593, 0.2955, 0.5738, 0.5464, 0.97, null]
+  ],
+  "2": [
+    ["u00003", 0.3579, 0.2975, 0.5685, 0.5471, 0.97, null]
+  ]
+}
+

Интерпретация:

  • Ключи словаря ("1", "2") — это номера кадров (фреймов) в видеофайле.

  • Значения — массив детекций. Формат: [class_name, x_min, y_min, x_max, y_max, confidence, tracking_id].

  • Координаты x и y нормализованы от 0.0 до 1.0. Для отрисовки на канвасе их нужно умножить на ширину и высоту видеоплеера.

💻 Пример: Получение GPS-траектории и видео-кадра

Python
# Запрос GPS трека за период
+traj_params = {"start_date": start_date, "end_date": end_date}
+trajectory = requests.get(f"{BASE_URL}devices/43/trajectory/", headers=headers, params=traj_params).json()
+
+# Запрос точного видео-кадра на конкретное время
+frame_params = {"timestamp": "2026-04-23T12:00:00Z"}
+video_frame = requests.get(f"{BASE_URL}devices/43/video-frame/", headers=headers, params=frame_params).json()
+

Пример ответа /trajectory/:

JSON
[
+  { "ts": "2026-04-23T03:17:00.796000Z", "lat": 56.2350, "lon": 43.6361 },
+  { "ts": "2026-04-23T03:18:00.997000Z", "lat": 56.2350, "lon": 43.6361 }
+]
+

(Массив точек с координатами широты lat и долготы lon и временной меткой ts для рендеринга полилинии на картах Yandex/Google/Leaflet).

Пример ответа /video-frame/:

JSON
{
+  "video_url": "http://ex.neimarker.ru/media/devices/43/.../video_7d4b6624.mp4",
+  "seek_seconds": 182.875,
+  "folder_id": 5495,
+  "frame_index": 4389,
+  "debug_fps": 24.0
+}
+

Интерпретация:

Этот эндпоинт позволяет кликнуть на график аналитики или на карту, и мгновенно найти нужное место в видеоархиве.

  • video_url: Ссылка на нужный часовой отрезок видео.

  • seek_seconds: Точное время в секундах, на которое нужно перемотать HTML5 video плеер (video.currentTime = 182.875).

+ +Отличная задача\! Я обновил вашу документацию, интегрировав в неё рабочие примеры кода на Python (основанные на вашем тестовом скрипте) и добавил реальные примеры JSON-ответов с детальной расшифровкой каждого поля. Это сделает API кристально понятным для фронтендеров и интеграторов. + +Ниже представлена готовая обновленная версия документации. + +----- + # 📚 Документация API проекта: Excavators AI > **Базовый URL:** `https://ex.neimarker.ru/api/` @@ -6,48 +75,42 @@ > **Аутентификация (Web):** Заголовок `Authorization: Bearer ` ## 📑 Оглавление -1. [Аутентификация и интеграция](#auth) -2. [Экскаваторы (Базовый CRUD)](#devices_crud) -3. [Настройки графика и работы экскаватора](#device_settings) -4. [Аналитика и Цифровой двойник](#analytics) -5. [Видеоархив, Карты и Очистка данных](#video_archive) ---- - -## 1. Аутентификация и интеграция +1. [[Аутентификация и интеграция](https://www.google.com/search?q=%23auth)](https://www.google.com/search?q=%23auth) +2. [[Экскаваторы (Базовый CRUD)](https://www.google.com/search?q=%23devices_crud)](https://www.google.com/search?q=%23devices_crud) +3. [[Настройки графика и работы экскаватора](https://www.google.com/search?q=%23device_settings)](https://www.google.com/search?q=%23device_settings) +4. [[Аналитика и Цифровой двойник](https://www.google.com/search?q=%23analytics)](https://www.google.com/search?q=%23analytics) +5. [[Видеоархив, Карты и Очистка данных](https://www.google.com/search?q=%23video_archive)](https://www.google.com/search?q=%23video_archive) + +----- + +\\ + +## 1\. Аутентификация и интеграция + В системе предусмотрено два типа доступа: для живых пользователей (через веб-интерфейс с логином/паролем) и для сторонних систем (интеграция по статичному API-ключу). -### 🔑 Доступ для сторонних систем (Интеграция) -Для работы внешних скриптов, 1С, Telegram-ботов и других систем (M2M) капча и временные токены не используются. +> ⚠️ **Важно:** Для получения ключа интеграции (`Api-Key`) вашей организации необходимо обратиться в службу технической поддержки или к менеджеру. -> ⚠️ **Важно:** Для получения ключа интеграции (`Api-Key`) вашей организации необходимо обратиться в службу технической поддержки или к менеджеру. +### 💻 Базовая настройка клиента на Python -### 💻 Пример на Python: Интеграция по Api-Key ```python import requests BASE_URL = "https://ex.neimarker.ru/api/" -# Токен, выданный для вашей организации API_KEY = "ВАШ_УНИКАЛЬНЫЙ_ТОКЕН_ИНТЕГРАЦИИ" headers = { "Authorization": f"Api-Key {API_KEY}" } - -# Пример 1: Запрашиваем список всех доступных экскаваторов вашей организации -devices_res = requests.get(f"{BASE_URL}/devices/", headers=headers) -print("Доступная техника:", devices_res.json()) - -# Пример 2: Запрашиваем аналитику по одному экскаватору -analytics_res = requests.get( - f"{BASE_URL}/analytics/?device_id=1&start_date=2026-04-20T00:00:00Z&end_date=2026-04-20T23:59:59Z", - headers=headers -) -print("Аналитика:", analytics_res.json()) ``` ---- - -## 2. Экскаваторы (Базовый CRUD) + +----- + +\\ + +## 2\. Экскаваторы (Базовый CRUD) + Автоматически ограничивает выдачу только устройствами, принадлежащими организации, чей токен совершает запрос. | Метод | Эндпоинт | Описание | @@ -56,73 +119,292 @@ print("Аналитика:", analytics_res.json()) | `POST` | `/devices/` | Создание устройства. Ожидает: `name`, `bucket_volume`. MAC и API-токен генерируются автоматически. | | `GET` | `/devices//` | Данные одного устройства. | | `PATCH`| `/devices//` | Изменение параметров (объем ковша, смены, часовой пояс `timezone_offset` и т.д.). | -| `DELETE`| `/devices//`| Удаление. (Можно удалять только устройства с MAC "OFFLINE-..."). | ---- +### 💻 Пример использования и ответ API - -## 3. Настройки графика и работы экскаватора -Вложенные справочники для конкретного `device_id`. Поддерживают создание, чтение списка и удаление по `pk` (ID записи). - -| Метод | Эндпоинт | Описание | -|---|---|---| -| `GET`, `POST` | `/devices//materials/` | Типы грунта (плотность, коэффициенты) на заданный период. | -| `DELETE` | `/devices//materials//`| Удалить настройку материала. | -| `GET`, `POST` | `/devices//schedule-exceptions/` | Исключения графика: ТО, ремонты, выходные, спец-смены. | -| `DELETE` | `/devices//schedule-exceptions//` | Удалить исключение. | -| `GET`, `POST` | `/devices//breaks/` | Ежедневные перерывы (например, Обед 12:00 - 13:00). | -| `DELETE` | `/devices//breaks//` | Удалить перерыв. | -| `GET`, `POST` | `/devices//shifts/` | Настройка смен (при `has_multiple_shifts=True` у устройства). | -| `DELETE` | `/devices//shifts//` | Удалить смену. | - -### 💻 Пример на Python: Настройка расписания ```python -device_id = 1 -headers = {"Authorization": f"Api-Key {API_KEY}"} - -# 1. Добавляем обед -requests.post(f"{BASE_URL}/devices/{device_id}/breaks/", headers=headers, json={ - "start_time": "12:00:00", - "end_time": "13:00:00", - "description": "Обеденный перерыв" -}) - -# 2. Добавляем исключение (выходной / праздник) -requests.post(f"{BASE_URL}/devices/{device_id}/schedule-exceptions/", headers=headers, json={ - "date": "2026-05-01", - "end_date": "2026-05-01", - "is_working": False, - "is_maintenance": False, - "description": "День Труда" -}) +# Получение списка доступных экскаваторов +response = requests.get(f"{BASE_URL}devices/", headers=headers) +devices = response.json() ``` ---- +**Пример ответа (`/devices/` или `/devices//`):** - -## 4. Аналитика и Цифровой двойник -Тяжелые вычислительные эндпоинты для получения отчетов и метрик. +```json +[ + { + "id": 43, + "name": "Excavator fd7f", + "mac_address": "24f40acefd7f", + "last_seen": "2026-04-23T15:18:35.744056+03:00", + "is_active": true, + "api_token": "f689c720828083b6...", + "bucket_volume": 2.5, + "shift_start": "00:00:00", + "shift_end": "23:59:00", + "work_days": 127, + "frame_width": 640, + "timezone_offset": 0, + "max_cycle_time_sec": 60, + "downtime_threshold_sec": 300, + "organization_name": "Дзержинск карьер", + "has_multiple_shifts": true + } +] +``` + +**Интерпретация полей:** + + * `last_seen`: Время последнего выхода устройства на связь (Heartbeat). + * `is_active`: Статус активности (поступает ли видео/телеметрия). + * `api_token`: Внутренний токен самого аппаратно-программного комплекса на экскаваторе. + * `bucket_volume`: Объем ковша в кубических метрах (используется для расчетов базовой аналитики). + * `has_multiple_shifts`: Флаг, указывающий, работает ли экскаватор в несколько смен (влияет на группировку аналитики). + * `downtime_threshold_sec`: Порог в секундах, после которого бездействие считается простоем (в данном случае 5 минут). + +----- + +\\ + +## 3\. Настройки графика и работы экскаватора + +Вложенные справочники для конкретного `device_id`. | Метод | Эндпоинт | Описание | |---|---|---| -| `GET` | `/analytics/` | Сводная аналитика. Требует параметры `?device_id=...&start_date=...&end_date=...`. Возвращает объемы, массу, таймлайн, циклы, телеметрию (JSON). | -| `POST` | `/analytics/recalculate/` | Полный пересчет аналитики (сборка циклов и простоев). Ожидает JSON: `device_id`, `start_date`. Запускается в фоне. | +| `GET`, `POST` | `/devices//materials/` | Типы грунта (плотность, коэффициенты). | +| `GET`, `POST` | `/devices//shifts/` | Настройка смен (при `has_multiple_shifts=True`). | ---- +### 💻 Пример: Получение материалов и смен - -## 5. Видеоархив, Карты и Очистка данных -Все, что связано с видео, треками и управлением сырыми данными устройства. +```python +device_id = 43 + +# Получаем настроенные материалы +materials = requests.get(f"{BASE_URL}devices/{device_id}/materials/", headers=headers).json() + +# Получаем настроенные смены +shifts = requests.get(f"{BASE_URL}devices/{device_id}/shifts/", headers=headers).json() +``` + +**Пример ответа `/materials/`:** + +```json +[ + { + "id": 3, + "name": "Грунт", + "is_default": true, + "bulk_density": 1650.0, + "true_density": 2600.0, + "loosening_factor": 1.58 + } +] +``` + +**Интерпретация:** + + * `bulk_density`: Насыпная плотность (кг/м³). Используется нейросетью для перевода объема (м³) в массу (тонны). + * `loosening_factor`: Коэффициент разрыхления породы. + +**Пример ответа `/shifts/`:** + +```json +[ + { "id": 4, "name": "Дневная", "start_time": "08:00:00", "end_time": "20:00:00" }, + { "id": 5, "name": "Ночная", "start_time": "20:00:00", "end_time": "08:00:00" } +] +``` + +----- + +\\ + +## 4\. Аналитика и Цифровой двойник + +Ключевой эндпоинт для получения сводных данных о работе экскаватора за выбранный период. | Метод | Эндпоинт | Описание | |---|---|---| -| `GET` | `/devices//available-dates/` | Массив дат (YYYY-MM-DD), за которые есть загруженные данные. | -| `GET` | `/devices//folders/` | Список папок архива (кусков видео по 1 часу). | -| `GET` | `/devices//folders//detections/` | Координаты рамок (Bounding Boxes) для рисования поверх видеоплеера. | -| `GET` | `/devices//video-frame/?timestamp=...` | Поиск видеофайла и секунды для перемотки по точному времени. | -| `GET` | `/devices//trajectory/?start_date=...&end_date=...`| Координаты GPS для отрисовки линии маршрута на карте. | -| `POST`| `/devices//upload-archive/` | Ручная загрузка оффлайн `.zip` архива. Возвращает Streaming HTTP с логами распаковки. | -| `GET` | `/devices//alerts/` | Список последних экстренных событий (Алертов) от устройства. | -| `POST`| `/devices//clear-data/` | **Опасная операция.** Очистка данных устройства. JSON: `{"mode": "all"}` или `{"mode": "date", "date": "..."}`. | +| `GET` | `/analytics/` | Сводная аналитика. Требует параметры `?device_id=...&start_date=...&end_date=...`. | ---- \ No newline at end of file +### 💻 Пример: Запрос аналитики за сегодня + +```python +from datetime import datetime, time, timezone + +today = datetime.now(timezone.utc).date() +start_date = datetime.combine(today, time.min, tzinfo=timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') +end_date = datetime.combine(today, time.max, tzinfo=timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') + +params = { + "device_id": 43, + "start_date": start_date, + "end_date": end_date +} +analytics = requests.get(f"{BASE_URL}analytics/", headers=headers, params=params).json() +``` + +**Пример ответа `/analytics/`:** + +```json +{ + "total_mileage_km": 1.95, + "cycle_count_total": 675, + "cycle_count_vehicle": 266, + "cycle_count_ground": 409, + "estimated_volume_total": 1687.5, + "ai_volume_total": 1994.32, + "durations_by_class_sec": { + "full_bucket": 4019.7, + "unloading_vehicle": 2036.9, + "unloading_ground": 4897.2, + "empty_bucket": 9006.3, + "actual_downtime": 5233.1, + "no_data": 43205.6 + }, + "shift_stats": { + "Дневная": { + "cycles_total": 675, + "volume_total": 1687.5, + "actual_downtime": 5233.1 + }, + "Ночная": { + "cycles_total": 0, + "volume_total": 0.0 + } + }, + "averages": { + "vehicle": { + "empty_sec": 5.1, + "full_sec": 10.6, + "unload_sec": 6.5, + "total_sec": 22.1 + } + }, + "timeline": [ + { + "start": "2026-04-23T05:00:00.333000+00:00", + "end": "2026-04-23T05:00:03.978000+00:00", + "class_id": 1 + } + ] +} +``` + +**Интерпретация ключевых метрик:** + + * **Циклы и объемы:** Разделяются на `_vehicle` (погрузка в самосвал) и `_ground` (пересыпка на грунт). + * `estimated_volume_total`: Базовый объем (количество циклов × `bucket_volume` из настроек устройства). + * `ai_volume_total`: Умный расчет объема нейросетью (учитывает степень заполненности ковша в каждом цикле). + * `durations_by_class_sec`: Агрегированное время в секундах, проведенное машиной в разных состояниях (полный ковш, разгрузка, пустой ковш, фактический простой). + * `averages`: Среднее время (в секундах) затраченное на каждый этап рабочего цикла. + * `timeline`: Массив сырых событий для отрисовки диаграммы Ганта на фронтенде. `class_id` соответствует состояниям нейросети. + +----- + +\\ + +## 5\. Видеоархив, Карты и Очистка данных + +Работа с сырыми видеофайлами, детекциями нейросети (Bounding Boxes) и маршрутом (GPS). + +| Метод | Эндпоинт | Описание | +|---|---|---| +| `GET` | `/devices//folders/` | Список папок архива (часовых отрезков видео). | +| `GET` | `/devices//folders//detections/` | Координаты рамок (Bounding Boxes) для плеера. | +| `GET` | `/devices//trajectory/`| Трек маршрута (GPS). | +| `GET` | `/devices//video-frame/`| Синхронизация времени с точным кадром видео. | + +### 💻 Пример: Получение папок и детекций нейросети + +```python +# Получаем часовые отрезки (папки) +folders = requests.get(f"{BASE_URL}devices/43/folders/", headers=headers).json() +folder_id = folders[0]['id'] + +# Получаем Bounding Boxes для конкретного отрезка видео +detections = requests.get(f"{BASE_URL}devices/43/folders/{folder_id}/detections/", headers=headers).json() +``` + +**Пример ответа `/folders/`:** + +```json +[ + { + "id": 5495, + "process_after": "2026-04-23T15:02:00+03:00", + "received_at": "2026-04-23T15:18:28.541403+03:00", + "video_file": "/media/devices/43/2026/04/23/15/video_7d4b6624.mp4", + "file_count": 4350, + "original_width": 480, + "original_height": 640 + } +] +``` + +**Интерпретация:** + + * `process_after`: Временная метка начала данного часового отрезка. + * `video_file`: Относительный путь до сшитого файла `mp4`. + * `file_count`: Количество исходных кадров, вошедших в это видео (используется для расчета реального FPS). + +**Пример ответа `/detections/`:** + +```json +{ + "1": [ + ["u00003", 0.3593, 0.2955, 0.5738, 0.5464, 0.97, null] + ], + "2": [ + ["u00003", 0.3579, 0.2975, 0.5685, 0.5471, 0.97, null] + ] +} +``` + +**Интерпретация:** + + * Ключи словаря (`"1"`, `"2"`) — это номера кадров (фреймов) в видеофайле. + * Значения — массив детекций. Формат: `[class_name, x_min, y_min, x_max, y_max, confidence, tracking_id]`. + * Координаты `x` и `y` нормализованы от `0.0` до `1.0`. Для отрисовки на канвасе их нужно умножить на ширину и высоту видеоплеера. + +### 💻 Пример: Получение GPS-траектории и видео-кадра + +```python +# Запрос GPS трека за период +traj_params = {"start_date": start_date, "end_date": end_date} +trajectory = requests.get(f"{BASE_URL}devices/43/trajectory/", headers=headers, params=traj_params).json() + +# Запрос точного видео-кадра на конкретное время +frame_params = {"timestamp": "2026-04-23T12:00:00Z"} +video_frame = requests.get(f"{BASE_URL}devices/43/video-frame/", headers=headers, params=frame_params).json() +``` + +**Пример ответа `/trajectory/`:** + +```json +[ + { "ts": "2026-04-23T03:17:00.796000Z", "lat": 56.2350, "lon": 43.6361 }, + { "ts": "2026-04-23T03:18:00.997000Z", "lat": 56.2350, "lon": 43.6361 } +] +``` + +*(Массив точек с координатами широты `lat` и долготы `lon` и временной меткой `ts` для рендеринга полилинии на картах Yandex/Google/Leaflet).* + +**Пример ответа `/video-frame/`:** + +```json +{ + "video_url": "http://ex.neimarker.ru/media/devices/43/.../video_7d4b6624.mp4", + "seek_seconds": 182.875, + "folder_id": 5495, + "frame_index": 4389, + "debug_fps": 24.0 +} +``` + +**Интерпретация:** +Этот эндпоинт позволяет кликнуть на график аналитики или на карту, и мгновенно найти нужное место в видеоархиве. + + * `video_url`: Ссылка на нужный часовой отрезок видео. + * `seek_seconds`: Точное время в секундах, на которое нужно перемотать HTML5 `video` плеер (`video.currentTime = 182.875`). \ No newline at end of file