diff --git a/README.md b/README.md
index 071ae03..16c5eb6 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,32 @@
# ha-bridge
Emulates Philips Hue api to other home automation gateways such as an Amazon Echo or Google Home. The Bridge handles basic commands such as "On", "Off" and "brightness" commands of the hue protocol. This bridge can control most devices that have a distinct API.
+Here are some diagrams to put this software in perspective.
+
+The Echo Path looks like this:
+```
+ +------------------------+ +------------------------+
++-------------+ | H A +------------------| | A +------------------+ |
+| Amazon Echo |----->| U P | ha-bridge core |--->| P | Device to control| |
++-------------+ | E I +------------------| | I +------------------+ |
+ +------------------------+ +------------------------+
+```
+The Google Home Path looks like this:
+```
+ +------------------------+ +------------------------+
++-------------+ | H A +------------------| | A +------------------+ |
+| Google Home |----->| U P | ha-bridge core |--->| P | Device to control| |
++-------------+ | E I +------------------| | I +------------------+ |
+ +------------------------+ +------------------------+
+```
+THe Harmony Hub Path looks like this:
+```
+ +------------------------+ +------------------------+
++-------------+ | H A +------------------| | A +------------------+ |
+| Harmony Hub |----->| U P | ha-bridge core |--->| P | Device to control| |
++-------------+ | E I +------------------| | I +------------------+ |
+ +------------------------+ +------------------------+
+```
**SECURITY RISK: If you are unsure on how this software operates and what it exposes to your network, please make sure you understand that it can allow root access to your system. It is best practice to not open this to the Internet through your router as there are no security protocols in place to protect the system. The License agreement states specifically that you use this at your own risk.**
**ATTENTION: This requires a physical Amazon Echo, Dot or Tap and does not work with prototype devices built using the Alexa Voice Service e.g. Amazon's Alexa AVS Sample App and Sam Machin's AlexaPi. The AVS version does not have any capability for Hue Bridge discovery!**
@@ -33,23 +59,23 @@ 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.1.4.jar
+java -jar ha-bridge-4.2.1.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.1.4.jar is in your /home/pi/habridge directory.
+Create the directory and make sure that ha-bridge-4.2.1.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.1.4/ha-bridge-4.1.4.jar
+pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.1/ha-bridge-4.2.1.jar
```
-Create the directory and make sure that ha-bridge-4.1.4.jar is in your /home/pi/habridge directory.
+Create the directory and make sure that ha-bridge-4.2.1.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.1.4/ha-bridge-4.1.4.jar
+pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v4.2.1/ha-bridge-4.2.1.jar
```
#### System Control Setup on a pi (preferred)
For next gen Linux systems (this includes the Raspberry Pi), here is a systemctl unit file that you can install. Here is a link on how to do this: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
@@ -69,7 +95,7 @@ After=network.target
[Service]
Type=simple
-ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.1.4.jar
+ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-4.2.1.jar
[Install]
WantedBy=multi-user.target
@@ -104,7 +130,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.1.4.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-4.2.1.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
chmod 777 /home/pi/habridge/habridge-log.txt
```
@@ -358,7 +384,7 @@ Headers can be added as well using a Json construct [{"name":"header type name",
Another option that is detected by the bridge is to use UDP or TCP direct calls such as `udp://:/` to send a UDP request. TCP calls are handled the same way as `tcp://:/`. If your data for the UDP or TCP request is formatted as "0x00F009B9" lexical hex format, the bridge will convert the data into a binary stream to send.
-You can also use the value replacement constructs within these statements. Such as using the expressions "${time.format(Java time format string)}" for inserting a date/time stamp, ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value or items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}". See Value Passing Controls Below.
+You can also use the value replacement constructs within these statements. Such as using the expressions "${time.format(Java time format string)}" for inserting a date/time stamp, ${intensity.percent} for 0-100 or ${intensity.decimal_percent} for 0.00-1.00 or ${intensity.byte} for 0-255 for straight pass through of the value or items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}". See Value Passing Controls Below.
Examples:
```
@@ -412,7 +438,7 @@ OR
```
#### Value Passing Controls
-There are multiple replacement constructs available to be put into any of the calls except Harmony items, Net Items and HAL items. These constructs are: "${time.format(Java time format string)}", "${intensity.percent}", "${intensity.byte}" and "${intensity.math(using X in your calc)}".
+There are multiple replacement constructs available to be put into any of the calls except Harmony items, Net Items and HAL items. These constructs are: "${time.format(Java time format string)}", "${intensity.percent}", "${intensity.decimal_percent}", "${intensity.byte}" and "${intensity.math(using X in your calc)}".
You can control items that require special calculated values using ${intensity.math()} i.e. "${intensity.math(X/4)}".
For the items that want to have a date time put into the message, utilize ${time.format(yyyy-MM-ddTHH:mm:ssXXX)} where "yyyy-MM-ddTHH:mm:ssXXX" can be any format from the Java SimpleDateFormat documented here: https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html
e.g.
@@ -522,7 +548,7 @@ contentBodyOff | string | This is the content body that you would like to send w
}
```
#### Dimming Control Example
-Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.byte} for 0-255 for straight pass through of the value.
+Dimming is also supported by using the expressions ${intensity.percent} for 0-100 or ${intensity.decimal_percent} for 0.00-1.00 or ${intensity.byte} for 0-255 for straight pass through of the value.
e.g.
```
{
diff --git a/kodivolume.md b/kodivolume.md
deleted file mode 100644
index 165278d..0000000
--- a/kodivolume.md
+++ /dev/null
@@ -1,144 +0,0 @@
-# Kodi volume control using dim commands & JSON-RPC
-
-You can use HA Bridge to adjust the Kodi software volume output. This allows you to use dim commands and set the volume level with percentage values.
-
-### What is JSON-RPC?
-
-The short answer is JSON-RPC an interface to communicate with Kodi. [See the official Kodi Wiki for more info](http://kodi.wiki/view/JSON-RPC_API)
-
-### Setup Kodi to allow control through JSON-RPC
-
-In Kodi navigate to Settings/Services/Control ([screenshot](http://kodi.wiki/view/Settings/Services/Control))
-
-Turn **ON** the following:
-- Allow control of Kodi via HTTP
-- Allow remote control from applications on this system
-- Allow remote control from applications on other systems
-
-Change the **username** to something unique and set a strong **password**.
-
-Make a note of the **PORT**
-### Adding the device to HA Bridge
-
-Access the HA Bridge Configuration in your browser and open the **Manual Add** tab.
-#### Name
-
-Give the device a unique name that doesn’t include **“volume”** as it will cause conflicts with the Echo’s built in volume controls. A device name of **“cody sound”** works well.
-#### Device type
-
-Select **TCP** in the dropdown
-### URLs
-
-This section might seem a little long winded and if you know what you are doing then feel free to jump ahead.
-#### Building the URL
-
-We need to log into the Kodi web server without having to fill in the popup each time. You can do this by putting the username and password in the URL. It is not a good idea to do this on other websites as it does put your password in clear view, but for your local network it is fine.
-
-Use the example below replacing the relevant sections with the details that you defined in the Kodi settings screen in the first step. Replacing the IP with the address of the machine that Kodi is running on.
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc
-```
-##### Testing the URL in a browser
-
-Before you continue, open your custom URL in a browser (making sure Kodi is running). If all is working as it should you will see a big page of JSON that starts with:
-
-``` json
-{
- "description": "JSON-RPC API of XBMC",
- "id": "http://xbmc.org/jsonrpc/ServiceDescription.json",
-```
-
-If you don’t see something that looks like the code above, then go back and double check your settings.
-#### The JSON request
-
-The URL is what connects you to Kodi, JSON is what is used to communicate with it. The JSON that is used to set the volume level is:
-
-``` json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-##### Joining the URL and JSON
-
-Join the two together by adding `?request=` to the end of the URL and then add the JSON to the end of the request. You will end up with something like:
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-### Testing the request in a browser
-
-Go ahead and test the combined URL/JSON in a browser changing **100** to whatever level you want to set. Kodi should adjust the volume accordingly, try a few different levels to be sure it is working correctly.
-
-The browser will reformat the URL each time you press return so don’t build the URL in the browser bar without making a copy first.
-
-Ideally build the URL in a text document which you can easily edit and then copy/paste each time.
-
-### Prepare the three URLs
-
-You want to end up with three full URLs in your text file, one for each of the commands.
-
-**ON**
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-
-**DIM**
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":45},"id":1}
-```
-
-**OFF**
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request={"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":0},"id":1}
-```
-
-### Test the three URLS
-
-You should now be able to control the volume of Kodi using the structured URL you built above in a browser.
-
-If you can’t get it to work in a browser then you won’t be able to get it to work in HA Bridge.
-
-
-### Manually adding the device
-
-Add a new manual device and give it a name e.g. “Cody Sound”
-
-Set `Device type` to `Custom`
-
-Use the same URL for all three (ON, OFF, DIM)
-
-```
-http://KODI_USERNAME:KODI_PASSWORD@192.168.1.123:8080/jsonrpc?request=
-```
-
-* `HTTP Verb` to `POST`
-* `Content type` to `application/json`
-
-**Content body On**
-```json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":100},"id":1}
-```
-**Content body Dim**
-```json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":${intensity.percent}},"id":1}
-```
-**Content body Off**
-```json
-{"jsonrpc":"2.0","method":"Application.SetVolume","params":{"volume":0},"id":1}
-```
-
-
-### HA Bridge
-
-Save and test the button in the Bridge Devices tab and hopefully it should turn the volume up in Kodi.
-
-### Controlling the Device
-
-You can use the commands as listed in the [README](https://github.com/bwssytems/ha-bridge#ask-alexa)
-
-“Set Cody Sound to 50 percent”
-“Cody Sound to 70 percent”
-
-Remembering that “Turn on Cody Sound” will set the volume to 100%, and “Turn off Cody Sound” will mute.
diff --git a/pom.xml b/pom.xml
index 07c2ae6..638a919 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bwssystems.HABridge
ha-bridge
- 4.1.4
+ 4.2.1
jar
HA Bridge
@@ -48,7 +48,7 @@
com.github.bwssytems
nest-controller
- 1.0.13
+ 1.0.14
org.slf4j
@@ -121,6 +121,16 @@
junit
4.11
+
+ com.github.bwssytems
+ lifx-sdk-java
+ 2.1.6
+
+
+ org.apache.commons
+ commons-lang3
+ 3.5
+
diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java
index d27f88c..9631a2d 100644
--- a/src/main/java/com/bwssystems/HABridge/BridgeSettings.java
+++ b/src/main/java/com/bwssystems/HABridge/BridgeSettings.java
@@ -167,6 +167,7 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setHassconfigured(theBridgeSettings.isValidHass());
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
theBridgeSettings.setSomfyconfigured(theBridgeSettings.isValidSomfy());
+ // Lifx is either configured or not, so it does not need an update.
if(serverPortOverride != null)
theBridgeSettings.setServerPort(serverPortOverride);
if(serverIpOverride != null)
diff --git a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java
index 58032ff..567c2b3 100644
--- a/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java
+++ b/src/main/java/com/bwssystems/HABridge/BridgeSettingsDescriptor.java
@@ -43,6 +43,8 @@ public class BridgeSettingsDescriptor {
private IpList somfyaddress;
private boolean somfyconfigured;
+ private boolean lifxconfigured;
+
public BridgeSettingsDescriptor() {
super();
this.upnpstrict = true;
@@ -278,6 +280,12 @@ public class BridgeSettingsDescriptor {
public void setDomoticzconfigured(boolean domoticzconfigured) {
this.domoticzconfigured = domoticzconfigured;
}
+ public boolean isLifxconfigured() {
+ return lifxconfigured;
+ }
+ public void setLifxconfigured(boolean lifxconfigured) {
+ this.lifxconfigured = lifxconfigured;
+ }
public Boolean isValidVera() {
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
return false;
@@ -351,4 +359,7 @@ public class BridgeSettingsDescriptor {
return false;
return true;
}
+ public Boolean isValidLifx() {
+ return this.isLifxconfigured();
+ }
}
diff --git a/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java b/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java
index c25946a..56a06a4 100644
--- a/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java
+++ b/src/main/java/com/bwssystems/HABridge/DeviceMapTypes.java
@@ -27,6 +27,7 @@ public class DeviceMapTypes {
public final static String[] HTTP_DEVICE = { "httpDevice", "HTTP Device"};
public final static String[] DOMOTICZ_DEVICE = { "domoticzDevice", "Domoticz Device"};
public final static String[] SOMFY_DEVICE = { "somfyDevice", "Somfy Device"};
+ public final static String[] LIFX_DEVICE = { "lifxDevice", "LIFX Device"};
public final static int typeIndex = 0;
public final static int displayIndex = 1;
@@ -47,6 +48,7 @@ public class DeviceMapTypes {
deviceMapTypes.add(HASS_DEVICE);
deviceMapTypes.add(HTTP_DEVICE);
deviceMapTypes.add(HUE_DEVICE);
+ deviceMapTypes.add(LIFX_DEVICE);
deviceMapTypes.add(MQTT_MESSAGE);
deviceMapTypes.add(NEST_HOMEAWAY);
deviceMapTypes.add(NEST_THERMO_SET);
diff --git a/src/main/java/com/bwssystems/HABridge/HomeManager.java b/src/main/java/com/bwssystems/HABridge/HomeManager.java
index 80b29cb..099a807 100644
--- a/src/main/java/com/bwssystems/HABridge/HomeManager.java
+++ b/src/main/java/com/bwssystems/HABridge/HomeManager.java
@@ -13,6 +13,7 @@ import com.bwssystems.HABridge.plugins.harmony.HarmonyHome;
import com.bwssystems.HABridge.plugins.hass.HassHome;
import com.bwssystems.HABridge.plugins.http.HTTPHome;
import com.bwssystems.HABridge.plugins.hue.HueHome;
+import com.bwssystems.HABridge.plugins.lifx.LifxHome;
import com.bwssystems.HABridge.plugins.mqtt.MQTTHome;
import com.bwssystems.HABridge.plugins.somfy.SomfyHome;
import com.bwssystems.HABridge.plugins.tcp.TCPHome;
@@ -72,7 +73,6 @@ 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.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the tcp handler Home
aHome = new TCPHome(bridgeSettings);
homeList.put(DeviceMapTypes.TCP_DEVICE[DeviceMapTypes.typeIndex], aHome);
@@ -81,17 +81,22 @@ public class HomeManager {
aHome = new UDPHome(bridgeSettings, aUdpDatagramSender);
homeList.put(DeviceMapTypes.UDP_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.UDP_DEVICE_COMPAT[DeviceMapTypes.typeIndex], aHome);
-
+ // Setup Vera Home if available
aHome = new VeraHome(bridgeSettings);
resourceList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
resourceList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
- //setup the HomeAssistant configuration if available
+ //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);
//setup the Somfy configuration if available
aHome = new SomfyHome(bridgeSettings);
homeList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
resourceList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
+ //setup the Lifx configuration if available
+ aHome = new LifxHome(bridgeSettings);
+ resourceList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
+ homeList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
}
public Home findHome(String type) {
diff --git a/src/main/java/com/bwssystems/HABridge/NamedIP.java b/src/main/java/com/bwssystems/HABridge/NamedIP.java
index 145f798..b7162a2 100644
--- a/src/main/java/com/bwssystems/HABridge/NamedIP.java
+++ b/src/main/java/com/bwssystems/HABridge/NamedIP.java
@@ -2,7 +2,8 @@ package com.bwssystems.HABridge;
public class NamedIP {
private String name;
- private String ip;
+ private String ip;
+ private String webhook;
private String port;
private String username;
private String password;
@@ -20,7 +21,13 @@ public class NamedIP {
public void setIp(String ip) {
this.ip = ip;
}
- public String getPort() {
+ public String getWebhook() {
+ return webhook;
+ }
+ public void setWebhook(final String webhook) {
+ this.webhook = webhook;
+ }
+ public String getPort() {
return port;
}
public void setPort(String port) {
diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java
index a727c26..547b04e 100644
--- a/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java
+++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceDescriptor.java
@@ -62,6 +62,9 @@ public class DeviceDescriptor{
@SerializedName("noState")
@Expose
private boolean noState;
+ @SerializedName("requesterAddress")
+ @Expose
+ private String requesterAddress;
private DeviceState deviceState;
@@ -219,6 +222,14 @@ public class DeviceDescriptor{
this.noState = noState;
}
+ public String getRequesterAddress() {
+ return requesterAddress;
+ }
+
+ public void setRequesterAddress(String requesterAddress) {
+ this.requesterAddress = requesterAddress;
+ }
+
public boolean containsType(String aType) {
if(aType == null)
return false;
diff --git a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java
index a06a8d8..cf44ecb 100644
--- a/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java
+++ b/src/main/java/com/bwssystems/HABridge/dao/DeviceRepository.java
@@ -83,6 +83,33 @@ public class DeviceRepository extends BackupHandler {
return list;
}
+ public List findAllByRequester(String anAddress) {
+ List list = new ArrayList(devices.values());
+ List theReturnList = new ArrayList();
+ Iterator anIterator = list.iterator();
+ DeviceDescriptor theDevice;
+ String theRequesterAddress;
+
+ HashMap addressMap;
+ while (anIterator.hasNext()) {
+ theDevice = anIterator.next();
+ theRequesterAddress = theDevice.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(theDevice);
+ }
+ return theReturnList;
+ }
+
public DeviceDescriptor findOne(String id) {
return devices.get(id);
}
diff --git a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java
index 43f7835..8a93bc8 100644
--- a/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java
+++ b/src/main/java/com/bwssystems/HABridge/devicemanagmeent/DeviceResource.java
@@ -18,12 +18,15 @@ import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.HomeManager;
+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.ErrorMessage;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonSyntaxException;
/**
spark core server for bridge configuration
@@ -33,11 +36,13 @@ public class DeviceResource {
private static final Logger log = LoggerFactory.getLogger(DeviceResource.class);
private DeviceRepository deviceRepository;
private HomeManager homeManager;
+ private Gson aGsonHandler;
private static final Set supportedVerbs = new HashSet<>(Arrays.asList("get", "put", "post"));
public DeviceResource(BridgeSettingsDescriptor theSettings, HomeManager aHomeManager) {
this.deviceRepository = new DeviceRepository(theSettings.getUpnpDeviceDb());
homeManager = aHomeManager;
+ aGsonHandler = new GsonBuilder().create();
setupEndpoints();
}
@@ -65,14 +70,44 @@ public class DeviceResource {
else {
devices = new Gson().fromJson("[" + request.body() + "]", DeviceDescriptor[].class);
}
+ CallItem[] callItems = null;
+ String errorMessage = null;
for(int i = 0; i < devices.length; i++) {
if(devices[i].getContentBody() != null ) {
if (devices[i].getContentType() == null || devices[i].getHttpVerb() == null || !supportedVerbs.contains(devices[i].getHttpVerb().toLowerCase())) {
response.status(HttpStatus.SC_BAD_REQUEST);
- log.debug("Bad http verb in create a Device(s): " + request.body());
- return new ErrorMessage("Bad http verb in create a Device(s): " + request.body() + " ");
+ errorMessage = "Bad http verb in create device(s) for name: " + devices[i].getName() + " with verb: " + devices[i].getHttpVerb();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
}
}
+ try {
+ if(devices[i].getOnUrl() != null && !devices[i].getOnUrl().isEmpty())
+ callItems = aGsonHandler.fromJson(devices[i].getOnUrl(), CallItem[].class);
+ } catch(JsonSyntaxException e) {
+ response.status(HttpStatus.SC_BAD_REQUEST);
+ errorMessage = "Bad on URL JSON in create device(s) for name: " + devices[i].getName() + " with on URL: " + devices[i].getOnUrl();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
+ }
+ try {
+ if(devices[i].getDimUrl() != null && !devices[i].getDimUrl().isEmpty())
+ callItems = aGsonHandler.fromJson(devices[i].getDimUrl(), CallItem[].class);
+ } catch(JsonSyntaxException e) {
+ response.status(HttpStatus.SC_BAD_REQUEST);
+ errorMessage = "Bad dim URL JSON in create device(s) for name: " + devices[i].getName() + " with dim URL: " + devices[i].getDimUrl();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
+ }
+ try {
+ if(devices[i].getOffUrl() != null && !devices[i].getOffUrl().isEmpty())
+ callItems = aGsonHandler.fromJson(devices[i].getOffUrl(), CallItem[].class);
+ } catch(JsonSyntaxException e) {
+ response.status(HttpStatus.SC_BAD_REQUEST);
+ errorMessage = "Bad off URL JSON in create device(s) for name: " + devices[i].getName() + " with off URL: " + devices[i].getOffUrl();
+ log.debug(errorMessage);
+ return new ErrorMessage(errorMessage);
+ }
}
deviceRepository.save(devices);
@@ -219,6 +254,12 @@ public class DeviceResource {
return homeManager.findResource(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.DOMOTICZ_DEVICE[DeviceMapTypes.typeIndex]);
}, new JsonTransformer());
+ get (API_CONTEXT + "/lifx/devices", "application/json", (request, response) -> {
+ log.debug("Get LIFX devices");
+ response.status(HttpStatus.SC_OK);
+ return homeManager.findResource(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex]);
+ }, new JsonTransformer());
+
get (API_CONTEXT + "/somfy/devices", "application/json", (request, response) -> {
log.debug("Get somfy devices");
response.status(HttpStatus.SC_OK);
diff --git a/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java b/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
index 55da9dd..ff6c186 100644
--- a/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
+++ b/src/main/java/com/bwssystems/HABridge/hue/BrightnessDecode.java
@@ -1,20 +1,18 @@
package com.bwssystems.HABridge.hue;
import java.math.BigDecimal;
-import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
-import javax.xml.bind.DatatypeConverter;
-
+import org.apache.commons.lang3.Conversion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import net.java.dev.eval.Expression;
public class BrightnessDecode {
private static final Logger log = LoggerFactory.getLogger(BrightnessDecode.class);
private static final String INTENSITY_PERCENT = "${intensity.percent}";
+ private static final String INTENSITY_DECIMAL_PERCENT = "${intensity.decimal_percent}";
private static final String INTENSITY_BYTE = "${intensity.byte}";
private static final String INTENSITY_MATH = "${intensity.math(";
private static final String INTENSITY_MATH_VALUE = "X";
@@ -49,9 +47,7 @@ public class BrightnessDecode {
}
if (request.contains(INTENSITY_BYTE)) {
if (isHex) {
- BigInteger bigInt = BigInteger.valueOf(intensity);
- byte[] theBytes = bigInt.toByteArray();
- String hexValue = DatatypeConverter.printHexBinary(theBytes);
+ String hexValue = convertToHex(intensity);
request = request.replace(INTENSITY_BYTE, hexValue);
} else {
String intensityByte = String.valueOf(intensity);
@@ -60,14 +56,17 @@ public class BrightnessDecode {
} else if (request.contains(INTENSITY_PERCENT)) {
int percentBrightness = (int) Math.round(intensity / 255.0 * 100);
if (isHex) {
- BigInteger bigInt = BigInteger.valueOf(percentBrightness);
- byte[] theBytes = bigInt.toByteArray();
- String hexValue = DatatypeConverter.printHexBinary(theBytes);
+ String hexValue = convertToHex(percentBrightness);
request = request.replace(INTENSITY_PERCENT, hexValue);
} else {
String intensityPercent = String.valueOf(percentBrightness);
request = request.replace(INTENSITY_PERCENT, intensityPercent);
}
+ } else if (request.contains(INTENSITY_DECIMAL_PERCENT)) {
+ float decimalBrightness = (float) (intensity / 255.0);
+
+ String intensityPercent = String.format("%1.2f", decimalBrightness);
+ request = request.replace(INTENSITY_DECIMAL_PERCENT, intensityPercent);
} else if (request.contains(INTENSITY_MATH)) {
Map variables = new HashMap();
String mathDescriptor = request.substring(request.indexOf(INTENSITY_MATH) + INTENSITY_MATH.length(),
@@ -81,9 +80,7 @@ public class BrightnessDecode {
BigDecimal result = exp.eval(variables);
Integer endResult = Math.round(result.floatValue());
if (isHex) {
- BigInteger bigInt = BigInteger.valueOf(endResult);
- byte[] theBytes = bigInt.toByteArray();
- String hexValue = DatatypeConverter.printHexBinary(theBytes);
+ String hexValue = convertToHex(endResult);
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE, hexValue);
} else {
request = request.replace(INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE,
@@ -100,4 +97,15 @@ public class BrightnessDecode {
public static String calculateReplaceIntensityValue(String request, int theIntensity, Integer targetBri, Integer targetBriInc, boolean isHex) {
return replaceIntensityValue(request, calculateIntensity(theIntensity, targetBri, targetBriInc), isHex);
}
-}
+
+ // Apache Commons Conversion utils likes little endian too much
+ private static String convertToHex(int theValue) {
+ String destHex = "00";
+ String hexValue = Conversion.intToHex(theValue, 0, destHex, 0, 2);
+ byte[] theBytes = hexValue.getBytes();
+ byte[] newBytes = new byte[2];
+ newBytes[0] = theBytes[1];
+ newBytes[1] = theBytes[0];
+ return new String(newBytes);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java
index 67b3db5..dca0dfe 100644
--- a/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java
+++ b/src/main/java/com/bwssystems/HABridge/hue/HueMulator.java
@@ -16,7 +16,6 @@ import com.bwssystems.HABridge.api.hue.HuePublicConfig;
import com.bwssystems.HABridge.api.hue.StateChangeBody;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
import com.bwssystems.HABridge.dao.*;
-import com.bwssystems.HABridge.plugins.hue.HueDeviceIdentifier;
import com.bwssystems.HABridge.plugins.hue.HueHome;
import com.bwssystems.HABridge.util.JsonTransformer;
import com.google.gson.Gson;
@@ -669,7 +668,8 @@ public class HueMulator {
log.debug("hue lights list requested: " + userId + " from " + requestIp);
theErrors = validateWhitelistUser(userId, false);
if (theErrors == null) {
- List deviceList = repository.findActive();
+ List deviceList = repository.findAllByRequester(requestIp);
+// List deviceList = repository.findActive();
deviceResponseMap = new HashMap();
for (DeviceDescriptor device : deviceList) {
DeviceResponse deviceResponse = null;
@@ -945,8 +945,8 @@ public class HueMulator {
}
for (int i = 0; callItems != null && i < callItems.length; i++) {
- if(!filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
- log.debug("filter for requester address not present in list: " + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
+ 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)
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java
index 379c7b7..56ada5a 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHandler.java
@@ -3,11 +3,12 @@ package com.bwssystems.HABridge.plugins.domoticz;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-
+import java.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.NamedIP;
+import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.google.gson.Gson;
@@ -16,32 +17,33 @@ public class DomoticzHandler {
private static final String GET_REQUEST = "/json.htm?type=";
private static final String DEVICES_TYPE = "devices";
private static final String SCENES_TYPE = "scenes";
- private static final String FILTER_USED = "&used=";
- private HTTPHandler httpClient;
+ private static final String FILTER_USED = "&used=true";
private NamedIP domoticzAddress;
public DomoticzHandler(NamedIP addressName) {
super();
- httpClient = new HTTPHandler();
domoticzAddress = addressName;
}
- public List getDevices() {
- return getDomoticzDevices(GET_REQUEST, DEVICES_TYPE, FILTER_USED);
+ public List getDevices(HTTPHandler httpClient) {
+ return getDomoticzDevices(GET_REQUEST, DEVICES_TYPE, FILTER_USED, httpClient);
}
- public List getScenes() {
- return getDomoticzDevices(GET_REQUEST, SCENES_TYPE, null);
+ public List getScenes(HTTPHandler httpClient) {
+ return getDomoticzDevices(GET_REQUEST, SCENES_TYPE, null, httpClient);
}
- private List getDomoticzDevices(String rootRequest, String type, String postpend) {
+ private List getDomoticzDevices(String rootRequest, String type, String postpend, HTTPHandler httpClient) {
Devices theDomoticzApiResponse = null;
List deviceList = null;
String theUrl = null;
String theData;
- theUrl = "http://" + domoticzAddress.getIp() + ":" + domoticzAddress.getPort() + rootRequest + type;
- theData = httpClient.doHttpRequest(theUrl, null, null, null, null);
+ if(postpend != null && !postpend.isEmpty())
+ theUrl = buildUrl(rootRequest + type + postpend);
+ else
+ theUrl = buildUrl(rootRequest + type);
+ theData = httpClient.doHttpRequest(theUrl, null, null, null, buildHeaders());
if(theData != null) {
log.debug("GET " + type + " DomoticzApiResponse - data: " + theData);
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
@@ -70,6 +72,44 @@ public class DomoticzHandler {
return deviceList;
}
+ public String buildUrl(String thePayload) {
+ String newUrl = null;
+
+ if(thePayload != null && !thePayload.isEmpty()) {
+ if(domoticzAddress.getSecure() != null && domoticzAddress.getSecure())
+ newUrl = "https://";
+ else
+ newUrl = "http://";
+
+ newUrl = newUrl + domoticzAddress.getIp();
+
+ if(domoticzAddress.getPort() != null && !domoticzAddress.getPort().isEmpty())
+ newUrl = newUrl + ":" + domoticzAddress.getPort();
+
+ if(thePayload.startsWith("/"))
+ newUrl = newUrl + thePayload;
+ else
+ newUrl = newUrl + "/" + thePayload;
+ }
+
+ return newUrl;
+ }
+
+ public NameValue[] buildHeaders() {
+ NameValue[] headers = null;
+
+ if(domoticzAddress.getUsername() != null && !domoticzAddress.getUsername().isEmpty()
+ && domoticzAddress.getPassword() != null && !domoticzAddress.getPassword().isEmpty()) {
+ NameValue theAuth = new NameValue();
+ theAuth.setName("Authorization");
+ String encoding = Base64.getEncoder().encodeToString((domoticzAddress.getUsername() + ":" + domoticzAddress.getPassword()).getBytes());
+ theAuth.setValue("Basic " + encoding);
+ headers = new NameValue[1];
+ headers[0] = theAuth;
+ }
+
+ return headers;
+ }
public NamedIP getDomoticzAddress() {
return domoticzAddress;
}
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 ebc5af8..45f66a7 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/domoticz/DomoticzHome.java
@@ -13,13 +13,19 @@ import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
+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.MultiCommandUtil;
+import com.bwssystems.HABridge.plugins.http.HTTPHandler;
+import com.google.gson.Gson;
public class DomoticzHome implements Home {
private static final Logger log = LoggerFactory.getLogger(DomoticzHome.class);
private Map domoticzs;
private Boolean validDomoticz;
+ private HTTPHandler httpClient;
public DomoticzHome(BridgeSettingsDescriptor bridgeSettings) {
super();
@@ -36,14 +42,14 @@ public class DomoticzHome implements Home {
List deviceList = new ArrayList();
while(keys.hasNext()) {
String key = keys.next();
- theResponse = domoticzs.get(key).getDevices();
+ theResponse = domoticzs.get(key).getDevices(httpClient);
if(theResponse != null)
addDomoticzDevices(deviceList, theResponse, key);
else {
log.warn("Cannot get lights for Domoticz with name: " + key + ", skipping this Domoticz.");
continue;
}
- theResponse = domoticzs.get(key).getScenes();
+ theResponse = domoticzs.get(key).getScenes(httpClient);
if(theResponse != null)
addDomoticzDevices(deviceList, theResponse, key);
else
@@ -66,8 +72,54 @@ 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) {
- // Not a device handler
- return null;
+ Devices theDomoticzApiResponse = null;
+ String responseString = null;
+
+ String theUrl = anItem.getItem().getAsString();
+ if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
+ String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
+ String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
+ String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
+ String hostAddr = null;
+ if (hostPortion.contains(":")) {
+ hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
+ } else
+ hostAddr = hostPortion;
+ DomoticzHandler theHandler = findHandlerByAddress(hostAddr);
+ if(theHandler != null){
+ String theData;
+ String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
+ intensity, targetBri, targetBriInc, false);
+ theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, null, theHandler.buildHeaders());
+ try {
+ theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
+ if(theDomoticzApiResponse.getStatus().equals("OK"))
+ responseString = null;
+ else {
+ log.warn("Call failed for Domoticz " + theHandler.getDomoticzAddress().getName() + " with status " + theDomoticzApiResponse.getStatus() + " for item " + theDomoticzApiResponse.getTitle());
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
+ } catch (Exception e) {
+ log.warn("Cannot interrpret result from call for Domoticz " + theHandler.getDomoticzAddress().getName() + " as response is not parsable.");
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
+ } else {
+ log.warn("Domoticz Call could not complete, no address found: " + theUrl);
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
+ } else {
+ log.warn("Domoticz Call to be presented as http(s)://(:)/payload, format of request unknown: " + theUrl);
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
+ return responseString;
}
@Override
@@ -76,6 +128,7 @@ public class DomoticzHome implements Home {
log.info("Domoticz Home created." + (validDomoticz ? "" : " No Domoticz devices configured."));
if(!validDomoticz)
return null;
+ httpClient = new HTTPHandler();
domoticzs = new HashMap();
Iterator theList = bridgeSettings.getDomoticzaddress().getDevices().iterator();
while(theList.hasNext()) {
@@ -90,9 +143,26 @@ public class DomoticzHome implements Home {
return this;
}
+ private DomoticzHandler findHandlerByAddress(String hostAddress) {
+ DomoticzHandler aHandler = null;
+ boolean found = false;
+ Iterator keys = domoticzs.keySet().iterator();
+ while(keys.hasNext()) {
+ String key = keys.next();
+ aHandler = domoticzs.get(key);
+ if(aHandler != null && aHandler.getDomoticzAddress().getIp().equals(hostAddress)) {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ aHandler = null;
+ return aHandler;
+ }
@Override
public void closeHome() {
- // noop
+ if(httpClient != null)
+ httpClient.closeHandler();
}
}
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 4788359..521f7ed 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/harmony/HarmonyServer.java
@@ -4,6 +4,8 @@ import static java.lang.String.format;
import javax.inject.Inject;
+import com.bwssystems.HABridge.plugins.http.HTTPHandler;
+import org.apache.http.client.methods.HttpGet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -18,69 +20,98 @@ import net.whistlingfish.harmony.HarmonyClientModule;
import net.whistlingfish.harmony.config.Activity;
import net.whistlingfish.harmony.protocol.OAReplyProvider;
+import java.net.URLEncoder;
+
public class HarmonyServer {
+
+ private static final String ACTIVIY_ID = "${activity.id}";
+ private static final String ACTIVIY_LABEL = "${activity.label}";
+
@Inject
private HarmonyClient harmonyClient;
-
+
private HarmonyHandler myHarmony;
private DevModeResponse devResponse;
private OAReplyProvider dummyProvider;
private NamedIP myNameAndIP;
private Boolean isDevMode;
+ private HTTPHandler httpClient;
private Logger log = LoggerFactory.getLogger(HarmonyServer.class);
- public HarmonyServer(NamedIP theHarmonyAddress) {
- super();
- myHarmony = null;
- dummyProvider = null;
- myNameAndIP = theHarmonyAddress;
- isDevMode = false;
- }
+ public HarmonyServer(NamedIP theHarmonyAddress) {
+ super();
+ myHarmony = null;
+ dummyProvider = null;
+ myNameAndIP = theHarmonyAddress;
+ isDevMode = false;
+ httpClient = new HTTPHandler();
+ }
- public static HarmonyServer setup(BridgeSettingsDescriptor bridgeSettings, Boolean harmonyDevMode, NamedIP theHarmonyAddress) throws Exception {
- if(!bridgeSettings.isValidHarmony() && harmonyDevMode) {
- return new HarmonyServer(theHarmonyAddress);
- }
- Injector injector = null;
- if(!harmonyDevMode)
- injector = Guice.createInjector(new HarmonyClientModule());
- HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
- if(!harmonyDevMode)
- injector.injectMembers(mainObject);
- mainObject.execute(bridgeSettings, harmonyDevMode);
- return mainObject;
- }
-
- private void execute(BridgeSettingsDescriptor mySettings, Boolean harmonyDevMode) throws Exception {
- Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
- isDevMode = harmonyDevMode;
- String modeString = "";
- if(dummyProvider != null)
- log.debug("something is very wrong as dummyProvider is not null...");
- if(isDevMode)
- modeString = " (development mode)";
- else if(noopCalls)
- modeString = " (no op calls to harmony)";
- log.info("setup initiated " + modeString + "....");
- if(isDevMode)
- {
- harmonyClient = null;
- devResponse = new DevModeResponse();
+ public static HarmonyServer setup(
+ BridgeSettingsDescriptor bridgeSettings,
+ Boolean harmonyDevMode,
+ NamedIP theHarmonyAddress
+ ) throws Exception {
+ if (!bridgeSettings.isValidHarmony() && harmonyDevMode) {
+ return new HarmonyServer(theHarmonyAddress);
}
- else {
- devResponse = null;
- harmonyClient.addListener(new ActivityChangeListener() {
- @Override
- public void activityStarted(Activity activity) {
- log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
- }
- });
- harmonyClient.connect(myNameAndIP.getIp());
+ Injector injector = null;
+ if (!harmonyDevMode) {
+ injector = Guice.createInjector(new HarmonyClientModule());
+ }
+ HarmonyServer mainObject = new HarmonyServer(theHarmonyAddress);
+ if (!harmonyDevMode) {
+ injector.injectMembers(mainObject);
+ }
+ mainObject.execute(bridgeSettings, harmonyDevMode);
+ return mainObject;
+ }
+
+ private void execute(BridgeSettingsDescriptor mySettings, Boolean harmonyDevMode) throws Exception {
+ Boolean noopCalls = Boolean.parseBoolean(System.getProperty("noop.calls", "false"));
+ isDevMode = harmonyDevMode;
+ String modeString = "";
+ if (dummyProvider != null) {
+ log.debug("something is very wrong as dummyProvider is not null...");
+ }
+ if (isDevMode) {
+ modeString = " (development mode)";
+ } else if (noopCalls) {
+ modeString = " (no op calls to harmony)";
+ }
+ log.info("setup initiated " + modeString + "....");
+ if (isDevMode) {
+ harmonyClient = null;
+ devResponse = new DevModeResponse();
+ } else {
+ devResponse = null;
+ harmonyClient.addListener(new ActivityChangeListener() {
+ @Override
+ public void activityStarted(Activity activity) {
+ String webhook = myNameAndIP.getWebhook();
+ if(webhook != null) {
+ try {
+ // Replacing variables
+ webhook = webhook.replace(ACTIVIY_ID, activity.getId().toString());
+ webhook = webhook.replace(ACTIVIY_LABEL, URLEncoder.encode(activity.getLabel(), "UTF-8"));
+
+ log.info(format("calling webhook: %s", webhook));
+
+ // Calling webhook
+ httpClient.doHttpRequest(webhook, HttpGet.METHOD_NAME, null, null, null);
+ } catch (Exception e) {
+ log.warn("could not call webhook: " + webhook, e);
+ }
+ }
+ log.info(format("activity changed: [%d] %s", activity.getId(), activity.getLabel()));
+ }
+ });
+ harmonyClient.connect(myNameAndIP.getIp());
}
myHarmony = new HarmonyHandler(harmonyClient, noopCalls, devResponse);
- }
+ }
- public HarmonyHandler getMyHarmony() {
- return myHarmony;
- }
+ public HarmonyHandler getMyHarmony() {
+ return myHarmony;
+ }
}
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 9f6a702..dcf4b54 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/hass/HomeAssistant.java
@@ -41,7 +41,12 @@ public class HomeAssistant {
aUrl = "https";
else
aUrl = "http";
- aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/" + aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
+ String domain = aCommand.getEntityId().substring(0, aCommand.getEntityId().indexOf("."));
+ aUrl = aUrl + "://" + hassAddress.getIp() + ":" + hassAddress.getPort() + "/api/services/";
+ if(domain.equals("group"))
+ aUrl = aUrl + "homeassistant";
+ else
+ aUrl = aUrl + domain;
String aBody = "{\"entity_id\":\"" + aCommand.getEntityId() + "\"";
NameValue[] headers = null;
if(hassAddress.getPassword() != null && !hassAddress.getPassword().isEmpty()) {
@@ -62,6 +67,7 @@ public class HomeAssistant {
aUrl = aUrl + "/turn_off";
aBody = aBody + "}";
}
+ log.debug("Calling HomeAssistant with url: " + aUrl);
String theData = anHttpHandler.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "application/json", aBody, headers);
log.debug("call Command return is: <" + theData + ">");
return 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 6cab6e0..7c6ef96 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHandler.java
@@ -4,27 +4,18 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
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;
import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
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.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,23 +24,13 @@ import com.bwssystems.HABridge.api.NameValue;
public class HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
- private HttpClient httpClient;
-// private CloseableHttpClient httpclientSSL;
-// private SSLContext sslcontext;
-// private SSLConnectionSocketFactory sslsf;
-// private RequestConfig globalConfig;
+ private CloseableHttpClient httpClient;
+ private RequestConfig globalConfig;
public HTTPHandler() {
- httpClient = HttpClients.createDefault();
- // Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
- // Trust own CA and all self-signed certs
-// sslcontext = SSLContexts.createDefault();
- // Allow TLSv1 protocol only
-// sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLS" }, null,
-// SSLConnectionSocketFactory.getDefaultHostnameVerifier());
-// globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
-// httpclientSSL = HttpClients.custom().setSSLSocketFactory(sslsf).setDefaultRequestConfig(globalConfig).build();
+ globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
+ httpClient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build();
}
@@ -100,33 +81,56 @@ public class HTTPHandler {
request.setHeader(headers[i].getName(), headers[i].getValue());
}
}
+ HttpResponse response;
try {
- HttpResponse response;
- // Removed Specific SSL as Apache HttpClient automatically uses SSL if the URI starts with https://
-// if (url.startsWith("xyzhttps"))
-// response = httpclientSSL.execute(request);
-// else
+ for(int retryCount = 0; retryCount < 2; retryCount++) {
response = httpClient.execute(request);
- log.debug((httpVerb == null ? "GET" : httpVerb) + " execute on URL responded: "
- + response.getStatusLine().getStatusCode());
- if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
- if (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);
+ log.debug((httpVerb == null ? "GET" : httpVerb) + " execute (" + retryCount + ") on URL responded: "
+ + response.getStatusLine().getStatusCode());
+ if (response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
+ if (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);
+ }
+ log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
}
+ retryCount = 2;
+ } else {
+ log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: " + response.getStatusLine());
+ try {
+ String someContent = EntityUtils.toString(response.getEntity(), Charset.forName("UTF-8")); // read
+ // content
+ // for
+ // data
+ EntityUtils.consume(response.getEntity()); // close out
+ // inputstream
+ // ignore
+ // content
+ log.debug("Unsuccessfull response - The http response is <<<" + someContent + ">>>");
+ } catch (Exception e) {
+ //noop
+ }
+ if (response.getStatusLine().getStatusCode() == 504) {
+ log.warn("HTTP response code was 504, retrying...");
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e1) {
+ // noop
+ }
+ }
+ else
+ retryCount = 2;
}
- if (theContent == null)
- theContent = "";
}
} catch (IOException e) {
log.warn("Error calling out to HA gateway: IOException in log", e);
@@ -134,23 +138,22 @@ public class HTTPHandler {
return theContent;
}
- public HttpClient getHttpClient() {
+// public HttpClient getHttpClient() {
+// return httpClient;
+// }
+
+
+ public CloseableHttpClient getHttpClient() {
return httpClient;
}
-// public CloseableHttpClient getHttpclientSSL() {
-// return httpclientSSL;
-// }
-
-
public void closeHandler() {
+ try {
+ httpClient.close();
+ } catch (IOException e) {
+ // noop
+ }
httpClient = null;
-// try {
-// httpclientSSL.close();
-// } catch (IOException e) {
-// // noop
-// }
-// httpclientSSL = 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 97cb753..985fd7e 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/http/HTTPHome.java
@@ -29,23 +29,25 @@ public class HTTPHome implements Home {
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
String responseString = null;
- //Backwards Compatibility Items
- if(anItem.getHttpVerb() == null || anItem.getHttpVerb().isEmpty())
- {
- if(device.getHttpVerb() != null && !device.getHttpVerb().isEmpty())
- anItem.setHttpVerb(device.getHttpVerb());
- }
+ String theUrl = anItem.getItem().getAsString();
+ if(theUrl != null && !theUrl.isEmpty () && (theUrl.startsWith("http://") || theUrl.startsWith("https://"))) {
+ //Backwards Compatibility Items
+ if(anItem.getHttpVerb() == null || anItem.getHttpVerb().isEmpty())
+ {
+ if(device.getHttpVerb() != null && !device.getHttpVerb().isEmpty())
+ anItem.setHttpVerb(device.getHttpVerb());
+ }
+
+ if(anItem.getHttpHeaders() == null || anItem.getHttpHeaders().isEmpty()) {
+ if(device.getHeaders() != null && !device.getHeaders().isEmpty() )
+ anItem.setHttpHeaders(device.getHeaders());
+ }
+
+ log.debug("executing HUE api request to Http "
+ + (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
+ + anItem.getItem().getAsString());
- if(anItem.getHttpHeaders() == null || anItem.getHttpHeaders().isEmpty()) {
- if(device.getHeaders() != null && !device.getHeaders().isEmpty() )
- anItem.setHttpHeaders(device.getHeaders());
- }
-
- log.debug("executing HUE api request to Http "
- + (anItem.getHttpVerb() == null ? "GET" : anItem.getHttpVerb()) + ": "
- + anItem.getItem().getAsString());
-
- String anUrl = BrightnessDecode.calculateReplaceIntensityValue(anItem.getItem().getAsString(),
+ String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrl,
intensity, targetBri, targetBriInc, false);
anUrl = TimeDecode.replaceTimeValue(anUrl);
@@ -63,6 +65,13 @@ public class HTTPHome implements Home {
"Error on calling url to change device state", "/lights/"
+ lightId + "state", null, null).getTheErrors(), HueError[].class);
}
+ } else {
+ log.warn("HTTP Call to be presented as http(s)://(:)/payload, format of request unknown: " + theUrl);
+ responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
+ "Error on calling url to change device state", "/lights/"
+ + lightId + "state", null, null).getTheErrors(), HueError[].class);
+ }
+
return responseString;
}
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxDevice.java b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxDevice.java
new file mode 100644
index 0000000..ea99d9d
--- /dev/null
+++ b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxDevice.java
@@ -0,0 +1,49 @@
+package com.bwssystems.HABridge.plugins.lifx;
+
+import com.github.besherman.lifx.LFXGroup;
+import com.github.besherman.lifx.LFXLight;
+
+public class LifxDevice {
+ private Object lifxObject;
+ private String type;
+ public final static String LIGHT_TYPE = "Light";
+ public final static String GROUP_TYPE = "Group";
+
+ public LifxDevice(Object lifxObject, String type) {
+ super();
+ this.lifxObject = lifxObject;
+ this.type = type;
+ }
+
+ public LifxEntry toEntry() {
+ LifxEntry anEntry = null;
+ if(type.equals(LIGHT_TYPE)) {
+ anEntry = new LifxEntry();
+ anEntry.setId(((LFXLight)lifxObject).getID());
+ anEntry.setName(((LFXLight)lifxObject).getLabel());
+ anEntry.setType(LIGHT_TYPE);
+ }
+ if(type.equals(GROUP_TYPE)) {
+ anEntry = new LifxEntry();
+ anEntry.setId("na");
+ anEntry.setName(((LFXGroup)lifxObject).getLabel());
+ anEntry.setType(GROUP_TYPE);
+ }
+ return anEntry;
+ }
+ public Object getLifxObject() {
+ return lifxObject;
+ }
+
+ public void setLifxObject(Object lifxObject) {
+ this.lifxObject = lifxObject;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxEntry.java b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxEntry.java
new file mode 100644
index 0000000..831095d
--- /dev/null
+++ b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxEntry.java
@@ -0,0 +1,25 @@
+package com.bwssystems.HABridge.plugins.lifx;
+
+public class LifxEntry {
+ private String name;
+ private String id;
+ private String type;
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getId() {
+ return id;
+ }
+ public void setId(String id) {
+ this.id = id;
+ }
+ public String getType() {
+ return type;
+ }
+ public void setType(String type) {
+ this.type = type;
+ }
+}
diff --git a/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java
new file mode 100644
index 0000000..51a002e
--- /dev/null
+++ b/src/main/java/com/bwssystems/HABridge/plugins/lifx/LifxHome.java
@@ -0,0 +1,257 @@
+package com.bwssystems.HABridge.plugins.lifx;
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+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.Home;
+import com.bwssystems.HABridge.api.CallItem;
+import com.bwssystems.HABridge.dao.DeviceDescriptor;
+import com.bwssystems.HABridge.hue.BrightnessDecode;
+import com.bwssystems.HABridge.hue.MultiCommandUtil;
+import com.github.besherman.lifx.LFXClient;
+import com.github.besherman.lifx.LFXGroup;
+import com.github.besherman.lifx.LFXGroupCollection;
+import com.github.besherman.lifx.LFXGroupCollectionListener;
+import com.github.besherman.lifx.LFXLight;
+import com.github.besherman.lifx.LFXLightCollection;
+import com.github.besherman.lifx.LFXLightCollectionListener;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class LifxHome implements Home {
+ private static final Logger log = LoggerFactory.getLogger(LifxHome.class);
+ private static final float DIM_DIVISOR = (float)254.00;
+ private Map lifxMap;
+ private LFXClient client;
+ private Boolean validLifx;
+ private Gson aGsonHandler;
+
+ public LifxHome(BridgeSettingsDescriptor bridgeSettings) {
+ super();
+ createHome(bridgeSettings);
+ }
+
+ @Override
+ public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
+ lifxMap = null;
+ aGsonHandler = null;
+ validLifx = bridgeSettings.isValidLifx();
+ log.info("LifxDevice Home created." + (validLifx ? "" : " No LifxDevices configured."));
+ if(validLifx) {
+ try {
+ log.info("Open Lifx client....");
+ InetAddress configuredAddress = InetAddress.getByName(bridgeSettings.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();
+ 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;
+ validLifx = false;
+ return this;
+ }
+ }
+ return this;
+ }
+
+ public LifxDevice getLifxDevice(String aName) {
+ if(!validLifx)
+ return null;
+ LifxDevice aLifxDevice = null;
+ if(aName == null || aName.equals("")) {
+ log.debug("Cannot get LifxDevice for name as it is empty.");
+ }
+ else {
+ aLifxDevice = lifxMap.get(aName);
+ log.debug("Retrieved a LifxDevice for name: " + aName);
+ }
+ return aLifxDevice;
+ }
+
+ @Override
+ public Object getItems(String type) {
+ log.debug("consolidating devices for lifx");
+ if(!validLifx)
+ return null;
+ LifxEntry theResponse = null;
+ Iterator keys = lifxMap.keySet().iterator();
+ List deviceList = new ArrayList();
+ while(keys.hasNext()) {
+ String key = keys.next();
+ theResponse = lifxMap.get(key).toEntry();
+ if(theResponse != null)
+ deviceList.add(theResponse);
+ else {
+ log.warn("Cannot get LifxDevice with name: " + key + ", skipping this Lifx.");
+ continue;
+ }
+ }
+ return deviceList;
+ }
+
+ private Boolean addLifxLights(LFXLightCollection theDeviceList) {
+ if(!validLifx)
+ return false;
+ Iterator devices = theDeviceList.iterator();;
+ while(devices.hasNext()) {
+ LFXLight theDevice = devices.next();
+ LifxDevice aNewLifxDevice = new LifxDevice(theDevice, LifxDevice.LIGHT_TYPE);
+ lifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
+ }
+ return true;
+ }
+
+ private Boolean addLifxGroups(LFXGroupCollection theDeviceList) {
+ if(!validLifx)
+ return false;
+ Iterator devices = theDeviceList.iterator();;
+ while(devices.hasNext()) {
+ LFXGroup theDevice = devices.next();
+ LifxDevice aNewLifxDevice = new LifxDevice(theDevice, LifxDevice.GROUP_TYPE);
+ lifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
+ }
+ return true;
+ }
+
+ @Override
+ public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
+ Integer targetBri, Integer targetBriInc, DeviceDescriptor device, String body) {
+ String theReturn = null;
+ float aBriValue;
+ float theValue;
+ log.debug("executing HUE api request to send message to LifxDevice: " + anItem.getItem().toString());
+ if(!validLifx) {
+ log.warn("Should not get here, no LifxDevice clients configured");
+ theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ + "\",\"description\": \"Should not get here, no LifxDevices configured\", \"parameter\": \"/lights/"
+ + lightId + "state\"}}]";
+
+ } else {
+ LifxEntry lifxCommand = null;
+ if(anItem.getItem().isJsonObject())
+ lifxCommand = aGsonHandler.fromJson(anItem.getItem(), LifxEntry.class);
+ else
+ lifxCommand = aGsonHandler.fromJson(anItem.getItem().getAsString(), LifxEntry.class);
+ LifxDevice theDevice = getLifxDevice(lifxCommand.getName());
+ if (theDevice == null) {
+ log.warn("Should not get here, no LifxDevices available");
+ theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ + "\",\"description\": \"Should not get here, no Lifx clients available\", \"parameter\": \"/lights/"
+ + lightId + "state\"}}]";
+ } else {
+ log.debug("calling LifxDevice: " + lifxCommand.getName());
+ if(theDevice.getType().equals(LifxDevice.LIGHT_TYPE)) {
+ LFXLight theLight = (LFXLight)theDevice.getLifxObject();
+ if(body.contains("true"))
+ theLight.setPower(true);
+ if(body.contains("false"))
+ theLight.setPower(false);
+ if(targetBri != null || targetBriInc != null) {
+ aBriValue = (float)BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc);
+ theValue = aBriValue/DIM_DIVISOR;
+ if(theValue > (float)1.0)
+ theValue = (float)0.99;
+ theLight.setBrightness(theValue);
+ }
+ } else if (theDevice.getType().equals(LifxDevice.GROUP_TYPE)) {
+ LFXGroup theGroup = (LFXGroup)theDevice.getLifxObject();
+ if(body.contains("true"))
+ theGroup.setPower(true);
+ if(body.contains("false"))
+ theGroup.setPower(false);
+ }
+ }
+ }
+ return theReturn;
+ }
+
+ @Override
+ public void closeHome() {
+ if(!validLifx)
+ return;
+ client.close();
+ }
+ private static class MyLightListener implements LFXLightCollectionListener {
+ private static final Logger log = LoggerFactory.getLogger(MyLightListener.class);
+ private Map aLifxMap;
+ public MyLightListener(Map theMap) {
+ aLifxMap = theMap;
+ }
+ @Override
+ public void lightAdded(LFXLight light) {
+ log.debug("Light added, label: " + light.getLabel() + " and id: " + light.getID());
+ LifxDevice aNewLifxDevice = new LifxDevice(light, LifxDevice.LIGHT_TYPE);
+ aLifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
+ }
+
+ @Override
+ public void lightRemoved(LFXLight light) {
+ log.debug("Light removed, label: " + light.getLabel() + " and id: " + light.getID());
+ aLifxMap.remove(light.getLabel());
+ }
+
+
+ }
+ private static class MyGroupListener implements LFXGroupCollectionListener {
+ private static final Logger log = LoggerFactory.getLogger(MyLightListener.class);
+ private Map aLifxMap;
+ public MyGroupListener(Map theMap) {
+ aLifxMap = theMap;
+ }
+
+ @Override
+ public void groupAdded(LFXGroup group) {
+ log.debug("Group: " + group.getLabel() + " added: " + group.size());
+ LifxDevice aNewLifxDevice = new LifxDevice(group, LifxDevice.GROUP_TYPE);
+ aLifxMap.put(aNewLifxDevice.toEntry().getName(), aNewLifxDevice);
+ }
+
+ @Override
+ public void groupRemoved(LFXGroup group) {
+ log.debug("Group: " + group.getLabel() + " removed");
+ aLifxMap.remove(group.getLabel());
+ }
+
+ }
+}
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 d96ab68..e40001f 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/mqtt/MQTTHandler.java
@@ -1,5 +1,6 @@
package com.bwssystems.HABridge.plugins.mqtt;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
@@ -47,7 +48,7 @@ public class MQTTHandler {
}
public void publishMessage(String topic, String content) {
- MqttMessage message = new MqttMessage(content.getBytes());
+ MqttMessage message = new MqttMessage(StringEscapeUtils.unescapeJava(content).getBytes());
message.setQos(qos);
try {
myClient.publish(topic, message);
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 52e94bc..53cb664 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/tcp/TCPHome.java
@@ -1,12 +1,17 @@
package com.bwssystems.HABridge.plugins.tcp;
import java.io.DataOutputStream;
+import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
import javax.xml.bind.DatatypeConverter;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,6 +26,7 @@ import com.bwssystems.HABridge.hue.TimeDecode;
public class TCPHome implements Home {
private static final Logger log = LoggerFactory.getLogger(TCPHome.class);
private byte[] sendData;
+ private Map theSockets;
public TCPHome(BridgeSettingsDescriptor bridgeSettings) {
@@ -31,48 +37,68 @@ 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) {
+ Socket dataSendSocket = null;
log.debug("executing HUE api request to TCP: " + anItem.getItem().getAsString());
- String intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
- String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
- String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
- String hostAddr = null;
- String port = null;
- InetAddress IPAddress = null;
- if (hostPortion.contains(":")) {
- hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
- port = hostPortion.substring(intermediate.indexOf(':') + 1);
+ String theUrl = anItem.getItem().getAsString();
+ if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("tcp://")) {
+ String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
+ String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
+ String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
+ String hostAddr = null;
+ String port = null;
+ InetAddress IPAddress = null;
+ dataSendSocket = theSockets.get(hostPortion);
+ if(dataSendSocket == null) {
+ if (hostPortion.contains(":")) {
+ hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
+ port = hostPortion.substring(intermediate.indexOf(':') + 1);
+ } else
+ hostAddr = hostPortion;
+ try {
+ IPAddress = InetAddress.getByName(hostAddr);
+ } catch (UnknownHostException e) {
+ // noop
+ }
+
+ try {
+ dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
+ theSockets.put(hostPortion, dataSendSocket);
+ } catch (Exception e) {
+ // noop
+ }
+ }
+
+ theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
+ if (theUrlBody.startsWith("0x")) {
+ theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
+ sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
+ } else {
+ theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
+ theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
+ sendData = theUrlBody.getBytes();
+ }
+ try {
+ DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
+ outToClient.write(sendData);
+ outToClient.flush();
+ } catch (Exception e) {
+ log.warn("Could not send data to TCP socket <<<" + e.getMessage() + ">>>, closing socket: " + theUrl);
+ try {
+ dataSendSocket.close();
+ } catch (IOException e1) {
+ // noop
+ }
+ theSockets.remove(hostPortion);
+ }
} else
- hostAddr = hostPortion;
- try {
- IPAddress = InetAddress.getByName(hostAddr);
- } catch (UnknownHostException e) {
- // noop
- }
-
- theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
- if (theUrlBody.startsWith("0x")) {
- theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
- sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
- } else {
- theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
- sendData = theUrlBody.getBytes();
- }
-
- try {
- Socket dataSendSocket = new Socket(IPAddress, Integer.parseInt(port));
- DataOutputStream outToClient = new DataOutputStream(dataSendSocket.getOutputStream());
- outToClient.write(sendData);
- outToClient.flush();
- dataSendSocket.close();
- } catch (Exception e) {
- // noop
- }
+ log.warn("Tcp Call to be presented as tcp://:/payload, format of request unknown: " + theUrl);
return null;
}
@Override
public Home createHome(BridgeSettingsDescriptor bridgeSettings) {
log.info("TCP Home created.");
+ theSockets = new HashMap();
return this;
}
@@ -84,8 +110,18 @@ public class TCPHome implements Home {
@Override
public void closeHome() {
- // noop
-
+ log.debug("Shutting down TCP sockets.");
+ if(theSockets != null && !theSockets.isEmpty()) {
+ Iterator keys = theSockets.keySet().iterator();
+ while(keys.hasNext()) {
+ String key = keys.next();
+ try {
+ theSockets.get(key).close();
+ } catch (IOException e) {
+ // noop
+ }
+ }
+ }
}
}
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 3669081..1244bff 100644
--- a/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java
+++ b/src/main/java/com/bwssystems/HABridge/plugins/udp/UDPHome.java
@@ -6,6 +6,7 @@ import java.net.UnknownHostException;
import javax.xml.bind.DatatypeConverter;
+import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,39 +34,45 @@ public class UDPHome implements Home {
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, DeviceDescriptor device, String body) {
log.debug("executing HUE api request to UDP: " + anItem.getItem().getAsString());
- String intermediate = anItem.getItem().getAsString().substring(anItem.getItem().getAsString().indexOf("://") + 3);
- String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
- String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
- String hostAddr = null;
- String port = null;
- InetAddress IPAddress = null;
- if (hostPortion.contains(":")) {
- hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
- port = hostPortion.substring(intermediate.indexOf(':') + 1);
+ String theUrl = anItem.getItem().getAsString();
+ if(theUrl != null && !theUrl.isEmpty () && theUrl.startsWith("udp://")) {
+ String intermediate = theUrl.substring(theUrl.indexOf("://") + 3);
+ String hostPortion = intermediate.substring(0, intermediate.indexOf('/'));
+ String theUrlBody = intermediate.substring(intermediate.indexOf('/') + 1);
+ String hostAddr = null;
+ String port = null;
+ InetAddress IPAddress = null;
+ if (hostPortion.contains(":")) {
+ hostAddr = hostPortion.substring(0, intermediate.indexOf(':'));
+ port = hostPortion.substring(intermediate.indexOf(':') + 1);
+ } else
+ hostAddr = hostPortion;
+ try {
+ IPAddress = InetAddress.getByName(hostAddr);
+ } catch (UnknownHostException e) {
+ log.warn("Udp Call, unknown host, continuing...");
+ return null;
+ }
+
+ theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
+ if (theUrlBody.startsWith("0x")) {
+ theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
+ sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
+ } else {
+ theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
+ theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
+ sendData = theUrlBody.getBytes();
+ }
+ try {
+ theUDPDatagramSender.sendUDPResponse(sendData, IPAddress, Integer.parseInt(port));
+ } catch (NumberFormatException e) {
+ log.warn("Udp Call, Number format exception on port, continuing...");
+ } catch (IOException e) {
+ log.warn("IO exception on udp call, continuing...");
+ }
} else
- hostAddr = hostPortion;
- try {
- IPAddress = InetAddress.getByName(hostAddr);
- } catch (UnknownHostException e) {
- log.warn("Udp Call, unknown host, continuing...");
- return null;
- }
+ log.warn("Udp Call to be presented as udp://:/payload, format of request unknown: " + theUrl);
- theUrlBody = TimeDecode.replaceTimeValue(theUrlBody);
- if (theUrlBody.startsWith("0x")) {
- theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, true);
- sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
- } else {
- theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
- sendData = theUrlBody.getBytes();
- }
- try {
- theUDPDatagramSender.sendUDPResponse(sendData, IPAddress, Integer.parseInt(port));
- } catch (NumberFormatException e) {
- log.warn("Udp Call, Number format exception on port, continuing...");
- } catch (IOException e) {
- log.warn("IO exception on udp call, continuing...");
- }
return null;
}
diff --git a/src/main/resources/public/scripts/app.js b/src/main/resources/public/scripts/app.js
index cbad3e0..1fffbbe 100644
--- a/src/main/resources/public/scripts/app.js
+++ b/src/main/resources/public/scripts/app.js
@@ -49,6 +49,11 @@ app.config (function ($locationProvider, $routeProvider) {
templateUrl: 'views/somfydevice.html',
controller: 'SomfyController'
}).otherwise ({
+ controller: 'DomoticzController'
+ }).when ('/lifxdevices', {
+ templateUrl: 'views/lifxdevice.html',
+ controller: 'LifxController'
+ }).otherwise ({
templateUrl: 'views/configuration.html',
controller: 'ViewingController'
})
@@ -74,7 +79,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: [], mapTypes: [], olddevicename: "", logShowAll: false, isInControl: false, showVera: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false, showDomoticz: false, showSomfy: false, habridgeversion: ""};
+ 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: ""};
this.displayWarn = function(errorTitle, error) {
var toastContent = errorTitle;
@@ -265,6 +270,11 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
return;
}
+ this.updateShowLifx = function () {
+ this.state.showLifx = self.state.settings.lifxconfigured;
+ return;
+ }
+
this.loadBridgeSettings = function () {
return $http.get(this.state.systemsbase + "/settings").then(
function (response) {
@@ -278,6 +288,7 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
self.updateShowHass();
self.updateShowDomoticz();
self.updateShowSomfy();
+ self.updateShowLifx();
},
function (error) {
self.displayWarn("Load Bridge Settings Error: ", error);
@@ -473,6 +484,19 @@ app.service ('bridgeService', function ($http, $window, ngToast) {
};
+ this.viewLifxDevices = function () {
+ if (!this.state.showLifx)
+ return;
+ return $http.get(this.state.base + "/lifx/devices").then(
+ function (response) {
+ self.state.lifxdevices = response.data;
+ },
+ function (error) {
+ self.displayWarn("Get Lifx Devices Error: ", error);
+ }
+ );
+ };
+
this.formatCallItem = function (currentItem) {
if(!currentItem.startsWith("{\"item") && !currentItem.startsWith("[{\"item")) {
if (currentItem.startsWith("[") || currentItem.startsWith("{"))
@@ -1247,7 +1271,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
$scope.device = bridgeService.state.device;
};
- $scope.buildDeviceUrls = function (veradevice, dim_control) {
+ $scope.buildDeviceUrls = function (veradevice, dim_control, buildonly) {
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0) {
dimpayload = "http://" + veradevice.veraaddress + ":" + $scope.vera.port
+ "/data_request?id=action&output_format=json&DeviceNum="
@@ -1268,8 +1292,10 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, veradevice.id, veradevice.name, veradevice.veraname, "switch", "veraDevice", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
$scope.buildSceneUrls = function (verascene) {
@@ -1288,10 +1314,11 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
$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.veradevices.length; x++) {
if(bridgeService.state.veradevices[x].id === $scope.bulk.devices[i]) {
- $scope.buildDeviceUrls(bridgeService.state.veradevices[x],dim_control);
+ $scope.buildDeviceUrls(bridgeService.state.veradevices[x],dim_control,true);
devicesList[i] = {
name: $scope.device.name,
mapId: $scope.device.mapId,
@@ -1308,6 +1335,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
contentBodyDim: $scope.device.contentBodyDim,
contentBodyOff: $scope.device.contentBodyOff
};
+ $scope.clearDevice();
}
}
}
@@ -1351,7 +1379,7 @@ app.controller('VeraController', function ($scope, $location, $http, bridgeServi
else {
$scope.selectAll = true;
for(var x = 0; x < bridgeService.state.veradevices.length; x++) {
- if($scope.bulk.devices.indexOf(bridgeService.state.veradevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.veradevices[x].id, bridgeService.state.veradevices[x].veraname, "veraDevice"))
+ if($scope.bulk.devices.indexOf(bridgeService.state.veradevices[x]) < 0)
$scope.bulk.devices.push(bridgeService.state.veradevices[x].id);
}
}
@@ -1561,16 +1589,19 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
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);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
$scope.bulkAddDevices = function() {
var devicesList = [];
+ $scope.clearDevice();
for(var i = 0; i < $scope.bulk.devices.length; i++) {
for(var x = 0; x < bridgeService.state.huedevices.length; x++) {
if(bridgeService.state.huedevices[x].device.uniqueid === $scope.bulk.devices[i]) {
- $scope.buildDeviceUrls(bridgeService.state.huedevices[x]);
+ $scope.buildDeviceUrls(bridgeService.state.huedevices[x],true);
devicesList[i] = {
name: $scope.device.name,
mapId: $scope.device.mapId,
@@ -1587,6 +1618,7 @@ app.controller('HueController', function ($scope, $location, $http, bridgeServic
contentBodyDim: $scope.device.contentBodyDim,
contentBodyOff: $scope.device.contentBodyOff
};
+ $scope.clearDevice();
}
}
}
@@ -1674,7 +1706,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
$scope.device = bridgeService.state.device;
};
- $scope.buildDeviceUrls = function (haldevice, dim_control) {
+ $scope.buildDeviceUrls = function (haldevice, dim_control, buildonly) {
var preOnCmd = "";
var preDimCmd = "";
var preOffCmd = "";
@@ -1729,11 +1761,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
+ postCmd;
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname, haldevice.haldevicename, haldevice.halname, aDeviceType, "halDevice", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
- $scope.buildButtonUrls = function (haldevice, onbutton, offbutton) {
+ $scope.buildButtonUrls = function (haldevice, onbutton, offbutton, buildonly) {
var actionOn = angular.fromJson(onbutton);
var actionOff = angular.fromJson(offbutton);
onpayload = "http://" + haldevice.haladdress + "/IrService!IrCmd=Set!IrDevice=" + haldevice.haldevicename.replaceAll(" ", "%20") + "!IrButton=" + actionOn.DeviceName.replaceAll(" ", "%20") + "?Token=" + $scope.bridge.settings.haltoken;
@@ -1741,20 +1775,24 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-" + actionOn.DeviceName, haldevice.haldevicename, haldevice.halname, "button", "halButton", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
- $scope.buildHALHomeUrls = function (haldevice) {
+ $scope.buildHALHomeUrls = function (haldevice, buildonly) {
onpayload = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Home?Token=" + $scope.bridge.settings.haltoken;
offpayload = "http://" + haldevice.haladdress + "/ModeService!ModeCmd=Set!ModeName=Away?Token=" + $scope.bridge.settings.haltoken;
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-HomeAway", haldevice.haldevicename, haldevice.halname, "home", "halHome", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
- $scope.buildHALHeatUrls = function (haldevice) {
+ $scope.buildHALHeatUrls = function (haldevice, buildonly) {
onpayload = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
@@ -1772,11 +1810,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
+ $scope.bridge.settings.haltoken;
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetHeat", haldevice.haldevicename + " Heat", haldevice.halname, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
- $scope.buildHALCoolUrls = function (haldevice) {
+ $scope.buildHALCoolUrls = function (haldevice, buildonly) {
onpayload = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
@@ -1794,11 +1834,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
+ $scope.bridge.settings.haltoken;
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetCool", haldevice.haldevicename + " Cool", haldevice.halname, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
- $scope.buildHALAutoUrls = function (haldevice) {
+ $scope.buildHALAutoUrls = function (haldevice, buildonly) {
onpayload = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
@@ -1810,11 +1852,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
+ "!HVACMode=Off?Token="
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetAuto", haldevice.haldevicename + " Auto", haldevice.halname, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
- $scope.buildHALOffUrls = function (haldevice) {
+ $scope.buildHALOffUrls = function (haldevice, buildonly) {
onpayload = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
@@ -1827,11 +1871,13 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
$scope.device.offUrl = "http://" + haldevice.haladdress
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-TurnOff", haldevice.haldevicename + " Thermostat", haldevice.halname, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ bridgeService.editNewDevice($scope.device);
+ $location.path('/editdevice');
+ }
};
- $scope.buildHALFanUrls = function (haldevice) {
+ $scope.buildHALFanUrls = function (haldevice, buildonly) {
onpayload = "http://" + haldevice.haladdress
+ "/HVACService!HVACCmd=Set!HVACName="
+ haldevice.haldevicename.replaceAll(" ", "%20")
@@ -1844,21 +1890,24 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
+ $scope.bridge.settings.haltoken;
bridgeService.buildUrls(onpayload, null, offpayload, false, haldevice.haldevicename + "-" + haldevice.halname + "-SetFan", haldevice.haldevicename + " Fan", haldevice.halname, "thermo", "halThermoSet", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ 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.haldevices.length; x++) {
if(bridgeService.state.haldevices[x].haldevicename === $scope.bulk.devices[i]) {
if(bridgeService.state.haldevices[x].haldevicetype === "HVAC")
- $scope.buildHALAutoUrls(bridgeService.state.haldevices[x]);
+ $scope.buildHALAutoUrls(bridgeService.state.haldevices[x], true);
else if(bridgeService.state.haldevices[x].haldevicetype === "HOME")
- $scope.buildHALHomeUrls(bridgeService.state.haldevices[x]);
+ $scope.buildHALHomeUrls(bridgeService.state.haldevices[x], true);
else
- $scope.buildDeviceUrls(bridgeService.state.haldevices[x],dim_control);
+ $scope.buildDeviceUrls(bridgeService.state.haldevices[x],dim_control, true);
devicesList[i] = {
name: $scope.device.name,
mapId: $scope.device.mapId,
@@ -1875,6 +1924,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
contentBodyDim: $scope.device.contentBodyDim,
contentBodyOff: $scope.device.contentBodyOff
};
+ $scope.clearDevice();
}
}
}
@@ -1917,7 +1967,7 @@ app.controller('HalController', function ($scope, $location, $http, bridgeServic
else {
$scope.selectAll = true;
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
- if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.haldevices[x].haldevicename + "-" + bridgeService.state.haldevices[x].halname, bridgeService.state.haldevices[x].halname, "halDevice"))
+ if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0)
$scope.bulk.devices.push(bridgeService.state.haldevices[x].haldevicename);
}
}
@@ -2006,7 +2056,7 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
$scope.device = bridgeService.state.device;
};
- $scope.buildDeviceUrls = function (hassdevice, dim_control) {
+ $scope.buildDeviceUrls = function (hassdevice, dim_control, buildonly) {
onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
@@ -2016,89 +2066,19 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
bridgeService.buildUrls(onpayload, dimpayload, offpayload, true, hassdevice.hassname + "-" + hassdevice.deviceState.entity_id, hassdevice.deviceState.entity_id, hassdevice.hassname, hassdevice.domain, "hassDevice", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
- };
-
- $scope.buildHassHeatUrls = function (hassdevice) {
- onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
- if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
- dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
- else
- 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);
- $scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
- };
-
- $scope.buildHassCoolUrls = function (hassdevice) {
- onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
- if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
- dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
- else
- 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);
- $scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
- };
-
- $scope.buildHassAutoUrls = function (hassdevice) {
- onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
- if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
- dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
- else
- 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);
- $scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
- };
-
- $scope.buildHassOffUrls = function (hassdevice) {
- onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
- if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
- dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
- else
- 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);
- $scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
- };
-
- $scope.buildHassFanUrls = function (hassdevice) {
- onpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\"}";
- if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0))
- dimpayload = "{\"entityId\":\"" + hassdevice.deviceState.entity_id + "\",\"hassName\":\"" + hassdevice.hassname + "\",\"state\":\"on\",\"bri\":\"" + dim_control + "\"}";
- else
- 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);
- $scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ 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.hassdevices.length; x++) {
- if(bridgeService.state.hassdevices[x].deviceName === $scope.bulk.devices[i]) {
- if(bridgeService.state.hassdevices[x].domain === "climate")
- $scope.buildHassAutoUrls(bridgeService.state.hassdevices[x]);
- else
- $scope.buildDeviceUrls(bridgeService.state.hassdevices[x],dim_control);
+ if(bridgeService.state.hassdevices[x].deviceState.entity_id === $scope.bulk.devices[i] && bridgeService.state.hassdevices[x].domain !== "sensor" && bridgeService.state.hassdevices[x].domain !== "sun") {
+ $scope.buildDeviceUrls(bridgeService.state.hassdevices[x],dim_control,true);
devicesList[i] = {
name: $scope.device.name,
mapId: $scope.device.mapId,
@@ -2115,6 +2095,7 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
contentBodyDim: $scope.device.contentBodyDim,
contentBodyOff: $scope.device.contentBodyOff
};
+ $scope.clearDevice();
}
}
}
@@ -2122,7 +2103,7 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
function () {
$scope.clearDevice();
bridgeService.viewDevices();
- bridgeService.viewhassdevices();
+ bridgeService.viewHassDevices();
},
function (error) {
bridgeService.displayWarn("Error adding Hass devices in bulk.", error)
@@ -2157,8 +2138,8 @@ app.controller('HassController', function ($scope, $location, $http, bridgeServi
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);
+ if($scope.bulk.devices.indexOf(bridgeService.state.hassdevices[x].deviceState.entity_id) < 0 && bridgeService.state.hassdevices[x].domain !== "sensor" && bridgeService.state.hassdevices[x].domain !== "sun")
+ $scope.bulk.devices.push(bridgeService.state.hassdevices[x].deviceState.entity_id);
}
}
};
@@ -2201,7 +2182,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
$scope.device = bridgeService.state.device;
};
- $scope.buildDeviceUrls = function (domoticzdevice, dim_control) {
+ $scope.buildDeviceUrls = function (domoticzdevice, dim_control, buildonly) {
var preCmd = "";
var postOnCmd = "";
var postDimCmd = "";
@@ -2240,16 +2221,19 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
+ postOffCmd;
bridgeService.buildUrls(onpayload, dimpayload, offpayload, false, domoticzdevice.devicename + "-" + domoticzdevice.domoticzname, domoticzdevice.devicename, domoticzdevice.domoticzname, aDeviceType, "domoticzDevice", null, null);
$scope.device = bridgeService.state.device;
- bridgeService.editNewDevice($scope.device);
- $location.path('/editdevice');
+ if (!buildonly) {
+ 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.domoticzdevices.length; x++) {
if(bridgeService.state.domoticzdevices[x].devicename === $scope.bulk.devices[i]) {
- $scope.buildDeviceUrls(bridgeService.state.domoticzdevices[x],dim_control);
+ $scope.buildDeviceUrls(bridgeService.state.domoticzdevices[x],dim_control,true);
devicesList[i] = {
name: $scope.device.name,
mapId: $scope.device.mapId,
@@ -2266,6 +2250,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
contentBodyDim: $scope.device.contentBodyDim,
contentBodyOff: $scope.device.contentBodyOff
};
+ $scope.clearDevice();
}
}
}
@@ -2276,7 +2261,7 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
bridgeService.viewHalDevices();
},
function (error) {
- bridgeService.displayWarn("Error adding HAL devices in bulk.", error)
+ bridgeService.displayWarn("Error adding Domoticz devices in bulk.", error)
}
);
$scope.bulk = { devices: [] };
@@ -2308,8 +2293,130 @@ app.controller('DomoticzController', function ($scope, $location, $http, bridgeS
else {
$scope.selectAll = true;
for(var x = 0; x < bridgeService.state.haldevices.length; x++) {
- if($scope.bulk.devices.indexOf(bridgeService.state.haldevices[x]) < 0 && !bridgeService.findDeviceByMapId(bridgeService.state.haldevices[x].haldevicename + "-" + bridgeService.state.haldevices[x].halname, bridgeService.state.haldevices[x].halname, "halDevice"))
- $scope.bulk.devices.push(bridgeService.state.haldevices[x].haldevicename);
+ if($scope.bulk.devices.indexOf(bridgeService.state.domoticzdevices[x]) < 0)
+ $scope.bulk.devices.push(bridgeService.state.domoticzdevices[x].devicename);
+ }
+ }
+ };
+
+ $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('LifxController', function ($scope, $location, $http, bridgeService, ngDialog) {
+ $scope.bridge = bridgeService.state;
+ $scope.device = bridgeService.state.device;
+ $scope.device_dim_control = "";
+ $scope.bulk = { devices: [] };
+ $scope.selectAll = false;
+ bridgeService.viewLifxDevices();
+ $scope.imgButtonsUrl = "glyphicon glyphicon-plus";
+ $scope.buttonsVisible = false;
+
+ $scope.clearDevice = function () {
+ bridgeService.clearDevice();
+ $scope.device = bridgeService.state.device;
+ };
+
+ $scope.buildDeviceUrls = function (lifxdevice, dim_control, buildonly) {
+ 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);
+ $scope.device = bridgeService.state.device;
+ if (!buildonly) {
+ 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.lifxdevices.length; x++) {
+ if(bridgeService.state.lifxdevices[x].devicename === $scope.bulk.devices[i]) {
+ $scope.buildDeviceUrls(bridgeService.state.lifxdevices[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.viewHalDevices();
+ },
+ function (error) {
+ bridgeService.displayWarn("Error adding LIFX 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.haldevices.length; x++) {
+ if($scope.bulk.devices.indexOf(bridgeService.state.lifxdevices[x]) < 0)
+ $scope.bulk.devices.push(bridgeService.state.lifxdevices[x].devicename);
}
}
};
@@ -2509,8 +2616,11 @@ app.controller('EditController', function ($scope, $location, $http, bridgeServi
bridgeService.displayWarn("Error adding device. Name has not been changed from original.", null);
return;
}
- if (copy)
+ if (copy) {
$scope.device.id = null;
+ $scope.device.uniqueid = null;
+ $scope.device.mapId = $scope.device.mapId + "-copy";
+ }
if($scope.mapTypeSelected !== undefined && $scope.mapTypeSelected !== null)
$scope.device.mapType = $scope.mapTypeSelected[0];
else
@@ -2733,6 +2843,20 @@ app.filter('configuredDomoticzItems', function (bridgeService) {
}
});
+app.filter('configuredLifxItems', 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], "lifx")) {
+ out.push(input[i]);
+ }
+ }
+ return out;
+ }
+});
+
app.filter('configuredSomfyDevices', function (bridgeService) {
return function(input) {
var out = [];
@@ -2752,4 +2876,4 @@ app.filter('configuredSomfyDevices', function (bridgeService) {
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 991b8df..14dc9b4 100644
--- a/src/main/resources/public/views/configuration.html
+++ b/src/main/resources/public/views/configuration.html
@@ -21,6 +21,7 @@
HomeAssistant Devices
Domoticz Devices
Somfy Devices
+ LIFX Devices
Add/Edit
diff --git a/src/main/resources/public/views/domoticzdevice.html b/src/main/resources/public/views/domoticzdevice.html
index 962a595..7eedd32 100644
--- a/src/main/resources/public/views/domoticzdevice.html
+++ b/src/main/resources/public/views/domoticzdevice.html
@@ -19,6 +19,7 @@
HomeAssistant Devices
Domoticz Devices
Somfy Devices
+ LIFX Devices
Add/Edit
@@ -36,17 +37,18 @@
done in the edit tab, click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured Domoticz Devices' list below will show what
is already setup for your Domoticz.
-
+
Also, use this select menu for which type of dim control you would
like to be generated:
none
Pass-thru Value
Percentage
+ Decimal Percentage
Custom Math
- Use the check boxes by the names to use the bulk addition
+
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 Domoticz.
@@ -76,7 +78,7 @@
{{domoticzdevice.domoticzname}}
Build Item
+ ng-click="buildDeviceUrls(domoticzdevice, device_dim_control,false)">Build Item
diff --git a/src/main/resources/public/views/editdevice.html b/src/main/resources/public/views/editdevice.html
index 426f36b..759b10b 100644
--- a/src/main/resources/public/views/editdevice.html
+++ b/src/main/resources/public/views/editdevice.html
@@ -21,6 +21,7 @@
href="#!/hassdevices">HomeAssistant Devices
Domoticz Devices
Somfy Devices
+ LIFX Devices
Add/Edit
@@ -33,7 +34,7 @@
fields the bridge uses. Please use care when updating these fields as
you may break the settings used by the bridge to call a specific end
point device.
- This area allows you to create any http or
+
This area allows you to create any http, tcp or
udp call to an endpoint. You can use the default GET or select the
http verb type below and configure a payload for either on, dim or
off methods. For Execution of a
@@ -41,10 +42,10 @@
can use Json notation of array with [{"item":"the
payload"},{"item":"another payload"}] to
execute multiple entries. Adding the value replacements
- (${intensity..byte},${intensity.percent},${intensity.math(X*1)}) will
+ (${intensity.byte},${intensity.percent},${intensity.decimal_percent},${intensity.math(X*1)}) will
also work. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command.
- When copying, update the name and select the "Add Bridge
+
When copying, update the name and select the "Add Bridge
Device" Button.