From afe755755f88879e7175374ab47878940a08e35d Mon Sep 17 00:00:00 2001 From: cpmeister Date: Sat, 2 May 2020 05:17:40 -0700 Subject: [PATCH] [bluetooth] Make BluetoothDevice more abstract (#7380) Signed-off-by: Connor Petty --- .../AirthingsDiscoveryParticipant.java | 14 +- .../internal/AM43DiscoveryParticipant.java | 8 +- .../bluegiga/BlueGigaBluetoothDevice.java | 31 +- .../bluetooth/bluez/BlueZBluetoothDevice.java | 15 +- .../internal/BlukiiDiscoveryParticipant.java | 11 +- .../RuuviTagDiscoveryParticipant.java | 8 +- .../bluetooth/BaseBluetoothDevice.java | 350 ++++++++++++++++ .../bluetooth/BeaconBluetoothHandler.java | 23 +- .../binding/bluetooth/BluetoothDevice.java | 374 ++---------------- .../bluetooth/DelegateBluetoothDevice.java | 167 ++++++++ .../discovery/BluetoothDiscoveryDevice.java | 125 ++++++ .../BluetoothDiscoveryParticipant.java | 7 +- .../internal/BluetoothDeviceSnapshot.java | 155 ++++---- .../internal/BluetoothDiscoveryProcess.java | 6 +- .../internal/BluetoothDiscoveryService.java | 2 +- .../bluetooth/MockBluetoothDevice.java | 29 +- .../BluetoothDiscoveryServiceTest.java | 35 +- 17 files changed, 883 insertions(+), 477 deletions(-) create mode 100644 bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BaseBluetoothDevice.java create mode 100644 bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/DelegateBluetoothDevice.java create mode 100644 bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryDevice.java diff --git a/bundles/org.openhab.binding.bluetooth.airthings/src/main/java/org/openhab/binding/bluetooth/airthings/internal/AirthingsDiscoveryParticipant.java b/bundles/org.openhab.binding.bluetooth.airthings/src/main/java/org/openhab/binding/bluetooth/airthings/internal/AirthingsDiscoveryParticipant.java index a0fbb98fd77a2..b243c55194125 100644 --- a/bundles/org.openhab.binding.bluetooth.airthings/src/main/java/org/openhab/binding/bluetooth/airthings/internal/AirthingsDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.bluetooth.airthings/src/main/java/org/openhab/binding/bluetooth/airthings/internal/AirthingsDiscoveryParticipant.java @@ -25,7 +25,7 @@ import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.bluetooth.BluetoothBindingConstants; -import org.openhab.binding.bluetooth.BluetoothDevice; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant; import org.osgi.service.component.annotations.Component; @@ -49,8 +49,7 @@ public Set getSupportedThingTypeUIDs() { } @Override - @Nullable - public ThingUID getThingUID(BluetoothDevice device) { + public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device) { if (isAirthingsDevice(device)) { if (WAVE_PLUS_MODEL.equals(device.getModel())) { return new ThingUID(AirthingsBindingConstants.THING_TYPE_AIRTHINGS_WAVE_PLUS, @@ -61,8 +60,7 @@ public ThingUID getThingUID(BluetoothDevice device) { } @Override - @Nullable - public DiscoveryResult createResult(BluetoothDevice device) { + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { if (!isAirthingsDevice(device)) { return null; } @@ -77,11 +75,11 @@ public DiscoveryResult createResult(BluetoothDevice device) { } @Override - public boolean requiresConnection(BluetoothDevice device) { + public boolean requiresConnection(BluetoothDiscoveryDevice device) { return isAirthingsDevice(device); } - private boolean isAirthingsDevice(BluetoothDevice device) { + private boolean isAirthingsDevice(BluetoothDiscoveryDevice device) { Integer manufacturerId = device.getManufacturerId(); if (manufacturerId != null && manufacturerId == AIRTHINGS_COMPANY_ID) { return true; @@ -89,7 +87,7 @@ private boolean isAirthingsDevice(BluetoothDevice device) { return false; } - private DiscoveryResult createWavePlus(BluetoothDevice device, ThingUID thingUID) { + private DiscoveryResult createWavePlus(BluetoothDiscoveryDevice device, ThingUID thingUID) { Map properties = new HashMap<>(); properties.put(BluetoothBindingConstants.CONFIGURATION_ADDRESS, device.getAddress().toString()); properties.put(Thing.PROPERTY_VENDOR, "Airthings AS"); diff --git a/bundles/org.openhab.binding.bluetooth.am43/src/main/java/org/openhab/binding/bluetooth/am43/internal/AM43DiscoveryParticipant.java b/bundles/org.openhab.binding.bluetooth.am43/src/main/java/org/openhab/binding/bluetooth/am43/internal/AM43DiscoveryParticipant.java index 6dc3cb2f7d91f..463dc558686dd 100644 --- a/bundles/org.openhab.binding.bluetooth.am43/src/main/java/org/openhab/binding/bluetooth/am43/internal/AM43DiscoveryParticipant.java +++ b/bundles/org.openhab.binding.bluetooth.am43/src/main/java/org/openhab/binding/bluetooth/am43/internal/AM43DiscoveryParticipant.java @@ -25,8 +25,8 @@ import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.bluetooth.BluetoothBindingConstants; -import org.openhab.binding.bluetooth.BluetoothDevice; import org.openhab.binding.bluetooth.BluetoothDevice.ConnectionState; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant; import org.osgi.service.component.annotations.Component; @@ -46,7 +46,7 @@ public Set getSupportedThingTypeUIDs() { } @Override - public @Nullable DiscoveryResult createResult(BluetoothDevice device) { + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { ThingUID thingUID = getThingUID(device); if (thingUID == null) { return null; @@ -68,7 +68,7 @@ public Set getSupportedThingTypeUIDs() { } @Override - public @Nullable ThingUID getThingUID(BluetoothDevice device) { + public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device) { if (device.getConnectionState() == ConnectionState.CONNECTED && device.supportsService(AM43BindingConstants.SERVICE_UUID)) { return new ThingUID(AM43BindingConstants.THING_TYPE_AM43, device.getAdapter().getUID(), @@ -78,7 +78,7 @@ public Set getSupportedThingTypeUIDs() { } @Override - public boolean requiresConnection(BluetoothDevice device) { + public boolean requiresConnection(BluetoothDiscoveryDevice device) { return device.getManufacturerId() == null && device.getName() != null; } } diff --git a/bundles/org.openhab.binding.bluetooth.bluegiga/src/main/java/org/openhab/binding/bluetooth/bluegiga/BlueGigaBluetoothDevice.java b/bundles/org.openhab.binding.bluetooth.bluegiga/src/main/java/org/openhab/binding/bluetooth/bluegiga/BlueGigaBluetoothDevice.java index 76d8951a12a3a..8dbc2ea355f57 100644 --- a/bundles/org.openhab.binding.bluetooth.bluegiga/src/main/java/org/openhab/binding/bluetooth/bluegiga/BlueGigaBluetoothDevice.java +++ b/bundles/org.openhab.binding.bluetooth.bluegiga/src/main/java/org/openhab/binding/bluetooth/bluegiga/BlueGigaBluetoothDevice.java @@ -20,9 +20,11 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.common.ThreadPoolManager; +import org.openhab.binding.bluetooth.BaseBluetoothDevice; import org.openhab.binding.bluetooth.BluetoothAddress; import org.openhab.binding.bluetooth.BluetoothCharacteristic; import org.openhab.binding.bluetooth.BluetoothCompletionStatus; +import org.openhab.binding.bluetooth.BluetoothDescriptor; import org.openhab.binding.bluetooth.BluetoothDevice; import org.openhab.binding.bluetooth.BluetoothService; import org.openhab.binding.bluetooth.bluegiga.handler.BlueGigaBridgeHandler; @@ -52,7 +54,7 @@ * @author Chris Jackson - Initial contribution */ @NonNullByDefault -public class BlueGigaBluetoothDevice extends BluetoothDevice implements BlueGigaEventListener { +public class BlueGigaBluetoothDevice extends BaseBluetoothDevice implements BlueGigaEventListener { private final long TIMEOUT_SEC = 60; private final Logger logger = LoggerFactory.getLogger(BlueGigaBluetoothDevice.class); @@ -169,6 +171,30 @@ public boolean discoverServices() { return true; } + @Override + public boolean enableNotifications(BluetoothCharacteristic characteristic) { + // TODO will be implemented in a followup PR + return false; + } + + @Override + public boolean disableNotifications(BluetoothCharacteristic characteristic) { + // TODO will be implemented in a followup PR + return false; + } + + @Override + public boolean enableNotifications(BluetoothDescriptor descriptor) { + // TODO will be implemented in a followup PR + return false; + } + + @Override + public boolean disableNotifications(BluetoothDescriptor descriptor) { + // TODO will be implemented in a followup PR + return false; + } + @Override public boolean readCharacteristic(@Nullable BluetoothCharacteristic characteristic) { if (characteristic == null || characteristic.getHandle() == 0) { @@ -278,7 +304,7 @@ private void handleScanEvent(BlueGigaScanResponseEvent event) { Map eirRecord = (Map) obj; Map.Entry eirEntry = eirRecord.entrySet().iterator().next(); - manufacturer = (int) eirEntry.getKey(); + manufacturer = eirEntry.getKey().intValue(); int[] manufacturerInt = eirEntry.getValue(); manufacturerData = new byte[manufacturerInt.length + 2]; @@ -539,4 +565,5 @@ private void cancelTimer(@Nullable ScheduledFuture task) { private ScheduledFuture startTimer(Runnable command, long timeout) { return scheduler.schedule(command, timeout, TimeUnit.SECONDS); } + } diff --git a/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/BlueZBluetoothDevice.java b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/BlueZBluetoothDevice.java index dd63b4cd21d04..066f72bb977ee 100644 --- a/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/BlueZBluetoothDevice.java +++ b/bundles/org.openhab.binding.bluetooth.bluez/src/main/java/org/openhab/binding/bluetooth/bluez/BlueZBluetoothDevice.java @@ -20,11 +20,11 @@ import org.eclipse.smarthome.core.common.ThreadPoolManager; import org.eclipse.smarthome.core.util.HexUtils; +import org.openhab.binding.bluetooth.BaseBluetoothDevice; import org.openhab.binding.bluetooth.BluetoothAddress; import org.openhab.binding.bluetooth.BluetoothCharacteristic; import org.openhab.binding.bluetooth.BluetoothCompletionStatus; import org.openhab.binding.bluetooth.BluetoothDescriptor; -import org.openhab.binding.bluetooth.BluetoothDevice; import org.openhab.binding.bluetooth.BluetoothService; import org.openhab.binding.bluetooth.bluez.handler.BlueZBridgeHandler; import org.openhab.binding.bluetooth.notification.BluetoothConnectionStatusNotification; @@ -43,7 +43,7 @@ * @author Kai Kreuzer - Initial contribution and API * */ -public class BlueZBluetoothDevice extends BluetoothDevice { +public class BlueZBluetoothDevice extends BaseBluetoothDevice { private tinyb.BluetoothDevice device; @@ -113,12 +113,14 @@ public synchronized void updateTinybDevice(tinyb.BluetoothDevice tinybDevice) { private void enableNotifications() { logger.debug("Enabling notifications for device '{}'", device.getAddress()); device.enableRSSINotifications(n -> { + updateLastSeenTime(); rssi = (int) n; BluetoothScanNotification notification = new BluetoothScanNotification(); notification.setRssi(n); notifyListeners(BluetoothEventType.SCAN_RECORD, notification); }); device.enableManufacturerDataNotifications(n -> { + updateLastSeenTime(); for (Map.Entry entry : n.entrySet()) { BluetoothScanNotification notification = new BluetoothScanNotification(); byte[] data = new byte[entry.getValue().length + 2]; @@ -133,12 +135,14 @@ private void enableNotifications() { } }); device.enableConnectedNotifications(connected -> { + updateLastSeenTime(); connectionState = connected ? ConnectionState.CONNECTED : ConnectionState.DISCONNECTED; logger.debug("Connection state of '{}' changed to {}", address, connectionState); notifyListeners(BluetoothEventType.CONNECTION_STATE, new BluetoothConnectionStatusNotification(connectionState)); }); device.enableServicesResolvedNotifications(resolved -> { + updateLastSeenTime(); logger.debug("Received services resolved event for '{}': {}", address, resolved); if (resolved) { refreshServices(); @@ -146,6 +150,7 @@ private void enableNotifications() { } }); device.enableServiceDataNotifications(data -> { + updateLastSeenTime(); if (logger.isDebugEnabled()) { logger.debug("Received service data for '{}':", address); for (Map.Entry entry : data.entrySet()) { @@ -221,6 +226,11 @@ public boolean disconnect() { return false; } + @Override + public boolean discoverServices() { + return false; + } + private void ensureConnected() { if (device == null || !device.getConnected()) { throw new IllegalStateException("TinyB device is not set or not connected"); @@ -396,4 +406,5 @@ public void dispose() { } } } + } diff --git a/bundles/org.openhab.binding.bluetooth.blukii/src/main/java/org/openhab/binding/bluetooth/blukii/internal/BlukiiDiscoveryParticipant.java b/bundles/org.openhab.binding.bluetooth.blukii/src/main/java/org/openhab/binding/bluetooth/blukii/internal/BlukiiDiscoveryParticipant.java index bbbdb17076745..91a2d161ade38 100644 --- a/bundles/org.openhab.binding.bluetooth.blukii/src/main/java/org/openhab/binding/bluetooth/blukii/internal/BlukiiDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.bluetooth.blukii/src/main/java/org/openhab/binding/bluetooth/blukii/internal/BlukiiDiscoveryParticipant.java @@ -17,7 +17,7 @@ import java.util.Map; import java.util.Set; -import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; @@ -25,8 +25,8 @@ import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.bluetooth.BluetoothBindingConstants; -import org.openhab.binding.bluetooth.BluetoothDevice; import org.openhab.binding.bluetooth.blukii.BlukiiBindingConstants; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant; import org.osgi.service.component.annotations.Component; @@ -36,16 +36,17 @@ * @author Kai Kreuzer - Initial contribution and API * */ +@NonNullByDefault @Component(immediate = true) public class BlukiiDiscoveryParticipant implements BluetoothDiscoveryParticipant { @Override - public @NonNull Set<@NonNull ThingTypeUID> getSupportedThingTypeUIDs() { + public Set getSupportedThingTypeUIDs() { return Collections.singleton(BlukiiBindingConstants.THING_TYPE_BEACON); } @Override - public @Nullable ThingUID getThingUID(@NonNull BluetoothDevice device) { + public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device) { String name = device.getName(); if (name != null && name.startsWith(BlukiiBindingConstants.BLUKII_PREFIX)) { if (name.charAt(BlukiiBindingConstants.BLUKII_PREFIX.length()) == 'B') { @@ -57,7 +58,7 @@ public class BlukiiDiscoveryParticipant implements BluetoothDiscoveryParticipant } @Override - public DiscoveryResult createResult(@NonNull BluetoothDevice device) { + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { ThingUID thingUID = getThingUID(device); if (thingUID != null) { diff --git a/bundles/org.openhab.binding.bluetooth.ruuvitag/src/main/java/org/openhab/binding/bluetooth/ruuvitag/internal/RuuviTagDiscoveryParticipant.java b/bundles/org.openhab.binding.bluetooth.ruuvitag/src/main/java/org/openhab/binding/bluetooth/ruuvitag/internal/RuuviTagDiscoveryParticipant.java index baa91a226b87f..064bc90b80ce7 100644 --- a/bundles/org.openhab.binding.bluetooth.ruuvitag/src/main/java/org/openhab/binding/bluetooth/ruuvitag/internal/RuuviTagDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.bluetooth.ruuvitag/src/main/java/org/openhab/binding/bluetooth/ruuvitag/internal/RuuviTagDiscoveryParticipant.java @@ -25,7 +25,7 @@ import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.openhab.binding.bluetooth.BluetoothBindingConstants; -import org.openhab.binding.bluetooth.BluetoothDevice; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant; import org.osgi.service.component.annotations.Component; @@ -47,8 +47,7 @@ public Set getSupportedThingTypeUIDs() { } @Override - @Nullable - public ThingUID getThingUID(BluetoothDevice device) { + public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device) { Integer manufacturerId = device.getManufacturerId(); if (manufacturerId != null && manufacturerId == RUUVITAG_COMPANY_ID) { return new ThingUID(RuuviTagBindingConstants.THING_TYPE_BEACON, device.getAdapter().getUID(), @@ -58,8 +57,7 @@ public ThingUID getThingUID(BluetoothDevice device) { } @Override - @Nullable - public DiscoveryResult createResult(BluetoothDevice device) { + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { ThingUID thingUID = getThingUID(device); if (thingUID == null) { return null; diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BaseBluetoothDevice.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BaseBluetoothDevice.java new file mode 100644 index 0000000000000..bc5b58dd8351e --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BaseBluetoothDevice.java @@ -0,0 +1,350 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth; + +import java.time.ZonedDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.bluetooth.notification.BluetoothConnectionStatusNotification; +import org.openhab.binding.bluetooth.notification.BluetoothScanNotification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link BaseBluetoothDevice} implements parts of the BluetoothDevice functionality that is + * shared to all concrete BluetoothDevice implementations. + * + * @author Connor Petty - Initial Contribution + */ +@NonNullByDefault +public abstract class BaseBluetoothDevice extends BluetoothDevice { + + private final Logger logger = LoggerFactory.getLogger(BaseBluetoothDevice.class); + + /** + * Current connection state + */ + protected ConnectionState connectionState = ConnectionState.DISCOVERING; + + /** + * Manufacturer id + */ + protected @Nullable Integer manufacturer = null; + + /** + * Device name. + *

+ * Uses the devices long name if known, otherwise the short name if known + */ + protected @Nullable String name; + + /** + * List of supported services + */ + protected final Map supportedServices = new ConcurrentHashMap<>(); + + /** + * Last known RSSI + */ + protected @Nullable Integer rssi = null; + + /** + * Last reported transmitter power + */ + protected @Nullable Integer txPower = null; + + /** + * Last time when activity occurred on this device. + */ + protected ZonedDateTime lastSeenTime; + + /** + * The event listeners will be notified of device updates + */ + private final List eventListeners = new CopyOnWriteArrayList<>(); + + /** + * Construct a Bluetooth device taking the Bluetooth address + * + * @param adapter + * @param sender + */ + public BaseBluetoothDevice(BluetoothAdapter adapter, BluetoothAddress address) { + super(adapter, address); + this.lastSeenTime = ZonedDateTime.now(); + } + + /** + * Returns the last time this device was active + * + * @return The last time this device was active + */ + @Override + public ZonedDateTime getLastSeenTime() { + return lastSeenTime; + } + + /** + * Updates the last activity timestamp for this device. + * Should be called whenever activity occurs on this device. + * + */ + @Override + public void updateLastSeenTime() { + lastSeenTime = ZonedDateTime.now(); + } + + /** + * Returns the name of the Bluetooth device. + * + * @return The devices name + */ + @Override + public @Nullable String getName() { + return name; + } + + /** + * Sets the manufacturer id for the device + * + * @param manufacturer the manufacturer id + */ + public void setManufacturerId(int manufacturer) { + this.manufacturer = manufacturer; + } + + /** + * Returns the manufacturer ID of the device + * + * @return an integer with manufacturer ID of the device, or null if not known + */ + @Override + public @Nullable Integer getManufacturerId() { + return manufacturer; + } + + /** + * Returns a {@link BluetoothService} if the requested service is supported + * + * @return the {@link BluetoothService} or null if the service is not supported. + */ + @Override + public @Nullable BluetoothService getServices(UUID uuid) { + return supportedServices.get(uuid); + } + + /** + * Returns a list of supported service UUIDs + * + * @return list of supported {@link BluetoothService}s. + */ + @Override + public Collection getServices() { + return supportedServices.values(); + } + + /** + * Sets the device transmit power + * + * @param power the current transmitter power in dBm + */ + public void setTxPower(int txPower) { + this.txPower = txPower; + } + + /** + * Returns the last Transmit Power value or null if no transmit power has been received + * + * @return the last reported transmitter power value in dBm + */ + @Override + public @Nullable Integer getTxPower() { + return txPower; + } + + /** + * Sets the current Receive Signal Strength Indicator (RSSI) value + * + * @param rssi the current RSSI value in dBm + * @return true if the RSSI has changed, false if it was the same as previous + */ + public boolean setRssi(int rssi) { + boolean changed = (this.rssi == null || this.rssi != rssi); + this.rssi = rssi; + + return changed; + } + + /** + * Returns the last Receive Signal Strength Indicator (RSSI) value or null if no RSSI has been received + * + * @return the last RSSI value in dBm + */ + @Override + public @Nullable Integer getRssi() { + return rssi; + } + + /** + * Set the name of the device + * + * @param name a {@link String} defining the device name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Check if the device supports the specified service + * + * @param uuid the service {@link UUID} + * @return true if the service is supported + */ + @Override + public boolean supportsService(UUID uuid) { + return supportedServices.containsKey(uuid); + } + + /** + * Get the current connection state for this device + * + * @return the current {@link ConnectionState} + */ + @Override + public ConnectionState getConnectionState() { + return connectionState; + } + + /** + * Adds a service to the device. + * + * @param service the new {@link BluetoothService} to add + * @return true if the service was added or false if the service was already supported + */ + @Override + protected boolean addService(BluetoothService service) { + BluetoothService oldValue = supportedServices.putIfAbsent(service.getUuid(), service); + if (oldValue == null) { + logger.trace("Adding new service to device {}: {}", address, service); + return true; + } + return false; + } + + /** + * Adds a device listener + * + * @param listener the {@link BluetoothDeviceListener} to add + */ + @Override + public void addListener(BluetoothDeviceListener listener) { + eventListeners.add(listener); + } + + /** + * Removes a device listener + * + * @param listener the {@link BluetoothDeviceListener} to remove + */ + @Override + public void removeListener(BluetoothDeviceListener listener) { + eventListeners.remove(listener); + } + + /** + * Checks if this device has any listeners + * + * @return true if this device has listeners + */ + @Override + public boolean hasListeners() { + return !eventListeners.isEmpty(); + } + + /** + * Releases resources that this device is using. + * + */ + @Override + protected void dispose() { + + } + + /** + * Notify the listeners of an event + * + * @param event the {@link BluetoothEventType} of this event + * @param args an array of arguments to pass to the callback + */ + @Override + protected void notifyListeners(BluetoothEventType event, Object... args) { + for (BluetoothDeviceListener listener : eventListeners) { + try { + switch (event) { + case SCAN_RECORD: + listener.onScanRecordReceived((BluetoothScanNotification) args[0]); + break; + case CONNECTION_STATE: + listener.onConnectionStateChange((BluetoothConnectionStatusNotification) args[0]); + break; + case SERVICES_DISCOVERED: + listener.onServicesDiscovered(); + break; + case CHARACTERISTIC_READ_COMPLETE: + listener.onCharacteristicReadComplete((BluetoothCharacteristic) args[0], + (BluetoothCompletionStatus) args[1]); + break; + case CHARACTERISTIC_WRITE_COMPLETE: + listener.onCharacteristicWriteComplete((BluetoothCharacteristic) args[0], + (BluetoothCompletionStatus) args[1]); + break; + case CHARACTERISTIC_UPDATED: + listener.onCharacteristicUpdate((BluetoothCharacteristic) args[0]); + break; + case DESCRIPTOR_UPDATED: + listener.onDescriptorUpdate((BluetoothDescriptor) args[0]); + break; + } + } catch (Exception e) { + logger.error("Failed to inform listener '{}': {}", listener, e.getMessage(), e); + } + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("BluetoothDevice [address="); + builder.append(address); + builder.append(", manufacturer="); + builder.append(manufacturer); + if (BluetoothCompanyIdentifiers.get(manufacturer) != null) { + builder.append(" ("); + builder.append(BluetoothCompanyIdentifiers.get(manufacturer)); + builder.append(')'); + } + builder.append(", name="); + builder.append(name); + builder.append(", rssi="); + builder.append(rssi); + builder.append(']'); + return builder.toString(); + } +} diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BeaconBluetoothHandler.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BeaconBluetoothHandler.java index 9226c4862dbb8..993ca12f80ae9 100644 --- a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BeaconBluetoothHandler.java +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BeaconBluetoothHandler.java @@ -15,6 +15,7 @@ import java.util.concurrent.locks.ReentrantLock; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.ChannelUID; @@ -115,14 +116,17 @@ public void handleCommand(ChannelUID channelUID, Command command) { */ protected void updateRSSI() { if (device != null) { - Integer rssi = device.getRssi(); - if (rssi != null && rssi != 0) { - updateState(BluetoothBindingConstants.CHANNEL_TYPE_RSSI, new DecimalType(rssi)); - updateStatusBasedOnRssi(true); - } else { - updateState(BluetoothBindingConstants.CHANNEL_TYPE_RSSI, UnDefType.NULL); - updateStatusBasedOnRssi(false); - } + updateRSSI(device.getRssi()); + } + } + + private void updateRSSI(@Nullable Integer rssi) { + if (rssi != null && rssi != 0) { + updateState(BluetoothBindingConstants.CHANNEL_TYPE_RSSI, new DecimalType(rssi)); + updateStatusBasedOnRssi(true); + } else { + updateState(BluetoothBindingConstants.CHANNEL_TYPE_RSSI, UnDefType.NULL); + updateStatusBasedOnRssi(false); } } @@ -144,8 +148,7 @@ protected void updateStatusBasedOnRssi(boolean receivedSignal) { public void onScanRecordReceived(BluetoothScanNotification scanNotification) { int rssi = scanNotification.getRssi(); if (rssi != Integer.MIN_VALUE) { - device.setRssi(rssi); - updateRSSI(); + updateRSSI(rssi); } } diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BluetoothDevice.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BluetoothDevice.java index a972cd82ed820..3459da0371324 100644 --- a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BluetoothDevice.java +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/BluetoothDevice.java @@ -14,18 +14,11 @@ import java.time.ZonedDateTime; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.UUID; -import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.bluetooth.notification.BluetoothConnectionStatusNotification; -import org.openhab.binding.bluetooth.notification.BluetoothScanNotification; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The {@link BluetoothDevice} class provides a base implementation of a Bluetooth Low Energy device @@ -36,8 +29,6 @@ @NonNullByDefault public abstract class BluetoothDevice { - private final Logger logger = LoggerFactory.getLogger(BluetoothDevice.class); - /** * Enumeration of Bluetooth connection states * @@ -79,11 +70,6 @@ protected enum BluetoothEventType { SERVICES_DISCOVERED } - /** - * Current connection state - */ - protected ConnectionState connectionState = ConnectionState.DISCOVERING; - /** * The adapter the device is accessed through */ @@ -94,49 +80,6 @@ protected enum BluetoothEventType { */ protected final BluetoothAddress address; - /** - * Manufacturer id - */ - protected @Nullable Integer manufacturer = null; - - /** - * Device name. - *

- * Uses the devices long name if known, otherwise the short name if known - */ - protected @Nullable String name; - - protected @Nullable String model; - protected @Nullable String serialNumber; - protected @Nullable String hardwareRevision; - protected @Nullable String firmwareRevision; - protected @Nullable String softwareRevision; - - /** - * List of supported services - */ - protected final Map supportedServices = new HashMap<>(); - - /** - * Last known RSSI - */ - protected @Nullable Integer rssi = null; - - /** - * Last reported transmitter power - */ - protected @Nullable Integer txPower = null; - - /** - * Last time when activity occurred on this device. - */ - protected ZonedDateTime lastSeenTime; - - /** - * The event listeners will be notified of device updates - */ - private final List eventListeners = new CopyOnWriteArrayList<>(); - /** * Construct a Bluetooth device taking the Bluetooth address * @@ -146,7 +89,6 @@ protected enum BluetoothEventType { public BluetoothDevice(BluetoothAdapter adapter, BluetoothAddress address) { this.address = address; this.adapter = adapter; - this.lastSeenTime = ZonedDateTime.now(); } /** @@ -154,72 +96,42 @@ public BluetoothDevice(BluetoothAdapter adapter, BluetoothAddress address) { * * @return The last time this device was active */ - public ZonedDateTime getLastSeenTime() { - return lastSeenTime; - } + public abstract ZonedDateTime getLastSeenTime(); /** * Updates the last activity timestamp for this device. * Should be called whenever activity occurs on this device. * */ - public void updateLastSeenTime() { - lastSeenTime = ZonedDateTime.now(); - } + public abstract void updateLastSeenTime(); /** * Returns the name of the Bluetooth device. * * @return The devices name */ - public @Nullable String getName() { - return name; - } + public abstract @Nullable String getName(); /** - * Returns the model of the Bluetooth device. - * - * @return The devices model, null if not known - */ - public @Nullable String getModel() { - return model; - } - - /** - * Returns the serial number of the Bluetooth device. - * - * @return The serial model, null if not known - */ - public @Nullable String getSerialNumber() { - return serialNumber; - } - - /** - * Returns the hardware revision of the Bluetooth device. + * Returns the manufacturer ID of the device * - * @return The hardware revision, null if not known + * @return an integer with manufacturer ID of the device, or null if not known */ - public @Nullable String getHardwareRevision() { - return hardwareRevision; - } + public abstract @Nullable Integer getManufacturerId(); /** - * Returns the firmware revision of the Bluetooth device. + * Returns the last Transmit Power value or null if no transmit power has been received * - * @return The firmware revision, null if not known + * @return the last reported transmitter power value in dBm */ - public @Nullable String getFirmwareRevision() { - return firmwareRevision; - } + public abstract @Nullable Integer getTxPower(); /** - * Returns the software revision of the Bluetooth device. + * Returns the last Receive Signal Strength Indicator (RSSI) value or null if no RSSI has been received * - * @return The software revision, null if not known + * @return the last RSSI value in dBm */ - public @Nullable String getSoftwareRevision() { - return softwareRevision; - } + public abstract @Nullable Integer getRssi(); /** * Returns the physical address of the device. @@ -239,135 +151,19 @@ public BluetoothAdapter getAdapter() { return adapter; } - /** - * Sets the manufacturer id for the device - * - * @param manufacturer the manufacturer id - */ - public void setManufacturerId(int manufacturer) { - this.manufacturer = manufacturer; - } - - /** - * Returns the manufacturer ID of the device - * - * @return an integer with manufacturer ID of the device, or null if not known - */ - public @Nullable Integer getManufacturerId() { - return manufacturer; - } - /** * Returns a {@link BluetoothService} if the requested service is supported * * @return the {@link BluetoothService} or null if the service is not supported. */ - public @Nullable BluetoothService getServices(UUID uuid) { - return supportedServices.get(uuid); - } + public abstract @Nullable BluetoothService getServices(UUID uuid); /** * Returns a list of supported service UUIDs * * @return list of supported {@link BluetoothService}s. */ - public Collection getServices() { - return supportedServices.values(); - } - - /** - * Sets the device transmit power - * - * @param power the current transmitter power in dBm - */ - public void setTxPower(int txPower) { - this.txPower = txPower; - } - - /** - * Returns the last Transmit Power value or null if no transmit power has been received - * - * @return the last reported transmitter power value in dBm - */ - public @Nullable Integer getTxPower() { - return txPower; - } - - /** - * Sets the current Receive Signal Strength Indicator (RSSI) value - * - * @param rssi the current RSSI value in dBm - * @return true if the RSSI has changed, false if it was the same as previous - */ - public boolean setRssi(int rssi) { - boolean changed = (this.rssi == null || this.rssi != rssi); - this.rssi = rssi; - - return changed; - } - - /** - * Returns the last Receive Signal Strength Indicator (RSSI) value or null if no RSSI has been received - * - * @return the last RSSI value in dBm - */ - public @Nullable Integer getRssi() { - return rssi; - } - - /** - * Set the name of the device - * - * @param name a {@link String} defining the device name - */ - public void setName(String name) { - this.name = name; - } - - /** - * Set the model of the device - * - * @param model a {@link String} defining the device model - */ - public void setModel(String model) { - this.model = model; - } - - /** - * Set the serial number of the device - * - * @param model a {@link String} defining the serial number - */ - public void setSerialNumberl(String serialNumber) { - this.serialNumber = serialNumber; - } - - /** - * Set the hardware revision of the device - * - * @param model a {@link String} defining the hardware revision - */ - public void setHardwareRevision(String hardwareRevision) { - this.hardwareRevision = hardwareRevision; - } - - /** - * Set the firmware revision of the device - * - * @param model a {@link String} defining the firmware revision - */ - public void setFirmwareRevision(String firmwareRevision) { - this.firmwareRevision = firmwareRevision; - } - - /** - * Set the software revision of the device - * - * @param model a {@link String} defining the software revision - */ - public void setSoftwareRevision(String softwareRevision) { - this.softwareRevision = softwareRevision; - } + public abstract Collection getServices(); /** * Check if the device supports the specified service @@ -375,18 +171,14 @@ public void setSoftwareRevision(String softwareRevision) { * @param uuid the service {@link UUID} * @return true if the service is supported */ - public boolean supportsService(UUID uuid) { - return supportedServices.containsKey(uuid); - } + public abstract boolean supportsService(UUID uuid); /** * Get the current connection state for this device * * @return the current {@link ConnectionState} */ - public ConnectionState getConnectionState() { - return connectionState; - } + public abstract ConnectionState getConnectionState(); /** * Connects to a device. This is an asynchronous method. Once the connection state is updated, the @@ -396,9 +188,7 @@ public ConnectionState getConnectionState() { * * @return true if the connection process is started successfully */ - public boolean connect() { - return false; - } + public abstract boolean connect(); /** * Disconnects from a device. Once the connection state is updated, the @@ -409,9 +199,7 @@ public boolean connect() { * * @return true if the disconnection process is started successfully */ - public boolean disconnect() { - return false; - } + public abstract boolean disconnect(); /** * Starts a discovery on a device. This will iterate through all services and characteristics to build up a view of @@ -421,9 +209,7 @@ public boolean disconnect() { * * @return true if the discovery process is started successfully */ - public boolean discoverServices() { - return false; - } + public abstract boolean discoverServices(); /** * Gets a Bluetooth characteristic if it is known. @@ -436,7 +222,7 @@ public boolean discoverServices() { * @return the {@link BluetoothCharacteristic} or null if the characteristic is not found in the device */ public @Nullable BluetoothCharacteristic getCharacteristic(UUID uuid) { - for (BluetoothService service : supportedServices.values()) { + for (BluetoothService service : getServices()) { if (service.providesCharacteristic(uuid)) { return service.getCharacteristic(uuid); } @@ -457,9 +243,7 @@ public boolean discoverServices() { * @param characteristic the {@link BluetoothCharacteristic} to read. * @return true if the characteristic read is started successfully */ - public boolean readCharacteristic(BluetoothCharacteristic characteristic) { - return false; - } + public abstract boolean readCharacteristic(BluetoothCharacteristic characteristic); /** * Writes a characteristic. Only a single read or write operation can be requested at once. Attempting to perform an @@ -471,9 +255,7 @@ public boolean readCharacteristic(BluetoothCharacteristic characteristic) { * @param characteristic the {@link BluetoothCharacteristic} to read. * @return true if the characteristic write is started successfully */ - public boolean writeCharacteristic(BluetoothCharacteristic characteristic) { - return false; - } + public abstract boolean writeCharacteristic(BluetoothCharacteristic characteristic); /** * Enables notifications for a characteristic. Only a single read or write operation can be requested at once. @@ -485,9 +267,7 @@ public boolean writeCharacteristic(BluetoothCharacteristic characteristic) { * @param characteristic the {@link BluetoothCharacteristic} to receive notifications for. * @return true if the characteristic notification is started successfully */ - public boolean enableNotifications(BluetoothCharacteristic characteristic) { - return false; - } + public abstract boolean enableNotifications(BluetoothCharacteristic characteristic); /** * Disables notifications for a characteristic. Only a single read or write operation can be requested at once. @@ -497,9 +277,7 @@ public boolean enableNotifications(BluetoothCharacteristic characteristic) { * @param characteristic the {@link BluetoothCharacteristic} to disable notifications for. * @return true if the characteristic notification is stopped successfully */ - public boolean disableNotifications(BluetoothCharacteristic characteristic) { - return false; - } + public abstract boolean disableNotifications(BluetoothCharacteristic characteristic); /** * Enables notifications for a descriptor. Only a single read or write operation can be requested at once. @@ -511,9 +289,7 @@ public boolean disableNotifications(BluetoothCharacteristic characteristic) { * @param descriptor the {@link BluetoothDescriptor} to receive notifications for. * @return true if the descriptor notification is started successfully */ - public boolean enableNotifications(BluetoothDescriptor descriptor) { - return false; - } + public abstract boolean enableNotifications(BluetoothDescriptor descriptor); /** * Disables notifications for a descriptor. Only a single read or write operation can be requested at once. @@ -523,9 +299,7 @@ public boolean enableNotifications(BluetoothDescriptor descriptor) { * @param descriptor the {@link BluetoothDescriptor} to disable notifications for. * @return true if the descriptor notification is stopped successfully */ - public boolean disableNotifications(BluetoothDescriptor descriptor) { - return false; - } + public abstract boolean disableNotifications(BluetoothDescriptor descriptor); /** * Adds a service to the device. @@ -533,14 +307,7 @@ public boolean disableNotifications(BluetoothDescriptor descriptor) { * @param service the new {@link BluetoothService} to add * @return true if the service was added or false if the service was already supported */ - protected boolean addService(BluetoothService service) { - if (supportedServices.containsKey(service.getUuid())) { - return false; - } - logger.trace("Adding new service to device {}: {}", address, service); - supportedServices.put(service.getUuid(), service); - return true; - } + protected abstract boolean addService(BluetoothService service); /** * Adds a list of services to the device @@ -567,11 +334,9 @@ protected void addServices(List uuids) { * @return the {@link BluetoothService} or null if the service was not found */ protected @Nullable BluetoothService getServiceByHandle(int handle) { - synchronized (supportedServices) { - for (BluetoothService service : supportedServices.values()) { - if (service.getHandleStart() <= handle && service.getHandleEnd() >= handle) { - return service; - } + for (BluetoothService service : getServices()) { + if (service.getHandleStart() <= handle && service.getHandleEnd() >= handle) { + return service; } } return null; @@ -588,7 +353,6 @@ protected void addServices(List uuids) { if (service != null) { return service.getCharacteristicByHandle(handle); } - return null; } @@ -597,34 +361,27 @@ protected void addServices(List uuids) { * * @param listener the {@link BluetoothDeviceListener} to add */ - public void addListener(BluetoothDeviceListener listener) { - eventListeners.add(listener); - } + public abstract void addListener(BluetoothDeviceListener listener); /** * Removes a device listener * * @param listener the {@link BluetoothDeviceListener} to remove */ - public void removeListener(BluetoothDeviceListener listener) { - eventListeners.remove(listener); - } + public abstract void removeListener(BluetoothDeviceListener listener); /** * Checks if this device has any listeners * * @return true if this device has listeners */ - public boolean hasListeners() { - return !eventListeners.isEmpty(); - } + public abstract boolean hasListeners(); /** * Releases resources that this device is using. * */ - protected void dispose() { - } + protected abstract void dispose(); /** * Notify the listeners of an event @@ -632,67 +389,6 @@ protected void dispose() { * @param event the {@link BluetoothEventType} of this event * @param args an array of arguments to pass to the callback */ - protected void notifyListeners(BluetoothEventType event, Object... args) { - for (BluetoothDeviceListener listener : eventListeners) { - try { - switch (event) { - case SCAN_RECORD: - listener.onScanRecordReceived((BluetoothScanNotification) args[0]); - break; - case CONNECTION_STATE: - listener.onConnectionStateChange((BluetoothConnectionStatusNotification) args[0]); - break; - case SERVICES_DISCOVERED: - listener.onServicesDiscovered(); - break; - case CHARACTERISTIC_READ_COMPLETE: - listener.onCharacteristicReadComplete((BluetoothCharacteristic) args[0], - (BluetoothCompletionStatus) args[1]); - break; - case CHARACTERISTIC_WRITE_COMPLETE: - listener.onCharacteristicWriteComplete((BluetoothCharacteristic) args[0], - (BluetoothCompletionStatus) args[1]); - break; - case CHARACTERISTIC_UPDATED: - listener.onCharacteristicUpdate((BluetoothCharacteristic) args[0]); - break; - case DESCRIPTOR_UPDATED: - listener.onDescriptorUpdate((BluetoothDescriptor) args[0]); - break; - } - } catch (Exception e) { - logger.error("Failed to inform listener '{}': {}", listener, e.getMessage(), e); - } - } - } + protected abstract void notifyListeners(BluetoothEventType event, Object... args); - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("BluetoothDevice [address="); - builder.append(address); - builder.append(", manufacturer="); - builder.append(manufacturer); - if (BluetoothCompanyIdentifiers.get(manufacturer) != null) { - builder.append(" ("); - builder.append(BluetoothCompanyIdentifiers.get(manufacturer)); - builder.append(')'); - } - builder.append(", name="); - builder.append(name); - builder.append(", model="); - builder.append(model); - builder.append(", serialNumber="); - builder.append(serialNumber); - builder.append(", hardwareRevision="); - builder.append(hardwareRevision); - builder.append(", firmwareRevision="); - builder.append(firmwareRevision); - builder.append(", softwareRevision="); - builder.append(softwareRevision); - builder.append(", rssi="); - builder.append(rssi); - builder.append(']'); - return builder.toString(); - } } diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/DelegateBluetoothDevice.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/DelegateBluetoothDevice.java new file mode 100644 index 0000000000000..53a746b51bd20 --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/DelegateBluetoothDevice.java @@ -0,0 +1,167 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth; + +import java.time.ZonedDateTime; +import java.util.Collection; +import java.util.UUID; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link DelegateBluetoothDevice} is an abstract parent class for BluetoothDevice implementations + * that delegate their functions to other BluetoothDevice instances. + * + * @author Connor Petty - Initial Contribution + */ +@NonNullByDefault +public abstract class DelegateBluetoothDevice extends BluetoothDevice { + + public DelegateBluetoothDevice(BluetoothAdapter adapter, BluetoothAddress address) { + super(adapter, address); + } + + protected abstract BluetoothDevice getDelegate(); + + @Override + public ZonedDateTime getLastSeenTime() { + return getDelegate().getLastSeenTime(); + } + + @Override + public void updateLastSeenTime() { + getDelegate().updateLastSeenTime(); + } + + @Override + public @Nullable String getName() { + return getDelegate().getName(); + } + + @Override + public @Nullable Integer getManufacturerId() { + return getDelegate().getManufacturerId(); + } + + @Override + public @Nullable Integer getRssi() { + return getDelegate().getRssi(); + } + + @Override + public @Nullable Integer getTxPower() { + return getDelegate().getTxPower(); + } + + @Override + public @Nullable BluetoothService getServices(UUID uuid) { + return getDelegate().getServices(uuid); + } + + @Override + public Collection getServices() { + return getDelegate().getServices(); + } + + @Override + public boolean supportsService(UUID uuid) { + return getDelegate().supportsService(uuid); + } + + @Override + public ConnectionState getConnectionState() { + return getDelegate().getConnectionState(); + } + + @Override + public boolean connect() { + return getDelegate().connect(); + } + + @Override + public boolean disconnect() { + return getDelegate().disconnect(); + } + + @Override + public boolean discoverServices() { + return getDelegate().discoverServices(); + } + + @Override + public boolean readCharacteristic(BluetoothCharacteristic characteristic) { + return getDelegate().readCharacteristic(characteristic); + } + + @Override + public boolean writeCharacteristic(BluetoothCharacteristic characteristic) { + return getDelegate().writeCharacteristic(characteristic); + } + + @Override + public boolean enableNotifications(BluetoothCharacteristic characteristic) { + return getDelegate().enableNotifications(characteristic); + } + + @Override + public boolean disableNotifications(BluetoothCharacteristic characteristic) { + return getDelegate().disableNotifications(characteristic); + } + + @Override + public boolean enableNotifications(BluetoothDescriptor descriptor) { + return getDelegate().enableNotifications(descriptor); + } + + @Override + public boolean disableNotifications(BluetoothDescriptor descriptor) { + return getDelegate().disableNotifications(descriptor); + } + + @Override + protected boolean addService(BluetoothService service) { + return getDelegate().addService(service); + } + + @Override + public void addListener(BluetoothDeviceListener listener) { + getDelegate().addListener(listener); + } + + @Override + public void removeListener(BluetoothDeviceListener listener) { + getDelegate().removeListener(listener); + } + + @Override + public boolean hasListeners() { + return getDelegate().hasListeners(); + } + + @Override + protected void notifyListeners(BluetoothEventType event, Object... args) { + getDelegate().notifyListeners(event, args); + } + + @Override + public @Nullable BluetoothCharacteristic getCharacteristic(UUID uuid) { + return getDelegate().getCharacteristic(uuid); + } + + @Override + protected void dispose() { + getDelegate().dispose(); + } + +} diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryDevice.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryDevice.java new file mode 100644 index 0000000000000..bd0ef1aade4bb --- /dev/null +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryDevice.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2010-2020 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.bluetooth.discovery; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.bluetooth.BluetoothCompanyIdentifiers; +import org.openhab.binding.bluetooth.BluetoothDevice; +import org.openhab.binding.bluetooth.DelegateBluetoothDevice; + +/** + * The {@link BluetoothDiscoveryDevice} is the BluetoothDevice subclass passed to + * BluetoothDiscoveryParticipants as part of discovery. It includes extra fields + * provided for the convenience of participant implementations. + * + * @author Connor Petty - Initial Contribution + */ +@NonNullByDefault +public class BluetoothDiscoveryDevice extends DelegateBluetoothDevice { + + private BluetoothDevice delegate; + + protected @Nullable String model; + protected @Nullable String serialNumber; + protected @Nullable String hardwareRevision; + protected @Nullable String firmwareRevision; + protected @Nullable String softwareRevision; + + public BluetoothDiscoveryDevice(BluetoothDevice device) { + super(device.getAdapter(), device.getAddress()); + this.delegate = device; + } + + @Override + protected BluetoothDevice getDelegate() { + return delegate; + } + + /** + * Returns the model of the Bluetooth device. + * + * @return The devices model, null if not known + */ + public @Nullable String getModel() { + return model; + } + + /** + * Returns the serial number of the Bluetooth device. + * + * @return The serial model, null if not known + */ + public @Nullable String getSerialNumber() { + return serialNumber; + } + + /** + * Returns the hardware revision of the Bluetooth device. + * + * @return The hardware revision, null if not known + */ + public @Nullable String getHardwareRevision() { + return hardwareRevision; + } + + /** + * Returns the firmware revision of the Bluetooth device. + * + * @return The firmware revision, null if not known + */ + public @Nullable String getFirmwareRevision() { + return firmwareRevision; + } + + /** + * Returns the software revision of the Bluetooth device. + * + * @return The software revision, null if not known + */ + public @Nullable String getSoftwareRevision() { + return softwareRevision; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("BluetoothDevice [address="); + builder.append(address); + builder.append(", manufacturer="); + + Integer manufacturer = getManufacturerId(); + builder.append(manufacturer); + if (BluetoothCompanyIdentifiers.get(manufacturer) != null) { + builder.append(" ("); + builder.append(BluetoothCompanyIdentifiers.get(manufacturer)); + builder.append(')'); + } + builder.append(", name="); + builder.append(getName()); + builder.append(", model="); + builder.append(model); + builder.append(", serialNumber="); + builder.append(serialNumber); + builder.append(", hardwareRevision="); + builder.append(hardwareRevision); + builder.append(", firmwareRevision="); + builder.append(firmwareRevision); + builder.append(", softwareRevision="); + builder.append(softwareRevision); + builder.append(", rssi="); + builder.append(getRssi()); + builder.append(']'); + return builder.toString(); + } +} diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryParticipant.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryParticipant.java index 48a71d29b1ffc..794bfed7e5a0c 100644 --- a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/BluetoothDiscoveryParticipant.java @@ -19,7 +19,6 @@ import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; -import org.openhab.binding.bluetooth.BluetoothDevice; /** * A {@link BluetoothDiscoveryParticipant} that is registered as a service is picked up by the BluetoothDiscoveryService @@ -45,7 +44,7 @@ public interface BluetoothDiscoveryParticipant { * @return the according discovery result or null, if device is not * supported by this participant */ - public @Nullable DiscoveryResult createResult(BluetoothDevice device); + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device); /** * Returns the thing UID for a Bluetooth device @@ -53,7 +52,7 @@ public interface BluetoothDiscoveryParticipant { * @param device the Bluetooth device * @return a thing UID or null, if the device is not supported by this participant */ - public @Nullable ThingUID getThingUID(BluetoothDevice device); + public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device); /** * Returns true if this participant requires the device to be connected before it can produce a @@ -69,7 +68,7 @@ public interface BluetoothDiscoveryParticipant { * @param device the Bluetooth device * @return true if a connection is required before calling {@link createResult(BluetoothDevice)} */ - public default boolean requiresConnection(BluetoothDevice device) { + public default boolean requiresConnection(BluetoothDiscoveryDevice device) { return false; } } diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDeviceSnapshot.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDeviceSnapshot.java index d4df3a9efe0d9..648e4896fb885 100644 --- a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDeviceSnapshot.java +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDeviceSnapshot.java @@ -12,18 +12,13 @@ */ package org.openhab.binding.bluetooth.discovery.internal; -import java.util.Collection; import java.util.Objects; -import java.util.UUID; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.bluetooth.BluetoothAddress; -import org.openhab.binding.bluetooth.BluetoothCharacteristic; -import org.openhab.binding.bluetooth.BluetoothDescriptor; import org.openhab.binding.bluetooth.BluetoothDevice; -import org.openhab.binding.bluetooth.BluetoothDeviceListener; -import org.openhab.binding.bluetooth.BluetoothService; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; /** * The {@link BluetoothDeviceSnapshot} acts as a dummy {@link BluetoothDevice} implementation that simply acts as a @@ -32,106 +27,114 @@ * @author Connor Petty - Initial Contribution */ @NonNullByDefault -public class BluetoothDeviceSnapshot extends BluetoothDevice { +public class BluetoothDeviceSnapshot extends BluetoothDiscoveryDevice { - private BluetoothDevice delegate; + private @Nullable String name; + private @Nullable Integer manufacturer; + private @Nullable Integer txPower; public BluetoothDeviceSnapshot(BluetoothDevice device) { - super(device.getAdapter(), device.getAddress()); - this.delegate = device; + super(device); this.txPower = device.getTxPower(); this.manufacturer = device.getManufacturerId(); this.name = device.getName(); - this.model = device.getModel(); - this.serialNumber = device.getSerialNumber(); - this.hardwareRevision = device.getHardwareRevision(); - this.firmwareRevision = device.getFirmwareRevision(); - this.softwareRevision = device.getSoftwareRevision(); } @Override - public boolean connect() { - return delegate.connect(); + public @Nullable String getName() { + return name; } - @Override - public boolean disconnect() { - return delegate.disconnect(); - } - - @Override - public boolean enableNotifications(BluetoothCharacteristic characteristic) { - return delegate.enableNotifications(characteristic); - } - - @Override - public boolean enableNotifications(BluetoothDescriptor descriptor) { - return delegate.enableNotifications(descriptor); - } - - @Override - public boolean disableNotifications(BluetoothCharacteristic characteristic) { - return delegate.disableNotifications(characteristic); - } - - @Override - public boolean disableNotifications(BluetoothDescriptor descriptor) { - return delegate.disableNotifications(descriptor); - } - - @Override - public boolean discoverServices() { - return delegate.discoverServices(); - } - - @Override - public void addListener(BluetoothDeviceListener listener) { - delegate.addListener(listener); + /** + * Set the name of the device + * + * @param name a {@link String} defining the device name + */ + public void setName(String name) { + this.name = name; } - @Override - public void removeListener(BluetoothDeviceListener listener) { - delegate.removeListener(listener); + /** + * Sets the manufacturer id for the device + * + * @param manufacturer the manufacturer id + */ + public void setManufacturerId(int manufacturer) { + this.manufacturer = manufacturer; } + /** + * Returns the manufacturer ID of the device + * + * @return an integer with manufacturer ID of the device, or null if not known + */ @Override - public ConnectionState getConnectionState() { - return delegate.getConnectionState(); + public @Nullable Integer getManufacturerId() { + return manufacturer; } - @Override - public Collection getServices() { - return delegate.getServices(); + /** + * Sets the device transmit power + * + * @param power the current transmitter power in dBm + */ + public void setTxPower(int txPower) { + this.txPower = txPower; } + /** + * Returns the last Transmit Power value or null if no transmit power has been received + * + * @return the last reported transmitter power value in dBm + */ @Override - public @Nullable BluetoothService getServices(UUID uuid) { - return delegate.getServices(uuid); + public @Nullable Integer getTxPower() { + return txPower; } - @Override - public @Nullable BluetoothCharacteristic getCharacteristic(UUID uuid) { - return delegate.getCharacteristic(uuid); + /** + * Set the model of the device + * + * @param model a {@link String} defining the device model + */ + public void setModel(String model) { + this.model = model; } - @Override - public boolean hasListeners() { - return delegate.hasListeners(); + /** + * Set the serial number of the device + * + * @param model a {@link String} defining the serial number + */ + public void setSerialNumberl(String serialNumber) { + this.serialNumber = serialNumber; } - @Override - public boolean supportsService(UUID uuid) { - return delegate.supportsService(uuid); + /** + * Set the hardware revision of the device + * + * @param model a {@link String} defining the hardware revision + */ + public void setHardwareRevision(String hardwareRevision) { + this.hardwareRevision = hardwareRevision; } - @Override - public boolean readCharacteristic(BluetoothCharacteristic characteristic) { - return delegate.readCharacteristic(characteristic); + /** + * Set the firmware revision of the device + * + * @param model a {@link String} defining the firmware revision + */ + public void setFirmwareRevision(String firmwareRevision) { + this.firmwareRevision = firmwareRevision; } - @Override - public boolean writeCharacteristic(BluetoothCharacteristic characteristic) { - return delegate.writeCharacteristic(characteristic); + /** + * Set the software revision of the device + * + * @param model a {@link String} defining the software revision + */ + public void setSoftwareRevision(String softwareRevision) { + this.softwareRevision = softwareRevision; } @Override @@ -209,7 +212,7 @@ public boolean equals(@Nullable Object obj) { * * @return true if this snapshot changed as a result of this operation */ - public void merge(BluetoothDevice device) { + public void merge(BluetoothDeviceSnapshot device) { Integer txPower = device.getTxPower(); Integer manufacturer = device.getManufacturerId(); String name = device.getName(); diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryProcess.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryProcess.java index 2db45f0cfb088..8c2044aea3b41 100644 --- a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryProcess.java +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryProcess.java @@ -66,7 +66,7 @@ public class BluetoothDiscoveryProcess implements Supplier, Blu private final Condition serviceDiscoveryCondition = serviceDiscoveryLock.newCondition(); private final Condition infoDiscoveryCondition = serviceDiscoveryLock.newCondition(); - private final BluetoothDevice device; + private final BluetoothDeviceSnapshot device; private final Collection participants; private final Set adapters; @@ -77,8 +77,8 @@ public class BluetoothDiscoveryProcess implements Supplier, Blu */ private volatile @Nullable GattCharacteristic ongoingGattCharacteristic; - public BluetoothDiscoveryProcess(BluetoothDevice device, Collection participants, - Set adapters) { + public BluetoothDiscoveryProcess(BluetoothDeviceSnapshot device, + Collection participants, Set adapters) { this.participants = participants; this.device = device; this.adapters = adapters; diff --git a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryService.java b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryService.java index be47261ca34ba..41e898a0b6ab6 100644 --- a/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryService.java +++ b/bundles/org.openhab.binding.bluetooth/src/main/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryService.java @@ -269,7 +269,7 @@ private synchronized void createDiscoveryFuture(BluetoothDevice device) { discoveryFutures.put(adapter, new SnapshotFuture(snapshot, future)); } - private CompletableFuture startDiscoveryProcess(BluetoothDevice device) { + private CompletableFuture startDiscoveryProcess(BluetoothDeviceSnapshot device) { return CompletableFuture.supplyAsync(new BluetoothDiscoveryProcess(device, participants, adapters), scheduler); } diff --git a/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/MockBluetoothDevice.java b/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/MockBluetoothDevice.java index a2a3c32761859..689e11a031f19 100644 --- a/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/MockBluetoothDevice.java +++ b/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/MockBluetoothDevice.java @@ -15,6 +15,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; +import org.eclipse.jdt.annotation.NonNull; import org.openhab.binding.bluetooth.BluetoothCharacteristic.GattCharacteristic; import org.openhab.binding.bluetooth.notification.BluetoothConnectionStatusNotification; @@ -23,7 +24,7 @@ * * @author Connor Petty - Initial contribution */ -public class MockBluetoothDevice extends BluetoothDevice { +public class MockBluetoothDevice extends BaseBluetoothDevice { private AtomicBoolean servicesDiscovered = new AtomicBoolean(false); @@ -88,4 +89,30 @@ public void setDeviceName(String deviceName) { protected void notifyListeners(BluetoothEventType event, Object... args) { CompletableFuture.runAsync(() -> super.notifyListeners(event, args)); } + + @Override + public boolean writeCharacteristic(@NonNull BluetoothCharacteristic characteristic) { + return false; + } + + @Override + public boolean enableNotifications(@NonNull BluetoothCharacteristic characteristic) { + return false; + } + + @Override + public boolean disableNotifications(@NonNull BluetoothCharacteristic characteristic) { + return false; + } + + @Override + public boolean enableNotifications(@NonNull BluetoothDescriptor descriptor) { + return false; + } + + @Override + public boolean disableNotifications(@NonNull BluetoothDescriptor descriptor) { + return false; + } + } diff --git a/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryServiceTest.java b/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryServiceTest.java index e9ce8af3c9939..a82118d152e47 100644 --- a/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryServiceTest.java +++ b/bundles/org.openhab.binding.bluetooth/src/test/java/org/openhab/binding/bluetooth/discovery/internal/BluetoothDiscoveryServiceTest.java @@ -47,6 +47,7 @@ import org.openhab.binding.bluetooth.MockBluetoothAdapter; import org.openhab.binding.bluetooth.MockBluetoothDevice; import org.openhab.binding.bluetooth.TestUtils; +import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant; import org.openhab.binding.bluetooth.notification.BluetoothConnectionStatusNotification; import org.slf4j.Logger; @@ -112,8 +113,8 @@ public void ignoreOtherDuplicateTest() { @Test public void ignoreRssiDuplicateTest() { - BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); - BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); + MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); + MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); discoveryService.deviceDiscovered(device); // changing the rssi should not result in a new discovery device.setRssi(100); @@ -126,8 +127,8 @@ public void ignoreRssiDuplicateTest() { @Test public void nonDuplicateNameTest() throws InterruptedException { - BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); - BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); + MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); + MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); discoveryService.deviceDiscovered(device); // this second call should produce another result device.setName("sdfad"); @@ -140,8 +141,8 @@ public void nonDuplicateNameTest() throws InterruptedException { @Test public void nonDuplicateTxPowerTest() { - BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); - BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); + MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); + MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); discoveryService.deviceDiscovered(device); // this second call should produce another result device.setTxPower(10); @@ -154,8 +155,8 @@ public void nonDuplicateTxPowerTest() { @Test public void nonDuplicateManufacturerIdTest() { - BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); - BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); + MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); + MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); discoveryService.deviceDiscovered(device); // this second call should produce another result device.setManufacturerId(100); @@ -316,8 +317,8 @@ public void removeDefaultDeviceTest() { @Test public void removeUpdatedDefaultDeviceTest() { Mockito.doReturn(null).when(participant1).createResult(ArgumentMatchers.any()); - BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); - BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); + MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); + MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); discoveryService.deviceDiscovered(device); device.setName("somename"); discoveryService.deviceDiscovered(device); @@ -354,12 +355,12 @@ public void bluezConnectionTimeoutTest() { public void replaceOlderDiscoveryTest() { Mockito.doReturn(null).when(participant1).createResult(ArgumentMatchers.any()); - BluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); - BluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); + MockBluetoothAdapter mockAdapter1 = new MockBluetoothAdapter(); + MockBluetoothDevice device = mockAdapter1.getDevice(TestUtils.randomAddress()); MockDiscoveryParticipant participant2 = new MockDiscoveryParticipant() { @Override - public @Nullable DiscoveryResult createResult(BluetoothDevice device) { + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { Integer manufacturer = device.getManufacturerId(); if (manufacturer != null && manufacturer.equals(10)) { // without a device name it should produce a random ThingUID @@ -424,13 +425,13 @@ public void recursiveFutureTest() throws InterruptedException { MockDiscoveryParticipant participant2 = new MockDiscoveryParticipant() { @Override - public @Nullable DiscoveryResult createResult(BluetoothDevice device) { + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { try { pauseLatch.await(); } catch (InterruptedException e) { // do nothing } - device.setName(deviceName); + ((BluetoothDeviceSnapshot) device).setName(deviceName); callCount.incrementAndGet(); return super.createResult(device); } @@ -465,14 +466,14 @@ public Set getSupportedThingTypeUIDs() { } @Override - public @Nullable DiscoveryResult createResult(BluetoothDevice device) { + public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { return DiscoveryResultBuilder.create(getThingUID(device)).withLabel(RandomStringUtils.randomAlphabetic(6)) .withRepresentationProperty(RandomStringUtils.randomAlphabetic(6)) .withBridge(device.getAdapter().getUID()).build(); } @Override - public @NonNull ThingUID getThingUID(BluetoothDevice device) { + public @NonNull ThingUID getThingUID(BluetoothDiscoveryDevice device) { String id = device.getName() != null ? device.getName() : RandomStringUtils.randomAlphabetic(6); return new ThingUID(typeUID, device.getAdapter().getUID(), id); }