2 * Copyright (c) 2010-2022 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;
15 import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
17 import java.util.HashMap;
19 import java.util.concurrent.ConcurrentHashMap;
21 import org.openhab.binding.digitalstrom.internal.discovery.DiscoveryServiceManager;
22 import org.openhab.binding.digitalstrom.internal.handler.BridgeHandler;
23 import org.openhab.binding.digitalstrom.internal.handler.CircuitHandler;
24 import org.openhab.binding.digitalstrom.internal.handler.DeviceHandler;
25 import org.openhab.binding.digitalstrom.internal.handler.SceneHandler;
26 import org.openhab.binding.digitalstrom.internal.handler.ZoneTemperatureControlHandler;
27 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
28 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.ConnectionManagerImpl;
29 import org.openhab.binding.digitalstrom.internal.lib.serverconnection.constants.JSONApiResponseKeysEnum;
30 import org.openhab.core.config.core.Configuration;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingTypeUID;
34 import org.openhab.core.thing.ThingUID;
35 import org.openhab.core.thing.binding.BaseThingHandlerFactory;
36 import org.openhab.core.thing.binding.ThingHandler;
37 import org.openhab.core.thing.binding.ThingHandlerFactory;
38 import org.osgi.service.component.annotations.Component;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * The {@link DigitalSTROMHandlerFactory} is responsible for creating things and thing
46 * @author Michael Ochel - Initial contribution
47 * @author Mathias Siegele - Initial contribution
49 @Component(service = ThingHandlerFactory.class, configurationPid = "binding.digitalstrom")
50 public class DigitalSTROMHandlerFactory extends BaseThingHandlerFactory {
52 private final Logger logger = LoggerFactory.getLogger(DigitalSTROMHandlerFactory.class);
53 private final Map<String, DiscoveryServiceManager> discoveryServiceManagers = new ConcurrentHashMap<>();
55 private Map<ThingUID, BridgeHandler> bridgeHandlers;
58 public boolean supportsThingType(ThingTypeUID thingTypeUID) {
59 return BridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
60 || SceneHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
61 || DeviceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
62 || ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
63 || CircuitHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID);
67 public Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration, ThingUID thingUID,
69 if (BridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
70 ThingUID dSSUID = getBridgeThingUID(thingTypeUID, thingUID, configuration);
72 return super.createThing(thingTypeUID, configuration, dSSUID, null);
74 logger.error("Can't generate thing UID for thing type {}"
75 + ", because digitalSTROM-Server is not reachable. Please check these points:\n"
76 + "Are the server address and portnumber correct?\n" + "Is the server turned on?\n"
77 + "Is the network configured correctly?", thingTypeUID);
82 if (DeviceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
83 ThingUID dsDeviceUID = getDeviceUID(thingTypeUID, thingUID, configuration, bridgeUID);
84 return super.createThing(thingTypeUID, configuration, dsDeviceUID, bridgeUID);
87 if (CircuitHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
88 ThingUID dsDeviceUID = getDeviceUID(thingTypeUID, thingUID, configuration, bridgeUID);
89 return super.createThing(thingTypeUID, configuration, dsDeviceUID, bridgeUID);
92 if (ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
93 ThingUID zoneTempConUID = getZoneTemperatureControlUID(thingTypeUID, thingUID, configuration, bridgeUID);
94 return super.createThing(thingTypeUID, configuration, zoneTempConUID, bridgeUID);
97 if (SceneHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
98 ThingUID dsSceneUID = getSceneUID(thingTypeUID, thingUID, configuration, bridgeUID);
99 return super.createThing(thingTypeUID, configuration, dsSceneUID, bridgeUID);
101 throw new IllegalArgumentException(
102 "The thing type " + thingTypeUID + " is not supported by the digitalSTROM binding.");
106 protected ThingHandler createHandler(Thing thing) {
107 ThingTypeUID thingTypeUID = thing.getThingTypeUID();
109 if (BridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
110 BridgeHandler handler = new BridgeHandler((Bridge) thing);
111 if (bridgeHandlers == null) {
112 bridgeHandlers = new HashMap<>();
114 bridgeHandlers.put(thing.getUID(), handler);
115 DiscoveryServiceManager discoveryServiceManager = new DiscoveryServiceManager(handler);
116 discoveryServiceManager.registerDiscoveryServices(bundleContext);
117 discoveryServiceManagers.put(handler.getThing().getUID().getAsString(), discoveryServiceManager);
121 if (DeviceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
122 return new DeviceHandler(thing);
125 if (CircuitHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
126 return new CircuitHandler(thing);
129 if (ZoneTemperatureControlHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
130 return new ZoneTemperatureControlHandler(thing);
133 if (SceneHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
134 return new SceneHandler(thing);
139 private ThingUID getDeviceUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
140 ThingUID bridgeUID) {
141 String id = (String) configuration.get(DEVICE_DSID);
142 if (thingUID == null && id != null && !id.isBlank()) {
143 return new ThingUID(thingTypeUID, bridgeUID, id);
148 private ThingUID getZoneTemperatureControlUID(ThingTypeUID thingTypeUID, ThingUID thingUID,
149 Configuration configuration, ThingUID bridgeUID) {
150 if (thingUID == null) {
151 Integer zoneID = ZoneTemperatureControlHandler.getZoneID(configuration, bridgeHandlers.get(bridgeUID));
152 if (zoneID > ZoneTemperatureControlHandler.ZONE_ID_NOT_EXISTS) {
153 return new ThingUID(thingTypeUID, bridgeUID, zoneID.toString());
156 case ZoneTemperatureControlHandler.ZONE_ID_NOT_EXISTS:
157 logger.error("Configured zone '{}' does not exist, please check your configuration.",
158 configuration.get(DigitalSTROMBindingConstants.ZONE_ID));
160 case ZoneTemperatureControlHandler.ZONE_ID_NOT_SET:
161 logger.error("ZoneID is missing at your configuration.");
163 case ZoneTemperatureControlHandler.BRIDGE_IS_NULL:
164 logger.error("Bridge is missing, can not check the zoneID.");
172 private ThingUID getSceneUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
173 ThingUID bridgeUID) {
174 if (thingUID != null) {
177 String sceneID = SceneHandler.getSceneID(configuration, bridgeHandlers.get(bridgeUID));
179 case SceneHandler.SCENE_WRONG:
181 "Configured scene '{}' does not exist or can not be used, please check your configuration.",
182 configuration.get(DigitalSTROMBindingConstants.SCENE_ID));
184 case SceneHandler.ZONE_WRONG:
185 logger.error("Configured zone '{}' does not exist, please check your configuration.",
186 configuration.get(DigitalSTROMBindingConstants.ZONE_ID));
188 case SceneHandler.GROUP_WRONG:
189 logger.error("Configured group '{}' does not exist, please check your configuration.",
190 configuration.get(DigitalSTROMBindingConstants.GROUP_ID));
192 case SceneHandler.NO_STRUC_MAN:
193 logger.error("Waiting for building digitalSTROM model.");
195 case SceneHandler.NO_SCENE:
196 logger.error("No Scene-ID is set!");
198 case SceneHandler.NO_BRIDGE:
199 logger.error("No related bridge found!");
201 return new ThingUID(thingTypeUID, bridgeUID, sceneID);
206 private ThingUID getBridgeThingUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration) {
207 if (thingUID != null) {
211 String configValue = (String) configuration.get(DS_ID);
212 if (configValue == null || configValue.isBlank()) {
213 dSID = getDSSid(configuration);
215 configuration.put(DS_ID, dSID);
218 dSID = configuration.get(DS_ID).toString();
221 return new ThingUID(thingTypeUID, dSID);
227 private String getDSSid(Configuration configuration) {
229 String hostConfigValue = (String) configuration.get(HOST);
230 if (hostConfigValue != null && !hostConfigValue.isBlank()) {
231 String host = hostConfigValue;
232 String applicationToken = null;
236 String atConfigValue = (String) configuration.get(APPLICATION_TOKEN);
237 if (atConfigValue != null && !atConfigValue.isBlank()) {
238 applicationToken = configuration.get(APPLICATION_TOKEN).toString();
241 if (checkUserPassword(configuration)) {
242 user = configuration.get(USER_NAME).toString();
243 pw = configuration.get(PASSWORD).toString();
245 ConnectionManager connMan = new ConnectionManagerImpl(host, user, pw, applicationToken, false, true);
246 Map<String, String> dsidMap = connMan.getDigitalSTROMAPI().getDSID(connMan.getSessionToken());
247 if (dsidMap != null) {
248 dSID = dsidMap.get(JSONApiResponseKeysEnum.DSID.getKey());
254 private boolean checkUserPassword(Configuration configuration) {
255 String userName = (String) configuration.get(USER_NAME);
256 String password = (String) configuration.get(PASSWORD);
257 return userName != null && !userName.isBlank() && password != null && !password.isBlank();
261 protected synchronized void removeHandler(ThingHandler thingHandler) {
262 if (thingHandler instanceof BridgeHandler) {
263 String uid = thingHandler.getThing().getUID().getAsString();
264 DiscoveryServiceManager discoveryServiceManager = discoveryServiceManagers.remove(uid);
265 if (discoveryServiceManager != null) {
266 discoveryServiceManager.unregisterDiscoveryServices(bundleContext);