Ο απόλυτος τρόπος: Δημιουργήστε μια εφαρμογή Bluetooth Swift με υλικό σε 20 λεπτά

Σε ένα προηγούμενο σεμινάριο, μάθατε πώς να προσθέτετε Bluetooth σε μια εφαρμογή Particle Xenon. Με αυτόν τον τρόπο θα μπορούσατε να ελέγξετε το ενσωματωμένο RGB LED από μια δοκιμαστική εφαρμογή όπως το nRF Connect ή το Light Blue Explorer.

Σε αυτήν την ανάρτηση, θα το κάνουμε ένα βήμα παραπέρα. Πρόκειται να αναπτύξουμε μια εφαρμογή Swift για τον έλεγχο ενός LED Particle Mesh RGB. Εάν όλα πάνε καλά, θα πρέπει να έχετε μια εφαρμογή εργασίας σε περίπου 20 λεπτά!

Ας αρχίσουμε.

Δεν έχετε χρόνο τώρα για να διαβάσετε ολόκληρο το άρθρο;

Κατεβάστε την έκδοση PDF εδώ.

Ετοιμαστείτε

  • Εγκατάσταση Xcode. Μπορείτε να το κατεβάσετε από το App Store εδώ.
  • Θα χρειαστείτε επίσης μια σύνδεση Apple. Χρησιμοποιώ το email μου στο iCloud. Μπορείτε να δημιουργήσετε έναν νέο λογαριασμό στο Xcode εάν δεν έχετε ακόμη.
  • Εγκαταστήστε το παράδειγμα RGB κώδικα σε έναν πίνακα Particle Mesh.

Δημιουργήστε το έργο

Μόλις εγκατασταθούν όλα, ας φτάσουμε στα διασκεδαστικά πράγματα!

Ανοίξτε το Xcode και μεταβείτε στο Αρχείο → Νέο έργο.

Νέο πρόγραμμα Xcode

Επιλέξτε Εφαρμογή μίας προβολής.

Νέες πληροφορίες έργου

Στη συνέχεια, ενημερώστε το Όνομα Έργου για να σας αρέσει. Έχω επίσης αλλάξει το αναγνωριστικό του οργανισμού μου σε com.jaredwolff. Τροποποιήστε το όπως κρίνετε κατάλληλο!

Επιλέξτε μια τοποθεσία για να την αποθηκεύσετε.

Στη συνέχεια, βρείτε το Info.plist.

Info.plist στο Xcocde

Ενημέρωση info.plistπροσθέτονταςPrivacy - Bluetooth Peripheral Usage Description

Η περιγραφή που κατέληξα ήταν App uses Bluetooth to connect to the Particle Xenon RGB Example

Αυτό σας επιτρέπει να χρησιμοποιείτε Bluetooth στην εφαρμογή σας εάν θέλετε να το κυκλοφορήσετε.

Τώρα, ας κάνουμε τα πάντα ελάχιστα λειτουργικά!

Ελάχιστα λειτουργικό

Νέα εικόνα ενότητας

Στη συνέχεια, θα λάβουμε μια ελάχιστα λειτουργική εφαρμογή για σύνδεση και ανακάλυψη υπηρεσιών. Το μεγαλύτερο μέρος της δράσης θα συμβεί στο ViewController.swift.

Αφήνει την πρώτη εισαγωγή CoreBluetooth

 import CoreBluetooth 

Αυτό μας επιτρέπει να ελέγξουμε τη λειτουργικότητα χαμηλής ενέργειας Bluetooth στο iOS. Τότε ας προσθέσουμε και το CBPeripheralDelegateκαι CBCentralManagerDelegateστην ViewControllerτάξη.

 class ViewController: UIViewController, CBPeripheralDelegate, CBCentralManagerDelegate { 

Ας δημιουργήσουμε τώρα τοπικές ιδιωτικές μεταβλητές για να αποθηκεύσουμε τον πραγματικό κεντρικό διαχειριστή και το περιφερειακό. Θα τα ρυθμίσουμε για λίγο.

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

Στη viewDidLoadλειτουργία σας , ας αρχίσουμε τοcentralManager

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

Η ρύθμιση delegate: selfείναι σημαντική. Διαφορετικά, η κεντρική πολιτεία δεν αλλάζει ποτέ κατά την εκκίνηση.

Προτού προχωρήσουμε περαιτέρω, ας δημιουργήσουμε ένα ξεχωριστό αρχείο και καλέστε το ParticlePeripheral.swift. Μπορεί να τοποθετηθεί οπουδήποτε, αλλά το έβαλα σε μια ξεχωριστή «ομάδα» που ονομάζεται Μοντέλα για αργότερα.

Μέσα θα δημιουργήσουμε μερικές δημόσιες μεταβλητές που περιέχουν τα UUID για το Particle Board. Πρέπει να φαίνονται οικεία!

 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") } 

Επιστρέψτε ViewController.swiftας συνδυάσουμε τα κομμάτια Bluetooth.

Κομμάτια Bluetooth

Διάγραμμα ροής για Bluetooth Swift σε iOS

Τα πάντα με το Bluetooth βασίζονται σε συμβάντα. Θα καθορίσουμε διάφορες λειτουργίες που χειρίζονται αυτά τα συμβάντα. Εδώ είναι τα σημαντικά:

centralManagerDidUpdateStateενημερώνεται όταν το Bluetooth Peripheral είναι ενεργοποιημένο ή απενεργοποιημένο. Θα ενεργοποιηθεί κατά την πρώτη εκκίνηση μιας εφαρμογής, ώστε να γνωρίζετε την κατάσταση του Bluetooth. Αρχίζουμε επίσης τη σάρωση εδώ.

Το centralManagerdidDiscoverσυμβάν συμβαίνει όταν λαμβάνετε αποτελέσματα σάρωσης. Θα το χρησιμοποιήσουμε για να ξεκινήσουμε μια σύνδεση.

Το centralManagerdidConnectσυμβάν ενεργοποιείται μόλις συνδεθεί η συσκευή. Θα ξεκινήσουμε την ανακάλυψη συσκευών εδώ. Σημείωση: Η ανακάλυψη συσκευών είναι ο τρόπος με τον οποίο καθορίζουμε ποιες υπηρεσίες και χαρακτηριστικά είναι διαθέσιμα. Αυτός είναι ένας καλός τρόπος για να επιβεβαιώσετε σε ποιον τύπο συσκευής είμαστε συνδεδεμένοι.

Η peripheraldidDiscoverServicesεκδήλωση πρώτα αφού ανακαλυφθούν όλες οι υπηρεσίες. Παρατηρήστε ότι έχουμε αλλάξει από centralManagerέως peripheralτώρα που είμαστε συνδεδεμένοι. Θα ξεκινήσουμε τη χαρακτηριστική ανακάλυψη εδώ. Θα χρησιμοποιήσουμε το UUID υπηρεσίας RGB ως στόχο.

Η peripheraldidDiscoverCharacteristicsForεκδήλωση θα παρέχει όλα τα χαρακτηριστικά χρησιμοποιώντας την παρεχόμενη υπηρεσία UUID. Αυτό είναι το τελευταίο βήμα στην αλυσίδα της πλήρους ανακάλυψης συσκευών. Είναι τριχωτό, αλλά πρέπει να γίνει μόνο μία φορά κατά τη φάση σύνδεσης!

Defining all the Bluetooth functions.

Now that we know what the functions events that get triggered. We'll define them in the logical order that they happen during a connection cycle.

First, we'll define centralManagerDidUpdateState to start scanning for a device with our Particle RGB LED Service. If Bluetooth is not enabled, it will not do anything.

 // 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]) } } 

Defining the centralManagerdidDiscover is our next step in the process. We know we've found a device if this event has occurred.

 // 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) } 

So, we stop scanning using self.centralManager.stopScan(). We set the peripheral so it persists through the app. Then we connect to that device using self.centralManager.connect

Once connected, we need to double check if we're working with the right device.

 // 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]) } } 

By comparing the two peripherals we'll know its the device we found earlier. We'll kick off a services discovery using peripheral.discoverService. We can use ParticlePeripheral.particleLEDServiceUUID as a parameter. That way we don't pick up any services we don't care about.

Once we finish the discovering services, we'll get a didDiscoverServices event. We iterate through all the "available" services. (Though there will only be one!)

 // 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 } } } } 

By this point this is the third time we're checking to make sure we have the correct service. This becomes more handy later when there are many characteristics and many services.

We call peripheral.discoverCharacteristics with an array of UUIDs for the characteristics we're looking for. They're all the UUIDs that we defined in ParticlePeripheral.swift.

Finally, we handle the didDiscoverCharacteriscsFor event. We iterate through all the available characteristics. As we iterate we compare with the ones we're looking for.

 // 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"); } } } } 

At this point we're ready to do a full device discovery of our Particle Mesh device. In the next section we'll test what we have to make sure things are working ok.

Testing our minimal example

Εικόνα ενότητας σχετικά με τη δοκιμή

Before we get started, if you run into trouble I've put some troubleshooting steps in the footnotes.

To test, you'll have to have an iPhone with Bluetooth Low Energy. Most modern iPhones have it. The last iPhone not to have it I believe was either the iPhone 4 or 3Gs. (so you're likely good)

