added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.jeelink/.classpath
Normal file
32
bundles/org.openhab.binding.jeelink/.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.jeelink/.project
Normal file
23
bundles/org.openhab.binding.jeelink/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.jeelink</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.jeelink/NOTICE
Normal file
13
bundles/org.openhab.binding.jeelink/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
|
||||
229
bundles/org.openhab.binding.jeelink/README.md
Normal file
229
bundles/org.openhab.binding.jeelink/README.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# Jeelink Binding
|
||||
|
||||
This binding integrates JeeLink USB RF receivers and LaCrosseGateways.
|
||||
|
||||
## Introduction
|
||||
|
||||
Binding should be compatible with JeeLink USB receivers and LaCrosseGateways. It supports connected LaCrosse temperature sensors, EC3000 sensors, PCA301 power monitoring wireless sockets and TX22 temperature and humidity sensors (including connected TX23 wind and TX26 rain sensors).
|
||||
|
||||
## Supported Things
|
||||
|
||||
This binding supports:
|
||||
|
||||
* JeeLink (connected to USB)
|
||||
* JeeLink (connected over TCP)
|
||||
* LaCrosseGateway (connected to USB)
|
||||
* LaCrosseGateway (connected over TCP)
|
||||
* LaCrosse temperature sensors
|
||||
* EC3000 power monitors
|
||||
* Revolt power monitors
|
||||
* PCA301 power monitoring wireless sockets
|
||||
* TX22 temperature & humidity Sensors (including connected TX23 wind and TX26 rain sensors)
|
||||
|
||||
## Binding configuration
|
||||
|
||||
Configuration of the binding is not needed.
|
||||
|
||||
## Thing discovery
|
||||
|
||||
Only sensor discovery is supported, the thing for the USB receiver / LaCrosseGateway has to be created manually. Pay attention to use the correct serial port, as otherwise the binding may interfere with other bindings accessing serial ports.
|
||||
|
||||
Afterwards, discovery reads from the USB receiver / LaCrosseGateways to find out which sensors are currently connected.
|
||||
It then creates a thing for every unknown sensor and puts it in the Inbox.
|
||||
|
||||
Discovery only creates things for sensors that actually send a value during discovery. LaCrosse temperature sensors send values every few seconds, so that they are normally caught by the discovery. In rare cases, a second discovery run is needed.
|
||||
|
||||
PCA301 sockets are polled every 120 seconds by default. This results in sockets not being found by the discovery. In order to make sure the socket is discovered, press the button on the socket during discovery (and make sure you have paired the socket to the USB stick / LaCrosseGateway before by pressing the button for 3 seconds while the receiver is powered).
|
||||
|
||||
## Thing configuration
|
||||
|
||||
#### JeeLink / LaCrosseGateway (connected to USB)
|
||||
|
||||
| Parameter | Item Type | Description |
|
||||
|---------------|-----------|----------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Serial Port | String | The serial port name for the USB receiver / LaCrosseGateway. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux |
|
||||
| Baud Rate | Number | The baud rate of the USB Receiver. Valid values are 9600, 19200, 38400, 57600 (default), and 115200 |
|
||||
| Init Commands | String | A semicolon separated list of init commands that will be send to the Jeelink / LaCrosseGateway, e.g. "0a" for disabling the LED |
|
||||
|
||||
The available init commands depend on the sketch that is running on the USB stick / LaCrosseGateway.
|
||||
|
||||
|
||||
#### JeeLink / LaCrosseGateway (connected over TCP)
|
||||
|
||||
| Parameter | Item Type | Description |
|
||||
|---------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| IP Address | String | The IP address of the Server to which the USB Receiver is connected, or the IP address of the LaCrosseGateway |
|
||||
| TCP Port | Number | The TCP port over which the serial port is made available, or the LaCrosseGateway port (which usually is 81) |
|
||||
| Init Commands | String | A semicolon separated list of init commands that will be send to the Jeelink / LaCrosseGateway, e.g. "0a" for disabling the LED |
|
||||
|
||||
|
||||
#### LaCrosse temperature sensors
|
||||
|
||||
| Parameter | Item Type | Description |
|
||||
|----------------------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Sensor ID | Number | The ID of the connected sensor |
|
||||
| Sensor Timeout | Number | The amount of time in seconds that should result in OFFLINE status when no readings have been received from the sensor |
|
||||
| Update Interval | Number | The update interval in seconds how often value updates are propagated. A value of 0 leads to propagation of every value |
|
||||
| Buffer Size | Number | The number of readings used for computing the rolling average |
|
||||
| Lower Temperature Limit | Decimal | The lowest allowed valid temperature. Lower temperature readings will be ignored |
|
||||
| Upper Temperature Limit | Decimal | The highest allowed valid temperature. Higher temperature readings will be ignored |
|
||||
| Maximum allowed difference | Decimal | The maximum allowed difference from a value to the previous value (0 disables this check). If the difference is higher, the reading will be ignored. |
|
||||
|
||||
#### EC3000 power monitors
|
||||
|
||||
| Parameter | Item Type | Description |
|
||||
|-----------------|-----------|-------------------------------------------------------------------------------------------------------------------------|
|
||||
| Sensor ID | Number | The ID of the connected sensor |
|
||||
| Sensor Timeout | Number | The amount of time in seconds that should result in OFFLINE status when no readings have been received from the sensor |
|
||||
| Update Interval | Number | The update interval in seconds how often value updates are propagated. A value of 0 leads to propagation of every value |
|
||||
| Buffer Size | Number | The number of readings used for computing the rolling average |
|
||||
|
||||
#### PCA301 power monitoring wireless sockets
|
||||
|
||||
| Parameter | Item Type | Description |
|
||||
|-------------------|--------------|------------------------------------------------------------------------------------------------------------------------|
|
||||
| Sensor ID | Number | The ID of the connected sensor |
|
||||
| Sensor Timeout | Number | The amount of time in seconds that should result in OFFLINE status when no readings have been received from the sensor |
|
||||
| Retry Count | Number | The number of times a switch command will be resent to the socket until giving up |
|
||||
|
||||
#### Revolt power monitors
|
||||
|
||||
| Parameter | Item Type | Description |
|
||||
|-------------------|--------------|------------------------------------------------------------------------------------------------------------------------|
|
||||
| Sensor ID | Number | The ID of the connected sensor |
|
||||
| Sensor Timeout | Number | The amount of time in seconds that should result in OFFLINE status when no readings have been received from the sensor |
|
||||
|
||||
## Channels
|
||||
|
||||
#### LaCrosse temperature sensors
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------------------|---------------------------------------------------|
|
||||
| temperature | Number:Temperature | Temperature reading |
|
||||
| humidity | Number:Dimensionless | Humidity reading |
|
||||
| batteryNew | Contact | Whether the battery is new (CLOSED) or not (OPEN) |
|
||||
| batteryLow | Contact | Whether the battery is low (CLOSED) or not (OPEN) |
|
||||
|
||||
#### TX22 temperature and humidity sensors
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-----------------|-----------------------|----------------------------|
|
||||
| temperature | Number:Temperature | Temperature reading |
|
||||
| humidity | Number:Dimensionless | Humidity reading |
|
||||
| pressure | Number:Pressure | Current pressure reading |
|
||||
| rain | Number:Length | Rainfall today |
|
||||
| windStrength | Number:Speed | Current wind speed |
|
||||
| windAngle | Number:Angle | Current wind direction |
|
||||
| gustStrength | Number:Speed | Gust speed |
|
||||
|
||||
#### EC3000 power monitors
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|------------------|---------------|-------------------------------------------|
|
||||
| currentPower | Number:Power | Current power draw |
|
||||
| maxPower | Number:Power | Maximum power draw |
|
||||
| consumptionTotal | Number:Energy | Total energy consumption |
|
||||
| applianceTime | Number:Time | Total electrical appliance operating time |
|
||||
| sensorTime | Number:Time | Total turn on time of power monitor |
|
||||
| resets | Number | Number of resets |
|
||||
|
||||
#### PCA301 power monitoring wireless sockets
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-------------------------|---------------|------------------------------------------------------|
|
||||
| switchingState | Switch | Whether the sockets are currently switched on or off |
|
||||
| currentPower | Number:Power | Current power draw |
|
||||
| consumptionTotal | Number:Energy | Total energy consumption |
|
||||
|
||||
#### Revolt power monitors
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-------------------|--------------------------|-------------------------------------------|
|
||||
| currentPower | Number:Power | Current power draw |
|
||||
| consumptionTotal | Number:Energy | Total energy consumption |
|
||||
| powerFactor | Number | Ratio of real power to apparent power |
|
||||
| electricCurrent | Number:ElectricCurrent | The measured Electric Current |
|
||||
| electricPotential | Number:ElectricPotential | The measured Electric Potential |
|
||||
| powerFrequency | Number:Frequency | The measured AC power frequency |
|
||||
|
||||
## Commands
|
||||
|
||||
#### PCA301 power monitoring wireless sockets
|
||||
|
||||
| Channel Type ID | Item Type | Description |
|
||||
|-------------------------|--------------|---------------------------------------------------|
|
||||
| switchingState | Switch | Supports ON and OFF commands to switch the socket |
|
||||
|
||||
## Full Example
|
||||
|
||||
A typical thing configuration for PCA301 looks like this:
|
||||
|
||||
```
|
||||
Bridge jeelink:jeelinkUsb:pca301 "Jeelink pca301" @ "home" [ serialPort="/dev/ttyUSB0" ]
|
||||
Thing jeelink:pca301:1-160-236 "ec3k 1" (jeelink:jeelinkUsb:pca301) @ "home" [ sensorId="1-160-236"]
|
||||
```
|
||||
|
||||
A typical thing configuration for EC3000 looks like this:
|
||||
|
||||
```
|
||||
Bridge jeelink:jeelinkUsb:ec3k "Jeelink ec3k" @ "home" [ serialPort="COM4" ]
|
||||
Thing jeelink:ec3k:0E3D "ec3k 1" (jeelink:jeelinkUsb:ec3k) @ "home" [ sensorId="0E3D"]
|
||||
Thing jeelink:ec3k:14E7 "ec3k 2" (jeelink:jeelinkUsb:ec3k) @ "home" [ sensorId="14E7"]
|
||||
```
|
||||
|
||||
A typical Thing configuration for lacrosse looks like this:
|
||||
|
||||
```
|
||||
Bridge jeelink:jeelinkUsb:lacrosse "Jeelink lacrosse" @ "home" [ serialPort="COM6" ]
|
||||
Thing jeelink:lacrosse:sensor1 "Jeelink lacrosse 1" (jeelink:jeelinkUsb:lacrosse) @ "home" [ sensorId="16", minTemp=10, maxTemp=32]
|
||||
Thing jeelink:lacrosse:sensor2 "Jeelink lacrosse 2" (jeelink:jeelinkUsb:lacrosse) @ "home" [ sensorId="18", minTemp=10, maxTemp=32]
|
||||
```
|
||||
|
||||
A typical thing configuration for Revolt looks like this:
|
||||
|
||||
```
|
||||
Bridge jeelink:jeelinkUsb:revolt "Jeelink revolt" @ "home" [ serialPort="COM4" ]
|
||||
Thing jeelink:revolt:4F1B "revolt 1" (jeelink:jeelinkUsb:revolt) @ "home" [ sensorId="4F1B"]
|
||||
```
|
||||
|
||||
A typical item configuration for a LaCrosse temperature sensor looks like this:
|
||||
|
||||
```
|
||||
Number:Dimensionless Humidty_LR "Living Room [%.1f %unit%]" <humidity> {channel="jeelink:lacrosse:42:humidity"}
|
||||
Number:Temperature Temperature_LR "Living Room [%.1f %unit%]" <temperature> {channel="jeelink:lacrosse:42:temperature"}
|
||||
Contact Battery_Low_LR "Battery Low Living Room" {channel="jeelink:lacrosse:42:batteryLow"}
|
||||
Contact Battery_New_LR "Battery New Living Room" {channel="jeelink:lacrosse:42:batteryNew"}
|
||||
```
|
||||
|
||||
A typical item configuration for a PCA301 power monitoring wireless sockets looks like this:
|
||||
|
||||
```
|
||||
Switch SocketSwitch {channel="jeelink:pca301:1-160-236:switchingState"}
|
||||
Number:Power SocketWattage {channel="jeelink:pca301:1-160-236:currentPower"}
|
||||
Number:Energy SocketConsumption {channel="jeelink:pca301:1-160-236:consumptionTotal"}
|
||||
```
|
||||
|
||||
A typical item configuration for a TX22 temperature and humidity sensor looks like this:
|
||||
|
||||
```
|
||||
Number:Dimensionless Humidity "Outside [%.1f %unit%]" <humidity> {channel="jeelink:tx22:42:humidity"}
|
||||
Number:Temperature Temperature "Outside [%.1f %unit%]" <temperature> {channel="jeelink:tx22:42:temperature"}
|
||||
Contact Battery_Low_LR "Battery Low Outside" {channel="jeelink:tx22:42:batteryLow"}
|
||||
Contact Battery_New_LR "Battery New Outside" {channel="jeelink:tx22:42:batteryNew"}
|
||||
Number:Length Rain "Outside [%.1f %unit%]" {channel="jeelink:tx22:42:rain"}
|
||||
Number:Speed WindStrength "Wind [%.1f %unit%]" {channel="jeelink:tx22:42:windStrength"}
|
||||
Number:Angle WindDir "Wind dir [%.1f %unit%]" {channel="jeelink:tx22:42:windAngle"}
|
||||
Number:Speed GustStrength "Gust [%.1f %unit%]" {channel="jeelink:tx22:42:gustStrength"}
|
||||
```
|
||||
|
||||
A typical item configuration for a Revolt power monitor looks like this:
|
||||
|
||||
```
|
||||
Number:Power SocketWattage {channel="jeelink:revolt:4F1B:currentPower"}
|
||||
Number:Energy SocketConsumption {channel="jeelink:revolt:4F1B:consumptionTotal"}
|
||||
Number:Dimensionless POwerFactor {channel="jeelink:revolt:4F1B:powerFactor"}
|
||||
Number:ElectricCurrent Current {channel="jeelink:revolt:4F1B:electricCurrent"}
|
||||
Number:ElectricPotential Voltage {channel="jeelink:revolt:4F1B:electricPotential"}
|
||||
Number:Frequency PowerFrequency {channel="jeelink:revolt:4F1B:powerFrequency"}
|
||||
```
|
||||
|
||||
17
bundles/org.openhab.binding.jeelink/pom.xml
Normal file
17
bundles/org.openhab.binding.jeelink/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.jeelink</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: JeeLink Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.jeelink-${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-jeelink" description="Jeelink Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-serial</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.jeelink/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -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.jeelink.internal;
|
||||
|
||||
/**
|
||||
* Converter that simply ignores input.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class IgnoringConverter implements JeeLinkReadingConverter<Reading> {
|
||||
|
||||
@Override
|
||||
public Reading createReading(String inputLine) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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.jeelink.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* Defines common constants, which are used across the whole binding.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JeeLinkBindingConstants {
|
||||
|
||||
private JeeLinkBindingConstants() {
|
||||
}
|
||||
|
||||
public static final String BINDING_ID = "jeelink";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>();
|
||||
public static final Set<ThingTypeUID> SUPPORTED_SENSOR_THING_TYPES_UIDS = new HashSet<>();
|
||||
|
||||
public static final ThingTypeUID JEELINK_USB_STICK_THING_TYPE = new ThingTypeUID(BINDING_ID, "jeelinkUsb");
|
||||
public static final ThingTypeUID JEELINK_TCP_STICK_THING_TYPE = new ThingTypeUID(BINDING_ID, "jeelinkTcp");
|
||||
public static final ThingTypeUID LGW_USB_STICK_THING_TYPE = new ThingTypeUID(BINDING_ID, "lgwUsb");
|
||||
public static final ThingTypeUID LGW_TCP_STICK_THING_TYPE = new ThingTypeUID(BINDING_ID, "lgwTcp");
|
||||
public static final ThingTypeUID LACROSSE_SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, "lacrosse");
|
||||
public static final ThingTypeUID EC3000_SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, "ec3k");
|
||||
public static final ThingTypeUID PCA301_SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, "pca301");
|
||||
public static final ThingTypeUID TX22_SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, "tx22");
|
||||
public static final ThingTypeUID REVOLT_SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, "revolt");
|
||||
public static final ThingTypeUID LGW_SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, "lgw");
|
||||
|
||||
// List of all channel ids for lacrosse sensor things
|
||||
public static final String TEMPERATURE_CHANNEL = "temperature";
|
||||
public static final String HUMIDITY_CHANNEL = "humidity";
|
||||
public static final String BATTERY_NEW_CHANNEL = "batteryNew";
|
||||
public static final String BATTERY_LOW_CHANNEL = "batteryLow";
|
||||
|
||||
public static final String PROPERTY_SENSOR_ID = "sensorId";
|
||||
|
||||
// List of all additional channel ids for ec3k sensor things
|
||||
public static final String CURRENT_POWER_CHANNEL = "currentPower";
|
||||
public static final String MAX_POWER_CHANNEL = "maxPower";
|
||||
public static final String CONSUMPTION_CHANNEL = "consumptionTotal";
|
||||
public static final String APPLIANCE_TIME_CHANNEL = "applianceTime";
|
||||
public static final String SENSOR_TIME_CHANNEL = "sensorTime";
|
||||
public static final String RESETS_CHANNEL = "resets";
|
||||
|
||||
// List of all additional channel ids for pca301 sensor things
|
||||
public static final String SWITCHING_STATE_CHANNEL = "switchingState";
|
||||
|
||||
// List of all additional channel ids for revolt sensor things
|
||||
public static final String POWER_FACTOR_CHANNEL = "powerFactor";
|
||||
public static final String ELECTRIC_CURRENT_CHANNEL = "electricCurrent";
|
||||
public static final String ELECTRIC_POTENTIAL_CHANNEL = "electricPotential";
|
||||
public static final String FREQUENCY_CHANNEL = "powerFrequency";
|
||||
|
||||
// List of all additional channel ids for tx22 sensor things
|
||||
public static final String PRESSURE_CHANNEL = "pressure";
|
||||
public static final String RAIN_CHANNEL = "rain";
|
||||
public static final String WIND_STENGTH_CHANNEL = "windStrength";
|
||||
public static final String WIND_ANGLE_CHANNEL = "windAngle";
|
||||
public static final String GUST_STRENGTH_CHANNEL = "gustStrength";
|
||||
|
||||
static {
|
||||
for (SensorDefinition<?> def : SensorDefinition.getDefinitions()) {
|
||||
SUPPORTED_SENSOR_THING_TYPES_UIDS.add(def.getThingTypeUID());
|
||||
}
|
||||
|
||||
SUPPORTED_THING_TYPES_UIDS.add(JeeLinkBindingConstants.JEELINK_USB_STICK_THING_TYPE);
|
||||
SUPPORTED_THING_TYPES_UIDS.add(JeeLinkBindingConstants.JEELINK_TCP_STICK_THING_TYPE);
|
||||
SUPPORTED_THING_TYPES_UIDS.add(JeeLinkBindingConstants.LGW_USB_STICK_THING_TYPE);
|
||||
SUPPORTED_THING_TYPES_UIDS.add(JeeLinkBindingConstants.LGW_TCP_STICK_THING_TYPE);
|
||||
SUPPORTED_THING_TYPES_UIDS.addAll(SUPPORTED_SENSOR_THING_TYPES_UIDS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
/**
|
||||
* 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.jeelink.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.config.JeeLinkConfig;
|
||||
import org.openhab.binding.jeelink.internal.connection.ConnectionListener;
|
||||
import org.openhab.binding.jeelink.internal.connection.JeeLinkConnection;
|
||||
import org.openhab.binding.jeelink.internal.connection.JeeLinkSerialConnection;
|
||||
import org.openhab.binding.jeelink.internal.connection.JeeLinkTcpConnection;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
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.thing.binding.BridgeHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a JeeLink USB Receiver thing.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class JeeLinkHandler extends BaseBridgeHandler implements BridgeHandler, ConnectionListener {
|
||||
private final Logger logger = LoggerFactory.getLogger(JeeLinkHandler.class);
|
||||
|
||||
private final List<JeeLinkReadingConverter<?>> converters = new ArrayList<>();
|
||||
private final Map<String, JeeLinkReadingConverter<?>> sensorTypeConvertersMap = new HashMap<>();
|
||||
private final Map<Class<?>, Set<ReadingHandler<? extends Reading>>> readingClassHandlerMap = new HashMap<>();
|
||||
private final SerialPortManager serialPortManager;
|
||||
|
||||
private JeeLinkConnection connection;
|
||||
private AtomicBoolean connectionInitialized = new AtomicBoolean(false);
|
||||
private ScheduledFuture<?> connectJob;
|
||||
private ScheduledFuture<?> initJob;
|
||||
|
||||
private long lastReadingTime;
|
||||
private ScheduledFuture<?> monitorJob;
|
||||
|
||||
public JeeLinkHandler(Bridge bridge, SerialPortManager serialPortManager) {
|
||||
super(bridge);
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
JeeLinkConfig cfg = getConfig().as(JeeLinkConfig.class);
|
||||
|
||||
if (cfg.serialPort != null && cfg.baudRate != null) {
|
||||
SerialPortIdentifier serialPortIdentifier = serialPortManager.getIdentifier(cfg.serialPort);
|
||||
if (serialPortIdentifier == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Port not found: " + cfg.serialPort);
|
||||
return;
|
||||
}
|
||||
connection = new JeeLinkSerialConnection(serialPortIdentifier, cfg.baudRate, this);
|
||||
connection.openConnection();
|
||||
} else if (cfg.ipAddress != null && cfg.port != null) {
|
||||
connection = new JeeLinkTcpConnection(cfg.ipAddress + ":" + cfg.port, scheduler, this);
|
||||
connection.openConnection();
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Connection configuration incomplete");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionOpened() {
|
||||
logger.debug("Connection to port {} opened.", connection.getPort());
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
if (connectJob != null) {
|
||||
logger.debug("Connection to port {} established. Reconnect cancelled.", connection.getPort());
|
||||
connectJob.cancel(true);
|
||||
connectJob = null;
|
||||
}
|
||||
|
||||
JeeLinkConfig cfg = getConfig().as(JeeLinkConfig.class);
|
||||
initJob = scheduler.schedule(() -> {
|
||||
intializeConnection();
|
||||
}, cfg.initDelay, TimeUnit.SECONDS);
|
||||
|
||||
logger.debug("Init commands scheduled in {} seconds.", cfg.initDelay);
|
||||
|
||||
if (cfg.reconnectInterval > 0) {
|
||||
monitorJob = scheduler.scheduleWithFixedDelay(new Runnable() {
|
||||
private long lastMonitorTime;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (getThing().getStatus() == ThingStatus.ONLINE && lastReadingTime < lastMonitorTime) {
|
||||
logger.debug("Monitoring job for port {} detected missing readings. Triggering reconnect...",
|
||||
connection.getPort());
|
||||
|
||||
connection.closeConnection();
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
|
||||
connection.openConnection();
|
||||
}
|
||||
lastMonitorTime = System.currentTimeMillis();
|
||||
}
|
||||
}, cfg.reconnectInterval, cfg.reconnectInterval, TimeUnit.SECONDS);
|
||||
logger.debug("Monitoring job started.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
logger.debug("Connection to port {} closed.", connection.getPort());
|
||||
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
connectionInitialized.set(false);
|
||||
|
||||
if (initJob != null) {
|
||||
initJob.cancel(true);
|
||||
}
|
||||
if (monitorJob != null) {
|
||||
monitorJob.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionAborted(String cause) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, cause);
|
||||
|
||||
if (monitorJob != null) {
|
||||
monitorJob.cancel(true);
|
||||
}
|
||||
if (initJob != null) {
|
||||
initJob.cancel(true);
|
||||
}
|
||||
connectionInitialized.set(false);
|
||||
|
||||
connectJob = scheduler.schedule(() -> {
|
||||
connection.openConnection();
|
||||
}, 10, TimeUnit.SECONDS);
|
||||
logger.debug("Connection to port {} aborted ({}). Reconnect scheduled.", connection.getPort(), cause);
|
||||
}
|
||||
|
||||
public void addReadingHandler(ReadingHandler<? extends Reading> h) {
|
||||
synchronized (readingClassHandlerMap) {
|
||||
Set<ReadingHandler<? extends Reading>> handlers = readingClassHandlerMap.get(h.getReadingClass());
|
||||
if (handlers == null) {
|
||||
handlers = new HashSet<>();
|
||||
|
||||
// this is the first handler for this reading class => also setup converter
|
||||
readingClassHandlerMap.put(h.getReadingClass(), handlers);
|
||||
|
||||
if (SensorDefinition.ALL_TYPE == h.getSensorType()) {
|
||||
converters.addAll(SensorDefinition.getDiscoveryConverters());
|
||||
} else {
|
||||
JeeLinkReadingConverter<?> c = SensorDefinition.getConverter(h.getSensorType());
|
||||
if (c != null) {
|
||||
converters.add(c);
|
||||
sensorTypeConvertersMap.put(h.getSensorType(), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!handlers.contains(h)) {
|
||||
logger.debug("Adding reading handler for class {}: {}", h.getReadingClass(), h);
|
||||
|
||||
handlers.add(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeReadingHandler(ReadingHandler<? extends Reading> h) {
|
||||
synchronized (readingClassHandlerMap) {
|
||||
Set<ReadingHandler<? extends Reading>> handlers = readingClassHandlerMap.get(h.getReadingClass());
|
||||
if (handlers != null) {
|
||||
logger.debug("Removing reading handler for class {}: {}", h.getReadingClass(), h);
|
||||
handlers.remove(h);
|
||||
|
||||
if (handlers.isEmpty()) {
|
||||
// this was the last handler for this reading class => also remove converter
|
||||
readingClassHandlerMap.remove(h.getReadingClass());
|
||||
|
||||
if (SensorDefinition.ALL_TYPE == h.getSensorType()) {
|
||||
converters.removeAll(SensorDefinition.getDiscoveryConverters());
|
||||
} else {
|
||||
JeeLinkReadingConverter<?> c = SensorDefinition.getConverter(h.getSensorType());
|
||||
if (c != null) {
|
||||
converters.remove(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUid, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInput(String input) {
|
||||
lastReadingTime = System.currentTimeMillis();
|
||||
|
||||
// try all associated converters to find the correct one
|
||||
for (JeeLinkReadingConverter<?> c : converters) {
|
||||
Reading r = c.createReading(input);
|
||||
|
||||
if (r != null) {
|
||||
// this converter is responsible
|
||||
intializeConnection();
|
||||
|
||||
// propagate to the appropriate sensor handler
|
||||
synchronized (readingClassHandlerMap) {
|
||||
Set<ReadingHandler<? extends Reading>> handlers = getAllHandlers(r.getClass());
|
||||
|
||||
for (ReadingHandler h : handlers) {
|
||||
h.handleReading(r);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<ReadingHandler<? extends Reading>> getAllHandlers(Class<? extends Reading> readingClass) {
|
||||
Set<ReadingHandler<? extends Reading>> handlers = new HashSet<>();
|
||||
|
||||
Set<ReadingHandler<? extends Reading>> typeHandlers = readingClassHandlerMap.get(readingClass);
|
||||
if (typeHandlers != null) {
|
||||
handlers.addAll(typeHandlers);
|
||||
}
|
||||
Set<ReadingHandler<? extends Reading>> discoveryHandlers = readingClassHandlerMap.get(Reading.class);
|
||||
if (discoveryHandlers != null) {
|
||||
handlers.addAll(discoveryHandlers);
|
||||
}
|
||||
|
||||
return handlers;
|
||||
}
|
||||
|
||||
private void intializeConnection() {
|
||||
if (!connectionInitialized.getAndSet(true)) {
|
||||
JeeLinkConfig cfg = getConfig().as(JeeLinkConfig.class);
|
||||
|
||||
String initCommands = cfg.initCommands;
|
||||
if (initCommands != null && !initCommands.trim().isEmpty()) {
|
||||
logger.debug("Sending init commands for port {}: {}", connection.getPort(), initCommands);
|
||||
connection.sendCommands(initCommands);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (connectJob != null) {
|
||||
connectJob.cancel(true);
|
||||
connectJob = null;
|
||||
}
|
||||
|
||||
if (connection != null) {
|
||||
connection.closeConnection();
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
public JeeLinkConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* 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.jeelink.internal;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.discovery.SensorDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.io.transport.serial.SerialPortManager;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link JeeLinkHandlerFactory} is responsible for creating things and thing handlers.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.jeelink")
|
||||
public class JeeLinkHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final Logger logger = LoggerFactory.getLogger(JeeLinkHandlerFactory.class);
|
||||
|
||||
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
|
||||
private final SerialPortManager serialPortManager;
|
||||
|
||||
@Activate
|
||||
public JeeLinkHandlerFactory(final @Reference SerialPortManager serialPortManager) {
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUid) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUid = thing.getThingTypeUID();
|
||||
ThingHandler handler = null;
|
||||
|
||||
if (thingTypeUid.equals(JEELINK_USB_STICK_THING_TYPE) || thingTypeUid.equals(JEELINK_TCP_STICK_THING_TYPE)
|
||||
|| thingTypeUid.equals(LGW_TCP_STICK_THING_TYPE) || thingTypeUid.equals(LGW_USB_STICK_THING_TYPE)) {
|
||||
logger.debug("creating JeeLinkHandler for thing {}...", thing.getUID().getId());
|
||||
|
||||
handler = new JeeLinkHandler((Bridge) thing, serialPortManager);
|
||||
registerSensorDiscoveryService((JeeLinkHandler) handler);
|
||||
} else {
|
||||
handler = SensorDefinition.createHandler(thingTypeUid, thing);
|
||||
|
||||
if (handler == null) {
|
||||
logger.debug("skipping creation of unknown handler for thing {} with type {}...",
|
||||
thing.getUID().getId(), thing.getThingTypeUID().getId());
|
||||
}
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void removeHandler(ThingHandler thingHandler) {
|
||||
if (thingHandler instanceof JeeLinkHandler) {
|
||||
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.remove(thingHandler.getThing().getUID());
|
||||
if (serviceReg != null) {
|
||||
serviceReg.unregister();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void registerSensorDiscoveryService(JeeLinkHandler bridgeHandler) {
|
||||
logger.debug("registering sensor discovery service...");
|
||||
SensorDiscoveryService discoveryService = new SensorDiscoveryService(bridgeHandler);
|
||||
discoveryServiceRegs.put(bridgeHandler.getThing().getUID(),
|
||||
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal;
|
||||
|
||||
/**
|
||||
* Interface for converting input read from a JeeLinkConnection to a Reading.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public interface JeeLinkReadingConverter<R extends Reading> {
|
||||
public R createReading(String inputLine);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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.jeelink.internal;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.config.JeeLinkSensorConfig;
|
||||
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.types.Command;
|
||||
|
||||
/**
|
||||
* Abstract thing handler for sensors connected to a JeeLink.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public abstract class JeeLinkSensorHandler<R extends Reading> extends BaseThingHandler implements ReadingHandler<R> {
|
||||
protected String id;
|
||||
protected final String sensorType;
|
||||
|
||||
private ReadingPublisher<R> publisher;
|
||||
private long secsSinceLastReading;
|
||||
private ScheduledFuture<?> statusUpdateJob;
|
||||
|
||||
public JeeLinkSensorHandler(Thing thing, String sensorType) {
|
||||
super(thing);
|
||||
this.sensorType = sensorType;
|
||||
}
|
||||
|
||||
public abstract ReadingPublisher<R> createPublisher();
|
||||
|
||||
@Override
|
||||
public String getSensorType() {
|
||||
return sensorType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReading(R r) {
|
||||
if (r != null && id.equals(r.getSensorId())) {
|
||||
secsSinceLastReading = 0;
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
if (publisher != null) {
|
||||
publisher.publish(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void handleCommand(ChannelUID channelUid, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void initialize() {
|
||||
JeeLinkHandler jlh = (JeeLinkHandler) getBridge().getHandler();
|
||||
jlh.addReadingHandler(this);
|
||||
|
||||
JeeLinkSensorConfig cfg = getConfigAs(JeeLinkSensorConfig.class);
|
||||
id = cfg.sensorId;
|
||||
|
||||
statusUpdateJob = createStatusUpdateJob(scheduler, cfg.sensorTimeout);
|
||||
|
||||
publisher = createPublisher();
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void dispose() {
|
||||
id = null;
|
||||
|
||||
JeeLinkHandler jlh = (JeeLinkHandler) getBridge().getHandler();
|
||||
jlh.removeReadingHandler(this);
|
||||
|
||||
if (statusUpdateJob != null) {
|
||||
statusUpdateJob.cancel(true);
|
||||
statusUpdateJob = null;
|
||||
}
|
||||
|
||||
if (publisher != null) {
|
||||
publisher.dispose();
|
||||
publisher = null;
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private ScheduledFuture<?> createStatusUpdateJob(ScheduledExecutorService execService, final int sensorTimeout) {
|
||||
return execService.scheduleWithFixedDelay(() -> {
|
||||
if (secsSinceLastReading++ > sensorTimeout) {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
}, sensorTimeout, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal;
|
||||
|
||||
/**
|
||||
* Interface for a Reading from a Sensor. Addiionally provided basic arithmetic operations needed
|
||||
* for computing average values for readings.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public interface Reading {
|
||||
/**
|
||||
* @return the sensor ID of the sensor that provided this reading.
|
||||
*/
|
||||
String getSensorId();
|
||||
}
|
||||
@@ -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.jeelink.internal;
|
||||
|
||||
/**
|
||||
* Interface for classes that handle Readings.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public interface ReadingHandler<R extends Reading> {
|
||||
public void handleReading(R r);
|
||||
|
||||
public Class<R> getReadingClass();
|
||||
|
||||
public String getSensorType();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.jeelink.internal;
|
||||
|
||||
/**
|
||||
* Interface for classes that publish readings.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public interface ReadingPublisher<R extends Reading> {
|
||||
public void publish(R reading);
|
||||
|
||||
public void dispose();
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.jeelink.internal;
|
||||
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Computes a rolling average of readings that is passed on to the next publisher
|
||||
* after a given time frame.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public abstract class RollingAveragePublisher<R extends Reading> implements ReadingPublisher<R> {
|
||||
private final ReadingPublisher<R> publisher;
|
||||
|
||||
private ScheduledFuture<?> valueUpdateJob;
|
||||
private RollingReadingAverage<R> rollingAvg;
|
||||
|
||||
public RollingAveragePublisher(int bufferSize, int interval, ReadingPublisher<R> p,
|
||||
ScheduledExecutorService execService) {
|
||||
publisher = p;
|
||||
|
||||
valueUpdateJob = createUpdateJob(execService, interval);
|
||||
rollingAvg = createRollingReadingAverage(bufferSize);
|
||||
}
|
||||
|
||||
public abstract RollingReadingAverage<R> createRollingReadingAverage(int bufferSize);
|
||||
|
||||
@Override
|
||||
public void publish(R reading) {
|
||||
rollingAvg.add(reading);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (valueUpdateJob != null) {
|
||||
valueUpdateJob.cancel(true);
|
||||
valueUpdateJob = null;
|
||||
}
|
||||
|
||||
publisher.dispose();
|
||||
}
|
||||
|
||||
private ScheduledFuture<?> createUpdateJob(ScheduledExecutorService execService, final int updateInterval) {
|
||||
return execService.scheduleWithFixedDelay(() -> {
|
||||
publisher.publish(rollingAvg.getAverage());
|
||||
}, updateInterval, updateInterval, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal;
|
||||
|
||||
/**
|
||||
* Computes a rolling average of readings.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public abstract class RollingReadingAverage<R extends Reading> {
|
||||
private int size = 0;
|
||||
private int maxSize;
|
||||
private R total = null;
|
||||
private int index = 0;
|
||||
private R[] samples;
|
||||
|
||||
public RollingReadingAverage(R[] array) {
|
||||
maxSize = array.length;
|
||||
samples = array;
|
||||
}
|
||||
|
||||
public void add(R reading) {
|
||||
if (size < maxSize) {
|
||||
size++;
|
||||
}
|
||||
|
||||
if (total == null) {
|
||||
total = reading;
|
||||
} else {
|
||||
total = add(total, reading);
|
||||
total = substract(total, samples[index]);
|
||||
}
|
||||
|
||||
samples[index] = reading;
|
||||
if (++index == maxSize) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public R getAverage() {
|
||||
if (total == null) {
|
||||
return null;
|
||||
}
|
||||
return divide(total, size);
|
||||
}
|
||||
|
||||
protected abstract R add(R value1, R value2);
|
||||
|
||||
protected abstract R substract(R from, R value);
|
||||
|
||||
protected abstract R divide(R value, int count);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 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.jeelink.internal;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.ec3k.Ec3kSensorDefinition;
|
||||
import org.openhab.binding.jeelink.internal.lacrosse.LaCrosseSensorDefinition;
|
||||
import org.openhab.binding.jeelink.internal.lacrosse.LgwSensorDefinition;
|
||||
import org.openhab.binding.jeelink.internal.lacrosse.Tx22SensorDefinition;
|
||||
import org.openhab.binding.jeelink.internal.pca301.Pca301SensorDefinition;
|
||||
import org.openhab.binding.jeelink.internal.revolt.RevoltSensorDefinition;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
|
||||
/**
|
||||
* Base class for sensor definitions.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*
|
||||
* @param <R> the Reading type this sensor provides.
|
||||
*/
|
||||
public abstract class SensorDefinition<R extends Reading> {
|
||||
public static final String ALL_TYPE = "All";
|
||||
|
||||
private static final Set<SensorDefinition<?>> SENSOR_DEFS = Stream
|
||||
.of(new LaCrosseSensorDefinition(), new Ec3kSensorDefinition(), new Pca301SensorDefinition(),
|
||||
new Tx22SensorDefinition(), new RevoltSensorDefinition(), new LgwSensorDefinition())
|
||||
.collect(Collectors.toSet());
|
||||
private static final Set<JeeLinkReadingConverter<?>> CONVERTERS = SENSOR_DEFS.stream()
|
||||
.map(SensorDefinition::createConverter).collect(Collectors.toSet());
|
||||
|
||||
protected final String type;
|
||||
|
||||
final ThingTypeUID thingTypeUid;
|
||||
final String name;
|
||||
|
||||
public SensorDefinition(ThingTypeUID thingTypeUid, String name, String type) {
|
||||
this.thingTypeUid = thingTypeUid;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ThingTypeUID getThingTypeUID() {
|
||||
return thingTypeUid;
|
||||
}
|
||||
|
||||
public abstract Class<R> getReadingClass();
|
||||
|
||||
public abstract JeeLinkSensorHandler<R> createHandler(Thing thing);
|
||||
|
||||
public abstract JeeLinkReadingConverter<R> createConverter();
|
||||
|
||||
public static SensorDefinition<?> getSensorDefinition(Reading reading) {
|
||||
for (SensorDefinition<?> sensor : SENSOR_DEFS) {
|
||||
if (sensor.getReadingClass().equals(reading.getClass())) {
|
||||
return sensor;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Set<SensorDefinition<?>> getDefinitions() {
|
||||
return SENSOR_DEFS;
|
||||
}
|
||||
|
||||
public static ThingHandler createHandler(ThingTypeUID thingTypeUid, Thing thing) {
|
||||
for (SensorDefinition<?> sensor : SENSOR_DEFS) {
|
||||
if (sensor.getThingTypeUID().equals(thingTypeUid)) {
|
||||
return sensor.createHandler(thing);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JeeLinkReadingConverter<?> getConverter(String sensorType) {
|
||||
for (SensorDefinition<?> sensor : SENSOR_DEFS) {
|
||||
if (sensor.getSensorType().equals(sensorType)) {
|
||||
return sensor.createConverter();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Set<JeeLinkReadingConverter<?>> getDiscoveryConverters() {
|
||||
return CONVERTERS;
|
||||
}
|
||||
|
||||
private String getSensorType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.jeelink.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration for a Handler that is able to buffer values.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class BufferedSensorConfig extends JeeLinkSensorConfig {
|
||||
public int updateInterval;
|
||||
public int bufferSize;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.jeelink.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration for a JeeLinkHandler.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class JeeLinkConfig {
|
||||
public String ipAddress;
|
||||
public Integer port;
|
||||
public String serialPort;
|
||||
public Integer baudRate;
|
||||
public String initCommands;
|
||||
public Integer initDelay;
|
||||
public Integer reconnectInterval;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.jeelink.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration for a JeeLinkSensorHandler.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class JeeLinkSensorConfig {
|
||||
public String sensorId;
|
||||
public int sensorTimeout;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.jeelink.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration for a LaCrossTemperatureSensorHandler.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LaCrosseTemperatureSensorConfig extends BufferedSensorConfig {
|
||||
public float minTemp;
|
||||
public float maxTemp;
|
||||
public float maxDiff;
|
||||
}
|
||||
@@ -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.jeelink.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration for a Pca301SensorHandler.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Pca301SensorConfig extends JeeLinkSensorConfig {
|
||||
public int sendCount;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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.jeelink.internal.connection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract base class for a connection to a JeeLink.
|
||||
* Manages ReadingListeners, finds out the sketch name and allows to propagate read lines.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public abstract class AbstractJeeLinkConnection implements JeeLinkConnection {
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractJeeLinkConnection.class);
|
||||
|
||||
protected final ConnectionListener connectionListener;
|
||||
|
||||
protected String port;
|
||||
|
||||
private AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
public AbstractJeeLinkConnection(String port, ConnectionListener listener) {
|
||||
this.port = port;
|
||||
connectionListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the stream that can be used to write the init commands to the receiver.
|
||||
*/
|
||||
protected abstract OutputStream getInitStream() throws IOException;
|
||||
|
||||
protected void notifyOpen() {
|
||||
connectionListener.connectionOpened();
|
||||
}
|
||||
|
||||
protected void notifyClosed() {
|
||||
connectionListener.connectionClosed();
|
||||
}
|
||||
|
||||
protected void notifyAbort(String cause) {
|
||||
connectionListener.connectionAborted(cause);
|
||||
initialized.set(false);
|
||||
}
|
||||
|
||||
public void propagateLine(String line) throws IOException {
|
||||
logger.trace("Read line from port {}: {}", port, line);
|
||||
|
||||
connectionListener.handleInput(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendCommands(String commands) {
|
||||
try {
|
||||
if (commands != null && !commands.trim().isEmpty()) {
|
||||
// do not create in try-with-resources as this will
|
||||
// close the undelying socket for TCP connections
|
||||
OutputStream initStream = getInitStream();
|
||||
if (initStream == null) {
|
||||
throw new IOException(
|
||||
"Connection on port " + port + " did not provide an init stream for writing init commands");
|
||||
}
|
||||
|
||||
// do not close the writer as this closes the underlying stream, and
|
||||
// in case of tcp connections, the underlying socket
|
||||
OutputStreamWriter w = new OutputStreamWriter(initStream);
|
||||
for (String cmd : commands.split(";")) {
|
||||
logger.debug("Writing to device on port {}: {} ", port, cmd);
|
||||
|
||||
w.write(cmd + "\n");
|
||||
}
|
||||
w.flush();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.debug("Error writing to output stream!", ex);
|
||||
closeConnection();
|
||||
notifyAbort("propagate: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.jeelink.internal.connection;
|
||||
|
||||
/**
|
||||
* Listener that is notified on connection status changes of JeeLinkConnections
|
||||
* as well as when input has been read from the connection.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public interface ConnectionListener {
|
||||
/**
|
||||
* Called when the connection has been opened.
|
||||
*/
|
||||
void connectionOpened();
|
||||
|
||||
/**
|
||||
* Called when the connection has been closed.
|
||||
*/
|
||||
void connectionClosed();
|
||||
|
||||
/**
|
||||
* Called when the connection has been aborted.
|
||||
*
|
||||
* @param cause a text describing the cause of the abort.
|
||||
*/
|
||||
void connectionAborted(String cause);
|
||||
|
||||
/**
|
||||
* Called whenever input has been read from the connection.
|
||||
*/
|
||||
public void handleInput(String input);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.jeelink.internal.connection;
|
||||
|
||||
/**
|
||||
* Interface for connections to JeeLink USB Receivers.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public interface JeeLinkConnection {
|
||||
/**
|
||||
* closes the connection to the receiver.
|
||||
*/
|
||||
void closeConnection();
|
||||
|
||||
/**
|
||||
* opens the connection to the receiver.
|
||||
*/
|
||||
void openConnection();
|
||||
|
||||
/**
|
||||
* returns port to which the receiver is connected.
|
||||
*/
|
||||
String getPort();
|
||||
|
||||
/**
|
||||
* sends the specified commands to the receiver (commands are semicolon separated)
|
||||
*/
|
||||
void sendCommands(String initCommands);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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.jeelink.internal.connection;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.util.TooManyListenersException;
|
||||
|
||||
import org.openhab.core.io.transport.serial.PortInUseException;
|
||||
import org.openhab.core.io.transport.serial.SerialPort;
|
||||
import org.openhab.core.io.transport.serial.SerialPortEvent;
|
||||
import org.openhab.core.io.transport.serial.SerialPortEventListener;
|
||||
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
|
||||
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Reads lines from serial port and propagates them to registered InputListeners.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class JeeLinkSerialConnection extends AbstractJeeLinkConnection {
|
||||
private final Logger logger = LoggerFactory.getLogger(JeeLinkSerialConnection.class);
|
||||
|
||||
private final int baudRate;
|
||||
private SerialPort serialPort;
|
||||
private final SerialPortIdentifier serialPortIdentifier;
|
||||
private boolean open;
|
||||
|
||||
public JeeLinkSerialConnection(SerialPortIdentifier serialPortIdentifier, int baudRate,
|
||||
ConnectionListener listener) {
|
||||
super(serialPortIdentifier.getName(), listener);
|
||||
|
||||
logger.debug("Creating serial connection for port {} with baud rate {}...", port, baudRate);
|
||||
this.baudRate = baudRate;
|
||||
this.serialPortIdentifier = serialPortIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeConnection() {
|
||||
if (open) {
|
||||
logger.debug("Closing serial connection to port {}...", port);
|
||||
|
||||
serialPort.notifyOnDataAvailable(false);
|
||||
serialPort.removeEventListener();
|
||||
|
||||
serialPort.close();
|
||||
notifyClosed();
|
||||
open = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void openConnection() {
|
||||
try {
|
||||
if (!open) {
|
||||
logger.debug("Opening serial connection to port {} with baud rate {}...", port, baudRate);
|
||||
serialPort = serialPortIdentifier.open("openhab", 3000);
|
||||
open = true;
|
||||
|
||||
serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
|
||||
SerialPort.PARITY_NONE);
|
||||
|
||||
final BufferedReader input = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
|
||||
|
||||
serialPort.addEventListener(new SerialPortEventListener() {
|
||||
@Override
|
||||
public void serialEvent(SerialPortEvent event) {
|
||||
try {
|
||||
if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
|
||||
propagateLine(input.readLine());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.debug("Error reading from serial port!", ex);
|
||||
closeConnection();
|
||||
notifyAbort("propagate: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
serialPort.notifyOnDataAvailable(true);
|
||||
notifyOpen();
|
||||
}
|
||||
} catch (UnsupportedCommOperationException | IOException | TooManyListenersException ex) {
|
||||
closeConnection();
|
||||
notifyAbort(ex.getMessage());
|
||||
} catch (PortInUseException ex) {
|
||||
notifyAbort("Port in use: " + port);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getInitStream() throws IOException {
|
||||
return open ? serialPort.getOutputStream() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* 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.jeelink.internal.connection;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Reads lines from TCP port and propagates them to registered InputListeners.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class JeeLinkTcpConnection extends AbstractJeeLinkConnection {
|
||||
private static final Pattern IP_PORT_PATTERN = Pattern.compile("([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):([0-9]+)");
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(JeeLinkTcpConnection.class);
|
||||
|
||||
private ScheduledExecutorService scheduler;
|
||||
private Reader reader;
|
||||
private Socket socket;
|
||||
|
||||
public JeeLinkTcpConnection(String port, ScheduledExecutorService scheduler, ConnectionListener l) {
|
||||
super(port, l);
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeConnection() {
|
||||
if (reader != null) {
|
||||
logger.debug("Closing TCP connection to port {}...", port);
|
||||
reader.close();
|
||||
reader = null;
|
||||
closeSocketSilently();
|
||||
socket = null;
|
||||
notifyClosed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void openConnection() {
|
||||
if (reader != null) {
|
||||
logger.debug("TCP connection to port {} is already open!", port);
|
||||
return;
|
||||
}
|
||||
|
||||
Matcher ipm = IP_PORT_PATTERN.matcher(port);
|
||||
if (!ipm.matches()) {
|
||||
notifyAbort("Invalid TCP port specification: " + port);
|
||||
}
|
||||
|
||||
String hostName = ipm.group(1);
|
||||
int portNumber = Integer.parseInt(ipm.group(2));
|
||||
|
||||
logger.debug("Opening TCP connection to host {} port {}...", hostName, portNumber);
|
||||
try {
|
||||
logger.debug("Creating TCP socket to {}...", port);
|
||||
socket = new Socket(hostName, portNumber);
|
||||
socket.setKeepAlive(true);
|
||||
logger.debug("TCP socket created.");
|
||||
|
||||
reader = new Reader(socket);
|
||||
scheduler.execute(reader);
|
||||
|
||||
notifyOpen();
|
||||
} catch (IOException ex) {
|
||||
if (socket != null) {
|
||||
closeSocketSilently();
|
||||
}
|
||||
|
||||
notifyAbort(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void closeSocketSilently() {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to close socket.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getInitStream() throws IOException {
|
||||
return socket == null ? null : socket.getOutputStream();
|
||||
}
|
||||
|
||||
private class Reader implements Runnable {
|
||||
private Socket socket;
|
||||
private BufferedReader inputReader;
|
||||
private volatile boolean isRunning = true;
|
||||
|
||||
private Reader(Socket socket) throws IOException {
|
||||
this.socket = socket;
|
||||
inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String line;
|
||||
logger.debug("Reader for TCP port {} starting...", port);
|
||||
try {
|
||||
while (isRunning) {
|
||||
line = inputReader.readLine();
|
||||
|
||||
if (line == null) {
|
||||
throw new IOException("Got EOF on port " + port);
|
||||
}
|
||||
|
||||
propagateLine(line);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
if (isRunning) {
|
||||
closeConnection();
|
||||
notifyAbort(ex.getMessage());
|
||||
}
|
||||
} finally {
|
||||
logger.debug("Reader for TCP port {} finished...", port);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
logger.debug("Shutting down reader for TCP port {}...", port);
|
||||
try {
|
||||
isRunning = false;
|
||||
socket.close();
|
||||
inputReader.close();
|
||||
} catch (IOException ex) {
|
||||
logger.debug("Failed to close TCP port {}!", port, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* 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.jeelink.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkHandler;
|
||||
import org.openhab.binding.jeelink.internal.Reading;
|
||||
import org.openhab.binding.jeelink.internal.ReadingHandler;
|
||||
import org.openhab.binding.jeelink.internal.SensorDefinition;
|
||||
import org.openhab.binding.jeelink.internal.config.JeeLinkSensorConfig;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Discovery service for sensors connected to a JeeLink USB Receiver.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class SensorDiscoveryService extends AbstractDiscoveryService implements ReadingHandler<Reading> {
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 30;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SensorDiscoveryService.class);
|
||||
|
||||
JeeLinkHandler bridge;
|
||||
AtomicBoolean capture = new AtomicBoolean();
|
||||
|
||||
/**
|
||||
* Creates the discovery service for the given handler and converter.
|
||||
*/
|
||||
public SensorDiscoveryService(JeeLinkHandler jeeLinkHandler) {
|
||||
super(SUPPORTED_SENSOR_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS, true);
|
||||
|
||||
bridge = jeeLinkHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void startScan() {
|
||||
if (!capture.getAndSet(true)) {
|
||||
logger.debug("discovery started for bridge {}", bridge.getThing().getUID());
|
||||
|
||||
// start listening for new sensor values
|
||||
bridge.addReadingHandler(this);
|
||||
capture.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
startScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
if (capture.getAndSet(false)) {
|
||||
bridge.removeReadingHandler(this);
|
||||
logger.debug("discovery stopped for bridge {}", bridge.getThing().getUID());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
stopScan();
|
||||
}
|
||||
|
||||
private boolean idExistsAtBridge(String id) {
|
||||
List<Thing> existingThings = bridge.getThing().getThings();
|
||||
boolean idExists = false;
|
||||
for (Thing t : existingThings) {
|
||||
idExists = idExists || t.getUID().getId().equals(id);
|
||||
}
|
||||
return idExists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReading(Reading reading) {
|
||||
final String id = reading.getSensorId();
|
||||
|
||||
List<Thing> existingThings = bridge.getThing().getThings();
|
||||
boolean sensorThingExists = false;
|
||||
|
||||
for (Thing t : existingThings) {
|
||||
sensorThingExists = sensorThingExists
|
||||
|| id.equals(t.getConfiguration().as(JeeLinkSensorConfig.class).sensorId);
|
||||
}
|
||||
|
||||
ThingUID bridgeUID = bridge.getThing().getUID();
|
||||
|
||||
if (!sensorThingExists) {
|
||||
SensorDefinition<?> def = SensorDefinition.getSensorDefinition(reading);
|
||||
logger.debug("discovery for bridge {} found unknown sensor of type {} with id {}", bridgeUID,
|
||||
def.getThingTypeUID(), id);
|
||||
|
||||
boolean idExists = idExistsAtBridge(id);
|
||||
String newId = id;
|
||||
|
||||
if (idExists) {
|
||||
logger.debug("bridge {} already has a connected sensor with thing id {}", bridgeUID, id);
|
||||
|
||||
int idx = 1;
|
||||
while (idExists) {
|
||||
newId = id + "-" + idx++;
|
||||
idExists = idExistsAtBridge(newId);
|
||||
}
|
||||
|
||||
logger.debug("Bridge {} uses thing id {} instead of {}", bridgeUID, newId, id);
|
||||
}
|
||||
|
||||
ThingUID sensorThing = new ThingUID(def.getThingTypeUID(), bridgeUID, newId);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(sensorThing).withLabel(def.getName())
|
||||
.withBridge(bridgeUID).withRepresentationProperty("id").withProperty(PROPERTY_SENSOR_ID, id)
|
||||
.build();
|
||||
thingDiscovered(discoveryResult);
|
||||
} else {
|
||||
logger.debug("discovery for bridge {} found already known sensor id {}", bridgeUID, id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Reading> getReadingClass() {
|
||||
return Reading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSensorType() {
|
||||
return SensorDefinition.ALL_TYPE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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.jeelink.internal.ec3k;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.Reading;
|
||||
|
||||
/**
|
||||
* Reading of a EC3000 sensor.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Ec3kReading implements Reading {
|
||||
private float currentWatt;
|
||||
private float maxWatt;
|
||||
private long consumptionTotal;
|
||||
private long applianceTime;
|
||||
private long sensorTime;
|
||||
private String sensorId;
|
||||
private int resets;
|
||||
|
||||
public Ec3kReading(String sensorId, float currentWatt, float maxWatt, long consumptionTotal, long applianceTime,
|
||||
long sensorTime, int resets) {
|
||||
this.currentWatt = currentWatt;
|
||||
this.maxWatt = maxWatt;
|
||||
this.consumptionTotal = consumptionTotal;
|
||||
this.applianceTime = applianceTime;
|
||||
this.sensorTime = sensorTime;
|
||||
this.sensorId = sensorId;
|
||||
this.resets = resets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "sensorId=" + sensorId + ": currWatt=" + currentWatt + ", maxWatt=" + maxWatt + ", consumption="
|
||||
+ consumptionTotal + ", applianceTime=" + applianceTime + ", sensorTime=" + sensorTime + ", resets="
|
||||
+ resets;
|
||||
}
|
||||
|
||||
public float getCurrentWatt() {
|
||||
return currentWatt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
public float getMaxWatt() {
|
||||
return maxWatt;
|
||||
}
|
||||
|
||||
public long getConsumptionTotal() {
|
||||
return consumptionTotal;
|
||||
}
|
||||
|
||||
public long getApplianceTime() {
|
||||
return applianceTime;
|
||||
}
|
||||
|
||||
public long getSensorTime() {
|
||||
return sensorTime;
|
||||
}
|
||||
|
||||
public int getResets() {
|
||||
return resets;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.jeelink.internal.ec3k;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
|
||||
/**
|
||||
* Converter for converting a line read from a ec3kSerial sketch to a Ec3kReading.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Ec3kReadingConverter implements JeeLinkReadingConverter<Ec3kReading> {
|
||||
private static final Pattern LINE_P = Pattern
|
||||
.compile("OK\\s+22\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)"
|
||||
+ "\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)"
|
||||
+ "\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)");
|
||||
|
||||
@Override
|
||||
public Ec3kReading createReading(String inputLine) {
|
||||
if (inputLine != null) {
|
||||
Matcher matcher = LINE_P.matcher(inputLine);
|
||||
if (matcher.matches()) {
|
||||
/*
|
||||
* OK 22 188 129 0 209 209 102 0 174 89 187 0 1 123 102 0 0 10 117 2 0 (ID = BC81)
|
||||
*/
|
||||
long id1 = Long.parseLong(matcher.group(1));
|
||||
long id2 = Long.parseLong(matcher.group(2));
|
||||
String id = String.format("%02X%02X", id1, id2);
|
||||
|
||||
long secTot1 = Long.parseLong(matcher.group(3));
|
||||
long secTot2 = Long.parseLong(matcher.group(4));
|
||||
long secTot3 = Long.parseLong(matcher.group(5));
|
||||
long secTot4 = Long.parseLong(matcher.group(6));
|
||||
long secondsTotal = (secTot1 << 24) + (secTot2 << 16) + (secTot3 << 8) + secTot4;
|
||||
|
||||
long secOn1 = Long.parseLong(matcher.group(7));
|
||||
long secOn2 = Long.parseLong(matcher.group(8));
|
||||
long secOn3 = Long.parseLong(matcher.group(9));
|
||||
long secOn4 = Long.parseLong(matcher.group(10));
|
||||
long secondsOn = (secOn1 << 24) + (secOn2 << 16) + (secOn3 << 8) + secOn4;
|
||||
|
||||
long con1 = Long.parseLong(matcher.group(11));
|
||||
long con2 = Long.parseLong(matcher.group(12));
|
||||
long con3 = Long.parseLong(matcher.group(13));
|
||||
long con4 = Long.parseLong(matcher.group(14));
|
||||
long consumptionTotal = ((con1 << 24) + (con2 << 16) + (con3 << 8) + con4) / 1000;
|
||||
|
||||
long cur1 = Long.parseLong(matcher.group(15));
|
||||
long cur2 = Long.parseLong(matcher.group(16));
|
||||
float currentWatt = ((cur1 << 8) + cur2) / 10f;
|
||||
|
||||
long max1 = Long.parseLong(matcher.group(17));
|
||||
long max2 = Long.parseLong(matcher.group(18));
|
||||
float maxWatt = ((max1 << 8) + max2) / 10f;
|
||||
|
||||
int resets = Integer.parseInt(matcher.group(19));
|
||||
return new Ec3kReading(id, currentWatt, maxWatt, consumptionTotal, secondsOn, secondsTotal, resets);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.jeelink.internal.ec3k;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.RollingReadingAverage;
|
||||
|
||||
/**
|
||||
* Computes a rolling average of readings.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Ec3kRollingReadingAverage extends RollingReadingAverage<Ec3kReading> {
|
||||
public Ec3kRollingReadingAverage(int bufferSize) {
|
||||
super(new Ec3kReading[bufferSize]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Ec3kReading add(Ec3kReading value1, Ec3kReading value2) {
|
||||
if (value2 != null) {
|
||||
return new Ec3kReading(value2.getSensorId(), value1.getCurrentWatt() + value2.getCurrentWatt(),
|
||||
value2.getMaxWatt(), value2.getConsumptionTotal(), value2.getApplianceTime(),
|
||||
value2.getSensorTime(), value2.getResets());
|
||||
}
|
||||
|
||||
return new Ec3kReading(value1.getSensorId(), value1.getCurrentWatt(), value1.getMaxWatt(),
|
||||
value1.getConsumptionTotal(), value1.getApplianceTime(), value1.getSensorTime(), value1.getResets());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Ec3kReading substract(Ec3kReading from, Ec3kReading value) {
|
||||
float newCurrWatt = from.getCurrentWatt();
|
||||
|
||||
if (value != null) {
|
||||
newCurrWatt -= value.getCurrentWatt();
|
||||
}
|
||||
|
||||
return new Ec3kReading(from.getSensorId(), newCurrWatt, from.getMaxWatt(), from.getConsumptionTotal(),
|
||||
from.getApplianceTime(), from.getSensorTime(), from.getResets());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Ec3kReading divide(Ec3kReading value, int number) {
|
||||
return new Ec3kReading(value.getSensorId(), value.getCurrentWatt() / number, value.getMaxWatt(),
|
||||
value.getConsumptionTotal(), value.getApplianceTime(), value.getSensorTime(), value.getResets());
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.ec3k;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkBindingConstants;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.SensorDefinition;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Sensor Defintion of a EC3000 Power Monitor.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Ec3kSensorDefinition extends SensorDefinition<Ec3kReading> {
|
||||
|
||||
public Ec3kSensorDefinition() {
|
||||
super(JeeLinkBindingConstants.EC3000_SENSOR_THING_TYPE, "EnergyCount 3000 Power Monitor", "22");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkReadingConverter<Ec3kReading> createConverter() {
|
||||
return new Ec3kReadingConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Ec3kReading> getReadingClass() {
|
||||
return Ec3kReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkSensorHandler<Ec3kReading> createHandler(Thing thing) {
|
||||
return new Ec3kSensorHandler(thing, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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.jeelink.internal.ec3k;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
import org.openhab.binding.jeelink.internal.RollingAveragePublisher;
|
||||
import org.openhab.binding.jeelink.internal.RollingReadingAverage;
|
||||
import org.openhab.binding.jeelink.internal.config.BufferedSensorConfig;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a EC3000 sensor thing.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Ec3kSensorHandler extends JeeLinkSensorHandler<Ec3kReading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(Ec3kSensorHandler.class);
|
||||
|
||||
public Ec3kSensorHandler(Thing thing, String sensorType) {
|
||||
super(thing, sensorType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Ec3kReading> getReadingClass() {
|
||||
return Ec3kReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingPublisher<Ec3kReading> createPublisher() {
|
||||
ReadingPublisher<Ec3kReading> publisher = new ReadingPublisher<Ec3kReading>() {
|
||||
@Override
|
||||
public void publish(Ec3kReading reading) {
|
||||
if (reading != null && getThing().getStatus() == ThingStatus.ONLINE) {
|
||||
BigDecimal currentWatt = new BigDecimal(reading.getCurrentWatt()).setScale(1, RoundingMode.HALF_UP);
|
||||
BigDecimal maxWatt = new BigDecimal(reading.getMaxWatt()).setScale(1, RoundingMode.HALF_UP);
|
||||
|
||||
logger.debug(
|
||||
"updating states for thing {}: currWatt={} ({}), maxWatt={}, consumption={}, secondsOn={}, secondsTotal={}",
|
||||
getThing().getUID().getId(), currentWatt, reading.getCurrentWatt(), maxWatt,
|
||||
reading.getConsumptionTotal(), reading.getApplianceTime(), reading.getSensorTime());
|
||||
|
||||
updateState(CURRENT_POWER_CHANNEL, new QuantityType<>(currentWatt, SmartHomeUnits.WATT));
|
||||
updateState(MAX_POWER_CHANNEL, new QuantityType<>(maxWatt, SmartHomeUnits.WATT));
|
||||
updateState(CONSUMPTION_CHANNEL,
|
||||
new QuantityType<>(reading.getConsumptionTotal(), SmartHomeUnits.WATT_HOUR));
|
||||
updateState(APPLIANCE_TIME_CHANNEL,
|
||||
new QuantityType<>(reading.getApplianceTime(), SmartHomeUnits.HOUR));
|
||||
updateState(SENSOR_TIME_CHANNEL, new QuantityType<>(reading.getSensorTime(), SmartHomeUnits.HOUR));
|
||||
updateState(RESETS_CHANNEL, new DecimalType(reading.getResets()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
|
||||
BufferedSensorConfig cfg = getConfigAs(BufferedSensorConfig.class);
|
||||
if (cfg.bufferSize > 1 && cfg.updateInterval > 0) {
|
||||
publisher = new RollingAveragePublisher<Ec3kReading>(cfg.bufferSize, cfg.updateInterval, publisher,
|
||||
scheduler) {
|
||||
@Override
|
||||
public RollingReadingAverage<Ec3kReading> createRollingReadingAverage(int bufferSize) {
|
||||
return new Ec3kRollingReadingAverage(bufferSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Checks that the given temperature is in range before passing it on to the next publisher.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class BoundsCheckingPublisher implements ReadingPublisher<LaCrosseTemperatureReading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(BoundsCheckingPublisher.class);
|
||||
|
||||
private final ReadingPublisher<LaCrosseTemperatureReading> publisher;
|
||||
|
||||
private final float minTemp;
|
||||
private final float maxTemp;
|
||||
|
||||
public BoundsCheckingPublisher(float min, float max, ReadingPublisher<LaCrosseTemperatureReading> p) {
|
||||
minTemp = min;
|
||||
maxTemp = max;
|
||||
publisher = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(LaCrosseTemperatureReading reading) {
|
||||
if (reading.getTemperature() >= minTemp && reading.getTemperature() <= maxTemp) {
|
||||
publisher.publish(reading);
|
||||
} else {
|
||||
logger.debug("Ignoring out of bounds reading {}", reading.getTemperature());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
publisher.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Checks that the given temperature does not differ too much from the last temperature
|
||||
* before passing it on to the next publisher.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class DifferenceCheckingPublisher implements ReadingPublisher<LaCrosseTemperatureReading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(DifferenceCheckingPublisher.class);
|
||||
|
||||
private final ReadingPublisher<LaCrosseTemperatureReading> publisher;
|
||||
private final float allowedDifference;
|
||||
|
||||
private LaCrosseTemperatureReading lastReading;
|
||||
|
||||
public DifferenceCheckingPublisher(float difference, ReadingPublisher<LaCrosseTemperatureReading> p) {
|
||||
allowedDifference = difference;
|
||||
publisher = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish(LaCrosseTemperatureReading reading) {
|
||||
if (lastReading == null
|
||||
|| Math.abs(reading.getTemperature() - lastReading.getTemperature()) < allowedDifference) {
|
||||
publisher.publish(reading);
|
||||
} else {
|
||||
logger.debug("Ignoring reading {} differing too much from previous value", reading.getTemperature());
|
||||
}
|
||||
|
||||
lastReading = reading;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
publisher.dispose();
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.RollingReadingAverage;
|
||||
|
||||
/**
|
||||
* Computes a rolling average of readings.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LaCrosseRollingReadingAverage extends RollingReadingAverage<LaCrosseTemperatureReading> {
|
||||
public LaCrosseRollingReadingAverage(int bufferSize) {
|
||||
super(new LaCrosseTemperatureReading[bufferSize]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LaCrosseTemperatureReading add(LaCrosseTemperatureReading value1, LaCrosseTemperatureReading value2) {
|
||||
if (value2 != null) {
|
||||
return new LaCrosseTemperatureReading(value2.getSensorId(), value2.getSensorType(), value2.getChannel(),
|
||||
value1.getTemperature() + value2.getTemperature(), value1.getHumidity() + value2.getHumidity(),
|
||||
value2.isBatteryNew(), value2.isBatteryLow());
|
||||
}
|
||||
|
||||
return new LaCrosseTemperatureReading(value1.getSensorId(), value1.getSensorType(), value1.getChannel(),
|
||||
value1.getTemperature(), value1.getHumidity(), value1.isBatteryNew(), value1.isBatteryLow());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LaCrosseTemperatureReading substract(LaCrosseTemperatureReading from, LaCrosseTemperatureReading value) {
|
||||
float newTemp = from.getTemperature();
|
||||
int newHum = from.getHumidity();
|
||||
|
||||
if (value != null) {
|
||||
newTemp -= value.getTemperature();
|
||||
newHum -= value.getHumidity();
|
||||
}
|
||||
|
||||
return new LaCrosseTemperatureReading(from.getSensorId(), from.getSensorType(), from.getChannel(), newTemp,
|
||||
newHum, from.isBatteryNew(), from.isBatteryLow());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LaCrosseTemperatureReading divide(LaCrosseTemperatureReading value, int number) {
|
||||
return new LaCrosseTemperatureReading(value.getSensorId(), value.getSensorType(), value.getChannel(),
|
||||
value.getTemperature() / number, value.getHumidity() / number, value.isBatteryNew(),
|
||||
value.isBatteryLow());
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkBindingConstants;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.SensorDefinition;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Sensor Defintion of a LaCrosse Temperature Sensor
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LaCrosseSensorDefinition extends SensorDefinition<LaCrosseTemperatureReading> {
|
||||
|
||||
public LaCrosseSensorDefinition() {
|
||||
super(JeeLinkBindingConstants.LACROSSE_SENSOR_THING_TYPE, "LaCrosse Temperature Sensor", "9");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkReadingConverter<LaCrosseTemperatureReading> createConverter() {
|
||||
return new LaCrosseTemperatureReadingConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<LaCrosseTemperatureReading> getReadingClass() {
|
||||
return LaCrosseTemperatureReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkSensorHandler<LaCrosseTemperatureReading> createHandler(Thing thing) {
|
||||
return new LaCrosseTemperatureSensorHandler(thing, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.Reading;
|
||||
|
||||
/**
|
||||
* Reading of a LaCrosse Temperature Sensor.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LaCrosseTemperatureReading implements Reading {
|
||||
private String sensorId;
|
||||
private int sensorType;
|
||||
private int channel;
|
||||
private Float temp;
|
||||
private Integer humidity;
|
||||
private boolean batteryNew;
|
||||
private boolean batteryLow;
|
||||
|
||||
public LaCrosseTemperatureReading(int sensorId, int sensorType, int channel, Float temp, Integer humidity,
|
||||
boolean batteryNew, boolean batteryLow) {
|
||||
this(String.valueOf(sensorId), sensorType, channel, temp, humidity, batteryNew, batteryLow);
|
||||
}
|
||||
|
||||
public LaCrosseTemperatureReading(String sensorId, int sensorType, int channel, Float temp, Integer humidity,
|
||||
boolean batteryNew, boolean batteryLow) {
|
||||
this.sensorId = sensorId;
|
||||
this.sensorType = sensorType;
|
||||
this.channel = channel;
|
||||
this.temp = temp;
|
||||
this.humidity = humidity;
|
||||
this.batteryNew = batteryNew;
|
||||
this.batteryLow = batteryLow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
public int getSensorType() {
|
||||
return sensorType;
|
||||
}
|
||||
|
||||
public Float getTemperature() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
public Integer getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public boolean isBatteryLow() {
|
||||
return batteryLow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "sensorId=" + sensorId + ": channel=" + channel + ", temp=" + temp + ", hum=" + humidity + ", batLow="
|
||||
+ batteryLow + ", batNew=" + batteryNew;
|
||||
}
|
||||
|
||||
public boolean isBatteryNew() {
|
||||
return batteryNew;
|
||||
}
|
||||
|
||||
public int getChannel() {
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Converter for converting a line read from a LaCrosseITPlusReader sketch to a LaCrosseTemperatureReading.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LaCrosseTemperatureReadingConverter implements JeeLinkReadingConverter<LaCrosseTemperatureReading> {
|
||||
private static final Pattern LINE_P = Pattern
|
||||
.compile("OK\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)");
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LaCrosseTemperatureReadingConverter.class);
|
||||
|
||||
@Override
|
||||
public LaCrosseTemperatureReading createReading(String inputLine) {
|
||||
// parse lines only if we have registered listeners
|
||||
if (inputLine != null) {
|
||||
Matcher matcher = LINE_P.matcher(inputLine);
|
||||
if (matcher.matches()) {
|
||||
// Format
|
||||
//
|
||||
// OK 9 56 1 4 156 37 (ID = 56 T: 18.0 H: 37 no NewBatt)
|
||||
// OK 9 49 1 4 182 54 (ID = 49 T: 20.6 H: 54 no NewBatt)
|
||||
// OK 9 55 129 4 192 56 (ID = 55 T: 21.6 H: 56 WITH NewBatt)
|
||||
// OK 9 ID XXX XXX XXX XXX
|
||||
// | | | | | | |
|
||||
// | | | | | | --- Humidity incl. WeakBatteryFlag
|
||||
// | | | | | |------ Temp * 10 + 1000 LSB
|
||||
// | | | | |---------- Temp * 10 + 1000 MSB
|
||||
// | | | |-------------- Sensor type (1 or 2) +128 if NewBatteryFlag
|
||||
// | | |----------------- Sensor ID
|
||||
// | |------------------- fix "9"
|
||||
// |---------------------- fix "OK"
|
||||
logger.trace("Creating reading from: {}", inputLine);
|
||||
|
||||
int sensorId = Integer.parseInt(matcher.group(2));
|
||||
int int3 = Integer.parseInt(matcher.group(3));
|
||||
|
||||
int batteryNewInt = (int3 & 0x80) >> 7;
|
||||
int type = (int3 & 0x70) >> 4;
|
||||
int channel = int3 & 0x0F;
|
||||
|
||||
float temperature = (float) (Integer.parseInt(matcher.group(4)) * 256
|
||||
+ Integer.parseInt(matcher.group(5)) - 1000) / 10;
|
||||
int humidity = Integer.parseInt(matcher.group(6)) & 0x7f;
|
||||
int batteryLowInt = (Integer.parseInt(matcher.group(6)) & 0x80) >> 7;
|
||||
|
||||
boolean batteryLow = batteryLowInt == 1;
|
||||
boolean batteryNew = batteryNewInt == 1;
|
||||
|
||||
return new LaCrosseTemperatureReading(sensorId, type, channel, temperature, humidity, batteryNew,
|
||||
batteryLow);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
import org.openhab.binding.jeelink.internal.RollingAveragePublisher;
|
||||
import org.openhab.binding.jeelink.internal.RollingReadingAverage;
|
||||
import org.openhab.binding.jeelink.internal.config.LaCrosseTemperatureSensorConfig;
|
||||
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.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a LaCrosse Temperature Sensor thing.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LaCrosseTemperatureSensorHandler extends JeeLinkSensorHandler<LaCrosseTemperatureReading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(LaCrosseTemperatureSensorHandler.class);
|
||||
|
||||
public LaCrosseTemperatureSensorHandler(Thing thing, String sensorType) {
|
||||
super(thing, sensorType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<LaCrosseTemperatureReading> getReadingClass() {
|
||||
return LaCrosseTemperatureReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingPublisher<LaCrosseTemperatureReading> createPublisher() {
|
||||
return new ReadingPublisher<LaCrosseTemperatureReading>() {
|
||||
private final Map<Integer, ReadingPublisher<LaCrosseTemperatureReading>> channelPublishers = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void publish(LaCrosseTemperatureReading reading) {
|
||||
if (reading != null) {
|
||||
int channelNo = reading.getChannel();
|
||||
|
||||
ReadingPublisher<LaCrosseTemperatureReading> publisher;
|
||||
synchronized (channelPublishers) {
|
||||
publisher = channelPublishers.get(channelNo);
|
||||
if (publisher == null) {
|
||||
publisher = createPublisherForChannel(channelNo);
|
||||
channelPublishers.put(channelNo, publisher);
|
||||
|
||||
createMissingChannels(reading.getChannel());
|
||||
}
|
||||
}
|
||||
|
||||
publisher.publish(reading);
|
||||
}
|
||||
}
|
||||
|
||||
private void createMissingChannels(int channelNo) {
|
||||
List<Channel> missingChannels = new ArrayList<>();
|
||||
|
||||
String idSuffix = channelNo > 1 ? String.valueOf(channelNo) : "";
|
||||
String labelSuffix = channelNo > 1 ? " " + channelNo : "";
|
||||
for (String channelName : new String[] { TEMPERATURE_CHANNEL, HUMIDITY_CHANNEL }) {
|
||||
if (getThing().getChannel(channelName + idSuffix) == null) {
|
||||
missingChannels.add(ChannelBuilder
|
||||
.create(new ChannelUID(getThing().getUID(), channelName + idSuffix), "Number")
|
||||
.withType(new ChannelTypeUID(getThing().getThingTypeUID().getBindingId(), channelName))
|
||||
.withLabel(StringUtils.capitalize(channelName + labelSuffix)).build());
|
||||
}
|
||||
}
|
||||
missingChannels.addAll(getThing().getChannels());
|
||||
|
||||
if (!missingChannels.isEmpty()) {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withChannels(missingChannels);
|
||||
updateThing(thingBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
synchronized (channelPublishers) {
|
||||
for (ReadingPublisher<LaCrosseTemperatureReading> p : channelPublishers.values()) {
|
||||
p.dispose();
|
||||
}
|
||||
channelPublishers.clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public ReadingPublisher<LaCrosseTemperatureReading> createPublisherForChannel(int channelNo) {
|
||||
ReadingPublisher<LaCrosseTemperatureReading> publisher = new ReadingPublisher<LaCrosseTemperatureReading>() {
|
||||
@Override
|
||||
public void publish(LaCrosseTemperatureReading reading) {
|
||||
if (reading != null && getThing().getStatus() == ThingStatus.ONLINE) {
|
||||
BigDecimal temp = new BigDecimal(reading.getTemperature()).setScale(1, RoundingMode.HALF_UP);
|
||||
|
||||
if (channelNo == 1) {
|
||||
logger.debug(
|
||||
"updating states for thing {} ({}): temp={} ({}), humidity={}, batteryNew={}, batteryLow={}",
|
||||
getThing().getLabel(), getThing().getUID().getId(), temp, reading.getTemperature(),
|
||||
reading.getHumidity(), reading.isBatteryNew(), reading.isBatteryLow());
|
||||
updateState(TEMPERATURE_CHANNEL, new QuantityType<>(temp, SIUnits.CELSIUS));
|
||||
updateState(HUMIDITY_CHANNEL,
|
||||
new QuantityType<>(reading.getHumidity(), SmartHomeUnits.PERCENT));
|
||||
updateState(BATTERY_NEW_CHANNEL, reading.isBatteryNew() ? OnOffType.ON : OnOffType.OFF);
|
||||
updateState(BATTERY_LOW_CHANNEL, reading.isBatteryLow() ? OnOffType.ON : OnOffType.OFF);
|
||||
} else {
|
||||
logger.debug("updating states for channel {} of thing {} ({}): temp={} ({}), humidity={}",
|
||||
reading.getChannel(), getThing().getLabel(), getThing().getUID().getId(), temp,
|
||||
reading.getTemperature(), reading.getHumidity());
|
||||
updateState(TEMPERATURE_CHANNEL + reading.getChannel(),
|
||||
new QuantityType<>(temp, SIUnits.CELSIUS));
|
||||
updateState(HUMIDITY_CHANNEL + reading.getChannel(),
|
||||
new QuantityType<>(reading.getHumidity(), SmartHomeUnits.PERCENT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
|
||||
LaCrosseTemperatureSensorConfig cfg = getConfigAs(LaCrosseTemperatureSensorConfig.class);
|
||||
if (cfg.bufferSize > 1 && cfg.updateInterval > 0) {
|
||||
publisher = new RollingAveragePublisher<LaCrosseTemperatureReading>(cfg.bufferSize, cfg.updateInterval,
|
||||
publisher, scheduler) {
|
||||
@Override
|
||||
public RollingReadingAverage<LaCrosseTemperatureReading> createRollingReadingAverage(int bufferSize) {
|
||||
return new LaCrosseRollingReadingAverage(bufferSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (cfg.maxDiff > 0) {
|
||||
publisher = new DifferenceCheckingPublisher(cfg.maxDiff, publisher);
|
||||
}
|
||||
|
||||
publisher = new BoundsCheckingPublisher(cfg.minTemp, cfg.maxTemp, publisher);
|
||||
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.Reading;
|
||||
|
||||
/**
|
||||
* Reading of sensors directly connected to a LGW.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LgwReading implements Reading {
|
||||
private String sensorId;
|
||||
private Float temp;
|
||||
private Integer humidity;
|
||||
private Integer pressure;
|
||||
|
||||
public LgwReading(int sensorId, Float temp, Integer humidity, Integer pressure) {
|
||||
this.sensorId = String.valueOf(sensorId);
|
||||
this.temp = temp;
|
||||
this.humidity = humidity;
|
||||
this.pressure = pressure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
public Float getTemperature() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
public Integer getHumidity() {
|
||||
return humidity;
|
||||
}
|
||||
|
||||
public Integer getPressure() {
|
||||
return pressure;
|
||||
}
|
||||
|
||||
public boolean hasPressure() {
|
||||
return pressure != null;
|
||||
}
|
||||
|
||||
public boolean hasHumidity() {
|
||||
return humidity != null;
|
||||
}
|
||||
|
||||
public boolean hasTemperature() {
|
||||
return temp != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "sensorId=" + sensorId + ": temp=" + temp + (hasHumidity() ? ", hum=" + humidity : "")
|
||||
+ (hasPressure() ? ", pressure=" + pressure : "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Converter for converting a line read from a LGW to a LgwReading.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LgwReadingConverter implements JeeLinkReadingConverter<LgwReading> {
|
||||
private static final Pattern LINE_P = Pattern.compile(
|
||||
"OK\\s+WS\\s+([0-9]+)\\s+4\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)(?:\\s+255){8}?\\s+0\\s+([0-9]+)\\s+([0-9]+)(?:\\s+255){9}?");
|
||||
private final Logger logger = LoggerFactory.getLogger(LgwReadingConverter.class);
|
||||
|
||||
@Override
|
||||
public LgwReading createReading(String inputLine) {
|
||||
// parse lines only if we have registered listeners
|
||||
if (inputLine != null) {
|
||||
Matcher matcher = LINE_P.matcher(inputLine);
|
||||
if (matcher.matches()) {
|
||||
/*
|
||||
* Format
|
||||
* OK WS 71 4 4 203 53 255 255 255 255 255 255 255 255 0 3 219 255 255 255 255 255 255 255 255 255
|
||||
* OK WS 75 4 4 195 61 255 255 255 255 255 255 255 255 0 255 255 255 255 255 255 255 255 255 255 255
|
||||
* OK WS 213 4 5 126 40 255 255 255 255 255 255 255 255 0 40 53 0 48 57
|
||||
* OK WS ID XXX TTT TTT HHH RRR RRR DDD DDD SSS SSS GGG GGG FFF PPP PPP GAS GAS GAS DEB DEB DEB LUX LUX
|
||||
* LUX
|
||||
* | | | | | | | | | | | | | | | | | |-------------------------------------- Pressure LSB
|
||||
* | | | | | | | | | | | | | | | | |------------------------------------------ Pressure MSB
|
||||
* | | | | | | | | | | | | | | | |-- Fix 0
|
||||
* | | | | | | |-------------------------------------- Humidity (1 ... 99 %rH) FF = none
|
||||
* | | | | | |------------------------------------------ Temp * 10 + 1000 LSB (-40 ... +60 °C) FF/FF =
|
||||
* none
|
||||
* | | | | |---------------------------------------------- Temp * 10 + 1000 MSB
|
||||
* | | | |-------------------------------------------------- fix "4"
|
||||
* | | |------------------------------------------------------ Sensor ID (1 ... 63)
|
||||
* | |--------------------------------------------------------- fix "WS"
|
||||
* |------------------------------------------------------------ fix "OK"
|
||||
*/
|
||||
logger.trace("Creating reading from: {}", inputLine);
|
||||
|
||||
int sensorId = Integer.parseInt(matcher.group(1));
|
||||
|
||||
Float temperature = "255".equals(matcher.group(2)) ? null
|
||||
: (float) (Integer.parseInt(matcher.group(2)) * 256 + Integer.parseInt(matcher.group(3)) - 1000)
|
||||
/ 10;
|
||||
|
||||
Integer humidity = "255".equals(matcher.group(4)) ? null : Integer.parseInt(matcher.group(4));
|
||||
|
||||
Integer pressure = null;
|
||||
if (!"255".equals(matcher.group(5))) {
|
||||
pressure = Integer.parseInt(matcher.group(5)) * 256 + Integer.parseInt(matcher.group(6));
|
||||
}
|
||||
|
||||
return new LgwReading(sensorId, temperature, humidity, pressure);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkBindingConstants;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.SensorDefinition;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Sensor definition of a sensor directly connected to a LGW.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class LgwSensorDefinition extends SensorDefinition<LgwReading> {
|
||||
|
||||
public LgwSensorDefinition() {
|
||||
super(JeeLinkBindingConstants.LGW_SENSOR_THING_TYPE, "LGW Sensor", "LGW");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkReadingConverter<LgwReading> createConverter() {
|
||||
return new LgwReadingConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<LgwReading> getReadingClass() {
|
||||
return LgwReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkSensorHandler<LgwReading> createHandler(Thing thing) {
|
||||
return new LgwSensorHandler(thing, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
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.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a LGW Sensor thing.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LgwSensorHandler extends JeeLinkSensorHandler<LgwReading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(LgwSensorHandler.class);
|
||||
private boolean hasHumidityChannel;
|
||||
private boolean hasPressureChannel;
|
||||
|
||||
public LgwSensorHandler(Thing thing, String sensorType) {
|
||||
super(thing, sensorType);
|
||||
|
||||
hasHumidityChannel = getThing().getChannel(HUMIDITY_CHANNEL) != null;
|
||||
hasPressureChannel = getThing().getChannel(PRESSURE_CHANNEL) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<LgwReading> getReadingClass() {
|
||||
return LgwReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingPublisher<LgwReading> createPublisher() {
|
||||
ReadingPublisher<LgwReading> publisher = new ReadingPublisher<LgwReading>() {
|
||||
@Override
|
||||
public void publish(LgwReading reading) {
|
||||
if (reading != null && getThing().getStatus() == ThingStatus.ONLINE) {
|
||||
logger.debug("updating states for thing {} ({}): {}", getThing().getLabel(),
|
||||
getThing().getUID().getId(), reading);
|
||||
|
||||
if (reading.hasTemperature()) {
|
||||
BigDecimal temp = new BigDecimal(reading.getTemperature()).setScale(1, RoundingMode.HALF_UP);
|
||||
updateState(TEMPERATURE_CHANNEL, new QuantityType<>(temp, SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
if (reading.hasHumidity()) {
|
||||
if (!hasHumidityChannel) {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withChannel(ChannelBuilder
|
||||
.create(new ChannelUID(getThing().getUID(), HUMIDITY_CHANNEL), "Number:Humidity")
|
||||
.withType(new ChannelTypeUID(getThing().getThingTypeUID().getBindingId(),
|
||||
HUMIDITY_CHANNEL))
|
||||
.withLabel(StringUtils.capitalize(HUMIDITY_CHANNEL)).build());
|
||||
updateThing(thingBuilder.build());
|
||||
|
||||
hasHumidityChannel = true;
|
||||
}
|
||||
|
||||
updateState(HUMIDITY_CHANNEL,
|
||||
new QuantityType<>(reading.getHumidity(), SmartHomeUnits.PERCENT));
|
||||
}
|
||||
|
||||
if (reading.hasPressure()) {
|
||||
if (!hasPressureChannel) {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
thingBuilder.withChannel(ChannelBuilder
|
||||
.create(new ChannelUID(getThing().getUID(), PRESSURE_CHANNEL), "Number:Pressure")
|
||||
.withType(new ChannelTypeUID(getThing().getThingTypeUID().getBindingId(),
|
||||
PRESSURE_CHANNEL))
|
||||
.withLabel(StringUtils.capitalize(PRESSURE_CHANNEL)).build());
|
||||
updateThing(thingBuilder.build());
|
||||
|
||||
hasPressureChannel = true;
|
||||
}
|
||||
|
||||
updateState(PRESSURE_CHANNEL, new QuantityType<>(reading.getPressure(), HECTO(SIUnits.PASCAL)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
/**
|
||||
* Reading of a TX22 Temperature/Humidity Sensor.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Tx22Reading extends LaCrosseTemperatureReading {
|
||||
private Integer rain;
|
||||
private Float windDirection;
|
||||
private Float windSpeed;
|
||||
private Float windGust;
|
||||
private Integer pressure;
|
||||
|
||||
public Tx22Reading(int sensorId, int sensorType, int channel, Float temp, Integer humidity, boolean batteryNew,
|
||||
boolean batteryLow, Integer rain, Float windDirection, Float windSpeed, Float windGust, Integer pressure) {
|
||||
super(String.valueOf(sensorId), sensorType, channel, temp, humidity, batteryNew, batteryLow);
|
||||
|
||||
this.rain = rain;
|
||||
this.windDirection = windDirection;
|
||||
this.windSpeed = windSpeed;
|
||||
this.windGust = windGust;
|
||||
this.pressure = pressure;
|
||||
}
|
||||
|
||||
public Integer getRain() {
|
||||
return rain;
|
||||
}
|
||||
|
||||
public Float getWindDirection() {
|
||||
return windDirection;
|
||||
}
|
||||
|
||||
public Float getWindSpeed() {
|
||||
return windSpeed;
|
||||
}
|
||||
|
||||
public Float getWindGust() {
|
||||
return windGust;
|
||||
}
|
||||
|
||||
public Integer getPressure() {
|
||||
return pressure;
|
||||
}
|
||||
|
||||
public boolean hasWindGust() {
|
||||
return windGust != null;
|
||||
}
|
||||
|
||||
public boolean hasWindSpeed() {
|
||||
return windSpeed != null;
|
||||
}
|
||||
|
||||
public boolean hasWindDirection() {
|
||||
return windDirection != null;
|
||||
}
|
||||
|
||||
public boolean hasPressure() {
|
||||
return pressure != null;
|
||||
}
|
||||
|
||||
public boolean hasRain() {
|
||||
return rain != null;
|
||||
}
|
||||
|
||||
public boolean hasHumidity() {
|
||||
return getHumidity() != null;
|
||||
}
|
||||
|
||||
public boolean hasTemperature() {
|
||||
return getTemperature() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " rain=" + rain + " windDirection=" + windDirection + " windSpeed=" + windSpeed
|
||||
+ " windGust=" + windGust + " pressure=" + pressure;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Converter for converting a line read from a LaCrosseITPlusReader sketch to a Tx22Reading.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Tx22ReadingConverter implements JeeLinkReadingConverter<Tx22Reading> {
|
||||
private static final Pattern LINE_P = Pattern.compile(
|
||||
"OK\\s+WS\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)(?:\\s+([0-9]+)\\s+([0-9]+))?");
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Tx22ReadingConverter.class);
|
||||
|
||||
@Override
|
||||
public Tx22Reading createReading(String inputLine) {
|
||||
// parse lines only if we have registered listeners
|
||||
if (inputLine != null) {
|
||||
Matcher matcher = LINE_P.matcher(inputLine);
|
||||
if (matcher.matches()) {
|
||||
/**
|
||||
* Format
|
||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
* -------------------------------------------------------------------
|
||||
* OK WS 14 1 4 208 53 0 0 7 8 0 29 0 31 1 4 1 I D=0E 23.2°C 52%rH 0mm Dir.: 180.0° Wind:2.9m/s
|
||||
* Gust:3.1m/s new Batt. 1025 hPa
|
||||
* OK WS ID XXX TTT TTT HHH RRR RRR DDD DDD SSS SSS GGG GGG FFF PPP PPP
|
||||
* | | | | | | | | | | | | | | | | | |-- Pressure LSB (optional, FF/FF = none)
|
||||
* | | | | | | | | | | | | | | | | |------ Pressure MSB (optional)
|
||||
* | | | | | | | | | | | | | | | |---------- Flags *
|
||||
* | | | | | | | | | | | | | | |-------------- WindGust * 10 LSB (0.0 ... 50.0 m/s) FF/FF = none
|
||||
* | | | | | | | | | | | | | |------------------ WindGust * 10 MSB
|
||||
* | | | | | | | | | | | | |---------------------- WindSpeed * 10 LSB(0.0 ... 50.0 m/s) FF/FF = none
|
||||
* | | | | | | | | | | | |-------------------------- WindSpeed * 10 MSB
|
||||
* | | | | | | | | | | |------------------------------ WindDirection * 10 LSB (0.0 ... 365.0 Degrees)
|
||||
* FF/FF = none
|
||||
* | | | | | | | | | |---------------------------------- WindDirection * 10 MSB
|
||||
* | | | | | | | | |-------------------------------------- Rain * 0.5mm LSB (0 ... 9999 mm) FF/FF = none
|
||||
* | | | | | | | |------------------------------------------ Rain * 0.5mm MSB
|
||||
* | | | | | | |---------------------------------------------- Humidity (1 ... 99 %rH) FF = none
|
||||
* | | | | | |-------------------------------------------------- Temp * 10 + 1000 LSB (-40 ... +60 °C)
|
||||
* FF/FF = none
|
||||
* | | | | |------------------------------------------------------ Temp * 10 + 1000 MSB
|
||||
* | | | |---------------------------------------------------------- Sensor type (1=TX22, 2=NodeSensor)
|
||||
* | | |------------------------------------------------------------- Sensor ID (0 ... 63)
|
||||
* | |---------------------------------------------------------------- fix "WS"
|
||||
* |------------------------------------------------------------------- fix "OK"
|
||||
*
|
||||
* Flags: 128 64 32 16 8 4 2 1
|
||||
* | | |
|
||||
* | | |-- New battery
|
||||
* | |------ ERROR
|
||||
* |---------- Low battery
|
||||
*/
|
||||
|
||||
logger.trace("Creating reading from: {}", inputLine);
|
||||
|
||||
int sensorId = Integer.parseInt(matcher.group(1));
|
||||
int type = Integer.parseInt(matcher.group(2));
|
||||
|
||||
Float temperature = "255".equals(matcher.group(3)) ? null
|
||||
: (float) (Integer.parseInt(matcher.group(3)) * 256 + Integer.parseInt(matcher.group(4)) - 1000)
|
||||
/ 10;
|
||||
|
||||
Integer humidity = "255".equals(matcher.group(5)) ? null : Integer.parseInt(matcher.group(5));
|
||||
|
||||
Integer rain = "255".equals(matcher.group(6)) ? null
|
||||
: (Integer.parseInt(matcher.group(6)) * 256 + Integer.parseInt(matcher.group(7))) * 2;
|
||||
|
||||
Float windDirection = "255".equals(matcher.group(8)) ? null
|
||||
: (Integer.parseInt(matcher.group(8)) * 256 + Integer.parseInt(matcher.group(9))) / 10f;
|
||||
Float windSpeed = "255".equals(matcher.group(10)) ? null
|
||||
: (Integer.parseInt(matcher.group(10)) * 256 + Integer.parseInt(matcher.group(11))) / 10f;
|
||||
Float windGust = "255".equals(matcher.group(12)) ? null
|
||||
: (Integer.parseInt(matcher.group(12)) * 256 + Integer.parseInt(matcher.group(13))) / 10f;
|
||||
|
||||
int flags = Integer.parseInt(matcher.group(14));
|
||||
boolean batteryNew = (flags & (byte) 1) > 0;
|
||||
boolean batteryLow = (flags & (byte) 4) > 0;
|
||||
|
||||
Integer pressure = null;
|
||||
if (matcher.groupCount() > 14 && matcher.group(15) != null && !"255".equals(matcher.group(15))) {
|
||||
pressure = Integer.parseInt(matcher.group(15)) * 256 + Integer.parseInt(matcher.group(16));
|
||||
}
|
||||
|
||||
return new Tx22Reading(sensorId, type, 0, temperature, humidity, batteryNew, batteryLow, rain,
|
||||
windDirection, windSpeed, windGust, pressure);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.lacrosse;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkBindingConstants;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.SensorDefinition;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Sensor Defintion of a TX22 Temperature/Humidity Sensor.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Tx22SensorDefinition extends SensorDefinition<Tx22Reading> {
|
||||
|
||||
public Tx22SensorDefinition() {
|
||||
super(JeeLinkBindingConstants.TX22_SENSOR_THING_TYPE, "TX22 Temperature/Humidity Sensor", "WS");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkReadingConverter<Tx22Reading> createConverter() {
|
||||
return new Tx22ReadingConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Tx22Reading> getReadingClass() {
|
||||
return Tx22Reading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkSensorHandler<Tx22Reading> createHandler(Thing thing) {
|
||||
return new Tx22SensorHandler(thing, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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.jeelink.internal.lacrosse;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
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.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a TX22 Temperature/Humidity Sensor thing.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Tx22SensorHandler extends JeeLinkSensorHandler<Tx22Reading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(Tx22SensorHandler.class);
|
||||
|
||||
public Tx22SensorHandler(Thing thing, String sensorType) {
|
||||
super(thing, sensorType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Tx22Reading> getReadingClass() {
|
||||
return Tx22Reading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingPublisher<Tx22Reading> createPublisher() {
|
||||
ReadingPublisher<Tx22Reading> publisher = new ReadingPublisher<Tx22Reading>() {
|
||||
@Override
|
||||
public void publish(Tx22Reading reading) {
|
||||
if (reading != null && getThing().getStatus() == ThingStatus.ONLINE) {
|
||||
logger.debug("updating states for thing {} ({}): {}", getThing().getLabel(),
|
||||
getThing().getUID().getId(), reading);
|
||||
|
||||
updateState(BATTERY_NEW_CHANNEL, reading.isBatteryNew() ? OnOffType.ON : OnOffType.OFF);
|
||||
updateState(BATTERY_LOW_CHANNEL, reading.isBatteryLow() ? OnOffType.ON : OnOffType.OFF);
|
||||
|
||||
if (reading.hasTemperature()) {
|
||||
BigDecimal temp = new BigDecimal(reading.getTemperature()).setScale(1, RoundingMode.HALF_UP);
|
||||
updateState(TEMPERATURE_CHANNEL, new QuantityType<>(temp, SIUnits.CELSIUS));
|
||||
}
|
||||
if (reading.hasHumidity()) {
|
||||
updateState(HUMIDITY_CHANNEL,
|
||||
new QuantityType<>(reading.getHumidity(), SmartHomeUnits.PERCENT));
|
||||
}
|
||||
if (reading.hasRain()) {
|
||||
updateState(RAIN_CHANNEL, new QuantityType<>(reading.getRain(), MILLI(SIUnits.METRE)));
|
||||
}
|
||||
if (reading.hasPressure()) {
|
||||
updateState(PRESSURE_CHANNEL, new QuantityType<>(reading.getPressure(), HECTO(SIUnits.PASCAL)));
|
||||
}
|
||||
if (reading.hasWindDirection()) {
|
||||
updateState(WIND_ANGLE_CHANNEL,
|
||||
new QuantityType<>(reading.getWindDirection(), SmartHomeUnits.DEGREE_ANGLE));
|
||||
}
|
||||
if (reading.hasWindSpeed()) {
|
||||
updateState(WIND_STENGTH_CHANNEL,
|
||||
new QuantityType<>(reading.getWindSpeed(), SmartHomeUnits.METRE_PER_SECOND));
|
||||
}
|
||||
if (reading.hasWindGust()) {
|
||||
updateState(GUST_STRENGTH_CHANNEL,
|
||||
new QuantityType<>(reading.getWindGust(), SmartHomeUnits.METRE_PER_SECOND));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.jeelink.internal.pca301;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.Reading;
|
||||
|
||||
/**
|
||||
* Reading of a PCA301 sensor.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Pca301Reading implements Reading {
|
||||
private final String sensorId;
|
||||
private final int channel;
|
||||
private final boolean on;
|
||||
private final float current;
|
||||
private final long total;
|
||||
|
||||
public Pca301Reading(String sensorId, int channel, boolean deviceOn, float consumptionCurrent,
|
||||
long consumptionTotal) {
|
||||
this.sensorId = sensorId;
|
||||
this.channel = channel;
|
||||
on = deviceOn;
|
||||
current = consumptionCurrent;
|
||||
total = consumptionTotal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
public int getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public float getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public long getTotal() {
|
||||
return total;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.jeelink.internal.pca301;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Converter for converting a line read from a pcaSerial sketch to a Pca301Reading.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Pca301ReadingConverter implements JeeLinkReadingConverter<Pca301Reading> {
|
||||
private static final Pattern READING_P = Pattern.compile(
|
||||
"OK\\s+24\\s+([0-9]+)\\s+4\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)");
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Pca301ReadingConverter.class);
|
||||
|
||||
@Override
|
||||
public Pca301Reading createReading(String inputLine) {
|
||||
// parse lines only if we have registered listeners
|
||||
if (inputLine != null) {
|
||||
Matcher matcher = READING_P.matcher(inputLine);
|
||||
if (matcher.matches()) {
|
||||
// Format
|
||||
//
|
||||
// OK 24 1 4 1 160 236 0 0 0 0 0
|
||||
// Interpretation:
|
||||
// OK 24: fixed
|
||||
// 1 Byte: channel
|
||||
// 1 Byte: command (04=retrieve measure data, 05=switch device, 06=identify device by toggling device
|
||||
// LED
|
||||
// 3 Byte: device address (UID)
|
||||
// 1 Byte: data -> 1 with command=4 resets device statistics
|
||||
// -> 0/1 with command=5 switches device off/on
|
||||
// 2 Byte: current consumption in watt (scale 1/10)
|
||||
// 2 Byte: total consumption in kWh (scale 1/100)
|
||||
logger.trace("Creating reading from: {}", inputLine);
|
||||
|
||||
int channelId = Integer.parseInt(matcher.group(1));
|
||||
String sensorId = matcher.group(2) + "-" + matcher.group(3) + "-" + matcher.group(4);
|
||||
int data = Integer.parseInt(matcher.group(5));
|
||||
|
||||
long con1 = Long.parseLong(matcher.group(6));
|
||||
long con2 = Long.parseLong(matcher.group(7));
|
||||
long consumptionCurrent = ((con1 << 8) + con2);
|
||||
|
||||
con1 = Long.parseLong(matcher.group(8));
|
||||
con2 = Long.parseLong(matcher.group(9));
|
||||
long consumptionTotal = ((con1 << 8) + con2);
|
||||
|
||||
return new Pca301Reading(sensorId, channelId, data == 1, consumptionCurrent / 10f,
|
||||
consumptionTotal * 10);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.pca301;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkBindingConstants;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.SensorDefinition;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Sensor Defintion of a PCA301 power switchable outlet.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Pca301SensorDefinition extends SensorDefinition<Pca301Reading> {
|
||||
|
||||
public Pca301SensorDefinition() {
|
||||
super(JeeLinkBindingConstants.PCA301_SENSOR_THING_TYPE, "PCA301 power monitoring wireless socket", "24");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkReadingConverter<Pca301Reading> createConverter() {
|
||||
return new Pca301ReadingConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Pca301Reading> getReadingClass() {
|
||||
return Pca301Reading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkSensorHandler<Pca301Reading> createHandler(Thing thing) {
|
||||
return new Pca301SensorHandler(thing, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 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.jeelink.internal.pca301;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkHandler;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
import org.openhab.binding.jeelink.internal.config.Pca301SensorConfig;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a EC3000 sensor thing.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class Pca301SensorHandler extends JeeLinkSensorHandler<Pca301Reading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(Pca301SensorHandler.class);
|
||||
|
||||
private JeeLinkHandler bridge;
|
||||
private OnOffType state;
|
||||
private final AtomicInteger channel = new AtomicInteger(-1);
|
||||
|
||||
private ScheduledFuture<?> retry;
|
||||
private int sendCount;
|
||||
|
||||
public Pca301SensorHandler(Thing thing, String sensorType) {
|
||||
super(thing, sensorType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Pca301Reading> getReadingClass() {
|
||||
return Pca301Reading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
|
||||
bridge = (JeeLinkHandler) getBridge().getHandler();
|
||||
|
||||
Pca301SensorConfig cfg = getConfigAs(Pca301SensorConfig.class);
|
||||
sendCount = cfg.sendCount;
|
||||
|
||||
logger.debug("initilized handler for thing {} ({}): sendCount = {}", getThing().getLabel(),
|
||||
getThing().getUID().getId(), sendCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
cancelRetry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void handleCommand(ChannelUID channelUid, Command command) {
|
||||
logger.debug("received command for thing {} ({}): {}", getThing().getLabel(), getThing().getUID().getId(),
|
||||
command);
|
||||
|
||||
if (channelUid.getIdWithoutGroup().equals(SWITCHING_STATE_CHANNEL)) {
|
||||
if (command instanceof OnOffType) {
|
||||
sendCommandRetry((OnOffType) command);
|
||||
} else {
|
||||
sendCommand(command);
|
||||
}
|
||||
} else if (command != RefreshType.REFRESH) {
|
||||
logger.warn("Unsupported command {} for channel {} of sensor with id {}.", command,
|
||||
channelUid.getIdWithoutGroup(), this.id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingPublisher<Pca301Reading> createPublisher() {
|
||||
return new ReadingPublisher<Pca301Reading>() {
|
||||
@Override
|
||||
public void publish(Pca301Reading reading) {
|
||||
if (reading != null) {
|
||||
channel.set(reading.getChannel());
|
||||
|
||||
BigDecimal current = new BigDecimal(reading.getCurrent()).setScale(1, RoundingMode.HALF_UP);
|
||||
state = reading.isOn() ? OnOffType.ON : OnOffType.OFF;
|
||||
|
||||
updateState(CURRENT_POWER_CHANNEL, new QuantityType<>(current, SmartHomeUnits.WATT));
|
||||
updateState(CONSUMPTION_CHANNEL, new QuantityType<>(reading.getTotal(), SmartHomeUnits.WATT_HOUR));
|
||||
updateState(SWITCHING_STATE_CHANNEL, state);
|
||||
|
||||
logger.debug("updated states for thing {} ({}): state={}, current={}, total={}",
|
||||
getThing().getLabel(), getThing().getUID().getId(), state, current, reading.getTotal());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void sendCommand(Command command) {
|
||||
int chan = channel.get();
|
||||
|
||||
if (chan != -1) {
|
||||
if (command == RefreshType.REFRESH) {
|
||||
bridge.getConnection().sendCommands(chan + ",4," + id.replaceAll("-", ",") + ",0,255,255,255,255s");
|
||||
} else if (command instanceof OnOffType) {
|
||||
bridge.getConnection().sendCommands(chan + ",5," + id.replaceAll("-", ",") + ","
|
||||
+ (command == OnOffType.ON ? "1" : "2") + ",255,255,255,255s");
|
||||
} else {
|
||||
logger.warn("Unsupported command {} for sensor with id {}.", command, this.id);
|
||||
}
|
||||
} else if (command != RefreshType.REFRESH && !(command instanceof OnOffType)) {
|
||||
logger.warn("Could not send command {} for sensor with id {}. Ignoring command.", command, this.id);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void sendCommandRetry(OnOffType command) {
|
||||
cancelRetry();
|
||||
|
||||
retry = scheduler.scheduleWithFixedDelay(new Runnable() {
|
||||
int remainingRetries = sendCount;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (state == null) {
|
||||
logger.debug("skip sending of command (current state not yet known) for thing {} ({}): {}",
|
||||
getThing().getLabel(), getThing().getUID().getId(), command);
|
||||
} else if ((state != command && remainingRetries > 0)) {
|
||||
logger.debug("sending command for thing {} ({}) attempt {}/{}: {}", getThing().getLabel(),
|
||||
getThing().getUID().getId(), (sendCount - remainingRetries + 1), sendCount, command);
|
||||
|
||||
sendCommand(command);
|
||||
remainingRetries--;
|
||||
} else {
|
||||
// we get here when the state is as expected or when the state is still not as expected after
|
||||
// the configured number of retries. we should cancel the retry for both cases
|
||||
if (state != command) {
|
||||
logger.debug("giving up command for thing {} ({}): {}", getThing().getLabel(),
|
||||
getThing().getUID().getId(), command);
|
||||
}
|
||||
|
||||
cancelRetry();
|
||||
}
|
||||
}
|
||||
}, 0, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private synchronized void cancelRetry() {
|
||||
if (retry != null) {
|
||||
retry.cancel(true);
|
||||
retry = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.jeelink.internal.revolt;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.Reading;
|
||||
|
||||
/**
|
||||
* Reading of a Revolt Energy Meter sensor.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class RevoltReading implements Reading {
|
||||
private int voltage;
|
||||
private float current;
|
||||
private int frequency;
|
||||
private float power;
|
||||
private float powerFact;
|
||||
private float consumption;
|
||||
private String sensorId;
|
||||
|
||||
public RevoltReading(String sensorId, int voltage, float current, int frequency, float power, float powerFactor,
|
||||
float consumption) {
|
||||
this.sensorId = sensorId;
|
||||
this.voltage = voltage;
|
||||
this.current = current;
|
||||
this.frequency = frequency;
|
||||
this.power = power;
|
||||
this.powerFact = powerFactor;
|
||||
this.consumption = consumption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "sensorId=" + sensorId + ": voltage=" + voltage + ", current=" + current + ", frequency=" + frequency
|
||||
+ ", power=" + power + ", powerFact=" + powerFact + ", consumption=" + consumption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
public int getVoltage() {
|
||||
return voltage;
|
||||
}
|
||||
|
||||
public float getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public int getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public float getPower() {
|
||||
return power;
|
||||
}
|
||||
|
||||
public float getPowerFactor() {
|
||||
return powerFact;
|
||||
}
|
||||
|
||||
public float getConsumption() {
|
||||
return consumption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.jeelink.internal.revolt;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
|
||||
/**
|
||||
* Converter for converting a line read from a SlowRF CUL to a RevoltReading.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class RevoltReadingConverter implements JeeLinkReadingConverter<RevoltReading> {
|
||||
private static final Pattern LINE_P = Pattern
|
||||
.compile("r([0-9A-Za-z]{4})([0-9A-Za-z]{2})([0-9A-Za-z]{4})([0-9A-Za-z]{2})([0-9A-Za-z]{4})"
|
||||
+ "([0-9A-Za-z]{2})([0-9A-Za-z]{4})[0-9A-Za-z][0-9A-Za-z]");
|
||||
|
||||
@Override
|
||||
public RevoltReading createReading(String inputLine) {
|
||||
if (inputLine != null) {
|
||||
Matcher matcher = LINE_P.matcher(inputLine);
|
||||
if (matcher.matches()) {
|
||||
/*
|
||||
* r4F1BE400513206875B312F25
|
||||
*/
|
||||
String id = matcher.group(1); // 4F1B
|
||||
|
||||
int voltage = toInt(matcher.group(2)); // 0xE4 = 228 => 228 V
|
||||
float current = toInt(matcher.group(3)) / 100f; // 0x0051 = 81 => 0,81 A
|
||||
int frequency = toInt(matcher.group(4)); // 0x32 = 50 => 50 Hz
|
||||
float power = toInt(matcher.group(5)) / 10f; // 0x0687 = 1671 => 167,1 W
|
||||
float powerFact = toInt(matcher.group(6)) / 100f; // 0x5B = 91 => 0,91 VA
|
||||
float consumption = toInt(matcher.group(7)) / 100f; // 0x312F = 12591 => 125,91 Wh
|
||||
|
||||
return new RevoltReading(id, voltage, current, frequency, power, powerFact, consumption);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int toInt(String hex) {
|
||||
Integer i = Integer.parseInt(hex, 16);
|
||||
return i.intValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.jeelink.internal.revolt;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkBindingConstants;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkReadingConverter;
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.SensorDefinition;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Sensor Definition of a Revolt Energy Meter.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class RevoltSensorDefinition extends SensorDefinition<RevoltReading> {
|
||||
public RevoltSensorDefinition() {
|
||||
super(JeeLinkBindingConstants.REVOLT_SENSOR_THING_TYPE, "Revolt Power Monitor", "r");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkReadingConverter<RevoltReading> createConverter() {
|
||||
return new RevoltReadingConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<RevoltReading> getReadingClass() {
|
||||
return RevoltReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JeeLinkSensorHandler<RevoltReading> createHandler(Thing thing) {
|
||||
return new RevoltSensorHandler(thing, type);
|
||||
}
|
||||
}
|
||||
@@ -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.jeelink.internal.revolt;
|
||||
|
||||
import static org.openhab.binding.jeelink.internal.JeeLinkBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.openhab.binding.jeelink.internal.JeeLinkSensorHandler;
|
||||
import org.openhab.binding.jeelink.internal.ReadingPublisher;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a Revolt Energy Meter sensor thing.
|
||||
*
|
||||
* @author Volker Bier - Initial contribution
|
||||
*/
|
||||
public class RevoltSensorHandler extends JeeLinkSensorHandler<RevoltReading> {
|
||||
private final Logger logger = LoggerFactory.getLogger(RevoltSensorHandler.class);
|
||||
|
||||
public RevoltSensorHandler(Thing thing, String sensorType) {
|
||||
super(thing, sensorType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<RevoltReading> getReadingClass() {
|
||||
return RevoltReading.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadingPublisher<RevoltReading> createPublisher() {
|
||||
ReadingPublisher<RevoltReading> publisher = new ReadingPublisher<RevoltReading>() {
|
||||
@Override
|
||||
public void publish(RevoltReading reading) {
|
||||
if (reading != null && getThing().getStatus() == ThingStatus.ONLINE) {
|
||||
BigDecimal power = new BigDecimal(reading.getPower()).setScale(1, RoundingMode.HALF_UP);
|
||||
BigDecimal powerFactor = new BigDecimal(reading.getPowerFactor()).setScale(2, RoundingMode.HALF_UP);
|
||||
BigDecimal consumption = new BigDecimal(reading.getConsumption()).setScale(2, RoundingMode.HALF_UP);
|
||||
BigDecimal current = new BigDecimal(reading.getCurrent()).setScale(2, RoundingMode.HALF_UP);
|
||||
|
||||
logger.debug(
|
||||
"updating states for thing {}: power={}, powerFactor={}, consumption={}, current={}, voltage={}, frequency={} ",
|
||||
getThing().getUID().getId(), power, powerFactor, consumption, current, reading.getVoltage(),
|
||||
reading.getFrequency());
|
||||
|
||||
updateState(CURRENT_POWER_CHANNEL, new QuantityType<>(power, SmartHomeUnits.WATT));
|
||||
updateState(POWER_FACTOR_CHANNEL, new DecimalType(powerFactor));
|
||||
updateState(CONSUMPTION_CHANNEL, new QuantityType<>(consumption, SmartHomeUnits.WATT_HOUR));
|
||||
updateState(ELECTRIC_CURRENT_CHANNEL, new QuantityType<>(current, SmartHomeUnits.AMPERE));
|
||||
updateState(ELECTRIC_POTENTIAL_CHANNEL,
|
||||
new QuantityType<>(reading.getVoltage(), SmartHomeUnits.VOLT));
|
||||
updateState(FREQUENCY_CHANNEL, new QuantityType<>(reading.getFrequency(), SmartHomeUnits.HERTZ));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
};
|
||||
|
||||
return publisher;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="jeelink" 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>@text/binding.jeelink.name</name>
|
||||
<description>@text/binding.jeelink.description</description>
|
||||
<author>Volker Bier</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,102 @@
|
||||
# binding
|
||||
binding.jeelink.name = JeeLink Binding
|
||||
binding.jeelink.description = This is the binding for JeeLink USB Receivers, LaCrosseGateways and connected sensors.
|
||||
|
||||
# bridge types
|
||||
bridge-type.jeelinkUsb.label = JeeLink (connected to USB)
|
||||
bridge-type.jeelinkUsb.description = Thing for a JeeLink USB Receiver. Currently supports LaCrosseITPlusReader and ec3kSerial sketches.
|
||||
bridge-type.jeelinkTcp.label = JeeLink (connected over TCP)
|
||||
bridge-type.jeelinkTcp.description = Thing for a JeeLink USB Receiver that is connected to a different machine on the network and made available to the openHAB server via TCP. Currently supports LaCrosseITPlusReader and ec3kSerial sketches.
|
||||
bridge-type.lgwUsb.label = LaCrosseGateway (connected to USB)
|
||||
bridge-type.lgwUsb.description = Thing for a LaCrosseGateway connected directly to the USB port.
|
||||
bridge-type.lgwTcp.label = LaCrosseGateway (connected over TCP)
|
||||
bridge-type.lgwTcp.description = Thing for a LaCrosseGateway that is connected via network.
|
||||
|
||||
# thing types
|
||||
thing-type.lacrosse.label = Lacrosse Temperature Sensor
|
||||
thing-type.lacrosse.description = Thing for a Lacrosse Temperature Sensor connected to a JeeLink USB Receiver.
|
||||
thing-type.ec3k.label = ec3k
|
||||
thing-type.ec3k.description = Thing for a EnergyCount 3000 Power Monitor connected to a JeeLink USB Receiver.
|
||||
thing-type.pca301.label = PCA301
|
||||
thing-type.pca301.description = Thing for a PCA301 power monitoring wireless socket connected to a JeeLink USB Receiver.
|
||||
thing-type.tx22.label = TX22 Sensor
|
||||
thing-type.tx22.description = Thing for a TX22 Sensor connected to a JeeLink USB Receiver.
|
||||
thing-type.revolt.label = Revolt Power Monitor
|
||||
thing-type.revolt.description = Thing for a Revolt Power Monitor connected to a JeeLink USB Receiver.
|
||||
thing-type.lgw.label = LGW Sensor
|
||||
thing-type.lgw.description = Thing for a Sensor directly connected to a LGW.
|
||||
|
||||
# parameters
|
||||
parameter.serialport.label = Serial Port
|
||||
parameter.serialport.description = The serial port name for the USB receiver. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux.
|
||||
parameter.serialportlgw.description = The serial port name for the LaCrosseGateway. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux.
|
||||
parameter.baudrate.label = Baud Rate
|
||||
parameter.baudrate.description = The baud rate of the USB Receiver / LGW. Valid values are 9600, 19200, 38400, 57600 (default), and 115200.
|
||||
parameter.ipaddress.label = IP Address
|
||||
parameter.ipaddress.description = The IP address of the Server to which the USB Receiver is connected.
|
||||
parameter.ipaddresslgw.description = The IP address of the LGW.
|
||||
parameter.port.label = TCP Port
|
||||
parameter.port.description = The TCP port over which the serial port is made available.
|
||||
parameter.portlgw.description = The TCP port of the LGW (usually this is port 81).
|
||||
parameter.initcommands.label = Init Commands
|
||||
parameter.initcommands.description = Optional initialization commands (semicolon separated) that will be send after the first reading has been received, e.g. "0a" to turn of the LED.
|
||||
parameter.initdelay.label = Init Delay
|
||||
parameter.initdelay.description = Time after which the init command is send after the connection has been established if no readings have been received.
|
||||
parameter.reconnectinterval.label = Reconnect Interval
|
||||
parameter.reconnectinterval.description = The number of seconds after which a reconnect is triggered when no values could be read fron any of the sensors.
|
||||
parameter.sensorid.label = Sensor ID
|
||||
parameter.sensorid.description = The sensor ID used by this sensor.
|
||||
parameter.updateinterval.label = Update Interval
|
||||
parameter.updateinterval.description = The update interval in seconds (0 puts the sensor in live mode). Setting this to a value greater than zero only makes sense if you specify a buffer size greater one.
|
||||
parameter.sensortimeout.label = Sensor Timeout
|
||||
parameter.sensortimeout.description = The amount of time that should result in OFFLINE status when no readings have been received from the sensor (in seconds).
|
||||
parameter.buffersize.label = Buffer Size
|
||||
parameter.buffersize.description = The amount of readings that should be used to compute a rolling average (1 disables the rolling average).
|
||||
parameter.mintemp.label = Lower Temperature Limit
|
||||
parameter.mintemp.description = The lowest temperature allowed as valid reading from the sensor. All lower readings will be ignored.
|
||||
parameter.maxtemp.label = Upper Temperature Limit
|
||||
parameter.maxtemp.description = The highest temperature allowed as valid reading from the sensor. All higher readings will be ignored.
|
||||
parameter.maxdiff.label = Maximum Allowed Temperature Difference
|
||||
parameter.maxdiff.description = The maximum allowed absolute difference from a value to the previous value (0 disables this check). If the difference is higher, the reading will be ignored.
|
||||
parameter.sendCount.label = Switching Command Count
|
||||
parameter.sendCount.description = The number of times a switching command will be sent (every 2 seconds) to the socket until giving up.
|
||||
|
||||
# channel types
|
||||
channel-type.current-power.label = Current Power
|
||||
channel-type.current-power.description = The current power draw of the appliance.
|
||||
channel-type.max-power.label = Max Power
|
||||
channel-type.max-power.description = The maximum power draw of the appliance.
|
||||
channel-type.consumption-total.label = Total Consumption
|
||||
channel-type.consumption-total.description = The total consumption of the connected appliance.
|
||||
channel-type.appliance-time.label = Appliance On Time
|
||||
channel-type.appliance-time.description = The time the appliance was turned on.
|
||||
channel-type.sensor-time.label = Sensor On Time
|
||||
channel-type.sensor-time.description = The time the EC3000 was connected to an outlet.
|
||||
channel-type.resets.label = Resets
|
||||
channel-type.resets.description = Number of resets performed by the sensor.
|
||||
channel-type.temperature.label = Temperature
|
||||
channel-type.temperature.description = The temperature read from the sensor.
|
||||
channel-type.humidity.label = Humidity
|
||||
channel-type.humidity.description = The humidity read from the sensor.
|
||||
channel-type.battery-new.label = Battery New
|
||||
channel-type.battery-new.description = Indicator for new battery.
|
||||
channel-type.switching-state.label = Switching State
|
||||
channel-type.switching-state.description = Whether the socket is currently switched on or not.
|
||||
channel-type.wind-angle.label = Wind Angle
|
||||
channel-type.wind-angle.description = Current wind direction
|
||||
channel-type.wind-strength.label = Wind Strength
|
||||
channel-type.wind-strength.description = Current wind speed
|
||||
channel-type.rain.label = Rain
|
||||
channel-type.rain.description = Quantity of water
|
||||
channel-type.pressure.label = Pressure
|
||||
channel-type.pressure.description = Current pressure
|
||||
gust-strength.label = Gust Strength
|
||||
gust-strength.description = Current gust speed
|
||||
channel-type.electric-current.label = Electric Current
|
||||
channel-type.electric-current.description = The measured electric current.
|
||||
channel-type.power-factor.label = Power Factor
|
||||
channel-type.power-factor.description = The ratio of the real power absorbed by the load to the apparent power flowing in the circuit.
|
||||
channel-type.electric-potential.label = Voltage
|
||||
channel-type.electric-potential.description = The measured electric potential.
|
||||
channel-type.power-frequency.label = Power Frequency
|
||||
channel-type.power-frequency.description = The measured AC power frequency.
|
||||
@@ -0,0 +1,102 @@
|
||||
# binding
|
||||
binding.jeelink.name = JeeLink Binding
|
||||
binding.jeelink.description = Binding für JeeLink USB Empfänger, LaCrosseGateways und damit verbundene Sensoren.
|
||||
|
||||
# bridge types
|
||||
bridge-type.jeelinkUsb.label = JeeLink USB Empfänger
|
||||
bridge-type.jeelinkUsb.description = JeeLink USB Empfänger. Momentan werden LaCrosseITPlusReader und ec3kSerial Sketche unterstützt.
|
||||
bridge-type.jeelinkTcp.label = JeeLink über TCP
|
||||
bridge-type.jeelinkTcp.description = Jeelink USB Empfänger, der an einem anderen Rechner angeschlossen ist. Die Schnittstelle muss über TCP zur Verfügung gestellt werden (z.B. auf Linux mit ser2net).
|
||||
bridge-type.lgwUsb.label = LaCrosseGateway am USB Port
|
||||
bridge-type.lgwUsb.description = LaCrosseGateway, das direkt am USB Port des openHAB Rechners angeschlossen ist.
|
||||
bridge-type.lgwTcp.label = LaCrosseGateway über TCP
|
||||
bridge-type.lgwTcp.description = LaCrosseGateway der über das Netzwerk verbunden ist.
|
||||
|
||||
# thing types
|
||||
thing-type.lacrosse.label = Lacrosse Temperatur-Sensor
|
||||
thing-type.lacrosse.description = Ein mit dem JeeLink USB Empfänger verbundener Lacrosse Temperatur-Sensor.
|
||||
thing-type.ec3k.label = ec3k
|
||||
thing-type.ec3k.description = Ein mit dem JeeLink USB Empfänger verbundenes EC3000 Energiekosten-Messgerät.
|
||||
thing-type.pca301.label = PCA301
|
||||
thing-type.pca301.description = Eine mit dem JeeLink USB Empfänger verbundene PCA301 Steckdose.
|
||||
thing-type.tx22.label = TX22 Sensor
|
||||
thing-type.tx22.description = Ein mit dem JeeLink USB Empfänger verbundener TX22 Sensor.
|
||||
thing-type.revolt.label = Revolt Energie-Messgerät
|
||||
thing-type.revolt.description = Ein mit dem JeeLink USB Empfänger verbundenes Revolt Energie-Messgerät.
|
||||
thing-type.lgw.label = LGW Sensor
|
||||
thing-type.lgw.description = Ein direkt mit dem LGW verbundener Sensor.
|
||||
|
||||
# parameters
|
||||
parameter.serialport.label = Serielle Schnittstelle
|
||||
parameter.serialport.description = Der Name der seriellen Schnittstelle, an die der Jeelink angeschlossen ist. Gültige Werte sind z.B. COM1 für Windows und /dev/ttyS0 oder /dev/ttyUSB0 für Linux.
|
||||
parameter.serialportlgw.description = Der Name der seriellen Schnittstelle, an die das LGW angeschlossen ist. Gültige Werte sind z.B. COM1 für Windows und /dev/ttyS0 oder /dev/ttyUSB0 für Linux.
|
||||
parameter.baudrate.label = Baud Rate
|
||||
parameter.baudrate.description = Die Baud Rate der seriellen Schnittstelle. Gültige Werte sind 9600, 19200, 38400, 57600 (default), and 115200.
|
||||
parameter.ipaddress.label = IP Adresse
|
||||
parameter.ipaddress.description = Die IP Adresse des Rechners, an den der Jeelink angeschlossen ist.
|
||||
parameter.ipaddresslgw.description = Die IP Adresse LGWs.
|
||||
parameter.port.label = TCP Port
|
||||
parameter.port.description = Der TCP Port über den die serielle Schnittstelle bereit gestellt wird.
|
||||
parameter.portlgw.description = Der TCP Port des LGWs (dies ist normalerweise Port 81).
|
||||
parameter.initcommands.label = Init Kommandos
|
||||
parameter.initcommands.description = Optionale Initialisierungs-Kommandos (durch Semikolon getrennt) die nach Empfang des ersten Wertes an den Jeelink geschickt werden, z.B. "0a" um die LED auszuschalten.
|
||||
parameter.initdelay.label = Init Verzögerung
|
||||
parameter.initdelay.description = Zeit nach der die Init Kommandos gesendet werden nachdem die Verbindung hergestellt wurde wenn keine Werte empfangen wurden.
|
||||
parameter.reconnectinterval.label = Reconnect Intervall
|
||||
parameter.reconnectinterval.description = Die Anzahl an Sekunden, nach denen die Verbindung neu aufgebaut wird, falls in der Zwischenzeit kein Wert von einem Sensor gelesen werden konnte.
|
||||
parameter.sensorid.label = Sensor ID
|
||||
parameter.sensorid.description = Die Sensor ID dieses Sensors.
|
||||
parameter.updateinterval.label = Update Intervall
|
||||
parameter.updateinterval.description = Das Update Intervall in Sekunden (0 setzt den Sensor in den 'live' Modus, d.h. jeder Wert wird an openHAB weitergereicht). Werte größer 0 machen nur Sinn, wenn eine Buffer Größe größer als 1 konfiguriert ist.
|
||||
parameter.sensortimeout.label = Sensor Timeout
|
||||
parameter.sensortimeout.description = Die Anzahl an Sekunden, nach deren Ausbleiben von Messwerten der Sensor Status auf OFFLINE gesetzt wird.
|
||||
parameter.buffersize.label = Buffer Größe
|
||||
parameter.buffersize.description = Die Anzahl von Messwertden, die zur Berechnung des Durchschnitts benutzt werden (1 schaltet die Durchschnittsberechnung ab).
|
||||
parameter.mintemp.label = Minimal gültige Temperatur
|
||||
parameter.mintemp.description = Die niedrigste vom Sensor gelesene, als gültig erachtete Temperatur. Alle niedrigeren Werte werden ignoriert.
|
||||
parameter.maxtemp.label = Maximal gültige Temperatur
|
||||
parameter.maxtemp.description = Die höchste vom Sensor gelesene, als gültig erachtete Temperatur. Alle höheren Werte werden ignoriert.
|
||||
parameter.maxdiff.label = Maximal erlaubte Temperaturdifferenz
|
||||
parameter.maxdiff.description = Die maximal erlaubte absolute Differenz eines Wertes zum Vorherigen (0 schaltet diese Prüfung ab). Alle Werte mit größerer Differenz werden ignoriert.
|
||||
parameter.sendCount.label = Anzahl der Schaltversuche
|
||||
parameter.sendCount.description = Die Anzahl der Versuche eine Steckdose zu schalten (alle 2 Sekunden) bevor aufgegeben wird.
|
||||
|
||||
# channel types
|
||||
channel-type.current-power.label = Momentaner Verbrauch
|
||||
channel-type.current-power.description = Der momentane Verbrauch des angeschlossenen Gerätes.
|
||||
channel-type.max-power.label = Höchster Verbrauch
|
||||
channel-type.max-power.description = Der höchste Verbrauch des angeschlossenen Gerätes.
|
||||
channel-type.consumption-total.label = Absoluter Verbrauch
|
||||
channel-type.consumption-total.description = Der absolute Verbrauch des angeschlossenen Gerätes.
|
||||
channel-type.appliance-time.label = Einschaltzeit des Gerätes
|
||||
channel-type.appliance-time.description = Die Zeit während derer das angeschlossene Gerät eingeschaltet war.
|
||||
channel-type.sensor-time.label = Einschaltzeit des Sensoren
|
||||
channel-type.sensor-time.description = Die Zeit während derer der Sensor eingeschaltet war.
|
||||
channel-type.resets.label = Resets
|
||||
channel-type.resets.description = Anzahl der Resets dieses Sensors.
|
||||
channel-type.temperature.label = Temperatur
|
||||
channel-type.temperature.description = Die vom Sensor gelesene Temperatur.
|
||||
channel-type.humidity.label = Luftfeuchtigkeit
|
||||
channel-type.humidity.description = Die vom Sensor gelesene Luftfeuchtigkeit.
|
||||
channel-type.battery-new.label = Battery neu
|
||||
channel-type.battery-new.description = Indikator für eine neu eingesetzte Batterie.
|
||||
channel-type.switching-state.label = Steckdose Ein
|
||||
channel-type.switching-state.description = Schaltzustand der Steckdose.
|
||||
channel-type.wind-angle.label = Wind Richtung
|
||||
channel-type.wind-angle.description = Momentane Wind Richtung
|
||||
channel-type.wind-strength.label = Windstärke
|
||||
channel-type.wind-strength.description = Momentane Windstärke
|
||||
channel-type.rain.label = Regen
|
||||
channel-type.rain.description = Regenmenge
|
||||
channel-type.pressure.label = Luftdruck
|
||||
channel-type.pressure.description = Momentaner Luftdruck
|
||||
gust-strength.label = Böenstärke
|
||||
gust-strength.description = Momentane Böenstärke
|
||||
channel-type.electric-current.label = Stromstärke
|
||||
channel-type.electric-current.description = Die gemessene elektrische Stromstärke .
|
||||
channel-type.power-factor.label = Leistungsfaktor
|
||||
channel-type.power-factor.description = Verhältnis des Betrages der Wirkleistung zur Scheinleistung.
|
||||
channel-type.electric-potential.label = Spannung
|
||||
channel-type.electric-potential.description = Die gemessene elektrische Spannung.
|
||||
channel-type.power-frequency.label = Stromnetzfrequenz
|
||||
channel-type.power-frequency.description = Die gemessene Netzfrequenz des Stromnetzes.
|
||||
@@ -0,0 +1,537 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="jeelink"
|
||||
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">
|
||||
|
||||
<!-- JeeLink USB Receiver Bridge Type -->
|
||||
<bridge-type id="jeelinkUsb">
|
||||
<label>@text/bridge-type.jeelinkUsb.label</label>
|
||||
<description>@text/bridge-type.jeelinkUsb.description</description>
|
||||
|
||||
<config-description>
|
||||
<parameter name="serialPort" type="text" required="true">
|
||||
<label>@text/parameter.serialport.label</label>
|
||||
<context>serial-port</context>
|
||||
<limitToOptions>false</limitToOptions>
|
||||
<description>@text/parameter.serialport.description</description>
|
||||
</parameter>
|
||||
<parameter name="initCommands" type="text" required="false">
|
||||
<label>@text/parameter.initcommands.label</label>
|
||||
<description>@text/parameter.initcommands.description</description>
|
||||
</parameter>
|
||||
<parameter name="baudRate" type="integer" required="false">
|
||||
<label>@text/parameter.baudrate.label</label>
|
||||
<description>@text/parameter.baudrate.description</description>
|
||||
<default>57600</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="initDelay" type="integer" required="false">
|
||||
<label>@text/parameter.initdelay.label</label>
|
||||
<description>@text/parameter.initdelay.description</description>
|
||||
<default>10</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="reconnectInterval" type="integer" required="false">
|
||||
<label>@text/parameter.reconnectinterval.label</label>
|
||||
<description>@text/parameter.reconnectinterval.description</description>
|
||||
<default>300</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<!-- LGW connected to USB port -->
|
||||
<bridge-type id="lgwUsb">
|
||||
<label>@text/bridge-type.lgwUsb.label</label>
|
||||
<description>@text/bridge-type.lgwUsb.description</description>
|
||||
|
||||
<config-description>
|
||||
<parameter name="serialPort" type="text" required="true">
|
||||
<label>@text/parameter.serialport.label</label>
|
||||
<context>serial-port</context>
|
||||
<limitToOptions>false</limitToOptions>
|
||||
<description>@text/parameter.serialportlgw.description</description>
|
||||
</parameter>
|
||||
<parameter name="initCommands" type="text" required="false">
|
||||
<label>@text/parameter.initcommands.label</label>
|
||||
<description>@text/parameter.initcommands.description</description>
|
||||
</parameter>
|
||||
<parameter name="baudRate" type="integer" required="false">
|
||||
<label>@text/parameter.baudrate.label</label>
|
||||
<description>@text/parameter.baudrate.description</description>
|
||||
<default>57600</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="initDelay" type="integer" required="false">
|
||||
<label>@text/parameter.initdelay.label</label>
|
||||
<description>@text/parameter.initdelay.description</description>
|
||||
<default>20</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="reconnectInterval" type="integer" required="false">
|
||||
<label>@text/parameter.reconnectinterval.label</label>
|
||||
<description>@text/parameter.reconnectinterval.description</description>
|
||||
<default>300</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<!-- JeeLink USB Receiver Bridge connected over TCP Type -->
|
||||
<bridge-type id="jeelinkTcp">
|
||||
<label>@text/bridge-type.jeelinkTcp.label</label>
|
||||
<description>@text/bridge-type.jeelinkTcp.description</description>
|
||||
|
||||
<config-description>
|
||||
<parameter name="ipAddress" type="text" required="true">
|
||||
<label>@text/parameter.ipaddress.label</label>
|
||||
<description>@text/parameter.ipaddress.description</description>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" required="true">
|
||||
<label>@text/parameter.port.label</label>
|
||||
<description>@text/parameter.port.description</description>
|
||||
</parameter>
|
||||
<parameter name="initCommands" type="text" required="false">
|
||||
<label>@text/parameter.initcommands.label</label>
|
||||
<description>@text/parameter.initcommands.description</description>
|
||||
</parameter>
|
||||
<parameter name="initDelay" type="integer" required="false">
|
||||
<label>@text/parameter.initdelay.label</label>
|
||||
<description>@text/parameter.initdelay.description</description>
|
||||
<default>10</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="reconnectInterval" type="integer" required="false">
|
||||
<label>@text/parameter.reconnectinterval.label</label>
|
||||
<description>@text/parameter.reconnectinterval.description</description>
|
||||
<default>300</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</bridge-type>
|
||||
|
||||
<!-- LaCrosseGateway connected over TCP Type -->
|
||||
<bridge-type id="lgwTcp">
|
||||
<label>@text/bridge-type.lgwTcp.label</label>
|
||||
<description>@text/bridge-type.lgwTcp.description</description>
|
||||
|
||||
<config-description>
|
||||
<parameter name="ipAddress" type="text" required="true">
|
||||
<label>@text/parameter.ipaddress.label</label>
|
||||
<description>@text/parameter.ipaddresslgw.description</description>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
<parameter name="initCommands" type="text" required="false">
|
||||
<label>@text/parameter.initcommands.label</label>
|
||||
<description>@text/parameter.initcommands.description</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" required="false">
|
||||
<label>@text/parameter.port.label</label>
|
||||
<description>@text/parameter.portlgw.description</description>
|
||||
<default>81</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="initDelay" type="integer" required="false">
|
||||
<label>@text/parameter.initdelay.label</label>
|
||||
<description>@text/parameter.initdelay.description</description>
|
||||
<default>20</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="reconnectInterval" type="integer" required="false">
|
||||
<label>@text/parameter.reconnectinterval.label</label>
|
||||
<description>@text/parameter.reconnectinterval.description</description>
|
||||
<default>300</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</bridge-type>
|
||||
|
||||
<!-- Lacrosse Temperature Sensor Thing Type -->
|
||||
<thing-type id="lacrosse">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="jeelinkTcp"/>
|
||||
<bridge-type-ref id="jeelinkUsb"/>
|
||||
<bridge-type-ref id="lgwTcp"/>
|
||||
<bridge-type-ref id="lgwUsb"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>@text/thing-type.lacrosse.label</label>
|
||||
<description>@text/thing-type.lacrosse.description</description>
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="humidity" typeId="humidity"/>
|
||||
<channel id="batteryNew" typeId="battery-new"/>
|
||||
<channel id="batteryLow" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text" required="true">
|
||||
<label>@text/parameter.sensorid.label</label>
|
||||
<description>@text/parameter.sensorid.description</description>
|
||||
</parameter>
|
||||
<parameter name="updateInterval" type="integer" required="false" min="0" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.updateinterval.label</label>
|
||||
<description>@text/parameter.updateinterval.description</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
<parameter name="sensorTimeout" type="integer" required="false" min="5" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.sensortimeout.label</label>
|
||||
<description>@text/parameter.sensortimeout.description</description>
|
||||
<default>60</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="bufferSize" type="integer" required="false" min="1" max="100">
|
||||
<label>@text/parameter.buffersize.label</label>
|
||||
<description>@text/parameter.buffersize.description</description>
|
||||
<default>20</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="minTemp" type="decimal" required="false">
|
||||
<label>@text/parameter.mintemp.label</label>
|
||||
<description>@text/parameter.mintemp.description</description>
|
||||
<default>-100</default>
|
||||
</parameter>
|
||||
<parameter name="maxTemp" type="decimal" required="false">
|
||||
<label>@text/parameter.maxtemp.label</label>
|
||||
<description>@text/parameter.maxtemp.description</description>
|
||||
<default>100</default>
|
||||
</parameter>
|
||||
<parameter name="maxDiff" type="decimal" required="true">
|
||||
<label>@text/parameter.maxdiff.label</label>
|
||||
<description>@text/parameter.maxdiff.description</description>
|
||||
<default>2</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- EC3000 Power Monitor Thing Type -->
|
||||
<thing-type id="ec3k">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="jeelinkTcp"/>
|
||||
<bridge-type-ref id="jeelinkUsb"/>
|
||||
<bridge-type-ref id="lgwTcp"/>
|
||||
<bridge-type-ref id="lgwUsb"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>@text/thing-type.ec3k.label</label>
|
||||
<description>@text/thing-type.ec3k.description</description>
|
||||
|
||||
<channels>
|
||||
<channel id="currentPower" typeId="current-power"/>
|
||||
<channel id="maxPower" typeId="max-power"/>
|
||||
<channel id="consumptionTotal" typeId="consumption-total"/>
|
||||
<channel id="applianceTime" typeId="appliance-time"/>
|
||||
<channel id="sensorTime" typeId="sensor-time"/>
|
||||
<channel id="resets" typeId="resets"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text" required="true">
|
||||
<label>@text/parameter.sensorid.label</label>
|
||||
<description>@text/parameter.sensorid.description</description>
|
||||
</parameter>
|
||||
<parameter name="updateInterval" type="integer" required="false" min="0" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.updateinterval.label</label>
|
||||
<description>@text/parameter.updateinterval.description</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
<parameter name="sensorTimeout" type="integer" required="false" min="5" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.sensortimeout.label</label>
|
||||
<description>@text/parameter.sensortimeout.description</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
<parameter name="bufferSize" type="integer" required="false" min="1" max="100">
|
||||
<label>@text/parameter.buffersize.label</label>
|
||||
<description>@text/parameter.buffersize.description</description>
|
||||
<default>20</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- PCA301 power monitoring wireless socket Thing Type -->
|
||||
<thing-type id="pca301">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="jeelinkTcp"/>
|
||||
<bridge-type-ref id="jeelinkUsb"/>
|
||||
<bridge-type-ref id="lgwTcp"/>
|
||||
<bridge-type-ref id="lgwUsb"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>@text/thing-type.pca301.label</label>
|
||||
<description>@text/thing-type.pca301.description</description>
|
||||
|
||||
<channels>
|
||||
<channel id="switchingState" typeId="switching-state"/>
|
||||
<channel id="currentPower" typeId="current-power"/>
|
||||
<channel id="consumptionTotal" typeId="consumption-total"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text" required="true">
|
||||
<label>@text/parameter.sensorid.label</label>
|
||||
<description>@text/parameter.sensorid.description</description>
|
||||
</parameter>
|
||||
<parameter name="sensorTimeout" type="integer" required="false" min="5" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.sensortimeout.label</label>
|
||||
<description>@text/parameter.sensortimeout.description</description>
|
||||
<default>600</default>
|
||||
</parameter>
|
||||
<parameter name="sendCount" type="integer" required="false" min="1" max="300">
|
||||
<label>@text/parameter.sendCount.label</label>
|
||||
<description>@text/parameter.sendCount.description</description>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Revolt Energy Meter Thing Type -->
|
||||
<thing-type id="revolt">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="jeelinkTcp"/>
|
||||
<bridge-type-ref id="jeelinkUsb"/>
|
||||
<bridge-type-ref id="lgwTcp"/>
|
||||
<bridge-type-ref id="lgwUsb"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>@text/thing-type.revolt.label</label>
|
||||
<description>@text/thing-type.revolt.description</description>
|
||||
|
||||
<channels>
|
||||
<channel id="currentPower" typeId="current-power"/>
|
||||
<channel id="consumptionTotal" typeId="consumption-total"/>
|
||||
<channel id="powerFactor" typeId="power-factor"/>
|
||||
<channel id="electricCurrent" typeId="electric-current"/>
|
||||
<channel id="electricPotential" typeId="electric-potential"/>
|
||||
<channel id="powerFrequency" typeId="power-frequency"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text" required="true">
|
||||
<label>@text/parameter.sensorid.label</label>
|
||||
<description>@text/parameter.sensorid.description</description>
|
||||
</parameter>
|
||||
<parameter name="sensorTimeout" type="integer" required="false" min="5" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.sensortimeout.label</label>
|
||||
<description>@text/parameter.sensortimeout.description</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- TX22 Temperature/Humidity SensorThing Type -->
|
||||
<thing-type id="tx22">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="jeelinkTcp"/>
|
||||
<bridge-type-ref id="jeelinkUsb"/>
|
||||
<bridge-type-ref id="lgwTcp"/>
|
||||
<bridge-type-ref id="lgwUsb"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>@text/thing-type.tx22.label</label>
|
||||
<description>@text/thing-type.tx22.description</description>
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="humidity" typeId="humidity"/>
|
||||
<channel id="batteryNew" typeId="battery-new"/>
|
||||
<channel id="batteryLow" typeId="system.low-battery"/>
|
||||
<channel id="pressure" typeId="pressure"/>
|
||||
<channel id="rain" typeId="rain"/>
|
||||
<channel id="windStrength" typeId="wind-strength"/>
|
||||
<channel id="windAngle" typeId="wind-angle"/>
|
||||
<channel id="gustStrength" typeId="wind-strength">
|
||||
<label>@text/gust-strength.label</label>
|
||||
<description>@text/gust-strength.description</description>
|
||||
</channel>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text" required="true">
|
||||
<label>@text/parameter.sensorid.label</label>
|
||||
<description>@text/parameter.sensorid.description</description>
|
||||
</parameter>
|
||||
<parameter name="sensorTimeout" type="integer" required="false" min="5" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.sensortimeout.label</label>
|
||||
<description>@text/parameter.sensortimeout.description</description>
|
||||
<default>600</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- LGW Sensor SensorThing Type -->
|
||||
<thing-type id="lgw">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="jeelinkTcp"/>
|
||||
<bridge-type-ref id="jeelinkUsb"/>
|
||||
<bridge-type-ref id="lgwTcp"/>
|
||||
<bridge-type-ref id="lgwUsb"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>@text/thing-type.lgw.label</label>
|
||||
<description>@text/thing-type.lgw.description</description>
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text" required="true">
|
||||
<label>@text/parameter.sensorid.label</label>
|
||||
<description>@text/parameter.sensorid.description</description>
|
||||
</parameter>
|
||||
<parameter name="sensorTimeout" type="integer" required="false" min="5" max="3600" unit="s" step="5">
|
||||
<label>@text/parameter.sensortimeout.label</label>
|
||||
<description>@text/parameter.sensortimeout.description</description>
|
||||
<default>600</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="wind-angle">
|
||||
<item-type>Number:Angle</item-type>
|
||||
<label>@text/channel-type.wind-angle.label</label>
|
||||
<description>@text/channel-type.wind-angle.description</description>
|
||||
<category>Wind</category>
|
||||
<state min="0" max="360" step="1" readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="wind-strength">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>@text/channel-type.wind-strength.label</label>
|
||||
<description>@text/channel-type.wind-strength.description</description>
|
||||
<category>Wind</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>@text/channel-type.rain.label</label>
|
||||
<description>@text/channel-type.rain.description</description>
|
||||
<category>Rain</category>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pressure">
|
||||
<item-type>Number:Pressure</item-type>
|
||||
<label>@text/channel-type.pressure.label</label>
|
||||
<description>@text/channel-type.pressure.description</description>
|
||||
<category>Pressure</category>
|
||||
<state readOnly="true" pattern="%.3f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Current Power Channel Type -->
|
||||
<channel-type id="current-power">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>@text/channel-type.current-power.label</label>
|
||||
<description>@text/channel-type.current-power.description</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Max Power Channel Type -->
|
||||
<channel-type id="max-power">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>@text/channel-type.max-power.label</label>
|
||||
<description>@text/channel-type.max-power.description</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Total Energy Consumption Channel Type -->
|
||||
<channel-type id="consumption-total">
|
||||
<item-type>Number:Energy</item-type>
|
||||
<label>@text/channel-type.consumption-total.label</label>
|
||||
<description>@text/channel-type.consumption-total.description</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Appliance On Time Channel Type -->
|
||||
<channel-type id="appliance-time" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>@text/channel-type.appliance-time.label</label>
|
||||
<description>@text/channel-type.appliance-time.description</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Sensor On Time Channel Type -->
|
||||
<channel-type id="sensor-time" advanced="true">
|
||||
<item-type>Number:Time</item-type>
|
||||
<label>@text/channel-type.sensor-time.label</label>
|
||||
<description>@text/channel-type.sensor-time.description</description>
|
||||
<state readOnly="true" pattern="%d %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Resets Channel Type -->
|
||||
<channel-type id="resets" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>@text/channel-type.resets.label</label>
|
||||
<description>@text/channel-type.resets.description</description>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Temperature Channel Type -->
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>@text/channel-type.temperature.label</label>
|
||||
<description>@text/channel-type.temperature.description</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Humidity Channel Type -->
|
||||
<channel-type id="humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>@text/channel-type.humidity.label</label>
|
||||
<description>@text/channel-type.humidity.description</description>
|
||||
<category>Humidity</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Battery New Channel Type -->
|
||||
<channel-type id="battery-new">
|
||||
<item-type>Switch</item-type>
|
||||
<label>@text/channel-type.battery-new.label</label>
|
||||
<description>@text/channel-type.battery-new.description</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- PCA301 Socket On Type -->
|
||||
<channel-type id="switching-state">
|
||||
<item-type>Switch</item-type>
|
||||
<label>@text/channel-type.switching-state.label</label>
|
||||
<description>@text/channel-type.switching-state.description</description>
|
||||
</channel-type>
|
||||
|
||||
<!-- Revolt Current Type -->
|
||||
<channel-type id="electric-current">
|
||||
<item-type>Number:ElectricCurrent</item-type>
|
||||
<label>@text/channel-type.electric-current.label</label>
|
||||
<description>@text/channel-type.electric-current.description</description>
|
||||
</channel-type>
|
||||
|
||||
<!-- Revolt Apparent Power Type -->
|
||||
<channel-type id="power-factor">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>@text/channel-type.power-factor.label</label>
|
||||
<description>@text/channel-type.power-factor.description</description>
|
||||
</channel-type>
|
||||
|
||||
<!-- Revolt Electric Potential Type -->
|
||||
<channel-type id="electric-potential">
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>@text/channel-type.electric-potential.label</label>
|
||||
<description>@text/channel-type.electric-potential.description</description>
|
||||
</channel-type>
|
||||
|
||||
<!-- Revolt Frequency Type -->
|
||||
<channel-type id="power-frequency">
|
||||
<item-type>Number:Frequency</item-type>
|
||||
<label>@text/channel-type.power-frequency.label</label>
|
||||
<description>@text/channel-type.power-frequency.description</description>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user