传感器宣传这些蓝牙LE套餐:
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 47 08 00 FE 04 16 0F 18 5B
B3
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 45 08 00 FE 04 16 0F 18 5A
BC
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 44 08 00 FE 04 16 0F 18 5B
B2
如何解码?
LE广告报告:
ADV_NONCONN_IND - Non connectable undirected advertising (3)
bdaddr D9:4C:5D:C0:AB:B8 (Random)
Flags: 0x04
Complete local name: '8BBAC49D'
Unknown type 0x16 with 6 bytes data
Unknown type 0x16 with 3 bytes data
RSSI: -77
答案 0 :(得分:11)
这不是灯塔广告。数据包是发送三条信息的设备。
此BLE发现数据包的细分:
> 04 3E 26 02 01 03 01 B8 AB C0 5D 4C D9 1A 02 01 04 09 09 38
42 42 41 43 34 39 44 07 16 09 18 44 08 00 FE 04 16 0F 18 5B
B2
如果您查看重复数据包,您会发现每个温度测量值都会略有不同,电池测量也是如此。
以下是数据包的细分:
B8 AB C0 5D 4C D9 1A # Bluetooth Mac Address
02 # Number of bytes that follow in first AD structure
01 # Flags AD type
04 # Flags value 0x04 = 000000100
bit 0 (OFF) LE Limited Discoverable Mode
bit 1 (OFF) LE General Discoverable Mode
bit 2 (ON) BR/EDR Not Supported
bit 3 (OFF) Simultaneous LE and BR/EDR to Same Device Capable (controller)
bit 4 (OFF) Simultaneous LE and BR/EDR to Same Device Capable (Host)
09 # Number of bytes that follow in the first AD Structure
09 # Complete Local Name AD Type
38 42 42 41 43 34 39 44 # "8BBAC49D"
07 # Number of bytes that follow in the second AD Structure
16 # Service Data AD Type
09 18 # 16-bit Service UUID 0x1809 = Health thermometer (org.bluetooth.service.health_thermometer)
44 08 00 FE # Additional Service Data 440800 (Temperature = 0x000844 x 10^-2) = 21.16 degrees
04 # Number of bytes that follow in the third AD Structure
16 # Service Data AD Type
0F 18 # 16-bit Service UUID 0x180F = Battery Service (org.bluetooth.service.battery_service)
5B # Additional Service Data (battery level)
B2 # checksum
有关详细信息,请参阅蓝牙16位服务UUID定义:
答案 1 :(得分:6)
您可以使用hcidump -w dump.log
录制一些软件包并在Wireshark中打开它 - 它可以为您完成大部分解码。
失踪的虱子:
04 # HCI Packet Type: HCI Event (0x04)
3E # Event Code: LE Meta (0x3e)
26 # Parameter Total Length: 38
02 # Sub Event: LE Advertising Report (0x02)
01 # Num Reports: 1
03 # Event Type: Non-Connectable Undirected Advertising (0x03)
01 # Peer Address Type: Random Device Address (0x01)
here是btsnoop.log格式的数据包。适用于Wireshark和hcidump -r packet.log
。
答案 2 :(得分:1)
public class Util {
public static int convertU16ToInt(byte i) {
int firstByte = (0x000000FF & ((int)i));
return firstByte;
}
public static int bytesToInt(final byte[] array, final int start)
{
final ByteBuffer buf = ByteBuffer.wrap(array); // big endian by default
buf.position(start);
buf.put(array);
buf.position(start);
return buf.getInt();
}
public static int convertU32ToInt(byte b[], int start) {
return ((b[start] << 24) & 0xff000000 |(b[start + 1] << 16) & 0xff0000
| (b[start + 2] << 8) & 0xff00 | (b[start + 3]) & 0xff);
}
public static long int64Converter(byte buf[], int start) {
return ((buf[start] & 0xFFL) << 56) | ((buf[start + 1] & 0xFFL) << 48)
| ((buf[start + 2] & 0xFFL) << 40)
| ((buf[start + 3] & 0xFFL) << 32)
| ((buf[start + 4] & 0xFFL) << 24)
| ((buf[start + 5] & 0xFFL) << 16)
| ((buf[start + 6] & 0xFFL) << 8)
| ((buf[start + 7] & 0xFFL) << 0);
}
public static long convertU16ToInt(byte[] buf, int index) {
int firstByte = (0x000000FF & ((int)buf[index]));
int secondByte = (0x000000FF & ((int)buf[index+1]));
int thirdByte = (0x000000FF & ((int)buf[index+2]));
int fourthByte = (0x000000FF & ((int)buf[index+3]));
index = index+4;
long anUnsignedInt = ((long) (firstByte << 24
| secondByte << 16
| thirdByte << 8
| fourthByte))
& 0xFFFFFFFFL;
return anUnsignedInt;
}
public static short toUnsigned(byte b) {
return (short)(b & 0xff);
}
public static int convertU16ToInt(byte byte1, byte byte2) {
int N = (( 255 - byte1 & 0xff ) << 8 ) | byte2 & 0xff;
return N;
}
public static short UInt16Decode(byte inbyByteA, byte inbyByteB) {
short n = (short)(((inbyByteA & 0xFF) << 8) | (inbyByteB & 0xFF));
return n;
}
public static long UInt32Decode(int inbyByteA, int inbyByteB) {
int n = inbyByteA<< 16 | inbyByteB;
return n;
}
public static long decodeMeasurement16(byte byte3, byte byte4) {
return 0L;
}
public static double decodeMeasurement32(byte byte3, byte byte4, byte byte6, byte byte7) {
double outdblFloatValue = 0;
int outi16DecimalPointPosition = 0;
int ui16Integer1 = convertU16ToInt (byte3, byte4);
int ui16Integer2 = convertU16ToInt (byte6, byte7);
int ui32Integer = ( (int)UInt32Decode (ui16Integer1, ui16Integer2) ) & 0x07FFFFFF;
outi16DecimalPointPosition = ((0x000000FF - byte3 ) >> 3) - 15;
// Decode raw value, with Exampledata: 0x05FFFFFC
if ((100000000 + 0x2000000) > ui32Integer) {
// Data is a valid value
if (0x04000000 == (ui32Integer & 0x04000000)) {
ui32Integer = (ui32Integer | 0xF8000000);
// With Exampledata: 0xFDFFFFFC
}
ui32Integer = ui32Integer + 0x02000000; // with Exampledata: 0xFFFFFFFC
}
else {
// Data contains error code, decode error code
outdblFloatValue = (double)((ui32Integer - 0x02000000) - 16352.0);
outi16DecimalPointPosition = 0;
return -36; // Return value is error code
}
outdblFloatValue = (double)ui32Integer;
outdblFloatValue = outdblFloatValue / (Math.pow(10.0f, (double)outi16DecimalPointPosition));
return outdblFloatValue;
}
public static int toByte(int number) {
int tmp = number & 0xff;
return (tmp & 0x80) == 0 ? tmp : tmp - 256;
}
public static long getUnsignedInt(int x) {
return x & 0x00000000ffffffffL;
}
}
获取字节数组后,调用Util.decodeMeasurement32(byte [9],byte [10],byte [11],byte [12])。这些字节是温度字节。
答案 3 :(得分:0)
温度计的工作原理类似于 BLE 信标,即您无法连接。所有信息每 5 秒左右在广告中给出。例如。使用 Android 和受祝福的库 (https://github.com/weliem/blessed-android):
lateinit var central: BluetoothCentralManager
val HTS_SERVICE_UUID = ParcelUuid.fromString("00001809-0000-1000-8000-00805f9b34fb")
val BTS_SERVICE_UUID = ParcelUuid.fromString("0000180f-0000-1000-8000-00805f9b34fb")
fun convertTemperature(bytes: ByteArray?): Float {
if (null == bytes)
return -273.15f
val bb: ByteBuffer = ByteBuffer.allocate(2)
bb.order(ByteOrder.LITTLE_ENDIAN)
bb.put(bytes[0])
bb.put(bytes[1])
return bb.getShort(0) / 100.0f
}
val bluetoothCentralManagerCallback: BluetoothCentralManagerCallback = object : BluetoothCentralManagerCallback() {
override fun onDiscoveredPeripheral(peripheral: BluetoothPeripheral, scanResult: ScanResult) {
val rssi = scanResult.rssi
val scanRec = scanResult.scanRecord
val payload = scanRec?.serviceData
val temperature = convertTemperature(payload?.get(key = HTS_SERVICE_UUID))
val other_data = payload?.get(key = HTS_SERVICE_UUID)?.sliceArray(2..3)
val battery_level = payload?.get(key = BTS_SERVICE_UUID)
central.stopScan()
tempLabel.text = getString(R.string.temp, temperature)
}
}
central = BluetoothCentralManager(applicationContext, bluetoothCentralManagerCallback, Handler(Looper.getMainLooper()))
central.scanForPeripheralsWithNames(arrayOf("7FE2183D"))
每次您想要新的阅读时,您都可以重新开始扫描。