]> git.basschouten.com Git - openhab-addons.git/blob
527aa2421768b8048e27ba5a8c7b143574514072
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.shelly.internal.api1;
14
15 import static org.openhab.binding.shelly.internal.api1.Shelly1CoapJSonDTO.COIOT_PORT;
16
17 import java.net.InetAddress;
18 import java.net.InetSocketAddress;
19 import java.net.SocketException;
20 import java.net.UnknownHostException;
21 import java.util.Set;
22 import java.util.concurrent.ConcurrentHashMap;
23
24 import org.eclipse.californium.core.CoapResource;
25 import org.eclipse.californium.core.CoapServer;
26 import org.eclipse.californium.core.coap.CoAP;
27 import org.eclipse.californium.core.coap.CoAP.Code;
28 import org.eclipse.californium.core.coap.CoAP.ResponseCode;
29 import org.eclipse.californium.core.coap.Request;
30 import org.eclipse.californium.core.coap.Response;
31 import org.eclipse.californium.core.network.CoapEndpoint;
32 import org.eclipse.californium.core.network.Exchange;
33 import org.eclipse.californium.core.network.config.NetworkConfig;
34 import org.eclipse.californium.elements.UdpMulticastConnector;
35 import org.eclipse.jdt.annotation.NonNullByDefault;
36 import org.eclipse.jdt.annotation.Nullable;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link Shelly1CoapServer} implements the UDP listener and status event processor (for /cit/s messages)
42  *
43  * @author Markus Michels - Initial contribution
44  */
45 @NonNullByDefault
46 public class Shelly1CoapServer {
47     private final Logger logger = LoggerFactory.getLogger(Shelly1CoapServer.class);
48
49     boolean started = false;
50     private CoapEndpoint statusEndpoint = new CoapEndpoint.Builder().build();
51     private @Nullable UdpMulticastConnector statusConnector;
52     private CoapServer server = new CoapServer(NetworkConfig.getStandard(), COIOT_PORT);
53     private final Set<Shelly1CoapListener> coapListeners = ConcurrentHashMap.newKeySet();
54
55     protected class ShellyStatusListener extends CoapResource {
56         private Shelly1CoapServer listener;
57
58         public ShellyStatusListener(String uri, Shelly1CoapServer listener) {
59             super(uri, true);
60             getAttributes().setTitle("ShellyCoapListener");
61             this.listener = listener;
62         }
63
64         @Override
65         public void handleRequest(@Nullable final Exchange exchange) {
66             if (exchange != null) {
67                 Request request = exchange.getRequest();
68                 Code code = exchange.getRequest().getCode();
69                 switch (code) {
70                     case CUSTOM_30:
71                     case PUT: // Shelly Motion beta: incorrect, but handle the format
72                         listener.processResponse(createResponse(request));
73                         break;
74                     default:
75                         super.handleRequest(exchange);
76                 }
77             }
78         }
79     }
80
81     public synchronized void start(String localIp, int port, Shelly1CoapListener listener)
82             throws UnknownHostException, SocketException {
83         if (!started) {
84             logger.debug("Initializing CoIoT listener (local IP={}:{})", localIp, port);
85             NetworkConfig nc = NetworkConfig.getStandard();
86             InetAddress localAddr = InetAddress.getByName(localIp);
87             InetSocketAddress localPort = new InetSocketAddress(port);
88
89             // Join the multicast group on the selected network interface
90             statusConnector = new UdpMulticastConnector(localAddr, localPort, CoAP.MULTICAST_IPV4); // bind UDP listener
91             statusEndpoint = new CoapEndpoint.Builder().setNetworkConfig(nc).setConnector(statusConnector).build();
92             server = new CoapServer(NetworkConfig.getStandard(), port);
93             server.addEndpoint(statusEndpoint);
94             CoapResource cit = new ShellyStatusListener("cit", this);
95             CoapResource s = new ShellyStatusListener("s", this);
96             cit.add(s);
97             server.add(cit);
98             started = true;
99         }
100
101         if (!coapListeners.contains(listener)) {
102             coapListeners.add(listener);
103         }
104     }
105
106     protected void processResponse(Response response) {
107         coapListeners.forEach(listener -> listener.processResponse(response));
108     }
109
110     public static Response createResponse(Request request) {
111         Response response = Response.createResponse(request, ResponseCode.CONTENT);
112         response.setType(request.getType());
113         response.setSourceContext(request.getSourceContext());
114         response.setMID(request.getMID());
115         response.setOptions(request.getOptions());
116         response.setPayload(request.getPayload());
117         return response;
118     }
119
120     @Nullable
121     public CoapEndpoint getEndpoint() {
122         return statusEndpoint;
123     }
124
125     /**
126      * Cancel pending requests and shutdown the client
127      */
128     public void stop(Shelly1CoapListener listener) {
129         coapListeners.remove(listener);
130         if (coapListeners.isEmpty()) {
131             stop();
132         }
133     }
134
135     private synchronized void stop() {
136         if (started) {
137             // Last listener
138             server.stop();
139             statusEndpoint.stop();
140             coapListeners.clear();
141             started = false;
142             logger.debug("CoAP Listener stopped");
143         }
144     }
145
146     public void dispose() {
147         stop();
148     }
149 }