]> git.basschouten.com Git - openhab-addons.git/blob
d05ab94af195314d944064de5411fe33a1adad7c
[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.thing.Bridge;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.ThingTypeUID;
37 import org.openhab.core.thing.binding.BaseBridgeHandler;
38 import org.openhab.core.thing.binding.ThingHandlerService;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import com.google.gson.Gson;
45
46 /**
47  * The {@link MeaterBridgeHandler} is responsible for handling commands, which are
48  * sent to one of the channels.
49  *
50  * @author Jan Gustafsson - Initial contribution
51  */
52 @NonNullByDefault
53 public class MeaterBridgeHandler extends BaseBridgeHandler {
54
55     private final Logger logger = LoggerFactory.getLogger(MeaterBridgeHandler.class);
56
57     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BRIDGE);
58
59     private final Gson gson;
60     private final HttpClient httpClient;
61     private final LocaleProvider localeProvider;
62     private final Map<String, MeaterProbeDTO.Device> meaterProbeThings = new ConcurrentHashMap<>();
63
64     private int refreshTimeInSeconds = 300;
65     private @Nullable MeaterRestAPI api;
66     private @Nullable ScheduledFuture<?> refreshJob;
67
68     public MeaterBridgeHandler(Bridge bridge, HttpClient httpClient, Gson gson, LocaleProvider localeProvider) {
69         super(bridge);
70         this.httpClient = httpClient;
71         this.gson = gson;
72         this.localeProvider = localeProvider;
73     }
74
75     @Override
76     public void initialize() {
77         MeaterBridgeConfiguration config = getConfigAs(MeaterBridgeConfiguration.class);
78
79         api = new MeaterRestAPI(config, gson, httpClient, localeProvider);
80         refreshTimeInSeconds = config.refresh;
81
82         if (config.email.isBlank() || config.password.isBlank()) {
83             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
84                     "@text/config.missing-username-password.description");
85         } else {
86             updateStatus(ThingStatus.UNKNOWN);
87             scheduler.execute(() -> {
88                 startAutomaticRefresh();
89             });
90         }
91     }
92
93     public Map<String, MeaterProbeDTO.Device> getMeaterThings() {
94         return meaterProbeThings;
95     }
96
97     @Override
98     public Collection<Class<? extends ThingHandlerService>> getServices() {
99         return Set.of(MeaterDiscoveryService.class);
100     }
101
102     @Override
103     public void dispose() {
104         stopAutomaticRefresh();
105         meaterProbeThings.clear();
106     }
107
108     private boolean refreshAndUpdateStatus() {
109         MeaterRestAPI localAPI = api;
110         if (localAPI != null) {
111             if (localAPI.refresh(meaterProbeThings)) {
112                 updateStatus(ThingStatus.ONLINE);
113                 getThing().getThings().stream().forEach(thing -> {
114                     MeaterHandler handler = (MeaterHandler) thing.getHandler();
115                     if (handler != null) {
116                         handler.update();
117                     }
118                 });
119                 return true;
120             } else {
121                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
122             }
123         }
124         return false;
125     }
126
127     private void startAutomaticRefresh() {
128         ScheduledFuture<?> refreshJob = this.refreshJob;
129         if (refreshJob == null || refreshJob.isCancelled()) {
130             this.refreshJob = scheduler.scheduleWithFixedDelay(this::refreshAndUpdateStatus, 0, refreshTimeInSeconds,
131                     TimeUnit.SECONDS);
132         }
133     }
134
135     private void stopAutomaticRefresh() {
136         ScheduledFuture<?> refreshJob = this.refreshJob;
137         if (refreshJob != null) {
138             refreshJob.cancel(true);
139             this.refreshJob = null;
140         }
141     }
142
143     @Override
144     public void handleCommand(ChannelUID channelUID, Command command) {
145         logger.debug("Command received: {}", command);
146         if (command instanceof RefreshType) {
147             if (channelUID.getId().equals(CHANNEL_STATUS)) {
148                 logger.debug("Refresh command on status channel {} will trigger instant refresh", channelUID);
149                 refreshAndUpdateStatus();
150             }
151         }
152     }
153 }