Bluetooth Low Energy Simulator-A New Hope in IoT Development

Elämme XXI vuosisadalla, jossa eläimet eivät ehkä vieläkään puhu meille, mutta asiat alkavat ehdottomasti puhua. Kävelemme ympäriinsä lähetyksenvalvontakeskuksiemme (eli älypuhelimien) kanssa, jotka voivat hoitaa rahamme, viestintämme, uutisemme, älykotimme ja kaikki muut älykkäät ratkaisut, jotka ympäröivät meitä, lyhyesti sanottuna – elämämme.

Harjoitteletko kisaa varten? Voit tehdä sen älykkään lihas-happimonitorin Humonin avulla. Haluatko parantaa unenlaatuasi? Hanki älynauha, älykello tai unenseurantalaite (jotka kaikki käyttävät Bluetooth Low Energyä ja kommunikoivat puhelimesi kanssa). Yritätkö päästä jonnekin polkupyörällä? Käytä BLE-yhteensopivaa navigointia, jotta voit minimoida häiriötekijät, kuten ilmoitukset, mutta tiedät silti, miten pääset haluamaasi paikkaan. Ehkä haluaisit tietää, milloin toimistokahvi on valmis? Me huolehdimme sinusta!

Mutta esineiden internetin tulon ja maailman lisääntyvän yhteenkytkeytyneisyyden myötä meille kehittäjille tuli uusia haasteita.

BLE-yhteensopivan sovelluksen kehittäminen

Jos olet koskaan työskennellyt mobiilisovelluksen parissa, joka muodostaa yhteyden Bluetooth Low Energy -laitteeseen, tiedät, että se ei ole kaikkein helpoin tehtävä. Sovelluksessa on monia näyttöjä ja sisäisiä tiloja, jotka liittyvät oheislaitteeseen ja sen käyttäytymiseen. Sovellus luodaan usein laitteen laiteohjelmiston (joskus jopa laitteiston (!!!)) rinnalla, yhteys voi olla ailahteleva, ulkoinen käyttöliittymä epävakaa, sisäinen logiikka buginen. Tämän seurauksena tiimi tuhlaa paljon aikaa Known Issues™ -ongelmiin, kun se testaa ominaisuuksiaan.

Yleisesti ottaen on kaksi tapaa lähestyä tätä asiaa:

  1. Ensiksi on helppo, aikaa vievä tapa: käytetään fyysistä älypuhelinta ja BLE-laitetta, käydään läpi kaikki vaivannäkö, jotta saadaan yhdistettyä ja asetettua laite siihen tilaan, jossa sen on oltava, ja luodaan testausolosuhteet uudelleen.
  2. Sitten on vaikea tapa: abstrahoidaan laite, luodaan yksinkertainen mock-up, joka voi piilottaa varsinaisen BLE-käsittelyn. Näin voit työskennellä Android-emulaattorilla/iOS-simulaattorilla, säästää aikaa myöhemmin ja voit ajaa automaattisia testejä CI:ssäsi. Samalla se lisää ylläpitokustannuksia ja tuo uuden riskin, koska todellista viestintää ei testata joka kerta, kun koodi ajetaan. Loppujen lopuksi tuo Bluetooth-oheislaite on luultavasti sovelluksemme ytimessä, eikä se saa katkaista yhteyttä odottamatta tai käyttäytyä oudosti.

Ystävämme Frontsidessa – Austinissa toimivassa frontend-ohjelmistosuunnittelu- ja arkkitehtuurikonsulttiyrityksessä – ovat tunnistaneet, että tarvitaan tehokkaampi ratkaisu. He pyysivät meitä kehittämään avoimen lähdekoodin ratkaisun luotettavaa BLE-yhteensopivaa sovelluskehitystä varten, josta kaikki voisivat hyötyä.

Ja niin tulee…

BLEmulator /pronun.: bleh-mulator/, Bluetooth Low Energy -simulaattori.

BLEmulator on täällä tekemässä elämästäsi helpompaa! Se käsittelee kaiken tuotantoon liittyvän BLE-koodisi ja simuloi todellisen oheislaitteen ja järjestelmän Bluetooth-pinon käyttäytymistä. Se on yksinkertainen ja joustava, ja sen avulla voit luoda sekä perusmockin että täyden simulaation BLE-yhteensopivasta laitteesta. Ja mikä parasta – se on avoimen lähdekoodin omaava!

