BLE温度传感器服务检测

时间:2014-07-06 04:58:09

标签: android bluetooth-lowenergy

我有能够扫描作为临时传感器的BLE devies的源代码,但是在扫描时它不会显示任何其他BLE决定。我想修改附加的代码,以便我可以扫描和查看所有BLE设备,无论它是否是温度传感器。有人可以解释我或告诉我如何做到这一点。以下是获取BLE Temp传感器数据的代码片段。

   package no.nordicsemi.android.nrftemp.ble;

  import java.util.ArrayList;
  import java.util.Calendar;
  import java.util.List;

 import no.nordicsemi.android.nrftemp.ble.parser.TemperatureData;
  import no.nordicsemi.android.nrftemp.ble.parser.TemperatureDataParser;
  import no.nordicsemi.android.nrftemp.database.DatabaseHelper;
 import android.bluetooth.BluetoothAdapter;
  import android.bluetooth.BluetoothDevice;
  import android.bluetooth.BluetoothManager;
 import android.content.Context;
  import android.os.Handler;

public class TemperatureManager implements BluetoothAdapter.LeScanCallback {
/** An minimal interval between each data row in the database for a single device */
private static final long DATA_INTERVAL = 60 * 5 * 1000L; // ms 

private BluetoothAdapter mBluetoothAdapter;
private DatabaseHelper mDatabaseHelper;

private List<TemperatureManagerCallback> mListeners;

public TemperatureManager(final Context context, final DatabaseHelper databaseHelper) {
    final BluetoothManager bluetoothManager = (BluetoothManager)        context.getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();
    mDatabaseHelper = databaseHelper;

    mListeners = new ArrayList<TemperatureManagerCallback>(2);
}

public void addCallback(final TemperatureManagerCallback callback) {
    mListeners.add(callback);
}

public void removeCallback(final TemperatureManagerCallback callback) {
    mListeners.remove(callback);
}

private void fireOnDevicesScanned() {
    for (TemperatureManagerCallback callback : mListeners)
        callback.onDevicesScaned();
}

private void fireOnRssiUpdate(final long sensorId, final int rssi) {
    for (TemperatureManagerCallback callback : mListeners)
        callback.onRssiUpdate(sensorId, rssi);
}

/**
  * Starts scanning for temperature data. Call {@link #stopScan()} when done to save the power.
 */
  public void startScan() {
    mBluetoothAdapter.startLeScan(this);
}

/**
 * Starts scanning for temperature data. Call {@link #stopScan()} when done to save the power.
 */
  public void startScan(final long period) {
    mBluetoothAdapter.startLeScan(this);

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            stopScan();
        }
    }, period);
}

/**
 * Stops scanning for temperature data from BLE sensors.
 */
public void stopScan() {
    mBluetoothAdapter.stopLeScan(this);
}

@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[]       scanRecord) {
    final TemperatureData td = TemperatureDataParser.parse(device, scanRecord);
    if (!td.isValid())
        return;

    final long now = Calendar.getInstance().getTimeInMillis();
    final long then = mDatabaseHelper.getLastTimestamp(td.getAddress());

    if (now - then > DATA_INTERVAL) {
        mDatabaseHelper.addNewSensorData(device.getAddress(), device.getName(), now,                
   td.getTemp(), td.getBattery());
        fireOnDevicesScanned();
    }
    final long sensorId = mDatabaseHelper.findSensor(device.getAddress());
    final int rssiPercent = (int) (100.0f * (127.0f + rssi) / 127.0f + 20.0f);
    mDatabaseHelper.updateSensorRssi(sensorId, rssiPercent);
    fireOnRssiUpdate(sensorId, rssiPercent);
}

/**
 * Return <code>true</code> if Bluetooth is currently enabled and ready for use.
 * 
 * @return <code>true</code> if the local adapter is turned on
 */
 public boolean isEnabled() {
    return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
}
  }


package no.nordicsemi.android.nrftemp.ble.parser;

