[bluetooth] Changed characteristic read/write to use CompletableFutures (#8970)

Signed-off-by: Connor Petty <mistercpp2000+gitsignoff@gmail.com>
This commit is contained in:
Connor Petty
2021-04-09 13:23:28 -07:00
committed by GitHub
parent 1822f77b07
commit 89d735bb0f
24 changed files with 1207 additions and 1562 deletions

View File

@@ -12,13 +12,14 @@
*/
package org.openhab.binding.bluetooth.daikinmadoka.handler;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.measure.quantity.Temperature;
import javax.measure.quantity.Time;
@@ -27,7 +28,6 @@ import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.bluetooth.BluetoothCharacteristic;
import org.openhab.binding.bluetooth.BluetoothCompletionStatus;
import org.openhab.binding.bluetooth.BluetoothDevice.ConnectionState;
import org.openhab.binding.bluetooth.ConnectedBluetoothHandler;
import org.openhab.binding.bluetooth.daikinmadoka.DaikinMadokaBindingConstants;
@@ -350,12 +350,12 @@ public class DaikinMadokaHandler extends ConnectedBluetoothHandler implements Re
}
@Override
public void onCharacteristicUpdate(BluetoothCharacteristic characteristic) {
public void onCharacteristicUpdate(BluetoothCharacteristic characteristic, byte[] msgBytes) {
if (logger.isDebugEnabled()) {
logger.debug("[{}] onCharacteristicUpdate({})", super.thing.getUID().getId(),
HexUtils.bytesToHex(characteristic.getByteValue()));
HexUtils.bytesToHex(msgBytes));
}
super.onCharacteristicUpdate(characteristic);
super.onCharacteristicUpdate(characteristic, msgBytes);
// Check that arguments are valid.
if (characteristic.getUuid() == null) {
@@ -367,9 +367,8 @@ public class DaikinMadokaHandler extends ConnectedBluetoothHandler implements Re
return;
}
// A message cannot be null or have a 0-byte length
byte[] msgBytes = characteristic.getByteValue();
if (msgBytes == null || msgBytes.length == 0) {
// A message cannot have a 0-byte length
if (msgBytes.length == 0) {
return;
}
@@ -398,7 +397,7 @@ public class DaikinMadokaHandler extends ConnectedBluetoothHandler implements Re
return;
}
if (!resolved) {
if (!device.isServicesDiscovered()) {
logger.debug("Unable to send command {} to device {}: services not resolved",
command.getClass().getSimpleName(), device.getAddress());
command.setState(BRC1HCommand.State.FAILED);
@@ -424,17 +423,23 @@ public class DaikinMadokaHandler extends ConnectedBluetoothHandler implements Re
// Commands can be composed of multiple chunks
for (byte[] chunk : command.getRequest()) {
charWrite.setValue(chunk);
command.setState(BRC1HCommand.State.ENQUEUED);
for (int i = 0; i < DaikinMadokaBindingConstants.WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
if (device.writeCharacteristic(charWrite)) {
command.setState(BRC1HCommand.State.SENT);
synchronized (command) {
command.wait(100);
}
break;
try {
device.writeCharacteristic(charWrite, chunk).get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException ex) {
return;
} catch (ExecutionException ex) {
logger.debug("Error while writing message {}: {}", command.getClass().getSimpleName(),
ex.getMessage());
Thread.sleep(100);
continue;
} catch (TimeoutException ex) {
Thread.sleep(100);
continue;
}
Thread.sleep(100);
command.setState(BRC1HCommand.State.SENT);
break;
}
}
@@ -459,39 +464,6 @@ public class DaikinMadokaHandler extends ConnectedBluetoothHandler implements Re
}
}
@Override
public void onCharacteristicWriteComplete(BluetoothCharacteristic characteristic,
BluetoothCompletionStatus status) {
super.onCharacteristicWriteComplete(characteristic, status);
byte[] request = characteristic.getByteValue();
BRC1HCommand command = currentCommand;
if (command != null) {
// last chunk:
byte[] lastChunk = command.getRequest()[command.getRequest().length - 1];
if (!Arrays.equals(request, lastChunk)) {
logger.debug("Write completed for a chunk, but not a complete command.");
synchronized (command) {
command.notify();
}
return;
}
switch (status) {
case SUCCESS:
command.setState(BRC1HCommand.State.SENT);
break;
case ERROR:
command.setState(BRC1HCommand.State.FAILED);
break;
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("No command found that matches request {}", HexUtils.bytesToHex(request));
}
}
}
/**
* When the method is triggered, it means that all message chunks have been received, re-assembled in the right
* order and that the payload is ready to be processed.