]> git.basschouten.com Git - openhab-addons.git/blob
02f8f7196d6e100d44512dcf1bba2c10463670b7
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.groheondus.internal.handler;
14
15 import java.io.IOException;
16 import java.util.concurrent.ScheduledFuture;
17 import java.util.concurrent.TimeUnit;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.groheondus.internal.GroheOndusApplianceConfiguration;
22 import org.openhab.core.thing.Bridge;
23 import org.openhab.core.thing.ChannelUID;
24 import org.openhab.core.thing.Thing;
25 import org.openhab.core.thing.ThingStatus;
26 import org.openhab.core.thing.ThingStatusDetail;
27 import org.openhab.core.thing.binding.BaseThingHandler;
28 import org.openhab.core.thing.binding.BridgeHandler;
29 import org.openhab.core.types.UnDefType;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import io.github.floriansw.ondus.api.OndusService;
34 import io.github.floriansw.ondus.api.model.BaseAppliance;
35 import io.github.floriansw.ondus.api.model.Location;
36 import io.github.floriansw.ondus.api.model.Room;
37
38 /**
39  * @author Florian Schmidt - Initial contribution
40  */
41 @NonNullByDefault
42 public abstract class GroheOndusBaseHandler<T extends BaseAppliance, M> extends BaseThingHandler {
43     private final Logger logger = LoggerFactory.getLogger(GroheOndusBaseHandler.class);
44
45     protected @Nullable GroheOndusApplianceConfiguration config;
46
47     private @Nullable ScheduledFuture<?> poller;
48
49     private final int applianceType;
50
51     // Used to space scheduled updates apart by 1 second to avoid rate limiting from service
52     private int thingCounter = 0;
53
54     public GroheOndusBaseHandler(Thing thing, int applianceType, int thingCounter) {
55         super(thing);
56         this.applianceType = applianceType;
57         this.thingCounter = thingCounter;
58     }
59
60     protected void schedulePolling() {
61         OndusService ondusService = getOndusService();
62         if (ondusService == null) {
63             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "@text/error.noservice");
64             return;
65         }
66
67         @Nullable
68         T appliance = getAppliance(ondusService);
69         if (appliance == null) {
70             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "@text/error.empty.response");
71             return;
72         }
73         int pollingInterval = getPollingInterval(appliance);
74         ScheduledFuture<?> poller = this.poller;
75         if (poller != null) {
76             // Cancel any previous polling
77             poller.cancel(true);
78         }
79         this.poller = scheduler.scheduleWithFixedDelay(this::updateChannels, thingCounter, pollingInterval,
80                 TimeUnit.SECONDS);
81         logger.debug("Scheduled polling every {}s for appliance {}", pollingInterval, thing.getUID());
82     }
83
84     @Override
85     public void dispose() {
86         logger.debug("Disposing scheduled updater for thing {}", thing.getUID());
87         ScheduledFuture<?> poller = this.poller;
88         if (poller != null) {
89             poller.cancel(true);
90         }
91         super.dispose();
92     }
93
94     @Override
95     public void initialize() {
96         config = getConfigAs(GroheOndusApplianceConfiguration.class);
97         schedulePolling();
98     }
99
100     public void updateChannels() {
101         logger.debug("Updating channels for appliance {}", thing.getUID());
102         OndusService ondusService = getOndusService();
103         if (ondusService == null) {
104             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "@text/error.noservice");
105             // Update channels to UNDEF
106
107             return;
108         }
109
110         @Nullable
111         T appliance = getAppliance(ondusService);
112         if (appliance == null) {
113             logger.debug("Updating channels failed since appliance is null, thing {}", thing.getUID());
114             return;
115         }
116
117         M measurement = getLastDataPoint(appliance);
118         if (measurement != null) {
119             getThing().getChannels().forEach(channel -> updateChannel(channel.getUID(), appliance, measurement));
120             updateStatus(ThingStatus.ONLINE);
121         } else {
122             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "@text/error.failedtoloaddata");
123         }
124     }
125
126     protected abstract M getLastDataPoint(T appliance);
127
128     protected abstract void updateChannel(ChannelUID channelUID, T appliance, M measurement);
129
130     public @Nullable OndusService getOndusService() {
131         Bridge bridge = getBridge();
132         if (bridge == null) {
133             return null;
134         }
135         BridgeHandler handler = bridge.getHandler();
136         if (!(handler instanceof GroheOndusAccountHandler)) {
137             return null;
138         }
139         try {
140             return ((GroheOndusAccountHandler) handler).getService();
141         } catch (IllegalStateException e) {
142             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
143             return null;
144         }
145     }
146
147     protected Room getRoom() {
148         return new Room(config.roomId, getLocation());
149     }
150
151     protected Location getLocation() {
152         return new Location(config.locationId);
153     }
154
155     protected @Nullable T getAppliance(OndusService ondusService) {
156         try {
157             BaseAppliance appliance = ondusService.getAppliance(getRoom(), config.applianceId).orElse(null);
158             if (appliance != null) {
159                 if (appliance.getType() != getType()) {
160                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/error.wrongtype");
161                     return null;
162                 }
163                 return (T) appliance;
164             } else {
165                 logger.debug("getAppliance for thing {} returned null", thing.getUID());
166                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
167                         "@text/error.failedtoloaddata");
168                 getThing().getChannels().forEach(channel -> updateState(channel.getUID(), UnDefType.UNDEF));
169             }
170
171         } catch (IOException e) {
172             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
173             getThing().getChannels().forEach(channel -> updateState(channel.getUID(), UnDefType.UNDEF));
174             logger.debug("Could not load appliance", e);
175         }
176         return null;
177     }
178
179     protected abstract int getPollingInterval(T appliance);
180
181     private int getType() {
182         return this.applianceType;
183     }
184 }