Clone
5
API
Andreev0597 edited this page 2026-04-23 16:18:44 +03:00
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.

📚 Документация 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. Видеоархив, Карты и Очистка данных
  6. Подробные примеры использования API (с ответами и их интерпретацией)

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

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

🔑 Доступ для сторонних систем (Интеграция)

Для работы внешних скриптов, 1С, Telegram-ботов и других систем (M2M) капча и временные токены не используются.

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

💻 Пример на Python: Интеграция по Api-Key

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)

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

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

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

Вложенные справочники для конкретного device_id. Поддерживают создание, чтение списка и удаление по pk (ID записи).

Метод Эндпоинт Описание
GET, POST /devices/<device_id>/materials/ Типы грунта (плотность, коэффициенты) на заданный период.
DELETE /devices/<device_id>/materials/<pk>/ Удалить настройку материала.
GET, POST /devices/<device_id>/schedule-exceptions/ Исключения графика: ТО, ремонты, выходные, спец-смены.
DELETE /devices/<device_id>/schedule-exceptions/<pk>/ Удалить исключение.
GET, POST /devices/<device_id>/breaks/ Ежедневные перерывы (например, Обед 12:00 - 13:00).
DELETE /devices/<device_id>/breaks/<pk>/ Удалить перерыв.
GET, POST /devices/<device_id>/shifts/ Настройка смен (при has_multiple_shifts=True у устройства).
DELETE /devices/<device_id>/shifts/<pk>/ Удалить смену.

💻 Пример на 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": "День Труда"
})

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

Тяжелые вычислительные эндпоинты для получения отчетов и метрик.

Метод Эндпоинт Описание
GET /analytics/ Сводная аналитика. Требует параметры ?device_id=...&start_date=...&end_date=.... Возвращает объемы, массу, таймлайн, циклы, телеметрию (JSON).
POST /analytics/recalculate/ Полный пересчет аналитики (сборка циклов и простоев). Ожидает JSON: device_id, start_date. Запускается в фоне.

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

Все, что связано с видео, треками и управлением сырыми данными устройства.

Метод Эндпоинт Описание
GET /devices/<device_id>/available-dates/ Массив дат (YYYY-MM-DD), за которые есть загруженные данные.
GET /devices/<device_id>/folders/ Список папок архива (кусков видео по 1 часу).
GET /devices/<device_id>/folders/<folder_id>/detections/ Координаты рамок (Bounding Boxes) для рисования поверх видеоплеера.
GET /devices/<device_id>/video-frame/?timestamp=... Поиск видеофайла и секунды для перемотки по точному времени.
GET /devices/<device_id>/trajectory/?start_date=...&end_date=... Координаты GPS для отрисовки линии маршрута на карте.
POST /devices/<device_id>/upload-archive/ Ручная загрузка оффлайн .zip архива. Возвращает Streaming HTTP с логами распаковки.
GET /devices/<device_id>/alerts/ Список последних экстренных событий (Алертов) от устройства.
POST /devices/<device_id>/clear-data/ Опасная операция. Очистка данных устройства. JSON: {"mode": "all"} или {"mode": "date", "date": "..."}.

6. Подробные примеры использования API (с ответами и их интерпретацией)

Ниже приведены расширенные примеры того, как обращаться к эндпоинтам и как правильно читать возвращаемые данные.

Пример 6.1: Получение информации об устройстве и его настройках

Запрос (Python):

# Получаем базовую информацию об экскаваторе
response = requests.get(f"{BASE_URL}/devices/43/", headers=headers)
device_data = response.json()

# Получаем настроенные для него материалы
mat_response = requests.get(f"{BASE_URL}/devices/43/materials/", headers=headers)
materials_data = mat_response.json()

Ответ API (Устройство):

{
  "id": 43,
  "name": "Excavator fd7f",
  "mac_address": "24f40acefd7f",
  "last_seen": "2026-04-23T15:18:35.744056+03:00",
  "is_active": true,
  "bucket_volume": 2.5,
  "max_cycle_time_sec": 60,
  "downtime_threshold_sec": 300,
  "organization_name": "Дзержинск карьер",
  "has_multiple_shifts": true
}

Ответ API (Материалы):

[
  {
    "id": 3,
    "name": "Грунт",
    "is_default": true,
    "bulk_density": 1650.0,
    "true_density": 2600.0,
    "loosening_factor": 1.58
  }
]

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

  • Устройство Excavator fd7f активно работает в организации «Дзержинск карьер». Связь с ним была совсем недавно (last_seen).
  • Физический объем ковша (bucket_volume) — 2.5 кубометра.
  • Если экскаватор не двигается более 300 секунд (downtime_threshold_sec), система засчитывает это как простой.
  • У машины включен режим работы по сменам (has_multiple_shifts: true).
  • По умолчанию машина работает с материалом «Грунт» (is_default: true). При расчете массы ИИ будет использовать объемный вес 1650 кг/м³ и коэффициент разрыхления 1.58 (loosening_factor).

