Преминете към основното съдържание

Протокол на конектора на Edge

Конекторът на Edge използва същия плик (envelope), hello, сигнал за активност и жизнен цикъл на задачите като агентите и конекторите на Axis (Протокол на агента и конектора) и добавя съобщенията и задачите за контрол на достъпа. Go типовете в entrosity-shared-go/proto/edge са единственият източник на истина; тази страница описва предназначението и поведението.

Както останалата част от протокола, тези типове само се разширяват: полета се добавят, но никога не се преименуват или пренасочват, за да продължат да работят конекторите на място.

Транспорт​

  • WebSocket: wss://hub.entrosity.com/edge/api/connector/v1/ws с Authorization: Bearer <connector key>. JSON текстови рамки, по един плик в рамка, най-много 1 MiB; сървърът изпраща ping на всеки 30 секунди.
  • Първото съобщение трябва да е hello (capabilities: ["access_control", "edge_update"], pending_job_ids); сървърът отговаря с hello.ack и след това доставя чакащите задачи. edge_update означава, че конекторът инсталира самообновявания (Самообновяване); на конектори без нея никога не се предлага обновяване. Всичко преди hello затваря връзката (1008).
  • Конекторът изпраща heartbeat всяка минута. Той е онлайн от своето hello, докато връзката не се затвори или след 3 минути без съобщение.
  • Задачите следват job.assign → job.ack → job.progress → job.result. Задача, изпратена без job.ack до 60 секунди, се изпраща отново; задача, неприключила преди срока си, става timeout.
  • Кодове за затваряне: 4003 ключът е отменен (конекторът е премахнат, тенантът е спрян); 4009 по-нова връзка на същата инсталация е поела; 1008 нарушение на правилата.

HTTP крайни точки (/api/connector/v1)​

Метод и пътПредназначение
POST /enroll{enrollment_token, hostname, domain, version} → {connector_id, connector_key, ws_url}. Токенът трябва да е токен за конектор на Edge. Същият компютър (тенант, име на хост, домейн), регистриран отново, сменя ключа си и затваря старата връзка. Ограничено за IP адрес (EDGE_ENROLL_RATE_PER_MINUTE).
GET /wsWebSocket връзката.
POST /heartbeatHTTP резервен вариант на heartbeat.
GET /jobs/pending, POST /jobs/{id}/ack, …/progress, …/resultHTTP резервен вариант (polling) на жизнения цикъл на задачите.
POST /eventsHTTP резервен вариант на edge.events: тялото е EventsChunk (приема се gzip; 4 MiB компресирано, 8 MiB разкомпресирано), отговорът е EventsAck.
POST /controllers/statusHTTP резервен вариант на edge.controller.status.
GET /releases/{id}/msi?exp=&sig=Изтегляне на MSI файла на издание на конектора по подписаната връзка от задача update_agent. Без ключ на конектора: връзката (валидна 24 часа, подписана с ключ, извлечен от EDGE_MASTER_KEY) е разрешението; изтекла или променена връзка получава 403 download_link_invalid.

Всички освен /enroll и изтеглянето на издания изискват ключа на конектора. Всичко, което прави конекторът, е ограничено в неговия тенант.

Съобщения​

Конектор → сървър​

ТипPayloadКога
edge.events{first_seq, events: [Event]}: 1–500 последователни събития (events[i].seq = first_seq + i)Когато опашката на конектора има събития.
edge.controller.status{controllers: [{controller_id, online, applied_version, applied_hash?, error?, doors?: [{index, open, locked}], info?: ControllerInfo}]} (до 1000 контролера)Поне всяка минута и веднага след промяна.

Сървър → конектор​

ТипPayloadКога
edge.events.ack{acked_seq}, в отговор (reply_to) на edge.eventsВсяко събитие до acked_seq е съхранено; конекторът ги премахва от опашката си.

Задачи​

