2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.fsinternetradio.internal.radio;
15 import java.io.IOException;
16 import java.util.concurrent.TimeUnit;
18 import org.eclipse.jetty.client.HttpClient;
19 import org.eclipse.jetty.client.api.ContentResponse;
20 import org.eclipse.jetty.client.api.Request;
21 import org.eclipse.jetty.http.HttpMethod;
22 import org.eclipse.jetty.http.HttpStatus;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * This class holds the http-connection and session information for controlling the radio.
29 * @author Rainer Ostendorf
30 * @author Patrick Koenemann
31 * @author Svilen Valkanov - replaced Apache HttpClient with Jetty
32 * @author Mihaela Memova - changed the calling of the stopHttpClient() method, fixed the hardcoded URL path, fixed the
33 * for loop condition part
35 public class FrontierSiliconRadioConnection {
37 private final Logger logger = LoggerFactory.getLogger(FrontierSiliconRadioConnection.class);
39 /** Timeout for HTTP requests in ms */
40 private static final int SOCKET_TIMEOUT = 5000;
42 /** Hostname of the radio. */
43 private final String hostname;
45 /** Port number, usually 80. */
46 private final int port;
48 /** Access pin, passed upon login as GET parameter. */
49 private final String pin;
51 /** The session ID we get from the radio after logging in. */
52 private String sessionId;
54 /** http clients, store cookies, so it is kept in connection class. */
55 private HttpClient httpClient = null;
57 /** Flag indicating if we are successfully logged in. */
58 private boolean isLoggedIn = false;
60 public FrontierSiliconRadioConnection(String hostname, int port, String pin, HttpClient httpClient) {
61 this.hostname = hostname;
64 this.httpClient = httpClient;
67 public boolean isLoggedIn() {
72 * Perform login/establish a new session. Uses the PIN number and when successful saves the assigned sessionID for
75 * @return <code>true</code> if login was successful; <code>false</code> otherwise.
76 * @throws IOException if communication with the radio failed, e.g. because the device is not reachable.
78 public boolean doLogin() throws IOException {
79 isLoggedIn = false; // reset login flag
81 final String url = "http://" + hostname + ":" + port + FrontierSiliconRadioConstants.CONNECTION_PATH
82 + "/CREATE_SESSION?pin=" + pin;
84 logger.trace("opening URL: {}", url);
86 Request request = httpClient.newRequest(url).method(HttpMethod.GET).timeout(SOCKET_TIMEOUT,
87 TimeUnit.MILLISECONDS);
90 ContentResponse response = request.send();
91 int statusCode = response.getStatus();
92 if (statusCode != HttpStatus.OK_200) {
93 String reason = response.getReason();
94 logger.debug("Communication with radio failed: {} {}", statusCode, reason);
95 if (statusCode == HttpStatus.FORBIDDEN_403) {
96 throw new IllegalStateException("Radio does not allow connection, maybe wrong pin?");
98 throw new IOException("Communication with radio failed, return code: " + statusCode);
101 final String responseBody = response.getContentAsString();
102 if (!responseBody.isEmpty()) {
103 logger.trace("login response: {}", responseBody);
106 final FrontierSiliconRadioApiResult result = new FrontierSiliconRadioApiResult(responseBody);
107 if (result.isStatusOk()) {
108 logger.trace("login successful");
109 sessionId = result.getSessionId();
111 return true; // login successful :-)
114 } catch (Exception e) {
115 logger.debug("Fatal transport error: {}", e.toString());
116 throw new IOException(e);
119 return false; // login not successful
123 * Performs a request to the radio with no further parameters.
125 * Typically used for polling state info.
127 * @param requestString REST API request, e.g. "GET/netRemote.sys.power"
128 * @return request result
129 * @throws IOException if the request failed.
131 public FrontierSiliconRadioApiResult doRequest(String requestString) throws IOException {
132 return doRequest(requestString, null);
136 * Performs a request to the radio with addition parameters.
138 * Typically used for changing parameters.
140 * @param requestString REST API request, e.g. "SET/netRemote.sys.power"
141 * @param params parameters, e.g. "value=1"
142 * @return request result
143 * @throws IOException if the request failed.
145 public FrontierSiliconRadioApiResult doRequest(String requestString, String params) throws IOException {
146 // 3 retries upon failure
147 for (int i = 0; i < 3; i++) {
148 if (!isLoggedIn && !doLogin()) {
149 continue; // not logged in and login was not successful - try again!
152 final String url = "http://" + hostname + ":" + port + FrontierSiliconRadioConstants.CONNECTION_PATH + "/"
153 + requestString + "?pin=" + pin + "&sid=" + sessionId
154 + (params == null || params.trim().length() == 0 ? "" : "&" + params);
156 logger.trace("calling url: '{}'", url);
158 Request request = httpClient.newRequest(url).method(HttpMethod.GET).timeout(SOCKET_TIMEOUT,
159 TimeUnit.MILLISECONDS);
162 ContentResponse response = request.send();
163 final int statusCode = response.getStatus();
164 if (statusCode != HttpStatus.OK_200) {
166 * Issue: https://github.com/eclipse/smarthome/issues/2548
167 * If the session expired, we might get a 404 here. That's ok, remember that we are not logged-in
168 * and try again. Print warning only if this happens in the last iteration.
171 String reason = response.getReason();
172 logger.warn("Method failed: {} {}", statusCode, reason);
178 final String responseBody = response.getContentAsString();
179 if (!responseBody.isEmpty()) {
180 logger.trace("got result: {}", responseBody);
182 logger.debug("got empty result");
187 final FrontierSiliconRadioApiResult result = new FrontierSiliconRadioApiResult(responseBody);
188 if (result.isStatusOk()) {
193 continue; // try again
194 } catch (Exception e) {
195 logger.error("Fatal transport error: {}", e.toString());
196 throw new IOException(e);
199 isLoggedIn = false; // 3 tries failed. log in again next time, maybe our session went invalid (radio restarted?)