Using multiples Beacons (poping a view on each different beacon)
Asked Answered
K

2

5

I m a beginner in objective C. My app work correctly with one beacon. I'm using the "estimote SDK". I have many problems, i want to use 2 or 3 beacons. I want to push a View for each of the beacons.

I don't understand how i can do it with multiple beacons.

  1. I don't know if i have to use multiple beacon manager. (ESTBeaconManager* beaconManager)

  2. I dont know how to pass differents regions to the didRangeBeacons:(NSArray *)beacons inRegion:(ESTBeaconRegion *)region

  3. Can i use one beacon only for notification and the 2 others to pop 2 differents view when i m close of them. ( one different view for each beacon )

Thanks for your help.

Best Regards.

Code:

#import "ESTViewController.h"
#import "PresentViewController.h"
#import <ESTBeaconManager.h>
#import <AudioToolbox/AudioToolbox.h>

@interface ESTViewController () <ESTBeaconManagerDelegate>

@property (nonatomic, strong) ESTBeaconManager* beaconManager;
@property (nonatomic, strong) ESTBeaconManager* beaconManager2;
@property (nonatomic, strong) ESTBeaconManager* beaconManager3;

@property (nonatomic, strong) ESTBeacon* selectedBeacon;


@end

@implementation ESTViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // should i create one manager instance or more ?

    self.beaconManager = [[ESTBeaconManager alloc] init];
    self.beaconManager.delegate = self;
    self.beaconManager.avoidUnknownStateBeacons = NO;

    //self.beaconManager2 = [[ESTBeaconManager alloc] init];
    //self.beaconManager2.delegate = self;
    //self.beaconManager2.avoidUnknownStateBeacons = NO;

    //self.beaconManager3 = [[ESTBeaconManager alloc] init];
    //self.beaconManager3.delegate = self;
    //self.beaconManager3.avoidUnknownStateBeacons = NO;



    // My Differents regions


    region = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_PROXIMITY_UUID
                                                      major:12800 minor:228 identifier:@"Icy Marshmellow"];

    region2 = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_PROXIMITY_UUID
                                                       major:12800 minor:128 identifier:@"Mint Cocktail"];

    region3 = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_PROXIMITY_UUID
                                                       major:12800 minor:328 identifier:@"Blueberry Pie"];


    // Should i do it for each region with one ESTBeaconManager or 3 ?

    [self.beaconManager requestStateForRegion:region];
    [self.beaconManager requestStateForRegion:region2];
    [self.beaconManager requestStateForRegion:region3];


}

// NOTIFICATION METHOD :

-(void)beaconManager:(ESTBeaconManager *)manager
      didEnterRegion:(ESTBeaconRegion *)region
{
    // iPhone/iPad entered beacon zone

    // present local notification
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    notification.alertBody = @"Hello blabla blabla";
    notification.soundName = UILocalNotificationDefaultSoundName;

    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}

-(void)beaconManager:(ESTBeaconManager *)manager
       didExitRegion:(ESTBeaconRegion *)region
{
    // iPhone/iPad left beacon zone

    // present local notification
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    notification.alertBody = @"bye bye";
    notification.soundName = UILocalNotificationDefaultSoundName;

    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}



- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.beaconManager startRangingBeaconsInRegion:region];
    [self.beaconManager startMonitoringForRegion:region];

    //[self.beaconManager2 startRangingBeaconsInRegion:region2];
    //[self.beaconManager2 startMonitoringForRegion:region2];

    //[self.beaconManager3 startRangingBeaconsInRegion:region3];
    //[self.beaconManager3 startMonitoringForRegion:region3];


}

  - (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    [self.beaconManager stopRangingBeaconsInRegion:region];
    [self.beaconManager stopMonitoringForRegion:region];

    //[self.beaconManager2 stopRangingBeaconsInRegion:region2];
    //[self.beaconManager2 stopMonitoringForRegion:region2];

    //[self.beaconManager3 stopRangingBeaconsInRegion:region3];
    //[self.beaconManager3 stopMonitoringForRegion:region3];

}

// My problem is here , i dont know how i can pass differents regions here


