Commit bd181f91 authored by ttschol's avatar ttschol
Browse files

Refactored TinybUtil to FindDevicesManager, ensure that we search long enough...

Refactored TinybUtil to FindDevicesManager, ensure that we search long enough until a device can be found, extended tests
parent fb99ed4b
Pipeline #41591 passed with stages
in 2 minutes and 4 seconds
package at.qe.skeleton.bleclient;
import com.google.common.base.Preconditions;
import tinyb.BluetoothDevice;
import tinyb.BluetoothManager;
import java.util.*;
// TODO: use logging instead of System.out
// TODO: add variable such as 'running' to stop searching in a graceful way
/**
* A class for found Bluetooth devices
*/
public class FindDevicesManager {
public static final int MIN_RSSI_ALLOWED = -80;
private static final int ATTEMPTS_TO_FIND = 5;
private final String searchDevice;
private final Set<BluetoothDevice> foundDevices = new HashSet<>();
public FindDevicesManager(final String searchDeviceName) {
Preconditions.checkNotNull(searchDeviceName, "Precondition violation - argument 'searchDeviceName' must not be NULL!");
this.searchDevice = searchDeviceName;
}
// TODO: could search for devices based on information from server e.g. at least two devices
// with a certain ID should be reachable
/**
* Search for Bluetooth devices until either at least one device could be found or until
* we reached the maximum number of attempts. We sleep a certain amount of time after each attempt.
* We need to we search long enough otherwise we may not find the device even though it is there.
*
* @param manager the Bluetooth manager from which we get the Bluetooth devices
* @return true if at least one device could be found
*/
public boolean findDevices(final BluetoothManager manager) throws InterruptedException {
Preconditions.checkNotNull(manager, "Precondition violation - argument 'manager' must not be NULL!");
for (int i = 0; i < ATTEMPTS_TO_FIND; i++) {
List<BluetoothDevice> devices = manager.getDevices();
if (devices == null) {
return false;
}
for (BluetoothDevice device : devices) {
checkDevice(device);
}
if (!this.foundDevices.isEmpty()) {
return true;
}
Thread.sleep(4000);
}
return false;
}
/**
* Check if the provided device is one we are searching for and add it to found devices
* Filter based on searchDeviceName and RSSI signal to ensure that we connect to the
* correct device and to prevent unstable communication.
*
* @param device the device to check
*/
private void checkDevice(final BluetoothDevice device) {
Preconditions.checkNotNull(device, "Precondition violation - argument 'device' must not be NULL!");
if (device.getName().toLowerCase(Locale.ROOT).contains(this.searchDevice.toLowerCase(Locale.ROOT))) {
final int rssi = device.getRSSI();
if (rssi == 0) {
System.out.println(this.searchDevice + " with address " + device.getAddress() + " has no signal.");
} else if (rssi < MIN_RSSI_ALLOWED) {
System.out.println(this.searchDevice + " with address " + device.getAddress() + " has a very low signal ("
+ rssi + ")");
} else {
this.foundDevices.add(device);
}
}
}
public Set<BluetoothDevice> getFoundDevices() {
return Collections.unmodifiableSet(this.foundDevices);
}
}
......@@ -4,7 +4,7 @@ import tinyb.BluetoothDevice;
import tinyb.BluetoothException;
import tinyb.BluetoothManager;
import java.util.List;
import java.util.Set;
// TODO: use logging instead of System.out/System.err
......@@ -23,13 +23,17 @@ public final class Main {
* @param args the program arguments
* @see <a href="https://github.com/DI-GROUP/TimeFlip.Docs/blob/master/Hardware/BLE_device_commutication_protocol_v3.0_en.md" target="_top">BLE device communication protocol v3.0</a>
*/
public static void main(String[] args) {
public static void main(String[] args) throws InterruptedException {
BluetoothManager manager = BluetoothManager.getBluetoothManager();
final String findDeviceName = "TimeFlip";
final boolean discoveryStarted = manager.startDiscovery();
System.out.println("The discovery started: " + (discoveryStarted ? "true" : "false"));
FindDevicesManager findDevicesManager = new FindDevicesManager(findDeviceName);
final boolean findDevicesSuccess = findDevicesManager.findDevices(manager);
try {
manager.stopDiscovery();
} catch (BluetoothException e) {
......@@ -39,14 +43,14 @@ public final class Main {
System.out.println("All found devices:");
manager.getDevices().forEach(d -> System.out.println(d.getAddress() + " - " + d.getName() + " (" + d.getRSSI() + ")"));
List<BluetoothDevice> filteredDevices = TinybUtil.getFilteredDevices(manager, findDeviceName);
if (filteredDevices.isEmpty()) {
if (!findDevicesSuccess) {
System.err.println("No " + findDeviceName + " devices found during discovery.");
System.exit(-1);
}
System.out.println("Found " + filteredDevices.size() + " " + findDeviceName + " device(s).");
for (BluetoothDevice device : filteredDevices) {
Set<BluetoothDevice> foundDevices = findDevicesManager.getFoundDevices();
System.out.println("Found " + foundDevices.size() + " " + findDeviceName + " device(s).");
for (BluetoothDevice device : foundDevices) {
System.out.println("Found " + findDeviceName + " device with address " + device.getAddress() + " and RSSI " +
device.getRSSI());
......
package at.qe.skeleton.bleclient;
import com.google.common.base.Preconditions;
import tinyb.BluetoothDevice;
import tinyb.BluetoothManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
// TODO: use logging instead of System.out
/**
* An utility class for bluetooth low energy devices
*/
public final class TinybUtil {
public static final int MIN_RSSI_ALLOWED = -80;
private TinybUtil() {
}
/**
* Filter Bluetooth devices based on searchDevice
* <p>
* If the signal strength is too low then we should not connect to the device. The communication may
* be unstable.
*
* @param manager the Bluetooth manager from which we get the Bluetooth devices
* @param searchDevice the devices we want to search for
* @return filtered bluetooth devices
*/
public static List<BluetoothDevice> getFilteredDevices(final BluetoothManager manager, final String searchDevice) {
Preconditions.checkNotNull(manager, "Precondition violation - argument 'manager' must not be NULL!");
Preconditions.checkNotNull(searchDevice, "Precondition violation - argument 'searchDevice' must not be NULL!");
final String searchDeviceLowercase = searchDevice.toLowerCase(Locale.ROOT);
List<BluetoothDevice> devices = new ArrayList<>();
for (BluetoothDevice device : manager.getDevices()) {
if (device.getName().toLowerCase(Locale.ROOT).contains(searchDeviceLowercase)) {
final int rssi = device.getRSSI();
if (rssi == 0) {
System.out.println(searchDevice + " with address " + device.getAddress() + " has no signal.");
} else if (rssi < MIN_RSSI_ALLOWED) {
System.out.println(searchDevice + " with address" + device.getAddress() + " has a very low signal ("
+ rssi + ")");
} else {
devices.add(device);
}
}
}
return devices;
}
}
......@@ -8,19 +8,25 @@ import tinyb.BluetoothManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.mockito.Mockito.when;
public class TinybUtilTest {
public class FindDevicesManagerTest {
@Test
public void testGetFilteredDevices() {
public void testFindDevices() throws InterruptedException {
BluetoothManager bluetoothManager = Mockito.mock(BluetoothManager.class);
List<BluetoothDevice> mockDevices = utilMockDevices();
when(bluetoothManager.getDevices()).thenReturn(mockDevices);
List<BluetoothDevice> devices = TinybUtil.getFilteredDevices(bluetoothManager, "TimeFlip");
FindDevicesManager findDevicesManager = new FindDevicesManager("TimeFlip");
Assert.assertNotNull(findDevicesManager);
boolean findDevicesSuccess = findDevicesManager.findDevices(bluetoothManager);
Assert.assertTrue(findDevicesSuccess);
Set<BluetoothDevice> devices = findDevicesManager.getFoundDevices();
Assert.assertNotNull(devices);
Assert.assertEquals(2, devices.size());
......@@ -37,31 +43,59 @@ public class TinybUtilTest {
}
}
@Test
public void testFindDevicesFailed() throws InterruptedException {
BluetoothManager bluetoothManager = Mockito.mock(BluetoothManager.class);
List<BluetoothDevice> mockDevices = utilMockDevices();
when(bluetoothManager.getDevices()).thenReturn(mockDevices);
FindDevicesManager findDevicesManager1 = new FindDevicesManager("headphones1");
Assert.assertNotNull(findDevicesManager1);
Assert.assertFalse(findDevicesManager1.findDevices(bluetoothManager));
Assert.assertNotNull(findDevicesManager1.getFoundDevices());
FindDevicesManager findDevicesManager2 = new FindDevicesManager("timeflip3");
Assert.assertNotNull(findDevicesManager2);
Assert.assertFalse(findDevicesManager2.findDevices(bluetoothManager));
Assert.assertNotNull(findDevicesManager2.getFoundDevices());
FindDevicesManager findDevicesManager3 = new FindDevicesManager("timeflip4");
Assert.assertNotNull(findDevicesManager3);
Assert.assertFalse(findDevicesManager3.findDevices(bluetoothManager));
Assert.assertNotNull(findDevicesManager3.getFoundDevices());
}
private List<BluetoothDevice> utilMockDevices() {
List<BluetoothDevice> mockDevices = new ArrayList<>();
BluetoothDevice mockTimeFlip1 = Mockito.mock(BluetoothDevice.class);
when(mockTimeFlip1.getName()).thenReturn("timeflip");
when(mockTimeFlip1.getAddress()).thenReturn("A8:A8:9F:B9:28:AD");
when(mockTimeFlip1.getRSSI()).thenReturn((short) -20);
mockDevices.add(mockTimeFlip1);
BluetoothDevice mockTimeFlip2 = Mockito.mock(BluetoothDevice.class);
when(mockTimeFlip2.getName()).thenReturn("TimeFlip2");
when(mockTimeFlip2.getAddress()).thenReturn("B8:A8:9F:B9:28:AD");
when(mockTimeFlip2.getRSSI()).thenReturn((short) -44);
mockDevices.add(mockTimeFlip2);
BluetoothDevice mockTimeFlip3 = Mockito.mock(BluetoothDevice.class);
when(mockTimeFlip3.getName()).thenReturn("timeflip3");
when(mockTimeFlip3.getAddress()).thenReturn("C8:A8:9F:B9:28:AD");
when(mockTimeFlip3.getRSSI()).thenReturn((short) -91);
mockDevices.add(mockTimeFlip3);
BluetoothDevice mockTimeFlip4 = Mockito.mock(BluetoothDevice.class);
when(mockTimeFlip4.getName()).thenReturn("timeflip4");
when(mockTimeFlip4.getAddress()).thenReturn("D8:A8:9F:B9:28:AD");
when(mockTimeFlip4.getRSSI()).thenReturn((short) 0);
mockDevices.add(mockTimeFlip4);
BluetoothDevice mockHeadphones = Mockito.mock(BluetoothDevice.class);
when(mockHeadphones.getName()).thenReturn("headphones");
when(mockHeadphones.getAddress()).thenReturn("D8:A8:9F:B9:28:AD");
when(mockHeadphones.getRSSI()).thenReturn((short) -35);
List<BluetoothDevice> mockDevices = new ArrayList<>();
mockDevices.add(mockTimeFlip1);
mockDevices.add(mockTimeFlip2);
mockDevices.add(mockTimeFlip3);
mockDevices.add(mockHeadphones);
return mockDevices;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment