How to know the closest iBeacon

旧巷老猫 提交于 2019-11-30 17:57:57

问题


I have a code to know which beacon is the closest, but I have a problem when a beacon's accuracy is -1.00000, the the app takes the second one.

So there is a bucle that seek for the closest beacon looking for others and comparing the one closest with the others found around. Then when I know which is the closest one I show it's view to the user, but when other beacon is closer to the ipad the view is close and the view is shown.

I'm using iOS 7.1 and 7.0.4 on 2 iPads, first is iPad3 and the second one is an iPad Mini Retina.

Here you have the code:

    - (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

- (void)initRegion {
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"00000000-0000-0000-0000-000000000002"];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:@"com.devfright.myRegion"];
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    NSLog(@"Beacon Found");
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    NSLog(@"Left Region");
    [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}
-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
    CLBeacon *beacon = [[CLBeacon alloc] init];
    CLBeacon *closestBeacon = [[CLBeacon alloc] init];
    closestBeacon = [beacons lastObject];

    //Search for the closest and show the view
    for (int i=0; i<beacons.count; i++) {
        beacon = beacons[i];
        if (beacon.accuracy < closestBeacon.accuracy && beacon.accuracy != -1.000000 && beacon.minor != closestBeacon.minor && beacon.proximity != CLProximityFar) {
            closestBeacon = beacons[i];
            //NSString *closeAccuracy = closestBeacon.minor.stringValue;
        }
        NSLog(@"\nActualBeacon:%@\nAccuracy:%f", beacon.minor.stringValue,beacon.accuracy);
        NSLog(@"\nCloserBeacon: %@\nAccuracy:%f", closestBeacon.minor.stringValue, closestBeacon.accuracy);

    }
    NSLog(@"\nClosestBeacon: %@", closestBeacon.minor.stringValue);
    if (viewShown == NO) {
        if ([closestBeacon.minor.stringValue  isEqual: @"1"]) {
            actualSection = 1;
            [self immediateDetection];
        }else if ([closestBeacon.minor.stringValue  isEqual: @"2"]){
            actualSection = 2;
            [self immediateDetection];
        }else if ([closestBeacon.minor.stringValue  isEqual: @"3"]){
            actualSection = 3;
            [self immediateDetection];
        }else if ([closestBeacon.minor.stringValue  isEqual: @"4"]){
            actualSection = 4;
            [self immediateDetection];
        }else if ([closestBeacon.minor.stringValue  isEqual: @"5"]){
            actualSection = 5;
            [self immediateDetection];
        }else if ([closestBeacon.minor.stringValue  isEqual: @"6"]){
            actualSection = 6;
            [self immediateDetection];
            NSLog(@"6");
        }else if ([closestBeacon.minor.stringValue  isEqual: @"7"]){
            actualSection = 7;
            [self immediateDetection];
            NSLog(@"7");
        }else if ([closestBeacon.minor.stringValue  isEqual: @"8"]){
            actualSection = 8;
            [self immediateDetection];
            NSLog(@"8");
        }else if ([closestBeacon.minor.stringValue  isEqual: @"9"]){
            actualSection = 9;
            [self immediateDetection];
            NSLog(@"9");
        }else if ([closestBeacon.minor.stringValue  isEqual: @"10"]){
            actualSection = 10;
            [self immediateDetection];
            NSLog(@"10");
        }else if ([closestBeacon.minor.stringValue  isEqual: @"11"]){
            actualSection = 11;
            [self immediateDetection];
            NSLog(@"11");
        }else if ([closestBeacon.minor.stringValue  isEqual: @"30"]){
            actualSection = 30;
            [self immediateDetection];
        }
    } else if (viewShown == YES) {
        if (closestBeacon.minor.integerValue != actualSection) {
            //Alarm: Beacon 11
//            if (closestBeacon.minor.integerValue != 11 || closestBeacon.minor.integerValue != 10) {
                [self dismissViewControllerAnimated:NO completion:nil];
                //actualSection = 0;
                viewShown = NO;
//            }
        }
    }
}
- (void)immediateDetection
{
    viewShown = YES;
    if (self.presentedViewController)
    {
        return;
    }
    if (actualSection == 1) {
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 1;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 2){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 2;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 3){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 3;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 4){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 4;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 5){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 5;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 6){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 6;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 7){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 7;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 8){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 8;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 9){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 9;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }else if (actualSection == 10){
        ThiefAlarmViewController *thiefAlarmView = [[ThiefAlarmViewController alloc] init];
        [self presentViewController:thiefAlarmView animated:NO completion:nil];
    }else if (actualSection == 11){
        ThiefAlarmViewController *thiefAlarmView = [[ThiefAlarmViewController alloc] init];
        [self presentViewController:thiefAlarmView animated:NO completion:nil];
    }else if (actualSection == 30){
        SectionViewController *sectionView = [[SectionViewController alloc] init];
        sectionView.section = 30;
        [self presentViewController:sectionView animated:NO completion:nil];
        sectionView.lbl_name.text = self.lbl_name.text;
    }
}

