Skip to content
Ioannis Papapanagiotou edited this page Apr 4, 2016 · 4 revisions

iOS Application

The iOS application that was developed utilized the iBeacons (Gimbal and Estimote) beacons for micro-location, geofencing and proximity purposes. There are four different tabs, 3 of which are for the afforementioned purposes while the fourth tab just contains the information about our group. Programming the application for beacons require the use of CoreLocation and CoreBluetooth Framework. The CoreLocation framework, in order to reduce the RSSI fluctuation (Beacon RSSI), averages the RSSI. The RSSI value can be used to provide the approximate distance between the user and the beacons. The beacons are mainly intended for proximity based services i.e. the user can be in any of the four regions a) Immediate b) Near c) Far d) Unknown.

iOS application

(everything within the iPhoneApp folder)

Since we have used cocoapods in the application, you need to install the pods in our application as well. For that you have to open up the terminal, go to the directory where your application project is located (You can use cd (path) to change the directory). Once you get to the specific directory, type pod install. This will install the podfiles required to compile the project.

alt text alt text

Microlocation tab

alt text alt text

In this tab the first thing we are observing in the code is the iBeacon UUID information and can change depending on the beacons you have. It starts out by prompting the user on whether or not they allow their location to be tracked via location services. It then goes into the ranging of the beacons. The code moves onto the locationManager() method to receive the beacon data that is being transmitted to the iPhone. Once beacons are detected the iPhone goes into the for loop and sends the iBeacon packets out to the server via the corresponding URL. Our app has utilized bluemix so the bluemix pathname for the data to be sent to is provided. Once the response object comes back in JSON, the app then parses the object for the necessary coordinates from the server to then plot in the proper space on the map of the room. The location is then removed and the loop starts back over again for the next user's location.

Geofencing tab

alt text

In this tab the first thing we are observing in the code is the iBeacon UUID information and can change depending on the beacons you have. It goes into the ranging of the beacons and then prompts the user on whether or not they allow their location to be tracked via location services. It then loads the table rows based on the number of beacons in the room which is displayed under the beacon proximity map. The code moves onto the locationManager() method to receive the beacon data that is being transmitted to the iPhone. The locationManager() method reloads the table each time it is called and updates the table data on the RSSI, accuracy, proximity and UUID in real time. This is displayed to the user as they are around the iBeacon and moving around.

Proximity tab

alt text

In this tab the first thing we are observing in the code is the iBeacon UUID information and can change depending on the beacons you have. It goes into the ranging of the beacons and then prompts the user on whether or not they allow their location to be tracked via location services. It then loads the table rows based on the number of beacons in the room which is displayed under the beacon proximity map. The code moves onto the locationManager() method to receive the beacon data that is being transmitted to the iPhone. The locationManager() method reloads the table each time it is called and updates the table data on the RSSI, accuracy, proximity and UUID in real time and moves on to plot the iBeacon location based on the proximity of the user's iPhone to the iBeacon.

Micro-location

Micro-location is the process of locating an entity with an accuracy as high as 10cm. We forked the localization application developed by Andrew Craze. The micro-location implements the particle filtering algorithm to find out the location of the user within a certain space through a number of different beacons. The app can be tuned to accommodate a number of particles, different number of beacons, and noise standard deviation (comes in handy for indoor environments and noisy surroundings). The number of beacons can be changed by going to the CDSiBeaconPFViewController.m and adding/removing the beacons. A new beacon can be added by modifying the following part of the code

#define LANDMARK1COLOR [UIColor greenColor] // the color of the icon for a particular beacon #define LANDMARK1MINOR 1 // the minor value of the beacon #define LANDMARK1X 0.20 // the x-coordinate of the beacon 1 in the space #define LANDMARK1Y 0.245 // the y-cordinate of the beacon 1 in the space

Also, we need to add the following code in the method - (void)viewWillAppear:(BOOL)animated

[CDSBeaconLandmark landmarkWithIdent:[CDSBeaconLandmark identFromMajor:LANDMARKSMAJOR minor:LANDMARK1MINOR] x:LANDMARK1X y:LANDMARK1Y color:LANDMARK1COLOR]

The number of particle filters can be varied as well by modifying

#define PARTICLECOUNT 2000

The RSSI value is converted into distance in the method

- (double)metersFromRssi:(NSInteger)rssi

of CDSBeaconLandmark.m using the equation

double ret = 0.0003351 * exp(0.143220*-rssi);.

This equation can be modified as per the environment conditions. (Note: This is based on log-normal shadowing model)

App Delegate

The AppDelegate class is the first class to run when the application starts. The first lines define the overall uuid the app should monitor. It then calls the Apple prompt that requires the user to allow the app to use the phone’s location. The next lines instantiate the Singleton class, as well two variables within the Singleton class. After that is the locationManager code that creates the beacon monitor and starts listening periodically per Apple’s proprietary guidelines.

The locationManager didRangeBeacons inRegion method is where the brunt of the magic happens in this class. The method starts by defining some variables, a boolean signifying whether the ranged beacon has already been sent to the server and returned with its information. Then the ranged beacons are stored in the Singleton class for use in other view controllers and the two tables that list the nearby beacons are told to update their information.

