]> git.basschouten.com Git - openhab-addons.git/blob
c9c93687f6c03bf6387fee55e59c0aeae5071960
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.upnpcontrol.internal.handler;
14
15 import java.util.HashMap;
16 import java.util.Map;
17
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;
29
30 /**
31  * The {@link UpnpHandler} is the base class for {@link UpnpRendererHandler} and {@link UpnpServerHandler}.
32  *
33  * @author Mark Herwege - Initial contribution
34  * @author Karel Goderis - Based on UPnP logic in Sonos binding
35  */
36 @NonNullByDefault
37 public abstract class UpnpHandler extends BaseThingHandler implements UpnpIOParticipant {
38
39     private final Logger logger = LoggerFactory.getLogger(UpnpHandler.class);
40
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;
47
48     public UpnpHandler(Thing thing, UpnpIOService upnpIOService) {
49         super(thing);
50
51         upnpIOService.registerParticipant(this);
52         this.service = upnpIOService;
53     }
54
55     @Override
56     public void initialize() {
57         config = getConfigAs(UpnpControlConfiguration.class);
58         service.registerParticipant(this);
59     }
60
61     @Override
62     public void dispose() {
63         service.unregisterParticipant(this);
64     }
65
66     /**
67      * Invoke PrepareForConnection on the UPnP Connection Manager.
68      * Result is received in {@link onValueReceived}.
69      *
70      * @param remoteProtocolInfo
71      * @param peerConnectionManager
72      * @param peerConnectionId
73      * @param direction
74      */
75     protected void prepareForConnection(String remoteProtocolInfo, String peerConnectionManager, int peerConnectionId,
76             String direction) {
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);
82
83         invokeAction("ConnectionManager", "PrepareForConnection", inputs);
84     }
85
86     /**
87      * Invoke ConnectionComplete on UPnP Connection Manager.
88      *
89      * @param connectionId
90      */
91     protected void connectionComplete(int connectionId) {
92         HashMap<String, String> inputs = new HashMap<String, String>();
93         inputs.put("ConnectionID", String.valueOf(connectionId));
94
95         invokeAction("ConnectionManager", "ConnectionComplete", inputs);
96     }
97
98     /**
99      * Invoke GetTransportState on UPnP AV Transport.
100      * Result is received in {@link onValueReceived}.
101      */
102     protected void getTransportState() {
103         HashMap<String, String> inputs = new HashMap<String, String>();
104         inputs.put("InstanceID", Integer.toString(avTransportId));
105
106         invokeAction("AVTransport", "GetTransportInfo", inputs);
107     }
108
109     /**
110      * Invoke GetProtocolInfo on UPnP Connection Manager.
111      * Result is received in {@link onValueReceived}.
112      */
113     protected void getProtocolInfo() {
114         Map<String, String> inputs = new HashMap<>();
115
116         invokeAction("ConnectionManager", "GetProtocolInfo", inputs);
117     }
118
119     @Override
120     public void onServiceSubscribed(@Nullable String service, boolean succeeded) {
121         logger.debug("Upnp device {} received subscription reply {} from service {}", thing.getLabel(), succeeded,
122                 service);
123     }
124
125     @Override
126     public void onStatusChanged(boolean status) {
127         if (status) {
128             updateStatus(ThingStatus.ONLINE);
129         } else {
130             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
131                     "Communication lost with " + thing.getLabel());
132         }
133     }
134
135     @Override
136     public @Nullable String getUDN() {
137         return config.udn;
138     }
139
140     /**
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.
145      *
146      * @param serviceId
147      * @param actionId
148      * @param inputs
149      */
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,
158                         serviceId, result);
159             }
160             for (String variable : result.keySet()) {
161                 onValueReceived(variable, result.get(variable), serviceId);
162             }
163         });
164     }
165
166     @Override
167     public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
168         if (variable == null) {
169             return;
170         }
171         switch (variable) {
172             case "CurrentTransportState":
173                 if (!((value == null) || (value.isEmpty()))) {
174                     transportState = value;
175                 }
176                 break;
177             case "ConnectionID":
178                 connectionId = Integer.parseInt(value);
179                 break;
180             case "AVTransportID":
181                 avTransportId = Integer.parseInt(value);
182                 break;
183             case "RcsID":
184                 rcsId = Integer.parseInt(value);
185                 break;
186             default:
187                 break;
188         }
189     }
190
191     /**
192      * Subscribe this handler as a participant to a GENA subscription.
193      *
194      * @param serviceId
195      * @param duration
196      */
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);
200     }
201
202     /**
203      * Remove this handler from the GENA subscriptions.
204      *
205      * @param serviceId
206      */
207     protected void removeSubscription(String serviceId) {
208         if (service.isRegistered(this)) {
209             service.removeSubscription(this, serviceId);
210         }
211     }
212 }