Într-o tutorialul anterior, ați învățat cum să adăugați Bluetooth la o aplicație Particle Xenon. În acest fel, puteți controla LED-ul RGB de la o aplicație de testare precum nRF Connect sau Light Blue Explorer.

În această postare, vom face un pas mai departe. Vom dezvolta o aplicație Swift pentru a controla un LED Particle Mesh RGB. Dacă totul merge bine, ar trebui să aveți o aplicație de lucru în aproximativ 20 de minute!

Să începem.

Nu aveți timp chiar acum să citiți articolul complet?

Descărcați versiunea PDF aici.

Pregătirea

Creați proiectul

Odată ce totul este instalat, să trecem la lucrurile distractive!

Deschideți Xcode și accesați Fișier → Proiect nou.

Proiect nou Xcode

Selectați Aplicație cu vizualizare unică.

Informații despre proiect nou

Apoi actualizați fișierul Denumirea proiectului să fie pe placul tău. De asemenea, mi-am schimbat identificatorul organizației în com.jaredwolff. Modificați-l după cum doriți!

Selectați o locație pentru ao salva.

Apoi găsiți-vă Info.plist.

Info.plist în Xcocde

Actualizați info.plist prin adăugarea Privacy - Bluetooth Peripheral Usage Description

Descrierea pe care am ajuns să o folosesc a fost App uses Bluetooth to connect to the Particle Xenon RGB Example

Acest lucru vă permite să utilizați Bluetooth în aplicația dvs. dacă vreți vreodată să îl lansați.

Acum, să facem totul minim funcțional!

Minim funcțional

Imagine de secțiune nouă

În continuare, vom obține o aplicație minim funcțională pentru a ne conecta și a face o descoperire de servicii. Cea mai mare parte a acțiunii se va întâmpla în ViewController.swift.

Permite primul import CoreBluetooth

    import CoreBluetooth

