diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java index e4a53bf..fe10832 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java @@ -151,6 +151,7 @@ public class BridgeSettings extends BackupHandler { theBridgeSettings.setHueconfigured(theBridgeSettings.isValidHue()); theBridgeSettings.setHalconfigured(theBridgeSettings.isValidHal()); theBridgeSettings.setMqttconfigured(theBridgeSettings.isValidMQTT()); + theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass()); if(serverPortOverride != null) theBridgeSettings.setServerPort(serverPortOverride); setupParams(Paths.get(theBridgeSettings.getConfigfile()), ".cfgbk", "habridge.config-"); diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java index 86ebe3e..4d298d1 100644 --- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java +++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java @@ -34,6 +34,8 @@ public class BridgeSettingsDescriptor { private String webaddress; private IpList mqttaddress; private boolean mqttconfigured; + private IpList hassaddress; + private boolean hassconfigured; public BridgeSettingsDescriptor() { super(); @@ -45,6 +47,7 @@ public class BridgeSettingsDescriptor { this.hueconfigured = false; this.halconfigured = false; this.mqttconfigured = false; + this.hassconfigured = false; this.farenheit = true; this.whitelist = null; this.settingsChanged = false; @@ -225,6 +228,18 @@ public class BridgeSettingsDescriptor { public void setMqttconfigured(boolean mqttconfigured) { this.mqttconfigured = mqttconfigured; } + public IpList getHassaddress() { + return hassaddress; + } + public void setHassaddress(IpList hassaddress) { + this.hassaddress = hassaddress; + } + public boolean isHassconfigured() { + return hassconfigured; + } + public void setHassconfigured(boolean hassconfigured) { + this.hassconfigured = hassconfigured; + } public Boolean isValidVera() { if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0) return false; @@ -274,4 +289,12 @@ public class BridgeSettingsDescriptor { return false; return true; } + public Boolean isValidHass() { + if(this.getHassaddress() == null || this.getHassaddress().getDevices().size() <= 0) + return false; + List devicesList = this.getHassaddress().getDevices(); + if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS)) + return false; + return true; + } } diff --git a/src/main/java/com/bwssystems/HABridge/HABridge.java b/src/main/java/com/bwssystems/HABridge/HABridge.java index e8462e3..55a89d5 100644 --- a/src/main/java/com/bwssystems/HABridge/HABridge.java +++ b/src/main/java/com/bwssystems/HABridge/HABridge.java @@ -12,6 +12,7 @@ import com.bwssystems.HABridge.upnp.UpnpSettingsResource; import com.bwssystems.NestBridge.NestHome; import com.bwssystems.hal.HalHome; import com.bwssystems.harmony.HarmonyHome; +import com.bwssystems.hass.HassHome; import com.bwssystems.hue.HueHome; import com.bwssystems.mqtt.MQTTHome; import com.bwssystems.util.UDPDatagramSender; @@ -41,6 +42,7 @@ public class HABridge { HueHome hueHome; HalHome halHome; MQTTHome mqttHome; + HassHome hassHome; HueMulator theHueMulator; UDPDatagramSender udpSender; UpnpSettingsResource theSettingResponder; @@ -77,7 +79,9 @@ public class HABridge { //setup the mqtt handlers if available mqttHome = new MQTTHome(bridgeSettings.getBridgeSettingsDescriptor()); // setup the class to handle the resource setup rest api - theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome, halHome, mqttHome); + //setup the HomeAssistant configuration if available + hassHome = new HassHome(bridgeSettings.getBridgeSettingsDescriptor()); + theResources = new DeviceResource(bridgeSettings.getBridgeSettingsDescriptor(), harmonyHome, nestHome, hueHome, halHome, mqttHome, hassHome); // setup the class to handle the upnp response rest api theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor()); theSettingResponder.setupServer(); diff --git a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java index d601dea..8c0f2ad 100644 --- a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java +++ b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java @@ -24,6 +24,7 @@ import com.bwssystems.HABridge.dao.ErrorMessage; import com.bwssystems.NestBridge.NestHome; import com.bwssystems.hal.HalHome; import com.bwssystems.harmony.HarmonyHome; +import com.bwssystems.hass.HassHome; import com.bwssystems.hue.HueHome; import com.bwssystems.luupRequests.Device; import com.bwssystems.luupRequests.Scene; @@ -45,9 +46,10 @@ public class DeviceResource { private HueHome hueHome; private HalHome halHome; private MQTTHome mqttHome; + private HassHome hassHome; private static final Set supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post")); - public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome, HalHome aHalHome, MQTTHome aMqttHome) { + public DeviceResource(BridgeSettingsDescriptor theSettings, HarmonyHome theHarmonyHome, NestHome aNestHome, HueHome aHueHome, HalHome aHalHome, MQTTHome aMqttHome, HassHome aHassHome) { this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb()); if(theSettings.isValidVera()) @@ -80,6 +82,11 @@ public class DeviceResource { else this.mqttHome = null; + if(theSettings.isValidHass()) + this.hassHome = aHassHome; + else + this.hassHome = null; + setupEndpoints(); } @@ -298,6 +305,16 @@ public class DeviceResource { return mqttHome.getBrokers(); }, new JsonTransformer()); + get (API_CONTEXT + "/hass/devices", "application/json", (request, response) -> { + log.debug("Get HomeAssistant Clients"); + if(hassHome == null) { + response.status(HttpStatus.SC_NOT_FOUND); + return new ErrorMessage("A HomeAssistant config is not available."); + } + response.status(HttpStatus.SC_OK); + return hassHome.getDevices(); + }, new JsonTransformer()); + get (API_CONTEXT + "/map/types", "application/json", (request, response) -> { log.debug("Get map types"); return new DeviceMapTypes(); diff --git a/src/main/java/com/bwssystems/hal/HalHome.java b/src/main/java/com/bwssystems/hal/HalHome.java index 17c8169..2f60abf 100644 --- a/src/main/java/com/bwssystems/hal/HalHome.java +++ b/src/main/java/com/bwssystems/hal/HalHome.java @@ -27,7 +27,7 @@ public class HalHome { try { hals.put(aHal.getName(), new HalInfo(aHal, bridgeSettings.getHaltoken())); } catch (Exception e) { - log.error("Cannot get harmony client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e); + log.error("Cannot get hal client (" + aHal.getName() + ") setup, Exiting with message: " + e.getMessage(), e); return; } } diff --git a/src/main/java/com/bwssystems/hass/HassDevice.java b/src/main/java/com/bwssystems/hass/HassDevice.java new file mode 100644 index 0000000..e3ddb59 --- /dev/null +++ b/src/main/java/com/bwssystems/hass/HassDevice.java @@ -0,0 +1,25 @@ +package com.bwssystems.hass; + +public class HassDevice { + private State deviceState; + private String hassaddress; + private String hassname; + public State getDeviceState() { + return deviceState; + } + public void setDeviceState(State deviceState) { + this.deviceState = deviceState; + } + public String getHassaddress() { + return hassaddress; + } + public void setHassaddress(String hassaddress) { + this.hassaddress = hassaddress; + } + public String getHassname() { + return hassname; + } + public void setHassname(String hassname) { + this.hassname = hassname; + } +} diff --git a/src/main/java/com/bwssystems/hass/HassHome.java b/src/main/java/com/bwssystems/hass/HassHome.java index 6e79533..89aca34 100644 --- a/src/main/java/com/bwssystems/hass/HassHome.java +++ b/src/main/java/com/bwssystems/hass/HassHome.java @@ -1,9 +1,66 @@ package com.bwssystems.hass; -public class HassHome { +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; - public HassHome() { - // TODO Auto-generated constructor stub +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.bwssystems.HABridge.BridgeSettingsDescriptor; +import com.bwssystems.HABridge.NamedIP; + +public class HassHome { + private static final Logger log = LoggerFactory.getLogger(HassHome.class); + private Map hassMap; + + public HassHome(BridgeSettingsDescriptor bridgeSettings) { + super(); + hassMap = new HashMap(); + if(!bridgeSettings.isValidHass()) + return; + Iterator theList = bridgeSettings.getHassaddress().getDevices().iterator(); + while(theList.hasNext()) { + NamedIP aHass = theList.next(); + try { + hassMap.put(aHass.getName(), new HomeAssistant(aHass)); + } catch (Exception e) { + log.error("Cannot get hass (" + aHass.getName() + ") setup, Exiting with message: " + e.getMessage(), e); + return; + } + } } + public List getDevices() { + log.debug("consolidating devices for hues"); + List theResponse = null; + Iterator keys = hassMap.keySet().iterator(); + List deviceList = new ArrayList(); + while(keys.hasNext()) { + String key = keys.next(); + theResponse = hassMap.get(key).getDevices(); + if(theResponse != null) + addHassDevices(deviceList, theResponse, key); + else { + log.warn("Cannot get devices for HomeAssistant with name: " + key + ", skipping this Hass."); + continue; + } + } + return deviceList; + } + + private Boolean addHassDevices(List theDeviceList, List theSourceList, String theKey) { + Iterator devices = theSourceList.iterator(); + while(devices.hasNext()) { + State theDevice = devices.next(); + HassDevice aNewHassDevice = new HassDevice(); + aNewHassDevice.setDeviceState(theDevice); + aNewHassDevice.setHassaddress(hassMap.get(theKey).getHassAddress().getIp()); + aNewHassDevice.setHassname(theKey); + theDeviceList.add(aNewHassDevice); + } + return true; + } } diff --git a/src/main/java/com/bwssystems/hass/HomeAssistant.java b/src/main/java/com/bwssystems/hass/HomeAssistant.java new file mode 100644 index 0000000..72ed904 --- /dev/null +++ b/src/main/java/com/bwssystems/hass/HomeAssistant.java @@ -0,0 +1,78 @@ +package com.bwssystems.hass; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.bwssystems.HABridge.NamedIP; +import com.google.gson.Gson; + +public class HomeAssistant { + private static final Logger log = LoggerFactory.getLogger(HomeAssistant.class); + private NamedIP hassAddress; + private HttpClient httpClient; + + public HomeAssistant(NamedIP addressName) { + super(); + httpClient = HttpClients.createDefault(); + hassAddress = addressName; + } + + public NamedIP getHassAddress() { + return hassAddress; + } + + public void setHassAddress(NamedIP hassAddress) { + this.hassAddress = hassAddress; + } + + public List getDevices() { + List theDeviceStates = null; + State[] theHassStates; + String theUrl = null; + String theData; + theUrl = "http://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/states"; + theData = doHttpGETRequest(theUrl); + if(theData != null) { + log.debug("GET Hass States - data: " + theData); + theHassStates = new Gson().fromJson(theData, State[].class); + if(theHassStates == null) { + log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " as response is not parsable."); + } + else { + theDeviceStates = new ArrayList(Arrays.asList(theHassStates)); + } + } + else + log.warn("Cannot get an devices for HomeAssistant " + hassAddress.getName() + " http call failed."); + return theDeviceStates; + } + + // This function executes the url against the hass + protected String doHttpGETRequest(String url) { + String theContent = null; + log.debug("calling GET on URL: " + url); + HttpGet httpGet = new HttpGet(url); + try { + HttpResponse response = httpClient.execute(httpGet); + log.debug("GET on URL responded: " + response.getStatusLine().getStatusCode()); + if(response.getStatusLine().getStatusCode() == 200){ + theContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); //read content for data + EntityUtils.consume(response.getEntity()); //close out inputstream ignore content + } + } catch (IOException e) { + log.error("doHttpGETRequest: Error calling out to HA gateway: " + e.getMessage()); + } + return theContent; + } +} diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js index 9f47957..7a31927 100644 --- a/src/main/resources/public/scripts/app.js +++ b/src/main/resources/public/scripts/app.js @@ -40,6 +40,9 @@ app.config(function ($routeProvider) { }).when('/mqttmessages', { templateUrl: 'views/mqttpublish.html', controller: 'MQTTController' + }).when('/hassdevices', { + templateUrl: 'views/hassevice.html', + controller: 'HassController' }).otherwise({ templateUrl: 'views/configuration.html', controller: 'ViewingController' @@ -65,7 +68,7 @@ String.prototype.replaceAll = function(search, replace) app.service('bridgeService', function ($http, $window, ngToast) { var self = this; - this.state = {base: window.location.origin + "/api/devices", bridgelocation: window.location.origin, systemsbase: window.location.origin + "/system", huebase: window.location.origin + "/api", configs: [], backups: [], devices: [], device: [], mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, habridgeversion: ""}; + this.state = {base: window.location.origin + "/api/devices", bridgelocation: window.location.origin, systemsbase: window.location.origin + "/system", huebase: window.location.origin + "/api", configs: [], backups: [], devices: [], device: [], mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false, habridgeversion: ""}; this.displayWarn = function(errorTitle, error) { var toastContent = errorTitle; @@ -197,6 +200,11 @@ app.service('bridgeService', function ($http, $window, ngToast) { return; } + this.updateShowHass = function () { + this.state.showHass = self.state.settings.hassconfigured; + return; + } + this.loadBridgeSettings = function () { return $http.get(this.state.systemsbase + "/settings").then( function (response) { @@ -207,6 +215,7 @@ app.service('bridgeService', function ($http, $window, ngToast) { self.updateShowHue(); self.updateShowHal(); self.updateShowMqtt(); + self.updateShowHass(); }, function (error) { self.displayWarn("Load Bridge Settings Error: ", error); @@ -362,6 +371,19 @@ app.service('bridgeService', function ($http, $window, ngToast) { ); }; + this.viewHassDevices = function () { + if(!this.state.showHass) + return; + return $http.get(this.state.base + "/hass/devices").then( + function (response) { + self.state.hassdevices = response.data; + }, + function (error) { + self.displayWarn("Get Hass Devices Error: ", error); + } + ); + }; + this.updateLogLevels = function(logComponents) { return $http.put(this.state.systemsbase + "/logmgmt/update", logComponents ).then( function (response) { @@ -1817,6 +1839,302 @@ app.controller('MQTTController', function ($scope, $location, $http, bridgeServi }); +app.controller('HassController', function ($scope, $location, $http, bridgeService, ngDialog) { + $scope.bridge = bridgeService.state; + $scope.device = $scope.bridge.device; + $scope.device_dim_control = ""; + $scope.bulk = { devices: [] }; + $scope.selectAll = false; + bridgeService.viewHassDevices(); + $scope.imgButtonsUrl = "glyphicon glyphicon-plus"; + $scope.buttonsVisible = false; + + $scope.clearDevice = function () { + bridgeService.clearDevice(); + }; + + $scope.buildDeviceUrls = function (hassdevice, dim_control) { + bridgeService.clearDevice(); + $scope.device = $scope.bridge.device; + var preOnCmd = ""; + var preDimCmd = ""; + var preOffCmd = ""; + var nameCmd = "" + var postCmd = "?Token=" + $scope.bridge.settings.haltoken; + if(hassdevice.hassdevicetype == "Group") { + $scope.device.deviceType = "group"; + preOnCmd = "/GroupService!GroupCmd=On"; + preOffCmd = "/GroupService!GroupCmd=Off"; + nameCmd = "!GroupName="; + } + else if(hassdevice.hassdevicetype == "Macro") { + $scope.device.deviceType = "macro"; + preOnCmd = "/MacroService!MacroCmd=Set!MacroName="; + preOffCmd = preOnCmd; + } + else if(hassdevice.hassdevicetype == "Scene") { + $scope.device.deviceType = "scene"; + preOnCmd = "/SceneService!SceneCmd=Set!SceneName="; + preOffCmd = preOnCmd; + } + else { + $scope.device.deviceType = "switch"; + preOnCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=On"; + preDimCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=Dim!DevicePercent="; + preOffCmd = "/DeviceService!DeviceCmd=SetDevice!DeviceValue=Off"; + nameCmd = "!DeviceName="; + } + $scope.device.name = hassdevice.hassdevicename; + $scope.device.targetDevice = hassdevice.halname; + $scope.device.mapType = "hassdevice"; + $scope.device.mapId = hassdevice.hassdevicename + "-" + hassdevice.halname; + if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) && $scope.device.deviceType == "switch") + $scope.device.dimUrl = "http://" + hassdevice.haladdress + + preDimCmd + + dim_control + + nameCmd + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + postCmd; + else + $scope.device.dimUrl = "http://" + hassdevice.haladdress + + preOnCmd + + nameCmd + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + postCmd; + $scope.device.onUrl = "http://" + hassdevice.haladdress + + preOnCmd + + nameCmd + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + postCmd; + $scope.device.offUrl = "http://" + hassdevice.haladdress + + preOffCmd + + nameCmd + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + postCmd; + }; + + $scope.buildHassHomeUrls = function (hassdevice) { + bridgeService.clearDevice(); + $scope.device.deviceType = "home"; + $scope.device.name = hassdevice.hassdevicename; + $scope.device.targetDevice = hassdevice.halname; + $scope.device.mapType = "halHome"; + $scope.device.mapId = hassdevice.hassdevicename + "-" + hassdevice.halname + "-HomeAway"; + $scope.device.onUrl = "http://" + hassdevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Home?Token=" + $scope.bridge.settings.haltoken; + $scope.device.offUrl = "http://" + hassdevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Away?Token=" + $scope.bridge.settings.haltoken; + }; + + $scope.buildHassHeatUrls = function (hassdevice) { + bridgeService.clearDevice(); + $scope.device.deviceType = "thermo"; + $scope.device.name = hassdevice.hassdevicename + " Heat"; + $scope.device.targetDevice = hassdevice.halname; + $scope.device.mapType = "halThermoSet"; + $scope.device.mapId = hassdevice.hassdevicename + "-" + hassdevice.halname + "-SetHeat"; + $scope.device.onUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Heat?Token=" + + $scope.bridge.settings.haltoken; + $scope.device.dimUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Heat!HeatSpValue=${intensity.percent}?Token=" + + $scope.bridge.settings.haltoken; + $scope.device.offUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Off?Token=" + }; + + $scope.buildHassCoolUrls = function (hassdevice) { + bridgeService.clearDevice(); + $scope.device.deviceType = "thermo"; + $scope.device.name = hassdevice.hassdevicename + " Cool"; + $scope.device.targetDevice = hassdevice.halname; + $scope.device.mapType = "halThermoSet"; + $scope.device.mapId = hassdevice.hassdevicename + "-" + hassdevice.halname + "-SetCool"; + $scope.device.onUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Cool?Token=" + + $scope.bridge.settings.haltoken; + $scope.device.dimUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Cool!CoolSpValue=${intensity.percent}?Token=" + + $scope.bridge.settings.haltoken; + $scope.device.offUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Off?Token=" + }; + + $scope.buildHassAutoUrls = function (hassdevice) { + bridgeService.clearDevice(); + $scope.device.deviceType = "thermo"; + $scope.device.name = hassdevice.hassdevicename + " Auto"; + $scope.device.targetDevice = hassdevice.halname; + $scope.device.mapType = "halThermoSet"; + $scope.device.mapId = hassdevice.hassdevicename + "-" + hassdevice.halname + "-SetAuto"; + $scope.device.onUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Auto?Token=" + + $scope.bridge.settings.haltoken; + $scope.device.offUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Off?Token=" + }; + + $scope.buildHassOffUrls = function (hassdevice) { + bridgeService.clearDevice(); + $scope.device.deviceType = "thermo"; + $scope.device.name = hassdevice.hassdevicename + " Thermostat"; + $scope.device.targetDevice = hassdevice.halname; + $scope.device.mapType = "halThermoSet"; + $scope.device.mapId = hassdevice.hassdevicename + "-" + hassdevice.halname + "-TurnOff"; + $scope.device.onUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Auto?Token=" + + $scope.bridge.settings.haltoken; + $scope.device.offUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!HVACMode=Off?Token=" + }; + + $scope.buildHassFanUrls = function (hassdevice) { + bridgeService.clearDevice(); + $scope.device.deviceType = "thermo"; + $scope.device.name = hassdevice.hassdevicename + " Fan"; + $scope.device.targetDevice = hassdevice.halname; + $scope.device.mapType = "halThermoSet"; + $scope.device.mapId = hassdevice.hassdevicename + "-" + hassdevice.halname + "-SetFan"; + $scope.device.onUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!FanMode=On?Token=" + + $scope.bridge.settings.haltoken; + $scope.device.offUrl = "http://" + hassdevice.haladdress + + "/HVACService!HVACCmd=Set!HVACName=" + + hassdevice.hassdevicename.replaceAll(" ", "%20") + + "!FanMode=Auto?Token=" + + $scope.bridge.settings.haltoken; + }; + + $scope.addDevice = function () { + if($scope.device.name == "" && $scope.device.onUrl == "") + return; + bridgeService.addDevice($scope.device).then( + function () { + $scope.clearDevice(); + bridgeService.viewDevices(); + bridgeService.viewhassdevices(); + }, + function (error) { + bridgeService.displayWarn("Error adding device: " + $scope.device.name, error) + } + ); + + }; + + $scope.bulkAddDevices = function(dim_control) { + var devicesList = []; + for(var i = 0; i < $scope.bulk.devices.length; i++) { + for(var x = 0; x < bridgeService.state.hassdevices.length; x++) { + if(bridgeService.state.hassdevices[x].hassdevicename == $scope.bulk.devices[i]) { + if(bridgeService.state.hassdevices[x].hassdevicetype == "HVAC") + $scope.buildHALAutoUrls(bridgeService.state.hassdevices[x]); + else if(bridgeService.state.hassdevices[x].hassdevicetype == "HOME") + $scope.buildHALHomeUrls(bridgeService.state.hassdevices[x]); + else + $scope.buildDeviceUrls(bridgeService.state.hassdevices[x],dim_control); + 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 + }; + } + } + } + bridgeService.bulkAddDevice(devicesList).then( + function () { + $scope.clearDevice(); + bridgeService.viewDevices(); + bridgeService.viewhassdevices(); + }, + function (error) { + bridgeService.displayWarn("Error adding Hass 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.hassdevices.length; x++) { + if($scope.bulk.devices.indexOf(bridgeService.state.hassdevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.hassdevices[x].hassdevicename + "-" + bridgeService.state.hassdevices[x].halname, bridgeService.state.hassdevices[x].halname, "hassdevice")) + $scope.bulk.devices.push(bridgeService.state.hassdevices[x].hassdevicename); + } + } + }; + + $scope.toggleButtons = function () { + $scope.buttonsVisible = !$scope.buttonsVisible; + if($scope.buttonsVisible) + $scope.imgButtonsUrl = "glyphicon glyphicon-minus"; + else + $scope.imgButtonsUrl = "glyphicon glyphicon-plus"; + }; + + $scope.deleteDeviceByMapId = function (id, mapType) { + $scope.bridge.mapandid = { id, mapType }; + ngDialog.open({ + template: 'deleteMapandIdDialog', + controller: 'DeleteMapandIdDialogCtrl', + className: 'ngdialog-theme-default' + }); + }; + +}); + app.controller('EditController', function ($scope, $location, $http, bridgeService) { $scope.bridge = bridgeService.state; $scope.device = $scope.bridge.device; @@ -2105,6 +2423,34 @@ app.filter('configuredMqttMsgs', function() { } }); +app.filter('availableHassDeviceId', function(bridgeService) { + return function(input) { + var out = []; + if(input == null) + return out; + for (var i = 0; i < input.length; i++) { + if(!bridgeService.findDeviceByMapId(input[i].hassdevicename + "-" + input[i].hassname, input[i].hassname, "hassDevice")){ + out.push(input[i]); + } + } + return out; + } +}); + +app.filter('unavailableHassDeviceId', function(bridgeService) { + return function(input) { + var out = []; + if(input == null) + return out; + for (var i = 0; i < input.length; i++) { + if(input[i].mapType != null && bridgeService.aContainsB(input[i].mapType, "hass")){ + out.push(input[i]); + } + } + return out; + } +}); + app.controller('VersionController', function ($scope, bridgeService) { $scope.bridge = bridgeService.state; }); \ No newline at end of file diff --git a/src/main/resources/public/views/configuration.html b/src/main/resources/public/views/configuration.html index 0d88a37..a6dfb19 100644 --- a/src/main/resources/public/views/configuration.html +++ b/src/main/resources/public/views/configuration.html @@ -18,6 +18,7 @@
  • HAL Devices
  • MQTT Messages
  • +
  • HomeAssistant Devices
  • Manual Add
  • diff --git a/src/main/resources/public/views/haldevice.html b/src/main/resources/public/views/haldevice.html index 21be227..b330d1f 100644 --- a/src/main/resources/public/views/haldevice.html +++ b/src/main/resources/public/views/haldevice.html @@ -10,7 +10,6 @@ href="#/harmonyactivities">Harmony Activities
  • Harmony Devices
  • -
  • HAL
  • Hue Devices
  • HAL Devices
  • MQTT Messages
  • +
  • HomeAssistant + Devices
  • Manual Add
  • @@ -265,6 +267,40 @@ + + HomeAssistant Names and IP Addresses + + + + + + + + + + + + + + + + + + + + + +
    NameIPPortManage
    {{hass.name}}{{hass.ip}}{{hass.port}}
    + Nest Username