-(void)beaconManager:(ESTBeaconManager *)manager
     didRangeBeacons:(NSArray *)beacons
            inRegion:(ESTBeaconRegion *)region
{
    if([beacons count] > 0)
    {

        if(!self.selectedBeacon)
        {
            // initialy pick closest beacon
            self.selectedBeacon = [beacons objectAtIndex:0];
        }
        else
        {
            for (ESTBeacon* cBeacon in beacons)
            {
                // update beacon it same as selected initially
                if([self.selectedBeacon.major unsignedShortValue] == [cBeacon.major unsignedShortValue] &&
                   [self.selectedBeacon.minor unsignedShortValue] == [cBeacon.minor unsignedShortValue])
                {
                    self.selectedBeacon = cBeacon;
                }
            }
        }



        switch (self.selectedBeacon.proximity)
        {
            case CLProximityUnknown:
            {

                self.rangeStatusImageView.image = [UIImage imageNamed:@"logo_signal.jpg"];
                self.descriptionStateLabel.text = @"Signal lost";
                break;
            }
            case CLProximityImmediate:
            {
                [self performSegueWithIdentifier: @"presentSegue" sender: self];
                break;
            }
            case CLProximityNear:
            {
                self.rangeStatusImageView.image = [UIImage imageNamed:@"logo_near_bleu.jpg"];
                self.descriptionStateLabel.text = @"Come closer";
                break;

            }
            case CLProximityFar:
            {
                self.rangeStatusImageView.image = [UIImage imageNamed:@"logo_far_clair.jpg"];
                self.descriptionStateLabel.text = @"Welcome";
                break;
            }

            default:
                break;
        }


    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

}

@end

EDIT

Ok i worked on my code and now i do it with one region. my array of beacons have 3 beacons.

region = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_PROXIMITY_UUID identifier:@"multibeacons"];

i dont use major or minor at the init.

in ViewDidAppears i do :

[self.beaconManager startRangingBeaconsInRegion:region];

The delegate like this :

-(void)beaconManager:(ESTBeaconManager *)manager
     didRangeBeacons:(NSArray *)beacons
            inRegion:(ESTBeaconRegion *)region
{

// I used a sort , sorting by distance
    NSSortDescriptor *sortDescriptor;
    sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"distance" ascending:YES];
    NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

