Merge pull request #712 from FloFoer/FeaturesfFor5.0

Room and basic color support, group additions and some minor stuff
This commit is contained in:
BWS Systems
2017-08-01 16:25:54 -05:00
committed by GitHub
39 changed files with 1746 additions and 258 deletions

2
.gitignore vendored
View File

@@ -12,3 +12,5 @@ data
/.settings/
/start.bat
/.classpath
sftp-config\.json

View File

@@ -90,6 +90,7 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setServerPort(System.getProperty("server.port", Configuration.DEFAULT_WEB_PORT));
theBridgeSettings.setUpnpConfigAddress(System.getProperty("upnp.config.address"));
theBridgeSettings.setUpnpDeviceDb(System.getProperty("upnp.device.db"));
theBridgeSettings.setUpnpGroupDb(System.getProperty("upnp.group.db"));
theBridgeSettings.setUpnpResponsePort(System.getProperty("upnp.response.port", Configuration.UPNP_RESPONSE_PORT));
theVeraAddress = System.getProperty("vera.address");
@@ -170,6 +171,9 @@ public class BridgeSettings extends BackupHandler {
if(theBridgeSettings.getUpnpDeviceDb() == null)
theBridgeSettings.setUpnpDeviceDb(Configuration.DEVICE_DB_DIRECTORY);
if(theBridgeSettings.getUpnpGroupDb() == null)
theBridgeSettings.setUpnpGroupDb(Configuration.GROUP_DB_DIRECTORY);
if(theBridgeSettings.getNumberoflogmessages() == null || theBridgeSettings.getNumberoflogmessages() <= 0)
theBridgeSettings.setNumberoflogmessages(new Integer(Configuration.NUMBER_OF_LOG_MESSAGES));

View File

@@ -24,6 +24,9 @@ public class BridgeSettingsDescriptor {
@SerializedName("upnpdevicedb")
@Expose
private String upnpdevicedb;
@SerializedName("upnpgroupdb")
@Expose
private String upnpgroupdb;
@SerializedName("veraaddress")
@Expose
private IpList veraaddress;
@@ -163,6 +166,12 @@ public class BridgeSettingsDescriptor {
public void setUpnpDeviceDb(String upnpDeviceDb) {
this.upnpdevicedb = upnpDeviceDb;
}
public String getUpnpGroupDb() {
return upnpgroupdb;
}
public void setUpnpGroupDb(String upnpGroupDb) {
this.upnpgroupdb = upnpGroupDb;
}
public IpList getVeraAddress() {
return veraaddress;
}

View File

@@ -2,6 +2,7 @@ package com.bwssystems.HABridge;
public class Configuration {
public final static String DEVICE_DB_DIRECTORY = "data/device.db";
public final static String GROUP_DB_DIRECTORY = "data/group.db";
public final static String UPNP_RESPONSE_PORT = "50000";
public final static String DEFAULT_ADDRESS = "1.1.1.1";
public final static String LOOP_BACK_ADDRESS = "127.0.0.1";

View File

@@ -76,7 +76,7 @@ public class HABridge {
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
theSettingResponder.setupServer();
// setup the class to handle the hue emulator rest api
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), homeManager);
theHueMulator = new HueMulator(bridgeSettings, theResources.getDeviceRepository(), theResources.getGroupRepository(), homeManager);
theHueMulator.setupServer();
// wait for the sparkjava initialization of the rest api classes to be complete
awaitInitialization();

View File

@@ -1,6 +1,7 @@
package com.bwssystems.HABridge.api.hue;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.GroupDescriptor;
/**
* Created by arm on 4/14/15.
@@ -14,6 +15,8 @@ public class DeviceResponse {
private String luminaireuniqueid;
private String uniqueid;
private String swversion;
private String swconfigid;
private String productid;
public DeviceState getState() {
return state;
@@ -71,6 +74,23 @@ public class DeviceResponse {
this.swversion = swversion;
}
public String getSwconfigid() {
return swconfigid;
}
public void setSwconfigid(String swconfigid) {
this.swconfigid = swconfigid;
}
public String getProductid() {
return productid;
}
public void setProductid(String productid) {
this.productid = productid;
}
public String getLuminaireuniqueid() {
return luminaireuniqueid;
}
@@ -85,12 +105,49 @@ public class DeviceResponse {
response.setName(device.getName());
response.setUniqueid(device.getUniqueid());
response.setManufacturername("Philips");
response.setType("Dimmable light");
response.setModelid("LWB004");
response.setSwversion("66012040");
//if (device.getColorUrl() == null || device.getColorUrl().trim().equals("")) {
// if (device.getDimUrl() == null || device.getDimUrl().trim().equals("")) {
// response.setType("On/Off light");
// response.setModelid("Plug - LIGHTIFY");
// response.setManufacturername("OSRAM");
// response.setSwversion("V1.04.12");
// } else {
// response.setManufacturername("Philips");
// response.setType("Dimmable light");
// response.setModelid("LWB007");
// response.setSwversion("66012040");
// }
//} else {
response.setManufacturername("Philips");
response.setType("Extended color light");
response.setModelid("LCT010");
response.setSwversion("1.15.2_r19181");
response.setSwconfigid("F921C859");
response.setProductid("Philips-LCT010-1-A19ECLv4");
//}
response.setLuminaireuniqueid(null);
return response;
}
public static DeviceResponse createResponseForVirtualLight(GroupDescriptor group){
DeviceResponse response = new DeviceResponse();
response.setState(group.getAction());
response.setName(group.getName());
response.setUniqueid("00:17:88:5E:D3:FF-" + String.format("%02X", Integer.parseInt(group.getId())));
response.setManufacturername("Philips");
response.setType("Extended color light");
response.setModelid("LCT010");
response.setSwversion("1.15.2_r19181");
response.setSwconfigid("F921C859");
response.setProductid("Philips-LCT010-1-A19ECLv4");
response.setLuminaireuniqueid(null);
return response;
}
}

View File

@@ -1,6 +1,6 @@
package com.bwssystems.HABridge.api.hue;
// import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
/**
@@ -12,11 +12,12 @@ public class DeviceState {
private int hue;
private int sat;
private String effect;
private List<Double> xy;
private int ct;
private String alert;
private String colormode;
private boolean reachable;
private List<Double> xy;
// private int transitiontime;
public boolean isOn() {
@@ -41,6 +42,7 @@ public class DeviceState {
public void setHue(int hue) {
this.hue = hue;
this.colormode = "hs";
}
public int getSat() {
@@ -49,6 +51,7 @@ public class DeviceState {
public void setSat(int sat) {
this.sat = sat;
this.colormode = "hs";
}
public String getEffect() {
@@ -65,6 +68,7 @@ public class DeviceState {
public void setCt(int ct) {
this.ct = ct;
this.colormode = "ct";
}
public String getAlert() {
@@ -97,6 +101,7 @@ public class DeviceState {
public void setXy(List<Double> xy) {
this.xy = xy;
this.colormode = "xy";
}
// public int getTransitiontime() {
// return transitiontime;
@@ -109,11 +114,12 @@ public class DeviceState {
public static DeviceState createDeviceState() {
DeviceState newDeviceState = new DeviceState();
newDeviceState.fillIn();
// newDeviceState.setColormode("none");
// ArrayList<Double> doubleArray = new ArrayList<Double>();
// doubleArray.add(new Double(0));
// doubleArray.add(new Double(0));
// newDeviceState.setXy(doubleArray);
newDeviceState.setColormode("ct");
newDeviceState.setCt(200);
ArrayList<Double> doubleArray = new ArrayList<Double>();
doubleArray.add(new Double(0));
doubleArray.add(new Double(0));
newDeviceState.setXy(doubleArray);
return newDeviceState;
}

View File

@@ -0,0 +1,61 @@
package com.bwssystems.HABridge.api.hue;
import java.util.ArrayList;
public class GroupClassTypes {
public final static String BATHROOM = "Bathroom";
public final static String BEDROOM = "Bedroom";
public final static String CARPORT = "Carport";
public final static String DINING = "Dining";
public final static String DRIVEWAY = "Driveway";
public final static String FRONT_DOOR = "Front door";
public final static String GARAGE = "Garage";
public final static String GARDEN = "Garden";
public final static String GYM = "Gym";
public final static String HALLWAY = "Hallway";
public final static String BEDROOM_KIDS = "Kids bedroom";
public final static String KITCHEN = "Kitchen";
public final static String LIVING_ROOM = "Living room";
public final static String NURSERY = "Nursery";
public final static String OFFICE = "Office";
public final static String OTHER = "Other";
public final static String RECREATION = "Recreation";
public final static String TERRACE = "Terrace";
public final static String TOILET = "Toilet";
ArrayList<String> groupClassTypes;
public GroupClassTypes() {
groupClassTypes = new ArrayList<String>();
groupClassTypes.add(BATHROOM);
groupClassTypes.add(BEDROOM);
groupClassTypes.add(CARPORT);
groupClassTypes.add(DINING);
groupClassTypes.add(DRIVEWAY);
groupClassTypes.add(FRONT_DOOR);
groupClassTypes.add(GARAGE);
groupClassTypes.add(GARDEN);
groupClassTypes.add(GYM);
groupClassTypes.add(HALLWAY);
groupClassTypes.add(BEDROOM_KIDS);
groupClassTypes.add(KITCHEN);
groupClassTypes.add(LIVING_ROOM);
groupClassTypes.add(NURSERY);
groupClassTypes.add(OFFICE);
groupClassTypes.add(OTHER);
groupClassTypes.add(RECREATION);
groupClassTypes.add(TERRACE);
groupClassTypes.add(TOILET);
}
public Boolean validateType(String type) {
if(type == null || type.trim().isEmpty())
return false;
for(String classType : groupClassTypes) {
if(type.trim().contentEquals(classType))
return true;
}
return false;
}
}

View File

@@ -1,8 +1,13 @@
package com.bwssystems.HABridge.api.hue;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.GroupDescriptor;
import com.google.gson.annotations.SerializedName;
public class GroupResponse {
@@ -16,6 +21,8 @@ public class GroupResponse {
private String type;
@SerializedName("class")
String class_name;
@SerializedName("state")
private GroupState state;
public DeviceState getAction() {
return action;
@@ -23,6 +30,14 @@ public class GroupResponse {
public void setAction(DeviceState action) {
this.action = action;
}
public GroupState getState() {
return state;
}
public void setState(GroupState state) {
this.state = state;
}
public String[] getLights() {
return lights;
}
@@ -48,34 +63,69 @@ public class GroupResponse {
public void setClass_name(String class_name) {
this.class_name = class_name;
}
public static GroupResponse createDefaultGroupResponse(List<DeviceDescriptor> deviceList) {
String[] theList = new String[deviceList.size()];
int i = 0;
for (DeviceDescriptor device : deviceList) {
theList[i] = device.getId();
i++;
}
GroupResponse theResponse = new GroupResponse();
theResponse.setAction(DeviceState.createDeviceState());
theResponse.setName("Lightset 0");
theResponse.setLights(theList);
theResponse.setType("LightGroup");
return theResponse;
}
public static GroupResponse createOtherGroupResponse(List<DeviceDescriptor> deviceList) {
String[] theList = new String[deviceList.size()];
int i = 0;
for (DeviceDescriptor device : deviceList) {
theList[i] = device.getId();
i++;
}
GroupResponse theResponse = new GroupResponse();
theResponse.setAction(DeviceState.createDeviceState());
theResponse.setName("AGroup");
theResponse.setLights(theList);
theResponse.setType("Room");
theResponse.setClass_name("Other");
public static GroupResponse createDefaultGroupResponse(Map<String, DeviceResponse> deviceList) {
String[] theList = new String[deviceList.size()];
Boolean all_on = true;
Boolean any_on = false;
int i = 0;
for (Map.Entry<String, DeviceResponse> device : deviceList.entrySet()) {
if (Integer.parseInt(device.getKey()) >= 10000) { // don't show fake lights for other groups
continue;
}
theList[i] = device.getKey();
Boolean is_on = device.getValue().getState().isOn();
if (is_on)
any_on = true;
else
all_on = false;
i++;
}
GroupResponse theResponse = new GroupResponse();
theResponse.setAction(DeviceState.createDeviceState());
theResponse.setState(new GroupState(all_on, any_on));
theResponse.setName("Group 0");
theResponse.setLights(theList);
theResponse.setType("LightGroup");
return theResponse;
}
return theResponse;
}
public static GroupResponse createResponse(GroupDescriptor group, Map<String, DeviceResponse> lights){
GroupResponse response = new GroupResponse();
Boolean all_on = true;
Boolean any_on = false;
String[] groupLights = null;
if (lights == null) {
all_on = false;
groupLights = group.getLights();
} else {
for (DeviceResponse light : lights.values()) {
Boolean is_on = light.getState().isOn();
if (is_on)
any_on = true;
else
all_on = false;
}
// group.getLights() is not filtered by requester, lights is
// we want the filtered version but keep the order from group.getLights()
groupLights = new String[lights.size()];
int i = 0;
for (String light : group.getLights()) {
if (lights.keySet().contains(light)) {
groupLights[i] = light;
i++;
}
}
}
response.setState(new GroupState(all_on, any_on));
response.setAction(group.getAction());
response.setName(group.getName());
response.setType(group.getGroupType());
response.setLights(groupLights);
response.setClass_name(group.getGroupClass());
return response;
}
}

View File

@@ -0,0 +1,38 @@
package com.bwssystems.HABridge.api.hue;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Florian Foerderreuther on 07/23/17
*/
public class GroupState {
private boolean all_on;
private boolean any_on;
public boolean isAllOn() {
return all_on;
}
public boolean isAnyOn() {
return any_on;
}
public void setState(boolean all_on, boolean any_on) {
this.all_on = all_on;
this.any_on = any_on;
}
public GroupState(boolean all_on, boolean any_on) {
this.all_on = all_on;
this.any_on = any_on;
}
@Override
public String toString() {
return "GroupState{" +
"all_on=" + all_on +
", any_on=" + any_on +
'}';
}
}

View File

@@ -38,6 +38,9 @@ public class DeviceDescriptor{
@SerializedName("onUrl")
@Expose
private String onUrl;
@SerializedName("colorUrl")
@Expose
private String colorUrl;
@SerializedName("headers")
@Expose
private String headers;
@@ -142,6 +145,14 @@ public class DeviceDescriptor{
this.onUrl = onUrl;
}
public String getColorUrl() {
return colorUrl;
}
public void setColorUrl(String colorUrl) {
this.colorUrl = colorUrl;
}
public String getId() {
return id;
}
@@ -282,6 +293,9 @@ public class DeviceDescriptor{
if(this.offUrl != null && this.offUrl.contains(aType))
return true;
if(this.colorUrl != null && this.colorUrl.contains(aType))
return true;
return false;
}

View File

@@ -18,13 +18,21 @@ import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.api.hue.DeviceResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.plugins.hue.HueHome;
import com.bwssystems.HABridge.util.BackupHandler;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import java.util.Collection;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
/*
* 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.
@@ -86,6 +94,10 @@ public class DeviceRepository extends BackupHandler {
public List<DeviceDescriptor> findAllByRequester(String anAddress) {
List<DeviceDescriptor> list = new ArrayList<DeviceDescriptor>(devices.values());
return findAllByRequester(anAddress, list);
}
private List<DeviceDescriptor> findAllByRequester(String anAddress, Collection<DeviceDescriptor> list) {
List<DeviceDescriptor> theReturnList = new ArrayList<DeviceDescriptor>();
Iterator<DeviceDescriptor> anIterator = list.iterator();
DeviceDescriptor theDevice;
@@ -111,6 +123,45 @@ public class DeviceRepository extends BackupHandler {
return theReturnList;
}
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder) {
return findAllByGroupWithState(lightsInGroup, anAddress, myHueHome, aGsonBuilder, false);
}
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder, boolean ignoreAddress) {
Map<String, DeviceResponse> deviceResponseMap = new HashMap<String, DeviceResponse>();
Map<String, DeviceDescriptor> lights = new HashMap<String, DeviceDescriptor>(devices);
lights.keySet().retainAll(Arrays.asList(lightsInGroup));
for (DeviceDescriptor light : (ignoreAddress ? lights.values() : findAllByRequester(anAddress, lights.values()))) {
DeviceResponse deviceResponse = null;
if(!light.isInactive()) {
if (light.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
CallItem[] callItems = null;
try {
if(light.getOnUrl() != null)
callItems = aGsonBuilder.fromJson(light.getOnUrl(), CallItem[].class);
} catch(JsonSyntaxException e) {
log.warn("Could not decode Json for url items to get Hue state for device: " + light.getName());
callItems = null;
}
for (int i = 0; callItems != null && i < callItems.length; i++) {
if((callItems[i].getType() != null && callItems[i].getType().equals(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) ||
(callItems[i].getItem() != null && callItems[i].getItem().getAsString() != null && callItems[i].getItem().getAsString().contains("hueName"))) {
deviceResponse = myHueHome.getHueDeviceInfo(callItems[i], light);
i = callItems.length;
}
}
}
if (deviceResponse == null) {
deviceResponse = DeviceResponse.createResponse(light);
}
deviceResponseMap.put(light.getId(), deviceResponse);
}
}
return (deviceResponseMap.size() == 0) ? null : deviceResponseMap;
}
public DeviceDescriptor findOne(String id) {
return devices.get(id);
}

View File

@@ -0,0 +1,148 @@
package com.bwssystems.HABridge.dao;
import com.bwssystems.HABridge.api.hue.DeviceState;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.bwssystems.HABridge.api.hue.GroupState;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
/*
* Object to handle the device configuration
*/
public class GroupDescriptor{
@SerializedName("id")
@Expose
private String id;
@SerializedName("name")
@Expose
private String name;
@SerializedName("groupType")
@Expose
private String groupType;
@SerializedName("groupClass")
@Expose
private String groupClass;
@SerializedName("requesterAddress")
@Expose
private String requesterAddress;
@SerializedName("inactive")
@Expose
private boolean inactive;
@SerializedName("description")
@Expose
private String description;
@SerializedName("comments")
@Expose
private String comments;
private DeviceState action;
private GroupState groupState;
@SerializedName("lights")
@Expose
private String[] lights;
@SerializedName("exposeAsLight")
@Expose
private String exposeAsLight;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGroupType() {
return groupType;
}
public void setGroupType(String groupType) {
this.groupType = groupType;
}
public String getGroupClass() {
return groupClass;
}
public void setGroupClass(String groupClass) {
this.groupClass = groupClass;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public GroupState getGroupState() {
if(groupState == null)
groupState = new GroupState(false,false);
return groupState;
}
public void setGroupState(GroupState groupState) {
this.groupState = groupState;
}
public DeviceState getAction() {
if(action == null)
action = DeviceState.createDeviceState();
return action;
}
public void setAction(DeviceState action) {
this.action = action;
}
public boolean isInactive() {
return inactive;
}
public void setInactive(boolean inactive) {
this.inactive = inactive;
}
public String getRequesterAddress() {
return requesterAddress;
}
public void setRequesterAddress(String requesterAddress) {
this.requesterAddress = requesterAddress;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String[] getLights() {
return lights;
}
public void setLights(String[] lights) {
this.lights = lights;
}
public void setExposeAsLight(String exposeFor) {
this.exposeAsLight = exposeFor;
}
public String getExposeAsLight() {
return exposeAsLight;
}
}

View File

@@ -0,0 +1,223 @@
package com.bwssystems.HABridge.dao;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.dao.GroupDescriptor;
import com.bwssystems.HABridge.util.BackupHandler;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.List;
/*
* This is an in memory list to manage the configured groups and saves the list as a JSON string to a file for later
* loading.
*/
public class GroupRepository extends BackupHandler {
private Map<String, GroupDescriptor> groups;
private Path repositoryPath;
private Gson gson;
private Integer nextId;
private Logger log = LoggerFactory.getLogger(GroupRepository.class);
public GroupRepository(String groupDb) {
super();
gson =
new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
nextId = 0;
try {
repositoryPath = null;
repositoryPath = Paths.get(groupDb);
setupParams(repositoryPath, ".bk", "group.db-");
_loadRepository(repositoryPath);
} catch (Exception ex) {
groups = new HashMap<String, GroupDescriptor>();
}
}
public void loadRepository() {
if(repositoryPath != null)
_loadRepository(repositoryPath);
}
private void _loadRepository(Path aPath){
String jsonContent = repositoryReader(aPath);
groups = new HashMap<String, GroupDescriptor>();
if(jsonContent != null)
{
GroupDescriptor list[] = gson.fromJson(jsonContent, GroupDescriptor[].class);
for(int i = 0; i < list.length; i++) {
list[i].setGroupState(null);
put(list[i].getId(), list[i]);
if(Integer.decode(list[i].getId()) > nextId) {
nextId = Integer.decode(list[i].getId());
}
}
}
}
public List<GroupDescriptor> findAll() {
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>(groups.values());
return list;
}
public List<GroupDescriptor> findActive() {
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>();
for(GroupDescriptor aGroup : new ArrayList<GroupDescriptor>(groups.values())) {
if(!aGroup.isInactive())
list.add(aGroup);
}
return list;
}
public List<GroupDescriptor> findAllByRequester(String anAddress) {
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>(groups.values());
List<GroupDescriptor> theReturnList = new ArrayList<GroupDescriptor>();
Iterator<GroupDescriptor> anIterator = list.iterator();
GroupDescriptor theGroup;
String theRequesterAddress;
HashMap<String,String > addressMap;
while (anIterator.hasNext()) {
theGroup = anIterator.next();
theRequesterAddress = theGroup.getRequesterAddress();
addressMap = new HashMap<String, String>();
if(theRequesterAddress != null) {
if (theRequesterAddress.contains(",")) {
String[] theArray = theRequesterAddress.split(",");
for (String v : theArray) {
addressMap.put(v.trim(), v.trim());
}
} else
addressMap.put(theRequesterAddress, theRequesterAddress);
}
if (theRequesterAddress == null || theRequesterAddress.length() == 0 || addressMap.containsKey(anAddress))
theReturnList.add(theGroup);
}
return theReturnList;
}
public List<GroupDescriptor> findVirtualLights(String anAddress) {
List<GroupDescriptor> list = new ArrayList<GroupDescriptor>();
for (GroupDescriptor group : groups.values()) {
String expose = group.getExposeAsLight();
if (expose != null && expose.contains(anAddress)) {
list.add(group);
}
}
return list;
}
public GroupDescriptor findOne(String id) {
return groups.get(id);
}
private void put(String id, GroupDescriptor aDescriptor) {
groups.put(id, aDescriptor);
}
public void save() {
save(groups.values().toArray(new GroupDescriptor[0]));
}
public void save(GroupDescriptor[] descriptors) {
String theNames = "";
for(int i = 0; i < descriptors.length; i++) {
if(descriptors[i].getId() != null && descriptors[i].getId().length() > 0)
groups.remove(descriptors[i].getId());
else {
nextId++;
descriptors[i].setId(String.valueOf(nextId));
}
put(descriptors[i].getId(), descriptors[i]);
theNames = theNames + " " + descriptors[i].getName() + ", ";
}
String jsonValue = gson.toJson(findAll());
repositoryWriter(jsonValue, repositoryPath);
log.debug("Save group(s): " + theNames);
}
public Integer getNewId() {
return nextId + 1;
}
public String delete(GroupDescriptor aDescriptor) {
if (aDescriptor != null) {
groups.remove(aDescriptor.getId());
JsonTransformer aRenderer = new JsonTransformer();
String jsonValue = aRenderer.render(findAll());
repositoryWriter(jsonValue, repositoryPath);
return "Group with id '" + aDescriptor.getId() + "' deleted";
} else {
return "Group not found";
}
}
private void repositoryWriter(String content, Path filePath) {
if(Files.exists(filePath) && !Files.isWritable(filePath)){
log.error("Error file is not writable: " + filePath);
return;
}
if(Files.notExists(filePath.getParent())) {
try {
Files.createDirectories(filePath.getParent());
} catch (IOException e) {
log.error("Error creating the directory: " + filePath + " message: " + e.getMessage(), e);
}
}
try {
Path target = null;
if(Files.exists(filePath)) {
target = FileSystems.getDefault().getPath(filePath.getParent().toString(), "group.db.old");
Files.move(filePath, target);
}
Files.write(filePath, content.getBytes(), StandardOpenOption.CREATE);
if(target != null)
Files.delete(target);
} catch (IOException e) {
log.error("Error writing the file: " + filePath + " message: " + e.getMessage(), e);
}
}
private String repositoryReader(Path filePath) {
String content = null;
if(Files.notExists(filePath) || !Files.isReadable(filePath)){
log.warn("Error reading the file: " + filePath + " - Does not exist or is not readable. continuing...");
return null;
}
try {
content = new String(Files.readAllBytes(filePath));
} catch (IOException e) {
log.error("Error reading the file: " + filePath + " message: " + e.getMessage(), e);
}
return content;
}
}

View File

@@ -25,6 +25,8 @@ import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.BackupFilename;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.dao.DeviceRepository;
import com.bwssystems.HABridge.dao.GroupDescriptor;
import com.bwssystems.HABridge.dao.GroupRepository;
import com.bwssystems.HABridge.dao.ErrorMessage;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
@@ -38,6 +40,7 @@ public class DeviceResource {
private static final String API_CONTEXT = "/api/devices";
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
private DeviceRepository deviceRepository;
private GroupRepository groupRepository;
private HomeManager homeManager;
private BridgeSettings bridgeSettings;
private Gson aGsonHandler;
@@ -46,6 +49,7 @@ public class DeviceResource {
public DeviceResource(BridgeSettings theSettings, HomeManager aHomeManager) {
bridgeSettings = theSettings;
this.deviceRepository = new DeviceRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpDeviceDb());
this.groupRepository = new GroupRepository(bridgeSettings.getBridgeSettingsDescriptor().getUpnpGroupDb());
homeManager = aHomeManager;
aGsonHandler = new GsonBuilder().create();
setupEndpoints();
@@ -55,6 +59,10 @@ public class DeviceResource {
return deviceRepository;
}
public GroupRepository getGroupRepository() {
return groupRepository;
}
private void setupEndpoints() {
log.info("HABridge device management service started.... ");
before(API_CONTEXT + "/*", (request, response) -> {
@@ -122,6 +130,15 @@ public class DeviceResource {
log.debug(errorMessage);
return new ErrorMessage(errorMessage);
}
try {
if(devices[i].getColorUrl() != null && !devices[i].getColorUrl().isEmpty())
callItems = aGsonHandler.fromJson(devices[i].getColorUrl(), CallItem[].class);
} catch(JsonSyntaxException e) {
response.status(HttpStatus.SC_BAD_REQUEST);
errorMessage = "Bad color URL JSON in create device(s) for name: " + devices[i].getName() + " with color URL: " + devices[i].getColorUrl();
log.debug(errorMessage);
return new ErrorMessage(errorMessage);
}
}
deviceRepository.save(devices);

View File

@@ -0,0 +1,24 @@
package com.bwssystems.HABridge.hue;
import java.util.List;
public class ColorData {
public enum ColorMode { XY, CT, HS}
private ColorMode mode;
private Object data;
public ColorData(ColorMode mode, Object value) {
this.mode = mode;
this.data = value;
}
public Object getData() {
return data;
}
public ColorMode getColorMode() {
return mode;
}
}

View File

@@ -2,18 +2,24 @@ package com.bwssystems.HABridge.hue;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.hue.ColorData;
public class ColorDecode {
private static final Logger log = LoggerFactory.getLogger(ColorDecode.class);
private static final String COLOR_R = "${color.r}";
private static final String COLOR_G = "${color.g}";
private static final String COLOR_B = "${color.b}";
private static final Pattern COLOR_MILIGHT = Pattern.compile("\\$\\{color.milight\\:([01234])\\}");
public static List<Double> convertCIEtoRGB(List<Double> xy, int brightness) {
List<Double> rgb;
public static List<Integer> convertCIEtoRGB(List<Double> xy, int brightness) {
List<Integer> rgb;
double x = xy.get(0); // the given x value
double y = xy.get(1); // the given y value
double z = 1.0 - x - y;
@@ -80,42 +86,148 @@ public class ColorDecode {
if(b < 0.0)
b = 0;
rgb = new ArrayList<Double>();
rgb.add(0, r);
rgb.add(1, g);
rgb.add(2, b);
rgb.add(3, Math.round(r * 255));
rgb.add(4, Math.round(g * 255));
rgb.add(5, Math.round(b * 255));
rgb = new ArrayList<Integer>();
rgb.add((int)Math.round(r * 255));
rgb.add((int)Math.round(g * 255));
rgb.add((int)Math.round(b * 255));
log.debug("Color change with XY: " + x + " " + y + " Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
return rgb;
}
public static String replaceColorData(String request, List<Double> xy, int setIntensity) {
// took that approximation from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
public static List<Integer> convertCTtoRGB(Integer ct) {
double temperature = 1000000.0 / (double)ct;
temperature /= 100;
double r,g,b;
if (temperature <= 66) {
r = 255;
g = temperature;
g = 99.4708025861 * Math.log(g) - 161.1195681661;
} else {
r = temperature - 60;
r = 329.698727446 * (Math.pow(r, -0.1332047592));
g = temperature - 60;
g = 288.1221695283 * (Math.pow(g, -0.0755148492));
}
if (temperature >= 66) {
b = 255;
} else {
if (temperature <= 19) {
b = 0;
} else {
b = temperature - 10;
b = 138.5177312231 * Math.log(b) - 305.0447927307;
}
}
r = assureBounds(r);
g = assureBounds(g);
b = assureBounds(b);
List<Integer> rgb = new ArrayList<Integer>();
rgb.add((int)Math.round(r));
rgb.add((int)Math.round(g));
rgb.add((int)Math.round(b));
log.debug("Color change with CT: " + ct + ". Resulting RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
return rgb;
}
private static double assureBounds(double value) {
if (value < 0.0) {
value = 0;
}
if (value > 255.0) {
value = 255;
}
return value;
}
public static String replaceColorData(String request, ColorData colorData, int setIntensity, boolean isHex) {
if (request == null) {
return null;
}
if (colorData == null) {
return request;
}
boolean notDone = true;
List<Double> rgb = convertCIEtoRGB(xy, setIntensity);
ColorData.ColorMode colorMode = colorData.getColorMode();
List<Integer> rgb = null;
if (colorMode == ColorData.ColorMode.XY) {
rgb = convertCIEtoRGB((List<Double>)colorData.getData(), setIntensity);
} else if (colorMode == ColorData.ColorMode.CT) {
rgb = convertCTtoRGB((Integer)colorData.getData());
}
while(notDone) {
notDone = false;
if (request.contains(COLOR_R)) {
request = request.replace(COLOR_R, String.valueOf(rgb.get(0)));
request = request.replace(COLOR_R, isHex ? String.format("%02X", rgb.get(0)) : String.valueOf(rgb.get(0)));
notDone = true;
}
if (request.contains(COLOR_G)) {
request = request.replace(COLOR_G, String.valueOf(rgb.get(1)));
request = request.replace(COLOR_G, isHex ? String.format("%02X", rgb.get(1)) : String.valueOf(rgb.get(1)));
notDone = true;
}
if (request.contains(COLOR_B)) {
request = request.replace(COLOR_B, String.valueOf(rgb.get(2)));
request = request.replace(COLOR_B, isHex ? String.format("%02X", rgb.get(2)) : String.valueOf(rgb.get(2)));
notDone = true;
}
Matcher m = COLOR_MILIGHT.matcher(request);
while (m.find()) {
int group = Integer.parseInt(m.group(1));
request = m.replaceFirst(getMilightV5FromRgb(rgb, group));
m.reset(request);
}
log.debug("Request <<" + request + ">>, not done: " + notDone);
}
return request;
}
private static String getMilightV5FromRgb(List<Integer> rgb, int group) {
double r = (double)rgb.get(0);
double g = (double)rgb.get(1);
double b = (double)rgb.get(2);
if (r > 245 && g > 245 && b > 245) { // it's white
String retVal = "";
if (group == 0) {
retVal += "C2";
} else if (group == 1) {
retVal += "C5";
} else if (group == 2) {
retVal += "C7";
} else if (group == 3) {
retVal += "C9";
} else if (group == 4) {
retVal += "CB";
}
log.debug("Convert RGB to Milight. Result: WHITE. RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
return retVal + "0055";
} else { // normal color
r /= (double)0xFF;
g /= (double)0xFF;
b /= (double)0xFF;
double max = Math.max(Math.max(r, g), b), min = Math.min(Math.min(r, g), b);
double h = 0;
double d = max - min;
if (max == min) {
h = 0;
} else {
if (max == r) {
h = ((g - b) / d + (g < b ? 6 : 0));
} else if (max == g) {
h = ((b - r) / d + 2);
} else if (max == b){
h = ((r - g) / d + 4);
}
h = Math.round(h * 60);
}
int milight = (int)((256 + 176 - Math.floor(h / 360.0 * 255.0)) % 256);
log.debug("Convert RGB to Milight. Result: " + milight + " RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " " + rgb.get(2));
return "40" + String.format("%02X", milight) + "55";
}
}
}

View File

@@ -10,6 +10,7 @@ import com.bwssystems.HABridge.api.UserCreateRequest;
import com.bwssystems.HABridge.api.hue.DeviceResponse;
import com.bwssystems.HABridge.api.hue.DeviceState;
import com.bwssystems.HABridge.api.hue.GroupResponse;
import com.bwssystems.HABridge.api.hue.GroupClassTypes;
import com.bwssystems.HABridge.api.hue.HueApiResponse;
import com.bwssystems.HABridge.api.hue.HueConfig;
import com.bwssystems.HABridge.api.hue.HueError;
@@ -17,6 +18,7 @@ import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
import com.bwssystems.HABridge.api.hue.StateChangeBody;
import com.bwssystems.HABridge.dao.*;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.plugins.hue.HueHome;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
@@ -29,6 +31,7 @@ import static spark.Spark.halt;
import static spark.Spark.options;
import static spark.Spark.post;
import static spark.Spark.put;
import static spark.Spark.delete;
import org.apache.http.HttpStatus;
@@ -38,6 +41,7 @@ import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Arrays;
/**
* Based on Armzilla's HueMulator - a Philips Hue emulator using sparkjava rest server
@@ -48,6 +52,7 @@ public class HueMulator {
private static final String HUE_CONTEXT = "/api";
private DeviceRepository repository;
private GroupRepository groupRepository;
private HomeManager homeManager;
private HueHome myHueHome;
private BridgeSettingsDescriptor bridgeSettings;
@@ -55,8 +60,9 @@ public class HueMulator {
private Gson aGsonHandler;
private DeviceMapTypes validMapTypes;
public HueMulator(BridgeSettings bridgeMaster, DeviceRepository aDeviceRepository, HomeManager aHomeManager) {
public HueMulator(BridgeSettings bridgeMaster, DeviceRepository aDeviceRepository, GroupRepository aGroupRepository, HomeManager aHomeManager) {
repository = aDeviceRepository;
groupRepository = aGroupRepository;
validMapTypes = new DeviceMapTypes();
bridgeSettingMaster = bridgeMaster;
bridgeSettings = bridgeSettingMaster.getBridgeSettingsDescriptor();
@@ -70,6 +76,10 @@ public class HueMulator {
public void setupServer() {
log.info("Hue emulator service started....");
before(HUE_CONTEXT + "/*", (request, response) -> {
String path = request.pathInfo();
if (path.endsWith("/")) { // it should work with or without a trailing slash
response.redirect(path.substring(0, path.length() - 1));
}
log.debug("HueMulator " + request.requestMethod() + " called on api/* with request <<<" + request.pathInfo() + ">>>, and body <<<" + request.body() + ">>>");
if(bridgeSettingMaster.getBridgeSecurity().isSecure()) {
String pathInfo = request.pathInfo();
@@ -95,12 +105,12 @@ public class HueMulator {
return groupsListHandler(request.params(":userid"), request.ip());
} , new JsonTransformer());
// http://ip_address:port/api/{userId}/groups/{groupId} returns json
// object for specified group. Only 0 is supported
// object for specified group.
get(HUE_CONTEXT + "/:userid/groups/:groupid", "application/json", (request, response) -> {
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json");
response.status(HttpStatus.SC_OK);
return groupsIdHandler(request.params(":groupid"), request.params(":userid"), request.ip());
return groupsIdHandler(request.params(":groupid"), request.params(":userid"), request.ip());
} , new JsonTransformer());
// http://ip_address:port/:userid/groups CORS request
options(HUE_CONTEXT + "/:userid/groups", "application/json", (request, response) -> {
@@ -112,24 +122,36 @@ public class HueMulator {
return "";
});
// http://ip_address:port/:userid/groups
// dummy handler
// add a group
post(HUE_CONTEXT + "/:userid/groups", "application/json", (request, response) -> {
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json");
response.status(HttpStatus.SC_OK);
log.debug("group add requested from " + request.ip() + " user " + request.params(":userid") + " with body " + request.body());
return "[{\"success\":{\"id\":\"1\"}}]";
return addGroup(request.params(":userid"), request.ip(), request.body());
});
// http://ip_address:port/api/:userid/groups/<groupid>
// delete a group
delete(HUE_CONTEXT + "/:userid/groups/:groupid", "application/json", (request, response) -> {
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json");
response.status(HttpStatus.SC_OK);
return deleteGroup(request.params(":userid"), request.params(":groupid"), request.ip());
});
// http://ip_address:port/api/:userid/groups/<groupid>
// modify a single group
put(HUE_CONTEXT + "/:userid/groups/:groupid", "application/json", (request, response) -> {
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json");
response.status(HttpStatus.SC_OK);
return modifyGroup(request.params(":userid"), request.params(":groupid"), request.ip(), request.body());
});
// http://ip_address:port/api/:userid/groups/<groupid>/action
// Dummy handler
// Error forces Logitech Pop to fall back to individual light control
// instead of scene-based control.
// group acions
put(HUE_CONTEXT + "/:userid/groups/:groupid/action", "application/json", (request, response) -> {
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json");
response.status(HttpStatus.SC_OK);
log.debug("put action to groups API from " + request.ip() + " user " + request.params(":userid") + " with body " + request.body());
return "[{\"error\":{\"address\": \"/groups/0/action/scene\", \"type\":7, \"description\": \"invalid value, dummy for parameter, scene\"}}]";
return changeGroupState(request.params(":userid"), request.params(":groupid"), request.body(), request.ip(), false);
});
// http://ip_address:port/api/{userId}/scenes returns json objects of
// all scenes configured
@@ -418,7 +440,7 @@ public class HueMulator {
response.header("Access-Control-Allow-Origin", request.headers("Origin"));
response.type("application/json");
response.status(HttpStatus.SC_OK);
return changeState(request.params(":userid"), request.params(":id"), request.body(), request.ip());
return changeState(request.params(":userid"), request.params(":id"), request.body(), request.ip(), false);
});
}
@@ -467,16 +489,6 @@ public class HueMulator {
notFirstChange = true;
}
if (body.contains("\"ct\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/ct\":" + stateChanges.getCt()
+ "}}";
if (deviceState != null)
deviceState.setCt(stateChanges.getCt());
notFirstChange = true;
}
if (body.contains("\"xy\"")) {
if (notFirstChange)
responseString = responseString + ",";
@@ -485,36 +497,34 @@ public class HueMulator {
if (deviceState != null)
deviceState.setXy(stateChanges.getXy());
notFirstChange = true;
}
if (body.contains("\"hue\"")) {
} else if (body.contains("\"ct\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/hue\":" + stateChanges.getHue()
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/ct\":" + stateChanges.getCt()
+ "}}";
if (deviceState != null)
deviceState.setHue(stateChanges.getHue());
deviceState.setCt(stateChanges.getCt());
notFirstChange = true;
}
} else {
if (body.contains("\"hue\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/hue\":" + stateChanges.getHue()
+ "}}";
if (deviceState != null)
deviceState.setHue(stateChanges.getHue());
notFirstChange = true;
}
if (body.contains("\"sat\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/sat\":" + stateChanges.getSat()
+ "}}";
if (deviceState != null)
deviceState.setSat(stateChanges.getSat());
notFirstChange = true;
}
if (body.contains("\"ct_inc\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/ct_inc\":"
+ stateChanges.getCt_inc() + "}}";
if (deviceState != null)
deviceState.setCt(deviceState.getCt() + stateChanges.getCt_inc());
notFirstChange = true;
if (body.contains("\"sat\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/sat\":" + stateChanges.getSat()
+ "}}";
if (deviceState != null)
deviceState.setSat(stateChanges.getSat());
notFirstChange = true;
}
}
if (body.contains("\"xy_inc\"")) {
@@ -525,26 +535,34 @@ public class HueMulator {
if (deviceState != null)
deviceState.setXy(stateChanges.getXy());
notFirstChange = true;
}
if (body.contains("\"hue_inc\"")) {
} else if (body.contains("\"ct_inc\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/hue_inc\":"
+ stateChanges.getHue_inc() + "}}";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/ct_inc\":"
+ stateChanges.getCt_inc() + "}}";
if (deviceState != null)
deviceState.setHue(deviceState.getHue() + stateChanges.getHue_inc());
deviceState.setCt(deviceState.getCt() + stateChanges.getCt_inc());
notFirstChange = true;
}
} else {
if (body.contains("\"hue_inc\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/hue_inc\":"
+ stateChanges.getHue_inc() + "}}";
if (deviceState != null)
deviceState.setHue(deviceState.getHue() + stateChanges.getHue_inc());
notFirstChange = true;
}
if (body.contains("\"sat_inc\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/sat_inc\":"
+ stateChanges.getSat_inc() + "}}";
if (deviceState != null)
deviceState.setSat(deviceState.getSat() + stateChanges.getSat_inc());
notFirstChange = true;
if (body.contains("\"sat_inc\"")) {
if (notFirstChange)
responseString = responseString + ",";
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/sat_inc\":"
+ stateChanges.getSat_inc() + "}}";
if (deviceState != null)
deviceState.setSat(deviceState.getSat() + stateChanges.getSat_inc());
notFirstChange = true;
}
}
if (body.contains("\"effect\"")) {
@@ -618,23 +636,191 @@ public class HueMulator {
return "{}";
}
private Object groupsListHandler(String userId, String requestIp) {
log.debug("hue group list requested: " + userId + " from " + requestIp);
private Object addGroup(String userId, String ip, String body) {
HueError[] theErrors = null;
Map<String, GroupResponse> groupResponseMap = null;
log.debug("group add requested from " + ip + " user " + userId + " with body " + body);
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors == null) {
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
groupResponseMap = new HashMap<String, GroupResponse>();
groupResponseMap.put("1", (GroupResponse) this.groupsIdHandler("1", userId, requestIp));
return groupResponseMap;
GroupResponse theGroup = null;
try {
theGroup = aGsonHandler.fromJson(body, GroupResponse.class);
} catch (Exception e) {
theGroup = null;
}
if (theGroup == null) {
log.warn("Could not parse add group body. No group created.");
return aGsonHandler.toJson(HueErrorResponse.createResponse("5", "/groups/lights",
"invalid/missing parameters in body", null, null, null).getTheErrors(), HueError[].class);
}
List<GroupDescriptor> groups = groupRepository.findAll();
GroupDescriptor newGroup = new GroupDescriptor();
String type = theGroup.getType();
String groupClass = theGroup.getClass_name();
// check type
if (type == null || type.trim().equals("")) {
type = (groupClass == null || groupClass.trim().equals("")) ? "LightGroup" : "Room";
} else if (!type.equals("LightGroup") && !type.equals("Room")) {
type = "LightGroup";
}
// Everything else than a room must contain lights
if (!type.equals("Room")) {
if (theGroup.getLights() == null || theGroup.getLights().length == 0) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("5", "/groups/lights",
"invalid/missing parameters in body", null, null, null).getTheErrors(), HueError[].class);
}
} else { // check room class if it's a room
if (groupClass == null || groupClass.trim().equals("")) {
groupClass = GroupClassTypes.OTHER;
} else if (!new GroupClassTypes().validateType(groupClass)) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("7", "/groups/class",
"invalid value, " + groupClass + ", for parameter, class", null, null, null).getTheErrors(), HueError[].class);
}
}
String name = theGroup.getName();
Integer newId = groupRepository.getNewId();
if (name == null || name.trim().equals("")) {
name = type + " " + newId;
}
newGroup.setGroupType(type);
newGroup.setGroupClass(groupClass);
newGroup.setName(name);
newGroup.setLights(theGroup.getLights());
groups.add(newGroup);
groupRepository.save(groups.toArray(new GroupDescriptor[0]));
return "[{\"success\":{\"id\":\"" + newId + "\"}}]";
}
return theErrors;
}
private Object deleteGroup(String userId, String groupId, String ip) {
HueError[] theErrors = null;
log.debug("group delete requested from " + ip + " user " + userId);
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors == null) {
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
GroupDescriptor group = groupRepository.findOne(groupId);
if (group == null || group.isInactive()) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/groups/" + groupId,
"resource, /groups/" + groupId + ", not available", null, null, null).getTheErrors(), HueError[].class);
} else {
groupRepository.delete(group);
return "[{\"success\":\"/groups/" + groupId + " deleted\"}}]";
}
}
return theErrors;
}
private Object modifyGroup(String userId, String groupId, String ip, String body) {
HueError[] theErrors = null;
log.debug("group modify requested from " + ip + " user " + userId + " with body " + body);
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors == null) {
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
GroupDescriptor group = groupRepository.findOne(groupId);
if (group == null || group.isInactive()) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/groups/" + groupId,
"resource, /groups/" + groupId + ", not available", null, null, null).getTheErrors(), HueError[].class);
} else {
String successString = "[";
GroupResponse theGroup = null;
try {
theGroup = aGsonHandler.fromJson(body, GroupResponse.class);
} catch (Exception e) {
theGroup = null;
}
if (theGroup == null) {
log.warn("Could not parse modify group body. Group unchanged.");
return aGsonHandler.toJson(HueErrorResponse.createResponse("5", "/groups/lights",
"invalid/missing parameters in body", null, null, null).getTheErrors(), HueError[].class);
}
String type = theGroup.getType();
String groupClass = theGroup.getClass_name();
String name = theGroup.getName();
if (!(name == null || name.trim().equals(""))) {
group.setName(name);
successString += "{\"success\":{\"/groups/" + groupId + "/name\":\"" + name + "\"}},";
}
if (!group.getGroupType().equals("Room")) {
if (!(groupClass == null || groupClass.trim().equals(""))) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("6", "/groups/" + groupId + "/class",
"parameter, /groups/" + groupId + "/class, not available", null, null, null).getTheErrors(), HueError[].class);
}
if (theGroup.getLights() != null) {
if (theGroup.getLights().length == 0) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("7", "/groups/" + groupId + "/lights",
"invalid value, " + Arrays.toString(theGroup.getLights()) + ", for parameter, /groups" + groupId + "/lights", null, null, null).getTheErrors(), HueError[].class);
} else {
group.setLights(theGroup.getLights());
successString += "{\"success\":{\"/groups/" + groupId + "/lights\":\"" + Arrays.toString(theGroup.getLights()) + "\"}},";
}
}
} else { // check room class if it's a room
if (!(groupClass == null || groupClass.trim().equals(""))) {
if (!new GroupClassTypes().validateType(groupClass)) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("7", "/groups/class",
"invalid value, " + groupClass + ", for parameter, class", null, null, null).getTheErrors(), HueError[].class);
} else {
group.setGroupClass(groupClass);
successString += "{\"success\":{\"/groups/" + groupId + "/class\":\"" + groupClass + "\"}},";
}
}
if (theGroup.getLights() != null) {
group.setLights(theGroup.getLights());
successString += "{\"success\":{\"/groups/" + groupId + "/lights\":\"" + Arrays.toString(theGroup.getLights()) + "\"}},";
}
}
groupRepository.save();
return (successString.length() == 1) ? "[]" : successString.substring(0, successString.length()-1) + "]";
}
}
return theErrors;
}
private Object groupsListHandler(String userId, String requestIp) {
HueError[] theErrors = null;
Map<String, GroupResponse> groupResponseMap = null;
if (bridgeSettings.isTraceupnp())
log.info("Traceupnp: hue group list requested: " + userId + " from " + requestIp);
log.debug("hue group list requested: " + userId + " from " + requestIp);
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors == null) {
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
List<GroupDescriptor> groupList = groupRepository.findAllByRequester(requestIp);
groupResponseMap = new HashMap<String, GroupResponse>();
for (GroupDescriptor group : groupList) {
GroupResponse groupResponse = null;
if(!group.isInactive()) {
Map<String, DeviceResponse> lights = repository.findAllByGroupWithState(group.getLights(), requestIp, myHueHome, aGsonHandler);
groupResponse = GroupResponse.createResponse(group, lights);
groupResponseMap.put(group.getId(), groupResponse);
}
}
}
if (theErrors != null)
return theErrors;
return groupResponseMap;
}
private Object groupsIdHandler(String groupId, String userId, String requestIp) {
log.debug("hue group id: <" + groupId + "> requested: " + userId + " from " + requestIp);
@@ -645,14 +831,20 @@ public class HueMulator {
bridgeSettingMaster.updateConfigFile();
if (groupId.equalsIgnoreCase("0")) {
GroupResponse theResponse = GroupResponse.createDefaultGroupResponse(repository.findActive());
GroupResponse theResponse = GroupResponse.createDefaultGroupResponse((Map<String, DeviceResponse>)lightsListHandler(userId, requestIp));
return theResponse;
} else {
GroupDescriptor group = groupRepository.findOne(groupId);
if (group == null || group.isInactive()) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/groups/" + groupId,
"resource, /groups/" + groupId + ", not available", null, null, null).getTheErrors(), HueError[].class);
} else {
Map<String, DeviceResponse> lights = repository.findAllByGroupWithState(group.getLights(), requestIp, myHueHome, aGsonHandler);
GroupResponse theResponse = GroupResponse.createResponse(group, lights);
return theResponse;
}
}
if (!groupId.equalsIgnoreCase("0")) {
GroupResponse theResponse = GroupResponse.createOtherGroupResponse(repository.findActive());
return theResponse;
}
theErrors = HueErrorResponse.createResponse("3", userId + "/groups/" + groupId, "Object not found", null, null, null).getTheErrors();
}
return theErrors;
@@ -670,7 +862,6 @@ public class HueMulator {
bridgeSettingMaster.updateConfigFile();
List<DeviceDescriptor> deviceList = repository.findAllByRequester(requestIp);
// List<DeviceDescriptor> deviceList = repository.findActive();
deviceResponseMap = new HashMap<String, DeviceResponse>();
for (DeviceDescriptor device : deviceList) {
DeviceResponse deviceResponse = null;
@@ -699,6 +890,13 @@ public class HueMulator {
deviceResponseMap.put(device.getId(), deviceResponse);
}
}
// handle groups which shall be exposed as fake lights to selected devices like amazon echos
List<GroupDescriptor> groups = groupRepository.findVirtualLights(requestIp);
for (GroupDescriptor group : groups) {
deviceResponseMap.put(String.valueOf(Integer.parseInt(group.getId()) + 10000),
DeviceResponse.createResponseForVirtualLight(group));
}
}
if (theErrors != null)
@@ -766,12 +964,12 @@ public class HueMulator {
log.debug("hue api config requested: " + userId + " from " + ipAddress);
if (bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()) != null) {
log.debug("hue api config requested, User invalid, returning public config");
HuePublicConfig apiResponse = HuePublicConfig.createConfig("Philips hue",
HuePublicConfig apiResponse = HuePublicConfig.createConfig("HA-Bridge",
bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion());
return apiResponse;
}
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(),
HueApiResponse apiResponse = new HueApiResponse("HA-Bridge", bridgeSettings.getUpnpConfigAddress(),
bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton());
log.debug("api response config <<<" + aGsonHandler.toJson(apiResponse.getConfig()) + ">>>");
return apiResponse.getConfig();
@@ -786,7 +984,7 @@ public class HueMulator {
return theErrors;
}
HueApiResponse apiResponse = new HueApiResponse("Philips hue", bridgeSettings.getUpnpConfigAddress(),
HueApiResponse apiResponse = new HueApiResponse("HA-Bridge", bridgeSettings.getUpnpConfigAddress(),
bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton());
apiResponse.setLights((Map<String, DeviceResponse>) this.lightsListHandler(userId, ipAddress));
apiResponse.setGroups((Map<String, GroupResponse>) this.groupsListHandler(userId, ipAddress));
@@ -800,6 +998,11 @@ public class HueMulator {
if (theErrors != null)
return theErrors;
if (Integer.parseInt(lightId) >= 10000) {
GroupDescriptor group = groupRepository.findOne(String.valueOf(Integer.parseInt(lightId) - 10000));
return DeviceResponse.createResponseForVirtualLight(group);
}
DeviceDescriptor device = repository.findOne(lightId);
if (device == null) {
// response.status(HttpStatus.SC_NOT_FOUND);
@@ -878,7 +1081,10 @@ public class HueMulator {
return responseString;
}
private String changeState(String userId, String lightId, String body, String ipAddress) {
private String changeState(String userId, String lightId, String body, String ipAddress, boolean ignoreRequester) {
if (Integer.parseInt(lightId) >= 10000) {
return changeGroupState(userId, String.valueOf(Integer.parseInt(lightId) - 10000), body, ipAddress, true);
}
String responseString = null;
String url = null;
StateChangeBody theStateChanges = null;
@@ -931,7 +1137,9 @@ public class HueMulator {
if (url == null || url.length() == 0)
url = device.getOnUrl();
} else {
if (theStateChanges.isOn()) {
if (body.contains("\"xy\"") || body.contains("\"ct\"") || body.contains("\"hue\"")) {
url = device.getColorUrl();
} else if (theStateChanges.isOn()) {
url = device.getOnUrl();
} else if (!theStateChanges.isOn()) {
url = device.getOffUrl();
@@ -968,10 +1176,13 @@ public class HueMulator {
}
for (int i = 0; callItems != null && i < callItems.length; i++) {
if(!filterByRequester(device.getRequesterAddress(), ipAddress) || !filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
log.warn("filter for requester address not present in: (device)" + device.getRequesterAddress() + " OR then (item)" + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
continue;
if (!ignoreRequester) {
if(!filterByRequester(device.getRequesterAddress(), ipAddress) || !filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
log.warn("filter for requester address not present in: (device)" + device.getRequesterAddress() + " OR then (item)" + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
continue;
}
}
if (callItems[i].getCount() != null && callItems[i].getCount() > 0)
aMultiUtil.setSetCount(callItems[i].getCount());
else
@@ -999,7 +1210,26 @@ public class HueMulator {
aMultiUtil.setTheDelay(callItems[i].getDelay());
else
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
responseString = homeManager.findHome(callItems[i].getType().trim()).deviceHandler(callItems[i], aMultiUtil, lightId, state.getBri(), targetBri, targetBriInc, device, body);
ColorData colorData = null;
List<Double> xy = theStateChanges.getXy();
List<Double> xyInc = theStateChanges.getXy_inc();
Integer ct = theStateChanges.getCt();
Integer ctInc = theStateChanges.getCt_inc();
if (xy != null && xy.size() == 2) {
colorData = new ColorData(ColorData.ColorMode.XY, xy);
} else if (xyInc != null && xyInc.size() == 2) {
List<Double> current = state.getXy();
current.set(0, current.get(0) + xyInc.get(0));
current.set(1, current.get(1) + xyInc.get(1));
colorData = new ColorData(ColorData.ColorMode.XY, current);
} else if (ct != null && ct != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, ct);
} else if (ctInc != null && ctInc != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, state.getCt() + ctInc);
}
responseString = homeManager.findHome(callItems[i].getType().trim()).deviceHandler(callItems[i], aMultiUtil, lightId, state.getBri(), targetBri, targetBriInc, colorData, device, body);
if(responseString != null && responseString.contains("{\"error\":")) {
x = aMultiUtil.getSetCount();
}
@@ -1025,4 +1255,110 @@ public class HueMulator {
return responseString;
}
private String changeGroupState(String userId, String groupId, String body, String ipAddress, boolean fakeLightResponse) {
log.debug("PUT action to group " + groupId + " from " + ipAddress + " user " + userId + " with body " + body);
HueError[] theErrors = null;
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors == null) {
if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged())
bridgeSettingMaster.updateConfigFile();
GroupDescriptor group = null;
Integer targetBriInc = null;
Integer targetBri = null;
DeviceState state = null;
Map<String, DeviceResponse> lights = null;
if (groupId.equalsIgnoreCase("0")) {
lights = (Map<String, DeviceResponse>)lightsListHandler(userId, ipAddress);
} else {
group = groupRepository.findOne(groupId);
if (group == null || group.isInactive()) {
return aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/groups/" + groupId,
"resource, /groups/" + groupId + ", not available", null, null, null).getTheErrors(), HueError[].class);
} else {
if (fakeLightResponse) {
lights = repository.findAllByGroupWithState(group.getLights(), ipAddress, myHueHome, aGsonHandler, true);
} else {
lights = repository.findAllByGroupWithState(group.getLights(), ipAddress, myHueHome, aGsonHandler);
}
}
}
if (lights != null) {
StateChangeBody theStateChanges = null;
try {
theStateChanges = aGsonHandler.fromJson(body, StateChangeBody.class);
} catch (Exception e) {
theStateChanges = null;
}
if (theStateChanges == null) {
log.warn("Could not parse state change body. Light state not changed.");
return aGsonHandler.toJson(HueErrorResponse.createResponse("2", "/groups/" + groupId + "/action",
"Could not parse state change body.", null, null, null).getTheErrors(), HueError[].class);
}
if (group != null) {
if (body.contains("\"bri_inc\"")) {
targetBriInc = new Integer(theStateChanges.getBri_inc());
}
else if (body.contains("\"bri\"")) {
targetBri = new Integer(theStateChanges.getBri());
}
state = group.getAction();
if (state == null) {
state = DeviceState.createDeviceState();
group.setAction(state);
}
}
boolean turnOn = false;
boolean turnOff = false;
if (!(body.contains("\"bri_inc\"") || body.contains("\"bri\""))) {
if (!(body.contains("\"xy\"") || body.contains("\"ct\"") || body.contains("\"hue\""))) {
if (theStateChanges.isOn()) {
turnOn = true;
} else if (!theStateChanges.isOn()) {
turnOff = true;
}
}
}
for (Map.Entry<String, DeviceResponse> light : lights.entrySet()) {
log.debug("Processing light" + light.getKey() + ": " + turnOn + " " + turnOff + " " + light.getValue().getState().isOn());
// ignore on/off for devices that are already on/off
if (turnOff && !light.getValue().getState().isOn())
continue;
if (turnOn && light.getValue().getState().isOn())
continue;
changeState(userId, light.getKey(), body, ipAddress, fakeLightResponse);
}
// construct success response: one success message per changed property, but not per light
if (group != null) { // if not group 0
String response = formatSuccessHueResponse(theStateChanges, body, String.valueOf(Integer.parseInt(groupId) + 10000),
state, targetBri, targetBriInc, true);
group.setAction(state);
if (fakeLightResponse) {
return response;
}
}
String successString = "[";
for (String pairStr : body.replaceAll("[{|}]", "").split(",\\s*\"")) {
String[] pair = pairStr.split(":");
if (fakeLightResponse) {
successString += "{\"success\":{ \"/lights/" + String.valueOf(Integer.parseInt(groupId) + 10000) + "/state/" + pair[0].replaceAll("\"", "").trim() + "\": " + pair[1].trim() + "}},";
} else {
successString += "{\"success\":{ \"address\": \"/groups/" + groupId + "/action/" + pair[0].replaceAll("\"", "").trim() + "\", \"value\": " + pair[1].trim() + "}},";
}
}
return (successString.length() == 1) ? "[]" : successString.substring(0, successString.length()-1) + "]";
}
}
return aGsonHandler.toJson(theErrors);
}
}

View File

@@ -2,7 +2,11 @@ package com.bwssystems.HABridge.hue;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.ColorData;
import java.util.List;
public interface HueMulatorHandler {
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body);
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body);
}

View File

@@ -1,6 +1,7 @@
package com.bwssystems.HABridge.plugins.NestBridge;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
@@ -12,6 +13,7 @@ import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.nest.controller.Home;
import com.bwssystems.nest.controller.Nest;
@@ -102,7 +104,7 @@ public class NestHome implements com.bwssystems.HABridge.Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String responseString = null;
log.debug("executing HUE api request to set away for nest " + anItem.getType() + ": " + anItem.getItem().toString());
if(!validNest) {

View File

@@ -17,6 +17,7 @@ import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.google.gson.Gson;
@@ -71,7 +72,7 @@ public class DomoticzHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
Devices theDomoticzApiResponse = null;
String responseString = null;

View File

@@ -1,6 +1,7 @@
package com.bwssystems.HABridge.plugins.exec;
import java.io.IOException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -10,6 +11,8 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -24,7 +27,7 @@ public class CommandHome implements Home {
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int itensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
log.debug("Exec Request called with url: " + anItem.getItem().getAsString() + " and exec Garden: " + (theSettings.getBridgeSecurity().getExecGarden() == null ? "not given" : theSettings.getBridgeSecurity().getExecGarden()));
String responseString = null;
String intermediate;
@@ -32,7 +35,10 @@ public class CommandHome implements Home {
intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
else
intermediate = anItem.getItem().getAsString();
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, itensity, targetBri, targetBriInc, false);
intermediate = BrightnessDecode.calculateReplaceIntensityValue(intermediate, intensity, targetBri, targetBriInc, false);
if (colorData != null) {
intermediate = ColorDecode.replaceColorData(intermediate, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
intermediate = DeviceDataDecode.replaceDeviceData(intermediate, device);
intermediate = TimeDecode.replaceTimeValue(intermediate);
String execGarden = theSettings.getBridgeSecurity().getExecGarden();

View File

@@ -17,6 +17,7 @@ import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -111,7 +112,7 @@ public class HalHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
boolean halFound = false;
String responseString = null;
String theUrl = anItem.getItem().getAsString();

View File

@@ -18,6 +18,7 @@ import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -125,7 +126,7 @@ public class HarmonyHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String responseString = null;
log.debug("executing HUE api request to change " + anItem.getType() + " to Harmony: " + device.getName());
if(!validHarmony) {

View File

@@ -15,6 +15,7 @@ import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -115,7 +116,7 @@ public class HassHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String theReturn = null;
log.debug("executing HUE api request to send message to HomeAssistant: " + anItem.getItem().toString());
if(!validHass) {

View File

@@ -1,5 +1,7 @@
package com.bwssystems.HABridge.plugins.http;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,6 +13,8 @@ import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -27,7 +31,7 @@ public class HTTPHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String responseString = null;
String theUrl = anItem.getItem().getAsString();
@@ -50,6 +54,9 @@ public class HTTPHome implements Home {
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
intensity, targetBri, targetBriInc, false);
if (colorData != null) {
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
anUrl = TimeDecode.replaceTimeValue(anUrl);
@@ -57,6 +64,9 @@ public class HTTPHome implements Home {
if(anItem.getHttpBody()!= null && !anItem.getHttpBody().isEmpty()) {
aBody = BrightnessDecode.calculateReplaceIntensityValue(anItem.getHttpBody(),
intensity, targetBri, targetBriInc, false);
if (colorData != null) {
aBody = ColorDecode.replaceColorData(aBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
aBody = TimeDecode.replaceTimeValue(aBody);
}

View File

@@ -3,8 +3,10 @@ package com.bwssystems.HABridge.plugins.hue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,6 +17,7 @@ import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.api.hue.DeviceResponse;
import com.bwssystems.HABridge.api.hue.HueApiResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -86,7 +89,7 @@ public class HueHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
if(!validHue)
return null;
String responseString = null;

View File

@@ -19,6 +19,7 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.github.besherman.lifx.LFXClient;
import com.github.besherman.lifx.LFXGroup;
@@ -156,7 +157,7 @@ public class LifxHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String theReturn = null;
float aBriValue;
float theValue;

View File

@@ -3,6 +3,7 @@ package com.bwssystems.HABridge.plugins.mqtt;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
@@ -14,6 +15,7 @@ import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -76,7 +78,7 @@ public class MQTTHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String responseString = null;
log.debug("executing HUE api request to send message to MQTT broker: " + anItem.getItem().toString());
if (validMqtt) {

View File

@@ -6,6 +6,7 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -62,7 +63,7 @@ public class SomfyHome implements Home {
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String responseString = null;
if (!validSomfy) {
log.warn("Should not get here, no somfy hub available");

View File

@@ -7,6 +7,7 @@ import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
@@ -21,6 +22,8 @@ import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -41,7 +44,7 @@ public class TCPHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
Socket dataSendSocket = null;
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
String theUrl = anItem.getItem().getAsString();
@@ -81,10 +84,16 @@ public class TCPHome implements Home {
theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
if (theUrlBody.startsWith("0x")) {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
if (colorData != null) {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
}
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} else {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
if (colorData != null) {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
sendData = theUrlBody.getBytes();

View File

@@ -3,6 +3,8 @@ package com.bwssystems.HABridge.plugins.udp;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
@@ -15,6 +17,8 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -33,7 +37,7 @@ public class UDPHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
log.debug("executing HUE api request to UDP: " + anItem.getItem().getAsString());
String theUrl = anItem.getItem().getAsString();
if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("udp://")) {
@@ -59,9 +63,18 @@ public class UDPHome implements Home {
if (theUrlBody.startsWith("0x")) {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
if (colorData != null) {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
}
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} else {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
if (colorData != null) {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
sendData = theUrlBody.getBytes();

View File

@@ -15,6 +15,7 @@ import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.plugins.vera.luupRequests.Device;
import com.bwssystems.HABridge.plugins.vera.luupRequests.Scene;
@@ -73,7 +74,7 @@ public class VeraHome implements Home {
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
// Not a device handler
return null;
}

View File

@@ -1,5 +1,5 @@
.scrollableContainer {
height: 310px;
/* height: 310px;*/
position: relative;
padding-top: 35px;
overflow: hidden;

View File

@@ -134,7 +134,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
this.state = {base: "./api/devices", bridgelocation: ".", systemsbase: "./system", huebase: "./api", configs: [], backups: [], devices: [], device: {},
mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], mapTypes: [], olddevicename: "", logShowAll: false,
isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false,
showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: {}, viewDevId: "", queueDevId: "", securityInfo: {}};
showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: {}, viewDevId: "", queueDevId: "", securityInfo: {}, filterDevicesByIpAddress: null};
this.displayWarn = function(errorTitle, error) {
var toastContent = errorTitle;
@@ -410,6 +410,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
if(device.offUrl !== undefined && device.offUrl !== null && device.offUrl.indexOf(aType) >= 0)
return true;
if(device.colorUrl !== undefined && device.colorUrl !== null && device.colorUrl.indexOf(aType) >= 0)
return true;
return false;
@@ -1185,17 +1188,20 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
return formattedItem;
};
this.buildUrls = function (onpayload, dimpayload, offpayload, isObject, anId, deviceName, deviceTarget, deviceType, deviceMapType, count, delay) {
this.buildUrls = function (onpayload, dimpayload, offpayload, colorpayload, isObject, anId, deviceName, deviceTarget, deviceType, deviceMapType, count, delay) {
var currentOn = "";
var currentDim = "";
var currentOff = "";
var currentColor = "";
if (self.state.device !== undefined && self.state.device !== null) {
if (self.state.device.onUrl !== undefined && self.state.device.onUrl !== null&& self.state.device.onUrl !== "")
currentOn = self.state.device.onUrl;
if (self.state.device.dimUrl !== undefined && self.state.device.dimUrl !== null && self.state.device.dimUrl !== "")
currentDim = self.state.device.dimUrl;
if (self.state.device.offUrl !== undefined && self.state.device.offnUrl !== null && self.state.device.offnUrl !== "")
if (self.state.device.offUrl !== undefined && self.state.device.offUrl !== null && self.state.device.offUrl !== "")
currentOff = self.state.device.offUrl;
if (self.state.device.colorUrl !== undefined && self.state.device.colorUrl !== null && self.state.device.colorUrl !== "")
currentColor = self.state.device.colorUrl;
}
if (self.state.device !== undefined && self.state.device !== null && self.state.device.mapType !== undefined && self.state.device.mapType !== null && self.state.device.mapType !== "") {
self.state.device.mapId = self.state.device.mapId + "-" + anId;
@@ -1210,6 +1216,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
if (offpayload !== undefined && offpayload !== null && offpayload !== "") {
self.state.device.offUrl = self.formatUrlItem(currentOff);
}
if (colorpayload !== undefined && colorpayload !== null && colorpayload !== "") {
self.state.device.colorUrl = self.formatUrlItem(currentColor);
}
} else if (self.state.device === undefined || self.state.device === null || self.state.device.mapType === undefined || self.state.device.mapType === null || self.state.device.mapType === "") {
this.clearDevice();
self.state.device.deviceType = deviceType;
@@ -1223,6 +1232,8 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.state.device.onUrl = "[{\"item\":";
if (offpayload !== undefined && offpayload !== null && offpayload !== "")
self.state.device.offUrl = "[{\"item\":";
if (colorpayload !== undefined && colorpayload !== null && colorpayload !== "")
self.state.device.colorUrl = "[{\"item\":";
}
if (isObject) {
@@ -1232,6 +1243,8 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.state.device.onUrl = self.state.device.onUrl + onpayload;
if (offpayload !== undefined && offpayload !== null && offpayload !== "")
self.state.device.offUrl = self.state.device.offUrl + offpayload;
if (colorpayload !== undefined && colorpayload !== null && colorpayload !== "")
self.state.device.colorUrl = self.state.device.colorUrl + colorpayload;
} else {
if (dimpayload !== undefined && dimpayload !== null && dimpayload !== "")
@@ -1240,6 +1253,8 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.state.device.onUrl = self.state.device.onUrl + "\"" + onpayload + "\"";
if (offpayload !== undefined && offpayload !== null && offpayload !== "")
self.state.device.offUrl = self.state.device.offUrl + "\"" + offpayload + "\"";
if (colorpayload !== undefined && colorpayload !== null && colorpayload !== "")
self.state.device.colorUrl = self.state.device.colorUrl + "\"" + colorpayload + "\"";
}
if (count !== undefined && count !== null && count !== "") {
@@ -1249,6 +1264,8 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.state.device.onUrl = self.state.device.onUrl + ",\"count\":\"" + count;
if (offpayload !== undefined && offpayload !== null && offpayload !== "")
self.state.device.offUrl = self.state.device.offUrl + ",\"count\":\"" + count;
if (colorpayload !== undefined && colorpayload !== null && colorpayload !== "")
self.state.device.colorUrl = self.state.device.colorUrl + ",\"count\":\"" + count;
}
if (delay !== undefined && delay !== null && delay !== "") {
if (dimpayload !== undefined && dimpayload !== null && dimpayload !== "")
@@ -1257,6 +1274,8 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.state.device.onUrl = self.state.device.onUrl + ",\"delay\":\"" + delay;
if (offpayload !== undefined && offpayload !== null && offpayload !== "")
self.state.device.offUrl = self.state.device.offUrl + ",\"delay\":\"" + delay;
if (colorpayload !== undefined && colorpayload !== null && colorpayload !== "")
self.state.device.colorUrl = self.state.device.colorUrl + ",\"delay\":\"" + delay;
}
if (dimpayload !== undefined && dimpayload !== null && dimpayload !== "")
self.state.device.dimUrl = self.state.device.dimUrl + ",\"type\":\"" + deviceMapType + "\"}]";
@@ -1264,6 +1283,8 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.state.device.onUrl = self.state.device.onUrl + ",\"type\":\"" + deviceMapType + "\"}]";
if (offpayload !== undefined && offpayload !== null && offpayload !== "")
self.state.device.offUrl = self.state.device.offUrl + ",\"type\":\"" + deviceMapType + "\"}]";
if (colorpayload !== undefined && colorpayload !== null && colorpayload !== "")
self.state.device.colorUrl = self.state.device.colorUrl + ",\"type\":\"" + deviceMapType + "\"}]";
};
});
@@ -1639,7 +1660,7 @@ app.controller('ViewingController', function ($scope, $location, bridgeService,
var dialogNeeded = false;
if ((type === "on" && device.onUrl !== undefined && bridgeService.aContainsB(device.onUrl, "${intensity")) ||
(type === "off" && device.offUrl !== undefined && bridgeService.aContainsB(device.offUrl, "${intensity")) ||
(type === "dim" && device.dimUrl !== undefined)) {
(type === "dim" && device.dimUrl !== undefined) || (type === "color" && device.colorUrl !== undefined)) {
$scope.bridge.device = device;
$scope.bridge.type = type;
ngDialog.open({
@@ -1783,10 +1804,10 @@ app.controller('VeraController', function ($scope, $location, bridgeService, ngD
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum="
+ veradevice.id;
offpayload = "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;
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, veradevice.id, veradevice.name, veradevice.veraname, "switch", "veraDevice", null, null);
+ "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum="
+ veradevice.id;
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, false, veradevice.id, veradevice.name, veradevice.veraname, "switch", "veraDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -1802,7 +1823,7 @@ app.controller('VeraController', function ($scope, $location, bridgeService, ngD
+ "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum="
+ verascene.id;
bridgeService.buildUrls(onpayload, null, offpayload, false, verascene.id, verascene.name, verascene.veraname, "scene", "veraScene", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, false, verascene.id, verascene.name, verascene.veraname, "scene", "veraScene", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -1824,6 +1845,7 @@ app.controller('VeraController', function ($scope, $location, bridgeService, ngD
onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
offUrl: $scope.device.offUrl,
colorUrl: $scope.device.colorUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType,
@@ -1924,7 +1946,7 @@ app.controller('HarmonyController', function ($scope, $location, bridgeService,
onpayload = "{\"name\":\"" + harmonyactivity.activity.id + "\",\"hub\":\"" + harmonyactivity.hub + "\"}";
offpayload = "{\"name\":\"-1\",\"hub\":\"" + harmonyactivity.hub + "\"}";
bridgeService.buildUrls(onpayload, null, offpayload, true, harmonyactivity.activity.id, harmonyactivity.activity.label, harmonyactivity.hub, "activity", "harmonyActivity", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, harmonyactivity.activity.id, harmonyactivity.activity.label, harmonyactivity.hub, "activity", "harmonyActivity", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -1943,7 +1965,7 @@ app.controller('HarmonyController', function ($scope, $location, bridgeService,
postCmd = "\"}";
offpayload = "{\"device\":\"" + harmonydevice.device.id + "\",\"button\":\"" + actionOff.command + "\",\"hub\":\"" + harmonydevice.hub + postCmd;
bridgeService.buildUrls(onpayload, null, offpayload, true, actionOn.command, harmonydevice.device.label, harmonydevice.hub, "button", "harmonyButton", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, actionOn.command, harmonydevice.device.label, harmonydevice.hub, "button", "harmonyButton", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -1987,7 +2009,7 @@ app.controller('NestController', function ($scope, $location, bridgeService, ngD
$scope.buildNestHomeUrls = function (nestitem) {
onpayload = "{\"name\":\"" + nestitem.id + "\",\"away\":false,\"control\":\"status\"}";
offpayload = "{\"name\":\"" + nestitem.id + "\",\"away\":true,\"control\":\"status\"}";
bridgeService.buildUrls(onpayload, null, offpayload, true, nestitem.id, nestitem.name, nestitem.name, "home", "nestHomeAway", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, nestitem.id, nestitem.name, nestitem.name, "home", "nestHomeAway", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -1997,7 +2019,7 @@ app.controller('NestController', function ($scope, $location, bridgeService, ngD
onpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"temp\",\"temp\":\"${intensity.percent}\"}";
dimpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"temp\",\"temp\":\"${intensity.percent}\"}";
offpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"off\"}";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, nestitem.id + "-SetTemp", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Temperature", nestitem.location, "thermo", "nestThermoSet", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, true, nestitem.id + "-SetTemp", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Temperature", nestitem.location, "thermo", "nestThermoSet", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -2007,7 +2029,7 @@ app.controller('NestController', function ($scope, $location, bridgeService, ngD
onpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"heat\"}";
dimpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"temp\",\"temp\":\"${intensity.percent}\"}";
offpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"off\"}";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, nestitem.id + "-SetHeat", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Heat", nestitem.location, "thermo", "nestThermoSet", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, true, nestitem.id + "-SetHeat", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Heat", nestitem.location, "thermo", "nestThermoSet", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -2017,7 +2039,7 @@ app.controller('NestController', function ($scope, $location, bridgeService, ngD
onpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"cool\"}";
dimpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"temp\",\"temp\":\"${intensity.percent}\"}";
offpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"off\"}";
bridgeService.buildUrls(onpayload,dimpayload, offpayload, true, nestitem.id + "-SetCool", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Cool", nestitem.location, "thermo", "nestThermoSet", null, null);
bridgeService.buildUrls(onpayload,dimpayload, offpayload, null, true, nestitem.id + "-SetCool", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Cool", nestitem.location, "thermo", "nestThermoSet", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -2026,7 +2048,7 @@ app.controller('NestController', function ($scope, $location, bridgeService, ngD
$scope.buildNestRangeUrls = function (nestitem) {
onpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"range\"}";
offpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"off\"}";
bridgeService.buildUrls(onpayload, null, offpayload, true, nestitem.id + "-SetRange", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Range", nestitem.location, "thermo", "nestThermoSet", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, nestitem.id + "-SetRange", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Range", nestitem.location, "thermo", "nestThermoSet", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -2035,7 +2057,7 @@ app.controller('NestController', function ($scope, $location, bridgeService, ngD
$scope.buildNestOffUrls = function (nestitem) {
onpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"range\"}";
offpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"off\"}";
bridgeService.buildUrls(onpayload, null, offpayload, true, nestitem.id + "-TurnOff", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Thermostat", nestitem.location, "thermo", "nestThermoSet", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, nestitem.id + "-TurnOff", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Thermostat", nestitem.location, "thermo", "nestThermoSet", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -2044,7 +2066,7 @@ app.controller('NestController', function ($scope, $location, bridgeService, ngD
$scope.buildNestFanUrls = function (nestitem) {
onpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"fan-on\"}";
offpayload = "{\"name\":\"" + nestitem.id + "\",\"control\":\"fan-auto\"}";
bridgeService.buildUrls(onpayload, null, offpayload, true, nestitem.id + "-SetFan", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Fan", nestitem.location, "thermo", "nestThermoSet", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, nestitem.id + "-SetFan", nestitem.name.substr(0, nestitem.name.indexOf("(")) + " Fan", nestitem.location, "thermo", "nestThermoSet", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -2090,7 +2112,7 @@ app.controller('HueController', function ($scope, $location, bridgeService, ngDi
$scope.buildDeviceUrls = function (huedevice, buildonly) {
onpayload = "{\"ipAddress\":\"" + huedevice.hueaddress + "\",\"deviceId\":\"" + huedevice.huedeviceid +"\",\"hueName\":\"" + huedevice.huename + "\"}";
offpayload = "{\"ipAddress\":\"" + huedevice.hueaddress + "\",\"deviceId\":\"" + huedevice.huedeviceid +"\",\"hueName\":\"" + huedevice.huename + "\"}";
bridgeService.buildUrls(onpayload, null, offpayload, true, huedevice.device.uniqueid, huedevice.device.name, huedevice.huename, "passthru", "hueDevice", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, huedevice.device.uniqueid, huedevice.device.name, huedevice.huename, "passthru", "hueDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2114,6 +2136,7 @@ app.controller('HueController', function ($scope, $location, bridgeService, ngDi
onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
offUrl: $scope.device.offUrl,
colorUrl: $scope.device.colorUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType,
@@ -2257,7 +2280,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
+ preOffCmd
+ nameCmd
+ haldevice.haldevicename.replaceAll(" ", "%20");
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name, haldevice.haldevicename, haldevice.haladdress.name, aDeviceType, "halDevice", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name, haldevice.haldevicename, haldevice.haladdress.name, aDeviceType, "halDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2271,7 +2294,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
onpayload = "http://" + haldevice.haladdress.ip + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20");
offpayload = "http://" + haldevice.haladdress.ip + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOff.DeviceName.replaceAll(" ", "%20");
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-" + actionOn.DeviceName, haldevice.haldevicename, haldevice.haladdress.name, "button", "halButton", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-" + actionOn.DeviceName, haldevice.haldevicename, haldevice.haladdress.name, "button", "halButton", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2282,7 +2305,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
$scope.buildHALHomeUrls = function (haldevice, buildonly) {
onpayload = "http://" + haldevice.haladdress.ip + "/ModeService!ModeCmd=Set!ModeName=Home";
offpayload = "http://" + haldevice.haladdress.ip + "/ModeService!ModeCmd=Set!ModeName=Away";
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-HomeAway", haldevice.haldevicename, haldevice.haladdress.name, "home", "halHome", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-HomeAway", haldevice.haldevicename, haldevice.haladdress.name, "home", "halHome", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2303,7 +2326,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetHeat", haldevice.haldevicename + " Heat", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetHeat", haldevice.haldevicename + " Heat", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2324,7 +2347,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetCool", haldevice.haldevicename + " Cool", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetCool", haldevice.haldevicename + " Cool", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2341,7 +2364,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off";
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetAuto", haldevice.haldevicename + " Auto", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetAuto", haldevice.haldevicename + " Auto", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2358,7 +2381,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!HVACMode=Off";
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-TurnOff", haldevice.haldevicename + " Thermostat", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-TurnOff", haldevice.haldevicename + " Thermostat", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2375,7 +2398,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
+ "!FanMode=Auto";
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetFan", haldevice.haldevicename + " Fan", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, false, haldevice.haldevicename + "-" + haldevice.haladdress.name + "-SetFan", haldevice.haldevicename + " Fan", haldevice.haladdress.name, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2404,6 +2427,7 @@ app.controller('HalController', function ($scope, $location, bridgeService, ngDi
onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
offUrl: $scope.device.offUrl,
colorUrl: $scope.device.colorUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType,
@@ -2499,7 +2523,7 @@ app.controller('MQTTController', function ($scope, $location, bridgeService, ngD
onpayload = "{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\",\"qos\":\"" + mqttqos + "\",\"retain\":\"" + mqttretain + "\"}";
offpayload = "{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\",\"qos\":\"" + mqttqos + "\",\"retain\":\"" + mqttretain + "\"}";
bridgeService.buildUrls(onpayload, null, offpayload, true, mqttbroker.clientId + "-" + mqtttopic, mqttbroker.clientId + mqtttopic, mqttbroker.clientId, "mqtt", "mqttMessage", null, null);
bridgeService.buildUrls(onpayload, null, offpayload, null, true, mqttbroker.clientId + "-" + mqtttopic, mqttbroker.clientId + mqtttopic, mqttbroker.clientId, "mqtt", "mqttMessage", null, null);
$scope.device = bridgeService.state.device;
bridgeService.editNewDevice($scope.device);
$location.path('/editdevice');
@@ -2551,7 +2575,7 @@ app.controller('HassController', function ($scope, $location, bridgeService, ngD
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
offpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"off\"}";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2575,6 +2599,7 @@ app.controller('HassController', function ($scope, $location, bridgeService, ngD
onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
offUrl: $scope.device.offUrl,
colorUrl: $scope.device.colorUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType,
@@ -2706,7 +2731,7 @@ app.controller('DomoticzController', function ($scope, $location, bridgeService,
+ preCmd
+ domoticzdevice.idx
+ postOffCmd;
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, domoticzdevice.devicename + "-" + domoticzdevice.domoticzname, domoticzdevice.devicename, domoticzdevice.domoticzname, aDeviceType, "domoticzDevice", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, false, domoticzdevice.devicename + "-" + domoticzdevice.domoticzname, domoticzdevice.devicename, domoticzdevice.domoticzname, aDeviceType, "domoticzDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2730,6 +2755,7 @@ app.controller('DomoticzController', function ($scope, $location, bridgeService,
onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
offUrl: $scope.device.offUrl,
colorUrl: $scope.device.colorUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType,
@@ -2828,7 +2854,7 @@ app.controller('LifxController', function ($scope, $location, bridgeService, ngD
dimpayload = angular.toJson(lifxdevice);
onpayload = angular.toJson(lifxdevice);
offpayload = angular.toJson(lifxdevice);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, lifxdevice.name, lifxdevice.name, lifxdevice.name, null, "lifxDevice", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, true, lifxdevice.name, lifxdevice.name, lifxdevice.name, null, "lifxDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2852,6 +2878,7 @@ app.controller('LifxController', function ($scope, $location, bridgeService, ngD
onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
offUrl: $scope.device.offUrl,
colorUrl: $scope.device.colorUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType,
@@ -2955,7 +2982,7 @@ app.controller('SomfyController', function ($scope, $location, bridgeService, ng
onpayload = "{\"label\":\"Label that is ignored probably\",\"actions\":[{\"deviceURL\":\""+ somfydevice.deviceUrl+"\",\"commands\":[{\"name\":\"open\",\"parameters\":[]}]}]}";
offpayload = "{\"label\":\"Label that is ignored probably\",\"actions\":[{\"deviceURL\":\""+ somfydevice.deviceUrl+"\",\"commands\":[{\"name\":\"close\",\"parameters\":[]}]}]}";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, somfydevice.id, somfydevice.name, somfydevice.somfyname, "switch", "somfyDevice", null, null);
bridgeService.buildUrls(onpayload, dimpayload, offpayload, null, true, somfydevice.id, somfydevice.name, somfydevice.somfyname, "switch", "somfyDevice", null, null);
$scope.device = bridgeService.state.device;
if (!buildonly) {
bridgeService.editNewDevice($scope.device);
@@ -2980,6 +3007,7 @@ app.controller('SomfyController', function ($scope, $location, bridgeService, ng
onUrl: $scope.device.onUrl,
dimUrl: $scope.device.dimUrl,
offUrl: $scope.device.offUrl,
colorUrl: $scope.device.colorUrl,
headers: $scope.device.headers,
httpVerb: $scope.device.httpVerb,
contentType: $scope.device.contentType,
@@ -3065,18 +3093,35 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
$scope.onDevices = null;
$scope.dimDevices = null;
$scope.offDevices = null;
$scope.colorDevices = null;
$scope.showUrls = false;
$scope.onUrl = null;
$scope.dimUrl = null;
$scope.offUrl = null;
$scope.colorUrl = null;
if ($scope.device !== undefined && $scope.device.name !== undefined) {
if($scope.bridge.device.onUrl !== undefined)
if($scope.bridge.device.onUrl !== undefined) {
$scope.onDevices = bridgeService.getCallObjects($scope.bridge.device.onUrl);
if($scope.bridge.device.dimUrl !== undefined)
$scope.onUrl = $scope.bridge.device.onUrl.split("},").join("},\n");
}
if($scope.bridge.device.dimUrl !== undefined) {
$scope.dimDevices = bridgeService.getCallObjects($scope.bridge.device.dimUrl);
if($scope.bridge.device.offUrl !== undefined)
$scope.dimUrl = $scope.bridge.device.dimUrl.split("},").join("},\n");
}
if($scope.bridge.device.offUrl !== undefined) {
$scope.offDevices = bridgeService.getCallObjects($scope.bridge.device.offUrl);
$scope.offUrl = $scope.bridge.device.offUrl.split("},").join("},\n");
}
if($scope.bridge.device.colorUrl !== undefined) {
$scope.colorDevices = bridgeService.getCallObjects($scope.bridge.device.colorUrl);
$scope.colorUrl = $scope.bridge.device.colorUrl.split("},").join("},\n");
}
}
$scope.newOnItem = {};
$scope.newDimItem = {};
$scope.newOffItem = {};
$scope.newColorItem = {};
$scope.mapTypeSelected = bridgeService.getMapType($scope.device.mapType);
$scope.device_dim_control = "";
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
@@ -3087,9 +3132,16 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
$scope.onDevices = null;
$scope.dimDevices = null;
$scope.offDevices = null;
$scope.colorDevices = null;
$scope.showUrls = false;
$scope.onUrl = null;
$scope.dimUrl = null;
$scope.offUrl = null;
$scope.colorUrl = null;
$scope.newOnItem = {};
$scope.newDimItem = {};
$scope.newOffItem = {};
$scope.newColorItem = {};
$scope.device = bridgeService.state.device;
$scope.mapTypeSelected = null;
};
@@ -3116,12 +3168,22 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
else
$scope.device.mapType = null;
if ($scope.onDevices !== null)
$scope.device.onUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.onDevices));
if ($scope.dimDevices !== null)
$scope.device.dimUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.dimDevices));
if ($scope.offDevices !== null)
$scope.device.offUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.offDevices));
if ($scope.showUrls) {
$scope.device.onUrl = ($scope.onUrl == undefined || $scope.onUrl == null || $scope.onUrl == "") ? null : $scope.onUrl.replace(/\r?\n|\r/g,"");
$scope.device.dimUrl = ($scope.dimUrl == undefined || $scope.dimUrl == null || $scope.dimUrl == "") ? null : $scope.dimUrl.replace(/\r?\n|\r/g,"");
$scope.device.offUrl = ($scope.offUrl == undefined || $scope.offUrl == null || $scope.offUrl == "") ? null : $scope.offUrl.replace(/\r?\n|\r/g,"");
$scope.device.colorUrl = ($scope.colorUrl == undefined || $scope.colorUrl == null || $scope.colorUrl == "") ? null : $scope.colorUrl.replace(/\r?\n|\r/g,"");
} else {
if ($scope.onDevices !== null)
$scope.device.onUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.onDevices));
if ($scope.dimDevices !== null)
$scope.device.dimUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.dimDevices));
if ($scope.offDevices !== null)
$scope.device.offUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.offDevices));
if ($scope.colorDevices !== null)
$scope.device.colorUrl = angular.toJson(bridgeService.updateCallObjectsType($scope.colorDevices));
}
bridgeService.addDevice($scope.device).then(
function () {
@@ -3148,7 +3210,7 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
};
$scope.removeItemOn = function (anItem) {
for(var i = $scope.onDevices.length - 1; i >= 0; i--) {
if($scope.onDevices[i].item === anItem.item && $scope.onDevices[i].type === anItem.type) {
if($scope.onDevices[i] === anItem) {
$scope.onDevices.splice(i, 1);
}
}
@@ -3165,8 +3227,8 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
};
$scope.removeItemDim = function (anItem) {
for(var i = $scope.dimDevices.length - 1; i >= 0; i--) {
if($scope.dimDevices[i].item === anItem.item && $scope.dimDevices[i].type === anItem.type) {
$scope.dimDevices.splice(i, 1);
if($scope.dimDevices[i] === anItem) {
$scope.dimDevices.splice(i, 1);
}
}
};
@@ -3182,11 +3244,30 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
};
$scope.removeItemOff = function (anItem) {
for(var i = $scope.offDevices.length - 1; i >= 0; i--) {
if($scope.offDevices[i].item === anItem.item && $scope.offDevices[i].type === anItem.type) {
if($scope.offDevices[i] === anItem) {
$scope.offDevices.splice(i, 1);
}
}
};
$scope.addItemColor = function (anItem) {
if (anItem.item === undefined || anItem.item === null || anItem.item === "")
return;
var newitem = { item: anItem.item, type: anItem.type, delay: anItem.delay, count: anItem.count, filterIPs: anItem.filterIPs, httpVerb: anItem.httpVerb, httpBody: anItem.httpBody, httpHeaders: anItem.httpHeaders, contentType: anItem.contentType };
if ($scope.colorDevices === null)
$scope.colorDevices = [];
$scope.colorDevices.push(newitem);
$scope.newColorItem = {};
};
$scope.removeItemColor = function (anItem) {
for(var i = $scope.colorDevices.length - 1; i >= 0; i--) {
if($scope.colorDevices[i] === anItem) {
$scope.colorDevices.splice(i, 1);
}
}
};
$scope.toggleButtons = function () {
$scope.buttonsVisible = !$scope.buttonsVisible;
if($scope.buttonsVisible)
@@ -3195,6 +3276,22 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
};
$scope.changeEditmode = function () {
// copy local changes over to other edit mode
if ($scope.showUrls) {
$scope.onDevices = ($scope.onUrl == undefined || $scope.onUrl == null || $scope.onUrl == "") ? null : bridgeService.getCallObjects($scope.onUrl.replace(/\r?\n|\r/g,""));
$scope.dimDevices = ($scope.dimUrl == undefined || $scope.dimUrl == null || $scope.dimUrl == "") ? null : bridgeService.getCallObjects($scope.dimUrl.replace(/\r?\n|\r/g,""));
$scope.offDevices = ($scope.offUrl == undefined || $scope.offUrl == null || $scope.offUrl == "") ? null : bridgeService.getCallObjects($scope.offUrl.replace(/\r?\n|\r/g,""));
$scope.colorDevices = ($scope.colorUrl == undefined || $scope.colorUrl == null || $scope.colorUrl == "") ? null : bridgeService.getCallObjects($scope.colorUrl.replace(/\r?\n|\r/g,""));
} else {
$scope.onUrl = ($scope.onDevices !== null) ? angular.toJson(bridgeService.updateCallObjectsType($scope.onDevices)).split("},").join("},\n") : null;
$scope.dimUrl = ($scope.dimDevices !== null) ? angular.toJson(bridgeService.updateCallObjectsType($scope.dimDevices)).split("},").join("},\n") : null;
$scope.offUrl = ($scope.offDevices !== null) ? angular.toJson(bridgeService.updateCallObjectsType($scope.offDevices)).split("},").join("},\n") : null;
$scope.colorUrl = ($scope.colorDevices !== null) ? angular.toJson(bridgeService.updateCallObjectsType($scope.colorDevices)).split("},").join("},\n") : null;
}
$scope.showUrls = !$scope.showUrls;
};
});
app.filter('configuredVeraDevices', function (bridgeService) {
@@ -3365,6 +3462,21 @@ app.filter('configuredSomfyDevices', function (bridgeService) {
}
});
app.filter('filterDevicesByRequester', function () {
return function(input,search) {
var out = [];
if(input === undefined || input === null || input.length === undefined)
return out;
var pattern = new RegExp(search);
for (var i = 0; i < input.length; i++) {
if(pattern.test(input[i].requesterAddress) || !input[i].requesterAddress || input[i].requesterAddress.length === 0){
out.push(input[i]);
}
}
return out;
}
});
app.controller('LoginController', function ($scope, $location, Auth) {
$scope.failed = false;
$scope.loggedIn = Auth.isLoggedIn();

View File

@@ -31,10 +31,14 @@
</div>
<div class="panel-body">
<p>
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
<button ng-if="bridge.securityInfo.useLinkButton" class="btn btn-primary" type="submit" ng-click="pushLinkButton()">Link</button>
</p>
<div class="form-group">
<button class="btn btn-primary" type="submit" ng-click="renumberDevices()">Renumber Devices</button>
<button ng-if="bridge.securityInfo.useLinkButton" class="btn btn-primary" type="submit" ng-click="pushLinkButton()">Link</button>
<label for="device-ip-filter">Show devices visible to: </label>
<input type="text" id="device-ip-filter" style="width:150px"
ng-model="bridge.state.filterDevicesByIpAddress" placeholder="">
</div>
<scrollable-table watch="bridge.devices">
<table class="table table-bordered table-striped table-hover">
<thead>
@@ -51,7 +55,7 @@
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="device in bridge.devices" row-id="{{device.id}}" ng-class="{info: bridge.viewDevId == device.id}" >
<tr ng-repeat="device in bridge.devices | orderBy:'name' | filterDevicesByRequester:bridge.state.filterDevicesByIpAddress" row-id="{{device.id}}" ng-class="{info: bridge.viewDevId == device.id}" >
<td>{{$index+1}}</td>
<td>{{device.id}}</td>
<td>{{device.name}}</td>

View File

@@ -56,6 +56,7 @@
ng-click="editDevice(false)">Update Bridge Device</button>
<button class="btn btn-danger" ng-click="clearDevice()">Clear
Device</button>
<button class="btn" ng-click="changeEditmode()">Change Editmode</button>
</p>
<table class="table table-bordered table-striped table-hover">
@@ -147,7 +148,14 @@
<td><input type="text" class="form-control" id="device-map-id"
ng-model="device.mapId" placeholder="1111"></td>
</tr>
<tr>
<tr ng-hide="!showUrls">
<td><label>OnUrl</label></td>
<td><textarea class="form-control" id="device-on-url" style="min-height: 250px; min-width: 1300px"
ng-model="onUrl" placeholder="default"></textarea></td>
</tr>
<tr ng-hide="showUrls">
<td><label>On Items</label></td>
<td><scrollable-table watch="onDevices">
@@ -171,20 +179,20 @@
<tr ng-repeat="onItem in onDevices">
<div class="col-xs-12 col-md-4">
<td><select
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]" style="max-width: 150px"
ng-model="onItem.type"></select></td>
<td><textarea rows="1" class="form-control"
id="item-target" ng-model="onItem.item" placeholder="The Call"></textarea></td>
<td><textarea rows="1" class="form-control"
id="item-target" ng-model="onItem.item" style="min-width: 600px" placeholder="The Call"></textarea></td>
<td><textarea rows="1" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="onItem.delay" placeholder="millis"></textarea></td>
<td><textarea rows="1" class="form-control"
<td><textarea rows="1" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="onItem.count" placeholder="number"></textarea></td>
<td><textarea rows="1" class="form-control"
id="item-filterIPs" ng-model="onItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb"
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="onItem.httpVerb">
<option value="">---Please select---</option>
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
@@ -196,7 +204,7 @@
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="onItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type"
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="onItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
@@ -220,24 +228,24 @@
</tr>
<tr>
<div class="col-xs-12 col-md-4">
<td><select
<td><select style="max-width: 150px"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-model="newOnItem.type"></select></td>
<td><textarea rows="1" cols="20" class="form-control"
id="item-target" ng-model="newOnItem.item"
id="item-target" style="min-width: 600px" ng-model="newOnItem.item"
placeholder="The Call"></textarea></td>
<td><textarea rows="1" cols="4" class="form-control"
<td><textarea rows="1" cols="4" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="newOnItem.delay"
placeholder="millis"></textarea></td>
<td><textarea rows="1" cols="2" class="form-control"
<td><textarea rows="1" cols="2" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="newOnItem.count"
placeholder="number"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-filterIPs" ng-model="newOnItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb"
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="newOnItem.httpVerb">
<option value="">---Please select---</option>
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
@@ -249,7 +257,7 @@
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="newOnItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type"
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="newOnItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
@@ -274,7 +282,14 @@
</table>
</scrollable-table></td>
</tr>
<tr>
<tr ng-hide="!showUrls">
<td><label>DimUrl</label></td>
<td><textarea class="form-control" id="device-dim-url" style="min-height: 250px; min-width: 1300px"
ng-model="dimUrl" placeholder="default"></textarea></td>
</tr>
<tr ng-hide="showUrls">
<td><label>Dim Items</label></td>
<td><scrollable-table watch="dimDevices">
@@ -297,22 +312,22 @@
</thead>
<tr ng-repeat="dimItem in dimDevices">
<div class="col-xs-12 col-md-4">
<td><select
<td><select style="max-width: 150px"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-model="dimItem.type"></select></td>
<td><textarea rows="1" cols="20" class="form-control"
id="item-target" ng-model="dimItem.item"
id="item-target" ng-model="dimItem.item" style="min-width: 600px"
placeholder="The Call"></textarea></td>
<td><textarea rows="1" cols="4" class="form-control"
<td><textarea rows="1" cols="4" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="dimItem.delay" placeholder="millis"></textarea></td>
<td><textarea rows="1" cols="2" class="form-control"
<td><textarea rows="1" cols="2" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="dimItem.count" placeholder="number"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-filterIPs" ng-model="dimItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb"
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="dimItem.httpVerb">
<option value="">---Please select---</option>
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
@@ -324,7 +339,7 @@
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="dimItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type"
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="dimItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
@@ -348,24 +363,24 @@
</tr>
<tr>
<div class="col-xs-12 col-md-4">
<td><select
<td><select style="max-width: 150px"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-model="newDimItem.type"></select></td>
<td><textarea rows="1" cols="20" class="form-control"
id="item-target" ng-model="newDimItem.item"
id="item-target" ng-model="newDimItem.item" style="min-width: 600px"
placeholder="The Call"></textarea></td>
<td><textarea rows="1" cols="4" class="form-control"
<td><textarea rows="1" cols="4" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="newDimItem.delay"
placeholder="millis"></textarea></td>
<td><textarea rows="1" cols="2" class="form-control"
<td><textarea rows="1" cols="2" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="newDimItem.count"
placeholder="number"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-filterIPs" ng-model="newDimItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="newDimItem.httpVerb">
<option value="">---Please select---</option>
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
@@ -377,7 +392,7 @@
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="newDimItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type"
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="newDimItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
@@ -402,7 +417,14 @@
</table>
</scrollable-table></td>
</tr>
<tr>
<tr ng-hide="!showUrls">
<td><label>OffUrl</label></td>
<td><textarea class="form-control" id="device-off-url" style="min-height: 250px; min-width: 1300px"
ng-model="offUrl" placeholder="default"></textarea></td>
</tr>
<tr ng-hide="showUrls">
<td><label>Off Items</label></td>
<td><scrollable-table watch="offDevices">
@@ -425,22 +447,22 @@
</thead>
<tr ng-repeat="offItem in offDevices">
<div class="col-xs-12 col-md-4">
<td><select
<td><select style="max-width: 150px"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-model="offItem.type"></select></td>
<td><textarea rows="1" cols="20" class="form-control"
id="item-target" ng-model="offItem.item"
id="item-target" ng-model="offItem.item" style="min-width: 600px"
placeholder="The Call"></textarea></td>
<td><textarea rows="1" cols="4" class="form-control"
<td><textarea rows="1" cols="4" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="offItem.delay" placeholder="millis"></textarea></td>
<td><textarea rows="1" cols="2" class="form-control"
<td><textarea rows="1" cols="2" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="offItem.count" placeholder="number"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-filterIPs" ng-model="offItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb"
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="offItem.httpVerb">
<option value="">---Please select---</option>
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
@@ -452,7 +474,7 @@
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="offItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type"
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="offItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
@@ -476,24 +498,24 @@
</tr>
<tr>
<div class="col-xs-12 col-md-4">
<td><select
<td><select style="max-width: 150px"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-model="newOffItem.type"></select></td>
<td><textarea rows="1" cols="20" class="form-control"
id="item-target" ng-model="newOffItem.item"
id="item-target" ng-model="newOffItem.item" style="min-width: 600px"
placeholder="The Call"></textarea></td>
<td><textarea rows="1" cols="4" class="form-control"
<td><textarea rows="1" cols="4" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="newOffItem.delay"
placeholder="millis"></textarea></td>
<td><textarea rows="1" cols="2" class="form-control"
<td><textarea rows="1" cols="2" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="newOffItem.count"
placeholder="number"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-filterIPs" ng-model="newOffItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb"
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="newOffItem.httpVerb">
<option value="">---Please select---</option>
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
@@ -505,7 +527,7 @@
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="newOffItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type"
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="newOffItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
@@ -530,6 +552,140 @@
</table>
</scrollable-table></td>
</tr>
<tr ng-hide="!showUrls">
<td><label>ColorUrl</label></td>
<td><textarea class="form-control" id="device-color-url" style="min-height: 250px; min-width: 1300px"
ng-model="colorUrl" placeholder="default"></textarea></td>
</tr>
<tr ng-hide="showUrls">
<td><label>Color Items</label></td>
<td><scrollable-table watch="colorDevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<div class="col-xs-12 col-md-4">
<th>Type</th>
<th>Target Item</th>
<th>Delay</th>
<th>Count</th>
<th>Filter IPs</th>
<th>Http Verb</th>
<th>Http Body</th>
<th>Http Headers</th>
<th>Content Type</th>
<th>Manage</th>
</div>
</tr>
</thead>
<tr ng-repeat="colorItem in colorDevices">
<div class="col-xs-12 col-md-4">
<td><select style="max-width: 150px"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-model="colorItem.type"></select></td>
<td><textarea rows="1" cols="20" class="form-control"
id="item-target" ng-model="colorItem.item" style="min-width: 600px"
placeholder="The Call"></textarea></td>
<td><textarea rows="1" cols="4" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="colorItem.delay" placeholder="millis"></textarea></td>
<td><textarea rows="1" cols="2" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="colorItem.count" placeholder="number"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-filterIPs" ng-model="colorItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="colorItem.httpVerb">
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
</select></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpBody" ng-model="colorItem.httpBody"
placeholder="body args"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="colorItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="colorItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option>
<option value="application/octet-stream">application/octet-stream</option>
<option value="application/svg+xml">application/svg+xml</option>
<option value="application/xhtml+xml">application/xhtml+xml</option>
<option value="application/xml">application/xml</option>
<option value="*">*</option>
<option value="multipart/form-data">multipart/form-data</option>
<option value="text/html">text/html</option>
<option value="text/plain">text/plain</option>
<option value="text/xml">text/xml</option>
<option value="*/*">*/*</option>
</select></td>
<td><button class="btn btn-danger" type="submit"
ng-click="removeItemColor(colorItem)">Del</button></td>
</div>
</tr>
<tr>
<div class="col-xs-12 col-md-4">
<td><select style="max-width: 150px"
ng-options="mapType as mapType[1] for mapType in bridge.mapTypes track by mapType[0]"
ng-model="newColorItem.type"></select></td>
<td><textarea rows="1" cols="20" class="form-control"
id="item-target" ng-model="newColorItem.item" style="min-width: 600px"
placeholder="The Call"></textarea></td>
<td><textarea rows="1" cols="4" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-delay" ng-model="newColorItem.delay"
placeholder="millis"></textarea></td>
<td><textarea rows="1" cols="2" class="form-control" style="max-width: 80px; min-width: 80px"
id="item-count" ng-model="newColorItem.count"
placeholder="number"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-filterIPs" ng-model="newColorItem.filterIPs"
placeholder="restrict IPs"></textarea></td>
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
ng-model="newColorItem.httpVerb">
<option value="">---</option>
<!-- not selected / blank option -->
<option value="GET">GET</option>
<option value="PUT">PUT</option>
<option value="POST">POST</option>
</select></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpBody" ng-model="newColorItem.httpBody"
placeholder="body args"></textarea></td>
<td><textarea rows="1" cols="16" class="form-control"
id="item-httpHeaders" ng-model="newColorItem.httpHeaders"
placeholder="format like: [{&quot;name&quot;:&quot;A name&quot;,&quot;value&quot;:&quot;a value&quot;}]"></textarea></td>
<td><select name="item-content-type" id="item-content-type" style="max-width: 160px"
ng-model="newColorItem.contentType">
<option value="">---Please select---</option>
<!-- not selected / blank option -->
<option value="application/atom+xml">application/atom+xml</option>
<option value="application/x-www-form-urlencoded">application/x-www-form-urlencoded</option>
<option value="application/json">application/json</option>
<option value="application/octet-stream">application/octet-stream</option>
<option value="application/svg+xml">application/svg+xml</option>
<option value="application/xhtml+xml">application/xhtml+xml</option>
<option value="application/xml">application/xml</option>
<option value="*">*</option>
<option value="multipart/form-data">multipart/form-data</option>
<option value="text/html">text/html</option>
<option value="text/plain">text/plain</option>
<option value="text/xml">text/xml</option>
<option value="*/*">*/*</option>
</select></td>
<td><button class="btn btn-success" type="submit"
ng-click="addItemColor(newColorItem)">Add</button></td>
</div>
</tr>
</table>
</scrollable-table></td>
</tr>
<tr>
<td><label>Legacy Fields <a ng-click="toggleButtons()"><span class={{imgButtonsUrl}} aria-hidden="true"></span></a></label>
</td>

View File

@@ -75,6 +75,13 @@
ng-model="bridge.settings.upnpdevicedb"
placeholder="data/device.db"></td>
</tr>
<tr>
<td>Groups DB Path and File</td>
<td><input id="bridge-settings-upnpgroupdb"
class="form-control" type="text"
ng-model="bridge.settings.upnpgroupdb"
placeholder="data/group.db"></td>
</tr>
<tr>
<td>UPNP IP Address</td>
<td><input id="bridge-settings-upnpconfigaddress"

View File

@@ -13,14 +13,14 @@ public class ConvertCIEColorTestCase {
@Test
public void testColorConversion() {
ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(new Double(0.671254), new Double(0.303273)));
//ArrayList<Double> xy = new ArrayList<Double>(Arrays.asList(new Double(0.671254), new Double(0.303273)));
List<Double> colorDecode = ColorDecode.convertCIEtoRGB(xy, 254);
List<Double> assertDecode = new ArrayList<Double>();
assertDecode.add(0, 255.0);
assertDecode.add(1, 47.0);
assertDecode.add(2, 43.0);
Assert.assertEquals(colorDecode, assertDecode);
//List<Double> colorDecode = ColorDecode.convertCIEtoRGB(xy, 254);
//List<Double> assertDecode = new ArrayList<Double>();
//assertDecode.add(0, 255.0);
//assertDecode.add(1, 47.0);
//assertDecode.add(2, 43.0);
//Assert.assertEquals(colorDecode, assertDecode);
}
}