Sen avulla voit testata laitteesi konseptia ilman laitteistoprototyyppien rakentamisesta aiheutuvia kustannuksia. Sen avulla mobiilitiimisi voi edetä eteenpäin odottamatta laiteohjelmia tai prototyyppejä, vain määrittelyn avulla. Sen avulla voit työskennellä vain Android-emulaattorilla tai iOS-simulaattorilla, mikä mahdollistaa suuremman liikkuvuuden, helpomman etätyöskentelyn ja fyysisten älypuhelinten rajallisen saatavuuden välttämisen. Sen avulla voit testata sovelluksiasi automaattisissa testeissä, joita CI:si ajaa.

Tällä hetkellä BLEmulator on saatavilla Flutterille ja toimii vain FlutterBleLibimme kanssa.

Miten se toimii

Flutter monialustakehyksenä tarvitsee natiivit riippuvuudet molemmille alustoille. Normaalisti ne olisivat osa itse kirjastoa, mutta käytimme tässä erilaista lähestymistapaa. Polidealla on React Native BLE -kirjasto, nimeltään react-native-ble-plx, joka on kollegojemme mahtava työ. Päätimme purkaa siitä kaiken natiivilogiikan erilliseen kirjastoon, joka tunnetaan nimellä Multiplatform BLE Adapter. Näin olemme luoneet yhteisen ytimen, jota käyttävät sekä react-native-ble-plx että Flutter-lisäosamme FlutterBleLib. Sivuvaikutuksena loimme yhteisen abstraktion, jota käytetään natiivisillassa, BleAdapter, joka on täydellinen lähtökohta simuloinnille!

Tältä näyttää FlutterBleLibin tietovirta:

  1. Kutsu metodi johonkin FlutterBleLib-objektiin (BleManager, Peripheral, Service, Characteristic)
  2. Tikkakoodi lähettää metodin nimen ja sen parametrit natiivisillalle
  3. Natiivisilta vastaanottaa datan ja deserialisoi sen tarvittaessa
  4. Natiivisilta kutsuu sopivaa metodia BleAdapter-instanssissa Multiplatform BLE Adapterista
  5. BleAdapter kutsuu metodia joko RxAndroidBle:ssä tai RxBluetoothKit:ssä, alustasta riippuen
  6. RxAndroidBle/RxBluetoothKit kutsuu järjestelmämetodia
  7. Järjestelmä palauttaa vastauksen välittäjälle
  8. Välittäjä palauttaa vastauksen BleAdapterille
  9. BleAdapter vastaa natiiville sillalle
  10. Natiivi. bridge mapittaa vastauksen ja lähettää sen Dartille
  11. Dart jäsentää vastauksen ja palauttaa sen alkuperäiselle kutsujalle

Meillä oli työmme valmiina – kohdat 4-9 ovat ihanteellisia sisäänmenopisteitä, joissa on asetettu ulkoinen sopimus. Injektoimalla BleAdapterin eri toteutuksen voimme kytkeä simulaation päälle milloin haluamme.

Seuraavaksi meidän piti päättää, missä simulaation piti tapahtua. Päätimme pitää mahdollisimman suuren osan simuloinnista Dartissa kahdesta syystä:

  1. Yksi määritelmä molemmille alustoille

On tärkeää minimoida sekä niiden paikkojen määrä, joissa on mahdollista tehdä virhe, että simuloidun oheislaitteen luomiseen ja ylläpitoon tarvittava työmäärä.

  1. Alustalle natiivisti kuuluva kieli

Tällä on muutama etu. Ensinnäkin kehittäjät työskentelevät tehokkaammin tunnetun työkalun kanssa, joten lisäkielten käyttöönottoa tulisi välttää. Toiseksi emme halunneet rajoittaa asioita, joita on mahdollista tehdä simuloidulla oheislaitteella. Jos haluat pyytää vastausta joiltakin HTTP-palvelimilta (ehkäpä kehittyneemmällä simulaatiolla, joka käyttää itse laiteohjelmistoa?), voit tehdä sen ongelmitta samalla koodilla, jonka kirjoittaisit mitä tahansa muuta HTTP-viestintää varten sovelluksessasi.

