2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.bluetooth.bluez.internal;
15 import java.util.Collections;
16 import java.util.concurrent.Future;
17 import java.util.concurrent.TimeUnit;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.core.config.discovery.AbstractDiscoveryService;
22 import org.openhab.core.config.discovery.DiscoveryResult;
23 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
24 import org.openhab.core.config.discovery.DiscoveryService;
25 import org.openhab.core.thing.ThingUID;
26 import org.osgi.service.component.annotations.Activate;
27 import org.osgi.service.component.annotations.Component;
28 import org.osgi.service.component.annotations.Reference;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 import com.github.hypfvieh.bluetooth.wrapper.BluetoothAdapter;
35 * This is a discovery service, which checks whether we are running on a Linux with a BlueZ stack.
36 * If this is the case, we create a bridge handler that provides Bluetooth access through BlueZ.
38 * @author Kai Kreuzer - Initial Contribution and API
39 * @author Hilbrand Bouwkamp - Moved background scan to actual background method
40 * @author Connor Petty - Replaced tinyB with bluezDbus
44 @Component(service = DiscoveryService.class, configurationPid = "discovery.bluetooth.bluez")
45 public class BlueZDiscoveryService extends AbstractDiscoveryService {
47 private final Logger logger = LoggerFactory.getLogger(BlueZDiscoveryService.class);
49 private final DeviceManagerFactory deviceManagerFactory;
50 private @Nullable Future<?> backgroundScan;
53 public BlueZDiscoveryService(@Reference DeviceManagerFactory deviceManagerFactory) {
54 super(Collections.singleton(BlueZAdapterConstants.THING_TYPE_BLUEZ), 1, true);
55 this.deviceManagerFactory = deviceManagerFactory;
58 private static void cancel(@Nullable Future<?> future) {
65 protected void startBackgroundDiscovery() {
66 backgroundScan = scheduler.scheduleWithFixedDelay(() -> {
67 DeviceManagerWrapper deviceManager = deviceManagerFactory.getDeviceManager();
68 if (deviceManager == null) {
72 }, 5, 10, TimeUnit.SECONDS);
76 protected void stopBackgroundDiscovery() {
77 cancel(backgroundScan);
78 backgroundScan = null;
82 protected void startScan() {
83 DeviceManagerWrapper deviceManager = deviceManagerFactory.getDeviceManager();
84 if (deviceManager == null) {
85 logger.warn("The DeviceManager is not available");
88 // the first time the device manager is not null we can cancel background discovery
89 stopBackgroundDiscovery();
90 deviceManager.scanForBluetoothAdapters().stream()//
91 .map(this::createDiscoveryResult)//
92 .forEach(this::thingDiscovered);
95 private DiscoveryResult createDiscoveryResult(BluetoothAdapter adapter) {
96 return DiscoveryResultBuilder.create(new ThingUID(BlueZAdapterConstants.THING_TYPE_BLUEZ, getId(adapter)))
97 .withLabel("Bluetooth Interface " + adapter.getName())
98 .withProperty(BlueZAdapterConstants.PROPERTY_ADDRESS, adapter.getAddress())
99 .withRepresentationProperty(BlueZAdapterConstants.PROPERTY_ADDRESS).build();
102 private String getId(BluetoothAdapter adapter) {
103 return adapter.getDeviceName().replaceAll("[^a-zA-Z0-9_]", "");