我正在尝试编写一个应用程序,定期接收有关当前找到的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";
}
}
应用程序本身的目标是根据用户是否在附近来切换灯泡。
答案 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秒后也是如此,那么您可能需要进行此校准。