11.4. Oglašavanje i skeniranje

Dva BLE uređaja koja se nikada prije nisu susrela moraju se prvo međusobno pronaći. Umrežavanje to rješava dodjeljivanjem adrese svakom uređaju iz zajedničkog skupa i omogućavanjem da svaka strana dosegne drugu kroz usmjerivače. BLE nema usmjerivača, nema zajedničkog skupa, i – između većine parova uređaja – nema nikakvog prethodnog odnosa. Generic Access Profile (GAP) umjesto toga rješava otkrivanje obrascem odašiljanja i slušanja. Jedna strana oglašava – odašilje kratki paket na tri kanala za oglašavanje u redovitom intervalu, opisujući tko je. Druga strana skenira – prelazi po ista tri kanala slušajući te pakete.

GAP definira četiri uloge oko tog obrasca, svaku kao određenu kombinaciju oglašavanja i slušanja.

11.4.1. Četiri GAP uloge

Matrica dva po dva. Redci su označeni sa "oglašava" i "ne oglašava". Stupci su označeni sa "prihvaća veze" i "ne prihvaća veze". Četiri ćelije sadrže nazive uloga: Peripheral, Broadcaster, Central, Observer.

Četiri GAP uloge. Okomita os je oglašava li uređaj; vodoravna os je prihvaća li (ili inicira) veze.

  • Peripheral oglašava pakete koji govore „ovdje sam i možeš se spojiti na mene”. Kada drugi uređaj otvori vezu, peripheral prestaje oglašavati i počinje posluživati GATT zahtjeve. Pojasevi za mjerenje otkucaja srca, termometri i većina kamera-kao-senzora djeluju kao peripherali.

  • Central skenira u potrazi za peripheralima, bira jednog i inicira vezu. Nakon spajanja govori GATT kao klijent. Telefoni, prijenosna računala i kamere koje djeluju kao sakupljači podataka su centrali.

  • Broadcaster oglašava, ali nikada ne prihvaća veze. Njegov sadržaj oglašavanja jest podatak – nema se na što spojiti. iBeaconi i većina signalnih odašiljača prisutnosti u trgovinama su broadcasteri.

  • Observer skenira ta oglašavanja i čita sadržaj, opet bez ikakvog spajanja. Kamera koja sluša obližnje signalne odašiljače i djeluje na temelju onoga što čuje jest observer.

Jedan uređaj može istovremeno igrati više od jedne uloge – kamera može biti peripheral koji objavljuje vlastito stanje i central koji se spaja na obližnji senzor. Radio multipleksira posao.

11.4.2. Što sadrži paket oglašavanja

Paket oglašavanja je mali: 31 bajt sadržaja, ili 62 ako oglašivač također objavljuje scan response koji skeneri mogu zatražiti u hodu. Sadržaj je popis kratkih tipiziranih polja:

  • Zastavice. Spojiv ili ne, opće / ograničeno otkriv.

  • Lokalno ime. Kratak, ljudima prihvatljiv niz – ime koje operativni sustav na telefonu ili prijenosnom računalu prikazuje u svom Bluetooth izborniku.

  • UUID-ovi usluga. Popis identifikatora GATT usluga koje uređaj udomljuje, tako da skener može prepoznati sposobne peripherale bez prethodnog spajanja. Pojas za mjerenje otkucaja srca oglašava 0x180D – standardni UUID usluge za otkucaje srca – i aplikacija za otkucaje srca na telefonu već samo iz toga zna da se uređaj isplati spojiti.

  • Izgled (Appearance). 16-bitna vrijednost iz Bluetoothovog popisa dodijeljenih brojeva (senzor, generička media, generički sat, …) – naznaka centralu o tome što prikazati.

  • Podaci specifični za proizvođača. Slobodni bajtovi s prefiksom ID-a tvrtke. iBeaconi koriste ovo polje za nošenje svog UUID-a, major i minor vrijednosti; prilagođene aplikacije ovdje mogu staviti što god žele.

Sadržaji oglašavanja su skučeni. Ograničenje od 31 bajta čini odabir onoga što uključiti stvarnom dizajnerskom odlukom – dugo ljudima čitljivo ime brzo može ne ostaviti mjesta za UUID-ove usluga. API aioble.advertise() uzima svako od ovih kao imenovani argument i sastavlja bajtove umjesto vas, automatski prelijevajući u scan response ako se glavni paket napuni.

11.4.3. Aktivno i pasivno skeniranje

Skener može raditi pasivno, gdje sluša pakete oglašavanja i obrađuje ono što stigne, ili aktivno, gdje također šalje scan request svakom oglašivaču i obrađuje scan response koji se vrati.

Pasivno skeniranje vidi samo početni paket oglašavanja (do 31 bajt). Aktivno skeniranje to udvostručuje – scan response je još 31 bajt koji peripheral može iskoristiti za polja koja nisu stala. Aktivno skeniranje također troši energiju na obje strane, jer skener odašilje, a oglašivač odašilje dodatni paket, pa je to izbor, a ne zadana postavka.

