使用CLLocationManager获取iBeacon邻近更新

时间:2017-01-30 18:28:26

标签: ios swift ibeacon

我正在尝试编写一个应用程序,定期接收有关当前找到的iBeacons附近的更新。我有两个想要跟踪的iBeacon,它们是我自己的,我将UUID硬编码以跟踪我的代码。 iBeacons本身具有相同的主要ID,但具有不同的次要ID。我的问题是如何获得有关使用预设UUID找到的iBeacons附近的定期更新。我知道这需要用CLLocationManager来完成,因为它实现了iBeacon范围。

我目前使用CLLocationManager进行实验:

import UIKit;
import CoreLocation;
import HomeKit;

class FirstViewController: UIViewController, CLLocationManagerDelegate, HMHomeManagerDelegate, UIPickerViewDelegate, UIPickerViewDataSource{

let homeManager = HMHomeManager();
let locationManager = CLLocationManager();
var beaconsInProximity: [CLBeacon] = [];
let beaconUUID: String = "11984894-7042-9801-839A-ADECCDFEDFF0";
let beaconMajor = 0x1;
let beaconMinor: [Int] = [0x1, 0x7];
let homeName = "Home";
var lamps = [HMAccessory]();
var lampNames = [String]();
var pickerNames = [String: HMAccessory]();
var selectedLamp: HMAccessory!;
var lightHome: HMHome!;
var firstLight: HMAccessory!;
var secondLight: HMAccessory!;
var thirdTestLight: HMAccessory!;
let beaconRegion: CLBeaconRegion = CLBeaconRegion(proximityUUID: NSUUID(uuidString:"11984894-7042-9801-839A-ADECCDFEDFF0")as! UUID, identifier: "Beaconons");

@IBOutlet weak var lampSwitch: UISwitch!
@IBOutlet weak var configureLampButton: UIButton!
@IBOutlet weak var lampPicker: UIPickerView!
@IBOutlet weak var identifyLampButton: UIButton!
@IBOutlet weak var lampSelectedLabel: UILabel!
@IBOutlet weak var lampStatusLabel: UILabel!
@IBOutlet weak var beaconStatusLabel: UILabel!

override func viewDidLoad(){
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    if(selectedLamp != nil){
        updateLampLabel(selectedLamp);
        updateLampStatusLabel(selectedLamp);
    }else{
        updateLampLabelNoLamp();
        updateLampStatusLabelNoStatus();
    }
    homeManager.delegate = self;
    lampPicker.delegate = self;
    lampPicker.dataSource = self;
    locationManager.delegate = self;
    locationManager.requestAlwaysAuthorization();
    locationManager.startMonitoring(for: beaconRegion);
    locationManager.startRangingBeacons(in: beaconRegion);
    locationManager.requestState(for: beaconRegion);
}

override func didReceiveMemoryWarning(){
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
    for home in homeManager.homes{
        for accessory in home.accessories{
            if(accessory.name.contains("lamp")){
                lamps.append(accessory);
                pickerNames[String(describing: accessory.services[1].characteristics[0].value)] = accessory;
                print("Added accessory " + String(describing: accessory.services[1].characteristics[0].value) + " to lamp list");
            }
        }
    }
    if(lamps.count != 0){
        for index in 0...(lamps.count - 1){
            lampNames.append(String(describing: lamps[index].services[1].characteristics[0].value));
        }
    }
}

func locationManager(_: CLLocationManager, didRangeBeacons: [CLBeacon], in: CLBeaconRegion){
    for beacon in didRangeBeacons{
        if(beacon.proximity == CLProximity.immediate){
            beaconsInProximity.append(beacon);
        }else{
            if(beaconsInProximity.contains(beacon)){
                for index in 0...beaconsInProximity.count{
                    if(beaconsInProximity[index] == beacon){
                        beaconsInProximity.remove(at: index);
                    }
                }
            }
        }
    }
    for beacon in beaconsInProximity{
        if(beacon.major.intValue == beaconMajor){
            if(beacon.minor.intValue == 0x3){
                if(selectedLamp != nil){
                    switchLamp(selectedLamp, true);
                    beaconStatusLabel.text = "region detected";
                }
            }else{
                if(selectedLamp != nil){
                    switchLamp(selectedLamp, false);
                    beaconStatusLabel.text = "lamping all the lamps that have ever lamped";
                }
            }
        }
    }
}

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    let bRegion = region as! CLBeaconRegion;
    if(bRegion.proximityUUID == beaconRegion.proximityUUID){
        print("Correct region");
        beaconStatusLabel.text = "Entered beacon region";
    }
}

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    let bRegion = region as! CLBeaconRegion;
    if(bRegion.proximityUUID == beaconRegion.proximityUUID){
        print("Exited correct region");
        beaconStatusLabel.text = "Beacon region left";
    }
}

