mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-18 16:17:30 +00:00
numbering more in line with how the hue bridge is done. Added special generation of hue device unique id as the philips api spec shows. Added a renumber function to convert id's.
362 lines
15 KiB
Java
362 lines
15 KiB
Java
package com.bwssystems.HABridge.devicemanagmeent;
|
|
|
|
import static spark.Spark.get;
|
|
import static spark.Spark.options;
|
|
import static spark.Spark.post;
|
|
import static spark.Spark.put;
|
|
import static spark.Spark.delete;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
import org.apache.http.HttpStatus;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
|
|
import com.bwssystems.HABridge.dao.BackupFilename;
|
|
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
|
import com.bwssystems.HABridge.dao.DeviceRepository;
|
|
import com.bwssystems.HABridge.dao.ErrorMessage;
|
|
import com.bwssystems.NestBridge.NestHome;
|
|
import com.bwssystems.hal.HalHome;
|
|
import com.bwssystems.harmony.HarmonyHome;
|
|
import com.bwssystems.hue.HueHome;
|
|
import com.bwssystems.luupRequests.Device;
|
|
import com.bwssystems.luupRequests.Scene;
|
|
import com.bwssystems.util.JsonTransformer;
|
|
import com.bwssystems.vera.VeraHome;
|
|
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;
|
|
private VeraHome veraHome;
|
|
private HarmonyHome myHarmonyHome;
|
|
private NestHome nestHome;
|
|
private HueHome hueHome;
|
|
private HalHome halHome;
|
|
private static final Set<String> supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
|
|
|
|
public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome, HalHome aHalHome) {
|
|
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
|
|
|
|
if(theSettings.isValidVera())
|
|
this.veraHome = new VeraHome(theSettings);
|
|
else
|
|
this.veraHome = null;
|
|
|
|
if(theSettings.isValidHarmony())
|
|
this.myHarmonyHome = theHarmonyHome;
|
|
else
|
|
this.myHarmonyHome = null;
|
|
|
|
if(theSettings.isValidNest())
|
|
this.nestHome = aNestHome;
|
|
else
|
|
this.nestHome = null;
|
|
|
|
if(theSettings.isValidHue())
|
|
this.hueHome = aHueHome;
|
|
else
|
|
this.hueHome = null;
|
|
|
|
if(theSettings.isValidHal())
|
|
this.halHome = aHalHome;
|
|
else
|
|
this.halHome = null;
|
|
|
|
setupEndpoints();
|
|
}
|
|
|
|
public DeviceRepository getDeviceRepository() {
|
|
return deviceRepository;
|
|
}
|
|
|
|
private void setupEndpoints() {
|
|
log.info("HABridge device management service started.... ");
|
|
// http://ip_address:port/api/devices CORS request
|
|
options(API_CONTEXT, "application/json", (request, response) -> {
|
|
response.status(HttpStatus.SC_OK);
|
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
|
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
|
response.header("Content-Type", "text/html; charset=utf-8");
|
|
return "";
|
|
});
|
|
post(API_CONTEXT, "application/json", (request, response) -> {
|
|
log.debug("Create a Device(s) - request body: " + request.body());
|
|
DeviceDescriptor devices[];
|
|
if(request.body().substring(0,1).equalsIgnoreCase("[") == true) {
|
|
devices = new Gson().fromJson(request.body(), DeviceDescriptor[].class);
|
|
}
|
|
else {
|
|
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
|
|
}
|
|
for(int i = 0; i < devices.length; i++) {
|
|
if(devices[i].getContentBody() != null ) {
|
|
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
|
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
|
log.debug("Bad http verb in create a Device(s): " + request.body());
|
|
return new ErrorMessage("Bad http verb in create a Device(s): " + request.body() + " ");
|
|
}
|
|
}
|
|
}
|
|
|
|
deviceRepository.save(devices);
|
|
log.debug("Created a Device(s): " + request.body());
|
|
|
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
|
response.status(HttpStatus.SC_CREATED);
|
|
|
|
return devices;
|
|
}, new JsonTransformer());
|
|
|
|
// http://ip_address:port/api/devices/:id CORS request
|
|
options(API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
|
response.status(HttpStatus.SC_OK);
|
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
|
response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
|
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
|
response.header("Content-Type", "text/html; charset=utf-8");
|
|
return "";
|
|
});
|
|
put (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
|
log.debug("Edit a Device - request body: " + request.body());
|
|
DeviceDescriptor device = new Gson().fromJson(request.body(), DeviceDescriptor.class);
|
|
if(deviceRepository.findOne(request.params(":id")) == null){
|
|
log.debug("Could not save an edited device, Device Id not found: " + request.params(":id"));
|
|
response.status(HttpStatus.SC_BAD_REQUEST);
|
|
return new ErrorMessage("Could not save an edited device, Device Id not found: " + request.params(":id") + " ");
|
|
}
|
|
else
|
|
{
|
|
log.debug("Saving an edited Device: " + device.getName());
|
|
|
|
if (device.getDeviceType() != null)
|
|
device.setDeviceType(device.getDeviceType());
|
|
|
|
DeviceDescriptor[] theDevices = new DeviceDescriptor[1];
|
|
theDevices[0] = device;
|
|
deviceRepository.save(theDevices);
|
|
response.status(HttpStatus.SC_OK);
|
|
}
|
|
return device;
|
|
}, 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);
|
|
response.status(HttpStatus.SC_OK);
|
|
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) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("Could not find, id: " + request.params(":id") + " ");
|
|
}
|
|
else
|
|
response.status(HttpStatus.SC_OK);
|
|
return descriptor;
|
|
}, new JsonTransformer());
|
|
|
|
delete (API_CONTEXT + "/:id", "application/json", (request, response) -> {
|
|
String anId = request.params(":id");
|
|
log.debug("Delete a device: " + anId);
|
|
DeviceDescriptor deleted = deviceRepository.findOne(anId);
|
|
if(deleted == null) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("Could not delete, id: " + anId + " not found. ");
|
|
}
|
|
else
|
|
{
|
|
deviceRepository.delete(deleted);
|
|
response.status(HttpStatus.SC_OK);
|
|
}
|
|
return null;
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/vera/devices", "application/json", (request, response) -> {
|
|
log.debug("Get vera devices");
|
|
if(veraHome == null){
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Vera is not available.");
|
|
}
|
|
List<Device> theDevices = veraHome.getDevices();
|
|
if(theDevices == null) {
|
|
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
|
return new ErrorMessage("A Vera request failed to get devices. Check your Vera IP addresses.");
|
|
}
|
|
else
|
|
response.status(HttpStatus.SC_OK);
|
|
return theDevices;
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/vera/scenes", "application/json", (request, response) -> {
|
|
log.debug("Get vera scenes");
|
|
if(veraHome == null){
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Vera is not available.");
|
|
}
|
|
List<Scene> theScenes = veraHome.getScenes();
|
|
if(theScenes == null) {
|
|
response.status(HttpStatus.SC_SERVICE_UNAVAILABLE);
|
|
return new ErrorMessage("A Vera is not available and failed to get scenes. Check your Vera IP addresses.");
|
|
}
|
|
else
|
|
response.status(HttpStatus.SC_OK);
|
|
return theScenes;
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> {
|
|
log.debug("Get harmony activities");
|
|
if(myHarmonyHome == null) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Harmony is not available.");
|
|
}
|
|
response.status(HttpStatus.SC_OK);
|
|
return myHarmonyHome.getActivities();
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/harmony/show", "application/json", (request, response) -> {
|
|
log.debug("Get harmony current activity");
|
|
if(myHarmonyHome == null) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Harmony is not available.");
|
|
}
|
|
response.status(HttpStatus.SC_OK);
|
|
return myHarmonyHome.getCurrentActivities();
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/harmony/devices", "application/json", (request, response) -> {
|
|
log.debug("Get harmony devices");
|
|
if(myHarmonyHome == null) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Harmony is not available.");
|
|
}
|
|
response.status(HttpStatus.SC_OK);
|
|
return myHarmonyHome.getDevices();
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/nest/items", "application/json", (request, response) -> {
|
|
log.debug("Get nest items");
|
|
if(nestHome == null) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Nest is not available.");
|
|
}
|
|
response.status(HttpStatus.SC_OK);
|
|
return nestHome.getItems();
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/hue/devices", "application/json", (request, response) -> {
|
|
log.debug("Get hue items");
|
|
if(hueHome == null) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Hue is not available.");
|
|
}
|
|
response.status(HttpStatus.SC_OK);
|
|
return hueHome.getDevices();
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/hal/devices", "application/json", (request, response) -> {
|
|
log.debug("Get hal items");
|
|
if(halHome == null) {
|
|
response.status(HttpStatus.SC_NOT_FOUND);
|
|
return new ErrorMessage("A Hal is not available.");
|
|
}
|
|
response.status(HttpStatus.SC_OK);
|
|
return halHome.getDevices();
|
|
}, new JsonTransformer());
|
|
|
|
// http://ip_address:port/api/devices/exec/renumber CORS request
|
|
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
|
|
response.status(HttpStatus.SC_OK);
|
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
|
response.header("Access-Control-Allow-Methods", "POST");
|
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
|
response.header("Content-Type", "text/html; charset=utf-8");
|
|
return "";
|
|
});
|
|
post (API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
|
|
log.debug("Renumber devices.");
|
|
deviceRepository.renumber();
|
|
return null;
|
|
}, new JsonTransformer());
|
|
|
|
get (API_CONTEXT + "/backup/available", "application/json", (request, response) -> {
|
|
log.debug("Get backup filenames");
|
|
response.status(HttpStatus.SC_OK);
|
|
return deviceRepository.getBackups();
|
|
}, new JsonTransformer());
|
|
|
|
// http://ip_address:port/api/devices/backup/create CORS request
|
|
options(API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
|
response.status(HttpStatus.SC_OK);
|
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
|
response.header("Access-Control-Allow-Methods", "PUT");
|
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
|
response.header("Content-Type", "text/html; charset=utf-8");
|
|
return "";
|
|
});
|
|
put (API_CONTEXT + "/backup/create", "application/json", (request, response) -> {
|
|
log.debug("Create backup: " + request.body());
|
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
|
BackupFilename returnFilename = new BackupFilename();
|
|
returnFilename.setFilename(deviceRepository.backup(aFilename.getFilename()));
|
|
return returnFilename;
|
|
}, new JsonTransformer());
|
|
|
|
// http://ip_address:port/api/devices/backup/delete CORS request
|
|
options(API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
|
response.status(HttpStatus.SC_OK);
|
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
|
response.header("Access-Control-Allow-Methods", "POST");
|
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
|
response.header("Content-Type", "text/html; charset=utf-8");
|
|
return "";
|
|
});
|
|
post (API_CONTEXT + "/backup/delete", "application/json", (request, response) -> {
|
|
log.debug("Delete backup: " + request.body());
|
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
|
if(aFilename != null)
|
|
deviceRepository.deleteBackup(aFilename.getFilename());
|
|
else
|
|
log.warn("No filename given for delete backup.");
|
|
return null;
|
|
}, new JsonTransformer());
|
|
|
|
// http://ip_address:port/api/devices/backup/restore CORS request
|
|
options(API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
|
response.status(HttpStatus.SC_OK);
|
|
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
|
response.header("Access-Control-Allow-Methods", "POST");
|
|
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
|
response.header("Content-Type", "text/html; charset=utf-8");
|
|
return "";
|
|
});
|
|
post (API_CONTEXT + "/backup/restore", "application/json", (request, response) -> {
|
|
log.debug("Restore backup: " + request.body());
|
|
BackupFilename aFilename = new Gson().fromJson(request.body(), BackupFilename.class);
|
|
if(aFilename != null) {
|
|
deviceRepository.restoreBackup(aFilename.getFilename());
|
|
deviceRepository.loadRepository();
|
|
}
|
|
else
|
|
log.warn("No filename given for restore backup.");
|
|
return null;
|
|
}, new JsonTransformer());
|
|
}
|
|
} |