U API-ju aioble, active=True na aioble.scan() prebacuje način rada, a svaki ScanResult izlaže kombinirane adv_data plus resp_data kao i pomoćnike poput result.name() i result.services() koji skrivaju obradu na razini bajtova.

Napomena

Atributi adv_data i resp_data su sirovi sadržaji oglašavanja i scan responsea (bytes). Pomoćnici – name(), services(), manufacturer() – pokrivaju uobičajena standardna polja i pravi su izbor u 99% slučajeva. Posegnite za sirovim bajtovima samo kada vam treba polje proizvođača koje pomoćnici ne obrađuju (Eddystone URL-ovi, iBeacon UUID/major/minor, prilagođene vrste oglašavanja). Raspored bajtova je standardni TLV: svako polje je length, type, value....

11.4.4. Interval oglašavanja

Koliko često peripheral odašilje kompromis je između potrošnje energije i kašnjenja otkrivanja. Oglasi koji izlaze svakih 20 ms skener pokupi gotovo odmah, ali drže radio zaposlenim i prazne bateriju; oglasi svake sekunde troše gotovo nimalo energije, ali čine da skener sporije primijeti uređaj.

interval_us na aioble.advertise() postavlja interval u mikrosekundama:

  • 20.000 do 100.000 us (20 ms - 100 ms) – brzo uparivanje, aplikacija očekuje brz odgovor, uređaj priključen na napajanje.

  • 250.000 do 1.000.000 us (250 ms - 1 s) – razuman zadani izbor za peripheral na bateriju koji želi biti otkriv bez trošenja punjenja.

  • Iznad 1.000.000 us – sporo pozadinsko odašiljanje, signalni odašiljači koji svakih nekoliko sekundi šalju ažuriranje položaja.

Strana skenera ima vlastite ručice – aioble.scan() uzima interval_us i window_us (koliko često skener budi svoj radio i koliko dugo sluša svaki put). Zadane postavke su u redu; jedina uobičajena promjena je postaviti obje jednake za neprekidno skeniranje kada baterija nije briga.

11.4.5. Obrasci bez veze – broadcaster i observer

Stranice Djelovanje kao periferija i Djelovanje u ulozi centrale razrađuju spojivi oblik API-ja – gdje peripheral prihvaća vezu i dvije strane razmjenjuju podatke kroz GATT. Drugi je oblik bez veze: broadcaster odašilje sadržaj-kao-oglašavanje, a bilo koji observer u dometu može ga pročitati bez ikakvog spajanja. Signalni odašiljači, senzori prisutnosti i jednosmjerna telemetrija svi su ovdje.

Broadcaster je aioble.advertise() s connectable=False. Podaci specifični za proizvođača nose sadržaj:

import aioble
import asyncio
import struct

_COMPANY_ID = const(0xFFFF)                # 0xFFFF is "no specific vendor"

async def beacon():
    seq = 0
    while True:
        seq = (seq + 1) & 0xFFFF
        payload = struct.pack("<H", seq)
        await aioble.advertise(
            interval_us=500000,
            connectable=False,
            name="openmv-beacon",
            manufacturer=(_COMPANY_ID, payload),
            timeout_ms=1000,                # one cycle, then loop
        )

asyncio.run(beacon())

Imenovani argument timeout_ms završava poziv oglašavanja nakon jedne sekunde; vanjska petlja ga ponovno izdaje sa sljedećim rednim brojem kako bi slušatelji vidjeli svježe podatke. Zastavica connectable=False čini oglašavanje broadcaster-stila – kamera neće odgovoriti na zahtjev za spajanjem čak ni ako stigne.

Observer je odgovarajući skener samo za čitanje. Pokreće aioble.scan() zauvijek, obrađuje dolazna oglašavanja i nikada ne poziva connect()

import aioble
import asyncio

_COMPANY_ID = const(0xFFFF)

async def watch():
    async with aioble.scan(duration_ms=0, active=False) as scanner:
        async for result in scanner:
            for company, data in result.manufacturer(filter=_COMPANY_ID):
                print(result.device.addr_hex(),
                      "rssi", result.rssi, "data", data)

asyncio.run(watch())

duration_ms=0 skenira dok kontekstni upravitelj ne izađe; active=False drži observerov vlastiti radio tihim (bez scan-response zahtjeva) za najnižu potrošnju energije. Argument filter= na manufacturer() odbacuje svako oglašavanje koje ne odgovara ID-u tvrtke, pa se petlja pokreće samo za promet broadcastera.

11.4.6. Od otkrivanja do veze

Kada central odabere peripheral za razgovor, prestaje slušati, šalje connect request na kanalu za oglašavanje koji je peripheral posljednji koristio, i obje strane prelaze na poskakujuće podatkovne kanale link sloja. Peripheral u ovom trenutku obično prestaje oglašavati. Što se događa dalje – parametri veze, GATT otkrivanje, životni vijek veze – nalazi se na Veze.