Acest lucru ne permite să controlăm funcționalitatea Bluetooth Low Energy din iOS. Atunci să adăugăm atât CBPeripheralDelegate și CBCentralManagerDelegate la ViewController clasă.

    class ViewController: UIViewController, CBPeripheralDelegate, CBCentralManagerDelegate {

Să creăm acum variabile private locale pentru a stoca managerul central real și perifericul. Le vom înființa în continuare momentan.

    // Properties
    private var centralManager: CBCentralManager!
    private var peripheral: CBPeripheral!

În dumneavoastră viewDidLoad funcție, să inițiem centralManager

    centralManager = CBCentralManager(delegate: self, queue: nil)

Setare delegate: self este important. În caz contrar, statul central nu se schimbă niciodată la pornire.

Înainte de a ajunge mai departe, să creăm un fișier separat și să-l numim ParticlePeripheral.swift. Poate fi plasat oriunde, dar l-am plasat într-un „grup” separat numit Modele pentru mai târziu.

În interior vom crea câteva variabile publice care conțin UUID-urile pentru placa noastră de particule. Ar trebui să pară familiari!

    import UIKit
    import CoreBluetooth

    class ParticlePeripheral: NSObject {

        /// MARK: - Particle LED services and charcteristics Identifiers

        public static let particleLEDServiceUUID     = CBUUID.init(string: "b4250400-fb4b-4746-b2b0-93f0e61122c6")
        public static let redLEDCharacteristicUUID   = CBUUID.init(string: "b4250401-fb4b-4746-b2b0-93f0e61122c6")
        public static let greenLEDCharacteristicUUID = CBUUID.init(string: "b4250402-fb4b-4746-b2b0-93f0e61122c6")
        public static let blueLEDCharacteristicUUID  = CBUUID.init(string: "b4250403-fb4b-4746-b2b0-93f0e61122c6")

    }

Înapoi în ViewController.swift să împărțim biții Bluetooth.

Biti Bluetooth

Diagrama de flux pentru Bluetooth Swift în iOS

Tot ce are de-a face cu Bluetooth este bazat pe evenimente. Vom defini mai multe funcții care gestionează aceste evenimente. Iată cele importante:

centralManagerDidUpdateState se actualizează când perifericul Bluetooth este pornit sau oprit. Se va declanșa când pornește prima aplicație, astfel încât să cunoașteți starea Bluetooth. De asemenea, începem scanarea aici.

centralManager didDiscover evenimentul apare atunci când primiți rezultatele scanării. Vom folosi acest lucru pentru a începe o conexiune.

centralManager didConnect evenimentul se declanșează odată ce dispozitivul este conectat. Vom începe descoperirea dispozitivului aici. Notă: Descoperirea dispozitivului este modul în care determinăm ce servicii și caracteristici sunt disponibile. Acesta este un mod bun de a confirma la ce tip de dispozitiv suntem conectați.

peripheral didDiscoverServices primul eveniment după ce toate serviciile au fost descoperite. Observați că am trecut de la centralManager la peripheral acum că suntem conectați. Vom începe descoperirea caracteristică aici. Vom folosi UUID-ul serviciului RGB ca țintă.

peripheral didDiscoverCharacteristicsFor evenimentul va furniza toate caracteristicile utilizând serviciul UUID furnizat. Acesta este ultimul pas al lanțului de a face o descoperire completă a dispozitivului. Este păros, dar trebuie făcut o singură dată în timpul fazei de conectare!

Definirea tuturor funcțiilor Bluetooth.

Acum că știm care sunt funcțiile care se declanșează evenimentele. Le vom defini în ordinea logică în care se întâmplă în timpul unui ciclu de conectare.

Mai întâi, vom defini centralManagerDidUpdateState pentru a începe scanarea unui dispozitiv cu serviciul nostru cu particule RGB LED. Dacă Bluetooth nu este activat, nu va face nimic.

    // If we're powered on, start scanning
        func centralManagerDidUpdateState(_ central: CBCentralManager) {
            print("Central state update")
            if central.state != .poweredOn {
                print("Central is not powered on")
            } else {
                print("Central scanning for", ParticlePeripheral.particleLEDServiceUUID);
                centralManager.scanForPeripherals(withServices: [ParticlePeripheral.particleLEDServiceUUID],
                                                  options: [CBCentralManagerScanOptionAllowDuplicatesKey : true])
            }
        }

Definirea centralManager didDiscover este următorul nostru pas în acest proces. Știm că am găsit un dispozitiv dacă a avut loc acest eveniment.

    // Handles the result of the scan
        func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {

            // We've found it so stop scan
            self.centralManager.stopScan()

            // Copy the peripheral instance
            self.peripheral = peripheral
            self.peripheral.delegate = self

            // Connect!
            self.centralManager.connect(self.peripheral, options: nil)

        }

Deci, nu mai scanăm folosind self.centralManager.stopScan(). Am setat peripheral deci persistă prin intermediul aplicației. Apoi ne conectăm la acel dispozitiv folosind self.centralManager.connect

Odată conectat, trebuie să verificăm dacă lucrăm cu dispozitivul potrivit.

    // The handler if we do connect succesfully
        func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
            if peripheral == self.peripheral {
                print("Connected to your Particle Board")
                peripheral.discoverServices([ParticlePeripheral.particleLEDServiceUUID])
            }
        }

Prin compararea celor două periferice, vom cunoaște dispozitivul pe care l-am găsit mai devreme. Vom începe o descoperire de servicii folosind peripheral.discoverService. Putem folosi ParticlePeripheral.particleLEDServiceUUID ca parametru. În acest fel nu primim niciun serviciu de care nu ne pasă.

Odată ce terminăm serviciile de descoperire, vom primi un didDiscoverServices eveniment. Iterăm prin toate serviciile „disponibile”. (Deși va exista doar unul!)

    // Handles discovery event
        func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
            if let services = peripheral.services {
                for service in services {
                    if service.uuid == ParticlePeripheral.particleLEDServiceUUID {
                        print("LED service found")
                        //Now kick off discovery of characteristics
                        peripheral.discoverCharacteristics([ParticlePeripheral.redLEDCharacteristicUUID,
                                                                 ParticlePeripheral.greenLEDCharacteristicUUID,
                                                                 ParticlePeripheral.blueLEDCharacteristicUUID], for: service)
                        return
                    }
                }
            }
        }

În acest moment, aceasta este a treia oară când verificăm pentru a ne asigura că avem serviciul corect. Acest lucru devine mai util mai târziu, când există multe caracteristici și multe servicii.

