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