I have made my iphone 4s an iBeacon and able to detect this using Locate Beacon app from my Glaxy S4, 5.01, I have also detected this using beacon reference library by modifying its layout found from this question. Its showing the detect beacon in device logs from the library files as below,
onScanResult() - ScanResult{mDevice=6C:64:80:68:86:59, mScanRecord=ScanRecord [mAdvertiseFlags=26, mServiceUuids=null, mManufacturerSpecificData={76=[2, 21, -96, -54, 104, -88, 101, -76, 75, 30, -66, -91, 73, -91, -114, -5, -124, 29, 0, 0, 0, 0, -59]}, mServiceData={}, mTxPowerLevel=-2147483648, mDeviceName=null], mRssi=-46, mTimestampNanos=162979288294680}
i am getting device name always null, and also unable to get the uuid, and i can't get that in my application, can any one please help how can i get beacon info in my application ?
Also How can i uniquely identify a beacon?
Here's what i have done so far, downloaded a ALT beacon library, then ALT beacon library reference, added library dependency, and written the following code in Ranging Activity class,
modified the onCreate method as
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ranging);
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:0-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")); // iBeacons
beaconManager.bind(this);
}
and implements this by BeaconConsumer, and added his method as
#Override
public void onBeaconServiceConnect() {
// TODO Auto-generated method stub
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
Log.i(TAG, "The first beacon I see is about "+beacons.iterator().next().getDistance()+" meters away.");
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
} catch (RemoteException e) { e.printStackTrace(); }
}
if i run the code without,
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:0-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")); // iBeacons
then it works fine when add this statement get exception as mentioned before.
Finally i am able to identify my problem, my beacon parser was wrong
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:0-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
i was using this while i correct results that detects an ibeacon for me are given by this parser
beaconManager.getBeaconParsers().add(new BeaconParser(). setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24"));
It sounds like you are using beacon Monitoring when you really want to be using beacon Ranging. Monitoring is used to tell you when any one of a group of beacons with shared identifier parts (or any beacon at all) is first detected. But it doesn't tell you the exact identifiers of the beacons in view.
In order to read the identifiers of beacons that are visible at a given time, you should use the Ranging APIs. These APIs give you a callback to your code once per second with a list of all visible beacons matching the Region you define.
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (Beacon beacon: beacons) {
Log.i(TAG, "I see a beacon with identifiers: "+beacon.getId1()+" "+beacon.getId2()+" "+beacon.getId3());
}
}
See the Ranging Example Code on this page for more details on how to set this up.
Related
I am trying to get the drone absolute altitude value (ASL) in real time (before taking off)
I have 2 drones, Mavic 2 enterprise advanced & M300.
When using the below code in mavic2, I was able to obtain the ASL, however the same code returns NULL value when using with M300:
Object heightAboveSeaLevel = KeyManager.getInstance().getValue(FlightControllerKey.create(FlightControllerKey.ABSOLUTE_GPS_ALTITUDE));
Also tried with no luck the below:
DJIKey GPSKey = FlightControllerKey.create(FlightControllerKey.ABSOLUTE_GPS_ALTITUDE);
DJISDKManager.getInstance().getKeyManager().getValue(GPSKey, new GetCallback() {
#Override public void onSuccess(#NonNull Object value) {
}
#Override public void onFailure(#NonNull DJIError error) {
}
});
On a side note, when using the M300, the ASL value is shown in the DJI Pilot app.
Anyone has accomplish the above or has any ideas to what I should use?
This is from DJI:
This KEY does not currently support the M300. Do you know how to use MSDK V5, which provides the KEY for obtaining real-time altitude: KeyRTKAbsoluteAltitude?
MSDK V5:https://developer.dji.com/doc/mobile-sdk-tutorial/cn/
On iOS, I only can check state of Bluetooth. I'm find the solutions on network and use it.
public class CallBluetoothIphoneService : ICallBlueTooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager();
if (bluetoothManager.State == CBCentralManagerState.PoweredOff|| bluetoothManager.State == CBCentralManagerState.Unknown)
// Does not go directly to bluetooth on every OS version though, but opens the Settings on most
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
But when I try turn off Bluetooth and test code, state of bluetooth is "Unknown".
Then I run code, device open settings, toggle button has color green (turn on bluetooth), but when I check state of Bluetooth in code, State of Bluetooth is "Unknown", is not "Power on".
I'm using Xamarin 3.3 and test on device iOS version 12.0.
I am not sure exactly what you want to do, but if your intent is to open the Bluetooth settings page, this:
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
won't work. Apple has at some points allowed this (iOS 8 IIRC) and at other points it has disallowed this (most versions of iOS). See this long SO thread about this issue: How to open Settings programmatically like in Facebook app?
Regardless, there is no need. When iOS detects that your app has created a CBCentralManager type with delegate, iOS will display an alert to the user that allows them to go to the bluetooth settings to enable bluetooth by tapping the "Settings" button in the alert.
As far as always getting state as "Unknown", you need to check the state in the delegate for the CBCentralManager. You cannot use the parameterless CBCentralManager constructor new CBCentralManager();. Check the apple docs: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager?language=objc and note that there are only two listed init methods, one that takes delegate and queue parameters, and one that takes delegate, queue, and options parameters, although no one complains if you use the parameterless constructor... but you will never get the correct state if you use it. See: https://stackoverflow.com/a/36824770/2913599
So try this:
public class CallBluetoothIphoneService : ICallBluetooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager(new MySimpleCBCentralManagerDelegate(), DispatchQueue.CurrentQueue);
// This will always show state "Unknown". You need to check it in the delegate's UpdatedState method
Console.WriteLine($"State: {bluetoothManager.State.ToString()}");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public class MySimpleCBCentralManagerDelegate : CBCentralManagerDelegate
{
override public void UpdatedState(CBCentralManager mgr)
{
// You can check the state in this delegate method
Console.WriteLine($"UpdatedState: {mgr.State.ToString()}");
if (mgr.State == CBCentralManagerState.PoweredOn)
{
//Passing in null scans for all peripherals. Peripherals can be targeted by using CBUIIDs
CBUUID[] cbuuids = null;
mgr.ScanForPeripherals(cbuuids); //Initiates async calls of DiscoveredPeripheral
//Timeout after 30 seconds
var timer = new Timer(30 * 1000);
timer.Elapsed += (sender, e) => mgr.StopScan();
}
else
{
//Invalid state -- Bluetooth powered down, unavailable, etc.
System.Console.WriteLine("Bluetooth is not available");
}
}
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
Console.WriteLine("Discovered {0}, data {1}, RSSI {2}", peripheral.Name, advertisementData, RSSI);
}
}
Bottom line: always create a CBCentralManager object with one of the following constructors:
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue)
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue, CBCentralInitOptions)
I'm trying to make a Proof of Concept (C#) for basic graphical maps, as an alternative to Google Maps for Andriod and iOS devices - because Google started charging fees for their APIs (from my understanding only affecting web right now).
I doesn't need to be particularly advanced, simply a GUI that shows a base map where you can draw:
Markers
Lines
Polygons
The only requirements I have is that it should be open-source, or at as low a cost as possible.
What I've done so far is to use data from http://openstreetmap.org - and set up a tile-server https://switch2osm.org/serving-tiles/ on a separate linux machine.
Furthermore, it went fairly quick to create a simple web app with OpenLayers.js and Leaflet.js connected to the custom tile-server with the requirments met.
What I need to do now is to find a free or cheap mobile SDK for Xamarin for Android and iOS. I managed to render a map from my own tile-server and add markers by referring .dll's from this zip from 2014 (only tested for Andriod): https://github.com/OsmSharp/ui/releases/tag/v4.2.0.723
using OsmSharp.Android.UI;
using OsmSharp.Android.UI.Data.SQLite;
using OsmSharp.Math.Geo;
using OsmSharp.UI.Map;
using OsmSharp.UI.Map.Layers;
[Activity(Label = "#string/app_name", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
private MapView _mapView { get; set; }
private Layer _mapLayer { get; set; }
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
try
{
Native.Initialize();
_mapView = new MapView(this, new MapViewSurface(this))
{
MapTilt = 0,
MapCenter = new GeoCoordinate(lat, long),
MapZoom = 16,
Map = new Map()
};
// create a marker under Resources/drawable/pin.png
using (var bitmap = BitmapFactory.DecodeResource(Resources, Resource.Drawable.pin))
{
var marker = new MapMarker(this, new GeoCoordinate(lat, long), MapMarkerAlignmentType.CenterBottom, bitmap);
_mapView.AddMarker(marker);
}
_mapLayer = _mapView.Map.AddLayerTile("http://*.*.*.*/{0}/{1}/{2}.png");
SetContentView(_mapView);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
However, these .dlls seemed to lack support for Lines and Polygons. I have tried to get something similar to work with OsmSharp's latest NuGet package (2018-06-04), but my novice Xamarin experiance only gets me so far.
Does anyone have any tips on how to use my own tile-server and render native maps on Android and iOS devices?
PS. It doen't strictly need to be OpenStreetMap with OsmSharp connected to a custom tile-server, that's just something im leaning towards right now. Again, requirents are open-source or at a low cost with the fexebility to add Markers, Lines and Polygons.
We are trying to use Altbeacon library to satisfy the next study case:
We want to put several IBeacons in a room or corridor with a distance of no more than 3 meters between each of them, and we want to get the current closest Ibeacon based on the user phone which scans for the beacons.
We first tried to build regions with only one beacon each, wondering that a region were a closed set, meaning that when you enter in a region, you couldn’t be in other region at the same time, and when you leave a region, you enter in the next closest one and so. But that’s not the approach that the library implements.
We want to know if there’s any way in Altbeacon library to apply our approach or if some kind of patch has to be made to satisfy the study case that I present to you.
The easiest way to accomplish this goal is to range for all beacons using a single region, and start ranging:
#Override
public void onBeaconServiceConnect() {
try {
// Set up a region that matches all of your beacons. You may want to replace the first
// null with a UUID that all your beacons share.
Region allBeaconsRegion = new Region("all beacons", null, null, null);
beaconManager.startRangingBeaconsInRegion(mAllBeaconsRegion);
beaconManager.setRangeNotifier(this);
} catch (RemoteException e) {
Log.e(TAG, "Cannot connect to beacon service");
}
}
Note, if you are using a custom Application class with the RegionBootstrap, you can put the above code above inside the didEnterRegion method instead of inside the onBeaconServiceConnect method.
Once you start ranging, you will get a callback once per second with a list of all visible beacons. You can add code to determine which one is closest:
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region arg1) {
Beacon closestBeacon = null;
for (Beacon beacon : beacons) {
if (closestBeacon == null) {
closestBeacon = beacon;
}
else {
if (closestBeacon.getDistance() > beacon.getDistance()) {
closestBeacon = beacon;
}
}
}
// Do Something with closestBeacon here
}
Keep in mind that the closest beacon may change back and forth due to radio noise, so you probably need to add extra logic to protect against the closest beacon flipping back and forth too often.
I am trying to detect iBeacons with a specific UUID and Major. The didRangeBeaconsInRegion is being called but the Beacon collection it returns has 0 entries.
The below is my code (abridged a bit)
private static final String BEACON_UUID = "F8AD3E82-0D91-4D9B-B5C7-7324744B2026";
private static final int BEACON_MAJOR = 36582;
#Override
public void onIBeaconServiceConnect() {
iBeaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<IBeacon> iBeacons, Region region) {
if (iBeacons.size() > 0) {
IBeacon thisBeacon = iBeacons.iterator().next();
}
}
});
try {
iBeaconManager.startRangingBeaconsInRegion(new Region("myUniqueID", BEACON_UUID, BEACON_MAJOR ,null));
} catch (RemoteException e) {
e.printStackTrace();
}
}
I am assuming I am doing my binding correctly as the didRangeBeaconsInRegion(..) is being called successfully.
I have used RadiusNetwork's own application to detected the beacons and that works fine and I can see them all so it is not seem to be an issue with Bluetooth on my device
A couple of tips:
Double check that your BEACON_UUID and BEACON_MAJOR are correct for the beacon that is transmitting. For testing, try setting both of these to null temporarily until you get it working, then you can set them back to the values you have.
It is normal for the iBeacons.size() to be zero sometimes if a beacon did not happen to be detected in a given cycle. But it should not always be of size zero. I'm not sure how you are testing, but try adding a Log.d(TAG, "Number of beacons detected: "+iBeacons.size()); and let it run to see if you ever get a non-zero number.
I suggest to check the uuid , major and minor values of your beacons and make them match with the region u want.
didRangeBeaconsInRegion should return an array af beacons.
You can use the "beecon" app to update easily the values.
Hope this can help you.
Regards.