2 * Copyright (c) 2010-2024 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.siemenshvac.internal.handler;
16 import java.net.URLConnection;
17 import java.text.DateFormat;
18 import java.text.MessageFormat;
19 import java.text.SimpleDateFormat;
20 import java.time.LocalDate;
21 import java.util.Collection;
22 import java.util.Locale;
24 import java.util.concurrent.TimeUnit;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.siemenshvac.internal.discovery.SiemensHvacDeviceDiscoveryService;
29 import org.openhab.binding.siemenshvac.internal.metadata.SiemensHvacMetadataRegistry;
30 import org.openhab.binding.siemenshvac.internal.network.SiemensHvacConnector;
31 import org.openhab.binding.siemenshvac.internal.type.SiemensHvacException;
32 import org.openhab.core.i18n.TranslationProvider;
33 import org.openhab.core.io.net.http.HttpClientFactory;
34 import org.openhab.core.net.NetworkAddressService;
35 import org.openhab.core.thing.Bridge;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.ThingStatusDetail;
39 import org.openhab.core.thing.binding.BaseBridgeHandler;
40 import org.openhab.core.thing.binding.ThingHandlerService;
41 import org.openhab.core.types.Command;
42 import org.osgi.framework.BundleContext;
43 import org.osgi.framework.FrameworkUtil;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 * The {@link SiemensHvacBridgeBaseThingHandler} is responsible for handling commands, which are
49 * sent to one of the channels.
51 * @author Laurent Arnal - Initial contribution and API
54 public class SiemensHvacBridgeThingHandler extends BaseBridgeHandler {
56 private final Logger logger = LoggerFactory.getLogger(SiemensHvacBridgeThingHandler.class);
57 private @Nullable SiemensHvacDeviceDiscoveryService discoveryService;
58 private final @Nullable HttpClientFactory httpClientFactory;
59 private final SiemensHvacMetadataRegistry metaDataRegistry;
60 private @Nullable SiemensHvacBridgeConfig config;
61 private final TranslationProvider translationProvider;
63 public SiemensHvacBridgeThingHandler(Bridge bridge, @Nullable NetworkAddressService networkAddressService,
64 @Nullable HttpClientFactory httpClientFactory, SiemensHvacMetadataRegistry metaDataRegistry,
65 TranslationProvider translationProvider) {
67 SiemensHvacConnector lcConnector = null;
68 this.httpClientFactory = httpClientFactory;
69 this.metaDataRegistry = metaDataRegistry;
70 this.translationProvider = translationProvider;
72 lcConnector = this.metaDataRegistry.getSiemensHvacConnector();
73 if (lcConnector != null) {
74 lcConnector.setSiemensHvacBridgeBaseThingHandler(this);
79 public void handleCommand(ChannelUID channelUID, Command command) {
83 public void dispose() {
84 metaDataRegistry.invalidate();
88 public void initialize() {
89 SiemensHvacBridgeConfig lcConfig = getConfigAs(SiemensHvacBridgeConfig.class);
90 String baseUrl = null;
92 if (logger.isDebugEnabled()) {
93 logger.debug("Initialize() bridge: {}", getBuildDate());
96 baseUrl = lcConfig.baseUrl;
98 if (baseUrl.isEmpty()) {
99 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
100 "@text/offline.error-gateway-init");
104 if (!baseUrl.startsWith("http://") && !baseUrl.startsWith("https://")) {
105 baseUrl = "http://" + baseUrl;
108 if (!baseUrl.endsWith("/")) {
109 baseUrl = baseUrl + "/";
114 updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "@text/offline.waiting-bridge-initialization");
116 // Will read metadata in background to not block initialize for a long period !
117 scheduler.schedule(this::initializeCode, 1, TimeUnit.SECONDS);
120 protected String getBuildDate() {
122 ClassLoader cl = getClass().getClassLoader();
124 URL res = cl.getResource(getClass().getCanonicalName().replace('.', '/') + ".class");
126 URLConnection cnx = res.openConnection();
127 LocalDate dt = LocalDate.ofEpochDay(cnx.getLastModified());
128 DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
129 return df.format(dt);
133 } catch (Exception ex) {
138 public static String getStackTrace(final Throwable throwable) {
139 StringBuffer sb = new StringBuffer();
141 Throwable current = throwable;
142 while (current != null) {
143 sb.append(current.getLocalizedMessage());
146 Throwable cause = throwable.getCause();
148 if (!cause.equals(throwable)) {
149 current = current.getCause();
157 return sb.toString();
160 private void initializeCode() {
162 metaDataRegistry.readMeta();
163 updateStatus(ThingStatus.ONLINE);
164 } catch (SiemensHvacException ex) {
165 Locale local = metaDataRegistry.getUserLocale();
166 BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
167 String text = translationProvider.getText(bundleContext.getBundle(), "offline.error-gateway-init",
168 "DefaultValue", local);
170 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
171 MessageFormat.format(text, ex.getMessage()));
175 public @Nullable SiemensHvacBridgeConfig getBridgeConfiguration() {
180 public void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
181 super.updateStatus(status, statusDetail, description);
184 public boolean registerDiscoveryListener(SiemensHvacDeviceDiscoveryService listener) {
185 SiemensHvacDeviceDiscoveryService lcDiscoveryService = discoveryService;
186 if (lcDiscoveryService == null) {
187 lcDiscoveryService = listener;
188 lcDiscoveryService.setSiemensHvacMetadataRegistry(metaDataRegistry);
195 public boolean unregisterDiscoveryListener() {
196 SiemensHvacDeviceDiscoveryService lcDiscoveryService = discoveryService;
197 if (lcDiscoveryService != null) {
198 discoveryService = null;
205 public @Nullable HttpClientFactory getHttpClientFactory() {
206 return this.httpClientFactory;
210 public Collection<Class<? extends ThingHandlerService>> getServices() {
211 return Set.of(SiemensHvacDeviceDiscoveryService.class);