First, plug it into your computer.

Go to the top by the play and stop buttons. Select your target device. In my case I chose my phone (Jared's iPhone). You can also use an iPad.

Επιλέξτε τύπο συσκευής

Then you can hit Command + R or hit that Play button to load the app to your phone.

Make sure you have your log tab open. Enable it by clicking the bottom pane button in the top right corner.

Κάτω τμήμα στο Xcode για αρχεία καταγραφής

Make sure you have a mesh device setup and running the example code. You can go to this post to get it. Remember your Particle Mesh board needs to be running device OS 1.3.0 or greater for Bluetooth to work!

Once both the firmware and app is loaded, let's check the log output.

It should look something like this:

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 

This means that your Phone has connected, found the LED service! The characteristics also being discovered is important here. Without those we wouldn't be able to send data to the mesh device.

Next step is to create some sliders so we can update the RGB values on the fly.

Slide to the left. Slide to the right.

Next we're going to add some elements to our Main.storyboard. Open Main.storyboard and click on the View underneath View Controller.

Ενημέρωση προβολής σε Xcode

Then click on the Library button. (It looks like the old art Apple used for the home button)

Κουμπί βιβλιοθήκης σε Xcode

You'll get a pop-up with all the choices that you can insert into your app.

Παράθυρο βιβλιοθήκης σε Xcode

Drag three Labels and copy three Sliders to your view.

Μεταφορά ετικετών στην προβολή Xcode

You can double click on the labels and rename them as you go.

Σύροντας το ρυθμιστικό στην προβολή Xcode

If you click and hold, some handy alignment tools will popup. They'll even snap to center!

Εργαλεία ευθυγράμμισης σε Xcode

You can also select them all and move them together. We'll align them vertically and horizontally.

In order for them to stay in the middle, let's remove the autoresizing property. Click the Ruler icon on the top right. Then click each of the red bars. This will ensure that your labels and sliders stay on the screen!

Παράθυρο χάρακα σε Xcode

Next let's click the Show Assistant Editor button. (Looks like a Venn diagram)

Εμφάνιση κουμπιού Βοηθού επεξεργαστή στο Xcode

Note: make sure that ViewController.swift is open in your Assistant Editor.

Αυτόματη επιλογή στο Assistant Editor

Then underneath the /properties section, Control-click and dragthe Red Slider into your code.

Σύρετε το ρυθμιστικό στον κώδικα

Repeat with all the other ones. Make sure you name them something different. Your code should look like this when you're done:

 // 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! 

This allow us to access the value of the sliders.

Next, let's attach the Value Changed event to each of the sliders. Right click on the Red Slider in the folder view.

Η τιμή μεταφοράς άλλαξε συμβάν σε κώδικα

It should give you some options for events. Click and drag the Value Changed event to your code. Make sure you name it something that makes sense. I used RedSliderChanged for the Red Slider.

Repeat two more times. Your code should look like this at the end of this step:

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

I've also selected each of the sliders to and un-checked Enabled. That way you can't move them. We'll enable them later on in code.

Απενεργοποιήστε το ρυθμιστικό από προεπιλογή

Also, this is a great time to change the maximum value to 255. Also set the default value from 0.5 to 0.

Ορίστε την προεπιλεγμένη τιμή και τη μέγιστη τιμή του ρυθμιστικού

Back at the top of the file. Let's create some local variables for each of the characteristics. We'll use these so we can write the slider variables to the Particle Mesh board.

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

Now, let's tie everything together!

In the didDiscoverCharacteristicsFor callback function. Let's assign those characteristics. For example

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

As we find each characteristic, we can also enable each of the sliders in the same spot.

 // Unmask red slider redSlider.isEnabled = true 

In the end your didDiscoverCharacteristicsFor should look like:

 // 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 } } } } 

Now, let's update the RedSliderChangedGreenSliderChanged and BlueSliderChanged functions. What we want to do here is update the characteristic associated with the Changed function. I created a separate function called writeLEDValueToChar. We'll pass in the characteristic and the data.

 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) } } 

