Организация

Руководство

Как пользоваться HorizonMesh

Для чего нужен каждый раздел консоли, как он устроен и пошаговые workflow — от организации до SCADA и обновлений прошивки.

Организация

Для чего

Изолированный арендатор для парка: устройства, классы, участники, квоты и настройки MQTT живут внутри одной организации.

Как работает

Активная организация выбирается в шапке. Панель, каталог устройств, SCADA и нотификации всегда относятся к выбранной org.

Workflow

  1. Зарегистрируйтесь и войдите.
  2. Создайте организацию или примите приглашение.
  3. Выберите org в шапке — на панели появится сводка парка.
  4. Пригласите команду с ролями owner, admin или member.

Примеры

Создание организации (тело API)

POST /v1/organizations — первая организация при регистрации; дополнительные через API или консоль.

{
  "name": "Теплица Ops",
  "slug": "greenhouse-ops"
}

Организация в MQTT-топиках

В каждом топике устройства — UUID организации, не slug.

# orgId = UUID из Настройки → Организация
to/organization/{orgId}/device/{deviceId}/telemetry/Cap
from/organization/{orgId}/device/{deviceId}/twin/reported

Класс устройства

Для чего

Шаблон типа устройства: protobuf-схема, дефолты twin, remote methods, прошивки и опциональный SCADA-символ.

Как работает

Каждое устройство принадлежит одному классу. Декодирование телеметрии, валидация twin, вызов методов и OTA-образы берутся из определения класса.

Workflow

  1. Откройте Классы устройств → Создать.
  2. Загрузите proto-схему и опишите потоки телеметрии.
  3. Добавьте remote methods и дефолтный twin при необходимости.
  4. Загрузите прошивки и SCADA-символ по желанию.
  5. Сохраните — новые устройства этого типа наследуют контракт.

Примеры

Remote methods (класс устройства)

JSON-массив в spec класса. Таймаут задаётся только при вызове из UI (10–300 с, по умолчанию 30).

[
  { "name": "ping", "description": "Проверка связи — ответ {"pong":true}" },
  { "name": "reboot", "description": "Перезагрузка устройства" },
  { "name": "cap_info", "description": "Интервал опроса и калибровка ADC" }
]

Default desired (hm-soil-cap)

Обычный JSON (не JSON Schema). Новые устройства наследуют эти значения twin.

{
  "cap_state": {
    "cap_interval_ms": 5000,
    "cap_calibration": {
      "dry_raw": 3200,
      "wet_raw": 1200
    }
  }
}

Конфиг графиков телеметрии (telemetryUi)

Имя потока = имя proto-сообщения (например Cap). Поля в JSON — camelCase.

{
  "charts": [
    {
      "id": "soil-moisture-percent",
      "title": "Влажность почвы",
      "type": "line",
      "streamFilter": "Cap",
      "timeField": "timestampMs",
      "timeUnit": "ms",
      "series": [{ "field": "moisturePercent", "label": "Влажность %" }]
    }
  ]
}

Онбординг устройства

Для чего

Безопасное первое подключение: provisioning-токен позволяет прошивке занять слот устройства и получить mTLS-сертификат без ручной работы с сертификатами в UI.

Как работает

Вы выпускаете токен в консоли, вшиваете claim в прошивку — устройство регистрируется по Wi‑Fi. mqtt-worker назначает маршруты; устройство появляется в каталоге.

Workflow

  1. Токены подключения → создайте токен для нужного класса.
  2. Пропишите claim в прошивку до прошивки чипа.
  3. Включите устройство в сети с доступом к MQTT-брокеру.
  4. Дождитесь регистрации и выдачи сертификата.
  5. Откройте карточку устройства и проверьте twin и MQTT-топики.

Примеры

Сценарий provisioning (схема)

Токен создаётся в консоли; claim вшивается в прошивку до первого подключения по Wi‑Fi.

{
  "provisioning_token": "<секрет из консоли>",
  "device_class": "hm-soil-cap",
  "claim_name": "greenhouse-sensor-01"
}

# После claim API возвращает URL MQTT-брокера, корни топиков
# и устройство получает mTLS-сертификат (CN = UUID устройства).

Устройства

Для чего

Каталог парка: каждая физическая единица со статусом, классом, состоянием связи и переходами к twin, телеметрии, методам и настройкам.

Как работает

Устройства создаются вручную или через provisioning. Presence (online/offline) обновляется по MQTT. Список поддерживает поиск, фильтр по статусу и сортировку.