Simuloitu kutsureitti näyttää tältä:

  1. Kutsu metodi johonkin FlutterBleLib-objektiin (BleManager, Peripheral, Service, Characteristic)
  2. Tikka-koodi lähettää metodin nimen ja sen parametrit natiivisillalle
  3. Natiivisilta vastaanottaa datan ja deserialisoi sen tarvittaessa
  4. Natiivisilta kutsuu simuloidun adapterin sopivaa metodia

    Changed osa alkaa nyt

  5. BleAdapteri – tässä tapauksessa simulaattorista tuleva – välittää kutsun BLEmulaattorin natiivisillalle
  6. BLEmulaattori joko tekee logiikan itse (jos se ei liity oheislaitteeseen) tai kutsuu toimitetun oheislaitteen sopivaa metodia. käyttäjän
  7. Vastaus välitetään BLEmulaattorin natiiville sillalle
  8. BLEmulaattorin natiivi silta välittää vastauksen SimulatedAdapterille
  9. SimulatedAdapter vastaa natiiville sillalle

    Paluu alkuperäiseen virtaukseen

  10. Natiivi silta. mapittaa vastauksen ja lähettää sen Dartille
  11. Dart jäsentää vastauksen ja palauttaa sen alkuperäiselle kutsujalle

Siten käytät kaikkea BLE-käsittelykoodiasi ja työskentelet FlutterBleLibin tarjoamilla tyypeillä riippumatta siitä, mitä backendiä käytät, olipa kyseessä sitten todellinen järjestelmän BT-pino tai simulaatio. Tämä tarkoittaa myös sitä, että voit testata vuorovaikutusta oheislaitteen kanssa automaattisissa testeissä CI:ssäsi!

Kuinka sitä käytetään

Olemme käsitelleet, miten se toimii ja mitä mahdollisuuksia se tarjoaa, joten hypätään nyt siihen, kuinka sitä käytetään.

  1. Lisää riippuvuus kohtaan blemulator pubspecissäsi.yml
  2. Luo oma simuloitu oheislaite käyttämällä pluginin tarjoamia luokkia SimulatedPeripheral, SimulatedService ja SimulatedCharacteristic (käsittelen sitä yksityiskohtaisesti seuraavassa osiossa)
  3. Lisää oheislaite BLEmulaattoriin käyttämällä Blemulator.addPeripheral(SimulatedPeripheral)
  4. Kutsu Blemulator.simulate() ennen kuin kutsut BleManager.createClient():aa FlutterBleLib:stä

Se on siinä, vain neljä vaihetta ja olet valmis! No, myönnän, että monimutkaisin vaihe on tavallaan ohitettu, joten puhutaanpa toisesta kohdasta – oheislaitteen määrittelystä.

Oheislaitesopimus

Perustan seuraavat esimerkit Texas Instrumentsin CC2541 SensorTag:iin keskittyen IR-lämpötila-anturiin.

Meidän on tiedettävä, miltä palvelun UUID:t ja sen ominaisuudet näyttävät. Olemme kiinnostuneita kahdesta kohdasta dokumentaatiossa.

UUID:t, joista olemme kiinnostuneita:

  • IR-lämpötilapalvelu: F000AA00-0451-4000-B000-000000000000 Tämä palvelu sisältää kaikki lämpötila-anturiin liittyvät ominaisuudet.
  • IR-lämpötilatiedot: F000AA01-0451-4000-B000-000000000000

    Lämpötilatiedot, joita voidaan lukea tai seurata. Tietojen muoto on ObjectLSB:ObjectMSB:AmbientLSB:AmbientMSB. Se lähettää ilmoituksen jokaisen määritettävissä olevan ajanjakson aikana seurannan aikana.

  • IR-lämpötilan konfig: F000AA02-0451-4000-B000-000000000000

    Asensorin päälle/pois-kytkin. Tälle ominaisuudelle on kaksi kelvollista arvoa::

    • 00-anturi asetettu lepotilaan (IR-lämpötilatiedot ovat neljän tavun nollia)
    • 01-anturi otettu käyttöön (IR-lämpötilatiedot lähettävät oikeita lukemia)
  • IR-lämpötilajakso: F000AA03-0451-4000-B000-000000000000

    Ilmoitusten välinen aika.alaraja on 300 ms, yläraja 1000 ms. Ominaisuuden arvo kerrotaan 10:llä, joten tuetut arvot ovat 30:n ja 100:n väliltä.

Muuta emme etsineet, joten siirrymme toteutukseen!

Yksinkertaisin oheislaite

Yksinkertaisin simulointi hyväksyy minkä tahansa arvon ja onnistuu kaikissa toiminnoissa.