Noi sunam peripheral.discoverCharacteristics cu o serie de UUID-uri pentru caracteristicile pe care le căutăm. Acestea sunt toate UUID-urile pe care le-am definit ParticlePeripheral.swift.

În cele din urmă, ne ocupăm de didDiscoverCharacteriscsFor eveniment. Repetăm ​​toate caracteristicile disponibile. Pe măsură ce iterăm, comparăm cu cele pe care le căutăm.

    // Handling discovery of characteristics
        func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
            if let characteristics = service.characteristics {
                for characteristic in characteristics {
                    if characteristic.uuid == ParticlePeripheral.redLEDCharacteristicUUID {
                        print("Red LED characteristic found")
                    } else if characteristic.uuid == ParticlePeripheral.greenLEDCharacteristicUUID {
                        print("Green LED characteristic found")
                    } else if characteristic.uuid == ParticlePeripheral.blueLEDCharacteristicUUID {
                        print("Blue LED characteristic found");
                    }
                }
            }
        }

În acest moment suntem gata să facem o descoperire completă a dispozitivului dispozitivului nostru Particle Mesh. În secțiunea următoare vom testa ce avem pentru a ne asigura că lucrurile funcționează bine.

Testarea exemplului nostru minim

Imaginea secțiunii despre testare

Înainte de a începe, dacă aveți probleme, am introdus câțiva pași de depanare în note de subsol.

Pentru a testa, va trebui să aveți un iPhone cu Bluetooth Low Energy. Majoritatea iPhone-urilor moderne o au. Ultimul iPhone care nu l-a avut, cred că a fost fie iPhone 4, fie 3G. (deci probabil esti bun)

Mai întâi, conectați-l la computer.

Mergeți în partea de sus a butoanelor de redare și oprire. Selectați dispozitivul țintă. În cazul meu mi-am ales telefonul (IPhone-ul lui Jared). De asemenea, puteți utiliza un iPad.

Selectați tipul de dispozitiv

Atunci poți să lovești Comandă + R sau lovește asta Butonul Redare pentru a încărca aplicația pe telefon.

Asigurați-vă că aveți fila jurnal deschisă. Activați-l făcând clic pe butonul panoului inferior din colțul din dreapta sus.

Panoul inferior din Xcode pentru jurnale

Asigurați-vă că aveți o configurare a dispozitivului mesh și rulați exemplul de cod. Poti sa te duci la acest post pentru a-l obține. Amintiți-vă că placa Particle Mesh trebuie să ruleze dispozitivul OS 1.3.0 sau o versiune ulterioară pentru ca Bluetooth să funcționeze!

Odată ce firmware-ul și aplicația sunt încărcate, să verificăm ieșirea jurnalului.

Ar trebui să arate cam așa:

View loaded
Central state update
Central scanning for B4250400-FB4B-4746-B2B0-93F0E61122C6
Connected to your Particle Board
LED service found
Red LED characteristic found
Green LED characteristic found
Blue LED characteristic found

Aceasta înseamnă că telefonul dvs. s-a conectat, a găsit serviciul LED! De asemenea, caracteristicile descoperite sunt importante aici. Fără acestea nu am putea trimite date către dispozitivul mesh.

Următorul pas este crearea unor glisoare, astfel încât să putem actualiza valorile RGB din mers.

Glisați spre stânga. Glisați spre dreapta.

În continuare vom adăuga câteva elemente la Main.storyboard. Deschis Main.storyboard și faceți clic pe Vedere dedesubt Vizualizați controlerul.

Actualizarea vizualizării în Xcode

Apoi faceți clic pe Bibliotecă buton. (Se pare că arta veche folosită de Apple pentru butonul de acasă)

Buton Bibliotecă în Xcode

Veți primi o fereastră pop-up cu toate opțiunile pe care le puteți insera în aplicația dvs.

Panoul bibliotecii în Xcode

Trageți trei Etichete și copiați trei Glisoare la viziunea ta.

Tragerea etichetelor în vizualizarea Xcode

Puteți face dublu clic pe etichete și le puteți redenumi pe măsură ce mergeți.

Glisați glisorul în vizualizarea Xcode

Dacă faceți clic și țineți apăsat, vor apărea unele instrumente de aliniere la îndemână. Vor ajunge chiar la centru!

Instrumente de aliniere în Xcode

