Merge pull request #914 from bwssytems/NewFeaturesfor5.1

New featuresfor5.1

Fixes #896 Incorrect examples in documentation for color. enhancement

Fixes #910 Order of data description fields seems to be hard-coded bug question

Fixes #891 Color replacement control in MQTT bug

Fixes #886 Exception every minute after linking harmony hub enhancement question

Fixes #879 Intensity.math(x).hex does not deliver hex values bug question

Fixes #809 Scanning Fibaro devices or scenes not working with 5.0.0 Informational bug

Fixes #236 Support for Broadlink Rm2/pro enhancement question

Fixes #874 Error on calling URL - Nanoleaf Aurora bug question

Fixes #808 In 5.0.0, colour UDP URLs not issued to milight hub enhancement question

Fixes #846 [5.1.0] Harmony commands not being split into on/dim enhancement question

Fixes #851 non-dimmable device enhancement question

Fixes #853 Turn Logging off enhancement question

Fixes #850 HB[5.1.0] Fibaro HomeCenter2: Devices "Build Item" not working bug question

Fixes #860 Discovery issues from Echo Dot 2nd Gen - potential fix enhancement

Fixes #675 FHEM home automation integration enhancement question

Fixes #516 OpenHAB integration enhancement
This commit is contained in:
BWS Systems
2018-03-08 14:00:27 -06:00
committed by GitHub
114 changed files with 4945 additions and 993 deletions

1
.gitignore vendored
View File

@@ -14,3 +14,4 @@ data
/.classpath
sftp-config\.json
/bin/

View File

@@ -1,9 +1,9 @@
# ha-bridge
Emulates Philips Hue API to other home automation gateways such as an Amazon Echo or other systems that support Philips Hue. 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.
Emulates Philips Hue API to other home automation gateways such as an Amazon Echo/Dot Gen 1 (gen 2 has issues discovering ha-bridge) or other systems that support Philips Hue. 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:
The Echo path looks like this:
```
+------------------------+ +------------------------+
+-------------+ | H A +------------------| | A +------------------+ |
@@ -11,15 +11,7 @@ The Echo Path looks like this:
+-------------+ | 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:
THe Harmony Hub path looks like this:
```
+------------------------+ +------------------------+
+-------------+ | H A +------------------| | A +------------------+ |
@@ -27,6 +19,14 @@ THe Harmony Hub Path looks like this:
+-------------+ | E I +------------------| | I +------------------+ |
+------------------------+ +------------------------+
```
A Custom implementation path looks like this:
```
+------------------------+ +------------------------+
+-------------+ | H A +------------------| | A +------------------+ |
| HA System |----->| 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!**
@@ -35,11 +35,13 @@ THe Harmony Hub Path looks like this:
**NOTE: This software does not control Philips Hue devices directly. A physical Philips Hue Hub is required for that, by which the ha-bridge can then proxy all of your real Hue bridges behind this bridge.**
**ISSUE: Amazon Echo (2nd Generation) has issues finding the ha-bridge. The only workaround is to have a first generation Echo or Dot on your network that finds the ha-bridge.**
**ISSUE: Google Home now seems to not support local connection to Philips Hue Hubs and requires that it connect to meethue.com. Since the ha-bridge only emulates the local API, and is not associated with Philips, this method will not work. If you have an older Google Home application, this may still work. YMMV.**
**FAQ: Please look here for the current FAQs! https://github.com/bwssytems/ha-bridge/wiki/HA-Bridge-FAQs**
In the cases of systems that require authorization and/or have APIs that cannot be handled in the current method, a module may need to be built. The Harmony Hub is such a module and so is the Nest module. The Bridge has helpers to build devices for the gateway for the Logitech Harmony Hub, Vera, Vera Lite or Vera Edge, Nest, Somfy Tahoma, Home Assistant, Domoticz, HAL, Fibaro, HomeWizard and the ability to proxy all of your real Hue bridges behind this bridge.
In the cases of systems that require authorization and/or have APIs that cannot be handled in the current method, a module may need to be built. The Harmony Hub is such a module and so is the Nest module. The Bridge has helpers to build devices for the gateway for the Logitech Harmony Hub, Vera, Vera Lite or Vera Edge, Nest, Somfy Tahoma, Home Assistant, Domoticz, MQTT, HAL, Fibaro, HomeWizard, LIFX, OpenHAB, FHEM, Broadlink and the ability to proxy all of your real Hue bridges behind this bridge.
Alternatively the Bridge supports custom calls as well using http/https/udp and tcp such as the LimitlessLED/MiLight bulbs using the UDP protocol. Binary data is supported with UDP/TCP.
@@ -61,17 +63,22 @@ 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-5.1.0.jar
java -jar ha-bridge-5.2.0.jar
```
ATTENTION: If running Java9, you will need to add the xml bind module
```
java -jar --add-modules java.xml.bind ha-bridge-5.2.0.jar
```
### Automation on Linux systems
To have this configured and running automatically there are a few resources to use. One is using Docker and a docker container has been built for this and can be gotten here: https://github.com/aptalca/docker-ha-bridge
Create the directory and make sure that ha-bridge-5.1.0.jar is in your /home/pi/habridge directory.
Create the directory and make sure that ha-bridge-5.2.0.jar is in your /home/pi/habridge directory.
```
pi@raspberrypi:~ $ mkdir habridge
pi@raspberrypi:~ $ cd habridge
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.1.0/ha-bridge-5.1.0.jar
pi@raspberrypi:~/habridge $ wget https://github.com/bwssytems/ha-bridge/releases/download/v5.2.0/ha-bridge-5.2.0.jar
```
#### System Control Setup on a pi (preferred)
@@ -92,7 +99,7 @@ After=network.target
[Service]
Type=simple
WorkingDirectory=/home/pi/habridge
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-5.1.0.jar
ExecStart=/usr/bin/java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-5.2.0.jar
[Install]
WantedBy=multi-user.target
@@ -127,7 +134,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-5.1.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
nohup java -jar -Dconfig.file=/home/pi/habridge/data/habridge.config /home/pi/habridge/ha-bridge-5.2.0.jar > /home/pi/habridge/habridge-log.txt 2>&1 &
chmod 777 /home/pi/habridge/habridge-log.txt
```
@@ -240,7 +247,7 @@ At the bottom of the screen is the "Bridge Device DB Backup" which can be access
#### Renumber Devices
This changes the numbering of the added devices to start at 1 and goes up from there. It was originally intended for a conversion from the previous system version that used large numbers and was not necessary. This also allows the system to try and number sequentially. If you use this button, you will need to re-discover your devices as their ID's will have changed.
#### Link
If this is present, you have enabled the ue link button feature for the ha-bridge. If you want a new system to recognize the ha-bridge, you will need to press this button when you are doign a discovery.
If this is present, you have enabled the Hue link button feature for the ha-bridge. If you want a new system to recognize the ha-bridge, you will need to press this button when you are doing a discovery.
### The Bridge Control Tab
This is where all of the configuration occurs for what ports and IP's the bridge runs on. It also contains the configurations for target devices so that Helper Tabs for configuration can be added as well as the connection information to control those devices.
#### Bridge server
@@ -268,7 +275,7 @@ The upnp response port that will be used. The default is 50000.
#### Vera Names and IP Addresses
Provide IP Addresses of your Veras that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Vera and device/scene you configure.
#### Fibaro Names and IP Addresses
Provide IP Addresses of your Fibaros that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Fibaro and device/scene you configure.
Provide IP Addresses of your Fibaros that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Fibaro and device/scene you configure. There are filter switches available to limit some of the returns for devices and scenes such as use save logs, use user description, use only Lili command and a switch that cleans up format Trash Chars. The default filters are false for everything but Trash Chars.
#### Harmony Names and IP Addresses
Provide IP Addresses of your Harmony Hubs that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the activity or buttons by the call it receives and send it to the target Harmony Hub and activity/button you configure. Also, an option of webhook can be called when the activity changes on the harmony hub that will send an HTTP GET call to the the address of your choosing. This can contain the replacement variables of ${activity.id} and/or ${activity.label}. Example : http://192.168.0.1/activity/${activity.id}/${activity.label} OR http://hook?a=${activity.label}
#### Hue Names and IP Addresses
@@ -281,10 +288,16 @@ Provide IP Addresses of your HAL Systems that you want to utilize with the bridg
Provide Client ID and IP Addresses and ports of your MQTT Brokers that you want to utilize with the bridge. Also, you can provide the username and password if you have secured your MQTT broker which is optional. When these Client ID and IP's are given, the bridge will be able to publish MQTT messages by the call it receives and send it to the target MQTT Broker you configure. The MQTT Messages Tab will become available to help you build messages.
#### Home Assistant Names and IP Addresses
Provide IP Addresses and ports of your Home Assistant that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Home Assistant and device/scene you configure.
#### HomeWizard Gateways Names and IP Addresses
Provide IP Addresses of your HomeWizard Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target HomeWizard and device/scene you configure.
#### Domoticz Names and IP Addresses
Provide IP Addresses of your Domoticz Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target Domoticz and device/scene you configure.
#### Somfy Tahoma Names and IP Addresses
Provide user name and password used to login to www.tahomalink.com. This needs to be provided if you're using the Somfy Tahoma features (for connecting to IO Homecontrol used by Velux among others). There is no need to give any IP address or host information as this contacts your cloud account. *Note:* you have to 'turn on' a window to open it, and 'turn off' to close.
#### OpenHAB Names and IP Addresses
Provide IP Addresses of your OpenHAB Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target OpenHAB and device/scene you configure.
#### FHEM Names and IP Addresses
Provide IP Addresses of your FHEM Systems that you want to utilize with the bridge. Also, give a meaningful name to each one so it is easy to decipher in the helper tab. When these names and IP's are given, the bridge will be able to control the devices or scenes by the call it receives and send it to the target FHEM and device/scene you configure.
#### Nest Username
The user name of the home.nest.com account for the Nest user. This needs to be given if you are using the Nest features. There is no need to give any ip address or host information as this contacts your cloud account.
#### Nest Password
@@ -293,6 +306,8 @@ The password for the user name of the home.nest.com account for the Nest user. T
This setting allows the value being sent into the bridge to be interpreted as Fahrenheit or Celsius. The default is to have Fahrenheit.
#### LIFX Support
This setting will have the ha-bridge look for LIFX devices on your network. Since this is broadcast based, there is no other info needed.
#### Broadlink Support
This setting will have the ha-bridge look for Broadlink devices on your network (i.e. RM2 IRcontrollers, Smart Power Strips and Smart Plugs). Since this is broadcast based, there is no other info needed.
#### Emulate Hue Hub Version
This setting is used to set the version that the ha-bridge will return in the hub version field. The default is 9999999999 which should work to be higher than the versions that are being used.
#### Emulate MAC
@@ -303,6 +318,8 @@ This setting is the time used in between button presses when there is multiple b
This controls how many log messages will be kept and displayed on the log tab. This does not affect what is written to the standard output for logging. The default is 512. Changing this will incur more memory usage of the process.
#### Trace UPNP Calls
Turn on tracing for upnp discovery messages to the log. The default is false.
#### UPNP Send Delay
This setting is for the upnp spec to delay a certain amount between upnp response messages sent back to a client. This is defaulted to 650ms and can be tuned to any value up to 1500ms.
#### My Echo URL
This sets the URL that is used in the menu bar to ge to your echo. For certain countries, this needs to be set to a different URL.
@@ -434,11 +451,11 @@ There are multiple replacement constructs available to be put into any of the ca
You can control items that require special calculated values using ${intensity.math(<your expression using "X" as the value to operate on>)} 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. Also, there is a $(time.millis) which will put the millis timestamp where this replacement control is located.
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. Also, there is a ${time.millis} which will put the millis timestamp where this replacement control is located.
Color has been added as a replacement control and the available values are $(color.r), $(color.g), $(color.b) which are representations of each color as 0 - 255. There are hex equivalents as well as $(color.rx), $(color.gx), $(color.bx) and $(color.rgbx) as 2 place hex representations except for rgbx which is a six place hex representation.
Color has been added as a replacement control and the available values are ${color.r}, ${color.g}, ${color.b} which are representations of each color as 0 - 255. There are hex equivalents as well as ${color.rx}, ${color.gx}, ${color.bx} and ${color.rgbx} as 2 place hex representations except for rgbx which is a six place hex representation.
Special handling for milights is included and is handled by $(color.milight:x). The usage for that is as follows: udp://ip:port/0x${color.milight:x} where x is a number between 0 and 4 (0 all groups, 1-4 specific group). The group is necessary in case the color turns out to be white. The correct group on must of course be sent before that udp packet.
Special handling for milights is included and is handled by ${color.milight:x}. The usage for that is as follows: udp://ip:port/0x${color.milight:x} where x is a number between 0 and 4 (0 all groups, 1-4 specific group). The group is necessary in case the color turns out to be white. The correct group on must of course be sent before that udp packet.
Note that milight can only use 255 colors and white is handled completely separate for the rgbw strips, so setting temperature via ct with milight does something but not really the desired result
Also, device data can be inserted into your payloads by the use of "${device.name}", "${device.id}", "${device.uniqueid}", "${device.targetDevice}", "${device.mapId}", "${device.mapType}", "${device.deviceType}", "${device.requesterAddress}", "${device.description}" and "${device.comments}". These work just like the dimming value replacements.

19
pom.xml
View File

@@ -5,7 +5,7 @@
<groupId>com.bwssystems.HABridge</groupId>
<artifactId>ha-bridge</artifactId>
<version>5.1.0</version>
<version>5.2.0</version>
<packaging>jar</packaging>
<name>HA Bridge</name>
@@ -33,7 +33,7 @@
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>harmony-java-client</artifactId>
<version>1.1.5</version>
<version>master-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
@@ -84,12 +84,12 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
<version>1.7.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.5</version>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
@@ -104,12 +104,12 @@
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.0-beta4</version>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-core</artifactId>
<version>4.0.7</version>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
@@ -119,13 +119,18 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>lifx-sdk-java</artifactId>
<version>2.1.6</version>
</dependency>
<dependency>
<groupId>com.github.bwssytems</groupId>
<artifactId>broadlink-java-api</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>

View File

