Populate git repository

First Update
This commit is contained in:
Admin
2015-07-28 12:21:10 -05:00
commit e4bbe3e8fb
23 changed files with 1644 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
package com.bwssytems.HABridge;
import static spark.Spark.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssytems.HABridge.devicemanagmeent.*;
import com.bwssytems.HABridge.hue.HueMulator;
import com.bwssytems.HABridge.upnp.UpnpListener;
import com.bwssytems.HABridge.upnp.UpnpSettingsResource;
public class AmazonEchoBridge {
/*
* This program is based on the work of armzilla from this github repository:
* https://github.com/armzilla/amazon-echo-ha-bridge
*
* This is the main entry point to start the amazon echo bridge.
*
* This program is using sparkjava rest server to build all the http calls.
* Sparkjava is a microframework that uses Jetty webserver module to host
* its' calls. This is a very compact system than using the spring frameworks
* that was previously used.
*
* There is a custom upnp listener that is started to handle discovery.
*
* This application does not store the lights configuration persistently.
*
*
*/
public static void main(String[] args) {
Logger log = LoggerFactory.getLogger(AmazonEchoBridge.class);
DeviceResource theResources;
HueMulator theHueMulator;
UpnpSettingsResource theSettingResponder;
UpnpListener theUpnpListener;
// sparkjava config directive to set ip address for the web server to listen on
ipAddress(System.getProperty("upnp.config.address", "0.0.0.0"));
// sparkjava config directive to set port for the web server to listen on
port(Integer.valueOf(System.getProperty("server.port", "8080")));
// sparkjava config directive to set html static file location for Jetty
staticFileLocation("/public");
log.debug("Starting setup....");
// setup the class to handle the resource setup rest api
theResources = new DeviceResource();
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(theResources.getDeviceRepository());
// setup the class to handle the upnp response rest api
theSettingResponder = new UpnpSettingsResource();
// wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization();
// start the upnp ssdp discovery listener
theUpnpListener = new UpnpListener();
log.debug("Done setup, application to run....");
theUpnpListener.startListening();
}
}

View File

@@ -0,0 +1,17 @@
package com.bwssytems.HABridge;
import com.google.gson.Gson;
import spark.ResponseTransformer;
/*
* Implementation of a Json renderer through google GSON utility.
*/
public class JsonTransformer implements ResponseTransformer {
private Gson gson = new Gson();
@Override
public String render(Object model) {
return gson.toJson(model);
}
}

View File

@@ -0,0 +1,43 @@
package com.bwssytems.HABridge.api;
/**
* Created by arm on 4/13/15.
*/
public class Device {
private String name;
private String deviceType;
private String offUrl;
private String onUrl;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getOffUrl() {
return offUrl;
}
public void setOffUrl(String offUrl) {
this.offUrl = offUrl;
}
public String getOnUrl() {
return onUrl;
}
public void setOnUrl(String onUrl) {
this.onUrl = onUrl;
}
}

View File

