11.14. Afronding¶
Je hebt Bluetooth Low Energy doorlopen van de radio tot aan de Python-API die wordt gebruikt om het aan te sturen:
De motivatie – BLE is het antwoord wanneer de camera met iets dichtbij wil praten zonder enige infrastructuur ertussen. Een telefoon in dezelfde ruimte, een wearable om een pols, een baken aan een muur. Korte afstand, geen netwerk om aan deel te nemen, vrijwel geen stroomverbruik.
De radio – 2,4 GHz, 40 kanalen: drie voor adverteren, 37 voor verbindingsgegevens, gehopt op een pseudo-willekeurige volgorde met adaptieve vermijding van rumoerige kanalen. Korte pakketten, radio’s die grotendeels slapen.
De linklaag – pakketframing, adressering, verbindingsplanning, retransmissie en linklaagversleuteling. Niets daarvan wordt geconfigureerd vanuit Python; het schemert allemaal door in de verbindingsparameters en de MTU.
Generic Access Profile (GAP) – ontdekkings- en verbindingsbeheer. Vier rollen: peripheral en broadcaster (adverteren), central en observer (scannen). Advertentie-payloads dragen de lokale naam, service-UUID’s, appearance en fabrikantspecifieke gegevens – 31 bytes plus een optionele scan-respons van 31 bytes. Het verbindingsinterval, de peripheral-latentie en de supervision-timeout bepalen hoe een open verbinding aanvoelt.
Generic Attribute Profile (GATT) – een boom van services, elk met characteristics, elk optioneel met descriptors, geïdentificeerd door UUID’s (16-bit voor Bluetooth-SIG-standaarden, 128-bit voor aangepaste). Vijf bewerkingen: read en write (pull, door client geïnitieerd), notify en indicate (push, door server geïnitieerd, geabonneerd via de Client Characteristic Configuration Descriptor). De payloadgrootte wordt begrensd door de onderhandelde MTU.
De Python-API –
aioblezet elk BLE-patroon om in een asyncio-coroutine. Een peripheral isaioble.advertise()die over verbindingen loopt, metService/Characteristic-objecten die eenmalig worden gebouwd en vastgelegd dooraioble.register_services(). Een central isaioble.scan()om een peer te vinden,connect()om de verbinding te openen,service()encharacteristic()om de externe GATT-boom te doorlopen, en daarnaread()/write()/subscribe()/notified()voor de daadwerkelijke gegevens. Verbroken verbindingen komen naar boven alsaioble.DeviceDisconnectedErrorbinnen de coroutine die stond te wachten.L2CAP-kanalen – de nooduitgang voor bulk-bytestromen die niet passen in het key/value-model van GATT.
aioble.DeviceConnection.l2cap_accept()/l2cap_connect()openen een kanaal per applicatie bovenop de GAP-verbinding, met krediet-flow-gecontroleerde send / recv en een grotere MTU dan GATT kan dragen.Pairing en versleuteling – BLE-verbindingen zijn standaard publiek.
aioble.DeviceConnection.pair()initieert een sleuteluitwisseling die een versleutelde verbinding oplevert;bond=True(de standaard) bewaart de sleutels zodat volgende verbindingen de handshake overslaan. Zondermitm=Trueen een bruikbare IO-capaciteit beschermt versleuteling tegen passieve afluisteraars, maar niet tegen een actieve omleiding tijdens de oorspronkelijke pairing.
Dat is genoeg om camera-applicaties te schrijven die status publiceren als een peripheral, sensorgegevens lezen als een central, live waarden naar een telefoon pushen via BLE, de verbinding beveiligen met een pair-and-bond-stap, en – voor het zeldzame geval van bulkoverdracht – van GATT af te stappen naar een L2CAP-kanaal.
11.14.1. Probleemoplossing¶
BLE-storingen zijn meestal mismatches tussen wat de twee kanten verwachten, en een inspector aan de telefoonkant is de snelste manier om te zien wiens verwachtingen niet kloppen. De standaardtool is nRF Connect for Mobile (Nordic Semiconductor, gratis op Android en iOS): hij scant, verbindt, doorloopt de GATT-database, leest en schrijft characteristics, en abonneert zich op notificaties – zodat het gedrag aan de camerakant geïsoleerd getest kan worden, zonder überhaupt een begeleidende app te schrijven.
De veelvoorkomende faalmodi:
“Mijn apparaat verschijnt in de scanner maar wil niet verbinden.” Meestal heeft het advertentiepakket
connectable=False(broadcaster-modus), of een eerdere verbinding is nog open en de camera is al voorbijaioble.advertise(). Voeg print-statements toe rond de advertise-aanroep om dit te bevestigen.“exchange_mtu(512) liep maar mijn notificaties zijn nog steeds beperkt tot 20 bytes.” De onderhandelde MTU is
min(local, peer)– de telefoon of central-bibliotheek heeft mogelijk geen grotere MTU aan zijn kant aangevraagd, in welk geval de verbinding op 23 blijft. Inspecteermtunadatexchange_mtu()terugkeert. Merk ook op datexchange_mtu()slechts één keer per verbinding werkt; roep het aan vóór de eerste grote bewerking.“Pairing faalt met een generieke fout.” Twee gebruikelijke boosdoeners: de IO-capaciteit-mismatch (vragen om
mitm=Trueop een camera dieio=3/ geen invoer geen uitvoer declareert – er is geen manier om de numerieke code te bevestigen, dus de pairing-engine geeft het op), en een wild verkeerde wandkloktijd op de camera wanneer de peer die vereist. Stel de klok in metntptime.settime()vóór de eerste pairing-poging.“Notificaties komen nooit aan bij de client.” Twee dingen om te controleren, in volgorde: (a) is de characteristic gedeclareerd met
notify=True? – de eigenschapsbit moet aan de serverkant gezet zijn; (b) heeft de clientsubscribe()aangeroepen? – zonder het schrijven van de Client Characteristic Configuration Descriptor (CCCD) krijgt de server te horen dat geen enkele client notificaties wil en verwerpt ze stilzwijgend.“De geadverteerde naam is afgekapt of ontbreekt.” De advertentie-payload is 31 bytes, en de flags + service-UUID + appearance-velden nemen elk bytes van de top af. Een lange
name=plus meerdere service-UUID’s loopt over. Verkort ofwel de naam of gebruik actief scannen zodat de scan-respons (nog eens 31 bytes) de overloop draagt. nRF Connect toont beide helften apart, wat de splitsing duidelijk maakt.“L2CAP-connect werpt onmiddellijk een fout.” Meestal een PSM-mismatch – beide kanten moeten out of band hetzelfde PSM-nummer overeenkomen. Een
L2CAPConnectionErrordraagt de Bluetooth-statuscode als eerste argument; status2(“PSM not supported”) is de verklikker.“Gebonden verbindingen activeren nog steeds een volledige pairing-handshake bij elke herverbinding.”
aioble.security.load_secrets()werd niet aangeroepen bij het opstarten. Zonder dat staan de opgeslagen sleutels in het flashgeheugen maar worden nooit in het geheugen geladen, dus de identiteit van de peer is onbekend en pairing loopt elke keer vanaf nul.
Wanneer al het andere faalt, stelt de lager-niveau bluetooth-module een IRQ-callback bloot die afgaat voor elke onderliggende gebeurtenis; je er kort op abonneren en de gebeurtenissen printen is het equivalent van een Wireshark-trace voor de camerakant.
11.14.2. Deze referentie later gebruiken¶
Behandel de Bluetooth-hoofdstukken als referentiemateriaal; terugkomen voor de exacte indeling van de advertentie-payload van een peripheral of de central-scan-en-abonneer-stroom is het bedoelde gebruik. De referentiepagina’s aioble — Async BLE en bluetooth — low-level Bluetooth lijsten elke methode, flag en constante op één plek op wanneer de vraag gewoon is “wat is de exacte naam van deze aanroep”.