ЗадачаPayloadРезултатВреме за изпълнение / срокЛента на конектора
edge.config.apply{controller: ControllerRef, version, hash, snapshot: ConfigSnapshot}{version, hash, cards}10 мин / 7 дни, приоритет 10config (по една)
edge.controller.remove{controller_id}{}1 мин / 30 дниconfig
edge.door.open{controller: ControllerRef, door_index, pulse_ms, requested_by?}{}30 с / 30 с, приоритет 100door (4 паралелно)
edge.discover{driver, transport?, addresses?: ["host:port", …]} (до 256; празно за симулатора показва всеки симулиран контролер){controllers: [ControllerInfo]}2 мин / 5 минdiscover (по една)
edge.controller.test{controller: ControllerRef}ControllerInfo1 мин / 5 минdiscover
update_agentUpdateJob (component: edge-connector, вижте Самообновяване)UpdateResult30 мин / 24 чupdate
  • ControllerRef е {controller_id, driver, target}; target (edge.Target) е {transport: "tcp"|"rs485", address, unit_id?, pin?}: address е host:port, серийно устройство (COM3) или Modbus шлюз host:port; unit_id е адресът по шината RS-485 1–31, липсва при TCP.
  • pin (uint32, 1–4294967294; липсва, когато не е зададен) е ПИН кодът на контролера (TrackBase002: всяка командна рамка го носи). Не е част от ключа на целта (транспорт, адрес, адрес по шината), така че нов ПИН е същият контролер. Edge го пази шифрован и го добавя, когато доставя задачата: payload-ите на задачите в базата данни не съдържат ПИН. Конекторът го пази в controllers.json и никога не го връща: ControllerInfo в резултатите от търсене и проверка, както и отчетите за състоянието, са без него.
  • ControllerInfo е {driver, target, model, serial, firmware, door_mode?}.
  • edge.config.apply кара контролера да пази точно моментната снимка. Нова задача за контролер отменя неговата по-стара отворена задача за прилагане. Задача, по-стара от вече приложената от конектора конфигурация (доставена със закъснение), е успешна с по-новата версия. Конекторът пази последната приложена моментна снимка и при стартиране я възстановява на контролерите, които са я загубили. Нов ПИН, адрес, транспорт или адрес по шината се изпраща като прилагане на непроменената конфигурация (същата версия и хеш): конекторът само обновява целта, без пълно презаписване.
  • edge.controller.remove спира четенето на контролера и забравя конфигурацията му. Изпраща се, когато контролерът бъде премахнат или деактивиран; деактивиран контролер, който бъде активиран отново, получава (принудително) edge.config.apply, което го регистрира отново в конектора.
  • edge.door.open освобождава ключалката за pulse_ms (времето за отключване на вратата; 3 с, ако липсва). Контролерът отчита door_opened_remote с requested_by в подробностите. Краткият срок гарантира, че вратата никога не се отваря дълго след заявката.

Самообновяване (update_agent)​

Същият тип задача и payload като при агентите и конекторите на Axis (Протокол), с component: edge-connector:

{"release_id": "…", "component": "edge-connector",
"target": {"version": "1.4.0", "url": "https://…/api/connector/v1/releases/…/msi?exp=…&sig=…",
"sha256": "…", "size_bytes": 9437184, "signature": "…"},
"rollback": {"version": "1.3.2", "url": "…", "sha256": "…", "size_bytes": 9412608, "signature": "…"}}
ПолеЗначение
release_idИдентификаторът в Edge на предложеното издание.
targetMSI файлът за инсталиране: version, url (подписана връзка за изтегляне, валидна 24 часа, добавена при доставката на задачата), sha256, size_bytes и signature – подписът Ed25519 (base64) на "rmm-release-v1\n<component>\n<version>\n<sha256>\n<size>\n" с EDGE_RELEASE_SIGNING_KEY.
rollbackСъщото за версията, с която работи конекторът, ако Edge още я има: защитният механизъм я инсталира отново, ако новата версия не стартира.

JobResult.Result е UpdateResult: {scheduled, from_version, to_version, rollback} (scheduled: инсталаторът се стартира след минута от планираната задача; rollback: пази се предишен MSI за защитния механизъм). Задачата е успешна, щом инсталирането е планирано; новата версия се вижда в следващото hello на конектора.

Edge предлага обновяване, когато конекторът изпрати hello, и на всеки 5 минути (releases.rollout): най-новото издание от канала за обновления на конектора (stable: стабилни издания; beta: бета и стабилни), което е по-ново от версията на конектора, само на конектори, които обявяват edge_update, не и докато има отворена задача update_agent за конектора, и същата версия не отново в рамките на час. Какво прави конекторът: Конектор на Edge → Самообновяване.

Кодове на грешки при задачи​

job.result.error_code на задачите на Edge:

КодЗначение
capacity_exceededМоментната снимка има повече карти, отколкото контролерът побира, или паметта за карти на контролера е пълна.
controller_unreachableКонтролерът не отговори.
config_rejectedКонтролерът или проверката на моментната снимка в конектора отказа конфигурацията.
unsupportedДрайверът не може да достигне контролера по тази връзка (trackbase002 по RS-485/серийна връзка).
unknown_driverТази версия на конектора няма драйвер с това име.
invalid_payloadPayload-ът не може да бъде декодиран или е невалиден.
exec_failedКонекторът се рестартира, преди задачата да приключи; при update_agent – папката за обновяване или планираната задача не могат да бъдат създадени.
update_unsignedupdate_agent: компилацията няма публичен ключ за изданията и отказва обновявания.
signature_invalidupdate_agent: подписът на изданието не е потвърден.
download_failed, hash_mismatchupdate_agent: MSI файлът не може да бъде изтеглен или не съответства на SHA-256 и размера на изданието.