@@ -0,0 +1,122 @@
package com.bwssytems.HABridge.api.hue;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Created by arm on 4/14/15.
*/
public class DeviceResponse {
private DeviceState state;
private String type;
private String name;
private String modelid;
private String manufacturername;
private String uniqueid;
private String swversion;
private Map<String, String> pointsymbol;
public DeviceState getState() {
return state;
}
public void setState(DeviceState state) {
this.state = state;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getModelid() {
return modelid;
}
public void setModelid(String modelid) {
this.modelid = modelid;
}
public String getManufacturername() {
return manufacturername;
}
public void setManufacturername(String manufacturername) {
this.manufacturername = manufacturername;
}
public String getUniqueid() {
return uniqueid;
}
public void setUniqueid(String uniqueid) {
this.uniqueid = uniqueid;
}
public String getSwversion() {
return swversion;
}
public void setSwversion(String swversion) {
this.swversion = swversion;
}
public Map<String, String> getPointsymbol() {
Map<String, String> dummyValue = new HashMap<>();
dummyValue.put("1", "none");
dummyValue.put("2", "none");
dummyValue.put("3", "none");
dummyValue.put("4", "none");
dummyValue.put("5", "none");
dummyValue.put("6", "none");
dummyValue.put("7", "none");
dummyValue.put("8", "none");
return dummyValue;
}
public void setPointsymbol(Map<String, String> pointsymbol) {
this.pointsymbol = pointsymbol;
}
public static DeviceResponse createResponse(String name, String id){
DeviceState deviceState = new DeviceState();
DeviceResponse response = new DeviceResponse();
response.setState(deviceState);
deviceState.setOn(false);
deviceState.setReachable(true);
deviceState.setEffect("none");
deviceState.setAlert("none");
deviceState.setBri(254);
deviceState.setHue(15823);
deviceState.setSat(88);
deviceState.setCt(313);
List<Double> xv = new LinkedList<>();
xv.add(0.4255);
xv.add(0.3998);
deviceState.setXy(xv);
deviceState.setColormode("ct");
response.setName(name);
response.setUniqueid(id);
response.setManufacturername("Philips");
response.setType("Extended color light");
response.setModelid("LCT001");
response.setSwversion("65003148");
return response;
}
}

View File

@@ -0,0 +1,107 @@
package com.bwssytems.HABridge.api.hue;
import java.util.List;
/**
* Created by arm on 4/14/15.
*/
public class DeviceState {
private boolean on;
private int bri = 255;
private int hue;
private int sat;
private String effect;
private int ct;
private String alert;
private String colormode;
private boolean reachable;
private List<Double> xy;
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
public int getBri() {
return bri;
}
public void setBri(int bri) {
this.bri = bri;
}
public int getHue() {
return hue;
}
public void setHue(int hue) {
this.hue = hue;
}
public int getSat() {
return sat;
}
public void setSat(int sat) {
this.sat = sat;
}
public String getEffect() {
return effect;
}
public void setEffect(String effect) {
this.effect = effect;
}
public int getCt() {
return ct;
}
public void setCt(int ct) {
this.ct = ct;
}
public String getAlert() {
return alert;
}
public void setAlert(String alert) {
this.alert = alert;
}
public String getColormode() {
return colormode;
}
public void setColormode(String colormode) {
this.colormode = colormode;
}
public boolean isReachable() {
return reachable;
}
public void setReachable(boolean reachable) {
this.reachable = reachable;
}
public List<Double> getXy() {
return xy;
}
public void setXy(List<Double> xy) {
this.xy = xy;
}
@Override
public String toString() {
return "DeviceState{" +
"on=" + on +
", bri=" + bri +
'}';
}
}

View File

@@ -0,0 +1,20 @@
package com.bwssytems.HABridge.api.hue;
import java.util.Map;
import com.bwssytems.HABridge.api.hue.DeviceResponse;
/**
* Created by arm on 4/14/15.
*/
public class HueApiResponse {
private Map<String, DeviceResponse> lights;
public Map<String, DeviceResponse> getLights() {
return lights;
}
public void setLights(Map<String, DeviceResponse> lights) {
this.lights = lights;
}
}

View File

@@ -0,0 +1,51 @@
package com.bwssytems.HABridge.dao;
/*
* Object to handle the device configuration
*/
public class DeviceDescriptor{
private String id;
private String name;
private String deviceType;
private String offUrl;
private String onUrl;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDeviceType() {
return deviceType;
}
public void setDeviceType(String deviceType) {
this.deviceType = deviceType;
}
public String getOffUrl() {
return offUrl;
}
public void setOffUrl(String offUrl) {
this.offUrl = offUrl;
}
public String getOnUrl() {
return onUrl;
}
public void setOnUrl(String onUrl) {
this.onUrl = onUrl;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

View File

@@ -0,0 +1,54 @@
package com.bwssytems.HABridge.dao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import com.bwssytems.HABridge.dao.DeviceDescriptor;
import java.util.List;
/*
* This is an in memory list to manage the configured devices.
*
*/
public class DeviceRepository {
Map<String, DeviceDescriptor> devices;
final Random random = new Random();
public DeviceRepository() {
super();
devices = new HashMap<String, DeviceDescriptor>();
}
public List<DeviceDescriptor> findAll() {
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
return list;
}
public List<DeviceDescriptor> findByDeviceType(String aType) {
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
return list;
}
public DeviceDescriptor findOne(String id) {
return devices.get(id);
}
public void save(DeviceDescriptor aDescriptor) {
int id = random.nextInt(Integer.MAX_VALUE);
aDescriptor.setId(String.valueOf(id));
devices.put(String.valueOf(id),aDescriptor);
}
public String delete(DeviceDescriptor aDescriptor) {
if (aDescriptor != null) {
devices.remove(aDescriptor.getId());
return "Device with id '" + aDescriptor.getId() + "' deleted";
} else {
return "Device not found";
}
}
}

View File

@@ -0,0 +1,106 @@
package com.bwssytems.HABridge.devicemanagmeent;
import com.bwssytems.HABridge.JsonTransformer;
import com.bwssytems.HABridge.dao.DeviceDescriptor;
import com.bwssytems.HABridge.dao.DeviceRepository;
import static spark.Spark.get;
import static spark.Spark.post;
import static spark.Spark.put;
import static spark.Spark.delete;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
/**
spark core server for bridge configuration
*/
public class DeviceResource {
private static final String API_CONTEXT = "/api/devices";
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
private DeviceRepository deviceRepository;
public DeviceResource() {
super();
deviceRepository = new DeviceRepository();
setupEndpoints();
}
public DeviceRepository getDeviceRepository() {
return deviceRepository;
}
private void setupEndpoints() {
log.debug("Setting up endpoints");
post(API_CONTEXT + "/", "application/json", (request, response) -> {
log.debug("Create a Device - request body: " + request.body());
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
DeviceDescriptor deviceEntry = new DeviceDescriptor();
deviceEntry.setName(device.getName());
log.debug("Create a Device - device json name: " + deviceEntry.getName());
deviceEntry.setDeviceType(device.getDeviceType());
log.debug("Create a Device - device json type:" + deviceEntry.getDeviceType());
deviceEntry.setOnUrl(device.getOnUrl());
log.debug("Create a Device - device json on URL:" + deviceEntry.getOnUrl());
deviceEntry.setOffUrl(device.getOffUrl());
log.debug("Create a Device - device json off URL:" + deviceEntry.getOffUrl());
deviceRepository.save(deviceEntry);
log.debug("Created a Device");
response.status(201);
return deviceEntry;
}, new JsonTransformer());
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
log.debug("Saved a Device");
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
DeviceDescriptor deviceEntry = deviceRepository.findOne(request.params(":id"));
if(deviceEntry == null){
return null;
}
deviceEntry.setName(device.getName());
deviceEntry.setDeviceType(device.getDeviceType());
deviceEntry.setOnUrl(device.getOnUrl());
deviceEntry.setOffUrl(device.getOffUrl());
deviceRepository.save(deviceEntry);
return deviceEntry;
}, new JsonTransformer());
get (API_CONTEXT + "/", "application/json", (request, response) -> {
List<DeviceDescriptor> deviceList = deviceRepository.findAll();
log.debug("Get all devices");
JsonTransformer aRenderer = new JsonTransformer();
String theStream = aRenderer.render(deviceList);
log.debug("The Device List: " + theStream);
return deviceList;
}, new JsonTransformer());
get (API_CONTEXT + "/:id", "application/json", (request, response) -> {
log.debug("Get a device");
DeviceDescriptor descriptor = deviceRepository.findOne(request.params(":id"));
if(descriptor == null){
return null;
}
return descriptor;
}, new JsonTransformer());
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
log.debug("Delete a device");
DeviceDescriptor deleted = deviceRepository.findOne(request.params(":id"));
if(deleted == null){
return null;
}
deviceRepository.delete(deleted);
return null;
}, new JsonTransformer());
}
}