// if breakpoint here 3 beacons in array
    self.beaconsArray = [beacons sortedArrayUsingDescriptors:sortDescriptors];

    if([self.beaconsArray count] > 0)
    {

        if(!self.selectedBeacon)
        {
            // initialy pick closest beacon
            self.selectedBeacon = [beacons objectAtIndex:0];
            currentBeaconMinor = self.selectedBeacon.minor;
        }
        else
        {
            for (ESTBeacon* cBeacon in self.beaconsArray)
            {
                // update beacon it same as selected initially
                if([self.selectedBeacon.major unsignedShortValue] == [cBeacon.major unsignedShortValue] &&
                   [self.selectedBeacon.minor unsignedShortValue] == [cBeacon.minor unsignedShortValue])
                {
                    self.selectedBeacon = cBeacon;
                    currentBeaconMinor = self.selectedBeacon.minor;
                }
            }
        }

I sort by distance and i have a currentBeaconMinor Value. My array of beacon have 3 beacons inside if i put a breakpoint i can see 3.

In the Switch proximity , i have do like this :

switch (self.selectedBeacon.proximity)
        {

            case CLProximityImmediate:
            {

                if ([currentBeaconMinor floatValue] == 128)
                {
                    NSLog(@"128 128 128");
                    //[self performSegueWithIdentifier: @"presentSegue1" sender: self];
                }

                else if ([currentBeaconMinor floatValue] == 228)
                {
                    NSLog(@"228 228 228");
                    //[self performSegueWithIdentifier: @"presentSegue2" sender: self];
                }
                else if ([currentBeaconMinor floatValue] == 328)
                {
                    NSLog(@"328 328 328");
                    //[self performSegueWithIdentifier: @"presentSegue3" sender: self];
                }

                break;
            }

But that still dont work :((( I m getting mad. My app pick initialy the closest beacon. After that app always keep the same beacon and never change. I move the beacon near the device but nslog always send me the same minor number. Please can you give me some help ? I m sure i m doing something wrong.

Katushka answered 19/5, 2014 at 0:19 Comment(1)
no need to sort, Estimote SDK while ranging for beacons, returns sorted by distance already array of beaconsPiling
P
5

Each beacon has 3 pieces of information - a UUID, a major number and a minor number. When you create a beacon region you must specify the UUID as a minimum. You can optionally specify a major and minor value. There is a limit to the number of beacon regions that iOS will scan for in the background (I believe it is 20), so generally it is best to be as broad as possible in your region registration and then determine when notified if you are interested in the beacon that is visible.

All Estimote beacons have the same UUID, so if you register a region with just the UUID your app will be notified whenever you are in range of any Estimote beacon. I can see that your three beacons are all using major 12800, so you could simply create a region that specified the UUID and the major and then you would be notified whenever a beacon with those values was visible - or you can do as you have done and register specific regions for each of your three beacons.

You only need a single EstBeaconManager instance to manage all regions.

Whenever you enter or exit a region your didEnterRegion and didExitRegion methods will be called. Also your didRangeBeacons method will be called if you are currently ranging beacons.

In these delegate methods you need to examine the major & minor (well, really just the minor, because in your case the major is always the same) values to determine which action you want to take. You can also examine the region identifier string to determine which beacon is visible.

Note that more than one beacon may be in range, so you may need to examine the proximities to determine which action you want to take.

Finally, although you define the three regions, you are not ranging/monitoring them all, so change your viewWillAppear to

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.beaconManager startRangingBeaconsInRegion:region];
    [self.beaconManager startMonitoringForRegion:region];

    [self.beaconManager startRangingBeaconsInRegion:region2];
    [self.beaconManager startMonitoringForRegion:region2];

    [self.beaconManager startRangingBeaconsInRegion:region3];
    [self.beaconManager startMonitoringForRegion:region3];


}
Pother answered 19/5, 2014 at 1:6 Comment(10)
Do you mean like this for identifier ? (void)beaconManager:(ESTBeaconManager *)manager didEnterRegion: (ESTBeaconRegion *)region { if ([region.identifier isEqualToString:@"firstRegionIdenfifier"]) { //do something } else if ([region.identifier isEqualToString:@"secondRegionIdentifier"]) { //do something else } }Katushka
Yes, or you can look at the numeric value of minorPother
You have an instance variable called 'region' and a local variable called 'region' - rename one of themPother
Thanks you very much for your help, i worked on my code but i always have the same beacon in the array "beacons" (i used breakpoints): -(void)beaconManager:(ESTBeaconManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(ESTBeaconRegion *)region { if([beacons count] > 0) { // do something } } The array contains only the beacons of region1, i have region2 and 3 but, even if i move my beacons aways , it detect always the same. Also i need this array to be sorted to be able to push different view for each beacon (on case immediate).Katushka
As I said in my answer, you need to work through the array to determine the closest beacon in the case where you can see more than one. You can use the distance property to helpPother
i tryed like u said , with a sort of the array by distance. ( see my code i edited it at the bottom ) but i that still dont work. Hope you can give me an hand for that. thanks in advance . Best regards.Katushka
I can't see how your updated code will ever change self.selectedBeacon. It is set when it is initially null, but after that it is only set when the minor and major match, so it will be set to the same beacon.Pother
Thanks for your help. I need it set with the closest beacon but i dont know how to do :( . I know i m on the good way to do it. Maybe you can tell me how to proceed ? ` i need to sort it again with self.beaconsArray = [beacons sortedArrayUsingDescriptors:sortDescriptors];` ?Katushka
You have already sorted the array by distance, ascending, so [self.beaconsArray objectAtIndex:0] will be the closest.Pother
YESSS ! I made it. Thanks you very much ! if([self.beaconsArray count] > 0) { if(!self.selectedBeacon) { // initialy pick closest beacon self.selectedBeacon = [beacons objectAtIndex:0]; currentBeaconMinor = self.selectedBeacon.minor; } else { self.beaconsArray = [beacons sortedArrayUsingDescriptors:sortDescriptors]; if(self.selectedBeacon != [beacons objectAtIndex:0] ) { self.selectedBeacon = [beacons objectAtIndex:0]; currentBeaconMinor = self.selectedBeacon.minor; }Katushka
A
3

I haven't used the Estimote SDK before. I just treat my Estimote beacons as vanilla iBeacons and use Apple's Location Manager framework.

It looks to me like you are very confused.

I looked at the Estimote SDK briefly, and it looked quite similar to Apple's location manager.

In the location manager, you create a beacon region, then you ask the location manager to start ranging for that beacon region (which tells you about estimated distance readings or you use startMonitoringForRegion to ask to be notified about enter/exit region events.

You can do both at the same time. Glancing at the Estimate APIs, it looks like they use the same approach.

You need to create a beacon region, then call startRangingBeaconsInRegion and/or startMonitoringForRegion to ask for range and/or enter/exit region notifications.

You then wait for your delegate method(s) to be called when a beacon enters/exits range, (startMonitoringForRegion) or changes distance (startRangingBeaconsInRegion)

Looking at the docs, it seems that calling requestStateForRegion will cause the Estimote beacon manager to call your locationManager:didDetermineState:forRegion: delegate method once and only once.

In your code, you haven't asked to monitor for regions or to range beacons, so all 3 regions will return a "not in range" state.

Don't call those requestStateForRegion. Call startMonitoringForRegion and/or startRangingBeaconsInRegion, and wait for the system to notify you when the beacon status changes.

Ave answered 19/5, 2014 at 0:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.