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.thing.binding.builder.ThingStatusInfoBuilder;
68 import org.openhab.core.types.Command;
69 import org.openhab.core.types.RefreshType;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
74 * The {@link BridgeHandler} is the handler for a digitalSTROM-Server and connects it to
76 * All {@link DeviceHandler}s and {@link SceneHandler}s use the {@link BridgeHandler} to execute the actual
79 * The {@link BridgeHandler} also:
81 * <li>manages the {@link DeviceStatusManager} (starts, stops, register {@link DeviceStatusListener},
82 * register {@link SceneStatusListener} and so on)</li>
83 * <li>creates and load the configurations in the {@link Config}.</li>
84 * <li>implements {@link ManagerStatusListener} to manage the expiration of the Thing initializations</li>
85 * <li>implements the {@link ConnectionListener} to manage the {@link ThingStatus} of this {@link BridgeHandler}</li>
86 * <li>and implements the {@link TotalPowerConsumptionListener} to update his Channels.</li>
89 * @author Michael Ochel - Initial contribution
90 * @author Matthias Siegele - Initial contribution
92 public class BridgeHandler extends BaseBridgeHandler
93 implements ConnectionListener, TotalPowerConsumptionListener, ManagerStatusListener {
95 private final Logger logger = LoggerFactory.getLogger(BridgeHandler.class);
98 * Contains all supported thing types of this handler
100 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DSS_BRIDGE);
102 private static final long RECONNECT_TRACKER_INTERVAL = 15;
105 private ConnectionManager connMan;
106 private StructureManager structMan;
107 private SceneManager sceneMan;
108 private DeviceStatusManager devStatMan;
109 private TemperatureControlManager tempContMan;
111 private EventListener eventListener;
112 private ScheduledFuture<?> reconnectTracker;
114 private DeviceStatusListener deviceDiscovery;
115 private SceneStatusListener sceneDiscovery;
116 private TemperatureControlStatusListener temperatureControlDiscovery;
117 private Config config;
119 List<SceneStatusListener> unregisterSceneStatusListeners;
120 private short connectionTimeoutCounter = 0;
121 private final short ignoredTimeouts = 5;
123 private class Initializer implements Runnable {
125 BridgeHandler bridge;
128 public Initializer(BridgeHandler bridge, Config config) {
129 this.bridge = bridge;
130 this.config = config;
135 logger.debug("Checking connection");
136 if (connMan == null) {
137 connMan = new ConnectionManagerImpl(config, bridge, true);
139 connMan.registerConnectionListener(bridge);
140 connMan.configHasBeenUpdated();
143 logger.debug("Initializing digitalSTROM Manager ");
144 if (eventListener == null) {
145 eventListener = new EventListener(connMan);
147 if (structMan == null) {
148 structMan = new StructureManagerImpl();
150 if (sceneMan == null) {
151 sceneMan = new SceneManagerImpl(connMan, structMan, bridge, eventListener);
153 if (devStatMan == null) {
154 devStatMan = new DeviceStatusManagerImpl(connMan, structMan, sceneMan, bridge, eventListener);
156 devStatMan.registerStatusListener(bridge);
159 devStatMan.registerTotalPowerConsumptionListener(bridge);
161 if (connMan.checkConnection()) {
162 logger.debug("connection established, start services");
163 if (TemperatureControlManager.isHeatingControllerInstallated(connMan)) {
164 if (tempContMan == null) {
165 tempContMan = new TemperatureControlManager(connMan, eventListener,
166 temperatureControlDiscovery);
167 temperatureControlDiscovery = null;
169 if (temperatureControlDiscovery != null) {
170 tempContMan.registerTemperatureControlStatusListener(temperatureControlDiscovery);
174 structMan.generateZoneGroupNames(connMan);
176 eventListener.start();
179 boolean configChanged = false;
180 Configuration configuration = bridge.getConfig();
181 if (connMan.getApplicationToken() != null) {
182 configuration.remove(USER_NAME);
183 configuration.remove(PASSWORD);
184 logger.debug("Application-Token is: {}", connMan.getApplicationToken());
185 configuration.put(APPLICATION_TOKEN, connMan.getApplicationToken());
186 configChanged = true;
188 Map<String, String> properties = editProperties();
189 String dSSname = connMan.getDigitalSTROMAPI().getInstallationName(connMan.getSessionToken());
190 if (dSSname != null) {
191 properties.put(DS_NAME, dSSname);
193 Map<String, String> dsidMap = connMan.getDigitalSTROMAPI().getDSID(connMan.getSessionToken());
194 if (dsidMap != null) {
195 logger.debug("{}", dsidMap);
196 properties.putAll(dsidMap);
198 Map<String, String> versions = connMan.getDigitalSTROMAPI().getSystemVersion();
199 if (versions != null) {
200 properties.putAll(versions);
202 if (StringUtils.isBlank(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT))
203 && StringUtils.isNotBlank(config.getCert())) {
204 properties.put(DigitalSTROMBindingConstants.SERVER_CERT, config.getCert());
206 logger.debug("update properties");
207 updateProperties(properties);
210 updateConfiguration(configuration);
216 * Creates a new {@link BridgeHandler}.
218 * @param bridge must not be null
220 public BridgeHandler(Bridge bridge) {
225 public void initialize() {
226 logger.debug("Initializing digitalSTROM-BridgeHandler");
227 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING, "Checking configuration...");
228 // Start an extra thread to readout the configuration and check the connection, because it takes sometimes more
229 // than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
230 Config config = loadAndCheckConfig();
232 if (config != null) {
233 logger.debug("{}", config.toString());
234 scheduler.execute(new Initializer(this, config));
238 private boolean checkLoginConfig(Config config) {
239 if ((StringUtils.isNotBlank(config.getUserName()) && StringUtils.isNotBlank(config.getPassword()))
240 || StringUtils.isNotBlank(config.getAppToken())) {
243 onConnectionStateChange(CONNECTION_LOST, NO_USER_PASSWORD);
247 private Config loadAndCheckConfig() {
248 Configuration thingConfig = super.getConfig();
249 Config config = loadAndCheckConnectionData(thingConfig);
250 if (config == null) {
253 logger.debug("Loading configuration");
254 List<String> numberExc = new ArrayList<>();
255 // Parameters can't be null, because of an existing default value.
256 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) instanceof BigDecimal) {
257 config.setSensordataRefreshInterval(
258 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL)).intValue()
261 numberExc.add("\"Sensor update interval\" ( "
262 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) + ")");
264 if (thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) instanceof BigDecimal) {
265 config.setTotalPowerUpdateInterval(
266 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL)).intValue()
269 numberExc.add("\"Total power update interval\" ("
270 + thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) + ")");
272 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) instanceof BigDecimal) {
273 config.setSensorReadingWaitTime(
274 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME)).intValue() * 1000);
276 numberExc.add("\"Wait time sensor reading\" ("
277 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) + ")");
279 if (thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) instanceof BigDecimal) {
280 config.setTrashDeviceDeleteTime(
281 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY))
284 numberExc.add("\"Days to be slaked trash bin devices\" ("
285 + thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) + ")");
287 if (!numberExc.isEmpty()) {
288 String excText = "The field ";
289 for (int i = 0; i < numberExc.size(); i++) {
290 excText = excText + numberExc.get(i);
291 if (i < numberExc.size() - 2) {
292 excText = excText + ", ";
293 } else if (i < numberExc.size() - 1) {
294 excText = excText + " and ";
297 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, excText + " have to be a number.");
300 if (StringUtils.isNotBlank(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT))) {
301 config.setCert(getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT));
306 private Config loadAndCheckConnectionData(Configuration thingConfig) {
307 if (this.config == null) {
308 this.config = new Config();
310 // load and check connection and authorization data
311 if (StringUtils.isNotBlank((String) thingConfig.get(HOST))) {
312 config.setHost(thingConfig.get(HOST).toString());
314 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
315 "The connection to the digitalSTROM-Server can't established, because the host address is missing. Please set the host address.");
318 if (thingConfig.get(USER_NAME) != null) {
319 config.setUserName(thingConfig.get(USER_NAME).toString());
321 config.setUserName(null);
323 if (thingConfig.get(PASSWORD) != null) {
324 config.setPassword(thingConfig.get(PASSWORD).toString());
326 config.setPassword(null);
328 if (thingConfig.get(APPLICATION_TOKEN) != null) {
329 config.setAppToken(thingConfig.get(APPLICATION_TOKEN).toString());
331 config.setAppToken(null);
334 if (!checkLoginConfig(config)) {
341 public void dispose() {
342 logger.debug("Handler disposed");
343 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
344 reconnectTracker.cancel(true);
346 if (eventListener != null) {
347 eventListener.stop();
349 if (devStatMan != null) {
350 devStatMan.unregisterTotalPowerConsumptionListener();
351 devStatMan.unregisterStatusListener();
352 this.devStatMan.stop();
354 if (connMan != null) {
355 connMan.unregisterConnectionListener();
360 public void handleCommand(ChannelUID channelUID, Command command) {
361 if (command instanceof RefreshType) {
362 channelLinked(channelUID);
364 logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
369 public void handleRemoval() {
370 for (Thing thing : getThing().getThings()) {
371 // Inform Thing-Child's about removed bridge.
372 final ThingHandler thingHandler = thing.getHandler();
373 if (thingHandler != null) {
374 thingHandler.bridgeStatusChanged(ThingStatusInfoBuilder.create(ThingStatus.REMOVED).build());
377 if (StringUtils.isNotBlank((String) super.getConfig().get(APPLICATION_TOKEN))) {
378 if (connMan == null) {
379 Config config = loadAndCheckConnectionData(this.getConfig());
380 if (config != null) {
381 this.connMan = new ConnectionManagerImpl(config, null, false);
383 updateStatus(ThingStatus.REMOVED);
387 if (connMan.removeApplicationToken()) {
388 logger.debug("Application-Token deleted");
391 updateStatus(ThingStatus.REMOVED);
394 /* methods to store listener */
397 * Registers a new {@link DeviceStatusListener} on the {@link DeviceStatusManager}.
399 * @param deviceStatusListener (must not be null)
401 public synchronized void registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
402 if (this.devStatMan != null) {
403 if (deviceStatusListener == null) {
404 throw new IllegalArgumentException("It's not allowed to pass null.");
407 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
408 if (devStatMan.getManagerState().equals(ManagerStates.RUNNING)) {
409 devStatMan.registerDeviceListener(deviceStatusListener);
410 } else if (deviceStatusListener.getDeviceStatusListenerID()
411 .equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
412 devStatMan.registerDeviceListener(deviceStatusListener);
415 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
418 if (deviceStatusListener.getDeviceStatusListenerID().equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
419 deviceDiscovery = deviceStatusListener;
425 * Unregisters a new {@link DeviceStatusListener} on the {@link BridgeHandler}.
427 * @param deviceStatusListener (must not be null)
429 public void unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
430 if (this.devStatMan != null) {
431 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
432 this.devStatMan.unregisterDeviceListener(deviceStatusListener);
434 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
440 * Registers a new {@link SceneStatusListener} on the {@link BridgeHandler}.
442 * @param sceneStatusListener (must not be null)
444 public synchronized void registerSceneStatusListener(SceneStatusListener sceneStatusListener) {
445 if (this.sceneMan != null) {
446 if (sceneStatusListener == null) {
447 throw new IllegalArgumentException("It's not allowed to pass null.");
450 if (sceneStatusListener.getSceneStatusListenerID() != null) {
451 this.sceneMan.registerSceneListener(sceneStatusListener);
453 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null.");
456 if (sceneStatusListener.getSceneStatusListenerID().equals(SceneStatusListener.SCENE_DISCOVERY)) {
457 sceneDiscovery = sceneStatusListener;
463 * Unregisters a new {@link SceneStatusListener} on the {@link DeviceStatusManager}.
465 * @param sceneStatusListener (must not be null)
467 public void unregisterSceneStatusListener(SceneStatusListener sceneStatusListener) {
468 if (this.sceneMan != null) {
469 if (sceneStatusListener.getSceneStatusListenerID() != null) {
470 this.sceneMan.unregisterSceneListener(sceneStatusListener);
472 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null..");
478 * Has to be called from a removed Thing-Child to rediscovers the Thing.
480 * @param id = scene or device id (must not be null)
482 public void childThingRemoved(String id) {
483 if (id != null && id.split("-").length == 3) {
484 InternalScene scene = sceneMan.getInternalScene(id);
486 sceneMan.removeInternalScene(id);
487 sceneMan.addInternalScene(scene);
490 devStatMan.removeDevice(id);
495 * Delegate a stop command from a Thing to the {@link DeviceStatusManager#sendStopComandsToDSS(Device)}.
497 * @param device can be null
499 public void stopOutputValue(Device device) {
500 this.devStatMan.sendStopComandsToDSS(device);
504 public void channelLinked(ChannelUID channelUID) {
505 if (devStatMan != null) {
506 MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
507 if (meteringType != null) {
508 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
509 onEnergyMeterValueChanged(devStatMan.getTotalEnergyMeterValue());
511 onTotalPowerConsumptionChanged(devStatMan.getTotalPowerConsumption());
514 logger.warn("Channel with id {} is not known for the thing with id {}.", channelUID.getId(),
515 getThing().getUID());
521 public void onTotalPowerConsumptionChanged(int newPowerConsumption) {
522 updateChannelState(MeteringTypeEnum.CONSUMPTION, MeteringUnitsEnum.WH, newPowerConsumption);
526 public void onEnergyMeterValueChanged(int newEnergyMeterValue) {
527 updateChannelState(MeteringTypeEnum.ENERGY, MeteringUnitsEnum.WH, newEnergyMeterValue * 0.001);
531 public void onEnergyMeterWsValueChanged(int newEnergyMeterValue) {
535 private void updateChannelState(MeteringTypeEnum meteringType, MeteringUnitsEnum meteringUnit, double value) {
536 String channelID = DsChannelTypeProvider.getMeteringChannelID(meteringType, meteringUnit, true);
537 if (getThing().getChannel(channelID) != null) {
538 updateState(channelID, new DecimalType(value));
543 public void onConnectionStateChange(String newConnectionState) {
544 switch (newConnectionState) {
545 case CONNECTION_LOST:
546 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
547 "The connection to the digitalSTROM-Server cannot be established.");
548 startReconnectTracker();
550 case CONNECTION_RESUMED:
551 if (connectionTimeoutCounter > 0) {
552 // reset connection timeout counter
553 connectionTimeoutCounter = 0;
554 if (connMan.checkConnection()) {
556 setStatus(ThingStatus.ONLINE);
560 case APPLICATION_TOKEN_GENERATED:
561 if (connMan != null) {
562 Configuration config = this.getConfig();
563 config.remove(USER_NAME);
564 config.remove(PASSWORD);
565 config.put(APPLICATION_TOKEN, connMan.getApplicationToken());
566 this.updateConfiguration(config);
574 private void setStatus(ThingStatus status) {
575 logger.debug("set status to: {}", status);
576 updateStatus(status);
577 for (Thing thing : getThing().getThings()) {
578 ThingHandler handler = thing.getHandler();
579 if (handler != null) {
580 handler.bridgeStatusChanged(getThing().getStatusInfo());
585 private void startReconnectTracker() {
586 if (reconnectTracker == null || reconnectTracker.isCancelled()) {
587 logger.debug("Connection lost, stop all services and start reconnectTracker.");
589 reconnectTracker = scheduler.scheduleWithFixedDelay(new Runnable() {
593 if (connMan != null) {
594 boolean conStat = connMan.checkConnection();
595 logger.debug("check connection = {}", conStat);
598 reconnectTracker.cancel(false);
602 }, RECONNECT_TRACKER_INTERVAL, RECONNECT_TRACKER_INTERVAL, TimeUnit.SECONDS);
606 private void stopServices() {
607 if (devStatMan != null && !devStatMan.getManagerState().equals(ManagerStates.STOPPED)) {
610 if (eventListener != null && eventListener.isStarted()) {
611 eventListener.stop();
615 private void restartServices() {
616 logger.debug("reconnect, stop reconnection tracker and restart services");
617 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
618 reconnectTracker.cancel(true);
621 if (devStatMan != null) {
624 if (eventListener != null) {
625 eventListener.start();
630 public void onConnectionStateChange(String newConnectionState, String reason) {
631 if (newConnectionState.equals(NOT_AUTHENTICATED) || newConnectionState.equals(CONNECTION_LOST)) {
633 case WRONG_APP_TOKEN:
634 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
635 "User defined Application-Token is wrong. "
636 + "Please set user name and password to generate an Application-Token or set an 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:\n" + " - Is digitalSTROM-Server turned on?\n"
661 + " - Is the host address correct?\n"
662 + " - Is the ethernet cable connection established?");
665 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
666 "Unknown host name, please check the set host name!");
669 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid URL is set.");
671 case CONNECTION_LOST:
672 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
673 "IOException / Connection lost.");
675 case SSL_HANDSHAKE_ERROR:
676 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
677 "SSL Handshake error / Connection lost.");
680 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
682 // reset connection timeout counter
683 connectionTimeoutCounter = 0;
684 startReconnectTracker();
689 * Returns a list of all {@link Device}'s.
691 * @return device list (cannot be null)
693 public List<Device> getDevices() {
694 return this.structMan != null && this.structMan.getDeviceMap() != null
695 ? new LinkedList<>(this.structMan.getDeviceMap().values())
700 * Returns the {@link StructureManager}.
702 * @return StructureManager
704 public StructureManager getStructureManager() {
705 return this.structMan;
709 * Delegates a scene command of a Thing to the
710 * {@link DeviceStatusManager#sendSceneComandsToDSS(InternalScene, boolean)}
712 * @param scene the called scene
713 * @param call_undo (true = call scene | false = undo scene)
715 public void sendSceneComandToDSS(InternalScene scene, boolean call_undo) {
716 if (devStatMan != null) {
717 devStatMan.sendSceneComandsToDSS(scene, call_undo);
722 * Delegates a device command of a Thing to the
723 * {@link DeviceStatusManager#sendComandsToDSS(Device, DeviceStateUpdate)}
725 * @param device can be null
726 * @param deviceStateUpdate can be null
728 public void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
729 if (devStatMan != null) {
730 devStatMan.sendComandsToDSS(device, deviceStateUpdate);
735 * Returns a list of all {@link InternalScene}'s.
737 * @return Scene list (cannot be null)
739 public List<InternalScene> getScenes() {
740 return sceneMan != null ? sceneMan.getScenes() : new LinkedList<>();
744 * Returns the {@link ConnectionManager}.
746 * @return ConnectionManager
748 public ConnectionManager getConnectionManager() {
753 public void onStatusChanged(ManagerTypes managerType, ManagerStates state) {
754 if (managerType.equals(ManagerTypes.DEVICE_STATUS_MANAGER)) {
757 if (deviceDiscovery != null) {
758 devStatMan.registerDeviceListener(deviceDiscovery);
759 deviceDiscovery = null;
761 logger.debug("Building digitalSTROM model");
764 updateStatus(ThingStatus.ONLINE);
767 if (!getThing().getStatusInfo().getStatusDetail().equals(ThingStatusDetail.COMMUNICATION_ERROR)
768 && !getThing().getStatusInfo().getStatusDetail()
769 .equals(ThingStatusDetail.CONFIGURATION_ERROR)) {
770 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "DeviceStatusManager is stopped.");
778 if (managerType.equals(ManagerTypes.SCENE_MANAGER)) {
780 case GENERATING_SCENES:
781 logger.debug("SceneManager reports that he is generating scenes");
782 if (sceneDiscovery != null) {
783 sceneMan.registerSceneListener(sceneDiscovery);
784 sceneDiscovery = null;
788 logger.debug("SceneManager reports that he is running");
797 * Returns a {@link List} of all {@link Circuit}'s.
799 * @return circuit list
801 public List<Circuit> getCircuits() {
802 logger.debug("circuits: {}", structMan.getCircuitMap().values().toString());
803 return structMan != null && structMan.getCircuitMap() != null
804 ? new LinkedList<>(structMan.getCircuitMap().values())
809 * Returns the {@link TemperatureControlManager} or null if no one exist.
811 * @return {@link TemperatureControlManager}
813 public TemperatureControlManager getTemperatureControlManager() {
818 * Registers the given {@link TemperatureControlStatusListener} to the {@link TemperatureControlManager}.
820 * @param temperatureControlStatusListener can be null
822 public void registerTemperatureControlStatusListener(
823 TemperatureControlStatusListener temperatureControlStatusListener) {
824 if (tempContMan != null) {
825 tempContMan.registerTemperatureControlStatusListener(temperatureControlStatusListener);
826 } else if (TemperatureControlStatusListener.DISCOVERY
827 .equals(temperatureControlStatusListener.getTemperationControlStatusListenrID())) {
828 this.temperatureControlDiscovery = temperatureControlStatusListener;
833 * Unregisters the given {@link TemperatureControlStatusListener} from the {@link TemperatureControlManager}.
835 * @param temperatureControlStatusListener can be null
837 public void unregisterTemperatureControlStatusListener(
838 TemperatureControlStatusListener temperatureControlStatusListener) {
839 if (tempContMan != null) {
840 tempContMan.unregisterTemperatureControlStatusListener(temperatureControlStatusListener);
845 * see {@link TemperatureControlManager#getTemperatureControlStatusFromAllZones()}
847 * @return all temperature control status objects
849 public Collection<TemperatureControlStatus> getTemperatureControlStatusFromAllZones() {
850 return tempContMan != null ? tempContMan.getTemperatureControlStatusFromAllZones() : new LinkedList<>();