2 * Copyright (c) 2010-2020 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.Collections;
21 import java.util.LinkedList;
22 import java.util.List;
25 import java.util.concurrent.ScheduledFuture;
26 import java.util.concurrent.TimeUnit;
28 import org.apache.commons.lang.StringUtils;
29 import org.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
30 import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
31 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
32 import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
33 import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
34 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
35 import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
36 import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
37 import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
38 import org.openhab.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
39 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
40 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
41 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
42 import org.openhab.binding.digitalstrom.internal.lib.manager.DeviceStatusManager;
43 import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
44 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
45 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.ConnectionManagerImpl;
46 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.DeviceStatusManagerImpl;
47 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.SceneManagerImpl;
48 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.StructureManagerImpl;
49 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.TemperatureControlManager;
50 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
51 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
52 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
53 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
54 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
55 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
56 import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
57 import org.openhab.core.config.core.Configuration;
58 import org.openhab.core.library.types.DecimalType;
59 import org.openhab.core.thing.Bridge;
60 import org.openhab.core.thing.ChannelUID;
61 import org.openhab.core.thing.Thing;
62 import org.openhab.core.thing.ThingStatus;
63 import org.openhab.core.thing.ThingStatusDetail;
64 import org.openhab.core.thing.ThingTypeUID;
65 import org.openhab.core.thing.binding.BaseBridgeHandler;
66 import org.openhab.core.thing.binding.ThingHandler;
67 import org.openhab.core.types.Command;
68 import org.openhab.core.types.RefreshType;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
73 * The {@link BridgeHandler} is the handler for a digitalSTROM-Server and connects it to
75 * All {@link DeviceHandler}s and {@link SceneHandler}s use the {@link BridgeHandler} to execute the actual
78 * The {@link BridgeHandler} also:
80 * <li>manages the {@link DeviceStatusManager} (starts, stops, register {@link DeviceStatusListener},
81 * register {@link SceneStatusListener} and so on)</li>
82 * <li>creates and load the configurations in the {@link Config}.</li>
83 * <li>implements {@link ManagerStatusListener} to manage the expiration of the Thing initializations</li>
84 * <li>implements the {@link ConnectionListener} to manage the {@link ThingStatus} of this {@link BridgeHandler}</li>
85 * <li>and implements the {@link TotalPowerConsumptionListener} to update his Channels.</li>
88 * @author Michael Ochel - Initial contribution
89 * @author Matthias Siegele - Initial contribution
91 public class BridgeHandler extends BaseBridgeHandler
92 implements ConnectionListener, TotalPowerConsumptionListener, ManagerStatusListener {
94 private final Logger logger = LoggerFactory.getLogger(BridgeHandler.class);
97 * Contains all supported thing types of this handler
99 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DSS_BRIDGE);
101 private static final long RECONNECT_TRACKER_INTERVAL = 15;
104 private ConnectionManager connMan;
105 private StructureManager structMan;
106 private SceneManager sceneMan;
107 private DeviceStatusManager devStatMan;
108 private TemperatureControlManager tempContMan;
110 private EventListener eventListener;
111 private ScheduledFuture<?> reconnectTracker;
113 private DeviceStatusListener deviceDiscovery;
114 private SceneStatusListener sceneDiscovery;
115 private TemperatureControlStatusListener temperatureControlDiscovery;
116 private Config config;
118 List<SceneStatusListener> unregisterSceneStatusListeners;
119 private short connectionTimeoutCounter = 0;
120 private final short ignoredTimeouts = 5;
122 private class Initializer implements Runnable {
124 BridgeHandler bridge;
127 public Initializer(BridgeHandler bridge, Config config) {
128 this.bridge = bridge;
129 this.config = config;
134 logger.debug("Checking connection");
135 if (connMan == null) {
136 connMan = new ConnectionManagerImpl(config, bridge, true);
138 connMan.registerConnectionListener(bridge);
139 connMan.configHasBeenUpdated();
142 logger.debug("Initializing digitalSTROM Manager ");
143 if (eventListener == null) {
144 eventListener = new EventListener(connMan);
146 if (structMan == null) {
147 structMan = new StructureManagerImpl();
149 if (sceneMan == null) {
150 sceneMan = new SceneManagerImpl(connMan, structMan, bridge, eventListener);
152 if (devStatMan == null) {
153 devStatMan = new DeviceStatusManagerImpl(connMan, structMan, sceneMan, bridge, eventListener);
155 devStatMan.registerStatusListener(bridge);
158 devStatMan.registerTotalPowerConsumptionListener(bridge);
160 if (connMan.checkConnection()) {
161 logger.debug("connection established, start services");
162 if (TemperatureControlManager.isHeatingControllerInstallated(connMan)) {
163 if (tempContMan == null) {
164 tempContMan = new TemperatureControlManager(connMan, eventListener,
165 temperatureControlDiscovery);
166 temperatureControlDiscovery = null;
168 if (temperatureControlDiscovery != null) {
169 tempContMan.registerTemperatureControlStatusListener(temperatureControlDiscovery);
173 structMan.generateZoneGroupNames(connMan);
175 eventListener.start();
178 boolean configChanged = false;
179 Configuration configuration = bridge.getConfig();
180 if (connMan.getApplicationToken() != null) {
181 configuration.remove(USER_NAME);
182 configuration.remove(PASSWORD);
183 logger.debug("Application-Token is: {}", connMan.getApplicationToken());
184 configuration.put(APPLICATION_TOKEN, connMan.getApplicationToken());
185 configChanged = true;
187 Map<String, String> properties = editProperties();
188 String dSSname = connMan.getDigitalSTROMAPI().getInstallationName(connMan.getSessionToken());
189 if (dSSname != null) {
190 properties.put(DS_NAME, dSSname);
192 Map<String, String> dsidMap = connMan.getDigitalSTROMAPI().getDSID(connMan.getSessionToken());
193 if (dsidMap != null) {
194 logger.debug("{}", dsidMap);
195 properties.putAll(dsidMap);
197 Map<String, String> versions = connMan.getDigitalSTROMAPI().getSystemVersion();
198 if (versions != null) {
199 properties.putAll(versions);
201 if (StringUtils.isBlank(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT))
202 && StringUtils.isNotBlank(config.getCert())) {
203 properties.put(DigitalSTROMBindingConstants.SERVER_CERT, config.getCert());
205 logger.debug("update properties");
206 updateProperties(properties);
209 updateConfiguration(configuration);
215 * Creates a new {@link BridgeHandler}.
217 * @param bridge must not be null
219 public BridgeHandler(Bridge bridge) {
224 public void initialize() {
225 logger.debug("Initializing digitalSTROM-BridgeHandler");
226 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING, "Checking configuration...");
227 // Start an extra thread to readout the configuration and check the connection, because it takes sometimes more
228 // than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
229 Config config = loadAndCheckConfig();
231 if (config != null) {
232 logger.debug("{}", config.toString());
233 scheduler.execute(new Initializer(this, config));
237 private boolean checkLoginConfig(Config config) {
238 if ((StringUtils.isNotBlank(config.getUserName()) && StringUtils.isNotBlank(config.getPassword()))
239 || StringUtils.isNotBlank(config.getAppToken())) {
242 onConnectionStateChange(CONNECTION_LOST, NO_USER_PASSWORD);
246 private Config loadAndCheckConfig() {
247 Configuration thingConfig = super.getConfig();
248 Config config = loadAndCheckConnectionData(thingConfig);
249 if (config == null) {
252 logger.debug("Loading configuration");
253 List<String> numberExc = new ArrayList<>();
254 // Parameters can't be null, because of an existing default value.
255 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) instanceof BigDecimal) {
256 config.setSensordataRefreshInterval(
257 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL)).intValue()
260 numberExc.add("\"Sensor update interval\" ( "
261 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) + ")");
263 if (thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) instanceof BigDecimal) {
264 config.setTotalPowerUpdateInterval(
265 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL)).intValue()
268 numberExc.add("\"Total power update interval\" ("
269 + thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) + ")");
271 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) instanceof BigDecimal) {
272 config.setSensorReadingWaitTime(
273 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME)).intValue() * 1000);
275 numberExc.add("\"Wait time sensor reading\" ("
276 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) + ")");
278 if (thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) instanceof BigDecimal) {
279 config.setTrashDeviceDeleteTime(
280 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY))
283 numberExc.add("\"Days to be slaked trash bin devices\" ("
284 + thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) + ")");
286 if (!numberExc.isEmpty()) {
287 String excText = "The field ";
288 for (int i = 0; i < numberExc.size(); i++) {
289 excText = excText + numberExc.get(i);
290 if (i < numberExc.size() - 2) {
291 excText = excText + ", ";
292 } else if (i < numberExc.size() - 1) {
293 excText = excText + " and ";
296 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, excText + " have to be a number.");
299 if (StringUtils.isNotBlank(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT))) {
300 config.setCert(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT));
305 private Config loadAndCheckConnectionData(Configuration thingConfig) {
306 if (this.config == null) {
307 this.config = new Config();
309 // load and check connection and authorization data
310 if (StringUtils.isNotBlank((String) thingConfig.get(HOST))) {
311 config.setHost(thingConfig.get(HOST).toString());
313 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
314 "The connection to the digitalSTROM-Server can't established, because the host address is missing. Please set the host address.");
317 if (thingConfig.get(USER_NAME) != null) {
318 config.setUserName(thingConfig.get(USER_NAME).toString());
320 config.setUserName(null);
322 if (thingConfig.get(PASSWORD) != null) {
323 config.setPassword(thingConfig.get(PASSWORD).toString());
325 config.setPassword(null);
327 if (thingConfig.get(APPLICATION_TOKEN) != null) {
328 config.setAppToken(thingConfig.get(APPLICATION_TOKEN).toString());
330 config.setAppToken(null);
333 if (!checkLoginConfig(config)) {
340 public void dispose() {
341 logger.debug("Handler disposed");
342 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
343 reconnectTracker.cancel(true);
345 if (eventListener != null) {
346 eventListener.stop();
348 if (devStatMan != null) {
349 devStatMan.unregisterTotalPowerConsumptionListener();
350 devStatMan.unregisterStatusListener();
351 this.devStatMan.stop();
353 if (connMan != null) {
354 connMan.unregisterConnectionListener();
359 public void handleCommand(ChannelUID channelUID, Command command) {
360 if (command instanceof RefreshType) {
361 channelLinked(channelUID);
363 logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
368 public void handleRemoval() {
369 String applicationToken = (String) super.getConfig().get(APPLICATION_TOKEN);
370 if (applicationToken != null && !applicationToken.isEmpty()) {
371 if (connMan == null) {
372 Config config = loadAndCheckConnectionData(this.getConfig());
373 if (config != null) {
374 this.connMan = new ConnectionManagerImpl(config, null, false);
376 updateStatus(ThingStatus.REMOVED);
380 if (connMan.removeApplicationToken()) {
381 logger.debug("Application-Token deleted");
384 updateStatus(ThingStatus.REMOVED);
387 /* methods to store listener */
390 * Registers a new {@link DeviceStatusListener} on the {@link DeviceStatusManager}.
392 * @param deviceStatusListener (must not be null)
394 public synchronized void registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
395 if (this.devStatMan != null) {
396 if (deviceStatusListener == null) {
397 throw new IllegalArgumentException("It's not allowed to pass null.");
400 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
401 if (devStatMan.getManagerState().equals(ManagerStates.RUNNING)) {
402 devStatMan.registerDeviceListener(deviceStatusListener);
403 } else if (deviceStatusListener.getDeviceStatusListenerID()
404 .equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
405 devStatMan.registerDeviceListener(deviceStatusListener);
408 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
411 if (deviceStatusListener.getDeviceStatusListenerID().equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
412 deviceDiscovery = deviceStatusListener;
418 * Unregisters a new {@link DeviceStatusListener} on the {@link BridgeHandler}.
420 * @param deviceStatusListener (must not be null)
422 public void unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
423 if (this.devStatMan != null) {
424 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
425 this.devStatMan.unregisterDeviceListener(deviceStatusListener);
427 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
433 * Registers a new {@link SceneStatusListener} on the {@link BridgeHandler}.
435 * @param sceneStatusListener (must not be null)
437 public synchronized void registerSceneStatusListener(SceneStatusListener sceneStatusListener) {
438 if (this.sceneMan != null) {
439 if (sceneStatusListener == null) {
440 throw new IllegalArgumentException("It's not allowed to pass null.");
443 if (sceneStatusListener.getSceneStatusListenerID() != null) {
444 this.sceneMan.registerSceneListener(sceneStatusListener);
446 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null.");
449 if (sceneStatusListener.getSceneStatusListenerID().equals(SceneStatusListener.SCENE_DISCOVERY)) {
450 sceneDiscovery = sceneStatusListener;
456 * Unregisters a new {@link SceneStatusListener} on the {@link DeviceStatusManager}.
458 * @param sceneStatusListener (must not be null)
460 public void unregisterSceneStatusListener(SceneStatusListener sceneStatusListener) {
461 if (this.sceneMan != null) {
462 if (sceneStatusListener.getSceneStatusListenerID() != null) {
463 this.sceneMan.unregisterSceneListener(sceneStatusListener);
465 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null..");
471 * Has to be called from a removed Thing-Child to rediscovers the Thing.
473 * @param id = scene or device id (must not be null)
475 public void childThingRemoved(String id) {
476 if (id != null && id.split("-").length == 3) {
477 InternalScene scene = sceneMan.getInternalScene(id);
479 sceneMan.removeInternalScene(id);
480 sceneMan.addInternalScene(scene);
483 devStatMan.removeDevice(id);
488 * Delegate a stop command from a Thing to the {@link DeviceStatusManager#sendStopComandsToDSS(Device)}.
490 * @param device can be null
492 public void stopOutputValue(Device device) {
493 this.devStatMan.sendStopComandsToDSS(device);
497 public void channelLinked(ChannelUID channelUID) {
498 if (devStatMan != null) {
499 MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
500 if (meteringType != null) {
501 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
502 onEnergyMeterValueChanged(devStatMan.getTotalEnergyMeterValue());
504 onTotalPowerConsumptionChanged(devStatMan.getTotalPowerConsumption());
507 logger.warn("Channel with id {} is not known for the thing with id {}.", channelUID.getId(),
508 getThing().getUID());
514 public void onTotalPowerConsumptionChanged(int newPowerConsumption) {
515 updateChannelState(MeteringTypeEnum.CONSUMPTION, MeteringUnitsEnum.WH, newPowerConsumption);
519 public void onEnergyMeterValueChanged(int newEnergyMeterValue) {
520 updateChannelState(MeteringTypeEnum.ENERGY, MeteringUnitsEnum.WH, newEnergyMeterValue * 0.001);
524 public void onEnergyMeterWsValueChanged(int newEnergyMeterValue) {
528 private void updateChannelState(MeteringTypeEnum meteringType, MeteringUnitsEnum meteringUnit, double value) {
529 String channelID = DsChannelTypeProvider.getMeteringChannelID(meteringType, meteringUnit, true);
530 if (getThing().getChannel(channelID) != null) {
531 updateState(channelID, new DecimalType(value));
536 public void onConnectionStateChange(String newConnectionState) {
537 switch (newConnectionState) {
538 case CONNECTION_LOST:
539 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
540 "The connection to the digitalSTROM-Server cannot be established.");
541 startReconnectTracker();
543 case CONNECTION_RESUMED:
544 if (connectionTimeoutCounter > 0) {
545 // reset connection timeout counter
546 connectionTimeoutCounter = 0;
547 if (connMan.checkConnection()) {
549 setStatus(ThingStatus.ONLINE);
553 case APPLICATION_TOKEN_GENERATED:
554 if (connMan != null) {
555 Configuration config = this.getConfig();
556 config.remove(USER_NAME);
557 config.remove(PASSWORD);
558 config.put(APPLICATION_TOKEN, connMan.getApplicationToken());
559 this.updateConfiguration(config);
567 private void setStatus(ThingStatus status) {
568 logger.debug("set status to: {}", status);
569 updateStatus(status);
570 for (Thing thing : getThing().getThings()) {
571 ThingHandler handler = thing.getHandler();
572 if (handler != null) {
573 handler.bridgeStatusChanged(getThing().getStatusInfo());
578 private void startReconnectTracker() {
579 if (reconnectTracker == null || reconnectTracker.isCancelled()) {
580 logger.debug("Connection lost, stop all services and start reconnectTracker.");
582 reconnectTracker = scheduler.scheduleWithFixedDelay(new Runnable() {
586 if (connMan != null) {
587 boolean conStat = connMan.checkConnection();
588 logger.debug("check connection = {}", conStat);
591 reconnectTracker.cancel(false);
595 }, RECONNECT_TRACKER_INTERVAL, RECONNECT_TRACKER_INTERVAL, TimeUnit.SECONDS);
599 private void stopServices() {
600 if (devStatMan != null && !devStatMan.getManagerState().equals(ManagerStates.STOPPED)) {
603 if (eventListener != null && eventListener.isStarted()) {
604 eventListener.stop();
608 private void restartServices() {
609 logger.debug("reconnect, stop reconnection tracker and restart services");
610 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
611 reconnectTracker.cancel(true);
614 if (devStatMan != null) {
617 if (eventListener != null) {
618 eventListener.start();
623 public void onConnectionStateChange(String newConnectionState, String reason) {
624 if (newConnectionState.equals(NOT_AUTHENTICATED) || newConnectionState.equals(CONNECTION_LOST)) {
626 case WRONG_APP_TOKEN:
627 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
628 "User defined Application-Token is wrong. "
629 + "Please set user name and password to generate an Application-Token or set an valid Application-Token.");
632 case WRONG_USER_OR_PASSWORD:
633 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
634 "The set username or password is wrong.");
637 case NO_USER_PASSWORD:
638 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
639 "No username or password is set to generate Application-Token. Please set user name and password or Application-Token.");
642 case CONNECTON_TIMEOUT:
643 // ignore the first connection timeout
644 if (connectionTimeoutCounter++ > ignoredTimeouts) {
645 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
646 "Connection lost because connection timeout to Server.");
652 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
653 "Server not found! Please check these points:\n" + " - Is digitalSTROM-Server turned on?\n"
654 + " - Is the host address correct?\n"
655 + " - Is the ethernet cable connection established?");
658 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
659 "Unknown host name, please check the set host name!");
662 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid URL is set.");
664 case CONNECTION_LOST:
665 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
666 "IOException / Connection lost.");
668 case SSL_HANDSHAKE_ERROR:
669 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
670 "SSL Handshake error / Connection lost.");
673 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
675 // reset connection timeout counter
676 connectionTimeoutCounter = 0;
677 startReconnectTracker();
682 * Returns a list of all {@link Device}'s.
684 * @return device list (cannot be null)
686 public List<Device> getDevices() {
687 return this.structMan != null && this.structMan.getDeviceMap() != null
688 ? new LinkedList<>(this.structMan.getDeviceMap().values())
693 * Returns the {@link StructureManager}.
695 * @return StructureManager
697 public StructureManager getStructureManager() {
698 return this.structMan;
702 * Delegates a scene command of a Thing to the
703 * {@link DeviceStatusManager#sendSceneComandsToDSS(InternalScene, boolean)}
705 * @param scene the called scene
706 * @param call_undo (true = call scene | false = undo scene)
708 public void sendSceneComandToDSS(InternalScene scene, boolean call_undo) {
709 if (devStatMan != null) {
710 devStatMan.sendSceneComandsToDSS(scene, call_undo);
715 * Delegates a device command of a Thing to the
716 * {@link DeviceStatusManager#sendComandsToDSS(Device, DeviceStateUpdate)}
718 * @param device can be null
719 * @param deviceStateUpdate can be null
721 public void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
722 if (devStatMan != null) {
723 devStatMan.sendComandsToDSS(device, deviceStateUpdate);
728 * Returns a list of all {@link InternalScene}'s.
730 * @return Scene list (cannot be null)
732 public List<InternalScene> getScenes() {
733 return sceneMan != null ? sceneMan.getScenes() : new LinkedList<>();
737 * Returns the {@link ConnectionManager}.
739 * @return ConnectionManager
741 public ConnectionManager getConnectionManager() {
746 public void onStatusChanged(ManagerTypes managerType, ManagerStates state) {
747 if (managerType.equals(ManagerTypes.DEVICE_STATUS_MANAGER)) {
750 if (deviceDiscovery != null) {
751 devStatMan.registerDeviceListener(deviceDiscovery);
752 deviceDiscovery = null;
754 logger.debug("Building digitalSTROM model");
757 updateStatus(ThingStatus.ONLINE);
760 if (!getThing().getStatusInfo().getStatusDetail().equals(ThingStatusDetail.COMMUNICATION_ERROR)
761 && !getThing().getStatusInfo().getStatusDetail()
762 .equals(ThingStatusDetail.CONFIGURATION_ERROR)) {
763 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "DeviceStatusManager is stopped.");
771 if (managerType.equals(ManagerTypes.SCENE_MANAGER)) {
773 case GENERATING_SCENES:
774 logger.debug("SceneManager reports that he is generating scenes");
775 if (sceneDiscovery != null) {
776 sceneMan.registerSceneListener(sceneDiscovery);
777 sceneDiscovery = null;
781 logger.debug("SceneManager reports that he is running");
790 * Returns a {@link List} of all {@link Circuit}'s.
792 * @return circuit list
794 public List<Circuit> getCircuits() {
795 logger.debug("circuits: {}", structMan.getCircuitMap().values().toString());
796 return structMan != null && structMan.getCircuitMap() != null
797 ? new LinkedList<>(structMan.getCircuitMap().values())
802 * Returns the {@link TemperatureControlManager} or null if no one exist.
804 * @return {@link TemperatureControlManager}
806 public TemperatureControlManager getTemperatureControlManager() {
811 * Registers the given {@link TemperatureControlStatusListener} to the {@link TemperatureControlManager}.
813 * @param temperatureControlStatusListener can be null
815 public void registerTemperatureControlStatusListener(
816 TemperatureControlStatusListener temperatureControlStatusListener) {
817 if (tempContMan != null) {
818 tempContMan.registerTemperatureControlStatusListener(temperatureControlStatusListener);
819 } else if (TemperatureControlStatusListener.DISCOVERY
820 .equals(temperatureControlStatusListener.getTemperationControlStatusListenrID())) {
821 this.temperatureControlDiscovery = temperatureControlStatusListener;
826 * Unregisters the given {@link TemperatureControlStatusListener} from the {@link TemperatureControlManager}.
828 * @param temperatureControlStatusListener can be null
830 public void unregisterTemperatureControlStatusListener(
831 TemperatureControlStatusListener temperatureControlStatusListener) {
832 if (tempContMan != null) {
833 tempContMan.unregisterTemperatureControlStatusListener(temperatureControlStatusListener);
838 * see {@link TemperatureControlManager#getTemperatureControlStatusFromAllZones()}
840 * @return all temperature control status objects
842 public Collection<TemperatureControlStatus> getTemperatureControlStatusFromAllZones() {
843 return tempContMan != null ? tempContMan.getTemperatureControlStatusFromAllZones() : new LinkedList<>();