iOS
Konfigurera Beacons med CoreBluetooth
Sök…
Introduktion
Het att läsa och skriva data till en Bluetooth-lågenergienhet.
Anmärkningar
Några viktiga punkter
- Inga funktioner behövs.
- iPhone-butiker bytes i Little Endian-format, så kontrollera om Bluetooth-tillbehör använder Little Endian också. Exempel:
- Intel CPU använder vanligtvis lite endian.
- ARM-arkitekturen var lite-endian före version 3 när den blev big-endian.
- Efter en enda eller batchoperation kommer förbindelsen att gå förlorad, så du måste ansluta igen innan du fortsätter.
Sök efter SERVICE UUID
func SearchBLE(){
cb_manager.scanForPeripherals(withServices:[service_uuid], options: nil)
StopSearchBLE()
}
Hur man upptäcker SERVICE UUID utan dokumentation
func centralManager(_ central: CBCentralManager, didConnect peripheral:
CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
print("Service: \(service)\n error: \(error)")
}
}
- DiscoverServices (nil) - NIL betyder att alla tjänster kommer att returneras, vilket inte är ett bra alternativ. (LÄS Anmärkningar 3)
- Om du inte har hittat SERVICE UUID kör du din kod och letar efter i konsolen
- Jag hittade att jag har tre tjänster: Batteri, enhetsinformation (Firmware) och FFF0
- Den här tysta tjänsten är inte en standard, en lista med standarder kan hittas här
- FFF0 är SERVICE UUID i detta fall
Konvertera data till UInt16 och tvärtom
Lägg till tillägg till din klass
protocol DataConvertible {
init?(data: Data)
var data: Data { get }
}
extension DataConvertible {
init?(data: Data) {
guard data.count == MemoryLayout<Self>.size else { return nil }
self = data.withUnsafeBytes { $0.pointee }
}
var data: Data {
var value = self
return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
}
extension UInt16 : DataConvertible {
init?(data: Data) {
guard data.count == MemoryLayout<UInt16>.size else { return nil }
self = data.withUnsafeBytes { $0.pointee }
}
var data: Data {
var value = CFSwapInt16HostToBig(self)
return Data(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
}
Visar namn på alla Bluetooth Low Energy (BLE)
- I det här exemplet har jag ett kontrollerat rum med en enda BLE-enhet aktiverad.
- Din klass bör utöka CBCentralManagerDelegate.
- Implementera metoden: centralManagerDidUpdateState (_ central: CBCentralManager).
- Använd global kö för att inte frysa skärmen när du söker efter en enhet.
- Instantiate CBCentralManager och vänta på callback centralManagerDidUpdateState svar.
class BLEController: CBCentralManagerDelegate{
var cb_manager: CBCentralManager!
var bles : [CBPeripheral] = []
override func viewDidLoad() {
super.viewDidLoad()
cb_manager = CBCentralManager(delegate: self, queue: DispatchQueue.global())
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("UPDATE STATE - \(central)")
}
}
Återuppringning till centralManagerDidUpdateState indikerar att CoreBluetooth är redo, så du kan söka efter BLE nu. Uppdatera centralManagerDidUpdateState-kod för att söka efter alla BLE-enheter när den är klar.
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("UPDATE STATE - \(central)")
SearchBLE()
}
func SearchBLE(){
cb_manager.scanForPeripherals(withServices: nil, options: nil)
StopSearchBLE()
}
func StopSearchBLE() {
let when = DispatchTime.now() + 5 // change 5 to desired number of seconds
DispatchQueue.main.asyncAfter(deadline: when) {
self.cb_manager.stopScan()
}
}
- SökBLE () söka efter BLE-enheter och sluta söka efter 5s
- cb_manager.scanForPeripherals (withServices: nil, option: nil) letar efter varje BLE i sortimentet med dig.
- StopSearchBLE () stoppar sökningen efter 5s.
- Varje BLE som hittas kommer återuppringning func centralManager (_ central: CBCentralManager, didDiscover perifera: CBPeripheral, reklamData: [String: Any], rssi RSSI: NSNumber)
func centralManager(_ central: CBCentralManager, didDiscover peripheral:
CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
guard let name = peripheral.name else {
return
}
print(name)
bles.append(peripheral)
}
Anslut och läs huvudvärdet
- Jag befinner mig i ett kontrollerat rum med ett enda gruvfyr som använder IBEACON-protokollet.
- BLEController måste utöka CBPeripheralDelegate
- Jag använder den första BLE för att ansluta efter att sökningen har upphört.
- Ändra metoden StopSearchBLE ()
class BLEController: CBCentralManagerDelegate, CBPeripheralDelegate{
//...
func StopSearchMiniewBeacon() {
let when = DispatchTime.now() + 5 // change 2 to desired number of seconds
DispatchQueue.main.asyncAfter(deadline: when) {
self.cb_manager.stopScan()
self.cb_manager.connect(bles.first)
}
}
/...
}
- I dokumentationen av din BLE-enhet bör du leta efter SERVICE UUID- och MAJOR UUID-EGENSKAPER
var service_uuid = CBUUID(string: "0000fff0-0000-1000-8000-00805f9b34fb")
var major_uuid = CBUUID(string: "0000fff2-0000-1000-8000-00805f9b34fb")
func centralManager(_ central: CBCentralManager, didConnect peripheral:
CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices([service_uuid])
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("Service: \(service)\n error: \(error)")
peripheral.discoverCharacteristics([major_uuid], for: (peripheral.services?[0])!)
}
- Skapa en variabel "service_uuid" och "major_uuid" som kod ovan. '-0000-1000-8000-00805f9b34fb' är en del av standarden. 'fff0' är min SERVICE UUID, 'fff2' är min STORA UUID-karakteristik och '0000' krävs för att fylla 4 bytes uuid 1º-blocket.
- DiscoverCharacteristics ([major_uuid], för: (peripheral.services?vud0])!) kommer att få huvudkarakteristik från min enhetsgatt-server och den kommer att ha NIL som värde för nu.
- (Peripheral.services?[0])! - 0 beacuse kommer att returnera ett enda värde när jag gjorde perifera.discoverServices ([service_uuid])
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic in service.characteristics! {
print("Characteristic: \(characteristic)\n error: \(error)")
if(characteristic.uuid.uuidString == "FFF2"){
peripheral.readValue(for: characteristic)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("Characteristic read: \(characteristic)\n error: \(error)")
let major = UInt16.init(bigEndian: UInt16(data: characteristic.value!)!)
print("major: \(major)")
}
- Karakteristiskt värde kommer endast att läsas efter peripheral.readValue (för: karakteristik)
- readValue kommer att resultera i func perifera (_ perifera: CBPeripher, didUpdateValueFor karakteristik: CBCharacteristic, error: Error?) med värde i Datatyp.
Skriv huvudvärde
- Du måste upptäcka tjänsterna och kännetecknen
- Du behöver inte läsvärde från karakteristiken innan du skriver om det.
- fortsätter för detta exempel efter läsvärde. Ändra func perifera (_ perifera: CBPeripheral, didUpdateValueFör karakteristik: CBCharacteristic, error: Error?)
- Lägg till en variabel new_major och reset_characteristic
var reset_characteristic : CBCharacteristic!
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
for characteristic in service.characteristics! {
print("Characteristic: \(characteristic)\n error: \(error)")
if(characteristic.uuid.uuidString == "FFF2"){
peripheral.readValue(for: characteristic)
}
if(characteristic.uuid.uuidString == "FFFF"){
reset_characteristic = characteristic
}
}
}
let new_major : UInt16 = 100
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("Characteristic read: \(characteristic)\n error: \(error)")
let major = UInt16.init(bigEndian: UInt16(data: characteristic.value!)!)
print("major: \(major)")
peripheral.writeValue(new_major.data, for: characteristic, type: CBCharacteristicWriteType.withResponse)
}
- iPhone av deafult skickar och tar emot byte i Little Endian-format, men min enhet MINEW-häxchipsuppsättning NRF51822 har ARM-arkiv och behöver byte i Big Endian-format, så jag måste byta den.
- BLE Enhetsdokumentation säger vilken typ av inmatning och utdata varje karaktär har och om du kan läsa den som ovan (CBCharacteristicWriteType.withResponse).
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
print("Characteristic write: \(characteristic)\n error: \(error)")
if(characteristic.uuid.uuidString == "FFF2"){
print("Resetting")
peripheral.writeValue("minew123".data(using: String.Encoding.utf8)!, for: reset_characteristic, type: CBCharacteristicWriteType.withResponse)
}
if(characteristic.uuid.uuidString == "FFFF"){
print("Reboot finish")
cb_manager.cancelPeripheralConnection(peripheral)
}
}
- För att uppdatera en gatt-serverinformation måste du starta om den programmatiskt eller spara data till den och stänga av och slå på den manuellt.
- FFFF är karakteristiskt som gör det i den här enheten.
- 'minew123' är standardlösenordet för omstart o spara information i detta fall.
- kör din app och se dig konsol för något fel, jag hoppas ingen, men du kommer inte att se det nya värdet än.
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("Characteristic read: \(characteristic)\n error: \(error)")
let major = UInt16.init(bigEndian: UInt16(data: characteristic.value!)!)
print("major: \(major)")
//peripheral.writeValue(new_major.data, for: characteristic, type: CBCharacteristicWriteType.withResponse)
}
- Sista steget är att kommentera sista raden i metoden didUpdateValueFor och kör appen igen, nu kommer du att det nya värdet.
Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow