added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
49
bundles/org.openhab.binding.bsblan/.classpath
Normal file
49
bundles/org.openhab.binding.bsblan/.classpath
Normal file
@@ -0,0 +1,49 @@
|
||||
<?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="src" path="target/generated-sources/annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
<attribute name="m2e-apt" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="ignore_optional_problems" value="true"/>
|
||||
<attribute name="m2e-apt" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
bundles/org.openhab.binding.bsblan/.project
Normal file
23
bundles/org.openhab.binding.bsblan/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.bsblan</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.bsblan/NOTICE
Normal file
13
bundles/org.openhab.binding.bsblan/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/openhab2-addons
|
||||
87
bundles/org.openhab.binding.bsblan/README.md
Normal file
87
bundles/org.openhab.binding.bsblan/README.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# BSB-LAN Binding
|
||||
|
||||
This binding uses the REST API of [BSB-LPB-PPS-LAN](https://github.com/fredlcore/bsb_lan) to obtain data from the device.
|
||||
|
||||
## Supported Things
|
||||
|
||||
Currently the binding supports the following thing types:
|
||||
|
||||
| Thing Type | Description |
|
||||
|-------------|----------------------------------------------------------------|
|
||||
| bridge | Represents the BSB-LAN device. |
|
||||
| parameter | Represents a single parameter available at the BSB-LAN device. |
|
||||
|
||||
## Discovery
|
||||
|
||||
There is no discovery implemented. You have to create your Things manually and specify the hostname/IP of the BSB-LAN device in the Bridge.
|
||||
|
||||
## Binding Configuration
|
||||
|
||||
The binding has no configuration options, all configuration is done at Thing level.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### Bridge Thing Configuration
|
||||
|
||||
| Property | Default | Required | Type | Description |
|
||||
|------------------|---------|----------|---------|--------------------------------------------------------------------------------------------|
|
||||
| host | - | Yes | String | The hostname or IP address of the BSB-LAN device. |
|
||||
| port | 80 | No | Integer | The port where the BSB-LAN device is listening. |
|
||||
| passkey | - | No | String | The passkey required to access the BSB-LAN device. |
|
||||
| username | - | No | String | The username required to access the BSB-LAN device (when using HTTP Basic Authentication). |
|
||||
| password | - | No | String | The password required to access the BSB-LAN device (when using HTTP Basic Authentication). |
|
||||
| refreshInterval | 60 | No | Integer | Specifies the refresh (poll) interval in seconds. Minimum value: 5s |
|
||||
|
||||
### Parameter Thing Configuration
|
||||
|
||||
| Property | Default | Required | Type | Description |
|
||||
|-----------|---------|----------|---------|------------------------------------------------------------------------------------------|
|
||||
| id | - | Yes | Integer | Specific parameter identifier (numeric value) |
|
||||
| setId | value of `id` | No | Integer | Parameter identifier used for set requests (numeric value).<br />If not specified it falls back to the value of the `id` property. |
|
||||
| setType | `SET` | No | String | Message type used for set requests. Possible values are: `INF` or `SET`.<br />If not specified or unknown it falls back to `SET`. |
|
||||
|
||||
Note: If you would also like to use the binding to set parameter values, ensure you have flashed the BSB-LAN adapter in write mode (see your `BSB_lan_config.h`)
|
||||
|
||||
## Channels
|
||||
|
||||
### Parameter Thing Channels
|
||||
|
||||
| Channel ID | Item Type | Description |
|
||||
|--------------|-----------|------------------------------------------------------------------------------------|
|
||||
| name | String | Name of the parameter as provided by the BSB-LAN device. |
|
||||
| number-value | Number | Value of the parameter converted to a numerical value (if possible).<br />The value is published as `DecimalType(int)` for values of `datatype` `DT_ENUM` and `DecimalType(double)` otherwise. |
|
||||
| string-value | String | Value of the parameter as provided by the BSB-LAN device. |
|
||||
| switch-value | Switch | Value of the parameter.<br />`0` is interpreted as `OFF`, everything else as `ON`. |
|
||||
| unit | String | Unit as provided by the BSB-LAN device (HTML unescaping applied). |
|
||||
| description | String | Description as provided by the BSB-LAN device. |
|
||||
| datatype | Number | Datatype as provided by the BSB-LAN device. Possible values are currently<br />`0` for `DT_VALS`: plain value<br />`1` for `DT_ENUM`: value (8/16 Bit) followed by space followed by text<br />`2` for `DT_BITS`: bit value followed by bitmask followed by text<br />`3` for `DT_WDAY`: weekday<br />`4` for `DT_HHMM`: hour:minute<br />`5` for `DT_DTTM`: date and time<br />`6` for `DT_DDMM`: day and month<br />`7` for `DT_STRN`: String<br />`8` for `DT_DWHM`: PPS time (day of week, hour:minute) |
|
||||
|
||||
## Full Example
|
||||
|
||||
bsblan.things:
|
||||
|
||||
```
|
||||
Bridge bsblan:bridge:heating [host="192.168.1.100", refreshInterval=30, username="atari", password="800xl"] {
|
||||
Thing parameter p700 [id=700]
|
||||
Thing parameter p710 [id=710]
|
||||
Thing parameter p8730 [id=8730]
|
||||
}
|
||||
```
|
||||
|
||||
bsblan.items:
|
||||
|
||||
```
|
||||
Number BsbParameter700NumberValue { channel="bsblan:parameter:heating:p700:number-value" }
|
||||
Number BsbParameter710NumberValue { channel="bsblan:parameter:heating:p710:number-value" }
|
||||
String BsbParameter8730Description { channel="bsblan:parameter:heating:p8730:description" }
|
||||
```
|
||||
|
||||
bsblan.sitemap:
|
||||
|
||||
```
|
||||
sitemap bsblan label="BSB-LAN" {
|
||||
Selection item=BsbParameter700NumberValue label="Operating Mode" mappings=[0="Protection", 1="Automatic", 2="Reduced", 3="Comfort"] icon="heating"
|
||||
Setpoint item=BsbParameter710NumberValue label="Room Temperature Comfort Setpoint [%.1f °C]" icon="temperature" minValue=22.0 maxValue=25.0 step=0.5
|
||||
Text item=BsbParameter8730Description label="Heating Circuit Pump [%s]"
|
||||
}
|
||||
```
|
||||
17
bundles/org.openhab.binding.bsblan/pom.xml
Normal file
17
bundles/org.openhab.binding.bsblan/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.bsblan</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: BSB-LAN Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.bsblan-${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-bsblan" description="BSB-LAN Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.bsblan/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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.bsblan.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "bsblan";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge");
|
||||
public static final ThingTypeUID THING_TYPE_PARAMETER = new ThingTypeUID(BINDING_ID, "parameter");
|
||||
|
||||
// List of all channel ids
|
||||
public static final String PARAMETER_CHANNEL_NAME = "name";
|
||||
public static final String PARAMETER_CHANNEL_NUMBER_VALUE = "number-value";
|
||||
public static final String PARAMETER_CHANNEL_STRING_VALUE = "string-value";
|
||||
public static final String PARAMETER_CHANNEL_SWITCH_VALUE = "switch-value";
|
||||
public static final String PARAMETER_CHANNEL_UNIT = "unit";
|
||||
public static final String PARAMETER_CHANNEL_DESCRIPTION = "description";
|
||||
public static final String PARAMETER_CHANNEL_DATATYPE = "datatype";
|
||||
|
||||
public static final Set<String> WRITEABLE_CHANNELS = new HashSet<String>() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
add(PARAMETER_CHANNEL_NUMBER_VALUE);
|
||||
add(PARAMETER_CHANNEL_STRING_VALUE);
|
||||
add(PARAMETER_CHANNEL_SWITCH_VALUE);
|
||||
}
|
||||
};
|
||||
|
||||
public static final int MIN_REFRESH_INTERVAL = 5;
|
||||
public static final int DEFAULT_REFRESH_INTERVAL = 60;
|
||||
public static final int API_TIMEOUT = 10000;
|
||||
public static final int DEFAULT_API_PORT = 80;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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.bsblan.internal;
|
||||
|
||||
import static org.openhab.binding.bsblan.internal.BsbLanBindingConstants.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bsblan.internal.handler.BsbLanBridgeHandler;
|
||||
import org.openhab.binding.bsblan.internal.handler.BsbLanParameterHandler;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.bsblan")
|
||||
public class BsbLanHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<ThingTypeUID>() {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
add(THING_TYPE_PARAMETER);
|
||||
add(THING_TYPE_BRIDGE);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_PARAMETER)) {
|
||||
return new BsbLanParameterHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_BRIDGE)) {
|
||||
return new BsbLanBridgeHandler((Bridge) thing);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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.bsblan.internal.api;
|
||||
|
||||
import static org.openhab.binding.bsblan.internal.BsbLanBindingConstants.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiContentDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterQueryResponseDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetRequestDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetResponseDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetResultDTO;
|
||||
import org.openhab.binding.bsblan.internal.configuration.BsbLanBridgeConfiguration;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Utility class to call the BSB-LAN REST API.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanApiCaller {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BsbLanApiCaller.class);
|
||||
private final BsbLanBridgeConfiguration bridgeConfig;
|
||||
|
||||
public BsbLanApiCaller(BsbLanBridgeConfiguration config) {
|
||||
bridgeConfig = config;
|
||||
}
|
||||
|
||||
public @Nullable BsbLanApiParameterQueryResponseDTO queryParameter(Integer parameterId) {
|
||||
Set<Integer> parameters = new HashSet<>();
|
||||
|
||||
parameters.add(parameterId);
|
||||
return queryParameters(parameters);
|
||||
}
|
||||
|
||||
public @Nullable BsbLanApiParameterQueryResponseDTO queryParameters(Set<Integer> parameterIds) {
|
||||
// note: make the request even if parameterIds is empty as
|
||||
// thing OFFLINE/ONLINE detection relies on a response
|
||||
|
||||
String apiPath = String.format("/JQ=%s", StringUtils.join(parameterIds, ","));
|
||||
return makeRestCall(BsbLanApiParameterQueryResponseDTO.class, "GET", apiPath, null);
|
||||
}
|
||||
|
||||
public boolean setParameter(Integer parameterId, String value, BsbLanApiParameterSetRequestDTO.Type type) {
|
||||
// prepare request content
|
||||
BsbLanApiParameterSetRequestDTO request = new BsbLanApiParameterSetRequestDTO();
|
||||
request.parameter = parameterId.toString();
|
||||
request.value = value;
|
||||
request.type = type;
|
||||
|
||||
// make REST call and process response
|
||||
BsbLanApiParameterSetResponseDTO setResponse = makeRestCall(BsbLanApiParameterSetResponseDTO.class, "POST",
|
||||
"/JS", request);
|
||||
if (setResponse == null) {
|
||||
logger.debug("Failed to set parameter {} to '{}': no response received", parameterId, value);
|
||||
return false;
|
||||
}
|
||||
|
||||
BsbLanApiParameterSetResultDTO result = setResponse.getOrDefault(parameterId, null);
|
||||
if (result == null) {
|
||||
logger.debug("Failed to set parameter {} to '{}'': result is null", parameterId, value);
|
||||
return false;
|
||||
}
|
||||
if (result.status == null) {
|
||||
logger.debug("Failed to set parameter {} to '{}': status is null", parameterId, value);
|
||||
return false;
|
||||
}
|
||||
if (result.status != BsbLanApiParameterSetResultDTO.Status.SUCCESS) {
|
||||
logger.debug("Failed to set parameter {} to '{}': status = {}", parameterId, value, result.status);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String createApiBaseUrl() {
|
||||
final String host = StringUtils.trimToEmpty(bridgeConfig.host);
|
||||
final String username = StringUtils.trimToEmpty(bridgeConfig.username);
|
||||
final String password = StringUtils.trimToEmpty(bridgeConfig.password);
|
||||
final String passkey = StringUtils.trimToEmpty(bridgeConfig.passkey);
|
||||
|
||||
StringBuilder url = new StringBuilder();
|
||||
url.append("http://");
|
||||
if (StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
|
||||
url.append(username).append(":").append(password).append("@");
|
||||
}
|
||||
url.append(host);
|
||||
if (bridgeConfig.port != 80) {
|
||||
url.append(":").append(bridgeConfig.port);
|
||||
}
|
||||
if (StringUtils.isNotBlank(passkey)) {
|
||||
url.append("/").append(passkey);
|
||||
}
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param responseType response class type
|
||||
* @param httpMethod to execute
|
||||
* @param apiPath to request
|
||||
* @param content to add to request
|
||||
* @return the object representation of the json response
|
||||
*/
|
||||
private <T> @Nullable T makeRestCall(Class<T> responseType, String httpMethod, String apiPath,
|
||||
@Nullable BsbLanApiContentDTO request) {
|
||||
try {
|
||||
String url = createApiBaseUrl() + apiPath;
|
||||
logger.trace("api request url = '{}'", url);
|
||||
|
||||
InputStream contentStream = null;
|
||||
String contentType = null;
|
||||
if (request != null) {
|
||||
String content = BsbLanApiContentConverter.toJson(request);
|
||||
logger.trace("api request content: '{}'", content);
|
||||
if (StringUtils.isNotBlank(content)) {
|
||||
contentStream = new ByteArrayInputStream(content.getBytes(Charset.forName("UTF-8")));
|
||||
contentType = "application/json";
|
||||
}
|
||||
}
|
||||
|
||||
String response = HttpUtil.executeUrl(httpMethod, url, contentStream, contentType, API_TIMEOUT);
|
||||
if (response == null) {
|
||||
logger.debug("no response returned");
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.trace("api response content: '{}'", response);
|
||||
return BsbLanApiContentConverter.fromJson(response, responseType);
|
||||
} catch (IOException | IllegalStateException e) {
|
||||
logger.debug("Error executing bsb-lan api request: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiContentDTO;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* Utility class to create JSON content.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanApiContentConverter {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BsbLanApiContentConverter.class);
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
public static String toJson(BsbLanApiContentDTO request) {
|
||||
return GSON.toJson(request);
|
||||
}
|
||||
|
||||
public static <T> @Nullable T fromJson(String content, Class<T> resultType) {
|
||||
try {
|
||||
T result = GSON.fromJson(content, resultType);
|
||||
if (result == null) {
|
||||
LOGGER.debug("result null after json parsing (response = {})", content);
|
||||
}
|
||||
return result;
|
||||
} catch (JsonSyntaxException e) {
|
||||
LOGGER.debug("Parsing JSON API response failed: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api.dto;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanApiContentDTO} reflects a request sent to the BSB-LAN device.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
public interface BsbLanApiContentDTO {
|
||||
// empty for now
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanApiParameterDTO} is responsible for storing parameter info.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
public class BsbLanApiParameterDTO {
|
||||
|
||||
public enum DataType {
|
||||
@SerializedName("0")
|
||||
DT_VALS(0), // plain value
|
||||
@SerializedName("1")
|
||||
DT_ENUM(1), // value (8/16 Bit) followed by space followed by text
|
||||
@SerializedName("2")
|
||||
DT_BITS(2), // bit value followed by bitmask followed by text
|
||||
@SerializedName("3")
|
||||
DT_WDAY(3), // weekday
|
||||
@SerializedName("4")
|
||||
DT_HHMM(4), // hour:minute
|
||||
@SerializedName("5")
|
||||
DT_DTTM(5), // date and time
|
||||
@SerializedName("6")
|
||||
DT_DDMM(6), // day and month
|
||||
@SerializedName("7")
|
||||
DT_STRN(7), // string
|
||||
@SerializedName("8")
|
||||
DT_DWHM(8); // PPS time (day of week, hour:minute)
|
||||
|
||||
private final int value;
|
||||
|
||||
DataType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@SerializedName("name")
|
||||
public String name;
|
||||
|
||||
@SerializedName("value")
|
||||
public String value;
|
||||
|
||||
@SerializedName("unit")
|
||||
public String unit;
|
||||
|
||||
@SerializedName("desc")
|
||||
public String description;
|
||||
|
||||
@SerializedName("dataType")
|
||||
public DataType dataType;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api.dto;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanApiParameterQueryResponseDTO} reflects the response received
|
||||
* when querying parameters.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BsbLanApiParameterQueryResponseDTO extends HashMap<Integer, BsbLanApiParameterDTO>
|
||||
implements BsbLanApiContentDTO {
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanApiParameterSetRequestDTO} reflects the request sent
|
||||
* when setting a parameter.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
public class BsbLanApiParameterSetRequestDTO implements BsbLanApiContentDTO {
|
||||
|
||||
public enum Type {
|
||||
@SerializedName("0")
|
||||
INF("INF"),
|
||||
@SerializedName("1")
|
||||
SET("SET");
|
||||
|
||||
private final String value;
|
||||
|
||||
Type(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Type getTypeWithFallback(String value) {
|
||||
if (value != null) {
|
||||
for (Type t : Type.values()) {
|
||||
if (t.value.toLowerCase().equals(value.toLowerCase())) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// fallback to SET
|
||||
return Type.SET;
|
||||
}
|
||||
}
|
||||
|
||||
// Although specifying the parameter as int (which would be nicer) also seems to work,
|
||||
// we use a String here as this is the way it is noted in the documentation.
|
||||
@SerializedName("Parameter")
|
||||
public String parameter;
|
||||
|
||||
@SerializedName("Value")
|
||||
public String value;
|
||||
|
||||
@SerializedName("Type")
|
||||
public Type type;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api.dto;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanApiParameterSetResponseDTO} reflects the response received
|
||||
* when setting a parameter.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BsbLanApiParameterSetResponseDTO extends HashMap<Integer, BsbLanApiParameterSetResultDTO>
|
||||
implements BsbLanApiContentDTO {
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api.dto;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanApiParameterSetResponseDTO} reflects the response received
|
||||
* when setting a parameter.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
public class BsbLanApiParameterSetResultDTO {
|
||||
|
||||
public enum Status {
|
||||
@SerializedName("0")
|
||||
ERROR(0),
|
||||
@SerializedName("1")
|
||||
SUCCESS(1),
|
||||
@SerializedName("2")
|
||||
READ_ONLY(2);
|
||||
|
||||
private final int value;
|
||||
|
||||
Status(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@SerializedName("status")
|
||||
public Status status;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.bsblan.internal.configuration;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanBridgeConfiguration} is the class used to match the
|
||||
* bridge configuration.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
public class BsbLanBridgeConfiguration {
|
||||
/**
|
||||
* Hostname or IP address of the device
|
||||
*/
|
||||
public String host;
|
||||
|
||||
/**
|
||||
* HTTP port where device is listening
|
||||
*/
|
||||
public Integer port;
|
||||
|
||||
/**
|
||||
* For "security" feature of BSB-LAN devices
|
||||
*/
|
||||
public String passkey;
|
||||
|
||||
/**
|
||||
* HTTP Basic Authentication User
|
||||
*/
|
||||
public String username;
|
||||
|
||||
/**
|
||||
* HTTP Basic Authentication Password
|
||||
*/
|
||||
public String password;
|
||||
|
||||
/**
|
||||
* Value refresh interval
|
||||
*/
|
||||
public Integer refreshInterval;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.bsblan.internal.configuration;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanParameterConfiguration} is the class used to match the
|
||||
* thing configuration.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
public class BsbLanParameterConfiguration {
|
||||
/**
|
||||
* Parameter Id (ProgNr) to query
|
||||
*/
|
||||
public Integer id;
|
||||
|
||||
/**
|
||||
* Parameter Id (ProgNr) used for change requests.
|
||||
*/
|
||||
public Integer setId;
|
||||
|
||||
/**
|
||||
* Command type used for change requests (INF or SET)
|
||||
*/
|
||||
public String setType;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* 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.bsblan.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bsblan.internal.api.BsbLanApiCaller;
|
||||
import org.openhab.binding.bsblan.internal.configuration.BsbLanBridgeConfiguration;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Basic Handler class for all BSB-LAN services.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class BsbLanBaseThingHandler extends BaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BsbLanBaseThingHandler.class);
|
||||
private @Nullable BsbLanBridgeHandler bridgeHandler;
|
||||
|
||||
public BsbLanBaseThingHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
updateChannel(channelUID.getId());
|
||||
} else {
|
||||
setChannel(channelUID.getId(), command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
BsbLanBridgeHandler bridgeHandler = getBridgeHandler();
|
||||
if (bridgeHandler == null) {
|
||||
logger.debug("Initializing '{}': thing is only supported within a bridge", getDescription());
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
return;
|
||||
}
|
||||
logger.trace("Initializing '{}' thing", getDescription());
|
||||
bridgeHandler.registerThing(this);
|
||||
}
|
||||
|
||||
protected synchronized @Nullable BsbLanBridgeHandler getBridgeHandler() {
|
||||
if (this.bridgeHandler == null) {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
return null;
|
||||
}
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof BsbLanBridgeHandler) {
|
||||
this.bridgeHandler = (BsbLanBridgeHandler) handler;
|
||||
}
|
||||
}
|
||||
return this.bridgeHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all channels
|
||||
*/
|
||||
protected void updateChannels() {
|
||||
for (Channel channel : getThing().getChannels()) {
|
||||
updateChannel(channel.getUID().getId());
|
||||
}
|
||||
}
|
||||
|
||||
protected @Nullable BsbLanApiCaller getApiCaller() {
|
||||
// use a local variable to avoid the build warning "Potential null pointer access"
|
||||
BsbLanBridgeHandler localBridgeHandler = bridgeHandler;
|
||||
if (localBridgeHandler == null) {
|
||||
return null;
|
||||
}
|
||||
return new BsbLanApiCaller(localBridgeHandler.getBridgeConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last data
|
||||
*
|
||||
* @param channelId the id identifying the channel to be updated
|
||||
*/
|
||||
protected abstract void updateChannel(String channelId);
|
||||
|
||||
/**
|
||||
* Set new value for channel
|
||||
*
|
||||
* @param channelId the id identifying the channel
|
||||
*/
|
||||
protected abstract void setChannel(String channelId, Command command);
|
||||
|
||||
/**
|
||||
* return an internal description for logging
|
||||
*
|
||||
* @return the description of the thing
|
||||
*/
|
||||
protected abstract String getDescription();
|
||||
|
||||
/**
|
||||
* do whatever a thing must do to update the values
|
||||
* this function is called from the bridge in a given interval
|
||||
*
|
||||
* @param bridgeConfiguration the connected bridge configuration
|
||||
*/
|
||||
public abstract void refresh(BsbLanBridgeConfiguration bridgeConfiguration);
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/**
|
||||
* 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.bsblan.internal.handler;
|
||||
|
||||
import static org.openhab.binding.bsblan.internal.BsbLanBindingConstants.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.*;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bsblan.internal.api.BsbLanApiCaller;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterQueryResponseDTO;
|
||||
import org.openhab.binding.bsblan.internal.configuration.BsbLanBridgeConfiguration;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Bridge for BSB-LAN devices.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanBridgeHandler extends BaseBridgeHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BsbLanBridgeHandler.class);
|
||||
private final Set<BsbLanBaseThingHandler> things = new HashSet<>();
|
||||
private BsbLanBridgeConfiguration bridgeConfig = new BsbLanBridgeConfiguration();
|
||||
private @Nullable ScheduledFuture<?> refreshJob;
|
||||
private @Nullable ScheduledFuture<?> debouncedInit;
|
||||
private @Nullable BsbLanApiParameterQueryResponseDTO cachedParameterQueryResponse;
|
||||
|
||||
public BsbLanBridgeHandler(Bridge bridge) {
|
||||
super(bridge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
public void registerThing(final BsbLanBaseThingHandler parameter) {
|
||||
this.things.add(parameter);
|
||||
|
||||
// To avoid having to wait up to refreshInterval seconds until values are updated
|
||||
// for the added thing, we trigger a debounced refresh to shorten the delay.
|
||||
// Alternatively the thing itself could make an additional REST call
|
||||
// on initialization but this would flood the device when lots of parameters are setup.
|
||||
|
||||
// use a local variable to avoid the build warning "Potential null pointer access"
|
||||
ScheduledFuture<?> localDebouncedInit = debouncedInit;
|
||||
if (localDebouncedInit == null || localDebouncedInit.isCancelled() || localDebouncedInit.isDone()) {
|
||||
debouncedInit = scheduler.schedule(this::doRefresh, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
bridgeConfig = getConfigAs(BsbLanBridgeConfiguration.class);
|
||||
|
||||
// validate 'host' configuration
|
||||
if (StringUtils.isBlank(bridgeConfig.host)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Parameter 'host' is mandatory and must be configured");
|
||||
return;
|
||||
}
|
||||
|
||||
// validate 'refreshInterval' configuration
|
||||
if (bridgeConfig.refreshInterval != null && bridgeConfig.refreshInterval < MIN_REFRESH_INTERVAL) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
String.format("Parameter 'refreshInterval' must be at least %d seconds", MIN_REFRESH_INTERVAL));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bridgeConfig.port == null) {
|
||||
bridgeConfig.port = DEFAULT_API_PORT;
|
||||
}
|
||||
|
||||
// all checks succeeded, start refreshing
|
||||
startAutomaticRefresh(bridgeConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// use a local variable to avoid the build warning "Potential null pointer access"
|
||||
ScheduledFuture<?> localRefreshJob = refreshJob;
|
||||
if (localRefreshJob != null) {
|
||||
localRefreshJob.cancel(true);
|
||||
}
|
||||
// use a local variable to avoid the build warning "Potential null pointer access"
|
||||
ScheduledFuture<?> localDebouncedInit = debouncedInit;
|
||||
if (localDebouncedInit != null) {
|
||||
localDebouncedInit.cancel(true);
|
||||
}
|
||||
things.clear();
|
||||
}
|
||||
|
||||
public @Nullable BsbLanApiParameterQueryResponseDTO getCachedParameterQueryResponse() {
|
||||
return cachedParameterQueryResponse;
|
||||
}
|
||||
|
||||
public BsbLanBridgeConfiguration getBridgeConfiguration() {
|
||||
return bridgeConfig;
|
||||
}
|
||||
|
||||
private void doRefresh() {
|
||||
logger.trace("Refreshing parameter values");
|
||||
|
||||
BsbLanApiCaller apiCaller = new BsbLanApiCaller(bridgeConfig);
|
||||
|
||||
// refresh all parameters
|
||||
Set<Integer> parameterIds = things.stream().filter(thing -> thing instanceof BsbLanParameterHandler)
|
||||
.map(thing -> (BsbLanParameterHandler) thing).map(thing -> thing.getParameterId())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
cachedParameterQueryResponse = apiCaller.queryParameters(parameterIds);
|
||||
|
||||
// InetAddress.isReachable(...) check returned false on RPi although the device is reachable (worked on
|
||||
// Windows).
|
||||
// Therefore we check status depending on the response.
|
||||
if (cachedParameterQueryResponse == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Did not receive a response from BSB-LAN device. Check your configuration and if device is online.");
|
||||
// continue processing, so things can go to OFFLINE too
|
||||
} else {
|
||||
// response received, tread device as reachable, refresh state now
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
for (BsbLanBaseThingHandler parameter : things) {
|
||||
parameter.refresh(bridgeConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the job refreshing the data
|
||||
*/
|
||||
private void startAutomaticRefresh(BsbLanBridgeConfiguration config) {
|
||||
// use a local variable to avoid the build warning "Potential null pointer access"
|
||||
ScheduledFuture<?> localRefreshJob = refreshJob;
|
||||
if (localRefreshJob == null || localRefreshJob.isCancelled()) {
|
||||
int interval = (config.refreshInterval != null) ? config.refreshInterval.intValue()
|
||||
: DEFAULT_REFRESH_INTERVAL;
|
||||
refreshJob = scheduler.scheduleWithFixedDelay(this::doRefresh, 0, interval, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* 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.bsblan.internal.handler;
|
||||
|
||||
import static org.openhab.binding.bsblan.internal.BsbLanBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bsblan.internal.api.BsbLanApiCaller;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterQueryResponseDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetRequestDTO.Type;
|
||||
import org.openhab.binding.bsblan.internal.configuration.BsbLanBridgeConfiguration;
|
||||
import org.openhab.binding.bsblan.internal.configuration.BsbLanParameterConfiguration;
|
||||
import org.openhab.binding.bsblan.internal.helper.BsbLanParameterConverter;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanParameterHandler} is responsible for updating the data, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanParameterHandler extends BsbLanBaseThingHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BsbLanParameterHandler.class);
|
||||
private BsbLanParameterConfiguration parameterConfig = new BsbLanParameterConfiguration();
|
||||
|
||||
public BsbLanParameterHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
public Integer getParameterId() {
|
||||
return parameterConfig.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDescription() {
|
||||
return "BSB-LAN Parameter";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(BsbLanBridgeConfiguration bridgeConfiguration) {
|
||||
updateChannels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
parameterConfig = getConfigAs(BsbLanParameterConfiguration.class);
|
||||
super.initialize();
|
||||
|
||||
// validate 'setId' configuration -> fallback to value of 'id' if invalid or not specified
|
||||
if (parameterConfig.setId == null || parameterConfig.setId <= 0) {
|
||||
parameterConfig.setId = parameterConfig.id;
|
||||
}
|
||||
|
||||
// validate 'setType' configuration -> fallback to 'SET' if invalid or not specified
|
||||
parameterConfig.setType = Type.getTypeWithFallback(parameterConfig.setType).toString();
|
||||
|
||||
// it will take up to refreshInterval seconds until we receive a value and thing goes online
|
||||
// see notes in {@link BsbLanBridgeHandler#registerThing(BsbLanBaseThingHandler)}
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last data retrieved
|
||||
*
|
||||
* @param channelId the id identifying the channel to be updated
|
||||
*/
|
||||
@Override
|
||||
protected void updateChannel(String channelId) {
|
||||
BsbLanApiParameterQueryResponseDTO data = null;
|
||||
BsbLanBridgeHandler bridgeHandler = getBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
data = bridgeHandler.getCachedParameterQueryResponse();
|
||||
}
|
||||
updateChannel(channelId, data);
|
||||
}
|
||||
|
||||
private void updateChannel(String channelId, @Nullable BsbLanApiParameterQueryResponseDTO data) {
|
||||
if (data == null) {
|
||||
logger.debug("no data available while updating channel '{}' of parameter {}", channelId,
|
||||
parameterConfig.id);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.BRIDGE_OFFLINE,
|
||||
"No data received from BSB-LAN device");
|
||||
return;
|
||||
}
|
||||
|
||||
BsbLanApiParameterDTO parameter = data.getOrDefault(parameterConfig.id, null);
|
||||
if (parameter == null) {
|
||||
logger.debug("parameter {} is not part of response data while updating channel '{}' ", parameterConfig.id,
|
||||
channelId);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
String.format("No data received for parameter %s", parameterConfig.id));
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
if (!isLinked(channelId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
State state = BsbLanParameterConverter.getState(channelId, parameter);
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateState(channelId, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the channel from the last data retrieved
|
||||
*
|
||||
* @param channelId the id identifying the channel to be updated
|
||||
* @param command the value to be set
|
||||
*/
|
||||
@Override
|
||||
protected void setChannel(String channelId, Command command) {
|
||||
logger.trace("Received command '{}' for channel '{}'", command, channelId);
|
||||
|
||||
if (!WRITEABLE_CHANNELS.contains(channelId)) {
|
||||
logger.warn("Channel '{}' is read only. Ignoring command", channelId);
|
||||
return;
|
||||
}
|
||||
|
||||
String value = BsbLanParameterConverter.getValue(channelId, command);
|
||||
if (value == null) {
|
||||
logger.warn("Channel '{}' is read only or conversion failed. Ignoring command", channelId);
|
||||
return;
|
||||
}
|
||||
|
||||
BsbLanApiCaller api = getApiCaller();
|
||||
if (api == null) {
|
||||
logger.debug("Failed to set parameter {} (API unavailable)", parameterConfig.setId);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean success = api.setParameter(parameterConfig.setId, value,
|
||||
Type.getTypeWithFallback(parameterConfig.setType));
|
||||
if (!success) {
|
||||
logger.debug("Failed to set parameter {} to '{}' for channel '{}'", parameterConfig.setId, value,
|
||||
channelId);
|
||||
}
|
||||
|
||||
// refresh value
|
||||
BsbLanApiParameterQueryResponseDTO queryResponse = api.queryParameter(parameterConfig.id);
|
||||
if (queryResponse == null) {
|
||||
logger.debug("Failed to refresh parameter {} after set request", parameterConfig.id);
|
||||
return;
|
||||
}
|
||||
|
||||
updateChannel(channelId, queryResponse);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* 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.bsblan.internal.helper;
|
||||
|
||||
import static org.openhab.binding.bsblan.internal.BsbLanBindingConstants.*;
|
||||
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterDTO;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanParameterHandler} is responsible for updating the data, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanParameterConverter {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BsbLanParameterConverter.class);
|
||||
|
||||
public static @Nullable State getState(String channelId, BsbLanApiParameterDTO parameter) {
|
||||
switch (channelId) {
|
||||
case PARAMETER_CHANNEL_NAME:
|
||||
return getStateForNameChannel(parameter);
|
||||
|
||||
case PARAMETER_CHANNEL_DESCRIPTION:
|
||||
return getStateForDescriptionChannel(parameter);
|
||||
|
||||
case PARAMETER_CHANNEL_DATATYPE:
|
||||
return getStateForDatatypeChannel(parameter);
|
||||
|
||||
case PARAMETER_CHANNEL_NUMBER_VALUE:
|
||||
return getStateForNumberValueChannel(parameter);
|
||||
|
||||
case PARAMETER_CHANNEL_STRING_VALUE:
|
||||
return getStateForStringValueChannel(parameter);
|
||||
|
||||
case PARAMETER_CHANNEL_SWITCH_VALUE:
|
||||
return getStateForSwitchValueChannel(parameter);
|
||||
|
||||
case PARAMETER_CHANNEL_UNIT:
|
||||
return getStateForUnitChannel(parameter);
|
||||
}
|
||||
|
||||
LOGGER.debug("unsupported channel '{}' while updating state", channelId);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static State getStateForNameChannel(BsbLanApiParameterDTO parameter) {
|
||||
return new StringType(parameter.name);
|
||||
}
|
||||
|
||||
private static State getStateForDescriptionChannel(BsbLanApiParameterDTO parameter) {
|
||||
return new StringType(parameter.description);
|
||||
}
|
||||
|
||||
private static State getStateForUnitChannel(BsbLanApiParameterDTO parameter) {
|
||||
String value = StringEscapeUtils.unescapeHtml(parameter.unit);
|
||||
return new StringType(value);
|
||||
}
|
||||
|
||||
private static State getStateForDatatypeChannel(BsbLanApiParameterDTO parameter) {
|
||||
int value = parameter.dataType.getValue();
|
||||
return new DecimalType(value);
|
||||
}
|
||||
|
||||
private static @Nullable State getStateForNumberValueChannel(BsbLanApiParameterDTO parameter) {
|
||||
try {
|
||||
switch (parameter.dataType) {
|
||||
// parse enum data type as integer
|
||||
case DT_ENUM:
|
||||
return new DecimalType(Integer.parseInt(parameter.value));
|
||||
|
||||
default:
|
||||
return new DecimalType(Double.parseDouble(parameter.value));
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// silently ignore - there is not "tryParse"
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static State getStateForStringValueChannel(BsbLanApiParameterDTO parameter) {
|
||||
return new StringType(parameter.value);
|
||||
}
|
||||
|
||||
private static State getStateForSwitchValueChannel(BsbLanApiParameterDTO parameter) {
|
||||
// treat "0" as OFF and everything else as ON
|
||||
return parameter.value.equals("0") ? OnOffType.OFF : OnOffType.ON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Command back to a value which is sent to the BSB-LAN device afterwards.
|
||||
*
|
||||
* @param channelId
|
||||
* @param command
|
||||
* @return null if conversion fails or channel is readonly.
|
||||
*/
|
||||
public static @Nullable String getValue(String channelId, Command command) {
|
||||
switch (channelId) {
|
||||
case PARAMETER_CHANNEL_NUMBER_VALUE:
|
||||
return getValueForNumberValueChannel(command);
|
||||
|
||||
case PARAMETER_CHANNEL_STRING_VALUE:
|
||||
return getValueForStringValueChannel(command);
|
||||
|
||||
case PARAMETER_CHANNEL_SWITCH_VALUE:
|
||||
return getValueForSwitchValueChannel(command);
|
||||
|
||||
default:
|
||||
LOGGER.debug("Channel '{}' is read only. Ignoring command", channelId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable String getValueForNumberValueChannel(Command command) {
|
||||
// check if numeric
|
||||
if (command.toString().matches("-?\\d+(\\.\\d+)?")) {
|
||||
return command.toString();
|
||||
}
|
||||
LOGGER.warn("Command '{}' is not a valid number value", command);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getValueForStringValueChannel(Command command) {
|
||||
// special OnOffType handling
|
||||
if (command.equals(OnOffType.ON)) {
|
||||
return "1";
|
||||
} else if (command.equals(OnOffType.OFF)) {
|
||||
return "0";
|
||||
}
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
private static @Nullable String getValueForSwitchValueChannel(Command command) {
|
||||
if (command.equals(OnOffType.ON)) {
|
||||
return "1";
|
||||
} else if (command.equals(OnOffType.OFF)) {
|
||||
return "0";
|
||||
}
|
||||
LOGGER.warn("Command '{}' is not a valid switch value", command);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="bsblan" 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>BSB-LAN Binding</name>
|
||||
<description>Binding for BSB-LAN Gateway.</description>
|
||||
<author>Peter Schraffl</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="bsblan"
|
||||
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">
|
||||
|
||||
<bridge-type id="bridge">
|
||||
<label>BSB-LAN Bridge</label>
|
||||
<description>A bridge to connect a BSB-LAN device</description>
|
||||
<config-description>
|
||||
<parameter name="host" type="text" required="true" groupName="network">
|
||||
<context>network-address</context>
|
||||
<label>Host</label>
|
||||
<description>The hostname or IP address of the BSB-LAN device.</description>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" required="false" groupName="network">
|
||||
<label>Port</label>
|
||||
<description>The port BSB-LAN device.</description>
|
||||
<default>80</default>
|
||||
</parameter>
|
||||
<parameter name="passkey" type="text" required="false" groupName="network">
|
||||
<label>Passkey</label>
|
||||
<description>The passkey required to access the BSB-LAN device.</description>
|
||||
</parameter>
|
||||
<parameter name="username" type="text" required="false" groupName="network">
|
||||
<label>Username</label>
|
||||
<description>The username required to access the BSB-LAN device (when using HTTP Basic Authentication).</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="false" groupName="network">
|
||||
<context>password</context>
|
||||
<label>Password</label>
|
||||
<description>The password required to access the BSB-LAN device (when using HTTP Basic Authentication).</description>
|
||||
</parameter>
|
||||
<parameter name="refreshInterval" type="integer" required="false" min="5">
|
||||
<label>Refresh Interval</label>
|
||||
<description>Specifies the refresh interval in seconds.</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="bsblan"
|
||||
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">
|
||||
|
||||
<!-- Parameter Thing Type -->
|
||||
<thing-type id="parameter">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Parameter</label>
|
||||
<description>Represents a single parameter available at the BSB-LAN device and identified by a numeric id.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="name" typeId="parameter_name"/>
|
||||
<channel id="number-value" typeId="parameter_number_value"/>
|
||||
<channel id="string-value" typeId="parameter_string_value"/>
|
||||
<channel id="switch-value" typeId="parameter_switch_value"/>
|
||||
<channel id="unit" typeId="parameter_unit"/>
|
||||
<channel id="description" typeId="parameter_description"/>
|
||||
<channel id="datatype" typeId="parameter_datatype"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="id" type="integer" required="true">
|
||||
<label>Parameter ID</label>
|
||||
<description>Specific parameter identifier</description>
|
||||
</parameter>
|
||||
<parameter name="setId" type="integer" required="false" groupName="Change Requests">
|
||||
<label>Parameter Set-ID</label>
|
||||
<description>Parameter identifier used for change requests. Defaults to the value of Parameter ID</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="setType" type="text" required="false" groupName="Change Requests">
|
||||
<label>Message Type</label>
|
||||
<description>Message type used for change requests. Defaults to SET.</description>
|
||||
<default>SET</default>
|
||||
<advanced>true</advanced>
|
||||
<options>
|
||||
<option value="INF">INF</option>
|
||||
<option value="SET">SET</option>
|
||||
</options>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="parameter_name">
|
||||
<item-type>String</item-type>
|
||||
<label>Name</label>
|
||||
<description>Name of the parameter</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
<channel-type id="parameter_number_value">
|
||||
<item-type>Number</item-type>
|
||||
<label>Value</label>
|
||||
<description>Value of the parameter</description>
|
||||
<state readOnly="false" pattern="%.1f °C"></state>
|
||||
</channel-type>
|
||||
<channel-type id="parameter_string_value">
|
||||
<item-type>String</item-type>
|
||||
<label>Value</label>
|
||||
<description>Value of the parameter</description>
|
||||
<state readOnly="false"></state>
|
||||
</channel-type>
|
||||
<channel-type id="parameter_switch_value">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Value</label>
|
||||
<description>Value of the parameter</description>
|
||||
<state readOnly="false"></state>
|
||||
</channel-type>
|
||||
<channel-type id="parameter_unit">
|
||||
<item-type>String</item-type>
|
||||
<label>Unit</label>
|
||||
<description>Unit of the parameter</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
<channel-type id="parameter_description">
|
||||
<item-type>String</item-type>
|
||||
<label>Description</label>
|
||||
<description>Description of the parameter</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
<channel-type id="parameter_datatype">
|
||||
<item-type>Number</item-type>
|
||||
<label>Data Type</label>
|
||||
<description>Data type of the parameter</description>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.bsblan.internal;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanHandlerFactoryTests} class implements tests
|
||||
* for {@link BsbLanHandlerFactory}.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanHandlerFactoryTests {
|
||||
|
||||
public static final ThingTypeUID UNKNOWN_THING_TYPE_UID = new ThingTypeUID("bsblan", "unknown");
|
||||
|
||||
/**
|
||||
* Test if factory knows all thing types.
|
||||
*/
|
||||
@Test
|
||||
public void supportsThingType() {
|
||||
BsbLanHandlerFactory factory = new BsbLanHandlerFactory();
|
||||
assertFalse(factory.supportsThingType(UNKNOWN_THING_TYPE_UID));
|
||||
|
||||
assertTrue(factory.supportsThingType(BsbLanBindingConstants.THING_TYPE_BRIDGE));
|
||||
assertTrue(factory.supportsThingType(BsbLanBindingConstants.THING_TYPE_PARAMETER));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.bsblan.internal.api;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterQueryResponseDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetRequestDTO;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterSetRequestDTO.Type;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanApiContentConverterTests} class implements tests
|
||||
* for {@link BsbLanApiContentConverter}.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanApiContentConverterTests {
|
||||
|
||||
@Test
|
||||
public void parseBsbLanApiParameterQueryResponse() {
|
||||
String content = "{\r\n" + "\"700\": {\r\n" + "\"name\": \"Betriebsart\",\r\n" + "\"value\": \"0\",\r\n"
|
||||
+ "\"unit\": \"\",\r\n" + "\"desc\": \"Schutzbetrieb\",\r\n" + "\"dataType\": 1\r\n" + "}\r\n" + "}";
|
||||
|
||||
BsbLanApiParameterQueryResponseDTO r = BsbLanApiContentConverter.fromJson(content,
|
||||
BsbLanApiParameterQueryResponseDTO.class);
|
||||
assertNotNull(r);
|
||||
assertTrue(r.containsKey(700));
|
||||
|
||||
BsbLanApiParameterDTO p = r.get(700);
|
||||
assertEquals("Betriebsart", p.name);
|
||||
assertEquals("0", p.value);
|
||||
assertEquals("", p.unit);
|
||||
assertEquals("Schutzbetrieb", p.description);
|
||||
assertEquals(BsbLanApiParameterDTO.DataType.DT_ENUM, p.dataType);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serializeBsbLanApiParameterSetRequest() {
|
||||
BsbLanApiParameterSetRequestDTO request = new BsbLanApiParameterSetRequestDTO();
|
||||
request.parameter = "1234";
|
||||
request.value = "Hello World";
|
||||
request.type = Type.SET;
|
||||
|
||||
String serializedRequest = BsbLanApiContentConverter.toJson(request);
|
||||
|
||||
// verify serialized content
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject json = parser.parse(serializedRequest).getAsJsonObject();
|
||||
|
||||
// Although specifying the parameter as int (which would be nicer) also seems to work,
|
||||
// we use a String here as this is the way it is noted in the documentation.
|
||||
// So ensure there is a 'Parameter' and it is serialized as string.
|
||||
assertEquals("1234", json.get("Parameter").getAsString());
|
||||
|
||||
// ensure there is a 'Value' and it is serialized as string
|
||||
assertEquals("Hello World", json.get("Value").getAsString());
|
||||
|
||||
// ensure there is a 'Type' and it is serialized as number
|
||||
assertEquals(1, json.get("Type").getAsInt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/**
|
||||
* 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.bsblan.internal.helper;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.openhab.binding.bsblan.internal.BsbLanBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.bsblan.internal.api.dto.BsbLanApiParameterDTO;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link BsbLanParameterConverterTests} class implements tests
|
||||
* for {@link BsbLanParameterConverter}.
|
||||
*
|
||||
* @author Peter Schraffl - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BsbLanParameterConverterTests {
|
||||
|
||||
@Test
|
||||
public void testGetStatesForStringParameter() {
|
||||
BsbLanApiParameterDTO parameter = new BsbLanApiParameterDTO();
|
||||
parameter.dataType = BsbLanApiParameterDTO.DataType.DT_STRN;
|
||||
parameter.description = "Test-Description";
|
||||
parameter.name = "Test-Name";
|
||||
parameter.unit = "Test-Unit";
|
||||
parameter.value = "Test-Value";
|
||||
|
||||
State state = null;
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DATATYPE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new DecimalType(BsbLanApiParameterDTO.DataType.DT_STRN.getValue()), state.as(DecimalType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DESCRIPTION, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Description"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NAME, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Name"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_UNIT, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Unit"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NUMBER_VALUE, parameter);
|
||||
assertNull(state);
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_STRING_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Value"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_SWITCH_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(OnOffType.ON, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStatesForEnumParameterValue1() {
|
||||
BsbLanApiParameterDTO parameter = new BsbLanApiParameterDTO();
|
||||
parameter.dataType = BsbLanApiParameterDTO.DataType.DT_ENUM;
|
||||
parameter.description = "Test-Description";
|
||||
parameter.name = "Test-Name";
|
||||
parameter.unit = "Test-Unit";
|
||||
parameter.value = "1";
|
||||
|
||||
State state = null;
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DATATYPE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new DecimalType(BsbLanApiParameterDTO.DataType.DT_ENUM.getValue()), state.as(DecimalType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DESCRIPTION, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Description"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NAME, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Name"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_UNIT, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Unit"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NUMBER_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new DecimalType(1), state.as(DecimalType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_STRING_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("1"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_SWITCH_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(OnOffType.ON, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStatesForEnumParameterValue0() {
|
||||
BsbLanApiParameterDTO parameter = new BsbLanApiParameterDTO();
|
||||
parameter.dataType = BsbLanApiParameterDTO.DataType.DT_ENUM;
|
||||
parameter.description = "Test-Description";
|
||||
parameter.name = "Test-Name";
|
||||
parameter.unit = "Test-Unit";
|
||||
parameter.value = "0";
|
||||
|
||||
State state = null;
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DATATYPE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new DecimalType(BsbLanApiParameterDTO.DataType.DT_ENUM.getValue()), state.as(DecimalType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DESCRIPTION, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Description"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NAME, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Name"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_UNIT, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Unit"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NUMBER_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new DecimalType(0), state.as(DecimalType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_STRING_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("0"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_SWITCH_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(OnOffType.OFF, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStatesForValueParameterValue() {
|
||||
BsbLanApiParameterDTO parameter = new BsbLanApiParameterDTO();
|
||||
parameter.dataType = BsbLanApiParameterDTO.DataType.DT_VALS;
|
||||
parameter.description = "Test-Description";
|
||||
parameter.name = "Test-Name";
|
||||
parameter.unit = "Test-Unit";
|
||||
parameter.value = "22.5";
|
||||
|
||||
State state = null;
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DATATYPE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new DecimalType(BsbLanApiParameterDTO.DataType.DT_VALS.getValue()), state.as(DecimalType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_DESCRIPTION, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Description"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NAME, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Name"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_UNIT, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("Test-Unit"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_NUMBER_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new DecimalType(22.5), state.as(DecimalType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_STRING_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("22.5"), state.as(StringType.class));
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_SWITCH_VALUE, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(OnOffType.ON, state);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStatesEscapesHtml() {
|
||||
BsbLanApiParameterDTO parameter = new BsbLanApiParameterDTO();
|
||||
parameter.dataType = BsbLanApiParameterDTO.DataType.DT_VALS;
|
||||
parameter.description = "Test-Description";
|
||||
parameter.name = "Test-Name";
|
||||
parameter.unit = "°C";
|
||||
parameter.value = "22.5";
|
||||
|
||||
State state = null;
|
||||
|
||||
state = BsbLanParameterConverter.getState(PARAMETER_CHANNEL_UNIT, parameter);
|
||||
assertNotNull(state);
|
||||
assertEquals(new StringType("°C"), state.as(StringType.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueForReadonlyChannels() {
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_DATATYPE, OnOffType.ON));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_DESCRIPTION, OnOffType.ON));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_NAME, OnOffType.ON));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_UNIT, OnOffType.ON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueForNumberValueChannel() {
|
||||
assertNull("1", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_NUMBER_VALUE, OnOffType.ON));
|
||||
assertNull("0", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_NUMBER_VALUE, OnOffType.OFF));
|
||||
assertEquals("42", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_NUMBER_VALUE, new DecimalType(42)));
|
||||
assertEquals("22.5", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_NUMBER_VALUE, new DecimalType(22.5)));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_NUMBER_VALUE,
|
||||
new StringType("Not a number value")));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_NUMBER_VALUE, new StringType("")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueForSwitchValueChannel() {
|
||||
assertEquals("1", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE, OnOffType.ON));
|
||||
assertEquals("0", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE, OnOffType.OFF));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE, new DecimalType(1)));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE, new DecimalType(0)));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE, new DecimalType(42)));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE, new DecimalType(22.5)));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE,
|
||||
new StringType("Not a number value")));
|
||||
assertNull(BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_SWITCH_VALUE, new StringType("")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueForStringValueChannel() {
|
||||
assertEquals("1", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_STRING_VALUE, OnOffType.ON));
|
||||
assertEquals("0", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_STRING_VALUE, OnOffType.OFF));
|
||||
assertEquals("42", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_STRING_VALUE, new DecimalType(42)));
|
||||
assertEquals("22.5", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_STRING_VALUE, new DecimalType(22.5)));
|
||||
assertEquals("A string value",
|
||||
BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_STRING_VALUE, new StringType("A string value")));
|
||||
assertEquals("", BsbLanParameterConverter.getValue(PARAMETER_CHANNEL_STRING_VALUE, new StringType("")));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user