2017-01-30 2 views
0

Я пытаюсь написать приложение, которое периодически получает обновления о близости к находящимся в настоящий момент iBeacons. У меня есть два iBeacons, которые я бы хотел отслеживать, они мои собственные, и я жестко запрограммировал UUID для отслеживания в моем коде. Сами iBeacons имеют один и тот же главный идентификатор, но другой младший id. Мой вопрос заключается в том, как получать периодические обновления о близости к iBeacons, найденным с предустановленным UUID. Я понимаю, что это нужно делать с помощью CLLocationManager, так как это реализует iBeacon.Получите обновления близости iBeacon с помощью CLLocationManager

Моего текущее экспериментирование с 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

В чем вопрос? Что делает ваш код сейчас? С чем вы столкнулись? – davidgyoung

+0

Вам нужно добавить экземпляры CLBeaconRegion для маяков, которые вы хотите контролировать. Если маяки можно увидеть одновременно, вам нужно будет зарегистрировать два региона. – Paulw11

+0

@davidgyoung Я обновил свой вопрос и изменил код на содержимое всего моего файла FirstViewController.swift. У меня есть iBeacon, что я хотел бы получить близость, как только он будет обнаружен. Как только он будет обнаружен, я хотел бы получать периодические обновления о близости, чтобы я знал, когда переключать свой свет. Я не могу понять, как я буду реализовывать что-то в этом направлении. – Joris

ответ

1

Поле beacon.proximity будет обновляться с каждым обратным вызовом до func locationManager(_: CLLocationManager, didRangeBeacons: [CLBeacon], in: CLBeaconRegion). Эти обратные вызовы будут поступать один раз в секунду с массивом объектов CLBeacon, которые имеют это поле. Поэтому каждые 1 секунду вы получите обновление.

Основываясь на способе создания кода, выясняется, что beaconsInProximity будет правильно обновляться, если маяковый радиосигнал находится в непосредственной близости, а switchLamp будет вызываться позже в методе обратного вызова.

Понимают, однако, что поле CLBeaconproximity может не обновляться так быстро, как хотелось бы. Это поле получено из поля accuracy, которое является оценкой расстояния в метрах. Если оценка расстояния < 0,5 метра, то accuracy будет установлен на немедленное. Если оценка расстояния> 0,5 метра, она будет установлена ​​на другое значение.

Оценка расстояния в accuracy основана на 20-секундном среднем значении измерений RSSI. Из-за этого, если вы очень быстро переместитесь с 5 метров вправо рядом с передатчиком маяка, поле accuracy будет медленно изменяться с ~ 5.0 до ~ 0.0 в течение 20 секунд. Поле proximity займет около 20 секунд, чтобы показать immediate.

Кроме того, важно понимать, что маяк должен быть правильно калиброван с измеренным значением мощности, установленным внутри маякового радиосигнала, для максимально точной оценки расстояния. Если вы получаете очень неточную оценку расстояния в accuracy даже после останова в течение 20 секунд, вам может понадобиться выполнить эту калибровку.

+0

Когда я пытаюсь настроить, он выглядит как 'func locationManager (_: CLLocationManager, didRangeBeacons: [CLBeacon], в: CLBeaconRegion)' даже не вызывается. Я только получаю сообщения в консоли для 'func locationManager (_ manager: CLLocationManager, didEnterRegion region: CLRegion)' и 'func locationManager (_ manager: CLLocationManager, didExitRegion region: CLRegion)'. Кажется, что что-то не так с моим утверждением 'if (beacon.proximity == CLProximity.immediate). Что я делаю не так? – Joris

+0

О, ничего себе, я думаю, что ваша подпись метода обратного вызова неверна. Вот правильная подпись для Swift 3.0: 'func locationManager (_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], в регионе: CLBeaconRegion)' – davidgyoung

+0

Я изменил свою функцию на 'func locationManager (_ manager: CLLocationManager, didRangeBeacons маяки: [CLBeacon], в регионе: CLBeaconRegion) 'и' if (beacon.proximity == CLProximity.immediate) 'все еще не работает. Я не вижу, что я делаю неправильно. – Joris

Смежные вопросы