]> git.basschouten.com Git - openhab-addons.git/blob
851b29393f74b9df89e8cf8760763d914cc8572d
[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.androidtv.internal;
14
15 import static org.openhab.binding.androidtv.internal.AndroidTVBindingConstants.*;
16
17 import java.util.ArrayList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.concurrent.ScheduledExecutorService;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
23
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;
42
43 /**
44  * The {@link AndroidTVHandler} is responsible for handling commands, which are
45  * sent to one of the channels.
46  *
47  * Significant portions reused from Lutron binding with permission from Bob A.
48  *
49  * @author Ben Rosenblum - Initial contribution
50  */
51 @NonNullByDefault
52 public class AndroidTVHandler extends BaseThingHandler {
53
54     private final Logger logger = LoggerFactory.getLogger(AndroidTVHandler.class);
55
56     private @Nullable ShieldTVConnectionManager shieldtvConnectionManager;
57     private @Nullable GoogleTVConnectionManager googletvConnectionManager;
58
59     private @Nullable ScheduledFuture<?> monitorThingStatusJob;
60     private final Object monitorThingStatusJobLock = new Object();
61     private static final int THING_STATUS_FREQUENCY = 250;
62
63     private final AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider;
64     private final AndroidTVTranslationProvider translationProvider;
65     private final ThingTypeUID thingTypeUID;
66     private final String thingID;
67
68     private String currentThingStatus = "";
69     private boolean currentThingFailed = false;
70
71     public AndroidTVHandler(Thing thing, AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider,
72             AndroidTVTranslationProvider translationProvider, ThingTypeUID thingTypeUID) {
73         super(thing);
74         this.commandDescriptionProvider = commandDescriptionProvider;
75         this.translationProvider = translationProvider;
76         this.thingTypeUID = thingTypeUID;
77         this.thingID = this.getThing().getUID().getId();
78     }
79
80     public void setThingProperty(String property, String value) {
81         thing.setProperty(property, value);
82     }
83
84     public AndroidTVTranslationProvider getTranslationProvider() {
85         return translationProvider;
86     }
87
88     public String getThingID() {
89         return this.thingID;
90     }
91
92     public void updateChannelState(String channel, State state) {
93         updateState(channel, state);
94     }
95
96     public ScheduledExecutorService getScheduler() {
97         return scheduler;
98     }
99
100     public void updateCDP(String channelName, Map<String, String> cdpMap) {
101         logger.trace("{} - Updating CDP for {}", this.thingID, channelName);
102         List<CommandOption> commandOptions = new ArrayList<CommandOption>();
103         cdpMap.forEach((key, value) -> commandOptions.add(new CommandOption(key, value)));
104         logger.trace("{} - CDP List: {}", this.thingID, commandOptions);
105         commandDescriptionProvider.setCommandOptions(new ChannelUID(getThing().getUID(), channelName), commandOptions);
106     }
107
108     private void monitorThingStatus() {
109         synchronized (monitorThingStatusJobLock) {
110             checkThingStatus();
111             monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
112                     TimeUnit.MILLISECONDS);
113         }
114     }
115
116     public void checkThingStatus() {
117         String currentThingStatus = this.currentThingStatus;
118         boolean currentThingFailed = this.currentThingFailed;
119
120         String statusMessage = "";
121         boolean failed = false;
122
123         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
124         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
125
126         if (googletvConnectionManager != null) {
127             if (!googletvConnectionManager.getLoggedIn()) {
128                 failed = true;
129             }
130             statusMessage = "GoogleTV: " + googletvConnectionManager.getStatusMessage();
131         }
132
133         if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
134             if (shieldtvConnectionManager != null) {
135                 if (!shieldtvConnectionManager.getLoggedIn()) {
136                     failed = true;
137                 }
138                 statusMessage = statusMessage + " | ShieldTV: " + shieldtvConnectionManager.getStatusMessage();
139             }
140         }
141
142         if (!currentThingStatus.equals(statusMessage) || (currentThingFailed != failed)) {
143             if (failed) {
144                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, statusMessage);
145             } else {
146                 updateStatus(ThingStatus.ONLINE);
147             }
148         }
149
150         this.currentThingStatus = statusMessage;
151         this.currentThingFailed = failed;
152     }
153
154     @Override
155     public void initialize() {
156         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.protocols-starting");
157
158         GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
159         String ipAddress = googletvConfig.ipAddress;
160
161         if (ipAddress.isBlank()) {
162             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
163                     "@text/offline.googletv-address-not-specified");
164             return;
165         }
166
167         googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
168
169         if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
170             ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
171             ipAddress = shieldtvConfig.ipAddress;
172
173             if (ipAddress.isBlank()) {
174                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
175                         "@text/offline.shieldtv-address-not-specified");
176                 return;
177             }
178
179             shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
180         }
181
182         monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
183                 TimeUnit.MILLISECONDS);
184     }
185
186     @Override
187     public void handleCommand(ChannelUID channelUID, Command command) {
188         logger.trace("{} - Command received at handler: {} {}", this.thingID, channelUID.getId(), command);
189
190         if (command.toString().equals("REFRESH")) {
191             // REFRESH causes issues on some channels. Block for now until implemented.
192             return;
193         }
194
195         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
196         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
197
198         if (CHANNEL_DEBUG.equals(channelUID.getId())) {
199             if (command instanceof StringType) {
200                 if (command.toString().equals("GOOGLETV_HALT") && (googletvConnectionManager != null)) {
201                     googletvConnectionManager.dispose();
202                     googletvConnectionManager = null;
203                 } else if (command.toString().equals("GOOGLETV_START")) {
204                     GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
205                     googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
206                 } else if (command.toString().equals("GOOGLETV_SHIM") && (googletvConnectionManager == null)) {
207                     GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
208                     googletvConfig.shim = true;
209                     googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
210                 } else if (command.toString().equals("SHIELDTV_HALT") && (shieldtvConnectionManager != null)) {
211                     shieldtvConnectionManager.dispose();
212                     shieldtvConnectionManager = null;
213                 } else if (command.toString().equals("SHIELDTV_START")) {
214                     ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
215                     shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
216                 } else if (command.toString().equals("SHIELDTV_SHIM") && (shieldtvConnectionManager == null)) {
217                     ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
218                     shieldtvConfig.shim = true;
219                     shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
220                 } else if (command.toString().startsWith("GOOGLETV") && (googletvConnectionManager != null)) {
221                     googletvConnectionManager.handleCommand(channelUID, command);
222                 } else if (command.toString().startsWith("SHIELDTV") && (shieldtvConnectionManager != null)) {
223                     shieldtvConnectionManager.handleCommand(channelUID, command);
224                 }
225             }
226             return;
227         }
228
229         if (THING_TYPE_SHIELDTV.equals(thingTypeUID) && (shieldtvConnectionManager != null)) {
230             if (CHANNEL_PINCODE.equals(channelUID.getId())) {
231                 if (command instanceof StringType) {
232                     if (!shieldtvConnectionManager.getLoggedIn()) {
233                         shieldtvConnectionManager.handleCommand(channelUID, command);
234                         return;
235                     }
236                 }
237             } else if (CHANNEL_APP.equals(channelUID.getId())) {
238                 if (command instanceof StringType) {
239                     shieldtvConnectionManager.handleCommand(channelUID, command);
240                     return;
241                 }
242             }
243         }
244
245         if (googletvConnectionManager != null) {
246             googletvConnectionManager.handleCommand(channelUID, command);
247             return;
248         }
249
250         logger.warn("{} - Commands All Failed.  Please report this as a bug. {} {}", thingID, channelUID.getId(),
251                 command);
252     }
253
254     @Override
255     public void dispose() {
256         synchronized (monitorThingStatusJobLock) {
257             ScheduledFuture<?> monitorThingStatusJob = this.monitorThingStatusJob;
258             if (monitorThingStatusJob != null) {
259                 monitorThingStatusJob.cancel(true);
260             }
261         }
262
263         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
264         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
265
266         if (shieldtvConnectionManager != null) {
267             shieldtvConnectionManager.dispose();
268         }
269
270         if (googletvConnectionManager != null) {
271             googletvConnectionManager.dispose();
272         }
273     }
274 }