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