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.digitalstrom.internal.handler;
15 import static org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants.*;
17 import java.math.BigDecimal;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.LinkedList;
21 import java.util.List;
24 import java.util.concurrent.ScheduledFuture;
25 import java.util.concurrent.TimeUnit;
27 import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
28 import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
29 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
30 import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
31 import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
32 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
33 import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
34 import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
35 import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
36 import org.openhab.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
37 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
38 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
39 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
40 import org.openhab.binding.digitalstrom.internal.lib.manager.DeviceStatusManager;
41 import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
42 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
43 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.ConnectionManagerImpl;
44 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.DeviceStatusManagerImpl;
45 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.SceneManagerImpl;
46 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.StructureManagerImpl;
47 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.TemperatureControlManager;
48 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
49 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
50 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
51 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
52 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
53 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
54 import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
55 import org.openhab.core.config.core.Configuration;
56 import org.openhab.core.library.types.DecimalType;
57 import org.openhab.core.thing.Bridge;
58 import org.openhab.core.thing.ChannelUID;
59 import org.openhab.core.thing.Thing;
60 import org.openhab.core.thing.ThingStatus;
61 import org.openhab.core.thing.ThingStatusDetail;
62 import org.openhab.core.thing.ThingTypeUID;
63 import org.openhab.core.thing.binding.BaseBridgeHandler;
64 import org.openhab.core.thing.binding.ThingHandler;
65 import org.openhab.core.types.Command;
66 import org.openhab.core.types.RefreshType;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
71 * The {@link BridgeHandler} is the handler for a digitalSTROM-Server and connects it to
73 * All {@link DeviceHandler}s and {@link SceneHandler}s use the {@link BridgeHandler} to execute the actual
76 * The {@link BridgeHandler} also:
78 * <li>manages the {@link DeviceStatusManager} (starts, stops, register {@link DeviceStatusListener},
79 * register {@link SceneStatusListener} and so on)</li>
80 * <li>creates and load the configurations in the {@link Config}.</li>
81 * <li>implements {@link ManagerStatusListener} to manage the expiration of the Thing initializations</li>
82 * <li>implements the {@link ConnectionListener} to manage the {@link ThingStatus} of this {@link BridgeHandler}</li>
83 * <li>and implements the {@link TotalPowerConsumptionListener} to update his Channels.</li>
86 * @author Michael Ochel - Initial contribution
87 * @author Matthias Siegele - Initial contribution
89 public class BridgeHandler extends BaseBridgeHandler
90 implements ConnectionListener, TotalPowerConsumptionListener, ManagerStatusListener {
92 private final Logger logger = LoggerFactory.getLogger(BridgeHandler.class);
95 * Contains all supported thing types of this handler
97 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_DSS_BRIDGE);
99 private static final long RECONNECT_TRACKER_INTERVAL = 15;
102 private ConnectionManager connMan;
103 private StructureManager structMan;
104 private SceneManager sceneMan;
105 private DeviceStatusManager devStatMan;
106 private TemperatureControlManager tempContMan;
108 private EventListener eventListener;
109 private ScheduledFuture<?> reconnectTracker;
111 private DeviceStatusListener deviceDiscovery;
112 private SceneStatusListener sceneDiscovery;
113 private TemperatureControlStatusListener temperatureControlDiscovery;
114 private Config config;
116 List<SceneStatusListener> unregisterSceneStatusListeners;
117 private short connectionTimeoutCounter = 0;
118 private final short ignoredTimeouts = 5;
120 private class Initializer implements Runnable {
122 BridgeHandler bridge;
125 public Initializer(BridgeHandler bridge, Config config) {
126 this.bridge = bridge;
127 this.config = config;
132 logger.debug("Checking connection");
133 if (connMan == null) {
134 connMan = new ConnectionManagerImpl(config, bridge, true);
136 connMan.registerConnectionListener(bridge);
137 connMan.configHasBeenUpdated();
140 logger.debug("Initializing digitalSTROM Manager ");
141 if (eventListener == null) {
142 eventListener = new EventListener(connMan);
144 if (structMan == null) {
145 structMan = new StructureManagerImpl();
147 if (sceneMan == null) {
148 sceneMan = new SceneManagerImpl(connMan, structMan, bridge, eventListener);
150 if (devStatMan == null) {
151 devStatMan = new DeviceStatusManagerImpl(connMan, structMan, sceneMan, bridge, eventListener);
153 devStatMan.registerStatusListener(bridge);
156 devStatMan.registerTotalPowerConsumptionListener(bridge);
158 if (connMan.checkConnection()) {
159 logger.debug("connection established, start services");
160 if (TemperatureControlManager.isHeatingControllerInstallated(connMan)) {
161 if (tempContMan == null) {
162 tempContMan = new TemperatureControlManager(connMan, eventListener,
163 temperatureControlDiscovery);
164 temperatureControlDiscovery = null;
166 if (temperatureControlDiscovery != null) {
167 tempContMan.registerTemperatureControlStatusListener(temperatureControlDiscovery);
171 structMan.generateZoneGroupNames(connMan);
173 eventListener.start();
176 boolean configChanged = false;
177 Configuration configuration = bridge.getConfig();
178 if (connMan.getApplicationToken() != null) {
179 configuration.remove(USER_NAME);
180 configuration.remove(PASSWORD);
181 logger.debug("Application-Token is: {}", connMan.getApplicationToken());
182 configuration.put(APPLICATION_TOKEN, connMan.getApplicationToken());
183 configChanged = true;
185 Map<String, String> properties = editProperties();
186 String dSSname = connMan.getDigitalSTROMAPI().getInstallationName(connMan.getSessionToken());
187 if (dSSname != null) {
188 properties.put(DS_NAME, dSSname);
190 Map<String, String> dsidMap = connMan.getDigitalSTROMAPI().getDSID(connMan.getSessionToken());
191 if (dsidMap != null) {
192 logger.debug("{}", dsidMap);
193 properties.putAll(dsidMap);
195 Map<String, String> versions = connMan.getDigitalSTROMAPI().getSystemVersion();
196 if (versions != null) {
197 properties.putAll(versions);
199 String certProperty = getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT);
200 String certConfig = config.getCert();
201 if ((certProperty == null || certProperty.isBlank()) && (certConfig != null && !certConfig.isBlank())) {
202 properties.put(DigitalSTROMBindingConstants.SERVER_CERT, certConfig);
204 logger.debug("update properties");
205 updateProperties(properties);
208 updateConfiguration(configuration);
214 * Creates a new {@link BridgeHandler}.
216 * @param bridge must not be null
218 public BridgeHandler(Bridge bridge) {
223 public void initialize() {
224 logger.debug("Initializing digitalSTROM-BridgeHandler");
225 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING, "Checking configuration...");
226 // Start an extra thread to readout the configuration and check the connection, because it takes sometimes more
227 // than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
228 Config config = loadAndCheckConfig();
230 if (config != null) {
231 logger.debug("{}", config.toString());
232 scheduler.execute(new Initializer(this, config));
236 private boolean checkLoginConfig(Config config) {
237 String userName = config.getUserName();
238 String password = config.getPassword();
239 String appToken = config.getAppToken();
241 if (((userName != null && !userName.isBlank()) && (password != null && !password.isBlank()))
242 || (appToken != null && !appToken.isBlank())) {
245 onConnectionStateChange(CONNECTION_LOST, NO_USER_PASSWORD);
249 private Config loadAndCheckConfig() {
250 Configuration thingConfig = super.getConfig();
251 Config config = loadAndCheckConnectionData(thingConfig);
252 if (config == null) {
255 logger.debug("Loading configuration");
256 List<String> numberExc = new ArrayList<>();
257 // Parameters can't be null, because of an existing default value.
258 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) instanceof BigDecimal) {
259 config.setSensordataRefreshInterval(
260 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL)).intValue()
263 numberExc.add("\"Sensor update interval\" ( "
264 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) + ")");
266 if (thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) instanceof BigDecimal) {
267 config.setTotalPowerUpdateInterval(
268 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL)).intValue()
271 numberExc.add("\"Total power update interval\" ("
272 + thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) + ")");
274 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) instanceof BigDecimal) {
275 config.setSensorReadingWaitTime(
276 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME)).intValue() * 1000);
278 numberExc.add("\"Wait time sensor reading\" ("
279 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) + ")");
281 if (thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) instanceof BigDecimal) {
282 config.setTrashDeviceDeleteTime(
283 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY))
286 numberExc.add("\"Days to be slaked trash bin devices\" ("
287 + thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) + ")");
289 if (!numberExc.isEmpty()) {
290 String excText = "The field ";
291 for (int i = 0; i < numberExc.size(); i++) {
292 excText = excText + numberExc.get(i);
293 if (i < numberExc.size() - 2) {
294 excText = excText + ", ";
295 } else if (i < numberExc.size() - 1) {
296 excText = excText + " and ";
299 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, excText + " have to be a number.");
302 String servertCert = getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT);
303 if (servertCert != null && !servertCert.isBlank()) {
304 config.setCert(servertCert);
309 private Config loadAndCheckConnectionData(Configuration thingConfig) {
310 if (this.config == null) {
311 this.config = new Config();
313 // load and check connection and authorization data
314 String host = (String) thingConfig.get(HOST);
315 if (host != null && !host.isBlank()) {
316 config.setHost(host);
318 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
319 "The connection to the digitalSTROM-Server can't established, because the host address is missing. Please set the host address.");
322 if (thingConfig.get(USER_NAME) != null) {
323 config.setUserName(thingConfig.get(USER_NAME).toString());
325 config.setUserName(null);
327 if (thingConfig.get(PASSWORD) != null) {
328 config.setPassword(thingConfig.get(PASSWORD).toString());
330 config.setPassword(null);
332 if (thingConfig.get(APPLICATION_TOKEN) != null) {
333 config.setAppToken(thingConfig.get(APPLICATION_TOKEN).toString());
335 config.setAppToken(null);
338 if (!checkLoginConfig(config)) {
345 public void dispose() {
346 logger.debug("Handler disposed");
347 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
348 reconnectTracker.cancel(true);
350 if (eventListener != null) {
351 eventListener.stop();
353 if (devStatMan != null) {
354 devStatMan.unregisterTotalPowerConsumptionListener();
355 devStatMan.unregisterStatusListener();
356 this.devStatMan.stop();
358 if (connMan != null) {
359 connMan.unregisterConnectionListener();
364 public void handleCommand(ChannelUID channelUID, Command command) {
365 if (command instanceof RefreshType) {
366 channelLinked(channelUID);
368 logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
373 public void handleRemoval() {
374 String applicationToken = (String) super.getConfig().get(APPLICATION_TOKEN);
375 if (applicationToken != null && !applicationToken.isEmpty()) {
376 if (connMan == null) {
377 Config config = loadAndCheckConnectionData(this.getConfig());
378 if (config != null) {
379 this.connMan = new ConnectionManagerImpl(config, null, false);
381 updateStatus(ThingStatus.REMOVED);
385 if (connMan.removeApplicationToken()) {
386 logger.debug("Application-Token deleted");
389 updateStatus(ThingStatus.REMOVED);
392 /* methods to store listener */
395 * Registers a new {@link DeviceStatusListener} on the {@link DeviceStatusManager}.
397 * @param deviceStatusListener (must not be null)
399 public synchronized void registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
400 if (this.devStatMan != null) {
401 if (deviceStatusListener == null) {
402 throw new IllegalArgumentException("It's not allowed to pass null.");
405 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
406 if (devStatMan.getManagerState().equals(ManagerStates.RUNNING)) {
407 devStatMan.registerDeviceListener(deviceStatusListener);
408 } else if (deviceStatusListener.getDeviceStatusListenerID()
409 .equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
410 devStatMan.registerDeviceListener(deviceStatusListener);
413 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
416 if (deviceStatusListener.getDeviceStatusListenerID().equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
417 deviceDiscovery = deviceStatusListener;
423 * Unregisters a new {@link DeviceStatusListener} on the {@link BridgeHandler}.
425 * @param deviceStatusListener (must not be null)
427 public void unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
428 if (this.devStatMan != null) {
429 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
430 this.devStatMan.unregisterDeviceListener(deviceStatusListener);
432 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
438 * Registers a new {@link SceneStatusListener} on the {@link BridgeHandler}.
440 * @param sceneStatusListener (must not be null)
442 public synchronized void registerSceneStatusListener(SceneStatusListener sceneStatusListener) {
443 if (this.sceneMan != null) {
444 if (sceneStatusListener == null) {
445 throw new IllegalArgumentException("It's not allowed to pass null.");
448 if (sceneStatusListener.getSceneStatusListenerID() != null) {
449 this.sceneMan.registerSceneListener(sceneStatusListener);
451 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null.");
454 if (sceneStatusListener.getSceneStatusListenerID().equals(SceneStatusListener.SCENE_DISCOVERY)) {
455 sceneDiscovery = sceneStatusListener;
461 * Unregisters a new {@link SceneStatusListener} on the {@link DeviceStatusManager}.
463 * @param sceneStatusListener (must not be null)
465 public void unregisterSceneStatusListener(SceneStatusListener sceneStatusListener) {
466 if (this.sceneMan != null) {
467 if (sceneStatusListener.getSceneStatusListenerID() != null) {
468 this.sceneMan.unregisterSceneListener(sceneStatusListener);
470 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null..");
476 * Has to be called from a removed Thing-Child to rediscovers the Thing.
478 * @param id = scene or device id (must not be null)
480 public void childThingRemoved(String id) {
481 if (id != null && id.split("-").length == 3) {
482 InternalScene scene = sceneMan.getInternalScene(id);
484 sceneMan.removeInternalScene(id);
485 sceneMan.addInternalScene(scene);
488 devStatMan.removeDevice(id);
493 * Delegate a stop command from a Thing to the {@link DeviceStatusManager#sendStopComandsToDSS(Device)}.
495 * @param device can be null
497 public void stopOutputValue(Device device) {
498 this.devStatMan.sendStopComandsToDSS(device);
502 public void channelLinked(ChannelUID channelUID) {
503 if (devStatMan != null) {
504 MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
505 if (meteringType != null) {
506 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
507 onEnergyMeterValueChanged(devStatMan.getTotalEnergyMeterValue());
509 onTotalPowerConsumptionChanged(devStatMan.getTotalPowerConsumption());
512 logger.warn("Channel with id {} is not known for the thing with id {}.", channelUID.getId(),
513 getThing().getUID());
519 public void onTotalPowerConsumptionChanged(int newPowerConsumption) {
520 updateChannelState(MeteringTypeEnum.CONSUMPTION, MeteringUnitsEnum.WH, newPowerConsumption);
524 public void onEnergyMeterValueChanged(int newEnergyMeterValue) {
525 updateChannelState(MeteringTypeEnum.ENERGY, MeteringUnitsEnum.WH, newEnergyMeterValue * 0.001);
529 public void onEnergyMeterWsValueChanged(int newEnergyMeterValue) {
533 private void updateChannelState(MeteringTypeEnum meteringType, MeteringUnitsEnum meteringUnit, double value) {
534 String channelID = DsChannelTypeProvider.getMeteringChannelID(meteringType, meteringUnit, true);
535 if (getThing().getChannel(channelID) != null) {
536 updateState(channelID, new DecimalType(value));
541 public void onConnectionStateChange(String newConnectionState) {
542 switch (newConnectionState) {
543 case CONNECTION_LOST:
544 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
545 "The connection to the digitalSTROM-Server cannot be established.");
546 startReconnectTracker();
548 case CONNECTION_RESUMED:
549 if (connectionTimeoutCounter > 0) {
550 // reset connection timeout counter
551 connectionTimeoutCounter = 0;
552 if (connMan.checkConnection()) {
554 setStatus(ThingStatus.ONLINE);
558 case APPLICATION_TOKEN_GENERATED:
559 if (connMan != null) {
560 Configuration config = this.getConfig();
561 config.remove(USER_NAME);
562 config.remove(PASSWORD);
563 config.put(APPLICATION_TOKEN, connMan.getApplicationToken());
564 this.updateConfiguration(config);
572 private void setStatus(ThingStatus status) {
573 logger.debug("set status to: {}", status);
574 updateStatus(status);
575 for (Thing thing : getThing().getThings()) {
576 ThingHandler handler = thing.getHandler();
577 if (handler != null) {
578 handler.bridgeStatusChanged(getThing().getStatusInfo());
583 private void startReconnectTracker() {
584 if (reconnectTracker == null || reconnectTracker.isCancelled()) {
585 logger.debug("Connection lost, stop all services and start reconnectTracker.");
587 reconnectTracker = scheduler.scheduleWithFixedDelay(new Runnable() {
591 if (connMan != null) {
592 boolean conStat = connMan.checkConnection();
593 logger.debug("check connection = {}", conStat);
596 reconnectTracker.cancel(false);
600 }, RECONNECT_TRACKER_INTERVAL, RECONNECT_TRACKER_INTERVAL, TimeUnit.SECONDS);
604 private void stopServices() {
605 if (devStatMan != null && !devStatMan.getManagerState().equals(ManagerStates.STOPPED)) {
608 if (eventListener != null && eventListener.isStarted()) {
609 eventListener.stop();
613 private void restartServices() {
614 logger.debug("reconnect, stop reconnection tracker and restart services");
615 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
616 reconnectTracker.cancel(true);
619 if (devStatMan != null) {
622 if (eventListener != null) {
623 eventListener.start();
628 public void onConnectionStateChange(String newConnectionState, String reason) {
629 if (newConnectionState.equals(NOT_AUTHENTICATED) || newConnectionState.equals(CONNECTION_LOST)) {
631 case WRONG_APP_TOKEN:
632 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
634 User defined Application-Token is wrong. \
635 Please set user name and password to generate an Application-Token or set a valid Application-Token.\
639 case WRONG_USER_OR_PASSWORD:
640 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
641 "The set username or password is wrong.");
644 case NO_USER_PASSWORD:
645 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
646 "No username or password is set to generate Application-Token. Please set user name and password or Application-Token.");
649 case CONNECTON_TIMEOUT:
650 // ignore the first connection timeout
651 if (connectionTimeoutCounter++ > ignoredTimeouts) {
652 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
653 "Connection lost because connection timeout to Server.");
659 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, """
660 Server not found! Please check these points:
661 - Is digitalSTROM-Server turned on?
662 - Is the host address correct?
663 - Is the ethernet cable connection established?\
667 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
668 "Unknown host name, please check the set host name!");
671 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid URL is set.");
673 case CONNECTION_LOST:
674 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
675 "IOException / Connection lost.");
677 case SSL_HANDSHAKE_ERROR:
678 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
679 "SSL Handshake error / Connection lost.");
682 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
684 // reset connection timeout counter
685 connectionTimeoutCounter = 0;
686 startReconnectTracker();
691 * Returns a list of all {@link Device}'s.
693 * @return device list (cannot be null)
695 public List<Device> getDevices() {
696 return this.structMan != null && this.structMan.getDeviceMap() != null
697 ? new LinkedList<>(this.structMan.getDeviceMap().values())
702 * Returns the {@link StructureManager}.
704 * @return StructureManager
706 public StructureManager getStructureManager() {
707 return this.structMan;
711 * Delegates a scene command of a Thing to the
712 * {@link DeviceStatusManager#sendSceneComandsToDSS(InternalScene, boolean)}
714 * @param scene the called scene
715 * @param call_undo (true = call scene | false = undo scene)
717 public void sendSceneComandToDSS(InternalScene scene, boolean call_undo) {
718 if (devStatMan != null) {
719 devStatMan.sendSceneComandsToDSS(scene, call_undo);
724 * Delegates a device command of a Thing to the
725 * {@link DeviceStatusManager#sendComandsToDSS(Device, DeviceStateUpdate)}
727 * @param device can be null
728 * @param deviceStateUpdate can be null
730 public void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
731 if (devStatMan != null) {
732 devStatMan.sendComandsToDSS(device, deviceStateUpdate);
737 * Returns a list of all {@link InternalScene}'s.
739 * @return Scene list (cannot be null)
741 public List<InternalScene> getScenes() {
742 return sceneMan != null ? sceneMan.getScenes() : new LinkedList<>();
746 * Returns the {@link ConnectionManager}.
748 * @return ConnectionManager
750 public ConnectionManager getConnectionManager() {
755 public void onStatusChanged(ManagerTypes managerType, ManagerStates state) {
756 if (managerType.equals(ManagerTypes.DEVICE_STATUS_MANAGER)) {
759 if (deviceDiscovery != null) {
760 devStatMan.registerDeviceListener(deviceDiscovery);
761 deviceDiscovery = null;
763 logger.debug("Building digitalSTROM model");
766 updateStatus(ThingStatus.ONLINE);
769 if (!getThing().getStatusInfo().getStatusDetail().equals(ThingStatusDetail.COMMUNICATION_ERROR)
770 && !getThing().getStatusInfo().getStatusDetail()
771 .equals(ThingStatusDetail.CONFIGURATION_ERROR)) {
772 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "DeviceStatusManager is stopped.");
780 if (managerType.equals(ManagerTypes.SCENE_MANAGER)) {
782 case GENERATING_SCENES:
783 logger.debug("SceneManager reports that he is generating scenes");
784 if (sceneDiscovery != null) {
785 sceneMan.registerSceneListener(sceneDiscovery);
786 sceneDiscovery = null;
790 logger.debug("SceneManager reports that he is running");
799 * Returns a {@link List} of all {@link Circuit}'s.
801 * @return circuit list
803 public List<Circuit> getCircuits() {
804 logger.debug("circuits: {}", structMan.getCircuitMap().values().toString());
805 return structMan != null && structMan.getCircuitMap() != null
806 ? new LinkedList<>(structMan.getCircuitMap().values())
811 * Returns the {@link TemperatureControlManager} or null if no one exist.
813 * @return {@link TemperatureControlManager}
815 public TemperatureControlManager getTemperatureControlManager() {
820 * Registers the given {@link TemperatureControlStatusListener} to the {@link TemperatureControlManager}.
822 * @param temperatureControlStatusListener can be null
824 public void registerTemperatureControlStatusListener(
825 TemperatureControlStatusListener temperatureControlStatusListener) {
826 if (tempContMan != null) {
827 tempContMan.registerTemperatureControlStatusListener(temperatureControlStatusListener);
828 } else if (TemperatureControlStatusListener.DISCOVERY
829 .equals(temperatureControlStatusListener.getTemperationControlStatusListenrID())) {
830 this.temperatureControlDiscovery = temperatureControlStatusListener;
835 * Unregisters the given {@link TemperatureControlStatusListener} from the {@link TemperatureControlManager}.
837 * @param temperatureControlStatusListener can be null
839 public void unregisterTemperatureControlStatusListener(
840 TemperatureControlStatusListener temperatureControlStatusListener) {
841 if (tempContMan != null) {
842 tempContMan.unregisterTemperatureControlStatusListener(temperatureControlStatusListener);
847 * see {@link TemperatureControlManager#getTemperatureControlStatusFromAllZones()}
849 * @return all temperature control status objects
851 public Collection<TemperatureControlStatus> getTemperatureControlStatusFromAllZones() {
852 return tempContMan != null ? tempContMan.getTemperatureControlStatusFromAllZones() : new LinkedList<>();