Dartissa se näyttää tältä:

Lyhyt ja ytimekäs, näyttää melkein JSON:lta.

Tässä tapahtuu näin: Loimme oheislaitteen nimeltä SensorTag, jolla on ajonaikana määritetty ID (mikä tahansa merkkijono kelpaa, mutta sen on oltava yksilöllinen BLEmulaattorin tuntemien oheislaitteiden keskuudessa). Kun oheislaitteen skannaus on päällä, se ilmoittaa oletusskannaustiedot 800 millisekunnin välein. Se sisältää yhden palvelun, jonka UUID-tunnus on mainostiedoissa. Palvelu sisältää 3 ominaisuutta, aivan kuten oikeassa laitteessa, ja kaikki ne ovat luettavissa. Ensimmäiseen ominaisuuteen ei voi kirjoittaa, mutta se tukee ilmoituksia; kahta muuta ominaisuutta ei voi seurata, mutta niihin voi kirjoittaa. Ominaisuuksissa ei ole virheellisiä arvoja. BLEmulaattori ei käytä argumenttia convenienceName millään tavalla, mutta se tekee määritelmästä helpommin luettavan.

IR Temperature Config ja IR Temperature Period hyväksyvät ja asettavat minkä tahansa sille annetun arvon. IR Temperature Data -ominaisuus tukee ilmoituksia, mutta ei itse asiassa koskaan lähetä niitä, koska emme ole määritelleet niitä millään tavalla.

BLEmulator tarjoaa peruskäyttäytymisen suoraan laatikosta ja huolehtii kaikkien konstruktioiden onnellisesta polusta minimoiden tarvittavan työn määrän. Vaikka se saattaa riittää joihinkin testeihin ja perusmäärittelyn noudattamisen tarkistuksiin, se ei yritä käyttäytyä kuin oikea laite.

Meidän täytyy toteuttaa mukautettu käyttäytyminen!

Pidimme kiinni sekä yksinkertaisuudesta että joustavuudesta luodessamme BLEmulatoria. Halusimme antaa kehittäjille tarvittavan hallinnan luodun oheislaitteen jokaiseen osa-alueeseen ja samalla vaatia heiltä mahdollisimman vähän työtä toimivan määritelmän luomiseksi. Saavuttaaksemme tämän tavoitteen päätimme luoda oletustoteutuksen kaikille metodeille, jotka voivat olla lähtökohtana mukautetulle käyttäytymiselle, ja annamme sinun päättää, mitä ohitetaan.

Lisätään nyt hieman logiikkaa.

Laita kytkeytyminen kestämään aikaa

Todellisessa oheislaitteessa kestää luultavasti jonkin verran aikaa, ennen kuin yhteys muodostuu. Tätä varten sinun tarvitsee vain ylikirjoittaa yksi metodi:

Se on siinä. Nyt yhteyden muodostaminen kestää 200 millisekuntia!

Yhteyden muodostamisen kieltäminen

Samankaltainen tapaus. Haluamme säilyttää viiveen, mutta palauttaa virheilmoituksen, että yhteyttä ei voitu muodostaa. Voisit ohittaa metodin ja heittää itse SimulatedBleError, mutta voit myös tehdä:

 @override Future<bool> onConnectRequest() async { await Future.delayed(Duration(milliseconds: 200)); return false; }

Oheislaitteen alustama yhteyden katkaisu

Esitettäköön, että haluat tarkistaa yhteyden uudelleen muodostamisen prosessin tai simuloida yhteyden katkeamista. Voit pyytää kollegaa juoksemaan toimiston toiselle puolelle oikean oheislaitteen kanssa tai lisätä jonkin debug-painikkeen ja tehdä sen onPress:

yourPeripheralInstance.onDisconnect();

(Tosin ensimmäinen vaihtoehto vaikuttaa tyydyttävämmältä.)

RSSI:n muokkaaminen skannaustiedoissa

Esitettäköön, että haluaisimme lajitella oheislaitteita havaitun signaalin voimakkuuden mukaan ja meidän täytyy testata sitä. Luomme muutaman simuloidun oheislaitteen, jätämme yhdelle staattisen RSSI:n ja teemme toisessa:

@overrideScanResult scanResult() { scanInfo.rssi = -20 - Random.nextInt(50); return super.scanResult();}

Tällöin meillä on pari laitetta, joilla on muuttuva RSSI ja voimme testata ominaisuutta.

MTU:n neuvotteleminen

