Skip to content

Идентификаторы: как найти нужное помещение

Любая интеграция из этого раздела сводится к одному вопросу: какому узлу графа здания соответствует запись в вашей системе? Ответите правильно — всё остальное трубопровод. Ответите неправильно — увидите 200 OK с written: 0 или значения, приехавшие не на тот этаж.

Граф, коротко

площадка → здание → этаж → помещение → элемент (оборудование) → точка (показание датчика)

Слои данных крепятся к помещениям. Заявки ссылаются на spaceId, storeyId или elementId. Телеметрия крепится к точке, которая принадлежит элементу, а тот стоит в помещении. Дерево одно, разная глубина.

Два идентификатора у каждого узла

Что этоПереживаетКогда использовать
idВнутренний UUID, который присваивает платформаВсё, кроме переимпорта с replaceУ здания нет BIM-модели либо вы уже разрешили идентификатор
externalIdИдентификатор из системы-источника — IFC GlobalId, если здание пришло из BIMПереимпорт: GlobalId приходит из самой моделиЗдание пришло из BIM и ваши данные привязаны к модели

У каждого узла есть ещё sourceSystem — метка происхождения: ifc у всего, что создал импорт IFC. Уникальность задана на тройке (buildingId, sourceSystem, externalId). Это значит, что ваша система может проставить свои externalId под своим sourceSystem и не столкнуться с уже существующими идентификаторами IFC.

Есть ещё code ("B1-S02-SP003") — машиночитаемая метка для человека, уникальная в пределах здания. Полезна в выгрузках; ключом поиска в API она не является.

Почему для BIM-здания GlobalId — более надёжный ключ связи

Внутренние идентификаторы пересоздаются, когда модель переимпортируют с replace: true. IFC GlobalId — нет: он приходит из самой модели и переживает цикл. Если здание пришло из BIM, стройте интеграцию на externalId — и вам не придётся заново разрешать всё после очередной ревизии модели.

Какой идентификатор ждёт каждый API

APIПринимает
Значения слоя (PUT …/values)ЛюбойkeyBy: "externalId" (по умолчанию, GlobalId) либо keyBy: "id" (внутренние UUID)
Заявки (POST /requests)Только внутренние UUID — spaceId, storeyId, elementId
Телеметрия (POST …/observations)pointId — внутренний UUID, точка должна уже существовать в этом здании
Создание помещений / элементовВаши собственные externalId + sourceSystem, если они вам нужны

Слои данных — самый снисходительный случай: передайте GlobalId, и они сами их разрешат. Именно поэтому «идентификатор помещения и какие-то данные» — это действительно весь payload слоя, и именно поэтому слой — самая быстрая первая интеграция.

Как построить соответствие

Всему, что требует внутренних UUID (в первую очередь заявкам), нужна карта GlobalId → id. Постройте её один раз и держите в кэше:

http
GET /api/v1/buildings/{buildingId}/spaces?limit=1000&offset=0

В каждой строке есть id, externalId, code, name, этаж и тип помещения — одного прохода хватает на все ключи связи.

Серверного поиска по externalId нет

Список помещений фильтруется по storeyId, spaceTypeSlug, status и isLeasable — но не по externalId и не по code. Спросить «какое помещение соответствует GlobalId X» нельзя: вы постранично выбираете здание и строите индекс у себя. Для здания в несколько тысяч помещений это несколько запросов, один раз, на старте.

Размер страницы: текущий tv-api допускает limit до 1000. Если приходит 400, значит контур, с которым вы говорите, всё ещё ограничен сотней, — переходите на 100, а не падайте.

Обновляйте карту после переимпорта модели. Значения, привязанные к GlobalId, переимпорт переживают; закэшированные внутренние UUID — не обязательно.

Когда BIM-модели нет

Таких зданий много. Их помещения рисуют в редакторе карт или создают через API, и GlobalId у них нетexternalId пустой. Два варианта:

  1. Использовать внутренние идентификаторы: грузить значения слоя с keyBy: "id".
  2. Проставить свои внешние идентификаторы: при создании помещения (POST /api/v1/buildings/{buildingId}/spaces) передайте свой externalId вместе с выбранным вами sourceSystem ("acme-fm"). Дальше keyBy: "externalId" будет совпадать с вашими идентификаторами напрямую, и таблица соответствия вам вообще не понадобится.

Вариант 2 лучше, когда именно ваша система знает состав помещений.

Когда не совпало

Загрузка, не совпавшая ни с чем, сама скажет, какая из трёх причин сработала:

diagnostics.reasonЧто значитЧто делать
BUILDING_HAS_NO_SPACESГраф пуст: ничего не импортировали и не создавалиИмпортировать модель или создать помещения
BUILDING_HAS_NO_EXTERNAL_IDSПомещения есть, GlobalId нет ни у одногоПерейти на keyBy: "id" или проставить внешние идентификаторы
IDENTIFIERS_NOT_IN_BUILDINGОбе стороны заполнены, но идентификаторы не из этого зданияПроверить buildingId — обычно это устаревший id в конфиге либо идентификаторы из другой модели той же площадки

Частичное совпадение ошибкой не считается: в unmatched перечислены ровно те ключи, которым не нашлось помещения, остальные записаны. Логируйте это и поднимайте тревогу по порогу — так вы поймаете день, когда на этаже перенумеровали помещения.

Один пограничный случай: одно и то же помещение может фигурировать под несколькими GlobalId, если у площадки несколько моделей по разделам. Если два идентификатора в одном payload разрешаются в одно помещение, побеждает последний — ошибки не будет, поэтому держите в одном payload один идентификатор на помещение.

Создано на платформе Tango Vision. Вопросы? developers@tango.vision