2 * Copyright (c) 2010-2020 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.upnpcontrol.internal.handler;
15 import java.util.HashMap;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.upnpcontrol.internal.config.UpnpControlConfiguration;
21 import org.openhab.core.io.transport.upnp.UpnpIOParticipant;
22 import org.openhab.core.io.transport.upnp.UpnpIOService;
23 import org.openhab.core.thing.Thing;
24 import org.openhab.core.thing.ThingStatus;
25 import org.openhab.core.thing.ThingStatusDetail;
26 import org.openhab.core.thing.binding.BaseThingHandler;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 * The {@link UpnpHandler} is the base class for {@link UpnpRendererHandler} and {@link UpnpServerHandler}.
33 * @author Mark Herwege - Initial contribution
34 * @author Karel Goderis - Based on UPnP logic in Sonos binding
37 public abstract class UpnpHandler extends BaseThingHandler implements UpnpIOParticipant {
39 private final Logger logger = LoggerFactory.getLogger(UpnpHandler.class);
41 protected UpnpIOService service;
42 protected volatile String transportState = "";
43 protected volatile int connectionId;
44 protected volatile int avTransportId;
45 protected volatile int rcsId;
46 protected @NonNullByDefault({}) UpnpControlConfiguration config;
48 public UpnpHandler(Thing thing, UpnpIOService upnpIOService) {
51 upnpIOService.registerParticipant(this);
52 this.service = upnpIOService;
56 public void initialize() {
57 config = getConfigAs(UpnpControlConfiguration.class);
58 service.registerParticipant(this);
62 public void dispose() {
63 service.unregisterParticipant(this);
67 * Invoke PrepareForConnection on the UPnP Connection Manager.
68 * Result is received in {@link onValueReceived}.
70 * @param remoteProtocolInfo
71 * @param peerConnectionManager
72 * @param peerConnectionId
75 protected void prepareForConnection(String remoteProtocolInfo, String peerConnectionManager, int peerConnectionId,
77 HashMap<String, String> inputs = new HashMap<String, String>();
78 inputs.put("RemoteProtocolInfo", remoteProtocolInfo);
79 inputs.put("PeerConnectionManager", peerConnectionManager);
80 inputs.put("PeerConnectionID", Integer.toString(peerConnectionId));
81 inputs.put("Direction", direction);
83 invokeAction("ConnectionManager", "PrepareForConnection", inputs);
87 * Invoke ConnectionComplete on UPnP Connection Manager.
91 protected void connectionComplete(int connectionId) {
92 HashMap<String, String> inputs = new HashMap<String, String>();
93 inputs.put("ConnectionID", String.valueOf(connectionId));
95 invokeAction("ConnectionManager", "ConnectionComplete", inputs);
99 * Invoke GetTransportState on UPnP AV Transport.
100 * Result is received in {@link onValueReceived}.
102 protected void getTransportState() {
103 HashMap<String, String> inputs = new HashMap<String, String>();
104 inputs.put("InstanceID", Integer.toString(avTransportId));
106 invokeAction("AVTransport", "GetTransportInfo", inputs);
110 * Invoke GetProtocolInfo on UPnP Connection Manager.
111 * Result is received in {@link onValueReceived}.
113 protected void getProtocolInfo() {
114 Map<String, String> inputs = new HashMap<>();
116 invokeAction("ConnectionManager", "GetProtocolInfo", inputs);
120 public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
121 logger.debug("Upnp device {} received subscription reply {} from service {}", thing.getLabel(), succeeded,
126 public void onStatusChanged(boolean status) {
128 updateStatus(ThingStatus.ONLINE);
130 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
131 "Communication lost with " + thing.getLabel());
136 public @Nullable String getUDN() {
141 * This method wraps {@link org.openhab.core.io.transport.upnp.UpnpIOService.invokeAction}. It schedules and
142 * submits the call and calls {@link onValueReceived} upon completion. All state updates or other actions depending
143 * on the results should be triggered from {@link onValueReceived} because the class fields with results will be
144 * filled asynchronously.
150 protected void invokeAction(String serviceId, String actionId, Map<String, String> inputs) {
151 scheduler.submit(() -> {
152 Map<String, String> result = service.invokeAction(this, serviceId, actionId, inputs);
153 if (logger.isDebugEnabled() && !"GetPositionInfo".equals(actionId)) {
154 // don't log position info refresh every second
155 logger.debug("Upnp device {} invoke upnp action {} on service {} with inputs {}", thing.getLabel(),
156 actionId, serviceId, inputs);
157 logger.debug("Upnp device {} invoke upnp action {} on service {} reply {}", thing.getLabel(), actionId,
160 for (String variable : result.keySet()) {
161 onValueReceived(variable, result.get(variable), serviceId);
167 public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
168 if (variable == null || value == null) {
172 case "CurrentTransportState":
173 if (!value.isEmpty()) {
174 transportState = value;
178 connectionId = Integer.parseInt(value);
180 case "AVTransportID":
181 avTransportId = Integer.parseInt(value);
184 rcsId = Integer.parseInt(value);
192 * Subscribe this handler as a participant to a GENA subscription.
197 protected void addSubscription(String serviceId, int duration) {
198 logger.debug("Upnp device {} add upnp subscription on {}", thing.getLabel(), serviceId);
199 service.addSubscription(this, serviceId, duration);
203 * Remove this handler from the GENA subscriptions.
207 protected void removeSubscription(String serviceId) {
208 if (service.isRegistered(this)) {
209 service.removeSubscription(this, serviceId);