Suche…


Einführung

Hot zum Lesen und Schreiben von Daten auf ein Bluetooth-Gerät mit niedrigem Energieverbrauch.

Bemerkungen

Einige wichtige Punkte

  • Es sind keine Fähigkeiten erforderlich.
  • iPhone speichert Bytes im Little Endian-Format. Überprüfen Sie daher, ob Bluetooth-Zubehör auch Little Endian verwendet. Beispiel:
    • Intel-CPU verwendet normalerweise Little Endian.
    • Die ARM-Architektur war Little Endian vor der Version 3, als sie Big-Endian wurde.
  • Nach einem Einzel- oder Batch-Vorgang geht die Verbindung verloren, daher müssen Sie die Verbindung wiederherstellen, bevor Sie fortfahren.

Scannen Sie nach SERVICE UUID

func SearchBLE(){
    cb_manager.scanForPeripherals(withServices:[service_uuid], options: nil)
    StopSearchBLE()
}

So entdecken Sie SERVICE UUID ohne 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 bedeutet, dass alle Dienste zurückgegeben werden, was keine gute Option ist. (LESEN Sie die Bemerkungen 3).
  • Wenn Sie die SERVICE-UUID nicht gefunden haben, führen Sie Ihren Code aus und suchen Sie in der Konsole Geben Sie hier die Bildbeschreibung ein
  • Ich habe 3 Dienste gefunden: Batterie, Geräteinformationen (Firmware) und FFF0
  • Dieser uuid-Dienst ist kein Standardservice. Eine Liste mit Standards finden Sie hier
  • In diesem Fall ist FFF0 die SERVICE-UUID

Konvertieren Sie Daten in UInt16 und umgekehrt

Fügen Sie diese Erweiterungen Ihrer Klasse hinzu

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

Namen aller Bluetooth Low Energy (BLE) anzeigen

  • Für dieses Beispiel habe ich einen kontrollierten Raum mit einer einzigen BLE-Gerätefreigabe.
  • Ihre Klasse sollte CBCentralManagerDelegate erweitern.
  • Implementieren Sie die Methode: centralManagerDidUpdateState (_ central: CBCentralManager).
  • Verwenden Sie die globale Warteschlange, um den Bildschirm bei der Suche nach einem Gerät nicht einzufrieren.
  • Instantiieren Sie CBCentralManager und warten Sie auf die Antwort von Callback centralManagerDidUpdateState.
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)")
    }
}

Ein Rückruf an centralManagerDidUpdateState zeigt an, dass CoreBluetooth bereit ist, sodass Sie jetzt nach BLE suchen können. Aktualisieren Sie den centralManagerDidUpdateState-Code, um nach allen BLE-Geräten zu suchen, wenn sie bereit sind.

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()
    }
}
  • SearchBLE () sucht nach BLE-Geräten und stoppt die Suche nach 5s
  • cb_manager.scanForPeripherals (withServices: nil, options: nil) sucht nach jeder BLE, die sich in Reichweite befindet.
  • StopSearchBLE () stoppt die Suche nach 5s.
  • Jede gefundene BLE ruft den func centralManager (_ central: CBCentralManager, didDiscover-Peripherie: CBPeripheral, advertisementData: [String: Any], RSSI: NSNumber) auf
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)
}

Verbinden Sie und lesen Sie den wichtigsten Wert

  • Ich befinde mich in einem kontrollierten Raum mit einem einzigen Minew Beacon, der das IBEACON-Protokoll verwendet.
  • BLEController muss CBPeripheralDelegate erweitern
  • Ich verwende die erste BLE, um eine Verbindung herzustellen, nachdem die Suche beendet wurde.
  • Ändern Sie die Methode 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)
        }
    }
/...
}
  • In der Dokumentation Ihres BLE-Geräts sollten Sie nach SERVICE UUID und MAJOR UUID CHARACTERISTIC suchen
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])!)
}
  • Erstellen Sie eine Variable wie "service_uuid" und "major_uuid" wie oben. '-0000-1000-8000-00805f9b34fb' gehört zum Standard. 'fff0' ist meine SERVICE-UUID, 'fff2' ist meine wichtige UUID-Eigenschaft und '0000' ist erforderlich, um den 4-Byte-Uuid-1º-Block zu füllen.
  • discoverCharacteristics ([major_uuid], für: (peripherie.services?[0])!) wird die Hauptcharakteristik von meinem gatt-Server meines Geräts erhalten, und es wird NIL als Wert für jetzt angezeigt.
  • (peripherie.services?[0])! - 0 beacuse gibt einen einzelnen Wert zurück, sobald ich peripher.discoverServices ([service_uuid]) ausgeführt habe.
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)")
}
  • Der Merkmalswert ist nur nach dem Aufruf peripher.readValue (für: Merkmal) lesbar.
  • readValue führt zu einem Peripheriegerät (_ Peripheriegerät: CBPeripheral, didUpdateValueFor-Eigenschaft: CBCharacteristic, Fehler: Fehler?) mit dem Wert in Datentyp.

Schreibe den Hauptwert

  • Sie müssen die Dienste und Merkmale entdecken
  • Sie müssen den Wert des Merkmals nicht lesen, bevor Sie darüber schreiben.
  • wird für dieses Beispiel nach dem gelesenen Wert fortgesetzt. Ändern Sie das Peripheriegerät (_ Peripheriegerät: CBPeripheral, didUpdateValueFor-Eigenschaft: CBCharacteristic, Fehler: Fehler?).
  • Fügen Sie eine Variable new_major und reset_characteristic hinzu
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)
}
  • Das iPhone von deafult sendet und empfängt Bytes im Little Endian-Format, aber mein Gerät MINEW, bei dem der NRF51822-Chipsatz ARM-Architektur besitzt, benötigt Bytes im Big Endian-Format.
  • In der Dokumentation zu BLE-Geräten wird angegeben, welche Art von Eingabe und Ausgabe jedes Merkmal hat und ob Sie es wie oben lesen können (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)
    }
}
  • Um die Informationen eines gatt-Servers zu aktualisieren, müssen Sie ihn programmgesteuert neu starten oder Daten darauf speichern und manuell ausschalten und einschalten.
  • FFFF ist charakteristisch für dieses Gerät.
  • In diesem Fall ist 'minew123' das Standardkennwort für den Neustart oder das Speichern von Informationen.
  • Starten Sie Ihre App und beobachten Sie die Konsole auf Fehler, ich hoffe nicht, aber Sie werden den neuen Wert noch nicht sehen.
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)

}

  • Der letzte Schritt besteht darin, die letzte Zeile in der Methode didUpdateValueFor zu kommentieren und die App erneut auszuführen. Jetzt wird der neue Wert angezeigt.


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow