iOS
CoreBluetoothでビーコンを設定する
サーチ…
前書き
Bluetooth低エネルギーデバイスにデータを読み書きするために熱い。
備考
いくつかの重要な点
- 機能は必要ありません。
- リトルエンディアン形式のiPhoneストアバイトですので、ブルートゥースアクセサリもリトルエンディアンを使用しているかどうかを確認してください。例:
- intel CPUは通常リトルエンディアンを使用します。
- ARMアーキテクチャは、ビッグエンディアンになったバージョン3より前のリトルエンディアンでした。
- シングルまたはバッチ操作の後、接続が失われるので、続行する前に再接続する必要があります。
SERVICE UUIDをスキャンする
func SearchBLE(){
cb_manager.scanForPeripherals(withServices:[service_uuid], options: nil)
StopSearchBLE()
}
ドキュメントなしでSERVICE UUIDを検出する方法
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は、すべてのサービスが返されることを意味しますが、これは適切なオプションではありません(READ注意3)
- SERVICE UUIDがコードを実行してコンソールで探していない場合
- 私は、バッテリー、デバイス情報(ファームウェア)、FFF0
- このuuidサービスは標準的なものではなく、標準のリストがここにあります
- この場合、FFF0はSERVICE UUIDです
データをUInt16に変換する
この拡張機能をクラスに追加する
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))
}
}
すべてのBluetooth Low Energy(BLE)の名前を表示
- この例では、単一のBLEデバイスが有効な制御された部屋があります。
- あなたのクラスはCBCentralManagerDelegateを拡張する必要があります。
- メソッド:centralManagerDidUpdateState(_ central:CBCentralManager)を実装します。
- グローバルキューを使用して、デバイスを検索している間は画面をフリーズしないでください。
- CBCentralManagerをインスタンス化し、コールバックの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)")
}
}
centralManagerDidUpdateStateへのコールバックはCoreBluetoothが準備完了であることを示しているので、今すぐBLEを検索できます。 centralManagerDidUpdateStateコードを更新して、準備ができたらすべてのBLEデバイスを検索します。
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()
}
}
- BLEデバイスのSearchBLE()検索と5秒後の検索停止
- cb_manager.scanForPeripherals(withServices:nil、options:nil)は、範囲内のすべてのBLEを探します。
- StopSearchBLE()は5秒後に検索を停止します。
- 見つかった各BLEは、コールバック関数centralManager(_中央:CBCentralManager、検出された周辺機器:CBPeripheral、advertisementData:[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)
}
主要な値を接続して読み取る
- 私はIBEACONプロトコルを使用する単一のミニビーコンで制御された部屋にいます。
- BLEControllerはCBPeripheralDelegateを拡張する必要があります
- 検索が停止した後、最初のBLEを使用して接続します。
- 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)
}
}
/...
}
- BLEデバイスのドキュメントでは、SERVICE UUIDとMAUOR UUID CHARACTERISTIC
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])!)
}
- 上のコードのような変数 'service_uuid'と 'major_uuid'を作成します。 '-0000-1000-8000-00805f9b34fb'は標準の一部です。 'fff0'は私のSERVICE UUID、 'fff2'は私のMAUOR UUID特性、 '0000'は4バイトのuuid 1ºブロックを埋めるために必要です。
- discoverCharacteristics([major_uuid]、for :( peripheral.services?[0))!)は私のデバイスgattサーバから大きな特徴を得るでしょう。
- (peripheral.services?[0])!私がperipheral.discoverServices([service_uuid])を実行すると0 beacuseは単一の値を返します
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)")
}
- 特性値は、呼び出し後にのみ表示されます。peripheral.readValue(for:特性)
- readValueは、データ型に値を持つfuncペリフェラル(_周辺:CBPeripheral、didUpdateValue特性:CBCharacteristic、エラー:エラー?)を返します。
主な価値を書く
- あなたはサービスと特性を発見する必要があります
- 上書きする前にその特性から読み値を取得する必要はありません。
- この例では、読み取り値の後に継続されます。 func周辺機器の変更(_周辺機器:CBPeripheral、didUpdateValue特性:CBCharacteristic、エラー:エラー?)
- 変数new_majorと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)
}
- deafultのiPhoneはLittle Endian形式のバイトを送受信しますが、私のデバイスMINEWの魔法チップセットNRF51822にはARMアーキテクチャがあり、Big Endian形式のバイトが必要なので、交換する必要があります。
- BLEデバイスのドキュメントでは、各特性にどのようなタイプの入出力があるか、また上記のように(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)
}
}
- gattサーバーの情報を更新するには、プログラムで再起動するか、データを保存して手動で電源を入れ直してください。
- FFFFはこのデバイスでそれを行う特徴です。
- この場合、情報を再起動して保存するためのデフォルトのパスワードは「minew123」です。
- あなたのアプリを実行し、エラーのためにコンソールを見て、私は誰も望んでいないが、あなたはまだ新しい値を表示されません。
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)
}
- 最後のステップは、メソッドdidUpdateValueForの最後の行にコメントしてアプリを再実行することです。今度は新しい値になります。
Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow