]> git.basschouten.com Git - openhab-addons.git/blob
962b5e438e638079cd785f3a398c5411da2117b0
[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.prowl.internal;
14
15 import static org.openhab.binding.prowl.internal.ProwlBindingConstants.*;
16
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
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.eclipse.jetty.client.api.ContentResponse;
28 import org.eclipse.jetty.client.util.StringContentProvider;
29 import org.openhab.binding.prowl.internal.action.ProwlActions;
30 import org.openhab.core.library.types.DecimalType;
31 import org.openhab.core.thing.ChannelUID;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.thing.binding.BaseThingHandler;
35 import org.openhab.core.thing.binding.ThingHandlerService;
36 import org.openhab.core.types.Command;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link ProwlHandler} is responsible for handling commands, which are
42  * sent to one of the channels.
43  *
44  * @author Ondrej Pecta - Initial contribution
45  */
46 @NonNullByDefault
47 public class ProwlHandler extends BaseThingHandler {
48
49     private final Logger logger = LoggerFactory.getLogger(ProwlHandler.class);
50
51     private ProwlConfiguration config = new ProwlConfiguration();
52     private final HttpClient httpClient;
53
54     /**
55      * Future to poll for status
56      */
57     private @Nullable ScheduledFuture<?> statusFuture;
58
59     public ProwlHandler(Thing thing, HttpClient client) {
60         super(thing);
61         this.httpClient = client;
62     }
63
64     @Override
65     public void handleCommand(ChannelUID channelUID, Command command) {
66     }
67
68     @Override
69     public void initialize() {
70         config = getConfigAs(ProwlConfiguration.class);
71         updateStatus(ThingStatus.UNKNOWN);
72
73         statusFuture = scheduler.scheduleWithFixedDelay(() -> updateStatus(), 0, config.refresh, TimeUnit.MINUTES);
74     }
75
76     private void updateStatus() {
77         if (keyVerificationSucceeded(config.apiKey)) {
78             updateStatus(ThingStatus.ONLINE);
79         } else {
80             updateStatus(ThingStatus.OFFLINE);
81         }
82     }
83
84     @Override
85     public void dispose() {
86         ScheduledFuture<?> localPollFuture = statusFuture;
87         if (localPollFuture != null && !localPollFuture.isCancelled()) {
88             localPollFuture.cancel(true);
89         }
90         super.dispose();
91     }
92
93     private boolean keyVerificationSucceeded(String apiKey) {
94         try {
95             ContentResponse response = httpClient.GET(PROWL_VERIFY_URI + "?apikey=" + apiKey);
96             String resp = response.getContentAsString();
97             logger.trace("verify response: {}", resp);
98             if (resp.contains("<success code=\"200\"")) {
99                 updateFreeMessages(resp);
100                 return true;
101             } else {
102                 return false;
103             }
104         } catch (InterruptedException e) {
105             Thread.currentThread().interrupt();
106         } catch (ExecutionException e) {
107             logger.debug("error during calling uri: {}", PROWL_ADD_URI, e);
108         } catch (TimeoutException e) {
109             logger.debug("timeout during calling uri: {}", PROWL_ADD_URI, e);
110         }
111         return false;
112     }
113
114     @Override
115     public Collection<Class<? extends ThingHandlerService>> getServices() {
116         return Collections.singletonList(ProwlActions.class);
117     }
118
119     public void pushNotification(@Nullable String event, @Nullable String description) {
120         pushNotification(event, description, 0);
121     }
122
123     public void pushNotification(@Nullable String event, @Nullable String description, int priority) {
124         if (event == null || description == null) {
125             logger.debug("Cannot push message with null event or null description");
126             return;
127         }
128
129         if (priority < -2) {
130             priority = -2;
131         } else if (priority > 2) {
132             priority = 2;
133         }
134
135         logger.debug("Pushing an event: {} with desc: {}", event, description);
136         try {
137             ContentResponse response = httpClient.POST(PROWL_ADD_URI).timeout(5, TimeUnit.SECONDS)
138                     .content(
139                             new StringContentProvider("apikey=" + config.apiKey + "&application=" + config.application
140                                     + "&event=" + event + "&description=" + description + "&priority=" + priority),
141                             "application/x-www-form-urlencoded; charset=UTF-8")
142                     .send();
143             String resp = response.getContentAsString();
144             updateFreeMessages(resp);
145             logger.trace("add response: {}", resp);
146         } catch (InterruptedException e) {
147             Thread.currentThread().interrupt();
148         } catch (ExecutionException e) {
149             logger.debug("error during calling uri: {}", PROWL_ADD_URI, e);
150         } catch (TimeoutException e) {
151             logger.debug("timeout during calling uri: {}", PROWL_ADD_URI, e);
152         }
153     }
154
155     private void updateFreeMessages(String resp) {
156         final String str = "remaining=\"";
157
158         // trying to simply parse the simple xml rather than using XPATH
159         int start = resp.indexOf(str) + str.length();
160         int end = resp.indexOf("\"", start + 1);
161
162         try {
163             String messages = resp.substring(start, end);
164             logger.debug("remaining messages parsed: {}", messages);
165             int freeMessages = Integer.parseInt(messages);
166             updateState(CHANNEL_REMAINING, new DecimalType(freeMessages));
167         } catch (StringIndexOutOfBoundsException | NumberFormatException ex) {
168             logger.debug("Error parsing remaining messages", ex);
169         }
170     }
171 }