I am trying a simple test right now.
Device 1:
Acts as beacon with UUID: XXX-XXX-XXX
Major: 1000
Minor: 1234
self.peripheralData = [MyRegion peripheralDataWithMeasuredPower:nil];
[self.peripheralManager startAdvertising:self.peripheralData];
Device 2:
Acts as listener for region with UUID: XXX-XXX-XXX
locationManager startMonitoringForRegion:_region
Device 2 does not detect Device 1. It only detects Device 1 if I program to listen to the region to have major:1000 and minor: 1234.
Does this sound right?
Let's say i have 100 phones acting as beacon with same uuid and identifier but different major and minor values. And I have 50 phones acting as listeners for the specific uuid and idenfitifer... Can I find all beacons with that uuid and read their major and minor values?
What am I doing wrong?
When you initialize your region, use
region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:identifierString];
instead of something like
region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid major:[major integerValue] minor:[minor integerValue] identifier:identifierString];
By not specifying the major and minor values, all beacons with the matching UUID should be detected. It works for me.
I think the key to your problem lies in this comment:
Sure. It's just created using initwithuuid major and minor – Legolas
yesterday
There are 3 different calls to create a beacon region:
initWithProximityUUID:identifier:
,
initWithProximityUUID:major:identifier:
and
initWithProximityUUID:major:minor:identifier:
If you want to detect beacons with any UUID, you need to use the first form that does not specify the major or minor value.
Then you need to also call startRangingBeaconsInRegion: and look at the beacon objects that are returned in the ranging calls.
DidEnterRegion calls only include major or minor values if they are part of the region.
The ranging callbacks include all the beacons that are detected, including their major and minor values, distance and proximity, etc.
To eliminate a problem in your code, try doing the exact same thing with my free Locate for iBeacon app in the app store. Try making one or both sides of the transmitter/detector be this app vs. your custom app.
If it does not work with Locate for iBeacon on both sides, then something is wrong with one of your devices. If it does work with Locate for iBeacon on one side, please post your code for the side that is having trouble.
Which delegate methods are you using for the Location Manager? Sometimes DidEnter is not called if you're already in the region i.e. you turn on the transmitting beacon before starting the one that's doing the monitoring. If that's the case monitor for state changes instead and you should be good.
Also, I highly recommend using David's Locate iBeacon app. It will really speed up your development process. Thanks D!
Related
I am developing a beacon detection application and at the moment works very well for kontakt brand beacons.
The client has sent me some new beacons that i have never seen and I have searched with google but i can't find what brand they can be.
The following information related to this beacon they gave me:
uuid: fda50693-a4e2-4fb1-afcf-c6eb07647825
pass: 000000
name: ion_beacon00021
major: 16789
minor: 24532
I have transformed my code to monitor both uuid without making it work
for (index, beaconID) in beaconsIds.enumerated() {
let beaconUUID = UUID(uuidString: beaconID)!
let identifier = "BLERegionBeacon \(index)"
let beaconRegion = CLBeaconRegion(proximityUUID: beaconUUID, identifier: identifier)
self.locationManager?.startMonitoring(for: beaconRegion)
self.locationManager?.startRangingBeacons(in: beaconRegion)
}
func configureLocationManager() {
self.locationManager = CLLocationManager()
self.locationManager!.delegate = self
self.locationManager!.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager!.distanceFilter = kCLDistanceFilterNone;
self.locationManager!.activityType = CLActivityType.automotiveNavigation;
for region in self.locationManager!.monitoredRegions {
self.locationManager?.stopMonitoring(for: region)
}
if CLLocationManager.authorizationStatus() != CLAuthorizationStatus.authorizedAlways {
self.locationManager?.requestAlwaysAuthorization()
}
self.locationManager!.startUpdatingLocation()
}
When not finding how to make this new ibeacon work I have resorted to third party applications (like MyBeacon, Detector, Beacon Demonstrator, Locate) to get validate if the information I have of this beacon is correct, but in no application I have been able to make it detect this ibeacon.
I bought a new battery to make sure it was not as simple as that, but neither. :'(
I had the idea to use any application that detects bluetooth devices and I found BLE Scanner. With this application i was lucky and could realize that at least the name that i have of the beacon is correct, but not found any related to major or minor or pass. I also thought that the long id seen there could be correct and that the I had was not... But I discarded it because when I connected the brand kontakt also gave me a different uuid.
ISCONNECTABLE Jumps between YES and NO.
When i use BLE Scanner to detect beacons Kontakt show me addional info called SERVICEDATA and ISCONNECTABLE still in YES.
- Is there anything else that needs to be done to detect these beacons?
- Anyone have any idea what may be going on?
Thank you very much
EDIT
Following the help of davidgyoung, I could realize that the Locate application if it works but only in its version for android. And in fact correctly returns the information I had been given from that beacon at first.
I found that these beacons with configurable using an application called BeaconFlyer and there I realized the reason for being that password that had sent me. I was able to change the uuid although strangely I just put numbers and no letters. I changed it by 32 zeros following the same pattern of 8-4-4-4-12. I still get no results in IOS but works on android, even after changing the uuid.
It is possible that some brands need to be certified to be detected by iOS devices and that the android do not have these restrictions.
EDIT 2
Considering all these details, it seems that the problem is IOS and not android, so it occurred to me that maybe if I created a simple android project just to test the functionality of the beacons, I should be able to detect it.
The test was done by registering this UUID f7826da6-4fa2-4e98-8024-bc5b71e0893e which is the one that has always works for me and with which I detect without any problem the beacons markkontakt.
To my surprise I detect it without problem even without registering the UUID that I have for this brand. It is very strange considering that only register 1 UUID that was the mark kontakt
If you are detecting another beacon with the same code, then the simplest explanation is that the ProxmityUUID you were given is wrong.
You won't be able to determine the correct ProximityUUID from BLE Scanner on iOS, as iOS blocks access to iBeacon advertisements unless you know the ProximityUUID up front. If you can get your hands on an Android device you can use the Locate app to see any beacon regardless of its identifiers. https://play.google.com/store/apps/details?id=com.radiusnetworks.locate&hl=en You can use this to find out what it is actually sending. There are similar apps for MacOS as well if you have access to a Mac.
It is quite clear that your client sent you "beacons" and not necessarily "iBeacons". As davidyoung pointed out, what constitutes an iBeacon is specified (quite strictly) by Apple. Download the specs from there and have a look, if you are so inclined.
I have used several BLE scanners to check what uuid, major, and minor numbers various brand iBeacons I worked with have, among them the mentioned BLE scanner. I think the specification does not prevent somehow putting additional services into an iBeacon, which results in different brand iBeacons potentially showing slightly different info in different scanners.
However, what you show in the screenshot and the fact that the isconnectable field switches values make me think that these beacons are not correctly working.
There will be no way to make them work on iOS that way then. You can write your own Bluetooth protocol code to do stuff with them, but that then won't rely on Apple's iBeacon mechanics. This will mean the nice stuff like region monitoring even while the app is suspended and so on won't work. It's also probably more battery draining and in general more work.
I am as said not a Bluetooth expert, but learned this much: UUIDs are all over the specs. The UUID you (and Apple) refer to is a part of the data packet the iBeacon is supposed to send, but I have also seen BLE services in general being identified by UUIDs in (non-Apple) reference documents. This can get confusing when you scan such a beacon and see UUIDs (or at least strings that look like ones) in several places. So even if the beacons you have follow the spec (or can be configured to do so somehow) my guess is that someone screwed up. For example, they could have edited (maybe even with a hardwired connection and tool) the wrong UUID, not setting the one you need to use, but accidentally overwriting the part that specifies the device as an iBeacon (byte 5 and 6 of the data packet come to mind), making it impossible for you to use them.
As an advice I would suggest the following: If your client is interested in actual iBeacon functionality, tell them they should buy correct beacons. the kontakt ones are actually quite good. I've tested cheap china knockoffs and would advise against those, as they quickly become unreliable. It might be tempting to save a few bucks at first, but if you need to constantly replace beacons in the long run that becomes more expensive in the end.
One other theory about what might be happening:
A beacon advertisement packet implementing iBeacon must have Apple's manufacturer code 004c in order to be detected by iOS. Android has no such restriction. If this beacon is sending a different manufacturer code it would explain why only Android can detect it.
How do you find out if this is true? You need to see the raw bytes of the advertisement somehow.
The beacon brand is Iotton and it's looks like the one we sell:
https://www.beaconzone.co.uk/ibeacon/ton9108
It's unlikely the Kontakt app is showing the Iotton beacon because the local name is incorrect. It's more likely your Kontakt beacon - turn it off for now. With this or any beacon, the best app for getting the UUID and seeing if the beacon is working is Nordic nRF Connect.
Are you sure you have set the delegate on CLLocationManager? The code doesn't show it, so unless this is somewhere above or below, you'll need to add:
self.locationManager?.delegate = self
Then make sure your class implements CLLocationManagerDelegate the didRange(beacons: region:) method to get callbacks.
If you think you already have this set up, showing that code might reveal something else that is missing preventing it from working.
I am trying to build a test app that would detect a given set of iBeacon deployed in a few physical locations. The detection should be done in the background, and make a call to a server following a certain logic.
Apple's rule of thumb is using the same UUID for all of my physical locations:
The UUID is shared by all locations.
This allows an iOS device to use a single identifier to recognize any of the stores with a single region.
Each specific store, San Francisco, Paris, and London, is then assigned a unique major value, allowing a device to identify which specific store
it is in.
I found the call for setting a region with a given UUID, but did not find what object is returned when the UUID is detected, and what fields are returned.
Where does the app get the major/minor value when iOS detects a beacon with a given UUID?
When using monitoring APIs, you only get a CLBeaconRegion object in the enter/exit callback from CoreLocation. A beacon region defined by this class typically doesn't represent individual beacons, but a range of beacons based on wildcard identifiers.
Because of this, if you use wildcards in your region definition (as is typical) you actually can't see which specific beacon triggered a region entry. To solve this problem, you must combine both monitoring and ranging APIs at the same time. If you monitor and range simultaneously, CoreLocation will give you a callback in the didRangeBeacons beacons: [CLBeacon] inRegion region: CLBeaconRegion method with an array of all the CLBeacon objects it saw.
Because the callback with the array of beacons arrives once per second, however, you will need to add custom logic to do something only once when beacon first appears, if necessary.
Since you want background detection, it is important that you do both ranging and monitoring simultaneously. Even if you don't put anything in your monitoring callback because of the lack of specific beacon information, you need to do monitoring just to get your app woken up in the background on a new beacon detection. Then, you will get ranging callbacks for approximately 10 seconds before your app is suspended again.
I am developing an iOS 8 app with multiple Estimote iBeacons. According to (https://community.estimote.com/hc/communities/public/questions/200966066-How-detect-multiple-beacons-iOS?locale=en-us), I implemented one BeaconManager, and registered it with two BeaconRegions. However, only the second beacon region works.
Instead, I used two BeaconManagers and register one BeaconRegion for each of them. Now it works. However, a new problem occurs: in some cases when I enter or exit the region, I receive multiple notifications for one beacon, instead of only one. This link (http://beekn.net/2013/11/ibeacon-tutorial-dealing-with-errors/) says it's a bug from Apple, but I am not sure about the case.
Anyone can help?
Thanks,
Ryan
Beacon regions are shared system resources, which means that all the BeaconManagers and LocationManagers are notified about state changes of all the regions registered in the app.
Example: if you monitor beacon region A with manager A, and beacon region B with manager B, manager A will still get notifications about region B. Same for manager B and region A.
Because of that, it rarely makes sense to have more than one instance of a BeaconManager in your app.
Monitoring multiple regions should work just fine with a single BeaconManager, there must be something specific to your code that leads to one of the regions not working. If you could add a code snippet to your question, that'd probably help tracking the issue down.
As per my opinion, these should be only one beacon manager to manage all beacon.
And if you have beacon from same vendor (In your case it is Estimote iBeacons) then I don't think that you need to create more than one region here.
Because all beacons of same vendors have same proximity UUID. What is different is its Major value and Minor value.
So you can differentiate all beacons with its Major and Minor values also there is a ranging which can make a further granularity for seperation.
When you set up an iOS device as a beacon (peripheral role), you can query its state by calling CBPeripheralManager.isAdvertising. I can't find the equivalent to query whether a device is scanning for a beacon (central role) on CLLocationManager. Any ideas?
Update:
Given David's answer, I encapsulated the code setting up the CLBeaconRegion with the specific UUID and added a boolean variable which is changed when calling startMonitoringRegion and stopMonitoringRegion on CLLocationManager.
I do not believe there is any way this is possible. Even though CoreLocation's iBeacon APIs use Bluetooth LE and CoreBluetooth under the hood, Apple appears to have gone to some lengths to hide this implementation. There is no obvious way to see whether a Bluetooth LE scan is going on at a specific point in time.
Generally speaking, a Bluetooth LE scan is always going on when an app is ranging for iBeacons in the foreground. When an app is monitoring for iBeacons (either in the foreground or background) or ranging in the background, indirect evidence suggests that scans for beacons take place every few minutes, with the exact number ranging from 1-15 depending on phone model and state. I know of no way to programmatically detect the exact times when this starts and stops, although it can be inferred by iBeacon monitoring entry/exit times. If you look at the graph below, the blue dots show the inferred scan times for one particular test case. Details of how I inferred this are described in this blog post.
We are looking at ordering some iBeacons from Roximity but I am not clear if we have to use the Roximity SDK with these beacons or if I can use the core location functionality?
The reason I am asking is that I do not want to get tied to their SDK and then have to always buy beacons from them.
I was able to get the UUID of the Roxmity beacon, but I do not know what the beacons "identifier" is, so in the case of this code:
[[CLBeaconRegion alloc] initWithProximityUUID:_uuid identifier:#"COM.TEST.APP"];
I do not know what to put in place of COM.TEST.APP
I received some Roximity beacons yesterday, and used them successfully without the Roximity SDK. The UUID that our beacons had was:
8DEEFBB9-F738-4297-8040-96668BB44281
We found the UUID by scanning with a Mac app we wrote that finds any beacons in the local area. Simply create a CLBeaconRegion with that UUID and start ranging, and they should show up. Make sure you've removed the plastic isolator tab from the battery.
As #davidgyoung mentions below, the identifier parameter won't affect whether you can detect the beacons or not.
The identifier you mention in this line of code does not affect the ability to detect an iBeacon, Roximity or otherwise:
[[CLBeaconRegion alloc] initWithProximityUUID:_uuid identifier:#"COM.TEST.APP"];
The "COM.TEST.APP" identifier is just a reference string for you as an application programmer. By using this same string when constructing a second region, you are telling iOS that these are the exact same region. This is useful for canceling monitoring or ranging. It is also useful for replacing one region with another using the CoreLocation APIS.
As long as you keep it consistent for these purposes, that string can be whatever you want.
As for the bigger question if you can use their beacons independently of their SDK, try detecting their beacon with my free Locate for iBeacon app in the AppStore. You have to add the Roximity UUID to the configuration list, but once you do so, if the app is able to locate it, that means it is compatible with standard CoreLocation iBeacon APIs.