@@ -210,6 +210,8 @@ public class BridgeSettings extends BackupHandler {
theBridgeSettings.setDomoticzconfigured(theBridgeSettings.isValidDomoticz());
theBridgeSettings.setSomfyconfigured(theBridgeSettings.isValidSomfy());
theBridgeSettings.setHomeWizardConfigured(theBridgeSettings.isValidHomeWizard());
theBridgeSettings.setOpenhabconfigured(theBridgeSettings.isValidOpenhab());
theBridgeSettings.setFhemconfigured(theBridgeSettings.isValidFhem());
// Lifx is either configured or not, so it does not need an update.
if(serverPortOverride != null)
theBridgeSettings.setServerPort(serverPortOverride);

View File

@@ -4,7 +4,7 @@ import java.util.List;
import java.util.Map;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
//import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.api.hue.HueConstants;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
@@ -87,6 +87,9 @@ public class BridgeSettingsDescriptor {
@SerializedName("somfyaddress")
@Expose
private IpList somfyaddress;
@SerializedName("openhabaddress")
@Expose
private IpList openhabaddress;
@SerializedName("hubversion")
@Expose
private String hubversion;
@@ -99,6 +102,21 @@ public class BridgeSettingsDescriptor {
@SerializedName("homewizardaddress")
@Expose
private IpList homewizardaddress;
@SerializedName("upnpsenddelay")
@Expose
private Integer upnpsenddelay;
@SerializedName("fhemaddress")
@Expose
private IpList fhemaddress;
@SerializedName("lifxconfigured")
@Expose
private boolean lifxconfigured;
@SerializedName("broadlinkconfigured")
@Expose
private boolean broadlinkconfigured;
// @SerializedName("activeloggers")
// @Expose
// private List<NameValue> activeloggers;
private boolean settingsChanged;
private boolean veraconfigured;
@@ -111,8 +129,9 @@ public class BridgeSettingsDescriptor {
private boolean hassconfigured;
private boolean domoticzconfigured;
private boolean somfyconfigured;
private boolean lifxconfigured;
private boolean homewizardconfigured;
private boolean openhabconfigured;
private boolean fhemconfigured;
// Deprecated settings
private String haltoken;
@@ -136,6 +155,7 @@ public class BridgeSettingsDescriptor {
this.domoticzconfigured = false;
this.homewizardconfigured = false;
this.lifxconfigured = false;
this.openhabconfigured = false;
this.farenheit = true;
this.securityData = null;
this.settingsChanged = false;
@@ -143,6 +163,9 @@ public class BridgeSettingsDescriptor {
this.webaddress = "0.0.0.0";
this.hubversion = HueConstants.HUB_VERSION;
this.hubmac = null;
// this.activeloggers = null;
this.upnpsenddelay = Configuration.UPNP_SEND_DELAY;
this.broadlinkconfigured = false;
}
public String getUpnpConfigAddress() {
return upnpconfigaddress;
@@ -384,6 +407,18 @@ public class BridgeSettingsDescriptor {
public void setHassconfigured(boolean hassconfigured) {
this.hassconfigured = hassconfigured;
}
public IpList getOpenhabaddress() {
return openhabaddress;
}
public void setOpenhabaddress(IpList openhabaddress) {
this.openhabaddress = openhabaddress;
}
public boolean isOpenhabconfigured() {
return openhabconfigured;
}
public void setOpenhabconfigured(boolean openhabconfigured) {
this.openhabconfigured = openhabconfigured;
}
public String getHubversion() {
return hubversion;
}
@@ -420,6 +455,36 @@ public class BridgeSettingsDescriptor {
public void setSecurityData(String securityData) {
this.securityData = securityData;
}
public Integer getUpnpsenddelay() {
return upnpsenddelay;
}
public void setUpnpsenddelay(Integer upnpsenddelay) {
this.upnpsenddelay = upnpsenddelay;
}
public IpList getFhemaddress() {
return fhemaddress;
}
public void setFhemaddress(IpList fhemaddress) {
this.fhemaddress = fhemaddress;
}
public boolean isFhemconfigured() {
return fhemconfigured;
}
public void setFhemconfigured(boolean fhemconfigured) {
this.fhemconfigured = fhemconfigured;
}
// public List<NameValue> getActiveloggers() {
// return activeloggers;
// }
// public void setActiveloggers(List<NameValue> activeloggers) {
// this.activeloggers = activeloggers;
// }
public boolean isBroadlinkconfigured() {
return broadlinkconfigured;
}
public void setBroadlinkconfigured(boolean broadlinkconfigured) {
this.broadlinkconfigured = broadlinkconfigured;
}
public Boolean isValidVera() {
if(this.getVeraAddress() == null || this.getVeraAddress().getDevices().size() <= 0)
return false;
@@ -527,4 +592,27 @@ public class BridgeSettingsDescriptor {
return true;
}
public Boolean isValidOpenhab() {
if(this.getOpenhabaddress() == null || this.getOpenhabaddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getOpenhabaddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidFhem() {
if(this.getFhemaddress() == null || this.getFhemaddress().getDevices().size() <= 0)
return false;
List<NamedIP> devicesList = this.getFhemaddress().getDevices();
if(devicesList.get(0).getIp().contains(Configuration.DEFAULT_ADDRESS))
return false;
return true;
}
public Boolean isValidBroadlink() {
return this.isBroadlinkconfigured();
}
}

View File

@@ -14,4 +14,7 @@ public class Configuration {
public static final String CONFIG_FILE = "data/habridge.config";
public static final int NUMBER_OF_LOG_MESSAGES = 512;
public static final long UPNP_NOTIFY_TIMEOUT = 20000;
public static final int UPNP_SEND_DELAY = 650;
public static final int BROADLINK_DISCOVER_PORT = 40000;
public static final int BROADLINK_DISCONVER_TIMEOUT = 5000;
}

View File

@@ -31,6 +31,9 @@ public class DeviceMapTypes {
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 String[] OPENHAB_DEVICE = { "openhabDevice", "OpenHAB Device"};
public final static String[] FHEM_DEVICE = { "fhemDevice", "FHEM Device"};
public final static String[] BROADLINK_DEVICE = { "broadlinkDevice", "Broadlink Device"};
public final static int typeIndex = 0;
public final static int displayIndex = 1;
@@ -56,7 +59,6 @@ public class DeviceMapTypes {
deviceMapTypes.add(MQTT_MESSAGE);
deviceMapTypes.add(NEST_HOMEAWAY);
deviceMapTypes.add(NEST_THERMO_SET);
deviceMapTypes.add(SOMFY_DEVICE);
deviceMapTypes.add(TCP_DEVICE);
deviceMapTypes.add(UDP_DEVICE);
deviceMapTypes.add(VERA_DEVICE);
@@ -64,6 +66,9 @@ public class DeviceMapTypes {
deviceMapTypes.add(FIBARO_DEVICE);
deviceMapTypes.add(FIBARO_SCENE);
deviceMapTypes.add(SOMFY_DEVICE);
deviceMapTypes.add(OPENHAB_DEVICE);
deviceMapTypes.add(FHEM_DEVICE);
deviceMapTypes.add(BROADLINK_DEVICE);
}
public static int getTypeIndex() {
return typeIndex;

View File

@@ -45,18 +45,17 @@ public class HABridge {
@SuppressWarnings("unused")
HttpClientPool thePool;
log.info("HA Bridge startup sequence...");
theVersion = new Version();
// Singleton initialization
thePool = new HttpClientPool();
log.info("HA Bridge (v" + theVersion.getVersion() + ") starting....");
bridgeSettings = new BridgeSettings();
// sparkjava config directive to set html static file location for Jetty
while(!bridgeSettings.getBridgeControl().isStop()) {
bridgeSettings.buildSettings();
bridgeSettings.getBridgeSecurity().removeTestUsers();
log.info("HA Bridge initializing....");
log.info("HA Bridge (v" + theVersion.getVersion() + ") initializing....");
// sparkjava config directive to set ip address for the web server to listen on
ipAddress(bridgeSettings.getBridgeSettingsDescriptor().getWebaddress());
// sparkjava config directive to set port for the web server to listen on
@@ -91,7 +90,7 @@ public class HABridge {
bridgeSettings.getBridgeSettingsDescriptor().isUseupnpiface() + " on web server: " +
bridgeSettings.getBridgeSettingsDescriptor().getWebaddress() + ":" + bridgeSettings.getBridgeSettingsDescriptor().getServerPort());
// setup the class to handle the upnp response rest api
theSettingResponder = new UpnpSettingsResource(bridgeSettings.getBridgeSettingsDescriptor());
theSettingResponder = new UpnpSettingsResource(bridgeSettings);
theSettingResponder.setupServer();
// start the upnp ssdp discovery listener
@@ -127,12 +126,12 @@ public class HABridge {
bridgeSettings.updateConfigFile();
try {
HttpClientPool.shutdown();
thePool = null;
} catch (InterruptedException e) {
log.warn("Error shutting down http pool: " + e.getMessage());;
} catch (IOException e) {
log.warn("Error shutting down http pool: " + e.getMessage());;
}
thePool = null;
log.info("HA Bridge (v" + theVersion.getVersion() + ") exiting....");
System.exit(0);
}

View File

@@ -9,8 +9,10 @@ import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.devicemanagmeent.ResourceHandler;
import com.bwssystems.HABridge.plugins.NestBridge.NestHome;
import com.bwssystems.HABridge.plugins.broadlink.BroadlinkHome;
import com.bwssystems.HABridge.plugins.domoticz.DomoticzHome;
import com.bwssystems.HABridge.plugins.exec.CommandHome;
import com.bwssystems.HABridge.plugins.fhem.FHEMHome;
import com.bwssystems.HABridge.plugins.hal.HalHome;
import com.bwssystems.HABridge.plugins.harmony.HarmonyHome;
import com.bwssystems.HABridge.plugins.hass.HassHome;
@@ -19,6 +21,7 @@ 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.openhab.OpenHABHome;
import com.bwssystems.HABridge.plugins.somfy.SomfyHome;
import com.bwssystems.HABridge.plugins.tcp.TCPHome;
import com.bwssystems.HABridge.plugins.udp.UDPHome;
@@ -39,6 +42,14 @@ public class HomeManager {
// factory method
public void buildHomes(BridgeSettings bridgeSettings, UDPDatagramSender aUdpDatagramSender) {
Home aHome = null;
//setup the http handler Home - This must be the first home created for devMode
aHome = new HTTPHome(bridgeSettings);
homeList.put(DeviceMapTypes.HTTP_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome);
//setup the harmony connection if available
aHome = new HarmonyHome(bridgeSettings);
resourceList.put(DeviceMapTypes.HARMONY_ACTIVITY[DeviceMapTypes.typeIndex], aHome);
@@ -77,14 +88,6 @@ public class HomeManager {
aHome = new CommandHome(bridgeSettings);
homeList.put(DeviceMapTypes.EXEC_DEVICE_COMPAT[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.CMD_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the http handler Home
aHome = new HTTPHome(bridgeSettings);
homeList.put(DeviceMapTypes.HTTP_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.VERA_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.VERA_SCENE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.FIBARO_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.FIBARO_SCENE[DeviceMapTypes.typeIndex], aHome);
//setup the tcp handler Home
aHome = new TCPHome(bridgeSettings);
homeList.put(DeviceMapTypes.TCP_DEVICE[DeviceMapTypes.typeIndex], aHome);
@@ -105,7 +108,7 @@ public class HomeManager {
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
//setup the Somfy configuration if availableOPENHAB
aHome = new SomfyHome(bridgeSettings);
homeList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
resourceList.put(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex], aHome);
@@ -113,6 +116,18 @@ public class HomeManager {
aHome = new LifxHome(bridgeSettings);
resourceList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.LIFX_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the OpenHAB configuration if available
aHome = new OpenHABHome(bridgeSettings);
resourceList.put(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the OpenHAB configuration if available
aHome = new FHEMHome(bridgeSettings);
resourceList.put(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex], aHome);
//setup the Broadlink configuration if available
aHome = new BroadlinkHome(bridgeSettings);
resourceList.put(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex], aHome);
homeList.put(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex], aHome);
}
public Home findHome(String type) {

View File

@@ -1,5 +1,7 @@
package com.bwssystems.HABridge;
import com.google.gson.JsonObject;
public class NamedIP {
private String name;
private String ip;
@@ -7,6 +9,7 @@ public class NamedIP {
private String port;
private String username;
private String password;
private JsonObject extensions;
private Boolean secure;
public String getName() {
@@ -51,4 +54,10 @@ public class NamedIP {
public void setSecure(Boolean secure) {
this.secure = secure;
}
public JsonObject getExtensions() {
return extensions;
}
public void setExtensions(JsonObject extensions) {
this.extensions = extensions;
}
}

View File

@@ -14,15 +14,19 @@ import java.net.InetAddress;
import java.net.MulticastSocket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
//import java.util.ArrayList;
import java.util.Arrays;
import java.util.Timer;
import java.util.Base64;
//import java.util.Iterator;
//import java.util.List;
import java.util.Map;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.api.hue.WhitelistEntry;
import com.bwssystems.HABridge.dao.BackupFilename;
import com.bwssystems.HABridge.util.JsonTransformer;
@@ -36,6 +40,7 @@ import com.google.gson.reflect.TypeToken;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
//import ch.qos.logback.core.Appender;
import ch.qos.logback.core.read.CyclicBufferAppender;
public class SystemControl {
@@ -55,7 +60,7 @@ public class SystemControl {
this.version = theVersion;
this.lc = (LoggerContext) LoggerFactory.getILoggerFactory();
this.dateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
reacquireCBA();
setupLoggerSettings();
theLogServiceMgr = new LoggingManager();
theLogServiceMgr.init();
}
@@ -88,7 +93,7 @@ public class SystemControl {
String logMsgs;
int count = -1;
if(cyclicBufferAppender == null)
reacquireCBA();
setupLoggerSettings();
if (cyclicBufferAppender != null) {
count = cyclicBufferAppender.getLength();
}
@@ -356,6 +361,8 @@ public class SystemControl {
log.debug("bridge settings requested from " + request.ip());
response.status(HttpStatus.SC_OK);
response.type("application/json");
// if(bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers() == null)
// bridgeSettings.getBridgeSettingsDescriptor().setActiveloggers(getLogAppenders());
return bridgeSettings.getBridgeSettingsDescriptor();
}, new JsonTransformer());
@@ -372,6 +379,8 @@ public class SystemControl {
put(SYSTEM_CONTEXT + "/settings", (request, response) -> {
log.debug("save bridge settings requested from " + request.ip() + " with body: " + request.body());
BridgeSettingsDescriptor newBridgeSettings = new Gson().fromJson(request.body(), BridgeSettingsDescriptor.class);
if(newBridgeSettings.getUpnpsenddelay() > 15000)
newBridgeSettings.setUpnpsenddelay(15000);
bridgeSettings.save(newBridgeSettings);
response.status(HttpStatus.SC_OK);
response.type("application/json");
@@ -482,11 +491,42 @@ public class SystemControl {
}, new JsonTransformer());
}
void reacquireCBA() {
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
private void setupLoggerSettings() {
// final ch.qos.logback.classic.Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
cyclicBufferAppender = (CyclicBufferAppender<ILoggingEvent>) lc.getLogger(
Logger.ROOT_LOGGER_NAME).getAppender(CYCLIC_BUFFER_APPENDER_NAME);
cyclicBufferAppender.setMaxSize(bridgeSettings.getBridgeSettingsDescriptor().getNumberoflogmessages());
}
// if(bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers() != null) {
// for (NameValue temp : bridgeSettings.getBridgeSettingsDescriptor().getActiveloggers()) {
// if(temp.getValue().equals("false"))
// logger.detachAppender(temp.getName());
// }
//
// }
}
// private List<NameValue> getLogAppenders() {
// final ch.qos.logback.classic.Logger logger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
//
// final Iterator<Appender<ILoggingEvent>> it = logger.iteratorForAppenders();
//
// List<NameValue> theLoggers = new ArrayList<NameValue>();
//
// while (it.hasNext()) {
//
// final Appender<ILoggingEvent> appender = it.next();
//
// if (!(appender instanceof CyclicBufferAppender)) {
// NameValue theLogger = new NameValue();
// theLogger.setName(appender.getName());
// theLogger.setValue("true");
// theLoggers.add(theLogger);
// }
// }
//
// return theLoggers;
// }
protected void pingListener() {
try {

View File

@@ -80,7 +80,10 @@ public class DeviceDescriptor{
@SerializedName("deviceState")
@Expose
private DeviceState deviceState;
@SerializedName("onFirstDim")
@Expose
private boolean onFirstDim;
public String getName() {
return name;
}
@@ -275,6 +278,14 @@ public class DeviceDescriptor{
this.comments = comments;
}
public boolean isOnFirstDim() {
return onFirstDim;
}
public void setOnFirstDim(boolean onFirstDim) {
this.onFirstDim = onFirstDim;
}
public boolean containsType(String aType) {
if(aType == null)
return false;

View File

@@ -315,11 +315,37 @@ public class DeviceResource {
return homeManager.findResource(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.SOMFY_DEVICE[DeviceMapTypes.typeIndex]);
}, new JsonTransformer());
get (API_CONTEXT + "/openhab/devices", "application/json", (request, response) -> {
log.debug("Get OpenHAB devices");
response.status(HttpStatus.SC_OK);
return homeManager.findResource(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.OPENHAB_DEVICE[DeviceMapTypes.typeIndex]);
}, new JsonTransformer());
get (API_CONTEXT + "/fhem/devices", "application/json", (request, response) -> {
log.debug("Get FHEM devices");
response.status(HttpStatus.SC_OK);
return homeManager.findResource(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex]);
}, new JsonTransformer());
get (API_CONTEXT + "/broadlink/devices", "application/json", (request, response) -> {
log.debug("Get Broadlink devices");
response.status(HttpStatus.SC_OK);
return homeManager.findResource(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex]).getItems(DeviceMapTypes.BROADLINK_DEVICE[DeviceMapTypes.typeIndex]);
}, new JsonTransformer());
get (API_CONTEXT + "/map/types", "application/json", (request, response) -> {
log.debug("Get map types");
return new DeviceMapTypes().getDeviceMapTypes();
}, new JsonTransformer());
get (API_CONTEXT + "/refresh/:typeIndex", "application/json", (request, response) -> {
String typeIndex = request.params(":typeIndex");
log.debug("Refresh Home: " + typeIndex);
response.status(HttpStatus.SC_OK);
homeManager.findResource(typeIndex).refresh();
return null;
}, new JsonTransformer());
// http://ip_address:port/api/devices/exec/renumber CORS request
options(API_CONTEXT + "/exec/renumber", "application/json", (request, response) -> {
response.status(HttpStatus.SC_OK);

View File

@@ -2,4 +2,5 @@ package com.bwssystems.HABridge.devicemanagmeent;
public interface ResourceHandler {
public Object getItems(String type);
public void refresh();
}

View File

@@ -111,11 +111,7 @@ public class BrightnessDecode {
Integer endResult = calculateMath(variables, mathDescriptor);
if(endResult != null) {
if (isHex) {
replaceValue = convertToHex(endResult);
} else {
replaceValue = endResult.toString();
}
replaceValue = convertToHex(endResult);
replaceTarget = INTENSITY_MATH + mathDescriptor + INTENSITY_MATH_CLOSE_HEX;
notDone = true;
}

View File

@@ -255,4 +255,20 @@ public class ColorDecode {
return "40" + String.format("%02X", milight) + "55";
}
}
@SuppressWarnings("unchecked")
public static int getIntRGB(ColorData colorData, int setIntensity) {
ColorData.ColorMode colorMode = colorData.getColorMode();
List<Integer> rgb = null;
if (colorMode == ColorData.ColorMode.XY) {
rgb = convertCIEtoRGB((List<Double>) colorData.getData(), setIntensity);
} else if (colorMode == ColorData.ColorMode.CT) {
rgb = convertCTtoRGB((Integer) colorData.getData());
}
int rgbIntVal = Integer.parseInt(String.format("%02X%02X%02X", rgb.get(0), rgb.get(1), rgb.get(2)), 16);
log.debug("Convert RGB to int. Result: " + rgbIntVal + " RGB Values: " + rgb.get(0) + " " + rgb.get(1) + " "
+ rgb.get(2));
return rgbIntVal;
}
}

View File

@@ -445,8 +445,9 @@ public class HueMulator {
});
}
@SuppressWarnings("unchecked")
private String formatSuccessHueResponse(StateChangeBody stateChanges, String body, String lightId,
DeviceState deviceState, Integer targetBri, Integer targetBriInc, boolean offState) {
DeviceState deviceState, Integer targetBri, Integer targetBriInc, ColorData colorData, boolean offState) {
String responseString = "[";
boolean notFirstChange = false;
@@ -534,7 +535,7 @@ public class HueMulator {
responseString = responseString + "{\"success\":{\"/lights/" + lightId + "/state/xy_inc\":"
+ stateChanges.getXy_inc() + "}}";
if (deviceState != null)
deviceState.setXy(stateChanges.getXy());
deviceState.setXy((List<Double>) colorData.getData());
notFirstChange = true;
} else if (body.contains("\"ct_inc\"")) {
if (notFirstChange)
@@ -1047,16 +1048,17 @@ public class HueMulator {
DeviceState state = null;
Integer targetBri = null;
Integer targetBriInc = null;
ColorData colorData = null;
log.debug("Update state requested: " + userId + " from " + ipAddress + " body: " + body);
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors != null)
return aGsonHandler.toJson(theErrors);
try {
theStateChanges = aGsonHandler.fromJson(body, StateChangeBody.class);
} catch (Exception e) {
theStateChanges = null;
}
if (theStateChanges == null) {
log.warn("Could not parse state change body. Light state not changed.");
return aGsonHandler.toJson(HueErrorResponse.createResponse("2", "/lights/" + lightId,
"Could not parse state change body.", null, null, null).getTheErrors(), HueError[].class);
@@ -1080,7 +1082,26 @@ public class HueMulator {
if (state == null)
state = DeviceState.createDeviceState(device.isColorDevice());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState());
if (body.contains("\"xy\"") || body.contains("\"ct\"") || body.contains("\"hue\"") || body.contains("\"xy_inc\"") || body.contains("\"ct_inc\"") || body.contains("\"hue_inc\"")) {
List<Double> xy = theStateChanges.getXy();
List<Double> xyInc = theStateChanges.getXy_inc();
Integer ct = theStateChanges.getCt();
Integer ctInc = theStateChanges.getCt_inc();
if (xy != null && xy.size() == 2) {
colorData = new ColorData(ColorData.ColorMode.XY, xy);
} else if (xyInc != null && xyInc.size() == 2) {
List<Double> current = state.getXy();
current.set(0, current.get(0) + xyInc.get(0));
current.set(1, current.get(1) + xyInc.get(1));
colorData = new ColorData(ColorData.ColorMode.XY, current);
} else if (ct != null && ct != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, ct);
} else if (ctInc != null && ctInc != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, state.getCt() + ctInc);
}
}
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, colorData, device.isOffState());
device.setDeviceState(state);
return responseString;
@@ -1096,10 +1117,10 @@ public class HueMulator {
DeviceState state = null;
Integer targetBri = null;
Integer targetBriInc = null;
MultiCommandUtil aMultiUtil = new MultiCommandUtil();
aMultiUtil.setTheDelay(bridgeSettings.getButtonsleep());
aMultiUtil.setDelayDefault(bridgeSettings.getButtonsleep());
aMultiUtil.setSetCount(1);
boolean isColorRequest = false;
boolean isDimRequest = false;
boolean isOnRequest = false;
ColorData colorData = null;
log.debug("hue state change requested: " + userId + " from " + ipAddress + " body: " + body);
HueError[] theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
if (theErrors != null) {
@@ -1125,146 +1146,143 @@ public class HueMulator {
"Could not find device.", "/lights/" + lightId, null, null).getTheErrors(), HueError[].class);
}
if (body.contains("\"bri_inc\"")) {
targetBriInc = new Integer(theStateChanges.getBri_inc());
}
else if (body.contains("\"bri\"")) {
targetBri = new Integer(theStateChanges.getBri());
}
state = device.getDeviceState();
if (state == null) {
state = DeviceState.createDeviceState(device.isColorDevice());
device.setDeviceState(state);
}
if (targetBri != null || targetBriInc != null) {
url = device.getDimUrl();
if (body.contains("\"bri_inc\"")) {
targetBriInc = new Integer(theStateChanges.getBri_inc());
isDimRequest = true;
}
else if (body.contains("\"bri\"")) {
targetBri = new Integer(theStateChanges.getBri());
isDimRequest = true;
}
if (url == null || url.length() == 0)
url = device.getOnUrl();
} else {
if (body.contains("\"xy\"") || body.contains("\"ct\"") || body.contains("\"hue\"")) {
url = device.getColorUrl();
} else if (theStateChanges.isOn()) {
if (body.contains("\"xy\"") || body.contains("\"ct\"") || body.contains("\"hue\"") || body.contains("\"xy_inc\"") || body.contains("\"ct_inc\"") || body.contains("\"hue_inc\"")) {
List<Double> xy = theStateChanges.getXy();
List<Double> xyInc = theStateChanges.getXy_inc();
Integer ct = theStateChanges.getCt();
Integer ctInc = theStateChanges.getCt_inc();
if (xy != null && xy.size() == 2) {
colorData = new ColorData(ColorData.ColorMode.XY, xy);
} else if (xyInc != null && xyInc.size() == 2) {
List<Double> current = state.getXy();
current.set(0, current.get(0) + xyInc.get(0));
current.set(1, current.get(1) + xyInc.get(1));
colorData = new ColorData(ColorData.ColorMode.XY, current);
} else if (ct != null && ct != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, ct);
} else if (ctInc != null && ctInc != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, state.getCt() + ctInc);
}
if(colorData != null)
isColorRequest = true;
}
if (body.contains("\"on\"")) {
isOnRequest = true;
}
if(device.isOnFirstDim() && isDimRequest && !device.getDeviceState().isOn()) {
isOnRequest = true;
isDimRequest = false;
isColorRequest = false;
} else if(device.isOnFirstDim() && isDimRequest && device.getDeviceState().isOn()) {
if(device.getDeviceState().getBri() == theStateChanges.getBri()) {
isOnRequest = true;
isDimRequest = false;
isColorRequest = false;
} else {
isOnRequest = false;
isDimRequest = true;
isColorRequest = false;
}
}
if(isOnRequest) {
log.debug("Calling on-off as requested.");
if (theStateChanges.isOn()) {
url = device.getOnUrl();
} else if (!theStateChanges.isOn()) {
url = device.getOffUrl();
}
}
// code for backwards compatibility
if(device.getMapType() != null && device.getMapType().equalsIgnoreCase(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
if(url == null)
url = device.getOnUrl();
}
if (url != null && !url.equals("")) {
if (!url.startsWith("[")) {
if (url.startsWith("{\"item"))
url = "[" + url + "]";
else {
if(url.startsWith("{"))
url = "[{\"item\":" + url + "}]";
else
url = "[{\"item\":\"" + url + "\"}]";
}
} else if(!url.startsWith("[{\"item\""))
url = "[{\"item\":" + url + "}]";
log.debug("Decode Json for url items: " + url);
CallItem[] callItems = null;
try {
callItems = aGsonHandler.fromJson(url, CallItem[].class);
} catch(JsonSyntaxException e) {
log.warn("Could not decode Json for url items: " + lightId + " for hue state change request: " + userId + " from "
+ ipAddress + " body: " + body + " url items: " + url);
return aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/lights/" + lightId,
"Could decode json in request", "/lights/" + lightId, null, null).getTheErrors(), HueError[].class);
// code for backwards compatibility
if(device.getMapType() != null && device.getMapType().equalsIgnoreCase(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
if(url == null)
url = device.getOnUrl();
}
for (int i = 0; callItems != null && i < callItems.length; i++) {
if (!ignoreRequester) {
if(!filterByRequester(device.getRequesterAddress(), ipAddress) || !filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
log.warn("filter for requester address not present in: (device)" + device.getRequesterAddress() + " OR then (item)" + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
continue;
}
}
if (callItems[i].getCount() != null && callItems[i].getCount() > 0)
aMultiUtil.setSetCount(callItems[i].getCount());
else
aMultiUtil.setSetCount(1);
// code for backwards compatibility
if((callItems[i].getType() == null || callItems[i].getType().trim().isEmpty())) {
if(validMapTypes.validateType(device.getMapType()))
callItems[i].setType(device.getMapType().trim());
else if(validMapTypes.validateType(device.getDeviceType()))
callItems[i].setType(device.getDeviceType().trim());
else
callItems[i].setType(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex]);
}
if (callItems[i].getType() != null) {
for (int x = 0; x < aMultiUtil.getSetCount(); x++) {
if (x > 0 || i > 0) {
try {
Thread.sleep(aMultiUtil.getTheDelay());
} catch (InterruptedException e) {
// ignore
}
}
if (callItems[i].getDelay() != null && callItems[i].getDelay() > 0)
aMultiUtil.setTheDelay(callItems[i].getDelay());
else
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
ColorData colorData = null;
List<Double> xy = theStateChanges.getXy();
List<Double> xyInc = theStateChanges.getXy_inc();
Integer ct = theStateChanges.getCt();
Integer ctInc = theStateChanges.getCt_inc();
if (xy != null && xy.size() == 2) {
colorData = new ColorData(ColorData.ColorMode.XY, xy);
} else if (xyInc != null && xyInc.size() == 2) {
List<Double> current = state.getXy();
current.set(0, current.get(0) + xyInc.get(0));
current.set(1, current.get(1) + xyInc.get(1));
colorData = new ColorData(ColorData.ColorMode.XY, current);
} else if (ct != null && ct != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, ct);
} else if (ctInc != null && ctInc != 0) {
colorData = new ColorData(ColorData.ColorMode.CT, state.getCt() + ctInc);
}
log.debug("Calling Home device handler for type : " + callItems[i].getType().trim());
responseString = homeManager.findHome(callItems[i].getType().trim()).deviceHandler(callItems[i], aMultiUtil, lightId, state.getBri(), targetBri, targetBriInc, colorData, device, body);
if(responseString != null && responseString.contains("{\"error\":")) {
x = aMultiUtil.getSetCount();
}
if (url != null && !url.equals("")) {
responseString = callUrl(url, device, userId, lightId, body, ipAddress, ignoreRequester, targetBri, targetBriInc, colorData);
} else {
log.info("On/off url not available for state change, lightId: " + lightId + ", userId: " + userId + ", from IP: "
+ ipAddress + ", body: " + body);
}
}
if (isDimRequest) {
log.debug("Calling dim as requested.");
url = device.getDimUrl();
// code for backwards compatibility
if(device.getMapType() != null && device.getMapType().equalsIgnoreCase(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
if(url == null)
url = device.getOnUrl();
}
if (url != null && !url.equals("")) {
if(isOnRequest) {
try {
Thread.sleep(bridgeSettings.getButtonsleep());
} catch (InterruptedException e) {
// ignore
}
}
else
log.warn("Call Items type is null <<<" + callItems[i] + ">>>");
responseString = callUrl(url, device, userId, lightId, body, ipAddress, ignoreRequester, targetBri, targetBriInc, colorData);
} else {
log.info("Dim url not available for state change, lightId: " + lightId + ", userId: " + userId + ", from IP: "
+ ipAddress + ", body: " + body);
}
if(callItems.length == 0)
log.warn("No call items were available: <<<" + url + ">>>");
} else {
log.warn("Could not find url: " + lightId + " for hue state change request: " + userId + " from "
+ ipAddress + " body: " + body);
responseString = aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/lights/" + lightId,
"Could not find url.", "/lights/" + lightId, null, null).getTheErrors(), HueError[].class);
}
if (isColorRequest) {
log.debug("Calling color as requested.");
url = device.getColorUrl();
// code for backwards compatibility
if(device.getMapType() != null && device.getMapType().equalsIgnoreCase(DeviceMapTypes.HUE_DEVICE[DeviceMapTypes.typeIndex])) {
if(url == null)
url = device.getOnUrl();
}
if (url != null && !url.equals("")) {
if((isOnRequest && !isDimRequest) || isDimRequest) {
try {
Thread.sleep(bridgeSettings.getButtonsleep());
} catch (InterruptedException e) {
// ignore
}
}
responseString = callUrl(url, device, userId, lightId, body, ipAddress, ignoreRequester, targetBri, targetBriInc, colorData);
} else {
log.info("Color url not available for state change, lightId: " + lightId + ", userId: " + userId + ", from IP: "
+ ipAddress + ", body: " + body);
}
}
if (responseString == null || !responseString.contains("[{\"error\":")) {
log.debug("Response is in error: " + ((responseString == null) ? "null" : responseString));
if(!device.isNoState()) {
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, device.isOffState());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, state, targetBri, targetBriInc, colorData, device.isOffState());
device.setDeviceState(state);
} else {
DeviceState dummyState = DeviceState.createDeviceState(device.isColorDevice());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, dummyState, targetBri, targetBriInc, device.isOffState());
responseString = this.formatSuccessHueResponse(theStateChanges, body, lightId, dummyState, targetBri, targetBriInc, colorData, device.isOffState());
}
}
return responseString;
}
@@ -1272,6 +1290,7 @@ public class HueMulator {
@SuppressWarnings("unchecked")
private String changeGroupState(String userId, String groupId, String body, String ipAddress, boolean fakeLightResponse) {
ColorData colorData = null;
log.debug("PUT action to group " + groupId + " from " + ipAddress + " user " + userId + " with body " + body);
HueError[] theErrors = null;
theErrors = bridgeSettingMaster.getBridgeSecurity().validateWhitelistUser(userId, null, bridgeSettingMaster.getBridgeSecurity().isUseLinkButton());
@@ -1352,7 +1371,7 @@ public class HueMulator {
// construct success response: one success message per changed property, but not per light
if (group != null) { // if not group 0
String response = formatSuccessHueResponse(theStateChanges, body, String.valueOf(Integer.parseInt(groupId) + 10000),
state, targetBri, targetBriInc, true);
state, targetBri, targetBriInc, colorData, true);
group.setAction(state);
if (fakeLightResponse) {
return response;
@@ -1375,4 +1394,87 @@ public class HueMulator {
return aGsonHandler.toJson(theErrors);
}
protected String callUrl(String url, DeviceDescriptor device, String userId, String lightId, String body, String ipAddress, boolean ignoreRequester, Integer targetBri, Integer targetBriInc, ColorData colorData) {
String responseString = null;
MultiCommandUtil aMultiUtil = new MultiCommandUtil();
aMultiUtil.setTheDelay(bridgeSettings.getButtonsleep());
aMultiUtil.setDelayDefault(bridgeSettings.getButtonsleep());
aMultiUtil.setSetCount(1);
if (!url.startsWith("[")) {
if (url.startsWith("{\"item"))
url = "[" + url + "]";
else {
if(url.startsWith("{"))
url = "[{\"item\":" + url + "}]";
else
url = "[{\"item\":\"" + url + "\"}]";
}
} else if(!url.startsWith("[{\"item\""))
url = "[{\"item\":" + url + "}]";
log.debug("Decode Json for url items: " + url);
CallItem[] callItems = null;
try {
callItems = aGsonHandler.fromJson(url, CallItem[].class);
} catch(JsonSyntaxException e) {
log.warn("Could not decode Json for url items: " + lightId + " for hue state change request: " + userId + " from "
+ ipAddress + " body: " + body + " url items: " + url);
return aGsonHandler.toJson(HueErrorResponse.createResponse("3", "/lights/" + lightId,
"Could decode json in request", "/lights/" + lightId, null, null).getTheErrors(), HueError[].class);
}
for (int i = 0; callItems != null && i < callItems.length; i++) {
if (!ignoreRequester) {
if(!filterByRequester(device.getRequesterAddress(), ipAddress) || !filterByRequester(callItems[i].getFilterIPs(), ipAddress)) {
log.warn("filter for requester address not present in: (device)" + device.getRequesterAddress() + " OR then (item)" + callItems[i].getFilterIPs() + " with request ip of: " + ipAddress);
continue;
}
}
if (callItems[i].getCount() != null && callItems[i].getCount() > 0)
aMultiUtil.setSetCount(callItems[i].getCount());
else
aMultiUtil.setSetCount(1);
// code for backwards compatibility
if((callItems[i].getType() == null || callItems[i].getType().trim().isEmpty())) {
if(validMapTypes.validateType(device.getMapType()))
callItems[i].setType(device.getMapType().trim());
else if(validMapTypes.validateType(device.getDeviceType()))
callItems[i].setType(device.getDeviceType().trim());
else
callItems[i].setType(DeviceMapTypes.CUSTOM_DEVICE[DeviceMapTypes.typeIndex]);
}
if (callItems[i].getType() != null) {
for (int x = 0; x < aMultiUtil.getSetCount(); x++) {
if (x > 0 || i > 0) {
try {
Thread.sleep(aMultiUtil.getTheDelay());
} catch (InterruptedException e) {
// ignore
}
}
if (callItems[i].getDelay() != null && callItems[i].getDelay() > 0)
aMultiUtil.setTheDelay(callItems[i].getDelay());
else
aMultiUtil.setTheDelay(aMultiUtil.getDelayDefault());
log.debug("Calling Home device handler for type : " + callItems[i].getType().trim());
responseString = homeManager.findHome(callItems[i].getType().trim()).deviceHandler(callItems[i], aMultiUtil, lightId, device.getDeviceState().getBri(), targetBri, targetBriInc, colorData, device, body);
if(responseString != null && responseString.contains("{\"error\":")) {
x = aMultiUtil.getSetCount();
}
}
}
else
log.warn("Call Items type is null <<<" + callItems[i] + ">>>");
}
if(callItems.length == 0)
log.warn("No call items were available: <<<" + url + ">>>");
return responseString;
}
}

View File

@@ -197,5 +197,10 @@ public class NestHome implements com.bwssystems.HABridge.Home {
}
return this;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -0,0 +1,77 @@
package com.bwssystems.HABridge.plugins.broadlink;
public class BroadlinkEntry {
private String name;
private String id;
private String ipAddr;
private String macAddr;
private String command;
private String data;
private String type;
private String baseType;
private String desc;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public String getIpAddr() {
return ipAddr;
}
public void setIpAddr(String ipAddr) {
this.ipAddr = ipAddr;
}
public String getMacAddr() {
return macAddr;
}
public void setMacAddr(String macAddr) {
this.macAddr = macAddr;
}
public void setId(String id) {
this.id = id;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getBaseType() {
return baseType;
}
public void setBaseType(String baseType) {
this.baseType = baseType;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public boolean hasIpAndMac() {
boolean deviceOk = true;
if(ipAddr == null || ipAddr.trim().isEmpty())
deviceOk = false;
else if(macAddr == null || macAddr.trim().isEmpty())
deviceOk = false;
else if(type == null || type.trim().isEmpty())
deviceOk = false;
return deviceOk;
}
}

View File

@@ -0,0 +1,355 @@
package com.bwssystems.HABridge.plugins.broadlink;
import java.io.IOException;
import java.math.BigInteger;
import java.net.BindException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.Configuration;
import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.github.mob41.blapi.BLDevice;
import com.github.mob41.blapi.MP1Device;
import com.github.mob41.blapi.SP1Device;
import com.github.mob41.blapi.SP2Device;
import com.github.mob41.blapi.mac.Mac;
import com.github.mob41.blapi.mac.MacFormatException;
import com.github.mob41.blapi.pkt.cmd.rm2.SendDataCmdPayload;
import com.google.gson.Gson;
public class BroadlinkHome implements Home {
private static final Logger log = LoggerFactory.getLogger(BroadlinkHome.class);
private Map<String, BLDevice> broadlinkMap;
private Boolean validBroadlink;
private boolean closed;
private Boolean isDevMode;
private BridgeSettingsDescriptor bridgeSettingsDesc;
public BroadlinkHome(BridgeSettings bridgeSettings) {
super();
closed = true;
createHome(bridgeSettings);
closed = false;
}
@Override
public Home createHome(BridgeSettings bridgeSettings) {
broadlinkMap = null;
bridgeSettingsDesc = bridgeSettings.getBridgeSettingsDescriptor();
validBroadlink = bridgeSettings.getBridgeSettingsDescriptor().isValidBroadlink();
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
if (isDevMode)
validBroadlink = true;
if(validBroadlink)
broadlinkDiscover();
log.info("Broadlink Home created." + (validBroadlink ? "" : " No Broadlinks configured.") + (isDevMode ? " DevMode is set." : ""));
return this;
}
@Override
public Object getItems(String type) {
List<BroadlinkEntry> deviceList = new ArrayList<BroadlinkEntry>();
if(!validBroadlink || broadlinkMap == null)
return deviceList;
BroadlinkEntry theResponse = null;
log.debug("consolidating devices for Broadlink");
Iterator<String> keys = broadlinkMap.keySet().iterator();
while(keys.hasNext()) {
String key = keys.next();
theResponse = toEntry(broadlinkMap.get(key));
if(theResponse != null)
deviceList.add(theResponse);
else {
log.warn("Cannot get BroadlinkDevice with name: " + key + ", skipping this Broadlink.");
continue;
}
}
return deviceList;
}
@Override
public void refresh() {
if(validBroadlink)
broadlinkDiscover();
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String theReturn = null;
boolean changeState = false;
String theStringData = null;
log.debug("executing HUE api request to send message to BroadlinkDevice: " + anItem.getItem().toString());
if(!validBroadlink) {
log.warn("Should not get here, no Broadlinks configured");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no LifxDevices configured\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
} else {
BroadlinkEntry broadlinkCommand = null;
broadlinkCommand = new Gson().fromJson(anItem.getItem().getAsString(), BroadlinkEntry.class);
BLDevice theDevice = null;
if(broadlinkMap != null && !broadlinkMap.isEmpty())
theDevice = broadlinkMap.get(broadlinkCommand.getId());
if (theDevice == null) {
if(broadlinkCommand.hasIpAndMac()) {
byte[] intBytes = DatatypeConverter.parseHexBinary(broadlinkCommand.getType());
BigInteger theBig = new BigInteger(intBytes);
int theType = theBig.intValue();
try {
theDevice = BLDevice.createInstance((short)theType, broadlinkCommand.getIpAddr(), new Mac(broadlinkCommand.getMacAddr()));
} catch (MacFormatException e) {
log.warn("Could not initialize BroadlinkDevice device due to Mac (" + broadlinkCommand.getId() + ") format exception: " + e.getMessage());
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to Mac format exception\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
} catch (IOException e) {
log.warn("Could not initialize BroadlinkDevice device due to IP Address (" + broadlinkCommand.getId() + ") exception: " + e.getMessage());
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to IP Address exception\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
} catch (Exception e) {
log.warn("Could not initialize BroadlinkDevice device due to (" + broadlinkCommand.getId() + ") exception: " + e.getMessage());
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Could not initialize BroadlinkDevice device due to exception\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
}
if(broadlinkMap == null)
broadlinkMap = new HashMap<String, BLDevice>();
String newId = theDevice.getHost() + "-" + String.format("%04x", theDevice.getDeviceType());
if(broadlinkMap.get(newId) == null)
broadlinkMap.put(newId, theDevice);
}
}
if (theDevice == null) {
log.warn("Should not get here, no BroadlinkDevice not available");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"Should not get here, no Broadlinks available\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
} else {
log.debug("calling BroadlinkDevice: " + broadlinkCommand.getName());
try {
if(!isDevMode) {
if(!theDevice.auth()) {
log.error("Call to " + broadlinkCommand.getId() + " device authorization failed.");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"" + broadlinkCommand.getId() + " device auth error.\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
}
}
switch (theDevice.getDeviceType()) {
case BLDevice.DEV_A1:
log.debug("Broadlink A1 device called and not supported. No Action, device name = " + device.getName() + ", id= " + broadlinkCommand.getId());
break;
case BLDevice.DEV_MP1:
if(broadlinkCommand.getCommand().equals("on"))
changeState = true;
else
changeState = false;
((MP1Device) theDevice).setState(Integer.parseInt(broadlinkCommand.getData()), changeState);
break;
case BLDevice.DEV_SP2:
case BLDevice.DEV_SP2_HONEYWELL_ALT1:
case BLDevice.DEV_SP2_HONEYWELL_ALT2:
case BLDevice.DEV_SP2_HONEYWELL_ALT3:
case BLDevice.DEV_SP2_HONEYWELL_ALT4:
case BLDevice.DEV_SPMINI:
case BLDevice.DEV_SP3:
case BLDevice.DEV_SPMINI2:
case BLDevice.DEV_SPMINI_OEM_ALT1:
case BLDevice.DEV_SPMINI_OEM_ALT2:
case BLDevice.DEV_SPMINI_PLUS:
if(broadlinkCommand.getCommand().equals("on"))
changeState = true;
else
changeState = false;
((SP2Device) theDevice).setState(changeState);
break;
case BLDevice.DEV_SP1:
if(broadlinkCommand.getCommand().equals("on"))
changeState = true;
else
changeState = false;
((SP1Device) theDevice).setPower(changeState);
break;
case BLDevice.DEV_RM_2:
case BLDevice.DEV_RM_MINI:
case BLDevice.DEV_RM_PRO_PHICOMM:
case BLDevice.DEV_RM_2_HOME_PLUS:
case BLDevice.DEV_RM_2_2HOME_PLUS_GDT:
case BLDevice.DEV_RM_2_PRO_PLUS:
case BLDevice.DEV_RM_2_PRO_PLUS_2:
case BLDevice.DEV_RM_2_PRO_PLUS_2_BL:
case BLDevice.DEV_RM_MINI_SHATE:
if(broadlinkCommand.getData() != null && !broadlinkCommand.getData().trim().isEmpty()) {
theStringData = broadlinkCommand.getData().trim();
if(targetBri != null || targetBriInc != null) {
theStringData = BrightnessDecode.calculateReplaceIntensityValue(theStringData, intensity, targetBri, targetBriInc, true);
}
if(colorData != null) {
theStringData = ColorDecode.replaceColorData(theStringData, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
}
theStringData = DeviceDataDecode.replaceDeviceData(theStringData, device);
theStringData = TimeDecode.replaceTimeValue(theStringData);
byte[] theData = DatatypeConverter.parseHexBinary(theStringData);
SendDataCmdPayload thePayload = new SendDataCmdPayload(theData);
DatagramPacket thePacket = theDevice.sendCmdPkt(Configuration.BROADLINK_DISCONVER_TIMEOUT, thePayload);
String returnData = null;
if(thePacket != null)
returnData = DatatypeConverter.printHexBinary(thePacket.getData());
else
returnData = "No Data - null";
log.debug("RM2 Device data return: <<<" + returnData + ">>>");
}
else {
log.error("Call to " + broadlinkCommand.getId() + " with no data, noop");
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"" + broadlinkCommand.getId() + " could not call device without data.\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
}
break;
}
} catch (Exception e) {
log.error("Call to " + broadlinkCommand.getId() + " device failed with exception: " + e.getMessage(), e);
theReturn = "[{\"error\":{\"type\": 6, \"address\": \"/lights/" + lightId
+ "\",\"description\": \"" + broadlinkCommand.getId() + " device call error.\", \"parameter\": \"/lights/"
+ lightId + "state\"}}]";
}
}
}
return theReturn;
}
private BroadlinkEntry toEntry(BLDevice broadlinkObject) {
short baseType = 0;
switch (broadlinkObject.getDeviceType()) {
case BLDevice.DEV_MP1:
baseType = BLDevice.DEV_MP1;
break;
case BLDevice.DEV_SP2:
case BLDevice.DEV_SP2_HONEYWELL_ALT1:
case BLDevice.DEV_SP2_HONEYWELL_ALT2:
case BLDevice.DEV_SP2_HONEYWELL_ALT3:
case BLDevice.DEV_SP2_HONEYWELL_ALT4:
case BLDevice.DEV_SPMINI:
case BLDevice.DEV_SP3:
case BLDevice.DEV_SPMINI2:
case BLDevice.DEV_SPMINI_OEM_ALT1:
case BLDevice.DEV_SPMINI_OEM_ALT2:
case BLDevice.DEV_SPMINI_PLUS:
baseType = BLDevice.DEV_SP2;
break;
case BLDevice.DEV_SP1:
baseType = BLDevice.DEV_SP1;
break;
case BLDevice.DEV_RM_2:
case BLDevice.DEV_RM_MINI:
case BLDevice.DEV_RM_PRO_PHICOMM:
case BLDevice.DEV_RM_2_HOME_PLUS:
case BLDevice.DEV_RM_2_2HOME_PLUS_GDT:
case BLDevice.DEV_RM_2_PRO_PLUS:
case BLDevice.DEV_RM_2_PRO_PLUS_2:
case BLDevice.DEV_RM_2_PRO_PLUS_2_BL:
case BLDevice.DEV_RM_MINI_SHATE:
baseType = BLDevice.DEV_RM_2;
break;
}
BroadlinkEntry anEntry = new BroadlinkEntry();
anEntry.setId(broadlinkObject.getHost() + "-" + String.format("%04x", broadlinkObject.getDeviceType()));
anEntry.setName(broadlinkObject.getDeviceDescription());
anEntry.setType(String.format("%04x", broadlinkObject.getDeviceType()));
anEntry.setBaseType(String.format("%04x", baseType));
anEntry.setDesc(BLDevice.getDescOfType(broadlinkObject.getDeviceType()));
anEntry.setIpAddr(broadlinkObject.getHost());
anEntry.setMacAddr(broadlinkObject.getMac().getMacString());
return anEntry;
}
public BLDevice[] broadlinkDiscover () {
BLDevice[] clients = null;
int aDiscoverPort = Configuration.BROADLINK_DISCOVER_PORT;
broadlinkMap = new HashMap<String, BLDevice>();
while(aDiscoverPort > 0) {
try {
log.info("Broadlink discover....");
if(isDevMode) {
clients = TestBLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
}
else
clients = BLDevice.discoverDevices(InetAddress.getByName(bridgeSettingsDesc.getUpnpConfigAddress()), aDiscoverPort, Configuration.BROADLINK_DISCONVER_TIMEOUT);
for(int i = 0; i < clients.length; i++) {
if(clients[i].getDeviceType() != BLDevice.DEV_A1 && broadlinkMap.get(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType())) == null) {
broadlinkMap.put(clients[i].getHost() + "-" + String.format("%04x", clients[i].getDeviceType()), clients[i]);
log.debug("Adding Device to Map - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
} else {
log.debug("Ignoring Device (already in the list or an A1 Device) - host: " + clients[i].getHost() + ", device Type: " + clients[i].getDeviceDescription() + ", mac: " + (clients[i].getMac() == null ? "no Mac in client" : clients[i].getMac().getMacString()));
}
}
aDiscoverPort = 0;
} catch (BindException e) {
log.warn("Could not discover Broadlinks, Port in use, increasing by 11");
aDiscoverPort += 11;
if(aDiscoverPort > Configuration.BROADLINK_DISCOVER_PORT + 110)
aDiscoverPort = 0;
} catch (IOException e) {
log.warn("Could not discover Broadlinks, with IO Exception", e);
broadlinkMap = null;
aDiscoverPort = 0;
}
}
if(clients == null || clients.length <= 0) {
log.warn("Did not discover any Broadlinks.");
broadlinkMap = null;
} else {
log.info("Broadlink discover found " + clients.length + " clients.");
}
return clients;
}
@Override
public void closeHome() {
if(!validBroadlink)
return;
log.debug("Closing Home.");
if(broadlinkMap != null) {
broadlinkMap.clear();
broadlinkMap = null;
}
if(closed) {
log.debug("Home is already closed....");
return;
}
closed = true;
}
}

View File

@@ -0,0 +1,73 @@
package com.bwssystems.HABridge.plugins.broadlink;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.mob41.blapi.BLDevice;
import com.github.mob41.blapi.mac.Mac;
import com.github.mob41.blapi.pkt.CmdPayload;
public class TestBLDevice extends BLDevice {
private static final Logger log = LoggerFactory.getLogger(TestBLDevice.class);
protected TestBLDevice(short deviceType, String deviceDesc, String host, Mac mac) throws IOException {
super(deviceType, deviceDesc, host, mac);
}
public void setState(boolean aState) {
log.info("setState called with " + aState);
}
public void setState(int anIndex, boolean aState) {
log.info("setState called with index " + anIndex + " and state " + aState);
}
public void setPower(boolean aState) {
log.info("setPower called with " + aState);
}
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
return null;
}
public static BLDevice[] discoverDevices(InetAddress theAddress, int aport, int timeout) {
TestMP1Device mp1Device = null;
TestSP1Device sp1Device = null;
TestSP2Device sp2Device = null;
TestRM2Device rm2Device = null;
try {
mp1Device = new TestMP1Device("mp1host", null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
sp1Device = new TestSP1Device("sp1host", null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
sp2Device = new TestSP2Device("sp2host", null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
rm2Device = new TestRM2Device("rm2host", null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BLDevice[] devices = { mp1Device, sp1Device, sp2Device, rm2Device };
log.info("Created test devices");
return devices;
}
}

View File

@@ -0,0 +1,29 @@
package com.bwssystems.HABridge.plugins.broadlink;
import java.io.IOException;
import java.net.DatagramPacket;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.mob41.blapi.MP1Device;
import com.github.mob41.blapi.mac.Mac;
import com.github.mob41.blapi.pkt.CmdPayload;
public class TestMP1Device extends MP1Device {
private static final Logger log = LoggerFactory.getLogger(TestMP1Device.class);
protected TestMP1Device(String host, Mac mac) throws IOException {
super(host, mac);
}
public void setState(int anIndex, boolean aState) {
log.info("setState called with index " + anIndex + " and state " + aState);
}
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
return null;
}
}

View File

@@ -0,0 +1,27 @@
package com.bwssystems.HABridge.plugins.broadlink;
import java.io.IOException;
import java.net.DatagramPacket;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.mob41.blapi.RM2Device;
import com.github.mob41.blapi.mac.Mac;
import com.github.mob41.blapi.pkt.CmdPayload;
import com.github.mob41.blapi.pkt.cmd.rm2.SendDataCmdPayload;
public class TestRM2Device extends RM2Device {
private static final Logger log = LoggerFactory.getLogger(TestRM2Device.class);
protected TestRM2Device(String host, Mac mac) throws IOException {
super(host, mac);
}
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(((SendDataCmdPayload)aCmd).getData()));
return null;
}
}

View File

@@ -0,0 +1,30 @@
package com.bwssystems.HABridge.plugins.broadlink;
import java.io.IOException;
import java.net.DatagramPacket;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.mob41.blapi.SP1Device;
import com.github.mob41.blapi.mac.Mac;
import com.github.mob41.blapi.pkt.CmdPayload;
public class TestSP1Device extends SP1Device {
private static final Logger log = LoggerFactory.getLogger(TestSP1Device.class);
protected TestSP1Device(String host, Mac mac) throws IOException {
super(host, mac);
}
public void setPower(boolean aState) {
log.info("setPower called with " + aState);
}
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
return null;
}
}

View File

@@ -0,0 +1,30 @@
package com.bwssystems.HABridge.plugins.broadlink;
import java.io.IOException;
import java.net.DatagramPacket;
import javax.xml.bind.DatatypeConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.mob41.blapi.SP2Device;
import com.github.mob41.blapi.mac.Mac;
import com.github.mob41.blapi.pkt.CmdPayload;
public class TestSP2Device extends SP2Device {
private static final Logger log = LoggerFactory.getLogger(TestSP2Device.class);
protected TestSP2Device(String host, Mac mac) throws IOException {
super(host, mac);
}
public void setState(boolean aState) {
log.info("setState called with " + aState);
}
public DatagramPacket sendCmdPkt(int timeout, CmdPayload aCmd) {
log.info("sendCmdPkt called with " + DatatypeConverter.printHexBinary(aCmd.getPayload().getData()));
return null;
}
}

View File

@@ -18,7 +18,10 @@ import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.bwssystems.HABridge.plugins.http.HTTPHome;
import com.google.gson.Gson;
@@ -41,7 +44,7 @@ public class DomoticzHome implements Home {
public Object getItems(String type) {
if(!validDomoticz)
return null;
log.debug("consolidating devices for hues");
log.debug("consolidating devices for Domoticzs");
List<DomoticzDevice> theResponse = null;
Iterator<String> keys = domoticzs.keySet().iterator();
List<DomoticzDevice> deviceList = new ArrayList<DomoticzDevice>();
@@ -63,6 +66,11 @@ public class DomoticzHome implements Home {
return deviceList;
}
@Override
public void refresh() {
// noop
}
private Boolean addDomoticzDevices(List<DomoticzDevice> theDeviceList, List<DomoticzDevice> theSourceList, String theKey) {
if(!validDomoticz)
return null;
@@ -95,7 +103,23 @@ public class DomoticzHome implements Home {
String theData;
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
intensity, targetBri, targetBriInc, false);
theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, null, theHandler.buildHeaders());
if (colorData != null) {
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
anUrl = TimeDecode.replaceTimeValue(anUrl);
String aBody = null;
if(anItem.getHttpBody()!= null && !anItem.getHttpBody().isEmpty()) {
aBody = BrightnessDecode.calculateReplaceIntensityValue(anItem.getHttpBody(),
intensity, targetBri, targetBriInc, false);
if (colorData != null) {
aBody = ColorDecode.replaceColorData(aBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
aBody = DeviceDataDecode.replaceDeviceData(aBody, device);
aBody = TimeDecode.replaceTimeValue(aBody);
}
theData = httpClient.doHttpRequest(theHandler.buildUrl(anUrl), null, null, aBody, theHandler.buildHeaders());
try {
theDomoticzApiResponse = new Gson().fromJson(theData, Devices.class);
if(theDomoticzApiResponse.getStatus().equals("OK"))
@@ -167,7 +191,7 @@ public class DomoticzHome implements Home {
@Override
public void closeHome() {
log.debug("Closing Home.");
if(closed) {
if(closed || !validDomoticz) {
log.debug("Home is already closed....");
return;
}
@@ -175,6 +199,7 @@ public class DomoticzHome implements Home {
if(httpClient != null)
httpClient.closeHandler();
domoticzs = null;
closed = true;
}
}

View File

@@ -92,6 +92,11 @@ public class CommandHome implements Home {
return null;
}
@Override
public void refresh() {
// noop
}
@Override
public void closeHome() {
log.debug("Closing Home.");

View File

@@ -0,0 +1,19 @@
package com.bwssystems.HABridge.plugins.fhem;
public class FHEMCommand {
private String url;
private String command;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
}

View File

@@ -0,0 +1,26 @@
package com.bwssystems.HABridge.plugins.fhem;
public class FHEMDevice {
private String address;
private String name;
private Result item;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Result getItem() {
return item;
}
public void setItem(Result item) {
this.item = item;
}
}

View File

@@ -0,0 +1,213 @@
package com.bwssystems.HABridge.plugins.fhem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.Home;
import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.api.hue.HueError;
import com.bwssystems.HABridge.api.hue.HueErrorResponse;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.bwssystems.HABridge.plugins.http.HTTPHome;
import com.bwssystems.HABridge.plugins.http.HttpTestHandler;
import com.google.gson.Gson;
public class FHEMHome implements Home {
private static final Logger log = LoggerFactory.getLogger(FHEMHome.class);
private Map<String, FHEMInstance> fhemMap;
private Boolean validFhem;
private Boolean isDevMode;
private HTTPHandler httpClient;
private boolean closed;
public FHEMHome(BridgeSettings bridgeSettings) {
super();
closed = true;
createHome(bridgeSettings);
closed = false;
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String theUrl = anItem.getItem().getAsString();
String responseString = null;
if(theUrl != null && !theUrl.isEmpty()) {
FHEMCommand theCommand = null;
try {
theCommand = new Gson().fromJson(theUrl, FHEMCommand.class);
} catch(Exception e) {
log.warn("Cannot parse command to FHEM <<<" + theUrl + ">>>", e);
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;
}
String intermediate = theCommand.getUrl().substring(theCommand.getUrl().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;
FHEMInstance theHandler = findHandlerByAddress(hostAddr);
if(theHandler != null) {
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
intensity, targetBri, targetBriInc, false);
if (colorData != null) {
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
anUrl = TimeDecode.replaceTimeValue(anUrl);
String aCommand = null;
if(theCommand.getCommand() != null && !theCommand.getCommand().isEmpty()) {
aCommand = BrightnessDecode.calculateReplaceIntensityValue(theCommand.getCommand(),
intensity, targetBri, targetBriInc, false);
if (colorData != null) {
aCommand = ColorDecode.replaceColorData(aCommand, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
aCommand = DeviceDataDecode.replaceDeviceData(aCommand, device);
aCommand = TimeDecode.replaceTimeValue(aCommand);
}
try {
theHandler.callCommand(anUrl, aCommand, httpClient);
} catch (Exception e) {
log.warn("Cannot send comand to FHEM", e);
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("FHEM 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("FHEM Call to be presented as http(s)://<ip_address>(:<port>)/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;
}
private FHEMInstance findHandlerByAddress(String hostAddress) {
FHEMInstance aHandler = null;
boolean found = false;
Iterator<String> keys = fhemMap.keySet().iterator();
while(keys.hasNext()) {
String key = keys.next();
aHandler = fhemMap.get(key);
if(aHandler != null && aHandler.getFhemAddress().getIp().equals(hostAddress)) {
found = true;
break;
}
}
if(!found)
aHandler = null;
return aHandler;
}
@Override
public Object getItems(String type) {
if(!validFhem)
return null;
log.debug("consolidating devices for FHEM");
List<FHEMDevice> theResponse = null;
Iterator<String> keys = fhemMap.keySet().iterator();
List<FHEMDevice> deviceList = new ArrayList<FHEMDevice>();
while(keys.hasNext()) {
String key = keys.next();
theResponse = fhemMap.get(key).getDevices(httpClient);
if(theResponse != null)
addFHEMDevices(deviceList, theResponse, key);
else {
log.warn("Cannot get devices for FHEM: " + key + ", skipping this FHEM.");
continue;
}
}
return deviceList;
}
@Override
public void refresh() {
// noop
}
private Boolean addFHEMDevices(List<FHEMDevice> theDeviceList, List<FHEMDevice> theSourceList, String theKey) {
Iterator<FHEMDevice> devices = theSourceList.iterator();
while(devices.hasNext()) {
FHEMDevice theDevice = devices.next();
theDeviceList.add(theDevice);
}
return true;
}
@Override
public Home createHome(BridgeSettings bridgeSettings) {
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
fhemMap = null;
validFhem = bridgeSettings.getBridgeSettingsDescriptor().isValidFhem();
log.info("FHEM Home created." + (validFhem ? "" : " No FHEMs configured.") + (isDevMode ? " DevMode is set." : ""));
if(validFhem) {
fhemMap = new HashMap<String,FHEMInstance>();
httpClient = HTTPHome.getHandler();
if(isDevMode) {
httpClient = new HttpTestHandler();
((HttpTestHandler)httpClient).setTheData("cmd=jsonlist2", FHEMTestData.TestData);
((HttpTestHandler)httpClient).setTheData("set", "FHEM Command Received");
((HttpTestHandler)httpClient).setTheData(null, "FHEM no match");
}
httpClient.setCallType(DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex]);
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getFhemaddress().getDevices().iterator();
while(theList.hasNext() && validFhem) {
NamedIP aFhem = theList.next();
try {
fhemMap.put(aFhem.getName(), new FHEMInstance(aFhem));
} catch (Exception e) {
log.error("Cannot get FHEM (" + aFhem.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
validFhem = false;
}
}
}
return this;
}
@Override
public void closeHome() {
log.debug("Closing Home.");
if(!closed && validFhem) {
log.debug("Home is already closed....");
return;
}
if(httpClient != null)
httpClient.closeHandler();
fhemMap = null;
closed = true;
}
}

View File

@@ -0,0 +1,111 @@
package com.bwssystems.HABridge.plugins.fhem;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
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;
public class FHEMInstance {
private static final Logger log = LoggerFactory.getLogger(FHEMInstance.class);
private NamedIP theFhem;
public FHEMInstance(NamedIP fhemLocation) {
super();
theFhem = fhemLocation;
}
public NamedIP getFhemAddress() {
return theFhem;
}
public void setFhemAddress(NamedIP fhemAddress) {
this.theFhem = fhemAddress;
}
public Boolean callCommand(String aCommand, String commandData, HTTPHandler httpClient) {
String aUrl = null;
NameValue[] headers = null;
if(theFhem.getSecure() != null && theFhem.getSecure())
aUrl = "https://";
else
aUrl = "http://";
if(theFhem.getUsername() != null && !theFhem.getUsername().isEmpty() && theFhem.getPassword() != null && !theFhem.getPassword().isEmpty()) {
aUrl = aUrl + theFhem.getUsername() + ":" + theFhem.getPassword() + "@";
}
aUrl = aUrl + theFhem.getIp() + ":" + theFhem.getPort() + "/" + aCommand + commandData;
log.debug("calling FHEM: " + aUrl);
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "text/plain", null, headers);
if(theData != null)
log.debug("doHttpRequest returned data: <" + theData + ">");
return true;
}
public List<FHEMDevice> getDevices(HTTPHandler httpClient) {
List<FHEMDevice> deviceList = null;
FHEMItem theFhemStates;
String theUrl = null;
String theData;
NameValue[] headers = null;
if(theFhem.getSecure() != null && theFhem.getSecure())
theUrl = "https://";
else
theUrl = "http://";
if(theFhem.getUsername() != null && !theFhem.getUsername().isEmpty() && theFhem.getPassword() != null && !theFhem.getPassword().isEmpty()) {
theUrl = theUrl + theFhem.getUsername() + ":" + theFhem.getPassword() + "@";
}
theUrl = theUrl + theFhem.getIp() + ":" + theFhem.getPort() + "/fhem?cmd=jsonlist2";
if(theFhem.getWebhook() != null && !theFhem.getWebhook().trim().isEmpty())
theUrl = theUrl + "%20room=" + theFhem.getWebhook().trim();
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
if(theData != null) {
log.debug("GET FHEM States - data: " + theData);
theData = getJSONData(theData);
theFhemStates = new Gson().fromJson(theData, FHEMItem.class);
if(theFhemStates == null) {
log.warn("Cannot get any devices for FHEM " + theFhem.getName() + " as response is not parsable.");
}
else {
deviceList = new ArrayList<FHEMDevice>();
for (Result aResult:theFhemStates.getResults()) {
String name = aResult.getName();
if(name.contains("<a href=")) {
name = name.substring(name.indexOf("<a href=") + name.indexOf(">"));
name = name.substring(1, name.indexOf("</a"));
aResult.setName(name);
}
FHEMDevice aNewFhemDeviceDevice = new FHEMDevice();
aNewFhemDeviceDevice.setItem(aResult);
aNewFhemDeviceDevice.setAddress(theFhem.getIp() + ":" + theFhem.getPort());
aNewFhemDeviceDevice.setName(theFhem.getName());
deviceList.add(aNewFhemDeviceDevice);
}
}
}
else
log.warn("Cannot get an devices for FHEM " + theFhem.getName() + " http call failed.");
return deviceList;
}
public String getJSONData(String response) {
String theData;
theData = response.substring(response.indexOf("<pre>") + 4);
theData = theData.substring(1, theData.indexOf("</pre>") - 1);
theData = theData.replace("\n", "");
theData = theData.replace("\r", "");
theData = theData.replace("<a href=\"", "<a href=\\\"");
theData = theData.replace("\">", "\\\">");
return theData;
}
protected void closeClient() {
}
}

View File

@@ -0,0 +1,44 @@
package com.bwssystems.HABridge.plugins.fhem;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class FHEMItem {
@SerializedName("Arg")
@Expose
private String arg;
@SerializedName("Results")
@Expose
private List<Result> results = null;
@SerializedName("totalResultsReturned")
@Expose
private Integer totalResultsReturned;
public String getArg() {
return arg;
}
public void setArg(String arg) {
this.arg = arg;
}
public List<Result> getResults() {
return results;
}
public void setResults(List<Result> results) {
this.results = results;
}
public Integer getTotalResultsReturned() {
return totalResultsReturned;
}
public void setTotalResultsReturned(Integer totalResultsReturned) {
this.totalResultsReturned = totalResultsReturned;
}
}

View File

@@ -0,0 +1,288 @@
package com.bwssystems.HABridge.plugins.fhem;
public class FHEMTestData {
public final static String TestData = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
" <head root=\"/fhem\">\n" +
" <title>Home, Sweet Home</title>\n" +
" <link rel=\"shortcut icon\" href=\"/fhem/icons/favicon\" />\n" +
" <meta charset=\"UTF-8\">\n" +
" <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
" <link href=\"/fhem/pgm2/style.css?v=1513026539\" rel=\"stylesheet\"/>\n" +
" <link href=\"/fhem/pgm2/jquery-ui.min.css\" rel=\"stylesheet\"/>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery.min.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery-ui.min.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_colorpicker.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_fbcalllist.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_knob.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsGroup.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsHistory.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_sortable.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_uzsu.js\"></script>\n" +
" <script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_weekprofile.js\"></script>\n" +
" </head>\n" +
" <body name='Home, Sweet Home' fw_id='7880' generated=\"1513272732\" longpoll=\"1\" data-confirmDelete='1' data-confirmJSError='1' data-webName='haBridgeWeb '>\n" +
" <div id=\"menuScrollArea\">\n" +
" <div>\n" +
" <a href=\"/fhem?\">\n" +
" <div id=\"logo\"></div>\n" +
" </a>\n" +
" </div>\n" +
" <div id=\"menu\">\n" +
" <table>\n" +
" <tr>\n" +
" <td>\n" +
" <table class=\"room roomBlock1\">\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_Save_config\">\n" +
" <a href=\"/fhem?cmd=save\">Save config</a>\n" +
" <a id=\"saveCheck\" class=\"changed\" style=\"visibility:visible\">?</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <table class=\"room roomBlock2\">\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_Alexa\">\n" +
" <a href=\"/fhem?room=Alexa\">Alexa</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_System\">\n" +
" <a href=\"/fhem?room=System\">System</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_WG_Zimmer\">\n" +
" <a href=\"/fhem?room=WG%2dZimmer\">WG-Zimmer</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_habridge\">\n" +
" <a href=\"/fhem?room=habridge\">habridge</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_Everything\">\n" +
" <a href=\"/fhem?room=all\">\n" +
" <img class='icon icoEverything' src=\"/fhem/images/default/icoEverything.png\" alt=\"icoEverything\" title=\"icoEverything\">&nbsp;Everything\n" +
" </a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <table class=\"room roomBlock3\">\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_Logfile\">\n" +
" <a href=\"/fhem/FileLog_logWrapper?dev=Logfile&type=text&file=fhem-2017-12.log\">Logfile</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div>\n" +
" <a href=\"/fhem/docs/commandref.html\" target=\"_blank\" >Commandref</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div>\n" +
" <a href=\"http://fhem.de/fhem.html#Documentation\" target=\"_blank\" >Remote doc</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_Edit_files\">\n" +
" <a href=\"/fhem?cmd=style%20list\">Edit files</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_Select_style\">\n" +
" <a href=\"/fhem?cmd=style%20select\">Select style</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" <tr>\n" +
" <td>\n" +
" <div class=\"menu_Event_monitor\">\n" +
" <a href=\"/fhem?cmd=style%20eventMonitor\">Event monitor</a>\n" +
" </div>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </div>\n" +
" </div>\n" +
" <div id=\"hdr\">\n" +
" <table border=\"0\" class=\"header\">\n" +
" <tr>\n" +
" <td style=\"padding:0\">\n" +
" <form method=\"post\" action=\"/fhem\">\n" +
" <input type=\"hidden\" name=\"fw_id\" value=\"7880\"/>\n" +
" <input type=\"text\" name=\"cmd\" class=\"maininput\" size=\"40\" value=\"\"/>\n" +
" </form>\n" +
" </td>\n" +
" </tr>\n" +
" </table>\n" +
" </div>\n" +
" <div id='content' >\n" +
" <pre>{ \n" +
" \"Arg\":\"room=habridge\", \n" +
" \"Results\": [ \n" +
" { \n" +
" \"Name\":\"Arbeitslicht\", \n" +
" \"PossibleSets\":\"on off\", \n" +
" \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 readingList setList useSetExtensions disable disabledForIntervals event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alexaName alexaRoom cmdIcon devStateIcon devStateStyle fhem_widget_command fhem_widget_command_2 fhem_widget_command_3 genericDeviceType:security,ignore,switch,outlet,light,blind,thermometer,thermostat,contact,garage,window,lock homebridgeMapping:textField-long icon sortby webCmd widgetOverride userattr\", \n" +
" \"Internals\": { \n" +
" \"NAME\": \"Arbeitslicht\", \n" +
" \"NR\": \"28\", \n" +
" \"STATE\": \"-\", \n" +
" \"TYPE\": \"dummy\" \n" +
" }, \n" +
" \"Readings\": { \"state\": { \"Value\":\"on\", \"Time\":\"2017-12-14 15:41:05\" } }, \n" +
" \"Attributes\": { \n" +
" \"alexaName\": \"Arbeitslicht\", \n" +
" \"alexaRoom\": \"alexaroom\", \n" +
" \"fhem_widget_command\": \"{ \\u0022allowed_values\\u0022 : [ \\u0022on\\u0022 ], \\u0022order\\u0022 : 0}\", \n" +
" \"icon\": \"scene_office\", \n" +
" \"room\": \"Alexa,habridge\", \n" +
" \"setList\": \"on off\", \n" +
" \"stateFormat\": \"-\", \n" +
" \"webCmd\": \"on\" \n" +
" } \n" +
" }, \n" +
" { \n" +
" \"Name\":\"DeckenlampeLinks\", \n" +
" \"PossibleSets\":\"on off dim dimup dimdown HSV RGB sync pair unpair\", \n" +
" \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 gamma dimStep defaultColor defaultRamp colorCast whitePoint event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alexaName alexaRoom cmdIcon devStateIcon devStateStyle fhem_widget_command fhem_widget_command_2 fhem_widget_command_3 genericDeviceType:security,ignore,switch,outlet,light,blind,thermometer,thermostat,contact,garage,window,lock homebridgeMapping:textField-long icon sortby webCmd widgetOverride \n" +
" <a href=\"/fhem?detail=AlleLampen\">AlleLampen</a> AlleLampen_map\n" +
" <a href=\"/fhem?detail=DeckenLampen\">DeckenLampen</a> DeckenLampen_map structexclude userattr\", \n" +
" \"Internals\": { \n" +
" \"CONNECTION\": \"bridge-V3\", \n" +
" \"DEF\": \"RGBW2 bridge-V3:10.2.3.3\", \n" +
" \"IP\": \"10.2.3.3\", \n" +
" \"LEDTYPE\": \"RGBW2\", \n" +
" \"NAME\": \"DeckenlampeLinks\", \n" +
" \"NR\": \"18\", \n" +
" \"NTFY_ORDER\": \"50-DeckenlampeLinks\", \n" +
" \"PORT\": \"8899\", \n" +
" \"PROTO\": \"0\", \n" +
" \"SLOT\": \"5\", \n" +
" \"STATE\": \"off\", \n" +
" \"TYPE\": \"WifiLight\" \n" +
" }, \n" +
" \"Readings\": { \n" +
" \"RGB\": { \"Value\":\"000000\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
" \"brightness\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
" \"hue\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
" \"saturation\": { \"Value\":\"0\", \"Time\":\"2017-12-14 15:41:10\" }, \n" +
" \"state\": { \"Value\":\"off\", \"Time\":\"2017-12-14 15:41:10\" } \n" +
" }, \n" +
" \"Attributes\": { \n" +
" \"AlleLampen\": \"AlleLampen\", \n" +
" \"DeckenLampen\": \"DeckenLampen\", \n" +
" \"fhem_widget_command\": \"{ \\u0022locations\\u0022 : [ \\u0022APP\\u0022, \\u0022WATCH\\u0022, \\u0022WIDGET\\u0022 ], \\u0022allowed_values\\u0022 : [ \\u0022off\\u0022, \\u0022on\\u0022 ], \\u0022order\\u0022 : 6}\", \n" +
" \"room\": \"habridge,Alexa,WG-Zimmer\", \n" +
" \"userattr\": \"AlleLampen AlleLampen_map\n" +
" <a href=\"/fhem?detail=DeckenLampen\">DeckenLampen</a> DeckenLampen_map structexclude\", \n" +
" \"webCmd\": \"RGB\", \n" +
" \"widgetOverride\": \"RGB:colorpicker,RGB\" \n" +
" } \n" +
" } ], \n" +
" \"totalResultsReturned\":2 \n" +
"}\n" +
" </pre>\n" +
" </div>\n" +
" </body>\n" +
"</html>";
public final static String TestData2 = " <div id='content' >\n" +
" <pre>\n" + "{ \"Arg\":\"room=HaBridge\", \"Results\": [ { \"Name\":\"wifi_steckdose3\", \"PossibleSets\":\"on:noArg off:noArg off on toggle\", \"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 IODev qos retain publishSet publishSet_.* subscribeReading_.* autoSubscribeReadings event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alarmDevice:Actor,Sensor alarmSettings cmdIcon devStateIcon devStateStyle icon lightSceneParamsToSave lightSceneRestoreOnlyIfChanged:1,0 sortby structexclude webCmd webCmdLabel:textField-long widgetOverride userattr\", \"Internals\": { \"CHANGED\": \"null\", \"NAME\": \"wifi_steckdose3\", \"NR\": \"270\", \"STATE\": \"off\", \"TYPE\": \"MQTT_DEVICE\", \"retain\": \"*:1 \" }, \"Readings\": { \"state\": { \"Value\":\"OFF\", \"Time\":\"2018-01-01 23:01:21\" }, \"transmission-state\": { \"Value\":\"subscription acknowledged\", \"Time\":\"2018-01-03 22:34:00\" } }, \"Attributes\": { \"IODev\": \"myBroker\", \"alias\": \"Stecki\", \"devStateIcon\": \"on:black_Steckdose.on off:black_Steckdose.off\", \"event-on-change-reading\": \"state\", \"eventMap\": \"ON:on OFF:off\", \"publishSet\": \"on off toggle /SmartHome/az/stecker/cmnd/POWER\", \"retain\": \"1\", \"room\": \"HaBridge,Arbeitszimmer,mqtt\", \"stateFormat\": \"state\", \"subscribeReading_state\": \"/SmartHome/az/stecker/stat/POWER\", \"webCmd\": \"on:off:toggle\" } } ], \"totalResultsReturned\":1 }" +
" </pre>\n" +
" </div>\n" +
" </body>\n" +
"</html>";
public final static String TestData3 ="DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
"<head root=\"/fhem\">\n" +
"<title>Home, Sweet Home</title>\n" +
"<link rel=\"shortcut icon\" href=\"/fhem/icons/favicon\" />\n" +
"<meta charset=\"UTF-8\">\n" +
"<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
"<link href=\"/fhem/pgm2/style.css?v=1515015198\" rel=\"stylesheet\"/>\n" +
"<link href=\"/fhem/pgm2/jquery-ui.min.css\" rel=\"stylesheet\"/>\n" +
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery.min.js\"></script>\n" +
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/jquery-ui.min.js\"></script>\n" +
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb.js\"></script>\n" +
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/doif.js\"></script>\n" +
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fronthemEditor.js\"></script>\n" +
"<script attr='' type=\"text/javascript\" src=\"/fhem/pgm2/fhemweb_readingsGroup.js\"></script>\n" +
"</head>\n" +
"<body name='Home, Sweet Home' fw_id='1490' generated=\"1515770038\" longpoll=\"websocket\" data-confirmDelete='1' data-confirmJSError='1' data-addHtmlTitle='1' data-availableJs='sortable,iconLabel,readingsHistory,colorpicker,iconButtons,fbcalllist,knob,weekprofile,iconRadio,readingsGroup,iconSwitch,uzsu' data-webName='WEB '>\n" +
"<div id=\"menuScrollArea\">\n" +
"</div>\n" +
"<div id='content' >\n" +
"<pre>{\n" +
"\"Arg\":\"room=HaBridge\",\n" +
"\"Results\": [\n" +
"{\n" +
"\"Name\":\"<a href='/fhem?detail=wifi_steckdose3'>wifi_steckdose3</a>\",\n" +
"\"PossibleSets\":\"on:noArg off:noArg off on toggle\",\n" +
"\"PossibleAttrs\":\"alias comment:textField-long eventMap group room suppressReading userReadings:textField-long verbose:0,1,2,3,4,5 IODev qos retain publishSet publishSet_.* subscribeReading_.* autoSubscribeReadings event-on-change-reading event-on-update-reading event-aggregator event-min-interval stateFormat:textField-long timestamp-on-change-reading alarmDevice:Actor,Sensor alarmSettings cmdIcon devStateIcon devStateStyle icon lightSceneParamsToSave lightSceneRestoreOnlyIfChanged:1,0 sortby structexclude webCmd webCmdLabel:textField-long widgetOverride userattr\",\n" +
"\"Internals\": {\n" +
"\"NAME\": \"<a href='/fhem?detail=wifi_steckdose3'>wifi_steckdose3</a>\",\n" +
"\"NR\": \"270\",\n" +
"\"STATE\": \"off\",\n" +
"\"TYPE\": \"MQTT_DEVICE\",\n" +
"\"retain\": \"*:1 \"\n" +
"},\n" +
"\"Readings\": {\n" +
"\"state\": { \"Value\":\"OFF\", \"Time\":\"2018-01-07 05:16:01\" },\n" +
"\"transmission-state\": { \"Value\":\"incoming publish received\", \"Time\":\"2018-01-07 05:16:01\" }\n" +
"},\n" +
"\"Attributes\": {\n" +
"\"IODev\": \"<a href='/fhem?detail=myBroker'>myBroker</a>\",\n" +
"\"alias\": \"Stecki\",\n" +
"\"devStateIcon\": \"on:black_Steckdose.on off:black_Steckdose.off\",\n" +
"\"event-on-change-reading\": \"state\",\n" +
"\"eventMap\": \"ON:on OFF:off\",\n" +
"\"publishSet\": \"on off toggle /SmartHome/az/stecker/cmnd/POWER\",\n" +
"\"retain\": \"1\",\n" +
"\"room\": \"HaBridge,Arbeitszimmer,mqtt\",\n" +
"\"stateFormat\": \"state\",\n" +
"\"subscribeReading_state\": \"/SmartHome/az/stecker/stat/POWER\",\n" +
"\"webCmd\": \"on:off:toggle\"\n" +
"}\n" +
"} ],\n" +
"\"totalResultsReturned\":1\n" +
"}\n" +
"</pre>\n" +
"</div>\n" +
"</body></html>";
}

View File

@@ -0,0 +1,43 @@
package com.bwssystems.HABridge.plugins.fhem;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Result {
@SerializedName("Name")
@Expose
private String name;
@SerializedName("PossibleSets")
@Expose
private String possibleSets;
@SerializedName("PossibleAttrs")
@Expose
private String possibleAttrs;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPossibleSets() {
return possibleSets;
}
public void setPossibleSets(String possibleSets) {
this.possibleSets = possibleSets;
}
public String getPossibleAttrs() {
return possibleAttrs;
}
public void setPossibleAttrs(String possibleAttrs) {
this.possibleAttrs = possibleAttrs;
}
}

View File

@@ -0,0 +1,34 @@
package com.bwssystems.HABridge.plugins.fibaro;
public class FibaroFilter {
boolean useSaveLogs;
boolean useUserDescription;
boolean scenesLiliCmddOnly;
boolean replaceTrash;
public boolean isUseSaveLogs() {
return useSaveLogs;
}
public void setUseSaveLogs(boolean useSaveLogs) {
this.useSaveLogs = useSaveLogs;
}
public boolean isUseUserDescription() {
return useUserDescription;
}
public void setUseUserDescription(boolean useUserDescription) {
this.useUserDescription = useUserDescription;
}
public boolean isReplaceTrash() {
return replaceTrash;
}
public void setReplaceTrash(boolean replaceTrash) {
this.replaceTrash = replaceTrash;
}
public boolean isScenesLiliCmddOnly() {
return scenesLiliCmddOnly;
}
public void setScenesLiliCmddOnly(boolean scenesLiliCmddOnly) {
this.scenesLiliCmddOnly = scenesLiliCmddOnly;
}
}

View File

@@ -84,6 +84,11 @@ public class FibaroHome implements Home
return null;
}
@Override
public void refresh() {
// noop
}
@Override
public Home createHome(BridgeSettings bridgeSettings)
{

View File

@@ -23,19 +23,33 @@ public class FibaroInfo
private final NamedIP fibaroAddress;
private final String fibaroAuth;
private final Gson gson;
// You can disable it if you want TODO config
boolean useSaveLogs = true; // This can be used to exclude some devices from list
boolean useUserDescription = true;
boolean replaceTrash = true;
boolean scenesWithLiliCommandOnly = true;
private Boolean isDevMode;
private FibaroFilter theFilters;
public FibaroInfo(NamedIP addressName)
{
super();
fibaroAddress = addressName;
fibaroAuth = "Basic " + new String(Base64.encodeBase64((addressName.getUsername() + ":" + addressName.getPassword()).getBytes()));
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
gson = new Gson();
theFilters = null;
if(fibaroAddress.getExtensions() != null) {
try {
theFilters = gson.fromJson(fibaroAddress.getExtensions(), FibaroFilter.class);
} catch(Exception e) {
log.warn("Could not read fibaro filters - continuing with defaults.");
theFilters = null;
}
}
if(theFilters == null) {
theFilters = new FibaroFilter();
theFilters.setUseSaveLogs(false);
theFilters.setUseUserDescription(false);
theFilters.setScenesLiliCmddOnly(false);
theFilters.setReplaceTrash(true);
}
}
private String request(String request)
@@ -66,24 +80,6 @@ public class FibaroInfo
return result;
}
protected boolean sendCommand(String request)
{
try
{
URL url = new URL("http://" + fibaroAddress.getIp() + ":" + fibaroAddress.getPort() + request);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", fibaroAuth);
connection.getResponseMessage();
}
catch(IOException e)
{
log.warn("Error while get getJson: {} ", request, e);
return false;
}
return true;
}
private String replaceTrash(String name)
{
String sanitizedName = name.replaceAll("[0-9:/-]", "");
@@ -93,9 +89,14 @@ public class FibaroInfo
private Room[] getRooms()
{
String result = request("/api/rooms");
String result = null;
if(isDevMode)
result = FibaroTestData.RoomTestData;
else
result = request("/api/rooms");
log.debug("getRooms response: <<<" + result + ">>>");
Room[] rooms = result == null ? new Room[0] : gson.fromJson(result, Room[].class);
if(replaceTrash)
if(theFilters.isReplaceTrash())
for(Room r : rooms)
r.setName(replaceTrash(r.getName()));
return rooms;
@@ -105,24 +106,29 @@ public class FibaroInfo
{
Room[] rooms = getRooms();
log.info("Found: " + rooms.length + " rooms");
log.debug("getDevices Found: " + rooms.length + " rooms");
String result = request("/api/devices?enabled=true&visible=true");
String result = null;
if(isDevMode)
result = FibaroTestData.DeviceTestData;
else
result = request("/api/devices?enabled=true&visible=true");
log.debug("getDevices response: <<<" + result + ">>>");
Device[] all_devices = result == null ? new Device[0] : gson.fromJson(result, Device[].class);
int count = 0;
for(Device d : all_devices)
if(d.getRoomID() > 0 && (useSaveLogs ? "true".equals(d.getProperties().getSaveLogs()) : true))
if(d.getRoomID() > 0 && (theFilters.isUseSaveLogs() ? "true".equals(d.getProperties().getSaveLogs()) : true))
count++;
Device[] devices = new Device[count];
int i = 0;
for(Device d : all_devices)
if(d.getRoomID() > 0 && (useSaveLogs ? "true".equals(d.getProperties().getSaveLogs()) : true))
if(d.getRoomID() > 0 && (theFilters.isUseSaveLogs() ? "true".equals(d.getProperties().getSaveLogs()) : true))
{
if(useUserDescription && d.getProperties().getUserDescription() != null && !d.getProperties().getUserDescription().isEmpty())
if(theFilters.isUseUserDescription() && d.getProperties().getUserDescription() != null && !d.getProperties().getUserDescription().isEmpty())
d.setName(d.getProperties().getUserDescription());
if(replaceTrash)
if(theFilters.isReplaceTrash())
d.setName(replaceTrash(d.getName()));
devices[i++] = d;
@@ -137,7 +143,7 @@ public class FibaroInfo
d.fibaroname = fibaroAddress.getName();
}
log.info("Found: " + devices.length + " devices");
log.debug("getDevices Found: " + devices.length + " devices");
return devices;
}
@@ -146,19 +152,24 @@ public class FibaroInfo
{
Room[] rooms = getRooms();
String result = request("/api/scenes?enabled=true&visible=true");
String result = null;
if(isDevMode)
result = FibaroTestData.SceneTestData;
else
result = request("/api/scenes?enabled=true&visible=true");
log.debug("getScenes response: <<<" + result + ">>>");
Scene[] all_scenes = result == null ? new Scene[0] : gson.fromJson(result, Scene[].class);
int count = 0;
for(Scene s : all_scenes)
if(!scenesWithLiliCommandOnly || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
count++;
Scene[] scenes = new Scene[count];
int i = 0;
for(Scene s : all_scenes)
if(!scenesWithLiliCommandOnly || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
if(!theFilters.isScenesLiliCmddOnly() || s.getLiliStartCommand() != null && !s.getLiliStartCommand().isEmpty())
{
if(replaceTrash)
if(theFilters.isReplaceTrash())
s.setName(replaceTrash(s.getName()));
scenes[i++] = s;
@@ -172,7 +183,7 @@ public class FibaroInfo
s.fibaroAuth = fibaroAuth;
s.fibaroname = fibaroAddress.getName();
}
log.info("Found: " + count + " scenes");
log.debug("getScenes Found: " + count + " scenes");
return scenes;
}
}

View File

@@ -0,0 +1,34 @@
package com.bwssystems.HABridge.plugins.fibaro;
public class FibaroTestData {
public final static String DeviceTestData = "[{\"id\":7,\"name\":\"Deckenspots\",\"roomID\":12,\"type\":\"com.fibaro.FGD212\",\"baseType\":\"com.fibaro.multilevelSwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":5,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveAlarm\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.5\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"alarmLevel\":\"0\",\"alarmType\":\"0\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"7.23\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"2\",\"parametersTemplate\":\"796\",\"power\":\"5.80\",\"productInfo\":\"1,15,1,2,16,0,3,5\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"25\",\"serialNumber\":\"h'000000000001c1b4\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"5\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":1},{\"id\":13,\"name\":\"Licht Küche\",\"roomID\":13,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":10,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":fals" +
"e,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"9.51\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"3\",\"parametersTemplate\":\"781\",\"power\":\"16.00\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'000000000000450d\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"true\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":2},{\"id\":14,\"name\":\"Lampe Tisch\",\"roomID\":14,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":10,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"2\",\"energy\":\"29.15\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":" +
"\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"3\",\"parametersTemplate\":\"781\",\"power\":\"11.50\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'000000000000450d\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"true\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":3},{\"id\":18,\"name\":\"Licht\",\"roomID\":16,\"type\":\"com.fibaro.binarySwitch\",\"baseType\":\"com.fibaro.actor\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":15,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"light\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.2\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"2\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"2\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"2.70\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"4\",\"parametersTemplate\":\"781\",\"power\":\"0.00\",\"productInfo\":\"1,15,2,3,16,0,3,2\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"h'00000000000044b4\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTempl" +
"ate\":\"true\",\"userDescription\":\"\",\"value\":\"false\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643104,\"modified\":1516643104,\"sortOrder\":4},{\"id\":26,\"name\":\"Licht\",\"roomID\":5,\"type\":\"com.fibaro.FGD212\",\"baseType\":\"com.fibaro.multilevelSwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":24,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveAlarm\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"3.5\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"alarmLevel\":\"0\",\"alarmType\":\"0\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"1\",\"energy\":\"28.02\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"7\",\"parametersTemplate\":\"796\",\"power\":\"0.00\",\"productInfo\":\"1,15,1,2,16,0,3,5\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"h'0000000000001fec\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":5},{\"id\":57,\"name\":\"Fenster rechts\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":56,\"remoteGatewayId\"" +
":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.78\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"19\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":12},{\"id\":60,\"name\":\"Fenster mitte\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":59,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlT" +
"ype\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.71\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"20\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"26\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643105,\"modified\":1516643105,\"sortOrder\":13},{\"id\":74,\"name\":\"Fenster links\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":73,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.64\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"21\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0" +
",25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643106,\"modified\":1516643106,\"sortOrder\":14},{\"id\":77,\"name\":\"Fenster Sideboard\",\"roomID\":14,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":76,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"levelChange\",\"power\",\"zwave\",\"zwaveMultiChannelAssociation\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"25.25\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.63\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"22\",\"parametersTemplate\":\"721\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,2,16,0,25,25\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionLocal\":\"0\",\"protectionLocalSupport\":\"5\",\"protectionRF\":\"0\",\"protectionRFSupport\":\"3\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneAc" +
"tivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"close\":0,\"open\":0,\"reconfigure\":0,\"reset\":0,\"sceneActivationSet\":0,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"stop\":0,\"stopLevelChange\":0},\"created\":1516643106,\"modified\":1516643106,\"sortOrder\":15},{\"id\":112,\"name\":\"Stehlampe\",\"roomID\":12,\"type\":\"com.fibaro.multilevelSwitch\",\"baseType\":\"com.fibaro.binarySwitch\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":111,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"fibaroFirmwareUpdate\",\"levelChange\",\"light\",\"zwave\",\"zwaveSwitchAll\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Domitech Products\",\"zwaveInfo\":\"3,4,5\",\"zwaveVersion\":\"5.14\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"23\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"5.14\\\"}\",\"isLight\":\"true\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"27\",\"parametersTemplate\":\"807\",\"productInfo\":\"2,14,76,66,49,52,5,14\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"switchAllMode\":\"SWITCH_ALL_INCLUDED_IN_THE_ALL_ON_ALL_OFF_FUNCTIONALITY\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"abortUpdate\":1,\"reconfigure\":0,\"retryUpdate\":1,\"setValue\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startUpdate\":1,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0,\"updateFirmware\":1},\"created\":1516643107,\"modified\":1516643107,\"sortOrder\":6},{\"id\":114,\"name\":\"RGBW\",\"roomID\":12,\"type\":\"com.fibaro.FGRGBW441M\",\"baseType\":\"com.fibaro.colorController\",\"enabled\":true,\"visible\":tr" +
"ue,\"isPlugin\":false,\"parentId\":113,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"deviceGrouping\",\"energy\",\"fibaroFirmwareUpdate\",\"levelChange\",\"light\",\"power\",\"zwave\",\"zwaveSwitchAll\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"26.25\",\"associationMode\":\"0\",\"brightness\":\"0\",\"buttonType\":\"0\",\"color\":\"0,0,0,0\",\"configured\":true,\"currentProgram\":\"0\",\"currentProgramID\":\"0\",\"dead\":\"false\",\"deviceControlType\":\"50\",\"deviceGroup\":\"[]\",\"deviceGroupMaster\":\"0\",\"deviceIcon\":\"15\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"1.72\",\"favoriteProgram\":\"0\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"26.25\\\"}\",\"isLight\":\"true\",\"lastColorSet\":\"0,0,0,0\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"mode\":\"0\",\"model\":\"\",\"nodeId\":\"28\",\"parametersTemplate\":\"231\",\"power\":\"0.00\",\"productInfo\":\"1,15,9,0,16,0,26,25\",\"programsSortOrder\":\"1,2,3,4,5\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"rememberColor\":\"false\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"switchAllMode\":\"SWITCH_ALL_INCLUDED_IN_THE_ALL_ON_ALL_OFF_FUNCTIONALITY\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\"},\"actions\":{\"abortUpdate\":1,\"reconfigure\":0,\"reset\":0,\"retryUpdate\":1,\"setB\":1,\"setBrightness\":1,\"setColor\":1,\"setFavoriteProgram\":2,\"setG\":1,\"setR\":1,\"setValue\":1,\"setW\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startProgram\":1,\"startUpdate\":1,\"stopLevelChange\":0,\"turnOff\":0,\"turnOn\":0,\"updateFirmware\":1},\"created\":1516643107,\"modified\":1516643107,\"sortOrder\":7},{\"id\":122,\"name\":\"Fenster\",\"roomID\":12,\"type\":\"com.fibaro.FGRM222\",\"baseType\":\"com.fibaro.FGR\",\"enabled\":true,\"visible\":true,\"isPlugin\":false,\"parentId\":121,\"remoteGatewayId\":0,\"viewXml\":false,\"configXml\":false,\"interfaces\":[\"energy\",\"fibaroFirmwareUpdate\",\"levelChange\",\"powe" +
"r\",\"zwave\",\"zwaveConfiguration\",\"zwaveProtection\",\"zwaveSceneActivation\"],\"properties\":{\"pollingTimeSec\":0,\"zwaveCompany\":\"Fibargroup\",\"zwaveInfo\":\"3,3,52\",\"zwaveVersion\":\"24.24\",\"RFProtectionState\":\"0\",\"RFProtectionSupport\":\"3\",\"configured\":true,\"dead\":\"false\",\"deviceControlType\":\"54\",\"deviceIcon\":\"87\",\"emailNotificationID\":\"0\",\"emailNotificationType\":\"0\",\"endPointId\":\"0\",\"energy\":\"0.17\",\"firmwareUpdate\":\"{\\\"info\\\":\\\"\\\",\\\"progress\\\":0,\\\"status\\\":\\\"UpToDate\\\",\\\"updateVersion\\\":\\\"24.24\\\"}\",\"liliOffCommand\":\"\",\"liliOnCommand\":\"\",\"localProtectionState\":\"0\",\"localProtectionSupport\":\"5\",\"log\":\"\",\"logTemp\":\"\",\"manufacturer\":\"\",\"markAsDead\":\"true\",\"model\":\"\",\"nodeId\":\"29\",\"parametersTemplate\":\"249\",\"power\":\"0.00\",\"productInfo\":\"1,15,3,1,16,1,24,24\",\"protectionExclusiveControl\":\"0\",\"protectionExclusiveControlSupport\":\"false\",\"protectionState\":\"0\",\"protectionTimeout\":\"0\",\"protectionTimeoutSupport\":\"false\",\"pushNotificationID\":\"0\",\"pushNotificationType\":\"0\",\"remoteGatewayId\":\"0\",\"saveLogs\":\"true\",\"sceneActivation\":\"0\",\"serialNumber\":\"\",\"showEnergy\":\"true\",\"smsNotificationID\":\"0\",\"smsNotificationType\":\"0\",\"updateVersion\":\"\",\"useTemplate\":\"true\",\"userDescription\":\"\",\"value\":\"0\",\"value2\":\"0\"},\"actions\":{\"abortUpdate\":1,\"close\":0,\"getParameter\":1,\"open\":0,\"reconfigure\":0,\"reset\":0,\"retryUpdate\":1,\"sceneActivationSet\":0,\"setParameter\":2,\"setValue\":1,\"setValue2\":1,\"startLevelDecrease\":0,\"startLevelIncrease\":0,\"startUpdate\":1,\"stop\":0,\"stopLevelChange\":0,\"updateFirmware\":1},\"created\":1516643108,\"modified\":1516643108,\"sortOrder\":16}]";
public final static String RoomTestData = "[{\"id\":4,\"name\":\"Dachboden\",\"sectionID\":4,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":1},{\"id\":5,\"name\":\"Badezimmer\",\"sectionID\":5,\"icon\":\"room_wanna\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":2},{\"id\":6,\"name\":\"Büro\",\"sectionID\":5,\"icon\":\"room_office\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":3},{\"id\":7,\"name\":\"Flur\",\"sectionID\":5,\"icon\":\"room_schody2\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":4},{\"id\":8,\"name\":\"Schlafzimmer\",\"sectionID\":5,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":5},{\"id\":9,\"name\":\"Emelie\",\"sectionID\":5,\"icon\":\"room_wardrobe\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":6},{\"id\":10,\"name\":\"Mino\",\"sectionID\":5,\"icon\":\"room_garage\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":7},{\"id\":11,\"name\":\"Flur\",\"sectionID\":6,\"icon\":\"room_drzwiwejsciowe\",\"defaultSensors\":{\"temperature\":181,\"humidity\":0,\"light\":182},\"defaultThermostat\":0,\"sortOrder\":8},{\"id\":12,\"name\":\"Wohnzimmer\",\"sectionID\":6,\"icon\":\"room_sofa\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":9},{\"id\":13,\"name\":\"Küche\",\"sectionID\":6,\"icon\":\"room_dining\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":10},{\"id\":14,\"name\":\"Esszimmer\",\"sectionID\":6,\"icon\":\"room_jadalnia\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":11},{\"id\":15,\"name\":\"HWR\",\"sectionID\":6,\"icon\":\"room_laundry\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":12},{\"id\":16,\"name\":\"Gäste WC\",\"sectionID\":6," +
"\"icon\":\"room_toilet\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":13},{\"id\":17,\"name\":\"Haus\",\"sectionID\":7,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":14},{\"id\":18,\"name\":\"Terrasse\",\"sectionID\":7,\"icon\":\"room_bedroom\",\"defaultSensors\":{\"temperature\":0,\"humidity\":0,\"light\":0},\"defaultThermostat\":0,\"sortOrder\":15}]";
public final static String SceneTestData = "[" +
"{\"id\":33,\"name\":\"Fernsehlicht aus\",\"type\":\"com.fibaro.luaScene\",\"roomID\":12,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":4,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":17}," +
"{\"id\":68,\"name\":\"Rollos runterfahren\",\"type\":\"com.fibaro.luaScene\",\"roomID\":14,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":8}," +
"{\"id\":69,\"name\":\"Rollos hochfahren\",\"type\":\"com.fibaro.luaScene\",\"roomID\":14,\"iconID\":6,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":true,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":true,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":9}," +
"{\"id\":93,\"name\":\"Alles aus Haus\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent1HeldDown_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 1 HeldDown\\\\n163 CentralSceneEvent 1 Released\\\",\\\"actionDeviceId\\\":92,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_92\\\",\\\"actionLua\\\":\\\"fibaro:startScene(92);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"1\",\"Released\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[92],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":18}," +
"{\"id\":94,\"name\":\"Fernsehlicht an\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":10}," +
"{\"id\":95,\"name\":\"Fernsehlicht + aus\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[7,10,11,12,13,14,57,60,74,77,97,112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":19}," +
"{\"id\":96,\"name\":\"Fernsehlicht Wohnzim\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent2Pressed_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 2 Pressed\\\",\\\"actionDeviceId\\\":94,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_94\\\",\\\"actionLua\\\":\\\"fibaro:startScene(94);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"2\",\"Pressed\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[94],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":20}," +
"{\"id\":98,\"name\":\"Fersehlicht blau\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":11}," +
"{\"id\":99,\"name\":\"Fernsehlicht blau+au\",\"type\":\"com.fibaro.blockScene\",\"roomID\":12,\"iconID\":5,\"runConfig\":\"MANUAL_ONLY\",\"alexaProhibited\":false,\"autostart\":true,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":true,\"isLua\":false,\"properties\":\"\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[],\"weather\":[]},\"actions\":{\"devices\":[7,10,11,12,13,14,112,114],\"scenes\":[],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":21}," +
"{\"id\":100,\"name\":\"Fernsehlicht blau+au\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent3HeldDown_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 3 HeldDown\\\\n163 CentralSceneEvent 3 Released\\\",\\\"actionDeviceId\\\":99,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_99\\\",\\\"actionLua\\\":\\\"fibaro:startScene(99);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"3\",\"Released\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[99],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":22}," +
"{\"id\":101,\"name\":\"Fersehlicht blau Woh\",\"type\":\"com.fibaro.magicScene\",\"roomID\":12,\"runConfig\":\"TRIGGER_AND_MANUAL\",\"alexaProhibited\":false,\"autostart\":false,\"protectedByPIN\":false,\"killable\":true,\"killOtherInstances\":false,\"maxRunningInstances\":2,\"runningInstances\":0,\"instances\":[],\"runningManualInstances\":0,\"visible\":false,\"properties\":\"{\\\"conditionDeviceId\\\":163,\\\"conditionObjectType\\\":\\\"device\\\",\\\"conditionId\\\":\\\"condition_centralSceneEvent3Pressed_163\\\",\\\"conditionLua\\\":\\\"true\\\",\\\"conditionValue\\\":\\\"\\\",\\\"conditionRooms\\\":[],\\\"trigger\\\":\\\"163 CentralSceneEvent 3 Pressed\\\",\\\"actionDeviceId\\\":98,\\\"actionObjectType\\\":\\\"scene\\\",\\\"actionId\\\":\\\"action_runScene_98\\\",\\\"actionLua\\\":\\\"fibaro:startScene(98);\\\",\\\"actionValue\\\":\\\"\\\",\\\"actionRooms\\\":[],\\\"looping\\\":false}\",\"triggers\":{\"properties\":[],\"globals\":[],\"events\":[{\"deviceId\":163,\"eventName\":\"CentralSceneEvent\",\"args\":[\"3\",\"Pressed\"]}],\"weather\":[]},\"actions\":{\"devices\":[],\"scenes\":[98],\"groups\":[]},\"liliStartCommand\":\"\",\"liliStopCommand\":\"\",\"sortOrder\":23}" +
"]";
public final static String CallActionTestData = "Fiabro action received";
public final static String SceneControlTestData = "Fiabro scene control received";
}

View File

@@ -1,35 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro;
public enum ModeType {
OFF(0, "Off"),
HEAT(1, "Heat"),
COOL(2, "Cool"),
AUTO(3, "Auto"),
AUX_HEAT(4, "Aux Heat"),
RESUME(5, "Resume"),
FAN_ONLY(6, "Fan Only"),
FURNANCE(7, "Furnace"),
DRY_AIR(8, "Dry Air"),
MOIST_AIR(9, "Moist Air"),
AUTO_CHANGEOVER(10, "Auto Changeover"),
HEAT_ECON(11, "Heat Econ"),
COOL_ECON(12, "Cool Econ"),
AWAY(13, "Away"),
MANUAL(31, "Manual");
private int key;
private String label;
private ModeType(int key, String label) {
this.key = key;
this.label = label;
}
public int getKey() {
return key;
}
public String getLabel() {
return label;
}
}

View File

@@ -17,48 +17,9 @@ public class Device {
@SerializedName("type")
private String type;
@SerializedName("baseType")
private String baseType;
@SerializedName("enabled")
private boolean enabled;
@SerializedName("visible")
private boolean visible;
@SerializedName("isPlugin")
private boolean isPlugin;
@SerializedName("parentId")
private int parentId;
@SerializedName("remoteGatewayId")
private int remoteGatewayId;
@SerializedName("viewXml")
private boolean viewXml;
@SerializedName("configXml")
private boolean configXml;
@SerializedName("interfaces")
private Object interfaces;
@SerializedName("properties")
private DeviceProperties properties;
@SerializedName("actions")
private Object actions;
@SerializedName("created")
private int created;
@SerializedName("modified")
private int modified;
@SerializedName("sortOrder")
private int sortOrder;
public String getRoomName() {
return roomName;
}

View File

@@ -3,242 +3,21 @@ package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class DeviceProperties {
@SerializedName("batteryLevel")
private String batteryLevel;
@SerializedName("UIMessageSendTime")
private String UIMessageSendTime;
@SerializedName("autoConfig")
private String autoConfig;
@SerializedName("color")
private String color;
@SerializedName("date")
private String date;
@SerializedName("dead")
private String dead;
@SerializedName("deviceControlType")
private String deviceControlType;
@SerializedName("deviceIcon")
private String deviceIcon;
@SerializedName("disabled")
private String disabled;
@SerializedName("emailNotificationID")
private String emailNotificationID;
@SerializedName("emailNotificationType")
private String emailNotificationType;
@SerializedName("endPoint")
private String endPoint;
@SerializedName("energy")
private String energy;
@SerializedName("liliOffCommand")
private String liliOffCommand;
@SerializedName("liliOnCommand")
private String liliOnCommand;
@SerializedName("log")
private String log;
@SerializedName("logTemp")
private String logTemp;
@SerializedName("manufacturer")
private String manufacturer;
@SerializedName("markAsDead")
private String markAsDead;
@SerializedName("mode")
private String mode;
@SerializedName("model")
private String model;
@SerializedName("nodeID")
private String nodeID;
@SerializedName("pollingDeadDevice")
private String pollingDeadDevice;
@SerializedName("pollingTime")
private String pollingTime;
@SerializedName("pollingTimeNext")
private String pollingTimeNext;
@SerializedName("pollingTimeSec")
private int pollingTimeSec;
@SerializedName("power")
private String power;
@SerializedName("productInfo")
private String productInfo;
@SerializedName("pushNotificationID")
private String pushNotificationID;
@SerializedName("pushNotificationType")
private String pushNotificationType;
@SerializedName("remoteGatewayId")
private String remoteGatewayId;
@SerializedName("requestNodeNeighborStat")
private String requestNodeNeighborStat;
@SerializedName("requestNodeNeighborStatTimeStemp")
private String requestNodeNeighborStatTimeStemp;
@SerializedName("requestNodeNeighborState")
private String requestNodeNeighborState;
@SerializedName("requestNodeNeighborStateTimeStemp")
private String requestNodeNeighborStateTimeStemp;
@SerializedName("value")
private String value;
@SerializedName("saveLogs")
private String saveLogs;
@SerializedName("showChildren")
private String showChildren;
@SerializedName("smsNotificationID")
private String smsNotificationID;
@SerializedName("smsNotificationType")
private String smsNotificationType;
@SerializedName("supportedModes")
private String supportedModes;
@SerializedName("targetLevel")
private String targetLevel;
@SerializedName("unit")
private String unit;
@SerializedName("useTemplate")
private String useTemplate;
@SerializedName("status")
private String status;
@SerializedName("sunriseHour")
private String sunriseHour;
@SerializedName("sunsetHour")
private String sunsetHour;
@SerializedName("userDescription")
private String userDescription;
@SerializedName("value")
private String value;
@SerializedName("zwaveBuildVersion")
private String zwaveBuildVersion;
@SerializedName("zwaveCompany")
private String zwaveCompany;
@SerializedName("zwaveInfo")
private String zwaveInfo;
@SerializedName("zwaveRegion")
private String zwaveRegion;
@SerializedName("zwaveVersion")
private double zwaveVersion;
public String getBatteryLevel() {
return batteryLevel;
}
public String getColor() {
return color;
}
public String getDeviceControlType() {
return deviceControlType;
}
public String getEnergy() {
return energy;
}
public String getPower() {
return power;
}
public String getTargetLevel() {
return targetLevel;
}
public String getValue() {
return value;
}
// --- begin yrWeather plugin ---
@SerializedName("Humidity")
private String Humidity;
@SerializedName("Pressure")
private String Pressure;
@SerializedName("Temperature")
private String Temperature;
@SerializedName("WeatherCondition")
private String WeatherCondition;
@SerializedName("Wind")
private String Wind;
public String getHumidity() {
return Humidity;
}
public String getPressure() {
return Pressure;
}
public String getSaveLogs()
{
return saveLogs;
}
public String getTemperature() {
return Temperature;
}
public String getWeatherCondition() {
return WeatherCondition;
}
public String getWind() {
return Wind;
}
// --- end yrWeather plugin ---
public String getUserDescription()
{
return userDescription;
}
public void setUserDescription(String userDescription)
{
this.userDescription = userDescription;
}
public String getSaveLogs() {
return saveLogs;
}
public String getUserDescription() {
return userDescription;
}
}

View File

@@ -12,18 +12,6 @@ public class Room {
@SerializedName("sectionID")
private int sectionID;
@SerializedName("icon")
private String icon;
@SerializedName("defaultSensors")
private Sensor defaultSensors;
@SerializedName("defaultThermostat")
private int defaultThermostat;
@SerializedName("sortOrder")
private int sortOrder;
public int getId() {
return id;
}

View File

@@ -14,51 +14,12 @@ public class Scene {
@SerializedName("type")
private String type;
@SerializedName("properties")
private String properties;
@SerializedName("roomID")
private int roomID;
@SerializedName("iconID")
private int iconID;
@SerializedName("runConfig")
private String runConfig;
@SerializedName("autostart")
private boolean autostart;
@SerializedName("protectedByPIN")
private boolean protectedByPIN;
@SerializedName("killable")
private boolean killable;
@SerializedName("maxRunningInstances")
private int maxRunningInstances;
@SerializedName("runningInstances")
private int runningInstances;
@SerializedName("visible")
private boolean visible;
@SerializedName("isLua")
private boolean isLua;
@SerializedName("triggers")
private SceneTriggers triggers;
@SerializedName("liliStartCommand")
private String liliStartCommand;
@SerializedName("liliStopCommand")
private String liliStopCommand;
@SerializedName("sortOrder")
private int sortOrder;
public String getRoomName() {
return roomName;
}

View File

@@ -1,11 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class SceneProperties {
@SerializedName("id")
private String id;
@SerializedName("name")
private String name;
}

View File

@@ -1,14 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class SceneTriggers {
@SerializedName("properties")
private SceneProperties[] properties;
@SerializedName("globals")
private String[] globals;
@SerializedName("events")
private String[] events;
}

View File

@@ -1,14 +0,0 @@
package com.bwssystems.HABridge.plugins.fibaro.json;
import com.google.gson.annotations.SerializedName;
public class Sensor {
@SerializedName("temperature")
private int temperature;
@SerializedName("humidity")
private int humidity;
@SerializedName("light")
private int light;
}

View File

@@ -113,6 +113,11 @@ public class HalHome implements Home {
return true;
}
@Override
public void refresh() {
// noop
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {

View File

@@ -269,4 +269,10 @@ public class HarmonyHome implements Home {
}
return null;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -117,6 +117,11 @@ public class HassHome implements Home {
return true;
}
@Override
public void refresh() {
// noop
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri,Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {

View File

@@ -85,7 +85,7 @@ public class HomeWizardHome implements Home {
public List<HomeWizardSmartPlugDevice> getDevices() {
log.debug("consolidating devices for plug gateways");
log.debug("consolidating devices for HomeWizard plug gateways");
Iterator<String> keys = plugGateways.keySet().iterator();
ArrayList<HomeWizardSmartPlugDevice> deviceList = new ArrayList<>();
@@ -147,4 +147,9 @@ public class HomeWizardHome implements Home {
plugGateways = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -19,9 +19,7 @@ import com.bwssystems.HABridge.NamedIP;
import com.bwssystems.HABridge.plugins.homewizard.json.Device;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import us.monoid.json.JSONException;
import us.monoid.json.JSONObject;
import com.google.gson.JsonParser;
/**
* Control HomeWizard devices over HomeWizard Cloud
@@ -75,10 +73,12 @@ public class HomeWizzardSmartPlugInfo {
br.close();
// Get session id from result JSON
JSONObject json = new JSONObject(buffer.toString());
cloudSessionId = json.get("session").toString();
JsonParser parser = new JsonParser();
JsonObject json = parser.parse(buffer.toString()).getAsJsonObject();
cloudSessionId = json.get("session").getAsString();
}
catch(IOException | JSONException e)
catch(Exception e)
{
log.warn("Error while login to cloud service ", e);
return false;
@@ -191,8 +191,9 @@ public class HomeWizzardSmartPlugInfo {
try {
String result = requestJson(EMPTY_STRING);
JSONObject resultJson = new JSONObject(result);
cloudPlugId = resultJson.getString("id");
JsonParser parser = new JsonParser();
JsonObject resultJson = parser.parse(result).getAsJsonObject();
cloudPlugId = resultJson.get("id").getAsString();
String all_devices_json = resultJson.get("devices").toString();
Device[] devices = gson.fromJson(all_devices_json, Device[].class);
@@ -203,7 +204,7 @@ public class HomeWizzardSmartPlugInfo {
homewizardDevices.add(mapDeviceToHomeWizardSmartPlugDevice(device));
}
}
catch(JSONException e) {
catch(Exception e) {
log.warn("Error while get devices from cloud service ", e);
}
@@ -211,12 +212,13 @@ public class HomeWizzardSmartPlugInfo {
return homewizardDevices;
}
public void execApply(String jsonToPost) throws JSONException, IOException {
public void execApply(String jsonToPost) throws Exception {
// Extract
JSONObject resultJson = new JSONObject(jsonToPost);
String deviceId = resultJson.getString("deviceid");
String action = resultJson.getString("action");
JsonParser parser = new JsonParser();
JsonObject resultJson = parser.parse(jsonToPost).getAsJsonObject();
String deviceId = resultJson.get("deviceid").getAsString();
String action = resultJson.get("action").getAsString();
// Check if we have an plug id stored
if (StringUtils.isBlank(cloudPlugId)) {

View File

@@ -17,20 +17,32 @@ import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.DeviceMapTypes;
import com.bwssystems.HABridge.api.NameValue;
public class HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HTTPHandler.class);
private String callType;
public HTTPHandler() {
super();
callType = null;
}
public HTTPHandler(String type) {
super();
callType = type;
}
// This function executes the url from the device repository against the
// target as http or https as defined
public String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
log.debug("doHttpRequest with url: " + url + " with http command: " + httpVerb + " with body: " + body);
log.debug("doHttpRequest with url <<<" + url + ">>>, verb: " + httpVerb + ", contentType: " + contentType + ", body <<<" + body + ">>>" );
if(headers != null && headers.length > 0)
for(int i = 0; i < headers.length; i++)
log.debug("header index " + i + " name: <<<" + headers[i].getName() + ">>>, value: <<<" + headers[i].getValue() + ">>>");
HttpUriRequest request = null;
String theContent = null;
URI theURI = null;
@@ -99,17 +111,24 @@ public class HTTPHandler {
}
}
if (response != null && response.getStatusLine().getStatusCode() >= 200 && response.getStatusLine().getStatusCode() < 300) {
if(theContent == null)
theContent = "";
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
retryCount = 2;
} else if (callType != null && callType == DeviceMapTypes.FHEM_DEVICE[DeviceMapTypes.typeIndex] && response.getStatusLine().getStatusCode() == 302) {
if(theContent == null)
theContent = "";
log.debug("Successfull response - The http response is <<<" + theContent + ">>>");
retryCount = 2;
} else if (response != null) {
log.warn("HTTP response code was not an expected successful response of between 200 - 299, the code was: "
+ response.getStatusLine());
+ response.getStatusLine() + " with the content of <<<" + theContent + ">>>");
if (response.getStatusLine().getStatusCode() == 504) {
log.warn("HTTP response code was 504, retrying...");
log.debug("The 504 error content is <<<" + theContent + ">>>");
theContent = null;
} else
retryCount = 2;
theContent = null;
}
} catch (ClientProtocolException e) {
@@ -130,6 +149,11 @@ public class HTTPHandler {
}
return theContent;
}
public void setCallType(String callType) {
this.callType = callType;
}
public void closeHandler() {
}
}

View File

@@ -16,11 +16,14 @@ import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.bwssystems.HABridge.plugins.fibaro.FibaroTestData;
import com.bwssystems.HABridge.plugins.vera.VeraTestData;
import com.google.gson.Gson;
public class HTTPHome implements Home {
private static final Logger log = LoggerFactory.getLogger(HTTPHome.class);
private static HTTPHandler anHttpHandler = null;
private Boolean isDevMode;
private boolean closed;
public HTTPHome(BridgeSettings bridgeSettings) {
@@ -78,13 +81,16 @@ public class HTTPHome implements Home {
aBody = TimeDecode.replaceTimeValue(aBody);
}
// make call
if (anHttpHandler.doHttpRequest(anUrl, anItem.getHttpVerb(), anItem.getContentType(), aBody,
new Gson().fromJson(anItem.getHttpHeaders(), NameValue[].class)) == null) {
String httpReply = anHttpHandler.doHttpRequest(anUrl, anItem.getHttpVerb(), anItem.getContentType(), aBody, new Gson().fromJson(anItem.getHttpHeaders(), NameValue[].class));
if (httpReply == null) {
log.warn("Error on calling url to change device state: " + anUrl);
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);
}
if(isDevMode)
log.info("Dev Mode response dump <<<" + httpReply +">>>");
} else {
log.warn("HTTP Call to be presented as http(s)://<ip_address>(:<port>)/payload, format of request unknown: " + theUrl);
responseString = new Gson().toJson(HueErrorResponse.createResponse("6", "/lights/" + lightId,
@@ -97,9 +103,21 @@ public class HTTPHome implements Home {
@Override
public Home createHome(BridgeSettings bridgeSettings) {
isDevMode = Boolean.parseBoolean(System.getProperty("dev.mode", "false"));
log.info("HTTP Home created." + (isDevMode ? " DevMode is set." : ""));
if(isDevMode) {
anHttpHandler = new HttpTestHandler();
((HttpTestHandler)anHttpHandler).setTheData("id=sdata", VeraTestData.SDataTestData);
((HttpTestHandler)anHttpHandler).setTheData("action=SetLoadLevelTarget", VeraTestData.SetLoadLevelTargetData);
((HttpTestHandler)anHttpHandler).setTheData("action=SetTarget", VeraTestData.SetTargetData);
((HttpTestHandler)anHttpHandler).setTheData("action=RunScene", VeraTestData.RunSceneData);
((HttpTestHandler)anHttpHandler).setTheData("/api/callAction", FibaroTestData.CallActionTestData);
((HttpTestHandler)anHttpHandler).setTheData("/api/sceneControl", FibaroTestData.SceneControlTestData);
((HttpTestHandler)anHttpHandler).setTheData(null, "generic treply - no match");
}
if(anHttpHandler == null)
anHttpHandler = new HTTPHandler();
log.info("Http Home created.");
return this;
}
@@ -121,5 +139,9 @@ public class HTTPHome implements Home {
anHttpHandler = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -0,0 +1,65 @@
package com.bwssystems.HABridge.plugins.http;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.api.NameValue;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
public class HttpTestHandler extends HTTPHandler {
private static final Logger log = LoggerFactory.getLogger(HttpTestHandler.class);
private List<NameValue> theData;
public void setTheData(String compareValue, String testData) {
if( this.theData == null )
this.theData = new ArrayList<NameValue>();
NameValue aValueSet = new NameValue();
aValueSet.setName(compareValue);
aValueSet.setValue(testData);
this.theData.add(aValueSet);
}
public void updateTheData(String compareValue, String testData) {
if( this.theData == null ) {
this.theData = new ArrayList<NameValue>();
NameValue aValueSet = new NameValue();
aValueSet.setName(compareValue);
aValueSet.setValue(testData);
this.theData.add(aValueSet);
}
else {
for(NameValue aTest:this.theData) {
if(aTest.getName().equals(compareValue));
aTest.setValue(testData);
}
}
}
public String doHttpRequest(String url, String httpVerb, String contentType, String body, NameValue[] headers) {
log.info("doHttpRequest with url <<<" + url + ">>>, verb: " + httpVerb + ", contentType: " + contentType + ", body <<<" + body + ">>>" );
if(headers != null && headers.length > 0)
for(int i = 0; i < headers.length; i++)
log.info("header index " + i + " name: <<<" + headers[i].getName() + ">>>, value: <<<" + headers[i].getValue() + ">>>");
String responseData = null;
for(NameValue aTest:theData) {
if(aTest.getName() == null)
responseData = aTest.getValue();
else {
if(url.contains(aTest.getName()))
responseData = aTest.getValue();
else if(aTest.getName() == null || aTest.getName().isEmpty())
responseData = aTest.getValue();
}
if(responseData != null)
break;
}
if(responseData == null)
responseData = "No data was set for HttpTestHandler for your request url.";
return responseData;
}
}

View File

@@ -153,4 +153,9 @@ public class HueHome implements Home {
hues = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -5,6 +5,7 @@ import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -20,6 +21,7 @@ import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.github.besherman.lifx.LFXClient;
import com.github.besherman.lifx.LFXGroup;
@@ -38,6 +40,7 @@ public class LifxHome implements Home {
private LFXClient client;
private Boolean validLifx;
private Gson aGsonHandler;
private InetAddress configuredAddress;
private boolean closed;
public LifxHome(BridgeSettings bridgeSettings) {
@@ -54,47 +57,17 @@ public class LifxHome implements Home {
validLifx = bridgeSettings.getBridgeSettingsDescriptor().isValidLifx();
log.info("LifxDevice Home created." + (validLifx ? "" : " No LifxDevices configured."));
if(validLifx) {
try {
log.info("Open Lifx client....");
InetAddress configuredAddress = InetAddress.getByName(bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress());
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
InetAddress bcastInetAddr = null;
if (networkInterface != null) {
for (InterfaceAddress ifaceAddr : networkInterface.getInterfaceAddresses()) {
InetAddress addr = ifaceAddr.getAddress();
if (addr instanceof Inet4Address) {
bcastInetAddr = ifaceAddr.getBroadcast();
break;
}
}
}
if(bcastInetAddr != null) {
lifxMap = new HashMap<String, LifxDevice>();
log.info("Opening LFX Client with broadcast address: " + bcastInetAddr.getHostAddress());
client = new LFXClient(bcastInetAddr.getHostAddress());
client.getLights().addLightCollectionListener(new MyLightListener(lifxMap));
client.getGroups().addGroupCollectionListener(new MyGroupListener(lifxMap));
client.open(false);
aGsonHandler =
new GsonBuilder()
.create();
} else {
log.warn("Could not open LIFX, no bcast addr available, check your upnp config address.");
client = null;
validLifx = false;
return this;
}
} catch (IOException e) {
log.warn("Could not open LIFX, with IO Exception", e);
client = null;
validLifx = false;
return this;
} catch (InterruptedException e) {
log.warn("Could not open LIFX, with Interruprted Exception", e);
client = null;
aGsonHandler =
new GsonBuilder()
.create();
try {
configuredAddress = InetAddress.getByName(bridgeSettings.getBridgeSettingsDescriptor().getUpnpConfigAddress());
} catch (UnknownHostException e) {
log.warn("Could not get Inet Address for Lifx broadcast.");
validLifx = false;
return this;
}
broadcastDiscover();
}
return this;
}
@@ -116,7 +89,7 @@ public class LifxHome implements Home {
@Override
public Object getItems(String type) {
log.debug("consolidating devices for lifx");
if(!validLifx)
if(!validLifx || lifxMap == null)
return null;
LifxEntry theResponse = null;
Iterator<String> keys = lifxMap.keySet().iterator();
@@ -200,6 +173,10 @@ public class LifxHome implements Home {
theValue = (float)0.99;
theLight.setBrightness(theValue);
}
if(colorData != null) {
int rgbVal = ColorDecode.getIntRGB(colorData, intensity);
theLight.setColor(rgbVal);
}
} else if (theDevice.getType().equals(LifxDevice.GROUP_TYPE)) {
LFXGroup theGroup = (LFXGroup)theDevice.getLifxObject();
if(body.contains("true"))
@@ -221,7 +198,8 @@ public class LifxHome implements Home {
log.debug("Home is already closed....");
return;
}
client.close();
if(client != null)
client.close();
closed = true;
}
private static class MyLightListener implements LFXLightCollectionListener {
@@ -266,4 +244,47 @@ public class LifxHome implements Home {
}
}
private void broadcastDiscover() {
try {
log.info("Open Lifx client....");
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(configuredAddress);
InetAddress bcastInetAddr = null;
if (networkInterface != null) {
for (InterfaceAddress ifaceAddr : networkInterface.getInterfaceAddresses()) {
InetAddress addr = ifaceAddr.getAddress();
if (addr instanceof Inet4Address) {
bcastInetAddr = ifaceAddr.getBroadcast();
break;
}
}
}
if(bcastInetAddr != null) {
lifxMap = new HashMap<String, LifxDevice>();
log.info("Opening LFX Client with broadcast address: " + bcastInetAddr.getHostAddress());
client = new LFXClient(bcastInetAddr.getHostAddress());
client.getLights().addLightCollectionListener(new MyLightListener(lifxMap));
client.getGroups().addGroupCollectionListener(new MyGroupListener(lifxMap));
client.open(false);
} else {
log.warn("Could not open LIFX, no bcast addr available, check your upnp config address.");
client = null;
return;
}
} catch (IOException e) {
log.warn("Could not open LIFX, with IO Exception", e);
client = null;
return;
} catch (InterruptedException e) {
log.warn("Could not open LIFX, with Interruprted Exception", e);
client = null;
return;
}
}
@Override
public void refresh() {
if(client == null)
broadcastDiscover();
}
}

View File

@@ -15,6 +15,7 @@ import com.bwssystems.HABridge.api.CallItem;
import com.bwssystems.HABridge.dao.DeviceDescriptor;
import com.bwssystems.HABridge.hue.BrightnessDecode;
import com.bwssystems.HABridge.hue.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
@@ -100,6 +101,9 @@ public class MQTTHome implements Home {
intensity, targetBri, targetBriInc, false);
mqttObject = DeviceDataDecode.replaceDeviceData(mqttObject, device);
mqttObject = TimeDecode.replaceTimeValue(mqttObject);
if (colorData != null) {
mqttObject = ColorDecode.replaceColorData(mqttObject, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
if (mqttObject.substring(0, 1).equalsIgnoreCase("{"))
mqttObject = "[" + mqttObject + "]";
MQTTMessage[] mqttMessages = aGsonHandler.fromJson(mqttObject, MQTTMessage[].class);
@@ -146,4 +150,9 @@ public class MQTTHome implements Home {
}
return this;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -0,0 +1,19 @@
package com.bwssystems.HABridge.plugins.openhab;
public class OpenHABCommand {
private String url;
private String command;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
}

View File

@@ -0,0 +1,27 @@
package com.bwssystems.HABridge.plugins.openhab;
public class OpenHABDevice {
private String address;
private String name;
private OpenHABItem item;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public OpenHABItem getItem() {
return item;
}
public void setItem(OpenHABItem item) {
this.item = item;
}
}

View File

@@ -0,0 +1,208 @@
package com.bwssystems.HABridge.plugins.openhab;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.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.ColorData;
import com.bwssystems.HABridge.hue.ColorDecode;
import com.bwssystems.HABridge.hue.DeviceDataDecode;
import com.bwssystems.HABridge.hue.MultiCommandUtil;
import com.bwssystems.HABridge.hue.TimeDecode;
import com.bwssystems.HABridge.plugins.http.HTTPHandler;
import com.bwssystems.HABridge.plugins.http.HTTPHome;
import com.google.gson.Gson;
public class OpenHABHome implements Home {
private static final Logger log = LoggerFactory.getLogger(OpenHABHome.class);
private Map<String, OpenHABInstance> openhabMap;
private Boolean validOpenhab;
private HTTPHandler httpClient;
private boolean closed;
public OpenHABHome(BridgeSettings bridgeSettings) {
super();
closed = true;
createHome(bridgeSettings);
closed = false;
}
@Override
public String deviceHandler(CallItem anItem, MultiCommandUtil aMultiUtil, String lightId, int intensity,
Integer targetBri, Integer targetBriInc, ColorData colorData, DeviceDescriptor device, String body) {
String theUrl = anItem.getItem().getAsString();
String responseString = null;
if(theUrl != null && !theUrl.isEmpty()) {
OpenHABCommand theCommand = null;
try {
theCommand = new Gson().fromJson(theUrl, OpenHABCommand.class);
} catch(Exception e) {
log.warn("Cannot parse command to OpenHAB <<<" + theUrl + ">>>", e);
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;
}
String intermediate = theCommand.getUrl().substring(theCommand.getUrl().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;
OpenHABInstance theHandler = findHandlerByAddress(hostAddr);
if(theHandler != null) {
String anUrl = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody,
intensity, targetBri, targetBriInc, false);
if (colorData != null) {
anUrl = ColorDecode.replaceColorData(anUrl, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
anUrl = DeviceDataDecode.replaceDeviceData(anUrl, device);
anUrl = TimeDecode.replaceTimeValue(anUrl);
String aCommand = null;
if(theCommand.getCommand() != null && !theCommand.getCommand().isEmpty()) {
aCommand = BrightnessDecode.calculateReplaceIntensityValue(theCommand.getCommand(),
intensity, targetBri, targetBriInc, false);
if (colorData != null) {
aCommand = ColorDecode.replaceColorData(aCommand, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
aCommand = DeviceDataDecode.replaceDeviceData(aCommand, device);
aCommand = TimeDecode.replaceTimeValue(aCommand);
}
try {
boolean success = theHandler.callCommand(anUrl, aCommand, httpClient);
if(!success) {
log.warn("Comand had error to OpenHAB");
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 send comand to OpenHAB", e);
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("OpenHAB 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("OpenHAB Call to be presented as http(s)://<ip_address>(:<port>)/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
public Object getItems(String type) {
if(!validOpenhab)
return null;
log.debug("consolidating devices for OpenHAB");
List<OpenHABDevice> theResponse = null;
Iterator<String> keys = openhabMap.keySet().iterator();
List<OpenHABDevice> deviceList = new ArrayList<OpenHABDevice>();
while(keys.hasNext()) {
String key = keys.next();
theResponse = openhabMap.get(key).getDevices(httpClient);
if(theResponse != null)
addOpenhabDevices(deviceList, theResponse, key);
else {
log.warn("Cannot get devices for OpenHAB with name: " + key + ", skipping this OpenHAB.");
continue;
}
}
return deviceList;
}
private Boolean addOpenhabDevices(List<OpenHABDevice> theDeviceList, List<OpenHABDevice> theSourceList, String theKey) {
Iterator<OpenHABDevice> devices = theSourceList.iterator();
while(devices.hasNext()) {
OpenHABDevice theDevice = devices.next();
theDeviceList.add(theDevice);
}
return true;
}
@Override
public Home createHome(BridgeSettings bridgeSettings) {
openhabMap = null;
validOpenhab = bridgeSettings.getBridgeSettingsDescriptor().isValidOpenhab();
log.info("OpenHAB Home created." + (validOpenhab ? "" : " No OpenHABs configured."));
if(validOpenhab) {
openhabMap = new HashMap<String,OpenHABInstance>();
httpClient = HTTPHome.getHandler();
Iterator<NamedIP> theList = bridgeSettings.getBridgeSettingsDescriptor().getOpenhabaddress().getDevices().iterator();
while(theList.hasNext() && validOpenhab) {
NamedIP anOpenhab = theList.next();
try {
openhabMap.put(anOpenhab.getName(), new OpenHABInstance(anOpenhab));
} catch (Exception e) {
log.error("Cannot get OpenHAB (" + anOpenhab.getName() + ") setup, Exiting with message: " + e.getMessage(), e);
validOpenhab = false;
}
}
}
return this;
}
private OpenHABInstance findHandlerByAddress(String hostAddress) {
OpenHABInstance aHandler = null;
boolean found = false;
Iterator<String> keys = openhabMap.keySet().iterator();
while(keys.hasNext()) {
String key = keys.next();
aHandler = openhabMap.get(key);
if(aHandler != null && aHandler.getOpenHABAddress().getIp().equals(hostAddress)) {
found = true;
break;
}
}
if(!found)
aHandler = null;
return aHandler;
}
@Override
public void closeHome() {
log.debug("Closing Home.");
if(!closed && validOpenhab) {
log.debug("Home is already closed....");
return;
}
if(httpClient != null)
httpClient.closeHandler();
openhabMap = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -0,0 +1,98 @@
package com.bwssystems.HABridge.plugins.openhab;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
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;
public class OpenHABInstance {
private static final Logger log = LoggerFactory.getLogger(OpenHABInstance.class);
private NamedIP theOpenHAB;
public OpenHABInstance(NamedIP openhabLocation) {
super();
theOpenHAB = openhabLocation;
}
public NamedIP getOpenHABAddress() {
return theOpenHAB;
}
public void setOpenHABAddress(NamedIP openhabAddress) {
this.theOpenHAB = openhabAddress;
}
public Boolean callCommand(String aCommand, String commandData, HTTPHandler httpClient) {
log.debug("calling OpenHAB: " + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + aCommand);
String aUrl = null;
NameValue[] headers = null;
if(theOpenHAB.getSecure() != null && theOpenHAB.getSecure())
aUrl = "https://";
else
aUrl = "http://";
if(theOpenHAB.getUsername() != null && !theOpenHAB.getUsername().isEmpty() && theOpenHAB.getPassword() != null && !theOpenHAB.getPassword().isEmpty()) {
aUrl = aUrl + theOpenHAB.getUsername() + ":" + theOpenHAB.getPassword() + "@";
}
aUrl = aUrl + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + "/" + aCommand;
String theData = httpClient.doHttpRequest(aUrl, HttpPost.METHOD_NAME, "text/plain", commandData, headers);
log.debug("call Command return is: <" + theData + ">");
if(theData.contains("error") || theData.contains("ERROR") || theData.contains("Error"))
return false;
return true;
}
public List<OpenHABDevice> getDevices(HTTPHandler httpClient) {
List<OpenHABDevice> deviceList = null;
OpenHABItem[] theOpenhabStates;
String theUrl = null;
String theData;
NameValue[] headers = null;
if(theOpenHAB.getSecure() != null && theOpenHAB.getSecure())
theUrl = "https://";
else
theUrl = "http://";
if(theOpenHAB.getUsername() != null && !theOpenHAB.getUsername().isEmpty() && theOpenHAB.getPassword() != null && !theOpenHAB.getPassword().isEmpty()) {
theUrl = theUrl + theOpenHAB.getUsername() + ":" + theOpenHAB.getPassword() + "@";
}
theUrl = theUrl + theOpenHAB.getIp() + ":" + theOpenHAB.getPort() + "/rest/items?recursive=false";
theData = httpClient.doHttpRequest(theUrl, HttpGet.METHOD_NAME, "application/json", null, headers);
if(theData != null) {
log.debug("GET OpenHAB States - data: " + theData);
try {
theOpenhabStates = new Gson().fromJson(theData, OpenHABItem[].class);
if(theOpenhabStates == null) {
log.warn("Cannot get any devices for OpenHAB " + theOpenHAB.getName() + " as response is not parsable.");
}
else {
deviceList = new ArrayList<OpenHABDevice>();
for (int i = 0; i < theOpenhabStates.length; i++) {
OpenHABDevice aNewOpenHABDeviceDevice = new OpenHABDevice();
aNewOpenHABDeviceDevice.setItem(theOpenhabStates[i]);
aNewOpenHABDeviceDevice.setAddress(theOpenHAB.getIp() + ":" + theOpenHAB.getPort());
aNewOpenHABDeviceDevice.setName(theOpenHAB.getName());
deviceList.add(aNewOpenHABDeviceDevice);
}
}
} catch (Exception e) {
log.warn("Cannot get an devices for OpenHAB " + theOpenHAB.getName() + " Gson Parse Error.");
}
}
else
log.warn("Cannot get an devices for OpenHAB " + theOpenHAB.getName() + " http call failed.");
return deviceList;
}
protected void closeClient() {
}
}

View File

@@ -0,0 +1,110 @@
package com.bwssystems.HABridge.plugins.openhab;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class OpenHABItem {
@SerializedName("link")
@Expose
private String link;
@SerializedName("state")
@Expose
private String state;
@SerializedName("type")
@Expose
private String type;
@SerializedName("name")
@Expose
private String name;
@SerializedName("label")
@Expose
private String label;
@SerializedName("category")
@Expose
private String category;
@SerializedName("tags")
@Expose
private List<Object> tags = null;
@SerializedName("groupNames")
@Expose
private List<Object> groupNames = null;
@SerializedName("stateDescription")
@Expose
private StateDescription stateDescription;
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public List<Object> getTags() {
return tags;
}
public void setTags(List<Object> tags) {
this.tags = tags;
}
public List<Object> getGroupNames() {
return groupNames;
}
public void setGroupNames(List<Object> groupNames) {
this.groupNames = groupNames;
}
public StateDescription getStateDescription() {
return stateDescription;
}
public void setStateDescription(StateDescription stateDescription) {
this.stateDescription = stateDescription;
}
}

View File

@@ -0,0 +1,32 @@
package com.bwssystems.HABridge.plugins.openhab;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Option {
@SerializedName("value")
@Expose
private String value;
@SerializedName("label")
@Expose
private String label;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}

View File

@@ -0,0 +1,44 @@
package com.bwssystems.HABridge.plugins.openhab;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class StateDescription {
@SerializedName("pattern")
@Expose
private String pattern;
@SerializedName("readOnly")
@Expose
private Boolean readOnly;
@SerializedName("options")
@Expose
private List<Option> options = null;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public Boolean getReadOnly() {
return readOnly;
}
public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}
public List<Option> getOptions() {
return options;
}
public void setOptions(List<Option> options) {
this.options = options;
}
}

View File

@@ -125,4 +125,9 @@ public class SomfyHome implements Home {
somfys = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -75,7 +75,7 @@ public class SomfyInfo {
urlEncodedFormEntity.writeTo(bos);
String body = bos.toString();
String response = httpClient.doHttpRequest(BASE_URL + "json/login",HttpPost.METHOD_NAME, "application/x-www-form-urlencoded", body,httpHeader);
log.debug(response);
log.debug("Somfy login response <<<" + response + ">>>");
}
private NameValue[] getHttpHeaders() {
@@ -89,7 +89,7 @@ public class SomfyInfo {
NameValue[] httpHeader = getHttpHeaders();
log.info("Making SOMFY http setup call");
String response = httpClient.doHttpRequest(BASE_URL + "json/getSetup", HttpGet.METHOD_NAME, "", "", httpHeader );
log.debug(response);
log.debug("Somfy getSetup response <<<" + response + ">>>");
GetSetup setupData = new Gson().fromJson(response, GetSetup.class);
return setupData;
}
@@ -98,7 +98,7 @@ public class SomfyInfo {
login(namedIP.getUsername(), namedIP.getPassword());
log.info("Making SOMFY http exec call");
String response = httpClient.doHttpRequest(BASE_URL_ENDUSER + "exec/apply", HttpPost.METHOD_NAME, "application/json;charset=UTF-8", jsonToPost, getHttpHeaders());
log.info(response);
log.debug("Somfy exec reply response <<<" + response + ">>>");
}

View File

@@ -89,6 +89,9 @@ public class TCPHome implements Home {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
}
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
if (colorData != null) {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), true);
}
sendData = DatatypeConverter.parseHexBinary(theUrlBody.substring(2));
} else {
theUrlBody = BrightnessDecode.calculateReplaceIntensityValue(theUrlBody, intensity, targetBri, targetBriInc, false);
@@ -96,6 +99,9 @@ public class TCPHome implements Home {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
theUrlBody = DeviceDataDecode.replaceDeviceData(theUrlBody, device);
if (colorData != null) {
theUrlBody = ColorDecode.replaceColorData(theUrlBody, colorData, BrightnessDecode.calculateIntensity(intensity, targetBri, targetBriInc), false);
}
theUrlBody = StringEscapeUtils.unescapeJava(theUrlBody);
sendData = theUrlBody.getBytes();
}
@@ -166,5 +172,9 @@ public class TCPHome implements Home {
}
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -114,5 +114,9 @@ public class UDPHome implements Home {
}
closed = true;
}
@Override
public void refresh() {
// noop
}
}

View File

@@ -118,4 +118,9 @@ public class VeraHome implements Home {
veras = null;
closed = true;
}
@Override
public void refresh() {
// noop
}
}

File diff suppressed because one or more lines are too long

View File

@@ -30,6 +30,7 @@ public class UpnpListener {
private String bridgeId;
private String bridgeSNUUID;
private HuePublicConfig aHueConfig;
private Integer theUpnpSendDelay;
private String responseTemplate1 = "HTTP/1.1 200 OK\r\n" +
"HOST: %s:%s\r\n" +
"CACHE-CONTROL: max-age=100\r\n" +
@@ -76,6 +77,7 @@ public class UpnpListener {
strict = theSettings.isUpnpStrict();
traceupnp = theSettings.isTraceupnp();
useUpnpIface = theSettings.isUseupnpiface();
theUpnpSendDelay = theSettings.getUpnpsenddelay();
bridgeControl = theControl;
aHueConfig = HuePublicConfig.createConfig("temp", responseAddress, HueConstants.HUB_VERSION, theSettings.getHubmac());
bridgeId = aHueConfig.getBridgeid();
@@ -230,6 +232,11 @@ public class UpnpListener {
protected void sendUpnpResponse(InetAddress requester, int sourcePort) throws IOException {
String discoveryResponse = null;
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
discoveryResponse = String.format(responseTemplate1, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: send upnp discovery template 1 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);
@@ -238,6 +245,11 @@ public class UpnpListener {
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " with discovery responseTemplate1 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
discoveryResponse = String.format(responseTemplate2, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: send upnp discovery template 2 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);
@@ -246,6 +258,11 @@ public class UpnpListener {
log.debug("sendUpnpResponse to address: " + requester + ":" + sourcePort + " discovery responseTemplate2 is <<<" + discoveryResponse + ">>>");
sendUDPResponse(discoveryResponse.getBytes(), requester, sourcePort);
try {
Thread.sleep(theUpnpSendDelay);
} catch (InterruptedException e) {
// noop
}
discoveryResponse = String.format(responseTemplate3, Configuration.UPNP_MULTICAST_ADDRESS, Configuration.UPNP_DISCOVERY_PORT, responseAddress, httpServerPort, bridgeId, bridgeSNUUID);
if(traceupnp) {
log.info("Traceupnp: send upnp discovery template 3 with response address: " + responseAddress + ":" + httpServerPort + " to address: " + requester + ":" + sourcePort);

View File

@@ -3,6 +3,7 @@ package com.bwssystems.HABridge.upnp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.bwssystems.HABridge.BridgeSettings;
import com.bwssystems.HABridge.BridgeSettingsDescriptor;
import com.bwssystems.HABridge.api.hue.HueConstants;
import com.bwssystems.HABridge.api.hue.HuePublicConfig;
@@ -16,6 +17,7 @@ public class UpnpSettingsResource {
private Logger log = LoggerFactory.getLogger(UpnpSettingsResource.class);
private BridgeSettingsDescriptor theSettings;
private BridgeSettings bridgeSettings;
private String hueTemplate = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">\n"
@@ -35,15 +37,6 @@ public class UpnpSettingsResource {
+ "<modelURL>http://www.meethue.com</modelURL>\n"
+ "<serialNumber>%s</serialNumber>\n"
+ "<UDN>uuid:" + HueConstants.UUID_PREFIX + "%s</UDN>\n"
+ "<serviceList>\n"
+ "<service>\n"
+ "<serviceType>(null)</serviceType>\n"
+ "<serviceId>(null)</serviceId>\n"
+ "<controlURL>(null)</controlURL>\n"
+ "<eventSubURL>(null)</eventSubURL>\n"
+ "<SCPDURL>(null)</SCPDURL>\n"
+ "</service>\n"
+ "</serviceList>\n"
+ "<presentationURL>index.html</presentationURL>\n"
+ "<iconList>\n"
+ "<icon>\n"
@@ -64,15 +57,22 @@ public class UpnpSettingsResource {
+ "</device>\n"
+ "</root>\n";
public UpnpSettingsResource(BridgeSettingsDescriptor theBridgeSettings) {
public UpnpSettingsResource(BridgeSettings theBridgeSettings) {
super();
this.theSettings = theBridgeSettings;
this.bridgeSettings = theBridgeSettings;
this.theSettings = theBridgeSettings.getBridgeSettingsDescriptor();
}
public void setupServer() {
log.info("Description xml service started....");
// http://ip_adress:port/description.xml which returns the xml configuration for the hue emulator
get("/description.xml", "application/xml; charset=utf-8", (request, response) -> {
if(bridgeSettings.getBridgeControl().isReinit() || bridgeSettings.getBridgeControl().isStop()) {
log.info("Get description.xml called while in re-init or stop state");
response.status(503);
return null;
}
String portNumber = Integer.toString(request.port());
String filledTemplate = null;
String bridgeIdMac = HuePublicConfig.createConfig("temp", theSettings.getUpnpConfigAddress(), HueConstants.HUB_VERSION, theSettings.getHubmac()).getSNUUIDFromMac();

View File

@@ -50,7 +50,7 @@ public class UDPDatagramSender {
udpResponsePort++;
}
}
log.info("UDP response Seocket initialized to: " + udpResponsePort);
log.info("UDP response Socket initialized to: " + udpResponsePort);
return true;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -15,6 +15,7 @@
<link href="css/ngDialog-theme-default.min.css" rel="stylesheet">
<link href="css/scrollable-table.css" rel="stylesheet">
<link href="css/strength-meter.min.css" rel="stylesheet">
<link href="css/colorpicker.min.css" rel="stylesheet">
<!--[if lt IE 9]>
<script type="text/javascript" src="js/html5shiv.min.js"></script>
@@ -88,6 +89,7 @@
<script src="js/angular-base64.min.js"></script>
<script src="js/angular-resource.min.js"></script>
<script src="js/ngStorage.min.js"></script>
<script src="js/bootstrap-colorpicker-module.min.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'base64', 'scrollable-table', 'ngResource', 'ngStorage']);
var app = angular.module ('habridge', ['ngRoute', 'ngToast', 'rzModule', 'ngDialog', 'base64', 'scrollable-table', 'ngResource', 'ngStorage', 'colorpicker.module']);
app.config (function ($locationProvider, $routeProvider) {
$locationProvider.hashPrefix('!');
@@ -79,6 +79,18 @@ app.config (function ($locationProvider, $routeProvider) {
templateUrl: 'views/lifxdevice.html',
controller: 'LifxController',
requiresAuthentication: true
}).when ('/openhabdevices', {
templateUrl: 'views/openhabdevice.html',
controller: 'OpenHABController',
requiresAuthentication: true
}).when ('/fhemdevices', {
templateUrl: 'views/fhemdevice.html',
controller: 'FhemController',
requiresAuthentication: true
}).when ('/broadlinkdevices', {
templateUrl: 'views/broadlinkdevice.html',
controller: 'BroadlinkController',
requiresAuthentication: true
}).when ('/login', {
templateUrl: 'views/login.html',
controller: 'LoginController'
@@ -147,7 +159,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
this.state = {base: "./api/devices", bridgelocation: ".", systemsbase: "./system", huebase: "./api", configs: [], backups: [], devices: [], device: {},
mapandid: [], type: "", settings: [], myToastMsg: [], logMsgs: [], loggerInfo: [], mapTypes: [], olddevicename: "", logShowAll: false,
isInControl: false, showVera: false, showFibaro: false, showHarmony: false, showNest: false, showHue: false, showHal: false, showMqtt: false, showHass: false,
showHomeWizard: false, showDomoticz: false, showSomfy: false, showLifx: false, habridgeversion: {}, viewDevId: "", queueDevId: "", securityInfo: {}, filterDevicesByIpAddress: null,
showHomeWizard: false, showDomoticz: false, showSomfy: false, showLifx: false, showOpenHAB: false, showFHEM: false, showBroadlink: false, habridgeversion: {}, viewDevId: "", queueDevId: "", securityInfo: {}, filterDevicesByIpAddress: null,
filterDevicesOnlyFiltered: false, filterDeviceType: null};
this.displayWarn = function(errorTitle, error) {
@@ -460,6 +472,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
return false;
}
this.compareHarmonyNumber = function(r1, r2) {
if (r1.device !== undefined) {
if (r1.device.id === r2.device.id)
@@ -557,6 +570,21 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
return;
}
this.updateShowOpenHAB = function () {
this.state.showOpenHAB = self.state.settings.openhabconfigured;
return;
}
this.updateShowFhem = function () {
this.state.showFHEM = self.state.settings.fhemconfigured;
return;
}
this.updateShowBroadlink = function () {
this.state.showBroadlink = self.state.settings.broadlinkconfigured;
return;
}
this.loadBridgeSettings = function () {
return $http.get(this.state.systemsbase + "/settings").then(
function (response) {
@@ -573,6 +601,9 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.updateShowDomoticz();
self.updateShowSomfy();
self.updateShowLifx();
self.updateShowOpenHAB();
self.updateShowFhem();
self.updateShowBroadlink();
},
function (error) {
if (error.status === 401)
@@ -880,13 +911,72 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
);
};
this.viewOpenHABDevices = function () {
if (!this.state.showOpenHAB)
return;
return $http.get(this.state.base + "/openhab/devices").then(
function (response) {
self.state.openhabdevices = response.data;
},
function (error) {
if (error.status === 401)
$rootScope.$broadcast('securityReinit', 'done');
else
self.displayWarn("Get OpenHAB Devices Error: ", error);
}
);
};
this.viewFhemDevices = function () {
if (!this.state.showFHEM)
return;
return $http.get(this.state.base + "/fhem/devices").then(
function (response) {
self.state.fhemdevices = response.data;
},
function (error) {
if (error.status === 401)
$rootScope.$broadcast('securityReinit', 'done');
else
self.displayWarn("Get FHEM Devices Error: ", error);
}
);
};
this.viewBroadlinkDevices = function () {
if (!this.state.showBroadlink)
return;
return $http.get(this.state.base + "/broadlink/devices").then(
function (response) {
self.state.broadlinkdevices = response.data;
},
function (error) {
if (error.status === 401)
$rootScope.$broadcast('securityReinit', 'done');
else
self.displayWarn("Get broadlink Devices Error: ", error);
}
);
};
this.refreshDevices = function (typeIndex) {
return $http.get(this.state.base + "/refresh/" + typeIndex).then(
function (response) {
self.displaySuccess("Refresh devices request complete");
},
function (error) {
self.displayWarn("Refresh devices request Error: ", error);
}
);
};
this.formatCallItem = function (currentItem) {
if(!currentItem.startsWith("{\"item") && !currentItem.startsWith("[{\"item")) {
if(currentItem.indexOf("item") < 0) {
if (currentItem.startsWith("[") || currentItem.startsWith("{"))
currentItem = "[{\"item\":" + currentItem + "}]";
else
currentItem = "[{\"item\":\"" + currentItem + "\"}]";
} else if(currentItem.startsWith("{\"item"))
} else if(currentItem.startsWith("{"))
currentItem = "[" + currentItem + "]";
return currentItem;
@@ -1139,7 +1229,7 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
content:"HABridge is re-initializing, waiting for completion..."});
setTimeout(function(){
self.checkForBridge();
}, 2000);
}, 5000);
},
function (error) {
if (error.status === 401)
@@ -1250,20 +1340,60 @@ app.service ('bridgeService', function ($rootScope, $http, $base64, $location, n
self.state.device = device;
};
this.testUrl = function (device, type, value) {
this.toXY = function (red, green, blue) {
//Gamma corrective
red = (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92);
green = (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92);
blue = (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92);
//Apply wide gamut conversion D65
var X = red * 0.664511 + green * 0.154324 + blue * 0.162028;
var Y = red * 0.283881 + green * 0.668433 + blue * 0.047685;
var Z = red * 0.000088 + green * 0.072310 + blue * 0.986039;
var fx = X / (X + Y + Z);
var fy = Y / (X + Y + Z);
if (isNaN(fx)) {
fx = 0.0;
}
if (isNaN(fy)) {
fy = 0.0;
}
return [fx.toPrecision(4),fy.toPrecision(4)];
};
this.testUrl = function (device, type, value, valueType) {
var msgDescription = "unknown";
self.getTestUser();
var testUrl = this.state.huebase + "/" + this.state.testuser + "/lights/" + device.id + "/state";
var testBody = "{\"on\":";
var addComma = false;
var testBody = "{";
if (type === "off") {
testBody = testBody + "false";
} else {
testBody = testBody + "true";
testBody = testBody + "\"on\":false";
addComma = true
}
if (value) {
testBody = testBody + ",\"bri\":" + value;
if (type === "on") {
testBody = testBody + "\"on\":true";
addComma = true
}
if (valueType === "dim" && value) {
if(addComma)
testBody = testBody + ",";
testBody = testBody + "\"bri\":" + value;
addComma = true
}
if (valueType === "color" && value) {
if(addComma)
testBody = testBody + ",";
testBody = testBody + "\"xy\": [" + value[0] +"," + value[1] + "]";
}
testBody = testBody + "}";
if (testBody === "{}") {
self.displayWarn("No value available for test call...", null);
return;
}
$http.put(testUrl, testBody).then(
function (response) {
if (typeof(response.data[0].success) !== 'undefined') {
@@ -1411,6 +1541,10 @@ app.controller ('SystemController', function ($scope, $location, bridgeService,
$scope.bridge.isInControl = false;
$scope.visible = false;
$scope.imgUrl = "glyphicon glyphicon-plus";
$scope.newhassport = "8123";
$scope.newdomoticzport = "8080";
$scope.newopenhabport = "8080";
$scope.newfhemport = "8080";
$scope.addVeratoSettings = function (newveraname, newveraip) {
if($scope.bridge.settings.veraaddress === undefined || $scope.bridge.settings.veraaddress === null) {
$scope.bridge.settings.veraaddress = { devices: [] };
@@ -1427,11 +1561,12 @@ app.controller ('SystemController', function ($scope, $location, bridgeService,
}
}
};
$scope.addFibarotoSettings = function (newfibaroname, newfibaroip, newfibaroport, newfibarousername, newfibaropassword) {
$scope.addFibarotoSettings = function (newfibaroname, newfibaroip, newfibaroport, newfibarousername, newfibaropassword, filters) {
if($scope.bridge.settings.fibaroaddress === undefined || $scope.bridge.settings.fibaroaddress === null) {
$scope.bridge.settings.fibaroaddress = { devices: [] };
}
var newFibaro = {name: newfibaroname, ip: newfibaroip, port: newfibaroport, username: newfibarousername, password: newfibaropassword }
var stringFilter = angular.toJson(filters);
var newFibaro = {name: newfibaroname, ip: newfibaroip, port: newfibaroport, username: newfibarousername, password: newfibaropassword, extensions: filters}
$scope.bridge.settings.fibaroaddress.devices.push(newFibaro);
$scope.newfibaroname = null;
$scope.newfibaroip = null;
@@ -1522,6 +1657,7 @@ app.controller ('SystemController', function ($scope, $location, bridgeService,
$scope.newhassip = null;
$scope.newhassport = null;
$scope.newhasspassword = null;
$scope.newhassport = "8123";
};
$scope.removeHasstoSettings = function (hassname, hassip) {
for(var i = $scope.bridge.settings.hassaddress.devices.length - 1; i >= 0; i--) {
@@ -1556,7 +1692,7 @@ app.controller ('SystemController', function ($scope, $location, bridgeService,
$scope.bridge.settings.domoticzaddress.devices.push(newdomoticz);
$scope.newdomoticzname = null;
$scope.newdomoticzip = null;
$scope.newdomoticzport = null;
$scope.newdomoticzport = "8080";
$scope.newdomoticzpassword = null;
};
$scope.removeDomoticztoSettings = function (domoticzname, domoticzip) {
@@ -1584,6 +1720,46 @@ app.controller ('SystemController', function ($scope, $location, bridgeService,
}
}
};
$scope.addOpenHABtoSettings = function (newopenhabname, newopenhabip, newopenhabport, newopenhabusername, newopenhabpassword, newopenhabsecure) {
if($scope.bridge.settings.openhabaddress === undefined || $scope.bridge.settings.openhabaddress === null) {
$scope.bridge.settings.openhabaddress = { devices: [] };
}
var newopenhab = {name: newopenhabname, ip: newopenhabip, port: newopenhabport, username: newopenhabusername, password: newopenhabpassword, secure: newopenhabsecure }
$scope.bridge.settings.openhabaddress.devices.push(newopenhab);
$scope.newopenhabname = null;
$scope.newopenhabip = null;
$scope.newopenhabport = "8080";
$scope.newopenhabusername = null;
$scope.newopenhabpassword = null;
};
$scope.removeOpenHABtoSettings = function (openhabname, openhabip) {
for(var i = $scope.bridge.settings.openhabaddress.devices.length - 1; i >= 0; i--) {
if($scope.bridge.settings.openhabaddress.devices[i].name === openhabname && $scope.bridge.settings.openhabaddress.devices[i].ip === openhabip) {
$scope.bridge.settings.openhabaddress.devices.splice(i, 1);
}
}
};
$scope.addFhemtoSettings = function (newfhemname, newfhemip, newfhemport, newfhemusername, newfhempassword, newfhemwebhook, newfhemsecure) {
if($scope.bridge.settings.fhemaddress === undefined || $scope.bridge.settings.fhemaddress === null) {
$scope.bridge.settings.fhemaddress = { devices: [] };
}
var newfhem = {name: newfhemname, ip: newfhemip, port: newfhemport, username: newfhemusername, password: newfhempassword, secure: newfhemsecure, webhook: newfhemwebhook }
$scope.bridge.settings.fhemaddress.devices.push(newfhem);
$scope.newfhemname = null;
$scope.newfhemip = null;
$scope.newfhemport = "8080";
$scope.newfhemusername = null;
$scope.newfhempassword = null;
$scope.newfhemwebhook = null;
};
$scope.removeFhemtoSettings = function (fhemname, fhemip) {
for(var i = $scope.bridge.settings.fhemaddress.devices.length - 1; i >= 0; i--) {
if($scope.bridge.settings.fhemaddress.devices[i].name === fhemname && $scope.bridge.settings.fhemaddress.devices[i].ip === fhemip) {
$scope.bridge.settings.fhemaddress.devices.splice(i, 1);
}
}
};
$scope.bridgeReinit = function () {
bridgeService.reinit();
@@ -1847,7 +2023,7 @@ app.controller('ViewingController', function ($scope, $location, bridgeService,
var dialogNeeded = false;
if ((type === "on" && device.onUrl !== undefined && bridgeService.aContainsB(device.onUrl, "${intensity")) ||
(type === "off" && device.offUrl !== undefined && bridgeService.aContainsB(device.offUrl, "${intensity")) ||
(type === "dim" && device.dimUrl !== undefined) || (type === "color" && device.colorUrl !== undefined)) {
(type === "dim" && device.dimUrl !== undefined)) {
$scope.bridge.device = device;
$scope.bridge.type = type;
ngDialog.open({
@@ -1856,8 +2032,19 @@ app.controller('ViewingController', function ($scope, $location, bridgeService,
className: 'ngdialog-theme-default'
});
}
else if ((type === "on" && device.onUrl !== undefined && bridgeService.aContainsB(device.onUrl, "${color")) ||
(type === "off" && device.offUrl !== undefined && bridgeService.aContainsB(device.offUrl, "${color")) ||
(type === "color" && device.colorUrl !== undefined)) {
$scope.bridge.device = device;
$scope.bridge.type = type;
ngDialog.open({
template: 'colorDialog',
controller: 'ColorDialogCtrl',
className: 'ngdialog-theme-default'
});
}
else
bridgeService.testUrl(device, type);
bridgeService.testUrl(device, type, null, type);
};
$scope.deleteDevice = function (device) {
$scope.bridge.device = device;
@@ -1946,7 +2133,28 @@ app.controller('ValueDialogCtrl', function ($scope, bridgeService, ngDialog) {
theValue = Math.round(($scope.slider.value * .01) * 255);
else
theValue = $scope.slider.value;
bridgeService.testUrl($scope.bridge.device, $scope.bridge.type, theValue);
bridgeService.testUrl($scope.bridge.device, $scope.bridge.type, theValue, "dim");
$scope.bridge.device = null;
$scope.bridge.type = "";
};
});
app.controller('ColorDialogCtrl', function ($scope, bridgeService, ngDialog) {
$scope.rgbPicker = {
color: 'rgb(255,255,255)'
};
$scope.bridge = bridgeService.state;
$scope.setValue = function () {
ngDialog.close('ngdialog1');
var next = $scope.rgbPicker.color.substr($scope.rgbPicker.color.indexOf('(') + 1);
var red = next.substr(0, next.indexOf(','));
next = next.substr(next.indexOf(',') + 1);
var green = next.substr(0, next.indexOf(','));
next = next.substr(next.indexOf(',') + 1);
var blue = next.substr(0, next.indexOf(')'));
var theValue = bridgeService.toXY(red, green, blue);
bridgeService.testUrl($scope.bridge.device, $scope.bridge.type, theValue, "color");
$scope.bridge.device = null;
$scope.bridge.type = "";
};
@@ -2139,6 +2347,7 @@ app.controller('FibaroController', function ($scope, $location, bridgeService, n
};
$scope.buildDeviceUrls = function (fibarodevice, dim_control, buildonly) {
var dimpayload = null;
if(dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)
dimpayload = "http://" + fibarodevice.fibaroaddress + ":" + fibarodevice.fibaroport + "/api/callAction?deviceID=" + fibarodevice.id + "&name=setValue&arg1=" + dim_control;
@@ -2155,6 +2364,8 @@ app.controller('FibaroController', function ($scope, $location, bridgeService, n
};
$scope.buildSceneUrls = function (fibaroscene) {
var onpayload = null;
var offpayload = null;
onpayload = "http://" + fibaroscene.fibaroaddress + ":" + fibaroscene.fibaroport + "/api/sceneControl?id=" + fibaroscene.id + "&action=start";
offpayload = "http://" + fibaroscene.fibaroaddress + ":" + fibaroscene.fibaroport + "/api/sceneControl?id=" + fibaroscene.id + "&action=stop";
@@ -2849,6 +3060,8 @@ app.controller('MQTTController', function ($scope, $location, bridgeService, ngD
bridgeService.viewMQTTDevices();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.mqttretain = false;
$scope.mqttqos = 1;
$scope.clearDevice = function () {
bridgeService.clearDevice();
@@ -2856,6 +3069,10 @@ app.controller('MQTTController', function ($scope, $location, bridgeService, ngD
};
$scope.buildMQTTPublish = function (mqttbroker, mqtttopic, mqttmessage, mqttqos, mqttretain) {
if(mqttretain === 'undefined')
mqttretain = false;
if(mqttqos === 'undefined')
mqttqos = 1;
onpayload = "{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\",\"qos\":\"" + mqttqos + "\",\"retain\":\"" + mqttretain + "\"}";
offpayload = "{\"clientId\":\"" + mqttbroker.clientId + "\",\"topic\":\"" + mqtttopic + "\",\"message\":\"" + mqttmessage + "\",\"qos\":\"" + mqttqos + "\",\"retain\":\"" + mqttretain + "\"}";
@@ -3312,6 +3529,11 @@ app.controller('LifxController', function ($scope, $location, bridgeService, ngD
$scope.device = bridgeService.state.device;
};
$scope.refreshDevices = function () {
bridgeService.refreshDevices("lifxDevice");
bridgeService.viewLifxDevices();
};
$scope.buildDeviceUrls = function (lifxdevice, dim_control, buildonly) {
dimpayload = angular.toJson(lifxdevice);
onpayload = angular.toJson(lifxdevice);
@@ -3440,7 +3662,7 @@ app.controller('SomfyController', function ($scope, $location, bridgeService, ng
$scope.buildDeviceUrls = function (somfydevice, dim_control, buildonly) {
//TODO - support partial window opening - add back 'dim_control' second param in here, and in somfydevice.html
dimpayload = "";
dimpayload = null;
onpayload = "{\"label\":\"Label that is ignored probably\",\"actions\":[{\"deviceURL\":\""+ somfydevice.deviceUrl+"\",\"commands\":[{\"name\":\"open\",\"parameters\":[]}]}]}";
offpayload = "{\"label\":\"Label that is ignored probably\",\"actions\":[{\"deviceURL\":\""+ somfydevice.deviceUrl+"\",\"commands\":[{\"name\":\"close\",\"parameters\":[]}]}]}";
@@ -3549,6 +3771,465 @@ app.controller('SomfyController', function ($scope, $location, bridgeService, ng
};
});
app.controller('OpenHABController', function ($scope, $location, bridgeService, ngDialog) {
$scope.bridge = bridgeService.state;
$scope.device = bridgeService.state.device;
$scope.device_dim_control = "";
$scope.bulk = { devices: [] };
$scope.selectAll = false;
bridgeService.viewOpenHABDevices();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.clearDevice = function () {
bridgeService.clearDevice();
$scope.device = bridgeService.state.device;
};
$scope.buildDeviceUrls = function (openhabdevice, dim_control, onaction, ondata, dimaction, dimdata, offaction, offdata, coloraction, colordata, buildonly) {
var preCmd = "/rest/items/" + openhabdevice.item.name;
if(openhabdevice.item.type !== 'String') {
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)) {
dimpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + dim_control + "\"}";
}
else
dimpayload = null;
onpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"ON\"}";
offpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"OFF\"}";
colorpayload = null;
}
else {
if(onaction === 'other')
onpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + ondata + "\"}";
else if(onaction !== undefined && onaction !== null && onaction !== '')
onpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + onaction + "\"}";
else
onpayload = null;
if(dimaction === 'other')
dimpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + dimdata + "\"}";
else if(dimaction !== undefined && dimaction !== null && dimaction !== '')
dimpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + dimaction + "\"}";
else
dimpayload = null;
if(offaction === 'other')
offpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + offdata + "\"}";
else if(offaction !== undefined && offaction !== null && offaction !== '')
offpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + offaction + "\"}";
else
offpayload = null;
if(coloraction === 'other')
colorpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + colordata + "\"}";
else if(coloraction !== undefined && coloraction !== null && coloraction !== '')
colorpayload = "{\"url\":\"http://" + openhabdevice.address + preCmd + "\",\"command\":\"" + coloraction + "\"}";
else
colorpayload = null;
}
bridgeService.buildUrls(onpayload, dimpayload, offpayload, colorpayload, true, openhabdevice.item.name + "-" + openhabdevice.name, openhabdevice.item.name, openhabdevice.name, openhabdevice.item.type, "openhabDevice", 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.openhabdevices.length; x++) {
if(bridgeService.state.openhabdevices[x].devicename === $scope.bulk.devices[i]) {
$scope.buildDeviceUrls(bridgeService.state.openhabdevices[x],dim_control, null, null, null, null, null, null, null, null, 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,
colorUrl: $scope.device.colorUrl,
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 openhab 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.openhabdevices.length; x++) {
if($scope.bulk.devices.indexOf(bridgeService.state.openhabdevices[x]) < 0)
$scope.bulk.devices.push(bridgeService.state.openhabdevices[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('FhemController', function ($scope, $location, bridgeService, ngDialog) {
$scope.bridge = bridgeService.state;
$scope.device = bridgeService.state.device;
$scope.device_dim_control = "";
$scope.bulk = { devices: [] };
$scope.selectAll = false;
bridgeService.viewFhemDevices();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.clearDevice = function () {
bridgeService.clearDevice();
$scope.device = bridgeService.state.device;
};
$scope.buildDeviceUrls = function (fhemdevice, dim_control, buildonly) {
var preCmd = "/fhem?cmd=set%20" + fhemdevice.item.Name + "%20";
if(fhemdevice.item.PossibleSets.toLowerCase().indexOf("dim") >= 0) {
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)) {
dimpayload = "{\"url\":\"http://" + fhemdevice.address + preCmd + "\",\"command\":\"dim%20" + dim_control + "\"}";
}
else
dimpayload = "{\"url\":\"http://" + fhemdevice.address + preCmd + "\",\"command\":\"dim%20${intensity.percent}\"}";
}
else if(fhemdevice.item.PossibleSets.toLowerCase().indexOf("pct") >= 0) {
if((dim_control.indexOf("byte") >= 0 || dim_control.indexOf("percent") >= 0 || dim_control.indexOf("math") >= 0)) {
dimpayload = "{\"url\":\"http://" + fhemdevice.address + preCmd + "\",\"command\":\"pct%20" + dim_control + "\"}";
}
else
dimpayload = "{\"url\":\"http://" + fhemdevice.address + preCmd + "\",\"command\":\"pct%20${intensity.percent}\"}";
}
else
dimpayload = null;
if(fhemdevice.item.PossibleSets.toLowerCase().indexOf("rgb") >= 0) {
colorpayload = "{\"url\":\"http://" + fhemdevice.address + preCmd + "\",\"command\":\"RGB%20${color.rgbx}\"}";
}
else
colorpayload = null;
onpayload = "{\"url\":\"http://" + fhemdevice.address + preCmd + "\",\"command\":\"on\"}";
offpayload = "{\"url\":\"http://" + fhemdevice.address + preCmd + "\",\"command\":\"off\"}";
bridgeService.buildUrls(onpayload, dimpayload, offpayload, colorpayload, true, fhemdevice.item.Name + "-" + fhemdevice.name, fhemdevice.item.Name, fhemdevice.name, fhemdevice.item.type, "fhemDevice", 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.fhemdevices.length; x++) {
if(bridgeService.state.fhemdevices[x].devicename === $scope.bulk.devices[i]) {
$scope.buildDeviceUrls(bridgeService.state.fhemdevices[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,
colorUrl: $scope.device.colorUrl,
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 fhem 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.fhemdevices.length; x++) {
if($scope.bulk.devices.indexOf(bridgeService.state.fhemdevices[x]) < 0)
$scope.bulk.devices.push(bridgeService.state.fhemdevices[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('BroadlinkController', function ($scope, $location, bridgeService, ngDialog) {
$scope.bridge = bridgeService.state;
$scope.device = bridgeService.state.device;
$scope.device_dim_control = "";
$scope.bulk = { devices: [] };
$scope.selectAll = false;
bridgeService.viewBroadlinkDevices();
$scope.imgButtonsUrl = "glyphicon glyphicon-plus";
$scope.buttonsVisible = false;
$scope.clearDevice = function () {
bridgeService.clearDevice();
$scope.device = bridgeService.state.device;
};
$scope.refreshDevices = function () {
bridgeService.refreshDevices("broadlinkDevice");
bridgeService.viewBroadlinkDevices();
};
$scope.buildDeviceUrls = function (broadlinkdevice, dim_control, ondata, dimdata, offdata, colordata, buildonly) {
var preCmd = "{\"id\":\"" + broadlinkdevice.id + "\",\"name\":\"" + broadlinkdevice.name + "\",\"type\":\"" + broadlinkdevice.type + "\",\"ipAddr\":\"" + broadlinkdevice.ipAddr + "\",\"macAddr\":\"" + broadlinkdevice.macAddr + "\",\"command\":\"";
if(broadlinkdevice.baseType === '0000' || broadlinkdevice.baseType === '2711') {
dimpayload = null;
colorpayload = null;
onpayload = preCmd + "on\"}";
offpayload = preCmd + "off\"}";
}
else if(broadlinkdevice.baseType === '4EB5') {
dimpayload = null;
colorpayload = null;
onpayload = preCmd + "on\",\"data\":\"" + ondata + "\"}";
offpayload = preCmd + "off\",\"data\":\"" + offdata + "\"}";
} else {
if( ondata !== undefined && ondata !== null && ondata !== "")
onpayload = preCmd + "ircommand\",\"data\":\"" + ondata + "\"}";
else
onpayload = null;
if( dimdata !== undefined && dimdata !== null && dimdata !== "")
dimpayload = preCmd + "ircommand\",\"data\":\"" + dimdata + "\"}";
else
dimpayload = null;
if( offdata !== undefined && offdata !== null && offdata !== "")
offpayload = preCmd + "ircommand\",\"data\":\"" + offdata + "\"}";
else
offpayload = null;
if( colordata !== undefined && colordata !== null && colordata !== "")
colorpayload = preCmd + "ircommand\",\"data\":\"" + colordata + "\"}";
else
colorpayload = null;
}
bridgeService.buildUrls(onpayload, dimpayload, offpayload, colorpayload, true, broadlinkdevice.id, broadlinkdevice.name, broadlinkdevice.id, broadlinkdevice.desc, "broadlinkDevice", 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.broadlinkdevices.length; x++) {
if(bridgeService.state.broadlinkdevices[x].devicename === $scope.bulk.devices[i]) {
$scope.buildDeviceUrls(bridgeService.state.broadlinkdevices[x],dim_control,null,null,null,null,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,
colorUrl: $scope.device.colorUrl,
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 openhab 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.broadlinkdevices.length; x++) {
if($scope.bulk.devices.indexOf(bridgeService.state.broadlinkdevices[x]) < 0)
$scope.bulk.devices.push(bridgeService.state.broadlinkdevices[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('EditController', function ($scope, $location, bridgeService) {
$scope.bridge = bridgeService.state;
$scope.device = bridgeService.state.device;
@@ -3676,6 +4357,7 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
$scope.onDevices.splice(i, 1);
}
}
$scope.newOnItem = {};
};
$scope.addItemDim = function (anItem) {
@@ -3693,6 +4375,7 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
$scope.dimDevices.splice(i, 1);
}
}
$scope.newDimItem = {};
};
$scope.addItemOff = function (anItem) {
@@ -3710,6 +4393,7 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
$scope.offDevices.splice(i, 1);
}
}
$scope.newOffItem = {};
};
$scope.addItemColor = function (anItem) {
@@ -3727,6 +4411,7 @@ app.controller('EditController', function ($scope, $location, bridgeService) {
$scope.colorDevices.splice(i, 1);
}
}
$scope.newColorItem = {};
};
@@ -3966,6 +4651,48 @@ app.filter('configuredHomeWizardDevices', function (bridgeService) {
}
});
app.filter('configuredOpenHABItems', 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], "openhab")) {
out.push(input[i]);
}
}
return out;
}
});
app.filter('configuredFhemItems', 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], "fhem")) {
out.push(input[i]);
}
}
return out;
}
});
app.filter('configuredBroadlinkItems', 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], "broadlink")) {
out.push(input[i]);
}
}
return out;
}
});
app.filter('filterDevicesByRequester', function () {
return function(input,search,mustContain,deviceType) {
var out = [];

View File

@@ -0,0 +1,241 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation" class="active"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Broadlink Device List
({{bridge.broadlinkdevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any Broadlink Device, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured Broadlink Devices' list below will show what
is already setup for your broadlink.</p>
<p class="text-muted">
Also, use this select menu for which type of dim control you would
like to be generated: <select name="device-dim-control"
id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity.byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<p class="text-muted">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 Broadlink.</p>
<p>
<button class="btn btn-success" type="submit"
ng-click="refreshDevices()">Refresh</button>
</p>
<scrollable-table watch="bridge.broadlinkdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="id">
<span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> ID</span></th>
<th sortable-header col="desc">Description</th>
<th sortable-header col="type">Type</th>
<th col="string-actions">On Actions</th>
<th col="string-actions">Dim Actions</th>
<th col="string-actions">Off Actions</th>
<th col="string-actions">Color Actions</th>
<th>Build Actions</th>
</tr>
</thead>
<tr ng-if="broadlinkdevice.baseType === '0000' || broadlinkdevice.baseType === '2711'" ng-repeat="broadlinkdevice in bridge.broadlinkdevices">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{broadlinkdevice.id}}"
ng-checked="bulk.devices.indexOf(broadlinkdevice.id) > -1"
ng-click="toggleSelection(broadlinkdevice.id)">
{{broadlinkdevice.id}}</td>
<td>{{broadlinkdevice.name}}</td>
<td>{{broadlinkdevice.type}}</td>
<td>
On
</td>
<td>
Not Available
</td>
<td>
Off
</td>
<td>
Not Available
</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(broadlinkdevice, device_dim_control, null, null, null, null, false)">Build Item</button>
</td>
</tr>
<tr ng-if="broadlinkdevice.baseType === '4EB5'" ng-repeat="broadlinkdevice in bridge.broadlinkdevices">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{broadlinkdevice.id}}"
ng-checked="bulk.devices.indexOf(broadlinkdevice.id) > -1"
ng-click="toggleSelection(broadlinkdevice.id)">
{{broadlinkdevice.id}}</td>
<td>{{broadlinkdevice.name}}</td>
<td>{{broadlinkdevice.type}}</td>
<td>
On
<select name="on-input-device-action" id="on-input-device-action" ng-model="ondata">
<option value="1">Socket 1</option>
<option value="2">Socket 2</option>
<option value="3">Socket 3</option>
<option value="4">Socket 4</option>
</select>
</td>
<td>
Not Available
</td>
<td>
Off
<select name="off-input-device-action" id="off-input-device-action" ng-model="offdata">
<option value="1">Socket 1</option>
<option value="2">Socket 2</option>
<option value="3">Socket 3</option>
<option value="4">Socket 4</option>
</select>
</td>
<td>
Not Available
</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(broadlinkdevice, device_dim_control, ondata, null, offdata, null, false)">Build Item</button>
</td>
</tr>
<tr ng-if="broadlinkdevice.baseType === '2712'" ng-repeat="broadlinkdevice in bridge.broadlinkdevices">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{broadlinkdevice.id}}"
ng-checked="bulk.devices.indexOf(broadlinkdevice.id) > -1"
ng-click="toggleSelection(broadlinkdevice.id)">
{{broadlinkdevice.id}}</td>
<td>{{broadlinkdevice.name}}</td>
<td>{{broadlinkdevice.type}}</td>
<td>
<input id="on-input-device-action"
class="form-control" type="text"
ng-model="ondata"
placeholder="IR Code Data in Hex String">
</td>
<td>
<input id="dim-input-device-action"
class="form-control" type="text"
ng-model="dimdata"
placeholder="IR Code Data in Hex String">
</td>
<td>
<input id="off-input-device-action"
class="form-control" type="text"
ng-model="offdata"
placeholder="IR Code Data in Hex String">
</td>
<td>
<input id="color-input-device-action"
class="form-control" type="text"
ng-model="colordata"
placeholder="IR Code Data in Hex String">
</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(broadlinkdevice, device_dim_control, ondata, dimdata, offdata, colordata, false)">Build Item</button>
</td>
</tr>
</table>
</scrollable-table>
<div class="panel-footer">
<button class="btn btn-success" type="submit"
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
({{bulk.devices.length}})</button>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
Already Configured Broadlink Devices <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
</h2>
</div>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table watch="bridge.broadlinkdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="category">Category</th>
<th sortable-header col="broadlinkname">Broadlink</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredBroadlinkItems">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -1,32 +1,26 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a href="#!/">Bridge
Devices</a></li>
<li role="presentation" class="active"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div postrender-action="goToRow()">
@@ -85,7 +79,7 @@
<td>{{device.id}}</td>
<td>{{device.name}}</td>
<td class="cr">{{device.description}}</td>
<td class="cr">on={{device.deviceState.on}},bri={{device.deviceState.on}},hue={{device.deviceState.hue}},sat={{device.deviceState.sat}},effect={{device.deviceState.effect}},ct={{device.deviceState.ct}},alert={{device.deviceState.alert}},colormode={{device.deviceState.colormode}},reachable={{device.deviceState.reachable}},XYList={{device.deviceState.xy}}</td>
<td class="cr">on={{device.deviceState.on}},bri={{device.deviceState.bri}},hue={{device.deviceState.hue}},sat={{device.deviceState.sat}},effect={{device.deviceState.effect}},ct={{device.deviceState.ct}},alert={{device.deviceState.alert}},colormode={{device.deviceState.colormode}},reachable={{device.deviceState.reachable}},XYList={{device.deviceState.xy}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.inactive}}</td>
@@ -98,6 +92,8 @@
ng-click="testUrl(device, 'dim')">Test Dim</button>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device, 'off')">Test OFF</button>
<button class="btn btn-info" type="submit"
ng-click="testUrl(device, 'color')">Test Color</button>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit/Copy</button>
<button class="btn btn-danger" type="submit"
@@ -168,6 +164,17 @@
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
</div>
</script>
<script type="text/ng-template" id="colorDialog">
<div class="ngdialog-message">
<h2>Select Color</h2>
<p>
<input colorpicker="rgb" ng-model="rgbPicker.color" type="text">
</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-primary" ng-click="setValue()">Set</button>
</div>
</script>
<script type="text/ng-template" id="deleteDialog">
<div class="ngdialog-message">
<h2>Device to Delete?</h2>

View File

@@ -2,29 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/domoticzdevices">HAL
Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li role="presentation" class="active"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation" class="active"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -2,31 +2,25 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a
href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a
href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation" class="active"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
@@ -100,6 +94,12 @@
ng-model="device.offState" ng-true-value=true
ng-false-value=false> {{device.offState}}</td>
</tr>
<tr>
<td><label>On with First Dim (If the device is not on in the ha-bridge state, it will send on instead of the dim.)</label></td>
<td><input type="checkbox"
ng-model="device.onFirstDim" ng-true-value=true
ng-false-value=false> {{device.onFirstDim}}</td>
</tr>
<tr>
<td><label>Filter Address (comma separated list)</label></td>
<td><input type="text" class="form-control" id="device-requester-addr"

View File

@@ -0,0 +1,143 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation" class="active"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">FHEM Device List
({{bridge.fhemdevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any FHEM Device, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured FHEM Devices' list below will show what
is already setup for your FHEM.</p>
<p class="text-muted">
Also, use this select menu for which type of dim control you would
like to be generated: <select name="device-dim-control"
id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity.byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<p class="text-muted">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 FHEM.</p>
<scrollable-table watch="bridge.fhemdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">
<span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()">Device Name</span></th>
<th sortable-header col="fhemname">FHEM</th>
<th sortable-header col="type">Capabilities</th>
<th>Build Actions</th>
</tr>
</thead>
<tr ng-repeat="fhemdevice in bridge.fhemdevices">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{fhemdevice.item.name}}"
ng-checked="bulk.devices.indexOf(fhemdevice.item.name) > -1"
ng-click="toggleSelection(fhemdevice.item.name)">
{{fhemdevice.item.Name}}</td>
<td>{{fhemdevice.name}}</td>
<td>{{fhemdevice.item.PossibleSets}}</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(fhemdevice, device_dim_control, false)">Build Item</button>
</td>
</tr>
</table>
</scrollable-table>
<div class="panel-footer">
<button class="btn btn-success" type="submit"
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
({{bulk.devices.length}})</button>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
Already Configured FHEM Devices <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
</h2>
</div>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table watch="bridge.fhemdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="category">Category</th>
<th sortable-header col="fhemname">FHEM</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredFhemItems">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -4,23 +4,22 @@
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li role="presentation" class="active"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation" class="active"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -4,23 +4,22 @@
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li role="presentation" class="active"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation" class="active"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -2,28 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li role="presentation" class="active"><a href="#!/haldevices">HAL
Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation" class="active"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -2,29 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li role="presentation" class="active"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li role="presentation"><a href="#!/harmonydevices">Harmony
Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation" class="active"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -2,29 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li role="presentation"><a href="#!/harmonyactivities">Harmony
Activities</a></li>
<li role="presentation" class="active"><a href="#!/harmonydevices">Harmony
Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation" class="active"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -2,29 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL
Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li role="presentation" class="active"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHass" role="presentation" class="active"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -13,9 +13,13 @@
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation" class="active"><a href="#!/homewizarddevices">Somfy Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation" class="active"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -2,29 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li role="presentation" class="active"><a href="#!/huedevices">Hue
Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation" class="active"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -13,10 +13,13 @@
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li role="presentation" class="active"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation" class="active"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
@@ -38,6 +41,10 @@
feature. Select your items and dim control type if wanted, then click
bulk add below. Your items will be added with on, off and dim
with the name of the device from the LIFX device.</p>
<p>
<button class="btn btn-success" type="submit"
ng-click="refreshDevices()">Refresh</button>
</p>
<scrollable-table watch="bridge.lifxdevices">
<table class="table table-bordered table-striped table-hover">
<thead>

View File

@@ -21,7 +21,7 @@
</div>
</form>
<div ng-if="failed">
<p><font color="red">Login failed! Username or passowrd incorrect.</font></p>
<p><font color="red">Login failed! Username or password incorrect.</font></p>
</div>
</div>

View File

@@ -2,29 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation" class="active"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -11,12 +11,15 @@
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li role="presentation" class="active"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showMqtt" role="presentation" class="active"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
@@ -68,8 +71,9 @@
ng-model="mqttqos" placeholder="1"/>
</td>
<td>
<input type="checkbox" rows="1" class="form-control" id="mqtt-retain"
ng-model="mqttretain"/>
<input type="checkbox" id="mqtt-retain"
ng-model="mqttretain" ng-true-value=true
ng-false-value=false>{{mqttretain}}</td>
</td>
<td>
<button class="btn btn-success" type="submit"

View File

@@ -2,29 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a
href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a
href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li role="presentation" class="active"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation" class="active"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

View File

@@ -0,0 +1,222 @@
<ul class="nav nav-pills" role="tablist">
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation" class="active"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">OpenHAB Device List
({{bridge.openhabdevices.length}})</h2>
</div>
<div class="panel-body">
<p class="text-muted">For any OpenHAB Device, use the build action buttons
to generate the item addition information into the ha-bridge device and this will put you into the edit screen. Then
you can modify the name to anything you want that will be the keyword
for the Echo or Google Home. Also, you can go back to any helper tab and click a build
action button to add another item for a multi-command. After you are
done in the edit tab, click the 'Add Bridge Device' to finish that selection
setup. The 'Already Configured OpenHAB Devices' list below will show what
is already setup for your OpenHAB.</p>
<p class="text-muted">
Also, use this select menu for which type of dim control you would
like to be generated: <select name="device-dim-control"
id="device-dim-control" ng-model="device_dim_control">
<option value="">none</option>
<option value="${intensity.byte}">Pass-thru Value</option>
<option value="${intensity.percent}">Percentage</option>
<option value="${intensity.decimal_percent}">Decimal Percentage</option>
<option value="${intensity.math(X*1)}">Custom Math</option>
</select>
</p>
<p class="text-muted">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 OpenHAB.</p>
<scrollable-table watch="bridge.openhabdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">
<span><input type="checkbox" name="selectAll"
value="{{selectAll}}"
ng-checked="selectAll"
ng-click="toggleSelectAll()"> Name</span></th>
<th sortable-header col="type">Type</th>
<th sortable-header col="openhabname">OpenHAB</th>
<th col="string-actions">On Actions</th>
<th col="string-actions">Dim Actions</th>
<th col="string-actions">Off Actions</th>
<th col="string-actions">Color Actions</th>
<th>Build Actions</th>
</tr>
</thead>
<tr ng-if="openhabdevice.item.type !== 'String'" ng-repeat="openhabdevice in bridge.openhabdevices">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{openhabdevice.item.name}}"
ng-checked="bulk.devices.indexOf(openhabdevice.item.name) > -1"
ng-click="toggleSelection(openhabdevice.item.name)">
{{openhabdevice.item.name}}</td>
<td>{{openhabdevice.item.type}}</td>
<td>{{openhabdevice.name}}</td>
<td>
On
</td>
<td>
<div ng-if="openhabdevice.item.type === 'Dimmer'">Use Dim Control selection</div>
<div ng-if="openhabdevice.item.type !== 'Dimmer'">Not Available</div>
</td>
<td>
Off
</td>
<td>
Not Available
</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(openhabdevice, device_dim_control, null, null, null, null, null, null, null, null, false)">Build Item</button>
</td>
</tr>
<tr ng-if="openhabdevice.item.type === 'String'" ng-repeat="openhabdevice in bridge.openhabdevices">
<td>{{$index+1}}</td>
<td><input type="checkbox" name="bulk.devices[]"
value="{{openhabdevice.item.name}}"
ng-checked="bulk.devices.indexOf(openhabdevice.item.name) > -1"
ng-click="toggleSelection(openhabdevice.item.name)">
{{openhabdevice.item.name}}</td>
<td>{{openhabdevice.item.type}}</td>
<td>{{openhabdevice.name}}</td>
<td>
<select name="on-device-action" id="on-device-action" ng-model="onaction">
<option value="">None</option>
<option ng-repeat="option in openhabdevice.item.stateDescription.options"
value="{{option.value}}">{{option.label}}</option>
<option value="other">Other</option>
</select>
<input ng-if="onaction === 'other'" id="on-input-device-action"
class="form-control" type="text"
ng-model="ondata"
placeholder="Type Action if Other">
</td>
<td>
<select name="dim-device-action" id="dim-device-action" ng-model="dimaction">
<option value="">None</option>
<option ng-repeat="option in openhabdevice.item.stateDescription.options"
value="{{option.value}}">{{option.label}}</option>
<option value="other">Other</option>
</select>
<input ng-if="dimaction === 'other'" id="dim-input-device-action"
class="form-control" type="text"
ng-model="dimdata"
placeholder="Type Action if Other">
</td>
<td>
<select name="off-device-action" id="off-device-action" ng-model="offaction">
<option value="">None</option>
<option ng-repeat="option in openhabdevice.item.stateDescription.options"
value="{{option.value}}">{{option.label}}</option>
<option value="other">Other</option>
</select>
<input ng-if="offaction === 'other'" id="off-input-device-action"
class="form-control" type="text"
ng-model="offdata"
placeholder="Type Action if Other">
</td>
<td>
<select name="color-device-action" id="color-device-action" ng-model="coloraction">
<option value="">None</option>
<option ng-repeat="option in openhabdevice.item.stateDescription.options"
value="{{option.value}}">{{option.label}}</option>
<option value="other">Other</option>
</select>
<inpu ng-if="coloraction === 'other'"t id="color-input-device-action"
class="form-control" type="text"
ng-model="colordata"
placeholder="Type Action if Other">
</td>
<td>
<button class="btn btn-success" type="submit"
ng-click="buildDeviceUrls(openhabdevice, device_dim_control, onaction, ondata, dimaction, dimdata, offaction, offdata, coloraction, colordata, false)">Build Item</button>
</td>
</tr>
</table>
</scrollable-table>
<div class="panel-footer">
<button class="btn btn-success" type="submit"
ng-click="bulkAddDevices(device_dim_control)">Bulk Add
({{bulk.devices.length}})</button>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">
Already Configured OpenHAB Devices <a ng-click="toggleButtons()"><span
class={{imgButtonsUrl}} aria-hidden="true"></span></a></a>
</h2>
</div>
<div ng-if="buttonsVisible" class="panel-body">
<scrollable-table watch="bridge.openhabdevices">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Row</th>
<th sortable-header col="name">Name</th>
<th sortable-header col="category">Category</th>
<th sortable-header col="openhabname">OpenHAB</th>
<th>Map Id</th>
<th>Actions</th>
</tr>
</thead>
<tr
ng-repeat="device in bridge.devices | configuredOpenHABItems">
<td>{{$index+1}}</td>
<td>{{device.name}}</td>
<td>{{device.deviceType}}</td>
<td>{{device.targetDevice}}</td>
<td>{{device.mapId}}</td>
<td>
<p>
<button class="btn btn-warning" type="submit"
ng-click="editDevice(device)">Edit</button>
<button class="btn btn-danger" type="submit"
ng-click="deleteDevice(device)">Delete</button>
</p>
</td>
</tr>
</table>
</scrollable-table>
</div>
</div>
<script type="text/ng-template" id="deleteMapandIdDialog">
<div class="ngdialog-message">
<h2>Device Map and Id?</h2>
<p>{{mapandid.mapType}} with {{mapandid.id}}</p>
<p>Are you Sure?</p>
</div>
<div class="ngdialog-buttons mt">
<button type="button" class="ngdialog-button ngdialog-button-error" ng-click="deleteMapandId(mapandid)">Delete</button>
</div>
</script>

View File

@@ -2,24 +2,24 @@
<li role="presentation"><a href="#!/">Bridge Devices</a></li>
<li role="presentation"><a href="#!/system">Bridge Control</a></li>
<li role="presentation"><a href="#!/logs">Logs</a></li>
<li role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a
href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/veradevices">Vera Devices</a></li>
<li ng-if="bridge.showVera" role="presentation"><a href="#!/verascenes">Vera Scenes</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibarodevices">Fibaro Devices</a></li>
<li ng-if="bridge.showFibaro" role="presentation"><a href="#!/fibaroscenes">Fibaro Scenes</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonyactivities">Harmony Activities</a></li>
<li ng-if="bridge.showHarmony" role="presentation"><a href="#!/harmonydevices">Harmony Devices</a></li>
<li ng-if="bridge.showNest" role="presentation"><a href="#!/nest">Nest</a></li>
<li ng-if="bridge.showHue" role="presentation"><a
href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a
href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showHue" role="presentation"><a href="#!/huedevices">Hue Devices</a></li>
<li ng-if="bridge.showHal" role="presentation"><a href="#!/haldevices">HAL Devices</a></li>
<li ng-if="bridge.showMqtt" role="presentation"><a href="#!/mqttmessages">MQTT Messages</a></li>
<li ng-if="bridge.showHass" role="presentation"><a href="#!/hassdevices">HomeAssistant Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showDomoticz" role="presentation"><a href="#!/domoticzdevices">Domoticz Devices</a></li>
<li ng-if="bridge.showSomfy" role="presentation" class="active"><a href="#!/somfydevices">Somfy Devices</a></li>
<li ng-if="bridge.showLifx" role="presentation"><a href="#!/lifxdevices">LIFX Devices</a></li>
<li ng-if="bridge.showHomeWizard" role="presentation"><a href="#!/homewizarddevices">HomeWizard Devices</a></li>
<li ng-if="bridge.showOpenHAB" role="presentation"><a href="#!/openhabdevices">OpenHAB Devices</a></li>
<li ng-if="bridge.showFHEM" role="presentation"><a href="#!/fhemdevices">FHEM Devices</a></li>
<li ng-if="bridge.showBroadlink" role="presentation"><a href="#!/broadlinkdevices">Broadlink Devices</a></li>
<li role="presentation"><a href="#!/editdevice">Add/Edit</a></li>
</ul>

Some files were not shown because too many files have changed in this diff Show More