mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-19 08:28:46 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ac83912f3 | ||
|
|
e62fcf7765 | ||
|
|
9c3d95f177 | ||
|
|
926a7f50dc | ||
|
|
ad820a68c9 | ||
|
|
73f0f766f7 | ||
|
|
113ce0ca59 | ||
|
|
a5860417c1 |
24
README.md
24
README.md
@@ -531,6 +531,30 @@ A response to a successful PUT request contains confirmation of the arguments pa
|
||||
{"success":{"/lights/1/state/on":true}},
|
||||
]
|
||||
```
|
||||
### Update bridge internal light state
|
||||
Allows the user to set the internal state of the light on and off, modify the brightness. This is not a HUE API call and is special to the bridge as it keeps track of the state changes to the light from the api. It is intended to allow you to sync the bridge state with your HA system state.
|
||||
```
|
||||
PUT http://host:port/api/<username>/lights/<id>/bridgeupdatestate
|
||||
```
|
||||
#### Body arguments
|
||||
Name | Type | Description
|
||||
-----|-------|-------------
|
||||
on | bool | On/Off state of the light. On=true, Off=false. Optional
|
||||
bri | uint8 | The brightness value to set the light to. Brightness is a scale from 1 (the minimum the light is capable of) to 254 (the maximum). Note: a brightness of 1 is not off. e.g. "brightness": 60 will set the light to a specific brightness. Optional
|
||||
```
|
||||
{
|
||||
"on": true,
|
||||
"bri": 200
|
||||
}
|
||||
```
|
||||
#### Response
|
||||
A response to a successful PUT request contains confirmation of the arguments passed in. Note: If the new value is too large to return in the response due to internal memory constraints then a value of "Updated." is returned.
|
||||
```
|
||||
[
|
||||
{"success":{"/lights/1/state/bri":200}},
|
||||
{"success":{"/lights/1/state/on":true}},
|
||||
]
|
||||
```
|
||||
### Create user
|
||||
Emulates creating a new user. The link button state on the HA Bridge is always on for the purpose of responding to this request. No actual user is saved as this is for compatibility.
|
||||
```
|
||||
|
||||
4
pom.xml
4
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>1.4.1</version>
|
||||
<version>1.4.3</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
@@ -43,7 +43,7 @@
|
||||
<dependency>
|
||||
<groupId>com.github.bwssytems</groupId>
|
||||
<artifactId>nest-controller</artifactId>
|
||||
<version>1.0.5</version>
|
||||
<version>1.0.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
||||
@@ -40,12 +40,14 @@ public class BridgeSettings extends BackupHandler {
|
||||
String addressString = null;
|
||||
String theVeraAddress = null;
|
||||
String theHarmonyAddress = null;
|
||||
|
||||
String configFileProperty = System.getProperty("config.file");
|
||||
if(configFileProperty == null) {
|
||||
Path filePath = Paths.get(Configuration.CONFIG_FILE);
|
||||
if(Files.exists(filePath) && Files.isReadable(filePath))
|
||||
configFileProperty = Configuration.CONFIG_FILE;
|
||||
}
|
||||
|
||||
if(configFileProperty != null)
|
||||
{
|
||||
log.info("reading from config file: " + configFileProperty);
|
||||
@@ -56,6 +58,7 @@ public class BridgeSettings extends BackupHandler {
|
||||
{
|
||||
log.info("reading from system properties");
|
||||
theBridgeSettings.setNumberoflogmessages(Configuration.NUMBER_OF_LOG_MESSAGES);
|
||||
theBridgeSettings.setFarenheit(true);
|
||||
theBridgeSettings.setConfigfile(Configuration.CONFIG_FILE);
|
||||
theBridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DEFAULT_WEB_PORT));
|
||||
theBridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address"));
|
||||
@@ -142,6 +145,9 @@ public class BridgeSettings extends BackupHandler {
|
||||
if(theBridgeSettings.getUpnpDeviceDb() == null)
|
||||
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
|
||||
|
||||
if(theBridgeSettings.getNumberoflogmessages() == null)
|
||||
theBridgeSettings.setNumberoflogmessages(Configuration.NUMBER_OF_LOG_MESSAGES);
|
||||
|
||||
if(theBridgeSettings.getButtonsleep() <= 0)
|
||||
theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP));
|
||||
|
||||
@@ -179,6 +185,8 @@ public class BridgeSettings extends BackupHandler {
|
||||
theBridgeSettings.setVeraconfigured(aBridgeSettings.isValidVera());
|
||||
theBridgeSettings.setHarmonyconfigured(aBridgeSettings.isValidHarmony());
|
||||
theBridgeSettings.setNestConfigured(aBridgeSettings.isValidNest());
|
||||
theBridgeSettings.setNumberoflogmessages(aBridgeSettings.getNumberoflogmessages());
|
||||
theBridgeSettings.setFarenheit(aBridgeSettings.isFarenheit());
|
||||
}
|
||||
|
||||
public void save(BridgeSettingsDescriptor newBridgeSettings) {
|
||||
|
||||
@@ -19,6 +19,7 @@ public class BridgeSettingsDescriptor {
|
||||
private boolean veraconfigured;
|
||||
private boolean harmonyconfigured;
|
||||
private boolean nestconfigured;
|
||||
private boolean farenheit;
|
||||
private String configfile;
|
||||
private Integer numberoflogmessages;
|
||||
|
||||
@@ -29,6 +30,7 @@ public class BridgeSettingsDescriptor {
|
||||
this.nestconfigured = false;
|
||||
this.veraconfigured = false;
|
||||
this.harmonyconfigured = false;
|
||||
this.farenheit = true;
|
||||
}
|
||||
public String getUpnpConfigAddress() {
|
||||
return upnpconfigaddress;
|
||||
@@ -144,8 +146,14 @@ public class BridgeSettingsDescriptor {
|
||||
public void setNumberoflogmessages(Integer numberoflogmessages) {
|
||||
this.numberoflogmessages = numberoflogmessages;
|
||||
}
|
||||
public boolean isFarenheit() {
|
||||
return farenheit;
|
||||
}
|
||||
public void setFarenheit(boolean farenheit) {
|
||||
this.farenheit = farenheit;
|
||||
}
|
||||
public Boolean isValidVera() {
|
||||
if(this.getVeraAddress() == null)
|
||||
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
|
||||
return false;
|
||||
List<NamedIP> devicesList = this.getVeraAddress().getDevices();
|
||||
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.bwssystems.HABridge.dao.BackupFilename;
|
||||
import com.bwssystems.logservices.LoggerInfo;
|
||||
import com.bwssystems.logservices.LoggingForm;
|
||||
import com.bwssystems.logservices.LoggingManager;
|
||||
import com.bwssystems.util.JsonFreeTextStringFormatter;
|
||||
import com.bwssystems.util.TextStringFormatter;
|
||||
import com.bwssystems.util.JsonTransformer;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
@@ -82,7 +82,7 @@ public class SystemControl {
|
||||
LoggingEvent le;
|
||||
for (int i = 0; i < count; i++) {
|
||||
le = (LoggingEvent) cyclicBufferAppender.get(i);
|
||||
logMsgs = logMsgs + ( i > 0?",{":"{") + "\"time\":\"" + dateFormat.format(le.getTimeStamp()) + "\",\"level\":\"" + le.getLevel().levelStr + "\",\"component\":\"" + le.getLoggerName() + "\",\"message\":\"" + JsonFreeTextStringFormatter.forJSON(le.getFormattedMessage()) + "\"}";
|
||||
logMsgs = logMsgs + ( i > 0?",{":"{") + "\"time\":\"" + dateFormat.format(le.getTimeStamp()) + "\",\"level\":\"" + le.getLevel().levelStr + "\",\"component\":\"" + le.getLoggerName() + "\",\"message\":\"" + TextStringFormatter.forJSON(le.getFormattedMessage()) + "\"}";
|
||||
}
|
||||
}
|
||||
logMsgs = logMsgs + "]";
|
||||
@@ -92,7 +92,7 @@ public class SystemControl {
|
||||
|
||||
// http://ip_address:port/system/logmgmt/loggers gets the logger info for the bridge
|
||||
get (SYSTEM_CONTEXT + "/logmgmt/loggers/:all", "application/json", (request, response) -> {
|
||||
log.info("Get loggers info with showAll argument: " + request.params(":all"));
|
||||
log.debug("Get loggers info with showAll argument: " + request.params(":all"));
|
||||
Boolean showAll = false;
|
||||
if(request.params(":all").equals("true"))
|
||||
showAll = true;
|
||||
@@ -113,6 +113,7 @@ public class SystemControl {
|
||||
});
|
||||
// http://ip_address:port/system/logmgmt/update which changes logging parameters for the process
|
||||
put(SYSTEM_CONTEXT + "/logmgmt/update", "application/json", (request, response) -> {
|
||||
log.debug("update loggers: " + request.body());
|
||||
response.status(200);
|
||||
LoggerInfo updateLoggers[];
|
||||
updateLoggers = new Gson().fromJson(request.body(), LoggerInfo[].class);
|
||||
@@ -239,7 +240,7 @@ public class SystemControl {
|
||||
}
|
||||
else
|
||||
log.warn("No filename given for restore backup.");
|
||||
return null;
|
||||
return bridgeSettings.getBridgeSettingsDescriptor();
|
||||
}, new JsonTransformer());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
|
||||
/**
|
||||
* Created by arm on 4/14/15.
|
||||
*/
|
||||
@@ -68,18 +70,18 @@ public class DeviceResponse {
|
||||
this.swversion = swversion;
|
||||
}
|
||||
|
||||
public static DeviceResponse createResponse(String name, String id){
|
||||
public static DeviceResponse createResponse(DeviceDescriptor device){
|
||||
DeviceState deviceState = new DeviceState();
|
||||
DeviceResponse response = new DeviceResponse();
|
||||
response.setState(deviceState);
|
||||
deviceState.setOn(false);
|
||||
deviceState.setOn(device.getDeviceState());
|
||||
deviceState.setReachable(true);
|
||||
deviceState.setEffect("none");
|
||||
deviceState.setAlert("none");
|
||||
deviceState.setBri(254);
|
||||
deviceState.setBri(device.getDeviceSetValue());
|
||||
|
||||
response.setName(name);
|
||||
response.setUniqueid(id);
|
||||
response.setName(device.getName());
|
||||
response.setUniqueid(device.getId());
|
||||
response.setManufacturername("Philips");
|
||||
response.setType("Dimmable light");
|
||||
response.setModelid("LWB004");
|
||||
|
||||
@@ -6,7 +6,7 @@ package com.bwssystems.HABridge.api.hue;
|
||||
*/
|
||||
public class DeviceState {
|
||||
private boolean on;
|
||||
private int bri = 255;
|
||||
private int bri = 0;
|
||||
private String effect;
|
||||
private String alert;
|
||||
private boolean reachable;
|
||||
|
||||
@@ -1,21 +1,55 @@
|
||||
package com.bwssystems.HABridge.dao;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/*
|
||||
* Object to handle the device configuration
|
||||
*/
|
||||
public class DeviceDescriptor{
|
||||
private String id;
|
||||
@SerializedName("id")
|
||||
@Expose
|
||||
private String id;
|
||||
@SerializedName("name")
|
||||
@Expose
|
||||
private String name;
|
||||
@SerializedName("mapId")
|
||||
@Expose
|
||||
private String mapId;
|
||||
@SerializedName("mapType")
|
||||
@Expose
|
||||
private String mapType;
|
||||
@SerializedName("deviceType")
|
||||
@Expose
|
||||
private String deviceType;
|
||||
@SerializedName("targetDevice")
|
||||
@Expose
|
||||
private String targetDevice;
|
||||
@SerializedName("offUrl")
|
||||
@Expose
|
||||
private String offUrl;
|
||||
@SerializedName("dimUrl")
|
||||
@Expose
|
||||
private String dimUrl;
|
||||
@SerializedName("onUrl")
|
||||
@Expose
|
||||
private String onUrl;
|
||||
@SerializedName("httpVerb")
|
||||
@Expose
|
||||
private String httpVerb;
|
||||
@SerializedName("contentType")
|
||||
@Expose
|
||||
private String contentType;
|
||||
@SerializedName("contentBody")
|
||||
@Expose
|
||||
private String contentBody;
|
||||
@SerializedName("contentBodyOff")
|
||||
@Expose
|
||||
private String contentBodyOff;
|
||||
|
||||
private boolean deviceState;
|
||||
private int deviceSetValue;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -64,7 +98,15 @@ public class DeviceDescriptor{
|
||||
this.offUrl = offUrl;
|
||||
}
|
||||
|
||||
public String getOnUrl() {
|
||||
public String getDimUrl() {
|
||||
return dimUrl;
|
||||
}
|
||||
|
||||
public void setDimUrl(String dimUrl) {
|
||||
this.dimUrl = dimUrl;
|
||||
}
|
||||
|
||||
public String getOnUrl() {
|
||||
return onUrl;
|
||||
}
|
||||
|
||||
@@ -112,5 +154,21 @@ public class DeviceDescriptor{
|
||||
this.contentBodyOff = contentBodyOff;
|
||||
}
|
||||
|
||||
public boolean getDeviceState() {
|
||||
return deviceState;
|
||||
}
|
||||
|
||||
public void setDeviceState(boolean deviceState) {
|
||||
this.deviceState = deviceState;
|
||||
}
|
||||
|
||||
public int getDeviceSetValue() {
|
||||
return deviceSetValue;
|
||||
}
|
||||
|
||||
public void setDeviceSetValue(int deviceSetValue) {
|
||||
this.deviceSetValue = deviceSetValue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.bwssystems.HABridge.dao;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -18,22 +17,27 @@ import org.slf4j.LoggerFactory;
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.util.BackupHandler;
|
||||
import com.bwssystems.util.JsonTransformer;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
/*
|
||||
* This is an in memory list to manage the configured devices and saves the list as a JSON string to a file for later
|
||||
* loading.
|
||||
*/
|
||||
public class DeviceRepository extends BackupHandler {
|
||||
Map<String, DeviceDescriptor> devices;
|
||||
Path repositoryPath;
|
||||
final Random random = new Random();
|
||||
final Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||
private Map<String, DeviceDescriptor> devices;
|
||||
private Path repositoryPath;
|
||||
private Gson gson;
|
||||
final private Random random = new Random();
|
||||
private Logger log = LoggerFactory.getLogger(DeviceRepository.class);
|
||||
|
||||
public DeviceRepository(String deviceDb) {
|
||||
super();
|
||||
gson =
|
||||
new GsonBuilder()
|
||||
.excludeFieldsWithoutExposeAnnotation()
|
||||
.create();
|
||||
repositoryPath = null;
|
||||
repositoryPath = Paths.get(deviceDb);
|
||||
setupParams(repositoryPath, ".bk", "device.db-");
|
||||
@@ -50,15 +54,11 @@ public class DeviceRepository extends BackupHandler {
|
||||
|
||||
if(jsonContent != null)
|
||||
{
|
||||
List<DeviceDescriptor> list = readJsonStream(jsonContent);
|
||||
ListIterator<DeviceDescriptor> theIterator = list.listIterator();
|
||||
DeviceDescriptor theDevice = null;
|
||||
while (theIterator.hasNext()) {
|
||||
theDevice = theIterator.next();
|
||||
put(theDevice.getId(), theDevice);
|
||||
DeviceDescriptor list[] = gson.fromJson(jsonContent, DeviceDescriptor[].class);
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
put(list[i].getId(), list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<DeviceDescriptor> findAll() {
|
||||
@@ -82,15 +82,14 @@ public class DeviceRepository extends BackupHandler {
|
||||
public void save(DeviceDescriptor[] descriptors) {
|
||||
String theNames = "";
|
||||
for(int i = 0; i < descriptors.length; i++) {
|
||||
if(descriptors[i].getId() != null)
|
||||
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
|
||||
devices.remove(descriptors[i].getId());
|
||||
else
|
||||
descriptors[i].setId(String.valueOf(random.nextInt(Integer.MAX_VALUE)));
|
||||
put(descriptors[i].getId(), descriptors[i]);
|
||||
theNames = theNames + " " + descriptors[i].getName() + ", ";
|
||||
}
|
||||
JsonTransformer aRenderer = new JsonTransformer();
|
||||
String jsonValue = aRenderer.render(findAll());
|
||||
String jsonValue = gson.toJson(findAll());
|
||||
repositoryWriter(jsonValue, repositoryPath);
|
||||
log.debug("Save device(s): " + theNames);
|
||||
}
|
||||
@@ -153,82 +152,4 @@ public class DeviceRepository extends BackupHandler {
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
private List<DeviceDescriptor> readJsonStream(String context) {
|
||||
JsonReader reader = new JsonReader(new StringReader(context));
|
||||
List<DeviceDescriptor> theDescriptors = null;
|
||||
try {
|
||||
theDescriptors = readDescriptorArray(reader);
|
||||
} catch (IOException e) {
|
||||
log.error("Error reading json array: " + context + " message: " + e.getMessage(), e);
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
log.error("Error closing json reader: " + context + " message: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return theDescriptors;
|
||||
}
|
||||
|
||||
public List<DeviceDescriptor> readDescriptorArray(JsonReader reader) throws IOException {
|
||||
List<DeviceDescriptor> descriptors = new ArrayList<DeviceDescriptor>();
|
||||
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
descriptors.add(readDescriptor(reader));
|
||||
}
|
||||
reader.endArray();
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
public DeviceDescriptor readDescriptor(JsonReader reader) throws IOException {
|
||||
DeviceDescriptor deviceEntry = new DeviceDescriptor();
|
||||
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String name = reader.nextName();
|
||||
if (name.equals("id")) {
|
||||
deviceEntry.setId(reader.nextString());
|
||||
log.debug("Read a Device - device json id: " + deviceEntry.getId());
|
||||
} else if (name.equals("name")) {
|
||||
deviceEntry.setName(reader.nextString());
|
||||
log.debug("Read a Device - device json name: " + deviceEntry.getName());
|
||||
} else if (name.equals("mapType")) {
|
||||
deviceEntry.setMapType(reader.nextString());
|
||||
log.debug("Read a Device - device json name: " + deviceEntry.getMapType());
|
||||
} else if (name.equals("mapId")) {
|
||||
deviceEntry.setMapId(reader.nextString());
|
||||
log.debug("Read a Device - device json name: " + deviceEntry.getMapId());
|
||||
} else if (name.equals("deviceType")) {
|
||||
deviceEntry.setDeviceType(reader.nextString());
|
||||
log.debug("Read a Device - device json type:" + deviceEntry.getDeviceType());
|
||||
} else if (name.equals("targetDevice")) {
|
||||
deviceEntry.setTargetDevice(reader.nextString());
|
||||
log.debug("Read a Device - device json type:" + deviceEntry.getTargetDevice());
|
||||
} else if (name.equals("offUrl")) {
|
||||
deviceEntry.setOffUrl(reader.nextString());
|
||||
log.debug("Read a Device - device json off URL:" + deviceEntry.getOffUrl());
|
||||
} else if (name.equals("onUrl")) {
|
||||
deviceEntry.setOnUrl(reader.nextString());
|
||||
log.debug("Read a Device - device json on URL:" + deviceEntry.getOnUrl());
|
||||
} else if (name.equals("httpVerb")) {
|
||||
deviceEntry.setHttpVerb(reader.nextString());
|
||||
log.debug("Read a Device - device json httpVerb:" + deviceEntry.getHttpVerb());
|
||||
} else if (name.equals("contentType")) {
|
||||
deviceEntry.setContentType(reader.nextString());
|
||||
log.debug("Read a Device - device json contentType:" + deviceEntry.getContentType());
|
||||
} else if (name.equals("contentBody")) {
|
||||
deviceEntry.setContentBody(reader.nextString());
|
||||
log.debug("Read a Device - device json contentBody:" + deviceEntry.getContentBody());
|
||||
} else if (name.equals("contentBodyOff")) {
|
||||
deviceEntry.setContentBodyOff(reader.nextString());
|
||||
log.debug("Read a Device - device json contentBodyOff:" + deviceEntry.getContentBodyOff());
|
||||
} else {
|
||||
reader.skipValue();
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
return deviceEntry;
|
||||
}
|
||||
}
|
||||
@@ -115,35 +115,24 @@ public class DeviceResource {
|
||||
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);
|
||||
DeviceDescriptor deviceEntry = deviceRepository.findOne(request.params(":id"));
|
||||
if(deviceEntry == null){
|
||||
log.debug("Could not save an edited Device Id: " + request.params(":id"));
|
||||
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 Id: " + request.params(":id") + " ");
|
||||
return new ErrorMessage("Could not save an edited device, Device Id not found: " + request.params(":id") + " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.debug("Saving an edited Device: " + deviceEntry.getName());
|
||||
log.debug("Saving an edited Device: " + device.getName());
|
||||
|
||||
deviceEntry.setName(device.getName());
|
||||
if (device.getDeviceType() != null)
|
||||
deviceEntry.setDeviceType(device.getDeviceType());
|
||||
deviceEntry.setMapId(device.getMapId());
|
||||
deviceEntry.setMapType(device.getMapType());
|
||||
deviceEntry.setTargetDevice(device.getTargetDevice());
|
||||
deviceEntry.setOnUrl(device.getOnUrl());
|
||||
deviceEntry.setOffUrl(device.getOffUrl());
|
||||
deviceEntry.setHttpVerb(device.getHttpVerb());
|
||||
deviceEntry.setContentType(device.getContentType());
|
||||
deviceEntry.setContentBody(device.getContentBody());
|
||||
deviceEntry.setContentBodyOff(device.getContentBodyOff());
|
||||
device.setDeviceType(device.getDeviceType());
|
||||
|
||||
DeviceDescriptor[] theDevices = new DeviceDescriptor[1];
|
||||
theDevices[0] = deviceEntry;
|
||||
theDevices[0] = device;
|
||||
deviceRepository.save(theDevices);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
}
|
||||
return deviceEntry;
|
||||
return device;
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT, "application/json", (request, response) -> {
|
||||
|
||||
@@ -101,7 +101,7 @@ public class HueMulator {
|
||||
List<DeviceDescriptor> deviceList = repository.findAll();
|
||||
Map<String, DeviceResponse> deviceResponseMap = new HashMap<>();
|
||||
for (DeviceDescriptor device : deviceList) {
|
||||
DeviceResponse deviceResponse = DeviceResponse.createResponse(device.getName(), device.getId());
|
||||
DeviceResponse deviceResponse = DeviceResponse.createResponse(device);
|
||||
deviceResponseMap.put(device.getId(), deviceResponse);
|
||||
}
|
||||
response.type("application/json; charset=utf-8");
|
||||
@@ -225,7 +225,7 @@ public class HueMulator {
|
||||
Map<String, DeviceResponse> deviceList = new HashMap<>();
|
||||
|
||||
descriptorList.forEach(descriptor -> {
|
||||
DeviceResponse deviceResponse = DeviceResponse.createResponse(descriptor.getName(), descriptor.getId());
|
||||
DeviceResponse deviceResponse = DeviceResponse.createResponse(descriptor);
|
||||
deviceList.put(descriptor.getId(), deviceResponse);
|
||||
}
|
||||
);
|
||||
@@ -249,13 +249,68 @@ public class HueMulator {
|
||||
} else {
|
||||
log.debug("found device named: " + device.getName());
|
||||
}
|
||||
DeviceResponse lightResponse = DeviceResponse.createResponse(device.getName(), device.getId());
|
||||
DeviceResponse lightResponse = DeviceResponse.createResponse(device);
|
||||
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
return lightResponse;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/api/:userid/lights/:id/bridgeupdatestate CORS request
|
||||
options(HUE_CONTEXT + "/:userid/lights/:id/bridgeupdatestate", "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");
|
||||
response.header("Access-Control-Allow-Headers", request.headers("Access-Control-Request-Headers"));
|
||||
response.header("Content-Type", "text/html; charset=utf-8");
|
||||
return "";
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/lights/{lightId}/bridgeupdatestate uses json object to update the internal bridge lights state.
|
||||
// THIS IS NOT A HUE API CALL... It is for state management if so desired.
|
||||
put(HUE_CONTEXT + "/:userid/lights/:id/bridgeupdatestate", "application/json", (request, response) -> {
|
||||
String userId = request.params(":userid");
|
||||
String lightId = request.params(":id");
|
||||
String responseString = null;
|
||||
DeviceState state = null;
|
||||
log.debug("Update state requested: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
|
||||
response.type("application/json; charset=utf-8");
|
||||
response.status(HttpStatus.SC_OK);
|
||||
try {
|
||||
state = mapper.readValue(request.body(), DeviceState.class);
|
||||
} catch (IOException e) {
|
||||
log.warn("Object mapper barfed on input of body.", e);
|
||||
responseString = "[{\"error\":{\"type\": 2, \"address\": \"/lights/" + lightId + "\",\"description\": \"Object mapper barfed on input of body.\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
DeviceDescriptor device = repository.findOne(lightId);
|
||||
if (device == null) {
|
||||
log.warn("Could not find device: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find device\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
||||
if(request.body().contains("bri"))
|
||||
{
|
||||
responseString = responseString + "true}},{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.isOn()) {
|
||||
responseString = responseString + "true}}]";
|
||||
state.setBri(255);
|
||||
} else if (request.body().contains("false")) {
|
||||
responseString = responseString + "false}}]";
|
||||
state.setBri(0);
|
||||
}
|
||||
}
|
||||
device.setDeviceSetValue(state.getBri());
|
||||
device.setDeviceState(state.isOn());
|
||||
|
||||
return responseString;
|
||||
});
|
||||
|
||||
// http://ip_address:port/api/:userid/lights/:id/state CORS request
|
||||
options(HUE_CONTEXT + "/:userid/lights/:id/state", "application/json", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
@@ -296,28 +351,34 @@ public class HueMulator {
|
||||
return responseString;
|
||||
}
|
||||
|
||||
if (state.isOn()) {
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":true}}";
|
||||
url = device.getOnUrl();
|
||||
} else if (request.body().contains("false")) {
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":false}}";
|
||||
url = device.getOffUrl();
|
||||
}
|
||||
|
||||
responseString = "[{\"success\":{\"/lights/" + lightId + "/state/on\":";
|
||||
if(request.body().contains("bri"))
|
||||
{
|
||||
if(url == null)
|
||||
{
|
||||
url = device.getOnUrl();
|
||||
responseString = "[";
|
||||
}
|
||||
else
|
||||
responseString = responseString + ",";
|
||||
url = device.getDimUrl();
|
||||
|
||||
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
||||
if(url == null || url.length() == 0)
|
||||
url = device.getOnUrl();
|
||||
|
||||
responseString = responseString + "true}},{\"success\":{\"/lights/" + lightId + "/state/bri\":" + state.getBri() + "}}]";
|
||||
}
|
||||
else
|
||||
responseString = responseString + "]";
|
||||
{
|
||||
if (state.isOn()) {
|
||||
responseString = responseString + "true}}]";
|
||||
url = device.getOnUrl();
|
||||
state.setBri(255);
|
||||
} else if (request.body().contains("false")) {
|
||||
responseString = responseString + "false}}]";
|
||||
url = device.getOffUrl();
|
||||
state.setBri(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (url == null) {
|
||||
log.warn("Could not find url: " + lightId + " for hue state change request: " + userId + " from " + request.ip() + " body: " + request.body());
|
||||
responseString = "[{\"error\":{\"type\": 3, \"address\": \"/lights/" + lightId + "\",\"description\": \"Could not find url\", \"resource\": \"/lights/" + lightId + "\"}}]";
|
||||
return responseString;
|
||||
}
|
||||
|
||||
if(device.getDeviceType().toLowerCase().contains("activity") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyActivity")))
|
||||
{
|
||||
@@ -337,7 +398,6 @@ public class HueMulator {
|
||||
else {
|
||||
log.warn("Should not get here, no harmony configured");
|
||||
responseString = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId + "\",\"description\": \"Should not get here, no harmony configured\", \"parameter\": \"/lights/" + lightId + "state\"}}]";
|
||||
|
||||
}
|
||||
}
|
||||
else if(device.getDeviceType().toLowerCase().contains("button") || (device.getMapType() != null && device.getMapType().equalsIgnoreCase("harmonyButton")))
|
||||
@@ -395,7 +455,10 @@ public class HueMulator {
|
||||
NestInstruction thermoSetting = new Gson().fromJson(url, NestInstruction.class);
|
||||
if(thermoSetting.getControl().equalsIgnoreCase("temp")) {
|
||||
if(request.body().contains("bri")) {
|
||||
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri())) - 32.0)/1.8));
|
||||
if(bridgeSettings.isFarenheit())
|
||||
thermoSetting.setTemp(String.valueOf((Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri())) - 32.0)/1.8));
|
||||
else
|
||||
thermoSetting.setTemp(String.valueOf(Double.parseDouble(replaceIntensityValue(thermoSetting.getTemp(), state.getBri()))));
|
||||
log.debug("Setting thermostat: " + thermoSetting.getName() + " to " + thermoSetting.getTemp() + "C");
|
||||
theNest.getThermostat(thermoSetting.getName()).setTargetTemperature(Float.parseFloat(thermoSetting.getTemp()));
|
||||
}
|
||||
@@ -454,6 +517,10 @@ public class HueMulator {
|
||||
}
|
||||
}
|
||||
|
||||
if(!responseString.contains("[{\"error\":")) {
|
||||
device.setDeviceSetValue(state.getBri());
|
||||
device.setDeviceState(state.isOn());
|
||||
}
|
||||
return responseString;
|
||||
});
|
||||
}
|
||||
@@ -499,31 +566,36 @@ public class HueMulator {
|
||||
// This function executes the url from the device repository against the vera
|
||||
protected boolean doHttpRequest(String url, String httpVerb, String contentType, String body) {
|
||||
HttpUriRequest request = null;
|
||||
if(HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb) || httpVerb == null) {
|
||||
request = new HttpGet(url);
|
||||
}else if(HttpPost.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||
HttpPost postRequest = new HttpPost(url);
|
||||
ContentType parsedContentType = ContentType.parse(contentType);
|
||||
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||
postRequest.setEntity(requestBody);
|
||||
request = postRequest;
|
||||
}else if(HttpPut.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||
HttpPut putRequest = new HttpPut(url);
|
||||
ContentType parsedContentType = ContentType.parse(contentType);
|
||||
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||
putRequest.setEntity(requestBody);
|
||||
request = putRequest;
|
||||
try {
|
||||
if(HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb) || httpVerb == null) {
|
||||
request = new HttpGet(url);
|
||||
}else if(HttpPost.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||
HttpPost postRequest = new HttpPost(url);
|
||||
ContentType parsedContentType = ContentType.parse(contentType);
|
||||
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||
postRequest.setEntity(requestBody);
|
||||
request = postRequest;
|
||||
}else if(HttpPut.METHOD_NAME.equalsIgnoreCase(httpVerb)){
|
||||
HttpPut putRequest = new HttpPut(url);
|
||||
ContentType parsedContentType = ContentType.parse(contentType);
|
||||
StringEntity requestBody = new StringEntity(body, parsedContentType);
|
||||
putRequest.setEntity(requestBody);
|
||||
request = putRequest;
|
||||
}
|
||||
} catch(IllegalArgumentException e) {
|
||||
log.warn("Error calling out to HA gateway: IllegalArgumentException in log", e);
|
||||
return false;
|
||||
}
|
||||
log.debug("Making outbound call in doHttpRequest: " + request);
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||
log.debug((httpVerb == null?"GET":httpVerb) + " execute on URL responded: " + response.getStatusLine().getStatusCode());
|
||||
if(response.getStatusLine().getStatusCode() == 200){
|
||||
if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Error calling out to HA gateway", e);
|
||||
log.warn("Error calling out to HA gateway: IOException in log", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.bwssystems.NestBridge;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
public class NestItem {
|
||||
private String name;
|
||||
private String id;
|
||||
@@ -9,7 +11,14 @@ public class NestItem {
|
||||
return name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
byte ptext[];
|
||||
String theLabel = new String(name);
|
||||
try {
|
||||
ptext = theLabel.getBytes("ISO-8859-1");
|
||||
this.name = new String(ptext, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
this.name = theLabel;
|
||||
}
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import net.whistlingfish.harmony.config.Activity;
|
||||
|
||||
public class HarmonyActivity {
|
||||
@@ -15,6 +17,14 @@ public class HarmonyActivity {
|
||||
return activity;
|
||||
}
|
||||
public void setActivity(Activity activity) {
|
||||
byte ptext[];
|
||||
String theLabel = activity.getLabel();
|
||||
try {
|
||||
ptext = theLabel.getBytes("ISO-8859-1");
|
||||
activity.setLabel(new String(ptext, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
activity.setLabel(theLabel);
|
||||
}
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.bwssystems.harmony;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import net.whistlingfish.harmony.config.Device;
|
||||
|
||||
public class HarmonyDevice {
|
||||
@@ -9,6 +11,14 @@ public class HarmonyDevice {
|
||||
return device;
|
||||
}
|
||||
public void setDevice(Device device) {
|
||||
byte ptext[];
|
||||
String theLabel = device.getLabel();
|
||||
try {
|
||||
ptext = theLabel.getBytes("ISO-8859-1");
|
||||
device.setLabel(new String(ptext, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
device.setLabel(theLabel);
|
||||
}
|
||||
this.device = device;
|
||||
}
|
||||
public String getHub() {
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.bwssystems.util;
|
||||
|
||||
import java.text.StringCharacterIterator;
|
||||
|
||||
public final class JsonFreeTextStringFormatter {
|
||||
private JsonFreeTextStringFormatter(){
|
||||
//empty - prevent construction
|
||||
}
|
||||
|
||||
public static String forJSON(String aText){
|
||||
final StringBuilder result = new StringBuilder();
|
||||
StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
||||
char character = iterator.current();
|
||||
while (character != StringCharacterIterator.DONE){
|
||||
if( character == '\"' ){
|
||||
result.append("\\\"");
|
||||
}
|
||||
else if(character == '\\'){
|
||||
result.append("\\\\");
|
||||
}
|
||||
else if(character == '/'){
|
||||
result.append("\\/");
|
||||
}
|
||||
else if(character == '\b'){
|
||||
result.append("\\b");
|
||||
}
|
||||
else if(character == '\f'){
|
||||
result.append("\\f");
|
||||
}
|
||||
else if(character == '\n'){
|
||||
result.append("\\n");
|
||||
}
|
||||
else if(character == '\r'){
|
||||
result.append("\\r");
|
||||
}
|
||||
else if(character == '\t'){
|
||||
result.append("\\t");
|
||||
}
|
||||
else {
|
||||
//the char is not a special one
|
||||
//add it to the result as is
|
||||
result.append(character);
|
||||
}
|
||||
character = iterator.next();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
259
src/main/java/com/bwssystems/util/TextStringFormatter.java
Normal file
259
src/main/java/com/bwssystems/util/TextStringFormatter.java
Normal file
@@ -0,0 +1,259 @@
|
||||
package com.bwssystems.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.CharacterIterator;
|
||||
import java.text.StringCharacterIterator;
|
||||
|
||||
public final class TextStringFormatter {
|
||||
private TextStringFormatter() {
|
||||
// empty - prevent construction
|
||||
}
|
||||
|
||||
/**
|
||||
Escapes characters for text appearing as data in the
|
||||
<a href='http://www.json.org/'>Javascript Object Notation</a>
|
||||
(JSON) data interchange format.
|
||||
|
||||
<P>The following commonly used control characters are escaped :
|
||||
<table border='1' cellpadding='3' cellspacing='0'>
|
||||
<tr><th> Character </th><th> Escaped As </th></tr>
|
||||
<tr><td> " </td><td> \" </td></tr>
|
||||
<tr><td> \ </td><td> \\ </td></tr>
|
||||
<tr><td> / </td><td> \/ </td></tr>
|
||||
<tr><td> back space </td><td> \b </td></tr>
|
||||
<tr><td> form feed </td><td> \f </td></tr>
|
||||
<tr><td> line feed </td><td> \n </td></tr>
|
||||
<tr><td> carriage return </td><td> \r </td></tr>
|
||||
<tr><td> tab </td><td> \t </td></tr>
|
||||
</table>
|
||||
|
||||
<P>See <a href='http://www.ietf.org/rfc/rfc4627.txt'>RFC 4627</a> for more information.
|
||||
*/
|
||||
public static String forJSON(String aText) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
||||
char character = iterator.current();
|
||||
while (character != StringCharacterIterator.DONE) {
|
||||
if (character == '\"') {
|
||||
result.append("\\\"");
|
||||
} else if (character == '\\') {
|
||||
result.append("\\\\");
|
||||
} else if (character == '/') {
|
||||
result.append("\\/");
|
||||
} else if (character == '\b') {
|
||||
result.append("\\b");
|
||||
} else if (character == '\f') {
|
||||
result.append("\\f");
|
||||
} else if (character == '\n') {
|
||||
result.append("\\n");
|
||||
} else if (character == '\r') {
|
||||
result.append("\\r");
|
||||
} else if (character == '\t') {
|
||||
result.append("\\t");
|
||||
} else {
|
||||
// the char is not a special one
|
||||
// add it to the result as is
|
||||
result.append(character);
|
||||
}
|
||||
character = iterator.next();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
Escape characters for text appearing in HTML markup.
|
||||
|
||||
<P>This method exists as a defence against Cross Site Scripting (XSS) hacks.
|
||||
The idea is to neutralize control characters commonly used by scripts, such that
|
||||
they will not be executed by the browser. This is done by replacing the control
|
||||
characters with their escaped equivalents.
|
||||
See {@link hirondelle.web4j.security.SafeText} as well.
|
||||
|
||||
<P>The following characters are replaced with corresponding
|
||||
HTML character entities :
|
||||
<table border='1' cellpadding='3' cellspacing='0'>
|
||||
<tr><th> Character </th><th>Replacement</th></tr>
|
||||
<tr><td> < </td><td> < </td></tr>
|
||||
<tr><td> > </td><td> > </td></tr>
|
||||
<tr><td> & </td><td> & </td></tr>
|
||||
<tr><td> " </td><td> "</td></tr>
|
||||
<tr><td> \t </td><td> 	</td></tr>
|
||||
<tr><td> ! </td><td> !</td></tr>
|
||||
<tr><td> # </td><td> #</td></tr>
|
||||
<tr><td> $ </td><td> $</td></tr>
|
||||
<tr><td> % </td><td> %</td></tr>
|
||||
<tr><td> ' </td><td> '</td></tr>
|
||||
<tr><td> ( </td><td> (</td></tr>
|
||||
<tr><td> ) </td><td> )</td></tr>
|
||||
<tr><td> * </td><td> *</td></tr>
|
||||
<tr><td> + </td><td> + </td></tr>
|
||||
<tr><td> , </td><td> , </td></tr>
|
||||
<tr><td> - </td><td> - </td></tr>
|
||||
<tr><td> . </td><td> . </td></tr>
|
||||
<tr><td> / </td><td> / </td></tr>
|
||||
<tr><td> : </td><td> :</td></tr>
|
||||
<tr><td> ; </td><td> ;</td></tr>
|
||||
<tr><td> = </td><td> =</td></tr>
|
||||
<tr><td> ? </td><td> ?</td></tr>
|
||||
<tr><td> @ </td><td> @</td></tr>
|
||||
<tr><td> [ </td><td> [</td></tr>
|
||||
<tr><td> \ </td><td> \</td></tr>
|
||||
<tr><td> ] </td><td> ]</td></tr>
|
||||
<tr><td> ^ </td><td> ^</td></tr>
|
||||
<tr><td> _ </td><td> _</td></tr>
|
||||
<tr><td> ` </td><td> `</td></tr>
|
||||
<tr><td> { </td><td> {</td></tr>
|
||||
<tr><td> | </td><td> |</td></tr>
|
||||
<tr><td> } </td><td> }</td></tr>
|
||||
<tr><td> ~ </td><td> ~</td></tr>
|
||||
</table>
|
||||
|
||||
<P>Note that JSTL's {@code <c:out>} escapes <em>only the first
|
||||
five</em> of the above characters.
|
||||
*/
|
||||
|
||||
public static String forHTML(String aText) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
final StringCharacterIterator iterator = new StringCharacterIterator(aText);
|
||||
char character = iterator.current();
|
||||
while (character != CharacterIterator.DONE) {
|
||||
if (character == '<') {
|
||||
result.append("<");
|
||||
} else if (character == '>') {
|
||||
result.append(">");
|
||||
} else if (character == '&') {
|
||||
result.append("&");
|
||||
} else if (character == '\"') {
|
||||
result.append(""");
|
||||
} else if (character == '\t') {
|
||||
addCharEntity(9, result);
|
||||
} else if (character == '!') {
|
||||
addCharEntity(33, result);
|
||||
} else if (character == '#') {
|
||||
addCharEntity(35, result);
|
||||
} else if (character == '$') {
|
||||
addCharEntity(36, result);
|
||||
} else if (character == '%') {
|
||||
addCharEntity(37, result);
|
||||
} else if (character == '\'') {
|
||||
addCharEntity(39, result);
|
||||
} else if (character == '(') {
|
||||
addCharEntity(40, result);
|
||||
} else if (character == ')') {
|
||||
addCharEntity(41, result);
|
||||
} else if (character == '*') {
|
||||
addCharEntity(42, result);
|
||||
} else if (character == '+') {
|
||||
addCharEntity(43, result);
|
||||
} else if (character == ',') {
|
||||
addCharEntity(44, result);
|
||||
} else if (character == '-') {
|
||||
addCharEntity(45, result);
|
||||
} else if (character == '.') {
|
||||
addCharEntity(46, result);
|
||||
} else if (character == '/') {
|
||||
addCharEntity(47, result);
|
||||
} else if (character == ':') {
|
||||
addCharEntity(58, result);
|
||||
} else if (character == ';') {
|
||||
addCharEntity(59, result);
|
||||
} else if (character == '=') {
|
||||
addCharEntity(61, result);
|
||||
} else if (character == '?') {
|
||||
addCharEntity(63, result);
|
||||
} else if (character == '@') {
|
||||
addCharEntity(64, result);
|
||||
} else if (character == '[') {
|
||||
addCharEntity(91, result);
|
||||
} else if (character == '\\') {
|
||||
addCharEntity(92, result);
|
||||
} else if (character == ']') {
|
||||
addCharEntity(93, result);
|
||||
} else if (character == '^') {
|
||||
addCharEntity(94, result);
|
||||
} else if (character == '_') {
|
||||
addCharEntity(95, result);
|
||||
} else if (character == '`') {
|
||||
addCharEntity(96, result);
|
||||
} else if (character == '{') {
|
||||
addCharEntity(123, result);
|
||||
} else if (character == '|') {
|
||||
addCharEntity(124, result);
|
||||
} else if (character == '}') {
|
||||
addCharEntity(125, result);
|
||||
} else if (character == '~') {
|
||||
addCharEntity(126, result);
|
||||
} else {
|
||||
// the char is not a special one
|
||||
// add it to the result as is
|
||||
result.append(character);
|
||||
}
|
||||
character = iterator.next();
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape all ampersand characters in a URL.
|
||||
*
|
||||
* <P>
|
||||
* Replaces all <tt>'&'</tt> characters with <tt>'&'</tt>.
|
||||
*
|
||||
* <P>
|
||||
* An ampersand character may appear in the query string of a URL. The
|
||||
* ampersand character is indeed valid in a URL.
|
||||
* <em>However, URLs usually appear as an <tt>HREF</tt> attribute, and such
|
||||
* attributes have the additional constraint that ampersands must be
|
||||
* escaped.</em>
|
||||
*
|
||||
* <P>
|
||||
* The JSTL <c:url> tag does indeed perform proper URL encoding of query
|
||||
* parameters. But it does not, in general, produce text which is valid as
|
||||
* an <tt>HREF</tt> attribute, simply because it does not escape the
|
||||
* ampersand character. This is a nuisance when multiple query parameters
|
||||
* appear in the URL, since it requires a little extra work.
|
||||
*/
|
||||
public static String forHrefAmpersand(String aURL) {
|
||||
return aURL.replace("&", "&");
|
||||
}
|
||||
|
||||
public static String forQuerySpace(String aURL) {
|
||||
return aURL.replace(" ", "\u0020");
|
||||
}
|
||||
/**
|
||||
* Synonym for <tt>URLEncoder.encode(String, "UTF-8")</tt>.
|
||||
*
|
||||
* <P>
|
||||
* Used to ensure that HTTP query strings are in proper form, by escaping
|
||||
* special characters such as spaces.
|
||||
*
|
||||
* <P>
|
||||
* It is important to note that if a query string appears in an
|
||||
* <tt>HREF</tt> attribute, then there are two issues - ensuring the query
|
||||
* string is valid HTTP (it is URL-encoded), and ensuring it is valid HTML
|
||||
* (ensuring the ampersand is escaped).
|
||||
*/
|
||||
public static String forURL(String aURLFragment) {
|
||||
String result = null;
|
||||
try {
|
||||
result = URLEncoder.encode(aURLFragment, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
throw new RuntimeException("UTF-8 not supported", ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void addCharEntity(Integer aIdx, StringBuilder aBuilder) {
|
||||
String padding = "";
|
||||
if (aIdx <= 9) {
|
||||
padding = "00";
|
||||
} else if (aIdx <= 99) {
|
||||
padding = "0";
|
||||
} else {
|
||||
// no prefix
|
||||
}
|
||||
String number = padding + aIdx.toString();
|
||||
aBuilder.append("&#" + number + ";");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bwssystems.vera;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
@@ -101,7 +102,7 @@ public class VeraInfo {
|
||||
HttpResponse response = httpClient.execute(httpGet);
|
||||
log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode());
|
||||
if(response.getStatusLine().getStatusCode() == 200){
|
||||
theContent = EntityUtils.toString(response.getEntity()); //read content for data
|
||||
theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data
|
||||
EntityUtils.consume(response.getEntity()); //close out inputstream ignore content
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -47,27 +47,25 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
this.state = {base: window.location.origin + "/api/devices", bridgelocation: window.location.origin, systemsbase: window.location.origin + "/system", huebase: window.location.origin + "/api", configs: [], backups: [], devices: [], device: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, habridgeversion: ""};
|
||||
|
||||
this.displayWarn = function(errorTitle, error) {
|
||||
if(error == null || typeof(error) != 'undefined') {
|
||||
error = {status: 200, statusText: "OK", data: []};
|
||||
error.data = {message: "success"};
|
||||
}
|
||||
var toastContent = errorTitle;
|
||||
if(error != null && typeof(error) != 'undefined')
|
||||
toastContent = toastContent + " " + error.data.message + " with status: " + error.statusText + " - " + error.status;
|
||||
ngToast.create({
|
||||
className: "warning",
|
||||
dismissButton: true,
|
||||
dismissOnTimeout: false,
|
||||
content: errorTitle + error.data.message + " with status: " + error.statusText + " - " + error.status});
|
||||
content: toastContent});
|
||||
};
|
||||
|
||||
this.displayError = function(errorTitle, error) {
|
||||
if(error == null || typeof(error) != 'undefined') {
|
||||
error = {status: 200, statusText: "OK", data: []};
|
||||
error.data = {message: "success"};
|
||||
}
|
||||
var toastContent = errorTitle;
|
||||
if(error != null && typeof(error) != 'undefined')
|
||||
toastContent = toastContent + " " + error.data.message + " with status: " + error.statusText + " - " + error.status;
|
||||
ngToast.create({
|
||||
className: "danger",
|
||||
dismissButton: true,
|
||||
dismissOnTimeout: false,
|
||||
content: errorTitle + error.data.message + " with status: " + error.statusText + " - " + error.status});
|
||||
content: toastContent});
|
||||
};
|
||||
|
||||
this.displayErrorMessage = function(errorTitle, errorMessage) {
|
||||
@@ -101,6 +99,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
self.state.device.mapId = null;
|
||||
self.state.device.name = "";
|
||||
self.state.device.onUrl = "";
|
||||
self.state.device.dimUrl = "";
|
||||
self.state.device.deviceType = "custom";
|
||||
self.state.device.targetDevice = null;
|
||||
self.state.device.offUrl = "";
|
||||
@@ -108,7 +107,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
self.state.device.contentType = null;
|
||||
self.state.device.contentBody = null;
|
||||
self.state.device.contentBodyOff = null;
|
||||
self.state.bridge.olddevicename = "";
|
||||
self.state.olddevicename = "";
|
||||
};
|
||||
|
||||
this.getHABridgeVersion = function () {
|
||||
@@ -303,27 +302,16 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
);
|
||||
};
|
||||
|
||||
this.addDevice = function (device) {
|
||||
this.addDevice = function (aDevice) {
|
||||
var device = {};
|
||||
angular.extend(device, aDevice );
|
||||
if(device.httpVerb != null && device.httpVerb != "")
|
||||
device.deviceType = "custom";
|
||||
if(device.targetDevice == null || device.targetDevice == "")
|
||||
device.targetDevice = "Encapsulated";
|
||||
if (device.id) {
|
||||
var putUrl = this.state.base + "/" + device.id;
|
||||
return $http.put(putUrl, {
|
||||
id: device.id,
|
||||
name: device.name,
|
||||
mapId: device.mapId,
|
||||
mapType: device.mapType,
|
||||
deviceType: device.deviceType,
|
||||
targetDevice: device.targetDevice,
|
||||
onUrl: device.onUrl,
|
||||
offUrl: device.offUrl,
|
||||
httpVerb: device.httpVerb,
|
||||
contentType: device.contentType,
|
||||
contentBody: device.contentBody,
|
||||
contentBodyOff: device.contentBodyOff
|
||||
}).then(
|
||||
return $http.put(putUrl, device).then(
|
||||
function (response) {
|
||||
},
|
||||
function (error) {
|
||||
@@ -333,19 +321,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
} else {
|
||||
if(device.deviceType == null || device.deviceType == "")
|
||||
device.deviceType = "custom";
|
||||
return $http.post(this.state.base, {
|
||||
name: device.name,
|
||||
mapId: device.mapId,
|
||||
mapType: device.mapType,
|
||||
deviceType: device.deviceType,
|
||||
targetDevice: device.targetDevice,
|
||||
onUrl: device.onUrl,
|
||||
offUrl: device.offUrl,
|
||||
httpVerb: device.httpVerb,
|
||||
contentType: device.contentType,
|
||||
contentBody: device.contentBody,
|
||||
contentBodyOff: device.contentBodyOff
|
||||
}).then(
|
||||
return $http.post(this.state.base, device).then(
|
||||
function (response) {
|
||||
},
|
||||
function (error) {
|
||||
@@ -474,6 +450,7 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
filename: afilename
|
||||
}).then(
|
||||
function (response) {
|
||||
self.state.settings = response.data;
|
||||
self.viewConfigs();
|
||||
self.viewDevices();
|
||||
},
|
||||
@@ -523,11 +500,11 @@ app.service('bridgeService', function ($http, $window, ngToast) {
|
||||
var msgDescription = "unknown";
|
||||
var testUrl = this.state.huebase + "/test/lights/" + device.id + "/state";
|
||||
var testBody = "{\"on\":";
|
||||
if(type == "on") {
|
||||
testBody = testBody + "true";
|
||||
if(type == "off") {
|
||||
testBody = testBody + "false";
|
||||
}
|
||||
else {
|
||||
testBody = testBody + "false";
|
||||
testBody = testBody + "true";
|
||||
}
|
||||
if(value) {
|
||||
testBody = testBody + ",\"bri\":" + value;
|
||||
@@ -683,12 +660,15 @@ app.controller('ViewingController', function ($scope, $location, $http, $window,
|
||||
$scope.imgBkUrl = "glyphicon glyphicon-plus";
|
||||
$scope.testUrl = function (device, type) {
|
||||
var dialogNeeded = false;
|
||||
if((type == "on" && (bridgeService.aContainsB(device.onUrl, "${intensity..byte}") ||
|
||||
if((type == "on" && (bridgeService.aContainsB(device.onUrl, "${intensity.byte}") ||
|
||||
bridgeService.aContainsB(device.onUrl, "${intensity.percent}") ||
|
||||
bridgeService.aContainsB(device.onUrl, "${intensity.math("))) ||
|
||||
(type == "off" && (bridgeService.aContainsB(device.offUrl, "${intensity..byte}") ||
|
||||
(type == "off" && (bridgeService.aContainsB(device.offUrl, "${intensity.byte}") ||
|
||||
bridgeService.aContainsB(device.offUrl, "${intensity.percent}") ||
|
||||
bridgeService.aContainsB(device.offUrl, "${intensity.math(")))) {
|
||||
bridgeService.aContainsB(device.offUrl, "${intensity.math("))) ||
|
||||
(type == "dim" && (bridgeService.aContainsB(device.dimUrl, "${intensity.byte}") ||
|
||||
bridgeService.aContainsB(device.dimUrl, "${intensity.percent}") ||
|
||||
bridgeService.aContainsB(device.dimUrl, "${intensity.math(")))) {
|
||||
$scope.bridge.device = device;
|
||||
$scope.bridge.type = type;
|
||||
ngDialog.open({
|
||||
@@ -786,27 +766,32 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildDeviceUrls = function (veradevice, dim_control) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "switch";
|
||||
$scope.device.name = veradevice.name;
|
||||
$scope.device.targetDevice = veradevice.veraname;
|
||||
$scope.device.mapType = "veraDevice";
|
||||
$scope.device.mapId = veradevice.id;
|
||||
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
|
||||
$scope.device.onUrl = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
||||
$scope.device.dimUrl = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&DeviceNum="
|
||||
+ veradevice.id
|
||||
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
|
||||
+ dim_control;
|
||||
else
|
||||
$scope.device.onUrl = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
||||
$scope.device.dimUrl = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
||||
+ veradevice.id;
|
||||
$scope.device.onUrl = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
||||
+ veradevice.id;
|
||||
$scope.device.offUrl = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
|
||||
+ veradevice.id;
|
||||
};
|
||||
|
||||
$scope.buildSceneUrls = function (verascene) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "scene";
|
||||
$scope.device.name = verascene.name;
|
||||
$scope.device.targetDevice = verascene.veraname;
|
||||
@@ -831,6 +816,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
|
||||
bridgeService.viewVeraScenes();
|
||||
},
|
||||
function (error) {
|
||||
bridgeService.displayWarn("Error adding device: " + $scope.device.name, error)
|
||||
}
|
||||
);
|
||||
|
||||
@@ -910,6 +896,7 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
|
||||
};
|
||||
|
||||
$scope.buildActivityUrls = function (harmonyactivity) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "activity";
|
||||
$scope.device.targetDevice = harmonyactivity.hub;
|
||||
$scope.device.name = harmonyactivity.activity.label;
|
||||
@@ -920,6 +907,7 @@ app.controller('HarmonyController', function ($scope, $location, $http, bridgeSe
|
||||
};
|
||||
|
||||
$scope.buildButtonUrls = function (harmonydevice, onbutton, offbutton) {
|
||||
bridgeService.clearDevice();
|
||||
var currentOn = $scope.device.onUrl;
|
||||
var currentOff = $scope.device.offUrl;
|
||||
var actionOn = angular.fromJson(onbutton);
|
||||
@@ -984,6 +972,7 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildNestHomeUrls = function (nestitem) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "home";
|
||||
$scope.device.name = nestitem.name;
|
||||
$scope.device.targetDevice = nestitem.name;
|
||||
@@ -994,16 +983,18 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildNestTempUrls = function (nestitem) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Temperature";
|
||||
$scope.device.targetDevice = nestitem.location;
|
||||
$scope.device.mapType = "nestThermoSet";
|
||||
$scope.device.mapId = nestitem.id + "-SetTemp";
|
||||
$scope.device.onUrl = "{\"name\":\"" + nestitem.id + "\",\"control\":\"temp\",\"temp\":\"${intensity.percent}\"}";
|
||||
$scope.device.offUrl = "{\"name\":\"" + nestitem.id + "\",\"control\":\"temp\",\"temp\":\"${intensity.percent}\"}";
|
||||
$scope.device.dimUrl = "{\"name\":\"" + nestitem.id + "\",\"control\":\"temp\",\"temp\":\"${intensity.percent}\"}";
|
||||
$scope.device.offUrl = "{\"name\":\"" + nestitem.id + "\",\"control\":\"off\"}";
|
||||
};
|
||||
|
||||
$scope.buildNestHeatUrls = function (nestitem) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Heat";
|
||||
$scope.device.targetDevice = nestitem.location;
|
||||
@@ -1014,6 +1005,7 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildNestCoolUrls = function (nestitem) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Cool";
|
||||
$scope.device.targetDevice = nestitem.location;
|
||||
@@ -1024,6 +1016,7 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildNestRangeUrls = function (nestitem) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Range";
|
||||
$scope.device.targetDevice = nestitem.location;
|
||||
@@ -1034,6 +1027,7 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildNestOffUrls = function (nestitem) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Thermostat";
|
||||
$scope.device.targetDevice = nestitem.location;
|
||||
@@ -1044,6 +1038,7 @@ app.controller('NestController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildNestFanUrls = function (nestitem) {
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "thermo";
|
||||
$scope.device.name = nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Fan";
|
||||
$scope.device.targetDevice = nestitem.location;
|
||||
@@ -1090,7 +1085,7 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
|
||||
$scope.device_dim_control = "";
|
||||
$scope.bulk = { devices: [] };
|
||||
var veraList = angular.fromJson($scope.bridge.settings.veraaddress);
|
||||
if(veraList != null)
|
||||
if(veraList != null && veraList.devices.length > 0)
|
||||
$scope.vera = {base: "http://" + veraList.devices[0].ip, port: "3480", id: ""};
|
||||
else
|
||||
$scope.vera = {base: "http://", port: "3480", id: ""};
|
||||
@@ -1102,32 +1097,31 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
|
||||
};
|
||||
|
||||
$scope.buildUrlsUsingDevice = function (dim_control) {
|
||||
if ($scope.vera.base.indexOf("http") < 0) {
|
||||
$scope.vera.base = "http://" + $scope.vera.base;
|
||||
}
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "switch";
|
||||
$scope.device.targetDevice = "Encapsulated";
|
||||
$scope.device.mapType = "veraDevice";
|
||||
$scope.device.mapId = $scope.vera.id;
|
||||
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
$scope.device.dimUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&DeviceNum="
|
||||
+ $scope.vera.id
|
||||
+ "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget="
|
||||
+ dim_control;
|
||||
else
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
$scope.device.dimUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
||||
+ $scope.vera.id;
|
||||
$scope.device.onUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
|
||||
+ $scope.vera.id;
|
||||
$scope.device.offUrl = $scope.vera.base + ":" + $scope.vera.port
|
||||
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
|
||||
+ $scope.vera.id;
|
||||
};
|
||||
|
||||
$scope.buildUrlsUsingScene = function () {
|
||||
if ($scope.vera.base.indexOf("http") < 0) {
|
||||
$scope.vera.base = "http://" + $scope.vera.base;
|
||||
}
|
||||
bridgeService.clearDevice();
|
||||
$scope.device.deviceType = "scene";
|
||||
$scope.device.targetDevice = "Encapsulated";
|
||||
$scope.device.mapType = "veraScene";
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
<p>
|
||||
<button class="btn btn-info" type="submit"
|
||||
ng-click="testUrl(device, 'on')">Test ON</button>
|
||||
<button class="btn btn-info" type="submit"
|
||||
ng-click="testUrl(device, 'dim')">Test Dim</button>
|
||||
<button class="btn btn-info" type="submit"
|
||||
ng-click="testUrl(device, 'off')">Test OFF</button>
|
||||
<button class="btn btn-warning" type="submit"
|
||||
|
||||
@@ -83,6 +83,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
|
||||
@@ -107,6 +107,17 @@
|
||||
Clear Device</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
|
||||
@@ -173,6 +173,11 @@
|
||||
<td><input type="checkbox" ng-model="bridge.settings.traceupnp"
|
||||
ng-true-value=true ng-false-value=false> {{bridge.settings.traceupnp}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Nest Temp Farenheit</td>
|
||||
<td><input type="checkbox" ng-model="bridge.settings.farenheit"
|
||||
ng-true-value=true ng-false-value=false> {{bridge.settings.farenheit}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -130,6 +130,17 @@
|
||||
<button class="btn btn-danger" ng-click="clearDevice()">
|
||||
Clear Device</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label" for="device-dim-url">Dim
|
||||
URL </label>
|
||||
|
||||
<div class="col-xs-8 col-sm-7">
|
||||
<textarea rows="3" class="form-control" id="device-dim-url"
|
||||
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label class="col-xs-12 col-sm-2 control-label"
|
||||
|
||||
Reference in New Issue
Block a user