View File

@@ -0,0 +1,197 @@
package com.bwssytems.HABridge.hue;
import com.bwssytems.HABridge.api.hue.DeviceResponse;
import com.bwssytems.HABridge.api.hue.DeviceState;
import com.bwssytems.HABridge.api.hue.HueApiResponse;
import com.bwssytems.HABridge.dao.*;
import com.bwssytems.HABridge.JsonTransformer;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import static spark.Spark.get;
import static spark.Spark.post;
import static spark.Spark.put;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
*/
public class HueMulator {
private static final Logger log = LoggerFactory.getLogger(HueMulator.class);
private static final String INTENSITY_PERCENT = "${intensity.percent}";
private static final String INTENSITY_BYTE = "${intensity.byte}";
private static final String HUE_CONTEXT = "/api";
private DeviceRepository repository;
private HttpClient httpClient;
private ObjectMapper mapper;
public HueMulator(DeviceRepository aDeviceRepository){
httpClient = HttpClients.createMinimal();
mapper = new ObjectMapper(); //armzilla: work around Echo incorrect content type and breaking mapping. Map manually
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
repository = aDeviceRepository;
setupEndpoints();
}
// This function sets up the sparkjava rest calls for the hue api
private void setupEndpoints() {
// http://ip_address:port/api/{userId}/lights returns json objects of all lights configured
get(HUE_CONTEXT + "/:userid/lights", "application/json", (request, response) -> {
String userId = request.params(":userid");
log.info("hue lights list requested: " + userId + " from " + request.ip());
List<DeviceDescriptor> deviceList = repository.findByDeviceType("switch");
JsonTransformer aRenderer = new JsonTransformer();
String theStream = aRenderer.render(deviceList);
log.debug("The Device List: " + theStream);
Map<String, String> deviceResponseMap = new HashMap<>();
for (DeviceDescriptor device : deviceList) {
deviceResponseMap.put(device.getId(), device.getName());
}
response.status(200);
return deviceResponseMap;
} , new JsonTransformer());
// http://ip_address:port/api/* returns json object for a test call
post(HUE_CONTEXT + "/*", "application/json", (request, response) -> {
response.status(200);
return "[{\"success\":{\"username\":\"lights\"}}]";
} );
// http://ip_address:port/api/{userId} returns json objects for the list of names of lights
get(HUE_CONTEXT + "/:userid", "application/json", (request, response) -> {
String userId = request.params(":userid");
log.info("hue api root requested: " + userId + " from " + request.ip());
List<DeviceDescriptor> descriptorList = repository.findByDeviceType("switch");
if (descriptorList == null) {
response.status(404);
return null;
}
Map<String, DeviceResponse> deviceList = new HashMap<>();
descriptorList.forEach(descriptor -> {
DeviceResponse deviceResponse = DeviceResponse.createResponse(descriptor.getName(), descriptor.getId());
deviceList.put(descriptor.getId(), deviceResponse);
}
);
HueApiResponse apiResponse = new HueApiResponse();
apiResponse.setLights(deviceList);
response.status(200);
return apiResponse;
}, new JsonTransformer());
// http://ip_address:port/api/{userId}/lights/{lightId} returns json object for a given light
get(HUE_CONTEXT + "/:userid/lights/:id", "application/json", (request, response) -> {
String userId = request.params(":userid");
String lightId = request.params(":id");
log.info("hue light requested: " + lightId + "for user: " + userId + " from " + request.ip());
DeviceDescriptor device = repository.findOne(lightId);
if (device == null) {
response.status(404);
return null;
} else {
log.info("found device named: " + device.getName());
}
DeviceResponse lightResponse = DeviceResponse.createResponse(device.getName(), device.getId());
response.status(200);
return lightResponse;
}, new JsonTransformer());
// http://ip_address:port/api/{userId}/lights/{lightId}/state uses json object to set the lights state
put(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> {
/**
* strangely enough the Echo sends a content type of application/x-www-form-urlencoded even though
* it sends a json object
*/
String userId = request.params(":userid");
String lightId = request.params(":id");
log.info("hue state change requested: " + userId + " from " + request.ip());
log.info("hue stage change body: " + request.body() );
DeviceState state = null;
try {
state = mapper.readValue(request.body(), DeviceState.class);
} catch (IOException e) {
log.info("object mapper barfed on input", e);
response.status(400);
return null;
}
DeviceDescriptor device = repository.findOne(lightId);
if (device == null) {
response.status(404);
return null;
}
String responseString;
String url;
if (state.isOn()) {
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}]";
url = device.getOnUrl();
} else {
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}]";
url = device.getOffUrl();
}
/* light weight templating here, was going to use free marker but it was a bit too
* heavy for what we were trying to do.
*
* currently provides only two variables:
* intensity.byte : 0-255 brightness. this is raw from the echo
* intensity.percent : 0-100, adjusted for the vera
*/
if(url.contains(INTENSITY_BYTE)){
String intensityByte = String.valueOf(state.getBri());
url = url.replace(INTENSITY_BYTE, intensityByte);
}else if(url.contains(INTENSITY_PERCENT)){
int percentBrightness = (int) Math.round(state.getBri()/255.0*100);
String intensityPercent = String.valueOf(percentBrightness);
url = url.replace(INTENSITY_PERCENT, intensityPercent);
}
//make call
if(!doHttpGETRequest(url)){
response.status(503);
return null;
}
response.status(200);
return responseString;
});
}
// This function executes the url from the device repository against the vera
protected boolean doHttpGETRequest(String url) {
log.info("calling GET on URL: " + url);
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(httpGet);
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
log.info("GET on URL responded: " + response.getStatusLine().getStatusCode());
if(response.getStatusLine().getStatusCode() == 200){
return true;
}
} catch (IOException e) {
log.error("Error calling out to HA gateway", e);
}
return false;
}
}