import android.bluetooth.BluetoothDevice;

 /**
   * Domain class contains data obtained from a single advertising package from a      temperature sensor.
     */
  public class TemperatureData {
   /** The device address */
   private final String address;

/** The device name */
private String name;

/** The temperature value */
private double temp;

/** Battery status (number 0-100 in percent) */
private int battery = 0xFF; // unknown value

/**
 * The flag whether the data are valid (holds real temperature measurement or not)
 */
private boolean valid;

public TemperatureData(BluetoothDevice device) {
    address = device.getAddress();
    name = device.getName();
}

public String getAddress() {
    return address;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public double getTemp() {
    return temp;
}

public void setTemp(double temp) {
    this.temp = temp;
    this.valid = true;
}

public int getBattery() {
    return battery;
}

public void setBattery(int battery) {
    this.battery = battery;
}

public boolean isValid() {
    return valid;
}
}


package no.nordicsemi.android.nrftemp.ble.parser;

    import java.io.UnsupportedEncodingException;
   import java.text.ParseException;

   import android.bluetooth.BluetoothDevice;
   import android.util.Log;

  public class TemperatureDataParser {
private static final String TAG = "TemperatureDataParser";

private static final int FLAGS = 0x02; // "Flags" Data Type (See section 18.1 of Core_V4.0.pdf)
private static final int LOCAL_NAME = 0x09; // "Complete Local Name" Data Type (See section 18.3 of Core_V4.0.pdf)
private static final int SERVICE_DATA = 0x16; // "Service Data" Data Type (See section 18.10 of Core_V4.0.pdf)

private static final short TEMPERATURE_SERVICE_UUID = 0x1809;
private static final short BATTERY_SERVICE_UUID = 0x180F;
private static final short DEVICE_INFORMATION_SERVICE_UUID = 0x180A;

/**
 * Parses the advertising package obtained by BLE device
 * 
 * @param data
 *            the data obtained (EIR data). Read Bluetooth Core Specification v4.0 (Core_V4.0.pdf -&gt; Vol.3 -&gt; Part C -&gt; Section 8) for details
 * @return the parsed temperature data
 * @throws ParseException
 *             thrown when the given data does not fit the expected format
 */
public static TemperatureData parse(final BluetoothDevice device, final byte[] data) {
    final TemperatureData td = new TemperatureData(device);

    /*
     * First byte of each EIR Data Structure has it's length (1 octet).
     * There comes the EIR Data Type (n bytes) and (length - n bytes) of data. 
     * See Core_V4.0.pdf -> Vol.3 -> Part C -> Section 8 for details
     */
    for (int i = 0; i < data.length;) {
        final int eirLength = data[i];

        // check whether there is no more to read
        if (eirLength == 0)
            break;

        final int eirDataType = data[++i];
        switch (eirDataType) {
        case FLAGS:
            // do nothing
            break;
        case LOCAL_NAME:
            /*
             * Local name data structure contains length - 1 bytes of the device name (1 byte for the data type)
             */
            final String name = decodeLocalName(data, i + 1, eirLength - 1);
            td.setName(name);
            break;
        case SERVICE_DATA:
            /*
             * First 2 bytes of service data are the 16-bit Service UUID in reverse order. The rest is service specific data.
             */
            final short serviceUUID = decodeServiceUUID(data, i + 1);

            switch (serviceUUID) {
            case BATTERY_SERVICE_UUID:
                final int battery = decodeBatteryLevel(data, i + 3);
                td.setBattery(battery);
                break;
            case TEMPERATURE_SERVICE_UUID:
                final double temp = decodeTempLevel(data, i + 3);
                td.setTemp(temp);
                break;
            case DEVICE_INFORMATION_SERVICE_UUID:
                // do nothing 
                break;
            }
            break;
        default:
            break;
        }
        i += eirLength;
    }
    return td;
}

private static String decodeLocalName(final byte[] data, final int start, final int length) {
    try {
        return new String(data, start, length, "UTF-8");
    } catch (UnsupportedEncodingException e) {
        Log.e(TAG, "Unable to convert the local name to UTF-8", e);
        return null;
    }
}

private static short decodeServiceUUID(final byte[] data, final int start) {
    return (short) ((data[start + 1] << 8) | data[start]);
}

private static int decodeBatteryLevel(final byte[] data, final int start) {
    /*
     * Battery level is a 1 byte number 0-100 (0x64). Value 255 (0xFF) is used for illegal measurement values
     */
    return data[start];
}

private static float decodeTempLevel(final byte[] data, final int start) {
    return bytesToFloat(data[start], data[start + 1], data[start + 2], data[start + 3]);
}

/**
 * Convert signed bytes to a 32-bit short float value.
 */
private static float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
    int mantissa = unsignedToSigned(unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8) + (unsignedByteToInt(b2) << 16), 24);
    return (float) (mantissa * Math.pow(10, b3));
}

/**
 * Convert a signed byte to an unsigned int.
 */
private static int unsignedByteToInt(byte b) {
    return b & 0xFF;
}

/**
 * Convert an unsigned integer value to a two's-complement encoded signed value.
 */
private static int unsignedToSigned(int unsigned, int size) {
    if ((unsigned & (1 << size - 1)) != 0) {
        unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
    }
    return unsigned;
}

}

1 个答案:

答案 0 :(得分:0)

据我所知,代码正在扫描每个BLE设备,扫描mBluetoothAdapter.startLeScan(this)中没有服务uuid​​限制;

此代码的问题(与许多示例一样)是它假设每个设备都属于他们自己的类型(在这种情况下是温度传感器)。

假设在这里:

public void onLeScan(final BluetoothDevice device, final int rssi, final byte[]       scanRecord) {
final TemperatureData td = TemperatureDataParser.parse(device, scanRecord);

通过连接设备来了解设备支持的服务的唯一方法是,进行服务发现并检查支持的服务。

问候,Rob。