using Bluetooth Low Energy (BLE) scan on Android, I noticed that sometimes RSSI values are incorrect.
My code simply calls the start scan function:
mBluetoothAdapter.startLeScan(mLeScanCallback);
and then I read results in the callback and save results in a file:
private static BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
String objScanRec = bytesToHex(scanRecord);
outStr = rssi + ";" + objScanRec + ";" + device.getName() + ";" + beaconLocation + ";\n";
try {
Raw_log.write(outStr);
Raw_log.flush();
} catch (IOException e) {
e.printStackTrace();
}
// }
}
};
the problem is that I read positive RSSI values, also if the beacon is at a fixed distance.
E.g. I have the beacon 30 cm from the phone (or smartwatch) I read a values around -45 which are realistic, but also values around +80 or +100 (which are not realistic) those values are around 20% of measurements.
Is there something that I'm missing?
thanks
thanks for your help I figured out it's a problem related only to Samsung Gear Live. I came up with this s solution:
if(rssi > 0){
rssi = rssi - 128;
}
I've tested the solution and it works fine. (e.g. the obtained positive values after correction are now similar to negative values, for example I read
-44 -45 -43 84 82
that after correctio become:
-44 -45 -43 -44 -46)
This is definitely not normal. I have never seen a rssi value in that callback be positive. Typical values are from -30 to -120.
I suspect there is something wrong with the way the data are written out to the log, or read back. What happens if you just do a regular Log.d(TAG, "rssi="+rssi); Do you ever see positive values? If so, can you share an excerpt, along with the device model you are using to detect and the device you are detecting?
Related
eg. I have a 1.5 GB data pack. It gives the total sum of 2.0 GB or more than that .
any idea about how to get correct speed every second.
TrafficStats.getTotalRxBytes() does not return your data pack value. It refers to the total received bytes (either wifi/mobile) since the last boot (turning ON phone). For mobile data, it will be TrafficStats.getMobileRxBytes(). More importantly, these values get reset in every reboot of device.
I have a 1.5 GB data pack. It gives the total sum of 2.0 GB or more
than that .
The android system does not know anything about your data pack. You are adding it again and again. When you call TrafficStats.getMobileRxBytes() at a moment, it returns total mobile data received upto this moment since last boot. Following is an explanation. Hope this helps.
// Suppose, you have just rebooted your device, then received 400 bytes and transmitted 300 bytes of mobile data
// After reboot, so far 'totalReceiveCount' bytes have been received by your device over mobile data.
// After reboot, so far 'totalTransmitCount' bytes have been sent from your device over mobile data.
// Hence after reboot, so far 'totalDataUsed' bytes used actually.
long totalReceiveCount = TrafficStats.getMobileRxBytes();
long totalTransmitCount = TrafficStats.getMobileTxBytes();
long totalDataUsed = totalReceiveCount + totalTransmitCount;
Log.d("Data Used", "" + totalDataUsed + " bytes"); // This will log 700 bytes
// After sometime passed, another 200 bytes have been transmitted from your device over mobile data.
totalDataUsed = TrafficStats.getMobileRxBytes() + TrafficStats.getMobileTxBytes();
Log.d("Data Used", "" + totalDataUsed + " bytes"); // Now this will log 900 bytes
any idea about how to get correct speed every second.
You cannot get actual speed this way. You can only calculate and show how much bytes have been received/transmitted in a second. All the speed meters in android do the same I think. Something like the following:
class SpeedMeter {
private long uptoNow = 0;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ScheduledFuture futureHandle;
public void startMeter() {
final Runnable meter = new Runnable() {
public void run() {
long now = TrafficStats.getMobileRxBytes() + TrafficStats.getMobileTxBytes();
System.out.println("Speed=" + (now - uptoNow)); // Prints value for current second
uptoNow = now;
}
};
uptoNow = TrafficStats.getMobileRxBytes() + TrafficStats.getMobileTxBytes();
futureHandle = scheduler.scheduleAtFixedRate(meter, 1, 1, SECONDS);
}
public void stopMeter() {
futureHandle.cancel(true);
}
}
And use like this:
SpeedMeter meter = new SpeedMeter();
meter.startMeter();
Although this code is not perfect, however it will suit your needs.
My Problem
I need to make the combined call for all the region on didRangeBeaconsInRegion right now for each uuid eg: if i have 2 uuid the didRangeBeaconsInRegion is called 2 times and for 4 uuid didRangeBeaconsInRegion called 4 times likewise it goes on. I want didRangeBeaconsInRegion to be called once for all the uuid that i set on region
My Code:
for (beaconparser.Beacon beacon : iBeacon.getBeacons()) {
try {
Identifier uuid = Identifier.parse(iBeacon.getUUID());
Identifier major = Identifier.parse("" + iBeacon.getMajor());
Identifier minor = Identifier.parse("" + iBeacon.getMinor());
beaconManager.startRangingBeaconsInRegion(new Region(iBeacon.getUUID() + major + minor, uuid, null, null));
setMonitoring(false);
} catch (RemoteException e) {
e.printStackTrace();
}
}
Sorry, the API just does not work like that. The easiest solution is to set up a wildcard Region that sets all identifiers to null. This will give you one callback for all beacons.
You can the use if statements to compare the beacon identifiers to ones you care about and only process them if they match one of your regions.
In my Beacon application I am getting different values of RSSI through beacon.getRSSI(). Now I want to get the max value of RSSI of all the scanned beacons. So I thought the possible solution will be array. Can anyone helpout how to do this?
Put all the Beacon objects into a Collection (List, Set), then use Collections.max to get the beacon with the highest RSSI. javadoc
List<Beacon> beacons = new ArrayList<Beacon>();
// add all the beacons
beacons.add(beacon);
(...)
Beacon maxBeacon = Collections.max(beacons, new Comparator<Beacon>(){
public int compare(Beacon b1, Beacon b2) {
return Integer.compare(b1.getRSSI(), b2.getRSSI);
}
}
I using this code for get wifi signal set.(BSSID, SSID, RSSI.. etc.).
public void sortScanResult()
{
wifiScan.scanWifiSignal();
scanedResults = new ArrayList<ScanResult>(wifiScan.getScanResults());
Comparator<ScanResult> comparator = new Comparator<ScanResult>() {
#Override
public int compare(ScanResult lhs, ScanResult rhs) {
return (lhs.level > rhs.level ? -1 : (lhs.level == rhs.level ? 0 : 1));
}
};
Collections.sort(scanedResults, comparator); //sorting result
if (scanedResults.size() > 10) {
int resultSize = scanedResults.size();
for (int index = resultSize - 1; ; index--) {
scanedResults.remove(index);
if (scanedResults.size() == 10) break;
}
}
}
but the scanResults of this code return RSSI level by INT.
I want get rssi level value by float for precision because I use for indoor navigation.(Finger Print).
Is there no way to get RSSI level value by float?
ps. sorry, I'm poor at English.
Even if it were in float, that doesn't imply greater accuracy as float is 32bit same as int.
But anyway it's just not available at the hardware level:
Vendors and chipset makers provide their own accuracy, granularity.
Cisco Systems cards have a RSSI_Max value of 100 and will report 101 different power levels, where the RSSI value is 0 to 100. Another popular Wi-Fi chipset is made by Atheros. An Atheros based card will return an RSSI value of 0 to 127 (0x7f) with 128 (0x80) indicating an invalid value.
So that's what you have to work with, around 7 bits.
P.S. you won't have much luck with your approach according to the wiki article:
RSSI doesn't always provide measurements that are sufficiently accurate to properly determine the location.
I am writing an app which is receiving values from a Light Sensor of a BLE device. I am trying to determine what it is that I am receiving. I am trying to get the Lux value which is provided by the sensor, but am concerned that it needs conversion. I do not know what the unit of measure is for this sensor. For example, the unit for an Android phone is SI Lux. Should be easy enough, but for this sensor, the specs do not state.
Here is the code which is giving me output:
case MSG_LIGHT:
characteristic = (BluetoothGattCharacteristic) msg.obj;
if (characteristic.getValue() == null) {
Log.w(TAG, "Error obtaining light value");
return;
}
int formatlgt1 = -1;
formatlgt1 = BluetoothGattCharacteristic.FORMAT_SINT8;
Log.i(LIGHT, "Light RawValue1 " + characteristic.getIntValue(formatlgt1, 0));
Log.i(LIGHT, "Light RawValue2 " + characteristic.getIntValue(formatlgt1, 1));
Log.w(LIGHT, "Light UUID " + characteristic.getUuid());
Log.w(LIGHT, "Light Stored Value " + characteristic.getValue());
Log.w(LIGHT, "Light Descriptors " + characteristic.getDescriptors());
Log.d(LIGHT, "Light Characteristic " + characteristic);
updateLightValues(characteristic);
break;
Simple enough, just read the sensor and give me the various outputs from that sensor at the time of reading. Next here is the output:
Light RawValue1 4
Light RawValue2 9
Light UUID 0000aa91-0000-1000-8000-00805f9b34fb
Light Stored Value [B#431d30b0
Light Descriptors [android.bluetooth.BluetoothGattDescriptor#4300e508, android.bluetooth.BluetoothGattDescriptor#4300eaf8]
Light Characteristic android.bluetooth.BluetoothGattCharacteristic#43002b10
I am interpreting that the measurement of this is the RawValues 1 & 2 but am logging what is stored to help. Problem is that the StoredValue is [B#431d30b0 which is beyond me. According to the description form the manufacturer, it states that the first byte is the HILUX at address 00x03 and the second is LOLUX at address 00x04 with a default value of 00:00.
What am I looking at here and where am I going wrong? Where I am hurting is my understanding of what I am reading. Can't seem to get a good search context to learn about it.
Thanks