View File

@@ -0,0 +1,108 @@
package com.bwssytems.HABridge.upnp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.*;
import java.util.Enumeration;
import org.apache.http.conn.util.*;
public class UpnpListener {
private Logger log = LoggerFactory.getLogger(UpnpListener.class);
private static final int UPNP_DISCOVERY_PORT = 1900;
private static final String UPNP_MULTICAST_ADDRESS = "239.255.255.250";
private int upnpResponsePort;
private int httpServerPort;
private String responseAddress;
public UpnpListener() {
super();
upnpResponsePort = Integer.valueOf(System.getProperty("upnp.response.port", "50000"));
httpServerPort = Integer.valueOf(System.getProperty("server.port", "8080"));
responseAddress = System.getProperty("upnp.config.address", "192.168.14.136");
}
public void startListening(){
log.info("Starting UPNP Discovery Listener");
try (DatagramSocket responseSocket = new DatagramSocket(upnpResponsePort);
MulticastSocket upnpMulticastSocket = new MulticastSocket(UPNP_DISCOVERY_PORT);) {
InetSocketAddress socketAddress = new InetSocketAddress(UPNP_MULTICAST_ADDRESS, UPNP_DISCOVERY_PORT);
Enumeration<NetworkInterface> ifs = NetworkInterface.getNetworkInterfaces();
while (ifs.hasMoreElements()) {
NetworkInterface xface = ifs.nextElement();
Enumeration<InetAddress> addrs = xface.getInetAddresses();
String name = xface.getName();
int IPsPerNic = 0;
while (addrs.hasMoreElements()) {
InetAddress addr = addrs.nextElement();
log.debug(name + " ... has addr " + addr);
if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) {
IPsPerNic++;
}
}
log.debug("Checking " + name + " to our interface set");
if (IPsPerNic > 0) {
upnpMulticastSocket.joinGroup(socketAddress, xface);
log.debug("Adding " + name + " to our interface set");
}
}
while(true){ //trigger shutdown here
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
upnpMulticastSocket.receive(packet);
String packetString = new String(packet.getData());
if(isSSDPDiscovery(packetString)){
log.debug("Got SSDP Discovery packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort());
sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort());
}
}
} catch (IOException e) {
log.error("UpnpListener encountered an error. Shutting down", e);
}
log.info("UPNP Discovery Listener Stopped");
}
/**
* very naive ssdp discovery packet detection
* @param body
* @return
*/
protected boolean isSSDPDiscovery(String body){
if(body != null && body.startsWith("M-SEARCH * HTTP/1.1") && body.contains("MAN: \"ssdp:discover\"")){
return true;
}
return false;
}
String discoveryTemplate = "HTTP/1.1 200 OK\r\n" +
"CACHE-CONTROL: max-age=86400\r\n" +
"EXT:\r\n" +
"LOCATION: http://%s:%s/upnp/amazon-ha-bridge/setup.xml\r\n" +
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" +
"01-NLS: %s\r\n" +
"ST: urn:schemas-upnp-org:device:basic:1\r\n" +
"USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n";
protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString());
log.debug("sndUpnpResponse: " + discoveryResponse);
DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort);
socket.send(response);
}
protected String getRandomUUIDString(){
return "88f6698f-2c83-4393-bd03-cd54a9f8595"; // https://xkcd.com/221/
}
}

