blob: 9b7c08e6d6851f97d9a5e415a50dcdd895f8f7e1 [file] [log] [blame]
//
// NTViewController.m
// HiBeacons
//
// Created by Nick Toumpelis on 2013-10-06.
// Copyright (c) 2013 Nick Toumpelis.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "NTViewController.h"
static NSString * const kUUID = @"00000000-0000-0000-0000-000000000000";
static NSString * const kIdentifier = @"SomeIdentifier";
static NSString * const kCellIdentifier = @"BeaconCell";
@interface NTViewController ()
@property (nonatomic, strong) CLLocationManager *locationManager;
@property (nonatomic, strong) CLBeaconRegion *beaconRegion;
@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) NSArray *detectedBeacons;
@end
@implementation NTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.advertisingSwitch addTarget:self
action:@selector(changeAdvertisingState:)
forControlEvents:UIControlEventValueChanged];
[self.rangingSwitch addTarget:self
action:@selector(changeRangingState:)
forControlEvents:UIControlEventValueChanged];
}
#pragma mark - Beacon ranging
- (void)createBeaconRegion
{
if (self.beaconRegion)
return;
NSUUID *proximityUUID = [[NSUUID alloc] initWithUUIDString:kUUID];
self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:proximityUUID identifier:kIdentifier];
}
- (void)turnOnRanging
{
NSLog(@"Turning on ranging...");
if (![CLLocationManager isRangingAvailable]) {
NSLog(@"Couldn't turn on ranging: Ranging is not available.");
self.rangingSwitch.on = NO;
return;
}
if (self.locationManager.rangedRegions.count > 0) {
NSLog(@"Didn't turn on ranging: Ranging already on.");
return;
}
[self createBeaconRegion];
[self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
NSLog(@"Ranging turned on for region: %@.", self.beaconRegion);
}
- (void)changeRangingState:sender
{
UISwitch *theSwitch = (UISwitch *)sender;
if (theSwitch.on) {
[self startRangingForBeacons];
} else {
[self stopRangingForBeacons];
}
}
- (void)startRangingForBeacons
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self turnOnRanging];
}
- (void)stopRangingForBeacons
{
if (self.locationManager.rangedRegions.count == 0) {
NSLog(@"Didn't turn off ranging: Ranging already off.");
return;
}
[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
self.detectedBeacons = nil;
[self.beaconTableView reloadData];
NSLog(@"Turned off ranging.");
}
#pragma mark - Beacon ranging delegate methods
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (![CLLocationManager locationServicesEnabled]) {
NSLog(@"Couldn't turn on ranging: Location services are not enabled.");
self.rangingSwitch.on = NO;
return;
}
if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
NSLog(@"Couldn't turn on ranging: Location services not authorised.");
self.rangingSwitch.on = NO;
return;
}
self.rangingSwitch.on = YES;
}
- (void)locationManager:(CLLocationManager *)manager
didRangeBeacons:(NSArray *)beacons
inRegion:(CLBeaconRegion *)region {
if ([beacons count] == 0) {
NSLog(@"No beacons found nearby.");
} else {
NSLog(@"Found %lu %@.", (unsigned long)[beacons count], [beacons count] > 1 ? @"beacons" : @"beacon");
}
self.detectedBeacons = beacons;
[self.beaconTableView reloadData];
}
#pragma mark - Beacon advertising
- (void)turnOnAdvertising
{
if (self.peripheralManager.state != CBPeripheralManagerStatePoweredOn) {
NSLog(@"Peripheral manager is off.");
self.advertisingSwitch.on = NO;
return;
}
time_t t;
srand((unsigned) time(&t));
CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:self.beaconRegion.proximityUUID
major:rand()
minor:rand()
identifier:self.beaconRegion.identifier];
NSDictionary *beaconPeripheralData = [region peripheralDataWithMeasuredPower:nil];
[self.peripheralManager startAdvertising:beaconPeripheralData];
NSLog(@"Turning on advertising for region: %@.", region);
}
- (void)changeAdvertisingState:sender
{
UISwitch *theSwitch = (UISwitch *)sender;
if (theSwitch.on) {
[self startAdvertisingBeacon];
} else {
[self stopAdvertisingBeacon];
}
}
- (void)startAdvertisingBeacon
{
NSLog(@"Turning on advertising...");
[self createBeaconRegion];
if (!self.peripheralManager)
self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];
[self turnOnAdvertising];
}
- (void)stopAdvertisingBeacon
{
[self.peripheralManager stopAdvertising];
NSLog(@"Turned off advertising.");
}
#pragma mark - Beacon advertising delegate methods
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheralManager error:(NSError *)error
{
if (error) {
NSLog(@"Couldn't turn on advertising: %@", error);
self.advertisingSwitch.on = NO;
return;
}
if (peripheralManager.isAdvertising) {
NSLog(@"Turned on advertising.");
self.advertisingSwitch.on = YES;
}
}
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheralManager
{
if (peripheralManager.state != CBPeripheralManagerStatePoweredOn) {
NSLog(@"Peripheral manager is off.");
self.advertisingSwitch.on = NO;
return;
}
NSLog(@"Peripheral manager is on.");
[self turnOnAdvertising];
}
#pragma mark - Table view functionality
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CLBeacon *beacon = self.detectedBeacons[indexPath.row];
UITableViewCell *defaultCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:kCellIdentifier];
defaultCell.textLabel.text = beacon.proximityUUID.UUIDString;
NSString *proximityString;
switch (beacon.proximity) {
case CLProximityNear:
proximityString = @"Near";
break;
case CLProximityImmediate:
proximityString = @"Immediate";
break;
case CLProximityFar:
proximityString = @"Far";
break;
case CLProximityUnknown:
default:
proximityString = @"Unknown";
break;
}
defaultCell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@ • %@ • %f • %li",
beacon.major.stringValue, beacon.minor.stringValue, proximityString, beacon.accuracy, (long)beacon.rssi];
defaultCell.detailTextLabel.textColor = [UIColor grayColor];
return defaultCell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.detectedBeacons.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return @"Detected beacons";
}
@end