implementing HomeAssistant

This commit is contained in:
Admin
2016-12-15 16:56:25 -06:00
parent 321b63f0fb
commit 74cccd6de3
13 changed files with 791 additions and 8 deletions

View File

@@ -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-");

View File

@@ -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<NamedIP> devicesList = this.getHassaddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
}

View File

@@ -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();

View File

@@ -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<String> 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();

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -1,9 +1,66 @@
package com.bwssystems.hass;
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.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.NamedIP;
public class HassHome {
private static final Logger log = LoggerFactory.getLogger(HassHome.class);
private Map<String, HomeAssistant> hassMap;
public HassHome() {
// TODO Auto-generated constructor stub
public HassHome(BridgeSettingsDescriptor bridgeSettings) {
super();
hassMap = new HashMap<String,HomeAssistant>();
if(!bridgeSettings.isValidHass())
return;
Iterator<NamedIP> 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<HassDevice> getDevices() {
log.debug("consolidating devices for hues");
List<State> theResponse = null;
Iterator<String> keys = hassMap.keySet().iterator();
List<HassDevice> deviceList = new ArrayList<HassDevice>();
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<HassDevice> theDeviceList, List<State> theSourceList, String theKey) {
Iterator<State> 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;
}
}

View File

@@ -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<State> getDevices() {
List<State> 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<State>(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;
}
}

View File

@@ -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;
});

View File

@@ -18,6 +18,7 @@
<li ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#/hassdevices">HomeAssistant Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>

View File

@@ -10,7 +10,6 @@
href="#/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showHAL" role="presentation"><a href="#/HAL">HAL</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#/huedevices">Hue Devices</a></li>
<li role="presentation" class="active"><a href="#/haldevices">HAL

View File

@@ -0,0 +1,196 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#">Bridge Devices</a></li>
<li role="presentation"><a href="#/system">Bridge Control</a></li>
<li role="presentation"><a href="#/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation" class="active"><a href="#/haldevices">HAL
Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
<li role="presentation" class="active"><a href="#/hassdevices">HomeAssistant
Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">HomeAssistant Device List
({{bridge.hassdevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any HomeAssistant Device, use the action buttons
to generate the device addition information below automatically. Then
you can modify the name to anything you want that will be the keyword
for Alexa. Click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured HomeAssistant Devices' list below will show what
is already setup for your HomeAssitant.</p>
<p>
Also, use this select menu for which type of dim control you would
like to be generated: <select name="device-dim-control"
id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity.byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<p>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 HomeAssitant.</p>
</div>
<scrollable-table watch="bridge.hassdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">
<span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></th>
<th sortable-header col="hassname">HomeAssitant</th>
<th>Actions</th>
</tr>
</thead>
<tr ng-repeat="hassdevice in bridge.hassdevices | availableHassDeviceId">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{hassdevice.deviceState.entity_id}}"
ng-checked="bulk.devices.indexOf(hassdevice.deviceState.entity_id) > -1"
ng-click="toggleSelection(hassdevice.deviceState.entity_id)">
{{hassdevice.deviceState.entity_id}}</td>
<td>{{hassdevice.hassname}}</td>
<td>
<button ng-if="hassdevice.hassdevicetype != 'Home' && hassdevice.hassdevicetype != 'HVAC' && hassdevice.hassdevicetype != 'IrData'" class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(hassdevice, device_dim_control)">Generate
Bridge Device</button>
<ul ng-if="hassdevice.hassdevicetype == 'HVAC'" class="list-group">
<li class="list-group-item">
<p>
<button class="btn btn-success" type="submit"
ng-click="buildhassHeatUrls(hassdevice)">Heat</button>
<button class="btn btn-success" type="submit"
ng-click="buildhassCoolUrls(hassdevice)">Cool</button>
<button class="btn btn-success" type="submit"
ng-click="buildhassAutoUrls(hassdevice)">Auto</button>
</p>
<p>
<button class="btn btn-success" type="submit"
ng-click="buildhassOffUrls(hassdevice)">Off</button>
<button class="btn btn-success" type="submit"
ng-click="buildhassFanUrls(hassdevice)">Fan</button>
</p>
</li>
</ul>
</td>
</tr>
</table>
</scrollable-table>
<div class="panel-footer">
<button class="btn btn-success" type="submit"
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
({{bulk.devices.length}})</button>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
Already Configured HomeAssitant Devices <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
</h2>
</div>
<scrollable-table ng-if="buttonsVisible" watch="bridge.hassdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="hassname">hass</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | unavailableHassDeviceId">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.targetDevice}}</td>
<td>
<button class="btn btn-danger" type="submit"
ng-click="deleteDeviceByMapId(device.mapId, device.mapType)">Delete</button>
</td>
</tr>
</table>
</scrollable-table>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Add Bridge Device for a HomeAssitant Device</h2>
</div>
<div class="panel-body">
<form class="form-horizontal">
<div class="form-group">
<label class="col-xs-12 col-sm-2 control-label" for="device-name">Name
</label>
<div class="col-xs-8 col-sm-7">
<input type="text" class="form-control" id="device-name"
ng-model="device.name" placeholder="Device Name">
</div>
<button type="submit" class="col-xs-4 col-sm-2 btn btn-primary"
ng-click="addDevice()">Add Bridge Device</button>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label" for="device-on-url">On
URL </label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-on-url"
ng-model="device.onUrl" placeholder="URL to turn device on"></textarea>
</div>
<button class="btn btn-danger" ng-click="clearDevice()">
Clear Device</button>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-dim-url">Dim URL </label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-dim-url"
ng-model="device.dimUrl" placeholder="URL to dim device"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label class="col-xs-12 col-sm-2 control-label"
for="device-off-url">Off URL </label>
<div class="col-xs-8 col-sm-7">
<textarea rows="3" class="form-control" id="device-off-url"
ng-model="device.offUrl" placeholder="URL to turn device off"></textarea>
</div>
</div>
</form>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -17,6 +17,8 @@
<li ng-if="bridge.showHal" role="presentation"><a
href="#/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#/hassdevices">HomeAssistant
Devices</a></li>
<li role="presentation"><a href="#/editor">Manual Add</a></li>
</ul>
@@ -265,6 +267,40 @@
</tr>
</table></td>
</tr>
<tr>
<td>HomeAssistant Names and IP Addresses</td>
<td><table
class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>IP</th>
<th>Port</th>
<th>Manage</th>
</tr>
</thead>
<tr ng-repeat="hass in bridge.settings.hassaddress.devices">
<td>{{hass.name}}</td>
<td>{{hass.ip}}</td>
<td>{{hass.port}}</td>
<td><button class="btn btn-danger" type="submit"
ng-click="removeHasstoSettings(hass.name, hass.ip)">Del</button></td>
</tr>
<tr>
<td><input id="bridge-settings-next-hass-name"
class="form-control" type="text" ng-model="newhassname"
placeholder="A HomeAssistant"></td>
<td><input id="bridge-settings-next-hass-ip"
class="form-control" type="text" ng-model="newhassip"
placeholder="192.168.1.3"></td>
<td><input id="bridge-settings-next-hass-port"
class="form-control" type="text" ng-model="newhassport"
deafult="8123"></td>
<td><button class="btn btn-success" type="submit"
ng-click="addHasstoSettings(newhassname, newhassip, newhassport)">Add</button></td>
</tr>
</table></td>
</tr>
<tr>
<td>Nest Username</td>
<td><input id="bridge-settings-nestuser" class="form-control"