]> git.basschouten.com Git - openhab-addons.git/blob
d529eb68ecd830c901745850ced55f9fa0712d27
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.pulseaudio.internal.discovery;
14
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.regex.PatternSyntaxException;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.openhab.binding.pulseaudio.internal.PulseaudioBindingConstants;
23 import org.openhab.binding.pulseaudio.internal.handler.DeviceIdentifier;
24 import org.openhab.binding.pulseaudio.internal.handler.DeviceStatusListener;
25 import org.openhab.binding.pulseaudio.internal.handler.PulseaudioBridgeHandler;
26 import org.openhab.binding.pulseaudio.internal.handler.PulseaudioHandler;
27 import org.openhab.binding.pulseaudio.internal.items.AbstractAudioDeviceConfig;
28 import org.openhab.binding.pulseaudio.internal.items.Sink;
29 import org.openhab.binding.pulseaudio.internal.items.SinkInput;
30 import org.openhab.binding.pulseaudio.internal.items.Source;
31 import org.openhab.binding.pulseaudio.internal.items.SourceOutput;
32 import org.openhab.core.config.core.Configuration;
33 import org.openhab.core.config.discovery.AbstractDiscoveryService;
34 import org.openhab.core.config.discovery.DiscoveryResult;
35 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
36 import org.openhab.core.thing.Thing;
37 import org.openhab.core.thing.ThingTypeUID;
38 import org.openhab.core.thing.ThingUID;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * The {@link PulseaudioDeviceDiscoveryService} class is used to discover Pulseaudio
44  * devices on a Pulseaudio server.
45  *
46  * @author Tobias Bräutigam - Initial contribution
47  */
48 @NonNullByDefault
49 public class PulseaudioDeviceDiscoveryService extends AbstractDiscoveryService implements DeviceStatusListener {
50
51     private final Logger logger = LoggerFactory.getLogger(PulseaudioDeviceDiscoveryService.class);
52
53     private PulseaudioBridgeHandler pulseaudioBridgeHandler;
54
55     public PulseaudioDeviceDiscoveryService(PulseaudioBridgeHandler pulseaudioBridgeHandler) {
56         super(PulseaudioHandler.SUPPORTED_THING_TYPES_UIDS, 10, true);
57         this.pulseaudioBridgeHandler = pulseaudioBridgeHandler;
58     }
59
60     public void activate() {
61         pulseaudioBridgeHandler.registerDeviceStatusListener(this);
62     }
63
64     @Override
65     public void deactivate() {
66         pulseaudioBridgeHandler.unregisterDeviceStatusListener(this);
67     }
68
69     @Override
70     public Set<ThingTypeUID> getSupportedThingTypes() {
71         return PulseaudioHandler.SUPPORTED_THING_TYPES_UIDS;
72     }
73
74     @Override
75     public void onDeviceAdded(Thing bridge, AbstractAudioDeviceConfig device) {
76         if (getAlreadyConfiguredThings().stream().anyMatch(deviceIdentifier -> device.matches(deviceIdentifier))) {
77             return;
78         }
79
80         String uidName = device.getPaName();
81         logger.debug("device {} found", device);
82         ThingTypeUID thingType = null;
83         Map<String, Object> properties = new HashMap<>();
84         // All devices need this parameter
85         properties.put(PulseaudioBindingConstants.DEVICE_PARAMETER_NAME_OR_DESCRIPTION, uidName);
86         if (device instanceof Sink sink) {
87             if (sink.isCombinedSink()) {
88                 thingType = PulseaudioBindingConstants.COMBINED_SINK_THING_TYPE;
89             } else {
90                 thingType = PulseaudioBindingConstants.SINK_THING_TYPE;
91             }
92         } else if (device instanceof SinkInput) {
93             thingType = PulseaudioBindingConstants.SINK_INPUT_THING_TYPE;
94         } else if (device instanceof Source) {
95             thingType = PulseaudioBindingConstants.SOURCE_THING_TYPE;
96         } else if (device instanceof SourceOutput) {
97             thingType = PulseaudioBindingConstants.SOURCE_OUTPUT_THING_TYPE;
98         }
99
100         if (thingType != null) {
101             logger.trace("Adding new pulseaudio {} with name '{}' to inbox", device.getClass().getSimpleName(),
102                     uidName);
103             ThingUID thingUID = new ThingUID(thingType, bridge.getUID(), device.getUIDName());
104             DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
105                     .withBridge(bridge.getUID()).withLabel(device.getUIDName()).build();
106             thingDiscovered(discoveryResult);
107         }
108     }
109
110     public Set<DeviceIdentifier> getAlreadyConfiguredThings() {
111         Set<DeviceIdentifier> alreadyConfiguredThings = new HashSet<>();
112         for (Thing thing : pulseaudioBridgeHandler.getThing().getThings()) {
113             Configuration configuration = thing.getConfiguration();
114             try {
115                 alreadyConfiguredThings.add(new DeviceIdentifier(
116                         (String) configuration.get(PulseaudioBindingConstants.DEVICE_PARAMETER_NAME_OR_DESCRIPTION),
117                         (String) configuration.get(PulseaudioBindingConstants.DEVICE_PARAMETER_ADDITIONAL_FILTERS)));
118             } catch (PatternSyntaxException p) {
119                 logger.debug(
120                         "There is an error with an already configured things. Cannot compare with discovery, skipping it");
121             }
122         }
123         return alreadyConfiguredThings;
124     }
125
126     @Override
127     protected void startScan() {
128         pulseaudioBridgeHandler.resetKnownActiveDevices();
129     }
130 }