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.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.openhab.binding.digitalstrom.internal.DigitalSTROMBindingConstants;
29 import org.openhab.binding.digitalstrom.internal.lib.climate.jsonresponsecontainer.impl.TemperatureControlStatus;
30 import org.openhab.binding.digitalstrom.internal.lib.config.Config;
31 import org.openhab.binding.digitalstrom.internal.lib.event.EventListener;
32 import org.openhab.binding.digitalstrom.internal.lib.listener.ConnectionListener;
33 import org.openhab.binding.digitalstrom.internal.lib.listener.DeviceStatusListener;
34 import org.openhab.binding.digitalstrom.internal.lib.listener.ManagerStatusListener;
35 import org.openhab.binding.digitalstrom.internal.lib.listener.SceneStatusListener;
36 import org.openhab.binding.digitalstrom.internal.lib.listener.TemperatureControlStatusListener;
37 import org.openhab.binding.digitalstrom.internal.lib.listener.TotalPowerConsumptionListener;
38 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerStates;
39 import org.openhab.binding.digitalstrom.internal.lib.listener.stateenums.ManagerTypes;
40 import org.openhab.binding.digitalstrom.internal.lib.manager.ConnectionManager;
41 import org.openhab.binding.digitalstrom.internal.lib.manager.DeviceStatusManager;
42 import org.openhab.binding.digitalstrom.internal.lib.manager.SceneManager;
43 import org.openhab.binding.digitalstrom.internal.lib.manager.StructureManager;
44 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.ConnectionManagerImpl;
45 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.DeviceStatusManagerImpl;
46 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.SceneManagerImpl;
47 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.StructureManagerImpl;
48 import org.openhab.binding.digitalstrom.internal.lib.manager.impl.TemperatureControlManager;
49 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Circuit;
50 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.Device;
51 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.DeviceStateUpdate;
52 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringTypeEnum;
53 import org.openhab.binding.digitalstrom.internal.lib.structure.devices.deviceparameters.constants.MeteringUnitsEnum;
54 import org.openhab.binding.digitalstrom.internal.lib.structure.scene.InternalScene;
55 import org.openhab.binding.digitalstrom.internal.providers.DsChannelTypeProvider;
56 import org.openhab.core.config.core.Configuration;
57 import org.openhab.core.library.types.DecimalType;
58 import org.openhab.core.thing.Bridge;
59 import org.openhab.core.thing.ChannelUID;
60 import org.openhab.core.thing.Thing;
61 import org.openhab.core.thing.ThingStatus;
62 import org.openhab.core.thing.ThingStatusDetail;
63 import org.openhab.core.thing.ThingTypeUID;
64 import org.openhab.core.thing.binding.BaseBridgeHandler;
65 import org.openhab.core.thing.binding.ThingHandler;
66 import org.openhab.core.types.Command;
67 import org.openhab.core.types.RefreshType;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
72 * The {@link BridgeHandler} is the handler for a digitalSTROM-Server and connects it to
74 * All {@link DeviceHandler}s and {@link SceneHandler}s use the {@link BridgeHandler} to execute the actual
77 * The {@link BridgeHandler} also:
79 * <li>manages the {@link DeviceStatusManager} (starts, stops, register {@link DeviceStatusListener},
80 * register {@link SceneStatusListener} and so on)</li>
81 * <li>creates and load the configurations in the {@link Config}.</li>
82 * <li>implements {@link ManagerStatusListener} to manage the expiration of the Thing initializations</li>
83 * <li>implements the {@link ConnectionListener} to manage the {@link ThingStatus} of this {@link BridgeHandler}</li>
84 * <li>and implements the {@link TotalPowerConsumptionListener} to update his Channels.</li>
87 * @author Michael Ochel - Initial contribution
88 * @author Matthias Siegele - Initial contribution
90 public class BridgeHandler extends BaseBridgeHandler
91 implements ConnectionListener, TotalPowerConsumptionListener, ManagerStatusListener {
93 private final Logger logger = LoggerFactory.getLogger(BridgeHandler.class);
96 * Contains all supported thing types of this handler
98 public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DSS_BRIDGE);
100 private static final long RECONNECT_TRACKER_INTERVAL = 15;
103 private ConnectionManager connMan;
104 private StructureManager structMan;
105 private SceneManager sceneMan;
106 private DeviceStatusManager devStatMan;
107 private TemperatureControlManager tempContMan;
109 private EventListener eventListener;
110 private ScheduledFuture<?> reconnectTracker;
112 private DeviceStatusListener deviceDiscovery;
113 private SceneStatusListener sceneDiscovery;
114 private TemperatureControlStatusListener temperatureControlDiscovery;
115 private Config config;
117 List<SceneStatusListener> unregisterSceneStatusListeners;
118 private short connectionTimeoutCounter = 0;
119 private final short ignoredTimeouts = 5;
121 private class Initializer implements Runnable {
123 BridgeHandler bridge;
126 public Initializer(BridgeHandler bridge, Config config) {
127 this.bridge = bridge;
128 this.config = config;
133 logger.debug("Checking connection");
134 if (connMan == null) {
135 connMan = new ConnectionManagerImpl(config, bridge, true);
137 connMan.registerConnectionListener(bridge);
138 connMan.configHasBeenUpdated();
141 logger.debug("Initializing digitalSTROM Manager ");
142 if (eventListener == null) {
143 eventListener = new EventListener(connMan);
145 if (structMan == null) {
146 structMan = new StructureManagerImpl();
148 if (sceneMan == null) {
149 sceneMan = new SceneManagerImpl(connMan, structMan, bridge, eventListener);
151 if (devStatMan == null) {
152 devStatMan = new DeviceStatusManagerImpl(connMan, structMan, sceneMan, bridge, eventListener);
154 devStatMan.registerStatusListener(bridge);
157 devStatMan.registerTotalPowerConsumptionListener(bridge);
159 if (connMan.checkConnection()) {
160 logger.debug("connection established, start services");
161 if (TemperatureControlManager.isHeatingControllerInstallated(connMan)) {
162 if (tempContMan == null) {
163 tempContMan = new TemperatureControlManager(connMan, eventListener,
164 temperatureControlDiscovery);
165 temperatureControlDiscovery = null;
167 if (temperatureControlDiscovery != null) {
168 tempContMan.registerTemperatureControlStatusListener(temperatureControlDiscovery);
172 structMan.generateZoneGroupNames(connMan);
174 eventListener.start();
177 boolean configChanged = false;
178 Configuration configuration = bridge.getConfig();
179 if (connMan.getApplicationToken() != null) {
180 configuration.remove(USER_NAME);
181 configuration.remove(PASSWORD);
182 logger.debug("Application-Token is: {}", connMan.getApplicationToken());
183 configuration.put(APPLICATION_TOKEN, connMan.getApplicationToken());
184 configChanged = true;
186 Map<String, String> properties = editProperties();
187 String dSSname = connMan.getDigitalSTROMAPI().getInstallationName(connMan.getSessionToken());
188 if (dSSname != null) {
189 properties.put(DS_NAME, dSSname);
191 Map<String, String> dsidMap = connMan.getDigitalSTROMAPI().getDSID(connMan.getSessionToken());
192 if (dsidMap != null) {
193 logger.debug("{}", dsidMap);
194 properties.putAll(dsidMap);
196 Map<String, String> versions = connMan.getDigitalSTROMAPI().getSystemVersion();
197 if (versions != null) {
198 properties.putAll(versions);
200 String certProperty = getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT);
201 String certConfig = config.getCert();
202 if ((certProperty == null || certProperty.isBlank()) && (certConfig != null && !certConfig.isBlank())) {
203 properties.put(DigitalSTROMBindingConstants.SERVER_CERT, certConfig);
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 String userName = config.getUserName();
239 String password = config.getPassword();
240 String appToken = config.getAppToken();
242 if (((userName != null && !userName.isBlank()) && (password != null && !password.isBlank()))
243 || (appToken != null && !appToken.isBlank())) {
246 onConnectionStateChange(CONNECTION_LOST, NO_USER_PASSWORD);
250 private Config loadAndCheckConfig() {
251 Configuration thingConfig = super.getConfig();
252 Config config = loadAndCheckConnectionData(thingConfig);
253 if (config == null) {
256 logger.debug("Loading configuration");
257 List<String> numberExc = new ArrayList<>();
258 // Parameters can't be null, because of an existing default value.
259 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) instanceof BigDecimal) {
260 config.setSensordataRefreshInterval(
261 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL)).intValue()
264 numberExc.add("\"Sensor update interval\" ( "
265 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_DATA_UPDATE_INTERVAL) + ")");
267 if (thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) instanceof BigDecimal) {
268 config.setTotalPowerUpdateInterval(
269 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL)).intValue()
272 numberExc.add("\"Total power update interval\" ("
273 + thingConfig.get(DigitalSTROMBindingConstants.TOTAL_POWER_UPDATE_INTERVAL) + ")");
275 if (thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) instanceof BigDecimal) {
276 config.setSensorReadingWaitTime(
277 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME)).intValue() * 1000);
279 numberExc.add("\"Wait time sensor reading\" ("
280 + thingConfig.get(DigitalSTROMBindingConstants.SENSOR_WAIT_TIME) + ")");
282 if (thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) instanceof BigDecimal) {
283 config.setTrashDeviceDeleteTime(
284 ((BigDecimal) thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY))
287 numberExc.add("\"Days to be slaked trash bin devices\" ("
288 + thingConfig.get(DigitalSTROMBindingConstants.DEFAULT_TRASH_DEVICE_DELETE_TIME_KEY) + ")");
290 if (!numberExc.isEmpty()) {
291 String excText = "The field ";
292 for (int i = 0; i < numberExc.size(); i++) {
293 excText = excText + numberExc.get(i);
294 if (i < numberExc.size() - 2) {
295 excText = excText + ", ";
296 } else if (i < numberExc.size() - 1) {
297 excText = excText + " and ";
300 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, excText + " have to be a number.");
303 String servertCert = getThing().getProperties().get(DigitalSTROMBindingConstants.SERVER_CERT);
304 if (servertCert != null && !servertCert.isBlank()) {
305 config.setCert(servertCert);
310 private Config loadAndCheckConnectionData(Configuration thingConfig) {
311 if (this.config == null) {
312 this.config = new Config();
314 // load and check connection and authorization data
315 String host = (String) thingConfig.get(HOST);
316 if (host != null && !host.isBlank()) {
317 config.setHost(host);
319 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
320 "The connection to the digitalSTROM-Server can't established, because the host address is missing. Please set the host address.");
323 if (thingConfig.get(USER_NAME) != null) {
324 config.setUserName(thingConfig.get(USER_NAME).toString());
326 config.setUserName(null);
328 if (thingConfig.get(PASSWORD) != null) {
329 config.setPassword(thingConfig.get(PASSWORD).toString());
331 config.setPassword(null);
333 if (thingConfig.get(APPLICATION_TOKEN) != null) {
334 config.setAppToken(thingConfig.get(APPLICATION_TOKEN).toString());
336 config.setAppToken(null);
339 if (!checkLoginConfig(config)) {
346 public void dispose() {
347 logger.debug("Handler disposed");
348 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
349 reconnectTracker.cancel(true);
351 if (eventListener != null) {
352 eventListener.stop();
354 if (devStatMan != null) {
355 devStatMan.unregisterTotalPowerConsumptionListener();
356 devStatMan.unregisterStatusListener();
357 this.devStatMan.stop();
359 if (connMan != null) {
360 connMan.unregisterConnectionListener();
365 public void handleCommand(ChannelUID channelUID, Command command) {
366 if (command instanceof RefreshType) {
367 channelLinked(channelUID);
369 logger.debug("Command {} is not supported for channel: {}", command, channelUID.getId());
374 public void handleRemoval() {
375 String applicationToken = (String) super.getConfig().get(APPLICATION_TOKEN);
376 if (applicationToken != null && !applicationToken.isEmpty()) {
377 if (connMan == null) {
378 Config config = loadAndCheckConnectionData(this.getConfig());
379 if (config != null) {
380 this.connMan = new ConnectionManagerImpl(config, null, false);
382 updateStatus(ThingStatus.REMOVED);
386 if (connMan.removeApplicationToken()) {
387 logger.debug("Application-Token deleted");
390 updateStatus(ThingStatus.REMOVED);
393 /* methods to store listener */
396 * Registers a new {@link DeviceStatusListener} on the {@link DeviceStatusManager}.
398 * @param deviceStatusListener (must not be null)
400 public synchronized void registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
401 if (this.devStatMan != null) {
402 if (deviceStatusListener == null) {
403 throw new IllegalArgumentException("It's not allowed to pass null.");
406 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
407 if (devStatMan.getManagerState().equals(ManagerStates.RUNNING)) {
408 devStatMan.registerDeviceListener(deviceStatusListener);
409 } else if (deviceStatusListener.getDeviceStatusListenerID()
410 .equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
411 devStatMan.registerDeviceListener(deviceStatusListener);
414 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
417 if (deviceStatusListener.getDeviceStatusListenerID().equals(DeviceStatusListener.DEVICE_DISCOVERY)) {
418 deviceDiscovery = deviceStatusListener;
424 * Unregisters a new {@link DeviceStatusListener} on the {@link BridgeHandler}.
426 * @param deviceStatusListener (must not be null)
428 public void unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
429 if (this.devStatMan != null) {
430 if (deviceStatusListener.getDeviceStatusListenerID() != null) {
431 this.devStatMan.unregisterDeviceListener(deviceStatusListener);
433 throw new IllegalArgumentException("It's not allowed to pass a DeviceStatusListener with ID = null.");
439 * Registers a new {@link SceneStatusListener} on the {@link BridgeHandler}.
441 * @param sceneStatusListener (must not be null)
443 public synchronized void registerSceneStatusListener(SceneStatusListener sceneStatusListener) {
444 if (this.sceneMan != null) {
445 if (sceneStatusListener == null) {
446 throw new IllegalArgumentException("It's not allowed to pass null.");
449 if (sceneStatusListener.getSceneStatusListenerID() != null) {
450 this.sceneMan.registerSceneListener(sceneStatusListener);
452 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null.");
455 if (sceneStatusListener.getSceneStatusListenerID().equals(SceneStatusListener.SCENE_DISCOVERY)) {
456 sceneDiscovery = sceneStatusListener;
462 * Unregisters a new {@link SceneStatusListener} on the {@link DeviceStatusManager}.
464 * @param sceneStatusListener (must not be null)
466 public void unregisterSceneStatusListener(SceneStatusListener sceneStatusListener) {
467 if (this.sceneMan != null) {
468 if (sceneStatusListener.getSceneStatusListenerID() != null) {
469 this.sceneMan.unregisterSceneListener(sceneStatusListener);
471 throw new IllegalArgumentException("It's not allowed to pass a SceneStatusListener with ID = null..");
477 * Has to be called from a removed Thing-Child to rediscovers the Thing.
479 * @param id = scene or device id (must not be null)
481 public void childThingRemoved(String id) {
482 if (id != null && id.split("-").length == 3) {
483 InternalScene scene = sceneMan.getInternalScene(id);
485 sceneMan.removeInternalScene(id);
486 sceneMan.addInternalScene(scene);
489 devStatMan.removeDevice(id);
494 * Delegate a stop command from a Thing to the {@link DeviceStatusManager#sendStopComandsToDSS(Device)}.
496 * @param device can be null
498 public void stopOutputValue(Device device) {
499 this.devStatMan.sendStopComandsToDSS(device);
503 public void channelLinked(ChannelUID channelUID) {
504 if (devStatMan != null) {
505 MeteringTypeEnum meteringType = DsChannelTypeProvider.getMeteringType(channelUID.getId());
506 if (meteringType != null) {
507 if (meteringType.equals(MeteringTypeEnum.ENERGY)) {
508 onEnergyMeterValueChanged(devStatMan.getTotalEnergyMeterValue());
510 onTotalPowerConsumptionChanged(devStatMan.getTotalPowerConsumption());
513 logger.warn("Channel with id {} is not known for the thing with id {}.", channelUID.getId(),
514 getThing().getUID());
520 public void onTotalPowerConsumptionChanged(int newPowerConsumption) {
521 updateChannelState(MeteringTypeEnum.CONSUMPTION, MeteringUnitsEnum.WH, newPowerConsumption);
525 public void onEnergyMeterValueChanged(int newEnergyMeterValue) {
526 updateChannelState(MeteringTypeEnum.ENERGY, MeteringUnitsEnum.WH, newEnergyMeterValue * 0.001);
530 public void onEnergyMeterWsValueChanged(int newEnergyMeterValue) {
534 private void updateChannelState(MeteringTypeEnum meteringType, MeteringUnitsEnum meteringUnit, double value) {
535 String channelID = DsChannelTypeProvider.getMeteringChannelID(meteringType, meteringUnit, true);
536 if (getThing().getChannel(channelID) != null) {
537 updateState(channelID, new DecimalType(value));
542 public void onConnectionStateChange(String newConnectionState) {
543 switch (newConnectionState) {
544 case CONNECTION_LOST:
545 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
546 "The connection to the digitalSTROM-Server cannot be established.");
547 startReconnectTracker();
549 case CONNECTION_RESUMED:
550 if (connectionTimeoutCounter > 0) {
551 // reset connection timeout counter
552 connectionTimeoutCounter = 0;
553 if (connMan.checkConnection()) {
555 setStatus(ThingStatus.ONLINE);
559 case APPLICATION_TOKEN_GENERATED:
560 if (connMan != null) {
561 Configuration config = this.getConfig();
562 config.remove(USER_NAME);
563 config.remove(PASSWORD);
564 config.put(APPLICATION_TOKEN, connMan.getApplicationToken());
565 this.updateConfiguration(config);
573 private void setStatus(ThingStatus status) {
574 logger.debug("set status to: {}", status);
575 updateStatus(status);
576 for (Thing thing : getThing().getThings()) {
577 ThingHandler handler = thing.getHandler();
578 if (handler != null) {
579 handler.bridgeStatusChanged(getThing().getStatusInfo());
584 private void startReconnectTracker() {
585 if (reconnectTracker == null || reconnectTracker.isCancelled()) {
586 logger.debug("Connection lost, stop all services and start reconnectTracker.");
588 reconnectTracker = scheduler.scheduleWithFixedDelay(new Runnable() {
592 if (connMan != null) {
593 boolean conStat = connMan.checkConnection();
594 logger.debug("check connection = {}", conStat);
597 reconnectTracker.cancel(false);
601 }, RECONNECT_TRACKER_INTERVAL, RECONNECT_TRACKER_INTERVAL, TimeUnit.SECONDS);
605 private void stopServices() {
606 if (devStatMan != null && !devStatMan.getManagerState().equals(ManagerStates.STOPPED)) {
609 if (eventListener != null && eventListener.isStarted()) {
610 eventListener.stop();
614 private void restartServices() {
615 logger.debug("reconnect, stop reconnection tracker and restart services");
616 if (reconnectTracker != null && !reconnectTracker.isCancelled()) {
617 reconnectTracker.cancel(true);
620 if (devStatMan != null) {
623 if (eventListener != null) {
624 eventListener.start();
629 public void onConnectionStateChange(String newConnectionState, String reason) {
630 if (newConnectionState.equals(NOT_AUTHENTICATED) || newConnectionState.equals(CONNECTION_LOST)) {
632 case WRONG_APP_TOKEN:
633 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.");
638 case WRONG_USER_OR_PASSWORD:
639 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
640 "The set username or password is wrong.");
643 case NO_USER_PASSWORD:
644 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
645 "No username or password is set to generate Application-Token. Please set user name and password or Application-Token.");
648 case CONNECTON_TIMEOUT:
649 // ignore the first connection timeout
650 if (connectionTimeoutCounter++ > ignoredTimeouts) {
651 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
652 "Connection lost because connection timeout to Server.");
658 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
659 "Server not found! Please check these points:\n" + " - Is digitalSTROM-Server turned on?\n"
660 + " - Is the host address correct?\n"
661 + " - Is the ethernet cable connection established?");
664 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
665 "Unknown host name, please check the set host name!");
668 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Invalid URL is set.");
670 case CONNECTION_LOST:
671 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
672 "IOException / Connection lost.");
674 case SSL_HANDSHAKE_ERROR:
675 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
676 "SSL Handshake error / Connection lost.");
679 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason);
681 // reset connection timeout counter
682 connectionTimeoutCounter = 0;
683 startReconnectTracker();
688 * Returns a list of all {@link Device}'s.
690 * @return device list (cannot be null)
692 public List<Device> getDevices() {
693 return this.structMan != null && this.structMan.getDeviceMap() != null
694 ? new LinkedList<>(this.structMan.getDeviceMap().values())
699 * Returns the {@link StructureManager}.
701 * @return StructureManager
703 public StructureManager getStructureManager() {
704 return this.structMan;
708 * Delegates a scene command of a Thing to the
709 * {@link DeviceStatusManager#sendSceneComandsToDSS(InternalScene, boolean)}
711 * @param scene the called scene
712 * @param call_undo (true = call scene | false = undo scene)
714 public void sendSceneComandToDSS(InternalScene scene, boolean call_undo) {
715 if (devStatMan != null) {
716 devStatMan.sendSceneComandsToDSS(scene, call_undo);
721 * Delegates a device command of a Thing to the
722 * {@link DeviceStatusManager#sendComandsToDSS(Device, DeviceStateUpdate)}
724 * @param device can be null
725 * @param deviceStateUpdate can be null
727 public void sendComandsToDSS(Device device, DeviceStateUpdate deviceStateUpdate) {
728 if (devStatMan != null) {
729 devStatMan.sendComandsToDSS(device, deviceStateUpdate);
734 * Returns a list of all {@link InternalScene}'s.
736 * @return Scene list (cannot be null)
738 public List<InternalScene> getScenes() {
739 return sceneMan != null ? sceneMan.getScenes() : new LinkedList<>();
743 * Returns the {@link ConnectionManager}.
745 * @return ConnectionManager
747 public ConnectionManager getConnectionManager() {
752 public void onStatusChanged(ManagerTypes managerType, ManagerStates state) {
753 if (managerType.equals(ManagerTypes.DEVICE_STATUS_MANAGER)) {
756 if (deviceDiscovery != null) {
757 devStatMan.registerDeviceListener(deviceDiscovery);
758 deviceDiscovery = null;
760 logger.debug("Building digitalSTROM model");
763 updateStatus(ThingStatus.ONLINE);
766 if (!getThing().getStatusInfo().getStatusDetail().equals(ThingStatusDetail.COMMUNICATION_ERROR)
767 && !getThing().getStatusInfo().getStatusDetail()
768 .equals(ThingStatusDetail.CONFIGURATION_ERROR)) {
769 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "DeviceStatusManager is stopped.");
777 if (managerType.equals(ManagerTypes.SCENE_MANAGER)) {
779 case GENERATING_SCENES:
780 logger.debug("SceneManager reports that he is generating scenes");
781 if (sceneDiscovery != null) {
782 sceneMan.registerSceneListener(sceneDiscovery);
783 sceneDiscovery = null;
787 logger.debug("SceneManager reports that he is running");
796 * Returns a {@link List} of all {@link Circuit}'s.
798 * @return circuit list
800 public List<Circuit> getCircuits() {
801 logger.debug("circuits: {}", structMan.getCircuitMap().values().toString());
802 return structMan != null && structMan.getCircuitMap() != null
803 ? new LinkedList<>(structMan.getCircuitMap().values())
808 * Returns the {@link TemperatureControlManager} or null if no one exist.
810 * @return {@link TemperatureControlManager}
812 public TemperatureControlManager getTemperatureControlManager() {
817 * Registers the given {@link TemperatureControlStatusListener} to the {@link TemperatureControlManager}.
819 * @param temperatureControlStatusListener can be null
821 public void registerTemperatureControlStatusListener(
822 TemperatureControlStatusListener temperatureControlStatusListener) {
823 if (tempContMan != null) {
824 tempContMan.registerTemperatureControlStatusListener(temperatureControlStatusListener);
825 } else if (TemperatureControlStatusListener.DISCOVERY
826 .equals(temperatureControlStatusListener.getTemperationControlStatusListenrID())) {
827 this.temperatureControlDiscovery = temperatureControlStatusListener;
832 * Unregisters the given {@link TemperatureControlStatusListener} from the {@link TemperatureControlManager}.
834 * @param temperatureControlStatusListener can be null
836 public void unregisterTemperatureControlStatusListener(
837 TemperatureControlStatusListener temperatureControlStatusListener) {
838 if (tempContMan != null) {
839 tempContMan.unregisterTemperatureControlStatusListener(temperatureControlStatusListener);
844 * see {@link TemperatureControlManager#getTemperatureControlStatusFromAllZones()}
846 * @return all temperature control status objects
848 public Collection<TemperatureControlStatus> getTemperatureControlStatusFromAllZones() {
849 return tempContMan != null ? tempContMan.getTemperatureControlStatusFromAllZones() : new LinkedList<>();