added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.konnected/.classpath
Normal file
32
bundles/org.openhab.binding.konnected/.classpath
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
bundles/org.openhab.binding.konnected/.project
Normal file
23
bundles/org.openhab.binding.konnected/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.konnected</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
bundles/org.openhab.binding.konnected/NOTICE
Normal file
13
bundles/org.openhab.binding.konnected/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
96
bundles/org.openhab.binding.konnected/README.md
Normal file
96
bundles/org.openhab.binding.konnected/README.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Konnected Binding
|
||||
|
||||
This binding is for interacting with the [Konnected Alarm Panel](https://konnected.io/).
|
||||
A module which interfaces with existing home security sensors.
|
||||
Konnected is an open-source firmware and software that runs on a NodeMCU ESP8266 device.
|
||||
The Konnected hardware is specifically designed for an alarm panel installation, but the general purpose firmware/software can be run on any ESP8266 device.
|
||||
|
||||
## Supported Things
|
||||
|
||||
This binding supports one type of thing module, which represents a Konnected Alarm Panel.
|
||||
|
||||
## Discovery
|
||||
|
||||
The binding will auto discover The Konnected Alarm Panels which are attached to the same network as the server running openHAB via UPnP.
|
||||
The binding will then create things for each module discovered which can be added.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The binding attempts to discover The Konnected Alarm Panels via the UPnP service.
|
||||
The auto-discovery service of the binding will detect the ip address and port of the Konnected Alarm Panel.
|
||||
The binding will attempt to obtain the ip address of your openHAB server as configured in the OSGi framework.
|
||||
However, if it is unable to determine the ip address it will also attempt to use the network address service to obtain the ip address and port.
|
||||
In addition you can also turn off discovery which when this setting is synced to the module will cause the device to no longer respond to UPnP requests as documented.
|
||||
https://help.konnected.io/support/solutions/articles/32000023968-disabling-device-discovery
|
||||
Please use this setting with caution and do not disable until a static ip address has been provided for your Konnected Alarm Panel via DHCP, router or otherwise.
|
||||
The blink setting will disable the transmission LED on the Konnected Alarm Panel.
|
||||
|
||||
|
||||
## Channels
|
||||
|
||||
The auto discovered thing adds two default channels.
|
||||
|
||||
| Channel | Channel Id | Channel Type | Description |
|
||||
|---------|------------|--------------|----------------------------------------------------------|
|
||||
| 1 | Zone_6 | Switch | A Switch channel for zone 6 |
|
||||
| 2 | Out | Actuator | The Channel for the Out Pin on the Konnected Alarm Panel |
|
||||
|
||||
One channel for Zone 6 which is a sensor type channel, and one channel for the out pin that is an actuator type channel.
|
||||
These channels represent the two pins on the Konnected Alarm Panel whose type cannot be changed.
|
||||
For zones 1-5, you will need to add channels for the remaining zones that you have connected and configure them with the appropriate configuration parameters for each channel.
|
||||
|
||||
|
||||
| Channel Type | Item Type | Config Parameters | Description |
|
||||
|--------------|----------------------|----------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Switch | Switch | Zone Number | This is the channel type for sensors or other read only devices |
|
||||
| Actuator | Switch | Zone Number, Momentary, Pause, Times | This is the channel type for devices whose state can be turned on an off by the Konnected Alarm Panel |
|
||||
| Temperature | Number:Temperature | Zone Number, DHT22, Poll Interval, DS18b20 Address | This is the channel for sensors which measure temperature (DHT22 and DS18B20). The DHT22 setting should be set to true when the channel is monitoring a zone connected to a DHT22 sensor and false if the zone is connected to a DS1820B sensor |
|
||||
| Humidity | Number:Dimensionless | Zone Number | This is the channel type for the humidity sensor on a connected DHT22 sensor |
|
||||
|
||||
You will need to configure each channel with the appropriate zone number corresponding to the zone on The Konnected Alarm Panel.
|
||||
Then you need to link the corresponding item to the channel.
|
||||
|
||||
For the actuator type channels you can also add configuration parameters times, pause and momentary which will be added to the payload that is sent to the Konnected Alarm Panel.
|
||||
These parameters will tell the module to pulse the actuator for certain time period.
|
||||
A momentary switch actuates a switch for a specified time (in milliseconds) and then reverts it back to the off state.
|
||||
This is commonly used with a relay module to actuate a garage door opener, or with a door bell to send a momentary trigger to sound the door bell.
|
||||
A beep/blink switch is like a momentary switch that repeats either a specified number of times or indefinitely.
|
||||
This is commonly used with a piezo buzzer to make a "beep beep" sound when a door is opened, or to make a repeating beep pattern for an alarm or audible warning.
|
||||
It can also be used to blink lights.
|
||||
|
||||
DSB1820 temperature probes.
|
||||
These are one wire devices which can all be Konnected to the same "Zone" on the Konnected Alarm Panel.
|
||||
As part of its transmission the module will include an unique "address" property of each sensor probe that will be logged to the debug log when received.
|
||||
This needs to be added to the channel if there are multiple probes connected.
|
||||
The default behavior in absence of this configuration will be to simply log the address of the received event.
|
||||
A channel should be added for each probe, as indicated above and configured with the appropriate address.
|
||||
|
||||
|
||||
## Full Example
|
||||
|
||||
*.items
|
||||
|
||||
```
|
||||
Contact Front_Door_Sensor "Front Door" {channel="konnected:module:generic:switch"}
|
||||
Switch Siren "Siren" {channel="konnected:module:generic:actuator"}
|
||||
```
|
||||
|
||||
*.sitemap
|
||||
|
||||
```
|
||||
Switch item=Front_Door_Sensor label="Front Door" icon="door" mappings=[OPEN="Open", CLOSED="Closed"]
|
||||
Switch item=Siren label="Alarm Siren" icon="Siren" mappings=[ON="Open", OFF="Closed"]
|
||||
```
|
||||
|
||||
*.things
|
||||
|
||||
```
|
||||
Thing konnected:module:generic "Konnected Module" [ipAddress="http://192.168.30.153:9586", macAddress="1586517"]{
|
||||
Type switch : switch "Front Door" [channel_zone=1]
|
||||
Type actuator : actuator "Siren" [channel_zone=1, momentary = 50, times = 2, pause = 50]
|
||||
Type humidity : humidity "DHT - Humidity" [channel_zone=1]
|
||||
Type temperature : temperature "DHT Temperature" [channel_zone=1, tempsensorType = true, pollinterval = 1]
|
||||
Type temperature : temperature "DS18B20 Temperature" [channel_zone=1, tempsensorType = false, pollinterval = 1, ds18b20_address = "XX:XX:XX:XX:XX:XX:XX"]
|
||||
}
|
||||
```
|
||||
|
||||
17
bundles/org.openhab.binding.konnected/pom.xml
Normal file
17
bundles/org.openhab.binding.konnected/pom.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.konnected</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Konnected Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.konnected-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-konnected" description="Konnected Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-http</feature>
|
||||
<feature>openhab-transport-upnp</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.konnected/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link KonnectedBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class KonnectedBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "konnected";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_MODULE = new ThingTypeUID(BINDING_ID, "module");
|
||||
|
||||
// Thing config properties
|
||||
public static final String HOST = "ipAddress";
|
||||
public static final String MAC_ADDR = "macAddress";
|
||||
public static final String CALLBACK_PATH = "callBackPath";
|
||||
public static final String REQUEST_TIMEOUT = "request_timeout";
|
||||
public static final String RETRY_COUNT = "retry_count";
|
||||
|
||||
// PIN_TO_ZONE array, this array maps an index location as a zone to the corresponding
|
||||
// pin location
|
||||
public static final Integer[] PIN_TO_ZONE = { 0, 1, 2, 5, 6, 7, 9, 8 };
|
||||
|
||||
public static final String WEBHOOK_APP = "app_security";
|
||||
|
||||
public static final String CHANNEL_ZONE = "zone";
|
||||
|
||||
// channeltypeids
|
||||
public static final String CHANNEL_SWITCH = "konnected:switch";
|
||||
public static final String CHANNEL_ACTUATOR = "konnected:actuator";
|
||||
public static final String CHANNEL_TEMPERATURE = "konnected:temperature";
|
||||
public static final String CHANNEL_HUMIDITY = "konnected:humidity";
|
||||
|
||||
public static final String CHANNEL_TEMPERATURE_TYPE = "tempsensorType";
|
||||
public static final String CHANNEL_TEMPERATURE_DS18B20_ADDRESS = "ds18b20_address";
|
||||
public static final String CHANNEL_TEMPERATRUE_POLL = "pollinterval";
|
||||
|
||||
public static final String CHANNEL_ACTUATOR_TIMES = "times";
|
||||
public static final String CHANNEL_ACTUATOR_MOMENTARY = "momentary";
|
||||
public static final String CHANNEL_ACTUATOR_PAUSE = "pause";
|
||||
|
||||
public static final String CHANNEL_ONVALUE = "onvalue";
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal;
|
||||
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
|
||||
/**
|
||||
* The {@link KonnectedConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
public class KonnectedConfiguration extends Configuration {
|
||||
|
||||
/**
|
||||
* @param blink identifies whether the Konnected Alarm Panel LED will blink on transmission of Wifi Commands
|
||||
* @param discovery identifies whether the Konnected Alarm Panel will be discoverable via UPnP
|
||||
*/
|
||||
public boolean blink;
|
||||
public boolean discovery;
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* HTTP Get and Put reqeust class.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
public class KonnectedHTTPUtils {
|
||||
private final Logger logger = LoggerFactory.getLogger(KonnectedHTTPUtils.class);
|
||||
private int requestTimeout;
|
||||
private String logTest = "";
|
||||
|
||||
public KonnectedHTTPUtils(int requestTimeout) {
|
||||
this.requestTimeout = (int) TimeUnit.SECONDS.toMillis(requestTimeout);
|
||||
}
|
||||
|
||||
public void setRequestTimeout(int requestTimeout) {
|
||||
this.requestTimeout = (int) TimeUnit.SECONDS.toMillis(requestTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link doPut} request with a timeout of 30 seconds
|
||||
*
|
||||
* @param urlAddress the address to send the request
|
||||
* @param payload the json payload to include with the request
|
||||
*/
|
||||
private String doPut(String urlAddress, String payload) throws IOException {
|
||||
logger.debug("The String url we want to put is : {}", urlAddress);
|
||||
logger.debug("The payload we want to put is: {}", payload);
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
|
||||
String retVal = HttpUtil.executeUrl("PUT", urlAddress, getHttpHeaders(), input, "application/json",
|
||||
requestTimeout);
|
||||
logger.trace("return value: {}", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected Properties getHttpHeaders() {
|
||||
Properties httpHeaders = new Properties();
|
||||
httpHeaders.put("Content-Type", "application/json");
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link doGet} request with a timeout of 30 seconds
|
||||
*
|
||||
* @param urlAddress the address to send the request
|
||||
*/
|
||||
|
||||
private synchronized String doGet(String urlAddress) throws IOException {
|
||||
logger.debug("The String url we want to get is : {}", urlAddress);
|
||||
String retVal = HttpUtil.executeUrl("GET", urlAddress, requestTimeout);
|
||||
logger.trace("return value: {}", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link doGet} request with a timeout of 30 seconds
|
||||
*
|
||||
* @param urlAddress the address to send the request
|
||||
* @param payload the json payload you want to send as part of the request
|
||||
*/
|
||||
|
||||
private synchronized String doGet(String urlAddress, String payload) throws IOException {
|
||||
logger.debug("The String url we want to get is : {}", urlAddress);
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));
|
||||
String retVal = HttpUtil.executeUrl("GET", urlAddress, getHttpHeaders(), input, "application/json",
|
||||
requestTimeout);
|
||||
logger.trace("return value: {}", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link doGet} request with a timeout of 30 seconds
|
||||
*
|
||||
* @param urlAddress the address to send the request
|
||||
* @param payload the json payload you want to send as part of the request, may be null.
|
||||
* @param retry the number of retries before throwing the IOexpcetion back to the handler
|
||||
*/
|
||||
public synchronized String doGet(String urlAddress, String payload, int retryCount)
|
||||
throws KonnectedHttpRetryExceeded {
|
||||
String response = null;
|
||||
int x = 0;
|
||||
Boolean loop = true;
|
||||
while (loop) {
|
||||
try {
|
||||
if (payload == null) {
|
||||
response = doGet(urlAddress, payload);
|
||||
} else {
|
||||
response = doGet(urlAddress);
|
||||
}
|
||||
loop = false;
|
||||
} catch (IOException e) {
|
||||
x++;
|
||||
if (x > retryCount) {
|
||||
throw new KonnectedHttpRetryExceeded("The number of retry attempts was exceeded", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a {@link doPut} request with a timeout of 30 seconds
|
||||
*
|
||||
* @param urlAddress the address to send the request
|
||||
* @param payload the json payload you want to send as part of the request
|
||||
* @param retry the number of retries before throwing the IOexpcetion back to the handler
|
||||
*/
|
||||
public synchronized String doPut(String urlAddress, String payload, int retryCount)
|
||||
throws KonnectedHttpRetryExceeded {
|
||||
String response = null;
|
||||
int x = 0;
|
||||
Boolean loop = true;
|
||||
while (loop) {
|
||||
try {
|
||||
response = doPut(urlAddress, payload);
|
||||
loop = false;
|
||||
} catch (IOException e) {
|
||||
x++;
|
||||
if (x > retryCount) {
|
||||
throw new KonnectedHttpRetryExceeded("The number of retry attempts was exceeded", e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal;
|
||||
|
||||
import static org.openhab.binding.konnected.internal.KonnectedBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.konnected.internal.handler.KonnectedHandler;
|
||||
import org.openhab.binding.konnected.internal.servlet.KonnectedHTTPServlet;
|
||||
import org.openhab.binding.konnected.internal.servlet.KonnectedWebHookFail;
|
||||
import org.openhab.core.net.HttpServiceUtil;
|
||||
import org.openhab.core.net.NetworkAddressService;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.http.HttpService;
|
||||
import org.osgi.service.http.NamespaceException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link KonnectedHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
@Component(configurationPid = "binding.konnected", service = ThingHandlerFactory.class)
|
||||
public class KonnectedHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final Logger logger = LoggerFactory.getLogger(KonnectedHandlerFactory.class);
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_MODULE);
|
||||
private static final String alias = "/" + BINDING_ID;
|
||||
|
||||
private HttpService httpService;
|
||||
private String callbackUrl = null;
|
||||
private NetworkAddressService networkAddressService;
|
||||
private KonnectedHTTPServlet servlet;
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(ComponentContext componentContext) {
|
||||
super.activate(componentContext);
|
||||
Dictionary<String, Object> properties = componentContext.getProperties();
|
||||
callbackUrl = (String) properties.get("callbackUrl");
|
||||
try {
|
||||
this.servlet = registerWebHookServlet();
|
||||
} catch (KonnectedWebHookFail e) {
|
||||
logger.error("Failed registering Konnected servlet - binding is not functional!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate(ComponentContext componentContext) {
|
||||
super.deactivate(componentContext);
|
||||
httpService.unregister(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
KonnectedHandler thingHandler = new KonnectedHandler(thing, '/' + BINDING_ID, createCallbackUrl(),
|
||||
createCallbackPort());
|
||||
if (servlet != null) {
|
||||
logger.debug("Adding thinghandler for thing {} to webhook.", thing.getUID().getId());
|
||||
servlet.add(thingHandler);
|
||||
}
|
||||
return thingHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param thingHandler thing handler to be removed
|
||||
*/
|
||||
@Override
|
||||
protected void removeHandler(ThingHandler thingHandler) {
|
||||
servlet.remove((KonnectedHandler) thingHandler);
|
||||
thingHandler.dispose();
|
||||
super.removeHandler(thingHandler);
|
||||
}
|
||||
|
||||
private KonnectedHTTPServlet registerWebHookServlet() throws KonnectedWebHookFail {
|
||||
KonnectedHTTPServlet servlet = new KonnectedHTTPServlet();
|
||||
try {
|
||||
httpService.registerServlet(alias, servlet, null, httpService.createDefaultHttpContext());
|
||||
return servlet;
|
||||
} catch (ServletException | NamespaceException e) {
|
||||
throw new KonnectedWebHookFail("Could not start Konnected Webhook servlet: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Reference
|
||||
public void setHttpService(HttpService httpService) {
|
||||
this.httpService = httpService;
|
||||
}
|
||||
|
||||
public void unsetHttpService(HttpService httpService) {
|
||||
this.httpService = null;
|
||||
}
|
||||
|
||||
private String createCallbackUrl() {
|
||||
if (callbackUrl != null) {
|
||||
logger.debug("The callback ip address from the OSGI is:{}", callbackUrl);
|
||||
return callbackUrl;
|
||||
} else {
|
||||
final String ipAddress = networkAddressService.getPrimaryIpv4HostAddress();
|
||||
if (ipAddress == null) {
|
||||
logger.warn("No network interface could be found.");
|
||||
return null;
|
||||
}
|
||||
logger.debug("The callback ip address obtained from the Network Address Service was:{}", ipAddress);
|
||||
return ipAddress;
|
||||
}
|
||||
}
|
||||
|
||||
private String createCallbackPort() {
|
||||
// we do not use SSL as it can cause certificate validation issues.
|
||||
final int port = HttpServiceUtil.getHttpServicePort(bundleContext);
|
||||
if (port == -1) {
|
||||
logger.warn("Cannot find port of the http service.");
|
||||
return null;
|
||||
}
|
||||
logger.debug("the port for the callback is: {}", port);
|
||||
return Integer.toString(port);
|
||||
}
|
||||
|
||||
@Reference
|
||||
protected void setNetworkAddressService(NetworkAddressService networkAddressService) {
|
||||
this.networkAddressService = networkAddressService;
|
||||
}
|
||||
|
||||
protected void unsetNetworkAddressService(NetworkAddressService networkAddressService) {
|
||||
this.networkAddressService = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal;
|
||||
|
||||
/**
|
||||
* Custom exception class to be thrown when number of retries is exceeded.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class KonnectedHttpRetryExceeded extends Exception {
|
||||
public KonnectedHttpRetryExceeded(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.konnected.internal.KonnectedBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.jupnp.model.meta.DeviceDetails;
|
||||
import org.jupnp.model.meta.ModelDetails;
|
||||
import org.jupnp.model.meta.RemoteDevice;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link KonnectedUPnPServer} is responsible for discovering new
|
||||
* Konnectedmodules modules. It uses the central {@link UpnpDiscoveryService}.
|
||||
*
|
||||
* @author Zachary Christainsen - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = UpnpDiscoveryParticipant.class, immediate = true)
|
||||
public class KonnectedUPnPServer implements UpnpDiscoveryParticipant {
|
||||
private Logger logger = LoggerFactory.getLogger(KonnectedUPnPServer.class);
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return Collections.singleton(THING_TYPE_MODULE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
|
||||
ThingUID uid = getThingUID(device);
|
||||
if (uid != null) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(HOST, device.getDetails().getBaseURL());
|
||||
properties.put(MAC_ADDR, device.getDetails().getSerialNumber());
|
||||
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withLabel(device.getDetails().getFriendlyName()).withRepresentationProperty(MAC_ADDR).build();
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
||||
DeviceDetails details = device.getDetails();
|
||||
if (details != null) {
|
||||
ModelDetails modelDetails = details.getModelDetails();
|
||||
|
||||
if (modelDetails != null) {
|
||||
String modelName = modelDetails.getModelName();
|
||||
logger.debug("Model Details: {} Url: {} UDN: {} Model Number: {}", modelName, details.getBaseURL(),
|
||||
details.getSerialNumber(), modelDetails.getModelNumber());
|
||||
if (modelName != null) {
|
||||
if (modelName.startsWith("Konnected")) {
|
||||
return new ThingUID(THING_TYPE_MODULE, details.getSerialNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal.gson;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link KonnectedModuleGson} is responsible to hold
|
||||
* data that models pin information which can be sent to a Konnected Module
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*
|
||||
*/
|
||||
public class KonnectedModuleGson {
|
||||
|
||||
private Integer pin;
|
||||
private String temp;
|
||||
private String humi;
|
||||
private String state;
|
||||
@SerializedName("Auth_Token")
|
||||
private String authToken;
|
||||
private String momentary;
|
||||
private String pause;
|
||||
private String times;
|
||||
@SerializedName("poll_interval")
|
||||
private Integer pollInterval;
|
||||
private String addr;
|
||||
|
||||
public Integer getPin() {
|
||||
return pin;
|
||||
}
|
||||
|
||||
public void setPin(Integer setPin) {
|
||||
this.pin = setPin;
|
||||
}
|
||||
|
||||
public Integer getPollInterval() {
|
||||
return pollInterval;
|
||||
}
|
||||
|
||||
public void setPollInterval(Integer setPollInterval) {
|
||||
this.pollInterval = setPollInterval;
|
||||
}
|
||||
|
||||
public String getTemp() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void setTemp(String setTemp) {
|
||||
this.temp = setTemp;
|
||||
}
|
||||
|
||||
public String getHumi() {
|
||||
return humi;
|
||||
}
|
||||
|
||||
public void setHumi(String setHumi) {
|
||||
this.humi = setHumi;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String setState) {
|
||||
this.state = setState;
|
||||
}
|
||||
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
public String getMomentary() {
|
||||
return momentary;
|
||||
}
|
||||
|
||||
public void setMomentary(String setMomentary) {
|
||||
this.momentary = setMomentary;
|
||||
}
|
||||
|
||||
public String getPause() {
|
||||
return pause;
|
||||
}
|
||||
|
||||
public void setPause(String setPause) {
|
||||
this.pause = setPause;
|
||||
}
|
||||
|
||||
public String getTimes() {
|
||||
return times;
|
||||
}
|
||||
|
||||
public void setTimes(String setTimes) {
|
||||
this.times = setTimes;
|
||||
}
|
||||
|
||||
public String getAddr() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
public void setAddr(String setAddr) {
|
||||
this.addr = setAddr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal.gson;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link KonnectedModulePayload} is responsible to hold
|
||||
* data to send as settings for the konnected module
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*
|
||||
*/
|
||||
public class KonnectedModulePayload {
|
||||
|
||||
private Set<KonnectedModuleGson> sensors;
|
||||
private Set<KonnectedModuleGson> actuators;
|
||||
@SerializedName("dht_sensors")
|
||||
private Set<KonnectedModuleGson> dht22;
|
||||
@SerializedName("ds18b20_sensors")
|
||||
private Set<KonnectedModuleGson> ds18b20;
|
||||
@SerializedName("token")
|
||||
private String authToken;
|
||||
private String apiUrl;
|
||||
private Boolean blink;
|
||||
private Boolean discovery;
|
||||
|
||||
public KonnectedModulePayload(String authTokenPassed, String apiURLPassed) {
|
||||
this.authToken = authTokenPassed;
|
||||
this.apiUrl = apiURLPassed;
|
||||
this.sensors = new HashSet<>();
|
||||
this.actuators = new HashSet<>();
|
||||
this.dht22 = new HashSet<>();
|
||||
this.ds18b20 = new HashSet<>();
|
||||
}
|
||||
|
||||
public Set<KonnectedModuleGson> getSensors() {
|
||||
return sensors;
|
||||
}
|
||||
|
||||
public void addSensor(KonnectedModuleGson sensor) {
|
||||
this.sensors.add(sensor);
|
||||
}
|
||||
|
||||
public void removeSensor(KonnectedModuleGson sensor) {
|
||||
this.sensors.remove(sensor);
|
||||
}
|
||||
|
||||
public Set<KonnectedModuleGson> getActuators() {
|
||||
return actuators;
|
||||
}
|
||||
|
||||
public void addActuators(KonnectedModuleGson actuator) {
|
||||
this.actuators.add(actuator);
|
||||
}
|
||||
|
||||
public void removeActuator(KonnectedModuleGson actuator) {
|
||||
this.actuators.remove(actuator);
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
public String getapiUrl() {
|
||||
return apiUrl;
|
||||
}
|
||||
|
||||
public Set<KonnectedModuleGson> getDht22() {
|
||||
return dht22;
|
||||
}
|
||||
|
||||
public void addDht22(KonnectedModuleGson Dht22) {
|
||||
this.dht22.add(Dht22);
|
||||
}
|
||||
|
||||
public void removeDht22(KonnectedModuleGson Dht22) {
|
||||
this.dht22.remove(Dht22);
|
||||
}
|
||||
|
||||
public Set<KonnectedModuleGson> getDs18b20() {
|
||||
return ds18b20;
|
||||
}
|
||||
|
||||
public void addDs18b20(KonnectedModuleGson Ds18b20) {
|
||||
this.ds18b20.add(Ds18b20);
|
||||
}
|
||||
|
||||
public void removeDs18b20(KonnectedModuleGson Ds18b20) {
|
||||
this.ds18b20.remove(Ds18b20);
|
||||
}
|
||||
|
||||
public void setDiscovery(Boolean setDiscovery) {
|
||||
this.discovery = setDiscovery;
|
||||
}
|
||||
|
||||
public void setBlink(Boolean setBlink) {
|
||||
this.blink = setBlink;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal.handler;
|
||||
|
||||
import static org.openhab.binding.konnected.internal.KonnectedBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openhab.binding.konnected.internal.KonnectedConfiguration;
|
||||
import org.openhab.binding.konnected.internal.KonnectedHTTPUtils;
|
||||
import org.openhab.binding.konnected.internal.KonnectedHttpRetryExceeded;
|
||||
import org.openhab.binding.konnected.internal.gson.KonnectedModuleGson;
|
||||
import org.openhab.binding.konnected.internal.gson.KonnectedModulePayload;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.config.core.validation.ConfigValidationException;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* The {@link KonnectedHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
public class KonnectedHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(KonnectedHandler.class);
|
||||
private KonnectedConfiguration config;
|
||||
|
||||
private final String konnectedServletPath;
|
||||
private final KonnectedHTTPUtils http = new KonnectedHTTPUtils(30);
|
||||
private String callbackIpAddress = null;
|
||||
private String moduleIpAddress;
|
||||
private Gson gson = new GsonBuilder().create();
|
||||
private int retryCount;
|
||||
|
||||
/**
|
||||
* This is the constructor of the Konnected Handler.
|
||||
*
|
||||
* @param thing the instance of the Konnected thing
|
||||
* @param webHookServlet the instance of the callback servlet that is running for communication with the Konnected
|
||||
* Module
|
||||
* @param hostAddress the webaddress of the openHAB server instance obtained by the runtime
|
||||
* @param port the port on which the openHAB instance is running that was obtained by the runtime.
|
||||
*/
|
||||
public KonnectedHandler(Thing thing, String path, String hostAddress, String port) {
|
||||
super(thing);
|
||||
|
||||
this.konnectedServletPath = path;
|
||||
callbackIpAddress = hostAddress + ":" + port;
|
||||
logger.debug("The callback ip address is: {}", callbackIpAddress);
|
||||
retryCount = 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
// get the zone number in integer form
|
||||
Channel channel = this.getThing().getChannel(channelUID.getId());
|
||||
String channelType = channel.getChannelTypeUID().getAsString();
|
||||
String zoneNumber = (String) channel.getConfiguration().get(CHANNEL_ZONE);
|
||||
Integer zone = Integer.parseInt(zoneNumber);
|
||||
logger.debug("The channelUID is: {} and the zone is : {}", channelUID.getAsString(), zone);
|
||||
// convert the zone to the pin based on value at index of zone
|
||||
Integer pin = Arrays.asList(PIN_TO_ZONE).get(zone);
|
||||
// if the command is OnOfftype
|
||||
if (command instanceof OnOffType) {
|
||||
if (channelType.equalsIgnoreCase(CHANNEL_SWITCH)) {
|
||||
logger.debug("A command was sent to a sensor type so we are ignoring the command");
|
||||
} else {
|
||||
int sendCommand = (OnOffType.OFF.compareTo((OnOffType) command));
|
||||
logger.debug("The command being sent to pin {} for channel:{} is {}", pin, channelUID.getAsString(),
|
||||
sendCommand);
|
||||
sendActuatorCommand(Integer.toString(sendCommand), pin, channelUID);
|
||||
}
|
||||
} else if (command instanceof RefreshType) {
|
||||
// check to see if handler has been initialized before attempting to get state of pin, else wait one minute
|
||||
if (this.isInitialized()) {
|
||||
getSwitchState(pin, channelUID);
|
||||
} else {
|
||||
scheduler.schedule(() -> {
|
||||
handleCommand(channelUID, command);
|
||||
}, 1, TimeUnit.MINUTES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a {@link WebHookEvent} that has been received by the Servlet from a Konnected module with respect to a
|
||||
* sensor event or status update request
|
||||
*
|
||||
* @param event the {@link KonnectedModuleGson} event that contains the state and pin information to be processed
|
||||
*/
|
||||
public void handleWebHookEvent(KonnectedModuleGson event) {
|
||||
// if we receive a command upteate the thing status to being online
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
// get the zone number based off of the index location of the pin value
|
||||
String sentZone = Integer.toString(Arrays.asList(PIN_TO_ZONE).indexOf(event.getPin()));
|
||||
// check that the zone number is in one of the channelUID definitions
|
||||
logger.debug("Looping Through all channels on thing: {} to find a match for {}", thing.getUID().getAsString(),
|
||||
event.getAuthToken());
|
||||
getThing().getChannels().forEach(channel -> {
|
||||
ChannelUID channelId = channel.getUID();
|
||||
String zoneNumber = (String) channel.getConfiguration().get(CHANNEL_ZONE);
|
||||
// if the string zone that was sent equals the last digit of the channelId found process it as the
|
||||
// channelId else do nothing
|
||||
if (sentZone.equalsIgnoreCase(zoneNumber)) {
|
||||
logger.debug(
|
||||
"The configrued zone of channelID: {} was a match for the zone sent by the alarm panel: {} on thing: {}",
|
||||
channelId, sentZone, this.getThing().getUID().getId());
|
||||
String channelType = channel.getChannelTypeUID().getAsString();
|
||||
logger.debug("The channeltypeID is: {}", channelType);
|
||||
// check if the itemType has been defined for the zone received
|
||||
// check the itemType of the Zone, if Contact, send the State if Temp send Temp, etc.
|
||||
if (channelType.equalsIgnoreCase(CHANNEL_SWITCH) || channelType.equalsIgnoreCase(CHANNEL_ACTUATOR)) {
|
||||
OnOffType onOffType = event.getState().equalsIgnoreCase(getOnState(channel)) ? OnOffType.ON
|
||||
: OnOffType.OFF;
|
||||
updateState(channelId, onOffType);
|
||||
} else if (channelType.equalsIgnoreCase(CHANNEL_HUMIDITY)) {
|
||||
// if the state is of type number then this means it is the humidity channel of the dht22
|
||||
updateState(channelId,
|
||||
new QuantityType<>(Double.parseDouble(event.getHumi()), SmartHomeUnits.PERCENT));
|
||||
} else if (channelType.equalsIgnoreCase(CHANNEL_TEMPERATURE)) {
|
||||
Configuration configuration = channel.getConfiguration();
|
||||
if (((Boolean) configuration.get(CHANNEL_TEMPERATURE_TYPE))) {
|
||||
updateState(channelId,
|
||||
new QuantityType<>(Double.parseDouble(event.getTemp()), SIUnits.CELSIUS));
|
||||
} else {
|
||||
// need to check to make sure right dsb1820 address
|
||||
logger.debug("The address of the DSB1820 sensor received from modeule {} is: {}",
|
||||
this.thing.getUID(), event.getAddr());
|
||||
if (event.getAddr().toString()
|
||||
.equalsIgnoreCase((String) (configuration.get(CHANNEL_TEMPERATURE_DS18B20_ADDRESS)))) {
|
||||
updateState(channelId,
|
||||
new QuantityType<>(Double.parseDouble(event.getTemp()), SIUnits.CELSIUS));
|
||||
} else {
|
||||
logger.debug("The address of {} does not match {} not updating this channel",
|
||||
event.getAddr().toString(),
|
||||
(configuration.get(CHANNEL_TEMPERATURE_DS18B20_ADDRESS)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.trace(
|
||||
"The zone number sent by the alarm panel: {} was not a match the configured zone for channelId: {} for thing {}",
|
||||
sentZone, channelId, getThing().getThingTypeUID().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void checkConfiguration() throws ConfigValidationException {
|
||||
logger.debug("Checking configuration on thing {}", this.getThing().getUID().getAsString());
|
||||
Configuration testConfig = this.getConfig();
|
||||
String testRetryCount = testConfig.get(RETRY_COUNT).toString();
|
||||
String testRequestTimeout = testConfig.get(REQUEST_TIMEOUT).toString();
|
||||
logger.debug("The RequestTimeout Parameter is Configured as: {}", testRequestTimeout);
|
||||
logger.debug("The Retry Count Parameter is Configured as: {}", testRetryCount);
|
||||
try {
|
||||
this.retryCount = Integer.parseInt(testRetryCount);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.debug(
|
||||
"Please check your configuration of the Retry Count as it is not an Integer. It is configured as: {}, will contintue to configure the binding with the default of 2",
|
||||
testRetryCount);
|
||||
this.retryCount = 2;
|
||||
}
|
||||
try {
|
||||
this.http.setRequestTimeout(Integer.parseInt(testRequestTimeout));
|
||||
} catch (NumberFormatException e) {
|
||||
logger.debug(
|
||||
"Please check your configuration of the Request Timeout as it is not an Integer. It is configured as: {}, will contintue to configure the binding with the default of 30",
|
||||
testRequestTimeout);
|
||||
}
|
||||
|
||||
if ((callbackIpAddress == null)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Unable to obtain hostaddress from OSGI service, please configure hostaddress");
|
||||
}
|
||||
|
||||
else {
|
||||
this.config = getConfigAs(KonnectedConfiguration.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleConfigurationUpdate(Map<String, Object> configurationParameters)
|
||||
throws ConfigValidationException {
|
||||
this.validateConfigurationParameters(configurationParameters);
|
||||
for (Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
|
||||
Object value = configurationParameter.getValue();
|
||||
logger.debug("Controller Configuration update {} to {}", configurationParameter.getKey(), value);
|
||||
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
// this is a nonstandard implementation to to address the configuration of the konnected alarm panel (as
|
||||
// opposed to the handler) until
|
||||
// https://github.com/eclipse/smarthome/issues/3484 has been implemented in the framework
|
||||
String[] cfg = configurationParameter.getKey().split("_");
|
||||
if ("controller".equals(cfg[0])) {
|
||||
if (cfg[1].equals("softreset") && value instanceof Boolean && (Boolean) value) {
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
http.doGet(moduleIpAddress + "/settings?restart=true", null, retryCount);
|
||||
} catch (KonnectedHttpRetryExceeded e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
});
|
||||
value = false;
|
||||
} else if (cfg[1].equals("removewifi") && value instanceof Boolean && (Boolean) value) {
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
http.doGet(moduleIpAddress + "/settings?restore=true", null, retryCount);
|
||||
} catch (KonnectedHttpRetryExceeded e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
});
|
||||
value = false;
|
||||
} else if (cfg[1].equals("sendConfig") && value instanceof Boolean && (Boolean) value) {
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
String response = updateKonnectedModule();
|
||||
logger.trace("The response from the konnected module with thingID {} was {}",
|
||||
getThing().getUID().toString(), response);
|
||||
if (response == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unable to communicate with Konnected Module.");
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} catch (KonnectedHttpRetryExceeded e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
});
|
||||
value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.handleConfigurationUpdate(configurationParameters);
|
||||
try
|
||||
|
||||
{
|
||||
String response = updateKonnectedModule();
|
||||
logger.trace("The response from the konnected module with thingID {} was {}",
|
||||
getThing().getUID().toString(), response);
|
||||
if (response == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unable to communicate with Konnected Module confirm settings.");
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} catch (KonnectedHttpRetryExceeded e) {
|
||||
logger.trace("The number of retries was exceeeded during the HandleConfigurationUpdate(): {}",
|
||||
e.getMessage());
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
try {
|
||||
checkConfiguration();
|
||||
} catch (ConfigValidationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
this.moduleIpAddress = this.getThing().getProperties().get(HOST).toString();
|
||||
scheduler.execute(() -> {
|
||||
try {
|
||||
String response = updateKonnectedModule();
|
||||
if (response == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unable to communicate with Konnected Module confirm settings or readd thing.");
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
} catch (KonnectedHttpRetryExceeded e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Running dispose()");
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method constructs the payload that will be sent
|
||||
* to the Konnected module via the put request
|
||||
* it adds the appropriate sensors and actuators to the {@link KonnectedModulePayload}
|
||||
* as well as the location of the callback {@link KonnectedJTTPServlet}
|
||||
* and auth_token which can be used for validation
|
||||
*
|
||||
* @return a json settings payload which can be sent to the Konnected Module based on the Thing
|
||||
*/
|
||||
private String constructSettingsPayload() {
|
||||
String hostPath = "";
|
||||
hostPath = callbackIpAddress + this.konnectedServletPath;
|
||||
String authToken = getThing().getUID().getAsString();
|
||||
logger.debug("The Auth_Token is: {}", authToken);
|
||||
KonnectedModulePayload payload = new KonnectedModulePayload(authToken, "http://" + hostPath);
|
||||
payload.setBlink(config.blink);
|
||||
payload.setDiscovery(config.discovery);
|
||||
this.getThing().getChannels().forEach(channel -> {
|
||||
// ChannelUID channelId = channel.getUID();
|
||||
if (isLinked(channel.getUID())) {
|
||||
// adds linked channels to list based on last value of Channel ID
|
||||
// which is set to a number
|
||||
// get the zone number in integer form
|
||||
String zoneNumber = (String) channel.getConfiguration().get(CHANNEL_ZONE);
|
||||
Integer zone = Integer.parseInt(zoneNumber);
|
||||
// convert the zone to the pin based on value at index of zone
|
||||
Integer pin = Arrays.asList(PIN_TO_ZONE).get(zone);
|
||||
// if the pin is an actuator add to actuator string
|
||||
// else add to sensor string
|
||||
// This is determined based off of the accepted item type, contact types are sensors
|
||||
// switch types are actuators
|
||||
String channelType = channel.getChannelTypeUID().getAsString();
|
||||
logger.debug("The channeltypeID is: {}", channelType);
|
||||
KonnectedModuleGson module = new KonnectedModuleGson();
|
||||
module.setPin(pin);
|
||||
if (channelType.equalsIgnoreCase(CHANNEL_SWITCH)) {
|
||||
payload.addSensor(module);
|
||||
logger.trace("Channel {} will be configured on the konnected alarm panel as a switch",
|
||||
channel.toString());
|
||||
} else if (channelType.equalsIgnoreCase(CHANNEL_ACTUATOR)) {
|
||||
payload.addActuators(module);
|
||||
logger.trace("Channel {} will be configured on the konnected alarm panel as an actuator",
|
||||
channel.toString());
|
||||
} else if (channelType.equalsIgnoreCase(CHANNEL_HUMIDITY)) {
|
||||
// the humidity channels do not need to be added because the supported sensor (dht22) is added under
|
||||
// the temp sensor
|
||||
logger.trace("Channel {} is a humidity channel.", channel.toString());
|
||||
} else if (channelType.equalsIgnoreCase(CHANNEL_TEMPERATURE)) {
|
||||
logger.trace("Channel {} will be configured on the konnected alarm panel as a temperature sensor",
|
||||
channel.toString());
|
||||
Configuration configuration = channel.getConfiguration();
|
||||
if (configuration.get(CHANNEL_TEMPERATRUE_POLL) == null) {
|
||||
module.setPollInterval(3);
|
||||
} else {
|
||||
module.setPollInterval(((BigDecimal) configuration.get(CHANNEL_TEMPERATRUE_POLL)).intValue());
|
||||
}
|
||||
logger.trace("The Temperature Sensor Type is: {} ",
|
||||
configuration.get(CHANNEL_TEMPERATURE_TYPE).toString());
|
||||
if ((boolean) configuration.get(CHANNEL_TEMPERATURE_TYPE)) {
|
||||
// add it as a dht22 module
|
||||
payload.addDht22(module);
|
||||
logger.trace(
|
||||
"Channel {} will be configured on the konnected alarm panel as a DHT22 temperature sensor",
|
||||
channel.toString());
|
||||
} else {
|
||||
// add to payload as a DS18B20 module if the parameter is false
|
||||
payload.addDs18b20(module);
|
||||
logger.trace(
|
||||
"Channel {} will be configured on the konnected alarm panel as a DS18B20 temperature sensor",
|
||||
channel.toString());
|
||||
}
|
||||
} else {
|
||||
logger.debug("Channel {} is of type {} which is not supported by the konnected binding",
|
||||
channel.toString(), channelType);
|
||||
}
|
||||
} else {
|
||||
logger.debug("The Channel {} is not linked to an item", channel.getUID());
|
||||
}
|
||||
});
|
||||
// Create Json to Send to Konnected Module
|
||||
|
||||
String payloadString = gson.toJson(payload);
|
||||
logger.debug("The payload is: {}", payloadString);
|
||||
return payloadString;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepares and sends the {@link KonnectedModulePayload} via the {@link KonnectedHttpUtils}
|
||||
*
|
||||
* @return response obtained from sending the settings payload to Konnected module defined by the thing
|
||||
*
|
||||
* @throws KonnectedHttpRetryExceeded if unable to communicate with the Konnected module defined by the Thing
|
||||
*/
|
||||
private String updateKonnectedModule() throws KonnectedHttpRetryExceeded {
|
||||
String payload = constructSettingsPayload();
|
||||
String response = http.doPut(moduleIpAddress + "/settings", payload, retryCount);
|
||||
logger.debug("The response of the put request was: {}", response);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to the module via {@link KonnectedHTTPUtils}
|
||||
*
|
||||
* @param scommand the string command, either 0 or 1 to send to the actutor pin on the Konnected module
|
||||
* @param pin the pin to send the command to on the Konnected Module
|
||||
*/
|
||||
private void sendActuatorCommand(String scommand, Integer pin, ChannelUID channelId) {
|
||||
try {
|
||||
Channel channel = getThing().getChannel(channelId.getId());
|
||||
if (!(channel == null)) {
|
||||
logger.debug("getasstring: {} getID: {} getGroupId: {} toString:{}", channelId.getAsString(),
|
||||
channelId.getId(), channelId.getGroupId(), channelId.toString());
|
||||
Configuration configuration = channel.getConfiguration();
|
||||
KonnectedModuleGson payload = new KonnectedModuleGson();
|
||||
payload.setState(scommand);
|
||||
payload.setPin(pin);
|
||||
// check to see if this is an On Command type, if so add the momentary, pause, times to the payload if
|
||||
// they exist on the configuration.
|
||||
if (scommand.equals(getOnState(channel))) {
|
||||
if (configuration.get(CHANNEL_ACTUATOR_TIMES) == null) {
|
||||
logger.debug(
|
||||
"The times configuration was not set for channelID: {}, not adding it to the payload.",
|
||||
channelId.toString());
|
||||
} else {
|
||||
payload.setTimes(configuration.get(CHANNEL_ACTUATOR_TIMES).toString());
|
||||
logger.debug("The times configuration was set to: {} for channelID: {}.",
|
||||
configuration.get(CHANNEL_ACTUATOR_TIMES).toString(), channelId.toString());
|
||||
}
|
||||
if (configuration.get(CHANNEL_ACTUATOR_MOMENTARY) == null) {
|
||||
logger.debug(
|
||||
"The momentary configuration was not set for channelID: {}, not adding it to the payload.",
|
||||
channelId.toString());
|
||||
} else {
|
||||
payload.setMomentary(configuration.get(CHANNEL_ACTUATOR_MOMENTARY).toString());
|
||||
logger.debug("The momentary configuration set to: {} channelID: {}.",
|
||||
configuration.get(CHANNEL_ACTUATOR_MOMENTARY).toString(), channelId.toString());
|
||||
}
|
||||
if (configuration.get(CHANNEL_ACTUATOR_PAUSE) == null) {
|
||||
logger.debug(
|
||||
"The pause configuration was not set for channelID: {}, not adding it to the payload.",
|
||||
channelId.toString());
|
||||
} else {
|
||||
payload.setPause(configuration.get(CHANNEL_ACTUATOR_PAUSE).toString());
|
||||
logger.debug("The pause configuration was set to: {} for channelID: {}.",
|
||||
configuration.get(CHANNEL_ACTUATOR_PAUSE).toString(), channelId.toString());
|
||||
}
|
||||
}
|
||||
String payloadString = gson.toJson(payload);
|
||||
logger.debug("The command payload is: {}", payloadString);
|
||||
http.doPut(moduleIpAddress + "/device", payloadString, retryCount);
|
||||
} else {
|
||||
logger.debug("The channel {} returned null for channelId.getID(): {}", channelId.toString(),
|
||||
channelId.getId());
|
||||
}
|
||||
} catch (KonnectedHttpRetryExceeded e) {
|
||||
logger.debug("Attempting to set the state of the actuator on thing {} failed: {}",
|
||||
this.thing.getUID().getId(), e.getMessage());
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unable to communicate with Konnected Alarm Panel confirm settings, and that module is online.");
|
||||
}
|
||||
}
|
||||
|
||||
private void getSwitchState(Integer pin, ChannelUID channelId) {
|
||||
Channel channel = getThing().getChannel(channelId.getId());
|
||||
if (!(channel == null)) {
|
||||
logger.debug("getasstring: {} getID: {} getGroupId: {} toString:{}", channelId.getAsString(),
|
||||
channelId.getId(), channelId.getGroupId(), channelId.toString());
|
||||
KonnectedModuleGson payload = new KonnectedModuleGson();
|
||||
payload.setPin(pin);
|
||||
String payloadString = gson.toJson(payload);
|
||||
logger.debug("The command payload is: {}", payloadString);
|
||||
try {
|
||||
sendSetSwitchState(payloadString);
|
||||
} catch (KonnectedHttpRetryExceeded e) {
|
||||
// try to get the state of the device one more time 30 seconds later. This way it can be confirmed if
|
||||
// the device was simply in a reboot loop when device state was attempted the first time
|
||||
scheduler.schedule(() -> {
|
||||
try {
|
||||
sendSetSwitchState(payloadString);
|
||||
} catch (KonnectedHttpRetryExceeded ex) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Unable to communicate with Konnected Alarm Panel confirm settings, and that module is online.");
|
||||
logger.debug("Attempting to get the state of the zone on thing {} failed for channel: {} : {}",
|
||||
this.thing.getUID().getId(), channelId.getAsString(), ex.getMessage());
|
||||
}
|
||||
}, 2, TimeUnit.MINUTES);
|
||||
}
|
||||
} else {
|
||||
logger.debug("The channel {} returned null for channelId.getID(): {}", channelId.toString(),
|
||||
channelId.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSetSwitchState(String payloadString) throws KonnectedHttpRetryExceeded {
|
||||
String response = http.doGet(moduleIpAddress + "/device", payloadString, retryCount);
|
||||
KonnectedModuleGson event = gson.fromJson(response, KonnectedModuleGson.class);
|
||||
this.handleWebHookEvent(event);
|
||||
}
|
||||
|
||||
private String getOnState(Channel channel) {
|
||||
String config = (String) channel.getConfiguration().get(CHANNEL_ONVALUE);
|
||||
if (config == null) {
|
||||
return "1";
|
||||
} else {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Scanner;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.openhab.binding.konnected.internal.gson.KonnectedModuleGson;
|
||||
import org.openhab.binding.konnected.internal.handler.KonnectedHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* Main OSGi service and HTTP servlet for Konnected Webhook.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
public class KonnectedHTTPServlet extends HttpServlet {
|
||||
private final Logger logger = LoggerFactory.getLogger(KonnectedHTTPServlet.class);
|
||||
|
||||
private static final long serialVersionUID = 1288539782077957954L;
|
||||
private static final String APPLICATION_JSON = "application/json";
|
||||
private static final String CHARSET = "utf-8";
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
private HashMap<String, KonnectedHandler> konnectedThingHandlers = new HashMap<>();
|
||||
|
||||
public KonnectedHTTPServlet() {
|
||||
}
|
||||
|
||||
public void add(KonnectedHandler thingHandler) {
|
||||
logger.trace("Adding KonnectedHandler[{}] to KonnectedHTTPServlet.", thingHandler.getThing().getUID());
|
||||
konnectedThingHandlers.put(thingHandler.getThing().getUID().getAsString(), thingHandler);
|
||||
}
|
||||
|
||||
public void remove(KonnectedHandler thingHandler) {
|
||||
logger.trace("Removing KonnectedHandler [{}] from KonnectedHTTPServlet. ", thingHandler.getThing().getUID());
|
||||
|
||||
konnectedThingHandlers.remove(thingHandler.getThing().getUID().getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void service(HttpServletRequest req, HttpServletResponse resp) {
|
||||
try {
|
||||
String data = inputStreamToString(req);
|
||||
|
||||
logger.debug("The raw json data is: {}", data);
|
||||
if (data != null && !konnectedThingHandlers.isEmpty()) {
|
||||
KonnectedModuleGson event = gson.fromJson(data, KonnectedModuleGson.class);
|
||||
String authorizationHeader = req.getHeader("Authorization");
|
||||
String thingHandlerKey = authorizationHeader.substring("Bearer".length()).trim();
|
||||
logger.debug("The path of the response was: {}", req.getContextPath());
|
||||
logger.debug("The json received was: {}", event.toString());
|
||||
logger.debug("The thing handler to send the command to is the handler for thing: {}", thingHandlerKey);
|
||||
try {
|
||||
KonnectedHandler thingHandler = konnectedThingHandlers.get(thingHandlerKey);
|
||||
thingHandler.handleWebHookEvent(event);
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("There was not a handler registered on the servlet to handler commands for thing: {}",
|
||||
thingHandlerKey);
|
||||
}
|
||||
}
|
||||
|
||||
setHeaders(resp);
|
||||
resp.getWriter().write("");
|
||||
} catch (IOException | JsonSyntaxException e) {
|
||||
logger.debug("The response received from the module was not valid. {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String inputStreamToString(HttpServletRequest req) throws IOException {
|
||||
Scanner scanner = new Scanner(req.getInputStream()).useDelimiter("\\A");
|
||||
return scanner.hasNext() ? scanner.next() : "";
|
||||
}
|
||||
|
||||
private void setHeaders(HttpServletResponse response) {
|
||||
response.setCharacterEncoding(CHARSET);
|
||||
response.setContentType(APPLICATION_JSON);
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Access-Control-Allow-Methods", "PUT");
|
||||
response.setHeader("Access-Control-Max-Age", "3600");
|
||||
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.konnected.internal.servlet;
|
||||
|
||||
/**
|
||||
* Custom exception class to be thrown by servlet when unable to start.
|
||||
*
|
||||
* @author Zachary Christiansen - Initial contribution
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class KonnectedWebHookFail extends Exception {
|
||||
public KonnectedWebHookFail(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="konnected" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
<name>Konnected Binding</name>
|
||||
<description>This is the binding for Konnected.</description>
|
||||
<author>Zachary Christiansen</author>
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
|
||||
https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
<config-description uri="thing-type:konnected:module">
|
||||
<parameter-group name="actions">
|
||||
<label>Actions</label>
|
||||
<description/>
|
||||
</parameter-group>
|
||||
<parameter name="blink" type="boolean">
|
||||
<label>Blink</label>
|
||||
<description> When set to false the Led on the device won't blink during transmission.</description>
|
||||
<default>true</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="discovery" type="boolean">
|
||||
<label>Discovery</label>
|
||||
<description>If set to false the device will not respond to discovery requests via UPnP. Make sure you have
|
||||
statically assigned an IP address to the module before turning this setting off. See
|
||||
https://help.konnected.io/support/solutions/articles/32000023968-disabling-device-discovery</description>
|
||||
<default>true</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="retry_count" type="integer">
|
||||
<label>Retry Count</label>
|
||||
<description>The number of times the binding attempts to send http requests to the Konnected Alarm Panel. Increase
|
||||
this setting if you are experiencing situations where the module is reporting as offline but you can access the
|
||||
website of the Alarm Panel to confirm that the Alarm Panel is Konnected to the Network. This will allow the binding
|
||||
to attempt more retries before it considers the connection a failure and marks the thing as offline.</description>
|
||||
<default>2</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="request_timeout" type="integer">
|
||||
<label>Request Timeout</label>
|
||||
<description>The timeout period in seconds for HTTP requests to the Konnected Alarm Panel. The default is 30.
|
||||
Adjusting this setting can help in networks situations with high latency where the binding is erroneously reporting
|
||||
the thing as offline.</description>
|
||||
<default>30</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="controller_softreset" type="boolean" groupName="actions">
|
||||
<label>Soft Reset Module</label>
|
||||
<description>Send A Restart Command to the Module.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
<parameter name="controller_removewifi" type="boolean" groupName="actions">
|
||||
<label>Factory Reset</label>
|
||||
<description>Resets the module to Factory Conditions.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
<parameter name="controller_sendConfig" type="boolean" groupName="actions">
|
||||
<label>Update Settings</label>
|
||||
<description>Manually sends the settings to the module. The binding will send settings on every restart and if there
|
||||
are any configuration changes but this can be used to manually update the settings as needed.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="konnected"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
<!-- This is the Konnected Thing-Type -->
|
||||
<thing-type id="module" extensible="switch,actuator,temperature,humidity">
|
||||
<label>The Konnected Alarm Panel</label>
|
||||
<description>The Konnected Module</description>
|
||||
<channels>
|
||||
<channel id="Zone_6" typeId="switch">
|
||||
<label>Zone 6</label>
|
||||
<description>Zone 6 Sensor</description>
|
||||
</channel>
|
||||
<channel id="Out" typeId="actuator">
|
||||
<label>The out Pin</label>
|
||||
</channel>
|
||||
</channels>
|
||||
<config-description-ref uri="thing-type:konnected:module"/>
|
||||
</thing-type>
|
||||
<!-- Zone Channel Type -->
|
||||
<channel-type id="switch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch</label>
|
||||
<description>This zone is a read only switch type zone</description>
|
||||
<state readOnly="true"/>
|
||||
<config-description>
|
||||
<parameter name="zone" type="text" required="true">
|
||||
<label>Zone Number</label>
|
||||
<description>The Zone Number of the channel.</description>
|
||||
<default>6</default>
|
||||
<options>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">Out</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="onvalue" type="text">
|
||||
<label>On Value</label>
|
||||
<description>The value that will be treated by the binding as the on value. For sensors that activate with a high
|
||||
value leave at the default of 1 and sensors that activate with a low value set to 0.</description>
|
||||
<default>1</default>
|
||||
<options>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
</options>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>This zone measures temperature</description>
|
||||
<state readOnly="true"/>
|
||||
<config-description>
|
||||
<parameter name="zone" type="text">
|
||||
<label>Zone Number</label>
|
||||
<description>The Zone Number of the channel.</description>
|
||||
<options>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">Out</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="tempsensorType" type="boolean">
|
||||
<label>DHT22</label>
|
||||
<description>Is the sensor a dht22 or a ds18b20? Set to true for dht22 sensor</description>
|
||||
</parameter>
|
||||
<parameter name="pollinterval" type="integer">
|
||||
<label>Poll Interval</label>
|
||||
<description>The interval in minutes to poll the sensor.</description>
|
||||
</parameter>
|
||||
<parameter name="ds18b20_address" type="text">
|
||||
<label>DS18b20 Address</label>
|
||||
<description>This is the unique address of the sensor on the one wire bus.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>This zone measures humidity</description>
|
||||
<state readOnly="true"/>
|
||||
<config-description>
|
||||
<parameter name="zone" type="text" required="true">
|
||||
<label>Zone Number</label>
|
||||
<description>The Zone Number of the channel.</description>
|
||||
<options>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">Out</option>
|
||||
</options>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="actuator">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Actuator</label>
|
||||
<description>This zone is an actuator</description>
|
||||
<config-description>
|
||||
<parameter name="zone" type="text" required="true">
|
||||
<label>Zone Number</label>
|
||||
<description>The Zone Number of the channel.</description>
|
||||
<default>7</default>
|
||||
<options>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">Out</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="onvalue" type="text">
|
||||
<label>On Value</label>
|
||||
<description>The value that will be treated by the binding as an on command. For actuators that activate with a high
|
||||
command set to 1 and actuators that activate with a low value set to 0.</description>
|
||||
<default>1</default>
|
||||
<options>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="momentary" type="integer">
|
||||
<label>Momentary</label>
|
||||
<description>The duration of the pulse in millisecods</description>
|
||||
</parameter>
|
||||
<parameter name="pause" type="integer">
|
||||
<label>Pause</label>
|
||||
<description>The time between pulses in millisecods</description>
|
||||
</parameter>
|
||||
<parameter name="times" type="integer">
|
||||
<label>Times</label>
|
||||
<description>is the number of times to repeat or `-1` for an infinitely repeating pulse</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user