Workflow

  1. Выберите организацию.
  2. Создайте устройство нужного класса или дождитесь enrollment по токену.
  3. На обзоре смотрите MQTT subscribe/publish префиксы.
  4. Вкладки: twin, живой лог, ивенты, настройки.

Примеры

Корни MQTT-топиков (карточка устройства)

Subscribe — облако→устройство; publish — устройство→облако.

# Подписка (downlink)
to/organization/{orgId}/device/{deviceId}/#

# Публикация (uplink)
from/organization/{orgId}/device/{deviceId}/

Вызов direct method (REST)

POST .../devices/{deviceId}/methods/{methodName}/invoke. Не проверяет online/offline — отправляет на брокер и ждёт до таймаута.

{
  "params": {},
  "timeout": "30s"
}

# С параметрами (если задана schema на классе):
{
  "params": { "dry_raw": 3200, "wet_raw": 1200 },
  "timeout": "60s"
}

Direct method MQTT (платформа ↔ прошивка)

Корреляция в поле id. Платформа шлёт request; устройство отвечает на from/.../response.

# Запрос (облако → устройство)
Топик: to/organization/{orgId}/device/{deviceId}/methods/ping/request
Тело:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "payload": {}
}

# Ответ (устройство → облако)
Топик: from/organization/{orgId}/device/{deviceId}/methods/ping/response
Тело:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": 200,
  "payload": { "pong": true }
}

Twin (desired и reported)

Для чего

Конфигурация облако→устройство (desired) и состояние устройство→облако (reported) в виде JSON по схеме класса.

Как работает

Desired патчите в UI; API сохраняет снимок, mqtt-worker публикует retained MQTT. Прошивка шлёт reported; twin-worker сливает в Postgres и обновляет presence.

Workflow

  1. Устройство → вкладка Twin.
  2. Отредактируйте desired JSON (температура, режимы и т.д.) и сохраните.
  3. После reconnect офлайн-устройство подхватит retained desired.
  4. Сравните с reported, что настройки применились.

Примеры

Patch desired (UI / API)

Частичный или полный desired. mqtt-worker публикует retained MQTT на устройство.

{
  "cap_state": {
    "cap_interval_ms": 10000,
    "cap_calibration": {
      "dry_raw": 3100,
      "wet_raw": 1150
    }
  }
}

Reported (устройство → облако)

Прошивка публикует применённый cap_state. Для hm-soil-cap форма как у desired.

{
  "cap_state": {
    "cap_interval_ms": 10000,
    "cap_calibration": {
      "dry_raw": 3100,
      "wet_raw": 1150
    }
  }
}

MQTT-топики twin

Подставьте {orgId} и {deviceId} — UUID с карточки устройства.

# Облако → устройство (retained diff desired)
to/organization/{orgId}/device/{deviceId}/twin/desired

# Устройство → облако (полный reported JSON)
from/organization/{orgId}/device/{deviceId}/twin/reported

Телеметрия

Для чего

Живые и исторические данные сенсоров из protobuf-потоков, описанных в классе устройства.

Как работает

Устройства публикуют protobuf по MQTT. telemetry-worker пишет в TimescaleDB и раздаёт WebSocket — графики обновляются без опроса REST API.

Workflow

  1. Опишите сообщения телеметрии в proto класса.
  2. Откройте обзор устройства или вкладку Живой лог.
  3. Смотрите последние 15 минут из хранилища и новые точки в реальном времени.
  4. Меняйте диапазон графиков для отладки.

Примеры

MQTT-топик телеметрии

В канале — protobuf; UI и правила работают с декодированным JSON.

# Публикация (proto-сообщение Cap)
from/organization/{orgId}/device/{deviceId}/telemetry/Cap

Декодированный Cap (JSON)

Так данные попадают в TimescaleDB и в условия ивентов (expr-lang).

{
  "timestampMs": 1710000000123,
  "moistureAdcRaw": 1842,
  "moisturePercent": 42.5,
  "sampleIndex": 128
}

Ивенты и нотификации

Для чего

Автоматические реакции на телеметрию или peer-условия — с уведомлениями в консоли при срабатывании правил.

Как работает

Правила — выражения expr-lang по JSON. rule-worker оценивает потоки; совпадения создают нотификации по устройству или организации.

Workflow

  1. Устройство → вкладка Ивенты.
  2. Создайте правило с условием (например moisturePercent < 60).
  3. Подпишитесь на нотификации устройства при необходимости.
  4. Лента org — раздел Нотификации в меню.

