嗨,我正在服务中运行 RxAndroidBle。我将其设置为自动连接,因为设备每 5 分钟唤醒一次并尝试将数据发送到配对设备。我还设置了通知以获取数据。它可以工作,但每次断开连接时,我都会收到通知错误和写入错误。
03-07 12:37:03.600 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: close()
03-07 12:37:03.600 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: unregisterApp() - mClientIf=6
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: connect() - device: B4:99:4C:67:5E:67, auto: true
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: registerApp()
03-07 12:37:03.604 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: registerApp() - UUID=1a9155ae-aa9c-465e-aacd-3c535c3d32a8
03-07 12:37:03.607 31014-31026/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientRegistered() - status=0 clientIf=6
03-07 12:37:03.610 31014-31027/com.lady.viktoria.lightdrip D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000ffe1-0000-1000-8000-00805f9b34fb enable: false
03-07 12:37:03.610 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Notifications error: BleGattException{macAddress=B4:99:4C:67:5E:67, status=8 (0x08 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'}}
03-07 12:37:03.612 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Write error: BleGattException{macAddress=B4:99:4C:67:5E:67, status=8 (0x08 -> https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.0_r1/stack/include/gatt_api.h), bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'}}
03-07 12:41:41.296 31014-7238/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=B4:99:4C:67:5E:67
03-07 12:41:41.304 31014-31093/com.lady.viktoria.lightdrip V/CgmBleService: Hey, connection has been established!
03-07 12:41:41.314 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: discoverServices() - device: B4:99:4C:67:5E:67
03-07 12:41:41.889 31014-7239/com.lady.viktoria.lightdrip D/BluetoothGatt: onSearchComplete() = Device=B4:99:4C:67:5E:67 Status=0
03-07 12:41:41.900 31014-31093/com.lady.viktoria.lightdrip D/BluetoothGatt: setCharacteristicNotification() - uuid: 0000ffe1-0000-1000-8000-00805f9b34fb enable: true
03-07 12:41:41.941 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Notifications has been set up
03-07 12:41:46.748 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Change: 1500300000002E000000D63CC12B680000000000
03-07 12:41:46.753 31014-31014/com.lady.viktoria.lightdrip I/CgmBleService: Received Data packet
03-07 12:41:46.763 31014-31014/com.lady.viktoria.lightdrip D/GlucoseRecord: create: No calibration yet
03-07 12:41:46.772 31014-31014/com.lady.viktoria.lightdrip I/GlucoseRecord: calculateAgeAdjustedRawValue: RAW VALUE ADJUSTMENT FROM:0.048 TO: 0.06792021355263159
03-07 12:41:46.781 31014-31014/com.lady.viktoria.lightdrip V/GlucoseRecord: glucoseRecord json: {"id":128,"a":0.0,"ageAdjustedRawValue":0.06792021355263159,"b":0.0,"c":0.0,"calculatedValue":0.0,"calculatedValueSlope":0.0,"calibrationFlag":false,"calibration_id":0,"filteredData":0.046,"ra":0.0,"rawData":0.048,"rb":0.0,"rc":0.0,"sensor_id":2,"synced":false,"timeSinceSensorStarted":1.2766377E7,"timestamp":1.488886906748E12}
03-07 12:41:46.782 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Change: 01
03-07 12:41:46.782 31014-31014/com.lady.viktoria.lightdrip D/CgmBleService: Sending Acknowledge Packet, to put wixel to sleep
03-07 12:41:46.791 31014-31014/com.lady.viktoria.lightdrip V/CgmBleService: Write success
03-07 12:42:01.144 31014-31027/com.lady.viktoria.lightdrip D/BluetoothGatt: onClientConnectionState() - status=8 clientIf=6 device=B4:99:4C:67:5E:67
03-07 12:42:01.147 31014-31027/com.lady.viktoria.lightdrip V/CgmBleService: Connection Failure
03-07 12:42:01.148 31014-31014/com.lady.viktoria.lightdrip D/BluetoothManager: getConnectionState()
03-07 12:42:01.148 31014-31014/com.lady.viktoria.lightdrip D/BluetoothManager: getConnectedDevices
03-07 12:42:01.153 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: close()
03-07 12:42:01.153 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: unregisterApp() - mClientIf=6
03-07 12:42:01.161 31014-31014/com.lady.viktoria.lightdrip D/BluetoothGatt: connect() - device: B4:99:4C:67:5E:67, auto: true
public class CgmBleService extends Service {
private final static String TAG = CgmBleService.class.getSimpleName();
public final static UUID UUID_BG_MEASUREMENT = UUID.fromString(GattAttributes.HM_RX_TX);
public final static String ACTION_BLE_CONNECTED = "ACTION_BLE_CONNECTED";
public final static String ACTION_BLE_DISCONNECTED = "ACTION_BLE_DISCONNECTED";
public final static String ACTION_BLE_DATA_AVAILABLE = "ACTION_BLE_DATA_AVAILABLE";
public final static String EXTRA_BLE_DATA = "EXTRA_BLE_DATA";
public final static String BEACON_SNACKBAR = "BEACON_SNACKBAR";
private RxBleClient rxBleClient;
private RxBleDevice bleDevice;
private AppPreferences mTrayPreferences;
private PublishSubject<Void> disconnectTriggerSubject = PublishSubject.create();
private Observable<RxBleConnection> connectionObservable;
Handler handler;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
handler = new Handler();
startJobScheduler();
// get mac address from selected wixelbridge
mTrayPreferences = new AppPreferences(this);
final String BTDeviceAddress = mTrayPreferences.getString("BT_MAC_Address", "00:00:00:00:00:00");
//init rxBleClient
rxBleClient = RxBleClient.create(this);
bleDevice = rxBleClient.getBleDevice(BTDeviceAddress);
// logging for RxBleClient
RxBleClient.setLogLevel(RxBleLog.INFO);
connectionObservable = prepareConnectionObservable();
connect();
return START_STICKY;
}
private Observable<RxBleConnection> prepareConnectionObservable() {
return bleDevice
.establishConnection(true)
.takeUntil(disconnectTriggerSubject)
//.compose(bindUntilEvent(PAUSE)
.doOnUnsubscribe(this::clearSubscription)
.compose(new ConnectionSharingAdapter());
}
public void connect() {
if (isConnected()) {
triggerDisconnect();
broadcastUpdate(ACTION_BLE_CONNECTED);
} else {
connectionObservable.subscribe(this::onConnectionReceived, this::onConnectionFailure);
broadcastUpdate(ACTION_BLE_DISCONNECTED);
}
}
public void writeCharacteristic(final ByteBuffer byteBuffer) {
byte[] bytearray = byteBuffer.array();
if (isConnected()) {
connectionObservable
.flatMap(rxBleConnection -> rxBleConnection
.writeCharacteristic(UUID_BG_MEASUREMENT, bytearray))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bytes -> onWriteSuccess(), this::onWriteFailure);
}
}
public void writeNotificationCharacteristic() {
if (isConnected()) {
connectionObservable
.flatMap(rxBleConnection -> rxBleConnection.setupNotification(UUID_BG_MEASUREMENT))
.doOnNext(notificationObservable -> runOnUiThread(this::notificationHasBeenSetUp))
.flatMap(notificationObservable -> notificationObservable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onNotificationReceived, this::onNotificationSetupFailure);
}
}
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
private boolean isConnected() {
return bleDevice.getConnectionState() == RxBleConnection.RxBleConnectionState.CONNECTED;
}
private void clearSubscription() {
updateUI();
}
private void triggerDisconnect() {
disconnectTriggerSubject.onNext(null);
}
private void updateUI() {
// connectButton.setText(isConnected() ? getString(R.string.disconnect) : getString(R.string.connect));
// readButton.setEnabled(isConnected());
// writeButton.setEnabled(isConnected());
// notifyButton.setEnabled(isConnected());
}
private void onConnectionFailure(Throwable throwable) {
//noinspection ConstantConditions
Log.v(TAG, "Connection Failure");
connect();
}
private void onConnectionReceived(RxBleConnection connection) {
//noinspection ConstantConditions
Log.v(TAG, "Hey, connection has been established!");
writeNotificationCharacteristic();
}
private void onWriteSuccess() {
//noinspection ConstantConditions
Log.v(TAG, "Write success");
}
private void onWriteFailure(Throwable throwable) {
//noinspection ConstantConditions
Log.v(TAG, "Write error: " + throwable);
}
private void onNotificationReceived(byte[] bytes) {
//noinspection ConstantConditions
Log.v(TAG, "Change: " + ConvertHexString.bytesToHex(bytes));
long timestamp = new Date().getTime();
int packatlength = bytes[0];
if (packatlength >= 2) {
if (CheckTransmitterID(bytes, bytes.length)) {
TransmitterRecord.create(bytes, bytes.length, timestamp);
} else {
broadcastUpdate(BEACON_SNACKBAR);
}
} else if (packatlength <= 1) {
writeAcknowledgePacket();
}
}
private void onNotificationSetupFailure(Throwable throwable) {
//noinspection ConstantConditions
Log.v(TAG, "Notifications error: " + throwable);
}
private void notificationHasBeenSetUp() {
//noinspection ConstantConditions
Log.v(TAG, "Notifications has been set up");
}
public boolean CheckTransmitterID(byte[] packet, int len) {
int DexSrc;
int TransmitterID;
ByteBuffer tmpBuffer;
final String TxId = mTrayPreferences.getString("Transmitter_Id", "00000");
TransmitterID = ConvertTxID.convertSrc(TxId);
tmpBuffer = ByteBuffer.allocate(len);
tmpBuffer.order(ByteOrder.LITTLE_ENDIAN);
tmpBuffer.put(packet, 0, len);
if (packet[0] == 7) {
Log.i(TAG, "Received Beacon packet.");
broadcastUpdate(BEACON_SNACKBAR);
writeTxIdPacket(TransmitterID);
return false;
} else if (packet[0] >= 21 && packet[1] == 0) {
Log.i(TAG, "Received Data packet");
DexSrc = tmpBuffer.getInt(12);
TransmitterID = ConvertTxID.convertSrc(TxId);
if (Integer.compare(DexSrc, TransmitterID) != 0) {
writeTxIdPacket(TransmitterID);
return false;
} else {
return true;
}
}
return false;
}
private void writeTxIdPacket(int TransmitterID) {
Log.v(TAG, "try to set transmitter ID");
ByteBuffer txidMessage = ByteBuffer.allocate(6);
txidMessage.order(ByteOrder.LITTLE_ENDIAN);
txidMessage.put(0, (byte) 0x06);
txidMessage.put(1, (byte) 0x01);
txidMessage.putInt(2, TransmitterID);
writeCharacteristic(txidMessage);
}
private void writeAcknowledgePacket() {
Log.d(TAG, "Sending Acknowledge Packet, to put wixel to sleep");
ByteBuffer ackMessage = ByteBuffer.allocate(2);
ackMessage.put(0, (byte) 0x02);
ackMessage.put(1, (byte) 0xF0);
writeCharacteristic(ackMessage);
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
public void startJobScheduler() {
final long REFRESH_INTERVAL = 15 * 60 * 1000;
ComponentName serviceComponent = new ComponentName(this, SchedulerJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setRequiresDeviceIdle(false);
builder.setRequiresCharging(false);
builder.setPeriodic(REFRESH_INTERVAL);
//builder.setPersisted(true);
JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
int result = jobScheduler.schedule(builder.build());
if (result == JobScheduler.RESULT_SUCCESS) Log.d(TAG, "Job scheduled successfully!");
}
public void stopJobScheduler() {
JobScheduler jobScheduler = (JobScheduler) this.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.cancel(0);
}
@Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent("com.lady.viktoria.lightdrip.services.RestartCgmBleService");
sendBroadcast(broadcastIntent);
stopJobScheduler();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}}