2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.samsungtv.internal.service;
15 import static org.openhab.binding.samsungtv.internal.SamsungTvBindingConstants.*;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.List;
23 import java.util.concurrent.CopyOnWriteArraySet;
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;
42 * The {@link MediaRendererService} is responsible for handling MediaRenderer
45 * @author Pauli Anttila - Initial contribution
48 public class MediaRendererService implements UpnpIOParticipant, SamsungTvService {
50 public static final String SERVICE_NAME = "MediaRenderer";
51 private static final List<String> SUPPORTED_CHANNELS = Arrays.asList(VOLUME, MUTE, BRIGHTNESS, CONTRAST, SHARPNESS,
54 private final Logger logger = LoggerFactory.getLogger(MediaRendererService.class);
56 private final UpnpIOService service;
58 private final String udn;
60 private Map<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
62 private Set<EventListener> listeners = new CopyOnWriteArraySet<>();
64 private boolean started;
66 public MediaRendererService(UpnpIOService upnpIOService, String udn) {
67 logger.debug("Creating a Samsung TV MediaRenderer service");
68 this.service = upnpIOService;
73 public List<String> getSupportedChannelNames() {
74 return SUPPORTED_CHANNELS;
78 public void addEventListener(EventListener listener) {
79 listeners.add(listener);
83 public void removeEventListener(EventListener listener) {
84 listeners.remove(listener);
89 service.registerParticipant(this);
95 service.unregisterParticipant(this);
100 public void clearCache() {
105 public boolean isUpnp() {
110 public void handleCommand(String channel, Command command) {
111 logger.debug("Received channel: {}, command: {}", channel, command);
117 if (command == RefreshType.REFRESH) {
118 if (isRegistered()) {
121 updateResourceState("RenderingControl", "GetVolume",
122 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
125 updateResourceState("RenderingControl", "GetMute",
126 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
129 updateResourceState("RenderingControl", "GetBrightness",
130 SamsungTvUtils.buildHashMap("InstanceID", "0"));
133 updateResourceState("RenderingControl", "GetContrast",
134 SamsungTvUtils.buildHashMap("InstanceID", "0"));
137 updateResourceState("RenderingControl", "GetSharpness",
138 SamsungTvUtils.buildHashMap("InstanceID", "0"));
140 case COLOR_TEMPERATURE:
141 updateResourceState("RenderingControl", "GetColorTemperature",
142 SamsungTvUtils.buildHashMap("InstanceID", "0"));
159 setBrightness(command);
162 setContrast(command);
165 setSharpness(command);
167 case COLOR_TEMPERATURE:
168 setColorTemperature(command);
171 logger.warn("Samsung TV doesn't support transmitting for channel '{}'", channel);
175 private boolean isRegistered() {
176 return service.isRegistered(this);
180 public String getUDN() {
185 public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
189 public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
190 if (variable == null) {
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);
200 stateMap.put(variable, (value != null) ? value : "");
202 for (EventListener listener : listeners) {
204 case "CurrentVolume":
205 listener.valueReceived(VOLUME, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
209 State newState = UnDefType.UNDEF;
211 newState = value.equals("true") ? OnOffType.ON : OnOffType.OFF;
213 listener.valueReceived(MUTE, newState);
216 case "CurrentBrightness":
217 listener.valueReceived(BRIGHTNESS, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
220 case "CurrentContrast":
221 listener.valueReceived(CONTRAST, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
224 case "CurrentSharpness":
225 listener.valueReceived(SHARPNESS, (value != null) ? new PercentType(value) : UnDefType.UNDEF);
228 case "CurrentColorTemperature":
229 listener.valueReceived(COLOR_TEMPERATURE,
230 (value != null) ? new DecimalType(value) : UnDefType.UNDEF);
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);
239 for (String variable : result.keySet()) {
240 onValueReceived(variable, result.get(variable), serviceId);
246 private void setVolume(Command command) {
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");
256 updateResourceState("RenderingControl", "SetVolume", SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel",
257 "Master", "DesiredVolume", Integer.toString(newValue)));
259 updateResourceState("RenderingControl", "GetVolume",
260 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
263 private void setMute(Command command) {
267 newValue = DataConverters.convertCommandToBooleanValue(command);
268 } catch (NumberFormatException e) {
269 throw new NumberFormatException("Command '" + command + "' not supported");
272 updateResourceState("RenderingControl", "SetMute", SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel",
273 "Master", "DesiredMute", Boolean.toString(newValue)));
275 updateResourceState("RenderingControl", "GetMute",
276 SamsungTvUtils.buildHashMap("InstanceID", "0", "Channel", "Master"));
279 private void setBrightness(Command command) {
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");
289 updateResourceState("RenderingControl", "SetBrightness",
290 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredBrightness", Integer.toString(newValue)));
292 updateResourceState("RenderingControl", "GetBrightness", SamsungTvUtils.buildHashMap("InstanceID", "0"));
295 private void setContrast(Command command) {
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");
305 updateResourceState("RenderingControl", "SetContrast",
306 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredContrast", Integer.toString(newValue)));
308 updateResourceState("RenderingControl", "GetContrast", SamsungTvUtils.buildHashMap("InstanceID", "0"));
311 private void setSharpness(Command command) {
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");
321 updateResourceState("RenderingControl", "SetSharpness",
322 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredSharpness", Integer.toString(newValue)));
324 updateResourceState("RenderingControl", "GetSharpness", SamsungTvUtils.buildHashMap("InstanceID", "0"));
327 private void setColorTemperature(Command command) {
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");
337 updateResourceState("RenderingControl", "SetColorTemperature",
338 SamsungTvUtils.buildHashMap("InstanceID", "0", "DesiredColorTemperature", Integer.toString(newValue)));
340 updateResourceState("RenderingControl", "GetColorTemperature", SamsungTvUtils.buildHashMap("InstanceID", "0"));
344 public void onStatusChanged(boolean status) {
345 logger.debug("onStatusChanged: status={}", status);