Now add a call to writeLEDValueToChar to each of the Changed functions. You will have to cast the value to a Uint8. (The Particle Mesh device expects an unsigned 8-bit number.)

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

Repeat this for GreenSliderChanged and BlueSliderChanged. Make sure you changed red to green and blue for each!

Finally, to keep things clean, i've also added a function that handles Bluetooth disconnects.

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

Inside, we should reset the state of the sliders to 0 and disable them.

 if peripheral == self.peripheral { print("Disconnected") redSlider.isEnabled = false greenSlider.isEnabled = false blueSlider.isEnabled = false redSlider.value = 0 greenSlider.value = 0 blueSlider.value = 0 

It's a good idea to reset self.peripheral to nil that way we're not ever trying to write to a phantom device.

 self.peripheral = nil 

Finally, because we've disconnected, start scanning again!

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

Alright! We just about ready to test. Let's move on to the next (and final) step.

Test the sliders.

Δοκιμή επόμενης ενότητας!

The hard work is done. Now it's time to play!

The easiest way to test everything is to click the Play button in the top left or the Command + R keyboard shortcut. Xcode will load the app to your phone. You should see a white screen proceeded by a screen with your sliders!

The sliders should stay greyed out until connected to your Particle Mesh board. You can check your log output if the connection has been established.

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 

(Look familiar? We're connected!)

Εάν ακολουθήσατε τα πάντα τέλεια, θα πρέπει να μπορείτε να μετακινήσετε τα ρυθμιστικά. Ακόμα καλύτερα, το RGB LED στην πλακέτα Particle Mesh θα πρέπει να αλλάξει χρώμα.

Τελικά αποτελέσματα δοκιμών

συμπέρασμα

Σε αυτό το άρθρο μάθατε πώς να συνδέετε την πλακέτα Particle Mesh και τη συσκευή iOS μέσω Bluetooth. Έχουμε μάθει πώς να συνδεθείτε σε καθένα από τα διαθέσιμα χαρακτηριστικά. Επιπλέον, πάνω από όλα, δημιουργήστε μια καθαρή διεπαφή για να τα κάνετε όλα.

Όπως μπορείτε να φανταστείτε, μπορείτε να κατεβείτε την τρύπα του κουνελιού με Bluetooth στο iOS. Έρχονται περισσότερα στον επερχόμενο οδηγό μου: Ο απόλυτος οδηγός για Particle Mesh. Οι συνδρομητές στη λίστα μου έχουν πρόσβαση σε περιεχόμενο πριν από την κυκλοφορία και έκπτωση όταν βγαίνει! Κάντε κλικ εδώ για να εγγραφείτε.

Κώδικας

Ο πλήρης πηγαίος κώδικας είναι διαθέσιμος στο Github. Εάν το βρείτε χρήσιμο, πατήστε το κουμπί με το αστέρι. ⭐️