Skip to content

Instantly share code, notes, and snippets.

@lawgimenez
Last active February 27, 2019 01:20
Show Gist options
  • Select an option

  • Save lawgimenez/66cabf092bda78f1b1ac8f94389d7559 to your computer and use it in GitHub Desktop.

Select an option

Save lawgimenez/66cabf092bda78f1b1ac8f94389d7559 to your computer and use it in GitHub Desktop.
SSDP Android Snippet
package com.somfy.android.utils;
import android.content.Context;
import android.net.wifi.WifiManager;
import com.somfy.android.BridgeApplication;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.ArrayList;
/**
* This class handles the LAN Discovery protocol.
* Also implements the sending and receiving of packets using
* SSDP multicast.
*
* Created by Lawrence Gimenez on 2/16/15.
*/
public class BridgeLan {
private static final String TAG = "BridgeLan";
// Newline
private static final String NEWLINE = "\r\n";
// Notify
//private static final String NOTIFY = "NOTIFY * HTTP/1.1";
// OK
private static final String HTTP_OK = "HTTP/1.1 200 OK";
// M-SEARCH
private static final String M_SEARCH = "M-SEARCH * HTTP/1.1";
// IP address of the Bridge Server
private static final String IP_ADDRESS = "239.255.255.250";
// Port of the Bridge Server
private static final int PORT = 1900;
// Cache control
private static final String CACHE_CONTROL = "CACHE-CONTROL: max-age = 60";
// Notification Type
// NT:urn:schemas-wifialliance-org:service:WFAWLANConfig:1
private static final String NT = "NT:urn:somfy.com:device:swf-ha-bridge:1";
// Unique Service Name
private static final String USN = "USN: ";
// Location of the API
private static final String LOCATION = "LOCATION:";
// MAN SSDP Discover
private static final String MAN_DISCOVER = "MAN: \"ssdp:discover\"";
// MX = 1
private static final String MX = "MX: 3";
// Search Target = ST
private static final String ST = "ST: urn:somfy.com:device:swf-ha-bridge:1";
// Device identifier for identifying packet responses that it
// came from Somfy Bridge
private static final String DEVICE_TYPE = "urn:somfy.com:device:swf-ha-bridge:1";
// private static final String ST = "ST:ssdp:all";
private static final String NTS_ALIVE = "NTS: ssdp:alive";
private static final String NTS_BYEBYE = "NTS: ssdp:byebye";
// Global state of our Application
private BridgeApplication mApplication;
// Implements a multicast socket for sending and receiving IP multicast datagram packets.
private MulticastSocket mMulticastSocket;
// Allows an application to receive Wifi Multicast packets.
private WifiManager.MulticastLock mMulticastLock;
private InetAddress mInetAddress;
public static boolean mIsReceiving;
private ArrayList<String> mListBridgesFound;
/**
* @param context - Represents the application environment, so we can access to
* app specific resources and methods.
*
* @throws IOException
*/
public BridgeLan(Context context) throws IOException{
// Get a reference to our Global state
mApplication = BridgeApplication.getInstance();
mListBridgesFound = new ArrayList<>();
//Log.i(TAG, "Instantiating Bridge LAN helper");
mMulticastSocket = new MulticastSocket(null);
// Represents IP Protocol
mInetAddress = InetAddress.getByName(IP_ADDRESS);
// Signals that this device will join the multicast group.
mMulticastSocket.setReuseAddress(true);
mMulticastSocket.joinGroup(mInetAddress);
mMulticastSocket.setTimeToLive(200);
mMulticastSocket.setLoopbackMode(true);
//mMulticastSocket.bind(new InetSocketAddress(PORT));
// For managing all aspects of Wi-Fi connectivity
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if(wifiManager != null) {
// We will acquire a lock so application can receive
// packets
mMulticastLock = wifiManager.createMulticastLock("TagMulticast");
mMulticastLock.setReferenceCounted(true);
mMulticastLock.acquire();
}
}
/**
* Sends a SSDP alive packet to the Bridge.
* @throws IOException
*/
/*public void notifySSDPAlive() throws IOException {
StringBuilder notify = new StringBuilder();
// Construct Notify 1st line
notify.append(NOTIFY + NEWLINE);
// Construct Host 2nd line
notify.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE);
// Construct cache control 3rd line
notify.append(CACHE_CONTROL + NEWLINE);
// Construct NT 4th line
notify.append(NT + NEWLINE);
// Construct NTS 5th line with alive
notify.append(NTS_ALIVE + NEWLINE);
// Construct USN
notify.append(USN).append(mApplication.getUUID() + NEWLINE + NEWLINE);
// Get the final String for our Notify SSDP Alive
String dataSsdpAlive = notify.toString();
Log.i(TAG, "NotifyAlive: \n" + dataSsdpAlive);
// Send packet to the Bridge
sendPacket(dataSsdpAlive);
}*/
/**
* Sends a SSDP byebye packet to the Bridge
* @throws IOException
*/
/*public void notifySSDPBye() throws IOException {
StringBuilder notify = new StringBuilder();
// Construct Notify 1st line
notify.append(NOTIFY + NEWLINE);
// Construct Host 2nd line
notify.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE);
// Construct NT 3rd line
notify.append(NT + NEWLINE);
// Construct NTS 4th line with byebye
notify.append("NTS: " + NTS_BYEBYE + NEWLINE);
// Construct USN
notify.append(USN).append(mApplication.getUUID() + NEWLINE + NEWLINE);
// Get the final String for our Notify SSDP byebye
String dataSsdpBye = notify.toString();
// Send packet to the Bridge
sendPacket(dataSsdpBye);
}*/
/**
* When the device desires to search for Bridge devices on the network.
* @throws IOException
*/
public boolean searchDiscover() throws IOException {
StringBuilder search = new StringBuilder();
// Construct M-SEARCH 1st line
search.append(M_SEARCH + NEWLINE);
// Construct Host 2nd line
search.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE);
// Construct MAN 3rd line
search.append(MAN_DISCOVER + NEWLINE);
// Construct MX 4th line
search.append(MX + NEWLINE);
// Construct ST 5th line
search.append(ST + NEWLINE + NEWLINE);
// Get the final String for our M-SEARCH multicast discover
String dataMSearchDiscover = search.toString();
//Log.i(TAG, "searchDiscover: " + dataMSearchDiscover);
return sendPacket(dataMSearchDiscover);
}
/**
* When the device desires to search for a specific device
* on the network.
* @throws IOException
*/
public boolean searchUnicast() throws IOException {
StringBuilder search = new StringBuilder();
// Construct M-SEARCH 1st line
search.append(M_SEARCH + NEWLINE);
// Construct Host 2nd line
search.append("HOST: " + IP_ADDRESS + ":" + PORT + NEWLINE);
//
search.append(ST + NEWLINE + NEWLINE);
// Construct MAN 3rd line
search.append(MAN_DISCOVER + NEWLINE);
// Construct ST 4th line
search.append(MX);
// Get the final String for M-SEARCH unicast
String dataMSearchUnicast = search.toString();
//Log.i(TAG, "searchUnicast: " + dataMSearchUnicast);
// Send packet to the Bridge
return sendPacket(dataMSearchUnicast);
}
/**
* Handles the received SSDP packet from the network.
* @return - Datagram Packet from the Bridge device
* @throws IOException
*/
/*public DatagramPacket receive() throws IOException {
byte[] buffer = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
mMulticastSocket.receive(datagramPacket);
return datagramPacket;
}*/
/**
* Sends a SSDP Packet to the Bridge
* @param data - data to be send through SSDP
* @throws IOException
*/
private boolean sendPacket(String data) throws IOException {
// Create a new datagram packet to be send to the network
DatagramPacket datagramPacket = new DatagramPacket(data.getBytes(),
data.length(), mInetAddress, PORT);
mMulticastSocket.setTimeToLive(200);
mMulticastSocket.setLoopbackMode(true);
//Log.i(TAG, "Host address: " + mInetAddress.getHostAddress());
//Log.i(TAG, "Is multicast address: " + mInetAddress.isMulticastAddress());
// Send the datagram packet to the Multicast IP and Port
mMulticastSocket.send(datagramPacket);
mIsReceiving = true;
return true;
}
/**
* Called to start receiving Multicast packets
*
* @throws IOException
*/
public void startReceiving() throws IOException {
// Get response from the server
byte[] buffer = new byte[500];
mIsReceiving = true;
//Log.i(TAG, "isReceiving?" + mIsReceiving);
while(mIsReceiving) {
// Create a new datagram packet received from the server
DatagramPacket packetReceived = new DatagramPacket(buffer, buffer.length);
// Receive the datagram packet
mMulticastSocket.receive(packetReceived);
String dataReceived = new String(packetReceived.getData()).trim();
//Log.i(TAG, "Response: " + dataReceived.trim());
//Log.i(TAG, "Response from: " + packetReceived.getAddress());
// If there are no more packet received, end listening for packets
if(packetReceived.getData() == null) {
mIsReceiving = false;
//Log.i(TAG, "No more packets");
} else {
//Log.i(TAG, "Found some packets");
// If packet has been received, check if packet came from Somfy device
// and at the same is an HTTP/1.1 200 OK header response.
if(dataReceived.contains(HTTP_OK) && dataReceived.contains(DEVICE_TYPE)) {
String[] packetElements = dataReceived.split(NEWLINE);
//Log.i(TAG, "Element NTS: " + packetElements[3]);
// If everything is OK, get the IP address of where
// this packet came from.
String bridgeLocation = packetReceived.getAddress().getHostAddress();
//Log.i(TAG, "Packet Location IP: " + packetReceived.getAddress().getHostAddress());
//Log.i(TAG, "Packet Location Port: " + packetReceived.getPort());
boolean isPresent = false;
// Check if the recently captured Bridge IP address location is
// already in our list.
for(int i=0; i<mListBridgesFound.size(); i++) {
if(bridgeLocation.equals(mListBridgesFound.get(i))) {
isPresent = true;
}
}
// If recently captured Bridge IP address location is not found on
// our list, add the Bridge IP address location.
if(!isPresent) {
mListBridgesFound.add(bridgeLocation);
}
// Add the list of Bridges found to our global state.
mApplication.setBridgesFound(mListBridgesFound);
}
}
//Log.i(TAG, "isReceiving: " + mIsReceiving);
}
//Log.i(TAG, "isReceivingAfterThread?" + mIsReceiving);
}
/**
* Called to stop receiving Multicast packets
*/
public void stopMulticasting() {
// Log.i(TAG, "Stop multicasting");
// Close socket, we're done
if(mMulticastSocket != null) {
mMulticastSocket.close();
mMulticastSocket = null;
}
if(mMulticastLock.isHeld()) {
mMulticastLock.release();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment