]> git.basschouten.com Git - openhab-addons.git/blob
45d3e23bd34eefb83281defdf1c814996f52b5c3
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.meater.internal.handler;
14
15 import static org.openhab.binding.meater.internal.MeaterBindingConstants.*;
16
17 import java.util.Collection;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.eclipse.jetty.client.HttpClient;
27 import org.openhab.binding.meater.internal.MeaterBridgeConfiguration;
28 import org.openhab.binding.meater.internal.api.MeaterRestAPI;
29 import org.openhab.binding.meater.internal.discovery.MeaterDiscoveryService;
30 import org.openhab.binding.meater.internal.dto.MeaterProbeDTO;
31 import org.openhab.core.i18n.LocaleProvider;
32 import org.openhab.core.i18n.TranslationProvider;
33 import org.openhab.core.thing.Bridge;
34 import org.openhab.core.thing.ChannelUID;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.ThingTypeUID;
38 import org.openhab.core.thing.binding.BaseBridgeHandler;
39 import org.openhab.core.thing.binding.ThingHandlerService;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 import com.google.gson.Gson;
46
47 /**
48  * The {@link MeaterBridgeHandler} is responsible for handling commands, which are
49  * sent to one of the channels.
50  *
51  * @author Jan Gustafsson - Initial contribution
52  */
53 @NonNullByDefault
54 public class MeaterBridgeHandler extends BaseBridgeHandler {
55
56     private final Logger logger = LoggerFactory.getLogger(MeaterBridgeHandler.class);
57
58     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BRIDGE);
59
60     private final Gson gson;
61     private final HttpClient httpClient;
62     private final TranslationProvider i18nProvider;
63     private final LocaleProvider localeProvider;
64     private final Map<String, MeaterProbeDTO.Device> meaterProbeThings = new ConcurrentHashMap<>();
65
66     private int refreshTimeInSeconds = 300;
67     private @Nullable MeaterRestAPI api;
68     private @Nullable ScheduledFuture<?> refreshJob;
69
70     public MeaterBridgeHandler(Bridge bridge, HttpClient httpClient, Gson gson, TranslationProvider i18nProvider,
71             LocaleProvider localeProvider) {
72         super(bridge);
73         this.httpClient = httpClient;
74         this.gson = gson;
75         this.i18nProvider = i18nProvider;
76         this.localeProvider = localeProvider;
77     }
78
79     @Override
80     public void initialize() {
81         MeaterBridgeConfiguration config = getConfigAs(MeaterBridgeConfiguration.class);
82
83         api = new MeaterRestAPI(config, gson, httpClient, localeProvider);
84         refreshTimeInSeconds = config.refresh;
85
86         if (config.email.isBlank() || config.password.isBlank()) {
87             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
88                     "@text/config.missing-username-password.description");
89         } else {
90             updateStatus(ThingStatus.UNKNOWN);
91             scheduler.execute(() -> {
92                 startAutomaticRefresh();
93             });
94         }
95     }
96
97     public Map<String, MeaterProbeDTO.Device> getMeaterThings() {
98         return meaterProbeThings;
99     }
100
101     @Override
102     public Collection<Class<? extends ThingHandlerService>> getServices() {
103         return Set.of(MeaterDiscoveryService.class);
104     }
105
106     @Override
107     public void dispose() {
108         stopAutomaticRefresh();
109         meaterProbeThings.clear();
110     }
111
112     private boolean refreshAndUpdateStatus() {
113         MeaterRestAPI localAPI = api;
114         if (localAPI != null) {
115             if (localAPI.refresh(meaterProbeThings)) {
116                 updateStatus(ThingStatus.ONLINE);
117                 getThing().getThings().stream().forEach(thing -> {
118                     MeaterHandler handler = (MeaterHandler) thing.getHandler();
119                     if (handler != null) {
120                         handler.update();
121                     }
122                 });
123                 return true;
124             } else {
125                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
126             }
127         }
128         return false;
129     }
130
131     private void startAutomaticRefresh() {
132         ScheduledFuture<?> refreshJob = this.refreshJob;
133         if (refreshJob == null || refreshJob.isCancelled()) {
134             this.refreshJob = scheduler.scheduleWithFixedDelay(this::refreshAndUpdateStatus, 0, refreshTimeInSeconds,
135                     TimeUnit.SECONDS);
136         }
137     }
138
139     private void stopAutomaticRefresh() {
140         ScheduledFuture<?> refreshJob = this.refreshJob;
141         if (refreshJob != null) {
142             refreshJob.cancel(true);
143             this.refreshJob = null;
144         }
145     }
146
147     @Override
148     public void handleCommand(ChannelUID channelUID, Command command) {
149         logger.debug("Command received: {}", command);
150         if (command instanceof RefreshType) {
151             if (channelUID.getId().equals(CHANNEL_STATUS)) {
152                 logger.debug("Refresh command on status channel {} will trigger instant refresh", channelUID);
153                 refreshAndUpdateStatus();
154             }
155         }
156     }
157
158     public TranslationProvider getI18nProvider() {
159         return i18nProvider;
160     }
161
162     public LocaleProvider getLocaleProvider() {
163         return localeProvider;
164     }
165 }