View File

@@ -0,0 +1,56 @@
package com.bwssytems.HABridge.upnp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static spark.Spark.get;
/**
*
*/
public class UpnpSettingsResource {
private static final String UPNP_CONTEXT = "/upnp";
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
private String hueTemplate = "<?xml version=\"1.0\"?>\n" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
+ "<specVersion>\n" + "<major>1</major>\n" + "<minor>0</minor>\n" + "</specVersion>\n"
+ "<URLBase>http://%s:%s/</URLBase>\n" + // hostname string
"<device>\n" + "<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>\n"
+ "<friendlyName>Amazon-Echo-HA-Bridge (%s)</friendlyName>\n"
+ "<manufacturer>Royal Philips Electronics</manufacturer>\n"
+ "<manufacturerURL>http://www.armzilla..com</manufacturerURL>\n"
+ "<modelDescription>Hue Emulator for Amazon Echo bridge</modelDescription>\n"
+ "<modelName>Philips hue bridge 2012</modelName>\n" + "<modelNumber>929000226503</modelNumber>\n"
+ "<modelURL>http://www.armzilla.com/amazon-echo-ha-bridge</modelURL>\n"
+ "<serialNumber>01189998819991197253</serialNumber>\n"
+ "<UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN>\n" + "<serviceList>\n" + "<service>\n"
+ "<serviceType>(null)</serviceType>\n" + "<serviceId>(null)</serviceId>\n"
+ "<controlURL>(null)</controlURL>\n" + "<eventSubURL>(null)</eventSubURL>\n"
+ "<SCPDURL>(null)</SCPDURL>\n" + "</service>\n" + "</serviceList>\n"
+ "<presentationURL>index.html</presentationURL>\n" + "<iconList>\n" + "<icon>\n"
+ "<mimetype>image/png</mimetype>\n" + "<height>48</height>\n" + "<width>48</width>\n"
+ "<depth>24</depth>\n" + "<url>hue_logo_0.png</url>\n" + "</icon>\n" + "<icon>\n"
+ "<mimetype>image/png</mimetype>\n" + "<height>120</height>\n" + "<width>120</width>\n"
+ "<depth>24</depth>\n" + "<url>hue_logo_3.png</url>\n" + "</icon>\n" + "</iconList>\n" + "</device>\n"
+ "</root>\n";
public UpnpSettingsResource() {
super();
setupListener();
}
private void setupListener () {
// http://ip_address:port/upnp/:id/setup.xml which returns the xml configuration for the location of the hue emulator
get(UPNP_CONTEXT + "/:id/setup.xml", "application/xml", (request, response) -> {
log.info("upnp device settings requested: " + request.params(":id") + " from " + request.ip());
String hostName = System.getProperty("upnp.config.address", "192.168.1.1");
String portNumber = Integer.toString(request.port());
String filledTemplate = String.format(hueTemplate, hostName, portNumber, hostName);
log.debug("upnp device settings response: " + filledTemplate);
response.status(201);
return filledTemplate;
} );
}
}