I am implementing beacons in my app with google beacon platform. Currently, beacon can be detected from a long range. I need to limit the range of detection which is quite not possible right now. Other option I am considering to detect the distance between iPhone and beacon. Is there anything provided by google or open-source SDK which can help me achieving the desired behaviour?
The documentation is pretty sparse, but I have open source code here detecting Eddystone on iOS and ranging beacons with it.
Here is an example of how you use it to detect Eddystone-UID:
var scanner: RNLBeaconScanner?
scanner = RNLBeaconScanner.shared()
scanner?.startScanning()
// Execute this code periodically (every second or so) to view the beacons detected
if let detectedBeacons = scanner?.trackedBeacons() as? [RNLBeacon] {
for beacon in detectedBeacons {
if (beacon.beaconTypeCode.intValue == 0x00 && beacon.serviceUuid.intValue == 0xFEAA) {
// this is eddystone uid
NSLog("Detected EDDYSTONE-UID with namespace %# instance %#", beacon.id1, beacon.id2)
NSLog("The beacon is about %.1f meters away", beacon.distance)
}
}
}
Related
Is it possible to detect iBeacons without knowing their UUID?
Is there any way to use Core Bluetooth or some other method?
You must know at least the UUID you are looking for in order to create a CLBeaconRegion. There is no way on iOS to scan for "all beacons".
iBeacons are specifically obscured from Core Bluetooth discovery.
While you cannot detect beacons on iOS without specifying the ProximityUUID up front, you can set up ranging to look for a large number of ProximityUUIDs -- I have successfully ranged for 100 of them at the same time (although 1000 crashes my app.)
By using an online beacon database, you can find a list of UUIDs known to be close to you. This won't detect every beacon for sure, but it will allow you to detect many that are around you without having to build the UUIDs into your app.
Here's an example using the NingoSDK to get the 100 nearest ProximityUUIDs to your location and register them for ranging.
let locationManager = CLLocationManager()
// Get up to 100 beacon ProximityUUIDs within 1km from our current location, so we can use these for beacon ranging
let queryClient = QueryBeaconClient(authToken: Settings().getSetting(key: Settings.ningoReadonlyApiTokenKey)!)
queryClient.queryFirstIdentifiers(latitude: latitude, longitude: longitude, radiusMeters: 1000, limit: 100) { (proximityUUIDStrings, errorCode, errorDetail) in
if let proximityUUIDStrings = proximityUUIDStrings {
NSLog("There are now \(proximityUUIDStrings.count) nearby beacon uuids")
if proximityUUIDStrings.count > 0 {
for region in locationManager.rangedRegions {
locationManager.stopRangingBeacons(in: region as! CLBeaconRegion)
}
for uuidString in proximityUUIDStrings {
let region = CLBeaconRegion(proximityUUID: UUID(uuidString: uuidString)!, identifier: uuidString)
locationManager.startRangingBeacons(in: region)
}
BeaconTracker.shared.updateTransientUuids(uuids: proximityUUIDStrings)
}
}
}
im trying to build a demo app using Estimote Beacons. i want the app to open e specific viewcontroller when the user is near a beacon. im using performseguewithidentifier but when the app starts is opens only the first viewcontroller representing the first beacon which is in the range and it doesnt open the other ones when i go near the other beacons. it somehow just stops ranging for other beacons.
below is the code im using to range for beacons:
func beaconManager(manager: AnyObject, didRangeBeacons beacons: [CLBeacon],
inRegion region: CLBeaconRegion) {
let knownBeacons = beacons.filter{ $0.proximity != CLProximity.Unknown}
if (knownBeacons.count > 0) {
let closestBeacon = knownBeacons [0] as CLBeacon
if(closestBeacon.minor.integerValue==50557){
performSegueWithIdentifier("VC1", sender: nil)
}
else if(closestBeacon.minor.integerValue==37890){
performSegueWithIdentifier("VC2", sender: nil)
}
else if(closestBeacon.minor.integerValue==18976){
performSegueWithIdentifier("VC3", sender: nil)
}
else {
self.view.backgroundColor = UIColor.brownColor()
}
I haven't used Estimote's custom library, but I assume it's similar to the location manager's.
In the Core Location Manager, if your app is in the background you get an entered region notification when you first enter a new beacon region, and then you only get ranging information for a few seconds.
If you've set up your region with a unique UUID and Major ID but no minor ID, then all beacons with that UUID and Major ID are considered part of the same region and you won't reliably get ranging notifications as the beacons with different minor IDs become the closest beacon.
If you want to handle multiple beacons in range at the same time and distinguish between them you'll need to create separate beacon regions for each beacon's UUID, Major ID and minor ID.
I don't know if that's the issue you're facing, but it could be.
I have this code to scan beacons
var closetBeacon: NSUUID?
let locationManager = CLLocationManager()
let region = CLBeaconRegion(proximityUUID: NSUUID(UUIDString: "B9407F30-F5F8-466E-AFF9-25556B57FE6D")!, identifier: "my_beacons")
func authorizeBeaconScan() -> Void{
locationManager.delegate = self
if (CLLocationManager.authorizationStatus() != CLAuthorizationStatus.AuthorizedWhenInUse) {
locationManager.requestWhenInUseAuthorization()
}
locationManager.startRangingBeaconsInRegion(region)
}
I understand region is supposed to filter only beacons I care about.
1) If I have few beacons I care about, how do I pass them all to CLBeaconRegion(..)?
2) can I scan for beacon without specifying region?
You have to have UUID of beacons to scan.
Without UUID you can't scan beacons.
1) You can scan all beacons of same UUID for region by only specifying UUID.
2) You can scan specific beacons of one group having common major value by specifying UUID and major value.
3) You can also scan for specific beacon by using UUID, major and minor value of that beacon.
You have to have at-least one UUID of beacon to create region and start scanning it.
I'm new to iOS and BLE. I've been following a tutorial to connect and send data to a BLE receiver board on an Arduino. The tutorial was designed for a different board, and I'm using the (the BLE board is the Adafruit nrf8001 if that might help).
The following code sets up the UUIDs...
let BLEServiceUUID = CBUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
let PositionCharUUID = CBUUID(string: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
let BLEServiceChangedStatusNotification = "kBLEServiceChangedStatusNotification"
And this code connects my iOS device to the BLE board.
central.connectPeripheral(peripheral, options: nil)
I then have a slider set up in my ViewController, and I want to send the value of that slider to the BLE board. Here's my writePosition function:
func writePosition(position: UInt8)->NSData {
let currentValue = NSUserDefaults.standardUserDefaults().floatForKey("sliderValue")
var currentValueString=NSString(format: "%.5f", currentValue)
var writeType:CBCharacteristicWriteType
let newString:NSString = currentValueString
let data = NSData(bytes: newString.UTF8String, length: newString.length)
peripheral?.writeValue(data, forCharacteristic: self.positionCharacteristic, type: writeType)
return data
}
Note that both my arduino AND my app confirm that they are indeed connected. However, if I change the slider value in the app, it does not send its value to the BLE board. What am I doing wrong??
Thanks in advance!
Please note that writing data to a BLE can not be done (typically), faster than 35 to 50 ms. It's a good idea to use a timer (which in iOS has a minimum tick between 50 to 100 ms) to write to the charactestistic, instead of writing directly from your slider. So the timer polls the slider's value and writes it. More advanced apps should use a tx queue.
Also, you may want to take a look to this answer: SWIFT - BLE communications
Hy guys, i need to find altitude, bearing and gps accuracy in my iPhone app. i've done this on my android app. in android, i did it like this :
public void onLocationChanged(Location location) {
if (isBetterLocation(location, lastValidLocation)
&& isEnable) {
lastValidLocation = location;
longitude = location.getLongitude();
latitude = location.getLatitude();
altitude = location.getAltitude();
speed = location.getSpeed();
accuracy = location.getAccuracy();
bearing = location.getBearing();
locationProvider = location.getProvider();
onPositionChanged(
LocationService.this,
new GeoPoint(location.getLongitude(), location
.getLatitude()));
}
}
how can i do the same thing in iOS ?
i've tried to get it from CLLocation, but it return null/0,0000/-1.0000 ..
btw, i get this result when i test it on iOS Simulator.
Thanks.
Regards.
The simulator is not a good place to test Core Location stuff. It only simulates a specific location but if you want to test speed, bearing etc. you're better of trying on a real device.
You need to use the class CLLocationManager (Apple doc) and fetch the data using the delegate protocol available. For example, if you want the heading you implement the method locationManager:didUpdateHeading: and call the method startUpdatingHeading on the location manager.