Пример 6.2: Запрос суточной аналитики (Цифровой двойник)

Запрос (Python):

params = {
    "device_id": 43,
    "start_date": "2026-04-23T00:00:00Z",
    "end_date": "2026-04-23T23:59:59Z"
}
response = requests.get(f"{BASE_URL}/analytics/", headers=headers, params=params)
analytics_data = response.json()

Ответ API (Аналитика, сокращенно):

{
  "total_mileage_km": 1.95756,
  "total_duration_sec": 68399.0,
  "cycle_count_total": 675,
  "cycle_count_vehicle": 266,
  "cycle_count_ground": 409,
  "estimated_volume_total": 1687.5,
  "estimated_mass_total": 2784375.0,
  "shift_stats": {
    "Дневная": {
      "cycles_total": 675,
      "actual_downtime": 5233.1,
      "volume_vehicle": 665.0
    },
    "Ночная": {
      "cycles_total": 0,
      "actual_downtime": 0,
      "volume_vehicle": 0.0
    }
  },
  "averages": {
    "vehicle": {"empty_sec": 5.1, "full_sec": 10.6, "unload_sec": 6.5, "total_sec": 22.1},
    "ground": {"empty_sec": 8.3, "full_sec": 4.5, "unload_sec": 5.4, "total_sec": 18.3}
  },
  "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
  }
}

Интерпретация: Данный эндпоинт отдает готовую сводку за запрошенный период:

  • Экскаватор проехал почти 2 км (total_mileage_km).
  • За день сделано 675 рабочих циклов (cycle_count_total). Из них полезная работа — загрузка в транспорт/самосвал (cycle_count_vehicle) составила 266 ковшей, а перекидка в отвал/на землю (cycle_count_ground) — 409 ковшей.
  • Перемещено около 1687 кубометров или ~2784 тонн породы.
  • В блоке shift_stats видно, что вся работа пришлась исключительно на смену «Дневная». В «Ночную» машину не заводили (0 циклов).
  • Блок averages показывает, что средний цикл загрузки в транспорт занимает 22.1 секунды, где 10.6 сек уходит на поворот с полным ковшом, а 6.5 сек — на выгрузку.
  • Блок durations_by_class_sec детально расписывает хронометраж. actual_downtime (фактический простой с включенным двигателем) составил ~1.45 часа (5233 сек). Параметр no_data (экскаватор выключен или нет связи) составил около 12 часов.

Пример 6.3: Работа с видеоархивом (Синхронизация видео и графика)

Частый сценарий — оператор кликает на событие в графике аналитики, и плеер должен перемотать видео точно на этот момент.

Шаг 1: Запрос доступных папок за день (Python):

response = requests.get(f"{BASE_URL}/devices/43/folders/", headers=headers)
folders = response.json()

Ответ:

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

Интерпретация: Видео на сервере нарезается часовыми кусками (папками). Внутри этого часа ИИ обработал 4350 кадров (поле file_count).

Шаг 2: Поиск точного кадра по Timestamp (Python):

params = {"timestamp": "2026-04-23T15:03:02Z"}
response = requests.get(f"{BASE_URL}/devices/43/video-frame/", headers=headers, params=params)
frame_data = response.json()

Ответ:

{
  "video_url": "http://ex.neimarker.ru/media/devices/43/2026/04/23/15/video_7d4b6624.mp4",
  "seek_seconds": 182.875,
  "folder_id": 5495,
  "frame_index": 4389
}

Интерпретация: API нашел, в каком видеофайле находится запрошенное время (timestamp). Фронтенду/приложению нужно загрузить video_url и перемотать плеер на 182.875 секунды (seek_seconds), чтобы показать нужный момент работы или нарушения.


Пример 6.4: Получение трека (маршрута) для карты

Запрос (Python):

params = {
    "start_date": "2026-04-23T03:17:00Z",
    "end_date": "2026-04-23T03:30:00Z"
}
response = requests.get(f"{BASE_URL}/devices/43/trajectory/", headers=headers, params=params)
trajectory = response.json()

Ответ API:

[
  {
    "ts": "2026-04-23T03:17:00.796000Z",
    "lat": 56.23502833333334,
    "lon": 43.63613999999999
  },
  {
    "ts": "2026-04-23T03:18:00.997000Z",
    "lat": 56.23502833333334,
    "lon": 43.63613999999999
  }
]

Интерпретация: Массив точек с широтой (lat) и долготой (lon), привязанных к меткам времени (ts). Эти данные идеально подходят для отрисовки полилинии (Polyline) маршрута движения экскаватора в гео-информационных системах, 1С (через интеграцию карт) или на веб-картах (Yandex Maps, Leaflet). Точки отдаются с фильтрацией погрешностей GPS (выбросов).