Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to Prototype an Airport

How to Prototype an Airport

I transformed my office building into an airport using a combination of Ruby, Objective-C, and a number of hardware hacks. The goal was to prototype a better in-airport experience using a mixture of GPS and iBeacon technology to establish precise indoor geolocation.

This talk discusses outdoor and indoor location, and how the iPhone (and Android) devices currently handle location and proximity. I’ll also discuss how I built a robust Ruby backend, and how I hacked some hardware together to create iBeacons.

3a1f18e5445bd821f290ed68c1f2d925?s=128

Barrett Clark

March 20, 2014
Tweet

Transcript

  1. Prototype an Airport An intersection of Ruby, native, and hardware

    hacks
  2. Barrett Clark @barrettclark (Twitter | GitHub)

  3. This began as an NFC Android experiment

  4. Airport Day of Travel Experience Breaks / Possible Sensor /

    Biometric / Tap-In Points 0.0 Home 1.0 Exterior Baggage Check 1.1 Personal Checkin Line 1.2 Personal Checkin Counter 1.3 Machine Checkin 2.0 Security Line Beginning 2.1 Security Line Check 3.0 Post Security 3.1 Concessionaires 3.2 Flight Boards 4.0 Gate Counter 4.1 Gate Seating 4.2 Boarding 5.0 On Plane 6.0 Gate Exit 2.0 2.1 3.0 1.1 1.3 4.1 3.1 5.0 0.0 1.0 1.3 1.2 2.0 2.1 3.0 3.1 3.2 4.2 4.0 5.0 6.0 1.0 1.3 1.2 2.1 3.1 4.2 4.0 5.0 6.0
  5. –You, every time you fly How long will it take

    to get through security? When should I leave for the airport?
  6. –Every Gate Agent Do I need to hold this flight

    for anyone?
  7. None
  8. Location It’s all relative http://www.flickr.com/photos/justinrflood/6550777169

  9. Geolocation • Accurate within feet • Store and query easily

    • Not difficult to setup/host • Combination of GPS, Cellular, and WiFi Access Point http://www.flickr.com/photos/trooper3d/707407034/
  10. Indoor Location • WiFi AP (satellite not visible) • Third

    Axis (elevation) important • Android can get more information from access points without connecting
  11. Indoor Location Tricky http://blogs.houstonpress.com/rocks/Run-DMC.jpg

  12. iPhone* Collection Server Location Server * or very recent versions

    of Android Hardware
  13. Bluetooth Buzzwords • Bluetooth v4.0/v4.1 • The latest version of

    the standard • Bluetooth Low Energy (BLE) • A subset of v4.0 • iBeacon • An implementation of BLE
  14. iBeacons Proximity

  15. iPhone* Collection Server Location Server * or very recent versions

    of Android Hardware
  16. CoreLocation

  17. #pragma mark Location Manager Delegate methods - (void)startStandardUpdates { //

    Create the location manager if this object does not // already have one. if (nil == locationManager) locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; locationManager.desiredAccuracy = kCLLocationAccuracyBest; // Set a movement threshold for new events. locationManager.distanceFilter = 10; // meters [locationManager startUpdatingLocation]; } Register For Location Updates
  18. - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { ! CLLocation* location =

    [locations lastObject]; NSDate* eventDate = location.timestamp; // Post to service (snipped) ! NSLog(@"lat %+.6f, lng %+.6f h accuracy %+.6f v accuracy %+.6f\n", location.coordinate.latitude, location.coordinate.longitude, location.horizontalAccuracy, location.verticalAccuracy); } Receive Location Updates
  19. CoreLocation, CLBeacon edition

  20. iBeacon Spec • proximityUUID • major • minor • [profit]

  21. #pragma mark iBeacon - (void) initializeBeacon { self.locationManager = [[CLLocationManager

    alloc] init]; self.locationManager.delegate = self; NSString *uuid = @"B8EF40B0-82D1-11E3-BAA7-0800200C9A66"; NSUUID *proximityUUID = [[NSUUID alloc] initWithUUIDString:uuid]; self.region = [[CLBeaconRegion alloc] initWithProximityUUID:proximityUUID major:0 identifier:@"Sabre Airport"]; ! self.region.notifyEntryStateOnDisplay = NO; self.region.notifyOnEntry = NO; self.region.notifyOnExit = NO; [self.locationManager startMonitoringForRegion:_region]; } Look For Beacons
  22. - (void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region { switch (state)

    { case CLRegionStateInside: // state == 1 // NOTE: The given proximityUUID is visible [self.locationManager startRangingBeaconsInRegion:self.region]; break; case CLRegionStateOutside: // state == 2 case CLRegionStateUnknown: default: ; // stop ranging beacons, etc [self.locationManager stopRangingBeaconsInRegion:self.region]; } } Range Beacons
  23. - (void) locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region { //

    A proximity value of 1 or 2 is considered "IN" the given area if ([beacons count] > 0) { CLBeacon *beacon; for (CLBeacon *b in beacons) { // Top secret business logic } ! // Post to service (snipped) ! NSLog(@"Major: %@, Minor: %@, Proximity: %d, Acc: %f, RSSI: %ld", beacon.major, beacon.minor, beacon.proximity, beacon.accuracy, (long)beacon.rssi); } } You are here near
  24. Mountain West Objective-C Conference?!

  25. iPhone* Collection Server Location Server * or very recent versions

    of Android Hardware
  26. Reading Collection Server • Write heavy • No enrichment •

    Return reading ID to native app • Publish reading (MQTT)
  27. Simple services can be simple

  28. class ReadingsController < ApplicationController skip_before_filter :verify_authenticity_token, :only => [:create] !

    def index render nothing: true end ! def create reading = Reading.create(reading_params) rescue nil if reading render json: reading.id else render nothing: true, status: 500 end end ! def show json_string = Rails.cache.read(params[:id]) || Reading.find(params[:id]).to_cache.to_json rescue nil render text: json_string end ! private ! def reading_params # list of the fields (snipped) params.require(:reading).permit(snipped) end end
  29. class Reading < ActiveRecord::Base validates_presence_of :latitude, :longitude, :accuracy, :unless =>

    :beacon_proximity_uuid? validates_presence_of :beacon_proximity_uuid, :beacon_major, :beacon_minor, :unless => :latitude? ! after_create :cache_reading after_create :publish_reading ! def to_cache { # Hash of the fields (snipped) } end ! private ! def cache_reading Rails.cache.write(self.id, self.to_cache.to_json) end ! def publish_reading $mqtt.publish('reading', self.to_cache.to_json) end end
  30. iPhone* Collection Server Location Server * or very recent versions

    of Android Hardware
  31. Location Server • PostGIS enabled • Subscribe to reading topic

    • REST call as backup to pub/sub • Tell native app what the reading means (locations)
  32. class Zone < ActiveRecord::Base has_many :zone_location_categories has_many :location_categories, :through =>

    :zone_location_categories ! def self.find_all_by_longitude_latitude(lng, lat) all. select([:id, :name]). where("ST_CONTAINS(fence,ST_GeomFromText('POINT(#{lng} #{lat})', 4326))") end ! def self.find_all_by_point(point) # SELECT * FROM my_spatial_table WHERE ST_Intersects(lonlat, polygon); all.select([:id, :name]).where(:fence => point) end ! def self.find_all_by_beacon(beacon_proximity_uuid, beacon_major, beacon_minor) all. select([:id, :name]). where(:beacon_proximity_uuid => beacon_proximity_uuid). where(:beacon_major => beacon_major). where(:beacon_minor => beacon_minor) end ! # snip end
  33. uri = URI.parse ENV['CLOUDMQTT_URL'] || 'mqtt://localhost:1883' conn_opts = { remote_host:

    uri.host, remote_port: uri.port, username: uri.user, password: uri.password, } ! Thread.new do MQTT::Client.connect(conn_opts) do |c| # The block will be called when a message arrives for the topic c.get('reading') do |topic, message| json = JSON.parse(message) reading = Reading.create!( # attributes (snipped) ) Rails.logger.debug "#{topic}: #{reading.id} : #{message}" end end end
  34. iPhone* Collection Server Location Server * or very recent versions

    of Android Hardware
  35. http://www.flickr.com/photos/mtl_shag/5799534248/

  36. None
  37. None
  38. None
  39. Prototyping The Airport • Geolocation for “where in the world

    am I?” • Proximity (iBeacon) for “where in the building am I?” • Rails backend to decipher what it all means • And most importantly….
  40. http://memegenerator.net/instance/47234981

  41. Barrett Clark @barrettclark (Twitter | GitHub)