Примеры

Создание ивента (тело API)

POST /v1/organizations/{orgId}/devices/{deviceId}/events

{
  "name": "Низкая влажность",
  "enabled": true,
  "trigger_stream": "Cap",
  "condition": "moisturePercent < 35",
  "action_type": "notification",
  "action_stream": "notification/warning",
  "action_payload": "{\"title\":\"Низкая влажность\",\"message\":\"{{ index . \"moisturePercent\" }}% при ADC {{ index . \"moistureAdcRaw\" }}\"}",
  "notification_retention_days": 30
}

Примеры условий (expr-lang)

Используйте camelCase полей телеметрии. Пустое условие = всегда true.

moisturePercent < 40
moisturePercent >= 10 && moisturePercent < 25
moistureAdcRaw > 3000

Шаблон payload нотификации

Go text/template по JSON телеметрии. Синтаксис: index . "fieldName".

{
  "title": "Тревога по почве",
  "message": "Влажность {{ index . "moisturePercent" }}% (ADC {{ index . "moistureAdcRaw" }})"
}

Шаблон ивента класса (telemetryUi.__eventPresets)

Сохраните ветку как шаблон класса, затем добавьте на другое устройство того же типа и настройте.

{
  "__eventPresets": {
    "templates": [
      {
        "id": "tpl-low-moisture",
        "label": "Низкая влажность",
        "trigger_stream": "Cap",
        "condition": "moisturePercent < 35",
        "action_payload": "{\"title\":\"Низкая влажность\",\"message\":\"{{ index . \"moisturePercent\" }}%\"}",
        "notif_severity": "warning"
      }
    ]
  }
}

SCADA-планы

Для чего

Визуальная топология парка: символы классов на холсте, связи между устройствами и автоматизация на соединениях.

Как работает

Планы используют классы и их SCADA-символы. Размещаете узлы, рисуете связи и настраиваете peer-автоматизацию без отдельного редактора схем.

Workflow

  1. Загрузите SCADA-символ на классе (опционально).
  2. Схемы → создайте план для организации.
  3. Перетащите устройства на холст и соедините их.
  4. Настройте автоматизацию на связях и инспекторы twin/методов.

Примеры

Автоматизация между устройствами (схема)

Настраивается в инспекторе SCADA при связи двух устройств на холсте.

{
  "source_device_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "target_device_id": "ffffffff-gggg-hhhh-iiii-jjjjjjjjjjjj",
  "condition": "moisturePercent < 30",
  "action_stream": "Cap",
  "action_payload": "{ \"relay\": \"on\" }"
}

Обновления прошивки

Для чего

OTA-доставка новых образов, опубликованных на классе, с отчётом о прогрессе по MQTT.

Как работает

Бинарники прошивки хранятся на классе. Задание desired-версии (или OTA-поток) запускает доставку через mqtt-worker; устройства скачивают и отчитываются.

Workflow

  1. Загрузите новую версию прошивки на классе.
  2. Создайте или обновите устройства этого класса.
  3. Задайте целевую версию в twin или через OTA-поток класса.
  4. Следите за статусом прошивки на карточке устройства.

Примеры

OTA прошивки (MQTT)

Бинарник хранится на классе устройства; twin-worker запускает доставку при расхождении версии.

# Облако → устройство (команда OTA)
to/organization/{orgId}/device/{deviceId}/firmware/update

# Устройство → облако (прогресс / результат)
from/organization/{orgId}/device/{deviceId}/firmware/status

Статус OTA (пример payload)

Точные поля зависят от прошивки; в UI показывается слот и версия.

{
  "current_version": "1.2.0",
  "target_version": "1.3.0",
  "phase": "downloading",
  "progress_percent": 45
}

Участники и роли

Для чего

Доступ команды внутри организации: кто управляет классами, устройствами, токенами и настройками org.

Как работает

Роли owner, admin, developer и member с разными правами. Приглашения добавляют существующих пользователей или создают новые аккаунты в org.

Workflow

  1. Организации → ваша org → Участники.
  2. Пригласите по email или создайте пользователя с логином и паролем.
  3. Назначьте роль owner, admin, developer или member.
  4. Участники переключают org в шапке и работают с одним парком.

Примеры

Приглашение участника (тело API)

POST /v1/organizations/{orgId}/members

{
  "email": "[email protected]",
  "role": "admin"
}