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#

A two-by-two matrix. Rows are labelled "advertises" and "does not advertise". Columns are labelled "accepts connections" and "does not accept connections". The four cells contain the role names: 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.