请建议我,iPhone应用程序是否可以连接外部蓝牙设备,如极地h7 / h6心率传感器健身带(http://www.polar.com/en/products/accessories/H7_heart_rate_sensor)?
我正在关注以下链接: http://www.tekritisoftware.com/scan-ble-devices-using-ios-core-bluetooth-framework https://github.com/sergiomtzlosa/CoreBluetooth-Demo/
但我不确定,iPhone应用程序是否会连接到这个外部健身带。请指导。
感谢。
答案 0 :(得分:2)
以下是扫描蓝牙HRM设备,发现其服务及其特征的完整工作示例的逻辑,然后是从通知中提取数据的逻辑。 希望代码中的注释是自我解释的。 在代码中我添加了一些URL到相关的蓝牙规格。
ViewController.h文件:
#import <UIKit/UIKit.h>
@import CoreBluetooth;
#define HRM_HEART_RATE_SERVICE_UUID @"180D"
#define DEVICE_INFO_SERVICE_UUID @"180A"
#define HRM_MEASUREMENT_CHARACTERISTIC_UUID @"2A37"
#define HRM_BODY_LOCATION_CHARACTERISTIC_UUID @"2A38"
#define DEVICE_MANUFACTURER_NAME_CHARACTERISTIC_UUID @"2A29"
@interface TestHRMViewController : UIViewController <CBCentralManagerDelegate, CBPeripheralDelegate>
@property (nonatomic, strong) CBCentralManager *centralManager;
@property (nonatomic, strong) CBPeripheral *hrmPeripheral;
// Instance method to get the heart rate BPM information
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error;
- (void) getBodyLocation:(CBCharacteristic *)characteristic;
// Instance methods to grab device Manufacturer Name, Body Location
- (void) getManufacturerName:(CBCharacteristic *)characteristic;
@end
ViewController.m文件:
#import "TestHRMViewController.h"
@interface TestHRMViewController ()
@end
@implementation TestHRMViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// Create the CoreBluetooth CentralManager //
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
self.centralManager = centralManager;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - CBCentralManagerDelegate
// Method called whenever you have successfully connected to the BLE peripheral //
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
// Set the delegate of the peripheral //
[peripheral setDelegate:self];
// Tell the peripheral to discover services //
// When the peripheral discovers one or more services, it calls the peripheral:didDiscoverServices: method //
[peripheral discoverServices:nil];
NSString *connected = [NSString stringWithFormat:@"Connected: %@", peripheral.state == CBPeripheralStateConnected ? @"YES" : @"NO"];
NSLog(@"%@", connected);
}
// Method called when an existing connection with a peripheral is disconnected //
// If the disconnection was not initiated by cancelPeripheralConnection: the cause is detailed in error //
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSString *connected = [NSString stringWithFormat:@"Connected: %@", peripheral.state == CBPeripheralStateConnected ? @"YES" : @"NO"];
NSLog(@"%@", connected);
}
// Method called with the CBPeripheral class as its main input parameter //
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
// Check to make sure that the device has a non-empty local name //
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if ([localName length] > 0){
NSLog(@"Found the HeartRate monitor: %@", localName);
// Stop scanning //
[self.centralManager stopScan];
// Store peripheral //
self.hrmPeripheral = peripheral;
peripheral.delegate = self;
// Connect to peripheral //
[self.centralManager connectPeripheral:peripheral options:nil];
}
else{
NSLog(@"Device with no localName");
}
}
// Method called whenever the device state changes //
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
// Determine the state of the CentralManager //
// (To make sure this iOS device is Bluetooth low energy compliant and it can be used as the CentralManager) //
if ([central state] == CBCentralManagerStatePoweredOff) {
NSLog(@"CoreBluetooth BLE hardware is powered off");
}
else if ([central state] == CBCentralManagerStatePoweredOn) {
NSLog(@"CoreBluetooth BLE hardware is powered on and ready");
// Create an array with Bluetooth-services you wish to detect //
NSArray *services = @[[CBUUID UUIDWithString:HRM_HEART_RATE_SERVICE_UUID], [CBUUID UUIDWithString:DEVICE_INFO_SERVICE_UUID]];
// Start scanning for services //
[self.centralManager scanForPeripheralsWithServices:services options:nil];
}
else if ([central state] == CBCentralManagerStateUnauthorized) {
NSLog(@"CoreBluetooth BLE state is unauthorized");
}
else if ([central state] == CBCentralManagerStateUnknown) {
NSLog(@"CoreBluetooth BLE state is unknown");
}
else if ([central state] == CBCentralManagerStateUnsupported) {
NSLog(@"CoreBluetooth BLE hardware is unsupported on this platform");
}
}
#pragma mark - CBPeripheralDelegate
// Method called when the peripheral's available services are discovered //
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
// Walk through all services //
for (CBService *service in peripheral.services){
NSLog(@"Discovered service: %@", service.UUID);
// Ask to discover characteristics for service //
[peripheral discoverCharacteristics:nil forService:service];
}
}
// Method called when the characteristics of a specified service are discovered //
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
// Check if service is HeartRate service //
if ([service.UUID isEqual:[CBUUID UUIDWithString:HRM_HEART_RATE_SERVICE_UUID]]){
// If so, iterate through the characteristics array and determine if the characteristic is a HeartRateMeasurement characteristic //
// If so, you subscribe to this characteristic //
for (CBCharacteristic *aChar in service.characteristics){
// Request HeartRateMeasurement notifications //
if ([aChar.UUID isEqual:[CBUUID UUIDWithString:HRM_MEASUREMENT_CHARACTERISTIC_UUID]]){
[self.hrmPeripheral setNotifyValue:YES forCharacteristic:aChar];
NSLog(@"Found heart rate measurement characteristic");
}
// Read BodySensorLocation once instead of subscribing to notifications //
else if ([aChar.UUID isEqual:[CBUUID UUIDWithString:HRM_BODY_LOCATION_CHARACTERISTIC_UUID]]){
[self.hrmPeripheral readValueForCharacteristic:aChar];
NSLog(@"Found body sensor location characteristic");
}
}
}
// Check if service is DeviceInformation service for Manufacturer name //
if ([service.UUID isEqual:[CBUUID UUIDWithString:DEVICE_INFO_SERVICE_UUID]]){
for (CBCharacteristic *aChar in service.characteristics){
// Read Manufacturer name once instead of subscribing to notifications //
if ([aChar.UUID isEqual:[CBUUID UUIDWithString:DEVICE_MANUFACTURER_NAME_CHARACTERISTIC_UUID]]){
[self.hrmPeripheral readValueForCharacteristic:aChar];
NSLog(@"Found a device manufacturer name characteristic");
}
}
}
}
// Method called when you retrieve a specified characteristic's value //
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
// New value for HeartRateMeasurement received //
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:HRM_MEASUREMENT_CHARACTERISTIC_UUID]]){
// Get HeartRate data //
[self getHeartBPMData:characteristic error:error];
}
// Characteristic value for ManufacturerName received //
else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:DEVICE_MANUFACTURER_NAME_CHARACTERISTIC_UUID]]){
// Get ManufacturerName //
[self getManufacturerName:characteristic];
}
// Characteristic value for BodySensorLocation received //
else if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:HRM_BODY_LOCATION_CHARACTERISTIC_UUID]]){
// Get BodySensorLocation //
[self getBodyLocation:characteristic];
}
}
#pragma mark - CBCharacteristic helpers
// Method to get the heart rate BPM data //
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error
{
// Get the BPM //
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml //
// Convert the contents of the characteristic value to a data-object //
NSData *data = [characteristic value];
// Get the byte sequence of the data-object //
const uint8_t *reportData = [data bytes];
// Initialise the offset variable //
NSUInteger offset = 1;
// Initialise the bpm variable //
uint16_t bpm = 0;
// Next, obtain the first byte at index 0 in the array as defined by reportData[0] and mask out all but the 1st bit //
// The result returned will either be 0, which means that the 2nd bit is not set, or 1 if it is set //
// If the 2nd bit is not set, retrieve the BPM value at the second byte location at index 1 in the array //
if ((reportData[0] & 0x01) == 0) {
// Retrieve the BPM value for the Heart Rate Monitor
bpm = reportData[1];
offset = offset + 1; // Plus 1 byte //
}
else {
// If the second bit is set, retrieve the BPM value at second byte location at index 1 in the array and //
// convert this to a 16-bit value based on the host’s native byte order //
bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));
offset = offset + 2; // Plus 2 bytes //
}
NSLog(@"bpm: %i", bpm);
// Determine if EE data is present //
// If the 3rd bit of the first byte is 1 this means there is EE data //
// If so, increase offset with 2 bytes //
if ((reportData[0] & 0x03) == 1) {
offset = offset + 2; // Plus 2 bytes //
}
// Determine if RR-interval data is present //
// If the 4th bit of the first byte is 1 this means there is RR data //
if ((reportData[0] & 0x04) == 0)
{
NSLog(@"%@", @"Data are not present");
}
else
{
// The number of RR-interval values is total bytes left / 2 (size of uint16) //
NSUInteger length = [data length];
NSUInteger count = (length - offset)/2;
NSLog(@"RR count: %lu", (unsigned long)count);
for (int i = 0; i < count; i++) {
// The unit for RR interval is 1/1024 seconds //
uint16_t value = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[offset]));
value = ((double)value / 1024.0 ) * 1000.0;
offset = offset + 2; // Plus 2 bytes //
NSLog(@"RR value %lu: %u", (unsigned long)i, value);
}
}
}
// Instance method to get the body location of the device //
- (void) getBodyLocation:(CBCharacteristic *)characteristic
{
// Get the BodySensorLocation //
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml //
NSData *sensorData = [characteristic value];
// Convert the characteristic value to a data object consisting of byte sequences //
uint8_t *bodyData = (uint8_t *)[sensorData bytes];
// Determine if you have device body location data //
if (bodyData){
// Access the first byte at index 0 in your array //
uint8_t bodyLocation = bodyData[0];
// Determine if it is 'Chest' or something else (other values mean other locations, see url) //
NSString *sensorLocation = [NSString stringWithFormat:@"Body Location: %@", bodyLocation == 1 ? @"Chest" : @"Undefined"];
NSLog(@"SensorLocation: %@", sensorLocation);
}
else {
// If no data is available, log N/A as the body location //
NSLog(@"SensorLocation: N?A");
}
}
// Method to get the manufacturer name of the device //
- (void) getManufacturerName:(CBCharacteristic *)characteristic
{
// Get the ManufacturerName //
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.manufacturer_name_string.xml //
NSString *manufacturerName = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
NSLog(@"ManufacturerName: %@", manufacturerName);
}
@end
答案 1 :(得分:2)
获得Swift的Swift实现 https://github.com/msyshani/PolarDemo-for-iOS
import UIKit
import CoreBluetooth
import QuartzCore
protocol polarDeledate{
func updateStatus(bpm:String)
func updateBPM(status:String)
}
class MSYPolarH7: NSObject , CBCentralManagerDelegate, CBPeripheralDelegate {
let POLARH7_HRM_DEVICE_INFO_SERVICE_UUID = "180A"
let POLARH7_HRM_HEART_RATE_SERVICE_UUID = "180D"
let POLARH7_HRM_MEASUREMENT_CHARACTERISTIC_UUID = "2A37"
let POLARH7_HRM_BODY_LOCATION_CHARACTERISTIC_UUID = "2A38"
let POLARH7_HRM_MANUFACTURER_NAME_CHARACTERISTIC_UUID = "2A29"
var polarDel:polarDeledate?
//MARK:- Var Init
var centralManager:CBCentralManager?
var polarH7HRMPeripheral:CBPeripheral?
//MARK:- Make Singleton
class var sharedInstance: MSYPolarH7 {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: MSYPolarH7? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = MSYPolarH7()
}
return Static.instance!
}
func startScanningDevice(){
let cManager=CBCentralManager(delegate: self, queue: dispatch_get_main_queue())
//cManager.delegate=self
// cManager.scanForPeripheralsWithServices([CBUUID(string: POLARH7_HRM_DEVICE_INFO_SERVICE_UUID),CBUUID(string: POLARH7_HRM_HEART_RATE_SERVICE_UUID)], options: nil)
cManager.scanForPeripheralsWithServices(nil, options: nil)
self.centralManager=cManager
}
//MARK:- CBCentralManager Delagates
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
peripheral.delegate=self
peripheral.discoverServices(nil)
if peripheral.state == CBPeripheralState.Connected {
print("Connected")
if let msyPolar = polarDel {
msyPolar.updateStatus("Connected")
}
}else{
print("Not connected")
if let msyPolar = polarDel {
msyPolar.updateStatus("Not connected")
}
}
}
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print("dis connected")
if let msyPolar = polarDel {
msyPolar.updateStatus("Disconnected")
}
self.centralManager?.connectPeripheral(peripheral, options: nil)
}
func centralManager(central: CBCentralManager, willRestoreState dict: [String : AnyObject]) {
print("Restored....")
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
let localName=advertisementData[CBAdvertisementDataLocalNameKey]
if localName?.length > 0 {
print("Found device is \(localName)")
self.centralManager?.stopScan()
peripheral.delegate=self
self.centralManager?.connectPeripheral(peripheral, options: nil)
self.polarH7HRMPeripheral=peripheral
}
}
func centralManagerDidUpdateState(central: CBCentralManager) {
if(central.state == CBCentralManagerState.PoweredOff){
print("CoreBluetooth BLE hardware is powered off")
}else if(central.state == CBCentralManagerState.PoweredOn){
print("CoreBluetooth BLE hardware is powered on and ready")
self.centralManager?.scanForPeripheralsWithServices([CBUUID(string: POLARH7_HRM_DEVICE_INFO_SERVICE_UUID),CBUUID(string: POLARH7_HRM_HEART_RATE_SERVICE_UUID)], options: nil)
}else if(central.state == CBCentralManagerState.Unauthorized){
print("CoreBluetooth BLE state is unauthorized")
}else if(central.state == CBCentralManagerState.Unknown){
print("CoreBluetooth BLE state is unknown")
}else if(central.state == CBCentralManagerState.Unsupported){
print("CoreBluetooth BLE hardware is unsupported on this platform")
}
}
//MARK:- CBPeripheralDelegate Delagates
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
for service:CBService in peripheral.services! {
print("discover service \(service.UUID)")
peripheral.discoverCharacteristics(nil, forService: service)
}
}
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
if service.UUID == CBUUID(string: POLARH7_HRM_HEART_RATE_SERVICE_UUID) {
for aChar:CBCharacteristic in service.characteristics! {
// Request heart rate notifications
if aChar.UUID == CBUUID(string: POLARH7_HRM_MEASUREMENT_CHARACTERISTIC_UUID) {
self.polarH7HRMPeripheral?.setNotifyValue(true, forCharacteristic: aChar)
print("Found heart rate measurement characteristic")
}else if aChar.UUID == CBUUID(string: POLARH7_HRM_BODY_LOCATION_CHARACTERISTIC_UUID){
self.polarH7HRMPeripheral?.readValueForCharacteristic(aChar)
print("Found body sensor location characteristic")
}
}
}
// Retrieve Device Information Services for the Manufacturer Name
if service.UUID == CBUUID(string: POLARH7_HRM_DEVICE_INFO_SERVICE_UUID) {
for aChar:CBCharacteristic in service.characteristics! {
// Request heart rate notifications
if aChar.UUID == CBUUID(string: POLARH7_HRM_MANUFACTURER_NAME_CHARACTERISTIC_UUID) {
self.polarH7HRMPeripheral?.readValueForCharacteristic(aChar)
print("Found a device manufacturer name characteristic")
}
}
}
}
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
// Updated value for heart rate measurement received
if characteristic.UUID == CBUUID(string: POLARH7_HRM_MEASUREMENT_CHARACTERISTIC_UUID) {
//print(characteristic)
//self.getHeartBPMData(characteristic, error:error!)
self.getHeartBPMData(characteristic)
}
// Retrieve the characteristic value for manufacturer name received
if characteristic.UUID == CBUUID(string: POLARH7_HRM_MANUFACTURER_NAME_CHARACTERISTIC_UUID ) {
getManufacturerName(characteristic)
}
// Retrieve the characteristic value for the body sensor location received
else if characteristic.UUID == CBUUID(string: POLARH7_HRM_BODY_LOCATION_CHARACTERISTIC_UUID ) {
getBodyLocation(characteristic)
}
}
//MARK:- CBCharacteristic helpers
// func getHeartBPMData(characteristic:CBCharacteristic,error:NSError)
func getHeartBPMData(characteristic:CBCharacteristic){
//print("Hello")
// print("characteristic \(characteristic)")
if characteristic.value == nil {
return
}
let data = characteristic.value
let reportData = UnsafePointer<UInt8>(data!.bytes)
var bpm : UInt16
if (reportData[0] & 0x01) == 0 {
bpm = UInt16(reportData[1])
} else {
bpm = UnsafePointer<UInt16>(reportData + 1)[0]
bpm = CFSwapInt16LittleToHost(bpm)
}
let outputString = String(bpm)
print("bpm is \(outputString)")
if let msyPolar = polarDel {
msyPolar.updateBPM(outputString)
}
//doHeartBeat()
return
// return outputString
}
func getManufacturerName(characteristic:CBCharacteristic){
let manufacturerName=NSString(data: characteristic.value!, encoding: NSUTF8StringEncoding)
print("Manufacturer is \(manufacturerName)")
return
}
}
答案 2 :(得分:1)
所以: Bluetooth Smart 是 Bluetooth Low Energy 的品牌名称。
来源:Bluetooth.com和WikiPedia。
Apple样本: CoreBluetooth温度传感器和iOS应用程序 LightBlue (检查/测试)是很好的开始。