I'm attempting to transmit as a beacon an Android phone using the altbeacon library as described here. I am trying to set some parameters using the following methods:
setServiceUuid(0xfeaa)
setBluetoothAddress("31:14:15:92:65:35")
setBluetoothName("MyBeacon")
When the beacon is interpreted on another Android device in the RangeNotifier listener method, didRangeBeaconsInRegion, the beacon doesn't have these parameters set. (eg. getServiceUuid is -1 and the BT address and name are each null).
I'm using the following beacon layout in the parser for the transmitting application and in the scanning application:
m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
I don't know what this means though; I wonder if I need to change it.
Anyone have an idea how to make the bluetooth address, name etc. be accessible in the beacon that is scanned on the receiving device?
Some fields in the Beacon class are only used when detecting beacons and do not affect transmissions. You have found three of these exact fields. Here is an explanation of each and why they work this way:
BluetoothAddress: this is a fixed six byte unique address built into the Bluetooth chip on your phone. When sending packets (beacon advertisements or otherwise), the chip always uses the same address. You cannot change it. This is by just the way Bluetooth works.
BluetoothName: this is the friendly name of your phone visible to other Bluetooth scanners. Changing this name affects not just beacon transmissions but all Bluetooth operations on the phone. For this reason, the library's BeaconTransmitter does not change this name. You can do so youself, however, by calling the setName method on Android's BluetoothAdapter class. See here.
ServiceUUID: This field applies only to certain beacon formats such as Eddystone, which are based on 16-bit GATT Service UUIDs. For other beacon formats (AltBeacon, iBeacon), this value is -1 as you have seen. The ServiceUUID is actually defined in the BeaconParser layout expression. In the Beacon class you can read it, but writing to it has no effect. You generally do not need to worry about this field, and certainly not for the AltBeacon layout shown in the question, because it is not used for that format.
Related
I am building an Android app that scans two types of beacon using the android-beacon-library:
iBeacon type (0x4c000215)
custom beacon which beacon type code is 0x4106
I know there was an issue that fixed broken Samsung screen off scans https://github.com/AltBeacon/android-beacon-library/pull/798.
That fix was implemented into the 2.15.3 release.
Since then, during every scan with a samsung device >= Android 8.0, I don't see any of my custom beacon but I do receive other beacon types like iBeacon. So I am still using the 2.15.2 release.
Here is my custom beacon layout:
"m:0-1=4106,i:2-3,i:4-4,i:5-6,i:7-8,i:9-10,i:11-11,i:12-12,i:13-13,i:14-14,i:15-15,i:16-16,i:17-17,i:18-23,p:24-24"
I checked the code from the lib and I can see a filter that applies for samsung devices only:
if (Build.MANUFACTURER.equalsIgnoreCase("samsung")) {
// On the Samsung Galaxy Note 8.1, scans are blocked with screen off when the
// scan filter is empty (wildcard). We do a more detailed filter on Samsung only
// because it might block detections of AltBeacon packets with non-standard
// manufacturer codes. See #769 for details.
filters = new ScanFilterUtils().createScanFiltersForBeaconParsers(
mBeaconManager.getBeaconParsers());
}
If I remove this code, everything works as I expect.
Is there something I have to do so I don't need to edit the library?
Thanks.
The library uses both the BLE manufacturer ID and the beacon type code to match BLE filters when the app is in the background. For this to work, you must set these up exactly right, or the filters will not match.
Two issues here:
Your beacon type code should not include the BLE manufacturer ID. Instead of 0x4c000215 use 0x0215 (Note: 0x4c00 is the Apple BLE manufacturer ID, and will be applied separately.) If using a beacon layout string with this, you must adjust the byte offsets to account for this, so your layout starts with m:2-3=0215
For any beacon layout that will be matched with these filters, you must set the hardware assist manufacturer identifiers. By default, the library includes 0x0118 (Radius Networks for AltBeacon) and 0x0215 (Apple for iBeacon) for all other manufacturer beacon types. For any custom beacon that uses yet another manufacturer code (see list here: https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers) you must add it like this (example shown for hardware manufacturer id 0x1234):
beaconParser.setHardwareAssistManufacturerCodes(new int[]{0x1234});
Important tip: Mobile devices have a limited number of bluetooth hardware filter slots. You can help ensure you do not run out of them by:
Only register as many beacon layouts as you need. If not using the default AltBeacon layout, call beaconManager.getBeaconParsers().clear(); to remove it.
Only register the exact hardware manufacturer codes you need with each BeaconParser. If you register more than one you will use more than one filter slot.
The above APIs were designed before this Samsung restriction came into place making this a more serious issue. I am open to other ideas on how to make this API more intuitive so other folks don't run into the same problem as you did.
In the application I am looking forward Bluetooth in Beacon is very good option as I want to collect PH from different sources to the application so I can't pair my android device with all the BLE devices at a time as it will be around 20-30.
But I can see that if there is Beacon then Android can scan all of them and also get the RSSI of all devices without being paired with them.
So is it possible that we add few other parameter for example PH, Temperature, Humidity and 3-4 other parameters so Beacon is going to broadcast all these parameter along with RSSI and in Android app I can collect all the information?
I am not sure if this is feasible solution or not and if it is then how to achieve this in beacon?
Bluetooth beacons generally rely upon advertisement packets to send data, which are limited in the number of bytes available. For manufacturer advertisements, you basically have 24 usable bytes to work with, although you need to reserve some of these as a flag to indicate it is your beacon format, and not somebody else's beacon format.
You can look at the AltBeacon spec as an example. This format uses two bytes to identify itself (the "beacon code"), 20 bytes of beacon identifiers, one byte of data and one byte for reference RSSI. You probably still want a unique identifier for each beacon so you know which beacon sent you the information. But you might be able to cut this down to four bytes for your purposes, which would allow you to have 2^32 different beacons sending this information.
The Android Beacon Library lets you both transmit and receive beacons using arbitrary formats you can define using the BeaconParser class. A beacon format that uses a four byte identifier, two bytes each for PH, Temperature and Humidity data fields, and two bytes each for five other data fields might look like this:
m:2-3=abcd,i:4-7,d:8-9,d:10-11,d:12-13,d:14-15,d:16-17,d:18-19,d:20-21,d:22-23,p:24-24
My application doesn't use beacons (at least not in the common meaning). The use case is to continuously background scan for BLE peripherals matching a specific format, then connect to those peripherals and transmit/receive data and disconnect (possibly doing this more than once).
The stability and reliability of Bluetooth LE on Android leaves something to be desired, especially if supporting earlier API versions (18+), as I am. AltBeacon seems to be a seasoned library that handles a lot of the weird edge cases and intricacies in Android Bluetooth LE management (at least on the scanning side). I'd like to leverage this library to scan and identify my peripherals and then connect to them on my own. Does anyone know how I might be able to achieve this?
While the Android Beacon Library really is not designed to scan for bluetooth services, there are certain cases where it can be convenient for that purpose. Be forewarned, however, that doing this goes against the grain of its design, and forces you to do a few pretty ugly hacks. If such hacks make your eyes bleed, then read no further! For those who can stand it, here's what you'd need to do:
Set up a beacon parser that will look for a GATT Service UUID. You must match on a few bytes in the service UUID, and the library's matchers are only designed to match a few bytes at a time. So if you have a GATT Service UUID of 00010203-0405-0607-0809-0a0b0c0d0e0f, you should take the first three bytes: 00,01,02 and use them as the matching expression. Because the matching expression has a different endianness, you have to reverse the order of the bytes to be 02,01,00. So you end up with code like this:
BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:0-2=020100,i:0-15l,p:15-15"));
Start ranging based on a region that matches your full GATT Service UUID. (Again, you must replace the UUID with that of your service.):
Region gattServiceRegion = new Region("gattServiceRegion",
Identifier.parse("00010203-0405-0607-0809-0a0b0c0d0e0f"), null, null);
beaconManager.setRangeNotifier(this);
beaconManager.startRangingBeaconsInRegion(region);
Now the library will make a callback to your class' didRangeBeaconsInRegion method each time it sees an advertisement for that GATT Service UUID. So you know it is nearby, and you can get all of the power saving, background launching and other benefits of the library. The problem now is that the library doesn't expose any reference to the raw BluetoothDevice object needed to call connectGatt(...).
So unless you modify the library source code you still have to use the raw scanning APIs once you know the beacon is around just to get this reference. You have to decide if using the Library is worth all this trouble, given that you have to use the raw scanning APIs to get the BluetoothDevice to make a connection, anyway.
I was wondering :
When we enter a shop, using the app shop, we receive for example a notification.
But what if the beacon is down, and it's replaced with another beacon, with a different UUID etc .. ? Are the UUID/Major/Minor value of a beacon not harcoded but in a database on the server ? How it's fetched ?
Thanks you
The UUID of an iBeacon is not related in any way to its MAC address. It is a value that is assigned to the beacon by the beacon owner. Some beacon vendors have a specific UUID or range of UUIDs while others allow any UUID to be used.
If a particular beacon failed then the replacement would likely be configured with the same UUID.
When the app detects a particular beacon it needs to refer to some database, either in the app or on a server, that gives "meaning" to the particular UUID/major/minor combination so it is possible that the database could be updated to reflect the new hardware but this is less likely than simply configuring the replacement hardware with the same values
It is a good practice to not hard code your beacon identifiers in your app. You can build your app so on launch, it contacts a web service to download a list of identifiers to search for. You can build your own or use an off the shelf service like my company's ProximityKit that does exactly this.
Of course, if you are relying on beacon detections to launch your app, your app won't get auto launched to download the new beacon identifiers if the beacon ids change in advance. The user will have to manually do the launch to get the new list.
There are a few ways around this:
Set the identifiers on replaced beacons so they are the same as the old ones.
If you know you cannot set the identifiers, broaden the beacon region filter for auto launch so it matches a wide variety of beacon identifiers. On iOS you can search for all beacons with a shared UUID. On Android, you can search for all beacons regardless of identifiers.
When you initialise Beacon Region then you need to identify at least UUID and it is either hardcoded with in the app or can be placed on the server and should be retrieved from server before calling initialising Beacon Region.
NOTE:You should have a copy of all beacons UUIDs,majors and minors for future purposes
But suppose your Beacon goes out of order then there's a backup plan.
Follow below said steps:
1.Install Estimote-iOS or android app
2.Place the new beacon near to your device and start ranging beacons in estimote app.
3.Then you need to login with your cloud account in your app and configure new beacon(i.e edit your beacon's UUID.)You can even edit major,minor etc
4.Save those settings and your new beacon is configured and ready to use.
Happy Coding :)
I have been trying to write an application to detect iBeacons. (I set up my iPhone 5 as iBeacon)
I slightly changed the fromScanData method to return only proximity UUID String. I have no idea how the pattern detection works. It always Logs "This is not an iBeacon advertisement".
I am not using the whole IBeacon class. I am using the method alone. I am calling it from my
onLeScan and passing the byte array scanRecord, rssi value and the BluetoothDevice object.
Once I have my proximity UUID for each ble device, I can filter the ones I want.
Please help. Thanks in advance.
The Log
04-17 14:44:29.828: D/BLEScan(28549): This is not an iBeacon advertisment (no 0215 seen in bytes 4-7).The bytes I see are :02011a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
The debug line says it all. Those bytes do not indicate a valid iBeacon advertisement. Are you sure your iPhone transmitter is really working properly? Can you detect the iBeacon using a different tool like the Android iBeacon Locate app?
I don't know how you set up the transmitter but you might also try Locate for iBeacon iOS app or EZ Beacon iOS app, which are known to transmit properly formed iBeacon advertisements that work with this code. The same Android code is inside the iBeacon Locate app.
Finally, make sure your iPhone transmitter is in the foreground. iOS devices cannot transmit as iBeacons in the background.