2 * Copyright (c) 2010-2023 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.androidtv.internal;
15 import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
17 import java.util.ArrayList;
18 import java.util.List;
20 import java.util.concurrent.ScheduledExecutorService;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.androidtv.internal.protocol.googletv.GoogleTVConfiguration;
27 import org.openhab.binding.androidtv.internal.protocol.googletv.GoogleTVConnectionManager;
28 import org.openhab.binding.androidtv.internal.protocol.shieldtv.ShieldTVConfiguration;
29 import org.openhab.binding.androidtv.internal.protocol.shieldtv.ShieldTVConnectionManager;
30 import org.openhab.core.library.types.StringType;
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.ThingStatusDetail;
35 import org.openhab.core.thing.ThingTypeUID;
36 import org.openhab.core.thing.binding.BaseThingHandler;
37 import org.openhab.core.types.Command;
38 import org.openhab.core.types.CommandOption;
39 import org.openhab.core.types.State;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * The {@link AndroidTVHandler} is responsible for handling commands, which are
45 * sent to one of the channels.
47 * Significant portions reused from Lutron binding with permission from Bob A.
49 * @author Ben Rosenblum - Initial contribution
52 public class AndroidTVHandler extends BaseThingHandler {
54 private final Logger logger = LoggerFactory.getLogger(AndroidTVHandler.class);
56 private @Nullable ShieldTVConnectionManager shieldtvConnectionManager;
57 private @Nullable GoogleTVConnectionManager googletvConnectionManager;
59 private @Nullable ScheduledFuture<?> monitorThingStatusJob;
60 private final Object monitorThingStatusJobLock = new Object();
61 private static final int THING_STATUS_FREQUENCY = 250;
63 private final AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider;
64 private final ThingTypeUID thingTypeUID;
65 private final String thingID;
67 public AndroidTVHandler(Thing thing, AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider,
68 ThingTypeUID thingTypeUID) {
70 this.commandDescriptionProvider = commandDescriptionProvider;
71 this.thingTypeUID = thingTypeUID;
72 this.thingID = this.getThing().getUID().getId();
75 public void setThingProperty(String property, String value) {
76 thing.setProperty(property, value);
79 public String getThingID() {
83 public void updateChannelState(String channel, State state) {
84 updateState(channel, state);
87 public ScheduledExecutorService getScheduler() {
91 public void updateCDP(String channelName, Map<String, String> cdpMap) {
92 logger.trace("{} - Updating CDP for {}", this.thingID, channelName);
93 List<CommandOption> commandOptions = new ArrayList<CommandOption>();
94 cdpMap.forEach((key, value) -> commandOptions.add(new CommandOption(key, value)));
95 logger.trace("{} - CDP List: {}", this.thingID, commandOptions);
96 commandDescriptionProvider.setCommandOptions(new ChannelUID(getThing().getUID(), channelName), commandOptions);
99 private void monitorThingStatus() {
100 synchronized (monitorThingStatusJobLock) {
102 monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
103 TimeUnit.MILLISECONDS);
107 public void checkThingStatus() {
108 String statusMessage = "";
109 boolean failed = false;
111 GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
112 ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
114 if (googletvConnectionManager != null) {
115 if (!googletvConnectionManager.getLoggedIn()) {
116 statusMessage = "GoogleTV: " + googletvConnectionManager.getStatusMessage();
119 statusMessage = "GoogleTV: ONLINE";
123 if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
124 if (shieldtvConnectionManager != null) {
125 if (!shieldtvConnectionManager.getLoggedIn()) {
126 statusMessage = statusMessage + " | ShieldTV: " + shieldtvConnectionManager.getStatusMessage();
129 statusMessage = statusMessage + " | ShieldTV: ONLINE";
135 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, statusMessage);
137 updateStatus(ThingStatus.ONLINE);
142 public void initialize() {
143 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.protocols-starting");
145 GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
146 String ipAddress = googletvConfig.ipAddress;
148 if (ipAddress.isBlank()) {
149 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
150 "@text/offline.googletv-address-not-specified");
154 googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
156 if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
157 ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
158 ipAddress = shieldtvConfig.ipAddress;
160 if (ipAddress.isBlank()) {
161 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
162 "@text/offline.shieldtv-address-not-specified");
166 shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
169 monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
170 TimeUnit.MILLISECONDS);
174 public void handleCommand(ChannelUID channelUID, Command command) {
175 logger.trace("{} - Command received at handler: {} {}", this.thingID, channelUID.getId(), command);
177 if (command.toString().equals("REFRESH")) {
178 // REFRESH causes issues on some channels. Block for now until implemented.
182 GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
183 ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
185 if (CHANNEL_DEBUG.equals(channelUID.getId())) {
186 if (command instanceof StringType) {
187 if (command.toString().equals("GOOGLETV_HALT") && (googletvConnectionManager != null)) {
188 googletvConnectionManager.dispose();
189 googletvConnectionManager = null;
190 } else if (command.toString().equals("GOOGLETV_START")) {
191 GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
192 googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
193 } else if (command.toString().equals("GOOGLETV_SHIM") && (googletvConnectionManager == null)) {
194 GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
195 googletvConfig.shim = true;
196 googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
197 } else if (command.toString().equals("SHIELDTV_HALT") && (shieldtvConnectionManager != null)) {
198 shieldtvConnectionManager.dispose();
199 shieldtvConnectionManager = null;
200 } else if (command.toString().equals("SHIELDTV_START")) {
201 ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
202 shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
203 } else if (command.toString().equals("SHIELDTV_SHIM") && (shieldtvConnectionManager == null)) {
204 ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
205 shieldtvConfig.shim = true;
206 shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
207 } else if (command.toString().startsWith("GOOGLETV") && (googletvConnectionManager != null)) {
208 googletvConnectionManager.handleCommand(channelUID, command);
209 } else if (command.toString().startsWith("SHIELDTV") && (shieldtvConnectionManager != null)) {
210 shieldtvConnectionManager.handleCommand(channelUID, command);
216 if (THING_TYPE_SHIELDTV.equals(thingTypeUID) && (shieldtvConnectionManager != null)) {
217 if (CHANNEL_PINCODE.equals(channelUID.getId())) {
218 if (command instanceof StringType) {
219 if (!shieldtvConnectionManager.getLoggedIn()) {
220 shieldtvConnectionManager.handleCommand(channelUID, command);
224 } else if (CHANNEL_APP.equals(channelUID.getId())) {
225 if (command instanceof StringType) {
226 shieldtvConnectionManager.handleCommand(channelUID, command);
232 if (googletvConnectionManager != null) {
233 googletvConnectionManager.handleCommand(channelUID, command);
237 logger.warn("{} - Commands All Failed. Please report this as a bug. {} {}", thingID, channelUID.getId(),
242 public void dispose() {
243 synchronized (monitorThingStatusJobLock) {
244 ScheduledFuture<?> monitorThingStatusJob = this.monitorThingStatusJob;
245 if (monitorThingStatusJob != null) {
246 monitorThingStatusJob.cancel(true);
250 GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
251 ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
253 if (shieldtvConnectionManager != null) {
254 shieldtvConnectionManager.dispose();
257 if (googletvConnectionManager != null) {
258 googletvConnectionManager.dispose();