]> git.basschouten.com Git - openhab-addons.git/blob
dd2660b3cc123f54a63bd1e14eeeced90589d841
[openhab-addons.git] /
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.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<>();
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             if (!THING_TYPE_GOOGLETV.equals(thingTypeUID)) {
133                 statusMessage = statusMessage + " | ";
134             }
135         }
136
137         if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
138             if (shieldtvConnectionManager != null) {
139                 if (!shieldtvConnectionManager.getLoggedIn()) {
140                     failed = true;
141                 }
142                 statusMessage = statusMessage + "ShieldTV: " + shieldtvConnectionManager.getStatusMessage();
143             }
144         }
145
146         if (!currentThingStatus.equals(statusMessage) || (currentThingFailed != failed)) {
147             if (failed) {
148                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, statusMessage);
149             } else {
150                 updateStatus(ThingStatus.ONLINE);
151             }
152         }
153
154         this.currentThingStatus = statusMessage;
155         this.currentThingFailed = failed;
156     }
157
158     @Override
159     public void initialize() {
160         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.protocols-starting");
161
162         GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
163         String ipAddress = googletvConfig.ipAddress;
164         boolean gtvEnabled = googletvConfig.gtvEnabled;
165
166         if (THING_TYPE_GOOGLETV.equals(thingTypeUID) || gtvEnabled) {
167             if (ipAddress.isBlank()) {
168                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
169                         "@text/offline.googletv-address-not-specified");
170                 return;
171             }
172
173             googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
174         }
175
176         if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
177             ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
178             ipAddress = shieldtvConfig.ipAddress;
179
180             if (ipAddress.isBlank()) {
181                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
182                         "@text/offline.shieldtv-address-not-specified");
183                 return;
184             }
185
186             shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
187         }
188
189         monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
190                 TimeUnit.MILLISECONDS);
191     }
192
193     public void sendCommandToProtocol(ChannelUID channelUID, Command command) {
194         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
195         if (THING_TYPE_SHIELDTV.equals(thingTypeUID) && (shieldtvConnectionManager != null)) {
196             shieldtvConnectionManager.handleCommand(channelUID, command);
197         }
198     }
199
200     @Override
201     public void handleCommand(ChannelUID channelUID, Command command) {
202         logger.trace("{} - Command received at handler: {} {}", this.thingID, channelUID.getId(), command);
203
204         if (command.toString().equals("REFRESH")) {
205             // REFRESH causes issues on some channels. Block for now until implemented.
206             return;
207         }
208
209         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
210         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
211
212         if (CHANNEL_DEBUG.equals(channelUID.getId())) {
213             if (command instanceof StringType) {
214                 if (command.toString().equals("GOOGLETV_HALT") && (googletvConnectionManager != null)) {
215                     googletvConnectionManager.dispose();
216                     googletvConnectionManager = null;
217                 } else if (command.toString().equals("GOOGLETV_START")) {
218                     GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
219                     googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
220                 } else if (command.toString().equals("GOOGLETV_SHIM") && (googletvConnectionManager == null)) {
221                     GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
222                     googletvConfig.shim = true;
223                     googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
224                 } else if (command.toString().equals("SHIELDTV_HALT") && (shieldtvConnectionManager != null)) {
225                     shieldtvConnectionManager.dispose();
226                     shieldtvConnectionManager = null;
227                 } else if (command.toString().equals("SHIELDTV_START")) {
228                     ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
229                     shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
230                 } else if (command.toString().equals("SHIELDTV_SHIM") && (shieldtvConnectionManager == null)) {
231                     ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
232                     shieldtvConfig.shim = true;
233                     shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
234                 } else if (command.toString().startsWith("GOOGLETV") && (googletvConnectionManager != null)) {
235                     googletvConnectionManager.handleCommand(channelUID, command);
236                 } else if (command.toString().startsWith("SHIELDTV") && (shieldtvConnectionManager != null)) {
237                     shieldtvConnectionManager.handleCommand(channelUID, command);
238                 }
239             }
240             return;
241         }
242
243         if (THING_TYPE_SHIELDTV.equals(thingTypeUID) && (shieldtvConnectionManager != null)) {
244             if (CHANNEL_PINCODE.equals(channelUID.getId())) {
245                 if (command instanceof StringType) {
246                     if (!shieldtvConnectionManager.getLoggedIn()) {
247                         shieldtvConnectionManager.handleCommand(channelUID, command);
248                         return;
249                     }
250                 }
251             } else if (CHANNEL_APP.equals(channelUID.getId())) {
252                 if (command instanceof StringType) {
253                     shieldtvConnectionManager.handleCommand(channelUID, command);
254                     return;
255                 }
256             } else if (googletvConnectionManager == null) {
257                 shieldtvConnectionManager.handleCommand(channelUID, command);
258                 return;
259             }
260         }
261
262         if (googletvConnectionManager != null) {
263             googletvConnectionManager.handleCommand(channelUID, command);
264             return;
265         }
266
267         logger.warn("{} - Commands All Failed.  Please report this as a bug. {} {}", thingID, channelUID.getId(),
268                 command);
269     }
270
271     @Override
272     public void dispose() {
273         synchronized (monitorThingStatusJobLock) {
274             ScheduledFuture<?> monitorThingStatusJob = this.monitorThingStatusJob;
275             if (monitorThingStatusJob != null) {
276                 monitorThingStatusJob.cancel(true);
277             }
278         }
279
280         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
281         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
282
283         if (shieldtvConnectionManager != null) {
284             shieldtvConnectionManager.dispose();
285         }
286
287         if (googletvConnectionManager != null) {
288             googletvConnectionManager.dispose();
289         }
290     }
291 }