When I know the closest iBeacon I show it's view, but when it's accuracy is -1.00000 and compare to others the app takes the second one cause the first has it's accuracy = -1.00000 .

Hope anyone can help me cause I don't know what to do, maybe this is an iBeacon problem, but I think there is a solution for this issue.

Thanks.


回答1:


First of all: Replace your long else/if of locationManager:didRangeBeacons:inRegion: with:

if (([closestBeacon.minor intValue] > 0 && [closestBeacon.minor intValue] <= 11) || [closestBeacon.minor intValue] == 30)
{
    actualSection = [closestBeacon.minor intValue]; 
    [self immediateDetection];
}

Replace your long else/if in immediateDetection with:

if ((actualSection > 0 && actualSection < 10 || actualSection == 30)
{
    SectionViewController *sectionView = [[SectionViewController alloc] init];
    sectionView.section = actualSection;
    [self presentViewController:sectionView animated:NO completion:nil];
    sectionView.lbl_name.text = self.lbl_name.text;
}
else if (actualSection == 10 || actualSection == 11)
{
    ThiefAlarmViewController *thiefAlarmView = [[ThiefAlarmViewController alloc] init];
    [self presentViewController:thiefAlarmView animated:NO completion:nil];
}
else
{
}

That should save you a lot of code.

For your issue, you could to this:

    NSPredicate *predicateIrrelevantBeacons = [NSPredicate predicateWithFormat:@"(self.accuracy != -1) AND ((self.proximity != %d) OR (self.proximity != %d))", CLProximityFar,CLProximityUnknown];
NSArray *relevantsBeacons = [beacons filteredArrayUsingPredicate: predicateIrrelevantBeacons];
    NSPredicate *predicateMin = [NSPredicate predicateWithFormat:@"self.accuracy == %@.@min.accuracy", relevantsBeacons];

    CLBeacon *closestBeacon = nil;
    NSArray *closestArray = [[relevantsBeacons filteredArrayUsingPredicate:predicateMin];
    if ([closestArray count] > 0)
        closestBeacon = [closestArray objectAtIndex:0];
   if (closestBeacon)
   { //Do your thing }
   else
   {//No relevant close beacon}



回答2:


locationManager:didRangeBeacons:inRegion: will return you a list of beacons in proximity order. That is, the first beacon in the list will be the nearest to you.

However, there is one exception to this rule: if any beacons have a proximity of Unknown, then they will be at the top of the list (because their accuracy is -1). To account for this, simply filter out any Unknown beacons, and then pick the first in the list:

beacons = [beacons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"proximity != %d", CLProximityUnknown]];
CLBeacon *nearestBeacon = [beacons firstObject];



回答3:


In addition to filtering out proximity values of -1, you also have to take into account cases where certain iBeacons periodically do not appear in a callback to didRangeBeacons: inRegion. This can happen due to radio interference, especially for battery powered beacons that do not transmit advertisements very frequently.

To solve this, you need to keep your own list of recently seen beacons, and track any beacons that have been seen in the last few seconds. If one of the beacons has a proximity of -1, you can either not put it in the list, or re-use the last known non -1 proximity value if it does not exist.

Another consideration that you need to take into account is that the proximity value will bounce around quite a bit. You may need to add some hysteresis logic to your algorithm so which beacon is the closest doesn't bounce back and forth every second. The specifics of how you want to do this depend on your use case.



来源:https://stackoverflow.com/questions/23290544/how-to-know-the-closest-ibeacon

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!