BLEmulator tekee suurimman osan logiikasta itse, jolloin se rajoittaa MTU:n tuetulle alueelle 23-512, mutta jos haluat rajoittaa sitä enemmän, sinun kannattaa ohittaa requestMtu()-metodi:

BLEmulator neuvottelee automaattisesti korkeimman iOS:n tukeman MTU:n.

Arvojen pakottaminen tuetulle alueelle

Ominaisuuden hyväksymien arvojen rajoittamiseksi on luotava uusi luokka, joka laajentaa luokkaa SimulatedCharacteristic.

Ominaisuus rajoittaa nyt syötteen joko 0:aan tai 1:een ensimmäisellä tavulla, jättää huomiotta kaikki muut tavut ja palauttaa virheen, jos arvo ylittää tuetun alueen. Virheen palauttamisen tukemiseksi ominaisuuden on palautettava vastaus kirjoitusoperaatioon, joten writableWithoutResponse asetetaan arvoksi false.

Anturin kytkeminen päälle

Haluaisimme tietää, milloin lämpötila-anturi on päällä tai pois päältä.

Tämän saavuttamiseksi luomme uuden palvelun, jossa on kovakoodatut UUID:t:

Määrittelemäämme ominaisuutta ei voi seurata FlutterBleLibin kautta, koska siitä puuttuu isNotifiable: true, mutta sitä voi kätevästi seurata BLEmulator-tasolla. Tämä helpottaa simuloimamme kokonaisvirran hallintaa, yksinkertaistaa rakennetta ja antaa meille mahdollisuuden välttää perusluokkien tarpeettomia laajennuksia.

Ilmoitusten lähettäminen

Meiltä puuttuu edelleen IR Temperature Data -ominaisuudesta ilmoitusten lähettäminen. Hoidetaan asia kuntoon.

_emitTemperature() kutsutaan Lämpötilapalvelun konstruktorissa ja se toimii loputtomassa silmukassa. Jokaisella IR Temperature Period -ominaisuuden arvolla määritetyllä aikavälillä tarkistetaan, onko kuuntelija (isNotifying). Jos sellainen on, se kirjoittaa tietoja (nollia tai satunnaisarvoa sen mukaan, onko anturi päällä vai pois päältä) IR Temperature Data -ominaisuuteen. SimulatedCharacteristic.write() ilmoittaa mahdollisille aktiivisille kuuntelijoille uudesta arvosta.

Kehittynyt oheislaite toiminnassa

Kokonaisvaltaisen esimerkin kehittyneemmästä oheislaitteesta löydät BLEmulatorin arkistosta. Jos haluat kokeilla sitä, kloonaa arkisto ja suorita sen esimerkki.

Käyttö automatisoidussa testauksessa

Suuri kiitos tässä yhteydessä kollegalleni Paweł Byszewskille hänen tutkimuksestaan BLEmulatorin käytöstä automatisoiduissa testeissä.

Flutterissa on eri suorituskonteksti testattavalle sovellukselle ja itse testille, mikä tarkoittaa sitä, että et voi vain jakaa simuloitua oheislaitetta molempien välille ja muuttaa käyttäytymistä testistä. Se, mitä voit tehdä, on lisätä testiajuriin datan käsittelijän käyttämällä enableFlutterDriverExtension(handler: DataHandler), siirtää simuloidut oheislaitteet sovelluksesi main():een ja siirtää merkkijonoviestejä käsittelijälle sovelluksen suorituskontekstin sisällä.

Se tiivistyy seuraavasti: Wrapper sovellukselle

Ohjaamasi oheislaite

Ohjaamasi testi

Tämän mekanismin ansiosta voisit alustaa oheislaitteen miten tahansa ja kutsua mitä tahansa ennalta määrittelemääsi käyttäytymistä simuloidun laitteesi sisältä.

Katsokaa ihmeessä itseksenne

Parhaimmaksi kaikessa tässä kaikessa tulee se, että sinun ei tarvitse uskoa minua! Tarkista se itse GitHubista. Käytä sitä, pidä hauskaa sen kanssa, yritä rikkoa se ja kerro meille kaikki siitä!

Haluatko nähdä sen myös muilla alustoilla? Ota meihin yhteyttä, niin teemme siitä totta! Muista tutustua myös muihin kirjastoihimme, äläkä epäröi ottaa meihin yhteyttä, jos haluat meidän työskentelevän projektisi parissa.