mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Implemented support for rooms
I implemented full api support for rooms. That means: - Create/Modify/Delete rooms/lightgroups - Get information about group list / individual group - Group actions: Change lighting for the whole group (except setting scenes, because scenes are not implemented in ha-bridge right now) For now the rooms/groups can only be configured through the api and apps, it's not visible/changeable through the web gui.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -12,3 +12,5 @@ data
|
||||
/.settings/
|
||||
/start.bat
|
||||
/.classpath
|
||||
|
||||
sftp-config\.json
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.bwssystems.HABridge.api.hue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import com.bwssystems.HABridge.dao.DeviceDescriptor;
|
||||
import com.bwssystems.HABridge.dao.GroupDescriptor;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public class GroupResponse {
|
||||
@@ -16,6 +20,8 @@ public class GroupResponse {
|
||||
private String type;
|
||||
@SerializedName("class")
|
||||
String class_name;
|
||||
@SerializedName("state")
|
||||
private GroupState state;
|
||||
|
||||
public DeviceState getAction() {
|
||||
return action;
|
||||
@@ -23,6 +29,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 +62,49 @@ 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()) {
|
||||
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;
|
||||
for (DeviceResponse light : lights.values()) {
|
||||
Boolean is_on = light.getState().isOn();
|
||||
if (is_on)
|
||||
any_on = true;
|
||||
else
|
||||
all_on = false;
|
||||
}
|
||||
|
||||
response.setState(new GroupState(all_on, any_on));
|
||||
response.setAction(group.getAction());
|
||||
response.setName(group.getName());
|
||||
response.setType(group.getGroupType());
|
||||
response.setLights(group.getLights());
|
||||
response.setClass_name(group.getGroupClass());
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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,41 @@ public class DeviceRepository extends BackupHandler {
|
||||
return theReturnList;
|
||||
}
|
||||
|
||||
public Map<String, DeviceResponse> findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder) {
|
||||
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 : 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);
|
||||
}
|
||||
|
||||
139
src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java
Normal file
139
src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java
Normal file
@@ -0,0 +1,139 @@
|
||||
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;
|
||||
@SerializedName("action")
|
||||
@Expose
|
||||
private DeviceState action;
|
||||
@SerializedName("groupState")
|
||||
@Expose
|
||||
private GroupState groupState;
|
||||
@SerializedName("lights")
|
||||
@Expose
|
||||
private String[] lights;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
213
src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java
Normal file
213
src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java
Normal file
@@ -0,0 +1,213 @@
|
||||
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;
|
||||
log.info("loading group.db from " + groupDb);
|
||||
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 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -29,6 +30,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 +40,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 +51,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 +59,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();
|
||||
@@ -100,7 +105,7 @@ public class HueMulator {
|
||||
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) -> {
|
||||
@@ -117,8 +122,19 @@ public class HueMulator {
|
||||
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());
|
||||
});
|
||||
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());
|
||||
});
|
||||
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
|
||||
@@ -128,8 +144,7 @@ public class HueMulator {
|
||||
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());
|
||||
});
|
||||
// http://ip_address:port/api/{userId}/scenes returns json objects of
|
||||
// all scenes configured
|
||||
@@ -614,23 +629,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);
|
||||
@@ -641,14 +824,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;
|
||||
@@ -666,7 +855,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;
|
||||
@@ -1023,4 +1211,63 @@ public class HueMulator {
|
||||
return responseString;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Object changeGroupState(String userId, String groupId, String body, String ipAddress) {
|
||||
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();
|
||||
|
||||
Map<String, DeviceResponse> lights = null;
|
||||
if (groupId.equalsIgnoreCase("0")) {
|
||||
lights = (Map<String, DeviceResponse>)lightsListHandler(userId, ipAddress);
|
||||
} 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 {
|
||||
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);
|
||||
}
|
||||
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()) {
|
||||
if (turnOff && !light.getValue().getState().isOn())
|
||||
continue;
|
||||
if (turnOn && light.getValue().getState().isOn())
|
||||
continue;
|
||||
changeState(userId, light.getKey(), body, ipAddress);
|
||||
}
|
||||
return "[]";
|
||||
}
|
||||
}
|
||||
|
||||
return theErrors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
<th>Target Item</th>
|
||||
<th>Delay</th>
|
||||
<th>Count</th>
|
||||
<!--<th>Filter IPs</th>-->
|
||||
<th>Filter IPs</th>
|
||||
<th>Http Verb</th>
|
||||
<th>Http Body</th>
|
||||
<th>Http Headers</th>
|
||||
@@ -187,9 +187,9 @@
|
||||
id="item-delay" ng-model="onItem.delay" placeholder="millis"></textarea></td>
|
||||
<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"
|
||||
<td><textarea rows="1" class="form-control"
|
||||
id="item-filterIPs" ng-model="onItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td>-->
|
||||
placeholder="restrict IPs"></textarea></td>
|
||||
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
|
||||
ng-model="onItem.httpVerb">
|
||||
<option value="">---</option>
|
||||
@@ -240,9 +240,9 @@
|
||||
<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"
|
||||
<td><textarea rows="1" cols="16" class="form-control"
|
||||
id="item-filterIPs" ng-model="newOnItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td>-->
|
||||
placeholder="restrict IPs"></textarea></td>
|
||||
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
|
||||
ng-model="newOnItem.httpVerb">
|
||||
<option value="">---</option>
|
||||
@@ -301,7 +301,7 @@
|
||||
<th>Target Item</th>
|
||||
<th>Delay</th>
|
||||
<th>Count</th>
|
||||
<!--<th>Filter IPs</th>-->
|
||||
<th>Filter IPs</th>
|
||||
<th>Http Verb</th>
|
||||
<th>Http Body</th>
|
||||
<th>Http Headers</th>
|
||||
@@ -322,9 +322,9 @@
|
||||
id="item-delay" ng-model="dimItem.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="dimItem.count" placeholder="number"></textarea></td>
|
||||
<!--<td><textarea rows="1" cols="16" class="form-control"
|
||||
<td><textarea rows="1" cols="16" class="form-control"
|
||||
id="item-filterIPs" ng-model="dimItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td>-->
|
||||
placeholder="restrict IPs"></textarea></td>
|
||||
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
|
||||
ng-model="dimItem.httpVerb">
|
||||
<option value="">---</option>
|
||||
@@ -375,9 +375,9 @@
|
||||
<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"
|
||||
<td><textarea rows="1" cols="16" class="form-control"
|
||||
id="item-filterIPs" ng-model="newDimItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td> -->
|
||||
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="">---</option>
|
||||
@@ -436,7 +436,7 @@
|
||||
<th>Target Item</th>
|
||||
<th>Delay</th>
|
||||
<th>Count</th>
|
||||
<!--<th>Filter IPs</th>-->
|
||||
<th>Filter IPs</th>
|
||||
<th>Http Verb</th>
|
||||
<th>Http Body</th>
|
||||
<th>Http Headers</th>
|
||||
@@ -457,9 +457,9 @@
|
||||
id="item-delay" ng-model="offItem.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="offItem.count" placeholder="number"></textarea></td>
|
||||
<!--<td><textarea rows="1" cols="16" class="form-control"
|
||||
<td><textarea rows="1" cols="16" class="form-control"
|
||||
id="item-filterIPs" ng-model="offItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td>-->
|
||||
placeholder="restrict IPs"></textarea></td>
|
||||
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
|
||||
ng-model="offItem.httpVerb">
|
||||
<option value="">---</option>
|
||||
@@ -510,9 +510,9 @@
|
||||
<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"
|
||||
<td><textarea rows="1" cols="16" class="form-control"
|
||||
id="item-filterIPs" ng-model="newOffItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td>-->
|
||||
placeholder="restrict IPs"></textarea></td>
|
||||
<td><select name="item-http-verb" id="item-http-verb" style="max-width: 80px"
|
||||
ng-model="newOffItem.httpVerb">
|
||||
<option value="">---</option>
|
||||
@@ -570,7 +570,7 @@
|
||||
<th>Target Item</th>
|
||||
<th>Delay</th>
|
||||
<th>Count</th>
|
||||
<!--<th>Filter IPs</th>-->
|
||||
<th>Filter IPs</th>
|
||||
<th>Http Verb</th>
|
||||
<th>Http Body</th>
|
||||
<th>Http Headers</th>
|
||||
@@ -591,9 +591,9 @@
|
||||
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"
|
||||
<td><textarea rows="1" cols="16" class="form-control"
|
||||
id="item-filterIPs" ng-model="colorItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td>-->
|
||||
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>
|
||||
@@ -644,9 +644,9 @@
|
||||
<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"
|
||||
<td><textarea rows="1" cols="16" class="form-control"
|
||||
id="item-filterIPs" ng-model="newColorItem.filterIPs"
|
||||
placeholder="restrict IPs"></textarea></td>-->
|
||||
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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user