@IBAction func configureLampButtonPressed(_ sender: AnyObject){
    if(pickerNames[lampNames[lampPicker.selectedRow(inComponent: 0)]] != nil){
        selectedLamp = pickerNames[lampNames[lampPicker.selectedRow(inComponent: 0)]];
    }
    if(selectedLamp != nil){
        updateLampLabel(selectedLamp);
        updateLampStatusLabel(selectedLamp);
    }else{
        updateLampLabelNoLamp();
        updateLampStatusLabelNoStatus();
    }

}

@IBAction func identifyLampButtonPressed(_ sender: AnyObject){
    if(selectedLamp != nil){
        identifyLamp(selectedLamp);
    }
}

@IBAction func lampSwitchFlipped(_ sender: AnyObject){
    if(selectedLamp != nil){
        switchLamp(selectedLamp, lampSwitch.isOn);
        updateLampStatusLabel(selectedLamp);
    }else{
        lampSwitch.setOn(!lampSwitch.isOn, animated: true);
        updateLampStatusLabelNoStatus();
    }
}

func updateLampLabelNoLamp(){
    lampSelectedLabel.text = "No lamp selected";
}

func updateLampLabel(_ lamp: HMAccessory){
    lampSelectedLabel.text = "Selected lamp: " + lamp.name;
}

func numberOfComponents(in pickerView: UIPickerView) -> Int{
    return 1;
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{
    return lampNames.count;
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?{
    return lampNames[row];
}

func booleanToInt(_ value: Bool) -> Int{
    if(value){
        return 1;
    }else{
        return 0;
    }
}

func sendLocalNotificationWithMessage(_ message: String!){

}

func switchLamp(_ lamp: HMAccessory, _ value: Bool){
    lamp.services[1].characteristics[1].writeValue(booleanToInt(value), completionHandler: {
        error in
        if let error = error{
            print("Something went wrong! \(error)");
        }
    })
}

func identifyLamp(_ lamp: HMAccessory){
    lamp.services[0].characteristics[3].writeValue(1, completionHandler: {
        error in
        if let error = error{
            print("Something went wrong! \(error)");
        }
    })
}

func updateLampStatusLabel(_ lamp: HMAccessory){
    lampStatusLabel.text = "Lamp status: " + String(describing: selectedLamp.services[1].characteristics[1].value);
}

func updateLampStatusLabelNoStatus(){
    lampStatusLabel.text = "Select a lamp";
}
}

应用程序本身的目标是根据用户是否在附近来切换灯泡。

1 个答案:

答案 0 :(得分:1)

beacon.proximity字段将在每次回调到func locationManager(_: CLLocationManager, didRangeBeacons: [CLBeacon], in: CLBeaconRegion)时更新。这些回调将每秒发生一次,其中包含具有此字段的CLBeacon对象数组。因此,每1秒钟您将获得一次更新。

根据代码的设置方式,如果信标紧邻,并且稍后将在回调方法中调用beaconsInProximity,则switchLamp似乎会正确更新。

但请注意,CLBeacon的{​​{1}}字段可能无法像您一样快速更新。此字段源自proximity字段,该字段是以米为单位的距离估计值。如果距离估计是< 0.5米,然后accuracy将立即设置。如果距离估计> 0.5米,它将被设置为另一个值。

accuracy中的距离估计基于RSSI测量的20秒运行平均值。因此,如果您非常快速地从5米远处移动到信标发射器旁边,accuracy场将在20秒内从~5.0缓慢变为~0.0。 accuracy字段显示proximity需要将近20秒的时间。

此外,重要的是要了解必须使用信标内设置的measuredPower值正确校准信标,以便尽可能准确地估算距离。如果您在immediate中获得非常不准确的距离估计值,即使在静止20秒后也是如此,那么您可能需要进行此校准。