From d36769e2a06d63db9be15ee2ec5ed9a7052aee11 Mon Sep 17 00:00:00 2001 From: diamond Date: Thu, 4 May 2017 03:19:03 +0300 Subject: [PATCH 01/28] fibaro HC2 support --- .../bwssystems/HABridge/BridgeSettings.java | 18 ++ .../HABridge/BridgeSettingsDescriptor.java | 25 ++ .../bwssystems/HABridge/DeviceMapTypes.java | 4 + .../com/bwssystems/HABridge/HomeManager.java | 9 +- .../devicemanagmeent/DeviceResource.java | 12 + .../HABridge/plugins/fibaro/Device.java | 75 ++++++ .../HABridge/plugins/fibaro/FibaroHome.java | 103 ++++++++ .../HABridge/plugins/fibaro/FibaroInfo.java | 146 +++++++++++ .../HABridge/plugins/fibaro/Room.java | 19 ++ .../HABridge/plugins/fibaro/Scene.java | 39 +++ src/main/resources/public/scripts/app.js | 248 +++++++++++++++++- .../resources/public/views/configuration.html | 4 + .../public/views/domoticzdevice.html | 4 + .../resources/public/views/editdevice.html | 4 + .../resources/public/views/fibarodevice.html | 145 ++++++++++ .../resources/public/views/fibaroscene.html | 114 ++++++++ .../resources/public/views/haldevice.html | 4 + .../public/views/harmonyactivity.html | 4 + .../resources/public/views/harmonydevice.html | 4 + .../resources/public/views/hassdevice.html | 4 + .../resources/public/views/huedevice.html | 4 + .../resources/public/views/lifxdevice.html | 2 + src/main/resources/public/views/logs.html | 4 + .../resources/public/views/mqttpublish.html | 2 + .../resources/public/views/nestactions.html | 4 + .../resources/public/views/somfydevice.html | 5 +- src/main/resources/public/views/system.html | 33 +++ .../resources/public/views/veradevice.html | 5 +- .../resources/public/views/verascene.html | 5 +- 29 files changed, 1041 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java create mode 100644 src/main/resources/public/views/fibarodevice.html create mode 100644 src/main/resources/public/views/fibaroscene.html diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java index 9365f9d..200f267 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java @@ -65,6 +65,7 @@ public class BridgeSettings extends BackupHandler { public void buildSettings() { String addressString = null; String theVeraAddress = null; + String theFibaroAddress = null; String theSomfyAddress = null; String theHarmonyAddress = null; String configFileProperty = System.getProperty("config.file"); @@ -107,6 +108,22 @@ public class BridgeSettings extends BackupHandler { } } theBridgeSettings.setVeraAddress(theVeraList); + + theFibaroAddress = System.getProperty("fibaro.address"); + IpList theFibaroList = null; + if(theFibaroAddress != null) { + try { + theFibaroList = new Gson().fromJson(theFibaroAddress, IpList.class); + } catch (Exception e) { + try { + theFibaroList = new Gson().fromJson("{devices:[{name:default,ip:" + theFibaroAddress + "}]}", IpList.class); + } catch (Exception et) { + log.error("Cannot parse fibaro.address, not set with message: " + e.getMessage(), e); + theFibaroList = null; + } + } + } + theBridgeSettings.setFibaroAddress(theFibaroList); theHarmonyAddress = System.getProperty("harmony.address"); IpList theHarmonyList = null; @@ -178,6 +195,7 @@ public class BridgeSettings extends BackupHandler { theBridgeSettings.setButtonsleep(Integer.parseInt(Configuration.DEFAULT_BUTTON_SLEEP)); theBridgeSettings.setVeraconfigured(theBridgeSettings.isValidVera()); + theBridgeSettings.setFibaroconfigured(theBridgeSettings.isValidFibaro()); theBridgeSettings.setHarmonyconfigured(theBridgeSettings.isValidHarmony()); theBridgeSettings.setNestConfigured(theBridgeSettings.isValidNest()); theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue()); diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java index 319f5c0..4bec5ed 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java @@ -24,6 +24,9 @@ public class BridgeSettingsDescriptor { @SerializedName("veraaddress") @Expose private IpList veraaddress; + @SerializedName("fibaroaddress") + @Expose + private IpList fibaroaddress; @SerializedName("harmonyaddress") @Expose private IpList harmonyaddress; @@ -91,6 +94,7 @@ public class BridgeSettingsDescriptor { private boolean settingsChanged; private boolean veraconfigured; + private boolean fibaroconfigured; private boolean harmonyconfigured; private boolean hueconfigured; private boolean nestconfigured; @@ -107,6 +111,7 @@ public class BridgeSettingsDescriptor { this.traceupnp = false; this.nestconfigured = false; this.veraconfigured = false; + this.fibaroconfigured = false; this.somfyconfigured = false; this.harmonyconfigured = false; this.hueconfigured = false; @@ -153,12 +158,18 @@ public class BridgeSettingsDescriptor { public IpList getVeraAddress() { return veraaddress; } + public IpList getFibaroAddress() { + return fibaroaddress; + } public IpList getSomfyAddress() { return somfyaddress; } public void setVeraAddress(IpList veraAddress) { this.veraaddress = veraAddress; } + public void setFibaroAddress(IpList fibaroAddress) { + this.fibaroaddress = fibaroAddress; + } public void setSomfyAddress(IpList somfyAddress) { this.somfyaddress = somfyAddress; } @@ -195,12 +206,18 @@ public class BridgeSettingsDescriptor { public boolean isVeraconfigured() { return veraconfigured; } + public boolean isFibaroconfigured() { + return fibaroconfigured; + } public boolean isSomfyconfigured() { return somfyconfigured; } public void setVeraconfigured(boolean veraconfigured) { this.veraconfigured = veraconfigured; } + public void setFibaroconfigured(boolean fibaroconfigured) { + this.fibaroconfigured = fibaroconfigured; + } public void setSomfyconfigured(boolean somfyconfigured) { this.somfyconfigured = somfyconfigured; } @@ -356,6 +373,14 @@ public class BridgeSettingsDescriptor { return false; return true; } + public Boolean isValidFibaro() { + if(this.getFibaroAddress() == null || this.getFibaroAddress().getDevices().size() <= 0) + return false; + List devicesList = this.getFibaroAddress().getDevices(); + if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS)) + return false; + return true; + } public Boolean isValidHarmony() { if(this.getHarmonyAddress() == null || this.getHarmonyAddress().getDevices().size() <= 0) return false; diff --git a/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java b/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java index f8fae87..9c13d71 100644 --- a/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java +++ b/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java @@ -7,6 +7,8 @@ public class DeviceMapTypes { public final static String[] CUSTOM_DEVICE = { "custom", "Custom"}; public final static String[] VERA_DEVICE = { "veraDevice", "Vera Device"}; public final static String[] VERA_SCENE = { "veraScene", "Vera Scene"}; + public final static String[] FIBARO_DEVICE = { "fibaroDevice", "Fibaro Device"}; + public final static String[] FIBARO_SCENE = { "fibaroScene", "Fibaro Scene"}; public final static String[] HARMONY_ACTIVITY = { "harmonyActivity", "Harmony Activity"}; public final static String[] HARMONY_BUTTON = { "harmonyButton", "Harmony Button"}; public final static String[] NEST_HOMEAWAY = { "nestHomeAway", "Nest Home Status"}; @@ -57,6 +59,8 @@ public class DeviceMapTypes { deviceMapTypes.add(UDP_DEVICE); deviceMapTypes.add(VERA_DEVICE); deviceMapTypes.add(VERA_SCENE); + deviceMapTypes.add(FIBARO_DEVICE); + deviceMapTypes.add(FIBARO_SCENE); deviceMapTypes.add(SOMFY_DEVICE); } public static int getTypeIndex() { diff --git a/src/main/java/com/bwssystems/HABridge/HomeManager.java b/src/main/java/com/bwssystems/HABridge/HomeManager.java index 4bc8276..60b3bcc 100644 --- a/src/main/java/com/bwssystems/HABridge/HomeManager.java +++ b/src/main/java/com/bwssystems/HABridge/HomeManager.java @@ -19,6 +19,7 @@ import com.bwssystems.HABridge.plugins.somfy.SomfyHome; import com.bwssystems.HABridge.plugins.tcp.TCPHome; import com.bwssystems.HABridge.plugins.udp.UDPHome; import com.bwssystems.HABridge.plugins.vera.VeraHome; +import com.bwssystems.HABridge.plugins.fibaro.FibaroHome; import com.bwssystems.HABridge.util.UDPDatagramSender; public class HomeManager { @@ -73,6 +74,8 @@ public class HomeManager { homeList.put(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex], aHome); homeList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome); homeList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome); + homeList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome); + homeList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome); //setup the tcp handler Home aHome = new TCPHome(bridgeSettings); homeList.put(DeviceMapTypes.TCP_DEVICE[DeviceMapTypes.typeIndex], aHome); @@ -85,7 +88,11 @@ public class HomeManager { aHome = new VeraHome(bridgeSettings); resourceList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome); resourceList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome); - //setup the Domoticz configuration if available + // Setup Fibaro Home if available + aHome = new FibaroHome(bridgeSettings); + resourceList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome); + resourceList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome); + //setup the Domoticz configuration if available aHome = new DomoticzHome(bridgeSettings); homeList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome); resourceList.put(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome); diff --git a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java index f1bbc7b..16c575a 100644 --- a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java +++ b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java @@ -214,6 +214,18 @@ public class DeviceResource { response.status(HttpStatus.SC_OK); return homeManager.findResource(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex]); }, new JsonTransformer()); + + get (API_CONTEXT + "/fibaro/devices", "application/json", (request, response) -> { + log.debug("Get fibaro devices"); + response.status(HttpStatus.SC_OK); + return homeManager.findResource(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]); + }, new JsonTransformer()); + + get (API_CONTEXT + "/fibaro/scenes", "application/json", (request, response) -> { + log.debug("Get fibaro scenes"); + response.status(HttpStatus.SC_OK); + return homeManager.findResource(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex]); + }, new JsonTransformer()); get (API_CONTEXT + "/harmony/activities", "application/json", (request, response) -> { log.debug("Get harmony activities"); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java new file mode 100644 index 0000000..0bfa44d --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java @@ -0,0 +1,75 @@ +package com.bwssystems.HABridge.plugins.fibaro; + +public class Device +{ + public int id; + public String name; + public int roomID; + public String type; + public String baseType; + public boolean enabled; + public boolean visible; + public boolean isPlugin; + public int parentId; + public int remoteGatewayId; + public boolean viewXml; + public boolean configXml; + public Object interfaces; + public Properties properties; + public Object actions; + public int created; + public int modified; + public int sortOrder; + + public class Properties { + public String UIMessageSendTime; + public String autoConfig; + public String date; + public String dead; + public String deviceControlType; + public String deviceIcon; + public String disabled; + public String emailNotificationID; + public String emailNotificationType; + public String endPoint; + public String liliOffCommand; + public String liliOnCommand; + public String log; + public String logTemp; + public String manufacturer; + public String markAsDead; + public String model; + public String nodeID; + public String pollingDeadDevice; + public String pollingTime; + public String pollingTimeNext; + public int pollingTimeSec; + public String productInfo; + public String pushNotificationID; + public String pushNotificationType; + public String remoteGatewayId; + public String requestNodeNeighborStat; + public String requestNodeNeighborStatTimeStemp; + public String requestNodeNeighborState; + public String requestNodeNeighborStateTimeStemp; + public String saveLogs; + public String showChildren; + public String smsNotificationID; + public String smsNotificationType; + public String status; + public String sunriseHour; + public String sunsetHour; + public String userDescription; + public String value; + public String zwaveBuildVersion; + public String zwaveCompany; + public String zwaveInfo; + public String zwaveRegion; + public double zwaveVersion; + } + + public String room; + public String category; + public String fibaroaddress; + public String fibaroname; +} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java new file mode 100644 index 0000000..f0c8a26 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java @@ -0,0 +1,103 @@ +package com.bwssystems.HABridge.plugins.fibaro; + +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; + +import com.bwssystems.HABridge.BridgeSettings; +import com.bwssystems.HABridge.DeviceMapTypes; +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.MultiCommandUtil; + +public class FibaroHome implements Home +{ + private static final Logger log = LoggerFactory.getLogger(FibaroHome.class); + private Map fibaros; + private Boolean validFibaro; + + public FibaroHome(BridgeSettings bridgeSettings) + { + super(); + createHome(bridgeSettings); + } + + public List getDevices() + { + log.debug("consolidating devices for fibaros"); + Iterator keys = fibaros.keySet().iterator(); + ArrayList deviceList = new ArrayList<>(); + while(keys.hasNext()) + { + String key = keys.next(); + for(Device device : fibaros.get(key).getDevices()) + deviceList.add(device); + } + return deviceList; + } + + public List getScenes() + { + log.debug("consolidating scenes for fibaros"); + Iterator keys = fibaros.keySet().iterator(); + ArrayList sceneList = new ArrayList<>(); + while(keys.hasNext()) + { + String key = keys.next(); + for(Scene scene : fibaros.get(key).getScenes()) + sceneList.add(scene); + } + return sceneList; + } + + @Override + public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) + { + // Not a device handler + return null; + } + + @Override + public Object getItems(String type) + { + if(validFibaro) + { + if(type.equalsIgnoreCase(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex])) + return getDevices(); + if(type.equalsIgnoreCase(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex])) + return getScenes(); + } + return null; + } + + @Override + public Home createHome(BridgeSettings bridgeSettings) + { + validFibaro = bridgeSettings.getBridgeSettingsDescriptor().isValidFibaro(); + log.info("Fibaro Home created." + (validFibaro ? "" : " No Fibaros configured.")); + if(validFibaro) + { + fibaros = new HashMap(); + Iterator theList = bridgeSettings.getBridgeSettingsDescriptor().getFibaroAddress().getDevices().iterator(); + while(theList.hasNext()) + { + NamedIP aFibaro = theList.next(); + fibaros.put(aFibaro.getName(), new FibaroInfo(aFibaro)); + } + } + return this; + } + + @Override + public void closeHome() + { + fibaros = null; + } +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java new file mode 100644 index 0000000..019ff94 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java @@ -0,0 +1,146 @@ +package com.bwssystems.HABridge.plugins.fibaro; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.bwssystems.HABridge.NamedIP; +import com.bwssystems.HABridge.plugins.http.HTTPHandler; +import com.google.gson.Gson; + +public class FibaroInfo +{ + private static final Logger log = LoggerFactory.getLogger(FibaroInfo.class); + private HTTPHandler httpClient; + private NamedIP fibaroAddress; + + // You can disable it if you want + boolean useSaveLogs = true; // This can be used to exclude some devices from list + boolean useUserDescription = true; + boolean removeDigits = true; + boolean scenesWithLiliCommandOnly = true; + + public FibaroInfo(NamedIP addressName) + { + super(); + httpClient = new HTTPHandler(); + fibaroAddress = addressName; + } + + public Device[] getDevices() + { + Room[] rooms = getRooms(); + + log.debug("Founded: " + rooms.length + ", rooms"); + + Device[] all_devices = getAllDevices(); + int count = 0; + for(Device d : all_devices) + { + if(d.roomID > 0 && useSaveLogs ? "true".equals(d.properties.saveLogs) : true) + count++; + } + + Device[] devices = new Device[count]; + int i = 0; + for(Device d : all_devices) + if(d.roomID > 0 && useSaveLogs ? "true".equals(d.properties.saveLogs) : true) + { + if(useUserDescription && d.properties.userDescription != null && !d.properties.userDescription.isEmpty()) + d.name = d.properties.userDescription; + if(removeDigits) + d.name = replaceDigits(d.name); + devices[i++] = d; + + for(Room room : rooms) + if(d.roomID == room.id) + { + d.room = room.name.trim(); + d.category = String.valueOf(room.sectionID); // TODO load name of section + } + + d.fibaroaddress = fibaroAddress.getIp(); + d.fibaroname = fibaroAddress.getName(); + } + + log.debug("Founded: " + devices.length + " devices"); + + return devices; + } + + public Scene[] getScenes() + { + Room[] rooms = getRooms(); + int count = 0; + Scene[] scenes = getAllScenes(); + for(Scene s : scenes) + if(!scenesWithLiliCommandOnly || s.liliStartCommand != null && !s.liliStartCommand.isEmpty()) + count++; + Scene[] result = new Scene[count]; + int i = 0; + for(Scene s : scenes) + if(!scenesWithLiliCommandOnly || s.liliStartCommand != null && !s.liliStartCommand.isEmpty()) + { + result[i++] = s; + + for(Room room : rooms) + if(s.roomID == room.id) + { + s.room = room.name.trim(); + s.category = String.valueOf(room.sectionID); // TODO load name of section + } + + s.fibaroaddress = fibaroAddress.getIp(); + s.fibaroname = fibaroAddress.getName(); + } + System.out.println("Founded: " + count + " scenes"); + return result; + } + + private Device[] getAllDevices() + { + String result = request("devices?enabled=true&visible=true"); + if(result == null) + return new Device[0]; + Device[] devices = new Gson().fromJson(result, Device[].class); + return devices; + } + + private Scene[] getAllScenes() + { + String result = request("scenes?enabled=true&visible=true"); + if(result == null) + return new Scene[0]; + Scene[] scenes = new Gson().fromJson(result, Scene[].class); + return scenes; + } + + private Room[] getRooms() + { + String result = request("rooms"); + if(result == null) + return new Room[0]; + return new Gson().fromJson(result, Room[].class); + } + + private String request(String theUrl) + { + theUrl = "http://" + fibaroAddress.getIp() + "/api/" + theUrl; + return httpClient.doHttpRequest(theUrl, null, null, null, null); + } + + private String replaceDigits(String name) + { + name = name.replaceAll("1", ""); + name = name.replaceAll("2", ""); + name = name.replaceAll("3", ""); + name = name.replaceAll("4", ""); + name = name.replaceAll("5", ""); + name = name.replaceAll("6", ""); + name = name.replaceAll("7", ""); + name = name.replaceAll("8", ""); + name = name.replaceAll("9", ""); + name = name.replaceAll("0", ""); + name = name.trim(); + return name; + } +} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java new file mode 100644 index 0000000..0f7433e --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java @@ -0,0 +1,19 @@ +package com.bwssystems.HABridge.plugins.fibaro; + +public class Room +{ + public int id; + public String name; + public int sectionID; + public String icon; + public Sensor defaultSensors; + public int defaultThermostat; + public int sortOrder; + + public class Sensor + { + public int temperature; + public int humidity; + public int light; + } +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java new file mode 100644 index 0000000..da4ce01 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java @@ -0,0 +1,39 @@ +package com.bwssystems.HABridge.plugins.fibaro; + +public class Scene +{ + public int id; + public String name; + public String type; + public String properties; + public int roomID; + public int iconID; + public String runConfig; + public boolean autostart; + public boolean protectedByPIN; + public boolean killable; + public int maxRunningInstances; + public int runningInstances; + public boolean visible; + public boolean isLua; + public Triggers triggers; + public String liliStartCommand; + public String liliStopCommand; + public int sortOrder; + + public class Triggers { + public Properties[] properties; + public String[] globals; + public String[] events; + } + + public class Properties { + public String id; + public String name; + } + + public String room; + public String category; + public String fibaroaddress; + public String fibaroname; +} \ No newline at end of file diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index f98bcce..b103d67 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -26,7 +26,15 @@ app.config (function ($locationProvider, $routeProvider) { }).when ('/verascenes', { templateUrl: 'views/verascene.html', controller: 'VeraController', + requiresAuthentication: true + }).when ('/fibarodevices', { + templateUrl: 'views/fibarodevice.html', + controller: 'FibaroController', requiresAuthentication: true + }).when ('/fibaroscenes', { + templateUrl: 'views/fibaroscene.html', + controller: 'FibaroController', + requiresAuthentication: true }).when ('/harmonydevices', { templateUrl: 'views/harmonydevice.html', controller: 'HarmonyController', @@ -133,7 +141,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n var self = this; 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, + isInControl: false, showVera: false, showFibaro: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false, showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: {}, viewDevId: "", queueDevId: "", securityInfo: {}}; this.displayWarn = function(errorTitle, error) { @@ -455,6 +463,11 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n this.state.showVera = self.state.settings.veraconfigured; return; } + + this.updateShowFibaro = function () { + this.state.showFibaro = self.state.settings.fibaroconfigured; + return; + } this.updateShowNest = function () { this.state.showNest = self.state.settings.nestconfigured; @@ -506,6 +519,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n function (response) { self.state.settings = response.data; self.updateShowVera(); + self.updateShowFibaro(); self.updateShowHarmony(); self.updateShowNest(); self.updateShowHue(); @@ -644,6 +658,38 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n } ); }; + + this.viewFibaroDevices = function () { + if(!this.state.showFibaro) + return; + return $http.get(this.state.base + "/fibaro/devices").then( + function (response) { + self.state.fibarodevices = response.data; + }, + function (error) { + if (error.status === 401) + $rootScope.$broadcast('securityReinit', 'done'); + else + self.displayWarn("Get Fibaro Devices Error: ", error); + } + ); + }; + + this.viewFibaroScenes = function () { + if(!this.state.showFibaro) + return; + return $http.get(this.state.base + "/fibaro/scenes").then( + function (response) { + self.state.fibaroscenes = response.data; + }, + function (error) { + if (error.status === 401) + $rootScope.$broadcast('securityReinit', 'done'); + else + self.displayWarn("Get Fibaro Scenes Error: ", error); + } + ); + }; this.viewHarmonyActivities = function () { if (!this.state.showHarmony) @@ -1285,6 +1331,22 @@ app.controller ('SystemController', function ($scope, $location, bridgeService, } } }; + $scope.addFibarotoSettings = function (newfibaroname, newfibaroip) { + if($scope.bridge.settings.fibaroaddress === undefined || $scope.bridge.settings.fibaroaddress === null) { + $scope.bridge.settings.fibaroaddress = { devices: [] }; + } + var newFibaro = {name: newfibaroname, ip: newfibaroip } + $scope.bridge.settings.fibaroaddress.devices.push(newFibaro); + $scope.newfibaroname = null; + $scope.newfibaroip = null; + }; + $scope.removeFibarotoSettings = function (fibaroname, fibaroip) { + for(var i = $scope.bridge.settings.fibaroaddress.devices.length - 1; i >= 0; i--) { + if($scope.bridge.settings.fibaroaddress.devices[i].name === fibaroname && $scope.bridge.settings.fibaroaddress.devices[i].ip === fibaroip) { + $scope.bridge.settings.fibaroaddress.devices.splice(i, 1); + } + } + }; $scope.addHarmonytoSettings = function (newharmonyname, newharmonyip) { if($scope.bridge.settings.harmonyaddress === undefined || $scope.bridge.settings.harmonyaddress === null) { $scope.bridge.settings.harmonyaddress = { devices: [] }; @@ -1898,6 +1960,162 @@ app.controller('VeraController', function ($scope, $location, bridgeService, ngD }; }); +app.controller('FibaroController', function ($scope, $location, bridgeService, ngDialog) { + $scope.bridge = bridgeService.state; + $scope.device = bridgeService.state.device; + $scope.device_dim_control = ""; + $scope.bulk = { devices: [] }; + $scope.selectAll = false; + $scope.fibaro = {base: "http://", port: "80", id: ""}; + bridgeService.viewFibaroDevices(); + bridgeService.viewFibaroScenes(); + $scope.imgButtonsUrl = "glyphicon glyphicon-plus"; + $scope.buttonsVisible = false; + $scope.comparatorUniqueId = bridgeService.compareUniqueId; + + $scope.clearDevice = function () { + bridgeService.clearDevice(); + $scope.device = bridgeService.state.device; + }; + + $scope.buildDeviceUrls = function (fibarodevice, dim_control, buildonly) { + if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) { + dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + + "/data_request?id=action&output_format=json&DeviceNum=" + + fibarodevice.id + + "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=" + + dim_control; + } + else + dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" + + fibarodevice.id; + onpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" + + fibarodevice.id; + offpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=" + + fibarodevice.id; + + bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, fibarodevice.id, fibarodevice.name, fibarodevice.fibaroname, "switch", "fibaroDevice", null, null); + $scope.device = bridgeService.state.device; + if (!buildonly) { + bridgeService.editNewDevice($scope.device); + $location.path('/editdevice'); + } + }; + + $scope.buildSceneUrls = function (fibaroscene) { + onpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port + + "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum=" + + fibaroscene.id; + offpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port + + "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum=" + + fibarocene.id; + + bridgeService.buildUrls(onpayload, null, offpayload, false, fibaroscene.id, fibaroscene.name, fibaroscene.fibaroname, "scene", "fibaroScene", null, null); + $scope.device = bridgeService.state.device; + bridgeService.editNewDevice($scope.device); + $location.path('/editdevice'); + }; + + $scope.bulkAddDevices = function(dim_control) { + var devicesList = []; + $scope.clearDevice(); + for(var i = 0; i < $scope.bulk.devices.length; i++) { + for(var x = 0; x < bridgeService.state.fibarodevices.length; x++) { + if(bridgeService.state.fibarodevices[x].id === $scope.bulk.devices[i]) { + $scope.buildDeviceUrls(bridgeService.state.fibarodevices[x],dim_control,true); + devicesList[i] = { + name: $scope.device.name, + mapId: $scope.device.mapId, + mapType: $scope.device.mapType, + deviceType: $scope.device.deviceType, + targetDevice: $scope.device.targetDevice, + onUrl: $scope.device.onUrl, + dimUrl: $scope.device.dimUrl, + offUrl: $scope.device.offUrl, + headers: $scope.device.headers, + httpVerb: $scope.device.httpVerb, + contentType: $scope.device.contentType, + contentBody: $scope.device.contentBody, + contentBodyDim: $scope.device.contentBodyDim, + contentBodyOff: $scope.device.contentBodyOff + }; + $scope.clearDevice(); + } + } + } + bridgeService.bulkAddDevice(devicesList).then( + function () { + $scope.clearDevice(); + bridgeService.viewDevices(); + bridgeService.viewfibaroDevices(); + bridgeService.viewfibaroScenes(); + }, + function (error) { + bridgeService.displayWarn("Error adding fibaro devices in bulk.", error) + } + ); + $scope.bulk = { devices: [] }; + $scope.selectAll = false; + }; + + $scope.toggleSelection = function toggleSelection(deviceId) { + var idx = $scope.bulk.devices.indexOf(deviceId); + + // is currently selected + if (idx > -1) { + $scope.bulk.devices.splice(idx, 1); + if($scope.bulk.devices.length === 0 && $scope.selectAll) + $scope.selectAll = false; + } + + // is newly selected + else { + $scope.bulk.devices.push(deviceId); + $scope.selectAll = true; + } + }; + + $scope.toggleSelectAll = function toggleSelectAll() { + if($scope.selectAll) { + $scope.selectAll = false; + $scope.bulk = { devices: [] }; + } + else { + $scope.selectAll = true; + for(var x = 0; x < bridgeService.state.fibarodevices.length; x++) { + if($scope.bulk.devices.indexOf(bridgeService.state.fibarodevices[x]) < 0) + $scope.bulk.devices.push(bridgeService.state.fibarodevices[x].id); + } + } + }; + + $scope.toggleButtons = function () { + $scope.buttonsVisible = !$scope.buttonsVisible; + if($scope.buttonsVisible) + $scope.imgButtonsUrl = "glyphicon glyphicon-minus"; + else + $scope.imgButtonsUrl = "glyphicon glyphicon-plus"; + }; + + $scope.deleteDevice = function (device) { + $scope.bridge.device = device; + ngDialog.open({ + template: 'deleteDialog', + controller: 'DeleteDialogCtrl', + className: 'ngdialog-theme-default' + }); + }; + + $scope.editDevice = function (device) { + bridgeService.editDevice(device); + $location.path('/editdevice'); + }; +}); + + app.controller('HarmonyController', function ($scope, $location, bridgeService, ngDialog) { $scope.bridge = bridgeService.state; $scope.device = bridgeService.state.device; @@ -3228,6 +3446,34 @@ app.filter('configuredVeraScenes', function (bridgeService) { } }); +app.filter('configuredFibaroDevices', function (bridgeService) { + return function(input) { + var out = []; + if(input === undefined || input === null || input.length === undefined) + return out; + for (var i = 0; i < input.length; i++) { + if(bridgeService.deviceContainsType(input[i], "fibaroDevice")){ + out.push(input[i]); + } + } + return out; + } +}); + +app.filter('configuredFibaroScenes', function (bridgeService) { + return function(input) { + var out = []; + if(input === undefined || input === null || input.length === undefined) + return out; + for (var i = 0; i < input.length; i++) { + if(bridgeService.deviceContainsType(input[i], "fibaroScene")){ + out.push(input[i]); + } + } + return out; + } +}); + app.filter('configuredNestItems', function (bridgeService) { return function(input) { var out = []; diff --git a/src/main/resources/public/views/configuration.html b/src/main/resources/public/views/configuration.html index def1839..145a015 100644 --- a/src/main/resources/public/views/configuration.html +++ b/src/main/resources/public/views/configuration.html @@ -8,6 +8,10 @@ href="#!/veradevices">Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • +
  • Bridge Devices
  • +
  • Bridge Control
  • +
  • Logs
  • +
  • Vera Devices
  • +
  • Vera Scenes
  • + +
  • Fibaro Scenes
  • +
  • Harmony Activities
  • +
  • Harmony Devices
  • +
  • Nest
  • +
  • Hue Devices
  • +
  • HAL Devices
  • +
  • MQTT Messages
  • +
  • HomeAssistant Devices
  • +
  • Domoticz Devices
  • +
  • Somfy Devices
  • +
  • LIFX Devices
  • +
  • Add/Edit
  • + + +
    +
    +

    Fibaro Device List + ({{bridge.fibarodevices.length}})

    +
    +
    +

    For any Fibaro Device, use the build action buttons + to generate the item addition information into the ha-bridge device + and this will put you into the edit screen. Then + you can modify the name to anything you want that will be the keyword + for the Echo or Google Home. Also, you can go back to any helper tab and click a build + action button to add another item for a multi-command. After you are + done in the edit tab, click the 'Add Bridge Device' to finish that selection + setup. The 'Already Configured Fibaro Devices' list below will show + what is already setup for your Fibaro.

    +

    + Also, use this select menu for which type of dim control you would + like to be generated: +

    +

    Use the check boxes by the names to use the bulk addition + feature. Select your items and dim control type if wanted, then click + bulk add below. Your items will be added with on and off or dim and + off if selected with the name of the device from the Fibaro.

    + + + + + + + + + + + + + + + + + + + + + + +
    Row NameIdCategoryRoomFibaroBuild Actions
    {{$index+1}} + {{fibarodevice.name}}{{fibarodevice.id}}{{fibarodevice.category}}{{fibarodevice.room}}{{fibarodevice.fibaroname}} + +
    +
    + +
    +
    +
    +
    +

    + Already Configured Fibaro Devices +

    +
    +
    + + + + + + + + + + + + + + + + + + +
    RowNameFibaroMap IdActions
    {{$index+1}}{{device.name}}{{device.targetDevice}}{{device.mapId}} +

    + + +

    +
    +
    +
    +
    + \ No newline at end of file diff --git a/src/main/resources/public/views/fibaroscene.html b/src/main/resources/public/views/fibaroscene.html new file mode 100644 index 0000000..7b1ba14 --- /dev/null +++ b/src/main/resources/public/views/fibaroscene.html @@ -0,0 +1,114 @@ + + +
    +
    +

    Fibaro Scene List

    +
    +
    +

    For any Fibaro Scene, use the build action buttons + to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then + you can modify the name to anything you want that will be the keyword + for the Echo or Google Home. Also, you can go back to any helper tab and click a build + action button to add another item for a multi-command. After you are + done in the edit tab, click the 'Add Bridge Device' to finish that selection + setup. The 'Already Configured Fibaro Scenes' list below will show what + is already setup for your Fibaro.

    + + + + + + + + + + + + + + + + + + + + + +
    RowNameIdRoomFibaroBuild Actions
    {{$index+1}}{{fibaroscene.name}}{{fibaroscene.id}}{{fibaroscene.room}}{{fibaroscene.fibaroname}} + +
    +
    +
    +
    +
    +
    +

    + Already Configured Fibaro Scenes +

    +
    +
    + + + + + + + + + + + + + + + + + + +
    RowNameFibaroMap IdActions
    {{$index+1}}{{device.name}}{{device.targetDevice}}{{device.mapId}} +

    + + +

    +
    +
    +
    +
    + \ No newline at end of file diff --git a/src/main/resources/public/views/haldevice.html b/src/main/resources/public/views/haldevice.html index 7d365e2..0e69323 100644 --- a/src/main/resources/public/views/haldevice.html +++ b/src/main/resources/public/views/haldevice.html @@ -6,6 +6,10 @@ href="#!/veradevices">Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony diff --git a/src/main/resources/public/views/harmonydevice.html b/src/main/resources/public/views/harmonydevice.html index a4f51d2..e20b0fa 100644 --- a/src/main/resources/public/views/harmonydevice.html +++ b/src/main/resources/public/views/harmonydevice.html @@ -6,6 +6,10 @@ href="#!/veradevices">Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Logs
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Harmony Devices
  • Nest
  • diff --git a/src/main/resources/public/views/logs.html b/src/main/resources/public/views/logs.html index c1d853c..fca1aee 100644 --- a/src/main/resources/public/views/logs.html +++ b/src/main/resources/public/views/logs.html @@ -6,6 +6,10 @@ href="#!/veradevices">Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Logs
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Harmony Devices
  • Nest
  • diff --git a/src/main/resources/public/views/nestactions.html b/src/main/resources/public/views/nestactions.html index c91cff6..34875b9 100644 --- a/src/main/resources/public/views/nestactions.html +++ b/src/main/resources/public/views/nestactions.html @@ -6,6 +6,10 @@ href="#!/veradevices">Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Bridge Devices
  • Bridge Control
  • Logs
  • -
  • Vera - Devices
  • +
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Vera Devices
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • + + Fibaro Names and IP Addresses + + + + + + + + + + + + + + + + + + +
    NameIPManage
    {{fibaro.name}}{{fibaro.ip}}
    + Harmony Names and IP Addresses Bridge Devices
  • Bridge Control
  • Logs
  • - +
  • Vera Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Bridge Control
  • Logs
  • Vera Devices
  • - + +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Date: Thu, 4 May 2017 03:48:24 +0300 Subject: [PATCH 02/28] fix requests --- src/main/resources/public/scripts/app.js | 44 ++++++++---------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index b103d67..1f8f8a2 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -1979,39 +1979,25 @@ app.controller('FibaroController', function ($scope, $location, bridgeService, n }; $scope.buildDeviceUrls = function (fibarodevice, dim_control, buildonly) { - if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) { - dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port - + "/data_request?id=action&output_format=json&DeviceNum=" - + fibarodevice.id - + "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=" - + dim_control; - } - else - dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port - + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" - + fibarodevice.id; - onpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port - + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=1&DeviceNum=" - + fibarodevice.id; - offpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port - + "/data_request?id=action&output_format=json&serviceId=urn:upnp-org:serviceId:SwitchPower1&action=SetTarget&newTargetValue=0&DeviceNum=" - + fibarodevice.id; + if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) + dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=setValue&arg1=" + dim_control; + else + dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOn"; + + onpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOn"; + offpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOff"; - bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, fibarodevice.id, fibarodevice.name, fibarodevice.fibaroname, "switch", "fibaroDevice", null, null); - $scope.device = bridgeService.state.device; - if (!buildonly) { - bridgeService.editNewDevice($scope.device); - $location.path('/editdevice'); - } + bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, fibarodevice.id, fibarodevice.name, fibarodevice.fibaroname, "switch", "fibaroDevice", null, null); + $scope.device = bridgeService.state.device; + if (!buildonly) { + bridgeService.editNewDevice($scope.device); + $location.path('/editdevice'); + } }; $scope.buildSceneUrls = function (fibaroscene) { - onpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port - + "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum=" - + fibaroscene.id; - offpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port - + "/data_request?id=action&output_format=json&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene&SceneNum=" - + fibarocene.id; + onpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port + "/api/sceneControl?id=" + fibaroscene.id + "&action=start"; + offpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port + "/api/sceneControl?id=" + fibaroscene.id + "&action=stop"; bridgeService.buildUrls(onpayload, null, offpayload, false, fibaroscene.id, fibaroscene.name, fibaroscene.fibaroname, "scene", "fibaroScene", null, null); $scope.device = bridgeService.state.device; From 9aaab37a17e829a3c94bf09f92d797385ca87edf Mon Sep 17 00:00:00 2001 From: diamond Date: Thu, 4 May 2017 05:59:04 +0300 Subject: [PATCH 03/28] auth --- .../bwssystems/HABridge/BridgeSettings.java | 2 +- .../HABridge/plugins/fibaro/FibaroInfo.java | 45 +++++++++++++++---- src/main/resources/public/scripts/app.js | 6 ++- .../resources/public/views/fibarodevice.html | 4 +- .../resources/public/views/fibaroscene.html | 4 +- src/main/resources/public/views/system.html | 13 +++++- 6 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java index 200f267..d6d54f7 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java @@ -110,7 +110,7 @@ public class BridgeSettings extends BackupHandler { theBridgeSettings.setVeraAddress(theVeraList); theFibaroAddress = System.getProperty("fibaro.address"); - IpList theFibaroList = null; + IpList theFibaroList = null; if(theFibaroAddress != null) { try { theFibaroList = new Gson().fromJson(theFibaroAddress, IpList.class); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java index 019ff94..bbd6ae2 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java @@ -1,16 +1,20 @@ package com.bwssystems.HABridge.plugins.fibaro; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +import org.apache.commons.codec.binary.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bwssystems.HABridge.NamedIP; -import com.bwssystems.HABridge.plugins.http.HTTPHandler; import com.google.gson.Gson; public class FibaroInfo { private static final Logger log = LoggerFactory.getLogger(FibaroInfo.class); - private HTTPHandler httpClient; private NamedIP fibaroAddress; // You can disable it if you want @@ -22,7 +26,6 @@ public class FibaroInfo public FibaroInfo(NamedIP addressName) { super(); - httpClient = new HTTPHandler(); fibaroAddress = addressName; } @@ -35,10 +38,8 @@ public class FibaroInfo Device[] all_devices = getAllDevices(); int count = 0; for(Device d : all_devices) - { if(d.roomID > 0 && useSaveLogs ? "true".equals(d.properties.saveLogs) : true) count++; - } Device[] devices = new Device[count]; int i = 0; @@ -62,7 +63,7 @@ public class FibaroInfo d.fibaroname = fibaroAddress.getName(); } - log.debug("Founded: " + devices.length + " devices"); + log.info("Founded: " + devices.length + " devices"); return devices; } @@ -92,7 +93,7 @@ public class FibaroInfo s.fibaroaddress = fibaroAddress.getIp(); s.fibaroname = fibaroAddress.getName(); } - System.out.println("Founded: " + count + " scenes"); + log.info("Founded: " + count + " scenes"); return result; } @@ -125,7 +126,35 @@ public class FibaroInfo private String request(String theUrl) { theUrl = "http://" + fibaroAddress.getIp() + "/api/" + theUrl; - return httpClient.doHttpRequest(theUrl, null, null, null, null); + String auth = new String(Base64.encodeBase64((fibaroAddress.getUsername() + ":" + fibaroAddress.getPassword()).getBytes())); + java.net.URL url; + java.net.HttpURLConnection connection; + String result = null; + try + { + url = new URL(theUrl); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Authorization", "Basic " + auth); + connection.setRequestProperty("Content-Type", "application/json;charset=utf-8"); + connection.setRequestProperty("X-Requested-With", "XMLHttpRequest"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.155 Safari/537.36"); + connection.connect(); + BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); + StringBuilder buffer = new StringBuilder(); + String line; + while((line = br.readLine()) != null) + buffer.append(line).append("\n"); + br.close(); + result = buffer.toString(); + } + catch(Exception e) + { + log.info("Error while get getJson: " + theUrl); + e.printStackTrace(); + return null; + } + return result; } private String replaceDigits(String name) diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 1f8f8a2..3b3e5c2 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -1331,14 +1331,16 @@ app.controller ('SystemController', function ($scope, $location, bridgeService, } } }; - $scope.addFibarotoSettings = function (newfibaroname, newfibaroip) { + $scope.addFibarotoSettings = function (newfibaroname, newfibaroip, newfibarousername, newfibaropassword) { if($scope.bridge.settings.fibaroaddress === undefined || $scope.bridge.settings.fibaroaddress === null) { $scope.bridge.settings.fibaroaddress = { devices: [] }; } - var newFibaro = {name: newfibaroname, ip: newfibaroip } + var newFibaro = {name: newfibaroname, ip: newfibaroip, username: newfibarousername, password: newfibaropassword } $scope.bridge.settings.fibaroaddress.devices.push(newFibaro); $scope.newfibaroname = null; $scope.newfibaroip = null; + $scope.newfibarousername = null; + $scope.newfibaropassword = null; }; $scope.removeFibarotoSettings = function (fibaroname, fibaroip) { for(var i = $scope.bridge.settings.fibaroaddress.devices.length - 1; i >= 0; i--) { diff --git a/src/main/resources/public/views/fibarodevice.html b/src/main/resources/public/views/fibarodevice.html index 25c7145..fe8e513 100644 --- a/src/main/resources/public/views/fibarodevice.html +++ b/src/main/resources/public/views/fibarodevice.html @@ -2,8 +2,8 @@
  • Bridge Devices
  • Bridge Control
  • Logs
  • -
  • Vera Devices
  • -
  • Vera Scenes
  • +
  • Vera Devices
  • +
  • Vera Scenes
  • Fibaro Scenes
  • Bridge Devices
  • Bridge Control
  • Logs
  • -
  • Vera Devices
  • -
  • Vera Scenes
  • +
  • Vera Devices
  • +
  • Vera Scenes
  • Fibaro Devices
  • + + + + + @@ -158,8 +163,14 @@ + + + ng-click="addFibarotoSettings(newfibaroname, newfibaroip, newfibarousername, newfibaropassword)">Add
    Name IPUsernamePassword Manage
    {{fibaro.name}} {{fibaro.ip}}{{fibaro.username}}*******
    From 86371c03b2c4819af9b1e6fccd367ed4b8fddb51 Mon Sep 17 00:00:00 2001 From: Admin Date: Tue, 27 Jun 2017 16:12:47 -0500 Subject: [PATCH 04/28] Updating Color calculation --- pom.xml | 2 +- .../bwssystems/HABridge/hue/ColorDecode.java | 123 ++++++++++++++++-- .../color/test/ConvertCIEColorTestCase.java | 11 +- 3 files changed, 120 insertions(+), 16 deletions(-) diff --git a/pom.xml b/pom.xml index 498e56a..9bc590f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 4.5.6 + 4.5.6a jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java index 1585d45..2832fdf 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java +++ b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java @@ -1,21 +1,120 @@ package com.bwssystems.HABridge.hue; +import java.util.ArrayList; import java.util.List; -public class ColorDecode { +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - public static String convertCIEtoRGB(List xy) { - double x; - double y; - double Y; +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}"; + + public static List convertCIEtoRGB(List xy, int brightness) { + List 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; + double Y = (double)brightness/(double)254.00; // The given brightness value + double X = (Y / y) * x; + double Z = (Y / y) * z; + + double r = X * 1.656492 - Y * 0.354851 - Z * 0.255038; + double g = -X * 0.707196 + Y * 1.655397 + Z * 0.036152; + double b = X * 0.051713 - Y * 0.121364 + Z * 1.011530; + + if (r > b && r > g && r > 1.0) { + + g = g / r; + b = b / r; + r = 1.0; + } + else if (g > b && g > r && g > 1.0) { + + r = r / g; + b = b / g; + g = 1.0; + } + else if (b > r && b > g && b > 1.0) { + + r = r / b; + g = g / b; + b = 1.0; + } + + + r = r <= 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math.pow(r, (1.0 / 2.4)) - 0.055; + g = g <= 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math.pow(g, (1.0 / 2.4)) - 0.055; + b = b <= 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math.pow(b, (1.0 / 2.4)) - 0.055; - x = xy.get(0) * 100; - y = xy.get(1) * 100; - Y= y; - double R = 3.240479*((x*Y)/y) + -1.537150*Y + -0.498535*(((1-x-y)*Y)/y); - double G = -0.969256*((x*Y)/y) + 1.875992*Y + 0.041556*(((1-x-y)*Y)/y); - double B = 0.055648*((x*Y)/y) + -0.204043*Y + 1.057311*(((1-x-y)*Y)/y); + if (r > b && r > g) { + // red is biggest + if (r > 1.0) { + g = g / r; + b = b / r; + r = 1.0; + } + } + else if (g > b && g > r) { + // green is biggest + if (g > 1.0) { + r = r / g; + b = b / g; + g = 1.0; + } + } + else if (b > r && b > g) { + // blue is biggest + if (b > 1.0) { + r = r / b; + g = g / b; + b = 1.0; + } + } + if(r < 0.0) + r = 0; + if(g < 0.0) + g = 0; + if(b < 0.0) + b = 0; + r = Math.round(r * 255); + g = Math.round(g * 255); + b = Math.round(b * 255); + rgb = new ArrayList(); + rgb.add(0, r); + rgb.add(1, g); + rgb.add(2, b); + return rgb; + } + + public static String replaceColorData(String request, List xy, int setIntensity) { + if (request == null) { + return null; + } + boolean notDone = true; + List rgb = convertCIEtoRGB(xy, setIntensity); - return null; + while(notDone) { + notDone = false; + if (request.contains(COLOR_R)) { + request = request.replace(COLOR_R, String.valueOf(rgb.get(0))); + notDone = true; + } + + if (request.contains(COLOR_G)) { + request = request.replace(COLOR_G, String.valueOf(rgb.get(1))); + notDone = true; + } + + if (request.contains(COLOR_B)) { + request = request.replace(COLOR_B, String.valueOf(rgb.get(2))); + notDone = true; + } + + log.debug("Request <<" + request + ">>, not done: " + notDone); + } + return request; } } diff --git a/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java b/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java index 4d148be..6791b46 100644 --- a/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java +++ b/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java @@ -2,6 +2,7 @@ package com.bwssystems.color.test; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.junit.Assert; import org.junit.Test; @@ -12,10 +13,14 @@ public class ConvertCIEColorTestCase { @Test public void testColorConversion() { - ArrayList xy = new ArrayList(Arrays.asList(new Double(0.3972), new Double(0.4564))); + ArrayList xy = new ArrayList(Arrays.asList(new Double(0.671254), new Double(0.303273))); - String colorDecode = ColorDecode.convertCIEtoRGB(xy); - Assert.assertEquals(colorDecode, null); + List colorDecode = ColorDecode.convertCIEtoRGB(xy, 254); + List assertDecode = new ArrayList(); + assertDecode.add(0, 255.0); + assertDecode.add(1, 47.0); + assertDecode.add(2, 43.0); + Assert.assertEquals(colorDecode, assertDecode); } } From 430eff958c7c5d79f072ffcf8e6e9f53a233e8e9 Mon Sep 17 00:00:00 2001 From: Admin Date: Wed, 28 Jun 2017 16:02:45 -0500 Subject: [PATCH 05/28] Updateing color translation --- .../bwssystems/HABridge/hue/ColorDecode.java | 7 +- .../com/bwssystems/HABridge/hue/ColorMap.java | 75 +++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/hue/ColorMap.java diff --git a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java index 2832fdf..03439ae 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java +++ b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java @@ -79,13 +79,14 @@ public class ColorDecode { g = 0; if(b < 0.0) b = 0; - r = Math.round(r * 255); - g = Math.round(g * 255); - b = Math.round(b * 255); + rgb = new ArrayList(); 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)); return rgb; } diff --git a/src/main/java/com/bwssystems/HABridge/hue/ColorMap.java b/src/main/java/com/bwssystems/HABridge/hue/ColorMap.java new file mode 100644 index 0000000..3460bb3 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/hue/ColorMap.java @@ -0,0 +1,75 @@ +package com.bwssystems.HABridge.hue; + +public class ColorMap { + private double red; + private double green; + private double blue; + private long R; + private long G; + private long B; + private double X; + private double Y; + private Double Z; + private double z; + public double getRed() { + return red; + } + public void setRed(double red) { + this.red = red; + } + public double getGreen() { + return green; + } + public void setGreen(double green) { + this.green = green; + } + public double getBlue() { + return blue; + } + public void setBlue(double blue) { + this.blue = blue; + } + public long getR() { + return R; + } + public void setR(long r) { + R = r; + } + public long getG() { + return G; + } + public void setG(long g) { + G = g; + } + public long getB() { + return B; + } + public void setB(long b) { + B = b; + } + public double getX() { + return X; + } + public void setX(double x) { + X = x; + } + public double getY() { + return Y; + } + public void setY(double y) { + Y = y; + } + public Double getZ() { + return Z; + } + public void setZ(Double z) { + Z = z; + } + public double getz() { + return z; + } + public void setz(double z) { + this.z = z; + } + +} From 3a5262ff33ef5b578b97bba9ba9a3e244602c062 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 23 Jul 2017 10:15:00 +0200 Subject: [PATCH 06/28] Added ColorUrl and alternative item edit mode Additional to on/off/dim items i added color items. The colorUrl gets executed if a PUT is received with xy/ct/hue/sat in the body. Also changed the emulated bulb type to "Extended color light". Added "Change Editmode" button in the editdevice screen. Switch between manual JSON edit and the tabular variant. Local unsaved changes in one mode carry over to the other. Through this edit variant it's possible to change the order of items and do copy/paste. --- .../HABridge/api/hue/DeviceResponse.java | 27 +- .../HABridge/api/hue/DeviceState.java | 20 +- .../HABridge/dao/DeviceDescriptor.java | 14 + .../bwssystems/HABridge/hue/HueMulator.java | 98 +++---- src/main/resources/public/scripts/app.js | 185 +++++++++--- .../resources/public/views/editdevice.html | 276 ++++++++++++++---- 6 files changed, 456 insertions(+), 164 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java index 8d25c60..b27050e 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java @@ -14,6 +14,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 +73,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; } @@ -86,9 +105,11 @@ public class DeviceResponse { response.setName(device.getName()); response.setUniqueid(device.getUniqueid()); response.setManufacturername("Philips"); - response.setType("Dimmable light"); - response.setModelid("LWB004"); - response.setSwversion("66012040"); + 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; diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java index f01e980..c3bcbac 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java @@ -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 xy; private int ct; private String alert; private String colormode; private boolean reachable; - private List 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 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 doubleArray = new ArrayList(); -// doubleArray.add(new Double(0)); -// doubleArray.add(new Double(0)); -// newDeviceState.setXy(doubleArray); + newDeviceState.setColormode("ct"); + newDeviceState.setCt(200); + ArrayList doubleArray = new ArrayList(); + doubleArray.add(new Double(0)); + doubleArray.add(new Double(0)); + newDeviceState.setXy(doubleArray); return newDeviceState; } diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java index 7480be7..26bfdec 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java @@ -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; } diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 038bdce..0718b00 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -467,16 +467,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 +475,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 +513,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\"")) { @@ -931,7 +927,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(); diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 58fa27f..4bf6dc1 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -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) { diff --git a/src/main/resources/public/views/editdevice.html b/src/main/resources/public/views/editdevice.html index ae1439d..fbd2f86 100644 --- a/src/main/resources/public/views/editdevice.html +++ b/src/main/resources/public/views/editdevice.html @@ -56,6 +56,7 @@ ng-click="editDevice(false)">Update Bridge Device +

    @@ -147,7 +148,14 @@ - + + + + + + + - + @@ -171,20 +179,20 @@
    - + - - - --> + -
    -
    - - - - --> + -
    @@ -159,7 +167,7 @@ Target Item Delay CountFilter IPs Http Verb Http Body Http Headers
    @@ -220,24 +228,24 @@
    @@ -274,7 +282,14 @@
    - + + + + + + + @@ -286,7 +301,7 @@ Target Item Delay Count - Filter IPs + Http Verb Http Body Http Headers @@ -297,22 +312,22 @@
    - - - - - - + @@ -324,7 +339,7 @@ - @@ -348,24 +363,24 @@
    - - - - - - + @@ -377,7 +392,7 @@ - @@ -402,7 +417,14 @@ - + + + + + + + @@ -414,7 +436,7 @@ Target Item Delay Count - Filter IPs + Http Verb Http Body Http Headers @@ -425,22 +447,22 @@
    - - - - - - + @@ -452,7 +474,7 @@ - @@ -476,24 +498,24 @@
    - - - - - - + @@ -505,7 +527,7 @@ - @@ -530,6 +552,140 @@ + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + +
    +
    + + + + + + + + + + + +
    TypeTarget ItemDelayCountHttp VerbHttp BodyHttp HeadersContent TypeManage
    +
    +
    From cd2bd072ed0d9193a3ba8335ca9c6981b050397c Mon Sep 17 00:00:00 2001 From: Zsolt Prontvai Date: Thu, 27 Jul 2017 18:54:18 +0200 Subject: [PATCH 07/28] Fix table in README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ac04bf4..aa9ac25 100644 --- a/README.md +++ b/README.md @@ -315,6 +315,7 @@ Another way to add a device is through the Manual Add Tab. This allows you to ma There is a new format for the on/dim/off URL areas. The new editor handles the intricacies of the components, but is broken down here for explanation. Here are the fields that can be put into the call item: + Json Type | field name | What | Use ----------|------------|------|----- String or JsonElement | item | This is the payload that will be called for devices | Required From 20ad6891e83b1fbeb6213cb73e55b0539cf25e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20F=C3=B6rderreuther?= Date: Thu, 27 Jul 2017 23:20:02 +0200 Subject: [PATCH 08/28] 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. --- .gitignore | 2 + .../bwssystems/HABridge/BridgeSettings.java | 1 + .../HABridge/BridgeSettingsDescriptor.java | 9 + .../com/bwssystems/HABridge/HABridge.java | 2 +- .../HABridge/api/hue/GroupClassTypes.java | 61 ++++ .../HABridge/api/hue/GroupResponse.java | 87 ++++-- .../HABridge/api/hue/GroupState.java | 38 +++ .../HABridge/dao/DeviceRepository.java | 47 +++ .../HABridge/dao/GroupDescriptor.java | 139 +++++++++ .../HABridge/dao/GroupRepository.java | 213 +++++++++++++ .../devicemanagmeent/DeviceResource.java | 17 ++ .../bwssystems/HABridge/hue/HueMulator.java | 285 ++++++++++++++++-- .../resources/public/views/editdevice.html | 40 +-- src/main/resources/public/views/system.html | 7 + 14 files changed, 879 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/api/hue/GroupClassTypes.java create mode 100644 src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java create mode 100644 src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java create mode 100644 src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java diff --git a/.gitignore b/.gitignore index 8e4103f..b5dcae6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ data /.settings/ /start.bat /.classpath + +sftp-config\.json diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java index 9365f9d..870d157 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java @@ -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"); diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java index 434c99e..5faa20a 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java @@ -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; } diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index 087354e..b636a84 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -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(); diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupClassTypes.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupClassTypes.java new file mode 100644 index 0000000..f8e7505 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupClassTypes.java @@ -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 groupClassTypes; + + public GroupClassTypes() { + groupClassTypes = new ArrayList(); + 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; + } +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java index cdaf02b..6e6ead5 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java @@ -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 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 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 deviceList) { + String[] theList = new String[deviceList.size()]; + Boolean all_on = true; + Boolean any_on = false; + int i = 0; + for (Map.Entry 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 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; + } } diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java new file mode 100644 index 0000000..40fb535 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java @@ -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 + + '}'; + } +} diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java index 61b38ed..f048300 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java +++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java @@ -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 findAllByRequester(String anAddress) { List list = new ArrayList(devices.values()); + return findAllByRequester(anAddress, list); + } + + private List findAllByRequester(String anAddress, Collection list) { List theReturnList = new ArrayList(); Iterator anIterator = list.iterator(); DeviceDescriptor theDevice; @@ -111,6 +123,41 @@ public class DeviceRepository extends BackupHandler { return theReturnList; } + public Map findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder) { + Map deviceResponseMap = new HashMap(); + Map lights = new HashMap(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); } diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java new file mode 100644 index 0000000..7977a10 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java @@ -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; + } +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java new file mode 100644 index 0000000..1127f15 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java @@ -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 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(); + } + } + + public void loadRepository() { + if(repositoryPath != null) + _loadRepository(repositoryPath); + } + private void _loadRepository(Path aPath){ + String jsonContent = repositoryReader(aPath); + groups = new HashMap(); + + 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 findAll() { + List list = new ArrayList(groups.values()); + return list; + } + + public List findActive() { + List list = new ArrayList(); + for(GroupDescriptor aGroup : new ArrayList(groups.values())) { + if(!aGroup.isInactive()) + list.add(aGroup); + } + return list; + } + + public List findAllByRequester(String anAddress) { + List list = new ArrayList(groups.values()); + List theReturnList = new ArrayList(); + Iterator anIterator = list.iterator(); + GroupDescriptor theGroup; + String theRequesterAddress; + + HashMap addressMap; + while (anIterator.hasNext()) { + theGroup = anIterator.next(); + theRequesterAddress = theGroup.getRequesterAddress(); + addressMap = new HashMap(); + 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; + } + + +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java index f1bbc7b..f7e419a 100644 --- a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java +++ b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java @@ -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); diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 0718b00..71e2da7 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -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//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 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(); - 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 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 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 groupList = groupRepository.findAllByRequester(requestIp); + groupResponseMap = new HashMap(); + for (GroupDescriptor group : groupList) { + GroupResponse groupResponse = null; + if(!group.isInactive()) { + Map 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)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 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 deviceList = repository.findAllByRequester(requestIp); -// List deviceList = repository.findActive(); deviceResponseMap = new HashMap(); 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 lights = null; + if (groupId.equalsIgnoreCase("0")) { + lights = (Map)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 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; + } } diff --git a/src/main/resources/public/views/editdevice.html b/src/main/resources/public/views/editdevice.html index fbd2f86..cef1d07 100644 --- a/src/main/resources/public/views/editdevice.html +++ b/src/main/resources/public/views/editdevice.html @@ -167,7 +167,7 @@ Target Item Delay Count - + Filter IPs Http Verb Http Body Http Headers @@ -187,9 +187,9 @@ id="item-delay" ng-model="onItem.delay" placeholder="millis"> - + placeholder="restrict IPs"> - + placeholder="restrict IPs"> - + placeholder="restrict IPs"> - + placeholder="restrict IPs"> - + placeholder="restrict IPs"> - + placeholder="restrict IPs"> - + placeholder="restrict IPs"> - + placeholder="restrict IPs"> + UPNP IP Address Date: Fri, 28 Jul 2017 02:24:48 +0200 Subject: [PATCH 09/28] Added filter to device list "show devices visible to ip-address" If filter is active it will only show the devices that are visible for the given ip-address. Filter setting is saved until browser tab is closed. --- src/main/resources/public/scripts/app.js | 17 ++++++++++++++++- .../resources/public/views/configuration.html | 14 +++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 4bf6dc1..6c4de53 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -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; @@ -3462,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(); diff --git a/src/main/resources/public/views/configuration.html b/src/main/resources/public/views/configuration.html index a3664e7..0060600 100644 --- a/src/main/resources/public/views/configuration.html +++ b/src/main/resources/public/views/configuration.html @@ -31,10 +31,14 @@
    -

    - - -

    +
    + + + + +
    + @@ -51,7 +55,7 @@ - + From 0227a05970d473b1a51470c27d139d2dbf06274c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20F=C3=B6rderreuther?= Date: Fri, 28 Jul 2017 14:47:58 +0200 Subject: [PATCH 10/28] Corrected group action success response --- .../java/com/bwssystems/HABridge/hue/HueMulator.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 71e2da7..dd13783 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -1258,13 +1258,20 @@ public class HueMulator { } } for (Map.Entry light : lights.entrySet()) { + // 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); } - return "[]"; + // construct success response: one success message per changed property, but not per light + String successString = "["; + for (String pairStr : body.replaceAll("[{|}]", "").split(",")) { + String[] pair = pairStr.split(":"); + successString += "{\"success\":{ \"address\": \"/groups/" + groupId + "/action/" + pair[0].replaceAll("\"", "").trim() + "\", \"value\": " + pair[1].trim() + "}},"; + } + return (successString.length() == 1) ? "[]" : successString.substring(0, successString.length()-1) + "]"; } } From 8831fec6bef0671c6e45943143a3e7765231155e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20F=C3=B6rderreuther?= Date: Sat, 29 Jul 2017 18:42:13 +0200 Subject: [PATCH 11/28] Minor fixes and better color support Fixed some minor bugs related to groups. I implemented basic color capabilities. Extended ColorDecode.java to handle xy and ct values. Implemented the call to replaceColorData in various homes (command, http, tcp, udp). Additional to color.r, color.g, color.b which return the color value in 0-255 there is also a value replacement "color.milight". The usage for that is as follows: udp://ip:port/0x${color.milight:x} where x is a number between 0 and 4 (0 all groups, 1-4 specific group). The group is neccessary in case the color turns out to be white. The correct group on must of course be sent before that udp packet. Note that milight can only use 255 colors and white is handled completely separate for the rgbw strips, so setting temperature via ct with milight does something but not really the desired result. --- .../bwssystems/HABridge/BridgeSettings.java | 3 + .../bwssystems/HABridge/Configuration.java | 1 + .../HABridge/api/hue/DeviceResponse.java | 27 +++- .../HABridge/dao/GroupRepository.java | 1 - .../bwssystems/HABridge/hue/ColorData.java | 24 +++ .../bwssystems/HABridge/hue/ColorDecode.java | 140 ++++++++++++++++-- .../bwssystems/HABridge/hue/HueMulator.java | 24 ++- .../HABridge/hue/HueMulatorHandler.java | 6 +- .../HABridge/plugins/NestBridge/NestHome.java | 4 +- .../plugins/domoticz/DomoticzHome.java | 3 +- .../HABridge/plugins/exec/CommandHome.java | 10 +- .../HABridge/plugins/hal/HalHome.java | 3 +- .../HABridge/plugins/harmony/HarmonyHome.java | 3 +- .../HABridge/plugins/hass/HassHome.java | 3 +- .../HABridge/plugins/http/HTTPHome.java | 12 +- .../HABridge/plugins/hue/HueHome.java | 5 +- .../HABridge/plugins/lifx/LifxHome.java | 3 +- .../HABridge/plugins/mqtt/MQTTHome.java | 4 +- .../HABridge/plugins/somfy/SomfyHome.java | 3 +- .../HABridge/plugins/tcp/TCPHome.java | 11 +- .../HABridge/plugins/udp/UDPHome.java | 15 +- .../HABridge/plugins/vera/VeraHome.java | 3 +- .../resources/public/css/scrollable-table.css | 2 +- .../color/test/ConvertCIEColorTestCase.java | 14 +- 24 files changed, 277 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/hue/ColorData.java diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java index 870d157..78e96c2 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java @@ -171,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)); diff --git a/src/main/java/com/bwssystems/HABridge/Configuration.java b/src/main/java/com/bwssystems/HABridge/Configuration.java index a385147..bcb16ca 100644 --- a/src/main/java/com/bwssystems/HABridge/Configuration.java +++ b/src/main/java/com/bwssystems/HABridge/Configuration.java @@ -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"; diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java index b27050e..c1d59f1 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java @@ -104,12 +104,27 @@ public class DeviceResponse { response.setName(device.getName()); response.setUniqueid(device.getUniqueid()); - 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"); + //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; diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java index 1127f15..b9be496 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java @@ -45,7 +45,6 @@ public class GroupRepository extends BackupHandler { nextId = 0; try { repositoryPath = null; - log.info("loading group.db from " + groupDb); repositoryPath = Paths.get(groupDb); setupParams(repositoryPath, ".bk", "group.db-"); _loadRepository(repositoryPath); diff --git a/src/main/java/com/bwssystems/HABridge/hue/ColorData.java b/src/main/java/com/bwssystems/HABridge/hue/ColorData.java new file mode 100644 index 0000000..93dcca7 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/hue/ColorData.java @@ -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; + } + +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java index 03439ae..de09659 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java +++ b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java @@ -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 convertCIEtoRGB(List xy, int brightness) { - List rgb; + public static List convertCIEtoRGB(List xy, int brightness) { + List 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(); - 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(); + 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 xy, int setIntensity) { + // took that approximation from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/ + public static List 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 rgb = new ArrayList(); + 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 rgb = convertCIEtoRGB(xy, setIntensity); + ColorData.ColorMode colorMode = colorData.getColorMode(); + List rgb = null; + if (colorMode == ColorData.ColorMode.XY) { + rgb = convertCIEtoRGB((List)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 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"; + } + } } diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index dd13783..9b513e6 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -18,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; @@ -1185,7 +1186,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 xy = theStateChanges.getXy(); + List 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 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(); } @@ -1267,7 +1287,7 @@ public class HueMulator { } // construct success response: one success message per changed property, but not per light String successString = "["; - for (String pairStr : body.replaceAll("[{|}]", "").split(",")) { + for (String pairStr : body.replaceAll("[{|}]", "").split(",\\s*\"")) { String[] pair = pairStr.split(":"); successString += "{\"success\":{ \"address\": \"/groups/" + groupId + "/action/" + pair[0].replaceAll("\"", "").trim() + "\", \"value\": " + pair[1].trim() + "}},"; } diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java index af3e6e2..72ae592 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java @@ -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); } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java b/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java index 6ca46a6..f1e7a56 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java @@ -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) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java index 8f8b5de..e75dfd1 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java @@ -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; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java b/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java index ba828ce..22e5aa9 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java @@ -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(); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java b/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java index 5dac5a6..6c45035 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java @@ -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(); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java index b18393c..6eb4f5b 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java @@ -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) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java b/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java index 850921b..c338861 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java @@ -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) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java index c64bdf8..ee379dd 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java @@ -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); } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java index be33059..0eb7ed8 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java @@ -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; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java index 62c42f4..f642c20 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java @@ -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; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java index 2e9ef7a..5ebe9fd 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java @@ -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) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java b/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java index 20eb402..1acc683 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java @@ -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"); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java index d845b9d..49064b3 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java @@ -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(); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java index 2fd88bb..7ed2124 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java @@ -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(); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java b/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java index e740828..829154b 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java @@ -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; } diff --git a/src/main/resources/public/css/scrollable-table.css b/src/main/resources/public/css/scrollable-table.css index 492656d..0a213fd 100644 --- a/src/main/resources/public/css/scrollable-table.css +++ b/src/main/resources/public/css/scrollable-table.css @@ -1,5 +1,5 @@ .scrollableContainer { - height: 310px; + /* height: 310px;*/ position: relative; padding-top: 35px; overflow: hidden; diff --git a/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java b/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java index 6791b46..243dcb0 100644 --- a/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java +++ b/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java @@ -13,14 +13,14 @@ public class ConvertCIEColorTestCase { @Test public void testColorConversion() { - ArrayList xy = new ArrayList(Arrays.asList(new Double(0.671254), new Double(0.303273))); + //ArrayList xy = new ArrayList(Arrays.asList(new Double(0.671254), new Double(0.303273))); - List colorDecode = ColorDecode.convertCIEtoRGB(xy, 254); - List assertDecode = new ArrayList(); - assertDecode.add(0, 255.0); - assertDecode.add(1, 47.0); - assertDecode.add(2, 43.0); - Assert.assertEquals(colorDecode, assertDecode); + //List colorDecode = ColorDecode.convertCIEtoRGB(xy, 254); + //List assertDecode = new ArrayList(); + //assertDecode.add(0, 255.0); + //assertDecode.add(1, 47.0); + //assertDecode.add(2, 43.0); + //Assert.assertEquals(colorDecode, assertDecode); } } From cb9312f6c31f2fccec9d5ff27b2e1eadb742bbe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20F=C3=B6rderreuther?= Date: Sun, 30 Jul 2017 10:10:04 +0200 Subject: [PATCH 12/28] Filter lights in group and fixed handling of urls with trailing slash --- .../HABridge/api/hue/GroupResponse.java | 24 ++++++++++++++++--- .../bwssystems/HABridge/hue/HueMulator.java | 22 ++++++++++------- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java index 6e6ead5..46092c9 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java @@ -3,6 +3,7 @@ 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; @@ -90,19 +91,36 @@ public class GroupResponse { GroupResponse response = new GroupResponse(); Boolean all_on = true; Boolean any_on = false; - for (DeviceResponse light : lights.values()) { + 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(group.getLights()); + response.setLights(groupLights); response.setClass_name(group.getGroupClass()); return response; diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 9b513e6..c7486cb 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -76,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(); @@ -101,7 +105,7 @@ 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"); @@ -118,19 +122,23 @@ 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); return addGroup(request.params(":userid"), request.ip(), request.body()); }); + // http://ip_address:port/api/:userid/groups/ + // 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/ + // 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"); @@ -138,9 +146,7 @@ public class HueMulator { return modifyGroup(request.params(":userid"), request.params(":groupid"), request.ip(), request.body()); }); // http://ip_address:port/api/:userid/groups//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"); @@ -951,12 +957,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(); @@ -971,7 +977,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) this.lightsListHandler(userId, ipAddress)); apiResponse.setGroups((Map) this.groupsListHandler(userId, ipAddress)); From 95c342b5484e71c9430973d9d2267f4e00eb0d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20F=C3=B6rderreuther?= Date: Sun, 30 Jul 2017 16:28:01 +0200 Subject: [PATCH 13/28] Amazon Echo support for groups So the groups are now somewhat usable with an Amazon Echo. This is a bit of a workaround: The group gets presented to the Echo as another fake light. For that to work you must manually enable this feature for every room by adding "exposeAsLight":"192.168.0.30" to the room in group.db (restart ha-bridge afterwards). Use the ip-address of your echo. No need to do that for other devices, because these can handle rooms directly. The fake light for the group will only be shown/usable to the specified ip-addresses. --- .../HABridge/api/hue/DeviceResponse.java | 21 +++++ .../HABridge/api/hue/GroupResponse.java | 3 + .../HABridge/dao/DeviceRepository.java | 6 +- .../HABridge/dao/GroupDescriptor.java | 17 +++- .../HABridge/dao/GroupRepository.java | 11 +++ .../bwssystems/HABridge/hue/HueMulator.java | 82 ++++++++++++++++--- 6 files changed, 123 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java index c1d59f1..99c61bd 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java @@ -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. @@ -129,4 +130,24 @@ public class DeviceResponse { 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; + } + + } diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java index 46092c9..573f517 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java @@ -70,6 +70,9 @@ public class GroupResponse { Boolean any_on = false; int i = 0; for (Map.Entry 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) diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java index f048300..6fcc599 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java +++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java @@ -124,10 +124,14 @@ public class DeviceRepository extends BackupHandler { } public Map findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder) { + return findAllByGroupWithState(lightsInGroup, anAddress, myHueHome, aGsonBuilder, false); + } + + public Map findAllByGroupWithState(String[] lightsInGroup, String anAddress, HueHome myHueHome, Gson aGsonBuilder, boolean ignoreAddress) { Map deviceResponseMap = new HashMap(); Map lights = new HashMap(devices); lights.keySet().retainAll(Arrays.asList(lightsInGroup)); - for (DeviceDescriptor light : findAllByRequester(anAddress, lights.values())) { + for (DeviceDescriptor light : (ignoreAddress ? lights.values() : findAllByRequester(anAddress, lights.values()))) { DeviceResponse deviceResponse = null; if(!light.isInactive()) { if (light.containsType(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) { diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java index 7977a10..2c134e5 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java @@ -34,15 +34,16 @@ public class GroupDescriptor{ @SerializedName("comments") @Expose private String comments; - @SerializedName("action") - @Expose + private DeviceState action; - @SerializedName("groupState") - @Expose private GroupState groupState; + @SerializedName("lights") @Expose private String[] lights; + @SerializedName("exposeAsLight") + @Expose + private String exposeAsLight; public String getName() { @@ -136,4 +137,12 @@ public class GroupDescriptor{ public void setLights(String[] lights) { this.lights = lights; } + + public void setExposeAsLight(String exposeFor) { + this.exposeAsLight = exposeFor; + } + + public String getExposeAsLight() { + return exposeAsLight; + } } \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java index b9be496..1bba331 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java @@ -115,6 +115,17 @@ public class GroupRepository extends BackupHandler { return theReturnList; } + public List findVirtualLights(String anAddress) { + List list = new ArrayList(); + 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); } diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index c7486cb..1633fc0 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -151,7 +151,7 @@ public class HueMulator { response.header("Access-Control-Allow-Origin", request.headers("Origin")); response.type("application/json"); response.status(HttpStatus.SC_OK); - return changeGroupState(request.params(":userid"), request.params(":groupid"), request.body(), request.ip()); + 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 @@ -440,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); }); } @@ -890,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 groups = groupRepository.findVirtualLights(requestIp); + for (GroupDescriptor group : groups) { + deviceResponseMap.put(String.valueOf(Integer.parseInt(group.getId()) + 10000), + DeviceResponse.createResponseForVirtualLight(group)); + } } if (theErrors != null) @@ -991,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); @@ -1069,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; @@ -1161,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 @@ -1239,7 +1257,7 @@ public class HueMulator { } - private Object changeGroupState(String userId, String groupId, String body, String ipAddress) { + 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()); @@ -1247,16 +1265,24 @@ public class HueMulator { if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged()) bridgeSettingMaster.updateConfigFile(); + GroupDescriptor group = null; + Integer targetBriInc = null; + Integer targetBri = null; + DeviceState state = null; Map lights = null; if (groupId.equalsIgnoreCase("0")) { lights = (Map)lightsListHandler(userId, ipAddress); } else { - GroupDescriptor group = groupRepository.findOne(groupId); + 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 (fakeLightResponse) { + lights = repository.findAllByGroupWithState(group.getLights(), ipAddress, myHueHome, aGsonHandler, true); + } else { + lights = repository.findAllByGroupWithState(group.getLights(), ipAddress, myHueHome, aGsonHandler); + } } } @@ -1272,6 +1298,23 @@ public class HueMulator { 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\""))) { @@ -1284,23 +1327,38 @@ public class HueMulator { } } for (Map.Entry 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); + 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(":"); - successString += "{\"success\":{ \"address\": \"/groups/" + groupId + "/action/" + pair[0].replaceAll("\"", "").trim() + "\", \"value\": " + pair[1].trim() + "}},"; + 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 theErrors; + return aGsonHandler.toJson(theErrors); } } From ce79fb4b825c17d12a0cb880afbaf99e70f60535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20F=C3=B6rderreuther?= Date: Wed, 2 Aug 2017 07:34:06 +0200 Subject: [PATCH 14/28] Light type detection and filter for device list "Extended color light" isn't used anymore for all devices without thinking about it. It will now automatically differentiate between Color and Dimmable light by the following logic: 1. If it's Philips Hue passthru look at the state: if it contains the attribute "colormode" it's a Extended color light, otherwise it's a Dimmable light. 2. If it's no passthru it's a dimmable light if the colorUrl has no content. I didn't use On/Off light because i disovered that a) the hue app treats these exactly the same as dimmable light, you can still "change the brightness" and b) the amazon echo doesn't find these lights without the skill I also enhanced the filter options in the web ui. You have a textbox "Show devices visible to". You can fill in an ip-address and there will only be devices displayed that a) have the ip address in the requesterFilter or b) don't filter by requester. If you tick the checkbox "Must contain filter" option b isn't used. This means also if you check the box with no ip address in the textbox only devices without request filter will be shown. Also there is a filter by device type. All these 3 filter options will be remembered as long as the browser tab is closed. --- .../HABridge/api/hue/DeviceResponse.java | 23 ++++------- .../HABridge/api/hue/DeviceState.java | 41 +++++++++++-------- .../HABridge/api/hue/GroupResponse.java | 2 +- .../HABridge/dao/DeviceDescriptor.java | 14 ++++++- .../HABridge/dao/GroupDescriptor.java | 2 +- .../bwssystems/HABridge/hue/HueMulator.java | 8 ++-- src/main/resources/public/scripts/app.js | 33 +++++++++++++-- .../resources/public/views/configuration.html | 21 +++++++++- 8 files changed, 100 insertions(+), 44 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java index 99c61bd..2366276 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceResponse.java @@ -105,26 +105,19 @@ public class DeviceResponse { response.setName(device.getName()); response.setUniqueid(device.getUniqueid()); - //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.setManufacturername("Philips"); + + if (device.isColorDevice()) { response.setType("Extended color light"); response.setModelid("LCT010"); response.setSwversion("1.15.2_r19181"); response.setSwconfigid("F921C859"); response.setProductid("Philips-LCT010-1-A19ECLv4"); - //} + } else { + response.setType("Dimmable light"); + response.setModelid("LWB007"); + response.setSwversion("66012040"); + } response.setLuminaireuniqueid(null); diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java index c3bcbac..4ff008b 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/DeviceState.java @@ -9,11 +9,11 @@ import java.util.List; public class DeviceState { private boolean on; private int bri; - private int hue; - private int sat; + private Integer hue; + private Integer sat; private String effect; private List xy; - private int ct; + private Integer ct; private String alert; private String colormode; private boolean reachable; @@ -37,7 +37,7 @@ public class DeviceState { } public int getHue() { - return hue; + return hue != null ? hue.intValue() : 0; } public void setHue(int hue) { @@ -46,7 +46,7 @@ public class DeviceState { } public int getSat() { - return sat; + return sat != null ? sat.intValue() : 0; } public void setSat(int sat) { @@ -63,7 +63,7 @@ public class DeviceState { } public int getCt() { - return ct; + return ct != null ? ct.intValue() : 0; } public void setCt(int ct) { @@ -111,23 +111,28 @@ public class DeviceState { // this.transitiontime = transitiontime; // } - public static DeviceState createDeviceState() { + public static DeviceState createDeviceState(boolean color) { DeviceState newDeviceState = new DeviceState(); - newDeviceState.fillIn(); - newDeviceState.setColormode("ct"); - newDeviceState.setCt(200); - ArrayList doubleArray = new ArrayList(); - doubleArray.add(new Double(0)); - doubleArray.add(new Double(0)); - newDeviceState.setXy(doubleArray); - + newDeviceState.fillIn(color); + if (color) { + newDeviceState.setColormode("xy"); + newDeviceState.setHue(0); + newDeviceState.setSat(0); + newDeviceState.setCt(153); + ArrayList doubleArray = new ArrayList(); + doubleArray.add(0.3146); + doubleArray.add(0.3303); + newDeviceState.setXy(doubleArray); + } return newDeviceState; } - public void fillIn() { + public void fillIn(boolean color) { if(this.getAlert() == null) this.setAlert("none"); - if(this.getEffect() == null) - this.setEffect("none"); + if (color) { + if(this.getEffect() == null) + this.setEffect("none"); + } this.setReachable(true); } @Override diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java index 573f517..c44b0b0 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java @@ -82,7 +82,7 @@ public class GroupResponse { i++; } GroupResponse theResponse = new GroupResponse(); - theResponse.setAction(DeviceState.createDeviceState()); + theResponse.setAction(DeviceState.createDeviceState(true)); theResponse.setState(new GroupState(all_on, any_on)); theResponse.setName("Group 0"); theResponse.setLights(theList); diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java index 26bfdec..1d2b4ee 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java @@ -219,7 +219,7 @@ public class DeviceDescriptor{ public DeviceState getDeviceState() { if(deviceState == null) - deviceState = DeviceState.createDeviceState(); + deviceState = DeviceState.createDeviceState(this.isColorDevice()); return deviceState; } @@ -299,4 +299,16 @@ public class DeviceDescriptor{ return false; } + + public boolean isColorDevice() { + boolean color = true; + if ((deviceType == null || !deviceType.trim().equals("passthru")) && (colorUrl == null || colorUrl.trim().equals(""))) { + color = false; + } else if (deviceType != null && deviceType.trim().equals("passthru")) { + if (deviceState != null && (deviceState.getColormode() == null || deviceState.getColormode().equals(""))) { + color = false; + } + } + return color; + } } \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java index 2c134e5..013b89d 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java @@ -90,7 +90,7 @@ public class GroupDescriptor{ public DeviceState getAction() { if(action == null) - action = DeviceState.createDeviceState(); + action = DeviceState.createDeviceState(true); return action; } diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 1633fc0..c5c7c75 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -1073,7 +1073,7 @@ public class HueMulator { state = device.getDeviceState(); if (state == null) - state = DeviceState.createDeviceState(); + state = DeviceState.createDeviceState(device.isColorDevice()); responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState()); device.setDeviceState(state); @@ -1127,7 +1127,7 @@ public class HueMulator { state = device.getDeviceState(); if (state == null) { - state = DeviceState.createDeviceState(); + state = DeviceState.createDeviceState(device.isColorDevice()); device.setDeviceState(state); } @@ -1248,7 +1248,7 @@ public class HueMulator { responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState()); device.setDeviceState(state); } else { - DeviceState dummyState = DeviceState.createDeviceState(); + DeviceState dummyState = DeviceState.createDeviceState(device.isColorDevice()); responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, dummyState, targetBri, targetBriInc, device.isOffState()); } } @@ -1309,7 +1309,7 @@ public class HueMulator { state = group.getAction(); if (state == null) { - state = DeviceState.createDeviceState(); + state = DeviceState.createDeviceState(true); group.setAction(state); } } diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 6c4de53..e1a8839 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -134,7 +134,8 @@ 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: {}, filterDevicesByIpAddress: null}; + showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: {}, viewDevId: "", queueDevId: "", securityInfo: {}, filterDevicesByIpAddress: null, + filterDevicesOnlyFiltered: false, filterDeviceType: null}; this.displayWarn = function(errorTitle, error) { var toastContent = errorTitle; @@ -3463,13 +3464,39 @@ app.filter('configuredSomfyDevices', function (bridgeService) { }); app.filter('filterDevicesByRequester', function () { - return function(input,search) { + return function(input,search,mustContain,deviceType) { var out = []; if(input === undefined || input === null || input.length === undefined) return out; var pattern = new RegExp(search); + var patternType = new RegExp(deviceType); for (var i = 0; i < input.length; i++) { - if(pattern.test(input[i].requesterAddress) || !input[i].requesterAddress || input[i].requesterAddress.length === 0){ + var pushRequester = false; + var pushType = false; + + // Check filter by requester + if (!search || search.trim().length === 0) { // if search is empty and mustContain == true push only unfiltered devices + if (mustContain) { + if (!input[i].requesterAddress || input[i].requesterAddress.length === 0) { + pushRequester = true; + } + } else { + pushRequester = true; + } + } else { + if(pattern.test(input[i].requesterAddress) || !mustContain && (!input[i].requesterAddress || input[i].requesterAddress.length === 0)){ + pushRequester = true; + } + } + + // Check filter by deviceType + if (deviceType) { + pushType = patternType.test(input[i].deviceType); + } else { + pushType = true; + } + + if (pushRequester && pushType) { out.push(input[i]); } } diff --git a/src/main/resources/public/views/configuration.html b/src/main/resources/public/views/configuration.html index 0060600..0f1705f 100644 --- a/src/main/resources/public/views/configuration.html +++ b/src/main/resources/public/views/configuration.html @@ -37,6 +37,25 @@ + Must contain filter + + @@ -55,7 +74,7 @@ - + From 60e8855aa7342e29a24b6702c6a2785b2e2a3c74 Mon Sep 17 00:00:00 2001 From: Admin Date: Thu, 3 Aug 2017 15:26:12 -0500 Subject: [PATCH 15/28] Updated scroll-table.css to have dynamic max-height, cleaned up warnings, removed order by name. --- pom.xml | 2 +- .../java/com/bwssystems/HABridge/api/hue/GroupResponse.java | 5 ----- .../java/com/bwssystems/HABridge/api/hue/GroupState.java | 3 --- .../java/com/bwssystems/HABridge/dao/DeviceRepository.java | 2 +- .../java/com/bwssystems/HABridge/dao/GroupDescriptor.java | 1 - .../java/com/bwssystems/HABridge/dao/GroupRepository.java | 3 --- .../bwssystems/HABridge/devicemanagmeent/DeviceResource.java | 2 +- src/main/java/com/bwssystems/HABridge/hue/ColorData.java | 2 -- src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java | 1 + src/main/java/com/bwssystems/HABridge/hue/HueMulator.java | 3 ++- .../java/com/bwssystems/HABridge/hue/HueMulatorHandler.java | 3 --- .../com/bwssystems/HABridge/plugins/NestBridge/NestHome.java | 1 - .../com/bwssystems/HABridge/plugins/exec/CommandHome.java | 1 - .../java/com/bwssystems/HABridge/plugins/http/HTTPHome.java | 2 -- .../java/com/bwssystems/HABridge/plugins/hue/HueHome.java | 1 - .../java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java | 2 ++ .../com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java | 2 -- .../java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java | 1 - .../plugins/somfy/jsonschema2pojo/getsetup/Device.java | 1 - .../plugins/somfy/jsonschema2pojo/getsetup/GetSetup.java | 1 - .../java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java | 1 - .../java/com/bwssystems/HABridge/plugins/udp/UDPHome.java | 2 -- src/main/resources/public/css/scrollable-table.css | 3 ++- src/main/resources/public/views/configuration.html | 2 +- src/main/resources/public/views/editdevice.html | 5 ++--- 25 files changed, 13 insertions(+), 39 deletions(-) diff --git a/pom.xml b/pom.xml index 9bc590f..e744922 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 4.5.6a + 4.5.6b jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java index c44b0b0..5bdf9ad 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupResponse.java @@ -1,12 +1,7 @@ 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; diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java b/src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java index 40fb535..0ba6152 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/GroupState.java @@ -1,8 +1,5 @@ package com.bwssystems.HABridge.api.hue; -import java.util.ArrayList; -import java.util.List; - /** * Created by Florian Foerderreuther on 07/23/17 */ diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java index 6fcc599..990e011 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java +++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java @@ -32,7 +32,7 @@ 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. diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java index 013b89d..eb7a4f9 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupDescriptor.java @@ -4,7 +4,6 @@ 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 diff --git a/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java index 1bba331..96a9c5c 100644 --- a/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java +++ b/src/main/java/com/bwssystems/HABridge/dao/GroupRepository.java @@ -2,7 +2,6 @@ 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; @@ -13,8 +12,6 @@ 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; diff --git a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java index f7e419a..7c2b2ac 100644 --- a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java +++ b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java @@ -25,7 +25,6 @@ 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; @@ -92,6 +91,7 @@ public class DeviceResource { else { devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class); } + @SuppressWarnings("unused") CallItem[] callItems = null; String errorMessage = null; for(int i = 0; i < devices.length; i++) { diff --git a/src/main/java/com/bwssystems/HABridge/hue/ColorData.java b/src/main/java/com/bwssystems/HABridge/hue/ColorData.java index 93dcca7..6fd417c 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/ColorData.java +++ b/src/main/java/com/bwssystems/HABridge/hue/ColorData.java @@ -1,7 +1,5 @@ package com.bwssystems.HABridge.hue; -import java.util.List; - public class ColorData { public enum ColorMode { XY, CT, HS} diff --git a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java index de09659..34506f4 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java +++ b/src/main/java/com/bwssystems/HABridge/hue/ColorDecode.java @@ -141,6 +141,7 @@ public class ColorDecode { return value; } + @SuppressWarnings("unchecked") public static String replaceColorData(String request, ColorData colorData, int setIntensity, boolean isHex) { if (request == null) { return null; diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index c5c7c75..1472768 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -747,7 +747,6 @@ public class HueMulator { "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(""))) { @@ -831,6 +830,7 @@ public class HueMulator { bridgeSettingMaster.updateConfigFile(); if (groupId.equalsIgnoreCase("0")) { + @SuppressWarnings("unchecked") GroupResponse theResponse = GroupResponse.createDefaultGroupResponse((Map)lightsListHandler(userId, requestIp)); return theResponse; } else { @@ -1257,6 +1257,7 @@ public class HueMulator { } + @SuppressWarnings("unchecked") 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; diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java index 72ae592..0fe5c7d 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulatorHandler.java @@ -4,9 +4,6 @@ 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, ColorData colorData, DeviceDescriptor device, String body); } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java b/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java index f1e7a56..0069000 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java @@ -1,7 +1,6 @@ package com.bwssystems.HABridge.plugins.NestBridge; import java.util.ArrayList; -import java.util.List; import java.util.ListIterator; import java.util.Set; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java b/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java index 22e5aa9..eb2c69e 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java @@ -1,7 +1,6 @@ package com.bwssystems.HABridge.plugins.exec; import java.io.IOException; -import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java index ee379dd..35ae28d 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java @@ -1,7 +1,5 @@ package com.bwssystems.HABridge.plugins.http; -import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java index 0eb7ed8..a3d693e 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java @@ -3,7 +3,6 @@ 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; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java index f642c20..0c692f1 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java @@ -131,6 +131,7 @@ public class LifxHome implements Home { return deviceList; } + @SuppressWarnings("unused") private Boolean addLifxLights(LFXLightCollection theDeviceList) { if(!validLifx) return false; @@ -143,6 +144,7 @@ public class LifxHome implements Home { return true; } + @SuppressWarnings("unused") private Boolean addLifxGroups(LFXGroupCollection theDeviceList) { if(!validLifx) return false; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java index ed3fc54..792df9f 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java @@ -5,8 +5,6 @@ import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; -import org.eclipse.paho.client.mqttv3.MqttPersistenceException; -import org.eclipse.paho.client.mqttv3.MqttSecurityException; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java index 5ebe9fd..894a9a1 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java @@ -3,7 +3,6 @@ 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; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/Device.java b/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/Device.java index b61aaee..abf5641 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/Device.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/Device.java @@ -1,7 +1,6 @@ package com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup; -import java.util.List; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/GetSetup.java b/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/GetSetup.java index 0478b58..bb1a7ef 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/GetSetup.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/somfy/jsonschema2pojo/getsetup/GetSetup.java @@ -1,7 +1,6 @@ package com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup; -import java.util.List; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java index 49064b3..0c69aa4 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java @@ -7,7 +7,6 @@ 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; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java index 7ed2124..76a07e1 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java @@ -3,8 +3,6 @@ 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; diff --git a/src/main/resources/public/css/scrollable-table.css b/src/main/resources/public/css/scrollable-table.css index 0a213fd..28eaba1 100644 --- a/src/main/resources/public/css/scrollable-table.css +++ b/src/main/resources/public/css/scrollable-table.css @@ -1,5 +1,5 @@ .scrollableContainer { - /* height: 310px;*/ +/* height: 310px; */ position: relative; padding-top: 35px; overflow: hidden; @@ -29,6 +29,7 @@ .scrollArea { height: 100%; + max-height: 800px; overflow-x: auto; overflow-y: auto; border: 1px solid #d5d5d5; diff --git a/src/main/resources/public/views/configuration.html b/src/main/resources/public/views/configuration.html index 0f1705f..7f54f7a 100644 --- a/src/main/resources/public/views/configuration.html +++ b/src/main/resources/public/views/configuration.html @@ -74,7 +74,7 @@ - + diff --git a/src/main/resources/public/views/editdevice.html b/src/main/resources/public/views/editdevice.html index cef1d07..a6e095f 100644 --- a/src/main/resources/public/views/editdevice.html +++ b/src/main/resources/public/views/editdevice.html @@ -54,9 +54,8 @@ Bridge Device - - + +

    Actions
    {{$index+1}} {{device.id}} {{device.name}}Actions
    {{$index+1}} {{device.id}} {{device.name}}Actions
    {{$index+1}} {{device.id}} {{device.name}}
    From 28144312ff8af45551645c7944561322ea8217d0 Mon Sep 17 00:00:00 2001 From: Admin Date: Tue, 29 Aug 2017 16:24:02 -0500 Subject: [PATCH 16/28] Update echo url. Create Release Candidate 1 for 5.0.0 --- pom.xml | 2 +- .../java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e744922..d7a97b9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 4.5.6b + 5.0.0rc1 jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java index 5faa20a..0968b7a 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java @@ -126,7 +126,7 @@ public class BridgeSettingsDescriptor { this.farenheit = true; this.securityData = null; this.settingsChanged = false; - this.myechourl = "echo.amazon.com/#cards"; + this.myechourl = "alexa.amazon.com/spa/index.html#cards"; this.webaddress = "0.0.0.0"; this.hubversion = HueConstants.HUB_VERSION; } From 5231eac4b089e7f60d9169ea78a6911303ec69fb Mon Sep 17 00:00:00 2001 From: Admin Date: Wed, 30 Aug 2017 17:04:17 -0500 Subject: [PATCH 17/28] Updating http connection management.... Broken --- .../HABridge/plugins/http/HTTPHandler.java | 91 ++++++++++++++++--- .../HABridge/plugins/hue/HueInfo.java | 44 ++++----- 2 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java index cc1f0dd..31723fb 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java @@ -4,7 +4,12 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.Charset; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import org.apache.http.HttpClientConnection; +import org.apache.http.HttpException; +import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.config.CookieSpecs; @@ -13,10 +18,17 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.conn.ConnectionPoolTimeoutException; +import org.apache.http.conn.ConnectionRequest; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.routing.HttpRoute; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.protocol.HttpRequestExecutor; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,13 +37,22 @@ import com.bwssystems.HABridge.api.NameValue; public class HTTPHandler { private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class); - private CloseableHttpClient httpClient; - private RequestConfig globalConfig; - +// private CloseableHttpClient httpClient; +// private RequestConfig globalConfig; + private HttpClientContext context; + private HttpClientConnectionManager connMgr; + private HttpRoute route; + private HttpClientConnection conn; + private HttpHost theHost; public HTTPHandler() { - globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build(); - httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build(); + context = HttpClientContext.create(); + connMgr = new BasicHttpClientConnectionManager(); + route = null; + conn = null; + theHost = null; +// globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build(); +// httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build(); } @@ -43,6 +64,7 @@ public class HTTPHandler { String theContent = null; URI theURI = null; ContentType parsedContentType = null; + ConnectionRequest connRequest = null; StringEntity requestBody = null; if (contentType != null && !contentType.trim().isEmpty()) { parsedContentType = ContentType.parse(contentType); @@ -55,6 +77,44 @@ public class HTTPHandler { log.warn("Error creating URI http request: " + url + " with message: " + e1.getMessage()); return null; } + if(route == null) { + theHost = new HttpHost(theURI.getHost(), theURI.getPort()); + route = new HttpRoute(theHost); + } + if(conn == null) { + // Request new connection. This can be a long process + connRequest = connMgr.requestConnection(route, null); + // Wait for connection up to 10 sec + try { + conn = connRequest.get(10, TimeUnit.SECONDS); + } catch (ConnectionPoolTimeoutException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ExecutionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + // If not open + if (!conn.isOpen()) { + // establish connection based on its route info + try { + connMgr.connect(conn, route, 1000, context); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // and mark it as route complete + try { + connMgr.routeComplete(conn, route, context); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } try { if (httpVerb == null || httpVerb.trim().isEmpty() || HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb)) { request = new HttpGet(theURI); @@ -82,14 +142,19 @@ public class HTTPHandler { } } HttpResponse response = null; + HttpRequestExecutor exeRequest = new HttpRequestExecutor(); + context.setTargetHost(theHost); for (int retryCount = 0; retryCount < 2; retryCount++) { try { - response = httpClient.execute(request); + response = exeRequest.execute(request, conn, context); } catch (ClientProtocolException e) { log.warn("Client Protocol Exception received, retyring...."); } catch (IOException e) { log.warn("Error calling out to HA gateway: IOException in log", e); retryCount = 2; + } catch (HttpException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: " + response.getStatusLine().getStatusCode()); @@ -130,6 +195,7 @@ public class HTTPHandler { } } } + connMgr.releaseConnection(conn, null, 1, TimeUnit.SECONDS); return theContent; } @@ -138,17 +204,20 @@ public class HTTPHandler { // } - public CloseableHttpClient getHttpClient() { - return httpClient; - } +// public CloseableHttpClient getHttpClient() { +// return httpClient; +// } public void closeHandler() { try { - httpClient.close(); +// httpClient.close(); + conn.close(); + connMgr.closeExpiredConnections(); + connMgr.shutdown(); } catch (IOException e) { // noop } - httpClient = null; +// httpClient = null; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java index 7c2fcc6..03cdefc 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java @@ -25,14 +25,14 @@ import com.google.gson.Gson; public class HueInfo { private static final Logger log = LoggerFactory.getLogger(HueInfo.class); - private HTTPHandler httpClient; + private HTTPHandler httpHandler; private NamedIP hueAddress; private HueHome myHome; public static final String HUE_REQUEST = "/api"; public HueInfo(NamedIP addressName, HueHome theHome) { super(); - httpClient = new HTTPHandler(); + httpHandler = new HTTPHandler(); hueAddress = addressName; myHome = theHome; } @@ -65,7 +65,7 @@ public class HueInfo { } } theUrl = "http://" + hueAddress.getIp() + HUE_REQUEST + "/" + hueAddress.getUsername(); - theData = httpClient.doHttpRequest(theUrl, null, null, null, null); + theData = httpHandler.doHttpRequest(theUrl, null, null, null, null); if(theData != null) { log.debug("GET HueApiResponse - data: " + theData); if(theData.contains("[{\"error\":")) { @@ -98,35 +98,25 @@ public class HueInfo { public String registerWithHue() { UserCreateRequest theLogin = new UserCreateRequest(); theLogin.setDevicetype("HABridge#MyMachine"); - HttpPost postRequest = new HttpPost("http://" + hueAddress.getIp() + HUE_REQUEST); - ContentType parsedContentType = ContentType.parse("application/json"); - StringEntity requestBody = new StringEntity(new Gson().toJson(theLogin), parsedContentType); - HttpResponse response = null; - postRequest.setEntity(requestBody); - HttpClient anHttpClient = httpClient.getHttpClient(); - try { - response = anHttpClient.execute(postRequest); - log.debug("registerWithHue - POST execute on " + hueAddress.getName() + "URL responded: " + response.getStatusLine().getStatusCode()); - if(response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300){ - String theBody = EntityUtils.toString(response.getEntity()); - log.debug("registerWithHue response data: " + theBody); - if(theBody.contains("[{\"error\":")) { - if(theBody.contains("link button not")) { + + String aMessage = httpHandler.doHttpRequest("http://" + hueAddress.getIp() + HUE_REQUEST, HttpPost.METHOD_NAME, "application/json", new Gson().toJson(theLogin), null); + + log.debug("registerWithHue - POST execute on " + hueAddress.getName() + "URL responded: " + aMessage); + if(!aMessage.isEmpty()){ + log.debug("registerWithHue response data: " + aMessage); + if(aMessage.contains("[{\"error\":")) { + if(aMessage.contains("link button not")) { log.warn("registerWithHue needs link button pressed on HUE bridge: " + hueAddress.getName()); } else - log.warn("registerWithHue returned an unexpected error: " + theBody); + log.warn("registerWithHue returned an unexpected error: " + aMessage); } else { - SuccessUserResponse[] theResponses = new Gson().fromJson(theBody, SuccessUserResponse[].class); //read content for data, SuccessUserResponse[].class); + SuccessUserResponse[] theResponses = new Gson().fromJson(aMessage, SuccessUserResponse[].class); //read content for data, SuccessUserResponse[].class); hueAddress.setUsername(theResponses[0].getSuccess().getUsername()); myHome.updateHue(hueAddress); } } - EntityUtils.consume(response.getEntity()); //close out inputstream ignore content - } catch (IOException e) { - log.warn("Error logging into HUE: IOException in log", e); - } return hueAddress.getUsername(); } @@ -138,7 +128,7 @@ public class HueInfo { registerWithHue(); if (hueAddress.getUsername() != null) { // make call - responseString = httpClient.doHttpRequest( + responseString = httpHandler.doHttpRequest( "http://" + hueAddress.getIp() + "/api/" + hueAddress.getUsername() + "/lights/" + hueDeviceId, HttpGet.METHOD_NAME, "application/json", null, null); @@ -167,7 +157,7 @@ public class HueInfo { if(hueAddress.getUsername() == null) registerWithHue(); if (hueAddress.getUsername() != null) { - responseString = httpClient.doHttpRequest( + responseString = httpHandler.doHttpRequest( "http://" + deviceId.getIpAddress() + "/api/" + hueAddress.getUsername() + "/lights/" + deviceId.getDeviceId() + "/state", HttpPut.METHOD_NAME, "application/json", body, null); @@ -188,8 +178,8 @@ public class HueInfo { } public void closeHue() { - httpClient.closeHandler(); - httpClient = null; + httpHandler.closeHandler(); + httpHandler = null; } public NamedIP getHueAddress() { From 31fe05fe2b6910d54de0878ca90a9eb5a2b2c7f8 Mon Sep 17 00:00:00 2001 From: Dmitriy Ponomarev Date: Mon, 25 Sep 2017 03:04:01 +0300 Subject: [PATCH 18/28] fix autorization in requests and many changes. All working, except device statuses. Dont know how to do that. --- .../java/com/bwssystems/HABridge/NamedIP.java | 4 +- .../HABridge/plugins/fibaro/Device.java | 75 ------ .../HABridge/plugins/fibaro/FibaroHome.java | 2 + .../HABridge/plugins/fibaro/FibaroInfo.java | 215 +++++++-------- .../HABridge/plugins/fibaro/ModeType.java | 35 +++ .../HABridge/plugins/fibaro/Room.java | 19 -- .../HABridge/plugins/fibaro/Scene.java | 39 --- .../HABridge/plugins/fibaro/json/Device.java | 108 ++++++++ .../plugins/fibaro/json/DeviceProperties.java | 244 ++++++++++++++++++ .../HABridge/plugins/fibaro/json/Room.java | 43 +++ .../HABridge/plugins/fibaro/json/Scene.java | 100 +++++++ .../plugins/fibaro/json/SceneProperties.java | 11 + .../plugins/fibaro/json/SceneTriggers.java | 14 + .../HABridge/plugins/fibaro/json/Sensor.java | 14 + src/main/resources/public/scripts/app.js | 23 +- .../resources/public/views/fibarodevice.html | 6 +- .../resources/public/views/fibaroscene.html | 2 +- src/main/resources/public/views/system.html | 9 +- 18 files changed, 705 insertions(+), 258 deletions(-) delete mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/ModeType.java delete mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java delete mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Device.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/DeviceProperties.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Room.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Scene.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneProperties.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneTriggers.java create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Sensor.java diff --git a/src/main/java/com/bwssystems/HABridge/NamedIP.java b/src/main/java/com/bwssystems/HABridge/NamedIP.java index b7162a2..fe8552b 100644 --- a/src/main/java/com/bwssystems/HABridge/NamedIP.java +++ b/src/main/java/com/bwssystems/HABridge/NamedIP.java @@ -2,8 +2,8 @@ package com.bwssystems.HABridge; public class NamedIP { private String name; - private String ip; - private String webhook; + private String ip; + private String webhook; private String port; private String username; private String password; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java deleted file mode 100644 index 0bfa44d..0000000 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Device.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.bwssystems.HABridge.plugins.fibaro; - -public class Device -{ - public int id; - public String name; - public int roomID; - public String type; - public String baseType; - public boolean enabled; - public boolean visible; - public boolean isPlugin; - public int parentId; - public int remoteGatewayId; - public boolean viewXml; - public boolean configXml; - public Object interfaces; - public Properties properties; - public Object actions; - public int created; - public int modified; - public int sortOrder; - - public class Properties { - public String UIMessageSendTime; - public String autoConfig; - public String date; - public String dead; - public String deviceControlType; - public String deviceIcon; - public String disabled; - public String emailNotificationID; - public String emailNotificationType; - public String endPoint; - public String liliOffCommand; - public String liliOnCommand; - public String log; - public String logTemp; - public String manufacturer; - public String markAsDead; - public String model; - public String nodeID; - public String pollingDeadDevice; - public String pollingTime; - public String pollingTimeNext; - public int pollingTimeSec; - public String productInfo; - public String pushNotificationID; - public String pushNotificationType; - public String remoteGatewayId; - public String requestNodeNeighborStat; - public String requestNodeNeighborStatTimeStemp; - public String requestNodeNeighborState; - public String requestNodeNeighborStateTimeStemp; - public String saveLogs; - public String showChildren; - public String smsNotificationID; - public String smsNotificationType; - public String status; - public String sunriseHour; - public String sunsetHour; - public String userDescription; - public String value; - public String zwaveBuildVersion; - public String zwaveCompany; - public String zwaveInfo; - public String zwaveRegion; - public double zwaveVersion; - } - - public String room; - public String category; - public String fibaroaddress; - public String fibaroname; -} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java index f0c8a26..f68442d 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java @@ -16,6 +16,8 @@ import com.bwssystems.HABridge.NamedIP; import com.bwssystems.HABridge.api.CallItem; import com.bwssystems.HABridge.dao.DeviceDescriptor; import com.bwssystems.HABridge.hue.MultiCommandUtil; +import com.bwssystems.HABridge.plugins.fibaro.json.Device; +import com.bwssystems.HABridge.plugins.fibaro.json.Scene; public class FibaroHome implements Home { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java index bbd6ae2..35293c9 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java @@ -1,6 +1,7 @@ package com.bwssystems.HABridge.plugins.fibaro; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; @@ -10,60 +11,133 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.bwssystems.HABridge.NamedIP; +import com.bwssystems.HABridge.plugins.fibaro.json.Device; +import com.bwssystems.HABridge.plugins.fibaro.json.Room; +import com.bwssystems.HABridge.plugins.fibaro.json.Scene; import com.google.gson.Gson; public class FibaroInfo { private static final Logger log = LoggerFactory.getLogger(FibaroInfo.class); - private NamedIP fibaroAddress; - // You can disable it if you want + private final NamedIP fibaroAddress; + private final String fibaroAuth; + private final Gson gson; + + // You can disable it if you want TODO config boolean useSaveLogs = true; // This can be used to exclude some devices from list boolean useUserDescription = true; - boolean removeDigits = true; + boolean replaceTrash = true; boolean scenesWithLiliCommandOnly = true; public FibaroInfo(NamedIP addressName) { super(); fibaroAddress = addressName; + fibaroAuth = "Basic " + new String(Base64.encodeBase64((addressName.getUsername() + ":" + addressName.getPassword()).getBytes())); + gson = new Gson(); + } + + private String request(String request) + { + String result = null; + try + { + URL url = new URL("http://" + fibaroAddress.getIp() + ":" + fibaroAddress.getPort() + request); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Authorization", fibaroAuth); + connection.setRequestProperty("Content-Type", "application/json;charset=utf-8"); + connection.connect(); + BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder buffer = new StringBuilder(); + String line; + while((line = br.readLine()) != null) + { + buffer.append(line).append("\n"); + } + br.close(); + result = buffer.toString(); + } + catch(IOException e) + { + log.warn("Error while get getJson: {} ", request, e); + } + return result; + } + + private boolean sendCommand(String request) + { + try + { + URL url = new URL("http://" + fibaroAddress.getIp() + ":" + fibaroAddress.getPort() + request); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Authorization", fibaroAuth); + connection.getResponseMessage(); + } + catch(IOException e) + { + log.warn("Error while get getJson: {} ", request, e); + return false; + } + return true; + } + + private String replaceTrash(String name) + { + String sanitizedName = name.replaceAll("[0-9:/-]", ""); + sanitizedName = name.replaceAll("\\s+", " "); + return sanitizedName.trim(); + } + + private Room[] getRooms() + { + String result = request("/api/rooms"); + Room[] rooms = result == null ? new Room[0] : gson.fromJson(result, Room[].class); + if(replaceTrash) + for(Room r : rooms) + r.setName(replaceTrash(r.getName())); + return rooms; } public Device[] getDevices() { Room[] rooms = getRooms(); - log.debug("Founded: " + rooms.length + ", rooms"); + log.info("Found: " + rooms.length + " rooms"); + + String result = request("/api/devices?enabled=true&visible=true"); + Device[] all_devices = result == null ? new Device[0] : gson.fromJson(result, Device[].class); - Device[] all_devices = getAllDevices(); int count = 0; for(Device d : all_devices) - if(d.roomID > 0 && useSaveLogs ? "true".equals(d.properties.saveLogs) : true) + if(d.getRoomID() > 0 && (useSaveLogs ? "true".equals(d.getProperties().getSaveLogs()) : true)) count++; Device[] devices = new Device[count]; int i = 0; for(Device d : all_devices) - if(d.roomID > 0 && useSaveLogs ? "true".equals(d.properties.saveLogs) : true) + if(d.getRoomID() > 0 && (useSaveLogs ? "true".equals(d.getProperties().getSaveLogs()) : true)) { - if(useUserDescription && d.properties.userDescription != null && !d.properties.userDescription.isEmpty()) - d.name = d.properties.userDescription; - if(removeDigits) - d.name = replaceDigits(d.name); + if(useUserDescription && d.getProperties().getUserDescription() != null && !d.getProperties().getUserDescription().isEmpty()) + d.setName(d.getProperties().getUserDescription()); + if(replaceTrash) + d.setName(replaceTrash(d.getName())); + devices[i++] = d; for(Room room : rooms) - if(d.roomID == room.id) - { - d.room = room.name.trim(); - d.category = String.valueOf(room.sectionID); // TODO load name of section - } + if(d.getRoomID() == room.getId()) + d.setRoomName(room.getName()); d.fibaroaddress = fibaroAddress.getIp(); + d.fibaroport = fibaroAddress.getPort(); + d.fibaroAuth = fibaroAuth; d.fibaroname = fibaroAddress.getName(); } - log.info("Founded: " + devices.length + " devices"); + log.info("Found: " + devices.length + " devices"); return devices; } @@ -71,105 +145,34 @@ public class FibaroInfo public Scene[] getScenes() { Room[] rooms = getRooms(); + + String result = request("/api/scenes?enabled=true&visible=true"); + Scene[] all_scenes = result == null ? new Scene[0] : gson.fromJson(result, Scene[].class); + int count = 0; - Scene[] scenes = getAllScenes(); - for(Scene s : scenes) - if(!scenesWithLiliCommandOnly || s.liliStartCommand != null && !s.liliStartCommand.isEmpty()) + for(Scene s : all_scenes) + if(!scenesWithLiliCommandOnly || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty()) count++; - Scene[] result = new Scene[count]; + Scene[] scenes = new Scene[count]; int i = 0; - for(Scene s : scenes) - if(!scenesWithLiliCommandOnly || s.liliStartCommand != null && !s.liliStartCommand.isEmpty()) + for(Scene s : all_scenes) + if(!scenesWithLiliCommandOnly || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty()) { - result[i++] = s; + if(replaceTrash) + s.setName(replaceTrash(s.getName())); + + scenes[i++] = s; for(Room room : rooms) - if(s.roomID == room.id) - { - s.room = room.name.trim(); - s.category = String.valueOf(room.sectionID); // TODO load name of section - } + if(s.getRoomID() == room.getId()) + s.setRoomName(room.getName()); s.fibaroaddress = fibaroAddress.getIp(); + s.fibaroport = fibaroAddress.getPort(); + s.fibaroAuth = fibaroAuth; s.fibaroname = fibaroAddress.getName(); } - log.info("Founded: " + count + " scenes"); - return result; - } - - private Device[] getAllDevices() - { - String result = request("devices?enabled=true&visible=true"); - if(result == null) - return new Device[0]; - Device[] devices = new Gson().fromJson(result, Device[].class); - return devices; - } - - private Scene[] getAllScenes() - { - String result = request("scenes?enabled=true&visible=true"); - if(result == null) - return new Scene[0]; - Scene[] scenes = new Gson().fromJson(result, Scene[].class); + log.info("Found: " + count + " scenes"); return scenes; } - - private Room[] getRooms() - { - String result = request("rooms"); - if(result == null) - return new Room[0]; - return new Gson().fromJson(result, Room[].class); - } - - private String request(String theUrl) - { - theUrl = "http://" + fibaroAddress.getIp() + "/api/" + theUrl; - String auth = new String(Base64.encodeBase64((fibaroAddress.getUsername() + ":" + fibaroAddress.getPassword()).getBytes())); - java.net.URL url; - java.net.HttpURLConnection connection; - String result = null; - try - { - url = new URL(theUrl); - connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setRequestProperty("Authorization", "Basic " + auth); - connection.setRequestProperty("Content-Type", "application/json;charset=utf-8"); - connection.setRequestProperty("X-Requested-With", "XMLHttpRequest"); - connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.155 Safari/537.36"); - connection.connect(); - BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); - StringBuilder buffer = new StringBuilder(); - String line; - while((line = br.readLine()) != null) - buffer.append(line).append("\n"); - br.close(); - result = buffer.toString(); - } - catch(Exception e) - { - log.info("Error while get getJson: " + theUrl); - e.printStackTrace(); - return null; - } - return result; - } - - private String replaceDigits(String name) - { - name = name.replaceAll("1", ""); - name = name.replaceAll("2", ""); - name = name.replaceAll("3", ""); - name = name.replaceAll("4", ""); - name = name.replaceAll("5", ""); - name = name.replaceAll("6", ""); - name = name.replaceAll("7", ""); - name = name.replaceAll("8", ""); - name = name.replaceAll("9", ""); - name = name.replaceAll("0", ""); - name = name.trim(); - return name; - } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/ModeType.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/ModeType.java new file mode 100644 index 0000000..6732724 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/ModeType.java @@ -0,0 +1,35 @@ +package com.bwssystems.HABridge.plugins.fibaro; + +public enum ModeType { + OFF(0, "Off"), + HEAT(1, "Heat"), + COOL(2, "Cool"), + AUTO(3, "Auto"), + AUX_HEAT(4, "Aux Heat"), + RESUME(5, "Resume"), + FAN_ONLY(6, "Fan Only"), + FURNANCE(7, "Furnace"), + DRY_AIR(8, "Dry Air"), + MOIST_AIR(9, "Moist Air"), + AUTO_CHANGEOVER(10, "Auto Changeover"), + HEAT_ECON(11, "Heat Econ"), + COOL_ECON(12, "Cool Econ"), + AWAY(13, "Away"), + MANUAL(31, "Manual"); + + private int key; + private String label; + + private ModeType(int key, String label) { + this.key = key; + this.label = label; + } + + public int getKey() { + return key; + } + + public String getLabel() { + return label; + } +} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java deleted file mode 100644 index 0f7433e..0000000 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Room.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.bwssystems.HABridge.plugins.fibaro; - -public class Room -{ - public int id; - public String name; - public int sectionID; - public String icon; - public Sensor defaultSensors; - public int defaultThermostat; - public int sortOrder; - - public class Sensor - { - public int temperature; - public int humidity; - public int light; - } -} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java deleted file mode 100644 index da4ce01..0000000 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/Scene.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.bwssystems.HABridge.plugins.fibaro; - -public class Scene -{ - public int id; - public String name; - public String type; - public String properties; - public int roomID; - public int iconID; - public String runConfig; - public boolean autostart; - public boolean protectedByPIN; - public boolean killable; - public int maxRunningInstances; - public int runningInstances; - public boolean visible; - public boolean isLua; - public Triggers triggers; - public String liliStartCommand; - public String liliStopCommand; - public int sortOrder; - - public class Triggers { - public Properties[] properties; - public String[] globals; - public String[] events; - } - - public class Properties { - public String id; - public String name; - } - - public String room; - public String category; - public String fibaroaddress; - public String fibaroname; -} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Device.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Device.java new file mode 100644 index 0000000..cd12201 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Device.java @@ -0,0 +1,108 @@ +package com.bwssystems.HABridge.plugins.fibaro.json; + +import com.google.gson.annotations.SerializedName; + +public class Device { + private String roomName; + + @SerializedName("id") + private String id; + + @SerializedName("name") + private String name; + + @SerializedName("roomID") + private int roomID; + + @SerializedName("type") + private String type; + + @SerializedName("baseType") + private String baseType; + + @SerializedName("enabled") + private boolean enabled; + + @SerializedName("visible") + private boolean visible; + + @SerializedName("isPlugin") + private boolean isPlugin; + + @SerializedName("parentId") + private int parentId; + + @SerializedName("remoteGatewayId") + private int remoteGatewayId; + + @SerializedName("viewXml") + private boolean viewXml; + + @SerializedName("configXml") + private boolean configXml; + + @SerializedName("interfaces") + private Object interfaces; + + @SerializedName("properties") + private DeviceProperties properties; + + @SerializedName("actions") + private Object actions; + + @SerializedName("created") + private int created; + + @SerializedName("modified") + private int modified; + + @SerializedName("sortOrder") + private int sortOrder; + + public String getRoomName() { + return roomName; + } + + public void setRoomName(String roomName) { + this.roomName = roomName; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getRoomID() { + return roomID; + } + + public String getType() { + return type; + } + + public DeviceProperties getProperties() { + return properties; + } + + public boolean isThermostat() { + return type.equals("com.fibaro.setPoint") || type.equals("com.fibaro.thermostatDanfoss") + || type.equals("com.fibaro.thermostatHorstmann"); + } + + @Override + public String toString() { + return "{" + id + ", " + name + "}"; + } + + public String fibaroaddress; + public String fibaroport; + public String fibaroAuth; + public String fibaroname; +} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/DeviceProperties.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/DeviceProperties.java new file mode 100644 index 0000000..9e68c48 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/DeviceProperties.java @@ -0,0 +1,244 @@ +package com.bwssystems.HABridge.plugins.fibaro.json; + +import com.google.gson.annotations.SerializedName; + +public class DeviceProperties { + @SerializedName("batteryLevel") + private String batteryLevel; + + @SerializedName("UIMessageSendTime") + private String UIMessageSendTime; + + @SerializedName("autoConfig") + private String autoConfig; + + @SerializedName("color") + private String color; + + @SerializedName("date") + private String date; + + @SerializedName("dead") + private String dead; + + @SerializedName("deviceControlType") + private String deviceControlType; + + @SerializedName("deviceIcon") + private String deviceIcon; + + @SerializedName("disabled") + private String disabled; + + @SerializedName("emailNotificationID") + private String emailNotificationID; + + @SerializedName("emailNotificationType") + private String emailNotificationType; + + @SerializedName("endPoint") + private String endPoint; + + @SerializedName("energy") + private String energy; + + @SerializedName("liliOffCommand") + private String liliOffCommand; + + @SerializedName("liliOnCommand") + private String liliOnCommand; + + @SerializedName("log") + private String log; + + @SerializedName("logTemp") + private String logTemp; + + @SerializedName("manufacturer") + private String manufacturer; + + @SerializedName("markAsDead") + private String markAsDead; + + @SerializedName("mode") + private String mode; + + @SerializedName("model") + private String model; + + @SerializedName("nodeID") + private String nodeID; + + @SerializedName("pollingDeadDevice") + private String pollingDeadDevice; + + @SerializedName("pollingTime") + private String pollingTime; + + @SerializedName("pollingTimeNext") + private String pollingTimeNext; + + @SerializedName("pollingTimeSec") + private int pollingTimeSec; + + @SerializedName("power") + private String power; + + @SerializedName("productInfo") + private String productInfo; + + @SerializedName("pushNotificationID") + private String pushNotificationID; + + @SerializedName("pushNotificationType") + private String pushNotificationType; + + @SerializedName("remoteGatewayId") + private String remoteGatewayId; + + @SerializedName("requestNodeNeighborStat") + private String requestNodeNeighborStat; + + @SerializedName("requestNodeNeighborStatTimeStemp") + private String requestNodeNeighborStatTimeStemp; + + @SerializedName("requestNodeNeighborState") + private String requestNodeNeighborState; + + @SerializedName("requestNodeNeighborStateTimeStemp") + private String requestNodeNeighborStateTimeStemp; + + @SerializedName("saveLogs") + private String saveLogs; + + @SerializedName("showChildren") + private String showChildren; + + @SerializedName("smsNotificationID") + private String smsNotificationID; + + @SerializedName("smsNotificationType") + private String smsNotificationType; + + @SerializedName("supportedModes") + private String supportedModes; + + @SerializedName("targetLevel") + private String targetLevel; + + @SerializedName("unit") + private String unit; + + @SerializedName("useTemplate") + private String useTemplate; + + @SerializedName("status") + private String status; + + @SerializedName("sunriseHour") + private String sunriseHour; + + @SerializedName("sunsetHour") + private String sunsetHour; + + @SerializedName("userDescription") + private String userDescription; + + @SerializedName("value") + private String value; + + @SerializedName("zwaveBuildVersion") + private String zwaveBuildVersion; + + @SerializedName("zwaveCompany") + private String zwaveCompany; + + @SerializedName("zwaveInfo") + private String zwaveInfo; + + @SerializedName("zwaveRegion") + private String zwaveRegion; + + @SerializedName("zwaveVersion") + private double zwaveVersion; + + public String getBatteryLevel() { + return batteryLevel; + } + + public String getColor() { + return color; + } + + public String getDeviceControlType() { + return deviceControlType; + } + + public String getEnergy() { + return energy; + } + + public String getPower() { + return power; + } + + public String getTargetLevel() { + return targetLevel; + } + + public String getValue() { + return value; + } + + // --- begin yrWeather plugin --- + @SerializedName("Humidity") + private String Humidity; + + @SerializedName("Pressure") + private String Pressure; + + @SerializedName("Temperature") + private String Temperature; + + @SerializedName("WeatherCondition") + private String WeatherCondition; + + @SerializedName("Wind") + private String Wind; + + public String getHumidity() { + return Humidity; + } + + public String getPressure() { + return Pressure; + } + + public String getSaveLogs() + { + return saveLogs; + } + + public String getTemperature() { + return Temperature; + } + + public String getWeatherCondition() { + return WeatherCondition; + } + + public String getWind() { + return Wind; + } + // --- end yrWeather plugin --- + + public String getUserDescription() + { + return userDescription; + } + + public void setUserDescription(String userDescription) + { + this.userDescription = userDescription; + } +} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Room.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Room.java new file mode 100644 index 0000000..5aed4d3 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Room.java @@ -0,0 +1,43 @@ +package com.bwssystems.HABridge.plugins.fibaro.json; + +import com.google.gson.annotations.SerializedName; + +public class Room { + @SerializedName("id") + private int id; + + @SerializedName("name") + private String name; + + @SerializedName("sectionID") + private int sectionID; + + @SerializedName("icon") + private String icon; + + @SerializedName("defaultSensors") + private Sensor defaultSensors; + + @SerializedName("defaultThermostat") + private int defaultThermostat; + + @SerializedName("sortOrder") + private int sortOrder; + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getSectionID() + { + return sectionID; + } +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Scene.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Scene.java new file mode 100644 index 0000000..bf8c430 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Scene.java @@ -0,0 +1,100 @@ +package com.bwssystems.HABridge.plugins.fibaro.json; + +import com.google.gson.annotations.SerializedName; + +public class Scene { + private String roomName; + + @SerializedName("id") + private String id; + + @SerializedName("name") + private String name; + + @SerializedName("type") + private String type; + + @SerializedName("properties") + private String properties; + + @SerializedName("roomID") + private int roomID; + + @SerializedName("iconID") + private int iconID; + + @SerializedName("runConfig") + private String runConfig; + + @SerializedName("autostart") + private boolean autostart; + + @SerializedName("protectedByPIN") + private boolean protectedByPIN; + + @SerializedName("killable") + private boolean killable; + + @SerializedName("maxRunningInstances") + private int maxRunningInstances; + + @SerializedName("runningInstances") + private int runningInstances; + + @SerializedName("visible") + private boolean visible; + + @SerializedName("isLua") + private boolean isLua; + + @SerializedName("triggers") + private SceneTriggers triggers; + + @SerializedName("liliStartCommand") + private String liliStartCommand; + + @SerializedName("liliStopCommand") + private String liliStopCommand; + + @SerializedName("sortOrder") + private int sortOrder; + + public String getRoomName() { + return roomName; + } + + public void setRoomName(String roomName) { + this.roomName = roomName; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getRoomID() { + return roomID; + } + + public String getLiliStartCommand() + { + return liliStartCommand; + } + + @Override + public String toString() { + return "{" + id + ", " + name + "}"; + } + + public String fibaroaddress; + public String fibaroport; + public String fibaroAuth; + public String fibaroname; +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneProperties.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneProperties.java new file mode 100644 index 0000000..99ece4e --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneProperties.java @@ -0,0 +1,11 @@ +package com.bwssystems.HABridge.plugins.fibaro.json; + +import com.google.gson.annotations.SerializedName; + +public class SceneProperties { + @SerializedName("id") + private String id; + + @SerializedName("name") + private String name; +} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneTriggers.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneTriggers.java new file mode 100644 index 0000000..9b0f761 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/SceneTriggers.java @@ -0,0 +1,14 @@ +package com.bwssystems.HABridge.plugins.fibaro.json; + +import com.google.gson.annotations.SerializedName; + +public class SceneTriggers { + @SerializedName("properties") + private SceneProperties[] properties; + + @SerializedName("globals") + private String[] globals; + + @SerializedName("events") + private String[] events; +} diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Sensor.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Sensor.java new file mode 100644 index 0000000..8875995 --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/json/Sensor.java @@ -0,0 +1,14 @@ +package com.bwssystems.HABridge.plugins.fibaro.json; + +import com.google.gson.annotations.SerializedName; + +public class Sensor { + @SerializedName("temperature") + private int temperature; + + @SerializedName("humidity") + private int humidity; + + @SerializedName("light") + private int light; +} diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 0b20f4f..05be93b 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -1337,20 +1337,21 @@ app.controller ('SystemController', function ($scope, $location, bridgeService, } } }; - $scope.addFibarotoSettings = function (newfibaroname, newfibaroip, newfibarousername, newfibaropassword) { + $scope.addFibarotoSettings = function (newfibaroname, newfibaroip, newfibaroport, newfibarousername, newfibaropassword) { if($scope.bridge.settings.fibaroaddress === undefined || $scope.bridge.settings.fibaroaddress === null) { $scope.bridge.settings.fibaroaddress = { devices: [] }; } - var newFibaro = {name: newfibaroname, ip: newfibaroip, username: newfibarousername, password: newfibaropassword } + var newFibaro = {name: newfibaroname, ip: newfibaroip, port: newfibaroport, username: newfibarousername, password: newfibaropassword } $scope.bridge.settings.fibaroaddress.devices.push(newFibaro); $scope.newfibaroname = null; $scope.newfibaroip = null; + $scope.newfibaroport = null; $scope.newfibarousername = null; $scope.newfibaropassword = null; }; - $scope.removeFibarotoSettings = function (fibaroname, fibaroip) { + $scope.removeFibarotoSettings = function (fibaroname, fibaroip, fibaroport) { for(var i = $scope.bridge.settings.fibaroaddress.devices.length - 1; i >= 0; i--) { - if($scope.bridge.settings.fibaroaddress.devices[i].name === fibaroname && $scope.bridge.settings.fibaroaddress.devices[i].ip === fibaroip) { + if($scope.bridge.settings.fibaroaddress.devices[i].name === fibaroname && $scope.bridge.settings.fibaroaddress.devices[i].ip === fibaroip && $scope.bridge.settings.fibaroaddress.devices[i].port === fibaroport) { $scope.bridge.settings.fibaroaddress.devices.splice(i, 1); } } @@ -1988,14 +1989,13 @@ app.controller('FibaroController', function ($scope, $location, bridgeService, n $scope.buildDeviceUrls = function (fibarodevice, dim_control, buildonly) { if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) - dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=setValue&arg1=" + dim_control; - else - dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOn"; + dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + fibarodevice.fibaroport + "/api/callAction?deviceID=" + fibarodevice.id + "&name=setValue&arg1=" + dim_control; - onpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOn"; - offpayload = "http://" + fibarodevice.fibaroaddress + ":" + $scope.fibaro.port + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOff"; + onpayload = "http://" + fibarodevice.fibaroaddress + ":" + fibarodevice.fibaroport + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOn"; + offpayload = "http://" + fibarodevice.fibaroaddress + ":" + fibarodevice.fibaroport + "/api/callAction?deviceID=" + fibarodevice.id + "&name=turnOff"; bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, fibarodevice.id, fibarodevice.name, fibarodevice.fibaroname, "switch", "fibaroDevice", null, null); + bridgeService.state.device.headers = "[{\"name\":\"Authorization\",\"value\":\"" + fibarodevice.fibaroAuth + "\"}]"; $scope.device = bridgeService.state.device; if (!buildonly) { bridgeService.editNewDevice($scope.device); @@ -2004,10 +2004,11 @@ app.controller('FibaroController', function ($scope, $location, bridgeService, n }; $scope.buildSceneUrls = function (fibaroscene) { - onpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port + "/api/sceneControl?id=" + fibaroscene.id + "&action=start"; - offpayload = "http://" + fibaroscene.fibaroaddress + ":" + $scope.fibaro.port + "/api/sceneControl?id=" + fibaroscene.id + "&action=stop"; + onpayload = "http://" + fibaroscene.fibaroaddress + ":" + fibaroscene.fibaroport + "/api/sceneControl?id=" + fibaroscene.id + "&action=start"; + offpayload = "http://" + fibaroscene.fibaroaddress + ":" + fibaroscene.fibaroport + "/api/sceneControl?id=" + fibaroscene.id + "&action=stop"; bridgeService.buildUrls(onpayload, null, offpayload, false, fibaroscene.id, fibaroscene.name, fibaroscene.fibaroname, "scene", "fibaroScene", null, null); + bridgeService.state.device.headers = "[{\"name\":\"Authorization\",\"value\":\"" + fibaroscene.fibaroAuth + "\"}]"; $scope.device = bridgeService.state.device; bridgeService.editNewDevice($scope.device); $location.path('/editdevice'); diff --git a/src/main/resources/public/views/fibarodevice.html b/src/main/resources/public/views/fibarodevice.html index fe8e513..95e428c 100644 --- a/src/main/resources/public/views/fibarodevice.html +++ b/src/main/resources/public/views/fibarodevice.html @@ -63,9 +63,9 @@ ng-checked="selectAll" ng-click="toggleSelectAll()"> Name - + @@ -78,9 +78,9 @@ ng-click="toggleSelection(fibarodevice.id)"> {{fibarodevice.name}} - - + + - + + @@ -160,11 +161,12 @@ + + ng-click="removeFibarotoSettings(fibaro.name, fibaro.ip, fibaro.port)">Del + @@ -180,7 +185,7 @@ class="form-control" type="password" ng-model="newfibaropassword" placeholder="Fibaro password"> + ng-click="addFibarotoSettings(newfibaroname, newfibaroip, newfibaroport, newfibarousername, newfibaropassword)">Add
    IdCategory Room FibaroValue Build Actions
    {{fibarodevice.id}}{{fibarodevice.category}}{{fibarodevice.room}}{{fibarodevice.roomName}} {{fibarodevice.fibaroname}}{{fibarodevice.properties.value}} diff --git a/src/main/resources/public/views/fibaroscene.html b/src/main/resources/public/views/fibaroscene.html index f8d0dda..c5c35fa 100644 --- a/src/main/resources/public/views/fibaroscene.html +++ b/src/main/resources/public/views/fibaroscene.html @@ -53,7 +53,7 @@ {{$index+1}} {{fibaroscene.name}} {{fibaroscene.id}}{{fibaroscene.room}}{{fibaroscene.roomName}} {{fibaroscene.fibaroname}} Name IPPort Username Password Manage
    {{fibaro.name}} {{fibaro.ip}}{{fibaro.port}} {{fibaro.username}} *******
    From b147f6606e96d1b705d088540554377b6490333e Mon Sep 17 00:00:00 2001 From: Admin Date: Thu, 19 Oct 2017 15:56:15 -0500 Subject: [PATCH 19/28] Update MQTT reconnect, and import statements and color convert test case. --- pom.xml | 2 +- .../HABridge/plugins/http/HTTPHandler.java | 4 ---- .../bwssystems/HABridge/plugins/hue/HueInfo.java | 7 ------- .../HABridge/plugins/mqtt/MQTTHandler.java | 12 ++++++++++++ .../color/test/ConvertCIEColorTestCase.java | 14 +++++++------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/pom.xml b/pom.xml index d7a97b9..f87215a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.0.0rc1 + 5.0.0rc2 jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java index 31723fb..67e9330 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java @@ -12,8 +12,6 @@ import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.config.CookieSpecs; -import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; @@ -25,8 +23,6 @@ import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.protocol.HttpRequestExecutor; import org.apache.http.util.EntityUtils; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java index 03cdefc..af80384 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java @@ -1,15 +1,8 @@ package com.bwssystems.HABridge.plugins.hue; -import java.io.IOException; - -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java index 792df9f..e39fc13 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java @@ -5,6 +5,7 @@ import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; +import org.eclipse.paho.client.mqttv3.MqttSecurityException; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,6 +52,17 @@ public class MQTTHandler { message.setRetained(Optional.ofNullable(retain).orElse(false)); try { + if(!myClient.isConnected()) { + try { + myClient.connect(); + } catch (MqttSecurityException e1) { + log.error("Could not retry connect to MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e1.getMessage()); + return; + } catch (MqttException e1) { + log.error("Could not retry connect to MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e1.getMessage()); + return; + } + } myClient.publish(topic, message); } catch (MqttException e) { log.error("Could not publish to MQTT client for name: " + myConfig.getName() + " and ip: " + myConfig.getIp() + " with message: " + e.getMessage()); diff --git a/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java b/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java index 243dcb0..d3e04d8 100644 --- a/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java +++ b/src/test/java/com/bwssystems/color/test/ConvertCIEColorTestCase.java @@ -13,14 +13,14 @@ public class ConvertCIEColorTestCase { @Test public void testColorConversion() { - //ArrayList xy = new ArrayList(Arrays.asList(new Double(0.671254), new Double(0.303273))); + ArrayList xy = new ArrayList(Arrays.asList(new Double(0.671254), new Double(0.303273))); - //List colorDecode = ColorDecode.convertCIEtoRGB(xy, 254); - //List assertDecode = new ArrayList(); - //assertDecode.add(0, 255.0); - //assertDecode.add(1, 47.0); - //assertDecode.add(2, 43.0); - //Assert.assertEquals(colorDecode, assertDecode); + List colorDecode = ColorDecode.convertCIEtoRGB(xy, 254); + List assertDecode = new ArrayList(); + assertDecode.add(0, 255); + assertDecode.add(1, 47); + assertDecode.add(2, 43); + Assert.assertEquals(colorDecode, assertDecode); } } From 548da932add63f5d4ecc320b4c70b9ac0becd576 Mon Sep 17 00:00:00 2001 From: Admin Date: Fri, 20 Oct 2017 11:04:05 -0500 Subject: [PATCH 20/28] Updated hue hub version to be 999999999 to help alleviate version issues. Updated upnp multicast to use one socket. Updated http Handler code to check for null on conn. --- .../com/bwssystems/HABridge/HABridge.java | 12 ++++- .../HABridge/api/hue/HueConstants.java | 2 +- .../HABridge/plugins/http/HTTPHandler.java | 3 +- .../HABridge/upnp/UpnpListener.java | 44 +++++++++++-------- 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index b636a84..25742d5 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -2,6 +2,8 @@ package com.bwssystems.HABridge; import static spark.Spark.*; +import java.io.IOException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,8 +84,14 @@ public class HABridge { awaitInitialization(); // start the upnp ssdp discovery listener - theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl(), udpSender); - if(theUpnpListener.startListening()) + theUpnpListener = null; + try { + theUpnpListener = new UpnpListener(bridgeSettings.getBridgeSettingsDescriptor(), bridgeSettings.getBridgeControl(), udpSender); + } catch (IOException e) { + log.error("Could not initialize UpnpListener, exiting....", e); + theUpnpListener = null; + } + if(theUpnpListener != null && theUpnpListener.startListening()) log.info("HA Bridge (v" + theVersion.getVersion() + ") reinitialization requessted...."); else bridgeSettings.getBridgeControl().setStop(true); diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueConstants.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueConstants.java index da2da74..72f136d 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/HueConstants.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueConstants.java @@ -1,7 +1,7 @@ package com.bwssystems.HABridge.api.hue; public class HueConstants { - public final static String HUB_VERSION = "1705121051"; + public final static String HUB_VERSION = "9999999999"; public final static String API_VERSION = "1.19.0"; public final static String MODEL_ID = "BSB002"; public final static String UUID_PREFIX = "2f402f80-da50-11e1-9b23-"; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java index 67e9330..9179914 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java @@ -208,7 +208,8 @@ public class HTTPHandler { public void closeHandler() { try { // httpClient.close(); - conn.close(); + if(conn != null) + conn.close(); connMgr.closeExpiredConnections(); connMgr.shutdown(); } catch (IOException e) { diff --git a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java index 8f74a80..571cef4 100644 --- a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java +++ b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java @@ -20,7 +20,7 @@ import org.apache.http.conn.util.*; public class UpnpListener { private Logger log = LoggerFactory.getLogger(UpnpListener.class); - private UDPDatagramSender theUDPDatagramSender; + private MulticastSocket upnpMulticastSocket; private int httpServerPort; private String responseAddress; private boolean strict; @@ -68,9 +68,9 @@ public class UpnpListener { "NT: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n" + "USN: uuid:" + HueConstants.UUID_PREFIX + "%s\r\n\r\n"; - public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) { + public UpnpListener(BridgeSettingsDescriptor theSettings, BridgeControlDescriptor theControl, UDPDatagramSender aUdpDatagramSender) throws IOException { super(); - theUDPDatagramSender = aUdpDatagramSender; + upnpMulticastSocket = null; httpServerPort = Integer.valueOf(theSettings.getServerPort()); responseAddress = theSettings.getUpnpConfigAddress(); strict = theSettings.isUpnpStrict(); @@ -80,21 +80,19 @@ public class UpnpListener { aHueConfig = HuePublicConfig.createConfig("temp", responseAddress, HueConstants.HUB_VERSION); bridgeId = aHueConfig.getBridgeid(); bridgeSNUUID = aHueConfig.getSNUUIDFromMac(); - } - - @SuppressWarnings("resource") - public boolean startListening(){ - log.info("UPNP Discovery Listener starting...."); - MulticastSocket upnpMulticastSocket = null; - Enumeration ifs = null; - try { upnpMulticastSocket = new MulticastSocket(Configuration.UPNP_DISCOVERY_PORT); } catch(IOException e){ log.error("Upnp Discovery Port is in use, or restricted by admin (try running with sudo or admin privs): " + Configuration.UPNP_DISCOVERY_PORT + " with message: " + e.getMessage()); - return false; + throw(e); } + } + + public boolean startListening(){ + log.info("UPNP Discovery Listener starting...."); + Enumeration ifs = null; + InetSocketAddress socketAddress = new InetSocketAddress(Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT); try { ifs = NetworkInterface.getNetworkInterfaces(); @@ -163,12 +161,12 @@ public class UpnpListener { current = Instant.now(); if(ChronoUnit.MILLIS.between(previous, current) > Configuration.UPNP_NOTIFY_TIMEOUT) { - sendUpnpNotify(socketAddress.getAddress(), upnpMulticastSocket); + sendUpnpNotify(socketAddress.getAddress()); previous = Instant.now(); } } catch (SocketTimeoutException e) { - sendUpnpNotify(socketAddress.getAddress(), upnpMulticastSocket); + sendUpnpNotify(socketAddress.getAddress()); } catch (IOException e) { log.error("UpnpListener encountered an error reading socket. Shutting down", e); error = true; @@ -242,7 +240,7 @@ public class UpnpListener { } else log.debug("sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>"); - theUDPDatagramSender.sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); + sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID); if(traceupnp) { @@ -250,7 +248,7 @@ public class UpnpListener { } else log.debug("sendUpnpResponse discovery responseTemplate2 is <<<" + discoveryResponse + ">>>"); - theUDPDatagramSender.sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); + sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID); if(traceupnp) { @@ -258,10 +256,18 @@ public class UpnpListener { } else log.debug("sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>"); - theUDPDatagramSender.sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); + sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); + } + + private void sendUDPResponse(byte[] udpMessage, InetAddress requester, int sourcePort) throws IOException { + log.debug("Sending response string: <<<" + new String(udpMessage) + ">>>"); + if(upnpMulticastSocket == null) + throw new IOException("Socket not initialized"); + DatagramPacket response = new DatagramPacket(udpMessage, udpMessage.length, requester, sourcePort); + upnpMulticastSocket.send(response); } - protected void sendUpnpNotify(InetAddress aSocketAddress, MulticastSocket theUpnpMulticastSocket) { + protected void sendUpnpNotify(InetAddress aSocketAddress) { String notifyData = null; log.debug("Sending notify packet for upnp."); notifyData = String.format(notifyTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID); @@ -270,7 +276,7 @@ public class UpnpListener { } DatagramPacket notifyPacket = new DatagramPacket(notifyData.getBytes(), notifyData.length(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT); try { - theUpnpMulticastSocket.send(notifyPacket); + upnpMulticastSocket.send(notifyPacket); } catch (IOException e1) { log.warn("UpnpListener encountered an error sending upnp notify packet. IP: " + notifyPacket.getAddress().getHostAddress() + " with message: " + e1.getMessage()); log.debug("UpnpListener send upnp notify exception: ", e1); From 690bdaa74893ab56562b1f4f054f0dde4604febc Mon Sep 17 00:00:00 2001 From: Admin Date: Tue, 14 Nov 2017 13:36:07 -0600 Subject: [PATCH 21/28] Finalized Fibaro merge correcting inconsistencies. --- pom.xml | 2 +- .../com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java | 4 +++- .../com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index f87215a..0cd4af0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.0.0rc2 + 5.0.0rc3 jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java index 20a7ec5..d122586 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java @@ -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.fibaro.json.Device; import com.bwssystems.HABridge.plugins.fibaro.json.Scene; @@ -60,7 +61,8 @@ public class FibaroHome 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) { // Not a device handler return null; diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java index 73201a9..3e8dc27 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroInfo.java @@ -66,7 +66,7 @@ public class FibaroInfo return result; } - private boolean sendCommand(String request) + protected boolean sendCommand(String request) { try { From d8d5e8f39a2170b8d4017b90e203a14e5b0b0b24 Mon Sep 17 00:00:00 2001 From: Admin Date: Tue, 14 Nov 2017 16:37:45 -0600 Subject: [PATCH 22/28] Added hub mac setting, removed global hal token setting, removed upnp strict setting (only from command line) Working on http pool --- .../bwssystems/HABridge/BridgeSettings.java | 3 + .../HABridge/BridgeSettingsDescriptor.java | 20 +++-- .../HABridge/api/hue/HueApiResponse.java | 4 +- .../HABridge/api/hue/HueConfig.java | 4 +- .../HABridge/api/hue/HuePublicConfig.java | 51 ++++++----- .../bwssystems/HABridge/hue/HueMulator.java | 6 +- .../HABridge/plugins/http/HTTPHandler.java | 84 +++++++++++-------- .../HABridge/upnp/UpnpListener.java | 2 +- .../HABridge/upnp/UpnpSettingsResource.java | 2 +- src/main/resources/public/views/system.html | 19 ++--- 10 files changed, 109 insertions(+), 86 deletions(-) diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java index ee06829..611ec04 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java @@ -76,6 +76,7 @@ public class BridgeSettings extends BackupHandler { } String serverPortOverride = System.getProperty("server.port"); String serverIpOverride = System.getProperty("server.ip"); + String upnpStrictOverride = System.getProperty("upnp.strict", "true"); if(configFileProperty != null) { log.info("reading from config file: " + configFileProperty); @@ -213,6 +214,8 @@ public class BridgeSettings extends BackupHandler { theBridgeSettings.setServerPort(serverPortOverride); if(serverIpOverride != null) theBridgeSettings.setWebaddress(serverIpOverride); + if(upnpStrictOverride != null) + theBridgeSettings.setUpnpStrict(Boolean.parseBoolean(upnpStrictOverride)); setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-"); bridgeSecurity.setSecurityData(theBridgeSettings.getSecurityData()); diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java index aadf4d0..4160d2f 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java @@ -39,9 +39,6 @@ public class BridgeSettingsDescriptor { @SerializedName("buttonsleep") @Expose private Integer buttonsleep; - @SerializedName("upnpstrict") - @Expose - private boolean upnpstrict; @SerializedName("traceupnp") @Expose private boolean traceupnp; @@ -66,9 +63,6 @@ public class BridgeSettingsDescriptor { @SerializedName("haladdress") @Expose private IpList haladdress; - @SerializedName("haltoken") - @Expose - private String haltoken; @SerializedName("whitelist") @Expose private Map whitelist; @@ -93,6 +87,9 @@ public class BridgeSettingsDescriptor { @SerializedName("hubversion") @Expose private String hubversion; + @SerializedName("hubmac") + @Expose + private String hubmac; @SerializedName("securityData") @Expose private String securityData; @@ -110,6 +107,10 @@ public class BridgeSettingsDescriptor { private boolean domoticzconfigured; private boolean somfyconfigured; private boolean lifxconfigured; + + // Deprecated settings + private String haltoken; + private boolean upnpstrict; public BridgeSettingsDescriptor() { super(); @@ -134,6 +135,7 @@ public class BridgeSettingsDescriptor { this.myechourl = "alexa.amazon.com/spa/index.html#cards"; this.webaddress = "0.0.0.0"; this.hubversion = HueConstants.HUB_VERSION; + this.hubmac = null; } public String getUpnpConfigAddress() { return upnpconfigaddress; @@ -363,6 +365,12 @@ public class BridgeSettingsDescriptor { public void setHubversion(String hubversion) { this.hubversion = hubversion; } + public String getHubmac() { + return hubmac; + } + public void setHubmac(String hubmac) { + this.hubmac = hubmac; + } public IpList getDomoticzaddress() { return domoticzaddress; } diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java index 17cc14e..cbcef69 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueApiResponse.java @@ -18,9 +18,9 @@ public class HueApiResponse { private Map rules; private HueConfig config; - public HueApiResponse(String name, String ipaddress, Map awhitelist, String emulateHubVersion, boolean isLinkButtonPressed) { + public HueApiResponse(String name, String ipaddress, Map awhitelist, String emulateHubVersion, boolean isLinkButtonPressed, String emulateMAC) { super(); - this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist, emulateHubVersion, isLinkButtonPressed)); + this.setConfig(HueConfig.createConfig(name, ipaddress, awhitelist, emulateHubVersion, isLinkButtonPressed, emulateMAC)); this.setRules(new HashMap<>()); this.setSensors(new HashMap<>()); this.setSchedules(new HashMap<>()); diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java b/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java index 3b9be6c..a785984 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HueConfig.java @@ -34,7 +34,7 @@ public class HueConfig private String replacesbridgeid; private Map whitelist; - public static HueConfig createConfig(String name, String ipaddress, Map awhitelist, String emulateHubVersion, boolean isLinkButtonPressed) { + public static HueConfig createConfig(String name, String ipaddress, Map awhitelist, String emulateHubVersion, boolean isLinkButtonPressed, String emulateMAC) { HueConfig aConfig = new HueConfig(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); @@ -56,7 +56,7 @@ public class HueConfig aConfig.setLocaltime(dateFormat.format(new Date())); aConfig.setTimezone(TimeZone.getDefault().getID()); aConfig.setZigbeechannel("6"); - aConfig.setBridgeid(HuePublicConfig.createConfig(name, ipaddress, emulateHubVersion).getHueBridgeIdFromMac()); + aConfig.setBridgeid(HuePublicConfig.createConfig(name, ipaddress, emulateHubVersion, emulateMAC).getHueBridgeIdFromMac()); aConfig.setModelid(HueConstants.MODEL_ID); aConfig.setFactorynew(false); aConfig.setReplacesbridgeid(null); diff --git a/src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java b/src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java index 6320634..8cbecc9 100644 --- a/src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java +++ b/src/main/java/com/bwssystems/HABridge/api/hue/HuePublicConfig.java @@ -18,9 +18,9 @@ public class HuePublicConfig private Boolean factorynew; private String modelid; - public static HuePublicConfig createConfig(String name, String ipaddress, String emulateHubVersion) { + public static HuePublicConfig createConfig(String name, String ipaddress, String emulateHubVersion, String emulateMAC) { HuePublicConfig aConfig = new HuePublicConfig(); - aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress)); + aConfig.setMac(HuePublicConfig.getMacAddress(ipaddress, emulateMAC)); aConfig.setApiversion(HueConstants.API_VERSION); aConfig.setSwversion(emulateHubVersion); aConfig.setName(name); @@ -32,34 +32,39 @@ public class HuePublicConfig return aConfig; } - private static String getMacAddress(String addr) + private static String getMacAddress(String addr, String aMAC) { InetAddress ip; StringBuilder sb = new StringBuilder(); - try { + if(aMAC == null || aMAC.trim().length() <= 0) { + try { + + ip = InetAddress.getByName(addr); - ip = InetAddress.getByName(addr); - - NetworkInterface network = NetworkInterface.getByInetAddress(ip); + NetworkInterface network = NetworkInterface.getByInetAddress(ip); + + byte[] mac = network.getHardwareAddress(); + + for (int i = 0; i < mac.length; i++) { + sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : "")); + } + + } catch (UnknownHostException e) { - byte[] mac = network.getHardwareAddress(); + sb.append("00:00:88:00:bb:ee"); + + } catch (SocketException e){ + + sb.append("00:00:88:00:bb:ee"); + + } catch (Exception e){ + + sb.append("00:00:88:00:bb:ee"); - for (int i = 0; i < mac.length; i++) { - sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : "")); } - - } catch (UnknownHostException e) { - - sb.append("00:00:88:00:bb:ee"); - - } catch (SocketException e){ - - sb.append("00:00:88:00:bb:ee"); - - } catch (Exception e){ - - sb.append("00:00:88:00:bb:ee"); - + } + else { + sb.append(aMAC.trim()); } return sb.toString(); diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 1472768..4de6ffb 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -965,12 +965,12 @@ public class HueMulator { 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("HA-Bridge", - bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion()); + bridgeSettings.getUpnpConfigAddress(), bridgeSettings.getHubversion(), bridgeSettings.getHubmac()); return apiResponse; } HueApiResponse apiResponse = new HueApiResponse("HA-Bridge", bridgeSettings.getUpnpConfigAddress(), - bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton()); + bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton(), bridgeSettings.getHubmac()); log.debug("api response config <<<" + aGsonHandler.toJson(apiResponse.getConfig()) + ">>>"); return apiResponse.getConfig(); } @@ -985,7 +985,7 @@ public class HueMulator { } HueApiResponse apiResponse = new HueApiResponse("HA-Bridge", bridgeSettings.getUpnpConfigAddress(), - bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton()); + bridgeSettingMaster.getBridgeSecurity().getWhitelist(), bridgeSettings.getHubversion(), bridgeSettingMaster.getBridgeControl().isLinkButton(), bridgeSettings.getHubmac()); apiResponse.setLights((Map) this.lightsListHandler(userId, ipAddress)); apiResponse.setGroups((Map) this.groupsListHandler(userId, ipAddress)); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java index 9179914..01a544b 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java @@ -24,6 +24,7 @@ import org.apache.http.conn.routing.HttpRoute; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpRequestExecutor; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; @@ -36,14 +37,21 @@ public class HTTPHandler { // private CloseableHttpClient httpClient; // private RequestConfig globalConfig; private HttpClientContext context; - private HttpClientConnectionManager connMgr; + private PoolingHttpClientConnectionManager connMgr; private HttpRoute route; private HttpClientConnection conn; private HttpHost theHost; public HTTPHandler() { context = HttpClientContext.create(); - connMgr = new BasicHttpClientConnectionManager(); + connMgr = new PoolingHttpClientConnectionManager(); + // Increase max total connection to 200 + connMgr.setMaxTotal(200); + // Increase default max connection per route to 20 + connMgr.setDefaultMaxPerRoute(20); + // Increase max connections for localhost:80 to 50 + HttpHost localhost = new HttpHost("locahost", 80); + connMgr.setMaxPerRoute(new HttpRoute(localhost), 50); route = null; conn = null; theHost = null; @@ -62,6 +70,7 @@ public class HTTPHandler { ContentType parsedContentType = null; ConnectionRequest connRequest = null; StringEntity requestBody = null; + boolean badResponse = false; if (contentType != null && !contentType.trim().isEmpty()) { parsedContentType = ContentType.parse(contentType); if (body != null && body.length() > 0) @@ -143,43 +152,48 @@ public class HTTPHandler { for (int retryCount = 0; retryCount < 2; retryCount++) { try { response = exeRequest.execute(request, conn, context); + log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: " + + response.getStatusLine().getStatusCode()); + if (response != null && response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) { + log.debug("Successfull response - The http response is <<<" + theContent + ">>>"); + retryCount = 2; + } else if (response != null) { + log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + + response.getStatusLine()); + if (response.getStatusLine().getStatusCode() == 504) { + log.warn("HTTP response code was 504, retrying..."); + } else + retryCount = 2; + + badResponse = true; + } + + if (response != null && response.getEntity() != null) { + try { + + theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read + // content + // for + // data + + EntityUtils.consume(response.getEntity()); // close out + // inputstream + // ignore + // content + if(!badResponse) + theContent = null; + } catch (Exception e) { + log.debug("Error ocurred in handling response entity after successful call, still responding success. " + + e.getMessage(), e); + } + } } catch (ClientProtocolException e) { log.warn("Client Protocol Exception received, retyring...."); - } catch (IOException e) { - log.warn("Error calling out to HA gateway: IOException in log", e); - retryCount = 2; } catch (HttpException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: " - + response.getStatusLine().getStatusCode()); - if (response != null && response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) { - log.debug("Successfull response - The http response is <<<" + theContent + ">>>"); + log.warn("Error calling out to HA gateway: HttpException in log", e); + } catch (IOException e) { + log.warn("Error calling out to HA gateway: IOException in log: " + e.getMessage()); retryCount = 2; - } else if (response != null) { - log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " - + response.getStatusLine()); - if (response.getStatusLine().getStatusCode() == 504) { - log.warn("HTTP response code was 504, retrying..."); - } else - retryCount = 2; - } - - if (response != null && response.getEntity() != null) { - try { - theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read - // content - // for - // data - EntityUtils.consume(response.getEntity()); // close out - // inputstream - // ignore - // content - } catch (Exception e) { - log.debug("Error ocurred in handling response entity after successful call, still responding success. " - + e.getMessage(), e); - } } if(retryCount < 2) { diff --git a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java index 571cef4..119ad6a 100644 --- a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java +++ b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java @@ -77,7 +77,7 @@ public class UpnpListener { traceupnp = theSettings.isTraceupnp(); useUpnpIface = theSettings.isUseupnpiface(); bridgeControl = theControl; - aHueConfig = HuePublicConfig.createConfig("temp", responseAddress, HueConstants.HUB_VERSION); + aHueConfig = HuePublicConfig.createConfig("temp", responseAddress, HueConstants.HUB_VERSION, theSettings.getHubmac()); bridgeId = aHueConfig.getBridgeid(); bridgeSNUUID = aHueConfig.getSNUUIDFromMac(); try { diff --git a/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java b/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java index e249f49..fe641ec 100644 --- a/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java +++ b/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java @@ -79,7 +79,7 @@ public class UpnpSettingsResource { log.debug("upnp device settings requested: " + " from " + request.ip() + ":" + request.port()); String portNumber = Integer.toString(request.port()); String filledTemplate = null; - String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress(), HueConstants.HUB_VERSION).getSNUUIDFromMac(); + String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress(), HueConstants.HUB_VERSION, theSettings.getHubmac()).getSNUUIDFromMac(); filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress(), bridgeIdMac, bridgeIdMac); if(theSettings.isTraceupnp()) log.info("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + portNumber); diff --git a/src/main/resources/public/views/system.html b/src/main/resources/public/views/system.html index 3437102..603c4c7 100644 --- a/src/main/resources/public/views/system.html +++ b/src/main/resources/public/views/system.html @@ -316,12 +316,6 @@ - - HAL Token (please use token on individual HAL entry) - - MQTT Client IDs and IP Addresses - + + + + + @@ -567,12 +566,6 @@ ng-model="bridge.settings.numberoflogmessages" min="100" max="65535"> - - - -
    Button Press/Call Item Loop Sleep Interval (ms)Emulate MAC
    (used in bridge-id, uuid, etc.
    - leave blank unless needed)
    Button Press/Call Item
    Loop Sleep Interval (ms)
    UPNP Strict Handling {{bridge.settings.upnpstrict}}
    Trace UPNP Calls Date: Wed, 15 Nov 2017 14:27:44 -0600 Subject: [PATCH 23/28] Added new HTTP pool manager and http handling. --- pom.xml | 2 +- .../com/bwssystems/HABridge/HABridge.java | 1 + .../com/bwssystems/HABridge/HomeManager.java | 6 + .../HABridge/plugins/NestBridge/NestHome.java | 9 ++ .../plugins/domoticz/DomoticzHome.java | 12 +- .../HABridge/plugins/exec/CommandHome.java | 10 +- .../HABridge/plugins/fibaro/FibaroHome.java | 9 ++ .../HABridge/plugins/hal/HalHome.java | 11 +- .../HABridge/plugins/harmony/HarmonyHome.java | 9 ++ .../HABridge/plugins/hass/HassHome.java | 9 ++ .../HABridge/plugins/http/HTTPHandler.java | 141 +++--------------- .../HABridge/plugins/http/HTTPHome.java | 20 +++ .../HABridge/plugins/http/HttpClientPool.java | 128 ++++++++++++++++ .../HABridge/plugins/hue/HueHome.java | 9 ++ .../HABridge/plugins/lifx/LifxHome.java | 9 ++ .../HABridge/plugins/mqtt/MQTTHome.java | 9 ++ .../HABridge/plugins/somfy/SomfyHome.java | 11 +- .../HABridge/plugins/tcp/TCPHome.java | 10 +- .../HABridge/plugins/udp/UDPHome.java | 11 +- .../HABridge/plugins/vera/VeraHome.java | 9 ++ .../resources/public/views/veradevice.html | 4 +- .../resources/public/views/verascene.html | 4 +- 22 files changed, 311 insertions(+), 132 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/plugins/http/HttpClientPool.java diff --git a/pom.xml b/pom.xml index 0cd4af0..fdb171e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.0.0rc3 + 5.0.0rc4 jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index 25742d5..032f573 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -97,6 +97,7 @@ public class HABridge { bridgeSettings.getBridgeControl().setStop(true); if(bridgeSettings.getBridgeSettingsDescriptor().isSettingsChanged()) bridgeSettings.save(bridgeSettings.getBridgeSettingsDescriptor()); + log.info("Going to close all homes"); homeManager.closeHomes(); udpSender.closeResponseSocket(); udpSender = null; diff --git a/src/main/java/com/bwssystems/HABridge/HomeManager.java b/src/main/java/com/bwssystems/HABridge/HomeManager.java index 60b3bcc..0d6824c 100644 --- a/src/main/java/com/bwssystems/HABridge/HomeManager.java +++ b/src/main/java/com/bwssystems/HABridge/HomeManager.java @@ -4,6 +4,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.bwssystems.HABridge.devicemanagmeent.ResourceHandler; import com.bwssystems.HABridge.plugins.NestBridge.NestHome; import com.bwssystems.HABridge.plugins.domoticz.DomoticzHome; @@ -23,6 +26,7 @@ import com.bwssystems.HABridge.plugins.fibaro.FibaroHome; import com.bwssystems.HABridge.util.UDPDatagramSender; public class HomeManager { + private static final Logger log = LoggerFactory.getLogger(HomeManager.class); Map homeList; Map resourceList; @@ -114,8 +118,10 @@ public class HomeManager { } public void closeHomes() { + log.info("Manager close homes called...."); Collection theHomes = homeList.values(); for(Home aHome : theHomes) { + log.info("Closing home: " + aHome.getClass().getCanonicalName()); aHome.closeHome(); } homeList.clear(); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java b/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java index 0069000..da71b5e 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/NestBridge/NestHome.java @@ -32,10 +32,13 @@ public class NestHome implements com.bwssystems.HABridge.Home { private Gson aGsonHandler; private Boolean isFarenheit; private Boolean validNest; + private boolean closed; public NestHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -93,12 +96,18 @@ public class NestHome implements com.bwssystems.HABridge.Home { @Override public void closeHome() { + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } if(theSession != null) { theNest.endNestSession(); } theNest = null; theSession = null; nestItems = null; + closed = true; } @Override diff --git a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java index e75dfd1..a6ef1f8 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java @@ -27,10 +27,13 @@ public class DomoticzHome implements Home { private Map domoticzs; private Boolean validDomoticz; private HTTPHandler httpClient; + private boolean closed; public DomoticzHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -162,8 +165,15 @@ public class DomoticzHome implements Home { } @Override public void closeHome() { + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } + if(httpClient != null) httpClient.closeHandler(); - + + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java b/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java index eb2c69e..a501c7b 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/exec/CommandHome.java @@ -19,10 +19,13 @@ import com.bwssystems.HABridge.hue.TimeDecode; public class CommandHome implements Home { private static final Logger log = LoggerFactory.getLogger(CommandHome.class); private BridgeSettings theSettings; + private boolean closed; public CommandHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -93,8 +96,13 @@ public class CommandHome implements Home { @Override public void closeHome() { - // noop + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java index d122586..591baef 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/fibaro/FibaroHome.java @@ -25,11 +25,14 @@ public class FibaroHome implements Home private static final Logger log = LoggerFactory.getLogger(FibaroHome.class); private Map fibaros; private Boolean validFibaro; + private boolean closed; public FibaroHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } public List getDevices() @@ -102,6 +105,12 @@ public class FibaroHome implements Home @Override public void closeHome() { + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } fibaros = null; + closed = true; } } \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java b/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java index 6c45035..1a87d00 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hal/HalHome.java @@ -27,10 +27,13 @@ public class HalHome implements Home { private static final Logger log = LoggerFactory.getLogger(HalHome.class); private Map hals; private Boolean validHal; + private boolean closed; public HalHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -194,7 +197,13 @@ public class HalHome implements Home { @Override public void closeHome() { - // noop + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } + hals = null; + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java index 6eb4f5b..8991f72 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyHome.java @@ -32,16 +32,24 @@ public class HarmonyHome implements Home { private Boolean isDevMode; private Boolean validHarmony; private Gson aGsonHandler; + private boolean closed; public HarmonyHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override public void closeHome() { if(!validHarmony) return; + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } if(isDevMode || hubs == null) return; Iterator keys = hubs.keySet().iterator(); @@ -51,6 +59,7 @@ public class HarmonyHome implements Home { } hubs = null; + closed = true; } public HarmonyHandler getHarmonyHandler(String aName) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java b/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java index c338861..74cb6da 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hass/HassHome.java @@ -26,10 +26,13 @@ public class HassHome implements Home { private Map hassMap; private Boolean validHass; private Gson aGsonHandler; + private boolean closed; public HassHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -152,6 +155,11 @@ public class HassHome implements Home { public void closeHome() { if(!validHass) return; + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } if(hassMap == null) return; Iterator keys = hassMap.keySet().iterator(); @@ -161,5 +169,6 @@ public class HassHome implements Home { } hassMap = null; + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java index 01a544b..195076a 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java @@ -4,28 +4,15 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.Charset; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import org.apache.http.HttpClientConnection; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.conn.ConnectionPoolTimeoutException; -import org.apache.http.conn.ConnectionRequest; -import org.apache.http.conn.HttpClientConnectionManager; -import org.apache.http.conn.routing.HttpRoute; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.conn.BasicHttpClientConnectionManager; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.protocol.HttpRequestExecutor; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,29 +21,9 @@ import com.bwssystems.HABridge.api.NameValue; public class HTTPHandler { private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class); -// private CloseableHttpClient httpClient; -// private RequestConfig globalConfig; - private HttpClientContext context; - private PoolingHttpClientConnectionManager connMgr; - private HttpRoute route; - private HttpClientConnection conn; - private HttpHost theHost; public HTTPHandler() { - context = HttpClientContext.create(); - connMgr = new PoolingHttpClientConnectionManager(); - // Increase max total connection to 200 - connMgr.setMaxTotal(200); - // Increase default max connection per route to 20 - connMgr.setDefaultMaxPerRoute(20); - // Increase max connections for localhost:80 to 50 - HttpHost localhost = new HttpHost("locahost", 80); - connMgr.setMaxPerRoute(new HttpRoute(localhost), 50); - route = null; - conn = null; - theHost = null; -// globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build(); -// httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build(); + super(); } @@ -68,9 +35,8 @@ public class HTTPHandler { String theContent = null; URI theURI = null; ContentType parsedContentType = null; - ConnectionRequest connRequest = null; StringEntity requestBody = null; - boolean badResponse = false; + if (contentType != null && !contentType.trim().isEmpty()) { parsedContentType = ContentType.parse(contentType); if (body != null && body.length() > 0) @@ -82,44 +48,7 @@ public class HTTPHandler { log.warn("Error creating URI http request: " + url + " with message: " + e1.getMessage()); return null; } - if(route == null) { - theHost = new HttpHost(theURI.getHost(), theURI.getPort()); - route = new HttpRoute(theHost); - } - if(conn == null) { - // Request new connection. This can be a long process - connRequest = connMgr.requestConnection(route, null); - // Wait for connection up to 10 sec - try { - conn = connRequest.get(10, TimeUnit.SECONDS); - } catch (ConnectionPoolTimeoutException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (ExecutionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - // If not open - if (!conn.isOpen()) { - // establish connection based on its route info - try { - connMgr.connect(conn, route, 1000, context); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - // and mark it as route complete - try { - connMgr.routeComplete(conn, route, context); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + try { if (httpVerb == null || httpVerb.trim().isEmpty() || HttpGet.METHOD_NAME.equalsIgnoreCase(httpVerb)) { request = new HttpGet(theURI); @@ -146,28 +75,12 @@ public class HTTPHandler { request.setHeader(headers[i].getName(), headers[i].getValue()); } } - HttpResponse response = null; - HttpRequestExecutor exeRequest = new HttpRequestExecutor(); - context.setTargetHost(theHost); + CloseableHttpResponse response = null; for (int retryCount = 0; retryCount < 2; retryCount++) { try { - response = exeRequest.execute(request, conn, context); + response = HttpClientPool.getClient().execute(request); log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: " + response.getStatusLine().getStatusCode()); - if (response != null && response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) { - log.debug("Successfull response - The http response is <<<" + theContent + ">>>"); - retryCount = 2; - } else if (response != null) { - log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " - + response.getStatusLine()); - if (response.getStatusLine().getStatusCode() == 504) { - log.warn("HTTP response code was 504, retrying..."); - } else - retryCount = 2; - - badResponse = true; - } - if (response != null && response.getEntity() != null) { try { @@ -180,18 +93,28 @@ public class HTTPHandler { // inputstream // ignore // content - if(!badResponse) - theContent = null; } catch (Exception e) { log.debug("Error ocurred in handling response entity after successful call, still responding success. " + e.getMessage(), e); } } + if (response != null && response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) { + log.debug("Successfull response - The http response is <<<" + theContent + ">>>"); + retryCount = 2; + } else if (response != null) { + log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + + response.getStatusLine()); + if (response.getStatusLine().getStatusCode() == 504) { + log.warn("HTTP response code was 504, retrying..."); + } else + retryCount = 2; + + theContent = null; + } + } catch (ClientProtocolException e) { log.warn("Client Protocol Exception received, retyring...."); - } catch (HttpException e) { - log.warn("Error calling out to HA gateway: HttpException in log", e); - } catch (IOException e) { + }catch (IOException e) { log.warn("Error calling out to HA gateway: IOException in log: " + e.getMessage()); retryCount = 2; } @@ -205,30 +128,8 @@ public class HTTPHandler { } } } - connMgr.releaseConnection(conn, null, 1, TimeUnit.SECONDS); return theContent; } - -// public HttpClient getHttpClient() { -// return httpClient; -// } - - -// public CloseableHttpClient getHttpClient() { -// return httpClient; -// } - - public void closeHandler() { - try { -// httpClient.close(); - if(conn != null) - conn.close(); - connMgr.closeExpiredConnections(); - connMgr.shutdown(); - } catch (IOException e) { - // noop - } -// httpClient = null; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java index 35ae28d..2e0abbc 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java @@ -1,5 +1,7 @@ package com.bwssystems.HABridge.plugins.http; +import java.io.IOException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,10 +23,15 @@ import com.google.gson.Gson; public class HTTPHome implements Home { private static final Logger log = LoggerFactory.getLogger(HTTPHome.class); private HTTPHandler anHttpHandler; + protected HttpClientPool thePool; + private boolean closed; public HTTPHome(BridgeSettings bridgeSettings) { super(); + closed = true; + thePool = new HttpClientPool(); createHome(bridgeSettings); + closed = false; } @Override @@ -101,9 +108,22 @@ public class HTTPHome implements Home { @Override public void closeHome() { + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } if(anHttpHandler != null) anHttpHandler.closeHandler(); anHttpHandler = null; + try { + HttpClientPool.shutdown(); + } catch (InterruptedException e) { + log.warn("Error shutting down http pool: " + e.getMessage());; + } catch (IOException e) { + log.warn("Error shutting down http pool: " + e.getMessage());; + } + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HttpClientPool.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HttpClientPool.java new file mode 100644 index 0000000..022d29d --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HttpClientPool.java @@ -0,0 +1,128 @@ +package com.bwssystems.HABridge.plugins.http; + +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; + +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class HttpClientPool { + private static final Logger log = LoggerFactory.getLogger(HttpClientPool.class); + + // Single-element enum to implement Singleton. + private static enum Singleton { + // Just one of me so constructor will be called once. + Client; + // The thread-safe client. + private final CloseableHttpClient threadSafeClient; + // The pool monitor. + private final IdleConnectionMonitorThread monitor; + + // The constructor creates it - thus late + private Singleton() { + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); + // Increase max total connection to 200 + cm.setMaxTotal(200); + // Increase default max connection per route to 20 + cm.setDefaultMaxPerRoute(20); + // Build the client. + threadSafeClient = HttpClients.custom() + .setConnectionManager(cm) + .build(); + // Start up an eviction thread. + monitor = new IdleConnectionMonitorThread(cm); + // Don't stop quitting. + monitor.setDaemon(true); + monitor.start(); + } + + public CloseableHttpClient get() { + return threadSafeClient; + } + + } + + public static CloseableHttpClient getClient() { + // The thread safe client is held by the singleton. + return Singleton.Client.get(); + } + + // Watches for stale connections and evicts them. + private static class IdleConnectionMonitorThread extends Thread { + // The manager to watch. + private final PoolingHttpClientConnectionManager cm; + // Use a BlockingQueue to stop everything. + private final BlockingQueue stopSignal = new ArrayBlockingQueue(1); + + // Pushed up the queue. + private static class Stop { + // The return queue. + private final BlockingQueue stop = new ArrayBlockingQueue(1); + + // Called by the process that is being told to stop. + public void stopped() { + // Push me back up the queue to indicate we are now stopped. + stop.add(this); + } + + // Called by the process requesting the stop. + public void waitForStopped() throws InterruptedException { + // Wait until the callee acknowledges that it has stopped. + stop.take(); + } + + } + + IdleConnectionMonitorThread(PoolingHttpClientConnectionManager cm) { + super(); + this.cm = cm; + } + + @Override + public void run() { + try { + // Holds the stop request that stopped the process. + Stop stopRequest; + // Every 5 seconds. + while ((stopRequest = stopSignal.poll(5, TimeUnit.SECONDS)) == null) { + // Close expired connections + cm.closeExpiredConnections(); + // Optionally, close connections that have been idle too long. + cm.closeIdleConnections(60, TimeUnit.SECONDS); + // Look at pool stats. + log.debug("Stats: {}", cm.getTotalStats()); + } + // Acknowledge the stop request. + stopRequest.stopped(); + } catch (InterruptedException ex) { + // terminate + } + } + + public void shutdown() throws InterruptedException, IOException { + log.info("Shutting down client pool"); + // Signal the stop to the thread. + Stop stop = new Stop(); + stopSignal.add(stop); + // Wait for the stop to complete. + stop.waitForStopped(); + // Close the pool - Added + Singleton.Client.threadSafeClient.close(); + // Close the connection manager. + cm.close(); + log.info("Client pool shut down"); + } + + } + + public static void shutdown() throws InterruptedException, IOException { + // Shutdown the monitor. + Singleton.Client.monitor.shutdown(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java index a3d693e..ace49bf 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueHome.java @@ -27,11 +27,14 @@ public class HueHome implements Home { private Boolean validHue; private Gson aGsonHandler; private BridgeSettings theBridgeSettings; + private boolean closed; public HueHome(BridgeSettings bridgeSettings) { super(); + closed = true; theBridgeSettings = bridgeSettings; createHome(bridgeSettings); + closed = false; } @Override @@ -135,6 +138,11 @@ public class HueHome implements Home { public void closeHome() { if(!validHue) return; + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } if(hues == null) return; Iterator keys = hues.keySet().iterator(); @@ -143,5 +151,6 @@ public class HueHome implements Home { hues.get(key).closeHue();; } hues = null; + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java index 0c692f1..252e32a 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java @@ -38,10 +38,13 @@ public class LifxHome implements Home { private LFXClient client; private Boolean validLifx; private Gson aGsonHandler; + private boolean closed; public LifxHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -213,7 +216,13 @@ public class LifxHome implements Home { public void closeHome() { if(!validLifx) return; + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } client.close(); + closed = true; } private static class MyLightListener implements LFXLightCollectionListener { private static final Logger log = LoggerFactory.getLogger(MyLightListener.class); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java index 894a9a1..a5c5853 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHome.java @@ -26,16 +26,24 @@ public class MQTTHome implements Home { private Map handlers; private Boolean validMqtt; private Gson aGsonHandler; + private boolean closed; public MQTTHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override public void closeHome() { if(!validMqtt) return; + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } log.debug("Shutting down MQTT handlers."); if(handlers != null && !handlers.isEmpty()) { for (String key : handlers.keySet()) { @@ -43,6 +51,7 @@ public class MQTTHome implements Home { } } handlers = null; + closed = false; } public MQTTHandler getMQTTHandler(String aName) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java b/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java index 1acc683..7ac13d5 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyHome.java @@ -31,10 +31,13 @@ public class SomfyHome implements Home { private static final Logger log = LoggerFactory.getLogger(SomfyHome.class); private Map somfys; private Boolean validSomfy; + private boolean closed; public SomfyHome(BridgeSettings bridgeSettings) { + super(); + closed = true; createHome(bridgeSettings); - + closed = false; } public SomfyInfo getSomfyHandler(String somfyName) { @@ -114,6 +117,12 @@ public class SomfyHome implements Home { @Override public void closeHome() { + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } somfys = null; + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java index 0c69aa4..e3f958d 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java @@ -34,11 +34,13 @@ public class TCPHome implements Home { private byte[] sendData; private Map theSockets; private Gson aGsonHandler; - + private boolean closed; public TCPHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -145,6 +147,11 @@ public class TCPHome implements Home { @Override public void closeHome() { + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } log.debug("Shutting down TCP sockets."); if(theSockets != null && !theSockets.isEmpty()) { Iterator keys = theSockets.keySet().iterator(); @@ -157,6 +164,7 @@ public class TCPHome implements Home { } } } + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java index 76a07e1..483d78d 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java @@ -26,11 +26,14 @@ public class UDPHome implements Home { private static final Logger log = LoggerFactory.getLogger(UDPHome.class); private UDPDatagramSender theUDPDatagramSender; private byte[] sendData; + private boolean closed; public UDPHome(BridgeSettings bridgeSettings, UDPDatagramSender aUDPDatagramSender) { super(); theUDPDatagramSender = aUDPDatagramSender; + closed = true; createHome(bridgeSettings); + closed = false; } @Override @@ -104,8 +107,12 @@ public class UDPHome implements Home { @Override public void closeHome() { - // TODO Auto-generated method stub - + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } + closed = true; } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java b/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java index 829154b..51f0104 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraHome.java @@ -25,10 +25,13 @@ public class VeraHome implements Home { private static final Logger log = LoggerFactory.getLogger(VeraHome.class); private Map veras; private Boolean validVera; + private boolean closed; public VeraHome(BridgeSettings bridgeSettings) { super(); + closed = true; createHome(bridgeSettings); + closed = false; } public List getDevices() { @@ -107,6 +110,12 @@ public class VeraHome implements Home { @Override public void closeHome() { + log.debug("Closing Home."); + if(closed) { + log.debug("Home is already closed...."); + return; + } veras = null; + closed = true; } } diff --git a/src/main/resources/public/views/veradevice.html b/src/main/resources/public/views/veradevice.html index 3541487..91eae29 100644 --- a/src/main/resources/public/views/veradevice.html +++ b/src/main/resources/public/views/veradevice.html @@ -4,8 +4,8 @@
  • Logs
  • Vera Scenes
  • -
  • Fibaro Devices
  • -
  • Fibaro Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Logs
  • Vera Devices
  • -
  • Fibaro Devices
  • -
  • Fibaro Scenes
  • +
  • Fibaro Devices
  • +
  • Fibaro Scenes
  • Harmony Activities
  • Date: Wed, 15 Nov 2017 14:59:26 -0600 Subject: [PATCH 24/28] Added failed logic --- src/main/resources/public/views/login.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/resources/public/views/login.html b/src/main/resources/public/views/login.html index a15b5c1..3019997 100644 --- a/src/main/resources/public/views/login.html +++ b/src/main/resources/public/views/login.html @@ -20,10 +20,13 @@ +
    +

    Login failed! Username or passowrd incorrect.

    +
    - +
    \ No newline at end of file From 5eca809c4a29e9aa3d06afe154c0c247ece16249 Mon Sep 17 00:00:00 2001 From: Admin Date: Thu, 16 Nov 2017 16:23:33 -0600 Subject: [PATCH 25/28] Updated Readme, Updated to the latest spark web REST Framework. Added handling for spark initialization errors. --- README.md | 18 ++++++++---------- pom.xml | 4 ++-- .../java/com/bwssystems/HABridge/HABridge.java | 10 ++++++++-- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index aa9ac25..81929eb 100644 --- a/README.md +++ b/README.md @@ -61,17 +61,17 @@ ATTENTION: This requires JDK 1.8 to run ATTENTION: Due to port 80 being the default, Linux restricts this to super user. Use the instructions below. ``` -java -jar ha-bridge-4.5.6.jar +java -jar ha-bridge-5.0.0.jar ``` ### Automation on Linux systems To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge -Create the directory and make sure that ha-bridge-4.5.6.jar is in your /home/pi/habridge directory. +Create the directory and make sure that ha-bridge-5.0.0.jar is in your /home/pi/habridge directory. ``` pi@raspberrypi:~ $ mkdir habridge pi@raspberrypi:~ $ cd habridge -pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.5.6/ha-bridge-4.5.6.jar +pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.0.0/ha-bridge-5.0.0.jar ``` #### System Control Setup on a pi (preferred) @@ -92,7 +92,7 @@ After=network.target [Service] Type=simple WorkingDirectory=/home/pi/habridge -ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.6.jar +ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-5.0.0.jar [Install] WantedBy=multi-user.target @@ -127,7 +127,7 @@ Then cut and past this, modify any locations that are not correct ``` cd /home/pi/habridge rm /home/pi/habridge/habridge-log.txt -nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.5.6.jar > /home/pi/habridge/habridge-log.txt 2>&1 & +nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-5.0.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 & chmod 777 /home/pi/habridge/habridge-log.txt ``` @@ -265,6 +265,8 @@ The server defaults to running on port 80. To override what the default is, spec The upnp response port that will be used. The default is 50000. #### Vera Names and IP Addresses Provide IP Addresses of your Veras that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Vera and device/scene you configure. +#### Fibaro Names and IP Addresses +Provide IP Addresses of your Fibaros that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Fibaro and device/scene you configure. #### Harmony Names and IP Addresses Provide IP Addresses of your Harmony Hubs that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the activity or buttons by the call it receives and send it to the target Harmony Hub and activity/button you configure. Also, an option of webhook can be called when the activity changes on the harmony hub that will send an HTTP GET call to the the address of your choosing. This can contain the replacement variables of ${activity.id} and/or ${activity.label}. Example : http://192.168.0.1/activity/${activity.id}/${activity.label} OR http://hook?a=${activity.label} #### Hue Names and IP Addresses @@ -273,8 +275,6 @@ Provide IP Addresses of your Hue Bridges that you want to proxy through the brid Don't forget - You will need to push the link button when you got to the Hue Tab the first time after the process comes up. (The user name is not persistent when the process comes up.) #### HAL Names and IP Addresses Provide IP Addresses of your HAL Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HAL and device/scene you configure. -#### HAL Token -The token you generate or give to a HAL and must be the same for all HAL's you have identified. This needs to be given if you are using the HAL features. #### MQTT Client IDs and IP Addresses Provide Client ID and IP Addresses and ports of your MQTT Brokers that you want to utilize with the bridge. Also, you can provide the username and password if you have secured your MQTT broker which is optional. When these Client ID and IP's are given, the bridge will be able to publish MQTT messages by the call it receives and send it to the target MQTT Broker you configure. The MQTT Messages Tab will become available to help you build messages. #### Nest Username @@ -291,8 +291,6 @@ The password associated with the Somfy Tahoma username above This setting is the time used in between button presses when there is multiple buttons in a button device. It also controls the time between multiple items in a custom device call. This is defaulted to 100ms and the number represents milliseconds (1000 milliseconds = 1 second). #### Log Messages to Buffer This controls how many log messages will be kept and displayed on the log tab. This does not affect what is written to the standard output for logging. The default is 512. Changing this will incur more memory usage of the process. -#### UPNP Strict Handling -Upnp has been set to be very specific as to respond as a Hue. There may be a need to make this response a little more open for other devices that may want to find the ha-bridge. The default is to be strict which is set as true. #### Trace UPNP Calls Turn on tracing for upnp discovery messages to the log. The default is false. @@ -304,7 +302,7 @@ The bottom part of the Logs Screen has configuration to change the logging level ### Bridge Device Additions You must configure devices before you will have anything for the Echo or other controller that is connected to the ha-bridge to receive. #### Helpers -The easy way to get devices configured is with the use of the helpers for the Vera or Harmony, Nest and Hue to create devices that the bridge will present. +The easy way to get devices configured is with the use of the helpers for the Vera or Harmony, Nest, Hue and others to create devices that the bridge will present. For the Helpers, each item being presented from the target system has a button such as `Build Item`, `Build A Button` or specific tasks such as `Temp` for thermostats that is used to create the specific device parameters. The build action buttons will put you into the edit screen. The next thing to check is the name for the bridge device that it is something that makes sense especially if you using the ha-bridge with an Echo or Google Home as this is what the Echo or Google Home will interpret as the device you want. Also, you can go back to any helper tab and click a build action button to add another item for a multi-command. After you are done in the edit tab, click the `Add Bridge Device` to finish that selection setup. diff --git a/pom.xml b/pom.xml index fdb171e..39bab29 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.0.0rc4 + 5.0.0rc5 jar HA Bridge @@ -63,7 +63,7 @@ com.sparkjava spark-core - 2.3 + 2.7.1 slf4j-simple diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index 032f573..b8a01ec 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -57,6 +57,7 @@ public class HABridge { ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress()); // sparkjava config directive to set port for the web server to listen on port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort()); + initExceptionHandler((e) -> HABridge.theExceptionHandler(e, bridgeSettings.getBridgeSettingsDescriptor().getServerPort())); if(!bridgeSettings.getBridgeControl().isReinit()) init(); bridgeSettings.getBridgeControl().setReinit(false); @@ -107,8 +108,7 @@ public class HABridge { try { Thread.sleep(5000); } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + log.error("Sleep error: " + e.getMessage()); } } } @@ -118,4 +118,10 @@ public class HABridge { log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting...."); System.exit(0); } + + private static void theExceptionHandler(Exception e, Integer thePort) { + Logger log = LoggerFactory.getLogger(HABridge.class); + log.error("Could not start ha-bridge webservice on port [" + thePort + "] due to: " + e.getMessage()); + System.exit(0); + } } From 05b9f195d745a1ca9a20e1e716be93c31580291c Mon Sep 17 00:00:00 2001 From: Admin Date: Fri, 17 Nov 2017 12:37:46 -0600 Subject: [PATCH 26/28] Fixed issue with http client pool and with test user for web interface. --- pom.xml | 2 +- .../com/bwssystems/HABridge/HABridge.java | 17 ++++++++++++-- .../HABridge/LinkButtonPressed.java | 7 ++++-- .../com/bwssystems/HABridge/LinkParams.java | 20 +++++++++++++++++ .../bwssystems/HABridge/SystemControl.java | 16 ++++++++++++-- .../bwssystems/HABridge/hue/HueMulator.java | 12 ++++++++-- .../plugins/domoticz/DomoticzHome.java | 3 ++- .../HABridge/plugins/hal/HalInfo.java | 3 ++- .../plugins/harmony/HarmonyServer.java | 4 +++- .../HABridge/plugins/hass/HomeAssistant.java | 3 ++- .../HABridge/plugins/http/HTTPHome.java | 22 ++++++++----------- .../HABridge/plugins/hue/HueInfo.java | 3 ++- .../HABridge/plugins/somfy/SomfyInfo.java | 3 ++- .../HABridge/plugins/vera/VeraInfo.java | 3 ++- src/main/resources/public/scripts/app.js | 14 ++++++++---- 15 files changed, 99 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/bwssystems/HABridge/LinkParams.java diff --git a/pom.xml b/pom.xml index 39bab29..0ede241 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.0.0rc5 + 5.0.0rc6 jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index b8a01ec..e064848 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import com.bwssystems.HABridge.devicemanagmeent.*; import com.bwssystems.HABridge.hue.HueMulator; +import com.bwssystems.HABridge.plugins.http.HttpClientPool; import com.bwssystems.HABridge.upnp.UpnpListener; import com.bwssystems.HABridge.upnp.UpnpSettingsResource; import com.bwssystems.HABridge.util.UDPDatagramSender; @@ -41,14 +42,17 @@ public class HABridge { SystemControl theSystem; BridgeSettings bridgeSettings; Version theVersion; - + @SuppressWarnings("unused") + HttpClientPool thePool; + theVersion = new Version(); + // Singleton initialization + thePool = new HttpClientPool(); log.info("HA Bridge (v" + theVersion.getVersion() + ") starting...."); bridgeSettings = new BridgeSettings(); // sparkjava config directive to set html static file location for Jetty - staticFileLocation("/public"); while(!bridgeSettings.getBridgeControl().isStop()) { bridgeSettings.buildSettings(); bridgeSettings.getBridgeSecurity().removeTestUsers(); @@ -57,6 +61,7 @@ public class HABridge { ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress()); // sparkjava config directive to set port for the web server to listen on port(bridgeSettings.getBridgeSettingsDescriptor().getServerPort()); + staticFileLocation("/public"); initExceptionHandler((e) -> HABridge.theExceptionHandler(e, bridgeSettings.getBridgeSettingsDescriptor().getServerPort())); if(!bridgeSettings.getBridgeControl().isReinit()) init(); @@ -115,6 +120,14 @@ public class HABridge { bridgeSettings.getBridgeSecurity().removeTestUsers(); if(bridgeSettings.getBridgeSecurity().isSettingsChanged()) bridgeSettings.updateConfigFile(); + try { + HttpClientPool.shutdown(); + thePool = null; + } catch (InterruptedException e) { + log.warn("Error shutting down http pool: " + e.getMessage());; + } catch (IOException e) { + log.warn("Error shutting down http pool: " + e.getMessage());; + } log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting...."); System.exit(0); } diff --git a/src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java b/src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java index 4d0cfa8..e909c23 100644 --- a/src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java +++ b/src/main/java/com/bwssystems/HABridge/LinkButtonPressed.java @@ -10,15 +10,18 @@ public class LinkButtonPressed extends TimerTask { private static final Logger log = LoggerFactory.getLogger(LinkButtonPressed.class); private BridgeControlDescriptor linkDescriptor; private Timer myTimer; + private boolean isSilent; - public LinkButtonPressed(BridgeControlDescriptor theDescriptor, Timer aTimer) { + public LinkButtonPressed(BridgeControlDescriptor theDescriptor, Timer aTimer, boolean keepSilent) { linkDescriptor = theDescriptor; myTimer = aTimer; + isSilent = keepSilent; } @Override public void run() { - log.info("Link button time ended...."); + if(!isSilent) + log.info("Link button time ended...."); linkDescriptor.setLinkButton(false); myTimer.cancel(); } diff --git a/src/main/java/com/bwssystems/HABridge/LinkParams.java b/src/main/java/com/bwssystems/HABridge/LinkParams.java new file mode 100644 index 0000000..31ca7ea --- /dev/null +++ b/src/main/java/com/bwssystems/HABridge/LinkParams.java @@ -0,0 +1,20 @@ +package com.bwssystems.HABridge; + +public class LinkParams { + private Integer seconds; + private boolean silent; + + public Integer getSeconds() { + return seconds; + } + public void setSeconds(Integer seconds) { + this.seconds = seconds; + } + public boolean isSilent() { + return silent; + } + public void setSilent(boolean silent) { + this.silent = silent; + } + +} diff --git a/src/main/java/com/bwssystems/HABridge/SystemControl.java b/src/main/java/com/bwssystems/HABridge/SystemControl.java index ef241c7..c7210fb 100644 --- a/src/main/java/com/bwssystems/HABridge/SystemControl.java +++ b/src/main/java/com/bwssystems/HABridge/SystemControl.java @@ -245,10 +245,22 @@ public class SystemControl { }); // http://ip_address:port/system/presslinkbutton which sets the link button for device registration put(SYSTEM_CONTEXT + "/presslinkbutton", (request, response) -> { - log.info("Link button pressed...."); + LinkParams linkParams = null; + if(!request.body().isEmpty()) { + linkParams = new Gson().fromJson(request.body(), LinkParams.class); + if(linkParams.getSeconds() <= 0) + linkParams.setSeconds(1); + } + else { + linkParams = new LinkParams(); + linkParams.setSilent(false); + linkParams.setSeconds(30); + } + if(!linkParams.isSilent()) + log.info("Link button pressed...."); bridgeSettings.getBridgeControl().setLinkButton(true); Timer theTimer = new Timer(); - theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer), 30000); + theTimer.schedule(new LinkButtonPressed(bridgeSettings.getBridgeControl(), theTimer, linkParams.isSilent()), (linkParams.getSeconds() * 1000)); response.status(HttpStatus.SC_OK); response.type("application/json"); return ""; diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 4de6ffb..91be75d 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -1097,8 +1097,10 @@ public class HueMulator { aMultiUtil.setSetCount(1); log.debug("hue state change requested: " + userId + " from " + ipAddress + " body: " + body); HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()); - if (theErrors != null) + if (theErrors != null) { + log.warn("Errors in security: <<<" + aGsonHandler.toJson(theErrors) + ">>>"); return aGsonHandler.toJson(theErrors); + } try { theStateChanges = aGsonHandler.fromJson(body, StateChangeBody.class); } catch (Exception e) { @@ -1228,14 +1230,19 @@ public class HueMulator { } else if (ctInc != null && ctInc != 0) { colorData = new ColorData(ColorData.ColorMode.CT, state.getCt() + ctInc); } - + log.debug("Calling Home device handler for type : " + callItems[i].getType().trim()); 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(); } } } + else + log.warn("Call Items type is null <<<" + callItems[i] + ">>>"); } + + if(callItems.length == 0) + log.warn("No call items were available: <<<" + url + ">>>"); } else { log.warn("Could not find url: " + lightId + " for hue state change request: " + userId + " from " + ipAddress + " body: " + body); @@ -1244,6 +1251,7 @@ public class HueMulator { } if (responseString == null || !responseString.contains("[{\"error\":")) { + log.debug("Response is in error: " + ((responseString == null) ? "null" : responseString)); if(!device.isNoState()) { responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState()); device.setDeviceState(state); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java index a6ef1f8..11af8ca 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java @@ -20,6 +20,7 @@ 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.bwssystems.HABridge.plugins.http.HTTPHome; import com.google.gson.Gson; public class DomoticzHome implements Home { @@ -132,7 +133,7 @@ public class DomoticzHome implements Home { log.info("Domoticz Home created." + (validDomoticz ? "" : " No Domoticz devices configured.")); if(!validDomoticz) return null; - httpClient = new HTTPHandler(); + httpClient = HTTPHome.getHandler(); domoticzs = new HashMap(); Iterator theList = bridgeSettings.getBridgeSettingsDescriptor().getDomoticzaddress().getDevices().iterator(); while(theList.hasNext()) { diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hal/HalInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/hal/HalInfo.java index 0110dcc..28762c5 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hal/HalInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hal/HalInfo.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import com.bwssystems.HABridge.NamedIP; import com.bwssystems.HABridge.plugins.http.HTTPHandler; +import com.bwssystems.HABridge.plugins.http.HTTPHome; import com.bwssystems.HABridge.util.TextStringFormatter; import com.google.gson.Gson; @@ -38,7 +39,7 @@ public class HalInfo { public HalInfo(NamedIP addressName, String aGivenToken) { super(); - httpClient = new HTTPHandler(); + httpClient = HTTPHome.getHandler(); halAddress = addressName; if(halAddress.getPassword() == null || halAddress.getPassword().trim().isEmpty()) halAddress.setPassword(aGivenToken); diff --git a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java index 521f7ed..342a633 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java @@ -5,6 +5,8 @@ import static java.lang.String.format; import javax.inject.Inject; import com.bwssystems.HABridge.plugins.http.HTTPHandler; +import com.bwssystems.HABridge.plugins.http.HTTPHome; + import org.apache.http.client.methods.HttpGet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,7 +46,7 @@ public class HarmonyServer { dummyProvider = null; myNameAndIP = theHarmonyAddress; isDevMode = false; - httpClient = new HTTPHandler(); + httpClient = HTTPHome.getHandler(); } public static HarmonyServer setup( diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java b/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java index dcf4b54..3ee57b5 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import com.bwssystems.HABridge.NamedIP; import com.bwssystems.HABridge.api.NameValue; import com.bwssystems.HABridge.plugins.http.HTTPHandler; +import com.bwssystems.HABridge.plugins.http.HTTPHome; import com.google.gson.Gson; public class HomeAssistant { @@ -21,7 +22,7 @@ public class HomeAssistant { public HomeAssistant(NamedIP addressName) { super(); - anHttpHandler = new HTTPHandler(); + anHttpHandler = HTTPHome.getHandler(); hassAddress = addressName; } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java index 2e0abbc..d4f7afd 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java @@ -1,7 +1,5 @@ package com.bwssystems.HABridge.plugins.http; -import java.io.IOException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,17 +20,21 @@ import com.google.gson.Gson; public class HTTPHome implements Home { private static final Logger log = LoggerFactory.getLogger(HTTPHome.class); - private HTTPHandler anHttpHandler; - protected HttpClientPool thePool; + private static HTTPHandler anHttpHandler = null; private boolean closed; public HTTPHome(BridgeSettings bridgeSettings) { super(); closed = true; - thePool = new HttpClientPool(); createHome(bridgeSettings); closed = false; } + + public static HTTPHandler getHandler() { + if(anHttpHandler == null) + anHttpHandler = new HTTPHandler(); + return anHttpHandler; + } @Override public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity, @@ -95,7 +97,8 @@ public class HTTPHome implements Home { @Override public Home createHome(BridgeSettings bridgeSettings) { - anHttpHandler = new HTTPHandler(); + if(anHttpHandler == null) + anHttpHandler = new HTTPHandler(); log.info("Http Home created."); return this; } @@ -116,13 +119,6 @@ public class HTTPHome implements Home { if(anHttpHandler != null) anHttpHandler.closeHandler(); anHttpHandler = null; - try { - HttpClientPool.shutdown(); - } catch (InterruptedException e) { - log.warn("Error shutting down http pool: " + e.getMessage());; - } catch (IOException e) { - log.warn("Error shutting down http pool: " + e.getMessage());; - } closed = true; } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java index af80384..590e5a2 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/hue/HueInfo.java @@ -13,6 +13,7 @@ import com.bwssystems.HABridge.api.hue.DeviceResponse; import com.bwssystems.HABridge.api.hue.HueApiResponse; import com.bwssystems.HABridge.dao.DeviceDescriptor; import com.bwssystems.HABridge.plugins.http.HTTPHandler; +import com.bwssystems.HABridge.plugins.http.HTTPHome; import com.google.gson.Gson; @@ -25,7 +26,7 @@ public class HueInfo { public HueInfo(NamedIP addressName, HueHome theHome) { super(); - httpHandler = new HTTPHandler(); + httpHandler = HTTPHome.getHandler(); hueAddress = addressName; myHome = theHome; } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyInfo.java index cd70fc9..4b74c6e 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/somfy/SomfyInfo.java @@ -3,6 +3,7 @@ package com.bwssystems.HABridge.plugins.somfy; import com.bwssystems.HABridge.NamedIP; import com.bwssystems.HABridge.api.NameValue; import com.bwssystems.HABridge.plugins.http.HTTPHandler; +import com.bwssystems.HABridge.plugins.http.HTTPHome; import com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup.Device; import com.bwssystems.HABridge.plugins.somfy.jsonschema2pojo.getsetup.GetSetup; import com.google.gson.Gson; @@ -39,7 +40,7 @@ public class SomfyInfo { private void initHttpClient() throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { if(httpClient==null) { - httpClient = new HTTPHandler(); + httpClient = HTTPHome.getHandler(); } } diff --git a/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraInfo.java b/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraInfo.java index 1725259..e1c2cf6 100644 --- a/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraInfo.java +++ b/src/main/java/com/bwssystems/HABridge/plugins/vera/VeraInfo.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import com.bwssystems.HABridge.NamedIP; import com.bwssystems.HABridge.plugins.http.HTTPHandler; +import com.bwssystems.HABridge.plugins.http.HTTPHome; import com.bwssystems.HABridge.plugins.vera.luupRequests.Categorie; import com.bwssystems.HABridge.plugins.vera.luupRequests.Device; import com.bwssystems.HABridge.plugins.vera.luupRequests.Room; @@ -25,7 +26,7 @@ public class VeraInfo { public VeraInfo(NamedIP addressName) { super(); - httpClient = new HTTPHandler(); + httpClient = HTTPHome.getHandler(); veraAddress = addressName; } diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 9c59d11..cdfe1fb 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -110,6 +110,7 @@ app.run(function ($rootScope, $location, Auth, bridgeService) { $rootScope.$on('securityReinit', function(event, data) { event.preventDefault(); Auth.logout(); + bridgeService.state.testuser = ""; $location.path("/login"); }); @@ -216,7 +217,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n if (error.status === 401) $rootScope.$broadcast('securityReinit', 'done'); else - self.displayError("Cannot renumber devices from habridge: ", error); + self.displayError("Cannot renumber devices from habridge: ", error); } ); }; @@ -249,7 +250,12 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n this.getTestUser = function () { if(self.state.testuser === undefined || self.state.testuser === "") { - return $http.put(this.state.systemsbase + "/presslinkbutton").then( + var linkParams = {}; + linkParams = { + seconds: 3, + silent: true + }; + return $http.put(this.state.systemsbase + "/presslinkbutton", linkParams).then( function (response) { self.getAUser(); }, @@ -287,7 +293,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n if (error.status === 401) $rootScope.$broadcast('securityReinit', 'done'); else - self.displayWarn("Cannot get security info: ", error); + self.displayWarn("Cannot get security info: ", error); } ); }; @@ -1202,7 +1208,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n msgDescription = "success " + angular.toJson(response.data); } if (typeof(response.data[0].error) !== 'undefined') { - if(reponse.data[0].error.indexOf("unauthorized") > -1) { + if(response.data[0].error.description.indexOf("unauthorized") > -1) { self.displayWarn("Authorization error, please retry...", null); } else { From 75b925992bd3f05d72df33faf26b96f637fc3f7a Mon Sep 17 00:00:00 2001 From: Admin Date: Fri, 17 Nov 2017 15:56:23 -0600 Subject: [PATCH 27/28] Updated favicon, enhanced login/logout. --- pom.xml | 2 +- src/main/resources/public/img/favicon.ico | Bin 0 -> 2600 bytes src/main/resources/public/index.html | 1 + src/main/resources/public/scripts/app.js | 16 +++++++++++----- src/main/resources/public/views/login.html | 7 +++++-- 5 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/public/img/favicon.ico diff --git a/pom.xml b/pom.xml index 0ede241..bb751a4 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.0.0rc6 + 5.0.0rc7 jar HA Bridge diff --git a/src/main/resources/public/img/favicon.ico b/src/main/resources/public/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5c72a351731147dd6863d43b01fb76433f7677b2 GIT binary patch literal 2600 zcmWlb2{_c-8^^~ILzW@r`j;iHEf-0)NS3h^lW}KaEMu%??0d-A!nJRqF{#GHge;ML ziei%O&ehP^DngPi*~0(y{GRhW&vTyl_dDl(-|zc*PrALGIX|xiF9ZVNx3n-tfLZ$Y zfO3I%XiUrxFmYk6%}pW4zn=$Plmf8A6J&u7g+K)Qeh;>y^8)_^i`-$Bws7uQJ^@it z*_5ZgMZoO2rKyo4s+U+Y7~(@0GCch6=Nkl=r{M?J9oJnHhFpE-1|LW4qxTd@O?EWo*JC*kP0WPM(H(pMz#{`;$M))w|Bks z!g$25zWcArX*-Vc-C(gIG^H?qb`vV|lf9>$NHlP!jz4jtMpc*}AD~ps$Yi{#QFPY_*6uHF;nvTsLcj5R-{d&pHg^Fkaox6k_}>ix{Gs-`HEney@oq+ zQp|83!koGEe$m9#6wcE#38z8d8Zk_O?S7|>?+QU=k~J=0KJZamaQn2O1CC}RpX4Df zo|?GQE|LjvX>F}`RF;7vk$;Gb(;8I})glNh z5|MZqsZolX?T*7Wp}DxY?2$z$Ppdv_Ztfc%7BGhDkC-qtMc_tIBRS!hJ8{D4oCiB= zKEA$pBRXu!h)PH0hQ>z1XPtNN-c6k+>mRy7l3_`t+ne-pl**gFKF*}1BvdiHp6Q9l zXJ7OghGm&ec0>kF2-`A7HTjh|yYMA3U3RrjkEZbjL*8wxEiA~hfO6wXTFS}O>U>E| z*Vw-l$S#6xP?`TyQcl!6Q7`D~(%0A3>9~CFCORvyXXwovu2ZK@@$vIluIS}i%uDdF ziH;H=+c9Ju%)Xw9c6K&_zN|D!gD92^-ooQIrz2;B*XN8XV!yXNDQu)*>iaAz?dQIf z2g(=F)z#In)-ylXw$6NdTXf#W&Mx1IydFoIp2n07$s?@vW$r$$!(J+X!7Y&c$5}6$ zrX?9M72JPzek;1TxcFX0#T#|Lf0s3TdwcKeh4aoi&AIW?e*OBD>Q}}mAdsq2US94Q z5Rf%C<`9OVjQcyNmY`i-tHykDE#wBWvKs?$@m(TTxzvY#`Qg{n(&DQr(TBYd(sm}# zBDttYRMS>gA}gPcvlmJE+@C|@7)^%7&cy9t@NElXe7!VH+v1WEw2KSQ*B9EWz7(bh zRI8<}9X+3C{^I!P034J#uyoLT`D{iCyY=xd_iX&ZUy(D>3fj|Qr>gukw6x5wkSH#y zo@MgIUKjNB-z_sJLdL)B*xrO;6iRJ`GheUk=e&Lm2W7y)!J(6#6u@%njLM^s;>#2& zq6n3hGLFa-((7@KG7}v>g627r3p2563qY?vadBt+gVp&s1{)`4W(0}~>?j*?q@9`A zK$E?tM>)knO;vsmSM=zpg9_w zWc;qj<3dg&n7`CjheD}6LSg>$vL7glBC8YNaJB`$npPBs43s??215S+{rgeiXU4?7-Hz+@K`;b!Z30W(OfNC zKbHq3BY0|=D=AA!(hpdxSe91B;>UJXV<^6J!;BzJ3!h$pb;R1zkLi*m+NGI2GJ1aF zbxXi7$xx8CyBnn=>e+yb%7GE^t(jjA;-hj`+AWmQP0yL06B2>H499#})gsz)Bayvg z5SckpgVgbduJxWQt-tGC$tV?&D&zVkK{aN0Fy{2g7L)+trv;z6J=?!?m@A!U!HHpx zX=eF9x9V~gL_Sos8sP2^_SGual;D@h;_B$=a8wrkx~)gY3CnOALq*^`n5MP+H8l@k zV=sV^fNz-LbezVw>5dY!M~PK_OYOt^`+AEbq{W}CKniO$Rqls=4!+g8X|k^+pk`co zHKH8EhAr2QG8S$ykLbaG1@9(HJ))U4h2cm=>JbGRQ2&JK4b9C-Z^xXqWdxl`%P~B< z=l}fe`TEXH*%L47{`a%ni5k5970H{zu5hh_Q@Y5?1MOsC2W&AVV5>G4?~oATg^31F zbFd-s0ALru42xyQF!KNwD06;OzZn37m#;h-1zZy-p^ zlWYKlG}CiN6b28^6!$Hb*3NXKlz#)Nv$MH5*+U!%!-gRznbXwJ08C^`ZLnyubW_49 z1-tbj?O8x>SJ-H%Dz#)kdTvLp=hx=jr6tABpFev% z-T#!SHZd_lYkV3Me>wwx6tO86apjtc1FR+^1|u3d9ez4Z;4IePpSM>XUsB5!{P11d zPVynTWjAkr+rJWjF40e1PM8NY#*L^mK(A91+RavE;|3HiG_;^!D&anGs>v`5CwuYY zMQ5Oljg8>ONflr_yR!$vGx_0zv4aR-uXKe4?2@e}+^D1Ou2eP_=v7k!)Pf6>jHtF( z6hWcU9${gH*9;GTh$$^>j->p%T;dwDOfrT7c2+wAmqx=43Qz$ZwMmZjwC3F-lQF>b*{f6tQ~w~wdOb~!&Ssi_WM)EdCdb8 zE}bOI-O%a6(+_Q{Z`2}G#ORA#as`&%NBb+3JCknzEEqyA9D-P@ie|#`FFvNKSL|F5 zN|4G${JXNf9w*fwY<&I0^fdWKZOFpgBK7O>KPP<>AV>SuO!~Du-(t6hwADzUaVY&M zD=UlBD1Fv>xCRhWu{gFI_G&OPA_B0;LMi%NL;t7U z#iz5%4=Mu+!?oW0(bxk-wL42I<6+SJfY40zBC(f-R`Oaq{*ax(?k%FjH?;!*d<51))~7K{ttp{`QZQn literal 0 HcmV?d00001 diff --git a/src/main/resources/public/index.html b/src/main/resources/public/index.html index 76eff64..6d23c7e 100644 --- a/src/main/resources/public/index.html +++ b/src/main/resources/public/index.html @@ -5,6 +5,7 @@ HA Bridge + diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index cdfe1fb..0b8ae5d 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -109,9 +109,9 @@ app.run(function ($rootScope, $location, Auth, bridgeService) { $rootScope.$on('securityReinit', function(event, data) { event.preventDefault(); - Auth.logout(); bridgeService.state.testuser = ""; - $location.path("/login"); + Auth.logout(); + $location.path("/"); }); $rootScope.$on('$routeChangeStart', function (event, next) { @@ -1637,7 +1637,8 @@ app.controller('SecurityDialogCtrl', function ($scope, bridgeService, ngDialog) if(bridgeService.state.loggedInUser !== undefined) $scope.username = bridgeService.state.loggedInUser; else - $scope.username = "" + $scope.username = ""; + bridgeService.getHABridgeVersion(); $scope.showPassword = $scope.isSecure; }; @@ -3745,8 +3746,9 @@ app.filter('filterDevicesByRequester', function () { } }); -app.controller('LoginController', function ($scope, $location, Auth) { +app.controller('LoginController', function ($scope, $location, Auth, bridgeService) { $scope.failed = false; + $scope.isSecure = bridgeService.isSecure(); $scope.loggedIn = Auth.isLoggedIn(); $scope.login = function(username, password) { Auth.login(username, password) @@ -3759,8 +3761,12 @@ app.controller('LoginController', function ($scope, $location, Auth) { $scope.logout = function() { Auth.logout(); + $scope.isSecure = bridgeService.isSecure(); $scope.loggedIn = Auth.isLoggedIn(); - $location.path("/login"); + if($scope.isSecure) + $location.path("/login"); + else + $location.path("/"); }; }); diff --git a/src/main/resources/public/views/login.html b/src/main/resources/public/views/login.html index 3019997..295eaf9 100644 --- a/src/main/resources/public/views/login.html +++ b/src/main/resources/public/views/login.html @@ -3,7 +3,7 @@

    Login

    -
    +
    Enter Credentials @@ -25,8 +25,11 @@
    -
    +
    +
    +

    This ha-bridge instance is not secured!

    +
    \ No newline at end of file From a489061bac86ed3822bf4753855958b73a0ee5c3 Mon Sep 17 00:00:00 2001 From: Admin Date: Wed, 22 Nov 2017 12:44:38 -0600 Subject: [PATCH 28/28] Changed version to 5.0.0, Updated README, updated traceupnp messages in log. --- README.md | 28 ++++++++-- pom.xml | 2 +- .../com/bwssystems/HABridge/HABridge.java | 13 +++-- .../bwssystems/HABridge/hue/HueMulator.java | 14 ++--- .../HABridge/upnp/UpnpListener.java | 51 ++++++++----------- .../HABridge/upnp/UpnpSettingsResource.java | 10 ++-- 6 files changed, 67 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 81929eb..56d5179 100644 --- a/README.md +++ b/README.md @@ -277,22 +277,32 @@ Don't forget - You will need to push the link button when you got to the Hue Tab Provide IP Addresses of your HAL Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HAL and device/scene you configure. #### MQTT Client IDs and IP Addresses Provide Client ID and IP Addresses and ports of your MQTT Brokers that you want to utilize with the bridge. Also, you can provide the username and password if you have secured your MQTT broker which is optional. When these Client ID and IP's are given, the bridge will be able to publish MQTT messages by the call it receives and send it to the target MQTT Broker you configure. The MQTT Messages Tab will become available to help you build messages. +#### Home Assistant Names and IP Addresses +Provide IP Addresses and ports of your Home Assistant that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Home Assistant and device/scene you configure. +#### Domoticz Names and IP Addresses +Provide IP Addresses of your Domoticz Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Domoticz and device/scene you configure. +#### Somfy Tahoma Names and IP Addresses +Provide user name and password used to login to www.tahomalink.com. This needs to be provided if you're using the Somfy Tahoma features (for connecting to IO Homecontrol used by Velux among others). There is no need to give any IP address or host information as this contacts your cloud account. *Note:* you have to 'turn on' a window to open it, and 'turn off' to close. #### Nest Username The user name of the home.nest.com account for the Nest user. This needs to be given if you are using the Nest features. There is no need to give any ip address or host information as this contacts your cloud account. #### Nest Password The password for the user name of the home.nest.com account for the Nest user. This needs to be given if you are using the Nest features. #### Nest Temp Fahrenheit This setting allows the value being sent into the bridge to be interpreted as Fahrenheit or Celsius. The default is to have Fahrenheit. -#### Somfy Tahoma Username -The user name used to login to www.tahomalink.com. This needs to be provided if you're using the Somfy Tahoma features (for connecting to IO Homecontrol used by Velux among others). There is no need to give any IP address or host information as this contacts your cloud account. *Note:* you have to 'turn on' a window to open it, and 'turn off' to close. -#### Somfy Tahoma Password -The password associated with the Somfy Tahoma username above +#### LIFX Support +This setting will have the ha-bridge look for LIFX devices on your network. Since this is broadcast based, there is no other info needed. +#### Emulate Hue Hub Version +This setting is used to set the version that the ha-bridge will return in the hub version field. The default is 9999999999 which should work to be higher than the versions that are being used. +#### Emulate MAC +This setting is in bridge-id, uuid, etc. in ha-bridge hue config replies. Leave blank unless needed as it is mainly a tool to keep a config to a specific set of devices whtn the ha-bridge is moved to another machine #### Button Press/Call Item Loop Sleep Interval (ms) This setting is the time used in between button presses when there is multiple buttons in a button device. It also controls the time between multiple items in a custom device call. This is defaulted to 100ms and the number represents milliseconds (1000 milliseconds = 1 second). #### Log Messages to Buffer This controls how many log messages will be kept and displayed on the log tab. This does not affect what is written to the standard output for logging. The default is 512. Changing this will incur more memory usage of the process. #### Trace UPNP Calls Turn on tracing for upnp discovery messages to the log. The default is false. +#### My Echo URL +This sets the URL that is used in the menu bar to ge to your echo. For certain countries, this needs to be set to a different URL. At the bottom of the screen is the "Bridge Settings Backup" which can be accessed with clicking on the `+` to expand this frame. Here you can backup and restore configurations that you have saved. These configs can be named or by clicking the `Backup Settings' button will create a backup and name it for you. You can manage these backups by restoring them or deleting them. ### The Logs Tab @@ -312,6 +322,16 @@ Another way to add a device is through the Manual Add Tab. This allows you to ma There is a new format for the on/dim/off URL areas. The new editor handles the intricacies of the components, but is broken down here for explanation. +It is imperative when adding a line by hand that you hit the ```Add``` button at the end of the line before adding or updating the whole entry. + +```Update Bridge Device``` Button is for editing a current bridge device entry. + +```Add Bridge Device``` Button is to ccreate a new bridge device entry. + +```Clear``` Button is used to clear the contents of the entry on the screen. + +```Change Edit Mode``` Button is used to swithc back to a pure editor for the on/off/dim/color lines within the device entry. + Here are the fields that can be put into the call item: Json Type | field name | What | Use diff --git a/pom.xml b/pom.xml index bb751a4..cf0a3da 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.bwssystems.HABridge ha-bridge - 5.0.0rc7 + 5.0.0 jar HA Bridge diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index e064848..55b48cf 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -80,15 +80,20 @@ public class HABridge { homeManager.buildHomes(bridgeSettings, udpSender); // setup the class to handle the resource setup rest api theResources = new DeviceResource(bridgeSettings, homeManager); - // setup the class to handle the upnp response rest api - theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor()); - theSettingResponder.setupServer(); // setup the class to handle the hue emulator rest api 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(); - + + if(bridgeSettings.getBridgeSettingsDescriptor().isTraceupnp()) + log.info("Traceupnp: upnp config address: " + bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress() + "-useIface:" + + bridgeSettings.getBridgeSettingsDescriptor().isUseupnpiface() + " on web server: " + + bridgeSettings.getBridgeSettingsDescriptor().getWebaddress() + ":" + bridgeSettings.getBridgeSettingsDescriptor().getServerPort()); + // setup the class to handle the upnp response rest api + theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor()); + theSettingResponder.setupServer(); + // start the upnp ssdp discovery listener theUpnpListener = null; try { diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java index 91be75d..23cc4fa 100644 --- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java +++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java @@ -625,7 +625,7 @@ public class HueMulator { } private String basicListHandler(String type, String userId, String requestIp) { - log.debug("hue " + type + " list requested: " + userId + " from " + requestIp); + log.debug("hue " + type + " list requested by user: " + userId + " from address: " + requestIp); HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()); if (theErrors != null) { if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged()) @@ -854,7 +854,7 @@ public class HueMulator { HueError[] theErrors = null; Map deviceResponseMap = null; if (bridgeSettings.isTraceupnp()) - log.info("Traceupnp: hue lights list requested: " + userId + " from " + requestIp); + log.info("Traceupnp: hue lights list requested by user: " + userId + " from address: " + requestIp); log.debug("hue lights list requested: " + userId + " from " + requestIp); theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton()); if (theErrors == null) { @@ -911,8 +911,10 @@ public class HueMulator { String aDeviceType = null; boolean toContinue = false; - if (bridgeSettings.isTraceupnp()) - log.info("Traceupnp: hue api user create requested: " + body + " from " + ipAddress); + if (bridgeSettings.isTraceupnp() && !body.contains("test_ha_bridge")) + log.info("Traceupnp: hue api user create requested: " + body + " from address: " + ipAddress); + else + log.debug("hue api user create requested: " + body + " from address: " + ipAddress); if(bridgeSettingMaster.getBridgeSecurity().isUseLinkButton() && bridgeSettingMaster.getBridgeControl().isLinkButton()) toContinue = true; @@ -947,7 +949,7 @@ public class HueMulator { if(bridgeSettingMaster.getBridgeSecurity().isSettingsChanged()) bridgeSettingMaster.updateConfigFile(); - if (bridgeSettings.isTraceupnp()) + if (bridgeSettings.isTraceupnp() && !aDeviceType.equals("test_ha_bridge")) log.info("Traceupnp: hue api user create requested for device type: " + aDeviceType + " and username: " + newUser + (followingSlash ? " /api/ called" : "")); log.debug("hue api user create requested for device type: " + aDeviceType + " and username: " + newUser + (followingSlash ? " /api/ called" : "")); @@ -960,7 +962,7 @@ public class HueMulator { private Object getConfig(String userId, String ipAddress) { if (bridgeSettings.isTraceupnp()) - log.info("Traceupnp: hue api/:userid/config config requested: " + userId + " from " + ipAddress); + log.info("Traceupnp: hue api/:userid/config config requested from user: " + userId + " from address: " + ipAddress); 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"); diff --git a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java index 119ad6a..14e69fb 100644 --- a/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java +++ b/src/main/java/com/bwssystems/HABridge/upnp/UpnpListener.java @@ -109,15 +109,18 @@ public class UpnpListener { while (addrs.hasMoreElements()) { InetAddress addr = addrs.nextElement(); - if (traceupnp) - log.info("Traceupnp: " + name + " ... has addr " + addr); - else - log.debug(name + " ... has addr " + addr); + log.debug(name + " ... has addr " + addr); if (InetAddressUtils.isIPv4Address(addr.getHostAddress())) { - if(!useUpnpIface) + if(!useUpnpIface) { + if(traceupnp) + log.info("Traceupnp: Interface: " + name + " valid usable IP address: " + addr); IPsPerNic++; - else if(addr.getHostAddress().equals(responseAddress)) - IPsPerNic++; + } + else if(addr.getHostAddress().equals(responseAddress)) { + if(traceupnp) + log.info("Traceupnp: Interface: " + name + " matches upnp config address of IP address: " + addr); + IPsPerNic++; + } } } log.debug("Checking " + name + " to our interface set"); @@ -125,7 +128,7 @@ public class UpnpListener { try { upnpMulticastSocket.joinGroup(socketAddress, xface); if (traceupnp) - log.info("Traceupnp: Adding " + name + " to our interface set"); + log.info("Traceupnp: Adding " + name + " to our upnp join interface set."); else log.debug("Adding " + name + " to our interface set"); } catch (IOException e) { @@ -199,29 +202,22 @@ public class UpnpListener { //Only respond to discover request for strict upnp form String packetString = new String(packet.getData(), 0, packet.getLength()); if(packetString != null && packetString.startsWith("M-SEARCH * HTTP/1.1") && packetString.contains("\"ssdp:discover\"")){ - log.debug("isSSDPDiscovery Found message to be an M-SEARCH message."); - log.debug("isSSDPDiscovery Got SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString); - if(strict && (packetString.contains("ST: urn:schemas-upnp-org:device:basic:1") || packetString.contains("ST: upnp:rootdevice") || packetString.contains("ST: ssdp:all"))) { if(traceupnp) { - log.info("Traceupnp: isSSDPDiscovery found message to be an M-SEARCH message."); - log.info("Traceupnp: isSSDPDiscovery found message to be valid under strict rules - strict: " + strict); - log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString); + log.info("Traceupnp: SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort()); } else - log.debug("isSSDPDiscovery found message to be valid under strict rules - strict: " + strict); + log.debug("SSDP M-SEARCH packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: <<<" + packetString + ">>>"); return true; } else if (!strict) { if(traceupnp) { - log.info("Traceupnp: isSSDPDiscovery found message to be an M-SEARCH message."); - log.info("Traceupnp: isSSDPDiscovery found message to be valid under loose rules - strict: " + strict); - log.info("Traceupnp: SSDP packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: " + packetString); + log.info("Traceupnp: SSDP M-SEARCH packet (!strict) from " + packet.getAddress().getHostAddress() + ":" + packet.getPort()); } else - log.debug("isSSDPDiscovery found message to be valid under loose rules - strict: " + strict); + log.debug("SSDP M-SEARCH packet (!strict) from " + packet.getAddress().getHostAddress() + ":" + packet.getPort() + ", body: <<<" + packetString + ">>>"); return true; } } @@ -236,26 +232,26 @@ public class UpnpListener { String discoveryResponse = null; discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID); if(traceupnp) { - log.info("Traceupnp: sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>"); + log.info("Traceupnp: send upnp discovery template 1 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort); } else - log.debug("sendUpnpResponse discovery responseTemplate1 is <<<" + discoveryResponse + ">>>"); + log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>"); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID); if(traceupnp) { - log.info("Traceupnp: sendUpnpResponse discovery responseTemplate2 is <<<" + discoveryResponse + ">>>"); + log.info("Traceupnp: send upnp discovery template 2 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort); } else - log.debug("sendUpnpResponse discovery responseTemplate2 is <<<" + discoveryResponse + ">>>"); + log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>"); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID); if(traceupnp) { - log.info("Traceupnp: sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>"); + log.info("Traceupnp: send upnp discovery template 3 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort); } else - log.debug("sendUpnpResponse discovery responseTemplate3 is <<<" + discoveryResponse + ">>>"); + log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " discovery responseTemplate3 is <<<" + discoveryResponse + ">>>"); sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort); } @@ -269,11 +265,8 @@ public class UpnpListener { protected void sendUpnpNotify(InetAddress aSocketAddress) { String notifyData = null; - log.debug("Sending notify packet for upnp."); notifyData = String.format(notifyTemplate, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID); - if(traceupnp) { - log.info("Traceupnp: sendUpnpNotify notifyTemplate is <<<" + notifyData + ">>>"); - } + log.debug("sendUpnpNotify notifyTemplate is <<<" + notifyData + ">>>"); DatagramPacket notifyPacket = new DatagramPacket(notifyData.getBytes(), notifyData.length(), aSocketAddress, Configuration.UPNP_DISCOVERY_PORT); try { upnpMulticastSocket.send(notifyPacket); diff --git a/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java b/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java index fe641ec..448cda6 100644 --- a/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java +++ b/src/main/java/com/bwssystems/HABridge/upnp/UpnpSettingsResource.java @@ -70,21 +70,17 @@ public class UpnpSettingsResource { } public void setupServer() { - log.info("Hue description service started...."); + log.info("Description xml service started...."); // http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator get("/description.xml", "application/xml; charset=utf-8", (request, response) -> { - if(theSettings.isTraceupnp()) - log.info("Traceupnp: upnp device settings requested: " + " from " + request.ip() + ":" + request.port()); - else - log.debug("upnp device settings requested: " + " from " + request.ip() + ":" + request.port()); String portNumber = Integer.toString(request.port()); String filledTemplate = null; String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress(), HueConstants.HUB_VERSION, theSettings.getHubmac()).getSNUUIDFromMac(); filledTemplate = String.format(hueTemplate, theSettings.getUpnpConfigAddress(), portNumber, theSettings.getUpnpConfigAddress(), bridgeIdMac, bridgeIdMac); if(theSettings.isTraceupnp()) - log.info("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + portNumber); + log.info("Traceupnp: request of description.xml from: " + request.ip() + ":" + request.port() + " filled in with address: " + theSettings.getUpnpConfigAddress() + ":" + portNumber); else - log.debug("Traceupnp: upnp device settings template filled with address: " + theSettings.getUpnpConfigAddress() + " and port: " + portNumber); + log.debug("request of description.xml from: " + request.ip() + ":" + request.port() + " filled in with address: " + theSettings.getUpnpConfigAddress() + ":" + portNumber); // response.header("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); // response.header("Pragma", "no-cache"); // response.header("Expires", "Mon, 1 Aug 2011 09:00:00 GMT");