2 * Copyright (c) 2010-2024 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.digitalstrom.internal.discovery;
15 import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.BINDING_ID;
16 import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.GROUP_ID;
17 import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.SCENE_ID;
18 import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.ZONE_ID;
20 import java.time.Instant;
21 import java.util.Arrays;
22 import java.util.HashMap;
23 import java.util.HashSet;
26 import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
27 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.ApplicationGroup;
28 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
29 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.constants.SceneEnum;
30 import org.openhab.core.config.discovery.AbstractDiscoveryService;
31 import org.openhab.core.config.discovery.DiscoveryResult;
32 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
33 import org.openhab.core.thing.ThingTypeUID;
34 import org.openhab.core.thing.ThingUID;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * The {@link SceneDiscoveryService} discovers all digitalSTROM-scene of one supported scene-type. The scene-type has to
40 * be given to the {@link #SceneDiscoveryService(BridgeHandler, ThingTypeUID)} as
41 * {@link org.openhab.core.thing.ThingTypeUID}. The supported {@link org.openhab.core.thing.ThingTypeUID}
42 * can be found at {@link org.openhab.binding.digitalstrom.internal.handler.SceneHandler#SUPPORTED_THING_TYPES}
44 * @author Michael Ochel - Initial contribution
45 * @author Matthias Siegele - Initial contribution
47 public class SceneDiscoveryService extends AbstractDiscoveryService {
49 private final Logger logger = LoggerFactory.getLogger(SceneDiscoveryService.class);
50 private final BridgeHandler bridgeHandler;
51 private final String sceneType;
53 public static final int TIMEOUT = 10;
56 * Creates a new {@link SceneDiscoveryService} for the given supportedThingType.
58 * @param bridgeHandler (must not be null)
59 * @param supportedThingType (must not be null)
60 * @throws IllegalArgumentException see {@link AbstractDiscoveryService#AbstractDiscoveryService(int)}
62 public SceneDiscoveryService(BridgeHandler bridgeHandler, ThingTypeUID supportedThingType)
63 throws IllegalArgumentException {
64 super(new HashSet<>(Arrays.asList(supportedThingType)), TIMEOUT, false);
65 this.sceneType = supportedThingType.getId();
66 this.bridgeHandler = bridgeHandler;
70 * Deactivates the {@link SceneDiscoveryService} and removes the {@link DiscoveryResult}s.
73 public void deactivate() {
74 logger.debug("deactivate discovery service for scene type {} remove thing tyspes {}", sceneType,
75 super.getSupportedThingTypes());
76 removeOlderResults(Instant.now().toEpochMilli());
80 protected void startScan() {
81 if (bridgeHandler != null) {
82 if (bridgeHandler.getScenes() != null) {
83 for (InternalScene scene : bridgeHandler.getScenes()) {
84 onSceneAddedInternal(scene);
91 protected synchronized void stopScan() {
93 removeOlderResults(getTimestampOfLastScan());
96 private void onSceneAddedInternal(InternalScene scene) {
97 logger.debug("{}", scene.getSceneType());
98 if (scene.getSceneType().equals(sceneType)) {
99 if (!ignoredScene(scene.getSceneID()) && !ignoreGroup(scene.getGroupID())) {
100 ThingUID thingUID = getThingUID(scene);
101 if (thingUID != null) {
102 ThingUID bridgeUID = bridgeHandler.getThing().getUID();
103 Map<String, Object> properties = new HashMap<>();
104 properties.put(ZONE_ID, scene.getZoneID());
105 properties.put(GROUP_ID, scene.getGroupID());
106 if (SceneEnum.containsScene(scene.getSceneID())) {
107 properties.put(SCENE_ID, SceneEnum.getScene(scene.getSceneID()).toString());
109 logger.debug("discovered scene: name '{}' with id {} have an invalid scene-ID",
110 scene.getSceneName(), scene.getID());
112 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
113 .withBridge(bridgeUID).withLabel(scene.getSceneName()).build();
115 thingDiscovered(discoveryResult);
118 logger.debug("discovered unsupported scene: name '{}' with id {}", scene.getSceneName(),
125 private boolean ignoreGroup(Short groupID) {
126 ApplicationGroup group = ApplicationGroup.getGroup(groupID);
129 case TEMPERATURE_CONTROL:
138 private boolean ignoredScene(short sceneID) {
139 switch (SceneEnum.getScene(sceneID)) {
148 case AREA_1_INCREMENT:
149 case AREA_1_DECREMENT:
151 case AREA_2_INCREMENT:
152 case AREA_2_DECREMENT:
154 case AREA_3_INCREMENT:
155 case AREA_3_DECREMENT:
157 case AREA_4_INCREMENT:
158 case AREA_4_DECREMENT:
160 case AREA_STEPPING_CONTINUE:
161 case ENERGY_OVERLOAD:
171 private ThingUID getThingUID(InternalScene scene) {
172 ThingUID bridgeUID = bridgeHandler.getThing().getUID();
173 ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, sceneType);
175 if (getSupportedThingTypes().contains(thingTypeUID)) {
176 String thingSceneId = scene.getID();
177 return new ThingUID(thingTypeUID, bridgeUID, thingSceneId);
184 * Returns the ID of this {@link SceneDiscoveryService}.
186 * @return id of this service
188 public String getID() {
193 * Creates a {@link DiscoveryResult} of the given {@link InternalScene}, if the scene exists, if it is allowed to
195 * and if the scene is not one of the following scenes:
197 * <li>{@link SceneEnum#INCREMENT}</li>
198 * <li>{@link SceneEnum#DECREMENT}</li>
199 * <li>{@link SceneEnum#STOP}</li>
200 * <li>{@link SceneEnum#MINIMUM}</li>
201 * <li>{@link SceneEnum#MAXIMUM}</li>
202 * <li>{@link SceneEnum#AUTO_OFF}</li>
203 * <li>{@link SceneEnum#DEVICE_ON}</li>
204 * <li>{@link SceneEnum#DEVICE_OFF}</li>
205 * <li>{@link SceneEnum#DEVICE_STOP}</li>
206 * <li>{@link SceneEnum#AREA_1_INCREMENT}</li>
207 * <li>{@link SceneEnum#AREA_1_DECREMENT}</li>
208 * <li>{@link SceneEnum#AREA_1_STOP}</li>
209 * <li>{@link SceneEnum#AREA_2_INCREMENT}</li>
210 * <li>{@link SceneEnum#AREA_2_DECREMENT}</li>
211 * <li>{@link SceneEnum#AREA_2_STOP}</li>
212 * <li>{@link SceneEnum#AREA_3_INCREMENT}</li>
213 * <li>{@link SceneEnum#AREA_3_DECREMENT}</li>
214 * <li>{@link SceneEnum#AREA_3_STOP}</li>
215 * <li>{@link SceneEnum#AREA_4_INCREMENT}</li>
216 * <li>{@link SceneEnum#AREA_4_DECREMENT}</li>
217 * <li>{@link SceneEnum#AREA_4_STOP}</li>
218 * <li>{@link SceneEnum#AREA_STEPPING_CONTINUE}</li>
219 * <li>{@link SceneEnum#ENERGY_OVERLOAD}</li>
220 * <li>{@link SceneEnum#ALARM_SIGNAL}</li>
221 * <li>{@link SceneEnum#AUTO_STANDBY}</li>
222 * <li>{@link SceneEnum#ZONE_ACTIVE}</li>
225 * @param scene (must not be null)
227 public void onSceneAdded(InternalScene scene) {
228 if (super.isBackgroundDiscoveryEnabled()) {
229 onSceneAddedInternal(scene);
234 * Removes the {@link DiscoveryResult} of the given {@link InternalScene}.
236 * @param scene (must not be null)
238 public void onSceneRemoved(InternalScene scene) {
239 ThingUID thingUID = getThingUID(scene);
240 if (thingUID != null) {
241 thingRemoved(thingUID);