]> git.basschouten.com Git - openhab-addons.git/blob
5f1a451f20d55e392db2581094f501d99498356b
[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.mystrom.internal;
14
15 import static org.openhab.binding.mystrom.internal.MyStromBindingConstants.*;
16
17 import java.text.DateFormat;
18 import java.util.Calendar;
19 import java.util.Locale;
20 import java.util.Map;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.eclipse.jetty.client.HttpClient;
29 import org.eclipse.jetty.client.api.ContentResponse;
30 import org.eclipse.jetty.client.api.Request;
31 import org.eclipse.jetty.client.util.StringContentProvider;
32 import org.eclipse.jetty.http.HttpHeader;
33 import org.eclipse.jetty.http.HttpMethod;
34 import org.eclipse.jetty.http.HttpStatus;
35 import org.openhab.core.thing.Thing;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import com.google.gson.Gson;
43 import com.google.gson.JsonSyntaxException;
44
45 /**
46  * The {@link AbstractMyStromHandler} is responsible for handling commands, which are
47  * sent to one of the channels.
48  *
49  * @author Frederic Chastagnol - Initial contribution
50  */
51 @NonNullByDefault
52 public abstract class AbstractMyStromHandler extends BaseThingHandler {
53     protected static final String COMMUNICATION_ERROR = "Error while communicating to the myStrom plug: ";
54     protected MyStromConfiguration config;
55
56     protected final HttpClient httpClient;
57     protected String mac = "";
58
59     private final Logger logger = LoggerFactory.getLogger(AbstractMyStromHandler.class);
60     private @Nullable ScheduledFuture<?> pollingJob;
61     protected final Gson gson = new Gson();
62
63     public AbstractMyStromHandler(Thing thing, HttpClient httpClient) {
64         super(thing);
65         config = getConfigAs(MyStromConfiguration.class);
66         this.httpClient = httpClient;
67     }
68
69     @Override
70     public final void initialize() {
71         config = getConfigAs(MyStromConfiguration.class);
72         updateStatus(ThingStatus.UNKNOWN);
73         scheduler.schedule(this::initializeInternal, 0, TimeUnit.SECONDS);
74     }
75
76     @Override
77     public final void dispose() {
78         ScheduledFuture<?> pollingJob = this.pollingJob;
79         if (pollingJob != null) {
80             pollingJob.cancel(true);
81             this.pollingJob = null;
82         }
83         super.dispose();
84     }
85
86     private void updateProperties() {
87         try {
88             String json = sendHttpRequest(HttpMethod.GET, "/api/v1/info", null);
89             MyStromDeviceInfo deviceInfo = gson.fromJson(json, MyStromDeviceInfo.class);
90             if (deviceInfo == null) {
91                 throw new MyStromException("Cannot retrieve device info from myStrom device " + getThing().getUID());
92             }
93             this.mac = deviceInfo.mac;
94             Map<String, String> properties = editProperties();
95             properties.put(PROPERTY_MAC, deviceInfo.mac);
96             properties.put(PROPERTY_VERSION, deviceInfo.version);
97             properties.put(PROPERTY_TYPE, Long.toString(deviceInfo.type));
98             properties.put(PROPERTY_SSID, deviceInfo.ssid);
99             properties.put(PROPERTY_IP, deviceInfo.ip);
100             properties.put(PROPERTY_MASK, deviceInfo.mask);
101             properties.put(PROPERTY_GW, deviceInfo.gw);
102             properties.put(PROPERTY_DNS, deviceInfo.dns);
103             properties.put(PROPERTY_STATIC, Boolean.toString(deviceInfo.staticState));
104             properties.put(PROPERTY_CONNECTED, Boolean.toString(deviceInfo.connected));
105             Calendar calendar = Calendar.getInstance();
106             DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM,
107                     Locale.getDefault());
108             properties.put(PROPERTY_LAST_REFRESH, formatter.format(calendar.getTime()));
109             updateProperties(properties);
110         } catch (JsonSyntaxException | MyStromException ex) {
111             logger.debug("Updating properties failed: ", ex);
112         }
113     }
114
115     /**
116      * Calls the API with the given http method, request path and actual data.
117      *
118      * @param method the http method to make the call with
119      * @param path The path of the API endpoint
120      * @param requestData the actual raw data to send in the request body, may be {@code null}
121      * @return String contents of the response for the GET request.
122      * @throws MyStromException Throws on communication error
123      */
124     protected final String sendHttpRequest(HttpMethod method, String path, @Nullable String requestData)
125             throws MyStromException {
126         String url = config.getHostname() + path;
127         try {
128             Request request = httpClient.newRequest(url).timeout(10, TimeUnit.SECONDS).method(method);
129             if (!config.getApiToken().isEmpty()) {
130                 request.getHeaders().add("Token", config.getApiToken());
131             }
132             if (requestData != null) {
133                 request = request.content(new StringContentProvider(requestData)).header(HttpHeader.CONTENT_TYPE,
134                         "application/x-www-form-urlencoded");
135             }
136             ContentResponse response = request.send();
137             if (response.getStatus() != HttpStatus.OK_200) {
138                 throw new MyStromException("Error sending HTTP " + method + " request to " + url
139                         + ". Got response code: " + response.getStatus());
140             }
141             return response.getContentAsString();
142         } catch (InterruptedException | TimeoutException | ExecutionException e) {
143             throw new MyStromException(COMMUNICATION_ERROR + e.getMessage());
144         }
145     }
146
147     private void initializeInternal() {
148         try {
149             updateProperties();
150             checkRequiredInfo();
151             pollingJob = scheduler.scheduleWithFixedDelay(this::pollDevice, 0, config.getRefresh(), TimeUnit.SECONDS);
152         } catch (MyStromException e) {
153             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
154         }
155     }
156
157     protected void checkRequiredInfo() throws MyStromException {
158     }
159
160     protected abstract void pollDevice();
161 }