Puteți, de asemenea, să le selectați pe toate și să le mutați împreună. Le vom alinia pe verticală și orizontală.

Pentru ca aceștia să rămână la mijloc, să eliminăm proprietatea de redimensionare automată. Apasă pe Pictogramă riglă în dreapta sus. Apoi faceți clic pe fiecare dintre bare roșii. Acest lucru vă va asigura că etichetele și glisoarele dvs. rămân pe ecran!

Panoul de regulă în Xcode

Apoi să facem clic pe Afișați editorul asistent buton. (Arată ca o diagramă Venn)

Afișați butonul Editor asistent în Xcode

Notă: asigura-te ca ViewController.swift este deschis în Editorul Asistent.

Opțiune automată în Editorul asistent

Apoi sub /properties secțiune, Faceți clic pe butonul Control și trageți glisorul roșu în codul tău.

Glisați glisorul în cod

Repetați cu toate celelalte. Asigurați-vă că le numiți altceva. Codul dvs. ar trebui să arate astfel când ați terminat:

        // Properties
        private var centralManager: CBCentralManager!
        private var peripheral: CBPeripheral!

        // Sliders
        @IBOutlet weak var redSlider: UISlider!
        @IBOutlet weak var greenSlider: UISlider!
        @IBOutlet weak var blueSlider: UISlider!

Acest lucru ne permite să accesăm valoarea glisoarelor.

Apoi, să atașăm fișierul Valoare modificată eveniment pentru fiecare dintre glisoare. Click dreapta pe Red Slider în vizualizarea folderului.

Trageți valoarea modificată a evenimentului în cod

Ar trebui să vă ofere câteva opțiuni pentru evenimente. Faceți clic și trageți fișierul Valoare modificată eveniment la codul dvs. Asigurați-vă că îl numiți ceva care are sens. obisnuiam RedSliderChanged pentru Glisorul Roșu.

Repetați încă două ori. Codul dvs. ar trebui să arate astfel la sfârșitul acestui pas:

        @IBAction func RedSliderChanged(_ sender: Any) {
        }

        @IBAction func GreenSliderChanged(_ sender: Any) {
        }

        @IBAction func BlueSliderChanged(_ sender: Any) {
        }

De asemenea, am selectat fiecare dintre glisoarele către și debifat Activat. În felul acesta nu le poți mișca. Le vom activa mai târziu în cod.

Dezactivați glisorul în mod implicit

De asemenea, acesta este un moment minunat pentru a schimba valoarea maximă la 255. De asemenea, setați valoarea implicită valoare de la 0,5 la 0.

Setați valoarea implicită și valoarea maximă a glisorului

Înapoi în partea de sus a fișierului. Să creăm câteva variabile locale pentru fiecare dintre caracteristici. Le vom folosi astfel încât să putem scrie variabilele glisante pe placa Particle Mesh.

        // Characteristics
        private var redChar: CBCharacteristic?
        private var greenChar: CBCharacteristic?
        private var blueChar: CBCharacteristic?

Acum, să legăm totul!

În didDiscoverCharacteristicsFor funcția de apel invers. Să atribuim acele caracteristici. De exemplu

    if characteristic.uuid == ParticlePeripheral.redLEDCharacteristicUUID {
        print("Red LED characteristic found")
        redChar = characteristic

Pe măsură ce găsim fiecare caracteristică, putem activa și fiecare dintre glisoarele din același loc.

    		// Unmask red slider
    		redSlider.isEnabled = true

În cele din urmă didDiscoverCharacteristicsFor ar trebui să arate ca:

    // Handling discovery of characteristics
        func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
            if let characteristics = service.characteristics {
                for characteristic in characteristics {
                    if characteristic.uuid == ParticlePeripheral.redLEDCharacteristicUUID {
                        print("Red LED characteristic found")

                        redChar = characteristic
                        redSlider.isEnabled = true
                    } else if characteristic.uuid == ParticlePeripheral.greenLEDCharacteristicUUID {
                        print("Green LED characteristic found")

                        greenChar = characteristic
                        greenSlider.isEnabled = true
                    } else if characteristic.uuid == ParticlePeripheral.blueLEDCharacteristicUUID {
                        print("Blue LED characteristic found");

                        blueChar = characteristic
                        blueSlider.isEnabled = true
                    }
                }
            }
        }

