Ойнатқыштардан және CMS жүйесінен көрсетілімдерді жіберу
Ешкім тексере алмайтын көрсетілім жай мәлімдеме ғана болып қалады. Бұл нұсқаулықта ойнатқыштың немесе оларды басқаратын CMS жүйесінің аяқталған көрсетілімдерді tanba.pop/1 пішімінде қалай хабарлайтыны көрсетілген: платформа оларды санай алады, ал кез келген адам сандарды сақталған пакеттермен салыстыра алады.
Анықтамалық беттер: Көрсетілімдерді есепке алу API және Құрылғы протоколы.
Арнаны таңдаңыз
Пакет келген арна платформаның оған қаншалықты сенетінін анықтайды. Пакет денесі деңгейді мәлімдемейді.
| Арна | Жол және хост | Аутентификация | Дәлел деңгейі |
|---|---|---|---|
| Сертификат | https://devices.tanba-ooh.kz хостындағы POST /d/v1/telemetry | Клиенттік сертификат және денеге құрылғы кілтімен жасалған қолтаңба | mtls |
| Қолтаңба | https://agents.tanba-ooh.kz хостындағы POST /s/v1/telemetry | Тіркеу кезінде жазылған кілтпен жасалған дене қолтаңбасы; денеде device_id және ts бар | signed |
| CMS (оператор растаған) | https://app.tanba-ooh.kz хостындағы POST /api/v1/pop/batches | write:plays рұқсаты бар API кілті және CMS орнатылымы үшін жазылған кілтпен жасалған қолтаңба | attested |
Қай деңгейлердің алымға есептелетінін осы интерфейс емес, платформа белгілейді. Оператор растаған көрсетілімдер оператордың өз мәлімдемесі болып табылады: олар операторды ешқашан бұзушылықтан арылтпайды және құрылғылар хабарлайтынның жанында айқас тексеру қызметін атқарады.
Пакет
{"schema": "tanba.pop/1", "batch_seq": 1042, "prev_sha256": "9f2b6a41c7d83e05a1b4c6d7e8f90123456789abcdef0123456789abcdef0123",
"sent_at": "2026-10-14T09:05:00.120Z", "events": [ ]}
batch_seq0-ден бастап бүтін сан, пакетке бір рет алынады. Платформа денені дәл алған күйінде сақтайды.prev_sha256batch_seq - 1пакеті денесінің hex түріндегі SHA-256 мәні; бірінші пакет үшін бос.- Пакетте көбі 1000 оқиға және 4 МБ (қолтаңбалы арнада 1 МБ). Пакетті әр 300 секунд сайын немесе 1000 оқиғаға жеткенде, қайсысы ертерек болса, жабыңыз. Heartbeat жауабы
telemetry_cut_sмәнін, яғни платформа сұрайтын аралықты алып жүреді. CMS пакетіндеeventsорнынаrecordsтұрады, шектеулер төменде. - Пакеттерді ретімен жіберіңіз және бірінші қатеде тоқтаңыз. Сәтсіз пакетті сол байттармен қайта жіберіңіз.
schemaжоқ дене бұрынғы пішім болып саналады. Құрылғының біріншіtanba.pop/1пакеті қабылданғаннан кейін артқа қайту мүмкін емес:schemaжоқ пакет409 legacy_after_popдеп қабылданбайды. Бұрынғы пішімде жиналғанның бәрін біріншіtanba.pop/1пакетінен бұрын жіберіңіз.
Жазбалар
Әр аяқталған көрсетілімге бір play жазбасы:
| Өріс | Түрі | Ереже |
|---|---|---|
kind | "play" | Басқа түрлері: reject (code өрісімен, мәні NO_SIGNATURE, BAD_SIGNATURE, HASH_MISMATCH, EXPIRED_APPROVAL, REVOKED біреуі), mode_change және tamper; оларда at бар |
seq | бүтін сан | play үшін міндетті. Әр ойнатқыш үшін пакеттер шекарасынан өтіп, әр жазбаға +1, 1-ден бастап |
play_id | жол, A-Za-z0-9_- таңбаларынан 8-ден 64-ке дейін | Ойнатқыш үшін бірегей |
approval_number | TNB-YYYY-NNNNNN | slot берілмесе міндетті |
slot | gov немесе emergency | Уәкілетті орган материалы: келісу нөмірі жоқ, ешқашан есептелмейді, бөлек саналады |
media_sha256 | 64 hex таңба | Көрсетілген файлдың SHA-256 мәні |
start, end | RFC 3339, миллисекундтар | start end мәнінен кеш емес |
duration_ms | 0 немесе одан көп бүтін сан | Экранда өлшенген уақыт |
structure | құрылым коды | Міндетті емес; ойнатқыштың өз құрылымы болуы тиіс, әйтпесе жазба белгі алады |
screen | {"power": ...} | Міндетті емес; көрсетілім кезіндегі дисплей күйі: on, off немесе unknown |
Көрсетілімдер қалай есептеледі
- Көрсетілім дегеніміз
duration_msмәні 1000 немесе одан көп қабылданған жазба, олendбойынша UTC сағатына есептеледі. Қысқа жазбалар қабылданады, бірақ еш жерде есептелмейді. - Көрсетілім келісілген материал ұзақтығына 500 мс дәлдікпен созылса, толық болып саналады (қозғалмайтын сурет үшін 1000 мс).
- Қабылданған, бірақ белгісі бар жазба бәрібір есептеледі. Белгілер:
approval_unknown,approval_not_for_structure,approval_outside_validity,revoked_at_time,media_mismatch,structure_mismatch,duration_mismatch,clock_skew,late,screen_off,incompleteжәнеlegacy. - Жазба қабылданбайды, есептелмейді және жауапта мына себептердің бірімен аталады:
kind_unknown,approval_number_invalid,time_invalid,end_before_start,time_in_future,too_old,seq_invalid,media_sha256_invalid. CMS арнасында тағы біреуі бар:player_unknown. screen.powerмәніoffкөрсетілім есептеледі жәнеscreen_offдеп белгіленеді. Белгі көрсетілімді санақтан ешқашан алып тастамайды.
Реттілік, қайталаулар және тізбек
- Сол
batch_seqсол байттармен200жәнеduplicate: trueжауабын алады және бір рет есептеледі. Солbatch_seqбасқа байттармен409 batch_conflictболады, ештеңе есептелмейді. - Әр ойнатқыш үшін платформа қабылданған жазба нөмірінің ең жоғарысын сақтайды. Одан аспайтын нөмірлі жазба қайталама болып табылады: тізімделеді, бірақ есептелмейді. Ескі жазбаларды жаңа
batch_seqастында қайта жіберу санақты ешқашан екі еселемейді; платформа мұны нөмірлеудің кері қайтуы деп жазады. - Қабылданған ең жоғары нөмірден біреуден артық жоғары жазба нөмірі қабылданады және олқылық ретінде жазылады. Нөмірлеуін жоғалтқан ойнатқыш жаңа құрылғы ретінде қайта тіркеледі.
- Платформада
batch_seq - 1пакеті болып, оның хэшіprev_sha256мәнінен өзгеше болса, пакет бәрібір қабылданады, ал тізбектің үзілуі жазылады.
Жауап
{"batch_seq": 1042, "received": 12, "accepted": 10, "duplicates": 0, "refused": 2, "flagged": 1, "duplicate": false,
"items": [{"index": 1, "status": "flagged", "flags": ["incomplete"]}, {"index": 10, "status": "refused", "reason": "time_in_future"},
{"index": 11, "status": "refused", "reason": "end_before_start"}]}
items тізімінде тек сөзсіз қабылданбаған жазбалар аталады. index 0-ден санала бастайды. Таза пакетте тізім бос.
CMS жүйесінен жіберу
Ойнатқыштары CMS астында жұмыс істейтін оператор олардың көрсетілімдерін CMS жүйесінен бір қол қойылған пакетпен көптеген ойнатқыш үшін хабарлай алады.
Консольде бір реттік баптау
Мұны тек оператор ұйымының әкімшісі «Интеграциялар» бөлімінде жасай алады. Әр қадам аудит журналына жазылады.
- CMS орнатылымын тіркеңіз: атауы, түрі және ашық кілті, яғни DER SubjectPublicKeyInfo құрылымының base64 түріндегі ECDSA P-256 кілті. Жабық кілт CMS жүйеңізден ешқашан шықпайды. Консоль әр пакетке кіретін көз идентификаторын көрсетеді.
- Құрылымдарыңыздың біріне қызмет ететін CMS-тің әр ойнатқышын байланыстырыңыз: CMS оны қалай атайтыны (жазбалардағы
player, 64 таңбаға дейін) және құрылым. Сыртқы идентификатор орнатылымға бір рет қолданылады. Байланыспаған ойнатқыштың көрсетілімдеріplayer_unknownдеп қабылданбайды. write:playsрұқсаты бар API кілтін жасаңыз. Аутентификация және API кілттері бөлімін қараңыз.- Кілтті ауыстыру үшін орнатылымға жаңа ашық кілтті тіркеңіз. Жаңа кілт бірден қолданылады; ескісі тағы 24 сағат жарамды болып қалады, содан кейін
401 source_unauthorizedжауабымен қабылданбайды. - Кілт ағып кетсе, оны бірден аяқтаңыз:
POST /api/v1/pop-sources/{id}/keys/{fingerprint}/revoke(оператор әкімшісі). Жаңа кілт тіркелгенше көз пакеттерді қабылдамайды. Әрбір пакеттің денесіндеX-Tanba-Sourceтақырыбымен бірдейsource_idболуы тиіс.
Пакетке қол қою
Қолтаңба JSON денесінің нақты байттары үшін ES256, gzip жіберсеңіз, ашқаннан кейінгі байттар үшін. Ол шикі түрде жазылады: r, содан кейін s, әрқайсысы 32 байт, толтырусыз base64url. Төмендегі көмекшіні pop_client.py деп сақтаңыз. Оған Python 3 және cryptography пакеті қажет.
import base64, gzip, hashlib, json, sys, urllib.request
from datetime import datetime, timezone
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec, utils
def new_key(path):
"""Run once. Keep the private key; register the printed public key in the console."""
key = ec.generate_private_key(ec.SECP256R1())
with open(path, "wb") as f:
f.write(key.private_bytes(serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption()))
der = key.public_key().public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo)
print("public key:", base64.b64encode(der).decode())
def load_key(path):
with open(path, "rb") as f:
return serialization.load_pem_private_key(f.read(), password=None)
def sign(key, body: bytes) -> str:
r, s = utils.decode_dss_signature(key.sign(body, ec.ECDSA(hashes.SHA256())))
return base64.urlsafe_b64encode(r.to_bytes(32, "big") + s.to_bytes(32, "big")).rstrip(b"=").decode()
def send(base, api_key, source_id, key, batch_seq, prev_sha256, records):
body = json.dumps({"schema": "tanba.pop/1", "source_id": source_id, "batch_seq": batch_seq, "prev_sha256": prev_sha256,
"sent_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.000Z"), "records": records},
separators=(",", ":")).encode()
req = urllib.request.Request(base + "/api/v1/pop/batches", data=gzip.compress(body), method="POST", headers={
"Authorization": "Bearer " + api_key, "X-Tanba-Source": source_id, "X-Tanba-Signature": sign(key, body),
"Content-Type": "application/json", "Content-Encoding": "gzip"})
with urllib.request.urlopen(req, timeout=60) as resp:
answer = json.load(resp)
return answer, hashlib.sha256(body).hexdigest() # the hash is the next batch's prev_sha256
if __name__ == "__main__":
if sys.argv[1] == "keygen": # python3 pop_client.py keygen cms-key.pem
new_key(sys.argv[2])
elif sys.argv[1] == "sign": # python3 pop_client.py sign cms-key.pem batch.json
print(sign(load_key(sys.argv[2]), open(sys.argv[3], "rb").read()))
Кілтті бір рет жасап, басылған ашық кілтті консольде тіркеңіз:
python3 pop_client.py keygen cms-key.pem
curl арқылы жіберу
Пакетті batch.json файлына жазыңыз, файлға қол қойыңыз және сол байттарды жіберіңіз. --data-binary пайдаланыңыз: -d жол үзілімдерін алып тастар еді, қолтаңба сәйкес келмей қалар еді.
export POP_API_KEY='tnbk_EXAMPLE_secret'
export POP_SOURCE='3f6c1d2a-8b47-4e19-a5d0-7c2e9b14f836'
cat > batch.json <<'EOF'
{"schema":"tanba.pop/1","source_id":"3f6c1d2a-8b47-4e19-a5d0-7c2e9b14f836","batch_seq":1042,"prev_sha256":"","sent_at":"2026-10-14T09:05:00.120Z","records":[{"kind":"play","player":"1001:55:2","seq":18,"play_id":"7c1e9a40b2d35f68","approval_number":"TNB-2026-000123","media_sha256":"9f2b6a41c7d83e05a1b4c6d7e8f90123456789abcdef0123456789abcdef0123","start":"2026-10-14T09:04:50.000Z","end":"2026-10-14T09:05:00.000Z","duration_ms":10000}]}
EOF
curl -X POST 'https://app.tanba-ooh.kz/api/v1/pop/batches' \
-H "Authorization: Bearer $POP_API_KEY" \
-H "X-Tanba-Source: $POP_SOURCE" \
-H "X-Tanba-Signature: $(python3 pop_client.py sign cms-key.pem batch.json)" \
-H 'Content-Type: application/json' \
--data-binary @batch.json
Python арқылы жіберу
from pop_client import load_key, send
key = load_key("cms-key.pem")
records = [{"kind": "play", "player": "1001:55:2", "seq": 18, "play_id": "7c1e9a40b2d35f68",
"approval_number": "TNB-2026-000123",
"media_sha256": "9f2b6a41c7d83e05a1b4c6d7e8f90123456789abcdef0123456789abcdef0123",
"start": "2026-10-14T09:04:50.000Z", "end": "2026-10-14T09:05:00.000Z", "duration_ms": 10000}]
answer, body_hash = send("https://app.tanba-ooh.kz", "tnbk_EXAMPLE_secret", "3f6c1d2a-8b47-4e19-a5d0-7c2e9b14f836",
key, batch_seq=1042, prev_sha256="", records=records)
print(answer)
body_hash мәнін келесі пакеттің prev_sha256 мәні ретінде сақтаңыз. Ойнатқыштардың seq есептегіштерін, batch_seq мәнін және дене хэшін өз қоймаңызда сақтаңыз, сонда қайта іске қосылғаннан кейін нөмірлеу қайталанбай, жалғаса береді.
Өз жүктемеңізді жазбаларға сәйкестендіру
player: ойнатқышты байланыстырған сыртқы идентификатор, мысалы, кадрдың үш идентификаторы:арқылы біріктірілген.end: UTC уақытымен. Жүктемеде алаңның жергілікті уақыты болса, оны аударыңыз; Қазақстан үшін белдеу Asia/Almaty.start: жүктемеде тек ұзақтық болса,endминус ұзақтық.play_id: ойнатқыш үшін бірегей көрсетілімнің кез келген тұрақты идентификаторы, мысалы, жүктеме жолы SHA-256 мәнінің алғашқы 16 hex таңбасы.seq: сіздің адаптеріңіз береді,endреті бойынша ойнатқыштың әр жазбасына +1.approval_numberжәнеmedia_sha256: сіз жүргізетін кестеден, онда әр ролик өзі жүретін келісумен және файлының хэшімен байланысқан. Ролигі кестеде жоқ жолды жіберу мүмкін емес; оны жібермей, операторға көрсетіңіз.
Шектеулер
| Пакеттегі жазбалар | 10 000 |
| Дене | жолда 4 МБ; ашқаннан кейін 16 МБ және қысылған көлемнен 20 еседен артық емес |
| Пакеттер | орнатылымға секундына 2 (жылдам жіберу 10) |
| Шақырулар | API кілтіне секундына 10 (жылдам жіберу 30) |
| Жазбалар | ұйымға сағатына 2 000 000 |
Шектеуден асқан сұрау Retry-After тақырыбымен 429 rate_limited жауабын алады, ал өлшем шектеулері үшін 413.
Ойнатқыштан жіберу
Ойнатқыш консольдегі токен арқылы бір рет тіркеледі, содан кейін өзі хабарлайды. Сертификат арнасында ол клиенттік сертификатын көрсетіп, денеге құрылғы кілтімен қол қояды; қолтаңбалы арнада денеге тіркеу кезінде жазылған кілтпен қол қояды, ал денеде device_id және ts болады, ts платформа сағатынан 300 секундтан алыс болмауы тиіс (екі арна да құрылғыға 10 секундта бір пакет қабылдайды, үзілістен кейін қатарынан 3-ке дейін). Қолтаңба жоғарыдағыдай жасалады. Шақырулар Құрылғы протоколы бетінде тізілген.
Қателер
Қателер тұрақты code өрісі бар problem құжаттары түрінде келеді.
| Статус | code | Қашан |
|---|---|---|
| 400 | invalid_json, schema_unknown | Дене оқылмайды, schema белгісіз |
| 400 / 401 | bad_signature | Қолтаңба расталмайды (сертификат арнасында 400, мұнда дене дәлел ретінде бөлек сақталады; қалғандарында 401, ештеңе сақталмайды) |
| 401 | device_unauthorized, device_cert_required, stale_request | Тұлғаны растайтын деректер белгісіз, кері қайтарылған немесе мерзімі өткен; қолтаңбалы арнада ts ауқымнан тыс |
| 401 | source_unauthorized | CMS арнасы: көз белгісіз немесе өшірілген, X-Tanba-Source тақырыбы жоқ немесе кілт 24 сағаттан бұрын ауыстырылған |
| 403 | forbidden, key_scope_denied | CMS арнасы: көз басқа ұйымға тиесілі, шақырушы API кілті емес немесе кілтте write:plays жоқ |
| 409 | batch_conflict | batch_seq басқа мазмұнды пакетпен алынған |
| 409 | legacy_after_pop | tanba.pop/1 жіберіп қойған құрылғыдан бұрынғы пішімдегі пакет; оны қайталамаңыз |
| 413 | body_too_large, batch_too_large | Өлшем шектеулерінен асты |
| 415 | unsupported_media_type | CMS арнасы: JSON емес немесе gzip-тен басқа кодтау |
| 422 | validation_failed | Қабық өрістері: batch_seq, prev_sha256 пішімі, бос events, жоқ немесе сәйкес келмейтін source_id |
| 429 | rate_limited | Жиілік шектеулерінен асты |
Сақталғанды тексеріңіз
Әрбір қабылданған пакет алынған нақты байттармен, қолтаңба тақырыбымен, дене SHA-256 мәнімен және оған қол қойған тұлғаны растайтын деректермен бірге сақталады. Ашық кілті бар кез келген адам сақталған пакетті алып, хэшін есептеп, қолтаңбасын тексеріп, платформа сандарына сенбей-ақ prev_sha256 бойынша тізбекті және seq бойынша жазба нөмірлерін аралап шыға алады. Платформа қабылданған статистиканы күн сайын қалай мөрлейтіні және мөрді офлайн қалай тексеру керек екені Тізімдемені оқу және оның дәлелдерін тексеру нұсқаулығында. Тексеру құралы Жүктеулер бетінде.