Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 954
mad_mask Avatar asked May 19 '14 00:05

mad_mask


2 Answers

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];


}
like image 68
Paulw11 Avatar answered Nov 12 '22 04:11

Paulw11


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.

like image 3
Duncan C Avatar answered Nov 12 '22 04:11

Duncan C