Acum, să actualizăm RedSliderChanged GreenSliderChanged și BlueSliderChanged funcții. Ceea ce vrem să facem aici este să actualizăm caracteristica asociată cu Changed funcţie. Am creat o funcție separată numită writeLEDValueToChar. Vom transmite caracteristica și datele.

    private func writeLEDValueToChar( withCharacteristic characteristic: CBCharacteristic, withValue value: Data) {

            // Check if it has the write property
            if characteristic.properties.contains(.writeWithoutResponse) && peripheral != nil {

                peripheral.writeValue(value, for: characteristic, type: .withoutResponse)

            }

        }

Acum adăugați un apel la writeLEDValueToChar la fiecare dintre Changed funcții. Va trebui să aruncați valoarea la a Uint8. (Dispozitivul Particle Mesh așteaptă un număr nesemnat de 8 biți.)

    		@IBAction func RedSliderChanged(_ sender: Any) {
            print("red:",redSlider.value);
            let slider:UInt8 = UInt8(redSlider.value)
            writeLEDValueToChar( withCharacteristic: redChar!, withValue: Data([slider]))

        }

Repetați acest lucru pentru GreenSliderChanged și BlueSliderChanged. Asigurați-vă că v-ați schimbat red la green și blue pentru fiecare!

În cele din urmă, pentru a menține lucrurile curate, am adăugat și o funcție care gestionează deconectările Bluetooth.

    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {

În interior, ar trebui să resetați starea glisoarelor la 0 și să le dezactivați.

            if peripheral == self.peripheral {
                print("Disconnected")

                redSlider.isEnabled = false
                greenSlider.isEnabled = false
                blueSlider.isEnabled = false

                redSlider.value = 0
                greenSlider.value = 0
                blueSlider.value = 0

Este o idee bună să resetați self.peripheral până la zero, nu încercăm niciodată să scriem pe un dispozitiv fantomă.

                self.peripheral = nil

În cele din urmă, pentru că ne-am deconectat, începeți din nou scanarea!

                // Start scanning again
                print("Central scanning for", ParticlePeripheral.particleLEDServiceUUID);
                centralManager.scanForPeripherals(withServices: [ParticlePeripheral.particleLEDServiceUUID],
                                                  options: [CBCentralManagerScanOptionAllowDuplicatesKey : true])
            }

Bine! Suntem aproape gata să testăm. Să trecem la următorul (și ultimul) pas.

Testați glisoarele.

Următoarea secțiune de testare!

Munca grea este făcută. Acum este timpul să te joci!

Cel mai simplu mod de a testa totul este să faceți clic pe butonul Redare în stânga sus sau în Comandă + R Comanda rapidă de la tastatură. Xcode va încărca aplicația pe telefon. Ar trebui să vedeți un ecran alb urmat de un ecran cu glisoarele dvs.!

Glisoarele ar trebui să rămână în gri până când sunt conectate la placa Particle Mesh. Puteți verifica ieșirea jurnalului dacă conexiunea a fost stabilită.

View loaded
Central state update
Central scanning for B4250400-FB4B-4746-B2B0-93F0E61122C6
Connected to your Particle Board
LED service found
Red LED characteristic found
Green LED characteristic found
Blue LED characteristic found

(Arată familiar? Suntem conectați!)

Dacă ați urmat totul perfect, ar trebui să puteți muta glisoarele. Mai bine, LED-ul RGB de pe placa Particle Mesh ar trebui să schimbe culoarea.

Rezultatele finale ale testului

Concluzie

În acest articol ați învățat cum să vă conectați placa Particle Mesh și dispozitivul iOS prin Bluetooth. Am învățat cum să ne conectăm la fiecare dintre caracteristicile disponibile. În plus, creează o interfață curată pentru a face totul.

După cum vă puteți imagina, puteți merge pe gaura de iepure cu Bluetooth pe iOS. Urmează mai multe în următorul meu ghid: Ghidul final pentru plasă de particule. Abonații la lista mea au acces la conținutul de pre-lansare și o reducere la ieșire! Faceți clic aici pentru a vă înscrie.

Cod

Codul sursă complet este disponibil pe Github. Dacă vi se pare util, apăsați butonul stea. ⭐️