mirror of
https://github.com/bwssytems/ha-bridge.git
synced 2025-12-16 18:24:36 +00:00
Updated broadlink discover and fixed list mapping issue. Added refresh
to ResourceHAndlers so Broadlink and Lifx can be refreshed from the tab.
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.bwssystems.HABridge</groupId>
|
||||
<artifactId>ha-bridge</artifactId>
|
||||
<version>5.2.0RC15</version>
|
||||
<version>5.2.0RC16</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>HA Bridge</name>
|
||||
|
||||
@@ -338,6 +338,14 @@ public class DeviceResource {
|
||||
return new DeviceMapTypes().getDeviceMapTypes();
|
||||
}, new JsonTransformer());
|
||||
|
||||
get (API_CONTEXT + "/refresh/:typeIndex", "application/json", (request, response) -> {
|
||||
String typeIndex = request.params(":typeIndex");
|
||||
log.debug("Refresh Home: " + typeIndex);
|
||||
response.status(HttpStatus.SC_OK);
|
||||
homeManager.findResource(typeIndex).refresh();
|
||||
return null;
|
||||
}, new JsonTransformer());
|
||||
|
||||
// http://ip_address:port/api/devices/exec/renumber CORS request
|
||||
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
|
||||
response.status(HttpStatus.SC_OK);
|
||||
|
||||
@@ -2,4 +2,5 @@ package com.bwssystems.HABridge.devicemanagmeent;
|
||||
|
||||
public interface ResourceHandler {
|
||||
public Object getItems(String type);
|
||||
public void refresh();
|
||||
}
|
||||
|
||||
@@ -197,5 +197,10 @@ public class NestHome implements com.bwssystems.HABridge.Home {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,59 +57,23 @@ public class BroadlinkHome implements Home {
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings) {
|
||||
broadlinkMap = null;
|
||||
bridgeSettingsDesc = bridgeSettings.getBridgeSettingsDescriptor();
|
||||
|
||||
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
|
||||
bridgeSettingsDesc = bridgeSettings.getBridgeSettingsDescriptor();
|
||||
validBroadlink = bridgeSettings.getBridgeSettingsDescriptor().isValidBroadlink();
|
||||
|
||||
broadlinkDiscover();
|
||||
|
||||
log.info("Broadlink Home created." + (validBroadlink ? "" : " No Broadlinks configured.") + (isDevMode ? " DevMode is set." : ""));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
BLDevice[] clients;
|
||||
if(!validBroadlink || broadlinkMap == null)
|
||||
return null;
|
||||
BroadlinkEntry theResponse = null;
|
||||
List<BroadlinkEntry> deviceList = new ArrayList<BroadlinkEntry>();
|
||||
log.debug("consolidating devices for Broadlink");
|
||||
if(!validBroadlink)
|
||||
return null;
|
||||
broadlinkMap = new HashMap<String, BLDevice>();
|
||||
int aDiscoverPort = Configuration.BROADLINK_DISCOVER_PORT;
|
||||
while(aDiscoverPort > 0) {
|
||||
try {
|
||||
log.info("Broadlink discover....");
|
||||
if(isDevMode) {
|
||||
clients = TestBLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||
}
|
||||
else
|
||||
clients = BLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||
if(clients.length <= 0) {
|
||||
log.warn("Did not discover any Broadlinks.");
|
||||
broadlinkMap = null;
|
||||
return deviceList;
|
||||
}
|
||||
for(int i = 0; i < clients.length; i++) {
|
||||
if(clients[i].getDeviceType() != BLDevice.DEV_A1) {
|
||||
broadlinkMap.put(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType()), clients[i]);
|
||||
log.debug("Adding Device to Map - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||
} else {
|
||||
log.debug("Ignoring A1 Device - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||
}
|
||||
}
|
||||
aDiscoverPort = 0;
|
||||
} catch (BindException e) {
|
||||
log.warn("Could not discover Broadlinks, Port in use, increasing by 11");
|
||||
aDiscoverPort += 11;
|
||||
if(aDiscoverPort > Configuration.BROADLINK_DISCOVER_PORT + 110)
|
||||
aDiscoverPort = 0;
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not discover Broadlinks, with IO Exception", e);
|
||||
broadlinkMap = null;
|
||||
validBroadlink = false;
|
||||
aDiscoverPort = 0;
|
||||
}
|
||||
}
|
||||
Iterator<String> keys = broadlinkMap.keySet().iterator();
|
||||
while(keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
@@ -124,6 +88,13 @@ public class BroadlinkHome implements Home {
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
if(validBroadlink)
|
||||
broadlinkDiscover();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
@@ -336,6 +307,51 @@ public class BroadlinkHome implements Home {
|
||||
}
|
||||
return theType;
|
||||
}
|
||||
|
||||
public BLDevice[] broadlinkDiscover () {
|
||||
BLDevice[] clients = null;
|
||||
int aDiscoverPort = Configuration.BROADLINK_DISCOVER_PORT;
|
||||
while(aDiscoverPort > 0) {
|
||||
try {
|
||||
log.info("Broadlink discover....");
|
||||
if(isDevMode) {
|
||||
clients = TestBLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||
}
|
||||
else
|
||||
clients = BLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
|
||||
for(int i = 0; i < clients.length; i++) {
|
||||
if(clients[i].getDeviceType() != BLDevice.DEV_A1) {
|
||||
broadlinkMap.put(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType()), clients[i]);
|
||||
log.debug("Adding Device to Map - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||
} else {
|
||||
log.debug("Ignoring A1 Device - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
|
||||
}
|
||||
}
|
||||
aDiscoverPort = 0;
|
||||
} catch (BindException e) {
|
||||
log.warn("Could not discover Broadlinks, Port in use, increasing by 11");
|
||||
aDiscoverPort += 11;
|
||||
if(aDiscoverPort > Configuration.BROADLINK_DISCOVER_PORT + 110)
|
||||
aDiscoverPort = 0;
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not discover Broadlinks, with IO Exception", e);
|
||||
broadlinkMap = null;
|
||||
validBroadlink = false;
|
||||
aDiscoverPort = 0;
|
||||
}
|
||||
}
|
||||
if(clients == null || clients.length <= 0) {
|
||||
log.warn("Did not discover any Broadlinks.");
|
||||
broadlinkMap = null;
|
||||
} else {
|
||||
broadlinkMap = new HashMap<String, BLDevice>();
|
||||
for(BLDevice aDevice : clients) {
|
||||
broadlinkMap.put(aDevice.getHost() + "-" + String.format("%04x", aDevice.getDeviceType()), aDevice);
|
||||
}
|
||||
}
|
||||
return clients;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
if(!validBroadlink)
|
||||
|
||||
@@ -66,6 +66,11 @@ public class DomoticzHome implements Home {
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
private Boolean addDomoticzDevices(List<DomoticzDevice> theDeviceList, List<DomoticzDevice> theSourceList, String theKey) {
|
||||
if(!validDomoticz)
|
||||
return null;
|
||||
|
||||
@@ -92,6 +92,11 @@ public class CommandHome implements Home {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeHome() {
|
||||
log.debug("Closing Home.");
|
||||
|
||||
@@ -151,6 +151,11 @@ public class FHEMHome implements Home {
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
private Boolean addFHEMDevices(List<FHEMDevice> theDeviceList, List<FHEMDevice> theSourceList, String theKey) {
|
||||
Iterator<FHEMDevice> devices = theSourceList.iterator();
|
||||
while(devices.hasNext()) {
|
||||
|
||||
@@ -84,6 +84,11 @@ public class FibaroHome implements Home
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public Home createHome(BridgeSettings bridgeSettings)
|
||||
{
|
||||
|
||||
@@ -113,6 +113,11 @@ public class HalHome implements Home {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
|
||||
@@ -269,4 +269,10 @@ public class HarmonyHome implements Home {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -117,6 +117,11 @@ public class HassHome implements Home {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
|
||||
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
|
||||
|
||||
@@ -147,4 +147,9 @@ public class HomeWizardHome implements Home {
|
||||
plugGateways = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,4 +140,8 @@ public class HTTPHome implements Home {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,4 +153,9 @@ public class HueHome implements Home {
|
||||
hues = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InterfaceAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@@ -39,6 +40,7 @@ public class LifxHome implements Home {
|
||||
private LFXClient client;
|
||||
private Boolean validLifx;
|
||||
private Gson aGsonHandler;
|
||||
private InetAddress configuredAddress;
|
||||
private boolean closed;
|
||||
|
||||
public LifxHome(BridgeSettings bridgeSettings) {
|
||||
@@ -55,47 +57,17 @@ public class LifxHome implements Home {
|
||||
validLifx = bridgeSettings.getBridgeSettingsDescriptor().isValidLifx();
|
||||
log.info("LifxDevice Home created." + (validLifx ? "" : " No LifxDevices configured."));
|
||||
if(validLifx) {
|
||||
try {
|
||||
log.info("Open Lifx client....");
|
||||
InetAddress configuredAddress = InetAddress.getByName(bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress());
|
||||
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
|
||||
InetAddress bcastInetAddr = null;
|
||||
if (networkInterface != null) {
|
||||
for (InterfaceAddress ifaceAddr : networkInterface.getInterfaceAddresses()) {
|
||||
InetAddress addr = ifaceAddr.getAddress();
|
||||
if (addr instanceof Inet4Address) {
|
||||
bcastInetAddr = ifaceAddr.getBroadcast();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bcastInetAddr != null) {
|
||||
lifxMap = new HashMap<String, LifxDevice>();
|
||||
log.info("Opening LFX Client with broadcast address: " + bcastInetAddr.getHostAddress());
|
||||
client = new LFXClient(bcastInetAddr.getHostAddress());
|
||||
client.getLights().addLightCollectionListener(new MyLightListener(lifxMap));
|
||||
client.getGroups().addGroupCollectionListener(new MyGroupListener(lifxMap));
|
||||
client.open(false);
|
||||
aGsonHandler =
|
||||
new GsonBuilder()
|
||||
.create();
|
||||
} else {
|
||||
log.warn("Could not open LIFX, no bcast addr available, check your upnp config address.");
|
||||
client = null;
|
||||
validLifx = false;
|
||||
return this;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not open LIFX, with IO Exception", e);
|
||||
client = null;
|
||||
validLifx = false;
|
||||
return this;
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Could not open LIFX, with Interruprted Exception", e);
|
||||
client = null;
|
||||
aGsonHandler =
|
||||
new GsonBuilder()
|
||||
.create();
|
||||
try {
|
||||
configuredAddress = InetAddress.getByName(bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress());
|
||||
} catch (UnknownHostException e) {
|
||||
log.warn("Could not get Inet Address for Lifx broadcast.");
|
||||
validLifx = false;
|
||||
return this;
|
||||
}
|
||||
broadcastDiscover();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -117,7 +89,7 @@ public class LifxHome implements Home {
|
||||
@Override
|
||||
public Object getItems(String type) {
|
||||
log.debug("consolidating devices for lifx");
|
||||
if(!validLifx)
|
||||
if(!validLifx || lifxMap == null)
|
||||
return null;
|
||||
LifxEntry theResponse = null;
|
||||
Iterator<String> keys = lifxMap.keySet().iterator();
|
||||
@@ -271,4 +243,47 @@ public class LifxHome implements Home {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void broadcastDiscover() {
|
||||
try {
|
||||
log.info("Open Lifx client....");
|
||||
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
|
||||
InetAddress bcastInetAddr = null;
|
||||
if (networkInterface != null) {
|
||||
for (InterfaceAddress ifaceAddr : networkInterface.getInterfaceAddresses()) {
|
||||
InetAddress addr = ifaceAddr.getAddress();
|
||||
if (addr instanceof Inet4Address) {
|
||||
bcastInetAddr = ifaceAddr.getBroadcast();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(bcastInetAddr != null) {
|
||||
lifxMap = new HashMap<String, LifxDevice>();
|
||||
log.info("Opening LFX Client with broadcast address: " + bcastInetAddr.getHostAddress());
|
||||
client = new LFXClient(bcastInetAddr.getHostAddress());
|
||||
client.getLights().addLightCollectionListener(new MyLightListener(lifxMap));
|
||||
client.getGroups().addGroupCollectionListener(new MyGroupListener(lifxMap));
|
||||
client.open(false);
|
||||
} else {
|
||||
log.warn("Could not open LIFX, no bcast addr available, check your upnp config address.");
|
||||
client = null;
|
||||
return;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not open LIFX, with IO Exception", e);
|
||||
client = null;
|
||||
return;
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("Could not open LIFX, with Interruprted Exception", e);
|
||||
client = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
if(client == null)
|
||||
broadcastDiscover();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,4 +150,9 @@ public class MQTTHome implements Home {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,5 +201,8 @@ public class OpenHABHome implements Home {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,4 +125,9 @@ public class SomfyHome implements Home {
|
||||
somfys = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,4 +173,8 @@ public class TCPHome implements Home {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,4 +115,8 @@ public class UDPHome implements Home {
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,4 +118,9 @@ public class VeraHome implements Home {
|
||||
veras = null;
|
||||
closed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public class UDPDatagramSender {
|
||||
udpResponsePort++;
|
||||
}
|
||||
}
|
||||
log.info("UDP response Seocket initialized to: " + udpResponsePort);
|
||||
log.info("UDP response Socket initialized to: " + udpResponsePort);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -959,6 +959,17 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
|
||||
);
|
||||
};
|
||||
|
||||
this.refreshDevices = function (typeIndex) {
|
||||
return $http.get(this.state.base + "/refresh/" + typeIndex).then(
|
||||
function (response) {
|
||||
self.displaySuccess("Refresh devices request complete");
|
||||
},
|
||||
function (error) {
|
||||
self.displayWarn("Refresh devices request Error: ", error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
this.formatCallItem = function (currentItem) {
|
||||
if(!currentItem.startsWith("{\"item") && !currentItem.startsWith("[{\"item")) {
|
||||
if (currentItem.startsWith("[") || currentItem.startsWith("{"))
|
||||
@@ -3518,6 +3529,11 @@ app.controller('LifxController', function ($scope, $location, bridgeService, ngD
|
||||
$scope.device = bridgeService.state.device;
|
||||
};
|
||||
|
||||
$scope.refreshDevices = function () {
|
||||
bridgeService.refreshDevices("lifxDevice");
|
||||
bridgeService.viewLifxDevices();
|
||||
};
|
||||
|
||||
$scope.buildDeviceUrls = function (lifxdevice, dim_control, buildonly) {
|
||||
dimpayload = angular.toJson(lifxdevice);
|
||||
onpayload = angular.toJson(lifxdevice);
|
||||
@@ -4074,6 +4090,11 @@ app.controller('BroadlinkController', function ($scope, $location, bridgeService
|
||||
$scope.device = bridgeService.state.device;
|
||||
};
|
||||
|
||||
$scope.refreshDevices = function () {
|
||||
bridgeService.refreshDevices("broadlinkDevice");
|
||||
bridgeService.viewBroadlinkDevices();
|
||||
};
|
||||
|
||||
$scope.buildDeviceUrls = function (broadlinkdevice, dim_control, ondata, dimdata, offdata, colordata, buildonly) {
|
||||
var preCmd = "{\"id\":\"" + broadlinkdevice.id + "\",\"name\":\"" + broadlinkdevice.name +"\",\"command\":\"";
|
||||
if(broadlinkdevice.type === 'SP1' || broadlinkdevice.type === 'SP2') {
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
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 Broadlink.</p>
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="refreshDevices()">Refresh</button>
|
||||
</p>
|
||||
<scrollable-table watch="bridge.broadlinkdevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
feature. Select your items and dim control type if wanted, then click
|
||||
bulk add below. Your items will be added with on, off and dim
|
||||
with the name of the device from the LIFX device.</p>
|
||||
<p>
|
||||
<button class="btn btn-success" type="submit"
|
||||
ng-click="refreshDevices()">Refresh</button>
|
||||
</p>
|
||||
<scrollable-table watch="bridge.lifxdevices">
|
||||
<table class="table table-bordered table-striped table-hover">
|
||||
<thead>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</div>
|
||||
</form>
|
||||
<div ng-if="failed">
|
||||
<p><font color="red">Login failed! Username or passowrd incorrect.</font></p>
|
||||
<p><font color="red">Login failed! Username or password incorrect.</font></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user