Skip to content

Commit 5d40a71

Browse files
authored
[roku] Check for ECP Limited Mode (openhab#17925)
Signed-off-by: Michael Lobstein <[email protected]>
1 parent 254f2f5 commit 5d40a71

File tree

5 files changed

+72
-5
lines changed

5 files changed

+72
-5
lines changed

bundles/org.openhab.binding.roku/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
This binding connects Roku streaming media players and Roku TVs to openHAB.
44
The Roku device must support the Roku ECP protocol REST API.
55

6+
In order for the binding to control the Roku, the following setting:
7+
**Settings-> System-> Advanced system settings-> Control by mobile apps**
8+
must be configured as `Enabled` or `Permissive`.
9+
610
## Supported Things
711

812
There are two supported thing types, which represent either a standalone Roku device or a Roku TV.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright (c) 2010-2024 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.roku.internal;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
17+
/**
18+
* The {@link RokuLimitedModeException} extends RokuHttpException
19+
*
20+
* @author Michael Lobstein - Initial contribution
21+
*/
22+
@NonNullByDefault
23+
public class RokuLimitedModeException extends RokuHttpException {
24+
private static final long serialVersionUID = 1L;
25+
26+
public RokuLimitedModeException(String errorMessage, Throwable t) {
27+
super(errorMessage, t);
28+
}
29+
30+
public RokuLimitedModeException(String errorMessage) {
31+
super(errorMessage);
32+
}
33+
}

bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/communication/RokuCommunicator.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.eclipse.jetty.client.HttpClient;
2929
import org.eclipse.jetty.http.HttpMethod;
3030
import org.openhab.binding.roku.internal.RokuHttpException;
31+
import org.openhab.binding.roku.internal.RokuLimitedModeException;
3132
import org.openhab.binding.roku.internal.dto.ActiveApp;
3233
import org.openhab.binding.roku.internal.dto.Apps;
3334
import org.openhab.binding.roku.internal.dto.Apps.App;
@@ -47,6 +48,7 @@
4748
@NonNullByDefault
4849
public class RokuCommunicator {
4950
private static final int REQUEST_TIMEOUT = 5000;
51+
private static final String LIMITED_MODE_RESPONSE = "ECP command not allowed";
5052

5153
private final Logger logger = LoggerFactory.getLogger(RokuCommunicator.class);
5254
private final HttpClient httpClient;
@@ -283,8 +285,12 @@ public List<Channel> getTvChannelList() throws RokuHttpException {
283285
*/
284286
private String getCommand(String url) throws RokuHttpException {
285287
try {
286-
return httpClient.newRequest(url).method(HttpMethod.GET).timeout(REQUEST_TIMEOUT, TimeUnit.MILLISECONDS)
287-
.send().getContentAsString();
288+
final String response = httpClient.newRequest(url).method(HttpMethod.GET)
289+
.timeout(REQUEST_TIMEOUT, TimeUnit.MILLISECONDS).send().getContentAsString();
290+
if (response != null && response.contains(LIMITED_MODE_RESPONSE)) {
291+
throw new RokuLimitedModeException(url + ": " + response);
292+
}
293+
return response != null ? response : "";
288294
} catch (TimeoutException | ExecutionException e) {
289295
throw new RokuHttpException("Error executing GET command for URL: " + url, e);
290296
} catch (InterruptedException e) {

bundles/org.openhab.binding.roku/src/main/java/org/openhab/binding/roku/internal/handler/RokuHandler.java

+23-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.eclipse.jetty.client.HttpClient;
2727
import org.openhab.binding.roku.internal.RokuConfiguration;
2828
import org.openhab.binding.roku.internal.RokuHttpException;
29+
import org.openhab.binding.roku.internal.RokuLimitedModeException;
2930
import org.openhab.binding.roku.internal.RokuStateDescriptionOptionProvider;
3031
import org.openhab.binding.roku.internal.communication.RokuCommunicator;
3132
import org.openhab.binding.roku.internal.dto.Apps.App;
@@ -73,6 +74,7 @@ public class RokuHandler extends BaseThingHandler {
7374
private DeviceInfo deviceInfo = new DeviceInfo();
7475
private int refreshInterval = DEFAULT_REFRESH_PERIOD_SEC;
7576
private boolean tvActive = false;
77+
private int limitedMode = -1;
7678
private Map<String, String> appMap = new HashMap<>();
7779

7880
private Object sequenceLock = new Object();
@@ -175,18 +177,20 @@ private void refreshPlayerState() {
175177
}
176178
tvActive = false;
177179
}
178-
updateStatus(ThingStatus.ONLINE);
179180
} catch (RokuHttpException e) {
180181
logger.debug("Unable to retrieve Roku active-app info. Exception: {}", e.getMessage(), e);
181182
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
183+
return;
182184
}
183185

184186
// On the home app and when using the TV or TV inputs, do not update the play mode or time channels
185-
if (!ROKU_HOME_ID.equals(activeAppId) && !activeAppId.contains(TV_INPUT)) {
187+
// if in limitedMode, keep checking getPlayerInfo to see if the error goes away
188+
if ((!ROKU_HOME_ID.equals(activeAppId) && !activeAppId.contains(TV_INPUT)) || limitedMode != 0) {
186189
try {
187190
Player playerInfo = communicator.getPlayerInfo();
191+
limitedMode = 0;
188192
// When nothing playing, 'close' is reported, replace with 'stop'
189-
updateState(PLAY_MODE, new StringType(playerInfo.getState().replaceAll(CLOSE, STOP)));
193+
updateState(PLAY_MODE, new StringType(playerInfo.getState().replace(CLOSE, STOP)));
190194
updateState(CONTROL,
191195
PLAY.equalsIgnoreCase(playerInfo.getState()) ? PlayPauseType.PLAY : PlayPauseType.PAUSE);
192196

@@ -208,9 +212,13 @@ private void refreshPlayerState() {
208212
}
209213
} catch (NumberFormatException e) {
210214
logger.debug("Unable to parse playerInfo integer value. Exception: {}", e.getMessage());
215+
} catch (RokuLimitedModeException e) {
216+
logger.debug("RokuLimitedModeException: {}", e.getMessage());
217+
limitedMode = 1;
211218
} catch (RokuHttpException e) {
212219
logger.debug("Unable to retrieve Roku media-player info. Exception: {}", e.getMessage(), e);
213220
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
221+
return;
214222
}
215223
} else {
216224
updateState(PLAY_MODE, UnDefType.UNDEF);
@@ -221,6 +229,7 @@ private void refreshPlayerState() {
221229
if (thingTypeUID.equals(THING_TYPE_ROKU_TV) && tvActive) {
222230
try {
223231
TvChannel tvChannel = communicator.getActiveTvChannel();
232+
limitedMode = 0;
224233
updateState(ACTIVE_CHANNEL, new StringType(tvChannel.getChannel().getNumber()));
225234
updateState(SIGNAL_MODE, new StringType(tvChannel.getChannel().getSignalMode()));
226235
updateState(SIGNAL_QUALITY,
@@ -229,10 +238,21 @@ private void refreshPlayerState() {
229238
updateState(PROGRAM_TITLE, new StringType(tvChannel.getChannel().getProgramTitle()));
230239
updateState(PROGRAM_DESCRIPTION, new StringType(tvChannel.getChannel().getProgramDescription()));
231240
updateState(PROGRAM_RATING, new StringType(tvChannel.getChannel().getProgramRatings()));
241+
} catch (RokuLimitedModeException e) {
242+
logger.debug("RokuLimitedModeException: {}", e.getMessage());
243+
limitedMode = 1;
232244
} catch (RokuHttpException e) {
233245
logger.debug("Unable to retrieve Roku tv-active-channel info. Exception: {}", e.getMessage(), e);
246+
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
247+
return;
234248
}
235249
}
250+
251+
if (limitedMode < 1) {
252+
updateStatus(ThingStatus.ONLINE);
253+
} else {
254+
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/error.limited");
255+
}
236256
}
237257
}
238258

bundles/org.openhab.binding.roku/src/main/resources/OH-INF/i18n/roku.properties

+4
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,7 @@ channel-type.roku.timeElapsed.label = Playback Time
101101
channel-type.roku.timeElapsed.description = The Current Playback Time Elapsed
102102
channel-type.roku.timeTotal.label = Total Time
103103
channel-type.roku.timeTotal.description = The Total Length of the Current Title
104+
105+
# error status descriptions
106+
107+
error.limited = Roku device is configured incorrectly - see README

0 commit comments

Comments
 (0)