]> git.basschouten.com Git - openhab-addons.git/blob
7639281bc435bf666f825348d94bcd4baec71030
[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.magentatv.internal.network;
14
15 import static org.openhab.binding.magentatv.internal.MagentaTVBindingConstants.*;
16 import static org.openhab.binding.magentatv.internal.MagentaTVUtil.*;
17
18 import java.io.IOException;
19 import java.net.DatagramPacket;
20 import java.net.InetAddress;
21 import java.net.MulticastSocket;
22 import java.net.NetworkInterface;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.magentatv.internal.MagentaTVHandlerFactory;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * The {@link MagentaTVPoweroffListener} implements a UPnP listener to detect
32  * power-off of the receiver
33  *
34  * @author Markus Michels - Initial contribution
35  */
36 @NonNullByDefault
37 public class MagentaTVPoweroffListener extends Thread {
38     private final Logger logger = LoggerFactory.getLogger(MagentaTVPoweroffListener.class);
39
40     private final MagentaTVHandlerFactory handlerFactory;
41
42     public static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";
43     public static final int UPNP_PORT = 1900;
44     public static final String UPNP_BYEBYE_MESSAGE = "ssdp:byebye";
45
46     protected final MulticastSocket socket;
47     protected @Nullable NetworkInterface networkInterface;
48     protected byte[] buf = new byte[256];
49     private boolean started = false;
50
51     public MagentaTVPoweroffListener(MagentaTVHandlerFactory handlerFactory,
52             @Nullable NetworkInterface networkInterface) throws IOException {
53         setName("OH-Binding-magentatv-upnp-listener");
54         setDaemon(true);
55
56         this.handlerFactory = handlerFactory;
57         this.networkInterface = networkInterface;
58         socket = new MulticastSocket(UPNP_PORT);
59     }
60
61     @Override
62     public void start() {
63         if (!isStarted()) {
64             logger.debug("Listening to SSDP shutdown messages");
65             started = true;
66             super.start();
67         }
68     }
69
70     /**
71      * Listening thread. Receive SSDP multicast packets and filter for byebye If
72      * such a packet is received the handlerFactory is called, which then dispatches
73      * the event to the thing handler.
74      */
75     @Override
76     public void run() {
77         try {
78             logger.debug("SSDP listener started");
79             socket.setReceiveBufferSize(1024);
80             socket.setReuseAddress(true);
81
82             // Join the Multicast group on the selected network interface
83             socket.setNetworkInterface(networkInterface);
84             InetAddress group = InetAddress.getByName(UPNP_MULTICAST_ADDRESS);
85             socket.joinGroup(group);
86
87             // read the SSDP messages
88             while (!socket.isClosed()) {
89                 DatagramPacket packet = new DatagramPacket(buf, buf.length);
90                 socket.receive(packet);
91                 String message = new String(packet.getData(), 0, packet.getLength());
92                 try {
93                     String ipAddress = substringAfter(packet.getAddress().toString(), "/");
94                     if (message.contains("NTS: ")) {
95                         String ssdpMsg = substringBetween(message, "NTS: ", "\r");
96                         if (ssdpMsg != null) {
97                             if (message.contains(MR400_DEF_DESCRIPTION_URL)
98                                     || message.contains(MR401B_DEF_DESCRIPTION_URL)) {
99                                 if (ssdpMsg.contains(UPNP_BYEBYE_MESSAGE)) {
100                                     handlerFactory.onPowerOff(ipAddress);
101                                 }
102                             }
103                         }
104                     }
105                 } catch (RuntimeException e) {
106                     logger.debug("Unable to process SSDP message: {}", message);
107                 }
108             }
109         } catch (IOException | RuntimeException e) {
110             logger.debug("Poweroff listener failure: {}", e.getMessage());
111         } finally {
112             close();
113         }
114     }
115
116     public boolean isStarted() {
117         return started;
118     }
119
120     /**
121      * Make sure the socket gets closed
122      */
123     public void close() {
124         if (started) { // if (isStarted()) {
125             logger.debug("No longer listening to SSDP messages");
126             if (!socket.isClosed()) {
127                 socket.close();
128             }
129             started = false;
130         }
131     }
132
133     /**
134      * Make sure the socket gets closed
135      */
136     public void dispose() {
137         logger.debug("SSDP listener terminated");
138         close();
139     }
140 }