]> git.basschouten.com Git - openhab-addons.git/blob
f43936324250feccb839f4ec90c1af2daef92689
[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 ThingTypeUID thingTypeUID;
65     private final String thingID;
66
67     public AndroidTVHandler(Thing thing, AndroidTVDynamicCommandDescriptionProvider commandDescriptionProvider,
68             ThingTypeUID thingTypeUID) {
69         super(thing);
70         this.commandDescriptionProvider = commandDescriptionProvider;
71         this.thingTypeUID = thingTypeUID;
72         this.thingID = this.getThing().getUID().getId();
73     }
74
75     public void setThingProperty(String property, String value) {
76         thing.setProperty(property, value);
77     }
78
79     public String getThingID() {
80         return this.thingID;
81     }
82
83     public void updateChannelState(String channel, State state) {
84         updateState(channel, state);
85     }
86
87     public ScheduledExecutorService getScheduler() {
88         return scheduler;
89     }
90
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);
97     }
98
99     private void monitorThingStatus() {
100         synchronized (monitorThingStatusJobLock) {
101             checkThingStatus();
102             monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
103                     TimeUnit.MILLISECONDS);
104         }
105     }
106
107     public void checkThingStatus() {
108         String statusMessage = "";
109         boolean failed = false;
110
111         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
112         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
113
114         if (googletvConnectionManager != null) {
115             if (!googletvConnectionManager.getLoggedIn()) {
116                 statusMessage = "GoogleTV: " + googletvConnectionManager.getStatusMessage();
117                 failed = true;
118             } else {
119                 statusMessage = "GoogleTV: ONLINE";
120             }
121         }
122
123         if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
124             if (shieldtvConnectionManager != null) {
125                 if (!shieldtvConnectionManager.getLoggedIn()) {
126                     statusMessage = statusMessage + " | ShieldTV: " + shieldtvConnectionManager.getStatusMessage();
127                     failed = true;
128                 } else {
129                     statusMessage = statusMessage + " | ShieldTV: ONLINE";
130                 }
131             }
132         }
133
134         if (failed) {
135             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, statusMessage);
136         } else {
137             updateStatus(ThingStatus.ONLINE);
138         }
139     }
140
141     @Override
142     public void initialize() {
143         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.protocols-starting");
144
145         GoogleTVConfiguration googletvConfig = getConfigAs(GoogleTVConfiguration.class);
146         String ipAddress = googletvConfig.ipAddress;
147
148         if (ipAddress.isBlank()) {
149             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
150                     "@text/offline.googletv-address-not-specified");
151             return;
152         }
153
154         googletvConnectionManager = new GoogleTVConnectionManager(this, googletvConfig);
155
156         if (THING_TYPE_SHIELDTV.equals(thingTypeUID)) {
157             ShieldTVConfiguration shieldtvConfig = getConfigAs(ShieldTVConfiguration.class);
158             ipAddress = shieldtvConfig.ipAddress;
159
160             if (ipAddress.isBlank()) {
161                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
162                         "@text/offline.shieldtv-address-not-specified");
163                 return;
164             }
165
166             shieldtvConnectionManager = new ShieldTVConnectionManager(this, shieldtvConfig);
167         }
168
169         monitorThingStatusJob = scheduler.schedule(this::monitorThingStatus, THING_STATUS_FREQUENCY,
170                 TimeUnit.MILLISECONDS);
171     }
172
173     @Override
174     public void handleCommand(ChannelUID channelUID, Command command) {
175         logger.trace("{} - Command received at handler: {} {}", this.thingID, channelUID.getId(), command);
176
177         if (command.toString().equals("REFRESH")) {
178             // REFRESH causes issues on some channels. Block for now until implemented.
179             return;
180         }
181
182         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
183         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
184
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);
211                 }
212             }
213             return;
214         }
215
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);
221                         return;
222                     }
223                 }
224             } else if (CHANNEL_APP.equals(channelUID.getId())) {
225                 if (command instanceof StringType) {
226                     shieldtvConnectionManager.handleCommand(channelUID, command);
227                     return;
228                 }
229             }
230         }
231
232         if (googletvConnectionManager != null) {
233             googletvConnectionManager.handleCommand(channelUID, command);
234             return;
235         }
236
237         logger.warn("{} - Commands All Failed.  Please report this as a bug. {} {}", thingID, channelUID.getId(),
238                 command);
239     }
240
241     @Override
242     public void dispose() {
243         synchronized (monitorThingStatusJobLock) {
244             ScheduledFuture<?> monitorThingStatusJob = this.monitorThingStatusJob;
245             if (monitorThingStatusJob != null) {
246                 monitorThingStatusJob.cancel(true);
247             }
248         }
249
250         GoogleTVConnectionManager googletvConnectionManager = this.googletvConnectionManager;
251         ShieldTVConnectionManager shieldtvConnectionManager = this.shieldtvConnectionManager;
252
253         if (shieldtvConnectionManager != null) {
254             shieldtvConnectionManager.dispose();
255         }
256
257         if (googletvConnectionManager != null) {
258             googletvConnectionManager.dispose();
259         }
260     }
261 }