2 * Copyright (c) 2010-2021 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.roku.internal.communication;
15 import java.io.StringReader;
16 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.TimeoutException;
20 import javax.xml.bind.JAXBContext;
21 import javax.xml.bind.JAXBException;
22 import javax.xml.bind.Unmarshaller;
23 import javax.xml.stream.XMLStreamException;
24 import javax.xml.stream.XMLStreamReader;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jetty.client.HttpClient;
28 import org.eclipse.jetty.http.HttpMethod;
29 import org.openhab.binding.roku.internal.RokuHttpException;
30 import org.openhab.binding.roku.internal.dto.ActiveApp;
31 import org.openhab.binding.roku.internal.dto.Apps;
32 import org.openhab.binding.roku.internal.dto.Apps.App;
33 import org.openhab.binding.roku.internal.dto.DeviceInfo;
34 import org.openhab.binding.roku.internal.dto.Player;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * Methods for accessing the HTTP interface of the Roku
41 * @author Michael Lobstein - Initial contribution
44 public class RokuCommunicator {
45 private final Logger logger = LoggerFactory.getLogger(RokuCommunicator.class);
46 private final HttpClient httpClient;
48 private final String urlKeyPress;
49 private final String urlLaunchApp;
50 private final String urlQryDevice;
51 private final String urlQryActiveApp;
52 private final String urlQryApps;
53 private final String urlQryPlayer;
55 public RokuCommunicator(HttpClient httpClient, String host, int port) {
56 this.httpClient = httpClient;
58 final String baseUrl = "http://" + host + ":" + port;
59 urlKeyPress = baseUrl + "/keypress/";
60 urlLaunchApp = baseUrl + "/launch/";
61 urlQryDevice = baseUrl + "/query/device-info";
62 urlQryActiveApp = baseUrl + "/query/active-app";
63 urlQryApps = baseUrl + "/query/apps";
64 urlQryPlayer = baseUrl + "/query/media-player";
68 * Send a keypress command to the Roku
70 * @param key The key code to send
73 public void keyPress(String key) throws RokuHttpException {
74 postCommand(urlKeyPress + key);
78 * Send a launch app command to the Roku
80 * @param appId The appId of the app to launch
83 public void launchApp(String appId) throws RokuHttpException {
84 postCommand(urlLaunchApp + appId);
88 * Send a command to get device-info from the Roku and return a DeviceInfo object
90 * @return A DeviceInfo object populated with information about the connected Roku
91 * @throws RokuHttpException
93 public DeviceInfo getDeviceInfo() throws RokuHttpException {
95 JAXBContext ctx = JAXBUtils.JAXBCONTEXT_DEVICE_INFO;
97 Unmarshaller unmarshaller = ctx.createUnmarshaller();
98 if (unmarshaller != null) {
99 XMLStreamReader xsr = JAXBUtils.XMLINPUTFACTORY
100 .createXMLStreamReader(new StringReader(getCommand(urlQryDevice)));
101 DeviceInfo device = (DeviceInfo) unmarshaller.unmarshal(xsr);
102 if (device != null) {
107 throw new RokuHttpException("No DeviceInfo model in response");
108 } catch (JAXBException | XMLStreamException e) {
109 throw new RokuHttpException("Exception creating DeviceInfo Unmarshaller: " + e.getLocalizedMessage());
114 * Send a command to get active-app from the Roku and return an ActiveApp object
116 * @return An ActiveApp object populated with information about the current running app on the Roku
117 * @throws RokuHttpException
119 public ActiveApp getActiveApp() throws RokuHttpException {
121 JAXBContext ctx = JAXBUtils.JAXBCONTEXT_ACTIVE_APP;
123 Unmarshaller unmarshaller = ctx.createUnmarshaller();
124 if (unmarshaller != null) {
125 XMLStreamReader xsr = JAXBUtils.XMLINPUTFACTORY
126 .createXMLStreamReader(new StringReader(getCommand(urlQryActiveApp)));
127 ActiveApp activeApp = (ActiveApp) unmarshaller.unmarshal(xsr);
128 if (activeApp != null) {
133 throw new RokuHttpException("No ActiveApp model in response");
134 } catch (JAXBException | XMLStreamException e) {
135 throw new RokuHttpException("Exception creating ActiveApp Unmarshaller: " + e.getLocalizedMessage());
140 * Send a command to get the installed app list from the Roku and return a List of App objects
142 * @return A List of App objects for all apps currently installed on the Roku
143 * @throws RokuHttpException
145 public List<App> getAppList() throws RokuHttpException {
147 JAXBContext ctx = JAXBUtils.JAXBCONTEXT_APPS;
149 Unmarshaller unmarshaller = ctx.createUnmarshaller();
150 if (unmarshaller != null) {
151 XMLStreamReader xsr = JAXBUtils.XMLINPUTFACTORY
152 .createXMLStreamReader(new StringReader(getCommand(urlQryApps)));
153 Apps appList = (Apps) unmarshaller.unmarshal(xsr);
154 if (appList != null) {
155 return appList.getApp();
159 throw new RokuHttpException("No AppList model in response");
160 } catch (JAXBException | XMLStreamException e) {
161 throw new RokuHttpException("Exception creating AppList Unmarshaller: " + e.getLocalizedMessage());
166 * Send a command to get media-player from the Roku and return a Player object
168 * @return A Player object populated with information about the current stream playing on the Roku
169 * @throws RokuHttpException
171 public Player getPlayerInfo() throws RokuHttpException {
173 JAXBContext ctx = JAXBUtils.JAXBCONTEXT_PLAYER;
175 Unmarshaller unmarshaller = ctx.createUnmarshaller();
176 if (unmarshaller != null) {
177 XMLStreamReader xsr = JAXBUtils.XMLINPUTFACTORY
178 .createXMLStreamReader(new StringReader(getCommand(urlQryPlayer)));
179 Player playerInfo = (Player) unmarshaller.unmarshal(xsr);
180 if (playerInfo != null) {
185 throw new RokuHttpException("No Player info model in response");
186 } catch (JAXBException | XMLStreamException e) {
187 throw new RokuHttpException("Exception creating Player info Unmarshaller: " + e.getLocalizedMessage());
192 * Sends a GET command to the Roku
194 * @param url The url to send with the command embedded in the URI
195 * @return The response content of the http request
197 private String getCommand(String url) {
199 return httpClient.GET(url).getContentAsString();
200 } catch (InterruptedException | TimeoutException | ExecutionException e) {
201 logger.debug("Error executing player GET command, URL: {}, {} ", url, e.getMessage());
207 * Sends a POST command to the Roku
209 * @param url The url to send with the command embedded in the URI
210 * @throws RokuHttpException
212 private void postCommand(String url) throws RokuHttpException {
214 httpClient.POST(url).method(HttpMethod.POST).send();
215 } catch (InterruptedException | TimeoutException | ExecutionException e) {
216 throw new RokuHttpException("Error executing player POST command, URL: " + url + e.getMessage());