As explained in the following thread:
How to find the devices in the range by using bluetooth?
An android app can get a list of devices in the range (bluetooth enabled)
My question is that if there is any way to limit the discovery range to a certain radius e.g. 1 meter?
Thanks,
Ben
You could use BluetoothDevice.EXTRA_RSSI to get the signal strength.
Nevertheless, it won't be very accurate because it's variable.
private final BroadcastReceiver receiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
System.out.println("RSSI: " + rssi + "dBm");
}
}
};
The value you obtain is in dBm. A really close device would have a rssi between around -20 dBm and -40 dBm depending of the device (built-in Bluetooth device, antenna, actual orientation of device). You can test the values you get to define an average 'dBm-range' for 1 meter. The closer the value is to 0, the stronger the received signal has been.
Related
The Android AltBeacon Library and Android Beacon API provides option to set the advertise power to advertise the beacon. The available setting are High, Medium, Low and Ultra Low. During my testing, I didnt find any difference in the visibility range between ultra low and low. I would like to understand what are visibility range for each of the power level. Do I need to consider any other settings to improve the advertise power and visibility range? Any idea on what is the battery impact with different advertise power and its frequency? How do I decide what to settings to use and when?
void startBeacon() {
if (!beaconTransmitter.isStarted()) {
try {
String id1 = editTextUUID.getText().toString();
String id2 = "1";
String id3 = "2";
final String advertizeMode =
((RadioButton) findViewById(advrtzFreqRadioButtonGroup.getCheckedRadioButtonId()))
.getText().toString();
if (advertizeMode.equals("LOW_POWER")) {
beaconTransmitter.setAdvertiseMode(ADVERTISE_MODE_LOW_POWER);
} else if (advertizeMode.equals("BALANCED")) {
beaconTransmitter.setAdvertiseMode(ADVERTISE_MODE_BALANCED);
} else if (advertizeMode.equals("LOW_LATENCY")) {
beaconTransmitter.setAdvertiseMode(ADVERTISE_MODE_LOW_LATENCY);
}
final String advertizePower =
((RadioButton) findViewById(advrtzPowerRadioButtonGroup.getCheckedRadioButtonId()))
.getText().toString();
if (advertizePower.equals("ULTRA_LOW")) {
beaconTransmitter.setAdvertiseTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW);
} else if (advertizePower.equals("LOW")) {
beaconTransmitter.setAdvertiseTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW);
} else if (advertizePower.equals("MEDIUM")) {
beaconTransmitter.setAdvertiseTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM);
} else if (advertizePower.equals("HIGH")) {
beaconTransmitter.setAdvertiseTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
}
int transmissionPower = Integer.parseInt(editTextTxPower.getText().toString());
beacon = new Beacon.Builder()
.setId1(id1)
.setId2(id2)
.setId3(id3)
.setManufacturer(0x0118)
.setTxPower(transmissionPower)
.setDataFields(Arrays.asList(new Long[]{0l}))
.build();
beaconTransmitter.startAdvertising(beacon);
Log.d(TAG, "startAdvertising started");
textViewStatus.setText("startAdvertising started...");
} catch (Exception e) {
Log.d(TAG, e.getMessage());
textViewStatus.setText("Error:" + e.getMessage());
}
} else {
Log.d(TAG, "Already dvertising");
textViewStatus.setText("Already startAdvertising...");
}
button.setText("Stop Beacon");
}
The different transmitter power settings are provided by the underlying Android OS APIs, and is not specific to the Android Beacon Library.. The actual difference between the different power levels varies significantly by device model. On the Nexus 4, for example, the first device I used to test this API, the ultra low level was not detectable at all at any range. I would say this ultra low setting is not advisable for any production purpose due to this lack of reliability.
The high setting is generally similar on all devices, as it is limited by regulatory agencies to prevent radio interference at higher (illegal) power levels. it does vary a bit based on each device's antenna, antenna placement and case, it is usually about -59 dBm at one meter.
There is no significant phone battery drain caused by advertising beacons even at full power. The energy used is insignificant compared to other sources of drain like cell standby, the screen, or CPU activity. The power used is so low, it is difficult to measure. Surprising but true!
Use cases for power settings other than high are rare. It sometimes useful for testing. Low power levels are also useful for limiting detection range, but this is more reliably handled with minimum RSSI thresholds on the receiving side, because leaving the transmitter at max power provides a higher signal to noise ratio and more reliable detections. Only if you cannot control the receiver code in your use case (to add a minimum RSSI filter) should you reduce the transmitter power to limit the detection range.
I am trying to scan all visible wifi APs using wifimanger class. My question is that my code is working good when the (wifiscan-results) called repeatedly every 5 sec using recursive (Runnable) service. But when the time is reduced to be 1 sec or less, such that I register (wifimanger.statrscan) every 1 sec to receive the (wifiscan-results) every 1 sec, the output give null and gives values only every 4 second at least. Could you tell me why this happens. My aim to scan all visible wifi APs every one second or less, repeatedly, Is this possible?
Runnable function code:
public void Running() {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
tv1.setText("counter : " + time1);
time1++;
Scan_number++;
mwifiManager.startScan();
periodic_recieving_wifi_signals();
Running();
}
}, 1000);}
broadcastreciever code:
public void periodic_recieving_wifi_signals() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION);
} else {
//flag1 = false;
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//tv2.setText("Each scan period is : " + results);
results = mwifiManager.getScanResults();
size = results.size();// number of the elements in the list
}
}, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}}
You almost certainly cannot get a WiFi scan every second ... the process simply takes too long.
I don't know all the technical details, and while some of the specific details may vary according to which version of WiFi you are using, looking at Wi-Fi / WLAN Channels, Frequencies, Bands & Bandwidths we can see that basic 2.4GHz 802.11 WiFi has 14 channels defined and 5GHz WiFi has 25 channels (not all channels are permitted in all locations).
To perform a scan, the radio in your phone has to tune to each channel in turn to see "what's out there". Seeing what (if anything) is on a particular channel will involve an exchange of messages, and will take a finite amount of time1 (it will have to wait "long enough" to tell the difference between a slow-to-respond device and "nothing there").
As you noted in a comment, if all of this is taking four seconds or so, you won't be able to perform a scan faster than about once every five seconds.
1 Thanks to John Hanley for supplying some numbers. By default, access points transmit their "I am here" beacons every 102.4ms. Thus some minimum scan-times are:
2.4GHz: 14 x 102.4ms = 1,433ms
5GHz: 25 x 102.4ms = 2,560ms
(Both figures may be slightly less in some locations, depending on the number or channels allowed to be used).
In practice, you would want to listen on each channel for longer than 102.4ms, otherwise you run the risk of not-quite-getting-a-beacon as you switch to a channel, and then switching from that channel just as (or before) the next beacon is sent. There may also be a small delay for the radio to stabilise to each new frequency.
This article: "SSID Overhead Calculator" from the Revolution WiFi website (as well as confirming the 102.4ms figure) also shows the dangers of having too many access-points (APs) and/or too many SSIDs... it doesn't take many of each before the time spent sending out these "beacon" frames takes a significant chunk out of your WiFi throughput. For example: 4 SSIDs on one AP (or 4 single-SSID APs on the same channel, or 2 double-SSID APs on the same channel) will each use about one-eighth of that channel's airtime just with "I am here" beacons!
I am looking to create an app that gets information about the phones connection to the cellular network.
My understanding is that RSSI is a measure of cellular signal with GSM and RSRP is a good measure for LTE.
To keep it consistent, is it possible to get a RSSI measure for LTE?
I am confused about what classes to use to get some of this information. At the moment, I am using the phone state listener which gives me a SignalStrength object. Using this object, I can call the two string method that provides me the following information when i split it. I am a little confused on what some of this means.
String ssignal = signalStrength.toString();
String[] parts = ssignal.split(" ");
The parts[] array will then contain these elements:
part[0] = "Signalstrength:" _ignore this, it's just the title_
parts[1] = GsmSignalStrength
parts[2] = GsmBitErrorRate
parts[3] = CdmaDbm
parts[4] = CdmaEcio
parts[5] = EvdoDbm
parts[6] = EvdoEcio
parts[7] = EvdoSnr
parts[8] = LteSignalStrength
parts[9] = LteRsrp
parts[10] = LteRsrq
parts[11] = LteRssnr
parts[12] = LteCqi
parts[13] = gsm|lte|cdma
parts[14] = _not really sure what this number is_
What is part 8 providing? RSSI?
Also, when you look at the signal strength in the android settings, it gives you the RSSI for GSM. When connected to LTE, is it giving us the RSRP or RSSI? It seems its providing RSRP.
My understanding is that part[1] provides the RSSI when connected on GSM. However, i am unsure, and interested about, part[2] (what is the rate measured against? what unit of time), part[8] (what does it measure exactly?), part[10] and part [11](what unit is it measured in and what is the unit range)
I understand this thread is all over the place. Hopefully it makes a little bit of sense and someone can clear something up.
Cheers guys!
To put it simply, RSSI and RSRP are signal level measurements for GSM and LTE, respectively. They are not exactly the same, because GSM and LTE are very different technologies. However, they both indicate the same type of information. RSRP holds no meaning in GSM and RSSI means something different in LTE.
This question may be worth reading:
How to get LTE signal strength in Android?
Most of what you are looking for, I was able to find here: https://developer.android.com/reference/packages.html
GsmSignalStrength - GSM Signal Strength, valid values are (0-31, 99) as defined in TS 27.007 8.5
GsmBitErrorRate - GSM bit error rate (0-7, 99) as defined in TS 27.007 8.5
CdmaDbm - CDMA RSSI value in dBm
CdmaEcio - CDMA Ec/Io value in dB*10
EvdoDbm - EVDO RSSI value in dBm
EvdoEcio - EVDO Ec/Io value in dB*10
EvdoSnr - Signal to noise ratio. Valid values are 0-8. 8 is the highest.
I could not locate the following, but here is what I suspect:
LteSignalStrength - LTE Signal Strength in ASU (0-31, 99)
LteRsrp - LTE RSRP value in dBm
LteRssnr - LTE SINR value in dB
LteCqi - LTE CQI (no units)
gsm|lte|cdma - Network type
I've got a simple iOS app which displays the proximity of the Bluetooth LE beacons it detects using such expressions as "immediate", "near" etc. and I need to write something similar on Android.
I've followed the tutorial at Android developer and I'm able to list detected devices and now want to estimate the distance/proximity - this is where it's become a problem. According to this SO thread it's just a handful of mathematical calculations. However, they require me to provide a txPower value.
According to this tutorial by Dave Smith (and cross-referencing with this Bluetooth SIG statement), it should be broadcast by the beacon devices as an "AD structure" of type 0x0A. So what I do is parse the AD structures and look for the payload of the one that matches the type.
Problem: I've got 4 beacons - 2 estimotes and 2 appflares. The estimotes don't broadcast the txPower at all and the appflares broadcast theirs as 0.
Is there anything I'm missing here? The iOS app seems to be handling it all without any problem, but using the iOS SDK it does it behind the scenes so I'm not sure how to produce the exact same or similar behaviour. Is there any other way I could solve my problem?
In case you'd like to take a look at the code I'm using to parse the AD structures, it's taken from the aforementioned Dave Smith's github and can be found here. The only change I did to that class was add the following method:
public byte[] getData() {
return mData;
}
And this is how I handle the callback from the scans:
// Prepare the callback for BLE device scan
this.leScanCallback = new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
if (!deviceList.contains(device)) {
MyService.this.deviceList.add(device);
Log.e("Test", "Device: " + device.getName());
List<AdRecord> adRecords = AdRecord.parseScanRecord(scanRecord);
for (AdRecord adRecord : adRecords) {
if (adRecord.getType() == AdRecord.TYPE_TRANSMITPOWER) {
Log.e("Test", "size of payload: " + adRecord.getData().length);
Log.e("Test", "payload: " + Byte.toString(adRecord.getData()[0]));
}
}
}
}
};
And what I see in the console is:
04-01 11:33:35.864: E/Test(15061): Device: estimote
04-01 11:33:36.304: E/Test(15061): Device: estimote
04-01 11:33:36.475: E/Test(15061): Device: n86
04-01 11:33:36.475: E/Test(15061): size of payload: 1
04-01 11:33:36.475: E/Test(15061): payload: 0
04-01 11:33:36.525: E/Test(15061): Device: f79
04-01 11:33:36.525: E/Test(15061): size of payload: 1
04-01 11:33:36.525: E/Test(15061): payload: 0
The txPower mentioned by #davidgyoung is given by the formula:
RSSI = -10 n log d + A
where
d = distance
A = txPower
n = signal propagation constant
RSSI = dBm
In free space n = 2, but it will vary based on local geometry – for example, a wall will reduce RSSI by ~3dBm and will affect n accordingly.
If you want the highest possible accuracy, it may be worthwhile to experimentally determine these values for your particular system.
Reference: see the paper Evaluation of the Reliability of RSSI for Indoor Localization by Qian Dong and Waltenegus Dargie for a more detailed explanation of the derivation and calibration.
double getDistance(int rssi, int txPower) {
/*
* RSSI = TxPower - 10 * n * lg(d)
* n = 2 (in free space)
*
* d = 10 ^ ((TxPower - RSSI) / (10 * n))
*/
return Math.pow(10d, ((double) txPower - rssi) / (10 * 2));
}
It is unclear whether your inability to read the "txPower" or "measuredPower" calibration constant is due to the AdRecord class or due to the information being missing from the advertisements you are trying to parse. It doesn't look to me like that class will parse a standard iBeacon advertisement. Either way, there is a solution:
SOLUTION 1: If your beacons send a standard iBeacon advertisement that includes the calibration constant, you can parse it out using code in the open source Android iBeacon Library's IBeacon class here.
SOLUTION 2: If your beacons DO NOT send a standard iBeacon advertisement or do not include a calibration constant:
You must hard-code a calibration constant in your app for each device type you might use. All you really need from the advertisement to estimate distance is the the RSSI measurement. The whole point of embedding a calibration constant in the transmission is to allow a wide variety of beacons with quite different transmitter output power to work with the same distance estimating algorithm.
The calibration constant, as defined by Apple, basically says what the RSSI should be if your device is exactly one meter away from the beacon. If the signal is stronger (less negative RSSI), then the device is less than one meter away. If the signal is weaker (more negative RSSI), then the device is over one meter away. You can use a formula to make a numerical estimate of distance. See here.
If you aren't dealing with advertisements that contain a "txPower" or "measuredPower" calibration constant, then you can hard-code a lookup table in your app that stores the known calibration constants for various transmitters. You will first need to measure the average RSSI of each transmitter at one meter away. You'll then need some kind of key to look up these calibration constants in the table. (Perhaps you can use the some part of the string from the AD structure, or the mac address?) So your table might look like this:
HashMap<String,Integer> txPowerLookupTable = new HashMap<String,Integer>();
txPowerLookupTable.put("a5:09:37:78:c3:22", new Integer(-65));
txPowerLookupTable.put("d2:32:33:5c:87:09", new Integer(-78));
Then after parsing an advertisement, you can look up the calibration constant in your onLeScan method like this:
String macAddress = device.getAddress();
Integer txPower = txPowerLookupTable.get(macAddress);
use the getAccuracy() method in the library, it gives you the distance of the beacon
I'm trying to display the bluetooth signal strength (rssi) evry second (Timer()) from detected device but i couldn't call onRecive() multiple times because Receiver Lifecycle.
I need a way(idea) to refresh the RSSI, or some other way to measure a signal every second?
Is it easier if the device is connected?
App gives a constant value always:
DeviceName 2b:3c:d5:6c:3x:0X 40 db
Part of the app stored in Timer() method:
BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI,Short.MIN_VALUE);
// Add the name and address to an array adapter to show in a ListView
msg = device.getName() + " " + device.getAddress() + " " +rssi+ " db";
}
}};
You can only get the RSSI value during a device discovery scan. (Bluetooth Discovery vs Connection)
"Is it easier if the device is connected?" Accordingly with android docs:
"if you already hold a connection with a device, then performing discovery can significantly reduce the bandwidth available for the connection, so you should not perform discovery while connected."
Do you really need to perform an inquiry every 1 second? Will consume a lot of battery...
Since you need to perform the measure periodically, why not use AlarmManager or CountDownTimer?
In your specific case, I believe you should be using AlarmManager, since it can repeat indefinitely. If you want something to execute every second for 10 seconds, for example, use CountDownTimer.