The next section of this method iterates through each of the beacons and creates a JSON dictionary with key-value pairs for uuid, major, and minor values of the beacon. Next an instance of the GetBeaconService class is instantiated and its delegate is set to the current class (this tells Xcode to throw a warning if the protocol methods defined in GetBeaconService are not implemented).

Next, if no beacons have been sent to and returned from the server, then the parameters are sent to the server by calling the GetBeaconService method. After successfully returning the first beacon’s information, it is added to a Singleton array of known beacons. For future beacons, the array of known beacons is iterated through and the major and minor values are compared with the current beacon to determine if the beacon is already known. Then outside the iteration, if the beacon isn’t known then it is added to list of known beacons.

On the other hand, if there are beacons that have already been sent to and returned from the server, then they shouldn’t be sent again (because the didRangeBeacons method is being called many times, close to once a second from observation). In order to accomplish this, like with the first beacon, the known beacons are iterated through and compared with the current beacon to determine if the beacon is already known. Again, outside the iteration, if the beacon is still unknown then it is sent to the server and then added to the known beacons upon returning successfully.

SecondViewController (Geofencing)

The first method called in this tab is the viewDidLoad method. In this method, the table is instantiated and added to the view. The next two methods are used to create arrays for the different types of beacons based on the “usecase” variable returned by the server. If usecase = GEO, then the beacons are added to an array of geofencing beacons and if not, they are added to an array of “other beacons”. The next methods are all Apple methods called when a table loads or reloads its data. These determine the number of sections in the table, the number to rows in each section, what each row in each section displays, and what to do when a row is tapped. In this table, there are two sections, one for geofencing beacons and one for other beacons. The number of rows in each section is the number of beacons in the two arrays created through the methods described above. For this table, nothing currently happens upon selection.

The final table method is the cellForRowAtIndexPath method. This is the method that determines what is displayed in each table cell. This method will iterate through all the rows on its own so it will be called for every entry in the data set. This method is first divided by section.

If the section is 0 (the first section, geofencing in this case) then the geo beacons array is checked for entries. If there aren’t any then only one row is populated with a string stating there aren’t any beacons of that type. If there are beacons, then the cell text is set to the name of the beacon (the one returned from the server). The cell’s detail text is set to the major and minor values of the beacon. If the beacon name is TV (one example of a device to turn on) and the boolean that checks if the script has already been ran is false, then a web service call to the tomcat server is made. This web service call tells the server to run a script and turn on the Wemo switch.

If the section is 1 (the second section, for beacons of other types in this case), then the cell displays the same kind of information as section 0 (name, major, minor), however no web service calls are made.

There are methods that are called upon the successful or failed running of the script, however nothing is being done in these methods except for logging the error if the script fails.

ProximityViewController (Third Tab)

Once again, the first method called is the viewDidLoad method. Also once again, this method instantiates and displays a table in the view. In addition, it also creates two images for use in the view. One image is to represent a beacon, and the other is to represent a beacon that has been selected from the table. There is also a background image that was added through the .xib located in the main.storyboard file. The next methods are the same table methods that were used in the SecondViewController. This time, there is only one section and it is populated with all of the sourced beacons. Within the cell construction, the current beacon is checked against the checked beacon to see if that row should display a checkmark. The images displayed outside the table are also removed each time the data is reloaded and re-added to the view to ensure the correct correlation between selected beacon in the table and the selected beacon image above it. The images are displayed based on their proximity (immediate, near, far), however a large number of beacons might create overlap between the sections of the image. This is because the code was not optimized to place the beacon images in a radial pattern. The last part of the cell construction assigns the text label to be the proximity of the beacon (immediate, near, far) and the detail text of the cell to contain the beacon name, the beacon’s RSSI value, and the beacon’s distance from the phone (calculated based on the RSSI value).

Singleton

A singleton is basically like a mediator between all classes. Normally, a variable in one class or view controller can’t be accessed by another class or view controller. This can be bypassed by storing the object in a variable retained by the singleton. The class method (designated by a + instead of a - at the beginning of the method) is used to instantiate the Singleton (called in the AppDelegate soon after the application launches).

AFNetworking

AFNetworking is a public third party API for making HTTP requests. The version used in this application is 1.3 rather than 2.0. Version 1.3 is much easier to implement (and read). AFNetworking supports both GET and POST requests and utilizes the service delegate pattern to perform the requests. While this requires specific class files for each URL call, it also allows for more separation between the view controllers / app delegate and the service calls. Version 2.0 does not require specific class files, however each service call is constructed from scratch, in line as needed.

GetBeaconService / WemoScriptService

These are both AFNetworking services calls that utilize a delegate pattern. They are first constructed with a base url and then with a POST and GET url path respectively. Next are two method definitions for success and failure of the HTTP request. As stated above, these service classes don’t call the web-service, but are used as constructors within the classes the service is going to be called.

iBeacon (Model Class)

This model is used to make it easier to access the database values of the returned beacons (name and use case). An alternative would have been to subclass the CLBeacon class so that all of its properties are still accessible, however this was the simpler method.

Clone this wiki locally