]> git.basschouten.com Git - openhab-addons.git/blob
6c535b4e7433a7c5f526b531bb64ffd775c2c721
[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.opensprinkler.internal.handler;
14
15 import java.util.concurrent.ScheduledFuture;
16 import java.util.concurrent.TimeUnit;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.opensprinkler.internal.api.OpenSprinklerApi;
21 import org.openhab.binding.opensprinkler.internal.api.OpenSprinklerApiFactory;
22 import org.openhab.binding.opensprinkler.internal.api.exception.CommunicationApiException;
23 import org.openhab.binding.opensprinkler.internal.api.exception.GeneralApiException;
24 import org.openhab.binding.opensprinkler.internal.api.exception.UnauthorizedApiException;
25 import org.openhab.binding.opensprinkler.internal.config.OpenSprinklerHttpInterfaceConfig;
26 import org.openhab.core.thing.Bridge;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.ThingStatus;
29 import org.openhab.core.thing.ThingStatusDetail;
30 import org.openhab.core.thing.binding.BaseBridgeHandler;
31 import org.openhab.core.types.Command;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * @author Chris Graham - Initial contribution
37  * @author Florian Schmidt - Refactoring
38  */
39 @NonNullByDefault
40 public class OpenSprinklerHttpBridgeHandler extends BaseBridgeHandler {
41     private final Logger logger = LoggerFactory.getLogger(OpenSprinklerHttpBridgeHandler.class);
42     private @Nullable ScheduledFuture<?> pollingJob;
43     private @Nullable ScheduledFuture<?> delayedJob;
44     private @Nullable OpenSprinklerApi openSprinklerDevice;
45     private OpenSprinklerHttpInterfaceConfig openSprinklerConfig = new OpenSprinklerHttpInterfaceConfig();
46     private OpenSprinklerApiFactory apiFactory;
47
48     public OpenSprinklerHttpBridgeHandler(Bridge bridge, OpenSprinklerApiFactory apiFactory) {
49         super(bridge);
50         this.apiFactory = apiFactory;
51     }
52
53     public OpenSprinklerApi getApi() {
54         OpenSprinklerApi api = openSprinklerDevice;
55         if (api == null) {
56             throw new IllegalStateException();
57         }
58         return api;
59     }
60
61     public void communicationError(Exception e) {
62         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
63                 "Communication Error with the OpenSprinkler: " + e.getMessage());
64     }
65
66     public void refreshStations() {
67         OpenSprinklerApi localApi = openSprinklerDevice;
68         if (localApi == null || !localApi.isManualModeEnabled()) {
69             setupAPI();
70             localApi = openSprinklerDevice;
71         }
72         if (localApi != null) {
73             try {
74                 localApi.refresh();
75                 updateStatus(ThingStatus.ONLINE);
76                 this.getThing().getThings().forEach(thing -> {
77                     OpenSprinklerBaseHandler handler = (OpenSprinklerBaseHandler) thing.getHandler();
78                     if (handler != null) {
79                         handler.updateChannels();
80                     }
81                 });
82             } catch (CommunicationApiException e) {
83                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
84                         "Could not sync status with the OpenSprinkler. " + e.getMessage());
85             } catch (UnauthorizedApiException e) {
86                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
87                         "Unauthorized, check your password is correct");
88             }
89         }
90     }
91
92     public void delayedRefresh() {
93         ScheduledFuture<?> localFuture = delayedJob;
94         if (localFuture == null || localFuture.isDone()) {
95             delayedJob = scheduler.schedule(this::refreshStations, 3, TimeUnit.SECONDS);
96         } else {// User has sent multiple commands quickly, only need to update the controls once.
97             localFuture.cancel(true);
98             delayedJob = scheduler.schedule(this::refreshStations, 3, TimeUnit.SECONDS);
99         }
100     }
101
102     private void setupAPI() {
103         logger.debug("Initializing OpenSprinkler with config (Hostname: {}, Port: {}, Refresh: {}).",
104                 openSprinklerConfig.hostname, openSprinklerConfig.port, openSprinklerConfig.refresh);
105         try {
106             openSprinklerDevice = apiFactory.getHttpApi(openSprinklerConfig);
107             OpenSprinklerApi localApi = openSprinklerDevice;
108             localApi.enterManualMode();
109             if (!localApi.isManualModeEnabled()) {
110                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
111                         "Could not initialize the connection to the OpenSprinkler.");
112             }
113         } catch (CommunicationApiException | GeneralApiException exp) {
114             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
115                     "Could not create an API connection to the OpenSprinkler. Error received: " + exp);
116             return;
117         }
118     }
119
120     @Override
121     public void handleCommand(ChannelUID channelUID, Command command) {
122         // Nothing to do for the bridge handler
123     }
124
125     @Override
126     public void initialize() {
127         openSprinklerConfig = getConfig().as(OpenSprinklerHttpInterfaceConfig.class);
128         pollingJob = scheduler.scheduleWithFixedDelay(this::refreshStations, 2, openSprinklerConfig.refresh,
129                 TimeUnit.SECONDS);
130     }
131
132     @Override
133     public void dispose() {
134         OpenSprinklerApi localApi = openSprinklerDevice;
135         if (localApi != null) {
136             try {
137                 localApi.leaveManualMode();
138             } catch (CommunicationApiException | UnauthorizedApiException e) {
139                 logger.warn("Could not close connection on teardown.");
140             }
141             openSprinklerDevice = null;
142         }
143         ScheduledFuture<?> localFuture = pollingJob;
144         if (localFuture != null) {
145             localFuture.cancel(true);
146             pollingJob = null;
147         }
148         localFuture = delayedJob;
149         if (localFuture != null) {
150             localFuture.cancel(true);
151             pollingJob = null;
152         }
153     }
154 }