Моментна снимка на конфигурацията​

{
"timezone": "Europe/Sofia",
"door_mode": "two_unidirectional",
"doors": [{"index": 1, "lock_relay": 1, "open_pulse_ms": 3000, "held_open_seconds": 30}],
"readers": [{"channel": "wiegand1", "door_index": 1, "direction": "in"}],
"schedules": [{"slot": 1, "name": "Office", "intervals": [{"day": 0, "start": 480, "end": 1080}]}],
"holidays": ["2026-12-25"],
"cards": [{"kind": "wiegand26", "facility_code": 12, "card_number": 3456,
"card_id": "…", "grants": [{"door_index": 1, "schedule_slot": 1}]}]
}
ПолеЗначение
timezoneIANA часовата зона, в която са изразени графиците и празниците: тази на обекта, иначе тази по подразбиране на тенанта, иначе UTC.
door_modeone_bidirectional (една врата, четец за вход и изход) или two_unidirectional (две врати с по един четец).
doorsindex на вратата 1–2, lock_relay 1–4, open_pulse_ms, held_open_seconds (0: никога не генерира door_held_open).
readersСамо включените четци: channel (wiegand1, wiegand2, ibutton1, ibutton2), вратата, която обслужва, direction (in, out).
schedulesГрафиците, които вратите на контролера използват, номерирани с slot 1–255. intervals са [start, end) в минути от полунощ; day 0 = понеделник … 6 = неделя, 7 = празнични прозорци.
holidaysДати (YYYY-MM-DD, в timezone) от предишния ден до 90 дни напред, на които важат празничните прозорци вместо тези на деня от седмицата.
cardsВсяка карта, която може да минава през поне една от вратите (най-много 2000): идентификаторът (wiegand26 с facility_code 0–255 и card_number 0–65535 или ibutton с ibutton_id, 2–16 шестнадесетични цифри), card_id в Edge и нейните grants (врата и слот на график).

hash е SHA-256 (hex) на JSON на моментната снимка; всеки списък е подреден детерминистично, така че една и съща конфигурация винаги има един и същ хеш. Конекторът отчита хеша, който контролерът пази, в applied_hash; различен хеш на контролер, който е онлайн и не се синхронизира, кара сървъра да изпрати конфигурацията отново.

Референтното решение (ConfigSnapshot.Allows, реализирано от драйверите и симулатора): непознат идентификатор → unknown_card; няма разрешение за вратата → access_denied/no_access; разрешение, чийто график има отворен прозорец в момента (празничните прозорци в празник) → access_granted; иначе access_denied с holiday в празник, в противен случай outside_schedule.

Събития​

{"seq": 1042, "controller_id": "…", "occurred_at": "2026-09-28T06:00:12Z",
"type": "access_granted", "door_index": 1, "reader_channel": "wiegand1",
"direction": "in", "credential": {"kind": "wiegand26", "facility_code": 12, "card_number": 3456}}
ПолеЗначение
seqДава се от опашката на конектора: строго нарастващ за всяка инсталация на конектор.
controller_id, occurred_at, typeЗадължителни. Типове: access_granted, access_denied, unknown_card, door_opened_remote, door_forced, door_held_open, door_closed, controller_online, controller_offline, config_applied, tamper.
door_index1–2; липсва при събития на контролера.
reader_channel, directionЧетецът, при събития с карти.
credentialПрочетената карта.
reasonЗа access_denied: no_access, outside_schedule, holiday.
detailСвободен текст, най-много 512 знака (кой е отворил врата дистанционно, съобщения на драйвера).

Точно веднъж: сървърът пази за всеки конектор най-високия пореден номер, който е съхранил. Част (chunk) на или под него е дубликат и само се потвърждава; частта над него се съхранява и курсорът се премества, в една транзакция. Конекторът пази събитията на диска, докато не бъдат потвърдени, така че изгубено потвърждение, рестартиране или прекъсване водят само до повторно изпращане. По WebSocket част без потвърждение до 15 секунди се изпраща отново по HTTP.

При приемането сървърът определя контролера, вратата, четеца, картата и картодържателя на всяко събитие (историята ги пази дори след изтриване) и предава новите записи на уеб приложението. occurred_at повече от 24 часа в бъдещето или повече от година в миналото се заменя с часа на пристигане, с бележка в подробностите.

controller_online и controller_offline се записват от сървъра при промени в edge.controller.status.

Ограничения​

ОграничениеСтойност
Карти на контролер2000
Графици на контролер (слотове)255
Врати на контролер, релета2, 4
Адреси по шината RS-4851–31
Събития в една част edge.events500 (конекторът освен това пази частта под 256 KiB)
Контролери в един отчет за състоянието1000
Съобщение по WebSocket1 MiB
Адреси при едно търсене256