bluetooth - 如何让 iBeacon 到在 iPhone 上运行的 Raspbberry PI?
问题描述
我有一个带有 Cambridge Scientific USB 适配器的 Raspberry PI,在该适配器上我有以下内容:
sudo hciconfig hci0 up
sudo hciconfig hci0 leadv 3
sudo hcitool -i hci0 cmd 0x08 0x0008 1E 02 01 06 1A FF 4C 00 02 15 C7 C1 A1 BF BB 00 4C AD 87 04 9F 2D 29 17 DE D2 00 00 00 00 C8 00
我编写了一个 MacOS Cocoa App,如下所示:
import Cocoa
import CoreBluetooth
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
BeaconScanner(type: BeaconType.iBeacon).scanEverySecond()
}
}
enum BeaconType {
case iBeacon
}
struct Beacon {
var uuid: NSUUID!
var major: UInt16!
var minor: UInt16!
var power: Int8!
var peripheral: CBPeripheral!
var advertisementData: NSDictionary!
var RSSI: NSNumber!
init(peripheral: CBPeripheral, advertisementData: NSDictionary, RSSI: NSNumber) {
self.peripheral = peripheral
self.advertisementData = advertisementData
self.RSSI = RSSI
}
private func getBytes(data: Any?, from: Int, count: Int) -> [CUnsignedChar] {
var bytes = [CUnsignedChar](repeating: 0, count: count)
(data! as AnyObject).getBytes(&bytes, range: NSMakeRange(from, count))
return bytes
}
private func getBytesAsUshort(data: Any?, from: Int) -> ushort {
var bytes = ushort()
(data! as AnyObject).getBytes(&bytes, range: NSMakeRange(from, 2))
return NSSwapShort(bytes)
}
private func getBytesAsInt8(data: Any?, from: Int) -> Int8 {
var bytes = Int8()
(data! as AnyObject).getBytes(&bytes, range: NSMakeRange(from, 1))
return bytes
}
func checkAdvertisementDataForPossibleiBeaconData() {
let beaconStandard: [CUnsignedChar] = [0x4c, 0x00, 0x02, 0x15]
var data = advertisementData.value(forKey: "kCBAdvDataManufacturerData")
if(data != nil) {
data = data as! Data
var beaconStandardBytes = [CUnsignedChar](repeating: 0, count: 4)
(data! as AnyObject).getBytes(&beaconStandardBytes, range: NSMakeRange(0,4))
if((data! as AnyObject).length >= 25 && beaconStandardBytes.elementsEqual(beaconStandard)) {
let uuid = NSUUID.init(uuidBytes: getBytes(data: data, from: 4, count: 16)) as UUID
let major = getBytesAsUshort(data: data, from: 20)
let minor = getBytesAsUshort(data: data, from: 22)
let power = getBytesAsInt8(data: data, from: 24)
let distance = calculateBeaconDistance(Int(power), RSSI: Int(truncating: RSSI))
print("BeaconStandard=\(beaconStandard), UUID=\(uuid.uuidString), major=\(major), minor=\(minor), power=\(power), RSSI=\(String(describing: RSSI)), Distance=\(String(format: "%.2f", distance))m")
}
}
}
func calculateBeaconDistance(_ power: Int, RSSI: Int) -> Double {
let ratio = Double(RSSI) * 1.0 / Double(power)
return ratio < 1.0 ? pow(ratio, 10.0) : round(10*((0.89976) * pow(ratio, 7.7095) + 0.111)) / 10
}
}
class BeaconScanner: NSObject, CBCentralManagerDelegate {
var cbManager: CBCentralManager!
var timer: Timer!
var type: BeaconType!
init(type: BeaconType) {
self.type = type
}
func scanEverySecond() {
cbManager = CBCentralManager(delegate: self, queue: nil)
self.timer = Timer.scheduledTimer(timeInterval: TimeInterval(1), target: self, selector: #selector(scan), userInfo: nil, repeats: true)
}
@objc func scan() {
if(cbManager != nil && cbManager.state.rawValue==CBManagerState.poweredOn.rawValue) {
cbManager.scanForPeripherals(withServices: nil, options: nil)
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
Beacon(peripheral: peripheral, advertisementData: advertisementData as NSDictionary, RSSI: RSSI).checkAdvertisementDataForPossibleiBeaconData()
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if(!(central.state.rawValue == CBManagerState.poweredOn.rawValue)) {
print("In order to user this tool, Bluetooth must be switched on\n")
exit(EXIT_FAILURE)
}
}
}
这似乎工作得很好。我得到以下信息:
BeaconStandard=[76, 0, 2, 21], UUID=C7C1A1BF-BB00-4CAD-8704-9F2D2917DED2, major=0, minor=0, power=-56, RSSI=Optional(-74), Distance=7.80m
BeaconStandard=[76, 0, 2, 21], UUID=C7C1A1BF-BB00-4CAD-8704-9F2D2917DED2, major=0, minor=0, power=-56, RSSI=Optional(-76), Distance=9.60m
然后我构建了一个 iOS 应用程序,只需复制 ViewController 代码替换
import Cocoa
import CoreBluetooth
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
BeaconScanner(type: BeaconType.iBeacon).scanEverySecond()
}
}
和
import UIKit
import CoreBluetooth
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
BeaconScanner(type: BeaconType.iBeacon).scanEverySecond()
}
}
我在 iOS 上运行了大约 5 分钟的代码,但没有成功。
我添加了一些调试代码,我确实看到了来自其他蓝牙设备的点击,但没有来自 PI。
MacOS 正在运行 10.14.6。iOS 运行 12.3.1,XCode 运行 10.3。
这是硬件限制吗?我知道 CSR 蓝牙很便宜。还是我的代码有问题?
解决方案
推荐阅读
- bash - shell脚本可以与at提示交互吗
- javascript - 父 div 外的 SVG 线
- asp.net-core - 从父目录运行网站时,asp.net core MVC 静态文件给出 404 错误
- c# - c# interop Word插入横向页面
- google-maps - 使用 react-google-maps 创建和添加样式地图类型
- linux - 我可以从终端输出中 grep(或过滤)特定颜色的行吗?
- java - 将集合划分为给定列表中包含的所有可能的子集
- html - VSCodeBeautify 如何为美化创建配置以防止文本换行
- java - Jackson 反序列化子类型将枚举字段设置为 null
- python - 如何在包含布尔值的python列表的列表中获取布尔值作为输出