]> git.basschouten.com Git - openhab-addons.git/blob
cc86d2a75aace44b367040ec964595115d42c6b1
[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.samsungtv.internal.service;
14
15 import static org.openhab.binding.samsungtv.internal.SamsungTvBindingConstants.*;
16
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.concurrent.CopyOnWriteArraySet;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.openhab.binding.samsungtv.internal.service.api.EventListener;
28 import org.openhab.binding.samsungtv.internal.service.api.SamsungTvService;
29 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
30 import org.openhab.core.io.transport.upnp.UpnpIOService;
31 import org.openhab.core.library.types.DecimalType;
32 import org.openhab.core.library.types.OnOffType;
33 import org.openhab.core.library.types.PercentType;
34 import org.openhab.core.types.Command;
35 import org.openhab.core.types.RefreshType;
36 import org.openhab.core.types.State;
37 import org.openhab.core.types.UnDefType;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * The {@link MediaRendererService} is responsible for handling MediaRenderer
43  * commands.
44  *
45  * @author Pauli Anttila - Initial contribution
46  */
47 @NonNullByDefault
48 public class MediaRendererService implements UpnpIOParticipant, SamsungTvService {
49
50     public static final String SERVICE_NAME = "MediaRenderer";
51     private static final List<String> SUPPORTED_CHANNELS = Arrays.asList(VOLUME, MUTE, BRIGHTNESS, CONTRAST, SHARPNESS,
52             COLOR_TEMPERATURE);
53
54     private final Logger logger = LoggerFactory.getLogger(MediaRendererService.class);
55
56     private final UpnpIOService service;
57
58     private final String udn;
59
60     private Map<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
61
62     private Set<EventListener> listeners = new CopyOnWriteArraySet<>();
63
64     private boolean started;
65
66     public MediaRendererService(UpnpIOService upnpIOService, String udn) {
67         logger.debug("Creating a Samsung TV MediaRenderer service");
68         this.service = upnpIOService;
69         this.udn = udn;
70     }
71
72     @Override
73     public List<String> getSupportedChannelNames() {
74         return SUPPORTED_CHANNELS;
75     }
76
77     @Override
78     public void addEventListener(EventListener listener) {
79         listeners.add(listener);
80     }
81
82     @Override
83     public void removeEventListener(EventListener listener) {
84         listeners.remove(listener);
85     }
86
87     @Override
88     public void start() {
89         service.registerParticipant(this);
90         started = true;
91     }
92
93     @Override
94     public void stop() {
95         service.unregisterParticipant(this);
96         started = false;
97     }
98
99     @Override
100     public void clearCache() {
101         stateMap.clear();
102     }
103
104     @Override
105     public boolean isUpnp() {
106         return true;
107     }
108
109     @Override
110     public void handleCommand(String channel, Command command) {
111         logger.debug("Received channel: {}, command: {}", channel, command);
112
113         if (!started) {
114             return;
115         }
116
117         if (command == RefreshType.REFRESH) {
118             if (isRegistered()) {
119                 switch (channel) {
120                     case VOLUME:
121                         updateResourceState("RenderingControl", "GetVolume",
122                                 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
123                         break;
124                     case MUTE:
125                         updateResourceState("RenderingControl", "GetMute",
126                                 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
127                         break;
128                     case BRIGHTNESS:
129                         updateResourceState("RenderingControl", "GetBrightness",
130                                 SamsungTvUtils.buildHashMap("InstanceID", "0"));
131                         break;
132                     case CONTRAST:
133                         updateResourceState("RenderingControl", "GetContrast",
134                                 SamsungTvUtils.buildHashMap("InstanceID", "0"));
135                         break;
136                     case SHARPNESS:
137                         updateResourceState("RenderingControl", "GetSharpness",
138                                 SamsungTvUtils.buildHashMap("InstanceID", "0"));
139                         break;
140                     case COLOR_TEMPERATURE:
141                         updateResourceState("RenderingControl", "GetColorTemperature",
142                                 SamsungTvUtils.buildHashMap("InstanceID", "0"));
143                         break;
144                     default:
145                         break;
146                 }
147             }
148             return;
149         }
150
151         switch (channel) {
152             case VOLUME:
153                 setVolume(command);
154                 break;
155             case MUTE:
156                 setMute(command);
157                 break;
158             case BRIGHTNESS:
159                 setBrightness(command);
160                 break;
161             case CONTRAST:
162                 setContrast(command);
163                 break;
164             case SHARPNESS:
165                 setSharpness(command);
166                 break;
167             case COLOR_TEMPERATURE:
168                 setColorTemperature(command);
169                 break;
170             default:
171                 logger.warn("Samsung TV doesn't support transmitting for channel '{}'", channel);
172         }
173     }
174
175     private boolean isRegistered() {
176         return service.isRegistered(this);
177     }
178
179     @Override
180     public String getUDN() {
181         return udn;
182     }
183
184     @Override
185     public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
186     }
187
188     @Override
189     public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
190         if (variable == null) {
191             return;
192         }
193
194         String oldValue = stateMap.get(variable);
195         if ((value == null && oldValue == null) || (value != null && value.equals(oldValue))) {
196             logger.trace("Value '{}' for {} hasn't changed, ignoring update", value, variable);
197             return;
198         }
199
200         stateMap.put(variable, (value != null) ? value : "");
201
202         for (EventListener listener : listeners) {
203             switch (variable) {
204                 case "CurrentVolume":
205                     listener.valueReceived(VOLUME, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
206                     break;
207
208                 case "CurrentMute":
209                     State newState = UnDefType.UNDEF;
210                     if (value != null) {
211                         newState = OnOffType.from("true".equals(value));
212                     }
213                     listener.valueReceived(MUTE, newState);
214                     break;
215
216                 case "CurrentBrightness":
217                     listener.valueReceived(BRIGHTNESS, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
218                     break;
219
220                 case "CurrentContrast":
221                     listener.valueReceived(CONTRAST, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
222                     break;
223
224                 case "CurrentSharpness":
225                     listener.valueReceived(SHARPNESS, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
226                     break;
227
228                 case "CurrentColorTemperature":
229                     listener.valueReceived(COLOR_TEMPERATURE,
230                             (value != null) ? new DecimalType(value) : UnDefType.UNDEF);
231                     break;
232             }
233         }
234     }
235
236     protected Map<String, String> updateResourceState(String serviceId, String actionId, Map<String, String> inputs) {
237         Map<String, String> result = service.invokeAction(this, serviceId, actionId, inputs);
238
239         for (String variable : result.keySet()) {
240             onValueReceived(variable, result.get(variable), serviceId);
241         }
242
243         return result;
244     }
245
246     private void setVolume(Command command) {
247         int newValue;
248
249         try {
250             newValue = DataConverters.convertCommandToIntValue(command, 0, 100,
251                     Integer.valueOf(stateMap.getOrDefault("CurrentVolume", "")));
252         } catch (NumberFormatException e) {
253             throw new NumberFormatException("Command '" + command + "' not supported");
254         }
255
256         updateResourceState("RenderingControl", "SetVolume", SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel",
257                 "Master", "DesiredVolume", Integer.toString(newValue)));
258
259         updateResourceState("RenderingControl", "GetVolume",
260                 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
261     }
262
263     private void setMute(Command command) {
264         boolean newValue;
265
266         try {
267             newValue = DataConverters.convertCommandToBooleanValue(command);
268         } catch (NumberFormatException e) {
269             throw new NumberFormatException("Command '" + command + "' not supported");
270         }
271
272         updateResourceState("RenderingControl", "SetMute", SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel",
273                 "Master", "DesiredMute", Boolean.toString(newValue)));
274
275         updateResourceState("RenderingControl", "GetMute",
276                 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
277     }
278
279     private void setBrightness(Command command) {
280         int newValue;
281
282         try {
283             newValue = DataConverters.convertCommandToIntValue(command, 0, 100,
284                     Integer.valueOf(stateMap.getOrDefault("CurrentBrightness", "")));
285         } catch (NumberFormatException e) {
286             throw new NumberFormatException("Command '" + command + "' not supported");
287         }
288
289         updateResourceState("RenderingControl", "SetBrightness",
290                 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredBrightness", Integer.toString(newValue)));
291
292         updateResourceState("RenderingControl", "GetBrightness", SamsungTvUtils.buildHashMap("InstanceID", "0"));
293     }
294
295     private void setContrast(Command command) {
296         int newValue;
297
298         try {
299             newValue = DataConverters.convertCommandToIntValue(command, 0, 100,
300                     Integer.valueOf(stateMap.getOrDefault("CurrentContrast", "")));
301         } catch (NumberFormatException e) {
302             throw new NumberFormatException("Command '" + command + "' not supported");
303         }
304
305         updateResourceState("RenderingControl", "SetContrast",
306                 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredContrast", Integer.toString(newValue)));
307
308         updateResourceState("RenderingControl", "GetContrast", SamsungTvUtils.buildHashMap("InstanceID", "0"));
309     }
310
311     private void setSharpness(Command command) {
312         int newValue;
313
314         try {
315             newValue = DataConverters.convertCommandToIntValue(command, 0, 100,
316                     Integer.valueOf(stateMap.getOrDefault("CurrentSharpness", "")));
317         } catch (NumberFormatException e) {
318             throw new NumberFormatException("Command '" + command + "' not supported");
319         }
320
321         updateResourceState("RenderingControl", "SetSharpness",
322                 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredSharpness", Integer.toString(newValue)));
323
324         updateResourceState("RenderingControl", "GetSharpness", SamsungTvUtils.buildHashMap("InstanceID", "0"));
325     }
326
327     private void setColorTemperature(Command command) {
328         int newValue;
329
330         try {
331             newValue = DataConverters.convertCommandToIntValue(command, 0, 4,
332                     Integer.valueOf(stateMap.getOrDefault("CurrentColorTemperature", "")));
333         } catch (NumberFormatException e) {
334             throw new NumberFormatException("Command '" + command + "' not supported");
335         }
336
337         updateResourceState("RenderingControl", "SetColorTemperature",
338                 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredColorTemperature", Integer.toString(newValue)));
339
340         updateResourceState("RenderingControl", "GetColorTemperature", SamsungTvUtils.buildHashMap("InstanceID", "0"));
341     }
342
343     @Override
344     public void onStatusChanged(boolean status) {
345         logger.debug("onStatusChanged: status={}", status);
346     }
347 }