added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
32
bundles/org.openhab.binding.onewire/.classpath
Normal file
32
bundles/org.openhab.binding.onewire/.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.onewire/.project
Normal file
23
bundles/org.openhab.binding.onewire/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.onewire</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.onewire/NOTICE
Normal file
13
bundles/org.openhab.binding.onewire/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
|
||||
320
bundles/org.openhab.binding.onewire/README.md
Normal file
320
bundles/org.openhab.binding.onewire/README.md
Normal file
@@ -0,0 +1,320 @@
|
||||
# OneWire Binding
|
||||
|
||||
The OneWire binding integrates OneWire (also spelled 1-Wire) devices.
|
||||
OneWire is a serial bus developed by Dallas Semiconductor.
|
||||
It provides cheap sensors for temperature, humidity, digital I/O and more.
|
||||
|
||||
## Getting Started
|
||||
|
||||
The OneWire File System (OWFS, https://owfs.org) provides an abstraction layer between the OneWire bus and this binding.
|
||||
It is assumed that you already have a working OWFS installation.
|
||||
Besides your sensors, you need a busmaster device (e.g. DS9490R).
|
||||
|
||||
## Supported Things
|
||||
|
||||
### Bridges
|
||||
|
||||
Currently only one bridge is supported.
|
||||
The `owserver` is the bridge that connects to an existing OWFS installation.
|
||||
|
||||
### Things
|
||||
|
||||
There are different types of things: the simple one (`basic`), multisensors built around the DS1923/DS2438 chip (`ms-tx`) and more advanced sensors from Elaborated Networks (www.wiregate.de) (`ams`, `bms`), Embedded Data System (www.embeddeddatasystems.com)(`edsenv`) and Brain4Home (www.brain4home.eu) (`bae091x`).
|
||||
|
||||
** Important: Breaking Change **
|
||||
|
||||
The thing types `ms-th`, `ms-tv`, `counter2`, `digitalio`, `digitalio2`, `digitalio8`, `ibutton`, `temperature` have been removed.
|
||||
|
||||
## Discovery
|
||||
|
||||
Discovery is supported for things. You have to add the bridges manually.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
It is strongly recommended to use discovery and Paper UI for thing configuration.
|
||||
Please note that:
|
||||
|
||||
* All things need a bridge.
|
||||
* The sensor id parameter supports only the dotted format, including the family id (e.g. `28.7AA256050000`).
|
||||
DS2409 MicroLAN couplers (hubs) are supported by adding their id and the branch (`main` or `aux`) in a directory-like format in front of the sensor id (e.g. `1F.EDC601000000/main/28.945042000000`).
|
||||
* Refresh time is the minimum time in seconds between two checks of that thing.
|
||||
It defaults to 300s for analog channels and 10s for digital channels.
|
||||
* Some thing channels need additional configuration, please see below in the channels section.
|
||||
|
||||
### OWFS Bridge (`owserver`)
|
||||
|
||||
There are no configuration options for the owserver besides the network address.
|
||||
It consists of two parts: `address` and `port`.
|
||||
|
||||
The `address` parameter is used to denote the location of the owserver instance.
|
||||
It supports both, a hostname or an IP address.
|
||||
|
||||
The `port` parameter is used to adjust non-standard OWFS installations.
|
||||
It defaults to `4304`, which is the default of each OWFS installation.
|
||||
|
||||
Bridges of type `owserver` are extensible with channels of type `owfs-number` and `owfs-string`.
|
||||
|
||||
### Generic (`basic`)
|
||||
|
||||
The `basic` thing supports iButton-like chips (DS1420, DS2401/DS1990A), temperature sensors (DS18B20, DS18S20, DS1822), digital i/o chips (DS2405, DS2406, DS2408, DS2413) and counter chips (DS2423).
|
||||
|
||||
It has two parameters: sensor id `id` and refresh time `refresh`.
|
||||
|
||||
Depending on the chip, either `present`, `temperature`, `digitalX` or `counterX` channel(s) are added.
|
||||
`X` is the number of the channel, starting from `0`.
|
||||
|
||||
### Multisensor (`ms-tx`)
|
||||
|
||||
The multisensor is build around the DS2438 or DS1923 chipset.
|
||||
It always provides a `temperature` channel.
|
||||
|
||||
Depnding on the actual sensor, additional channels (`current`, `humidity`, `light`, `voltage`, `supplyvoltage`) are added.
|
||||
If the voltage input of the DS2438 is connected to a humidity sensor, several common types are supported (see below).
|
||||
|
||||
It has three parameters: sensor id `id`, refresh time `refresh` and `manualsensor` (advanced option).
|
||||
|
||||
Known DS2438-base sensors are iButtonLink (https://www.ibuttonlink.com/) MS-T (recognized as generic DS2438), MS-TH, MS-TC, MS-TL, MS-TV.
|
||||
Unknown multisensors are added as generic DS2438 and have `temperature`, `current`, `voltage` and `supplyvoltage` channels.
|
||||
|
||||
In case the sensor is not properly detected (e.g. because it is a self-made sensor), check if it is compatible with one of the sensors listed above.
|
||||
You can use `manualsensor` to override the auto-detected sensortype by setting `DS2438`, `MS_TH`, `MS_TV`, `MS_TL` or `MS_TC`.
|
||||
|
||||
### Elaborated Networks Multisensors (`ams`, `bms`)
|
||||
|
||||
These things are complex devices from Elaborated networks.
|
||||
They consist of a DS2438 and a DS18B20 with additional circuitry on one PCB.
|
||||
The AMS additionally has a second DS2438 and a DS2413 for digital I/O on-board.
|
||||
Analog light sensors can optionally be attached to both sensors.
|
||||
|
||||
These sensors provide `temperature`, `humidity` and `supplyvoltage` channels.
|
||||
If the light sensor is attached and configured, a `light` channel is provided, otherwise a `current` channel.
|
||||
The AMS has an additional `voltage`and two `digitalX` channels.
|
||||
|
||||
It has two (`bms`) or four (`ams`) sensors.
|
||||
The id parameter (`id`) has to be configured with the sensor id of the humidity sensor.
|
||||
|
||||
Additionally the refresh time `refresh` can be configured.
|
||||
The AMS supports a `digitalrefresh` parameter for the refresh time of the digital channels.
|
||||
|
||||
Since both multisensors have two temperature sensors on-board, the `temperaturesensor` parameter allows to select `DS18B20` or `DS2438` to be used for temperature measurement.
|
||||
This parameter has a default of `DS18B20` as this is considered more accurate.
|
||||
The `temperature` channel is of type `temperature` if the internal sensor is used and of type `temperature-por-res` for the external DS18B20.
|
||||
|
||||
The last parameter is the `lightsensor` option to configure if an ambient light sensor is attached.
|
||||
It defaults to `false`.
|
||||
In that mode, a `current` channel is provided.
|
||||
If set to `true`, a `light` channel is added to the thing.
|
||||
The correct formula for the ambient light is automatically determined from the sensor version.
|
||||
|
||||
### Embedded Data System Environmental sensors (`edsenv`)
|
||||
|
||||
This thing supports EDS0064, EDS0065, EDS0066 or EDS0067 sensors.
|
||||
It has two parameters: sensor id `id` and refresh time `refresh`.
|
||||
|
||||
All things have a `temperature` channel.
|
||||
Additional channels (`light`, `pressure`, `humidity`, `dewpoint`, `abshumidity`) will be added if available from the sensor automatically.
|
||||
|
||||
### Brain4Home BAE091x (`bae091x`)
|
||||
|
||||
Currently this thing only supports BAE0910 sensors.
|
||||
All functional pins of this sensor have multiple functions which can be configured individually.
|
||||
For detailed information of each mode, please see the official documentation.
|
||||
Each pin has the can be configured as `disabled`.
|
||||
The necessary channels are automatically added.
|
||||
|
||||
Pin 1 (`pin1`) has only one function `counter` (channel `counter`).
|
||||
Pin 2 (`pin2`) can be configured as digital output (`output`, channel `digital2`) or pulse width modulated output (`pwm`, software PWM 4, channels `freq2`, `duty4`).
|
||||
Pin 6 (`pin6`) can be configured as digital in-/output (`pio`, channel `digital6`) or pulse width modulated output (`pwm`, software PWM 3, channels `freq1`, `duty3`).
|
||||
Pin 7 (`pin7`) can be configured as analog input (`analog`), digital output (`output`, channel `digital7`) or pulse width modulated output (`pwm`, hardware PWM 2, channels `freq2`, `duty2`).
|
||||
Pin 8 (`pin8`) can be configured as digital input (`input`, channel `digital8`), digital output (`output`, channel `digital8`) or pulse width modulated output (`pwm`, hardware PWM 1, channels `freq1`, `duty1`).
|
||||
|
||||
Please note: support for this sensor is considered experimental.
|
||||
|
||||
## Channels
|
||||
|
||||
| Type-ID | Thing | Item | readonly | Description |
|
||||
|---------------------|----------------------------|--------------------------|------------|----------------------------------------------------|
|
||||
| absolutehumidity | ms-tx, ams, bms, edsenv | Number:Density | yes | absolute humidity |
|
||||
| current | ms-tx, ams | Number:ElectricCurrent | yes | current |
|
||||
| counter | counter2 | Number | yes | countervalue |
|
||||
| dewpoint | ms-tx, ams, bms, edsenv | Number:Temperature | yes | dewpoint |
|
||||
| dio | digitalX, ams | Switch | no | digital I/O, can be configured as input or output |
|
||||
| humidity | ms-tx, ams, bms, edsenv | Number:Dimensionless | yes | relative humidity |
|
||||
| humidityconf | ms-tx | Number:Dimensionless | yes | relative humidity |
|
||||
| light | ams, bms, edsenv | Number:Illuminance | yes | lightness |
|
||||
| owfs-number | owserver | Number | yes | direct access to OWFS nodes |
|
||||
| owfs-string | owserver | String | yes | direct access to OWFS nodes |
|
||||
| present | all | Switch | yes | sensor found on bus (yes = ON) |
|
||||
| pressure | edsenv | Number:Pressure | yes | environmental pressure |
|
||||
| supplyvoltage | ms-tx | Number:ElectricPotential | yes | sensor supplyvoltage |
|
||||
| temperature | temperature, ms-tx, edsenv | Number:Temperature | yes | environmental temperature |
|
||||
| temperature-por | temperature | Number:Temperature | yes | environmental temperature |
|
||||
| temperature-por-res | temperature, ams, bms | Number:Temperature | yes | environmental temperature |
|
||||
| voltage | ms-tx, ams | Number:ElectricPotential | yes | voltage input |
|
||||
| bae-pwm-frequency | bae091x | Number:Frequency | no | frequency for PWM output |
|
||||
| bae-pwm-duty | bae091x | Number:Dimensionless | no | duty cycle (0-100%) for PWM output |
|
||||
| bae-di | bae091x | Switch | yes | digital input |
|
||||
| bae-do | bae091x | Switch | no | digital output |
|
||||
| bae-pio | bae091x | Switch | yes | digital in-/output |
|
||||
| bae-analog | bae091x | Number:ElectricPotential | yes | analog input |
|
||||
| bae-counter | bae091x | Number | yes | countervalue |
|
||||
|
||||
### Digital I/O (`dio`)
|
||||
|
||||
Channels of type `dio` channels each have two parameters: `mode` and `logic`.
|
||||
|
||||
The `mode` parameter is used to configure this channels as `input` or `output`.
|
||||
|
||||
The `logic` parameter can be used to invert the channel.
|
||||
In `normal` mode the channel is considered `ON` for logic high, and `OFF` for logic low.
|
||||
In `inverted` mode `ON` is logic low and `OFF` is logic high.
|
||||
|
||||
### Humidity (`humidity`, `humidityconf`, `abshumidity`, `dewpoint`)
|
||||
|
||||
Depending on the sensor, a `humidity` or `humidityconf` channel may be added.
|
||||
This is only relevant for DS2438-based sensors of thing-type `ms-tx`.
|
||||
`humidityconf`-type channels have the `humiditytype` parameter.
|
||||
Possible options are `/humidity` for HIH-3610 sensors, `/HIH4000/humidity` for HIH-4000 sensors, `/HTM1735/humidity` for HTM-1735 sensors and `/DATANAB/humidity` for sensors from Datanab.
|
||||
|
||||
All humidity sensors also support `absolutehumidity` and `dewpoint`.
|
||||
|
||||
### OWFS Direct Access (`owfs-number`, `owfs-string`)
|
||||
|
||||
These channels allow direct access to OWFS nodes.
|
||||
They have two configuration parameters: `path` and `refresh`.
|
||||
|
||||
The `path` parameter is mandatory and contains a full path inside the OWFS (e.g. `statistics/errors/CRC8_errors`).
|
||||
|
||||
The `refresh` parameter is the number of seconds between two consecutive (successful) reads of the node.
|
||||
It defaults to 300s.
|
||||
|
||||
### Temperature (`temperature`, `temperature-por`, `temperature-por-res`)
|
||||
|
||||
There are three temperature channel types: `temperature`, `temperature-por`and `temperature-por-res`.
|
||||
The correct channel-type is selected automatically by the thing handler depending on the sensor type.
|
||||
|
||||
If the channel-type is `temperature`, there is nothing else to configure.
|
||||
|
||||
Some sensors (e.g. DS18x20) report 85 °C as Power-On-Reset value.
|
||||
In some installations this leads to errorneous temperature readings.
|
||||
If the `ignorepor` parameter is set to `true` 85 °C values will be filtered.
|
||||
The default is `false` as correct reading of 85 °C will otherwise be filtered, too.
|
||||
Please note that the parameter value must not be set in quotation marks (see example below).
|
||||
|
||||
A channel of type `temperature-por-res` has one parameter: `resolution`.
|
||||
OneWire temperature sensors are capable of different resolutions: `9`, `10`, `11` and `12` bits.
|
||||
This corresponds to 0.5 °C, 0.25 °C, 0.125 °C, 0.0625 °C respectively.
|
||||
The conversion time is inverse to that and ranges from 95 ms to 750 ms.
|
||||
For best performance it is recommended to set the resolution only as high as needed.
|
||||
|
||||
|
||||
### BAE PWM (`bae-pwm-frequency`, `bae-pwm-duty`)
|
||||
|
||||
PWM output 1 and 3 (2 and 4) share a frequency channel `pwmfreq1` (`pwmfreq2`).
|
||||
Each PWM output has its own duty cycle (`pwmduty1` to `pwmduty4`).
|
||||
|
||||
The frequency channel has two configuration options (`prescaler`, `reversePolarity`).
|
||||
The `prescaler` sets the frequency range which can be used.
|
||||
Valid values are `0`to `7` (`0` => 245 Hz - 8 MHz, `1`=> 123 Hz - 4 MHz, `2` => 62 Hz - 2 MHz, `3` => 31 Hz - 1 MHz, `4` => 16 Hz - 500 kHz, `5` => 8 Hz - 250 kHz, `6` => 4 Hz - 125 kHz, `7` => 2 Hz - 62.5 kHz).
|
||||
The default value is `0`.
|
||||
The `reversePolarity` option is used to invert the output.
|
||||
It can be `true` or `false`.
|
||||
The default value is `false`.
|
||||
|
||||
The duty cycle can be set from 0-100%.
|
||||
|
||||
### BAE PIO (`bae-pio`)
|
||||
|
||||
|
||||
The PIO channel (programmable I/O channel) has two configuration options: `mode` and `pulldevice`.
|
||||
The `mode`can be set to `input`or `output`.
|
||||
The default is `input`.
|
||||
|
||||
The `pulldevice` is only relevant for `input` mode.
|
||||
It can be configured as `disabled`, `pullup`, `pulldown`.
|
||||
The default is disabled.
|
||||
|
||||
|
||||
## Full Example
|
||||
|
||||
** Attention: Adding channels with UIDs different from the ones mentioned in the thing description will not work and may cause problems.
|
||||
Please use the pre-defined channel names only. **
|
||||
|
||||
This is the configuration for a OneWire network consisting of an owserver as bridge (`onewire:owserver:mybridge`) as well as a temperature sensor, a BMS and a 2-port Digital I/O as things (`onewire:basic:mybridge:mysensor`, `onewire:bms:mybridge:mybms`, `onewire:basic:mybridge:mydio`).
|
||||
|
||||
### demo.things:
|
||||
|
||||
```
|
||||
Bridge onewire:owserver:mybridge [
|
||||
network-address="192.168.0.51"
|
||||
] {
|
||||
|
||||
Thing basic mysensor [
|
||||
id="28.505AF0020000",
|
||||
refresh=60
|
||||
] {
|
||||
Channels:
|
||||
Type temperature-por-res : temperature [
|
||||
ignorepor=true,
|
||||
resolution="11"
|
||||
]
|
||||
}
|
||||
|
||||
Thing bms mybms [
|
||||
id="26.CD497C010000",
|
||||
refresh=60,
|
||||
lightsensor=true,
|
||||
temperaturesensor="DS18B20"
|
||||
] {
|
||||
Channels:
|
||||
Type temperature-por-res : temperature [
|
||||
ignorepor=false,
|
||||
resolution="9"
|
||||
]
|
||||
}
|
||||
|
||||
Thing basic mydio [
|
||||
id="3A.67F113000000"
|
||||
] {
|
||||
Channels:
|
||||
Type dio : digital0 [
|
||||
mode="input"
|
||||
]
|
||||
Type dio : digital1 [
|
||||
mode="output"
|
||||
]
|
||||
}
|
||||
|
||||
Channels:
|
||||
Type owfs-number : crc8errors [
|
||||
path="statistics/errors/CRC8_errors"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### demo.items:
|
||||
|
||||
```
|
||||
Number:Temperature MySensor "MySensor [%.1f °C]" { channel="onewire:basic:mybridge:mysensor:temperature" }
|
||||
Number:Temperature MyBMS_T "MyBMS Temperature [%.1f °F]" { channel="onewire:bms:mybridge:mybms:temperature" }
|
||||
Number:Dimensionless MyBMS_H "MyBMS Humidity [%.1f %unit%]" { channel="onewire:bms:mybridge:mybms:humidity" }
|
||||
Switch Digital0 "Digital 0" { channel="onewire:basic:mybridge:mydio:digital0" }
|
||||
Switch Digital1 "Digital 1" { channel="onewire:basic:mybridge:mydio:digital1" }
|
||||
Number CRC8Errors "Bus-Errors [%d]" { channel="onewire:owserver:mybridge:crc8errors" }
|
||||
```
|
||||
|
||||
### demo.sitemap:
|
||||
|
||||
```
|
||||
sitemap demo label="Main Menu"
|
||||
{
|
||||
Frame {
|
||||
Text item=MySensor
|
||||
Text item=MyBMS_T
|
||||
Text item=MyBMS_H
|
||||
Text item=CRC8Errors
|
||||
Text item=Digital0
|
||||
Switch item=Digital1
|
||||
}
|
||||
}
|
||||
```
|
||||
17
bundles/org.openhab.binding.onewire/pom.xml
Normal file
17
bundles/org.openhab.binding.onewire/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-v4_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.onewire</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: OneWire Binding</name>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.onewire-${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-onewire" description="OneWire Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.onewire/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
|
||||
/**
|
||||
* The {@link DS2438Configuration} is a helper class for the multisensor thing configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2438Configuration {
|
||||
private OwSensorType sensorSubType = OwSensorType.DS2438;
|
||||
private String vendor = "Dallas/Maxim";
|
||||
private String hwRevision = "0";
|
||||
private String prodDate = "unknown";
|
||||
|
||||
private final Map<SensorId, OwSensorType> associatedSensors = new HashMap<>();
|
||||
|
||||
public DS2438Configuration(OwserverBridgeHandler bridgeHandler, SensorId sensorId) throws OwException {
|
||||
OwSensorType sensorType = bridgeHandler.getType(sensorId);
|
||||
if (sensorType != OwSensorType.DS2438) {
|
||||
throw new OwException("sensor " + sensorId.getId() + " is not a DS2438!");
|
||||
}
|
||||
OwPageBuffer pageBuffer = bridgeHandler.readPages(sensorId);
|
||||
|
||||
String sensorTypeId = pageBuffer.getPageString(3).substring(0, 2);
|
||||
switch (sensorTypeId) {
|
||||
case "19":
|
||||
vendor = "iButtonLink";
|
||||
sensorSubType = OwSensorType.MS_TH;
|
||||
break;
|
||||
case "1A":
|
||||
vendor = "iButtonLink";
|
||||
sensorSubType = OwSensorType.MS_TV;
|
||||
break;
|
||||
case "1B":
|
||||
vendor = "iButtonLink";
|
||||
sensorSubType = OwSensorType.MS_TL;
|
||||
break;
|
||||
case "1C":
|
||||
vendor = "iButtonLink";
|
||||
sensorSubType = OwSensorType.MS_TC;
|
||||
break;
|
||||
case "F1":
|
||||
case "F3":
|
||||
vendor = "Elaborated Networks";
|
||||
sensorSubType = OwSensorType.MS_TH;
|
||||
break;
|
||||
case "F2":
|
||||
vendor = "Elaborated Networks";
|
||||
sensorSubType = OwSensorType.MS_TH_S;
|
||||
break;
|
||||
case "F4":
|
||||
vendor = "Elaborated Networks";
|
||||
sensorSubType = OwSensorType.MS_TV;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (sensorSubType == OwSensorType.MS_TH || sensorSubType == OwSensorType.MS_TH_S
|
||||
|| sensorSubType == OwSensorType.MS_TV) {
|
||||
for (int i = 4; i < 7; i++) {
|
||||
String str = new StringBuilder(pageBuffer.getPageString(i)).insert(2, ".").delete(15, 17).toString();
|
||||
Matcher matcher = SensorId.SENSOR_ID_PATTERN.matcher(str);
|
||||
if (matcher.matches()) {
|
||||
SensorId associatedSensorId = new SensorId(sensorId.getPath() + matcher.group(2));
|
||||
|
||||
switch (matcher.group(2).substring(0, 2)) {
|
||||
case "26":
|
||||
DS2438Configuration associatedDs2438Config = new DS2438Configuration(bridgeHandler,
|
||||
associatedSensorId);
|
||||
associatedSensors.put(associatedSensorId, associatedDs2438Config.getSensorSubType());
|
||||
associatedSensors.putAll(associatedDs2438Config.getAssociatedSensors());
|
||||
break;
|
||||
case "28":
|
||||
associatedSensors.put(associatedSensorId, OwSensorType.DS18B20);
|
||||
break;
|
||||
case "3A":
|
||||
associatedSensors.put(associatedSensorId, OwSensorType.DS2413);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
prodDate = String.format("%d/%d", pageBuffer.getByte(5, 0),
|
||||
256 * pageBuffer.getByte(5, 1) + pageBuffer.getByte(5, 2));
|
||||
hwRevision = String.valueOf(pageBuffer.getByte(5, 3));
|
||||
}
|
||||
}
|
||||
|
||||
public Map<SensorId, OwSensorType> getAssociatedSensors() {
|
||||
return associatedSensors;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a list of sensor ids associated with this sensor
|
||||
*
|
||||
* @return a list of the sensor ids (if found), empty list otherwise
|
||||
*/
|
||||
public List<SensorId> getAssociatedSensorIds() {
|
||||
return new ArrayList<>(associatedSensors.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* get all secondary sensor ids of a given type
|
||||
*
|
||||
* @param sensorType filter for sensors
|
||||
* @return a list of OwDiscoveryItems
|
||||
*/
|
||||
public List<SensorId> getAssociatedSensorIds(OwSensorType sensorType) {
|
||||
return associatedSensors.entrySet().stream().filter(s -> s.getValue() == sensorType).map(s -> s.getKey())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* get a list of sensor types associated with this sensor
|
||||
*
|
||||
* @return a list of the sensor typess (if found), empty list otherwise
|
||||
*/
|
||||
public List<OwSensorType> getAssociatedSensorTypes() {
|
||||
return new ArrayList<>(associatedSensors.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* get the number of associated sensors
|
||||
*
|
||||
* @return the number
|
||||
*/
|
||||
public int getAssociatedSensorCount() {
|
||||
return associatedSensors.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* get hardware revision (available on some multisensors)
|
||||
*
|
||||
* @return hardware revision
|
||||
*/
|
||||
public String getHardwareRevision() {
|
||||
return hwRevision;
|
||||
}
|
||||
|
||||
/**
|
||||
* get production date (available on some multisensors)
|
||||
*
|
||||
* @return production date in ww/yy
|
||||
*/
|
||||
public String getProductionDate() {
|
||||
return prodDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* get sensor type (without associated sensors)
|
||||
*
|
||||
* @return basic sensor type
|
||||
*/
|
||||
public OwSensorType getSensorSubType() {
|
||||
return sensorSubType;
|
||||
}
|
||||
|
||||
/**
|
||||
* get vendor name (if available)
|
||||
*
|
||||
* @return the vendor name
|
||||
*/
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* determine multisensor type
|
||||
*
|
||||
* @param mainsensorType the type of the main sensor
|
||||
* @param associatedSensorTypes a list of OwSensorTypes of all associated sensors
|
||||
* @return the multisensor type (if known)
|
||||
*/
|
||||
public static OwSensorType getMultisensorType(OwSensorType mainsensorType,
|
||||
List<OwSensorType> associatedSensorTypes) {
|
||||
OwSensorType multisensorType = OwSensorType.UNKNOWN;
|
||||
switch (associatedSensorTypes.size()) {
|
||||
case 0:
|
||||
multisensorType = mainsensorType;
|
||||
break;
|
||||
case 1:
|
||||
if (mainsensorType == OwSensorType.MS_TH_S && associatedSensorTypes.contains(OwSensorType.DS18B20)) {
|
||||
multisensorType = OwSensorType.BMS_S;
|
||||
} else if (mainsensorType == OwSensorType.MS_TH
|
||||
&& associatedSensorTypes.contains(OwSensorType.DS18B20)) {
|
||||
multisensorType = OwSensorType.BMS;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (mainsensorType == OwSensorType.MS_TH_S && associatedSensorTypes.contains(OwSensorType.MS_TV)
|
||||
&& associatedSensorTypes.contains(OwSensorType.DS18B20)
|
||||
&& associatedSensorTypes.contains(OwSensorType.DS2413)) {
|
||||
// two DS2438 (first THS, second TV), DS18B20, DS2413
|
||||
multisensorType = OwSensorType.AMS_S;
|
||||
} else if (mainsensorType == OwSensorType.MS_TH && associatedSensorTypes.contains(OwSensorType.MS_TV)
|
||||
&& associatedSensorTypes.contains(OwSensorType.DS18B20)
|
||||
&& associatedSensorTypes.contains(OwSensorType.DS2413)) {
|
||||
// two DS2438 (first TH, second TV), DS18B20, DS2413
|
||||
multisensorType = OwSensorType.AMS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return multisensorType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_DIGITAL;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The {@link DigitalIoConfig} class provides the configuration of a digital IO channel
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DigitalIoConfig {
|
||||
private final String channelID;
|
||||
private final ChannelUID channelUID;
|
||||
private final OwserverDeviceParameter inParam;
|
||||
private final OwserverDeviceParameter outParam;
|
||||
private DigitalIoMode ioMode = DigitalIoMode.INPUT;
|
||||
private DigitalIoLogic ioLogic = DigitalIoLogic.NORMAL;
|
||||
|
||||
public DigitalIoConfig(Thing thing, Integer channelIndex, OwserverDeviceParameter inParam,
|
||||
OwserverDeviceParameter outParam) {
|
||||
this.channelUID = new ChannelUID(thing.getUID(), String.format("%s%d", CHANNEL_DIGITAL, channelIndex));
|
||||
this.channelID = String.format("%s%d", CHANNEL_DIGITAL, channelIndex);
|
||||
this.inParam = inParam;
|
||||
this.outParam = outParam;
|
||||
}
|
||||
|
||||
public void setIoMode(String ioMode) {
|
||||
this.ioMode = DigitalIoMode.valueOf(ioMode.toUpperCase());
|
||||
}
|
||||
|
||||
public void setIoLogic(String ioLogic) {
|
||||
this.ioLogic = DigitalIoLogic.valueOf(ioLogic.toUpperCase());
|
||||
}
|
||||
|
||||
public Boolean isInverted() {
|
||||
return (ioLogic == DigitalIoLogic.INVERTED);
|
||||
}
|
||||
|
||||
public ChannelUID getChannelUID() {
|
||||
return channelUID;
|
||||
}
|
||||
|
||||
public String getChannelId() {
|
||||
return channelID;
|
||||
}
|
||||
|
||||
public OwserverDeviceParameter getParameter() {
|
||||
return (ioMode == DigitalIoMode.INPUT) ? inParam : outParam;
|
||||
}
|
||||
|
||||
public Boolean isInput() {
|
||||
return (ioMode == DigitalIoMode.INPUT);
|
||||
}
|
||||
|
||||
public Boolean isOutput() {
|
||||
return (ioMode == DigitalIoMode.OUTPUT);
|
||||
}
|
||||
|
||||
public DigitalIoMode getIoDirection() {
|
||||
return ioMode;
|
||||
}
|
||||
|
||||
public State convertState(Boolean rawValue) {
|
||||
if (ioLogic == DigitalIoLogic.NORMAL) {
|
||||
return rawValue ? OnOffType.ON : OnOffType.OFF;
|
||||
} else {
|
||||
return rawValue ? OnOffType.OFF : OnOffType.ON;
|
||||
}
|
||||
}
|
||||
|
||||
public DecimalType convertState(OnOffType command) {
|
||||
if (ioLogic == DigitalIoLogic.NORMAL) {
|
||||
return command.equals(OnOffType.ON) ? new DecimalType(1) : DecimalType.ZERO;
|
||||
} else {
|
||||
return command.equals(OnOffType.ON) ? DecimalType.ZERO : new DecimalType(1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("path=%s, mode=%s, logic=%s", Arrays.asList(getParameter()), ioMode, ioLogic);
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link DigitalIoLogic} provides the logic level of a digital IO channel
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum DigitalIoLogic {
|
||||
NORMAL,
|
||||
INVERTED
|
||||
}
|
||||
@@ -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.onewire.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link DigitalIoMode} provides the direction of a digital IO channel
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum DigitalIoMode {
|
||||
INPUT,
|
||||
OUTPUT
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link OneWireBinding} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwBindingConstants {
|
||||
public static final String BINDING_ID = "onewire";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_OWSERVER = new ThingTypeUID(BINDING_ID, "owserver");
|
||||
public static final ThingTypeUID THING_TYPE_MS_TX = new ThingTypeUID(BINDING_ID, "ms-tx");
|
||||
public static final ThingTypeUID THING_TYPE_BMS = new ThingTypeUID(BINDING_ID, "bms");
|
||||
public static final ThingTypeUID THING_TYPE_AMS = new ThingTypeUID(BINDING_ID, "ams");
|
||||
public static final ThingTypeUID THING_TYPE_BASIC = new ThingTypeUID(BINDING_ID, "basic");
|
||||
public static final ThingTypeUID THING_TYPE_EDS_ENV = new ThingTypeUID(BINDING_ID, "edsenv");
|
||||
public static final ThingTypeUID THING_TYPE_BAE091X = new ThingTypeUID(BINDING_ID, "bae091x");
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections
|
||||
.unmodifiableSet(Stream.of(THING_TYPE_OWSERVER, THING_TYPE_AMS, THING_TYPE_BMS, THING_TYPE_MS_TX,
|
||||
THING_TYPE_EDS_ENV, THING_TYPE_BASIC, THING_TYPE_BAE091X).collect(Collectors.toSet()));
|
||||
|
||||
// List of all config options
|
||||
public static final String CONFIG_ADDRESS = "network-address";
|
||||
public static final String CONFIG_PORT = "port";
|
||||
|
||||
public static final String CONFIG_ID = "id";
|
||||
public static final String CONFIG_RESOLUTION = "resolution";
|
||||
public static final String CONFIG_IGNORE_POR = "ignorepor";
|
||||
public static final String CONFIG_REFRESH = "refresh";
|
||||
public static final String CONFIG_DIGITALREFRESH = "digitalrefresh";
|
||||
public static final String CONFIG_OFFSET = "offset";
|
||||
public static final String CONFIG_HUMIDITY = "humiditytype";
|
||||
public static final String CONFIG_DIGITAL_MODE = "mode";
|
||||
public static final String CONFIG_DIGITAL_LOGIC = "logic";
|
||||
public static final String CONFIG_TEMPERATURESENSOR = "temperaturesensor";
|
||||
public static final String CONFIG_LIGHTSENSOR = "lightsensor";
|
||||
public static final String CONFIG_BAE_PIN_DISABLED = "disabled";
|
||||
public static final String CONFIG_BAE_PIN_PIO = "pio";
|
||||
public static final String CONFIG_BAE_PIN_COUNTER = "counter";
|
||||
public static final String CONFIG_BAE_PIN_PWM = "pwm";
|
||||
public static final String CONFIG_BAE_PIN_ANALOG = "analog";
|
||||
public static final String CONFIG_BAE_PIN_IN = "input";
|
||||
public static final String CONFIG_BAE_PIN_OUT = "output";
|
||||
|
||||
// list of all properties
|
||||
public static final String PROPERTY_MODELID = "modelId";
|
||||
public static final String PROPERTY_VENDOR = "vendor";
|
||||
public static final String PROPERTY_SENSORCOUNT = "sensorCount";
|
||||
public static final String PROPERTY_PROD_DATE = "prodDate";
|
||||
public static final String PROPERTY_HW_REVISION = "hwRevision";
|
||||
|
||||
// List of all channel ids
|
||||
public static final String CHANNEL_HUMIDITY = "humidity";
|
||||
public static final String CHANNEL_ABSOLUTE_HUMIDITY = "absolutehumidity";
|
||||
public static final String CHANNEL_DEWPOINT = "dewpoint";
|
||||
public static final String CHANNEL_PRESENT = "present";
|
||||
public static final String CHANNEL_TEMPERATURE = "temperature";
|
||||
public static final String CHANNEL_LIGHT = "light";
|
||||
public static final String CHANNEL_SUPPLYVOLTAGE = "supplyvoltage";
|
||||
public static final String CHANNEL_VOLTAGE = "voltage";
|
||||
public static final String CHANNEL_CURRENT = "current";
|
||||
public static final String CHANNEL_PRESSURE = "pressure";
|
||||
public static final String CHANNEL_DIGITAL = "digital";
|
||||
public static final String CHANNEL_DIGITAL0 = "digital0";
|
||||
public static final String CHANNEL_DIGITAL1 = "digital1";
|
||||
public static final String CHANNEL_DIGITAL2 = "digital2";
|
||||
public static final String CHANNEL_DIGITAL3 = "digital3";
|
||||
public static final String CHANNEL_DIGITAL4 = "digital4";
|
||||
public static final String CHANNEL_DIGITAL5 = "digital5";
|
||||
public static final String CHANNEL_DIGITAL6 = "digital6";
|
||||
public static final String CHANNEL_DIGITAL7 = "digital7";
|
||||
public static final String CHANNEL_DIGITAL8 = "digital8";
|
||||
public static final String CHANNEL_COUNTER = "counter";
|
||||
public static final String CHANNEL_COUNTER0 = "counter0";
|
||||
public static final String CHANNEL_COUNTER1 = "counter1";
|
||||
public static final String CHANNEL_PWM_DUTY1 = "pwmduty1";
|
||||
public static final String CHANNEL_PWM_DUTY2 = "pwmduty2";
|
||||
public static final String CHANNEL_PWM_DUTY3 = "pwmduty3";
|
||||
public static final String CHANNEL_PWM_DUTY4 = "pwmduty4";
|
||||
public static final String CHANNEL_PWM_FREQ1 = "pwmfreq1";
|
||||
public static final String CHANNEL_PWM_FREQ2 = "pwmfreq2";
|
||||
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_ABSHUMIDITY = new ChannelTypeUID(BINDING_ID, "abshumidity");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_COUNTER = new ChannelTypeUID(BINDING_ID, "counter");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_CURRENT = new ChannelTypeUID(BINDING_ID, "current");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_DEWPOINT = new ChannelTypeUID(BINDING_ID, "dewpoint");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_DIO = new ChannelTypeUID(BINDING_ID, "dio");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_HUMIDITY = new ChannelTypeUID(BINDING_ID, "humidity");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_HUMIDITYCONF = new ChannelTypeUID(BINDING_ID, "humidityconf");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_LIGHT = new ChannelTypeUID(BINDING_ID, "light");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_PRESENT = new ChannelTypeUID(BINDING_ID, "present");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_PRESSURE = new ChannelTypeUID(BINDING_ID, "pressure");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_TEMPERATURE = new ChannelTypeUID(BINDING_ID, "temperature");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_TEMPERATURE_POR = new ChannelTypeUID(BINDING_ID,
|
||||
"temperature-por");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_TEMPERATURE_POR_RES = new ChannelTypeUID(BINDING_ID,
|
||||
"temperature-por-res");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_VOLTAGE = new ChannelTypeUID(BINDING_ID, "voltage");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_ANALOG = new ChannelTypeUID(BINDING_ID, "bae-analog");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_COUNTER = new ChannelTypeUID(BINDING_ID, "bae-counter");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_DIGITAL_OUT = new ChannelTypeUID(BINDING_ID, "bae-do");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_DIN = new ChannelTypeUID(BINDING_ID, "bae-in");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_DOUT = new ChannelTypeUID(BINDING_ID, "bae-out");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_PIO = new ChannelTypeUID(BINDING_ID, "bae-pio");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_PWM_DUTY = new ChannelTypeUID(BINDING_ID, "bae-pwm-duty");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY = new ChannelTypeUID(BINDING_ID,
|
||||
"bae-pwm-frequency");
|
||||
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_OWFS_NUMBER = new ChannelTypeUID(BINDING_ID, "owfs-number");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UID_OWFS_STRING = new ChannelTypeUID(BINDING_ID, "owfs-string");
|
||||
|
||||
// Maps for Discovery
|
||||
public static final Map<OwSensorType, ThingTypeUID> THING_TYPE_MAP;
|
||||
public static final Map<OwSensorType, String> THING_LABEL_MAP;
|
||||
public static final Map<OwSensorType, Set<OwChannelConfig>> SENSOR_TYPE_CHANNEL_MAP;
|
||||
|
||||
public static final Map<String, String> ACCEPTED_ITEM_TYPES_MAP = Util
|
||||
.readPropertiesFile("accepted_itemtypes.properties");
|
||||
|
||||
static {
|
||||
Map<String, String> properties = Util.readPropertiesFile("sensor.properties");
|
||||
THING_TYPE_MAP = properties.entrySet().stream().filter(e -> e.getKey().endsWith(".thingtype"))
|
||||
.collect(Collectors.toConcurrentMap(e -> OwSensorType.valueOf(e.getKey().split("\\.")[0]),
|
||||
e -> new ThingTypeUID(BINDING_ID, e.getValue())));
|
||||
SENSOR_TYPE_CHANNEL_MAP = properties.entrySet().stream().filter(e -> e.getKey().endsWith(".channels"))
|
||||
.collect(Collectors.toConcurrentMap(e -> OwSensorType.valueOf(e.getKey().split("\\.")[0]),
|
||||
e -> !e.getValue().isEmpty() ? Stream.of(e.getValue().split(","))
|
||||
.map(c -> OwChannelConfig.fromString(c)).collect(Collectors.toSet())
|
||||
: new HashSet<>()));
|
||||
THING_LABEL_MAP = properties.entrySet().stream().filter(e -> e.getKey().endsWith(".label")).collect(
|
||||
Collectors.toConcurrentMap(e -> OwSensorType.valueOf(e.getKey().split("\\.")[0]), e -> e.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Dynamic channel state description provider.
|
||||
* Overrides the state description for the controls, which receive its configuration in the runtime.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { DynamicStateDescriptionProvider.class,
|
||||
OwDynamicStateDescriptionProvider.class }, immediate = true)
|
||||
public class OwDynamicStateDescriptionProvider implements DynamicStateDescriptionProvider {
|
||||
|
||||
private final Map<ChannelUID, StateDescription> descriptions = new ConcurrentHashMap<>();
|
||||
private final Logger logger = LoggerFactory.getLogger(OwDynamicStateDescriptionProvider.class);
|
||||
|
||||
/**
|
||||
* Set a state description for a channel. This description will be used when preparing the channel state by
|
||||
* the framework for presentation. A previous description, if existed, will be replaced.
|
||||
*
|
||||
* @param channelUID
|
||||
* channel UID
|
||||
* @param description
|
||||
* state description for the channel
|
||||
*/
|
||||
public void setDescription(ChannelUID channelUID, StateDescription description) {
|
||||
logger.trace("adding state description for channel {}", channelUID);
|
||||
descriptions.put(channelUID, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* remove all descriptions for a given thing
|
||||
*
|
||||
* @param thingUID the thing's UID
|
||||
*/
|
||||
public void removeDescriptionsForThing(ThingUID thingUID) {
|
||||
logger.trace("removing state description for thing {}", thingUID);
|
||||
descriptions.entrySet().removeIf(entry -> entry.getKey().getThingUID().equals(thingUID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable StateDescription getStateDescription(Channel channel,
|
||||
@Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
|
||||
if (descriptions.containsKey(channel.getUID())) {
|
||||
logger.trace("returning new stateDescription for {}", channel.getUID());
|
||||
return descriptions.get(channel.getUID());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OwException} class defines an exception for handling OneWireExceptions
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwException extends Exception {
|
||||
private static final long serialVersionUID = 71120587360960199L;
|
||||
|
||||
public OwException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.SUPPORTED_THING_TYPES;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.onewire.internal.discovery.OwDiscoveryService;
|
||||
import org.openhab.binding.onewire.internal.handler.AdvancedMultisensorThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.BAE091xSensorThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.BasicMultisensorThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.BasicThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.EDSSensorThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
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.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.onewire")
|
||||
public class OwHandlerFactory extends BaseThingHandlerFactory {
|
||||
Logger logger = LoggerFactory.getLogger(OwHandlerFactory.class);
|
||||
private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
|
||||
|
||||
@NonNullByDefault({})
|
||||
private OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider;
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (OwserverBridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
OwserverBridgeHandler owserverBridgeHandler = new OwserverBridgeHandler((Bridge) thing);
|
||||
registerDiscoveryService(owserverBridgeHandler);
|
||||
return owserverBridgeHandler;
|
||||
} else if (BasicMultisensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
return new BasicMultisensorThingHandler(thing, dynamicStateDescriptionProvider);
|
||||
} else if (AdvancedMultisensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
return new AdvancedMultisensorThingHandler(thing, dynamicStateDescriptionProvider);
|
||||
} else if (BasicThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
return new BasicThingHandler(thing, dynamicStateDescriptionProvider);
|
||||
} else if (EDSSensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
return new EDSSensorThingHandler(thing, dynamicStateDescriptionProvider);
|
||||
} else if (BAE091xSensorThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
return new BAE091xSensorThingHandler(thing, dynamicStateDescriptionProvider);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterHandler(Thing thing) {
|
||||
super.unregisterHandler(thing);
|
||||
logger.error("factory {} deleting thing {}", this, thing);
|
||||
}
|
||||
|
||||
private synchronized void registerDiscoveryService(OwserverBridgeHandler owserverBridgeHandler) {
|
||||
OwDiscoveryService owDiscoveryService = new OwDiscoveryService(owserverBridgeHandler);
|
||||
|
||||
this.discoveryServiceRegs.put(owserverBridgeHandler.getThing().getUID(),
|
||||
bundleContext.registerService(DiscoveryService.class.getName(), owDiscoveryService, new Hashtable<>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void removeHandler(ThingHandler thingHandler) {
|
||||
if (thingHandler instanceof OwserverBridgeHandler) {
|
||||
// remove discovery service, if bridge handler is removed
|
||||
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.remove(thingHandler.getThing().getUID());
|
||||
if (serviceReg != null) {
|
||||
OwDiscoveryService service = (OwDiscoveryService) bundleContext.getService(serviceReg.getReference());
|
||||
serviceReg.unregister();
|
||||
if (service != null) {
|
||||
service.deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Reference
|
||||
protected void setDynamicStateDescriptionProvider(OwDynamicStateDescriptionProvider provider) {
|
||||
this.dynamicStateDescriptionProvider = provider;
|
||||
}
|
||||
|
||||
protected void unsetDynamicStateDescriptionProvider(OwDynamicStateDescriptionProvider provider) {
|
||||
this.dynamicStateDescriptionProvider = null;
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.util.HexUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwPageBuffer} provides encapsulates a buffer for OwPacket payloads
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class OwPageBuffer {
|
||||
private final Logger logger = LoggerFactory.getLogger(OwPageBuffer.class);
|
||||
public static final int PAGE_SIZE = 8;
|
||||
|
||||
private ByteBuffer byteBuffer;
|
||||
|
||||
/**
|
||||
* constructor for empty buffer
|
||||
*
|
||||
*/
|
||||
public OwPageBuffer() {
|
||||
byteBuffer = ByteBuffer.allocate(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor for new buffer of given length
|
||||
*
|
||||
* @param pageNum number of pages
|
||||
*/
|
||||
public OwPageBuffer(int pageNum) {
|
||||
byteBuffer = ByteBuffer.allocate(pageNum * PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor for given byte array
|
||||
*
|
||||
* @param bytes byte array containing the data
|
||||
*/
|
||||
public OwPageBuffer(byte[] bytes) {
|
||||
if (bytes.length % PAGE_SIZE != 0) {
|
||||
byteBuffer = ByteBuffer.allocate((bytes.length / PAGE_SIZE + 1) * PAGE_SIZE);
|
||||
logger.warn("initializing buffer which is not aligned to pages (requested size is {})!", bytes.length);
|
||||
} else {
|
||||
byteBuffer = ByteBuffer.allocate(bytes.length);
|
||||
}
|
||||
|
||||
byteBuffer.put(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* get number of pages in this buffer
|
||||
*
|
||||
* @return number of pages
|
||||
*/
|
||||
public int length() {
|
||||
return byteBuffer.limit() / PAGE_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a single page as byte array
|
||||
*
|
||||
* @param pageNum page number, starting with 0
|
||||
* @return byte array containing the page's data
|
||||
*/
|
||||
public byte[] getPage(int pageNum) {
|
||||
byte[] page = new byte[PAGE_SIZE];
|
||||
byteBuffer.position(pageNum * PAGE_SIZE);
|
||||
byteBuffer.get(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a single page
|
||||
*
|
||||
* @param pageNum page number, starting with 0
|
||||
* @return string representation of the page's data
|
||||
*/
|
||||
public String getPageString(int pageNum) {
|
||||
return HexUtils.bytesToHex(getPage(pageNum));
|
||||
}
|
||||
|
||||
/**
|
||||
* get a single byte in a page
|
||||
*
|
||||
* @param pageNum page number, starting with 0
|
||||
* @param byteNum byte number, starting from 0 (beginning of page)
|
||||
* @return integer of the requested byte
|
||||
*/
|
||||
public int getByte(int pageNum, int byteNum) {
|
||||
int index = pageNum * PAGE_SIZE + byteNum;
|
||||
if (index < byteBuffer.limit()) {
|
||||
return byteBuffer.get(index) & 0xFF;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void setByte(int pageNum, int byteNum, byte value) {
|
||||
int index = pageNum * PAGE_SIZE + byteNum;
|
||||
if (index < byteBuffer.limit()) {
|
||||
byteBuffer.put(index, value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get this page buffer as byte array
|
||||
*
|
||||
* @return this page buffer as byte array
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(new String("["));
|
||||
for (int i = 0; i < length(); i++) {
|
||||
if (i > 0) {
|
||||
s.append(new String(", "));
|
||||
}
|
||||
s.append(getPageString(i));
|
||||
}
|
||||
s.append(new String("]"));
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link SensorId} provides a sensorID for the Onewire bus.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SensorId {
|
||||
public static final Pattern SENSOR_ID_PATTERN = Pattern
|
||||
.compile("^\\/?((?:(?:1F\\.[0-9A-Fa-f]{12})\\/(?:main|aux)\\/)+)?([0-9A-Fa-f]{2}\\.[0-9A-Fa-f]{12})$");
|
||||
|
||||
private final String sensorId;
|
||||
private final String path;
|
||||
private final String fullPath;
|
||||
|
||||
/**
|
||||
* construct a new SensorId object
|
||||
*
|
||||
* allowed formats:
|
||||
* - "28.0123456789ab"
|
||||
* - "1F.1234566890ab/main/28.0123456789ab"
|
||||
* - "1F.1234566890ab/aux/28.0123456789ab"
|
||||
* - leading "/" characters are allowed but not required
|
||||
* - characters are case-insensitive
|
||||
* - hubs ("1F.xxxxxxxxxxxx/aux/") may be repeated
|
||||
*/
|
||||
public SensorId(String fullPath) {
|
||||
Matcher matcher = SENSOR_ID_PATTERN.matcher(fullPath);
|
||||
if (matcher.matches() && matcher.groupCount() == 2) {
|
||||
path = matcher.group(1) == null ? "" : matcher.group(1);
|
||||
sensorId = matcher.group(2);
|
||||
this.fullPath = "/" + path + sensorId;
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the full path to the sensor
|
||||
*
|
||||
* @return full path (including hub parts, separated by "/" characters)
|
||||
*/
|
||||
public String getFullPath() {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the sensor id
|
||||
*
|
||||
* @return sensor id without leading "/" character
|
||||
*/
|
||||
public String getId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the path of this sensorId
|
||||
*
|
||||
* @return path without sensor id (including hub parts, separated by "/" characters)
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* get family id (first to characters of sensor id)
|
||||
*
|
||||
* @return the family id
|
||||
*/
|
||||
public String getFamilyId() {
|
||||
return sensorId.substring(0, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.fullPath.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof SensorId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((SensorId) o).fullPath.equals(fullPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.onewire.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
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.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link Util} is a set of helper functions
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Util {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Util.class);
|
||||
|
||||
/**
|
||||
* calculate absolute humidity in g/m³ from measured values
|
||||
*
|
||||
* @param temperature the measured temperature
|
||||
* @param relativeHumidity the measured relative humidity
|
||||
* @return the corresponding absolute humidity
|
||||
*/
|
||||
public static State calculateAbsoluteHumidity(QuantityType<Temperature> temperature,
|
||||
QuantityType<Dimensionless> relativeHumidity) {
|
||||
QuantityType<Temperature> temperatureDegC = temperature.toUnit(SIUnits.CELSIUS);
|
||||
if (temperatureDegC == null) {
|
||||
throw new IllegalArgumentException("could not change unit");
|
||||
}
|
||||
Double theta = temperatureDegC.doubleValue();
|
||||
// saturation vapor pressure in kg/(m s^2)
|
||||
Double saturationVaporPressure = 611.2 * Math.exp(17.62 * theta / (243.12 + theta));
|
||||
// absolute humidity in kg/m^3
|
||||
Double aH = relativeHumidity.doubleValue() / 100 * saturationVaporPressure / (461.52 * (273.15 + theta));
|
||||
State absoluteHumidity = new QuantityType<>(aH, SmartHomeUnits.KILOGRAM_PER_CUBICMETRE).toUnit("g/m³");
|
||||
if (absoluteHumidity != null) {
|
||||
return absoluteHumidity;
|
||||
} else {
|
||||
throw new IllegalArgumentException("could not change unit");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* calculates the dewpoint in °C from measured values
|
||||
*
|
||||
* @param temperature the measured temperature
|
||||
* @param relativeHumidity the measured relative humidity
|
||||
* @return the corresponding dewpoint
|
||||
*/
|
||||
public static State calculateDewpoint(QuantityType<Temperature> temperature,
|
||||
QuantityType<Dimensionless> relativeHumidity) {
|
||||
QuantityType<Temperature> temperatureDegC = temperature.toUnit(SIUnits.CELSIUS);
|
||||
if (temperatureDegC == null) {
|
||||
throw new IllegalArgumentException("could not change unit");
|
||||
}
|
||||
Double theta = temperatureDegC.doubleValue();
|
||||
Double rH = relativeHumidity.doubleValue() / 100;
|
||||
// dewpoint in °C
|
||||
Double dP = 243.12 * (((17.62 * theta) / (243.12 + theta) + Math.log(rH))
|
||||
/ (((17.62 * 243.12) / (243.12 + theta) - Math.log(rH))));
|
||||
State dewPoint = new QuantityType<>(dP, SIUnits.CELSIUS);
|
||||
return dewPoint;
|
||||
}
|
||||
|
||||
public static Map<String, String> readPropertiesFile(String filename) {
|
||||
URL resource = Thread.currentThread().getContextClassLoader().getResource(filename);
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
properties.load(resource.openStream());
|
||||
return properties.entrySet().stream()
|
||||
.collect(Collectors.toMap(e -> (String) e.getKey(), e -> (String) e.getValue()));
|
||||
} catch (IOException e) {
|
||||
LOGGER.warn("Could not read resource file {}, binding will probably fail: {}", filename, e.getMessage());
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.onewire.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link AMSHandlerConfiguration} is a helper class for the mstx thing handler configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AMSHandlerConfiguration extends BaseHandlerConfiguration {
|
||||
public int digitalRefresh = 10;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.onewire.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link BAE091xAnalogConfiguration} is a helper class for the BAE091x ADC Pin configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BAE091xAnalogConfiguration {
|
||||
public Boolean hires = false;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.onewire.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwBindingConstants;
|
||||
|
||||
/**
|
||||
* The {@link BAE091xHandlerConfiguration} is a helper class for the BAE091x thing handler configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BAE091xHandlerConfiguration extends BaseHandlerConfiguration {
|
||||
public String pin1 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
|
||||
public String pin2 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
|
||||
public String pin6 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
|
||||
public String pin7 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
|
||||
public String pin8 = OwBindingConstants.CONFIG_BAE_PIN_DISABLED;
|
||||
}
|
||||
@@ -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.onewire.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link BAE091xPIOConfiguration} is a helper class for the BAE091x PIO Pin configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BAE091xPIOConfiguration {
|
||||
public String mode = "input";
|
||||
public String pulldevice = "disabled";
|
||||
}
|
||||
@@ -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.onewire.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link BAE091xPWMConfiguration} is a helper class for the BAE091x PWM Frequency configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BAE091xPWMConfiguration {
|
||||
public int prescaler = 0;
|
||||
public boolean reversePolarity = false;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.onewire.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link BaseHandlerConfiguration} is a helper class for the base thing handler configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BaseHandlerConfiguration {
|
||||
public @Nullable String id;
|
||||
public int refresh = 300;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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.onewire.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
|
||||
/**
|
||||
* The {@link MstxHandlerConfiguration} is a helper class for the mstx thing handler configuration
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MstxHandlerConfiguration extends BaseHandlerConfiguration {
|
||||
public @Nullable OwSensorType manualsensor;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.DigitalIoConfig;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.StateDescription;
|
||||
import org.openhab.core.types.StateDescriptionFragmentBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AbstractDigitalOwDevice} class defines an abstract digital I/O device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractDigitalOwDevice extends AbstractOwDevice {
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractDigitalOwDevice.class);
|
||||
|
||||
protected @NonNullByDefault({}) OwserverDeviceParameter fullInParam;
|
||||
protected @NonNullByDefault({}) OwserverDeviceParameter fullOutParam;
|
||||
|
||||
protected final List<DigitalIoConfig> ioConfig = new ArrayList<>();
|
||||
|
||||
public AbstractDigitalOwDevice(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
Thing thing = callback.getThing();
|
||||
OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider = callback
|
||||
.getDynamicStateDescriptionProvider();
|
||||
|
||||
for (Integer i = 0; i < ioConfig.size(); i++) {
|
||||
String channelId = ioConfig.get(i).getChannelId();
|
||||
Channel channel = thing.getChannel(channelId);
|
||||
|
||||
if (channel != null) {
|
||||
Configuration channelConfig = channel.getConfiguration();
|
||||
|
||||
try {
|
||||
if (channelConfig.get(CONFIG_DIGITAL_MODE) != null) {
|
||||
ioConfig.get(i).setIoMode((String) channelConfig.get(CONFIG_DIGITAL_MODE));
|
||||
}
|
||||
if (channelConfig.get(CONFIG_DIGITAL_LOGIC) != null) {
|
||||
ioConfig.get(i).setIoLogic((String) channelConfig.get(CONFIG_DIGITAL_LOGIC));
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new OwException(channelId + " has invalid configuration");
|
||||
}
|
||||
|
||||
if (dynamicStateDescriptionProvider != null) {
|
||||
StateDescription stateDescription = StateDescriptionFragmentBuilder.create()
|
||||
.withReadOnly(ioConfig.get(i).isInput()).build().toStateDescription();
|
||||
if (stateDescription != null) {
|
||||
dynamicStateDescriptionProvider.setDescription(ioConfig.get(i).getChannelUID(),
|
||||
stateDescription);
|
||||
} else {
|
||||
logger.warn("Failed to create state description in thing {}", thing.getUID());
|
||||
}
|
||||
} else {
|
||||
logger.debug(
|
||||
"state description may be inaccurate, state description provider not available in thing {}",
|
||||
thing.getUID());
|
||||
}
|
||||
|
||||
logger.debug("configured {} channel {}: {}", thing.getUID(), i, ioConfig.get(i));
|
||||
} else {
|
||||
throw new OwException(channelId + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* refreshes this sensor - note that the update interval check is not performed as its and i/o device
|
||||
*/
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
logger.trace("refresh of sensor {} started", sensorId);
|
||||
if (isConfigured) {
|
||||
State state;
|
||||
|
||||
BitSet statesSensed = bridgeHandler.readBitSet(sensorId, fullInParam);
|
||||
BitSet statesPIO = bridgeHandler.readBitSet(sensorId, fullOutParam);
|
||||
|
||||
for (int i = 0; i < ioConfig.size(); i++) {
|
||||
if (ioConfig.get(i).isInput()) {
|
||||
state = ioConfig.get(i).convertState(statesSensed.get(i));
|
||||
logger.trace("{} IN{}: raw {}, final {}", sensorId, i, statesSensed, state);
|
||||
} else {
|
||||
state = ioConfig.get(i).convertState(statesPIO.get(i));
|
||||
logger.trace("{} OUT{}: raw {}, final {}", sensorId, i, statesPIO, state);
|
||||
}
|
||||
callback.postUpdate(ioConfig.get(i).getChannelId(), state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the number of channels
|
||||
*
|
||||
* @return number of channels
|
||||
*/
|
||||
public int getChannelCount() {
|
||||
return ioConfig.size();
|
||||
}
|
||||
|
||||
public boolean writeChannel(OwserverBridgeHandler bridgeHandler, Integer ioChannel, Command command) {
|
||||
if (ioChannel < getChannelCount()) {
|
||||
try {
|
||||
if (ioConfig.get(ioChannel).isOutput()) {
|
||||
bridgeHandler.writeDecimalType(sensorId, ioConfig.get(ioChannel).getParameter(),
|
||||
ioConfig.get(ioChannel).convertState((OnOffType) command));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (OwException e) {
|
||||
logger.info("could not write {} to {}: {}", command, ioChannel, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("channel number out of range");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AbstractOwClass} class defines an abstract onewire device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractOwDevice {
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractOwDevice.class);
|
||||
|
||||
protected SensorId sensorId;
|
||||
protected OwSensorType sensorType;
|
||||
protected OwBaseThingHandler callback;
|
||||
protected Boolean isConfigured = false;
|
||||
|
||||
protected Set<String> enabledChannels = new HashSet<>();
|
||||
|
||||
/**
|
||||
* constructor for the onewire device
|
||||
*
|
||||
* @param sensorId onewire ID of the sensor
|
||||
* @param callback ThingHandler callback for posting updates
|
||||
*/
|
||||
public AbstractOwDevice(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
this.sensorId = sensorId;
|
||||
this.callback = callback;
|
||||
this.sensorType = OwSensorType.UNKNOWN;
|
||||
}
|
||||
|
||||
public AbstractOwDevice(SensorId sensorId, OwSensorType sensorType, OwBaseThingHandler callback) {
|
||||
this.sensorId = sensorId;
|
||||
this.callback = callback;
|
||||
this.sensorType = sensorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* configures the onewire devices channels
|
||||
*
|
||||
*/
|
||||
public abstract void configureChannels() throws OwException;
|
||||
|
||||
/**
|
||||
* refresh this sensor
|
||||
*
|
||||
* @param bridgeHandler for sending requests
|
||||
* @param forcedRefresh post update even if state did not change
|
||||
* @throws OwException in case of communication error
|
||||
*/
|
||||
public abstract void refresh(OwserverBridgeHandler owBridgeHandler, Boolean forcedRefresh) throws OwException;
|
||||
|
||||
/**
|
||||
* enables a channel on this device
|
||||
*
|
||||
* @param channelID the channels channelID
|
||||
*/
|
||||
public void enableChannel(String channelID) {
|
||||
if (!enabledChannels.contains(channelID)) {
|
||||
enabledChannels.add(channelID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disables a channel on this device
|
||||
*
|
||||
* @param channelID the channels channelID
|
||||
*/
|
||||
public void disableChannel(String channelID) {
|
||||
if (enabledChannels.contains(channelID)) {
|
||||
enabledChannels.remove(channelID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get onewire ID of this sensor
|
||||
*
|
||||
* @return sensor ID
|
||||
*/
|
||||
public SensorId getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
/**
|
||||
* check sensor presence and update thing state
|
||||
*
|
||||
* @param owServerConnection
|
||||
* @return sensors presence state
|
||||
*/
|
||||
|
||||
public Boolean checkPresence(OwserverBridgeHandler bridgeHandler) {
|
||||
try {
|
||||
State present = bridgeHandler.checkPresence(sensorId);
|
||||
callback.updatePresenceStatus(present);
|
||||
return OnOffType.ON.equals(present);
|
||||
} catch (OwException e) {
|
||||
logger.debug("error refreshing presence {} on bridge {}: {}", this.sensorId,
|
||||
bridgeHandler.getThing().getUID(), e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get this sensors type
|
||||
*
|
||||
* @param bridgeHandler bridge handler to request from if type formerly unknown
|
||||
* @return this sensors type
|
||||
* @throws OwException
|
||||
*/
|
||||
public OwSensorType getSensorType(OwserverBridgeHandler bridgeHandler) throws OwException {
|
||||
if (sensorType == OwSensorType.UNKNOWN) {
|
||||
sensorType = bridgeHandler.getType(sensorId);
|
||||
}
|
||||
return sensorType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,408 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Frequency;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.config.BAE091xAnalogConfiguration;
|
||||
import org.openhab.binding.onewire.internal.config.BAE091xPIOConfiguration;
|
||||
import org.openhab.binding.onewire.internal.config.BAE091xPWMConfiguration;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
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.Channel;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BAE0910} class defines an BAE0910 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BAE0910 extends AbstractOwDevice {
|
||||
private static final int OUTC_OUTEN = 4;
|
||||
private static final int OUTC_DS = 3;
|
||||
|
||||
private static final int PIOC_PIOEN = 4;
|
||||
private static final int PIOC_DS = 3;
|
||||
private static final int PIOC_PD = 2;
|
||||
private static final int PIOC_PE = 1;
|
||||
private static final int PIOC_DD = 0;
|
||||
|
||||
private static final int ADCC_ADCEN = 4;
|
||||
private static final int ADCC_10BIT = 3;
|
||||
@SuppressWarnings("unused") // for future use
|
||||
private static final int ADCC_OFS = 2;
|
||||
@SuppressWarnings("unused")
|
||||
private static final int ADCC_GRP = 1;
|
||||
@SuppressWarnings("unused")
|
||||
private static final int ADCC_STP = 0;
|
||||
|
||||
private static final int TPMC_POL = 7;
|
||||
private static final int TPMC_INENA = 5;
|
||||
private static final int TPMC_PWMDIS = 4;
|
||||
private static final int TPMC_PS2 = 2;
|
||||
private static final int TPMC_PS1 = 1;
|
||||
private static final int TPMC_PS0 = 0;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BAE0910.class);
|
||||
private final OwserverDeviceParameter pin1CounterParameter = new OwserverDeviceParameter("/counter");
|
||||
private final OwserverDeviceParameter pin2OutParameter = new OwserverDeviceParameter("/out");
|
||||
private final OwserverDeviceParameter pin6PIOParameter = new OwserverDeviceParameter("/pio");
|
||||
private final OwserverDeviceParameter pin7AnalogParameter = new OwserverDeviceParameter("/adc");
|
||||
private final OwserverDeviceParameter outcParameter = new OwserverDeviceParameter("/outc");
|
||||
private final OwserverDeviceParameter piocParameter = new OwserverDeviceParameter("/pioc");
|
||||
private final OwserverDeviceParameter adccParameter = new OwserverDeviceParameter("/adcc");
|
||||
private final OwserverDeviceParameter tpm1cParameter = new OwserverDeviceParameter("/tpm1c");
|
||||
private final OwserverDeviceParameter tpm2cParameter = new OwserverDeviceParameter("/tpm2c");
|
||||
private final OwserverDeviceParameter period1Parameter = new OwserverDeviceParameter("/period1");
|
||||
private final OwserverDeviceParameter period2Parameter = new OwserverDeviceParameter("/period2");
|
||||
private final OwserverDeviceParameter duty1Parameter = new OwserverDeviceParameter("/duty1");
|
||||
private final OwserverDeviceParameter duty2Parameter = new OwserverDeviceParameter("/duty2");
|
||||
private final OwserverDeviceParameter duty3Parameter = new OwserverDeviceParameter("/duty3");
|
||||
private final OwserverDeviceParameter duty4Parameter = new OwserverDeviceParameter("/duty4");
|
||||
|
||||
private BitSet outcRegister = new BitSet(8);
|
||||
private BitSet piocRegister = new BitSet(8);
|
||||
private BitSet adccRegister = new BitSet(8);
|
||||
private BitSet tpm1cRegister = new BitSet(8);
|
||||
private BitSet tpm2cRegister = new BitSet(8);
|
||||
|
||||
private double resolution1 = 8; // in µs
|
||||
private double resolution2 = 8; // in µs
|
||||
|
||||
public BAE0910(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() {
|
||||
}
|
||||
|
||||
public void configureChannels(OwserverBridgeHandler bridgeHandler) throws OwException {
|
||||
outcRegister.clear();
|
||||
piocRegister.clear();
|
||||
adccRegister.clear();
|
||||
tpm1cRegister.clear();
|
||||
tpm2cRegister.clear();
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_PWM_FREQ1)) {
|
||||
Channel channel = callback.getThing().getChannel(CHANNEL_PWM_FREQ1);
|
||||
if (channel != null) {
|
||||
BAE091xPWMConfiguration channelConfig = channel.getConfiguration().as(BAE091xPWMConfiguration.class);
|
||||
tpm1cRegister.set(TPMC_POL, channelConfig.reversePolarity);
|
||||
tpm1cRegister.set(TPMC_PS2, (channelConfig.prescaler & 4) == 4);
|
||||
tpm1cRegister.set(TPMC_PS1, (channelConfig.prescaler & 2) == 2);
|
||||
tpm1cRegister.set(TPMC_PS0, (channelConfig.prescaler & 1) == 1);
|
||||
resolution1 = 0.0625 * (1 << channelConfig.prescaler);
|
||||
} else {
|
||||
throw new OwException("trying to configure pwm but frequency channel is missing");
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_PWM_FREQ2)) {
|
||||
Channel channel = callback.getThing().getChannel(CHANNEL_PWM_FREQ2);
|
||||
if (channel != null) {
|
||||
BAE091xPWMConfiguration channelConfig = channel.getConfiguration().as(BAE091xPWMConfiguration.class);
|
||||
tpm2cRegister.set(TPMC_POL, channelConfig.reversePolarity);
|
||||
tpm2cRegister.set(TPMC_PS2, (channelConfig.prescaler & 4) == 4);
|
||||
tpm2cRegister.set(TPMC_PS1, (channelConfig.prescaler & 2) == 2);
|
||||
tpm2cRegister.set(TPMC_PS0, (channelConfig.prescaler & 1) == 1);
|
||||
resolution2 = 0.0625 * (1 << channelConfig.prescaler);
|
||||
} else {
|
||||
throw new OwException("trying to configure pwm but frequency channel is missing");
|
||||
}
|
||||
}
|
||||
|
||||
// Pin 2
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
|
||||
outcRegister.set(OUTC_DS);
|
||||
outcRegister.set(OUTC_OUTEN);
|
||||
}
|
||||
|
||||
// Pin 6
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
|
||||
piocRegister.set(PIOC_PIOEN);
|
||||
piocRegister.set(PIOC_DS);
|
||||
Channel channel = callback.getThing().getChannel(CHANNEL_DIGITAL6);
|
||||
if (channel != null) {
|
||||
BAE091xPIOConfiguration channelConfig = channel.getConfiguration().as(BAE091xPIOConfiguration.class);
|
||||
piocRegister.set(PIOC_DD, channelConfig.mode.equals("output"));
|
||||
switch (channelConfig.pulldevice) {
|
||||
case "pullup":
|
||||
piocRegister.set(PIOC_PE);
|
||||
piocRegister.clear(PIOC_PD);
|
||||
break;
|
||||
case "pulldown":
|
||||
piocRegister.set(PIOC_PE);
|
||||
piocRegister.set(PIOC_PD);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
throw new OwException("trying to configure pin 6 but channel is missing");
|
||||
}
|
||||
}
|
||||
|
||||
// Pin 7
|
||||
if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
|
||||
adccRegister.set(ADCC_ADCEN);
|
||||
Channel channel = callback.getThing().getChannel(CHANNEL_VOLTAGE);
|
||||
if (channel != null) {
|
||||
BAE091xAnalogConfiguration channelConfig = channel.getConfiguration()
|
||||
.as(BAE091xAnalogConfiguration.class);
|
||||
adccRegister.set(ADCC_10BIT, channelConfig.hires);
|
||||
} else {
|
||||
throw new OwException("trying to configure pin 7 but channel is missing");
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
|
||||
tpm2cRegister.set(TPMC_PWMDIS);
|
||||
}
|
||||
|
||||
// Pin 8
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
|
||||
tpm1cRegister.set(TPMC_PWMDIS);
|
||||
Channel channel = callback.getThing().getChannel(CHANNEL_DIGITAL8);
|
||||
if (channel != null) {
|
||||
if ((new ChannelTypeUID(BINDING_ID, "bae-in")).equals(channel.getChannelTypeUID())) {
|
||||
tpm1cRegister.set(TPMC_INENA);
|
||||
}
|
||||
} else {
|
||||
throw new OwException("trying to configure pin 8 but channel is missing");
|
||||
}
|
||||
}
|
||||
|
||||
// write configuration
|
||||
bridgeHandler.writeBitSet(sensorId, outcParameter, outcRegister);
|
||||
bridgeHandler.writeBitSet(sensorId, piocParameter, piocRegister);
|
||||
bridgeHandler.writeBitSet(sensorId, adccParameter, adccRegister);
|
||||
bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
|
||||
bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
|
||||
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
if (isConfigured) {
|
||||
logger.trace("refresh of sensor {} started", sensorId);
|
||||
// Counter
|
||||
if (enabledChannels.contains(CHANNEL_COUNTER)) {
|
||||
State counterValue = bridgeHandler.readDecimalType(sensorId, pin1CounterParameter);
|
||||
callback.postUpdate(CHANNEL_COUNTER, counterValue);
|
||||
}
|
||||
|
||||
// Digital Pins
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL2)) {
|
||||
BitSet value = bridgeHandler.readBitSet(sensorId, pin2OutParameter);
|
||||
callback.postUpdate(CHANNEL_DIGITAL2, OnOffType.from(value.get(0)));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL6)) {
|
||||
BitSet value = bridgeHandler.readBitSet(sensorId, pin6PIOParameter);
|
||||
callback.postUpdate(CHANNEL_DIGITAL6, OnOffType.from(value.get(0)));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL7)) {
|
||||
BitSet value = bridgeHandler.readBitSet(sensorId, tpm2cParameter);
|
||||
callback.postUpdate(CHANNEL_DIGITAL7, OnOffType.from(value.get(TPMC_POL)));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_DIGITAL8)) {
|
||||
BitSet value = bridgeHandler.readBitSet(sensorId, tpm1cParameter);
|
||||
callback.postUpdate(CHANNEL_DIGITAL8, OnOffType.from(value.get(TPMC_POL)));
|
||||
}
|
||||
|
||||
// Analog
|
||||
if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
|
||||
State analogValue = bridgeHandler.readDecimalType(sensorId, pin7AnalogParameter);
|
||||
callback.postUpdate(CHANNEL_VOLTAGE,
|
||||
new QuantityType<>((DecimalType) analogValue, SmartHomeUnits.VOLT));
|
||||
}
|
||||
|
||||
// PWM
|
||||
int period1 = 0;
|
||||
int period2 = 0;
|
||||
if (enabledChannels.contains(CHANNEL_PWM_FREQ1)) {
|
||||
period1 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)).intValue();
|
||||
double frequency = (period1 > 0) ? 1 / (period1 * resolution1 * 1e-6) : 0;
|
||||
callback.postUpdate(CHANNEL_PWM_FREQ1, new QuantityType<>(frequency, SmartHomeUnits.HERTZ));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_PWM_FREQ2)) {
|
||||
period2 = ((DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)).intValue();
|
||||
double frequency = (period2 > 0) ? 1 / (period2 * resolution2 * 1e-6) : 0;
|
||||
callback.postUpdate(CHANNEL_PWM_FREQ2, new QuantityType<>(frequency, SmartHomeUnits.HERTZ));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_PWM_DUTY1)) {
|
||||
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty1Parameter)).intValue();
|
||||
double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
|
||||
callback.postUpdate(CHANNEL_PWM_DUTY1, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_PWM_DUTY2)) {
|
||||
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty2Parameter)).intValue();
|
||||
double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
|
||||
callback.postUpdate(CHANNEL_PWM_DUTY2, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_PWM_DUTY3)) {
|
||||
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty3Parameter)).intValue();
|
||||
double duty = (period1 > 0 && dutyValue <= period1) ? 100 * dutyValue / period1 : 100;
|
||||
callback.postUpdate(CHANNEL_PWM_DUTY3, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
|
||||
}
|
||||
if (enabledChannels.contains(CHANNEL_PWM_DUTY4)) {
|
||||
int dutyValue = ((DecimalType) bridgeHandler.readDecimalType(sensorId, duty4Parameter)).intValue();
|
||||
double duty = (period2 > 0 && dutyValue <= period2) ? 100 * dutyValue / period2 : 100;
|
||||
callback.postUpdate(CHANNEL_PWM_DUTY4, new QuantityType<>(duty, SmartHomeUnits.PERCENT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean writeChannel(OwserverBridgeHandler bridgeHandler, String channelId, Command command) {
|
||||
try {
|
||||
BitSet value = new BitSet(8);
|
||||
switch (channelId) {
|
||||
case CHANNEL_DIGITAL2:
|
||||
// output
|
||||
if (!outcRegister.get(OUTC_OUTEN)) {
|
||||
return false;
|
||||
}
|
||||
value.set(0, ((OnOffType) command).equals(OnOffType.ON));
|
||||
bridgeHandler.writeBitSet(sensorId, pin2OutParameter, value);
|
||||
break;
|
||||
case CHANNEL_DIGITAL6:
|
||||
// not input, pio
|
||||
if (!piocRegister.get(PIOC_DD) || !piocRegister.get(PIOC_PIOEN)) {
|
||||
return false;
|
||||
}
|
||||
value.set(0, ((OnOffType) command).equals(OnOffType.ON));
|
||||
bridgeHandler.writeBitSet(sensorId, pin6PIOParameter, value);
|
||||
break;
|
||||
case CHANNEL_DIGITAL7:
|
||||
// not pwm, not analog
|
||||
if (!tpm2cRegister.get(TPMC_PWMDIS) || adccRegister.get(ADCC_ADCEN)) {
|
||||
return false;
|
||||
}
|
||||
tpm2cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
|
||||
bridgeHandler.writeBitSet(sensorId, tpm2cParameter, tpm2cRegister);
|
||||
break;
|
||||
case CHANNEL_DIGITAL8:
|
||||
// not input, not pwm
|
||||
if (tpm1cRegister.get(TPMC_INENA) || !tpm1cRegister.get(TPMC_PWMDIS)) {
|
||||
return false;
|
||||
}
|
||||
tpm1cRegister.set(TPMC_POL, ((OnOffType) command).equals(OnOffType.ON));
|
||||
bridgeHandler.writeBitSet(sensorId, tpm1cParameter, tpm1cRegister);
|
||||
break;
|
||||
case CHANNEL_PWM_FREQ1:
|
||||
if (command instanceof QuantityType<?>) {
|
||||
bridgeHandler.writeDecimalType(sensorId, period1Parameter,
|
||||
convertFrequencyToPeriod(command, resolution1));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PWM_FREQ2:
|
||||
if (command instanceof QuantityType<?>) {
|
||||
bridgeHandler.writeDecimalType(sensorId, period2Parameter,
|
||||
convertFrequencyToPeriod(command, resolution2));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PWM_DUTY1:
|
||||
if (command instanceof QuantityType<?>) {
|
||||
bridgeHandler.writeDecimalType(sensorId, duty1Parameter, calculateDutyCycle(command,
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PWM_DUTY2:
|
||||
if (command instanceof QuantityType<?>) {
|
||||
bridgeHandler.writeDecimalType(sensorId, duty2Parameter, calculateDutyCycle(command,
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PWM_DUTY3:
|
||||
if (command instanceof QuantityType<?>) {
|
||||
bridgeHandler.writeDecimalType(sensorId, duty3Parameter, calculateDutyCycle(command,
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, period1Parameter)));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_PWM_DUTY4:
|
||||
if (command instanceof QuantityType<?>) {
|
||||
bridgeHandler.writeDecimalType(sensorId, duty4Parameter, calculateDutyCycle(command,
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, period2Parameter)));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new OwException("unknown or invalid channel");
|
||||
}
|
||||
return true;
|
||||
} catch (
|
||||
|
||||
OwException e) {
|
||||
logger.info("could not write {} to {}: {}", command, channelId, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static OwSensorType getDeviceSubType(OwserverBridgeHandler bridgeHandler, SensorId sensorId)
|
||||
throws OwException {
|
||||
OwserverDeviceParameter deviceTypeParameter = new OwserverDeviceParameter("/device_type");
|
||||
|
||||
String subDeviceType = bridgeHandler.readString(sensorId, deviceTypeParameter);
|
||||
switch (subDeviceType) {
|
||||
case "2":
|
||||
return OwSensorType.BAE0910;
|
||||
case "3":
|
||||
return OwSensorType.BAE0911;
|
||||
default:
|
||||
return OwSensorType.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private DecimalType convertFrequencyToPeriod(Command command, double resolution) throws OwException {
|
||||
@SuppressWarnings("unchecked")
|
||||
QuantityType<Frequency> fHz = ((QuantityType<Frequency>) command).toUnit(SmartHomeUnits.HERTZ);
|
||||
if (fHz == null) {
|
||||
throw new OwException("could not convert command to frequency");
|
||||
}
|
||||
double f = fHz.doubleValue();
|
||||
int period = 0;
|
||||
if (f > 0) {
|
||||
period = (int) Math.min(Math.round(1 / (f * resolution * 1e-6)), 65535);
|
||||
}
|
||||
return new DecimalType(period);
|
||||
}
|
||||
|
||||
private DecimalType calculateDutyCycle(Command command, DecimalType period) throws OwException {
|
||||
@SuppressWarnings("unchecked")
|
||||
double dutyCycle = ((QuantityType<Dimensionless>) command).doubleValue();
|
||||
int dutyValue = 0;
|
||||
if (dutyCycle > 0 && dutyCycle <= 100) {
|
||||
dutyValue = (int) Math.round(dutyCycle / 100.0 * period.intValue());
|
||||
} else if (dutyCycle > 100) {
|
||||
dutyValue = 65535;
|
||||
}
|
||||
return new DecimalType(dutyValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link DS18x20} class defines an DS18x20 or DS1822 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS18x20 extends AbstractOwDevice {
|
||||
private final Logger logger = LoggerFactory.getLogger(DS18x20.class);
|
||||
|
||||
private OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
|
||||
|
||||
private boolean ignorePOR = false;
|
||||
|
||||
public DS18x20(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
Thing thing = callback.getThing();
|
||||
Channel temperatureChannel = thing.getChannel(CHANNEL_TEMPERATURE);
|
||||
|
||||
if (temperatureChannel != null) {
|
||||
Configuration channelConfiguration = temperatureChannel.getConfiguration();
|
||||
if (channelConfiguration.containsKey(CONFIG_RESOLUTION)) {
|
||||
temperatureParameter = new OwserverDeviceParameter(
|
||||
"/temperature" + (String) channelConfiguration.get(CONFIG_RESOLUTION));
|
||||
} else {
|
||||
temperatureParameter = new OwserverDeviceParameter("/temperature");
|
||||
}
|
||||
if (channelConfiguration.containsKey(CONFIG_IGNORE_POR)) {
|
||||
ignorePOR = (Boolean) channelConfiguration.get(CONFIG_IGNORE_POR);
|
||||
} else {
|
||||
ignorePOR = false;
|
||||
}
|
||||
} else {
|
||||
throw new OwException(CHANNEL_TEMPERATURE + " not found");
|
||||
}
|
||||
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
if (isConfigured && enabledChannels.contains(CHANNEL_TEMPERATURE)) {
|
||||
logger.trace("refresh of sensor {} started", sensorId);
|
||||
QuantityType<Temperature> temperature = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
|
||||
logger.trace("read temperature {} from {}", temperature, sensorId);
|
||||
if (ignorePOR && (Double.compare(temperature.doubleValue(), 85.0) == 0)) {
|
||||
logger.trace("ignored POR value from sensor {}", sensorId);
|
||||
} else {
|
||||
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.Util;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link DS1923} class defines an DS1923 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
* @author Michał Wójcik - Adapted to DS1923
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS1923 extends AbstractOwDevice {
|
||||
private final Logger logger = LoggerFactory.getLogger(DS1923.class);
|
||||
private final OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
|
||||
private final OwserverDeviceParameter humidityParameter = new OwserverDeviceParameter("/humidity");
|
||||
|
||||
public DS1923(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
if (isConfigured) {
|
||||
logger.trace("refresh of sensor {} started", sensorId);
|
||||
if (enabledChannels.contains(CHANNEL_TEMPERATURE) || enabledChannels.contains(CHANNEL_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
QuantityType<Temperature> temperature = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
|
||||
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_HUMIDITY) || enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
QuantityType<Dimensionless> humidity = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, humidityParameter),
|
||||
SmartHomeUnits.PERCENT);
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_HUMIDITY)) {
|
||||
callback.postUpdate(CHANNEL_HUMIDITY, humidity);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)) {
|
||||
callback.postUpdate(CHANNEL_ABSOLUTE_HUMIDITY,
|
||||
Util.calculateAbsoluteHumidity(temperature, humidity));
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
callback.postUpdate(CHANNEL_DEWPOINT, Util.calculateDewpoint(temperature, humidity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
|
||||
/**
|
||||
* The {@link DS2401} class defines an DS2401 (iButton) device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2401 extends AbstractOwDevice {
|
||||
public DS2401(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.DigitalIoConfig;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
|
||||
/**
|
||||
* The {@link DS2405} class defines an DS2405 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2405 extends AbstractDigitalOwDevice {
|
||||
public DS2405(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
OwserverDeviceParameter inParam = new OwserverDeviceParameter("uncached/", "/sensed");
|
||||
OwserverDeviceParameter outParam = new OwserverDeviceParameter("/PIO");
|
||||
|
||||
ioConfig.add(new DigitalIoConfig(callback.getThing(), 0, inParam, outParam));
|
||||
|
||||
fullInParam = inParam;
|
||||
fullOutParam = outParam;
|
||||
|
||||
super.configureChannels();
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.DigitalIoConfig;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
|
||||
/**
|
||||
* The {@link DS2406_DS2413} class defines an DS2406 or DS2413 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2406_DS2413 extends AbstractDigitalOwDevice {
|
||||
public DS2406_DS2413(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
ioConfig.clear();
|
||||
ioConfig.add(new DigitalIoConfig(callback.getThing(), 0, new OwserverDeviceParameter("uncached/", "/sensed.A"),
|
||||
new OwserverDeviceParameter("/PIO.A")));
|
||||
ioConfig.add(new DigitalIoConfig(callback.getThing(), 1, new OwserverDeviceParameter("uncached/", "/sensed.B"),
|
||||
new OwserverDeviceParameter("/PIO.B")));
|
||||
|
||||
fullInParam = new OwserverDeviceParameter("uncached/", "/sensed.BYTE");
|
||||
fullOutParam = new OwserverDeviceParameter("/PIO.BYTE");
|
||||
|
||||
super.configureChannels();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.DigitalIoConfig;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
|
||||
/**
|
||||
* The {@link DS2408} class defines an DS2408 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2408 extends AbstractDigitalOwDevice {
|
||||
public DS2408(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
ioConfig.clear();
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ioConfig.add(new DigitalIoConfig(callback.getThing(), i,
|
||||
new OwserverDeviceParameter("uncached/", String.format("/sensed.%d", i)),
|
||||
new OwserverDeviceParameter(String.format("/PIO.%d", i))));
|
||||
}
|
||||
|
||||
fullInParam = new OwserverDeviceParameter("uncached/", "/sensed.BYTE");
|
||||
fullOutParam = new OwserverDeviceParameter("/PIO.BYTE");
|
||||
|
||||
super.configureChannels();
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_COUNTER;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link DS2423} class defines an DS2423 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2423 extends AbstractOwDevice {
|
||||
private final Logger logger = LoggerFactory.getLogger(DS2423.class);
|
||||
private final OwserverDeviceParameter counterParameter = new OwserverDeviceParameter("/counters.ALL");
|
||||
|
||||
public DS2423(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() throws OwException {
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
if (isConfigured) {
|
||||
logger.trace("refresh of sensor {} started", sensorId);
|
||||
List<State> states = bridgeHandler.readDecimalTypeArray(sensorId, counterParameter);
|
||||
|
||||
if (states.size() != 2) {
|
||||
throw new OwException("Expected exactly two values, got " + String.valueOf(states.size()));
|
||||
} else {
|
||||
callback.postUpdate(CHANNEL_COUNTER + "0", states.get(0));
|
||||
callback.postUpdate(CHANNEL_COUNTER + "1", states.get(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
import static org.openhab.core.library.unit.MetricPrefix.MILLI;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.Util;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
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.Thing;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link DS2438} class defines an DS2438 device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2438 extends AbstractOwDevice {
|
||||
private final Logger logger = LoggerFactory.getLogger(DS2438.class);
|
||||
|
||||
public enum LightSensorType {
|
||||
ELABNET_V1,
|
||||
ELABNET_V2,
|
||||
IBUTTONLINK
|
||||
}
|
||||
|
||||
public enum CurrentSensorType {
|
||||
INTERNAL,
|
||||
IBUTTONLINK
|
||||
}
|
||||
|
||||
private LightSensorType lightSensorType = LightSensorType.ELABNET_V1;
|
||||
private CurrentSensorType currentSensorType = CurrentSensorType.INTERNAL;
|
||||
|
||||
private final OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
|
||||
private OwserverDeviceParameter humidityParameter = new OwserverDeviceParameter("/humidity");
|
||||
private final OwserverDeviceParameter voltageParameter = new OwserverDeviceParameter("/VAD");
|
||||
private final OwserverDeviceParameter currentParamater = new OwserverDeviceParameter("/vis");
|
||||
private final OwserverDeviceParameter supplyVoltageParameter = new OwserverDeviceParameter("/VDD");
|
||||
|
||||
public DS2438(SensorId sensorId, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() {
|
||||
Thing thing = callback.getThing();
|
||||
|
||||
Channel humidityChannel = thing.getChannel(CHANNEL_HUMIDITY);
|
||||
if (humidityChannel != null) {
|
||||
Configuration channelConfiguration = humidityChannel.getConfiguration();
|
||||
if (channelConfiguration.get(CONFIG_HUMIDITY) != null) {
|
||||
humidityParameter = new OwserverDeviceParameter((String) channelConfiguration.get(CONFIG_HUMIDITY));
|
||||
} else {
|
||||
humidityParameter = new OwserverDeviceParameter("/humidity");
|
||||
}
|
||||
}
|
||||
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
if (isConfigured) {
|
||||
logger.trace("refresh of sensor {} started", sensorId);
|
||||
double Vcc = 5.0;
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_TEMPERATURE) || enabledChannels.contains(CHANNEL_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
QuantityType<Temperature> temperature = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
|
||||
logger.trace("read temperature {} from {}", temperature, sensorId);
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_TEMPERATURE)) {
|
||||
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_HUMIDITY) || enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
QuantityType<Dimensionless> humidity = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, humidityParameter),
|
||||
SmartHomeUnits.PERCENT);
|
||||
logger.trace("read humidity {} from {}", humidity, sensorId);
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_HUMIDITY)) {
|
||||
callback.postUpdate(CHANNEL_HUMIDITY, humidity);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)) {
|
||||
callback.postUpdate(CHANNEL_ABSOLUTE_HUMIDITY,
|
||||
Util.calculateAbsoluteHumidity(temperature, humidity));
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
callback.postUpdate(CHANNEL_DEWPOINT, Util.calculateDewpoint(temperature, humidity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_VOLTAGE)) {
|
||||
double measured = ((DecimalType) bridgeHandler.readDecimalType(sensorId, voltageParameter))
|
||||
.doubleValue();
|
||||
if (measured < 0 || measured > 10.0) {
|
||||
// workaround bug in DS2438
|
||||
measured = 0.0;
|
||||
}
|
||||
State voltage = new QuantityType<>(measured, SmartHomeUnits.VOLT);
|
||||
|
||||
logger.trace("read voltage {} from {}", voltage, sensorId);
|
||||
callback.postUpdate(CHANNEL_VOLTAGE, voltage);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_CURRENT)) {
|
||||
if (currentSensorType == CurrentSensorType.IBUTTONLINK) {
|
||||
State current = bridgeHandler.readDecimalType(sensorId, voltageParameter);
|
||||
if (current instanceof DecimalType) {
|
||||
double currentDouble = ((DecimalType) current).doubleValue();
|
||||
if (currentDouble >= 0.1 || currentDouble <= 3.78) {
|
||||
current = new QuantityType<>(currentDouble * 5.163 + 0.483, SmartHomeUnits.AMPERE);
|
||||
}
|
||||
callback.postUpdate(CHANNEL_CURRENT, current);
|
||||
} else {
|
||||
callback.postUpdate(CHANNEL_CURRENT, UnDefType.UNDEF);
|
||||
}
|
||||
} else {
|
||||
State current = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, currentParamater),
|
||||
MILLI(SmartHomeUnits.AMPERE));
|
||||
callback.postUpdate(CHANNEL_CURRENT, current);
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_SUPPLYVOLTAGE)) {
|
||||
Vcc = ((DecimalType) bridgeHandler.readDecimalType(sensorId, supplyVoltageParameter)).doubleValue();
|
||||
State supplyVoltage = new QuantityType<>(Vcc, SmartHomeUnits.VOLT);
|
||||
callback.postUpdate(CHANNEL_SUPPLYVOLTAGE, supplyVoltage);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_LIGHT)) {
|
||||
switch (lightSensorType) {
|
||||
case ELABNET_V2:
|
||||
State light = bridgeHandler.readDecimalType(sensorId, currentParamater);
|
||||
if (light instanceof DecimalType) {
|
||||
light = new QuantityType<>(
|
||||
Math.round(Math.pow(10, ((DecimalType) light).doubleValue() / 47 * 1000)),
|
||||
SmartHomeUnits.LUX);
|
||||
callback.postUpdate(CHANNEL_LIGHT, light);
|
||||
}
|
||||
break;
|
||||
case ELABNET_V1:
|
||||
light = bridgeHandler.readDecimalType(sensorId, currentParamater);
|
||||
if (light instanceof DecimalType) {
|
||||
light = new QuantityType<>(Math.round(Math
|
||||
.exp(1.059 * Math.log(1000000 * ((DecimalType) light).doubleValue() / (4096 * 390))
|
||||
+ 4.518)
|
||||
* 20000), SmartHomeUnits.LUX);
|
||||
callback.postUpdate(CHANNEL_LIGHT, light);
|
||||
}
|
||||
break;
|
||||
case IBUTTONLINK:
|
||||
double measured = ((DecimalType) bridgeHandler.readDecimalType(sensorId, voltageParameter))
|
||||
.doubleValue();
|
||||
if (measured <= 0 || measured > 10.0) {
|
||||
// workaround bug in DS2438
|
||||
light = new QuantityType<>(0, SmartHomeUnits.LUX);
|
||||
} else {
|
||||
light = new QuantityType<>(Math.pow(10, (65 / 7.5) - (47 / 7.5) * (Vcc / measured)),
|
||||
SmartHomeUnits.LUX);
|
||||
}
|
||||
callback.postUpdate(CHANNEL_LIGHT, light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the type of the attached light sensor
|
||||
*
|
||||
* @param lightSensorType
|
||||
*/
|
||||
public void setLightSensorType(LightSensorType lightSensorType) {
|
||||
this.lightSensorType = lightSensorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the type of the attached current sensor
|
||||
*
|
||||
* @param currentSensorType
|
||||
*/
|
||||
public void setCurrentSensorType(CurrentSensorType currentSensorType) {
|
||||
this.currentSensorType = currentSensorType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Illuminance;
|
||||
import javax.measure.quantity.Pressure;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.Util;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.MetricPrefix;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link EDS006x} class defines an EDS006x device
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EDS006x extends AbstractOwDevice {
|
||||
private final Logger logger = LoggerFactory.getLogger(EDS006x.class);
|
||||
private OwserverDeviceParameter temperatureParameter = new OwserverDeviceParameter("/temperature");
|
||||
private OwserverDeviceParameter humidityParameter = new OwserverDeviceParameter("/humidity");
|
||||
private OwserverDeviceParameter pressureParameter = new OwserverDeviceParameter("/pressure");
|
||||
private OwserverDeviceParameter lightParameter = new OwserverDeviceParameter("/light");
|
||||
|
||||
public EDS006x(SensorId sensorId, OwSensorType sensorType, OwBaseThingHandler callback) {
|
||||
super(sensorId, callback);
|
||||
|
||||
String sensorTypeName = sensorType.name();
|
||||
temperatureParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/temperature");
|
||||
humidityParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/humidity");
|
||||
pressureParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/pressure");
|
||||
lightParameter = new OwserverDeviceParameter("/" + sensorTypeName + "/light");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChannels() {
|
||||
isConfigured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, Boolean forcedRefresh) throws OwException {
|
||||
if (isConfigured) {
|
||||
logger.trace("refresh of sensor {} started", sensorId);
|
||||
if (enabledChannels.contains(CHANNEL_TEMPERATURE) || enabledChannels.contains(CHANNEL_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
QuantityType<Temperature> temperature = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, temperatureParameter), SIUnits.CELSIUS);
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_TEMPERATURE)) {
|
||||
callback.postUpdate(CHANNEL_TEMPERATURE, temperature);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_HUMIDITY) || enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)
|
||||
|| enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
QuantityType<Dimensionless> humidity = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, humidityParameter),
|
||||
SmartHomeUnits.PERCENT);
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_HUMIDITY)) {
|
||||
callback.postUpdate(CHANNEL_HUMIDITY, humidity);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_ABSOLUTE_HUMIDITY)) {
|
||||
callback.postUpdate(CHANNEL_ABSOLUTE_HUMIDITY,
|
||||
Util.calculateAbsoluteHumidity(temperature, humidity));
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_DEWPOINT)) {
|
||||
callback.postUpdate(CHANNEL_DEWPOINT, Util.calculateDewpoint(temperature, humidity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_LIGHT)) {
|
||||
QuantityType<Illuminance> light = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, lightParameter), SmartHomeUnits.LUX);
|
||||
callback.postUpdate(CHANNEL_LIGHT, light);
|
||||
}
|
||||
|
||||
if (enabledChannels.contains(CHANNEL_PRESSURE)) {
|
||||
QuantityType<Pressure> pressure = new QuantityType<>(
|
||||
(DecimalType) bridgeHandler.readDecimalType(sensorId, pressureParameter),
|
||||
MetricPrefix.HECTO(SIUnits.PASCAL));
|
||||
callback.postUpdate(CHANNEL_PRESSURE, pressure);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.BINDING_ID;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link OwChannelConfig} class defines a map entry
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwChannelConfig {
|
||||
private static final Pattern CONFIG_PATTERN = Pattern.compile("^(.+):(.+):(.*)$");
|
||||
|
||||
public String channelId;
|
||||
public ChannelTypeUID channelTypeUID;
|
||||
public @Nullable String label;
|
||||
|
||||
public OwChannelConfig(String channelId, ChannelTypeUID channelTypeUID, @Nullable String label) {
|
||||
this.channelId = channelId;
|
||||
this.channelTypeUID = channelTypeUID;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public OwChannelConfig(String channelId, ChannelTypeUID channelTypeUID) {
|
||||
this(channelId, channelTypeUID, null);
|
||||
}
|
||||
|
||||
public static OwChannelConfig fromString(String configString) {
|
||||
Matcher matcher = CONFIG_PATTERN.matcher(configString);
|
||||
if (matcher.matches()) {
|
||||
if (matcher.group(3).trim().isEmpty()) {
|
||||
return new OwChannelConfig(matcher.group(1).trim(),
|
||||
new ChannelTypeUID(BINDING_ID, matcher.group(2).trim()));
|
||||
} else {
|
||||
return new OwChannelConfig(matcher.group(1).trim(),
|
||||
new ChannelTypeUID(BINDING_ID, matcher.group(2).trim()), matcher.group(3).trim());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return channelId + "/" + channelTypeUID.getAsString() + "/" + label;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.onewire.internal.device;
|
||||
|
||||
/**
|
||||
* The {@link OwSensorType} defines all known sensor types
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
public enum OwSensorType {
|
||||
DS1420,
|
||||
DS18S20,
|
||||
DS18B20,
|
||||
DS1822,
|
||||
DS1923,
|
||||
DS2401,
|
||||
DS2405,
|
||||
DS2406,
|
||||
DS2408,
|
||||
DS2409,
|
||||
DS2413,
|
||||
DS2423,
|
||||
DS2431,
|
||||
DS2438,
|
||||
MS_TC,
|
||||
MS_TH,
|
||||
MS_TL,
|
||||
MS_TH_S,
|
||||
MS_TV,
|
||||
AMS,
|
||||
AMS_S,
|
||||
BAE,
|
||||
BAE0910,
|
||||
BAE0911,
|
||||
BMS,
|
||||
BMS_S,
|
||||
EDS,
|
||||
EDS0064,
|
||||
EDS0065,
|
||||
EDS0066,
|
||||
EDS0067,
|
||||
EDS0068,
|
||||
UNKNOWN
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* 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.onewire.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.DS2438Configuration;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.OwPageBuffer;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwDiscoveryItem} class defines a discovery item for OneWire devices
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwDiscoveryItem {
|
||||
private final Logger logger = LoggerFactory.getLogger(OwDiscoveryItem.class);
|
||||
|
||||
private final SensorId sensorId;
|
||||
private OwSensorType sensorType = OwSensorType.UNKNOWN;
|
||||
private String vendor = "Dallas/Maxim";
|
||||
|
||||
private OwPageBuffer pages = new OwPageBuffer();
|
||||
|
||||
private ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, "");
|
||||
|
||||
private final Map<SensorId, OwSensorType> associatedSensors = new HashMap<>();
|
||||
|
||||
public OwDiscoveryItem(OwserverBridgeHandler bridgeHandler, SensorId sensorId) throws OwException {
|
||||
this.sensorId = sensorId;
|
||||
sensorType = bridgeHandler.getType(sensorId);
|
||||
switch (sensorType) {
|
||||
case DS2438:
|
||||
pages = bridgeHandler.readPages(sensorId);
|
||||
DS2438Configuration config = new DS2438Configuration(bridgeHandler, sensorId);
|
||||
associatedSensors.putAll(config.getAssociatedSensors());
|
||||
logger.trace("found associated sensors: {}", associatedSensors);
|
||||
vendor = config.getVendor();
|
||||
sensorType = config.getSensorSubType();
|
||||
break;
|
||||
case EDS:
|
||||
vendor = "Embedded Data Systems";
|
||||
pages = bridgeHandler.readPages(sensorId);
|
||||
|
||||
try { // determine subsensorType
|
||||
sensorType = OwSensorType.valueOf(new String(pages.getPage(0), 0, 7, StandardCharsets.US_ASCII));
|
||||
} catch (IllegalArgumentException e) {
|
||||
sensorType = OwSensorType.UNKNOWN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get sensor type
|
||||
*
|
||||
* @return sensor type
|
||||
*/
|
||||
public OwSensorType getSensorType() {
|
||||
return sensorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* get this sensor id
|
||||
*
|
||||
* @return sensor id
|
||||
*/
|
||||
public SensorId getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
|
||||
/**
|
||||
* normalized sensor id (for naming the discovery result)
|
||||
*
|
||||
* @return sensor id in format familyId_xxxxxxxxxx
|
||||
*/
|
||||
public String getNormalizedSensorId() {
|
||||
return sensorId.getId().replace(".", "_");
|
||||
}
|
||||
|
||||
/**
|
||||
* get vendor name (if available)
|
||||
*
|
||||
* @return vendor name
|
||||
*/
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* get this sensors ThingTypeUID
|
||||
*
|
||||
* @return ThingTypeUID if mapping successful
|
||||
*/
|
||||
public ThingTypeUID getThingTypeUID() throws OwException {
|
||||
if (THING_TYPE_MAP.containsKey(sensorType)) {
|
||||
thingTypeUID = THING_TYPE_MAP.get(sensorType);
|
||||
return thingTypeUID;
|
||||
} else {
|
||||
throw new OwException(sensorType + " cannot be mapped to thing type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get a list of all sensors associated to this sensor
|
||||
*
|
||||
* @return list of strings
|
||||
*/
|
||||
public List<SensorId> getAssociatedSensorIds() {
|
||||
return new ArrayList<>(associatedSensors.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* determine this sensors type
|
||||
*/
|
||||
public void checkSensorType() {
|
||||
logger.debug("checkSensorType: {} with {}", this, associatedSensors);
|
||||
|
||||
switch (sensorType) {
|
||||
case MS_TH:
|
||||
case MS_TH_S:
|
||||
sensorType = DS2438Configuration.getMultisensorType(sensorType,
|
||||
new ArrayList<>(associatedSensors.values()));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get Label "<thingtype> (<id>)"
|
||||
*
|
||||
* @return the thing label
|
||||
*/
|
||||
public String getLabel() {
|
||||
return THING_LABEL_MAP.get(sensorType) + " (" + this.sensorId.getId() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s/%s (associated: %d)", sensorId, sensorType, associatedSensors.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* 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.onewire.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
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.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwDiscoveryService} implements the discovery service for the OneWire binding.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwDiscoveryService extends AbstractDiscoveryService {
|
||||
private final Logger logger = LoggerFactory.getLogger(OwDiscoveryService.class);
|
||||
|
||||
private final OwserverBridgeHandler owBridgeHandler;
|
||||
private final ThingUID bridgeUID;
|
||||
|
||||
Map<SensorId, OwDiscoveryItem> owDiscoveryItems = new HashMap<>();
|
||||
Set<SensorId> associatedSensors = new HashSet<>();
|
||||
|
||||
public OwDiscoveryService(OwserverBridgeHandler owBridgeHandler) {
|
||||
super(SUPPORTED_THING_TYPES, 60, false);
|
||||
this.owBridgeHandler = owBridgeHandler;
|
||||
this.bridgeUID = owBridgeHandler.getThing().getUID();
|
||||
logger.debug("registering discovery service for {}", owBridgeHandler);
|
||||
}
|
||||
|
||||
private void scanDirectory(String baseDirectory) {
|
||||
List<SensorId> directoryList;
|
||||
|
||||
logger.trace("scanning {} on bridge {}", baseDirectory, bridgeUID);
|
||||
try {
|
||||
directoryList = owBridgeHandler.getDirectory(baseDirectory);
|
||||
} catch (OwException e) {
|
||||
logger.info("empty directory '{}' for {}", baseDirectory, bridgeUID);
|
||||
return;
|
||||
}
|
||||
|
||||
// find all valid sensors
|
||||
for (SensorId directoryEntry : directoryList) {
|
||||
try {
|
||||
OwDiscoveryItem owDiscoveryItem = new OwDiscoveryItem(owBridgeHandler, directoryEntry);
|
||||
if (owDiscoveryItem.getSensorType() == OwSensorType.DS2409) {
|
||||
// scan hub sub-directories
|
||||
logger.trace("found hub {}, scanning sub-directories", directoryEntry);
|
||||
|
||||
scanDirectory(owDiscoveryItem.getSensorId().getFullPath() + "/main/");
|
||||
scanDirectory(owDiscoveryItem.getSensorId().getFullPath() + "/aux/");
|
||||
} else {
|
||||
// add found sensor to list
|
||||
logger.trace("found sensor {} (type: {})", directoryEntry, owDiscoveryItem.getSensorType());
|
||||
|
||||
owDiscoveryItems.put(owDiscoveryItem.getSensorId(), owDiscoveryItem);
|
||||
associatedSensors.addAll(owDiscoveryItem.getAssociatedSensorIds());
|
||||
}
|
||||
} catch (OwException e) {
|
||||
logger.debug("error while scanning for sensors in directory {} on bridge {}: {}", baseDirectory,
|
||||
bridgeUID, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startScan() {
|
||||
scanDirectory("/");
|
||||
|
||||
// remove duplicates
|
||||
owDiscoveryItems.entrySet().removeIf(s -> associatedSensors.contains(s.getKey()));
|
||||
|
||||
// make discovery results
|
||||
for (OwDiscoveryItem owDiscoveryItem : owDiscoveryItems.values()) {
|
||||
owDiscoveryItem.checkSensorType();
|
||||
try {
|
||||
ThingTypeUID thingTypeUID = owDiscoveryItem.getThingTypeUID();
|
||||
|
||||
String normalizedId = owDiscoveryItem.getNormalizedSensorId();
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, normalizedId);
|
||||
logger.debug("created thing UID {} for sensor {}, type {}", thingUID, owDiscoveryItem.getSensorId(),
|
||||
owDiscoveryItem.getSensorType());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(PROPERTY_MODELID, owDiscoveryItem.getSensorType().toString());
|
||||
properties.put(PROPERTY_VENDOR, owDiscoveryItem.getVendor());
|
||||
properties.put(CONFIG_ID, owDiscoveryItem.getSensorId().getFullPath());
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID)
|
||||
.withProperties(properties).withBridge(bridgeUID).withLabel(owDiscoveryItem.getLabel()).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
} catch (OwException e) {
|
||||
logger.info("sensor-id {}: {}", owDiscoveryItem.getSensorId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
removeOlderResults(getTimestampOfLastScan());
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
removeOlderResults(new Date().getTime());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/**
|
||||
* 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.onewire.internal.handler;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.DS2438Configuration;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.config.AMSHandlerConfiguration;
|
||||
import org.openhab.binding.onewire.internal.device.AbstractOwDevice;
|
||||
import org.openhab.binding.onewire.internal.device.DS18x20;
|
||||
import org.openhab.binding.onewire.internal.device.DS2406_DS2413;
|
||||
import org.openhab.binding.onewire.internal.device.DS2438;
|
||||
import org.openhab.binding.onewire.internal.device.DS2438.LightSensorType;
|
||||
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AdvancedMultisensorThingHandler} is responsible for handling DS2438 based multisensors (modules)
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AdvancedMultisensorThingHandler extends OwBaseThingHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
|
||||
Arrays.asList(THING_TYPE_AMS, THING_TYPE_BMS));
|
||||
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
|
||||
.unmodifiableSet(Stream.of(OwSensorType.AMS, OwSensorType.AMS_S, OwSensorType.BMS, OwSensorType.BMS_S)
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
private static final String PROPERTY_DS18B20 = "ds18b20";
|
||||
private static final String PROPERTY_DS2413 = "ds2413";
|
||||
private static final String PROPERTY_DS2438 = "ds2438";
|
||||
private static final Set<String> REQUIRED_PROPERTIES_AMS = Collections.unmodifiableSet(
|
||||
Stream.of(PROPERTY_HW_REVISION, PROPERTY_PROD_DATE, PROPERTY_DS18B20, PROPERTY_DS2438, PROPERTY_DS2413)
|
||||
.collect(Collectors.toSet()));
|
||||
private static final Set<String> REQUIRED_PROPERTIES_BMS = Collections.unmodifiableSet(
|
||||
Stream.of(PROPERTY_HW_REVISION, PROPERTY_PROD_DATE, PROPERTY_DS18B20).collect(Collectors.toSet()));
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AdvancedMultisensorThingHandler.class);
|
||||
|
||||
private final ThingTypeUID thingType = this.thing.getThingTypeUID();
|
||||
private int hwRevision = 0;
|
||||
|
||||
private int digitalRefreshInterval = 10 * 1000;
|
||||
private long digitalLastRefresh = 0;
|
||||
|
||||
public AdvancedMultisensorThingHandler(Thing thing,
|
||||
OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
|
||||
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES,
|
||||
getRequiredProperties(thing.getThingTypeUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
AMSHandlerConfiguration configuration = getConfig().as(AMSHandlerConfiguration.class);
|
||||
Map<String, String> properties = editProperties();
|
||||
|
||||
if (!super.configureThingHandler()) {
|
||||
return;
|
||||
}
|
||||
|
||||
hwRevision = Integer.valueOf(properties.get(PROPERTY_HW_REVISION));
|
||||
|
||||
sensors.add(new DS2438(sensorId, this));
|
||||
sensors.add(new DS18x20(new SensorId(properties.get(PROPERTY_DS18B20)), this));
|
||||
if (THING_TYPE_AMS.equals(thingType)) {
|
||||
sensors.add(new DS2438(new SensorId(properties.get(PROPERTY_DS2438)), this));
|
||||
sensors.add(new DS2406_DS2413(new SensorId(properties.get(PROPERTY_DS2413)), this));
|
||||
digitalRefreshInterval = configuration.digitalRefresh * 1000;
|
||||
digitalLastRefresh = 0;
|
||||
}
|
||||
|
||||
scheduler.execute(() -> {
|
||||
configureThingChannels();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, long now) {
|
||||
try {
|
||||
if ((now >= (digitalLastRefresh + digitalRefreshInterval)) && (thingType.equals(THING_TYPE_AMS))) {
|
||||
logger.trace("refreshing digital {}", this.thing.getUID());
|
||||
|
||||
Boolean forcedRefresh = digitalLastRefresh == 0;
|
||||
digitalLastRefresh = now;
|
||||
|
||||
if (!sensors.get(3).checkPresence(bridgeHandler)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sensors.get(3).refresh(bridgeHandler, forcedRefresh);
|
||||
}
|
||||
|
||||
if (now >= (lastRefresh + refreshInterval)) {
|
||||
if (!sensors.get(0).checkPresence(bridgeHandler)) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.trace("refreshing analog {}", this.thing.getUID());
|
||||
|
||||
Boolean forcedRefresh = lastRefresh == 0;
|
||||
lastRefresh = now;
|
||||
|
||||
if (thingType.equals(THING_TYPE_AMS)) {
|
||||
for (int i = 0; i < sensors.size() - 1; i++) {
|
||||
sensors.get(i).refresh(bridgeHandler, forcedRefresh);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < sensors.size(); i++) {
|
||||
sensors.get(i).refresh(bridgeHandler, forcedRefresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (OwException e) {
|
||||
logger.debug("{}: refresh exception '{}'", this.thing.getUID(), e.getMessage());
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "refresh exception");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureThingChannels() {
|
||||
Configuration configuration = getConfig();
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
|
||||
// delete unwanted channels
|
||||
Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> wantedChannelIds = SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream()
|
||||
.map(channelConfig -> channelConfig.channelId).collect(Collectors.toSet());
|
||||
wantedChannelIds.add(CHANNEL_TEMPERATURE);
|
||||
wantedChannelIds.add(CHANNEL_HUMIDITY);
|
||||
existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
|
||||
.forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
|
||||
|
||||
// add or update wanted channels
|
||||
SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream().forEach(channelConfig -> {
|
||||
addChannelIfMissingAndEnable(thingBuilder, channelConfig);
|
||||
});
|
||||
|
||||
// temperature channel
|
||||
if (configuration.containsKey(CONFIG_TEMPERATURESENSOR)
|
||||
&& configuration.get(CONFIG_TEMPERATURESENSOR).equals("DS18B20")) {
|
||||
addChannelIfMissingAndEnable(thingBuilder,
|
||||
new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE_POR_RES), 1);
|
||||
} else {
|
||||
addChannelIfMissingAndEnable(thingBuilder,
|
||||
new OwChannelConfig(CHANNEL_TEMPERATURE, CHANNEL_TYPE_UID_TEMPERATURE));
|
||||
}
|
||||
|
||||
// humidity channel
|
||||
|
||||
addChannelIfMissingAndEnable(thingBuilder, new OwChannelConfig(CHANNEL_HUMIDITY, CHANNEL_TYPE_UID_HUMIDITY),
|
||||
new Configuration(new HashMap<String, Object>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
put(CONFIG_HUMIDITY, "/HIH4000/humidity");
|
||||
}
|
||||
}));
|
||||
|
||||
// configure light channel
|
||||
if (sensorType == OwSensorType.AMS_S || sensorType == OwSensorType.BMS_S) {
|
||||
if (hwRevision <= 13) {
|
||||
((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V1);
|
||||
} else {
|
||||
((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.ELABNET_V2);
|
||||
}
|
||||
}
|
||||
|
||||
updateThing(thingBuilder.build());
|
||||
|
||||
try {
|
||||
for (AbstractOwDevice sensor : sensors) {
|
||||
sensor.configureChannels();
|
||||
}
|
||||
} catch (OwException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
validConfig = true;
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
|
||||
Map<String, String> properties = editProperties();
|
||||
DS2438Configuration ds2438configuration = new DS2438Configuration(bridgeHandler, sensorId);
|
||||
|
||||
sensorType = DS2438Configuration.getMultisensorType(ds2438configuration.getSensorSubType(),
|
||||
ds2438configuration.getAssociatedSensorTypes());
|
||||
|
||||
properties.put(PROPERTY_MODELID, sensorType.toString());
|
||||
properties.put(PROPERTY_VENDOR, ds2438configuration.getVendor());
|
||||
|
||||
properties.put(PROPERTY_PROD_DATE, ds2438configuration.getProductionDate());
|
||||
properties.put(PROPERTY_HW_REVISION, ds2438configuration.getHardwareRevision());
|
||||
|
||||
switch (sensorType) {
|
||||
case BMS:
|
||||
case BMS_S:
|
||||
properties.put(PROPERTY_DS18B20,
|
||||
ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
|
||||
break;
|
||||
case AMS:
|
||||
case AMS_S:
|
||||
properties.put(PROPERTY_DS18B20,
|
||||
ds2438configuration.getAssociatedSensorIds(OwSensorType.DS18B20).get(0).getFullPath());
|
||||
properties.put(PROPERTY_DS2413,
|
||||
ds2438configuration.getAssociatedSensorIds(OwSensorType.DS2413).get(0).getFullPath());
|
||||
properties.put(PROPERTY_DS2438,
|
||||
ds2438configuration.getAssociatedSensorIds(OwSensorType.MS_TV).get(0).getFullPath());
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new OwException("sensorType " + sensorType.toString() + " not supported by this thing handler");
|
||||
}
|
||||
|
||||
updateProperties(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* used to determine the correct set of required properties
|
||||
*
|
||||
* @param thingType
|
||||
* @return
|
||||
*/
|
||||
private static Set<String> getRequiredProperties(ThingTypeUID thingType) {
|
||||
if (THING_TYPE_AMS.equals(thingType)) {
|
||||
return REQUIRED_PROPERTIES_AMS;
|
||||
} else {
|
||||
return REQUIRED_PROPERTIES_BMS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/**
|
||||
* 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.onewire.internal.handler;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.config.BAE091xHandlerConfiguration;
|
||||
import org.openhab.binding.onewire.internal.device.BAE0910;
|
||||
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BAE091xSensorThingHandler} is responsible for handling BAE0910 based multisensors
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BAE091xSensorThingHandler extends OwBaseThingHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BAE091X);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BAE091xSensorThingHandler.class);
|
||||
|
||||
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections.singleton(OwSensorType.BAE0910);
|
||||
|
||||
public BAE091xSensorThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
|
||||
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof OnOffType) {
|
||||
if (channelUID.getId().startsWith(CHANNEL_DIGITAL)) {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
OwserverBridgeHandler bridgeHandler = (OwserverBridgeHandler) bridge.getHandler();
|
||||
if (bridgeHandler != null) {
|
||||
if (!((BAE0910) sensors.get(0)).writeChannel(bridgeHandler, channelUID.getId(), command)) {
|
||||
logger.debug("writing to channel {} in thing {} not permitted (input channel)", channelUID,
|
||||
this.thing.getUID());
|
||||
}
|
||||
} else {
|
||||
logger.warn("bridge handler not found");
|
||||
}
|
||||
} else {
|
||||
logger.warn("bridge not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: PWM channels
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (!super.configureThingHandler()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sensors.add(new BAE0910(sensorId, this));
|
||||
|
||||
scheduler.execute(() -> {
|
||||
configureThingChannels();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureThingChannels() {
|
||||
ThingUID thingUID = getThing().getUID();
|
||||
logger.debug("configuring sensors for {}", thingUID);
|
||||
|
||||
BAE091xHandlerConfiguration configuration = getConfig().as(BAE091xHandlerConfiguration.class);
|
||||
|
||||
Set<OwChannelConfig> wantedChannel = new HashSet<>();
|
||||
wantedChannel.addAll(SENSOR_TYPE_CHANNEL_MAP.get(sensorType));
|
||||
|
||||
// Pin1:
|
||||
switch (configuration.pin1) {
|
||||
case CONFIG_BAE_PIN_DISABLED:
|
||||
break;
|
||||
case CONFIG_BAE_PIN_COUNTER:
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_COUNTER, CHANNEL_TYPE_UID_BAE_COUNTER));
|
||||
break;
|
||||
default:
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"unknown configuration option for pin 1");
|
||||
return;
|
||||
}
|
||||
|
||||
// Pin2:
|
||||
switch (configuration.pin2) {
|
||||
case CONFIG_BAE_PIN_DISABLED:
|
||||
break;
|
||||
case CONFIG_BAE_PIN_OUT:
|
||||
wantedChannel.add(
|
||||
new OwChannelConfig(CHANNEL_DIGITAL2, CHANNEL_TYPE_UID_BAE_DIGITAL_OUT, "Digital Out Pin 2"));
|
||||
break;
|
||||
case CONFIG_BAE_PIN_PWM:
|
||||
wantedChannel
|
||||
.add(new OwChannelConfig(CHANNEL_PWM_DUTY3, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 3"));
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ1, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
|
||||
"Frequency PWM 1/3"));
|
||||
break;
|
||||
default:
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"unknown configuration option for pin 2");
|
||||
return;
|
||||
}
|
||||
|
||||
// Pin6:
|
||||
switch (configuration.pin6) {
|
||||
case CONFIG_BAE_PIN_DISABLED:
|
||||
break;
|
||||
case CONFIG_BAE_PIN_PIO:
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_DIGITAL6, CHANNEL_TYPE_UID_BAE_PIO, "PIO Pin 6"));
|
||||
break;
|
||||
case CONFIG_BAE_PIN_PWM:
|
||||
wantedChannel
|
||||
.add(new OwChannelConfig(CHANNEL_PWM_DUTY4, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 4"));
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ2, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
|
||||
"Frequency PWM 2/4"));
|
||||
break;
|
||||
default:
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"unknown configuration option for pin 6");
|
||||
return;
|
||||
}
|
||||
|
||||
// Pin7:
|
||||
switch (configuration.pin7) {
|
||||
case CONFIG_BAE_PIN_DISABLED:
|
||||
break;
|
||||
case CONFIG_BAE_PIN_ANALOG:
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_VOLTAGE, CHANNEL_TYPE_UID_BAE_ANALOG, "Analog Input"));
|
||||
break;
|
||||
case CONFIG_BAE_PIN_OUT:
|
||||
wantedChannel.add(
|
||||
new OwChannelConfig(CHANNEL_DIGITAL7, CHANNEL_TYPE_UID_BAE_DIGITAL_OUT, "Digital Out Pin 7"));
|
||||
break;
|
||||
case CONFIG_BAE_PIN_PWM:
|
||||
wantedChannel
|
||||
.add(new OwChannelConfig(CHANNEL_PWM_DUTY2, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 2"));
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ2, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
|
||||
"Frequency PWM 2/4"));
|
||||
break;
|
||||
default:
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"unknown configuration option for pin 7");
|
||||
return;
|
||||
}
|
||||
|
||||
// Pin8:
|
||||
switch (configuration.pin8) {
|
||||
case CONFIG_BAE_PIN_DISABLED:
|
||||
break;
|
||||
case CONFIG_BAE_PIN_IN:
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_DIGITAL8, CHANNEL_TYPE_UID_BAE_DIN, "Digital In Pin 8"));
|
||||
break;
|
||||
case CONFIG_BAE_PIN_OUT:
|
||||
wantedChannel
|
||||
.add(new OwChannelConfig(CHANNEL_DIGITAL8, CHANNEL_TYPE_UID_BAE_DOUT, "Digital Out Pin 8"));
|
||||
break;
|
||||
case CONFIG_BAE_PIN_PWM:
|
||||
wantedChannel
|
||||
.add(new OwChannelConfig(CHANNEL_PWM_DUTY1, CHANNEL_TYPE_UID_BAE_PWM_DUTY, "Duty Cycle PWM 1"));
|
||||
wantedChannel.add(new OwChannelConfig(CHANNEL_PWM_FREQ1, CHANNEL_TYPE_UID_BAE_PWM_FREQUENCY,
|
||||
"Frequency PWM 1/3"));
|
||||
|
||||
break;
|
||||
default:
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"unknown configuration option for pin 8");
|
||||
return;
|
||||
}
|
||||
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
|
||||
// remove unwanted channels
|
||||
Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> wantedChannelIds = wantedChannel.stream().map(channelConfig -> channelConfig.channelId)
|
||||
.collect(Collectors.toSet());
|
||||
existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
|
||||
.forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
|
||||
|
||||
// add or update wanted channels
|
||||
wantedChannel.stream().forEach(channelConfig -> {
|
||||
addChannelIfMissingAndEnable(thingBuilder, channelConfig);
|
||||
});
|
||||
|
||||
updateThing(thingBuilder.build());
|
||||
|
||||
try {
|
||||
sensors.get(0).configureChannels();
|
||||
} catch (OwException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
validConfig = true;
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
|
||||
Map<String, String> properties = editProperties();
|
||||
|
||||
sensorType = BAE0910.getDeviceSubType(bridgeHandler, sensorId);
|
||||
|
||||
properties.put(PROPERTY_MODELID, sensorType.toString());
|
||||
properties.put(PROPERTY_VENDOR, "Brain4home");
|
||||
|
||||
updateProperties(properties);
|
||||
|
||||
logger.trace("updated modelid/vendor to {} / {}", sensorType.name(), "Brain4home");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.onewire.internal.handler;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.DS2438Configuration;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.config.MstxHandlerConfiguration;
|
||||
import org.openhab.binding.onewire.internal.device.DS1923;
|
||||
import org.openhab.binding.onewire.internal.device.DS2438;
|
||||
import org.openhab.binding.onewire.internal.device.DS2438.CurrentSensorType;
|
||||
import org.openhab.binding.onewire.internal.device.DS2438.LightSensorType;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BasicMultisensorThingHandler} is responsible for handling DS2438/DS1923 based multisensors (single
|
||||
* sensors)
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BasicMultisensorThingHandler extends OwBaseThingHandler {
|
||||
public Logger logger = LoggerFactory.getLogger(BasicMultisensorThingHandler.class);
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_MS_TX);
|
||||
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
|
||||
.unmodifiableSet(Stream.of(OwSensorType.MS_TH, OwSensorType.MS_TC, OwSensorType.MS_TL, OwSensorType.MS_TV,
|
||||
OwSensorType.DS1923, OwSensorType.DS2438).collect(Collectors.toSet()));
|
||||
|
||||
public BasicMultisensorThingHandler(Thing thing,
|
||||
OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
|
||||
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (!super.configureThingHandler()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MstxHandlerConfiguration configuration = getConfig().as(MstxHandlerConfiguration.class);
|
||||
if (configuration.manualsensor != null && sensorType != configuration.manualsensor) {
|
||||
logger.debug("sensorType override for thing {}: old={}, new={}", thing.getUID(), sensorType,
|
||||
configuration.manualsensor);
|
||||
sensorType = configuration.manualsensor;
|
||||
}
|
||||
|
||||
// add sensors
|
||||
if (sensorType == OwSensorType.DS1923) {
|
||||
sensors.add(new DS1923(sensorId, this));
|
||||
} else {
|
||||
sensors.add(new DS2438(sensorId, this));
|
||||
}
|
||||
|
||||
scheduler.execute(() -> {
|
||||
configureThingChannels();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureThingChannels() {
|
||||
switch (sensorType) {
|
||||
case DS2438:
|
||||
((DS2438) sensors.get(0)).setCurrentSensorType(CurrentSensorType.INTERNAL);
|
||||
break;
|
||||
case MS_TC:
|
||||
((DS2438) sensors.get(0)).setCurrentSensorType(CurrentSensorType.IBUTTONLINK);
|
||||
break;
|
||||
case MS_TL:
|
||||
((DS2438) sensors.get(0)).setLightSensorType(LightSensorType.IBUTTONLINK);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
super.configureThingChannels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
|
||||
Map<String, String> properties = editProperties();
|
||||
sensorType = bridgeHandler.getType(sensorId);
|
||||
|
||||
if (sensorType == OwSensorType.DS1923) {
|
||||
properties.put(PROPERTY_MODELID, sensorType.toString());
|
||||
properties.put(PROPERTY_VENDOR, "Dallas/Maxim");
|
||||
} else {
|
||||
DS2438Configuration ds2438configuration = new DS2438Configuration(bridgeHandler, sensorId);
|
||||
|
||||
sensorType = ds2438configuration.getSensorSubType();
|
||||
properties.put(PROPERTY_MODELID, sensorType.toString());
|
||||
|
||||
String vendor = ds2438configuration.getVendor();
|
||||
properties.put(PROPERTY_VENDOR, vendor);
|
||||
}
|
||||
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* 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.onewire.internal.handler;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_DIGITAL;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_BASIC;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.device.*;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BasicThingHandler} is responsible for handling simple sensors
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BasicThingHandler extends OwBaseThingHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BASIC);
|
||||
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
|
||||
.unmodifiableSet(Stream.of(OwSensorType.DS1420, OwSensorType.DS18B20, OwSensorType.DS18S20,
|
||||
OwSensorType.DS1822, OwSensorType.DS2401, OwSensorType.DS2405, OwSensorType.DS2406,
|
||||
OwSensorType.DS2408, OwSensorType.DS2413, OwSensorType.DS2423).collect(Collectors.toSet()));
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BasicThingHandler.class);
|
||||
|
||||
public BasicThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
|
||||
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (!super.configureThingHandler()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add sensor
|
||||
switch (sensorType) {
|
||||
case DS18B20:
|
||||
case DS18S20:
|
||||
case DS1822:
|
||||
sensors.add(new DS18x20(sensorId, this));
|
||||
break;
|
||||
case DS1420:
|
||||
case DS2401:
|
||||
sensors.add(new DS2401(sensorId, this));
|
||||
break;
|
||||
case DS2405:
|
||||
sensors.add(new DS2405(sensorId, this));
|
||||
break;
|
||||
case DS2406:
|
||||
case DS2413:
|
||||
sensors.add(new DS2406_DS2413(sensorId, this));
|
||||
break;
|
||||
case DS2408:
|
||||
sensors.add(new DS2408(sensorId, this));
|
||||
break;
|
||||
case DS2423:
|
||||
sensors.add(new DS2423(sensorId, this));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"unsupported sensorType " + sensorType.name() + ", this should have been checked before!");
|
||||
}
|
||||
|
||||
scheduler.execute(() -> {
|
||||
configureThingChannels();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof OnOffType) {
|
||||
if (channelUID.getId().startsWith(CHANNEL_DIGITAL) && thing.getChannel(channelUID.getId()) != null) {
|
||||
Integer ioChannel = Integer.valueOf(channelUID.getId().substring(channelUID.getId().length() - 1));
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
OwserverBridgeHandler bridgeHandler = (OwserverBridgeHandler) bridge.getHandler();
|
||||
if (bridgeHandler != null) {
|
||||
if (!((AbstractDigitalOwDevice) sensors.get(0)).writeChannel(bridgeHandler, ioChannel,
|
||||
command)) {
|
||||
logger.debug("writing to channel {} in thing {} not permitted (input channel)", channelUID,
|
||||
this.thing.getUID());
|
||||
}
|
||||
} else {
|
||||
logger.warn("bridge handler not found");
|
||||
}
|
||||
} else {
|
||||
logger.warn("bridge not found");
|
||||
}
|
||||
}
|
||||
}
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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.onewire.internal.handler;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.OwPageBuffer;
|
||||
import org.openhab.binding.onewire.internal.device.EDS006x;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link EDSSensorThingHandler} is responsible for handling EDS multisensors
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EDSSensorThingHandler extends OwBaseThingHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_EDS_ENV);
|
||||
public static final Set<OwSensorType> SUPPORTED_SENSOR_TYPES = Collections
|
||||
.unmodifiableSet(Stream.of(OwSensorType.EDS0064, OwSensorType.EDS0065, OwSensorType.EDS0066,
|
||||
OwSensorType.EDS0067, OwSensorType.EDS0068).collect(Collectors.toSet()));
|
||||
private static final Set<String> REQUIRED_PROPERTIES = Collections.singleton(PROPERTY_HW_REVISION);
|
||||
|
||||
public EDSSensorThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
|
||||
super(thing, dynamicStateDescriptionProvider, SUPPORTED_SENSOR_TYPES, REQUIRED_PROPERTIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (!super.configureThingHandler()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add sensors
|
||||
sensors.add(new EDS006x(sensorId, sensorType, this));
|
||||
|
||||
scheduler.execute(() -> {
|
||||
configureThingChannels();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
|
||||
Map<String, String> properties = editProperties();
|
||||
|
||||
OwPageBuffer pages = bridgeHandler.readPages(sensorId);
|
||||
|
||||
OwSensorType sensorType = OwSensorType.UNKNOWN;
|
||||
try {
|
||||
sensorType = OwSensorType.valueOf(new String(pages.getPage(0), 0, 7, StandardCharsets.US_ASCII));
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
|
||||
if (!SUPPORTED_SENSOR_TYPES.contains(sensorType)) {
|
||||
throw new OwException("sensorType not supported for EDSSensorThing");
|
||||
}
|
||||
|
||||
int fwRevisionLow = pages.getByte(3, 3);
|
||||
int fwRevisionHigh = pages.getByte(3, 4);
|
||||
String fwRevision = String.format("%d.%d", fwRevisionHigh, fwRevisionLow);
|
||||
|
||||
properties.put(PROPERTY_MODELID, sensorType.name());
|
||||
properties.put(PROPERTY_VENDOR, "Embedded Data Systems");
|
||||
properties.put(PROPERTY_HW_REVISION, String.valueOf(fwRevision));
|
||||
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* 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.onewire.internal.handler;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
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.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.config.BaseHandlerConfiguration;
|
||||
import org.openhab.binding.onewire.internal.device.AbstractOwDevice;
|
||||
import org.openhab.binding.onewire.internal.device.OwChannelConfig;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwBaseThingHandler} class defines a handler for simple OneWire devices
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class OwBaseThingHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(OwBaseThingHandler.class);
|
||||
|
||||
protected static final int PROPERTY_UPDATE_INTERVAL = 5000; // in ms
|
||||
protected static final int PROPERTY_UPDATE_MAX_RETRY = 5;
|
||||
|
||||
private static final Set<String> REQUIRED_PROPERTIES = Collections
|
||||
.unmodifiableSet(Stream.of(PROPERTY_MODELID, PROPERTY_VENDOR).collect(Collectors.toSet()));
|
||||
|
||||
protected List<String> requiredProperties = new ArrayList<>(REQUIRED_PROPERTIES);
|
||||
protected Set<OwSensorType> supportedSensorTypes;
|
||||
|
||||
protected final List<AbstractOwDevice> sensors = new ArrayList<>();
|
||||
protected @NonNullByDefault({}) SensorId sensorId;
|
||||
protected @NonNullByDefault({}) OwSensorType sensorType;
|
||||
|
||||
protected long lastRefresh = 0;
|
||||
protected long refreshInterval = 300 * 1000;
|
||||
|
||||
protected boolean validConfig = false;
|
||||
protected boolean showPresence = false;
|
||||
|
||||
protected OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider;
|
||||
|
||||
protected @Nullable ScheduledFuture<?> updateTask;
|
||||
|
||||
public OwBaseThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider,
|
||||
Set<OwSensorType> supportedSensorTypes) {
|
||||
super(thing);
|
||||
|
||||
this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider;
|
||||
this.supportedSensorTypes = supportedSensorTypes;
|
||||
}
|
||||
|
||||
public OwBaseThingHandler(Thing thing, OwDynamicStateDescriptionProvider dynamicStateDescriptionProvider,
|
||||
Set<OwSensorType> supportedSensorTypes, Set<String> requiredProperties) {
|
||||
super(thing);
|
||||
|
||||
this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider;
|
||||
this.supportedSensorTypes = supportedSensorTypes;
|
||||
this.requiredProperties.addAll(requiredProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof RefreshType) {
|
||||
lastRefresh = 0;
|
||||
logger.trace("scheduled {} for refresh", this.thing.getUID());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
configureThingHandler();
|
||||
}
|
||||
|
||||
protected boolean configureThingHandler() {
|
||||
BaseHandlerConfiguration configuration = getConfig().as(BaseHandlerConfiguration.class);
|
||||
Map<String, String> properties = thing.getProperties();
|
||||
|
||||
if (getBridge() == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "bridge missing");
|
||||
return false;
|
||||
}
|
||||
sensors.clear();
|
||||
|
||||
final String id = configuration.id;
|
||||
if (id != null) {
|
||||
try {
|
||||
this.sensorId = new SensorId(id);
|
||||
} catch (IllegalArgumentException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "sensor id format mismatch");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "sensor id missing");
|
||||
return false;
|
||||
}
|
||||
|
||||
refreshInterval = configuration.refresh * 1000;
|
||||
|
||||
// check if all required properties are present. update if not
|
||||
for (String property : requiredProperties) {
|
||||
if (!properties.containsKey(property)) {
|
||||
updateSensorProperties();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sensorType = OwSensorType.valueOf(properties.get(PROPERTY_MODELID));
|
||||
if (!supportedSensorTypes.contains(sensorType)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"sensor type not supported by this thing type");
|
||||
return false;
|
||||
}
|
||||
|
||||
lastRefresh = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void configureThingChannels() {
|
||||
ThingBuilder thingBuilder = editThing();
|
||||
|
||||
logger.debug("configuring sensors for {}", thing.getUID());
|
||||
|
||||
// remove unwanted channels
|
||||
Set<String> existingChannelIds = thing.getChannels().stream().map(channel -> channel.getUID().getId())
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> wantedChannelIds = SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream()
|
||||
.map(channelConfig -> channelConfig.channelId).collect(Collectors.toSet());
|
||||
existingChannelIds.stream().filter(channelId -> !wantedChannelIds.contains(channelId))
|
||||
.forEach(channelId -> removeChannelIfExisting(thingBuilder, channelId));
|
||||
|
||||
// add or update wanted channels
|
||||
SENSOR_TYPE_CHANNEL_MAP.get(sensorType).stream().forEach(channelConfig -> {
|
||||
addChannelIfMissingAndEnable(thingBuilder, channelConfig);
|
||||
});
|
||||
|
||||
updateThing(thingBuilder.build());
|
||||
|
||||
try {
|
||||
sensors.get(0).configureChannels();
|
||||
} catch (OwException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (thing.getChannel(CHANNEL_PRESENT) != null) {
|
||||
showPresence = true;
|
||||
}
|
||||
|
||||
validConfig = true;
|
||||
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if thing can be refreshed from the bridge handler
|
||||
*
|
||||
* @return true if thing can be refreshed
|
||||
*/
|
||||
public boolean isRefreshable() {
|
||||
return super.isInitialized()
|
||||
&& this.thing.getStatusInfo().getStatusDetail() != ThingStatusDetail.CONFIGURATION_ERROR
|
||||
&& this.thing.getStatusInfo().getStatusDetail() != ThingStatusDetail.BRIDGE_OFFLINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* refresh this thing
|
||||
*
|
||||
* needs proper exception handling for refresh errors if overridden
|
||||
*
|
||||
* @param bridgeHandler bridge handler to use for communication with ow bus
|
||||
* @param now current time
|
||||
*/
|
||||
public void refresh(OwserverBridgeHandler bridgeHandler, long now) {
|
||||
try {
|
||||
Boolean forcedRefresh = lastRefresh == 0;
|
||||
if (now >= (lastRefresh + refreshInterval)) {
|
||||
logger.trace("refreshing {}", this.thing.getUID());
|
||||
|
||||
lastRefresh = now;
|
||||
|
||||
if (!sensors.get(0).checkPresence(bridgeHandler)) {
|
||||
logger.trace("sensor not present");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sensors.size(); i++) {
|
||||
logger.trace("refreshing sensor {} ({})", i, sensors.get(i).getSensorId());
|
||||
sensors.get(i).refresh(bridgeHandler, forcedRefresh);
|
||||
}
|
||||
}
|
||||
} catch (OwException e) {
|
||||
logger.debug("{}: refresh exception {}", this.thing.getUID(), e.getMessage());
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "refresh exception");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update presence status to present state of slave
|
||||
*
|
||||
* @param presentState current present state
|
||||
*/
|
||||
public void updatePresenceStatus(State presentState) {
|
||||
if (OnOffType.ON.equals(presentState)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
if (showPresence) {
|
||||
updateState(CHANNEL_PRESENT, OnOffType.ON);
|
||||
}
|
||||
} else if (OnOffType.OFF.equals(presentState)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "slave missing");
|
||||
if (showPresence) {
|
||||
updateState(CHANNEL_PRESENT, OnOffType.OFF);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
if (showPresence) {
|
||||
updateState(CHANNEL_PRESENT, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* post update to channel
|
||||
*
|
||||
* @param channelId channel id
|
||||
* @param state new channel state
|
||||
*/
|
||||
public void postUpdate(String channelId, State state) {
|
||||
if (this.thing.getChannel(channelId) != null) {
|
||||
updateState(channelId, state);
|
||||
} else {
|
||||
logger.warn("{} missing channel {} when posting update {}", this.thing.getUID(), channelId, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
|
||||
if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE
|
||||
&& getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.BRIDGE_OFFLINE) {
|
||||
if (validConfig) {
|
||||
updatePresenceStatus(UnDefType.UNDEF);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
|
||||
}
|
||||
} else if (bridgeStatusInfo.getStatus() == ThingStatus.OFFLINE) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
dynamicStateDescriptionProvider.removeDescriptionsForThing(thing.getUID());
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* add this sensor to the property update list of the bridge handler
|
||||
*
|
||||
*/
|
||||
protected void updateSensorProperties() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "bridge not found");
|
||||
return;
|
||||
}
|
||||
|
||||
OwserverBridgeHandler bridgeHandler = (OwserverBridgeHandler) bridge.getHandler();
|
||||
if (bridgeHandler == null) {
|
||||
logger.debug("bridgehandler for {} not available for scheduling property update, retrying in 5s",
|
||||
thing.getUID());
|
||||
scheduler.schedule(() -> {
|
||||
updateSensorProperties();
|
||||
}, 5000, TimeUnit.MILLISECONDS);
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "required properties missing");
|
||||
bridgeHandler.scheduleForPropertiesUpdate(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* thing specific update method for sensor properties
|
||||
*
|
||||
* called by the bridge handler
|
||||
*
|
||||
* @param bridgeHandler the bridge handler to be used
|
||||
* @return properties to be added to the properties map
|
||||
* @throws OwException
|
||||
*/
|
||||
public void updateSensorProperties(OwserverBridgeHandler bridgeHandler) throws OwException {
|
||||
Map<String, String> properties = editProperties();
|
||||
OwSensorType sensorType = bridgeHandler.getType(sensorId);
|
||||
properties.put(PROPERTY_MODELID, sensorType.toString());
|
||||
properties.put(PROPERTY_VENDOR, "Dallas/Maxim");
|
||||
|
||||
updateProperties(properties);
|
||||
|
||||
logger.trace("updated modelid/vendor to {} / {}", sensorType.name(), "Dallas/Maxim");
|
||||
}
|
||||
|
||||
/**
|
||||
* get the dynamic state description provider for this thing
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public @Nullable OwDynamicStateDescriptionProvider getDynamicStateDescriptionProvider() {
|
||||
return dynamicStateDescriptionProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove a channel during initialization if it exists
|
||||
*
|
||||
* @param thingBuilder ThingBuilder of the edited thing
|
||||
* @param channelId id of the channel
|
||||
*/
|
||||
protected void removeChannelIfExisting(ThingBuilder thingBuilder, String channelId) {
|
||||
if (thing.getChannel(channelId) != null) {
|
||||
thingBuilder.withoutChannel(new ChannelUID(thing.getUID(), channelId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adds (or replaces) a channel and enables it within the sensor (configuration preserved, default sensor)
|
||||
*
|
||||
* @param thingBuilder ThingBuilder of the edited thing
|
||||
* @param channelConfig a OwChannelConfig for the new channel
|
||||
* @return the newly created channel
|
||||
*/
|
||||
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig) {
|
||||
return addChannelIfMissingAndEnable(thingBuilder, channelConfig, null, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds (or replaces) a channel and enables it within the sensor (configuration overridden, default sensor)
|
||||
*
|
||||
* @param thingBuilder ThingBuilder of the edited thing
|
||||
* @param channelConfig a OwChannelConfig for the new channel
|
||||
* @param configuration the new Configuration for this channel
|
||||
* @return the newly created channel
|
||||
*/
|
||||
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig,
|
||||
Configuration configuration) {
|
||||
return addChannelIfMissingAndEnable(thingBuilder, channelConfig, configuration, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds (or replaces) a channel and enables it within the sensor (configuration preserved)
|
||||
*
|
||||
* @param thingBuilder ThingBuilder of the edited thing
|
||||
* @param channelConfig a OwChannelConfig for the new channel
|
||||
* @param sensorNo number of sensor that provides this channel
|
||||
* @return the newly created channel
|
||||
*/
|
||||
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig,
|
||||
int sensorNo) {
|
||||
return addChannelIfMissingAndEnable(thingBuilder, channelConfig, null, sensorNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds (or replaces) a channel and enables it within the sensor (configuration overridden)
|
||||
*
|
||||
* @param thingBuilder ThingBuilder of the edited thing
|
||||
* @param channelConfig a OwChannelConfig for the new channel
|
||||
* @param configuration the new Configuration for this channel
|
||||
* @param sensorNo number of sensor that provides this channel
|
||||
* @return the newly created channel
|
||||
*/
|
||||
protected Channel addChannelIfMissingAndEnable(ThingBuilder thingBuilder, OwChannelConfig channelConfig,
|
||||
@Nullable Configuration configuration, int sensorNo) {
|
||||
Channel channel = thing.getChannel(channelConfig.channelId);
|
||||
Configuration config = configuration;
|
||||
String label = channelConfig.label;
|
||||
|
||||
// remove channel if wrong type uid and preserve config if not overridden
|
||||
if (channel != null && !channelConfig.channelTypeUID.equals(channel.getChannelTypeUID())) {
|
||||
removeChannelIfExisting(thingBuilder, channelConfig.channelId);
|
||||
if (config == null) {
|
||||
config = channel.getConfiguration();
|
||||
}
|
||||
channel = null;
|
||||
}
|
||||
|
||||
// create channel if missing
|
||||
if (channel == null) {
|
||||
ChannelBuilder channelBuilder = ChannelBuilder
|
||||
.create(new ChannelUID(thing.getUID(), channelConfig.channelId),
|
||||
ACCEPTED_ITEM_TYPES_MAP.get(channelConfig.channelId))
|
||||
.withType(channelConfig.channelTypeUID);
|
||||
if (label != null) {
|
||||
channelBuilder.withLabel(label);
|
||||
}
|
||||
if (config != null) {
|
||||
channelBuilder.withConfiguration(config);
|
||||
}
|
||||
channel = channelBuilder.build();
|
||||
thingBuilder.withChannel(channel);
|
||||
}
|
||||
|
||||
// enable channel in sensor
|
||||
sensors.get(sensorNo).enableChannel(channelConfig.channelId);
|
||||
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
/**
|
||||
* 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.onewire.internal.handler;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.OwPageBuffer;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwfsDirectChannelConfig;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverConnection;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverConnectionState;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwserverBridgeHandler} class implements the refresher and the interface for reading from the bridge
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwserverBridgeHandler extends BaseBridgeHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_OWSERVER);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OwserverBridgeHandler.class);
|
||||
protected boolean refreshable = false;
|
||||
|
||||
protected ScheduledFuture<?> refreshTask = scheduler.scheduleWithFixedDelay(this::refresh, 1, 1000,
|
||||
TimeUnit.MILLISECONDS);
|
||||
|
||||
// thing update
|
||||
private final Queue<@Nullable Thing> thingPropertiesUpdateQueue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private static final int RECONNECT_AFTER_FAIL_TIME = 5000; // in ms
|
||||
private final OwserverConnection owserverConnection;
|
||||
|
||||
private final List<OwfsDirectChannelConfig> channelConfigs = new ArrayList<>();
|
||||
|
||||
public OwserverBridgeHandler(Bridge bridge) {
|
||||
super(bridge);
|
||||
this.owserverConnection = new OwserverConnection(this);
|
||||
}
|
||||
|
||||
public OwserverBridgeHandler(Bridge bridge, OwserverConnection owserverConnection) {
|
||||
super(bridge);
|
||||
this.owserverConnection = owserverConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
Configuration configuration = getConfig();
|
||||
|
||||
if (configuration.get(CONFIG_ADDRESS) != null) {
|
||||
owserverConnection.setHost((String) configuration.get(CONFIG_ADDRESS));
|
||||
}
|
||||
if (configuration.get(CONFIG_PORT) != null) {
|
||||
owserverConnection.setPort(((BigDecimal) configuration.get(CONFIG_PORT)).intValue());
|
||||
}
|
||||
|
||||
for (Channel channel : thing.getChannels()) {
|
||||
if (CHANNEL_TYPE_UID_OWFS_NUMBER.equals(channel.getChannelTypeUID())
|
||||
|| CHANNEL_TYPE_UID_OWFS_STRING.equals(channel.getChannelTypeUID())) {
|
||||
final OwfsDirectChannelConfig channelConfig = channel.getConfiguration()
|
||||
.as(OwfsDirectChannelConfig.class);
|
||||
if (channelConfig.initialize(channel.getUID(), channel.getAcceptedItemType())) {
|
||||
channelConfigs.add(channelConfig);
|
||||
} else {
|
||||
logger.info("configuration mismatch: {}", channelConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// makes it possible for unit tests to differentiate direct update and
|
||||
// postponed update through the owserverConnection:
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
scheduler.execute(() -> {
|
||||
synchronized (owserverConnection) {
|
||||
owserverConnection.start();
|
||||
}
|
||||
});
|
||||
|
||||
if (refreshTask.isCancelled()) {
|
||||
refreshTask = scheduler.scheduleWithFixedDelay(this::refresh, 1, 1000, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* refresh all sensors on this bridge
|
||||
*/
|
||||
private void refresh() {
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
if (!refreshable) {
|
||||
logger.trace("refresh requested by thread ID {} denied, as not refresheable",
|
||||
Thread.currentThread().getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// refresh thing channels
|
||||
List<Thing> thingList = getThing().getThings();
|
||||
int thingCount = thingList.size();
|
||||
Iterator<Thing> childListIterator = thingList.iterator();
|
||||
logger.trace("refreshTask with thread ID {} starts at {}, {} childs", Thread.currentThread().getId(), now,
|
||||
thingCount);
|
||||
while (childListIterator.hasNext() && refreshable) {
|
||||
Thing owThing = childListIterator.next();
|
||||
|
||||
logger.trace("refresh: getting handler for {} ({} to go)", owThing.getUID(), thingCount);
|
||||
OwBaseThingHandler owHandler = (OwBaseThingHandler) owThing.getHandler();
|
||||
if (owHandler != null) {
|
||||
if (owHandler.isRefreshable()) {
|
||||
logger.trace("{} initialized, refreshing", owThing.getUID());
|
||||
owHandler.refresh(OwserverBridgeHandler.this, now);
|
||||
} else {
|
||||
logger.trace("{} not initialized, skipping refresh", owThing.getUID());
|
||||
}
|
||||
} else {
|
||||
logger.debug("{} handler missing", owThing.getUID());
|
||||
}
|
||||
thingCount--;
|
||||
}
|
||||
|
||||
if (!refreshable) {
|
||||
logger.trace("refresh aborted, as brige became non-refresheable.");
|
||||
return;
|
||||
}
|
||||
refreshBridgeChannels(now);
|
||||
|
||||
// update thing properties (only one per refresh cycle)
|
||||
if (!refreshable) {
|
||||
logger.trace("refresh aborted, as brige became non-refresheable.");
|
||||
return;
|
||||
}
|
||||
Thing updateThing = thingPropertiesUpdateQueue.poll();
|
||||
if (updateThing != null) {
|
||||
logger.trace("update: getting handler for {} ({} total in list)", updateThing.getUID(),
|
||||
thingPropertiesUpdateQueue.size());
|
||||
OwBaseThingHandler owHandler = (OwBaseThingHandler) updateThing.getHandler();
|
||||
if (owHandler != null) {
|
||||
try {
|
||||
owHandler.updateSensorProperties(this);
|
||||
owHandler.initialize();
|
||||
logger.debug("{} sucessfully updated properties, removing from property update list",
|
||||
updateThing.getUID());
|
||||
} catch (OwException e) {
|
||||
thingPropertiesUpdateQueue.add(updateThing);
|
||||
logger.debug("updating thing properties for {} failed: {}, adding to end of list",
|
||||
updateThing.getUID(), e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.debug("{} is missing handler, removing from property update list", updateThing.getUID());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
// catching RuntimeException because scheduled tasks finish once an exception occurs
|
||||
logger.error("refresh encountered exception of {}: {}, please report bug", e.getClass(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
refreshable = false;
|
||||
if (!refreshTask.isCancelled()) {
|
||||
refreshTask.cancel(false);
|
||||
}
|
||||
owserverConnection.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* schedules a thing for updating the thing properties
|
||||
*
|
||||
* @param thing the thing to be updated
|
||||
*/
|
||||
public void scheduleForPropertiesUpdate(Thing thing) {
|
||||
thingPropertiesUpdateQueue.add(thing);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all sensors attached to this bridge
|
||||
*
|
||||
* @return a list of all sensor-IDs
|
||||
*/
|
||||
public List<SensorId> getDirectory(String basePath) throws OwException {
|
||||
synchronized (owserverConnection) {
|
||||
return owserverConnection.getDirectory(basePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check the presence of a sensor on the bus
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @return ON if present, OFF if missing
|
||||
* @throws OwException
|
||||
*/
|
||||
public State checkPresence(SensorId sensorId) throws OwException {
|
||||
synchronized (owserverConnection) {
|
||||
return owserverConnection.checkPresence(sensorId.getFullPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get a sensors type string
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @return a String containing the sensor type
|
||||
* @throws OwException
|
||||
*/
|
||||
public OwSensorType getType(SensorId sensorId) throws OwException {
|
||||
OwSensorType sensorType = OwSensorType.UNKNOWN;
|
||||
synchronized (owserverConnection) {
|
||||
try {
|
||||
sensorType = OwSensorType.valueOf(owserverConnection.readString(sensorId + "/type"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
return sensorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* get full sensor information stored in pages (not available on all sensors)
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @return a OwPageBuffer object containing the requested information
|
||||
* @throws OwException
|
||||
*/
|
||||
public OwPageBuffer readPages(SensorId sensorId) throws OwException {
|
||||
synchronized (owserverConnection) {
|
||||
return owserverConnection.readPages(sensorId.getFullPath());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read a single decimal value from a sensor
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @param parameter device parameters needed for this request
|
||||
* @return a DecimalType
|
||||
* @throws OwException
|
||||
*/
|
||||
public State readDecimalType(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
|
||||
synchronized (owserverConnection) {
|
||||
return owserverConnection.readDecimalType(parameter.getPath(sensorId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read a BitSet value from a sensor
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @param parameter device parameters needed for this request
|
||||
* @return a BitSet
|
||||
* @throws OwException
|
||||
*/
|
||||
public BitSet readBitSet(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
|
||||
return BitSet.valueOf(new long[] { ((DecimalType) readDecimalType(sensorId, parameter)).longValue() });
|
||||
}
|
||||
|
||||
/**
|
||||
* read an array of decimal values from a sensor
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @param parameter device parameters needed for this request
|
||||
* @return a list of DecimalType values
|
||||
* @throws OwException
|
||||
*/
|
||||
public List<State> readDecimalTypeArray(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
|
||||
synchronized (owserverConnection) {
|
||||
return owserverConnection.readDecimalTypeArray(parameter.getPath(sensorId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read a string from a sensor
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @param parameter device parameters needed for this request
|
||||
* @return a String
|
||||
* @throws OwException
|
||||
*/
|
||||
public String readString(SensorId sensorId, OwserverDeviceParameter parameter) throws OwException {
|
||||
synchronized (owserverConnection) {
|
||||
return owserverConnection.readString(parameter.getPath(sensorId));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* writes a DecimalType to the sensor
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @param parameter device parameters needed for this request
|
||||
* @throws OwException
|
||||
*/
|
||||
public void writeDecimalType(SensorId sensorId, OwserverDeviceParameter parameter, DecimalType value)
|
||||
throws OwException {
|
||||
synchronized (owserverConnection) {
|
||||
owserverConnection.writeDecimalType(parameter.getPath(sensorId), value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* writes a BitSet to the sensor
|
||||
*
|
||||
* @param sensorId the sensor's full ID
|
||||
* @param parameter device parameters needed for this request
|
||||
* @throws OwException
|
||||
*/
|
||||
public void writeBitSet(SensorId sensorId, OwserverDeviceParameter parameter, BitSet value) throws OwException {
|
||||
writeDecimalType(sensorId, parameter, new DecimalType(value.toLongArray()[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if this bridge is refreshable
|
||||
*
|
||||
* @return true if implementation reports communication ready
|
||||
*/
|
||||
public boolean isRefreshable() {
|
||||
return refreshable;
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the thing status with the current connection state
|
||||
*
|
||||
* @param connectionState current connection state
|
||||
*/
|
||||
public void reportConnectionState(OwserverConnectionState connectionState) {
|
||||
logger.debug("Updating owserverconnectionstate to {}", connectionState);
|
||||
switch (connectionState) {
|
||||
case FAILED:
|
||||
refreshable = false;
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
scheduler.schedule(() -> {
|
||||
synchronized (owserverConnection) {
|
||||
owserverConnection.start();
|
||||
}
|
||||
}, RECONNECT_AFTER_FAIL_TIME, TimeUnit.MILLISECONDS);
|
||||
break;
|
||||
case STOPPED:
|
||||
refreshable = false;
|
||||
break;
|
||||
case OPENED:
|
||||
case CLOSED:
|
||||
refreshable = true;
|
||||
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* refreshes channels attached to the bridge
|
||||
*
|
||||
* @param now current time
|
||||
*/
|
||||
public void refreshBridgeChannels(long now) {
|
||||
for (OwfsDirectChannelConfig channelConfig : channelConfigs) {
|
||||
if (now > channelConfig.lastRefresh + channelConfig.refreshCycle) {
|
||||
State value;
|
||||
try {
|
||||
synchronized (owserverConnection) {
|
||||
if (channelConfig.acceptedItemType.equals("String")) {
|
||||
value = new StringType(owserverConnection.readString(channelConfig.path));
|
||||
} else if (channelConfig.acceptedItemType.equals("Number")) {
|
||||
value = owserverConnection.readDecimalType(channelConfig.path);
|
||||
} else {
|
||||
logger.debug("mismatched configuration, itemType unknown for channel {}",
|
||||
channelConfig.channelUID);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
final ChannelUID channelUID = channelConfig.channelUID;
|
||||
if (channelUID == null) {
|
||||
throw new OwException("channelUID is null");
|
||||
}
|
||||
updateState(channelUID, value);
|
||||
logger.trace("updated {} to {}", channelConfig.channelUID, value);
|
||||
|
||||
channelConfig.lastRefresh = now;
|
||||
} catch (OwException e) {
|
||||
logger.debug("could not read direct channel {}: {}", channelConfig.channelUID, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.onewire.internal.owserver;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
|
||||
/**
|
||||
* The {@link OwfsDirectChannelConfig} defines config for owfsdirect channels
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwfsDirectChannelConfig {
|
||||
public String path = "";
|
||||
public BigDecimal refresh = new BigDecimal(300);
|
||||
|
||||
public long lastRefresh = 0;
|
||||
public int refreshCycle = 300;
|
||||
|
||||
public @Nullable ChannelUID channelUID;
|
||||
public String acceptedItemType = "";
|
||||
|
||||
public boolean initialize(ChannelUID channelUID, @Nullable String acceptedItemType) {
|
||||
this.channelUID = channelUID;
|
||||
this.acceptedItemType = acceptedItemType != null ? acceptedItemType : "";
|
||||
refreshCycle = refresh.intValue() * 1000;
|
||||
|
||||
return !path.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
/**
|
||||
* 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.onewire.internal.owserver;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.OwPageBuffer;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwserverConnection} defines the protocol for connections to owservers.
|
||||
*
|
||||
* Data is requested by using one of the read / write methods. In case of errors, an {@link OwException}
|
||||
* is thrown. All other exceptions are caught and handled.
|
||||
*
|
||||
* The data request methods follow a general pattern:
|
||||
* * build the appropriate {@link OwserverPacket} for the request
|
||||
* * call {@link #request(OwserverPacket)} to ask for the data, which then
|
||||
* * uses {@link #write(OwserverPacket)} to get the request to the server and
|
||||
* * uses {@link #read(boolean)} to get the result
|
||||
*
|
||||
* Hereby, the resulting packet is examined on an appropriate return code (!= -1) and whether the
|
||||
* expected payload is attached. If not, an {@link OwException} is thrown.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class OwserverConnection {
|
||||
public static final int DEFAULT_PORT = 4304;
|
||||
public static final int KEEPALIVE_INTERVAL = 1000;
|
||||
|
||||
private static final int CONNECTION_MAX_RETRY = 5;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(OwserverConnection.class);
|
||||
|
||||
private final OwserverBridgeHandler thingHandlerCallback;
|
||||
private String owserverAddress = "";
|
||||
private int owserverPort = DEFAULT_PORT;
|
||||
|
||||
private @Nullable Socket owserverSocket = null;
|
||||
private @Nullable DataInputStream owserverInputStream = null;
|
||||
private @Nullable DataOutputStream owserverOutputStream = null;
|
||||
private OwserverConnectionState owserverConnectionState = OwserverConnectionState.STOPPED;
|
||||
private boolean tryingConnectionRecovery = false;
|
||||
|
||||
// reset to 0 after successful request
|
||||
private int connectionErrorCounter = 0;
|
||||
|
||||
public OwserverConnection(OwserverBridgeHandler owBaseBridgeHandler) {
|
||||
this.thingHandlerCallback = owBaseBridgeHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the owserver host address
|
||||
*
|
||||
* @param address as String (IP or FQDN), defaults to localhost
|
||||
*/
|
||||
public void setHost(String address) {
|
||||
this.owserverAddress = address;
|
||||
if (owserverConnectionState != OwserverConnectionState.STOPPED) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the owserver port
|
||||
*
|
||||
* @param port defaults to 4304
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.owserverPort = port;
|
||||
if (owserverConnectionState != OwserverConnectionState.STOPPED) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start the owserver connection
|
||||
*/
|
||||
public void start() {
|
||||
logger.debug("Trying to (re)start OW server connection - previous state: {}",
|
||||
owserverConnectionState.toString());
|
||||
connectionErrorCounter = 0;
|
||||
tryingConnectionRecovery = true;
|
||||
boolean success = false;
|
||||
do {
|
||||
success = open();
|
||||
if (success && owserverConnectionState != OwserverConnectionState.FAILED) {
|
||||
tryingConnectionRecovery = false;
|
||||
}
|
||||
} while (!success && (owserverConnectionState != OwserverConnectionState.FAILED || tryingConnectionRecovery));
|
||||
}
|
||||
|
||||
/**
|
||||
* stop the owserver connection and report new {@link OwserverConnectionState} to {@link #thingHandlerCallback}.
|
||||
*/
|
||||
public void stop() {
|
||||
close();
|
||||
owserverConnectionState = OwserverConnectionState.STOPPED;
|
||||
thingHandlerCallback.reportConnectionState(owserverConnectionState);
|
||||
}
|
||||
|
||||
/**
|
||||
* list all devices on this owserver
|
||||
*
|
||||
* @return a list of device ids
|
||||
*/
|
||||
public @NonNullByDefault({}) List<SensorId> getDirectory(String basePath) throws OwException {
|
||||
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.DIRALL, basePath);
|
||||
OwserverPacket returnPacket = request(requestPacket);
|
||||
|
||||
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
|
||||
return Arrays.stream(returnPacket.getPayloadString().split(",")).map(this::stringToSensorId)
|
||||
.filter(Objects::nonNull).collect(Collectors.toList());
|
||||
} else {
|
||||
throw new OwException("invalid of empty packet when requesting directory");
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable SensorId stringToSensorId(String s) {
|
||||
try {
|
||||
return new SensorId(s);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check sensor presence
|
||||
*
|
||||
* Errors are caught and interpreted as sensor not present.
|
||||
*
|
||||
* @param path full owfs path to sensor
|
||||
* @return OnOffType, ON=present, OFF=not present
|
||||
*/
|
||||
public State checkPresence(String path) {
|
||||
State returnValue = OnOffType.OFF;
|
||||
try {
|
||||
OwserverPacket requestPacket;
|
||||
requestPacket = new OwserverPacket(OwserverMessageType.PRESENT, path, OwserverControlFlag.UNCACHED);
|
||||
|
||||
OwserverPacket returnPacket = request(requestPacket);
|
||||
if (returnPacket.getReturnCode() == 0) {
|
||||
returnValue = OnOffType.ON;
|
||||
}
|
||||
|
||||
} catch (OwException e) {
|
||||
returnValue = OnOffType.OFF;
|
||||
}
|
||||
logger.trace("presence {} : {}", path, returnValue);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a decimal type
|
||||
*
|
||||
* @param path full owfs path to sensor
|
||||
* @return DecimalType if successful
|
||||
* @throws OwException
|
||||
*/
|
||||
public State readDecimalType(String path) throws OwException {
|
||||
State returnState = UnDefType.UNDEF;
|
||||
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path);
|
||||
|
||||
OwserverPacket returnPacket = request(requestPacket);
|
||||
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
|
||||
try {
|
||||
returnState = DecimalType.valueOf(returnPacket.getPayloadString().trim());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new OwException("could not parse '" + returnPacket.getPayloadString().trim() + "' to a number");
|
||||
}
|
||||
} else {
|
||||
throw new OwException("invalid or empty packet when requesting decimal type");
|
||||
}
|
||||
|
||||
return returnState;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a decimal type array
|
||||
*
|
||||
* @param path full owfs path to sensor
|
||||
* @return a List of DecimalType values if successful
|
||||
* @throws OwException
|
||||
*/
|
||||
public List<State> readDecimalTypeArray(String path) throws OwException {
|
||||
List<State> returnList = new ArrayList<>();
|
||||
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path);
|
||||
OwserverPacket returnPacket = request(requestPacket);
|
||||
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
|
||||
Arrays.stream(returnPacket.getPayloadString().split(","))
|
||||
.forEach(v -> returnList.add(DecimalType.valueOf(v.trim())));
|
||||
} else {
|
||||
throw new OwException("invalid or empty packet when requesting decimal type array");
|
||||
}
|
||||
|
||||
return returnList;
|
||||
}
|
||||
|
||||
/**
|
||||
* read a string
|
||||
*
|
||||
* @param path full owfs path to sensor
|
||||
* @return requested String
|
||||
* @throws OwException
|
||||
*/
|
||||
public String readString(String path) throws OwException {
|
||||
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path);
|
||||
OwserverPacket returnPacket = request(requestPacket);
|
||||
|
||||
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
|
||||
return returnPacket.getPayloadString().trim();
|
||||
} else {
|
||||
throw new OwException("invalid or empty packet when requesting string type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read all sensor pages
|
||||
*
|
||||
* @param path full owfs path to sensor
|
||||
* @return page buffer
|
||||
* @throws OwException
|
||||
*/
|
||||
public OwPageBuffer readPages(String path) throws OwException {
|
||||
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.READ, path + "/pages/page.ALL");
|
||||
OwserverPacket returnPacket = request(requestPacket);
|
||||
if ((returnPacket.getReturnCode() != -1) && returnPacket.hasPayload()) {
|
||||
return returnPacket.getPayload();
|
||||
} else {
|
||||
throw new OwException("invalid or empty packet when requesting pages");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write a DecimalType
|
||||
*
|
||||
* @param path full owfs path to the sensor
|
||||
* @param value the value to write
|
||||
* @throws OwException
|
||||
*/
|
||||
public void writeDecimalType(String path, DecimalType value) throws OwException {
|
||||
OwserverPacket requestPacket = new OwserverPacket(OwserverMessageType.WRITE, path);
|
||||
requestPacket.appendPayload(String.valueOf(value));
|
||||
|
||||
// request method throws an OwException in case of issues...
|
||||
OwserverPacket returnPacket = request(requestPacket);
|
||||
|
||||
logger.trace("wrote: {}, got: {} ", requestPacket, returnPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* process a request to the owserver
|
||||
*
|
||||
* @param requestPacket the request to be send
|
||||
* @return the raw owserver answer
|
||||
* @throws OwException
|
||||
*/
|
||||
private OwserverPacket request(OwserverPacket requestPacket) throws OwException {
|
||||
OwserverPacket returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
|
||||
|
||||
// answer to value write is always empty
|
||||
boolean payloadExpected = requestPacket.getMessageType() != OwserverMessageType.WRITE;
|
||||
|
||||
try {
|
||||
// write request - error may be thrown
|
||||
write(requestPacket);
|
||||
|
||||
// try to read data as long as we don't get any feedback and no error is thrown...
|
||||
do {
|
||||
if (requestPacket.getMessageType() == OwserverMessageType.PRESENT
|
||||
|| requestPacket.getMessageType() == OwserverMessageType.NOP) {
|
||||
returnPacket = read(true);
|
||||
} else {
|
||||
returnPacket = read(false);
|
||||
}
|
||||
} while (returnPacket.isPingPacket() || !(returnPacket.hasPayload() == payloadExpected));
|
||||
|
||||
} catch (OwException e) {
|
||||
logger.debug("failed requesting {}->{} [{}]", requestPacket, returnPacket, e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (!returnPacket.hasControlFlag(OwserverControlFlag.PERSISTENCE)) {
|
||||
logger.trace("closing connection because persistence was denied");
|
||||
close();
|
||||
}
|
||||
|
||||
// Success! Reset error counter.
|
||||
connectionErrorCounter = 0;
|
||||
return returnPacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* open/reopen the connection to the owserver
|
||||
*
|
||||
* In case of issues, the connection is closed using {@link #closeOnError()} and false is returned.
|
||||
* If the {@link #owserverConnectionState} is in STOPPED or FAILED, the method directly returns false.
|
||||
*
|
||||
* @return true if open
|
||||
*/
|
||||
private boolean open() {
|
||||
try {
|
||||
if (owserverConnectionState == OwserverConnectionState.CLOSED || tryingConnectionRecovery) {
|
||||
// open socket & set timeout to 3000ms
|
||||
final Socket owserverSocket = new Socket(owserverAddress, owserverPort);
|
||||
owserverSocket.setSoTimeout(3000);
|
||||
this.owserverSocket = owserverSocket;
|
||||
|
||||
owserverInputStream = new DataInputStream(owserverSocket.getInputStream());
|
||||
owserverOutputStream = new DataOutputStream(owserverSocket.getOutputStream());
|
||||
|
||||
owserverConnectionState = OwserverConnectionState.OPENED;
|
||||
thingHandlerCallback.reportConnectionState(owserverConnectionState);
|
||||
|
||||
logger.debug("OW connection state: opened to {}:{}", owserverAddress, owserverPort);
|
||||
return true;
|
||||
} else if (owserverConnectionState == OwserverConnectionState.OPENED) {
|
||||
// socket already open, clear input buffer
|
||||
logger.trace("owServerConnection already open, skipping input buffer");
|
||||
final DataInputStream owserverInputStream = this.owserverInputStream;
|
||||
while (owserverInputStream != null) {
|
||||
if (owserverInputStream.skip(owserverInputStream.available()) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
logger.debug("input stream not available on skipping");
|
||||
closeOnError();
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.debug("could not open owServerConnection to {}:{}: {}", owserverAddress, owserverPort,
|
||||
e.getMessage());
|
||||
closeOnError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* close connection and report connection state to callback
|
||||
*/
|
||||
private void close() {
|
||||
this.close(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* close the connection to the owserver instance.
|
||||
*
|
||||
* @param reportConnectionState true, if connection state shall be reported to callback
|
||||
*/
|
||||
private void close(boolean reportConnectionState) {
|
||||
final Socket owserverSocket = this.owserverSocket;
|
||||
if (owserverSocket != null) {
|
||||
try {
|
||||
owserverSocket.close();
|
||||
owserverConnectionState = OwserverConnectionState.CLOSED;
|
||||
logger.debug("closed connection");
|
||||
} catch (IOException e) {
|
||||
owserverConnectionState = OwserverConnectionState.FAILED;
|
||||
logger.warn("could not close connection: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
this.owserverSocket = null;
|
||||
this.owserverInputStream = null;
|
||||
this.owserverOutputStream = null;
|
||||
|
||||
if (reportConnectionState) {
|
||||
thingHandlerCallback.reportConnectionState(owserverConnectionState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if the connection is dead and close it
|
||||
*/
|
||||
private void checkConnection() {
|
||||
try {
|
||||
int pid = ((DecimalType) readDecimalType("/system/process/pid")).intValue();
|
||||
logger.debug("read pid {} -> connection still alive", pid);
|
||||
return;
|
||||
} catch (OwException e) {
|
||||
closeOnError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* close the connection to the owserver instance after an error occured.
|
||||
* if {@link #CONNECTION_MAX_RETRY} is exceeded, {@link #owserverConnectionState} is set to FAILED
|
||||
* and state is reported to callback.
|
||||
*/
|
||||
private void closeOnError() {
|
||||
connectionErrorCounter++;
|
||||
close(false);
|
||||
if (connectionErrorCounter > CONNECTION_MAX_RETRY) {
|
||||
logger.debug("OW connection state: set to failed as max retries exceeded.");
|
||||
owserverConnectionState = OwserverConnectionState.FAILED;
|
||||
tryingConnectionRecovery = false;
|
||||
thingHandlerCallback.reportConnectionState(owserverConnectionState);
|
||||
} else if (!tryingConnectionRecovery) {
|
||||
// as close did not report connections state and we are not trying to recover ...
|
||||
thingHandlerCallback.reportConnectionState(owserverConnectionState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write to the owserver
|
||||
*
|
||||
* In case of issues, the connection is closed using {@link #closeOnError()} and an
|
||||
* {@link OwException} is thrown.
|
||||
*
|
||||
* @param requestPacket data to write
|
||||
* @throws OwException
|
||||
*/
|
||||
private void write(OwserverPacket requestPacket) throws OwException {
|
||||
try {
|
||||
if (open()) {
|
||||
requestPacket.setControlFlags(OwserverControlFlag.PERSISTENCE);
|
||||
final DataOutputStream owserverOutputStream = this.owserverOutputStream;
|
||||
if (owserverOutputStream != null) {
|
||||
owserverOutputStream.write(requestPacket.toBytes());
|
||||
logger.trace("wrote: {}", requestPacket);
|
||||
} else {
|
||||
logger.debug("output stream not available on write");
|
||||
closeOnError();
|
||||
throw new OwException("I/O Error: output stream not available on write");
|
||||
}
|
||||
} else {
|
||||
// was not opened
|
||||
throw new OwException("I/O error: could not open connection to send request packet");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
closeOnError();
|
||||
logger.debug("couldn't send {}, {}", requestPacket, e.getMessage());
|
||||
throw new OwException("I/O Error: exception while sending request packet - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read from owserver
|
||||
*
|
||||
* In case of errors (which may also be due to an erroneous path), the connection is checked and potentially closed
|
||||
* using {@link #checkConnection()}.
|
||||
*
|
||||
* @param noTimeoutException retry in case of read time outs instead of exiting with an {@link OwException}.
|
||||
* @return the read packet
|
||||
* @throws OwException
|
||||
*/
|
||||
private OwserverPacket read(boolean noTimeoutException) throws OwException {
|
||||
OwserverPacket returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
|
||||
final DataInputStream owserverInputStream = this.owserverInputStream;
|
||||
if (owserverInputStream != null) {
|
||||
DataInputStream inputStream = owserverInputStream;
|
||||
try {
|
||||
returnPacket = new OwserverPacket(inputStream, OwserverPacketType.RETURN);
|
||||
} catch (EOFException e) {
|
||||
// Read suddenly ended ....
|
||||
logger.warn("EOFException: exception while reading packet - {}", e.getMessage());
|
||||
checkConnection();
|
||||
throw new OwException("EOFException: exception while reading packet - " + e.getMessage());
|
||||
} catch (OwException e) {
|
||||
// Some other issue
|
||||
checkConnection();
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
// Read time out
|
||||
if (e.getMessage().equals("Read timed out") && noTimeoutException) {
|
||||
logger.trace("timeout - setting error code to -1");
|
||||
// will lead to re-try reading in request method!!!
|
||||
returnPacket.setPayload("timeout");
|
||||
returnPacket.setReturnCode(-1);
|
||||
} else {
|
||||
// Other I/O issue
|
||||
checkConnection();
|
||||
throw new OwException("I/O error: exception while reading packet - " + e.getMessage());
|
||||
}
|
||||
}
|
||||
logger.trace("read: {}", returnPacket);
|
||||
} else {
|
||||
logger.debug("input stream not available on read");
|
||||
closeOnError();
|
||||
throw new OwException("I/O Error: input stream not available on read");
|
||||
}
|
||||
|
||||
return returnPacket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.onewire.internal.owserver;
|
||||
|
||||
/**
|
||||
* The {@link OwserverConnectionState} defines the state for connections to owservers
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
public enum OwserverConnectionState {
|
||||
/**
|
||||
* The {@link OwserverConnection} is being torn down (mostly due to dispose of handler).
|
||||
* No refresh, etc. are possible.
|
||||
*/
|
||||
STOPPED,
|
||||
/**
|
||||
* The connection is open.
|
||||
*/
|
||||
OPENED,
|
||||
/**
|
||||
* The connection is closed. On next read / write it will be opened.
|
||||
*/
|
||||
CLOSED,
|
||||
/**
|
||||
* The connection is erroneous and was closed by the {@link OwserverConnection}. After due wait time, it
|
||||
* is tried to reopen it by a scheduled task of
|
||||
* {@link OwserverBridgeHandler#reportConnectionState(OwserverConnectionState)}.
|
||||
*/
|
||||
FAILED
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* 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.onewire.internal.owserver;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OwserverControlFlag} provides the owserver protocol control flag
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public enum OwserverControlFlag {
|
||||
UNCACHED(0x00000020),
|
||||
SAFEMODE(0x00000010),
|
||||
ALIAS(0x00000008),
|
||||
PERSISTENCE(0x00000004),
|
||||
BUS_RET(0x00000002),
|
||||
DEVICE_DISPLAY(0x00000000),
|
||||
OWNET(0x00000100);
|
||||
|
||||
private final int controlFlag;
|
||||
|
||||
OwserverControlFlag(int controlFlag) {
|
||||
this.controlFlag = controlFlag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the this flag's numeric representation
|
||||
*
|
||||
* @return integer value of this flag
|
||||
*/
|
||||
public int getValue() {
|
||||
return controlFlag;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a this flag is set in the parameter
|
||||
*
|
||||
* @param controlFlags full control flag
|
||||
* @return true if this flag is set in the parameter
|
||||
*/
|
||||
public boolean isSet(int controlFlags) {
|
||||
return (this.getValue() & controlFlags) == this.getValue();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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.onewire.internal.owserver;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
|
||||
/**
|
||||
* The {@link OwserverDeviceParameter} device parameter definition for owserver bridge handler
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class OwserverDeviceParameter {
|
||||
private String prefix = "";
|
||||
private String path = "";
|
||||
|
||||
/**
|
||||
* device parameter for owserver bridge handler
|
||||
*
|
||||
* @param prefix path prefix (e.g. "uncached/")
|
||||
* @param path path without sensor id (e.g. "/humidity")
|
||||
*/
|
||||
public OwserverDeviceParameter(String prefix, String path) {
|
||||
if (prefix.endsWith("/")) {
|
||||
this.prefix = prefix.substring(0, prefix.length() - 1);
|
||||
} else {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
if (path.startsWith("/")) {
|
||||
this.path = path;
|
||||
} else {
|
||||
this.path = "/" + path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* device parameter for owserver bridge handler
|
||||
*
|
||||
* @param path path without sensor id (e.g. "/humidity")
|
||||
*/
|
||||
public OwserverDeviceParameter(String path) {
|
||||
this("", path);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the full owfs path for a given sensor id
|
||||
*
|
||||
* @param sensorId
|
||||
*/
|
||||
public String getPath(SensorId sensorId) {
|
||||
return prefix + sensorId.getFullPath() + path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return prefix + "/sensorId" + path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof OwserverDeviceParameter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((OwserverDeviceParameter) o).toString().equals(toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.onewire.internal.owserver;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OwserverMessageType} provides the owserver protocol message type
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public enum OwserverMessageType {
|
||||
ERROR(0x00000000),
|
||||
NOP(0x00000001),
|
||||
READ(0x00000002),
|
||||
WRITE(0x00000003),
|
||||
DIR(0x00000004),
|
||||
SIZE(0x00000005),
|
||||
PRESENT(0x00000006),
|
||||
DIRALL(0x00000007),
|
||||
GET(0x00000008),
|
||||
DIRALLSLASH(0x00000009),
|
||||
GETSLASH(0x0000000a);
|
||||
|
||||
private final int messageType;
|
||||
|
||||
OwserverMessageType(int messageType) {
|
||||
this.messageType = messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the this message type's numeric representation
|
||||
*
|
||||
* @return integer value of this message type
|
||||
*/
|
||||
public int getValue() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* return a new OwMessageType from an integer
|
||||
*
|
||||
* @param messageType the message type as integer
|
||||
* @return OwMessageType
|
||||
*/
|
||||
public static OwserverMessageType fromInt(int messageType) throws IllegalArgumentException {
|
||||
for (OwserverMessageType value : values()) {
|
||||
if (value.getValue() == messageType) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
/**
|
||||
* 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.onewire.internal.owserver;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.OwPageBuffer;
|
||||
|
||||
/**
|
||||
* The {@link OwserverPacket} class provides a single packet for communication with the owserver
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public class OwserverPacket {
|
||||
public static final int PROTOCOL_VERSION = 0;
|
||||
|
||||
// 6x4 bytes
|
||||
public static final int HEADER_SIZE = 24;
|
||||
protected int payloadLength = 0;
|
||||
|
||||
protected final OwserverPacketType packetType;
|
||||
|
||||
protected int protocolVersion = PROTOCOL_VERSION;
|
||||
protected int controlFlags;
|
||||
protected int packetCode = 0;
|
||||
protected int packetSize = 0;
|
||||
protected int payloadOffset = 0;
|
||||
|
||||
protected byte payload[] = new byte[0];
|
||||
|
||||
/**
|
||||
* constructor for new packet
|
||||
*
|
||||
* @param packetType packetType;
|
||||
*/
|
||||
public OwserverPacket(OwserverPacketType packetType) {
|
||||
this.packetType = packetType;
|
||||
setControlFlags(OwserverControlFlag.OWNET, OwserverControlFlag.DEVICE_DISPLAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor for reading packet from stream
|
||||
*
|
||||
* @param owInputStream input stream to read from
|
||||
* @throws IOException
|
||||
* @throws OwExeption
|
||||
*/
|
||||
public OwserverPacket(DataInputStream owInputStream, OwserverPacketType packetType)
|
||||
throws IOException, OwException, EOFException {
|
||||
this.packetType = packetType;
|
||||
|
||||
// header
|
||||
protocolVersion = owInputStream.readInt();
|
||||
payloadLength = owInputStream.readInt();
|
||||
packetCode = owInputStream.readInt();
|
||||
controlFlags = owInputStream.readInt();
|
||||
packetSize = owInputStream.readInt();
|
||||
payloadOffset = owInputStream.readInt();
|
||||
|
||||
// payload
|
||||
if (payloadLength != -1) {
|
||||
if ((protocolVersion != PROTOCOL_VERSION) || !OwserverControlFlag.OWNET.isSet(controlFlags)) {
|
||||
throw new OwException("invalid data read");
|
||||
}
|
||||
if (payloadLength > 0) {
|
||||
payload = new byte[payloadLength];
|
||||
owInputStream.readFully(payload, 0, payloadLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor for a new request message
|
||||
*
|
||||
* @param owMessageType
|
||||
* @param path
|
||||
* @param owControlFlags
|
||||
*/
|
||||
public OwserverPacket(OwserverMessageType owMessageType, String path, OwserverControlFlag... owControlFlags) {
|
||||
this(OwserverPacketType.REQUEST);
|
||||
packetCode = owMessageType.getValue();
|
||||
setPayload(path);
|
||||
setTemperatureScale(OwserverTemperatureScale.CENTIGRADE);
|
||||
setControlFlags(owControlFlags);
|
||||
if (owMessageType == OwserverMessageType.WRITE) {
|
||||
packetSize = 0x00000000;
|
||||
} else {
|
||||
packetSize = 0x00010000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set one or more control flags for this packet
|
||||
*
|
||||
* @param flags one or more flags as OwControlFlag
|
||||
*/
|
||||
public void setControlFlags(OwserverControlFlag... flags) {
|
||||
for (int i = 0; i < flags.length; i++) {
|
||||
controlFlags |= flags[i].getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a certain flag is set in this packet
|
||||
*
|
||||
* @param flag flag to be tested
|
||||
* @return true if flag is set
|
||||
*/
|
||||
public boolean hasControlFlag(OwserverControlFlag flag) {
|
||||
return flag.isSet(controlFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* set this packet's pressure scale
|
||||
*
|
||||
* @param pressureScale
|
||||
*/
|
||||
public void setPressureScale(OwserverPressureScale pressureScale) {
|
||||
controlFlags = pressureScale.setFlag(controlFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* get this packets pressure scale
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public OwserverPressureScale getPressureScale() {
|
||||
return OwserverPressureScale.getFlag(controlFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* set this packet's temperature scale
|
||||
*
|
||||
* @param pressureScale
|
||||
*/
|
||||
public void setTemperatureScale(OwserverTemperatureScale temperatureScale) {
|
||||
controlFlags = temperatureScale.setFlag(controlFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* get this packets temperature scale
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public OwserverTemperatureScale getTemperatureScale() {
|
||||
return OwserverTemperatureScale.getFlag(controlFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* set (or replace) this packet's payload from a string
|
||||
*
|
||||
* @param payload string representation of the payload
|
||||
*/
|
||||
public void setPayload(String payload) {
|
||||
byte[] bytes = payload.getBytes();
|
||||
payloadLength = bytes.length + 1;
|
||||
this.payload = new byte[payloadLength];
|
||||
System.arraycopy(bytes, 0, this.payload, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* append to this packet's payload from a string
|
||||
*
|
||||
* @param payload string representation of the payload to append
|
||||
*/
|
||||
public void appendPayload(String payload) {
|
||||
byte appendBytes[] = payload.getBytes();
|
||||
|
||||
byte[] fullPayload = new byte[this.payload.length + appendBytes.length];
|
||||
System.arraycopy(this.payload, 0, fullPayload, 0, this.payload.length);
|
||||
System.arraycopy(appendBytes, 0, fullPayload, this.payload.length, appendBytes.length);
|
||||
|
||||
this.packetSize += appendBytes.length;
|
||||
this.payloadLength = fullPayload.length;
|
||||
this.payload = fullPayload;
|
||||
}
|
||||
|
||||
/**
|
||||
* set this packet payload from a OwPageBuffer
|
||||
*
|
||||
* @param payload string representation of the payload
|
||||
*/
|
||||
public void setPayload(OwPageBuffer payload) {
|
||||
byte[] bytes = payload.getBytes();
|
||||
payloadLength = bytes.length + 1;
|
||||
this.payload = new byte[payloadLength];
|
||||
System.arraycopy(bytes, 0, this.payload, 0, bytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the payload of this packet
|
||||
*
|
||||
* @return string representation of this packet's payload
|
||||
*/
|
||||
public String getPayloadString() {
|
||||
if (payloadLength > 0) {
|
||||
// already null terminated strings skip the termination character
|
||||
if (payload[payloadLength - 1] == 0) {
|
||||
return new String(payload, 0, payloadLength - 1);
|
||||
} else {
|
||||
return new String(payload, 0, payloadLength);
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set this packet's return code (0 is ok)
|
||||
*
|
||||
* @param returnCode an integer
|
||||
*/
|
||||
public void setReturnCode(int returnCode) {
|
||||
if (packetType == OwserverPacketType.RETURN) {
|
||||
this.packetCode = returnCode;
|
||||
} else {
|
||||
throw new IllegalStateException("setting return code not allowed in REQUEST packets");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get this packet's return code (0 is ok)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getReturnCode() {
|
||||
if (packetType == OwserverPacketType.RETURN) {
|
||||
return packetCode;
|
||||
} else {
|
||||
throw new IllegalStateException("getting return code not allowed in REQUEST packets");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set this packet's message type
|
||||
*
|
||||
* @param messageType
|
||||
*/
|
||||
public void setMessageType(OwserverMessageType messageType) {
|
||||
if (packetType == OwserverPacketType.REQUEST) {
|
||||
packetCode = messageType.getValue();
|
||||
} else {
|
||||
throw new IllegalStateException("setting message type not allowed in RETURN packets");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get this packets message type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public OwserverMessageType getMessageType() {
|
||||
if (packetType == OwserverPacketType.REQUEST) {
|
||||
return OwserverMessageType.fromInt(packetCode);
|
||||
} else {
|
||||
throw new IllegalStateException("getting message type not allowed in RETURN packets");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if packed is valid return packet
|
||||
*
|
||||
* @return true if valid
|
||||
*/
|
||||
public boolean isValidReturnPacket() {
|
||||
return (packetCode == 0 && packetType == OwserverPacketType.RETURN);
|
||||
}
|
||||
|
||||
/**
|
||||
* check if packed is valid return packet
|
||||
*
|
||||
* @return true if valid
|
||||
*/
|
||||
public boolean isPingPacket() {
|
||||
return (payloadLength == -1 && packetType == OwserverPacketType.RETURN);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the payload of this packet
|
||||
*
|
||||
* @return OwPageBuffer with this packet's payload
|
||||
*/
|
||||
public OwPageBuffer getPayload() {
|
||||
OwPageBuffer byteBuffer = new OwPageBuffer(payload);
|
||||
return byteBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if this packet has a payload
|
||||
*
|
||||
* @return true if payload present
|
||||
*/
|
||||
public boolean hasPayload() {
|
||||
return (payloadLength > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert this packet to an array of bytes
|
||||
*
|
||||
* @return array of bytes
|
||||
*/
|
||||
public byte[] toBytes() {
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate(HEADER_SIZE + payloadLength);
|
||||
byteBuffer.putInt(protocolVersion);
|
||||
byteBuffer.putInt(payloadLength);
|
||||
byteBuffer.putInt(packetCode);
|
||||
byteBuffer.putInt(controlFlags);
|
||||
byteBuffer.putInt(packetSize);
|
||||
byteBuffer.putInt(payloadOffset);
|
||||
if (payloadLength > 0) {
|
||||
byteBuffer.put(payload);
|
||||
}
|
||||
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String prefix;
|
||||
|
||||
if (packetType == OwserverPacketType.RETURN) {
|
||||
prefix = String.format("return code %d", packetCode);
|
||||
} else {
|
||||
prefix = String.format("messageType %s", OwserverMessageType.fromInt(packetCode));
|
||||
}
|
||||
|
||||
return String.format("%s, size %d, controlFlags 0x%08x, payload '%s'", prefix, HEADER_SIZE + payloadLength,
|
||||
controlFlags, getPayloadString().replaceAll("\\p{C}", "?"));
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal.owserver;
|
||||
|
||||
/**
|
||||
* The {@link OwserverPacketType} defines owserver packet types
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
public enum OwserverPacketType {
|
||||
REQUEST,
|
||||
RETURN
|
||||
}
|
||||
@@ -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.onewire.internal.owserver;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OwserverPressureScale} provides the owserver protocol pressure scale flags
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public enum OwserverPressureScale {
|
||||
MILLIBAR(0x00000000),
|
||||
ATM(0x00040000),
|
||||
MMHG(0x00080000),
|
||||
INHG(0x000C0000),
|
||||
PSI(0x00100000),
|
||||
PASCAL(0x00140000);
|
||||
|
||||
private static final int CLEAR_MASK = 0x001C0000;
|
||||
private final int flag;
|
||||
|
||||
OwserverPressureScale(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get numeric value of this flag
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getValue() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* set this flag in a set of given flags
|
||||
*
|
||||
* @param flags aggregated flags
|
||||
* @return parameter with this flag set
|
||||
*/
|
||||
public int setFlag(int flags) {
|
||||
return (flags & ~CLEAR_MASK) | this.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* get the pressure scale flag from a given set of flags
|
||||
*
|
||||
* @param flags set of flags
|
||||
* @return pressure scale flag
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public static OwserverPressureScale getFlag(int flags) throws IllegalArgumentException {
|
||||
for (OwserverPressureScale value : values()) {
|
||||
if (value.getValue() == (flags & CLEAR_MASK)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Pressure scale flag not found");
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.internal.owserver;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link OwserverTemperatureScale} provides the owserver protocol temperature scale flags
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
public enum OwserverTemperatureScale {
|
||||
CENTIGRADE(0x00000000),
|
||||
FAHRENHEIT(0x00010000),
|
||||
KELVIN(0x00020000),
|
||||
RANKINE(0x00030000);
|
||||
|
||||
private static final int CLEAR_MASK = 0x00030000;
|
||||
private final int flag;
|
||||
|
||||
OwserverTemperatureScale(int flag) {
|
||||
this.flag = flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get numeric value of this flag
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getValue() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* set this flag in a set of given flags
|
||||
*
|
||||
* @param flags aggregated flags
|
||||
* @return parameter with this flag set
|
||||
*/
|
||||
public int setFlag(int flags) {
|
||||
int tempFlags = flags;
|
||||
tempFlags &= ~CLEAR_MASK;
|
||||
tempFlags |= this.getValue();
|
||||
return tempFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the temperature scale flag from a given set of flags
|
||||
*
|
||||
* @param flags set of flags
|
||||
* @return temperature scale flag
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public static OwserverTemperatureScale getFlag(int flags) {
|
||||
int tempFlags = flags;
|
||||
tempFlags &= CLEAR_MASK;
|
||||
for (OwserverTemperatureScale value : values()) {
|
||||
if (value.getValue() == tempFlags) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return CENTIGRADE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="onewire" 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>OneWire Binding</name>
|
||||
<description>This is the binding for OneWire.</description>
|
||||
<author>Jan N. Klug</author>
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
<config-description uri="thing-type:onewire:basethingconfig">
|
||||
<parameter name="id" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>Sensor ID in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time</label>
|
||||
<description>Time in seconds after which the thing is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
<config-description uri="thing-type:onewire:mstxconfig">
|
||||
<parameter name="id" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>Sensor ID in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time</label>
|
||||
<description>Time in seconds after which the thing is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
<parameter name="manualsensor" type="text">
|
||||
<label>Manual Sensor Type</label>
|
||||
<description>Overrides detected sensor type</description>
|
||||
<options>
|
||||
<option value="DS2438">Generic</option>
|
||||
<option value="MS_TH">MS-TH</option>
|
||||
<option value="MS_TV">MS-TV</option>
|
||||
<option value="MS_TL">MS-TL</option>
|
||||
<option value="MS_TC">MS-TC</option>
|
||||
</options>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<required>false</required>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="onewire"
|
||||
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">
|
||||
<thing-type id="bae091x">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="owserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Multisensor BAE0910</label>
|
||||
<description>1-wire multisensor (BAE0910-based)</description>
|
||||
<properties>
|
||||
<property name="sensorCount">1</property>
|
||||
</properties>
|
||||
<config-description>
|
||||
<parameter name="id" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>Sensor ID in format: xx.xxxxxxxxxxxx)</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time</label>
|
||||
<description>Time in seconds after which the thing is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
</parameter>
|
||||
<parameter name="pin1" type="text">
|
||||
<label>Pin 1 Mode Configuration</label>
|
||||
<options>
|
||||
<option value="disabled">disabled</option>
|
||||
<option value="counter">Counter</option>
|
||||
</options>
|
||||
<default>counter</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="pin2" type="text">
|
||||
<label>Pin 2 Mode Configuration</label>
|
||||
<options>
|
||||
<option value="disabled">disabled</option>
|
||||
<option value="output">Digital Output</option>
|
||||
<option value="pwm">Software PWM 4</option>
|
||||
</options>
|
||||
<default>output</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="pin6" type="text">
|
||||
<label>Pin 6 Mode Configuration</label>
|
||||
<options>
|
||||
<option value="disabled">disabled</option>
|
||||
<option value="pio">PIO</option>
|
||||
<option value="pwm">Software PWM 3</option>
|
||||
</options>
|
||||
<default>pio</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="pin7" type="text">
|
||||
<label>Pin 7 Mode Configuration</label>
|
||||
<options>
|
||||
<option value="disabled">disabled</option>
|
||||
<option value="analog">Analog Input</option>
|
||||
<option value="output">Digital Output</option>
|
||||
<option value="pwm">Hardware PWM 2</option>
|
||||
</options>
|
||||
<default>analog</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="pin8" type="text">
|
||||
<label>Pin 8 Mode Configuration</label>
|
||||
<options>
|
||||
<option value="disabled">disabled</option>
|
||||
<option value="input">Digital Input</option>
|
||||
<option value="output">Digital Output</option>
|
||||
<option value="pwm">Hardware PWM 1</option>
|
||||
</options>
|
||||
<default>output</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
<!-- PWM Channels -->
|
||||
<channel-type id="bae-pwm-frequency">
|
||||
<item-type>Number:Frequency</item-type>
|
||||
<label>Frequency</label>
|
||||
<description>Frequency of PWM output in Hz</description>
|
||||
<config-description>
|
||||
<parameter name="prescaler" type="integer">
|
||||
<label>Range</label>
|
||||
<description>defines the frequency range of PWM output</description>
|
||||
<options>
|
||||
<option value="0">245 Hz - 8 MHz</option>
|
||||
<option value="1">123 Hz - 4 MHz</option>
|
||||
<option value="2">62 Hz - 2 MHz</option>
|
||||
<option value="3">31 Hz - 1 MHz</option>
|
||||
<option value="4">16 Hz - 500 kHz</option>
|
||||
<option value="5">8 Hz - 250 kHz</option>
|
||||
<option value="6">4 Hz - 125 kHz</option>
|
||||
<option value="7">2 Hz - 62.5 kHz</option>
|
||||
</options>
|
||||
<default>0</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="reversePolarity" type="boolean">
|
||||
<label>Reverse Polarity</label>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="bae-pwm-duty">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Duty Cycle</label>
|
||||
<description>Duty cycle of PWM output in %</description>
|
||||
</channel-type>
|
||||
<!-- Digital Channels -->
|
||||
<channel-type id="bae-pio">
|
||||
<item-type>Switch</item-type>
|
||||
<label>PIO</label>
|
||||
<description>Programmable I/O channel</description>
|
||||
<config-description>
|
||||
<parameter name="mode" type="text">
|
||||
<label>Mode</label>
|
||||
<options>
|
||||
<option value="input">Input</option>
|
||||
<option value="output">Output</option>
|
||||
</options>
|
||||
<default>input</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="pulldevice" type="text">
|
||||
<label>Pull-Up/Pull-Down Resistor</label>
|
||||
<options>
|
||||
<option value="disabled">disabled</option>
|
||||
<option value="pullup">Pull-Up</option>
|
||||
<option value="pulldown">Pull-Down</option>
|
||||
</options>
|
||||
<default>disabled</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="bae-do">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Digital Out</label>
|
||||
</channel-type>
|
||||
<channel-type id="bae-di">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Digital In</label>
|
||||
</channel-type>
|
||||
<!-- Analog In (ADC) -->
|
||||
<channel-type id="bae-analog">
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>Analog Input</label>
|
||||
<description>Analog input (ADC)</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
<config-description>
|
||||
<parameter name="hires" type="boolean">
|
||||
<label>Hires</label>
|
||||
<description>High resolution Mode (10bit)</description>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<!-- Counter Channel -->
|
||||
<channel-type id="bae-counter">
|
||||
<item-type>Number</item-type>
|
||||
<label>Counter</label>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="onewire"
|
||||
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">
|
||||
<thing-type id="basic">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="owserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Basic 1 Wire Sensor</label>
|
||||
<config-description-ref uri="thing-type:onewire:basethingconfig"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="onewire"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
<bridge-type id="owserver" extensible="owfs-string,owfs-number">
|
||||
<label>OW Server</label>
|
||||
<description>An owserver instance</description>
|
||||
<config-description>
|
||||
<parameter name="network-address" type="text">
|
||||
<context>network_address</context>
|
||||
<label>Network Address</label>
|
||||
<description>Network address of the host running the owserver</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer">
|
||||
<label>Port</label>
|
||||
<description>Listening port of the owserver</description>
|
||||
<default>4304</default>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
<channel-type id="owfs-string">
|
||||
<item-type>String</item-type>
|
||||
<label>Direct Access to OWFS-Path (String)</label>
|
||||
<description>Allows direct access to the OWFS</description>
|
||||
<state readOnly="true"/>
|
||||
<config-description>
|
||||
<parameter name="path" type="text">
|
||||
<label>OWFS Path</label>
|
||||
<description>full path to the OWFS-node (e.g. statistics/errors/CRC8_errors)</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time</label>
|
||||
<description>Time in seconds after which the channel is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="owfs-number">
|
||||
<item-type>Number</item-type>
|
||||
<label>Direct Access to OWFS-Path (Number)</label>
|
||||
<description>Allows direct access to the OWFS</description>
|
||||
<state readOnly="true"/>
|
||||
<config-description>
|
||||
<parameter name="path" type="text">
|
||||
<label>OWFS Path</label>
|
||||
<description>full path to the OWFS-node (e.g. statistics/errors/CRC8_errors)</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time</label>
|
||||
<description>Time in seconds after which the channel is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="onewire"
|
||||
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">
|
||||
<!-- Device Present Channel -->
|
||||
<channel-type id="present">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Present</label>
|
||||
<description>ON if device present on OneWire bus</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
<!-- Temperature Channel -->
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>temperature value of this sensor</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<channel-type id="temperature-por">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>temperature value of this sensor</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
<config-description>
|
||||
<parameter name="ignorepor" type="boolean">
|
||||
<label>Ignore POR-value</label>
|
||||
<description>filters all 85°C readings (POR-value), may suppress valid readings if enabled</description>
|
||||
<default>false</default>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="temperature-por-res">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>temperature value of this sensor</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
<config-description>
|
||||
<parameter name="ignorepor" type="boolean">
|
||||
<label>Ignore POR-value</label>
|
||||
<description>filters all 85°C readings (POR-value), may suppress valid readings if enabled</description>
|
||||
<default>false</default>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
<parameter name="resolution" type="text">
|
||||
<label>Sensor Resolution</label>
|
||||
<options>
|
||||
<option value="9">9 bit</option>
|
||||
<option value="10">10 bit</option>
|
||||
<option value="11">11 bit</option>
|
||||
<option value="12">12 bit</option>
|
||||
</options>
|
||||
<default>10</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<!-- Dewpoint Channel -->
|
||||
<channel-type id="dewpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Dewpoint</label>
|
||||
<description>dewpoint (calculated from temperature and relative humidity)</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Relative Humidity Channel -->
|
||||
<channel-type id="humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>relative humidity (0-100%)</description>
|
||||
<state readOnly="true" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
<channel-type id="humidityconf">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>relative humidity (0-100%)</description>
|
||||
<state readOnly="true" pattern="%d %%"/>
|
||||
<config-description>
|
||||
<parameter name="humiditytype" type="text">
|
||||
<label>Humidity Sensor-Type</label>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<options>
|
||||
<option value="/humidity">HIH-3610</option>
|
||||
<option value="/HIH4000/humidity">HIH-4000</option>
|
||||
<option value="/HTM1735/humidity">HTM-1735</option>
|
||||
<option value="/DATANAB/humidity">Datanab</option>
|
||||
</options>
|
||||
<default>/humidity</default>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<!-- Absolute Humidity Channel -->
|
||||
<channel-type id="absolutehumidity">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>Abs. Humidity</label>
|
||||
<description>absolute humidity (calculated from temperature and relative humidity)</description>
|
||||
<state readOnly="true" pattern="%.2f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Voltage Channel -->
|
||||
<channel-type id="voltage">
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>Voltage</label>
|
||||
<description>The voltage measured by the sensor</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Supply-Voltage Channel -->
|
||||
<channel-type id="supplyvoltage">
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>Supply Voltage</label>
|
||||
<description>The sensor's supply voltage</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Light Channel -->
|
||||
<channel-type id="light">
|
||||
<item-type>Number:Illuminance</item-type>
|
||||
<label>Illuminance</label>
|
||||
<description>Ambient light</description>
|
||||
<state readOnly="true" pattern="%.0f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Current Channel -->
|
||||
<channel-type id="current">
|
||||
<item-type>Number:ElectricCurrent</item-type>
|
||||
<label>Current</label>
|
||||
<description>The current measured by the sensor</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Digital I/O Channel -->
|
||||
<channel-type id="dio">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Digital I/O</label>
|
||||
<config-description>
|
||||
<parameter name="mode" type="text">
|
||||
<label>Mode</label>
|
||||
<options>
|
||||
<option value="input">Input</option>
|
||||
<option value="output">Output</option>
|
||||
</options>
|
||||
<default>input</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
<parameter name="logic" type="text">
|
||||
<label>Channel Logic</label>
|
||||
<options>
|
||||
<option value="normal">normal</option>
|
||||
<option value="inverted">inverted</option>
|
||||
</options>
|
||||
<default>normal</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<!-- Pressure Channel -->
|
||||
<channel-type id="pressure">
|
||||
<item-type>Number:Pressure</item-type>
|
||||
<label>Pressure</label>
|
||||
<description>The pressure measured by the sensor</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
<!-- Counter Channel -->
|
||||
<channel-type id="counter">
|
||||
<item-type>Number</item-type>
|
||||
<label>Counter</label>
|
||||
<description>A single counter (reset on power loss)</description>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="onewire"
|
||||
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">
|
||||
<thing-type id="ms-tx">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="owserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Multisensor (T, TC, TH, TL, TV, Generic)</label>
|
||||
<description>A 1-wire multisensor (DS1923/DS2438-based)</description>
|
||||
<config-description-ref uri="thing-type:onewire:mstxconfig"/>
|
||||
</thing-type>
|
||||
<thing-type id="bms">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="owserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Multisensor BMS</label>
|
||||
<description>1-wire multisensor (DS2438-based)</description>
|
||||
<config-description>
|
||||
<parameter name="id" type="text">
|
||||
<label>TH(S) Sensor ID</label>
|
||||
<description>Sensor ID of the DS2438 sensor in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time</label>
|
||||
<description>Time in seconds after which the thing is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
<parameter name="temperaturesensor" type="text">
|
||||
<label>Temperature Sensor</label>
|
||||
<options>
|
||||
<option value="DS2438">internal (DS2438)</option>
|
||||
<option value="DS18B20">external (DS18B20)</option>
|
||||
</options>
|
||||
<default>DS2438</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
<thing-type id="ams">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="owserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Multisensor AMS</label>
|
||||
<description>1-wire multisensor (DS2438-based)</description>
|
||||
<config-description>
|
||||
<parameter name="id" type="text">
|
||||
<label>TH(S) Sensor ID</label>
|
||||
<description>Sensor ID of the DS2438 sensor in format: xx.xxxxxxxxxxxx or a full path including hubs/branches</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time for Analog Channels</label>
|
||||
<description>Time in seconds after which the thing is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
<parameter name="refreshdigital" type="integer" min="1">
|
||||
<label>Refresh Time for Digital Channels</label>
|
||||
<description>Time in seconds after which the digital I/Os are refreshed</description>
|
||||
<default>10</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
<parameter name="temperaturesensor" type="text">
|
||||
<label>Temperature Sensor</label>
|
||||
<options>
|
||||
<option value="DS2438">internal (DS2438)</option>
|
||||
<option value="DS18B20">external (DS18B20)</option>
|
||||
</options>
|
||||
<default>DS2438</default>
|
||||
<limitToOptions>true</limitToOptions>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
<thing-type id="edsenv">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="owserver"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Multisensor EDS</label>
|
||||
<description>A 1-wire multisensor (EDS00xx-based)</description>
|
||||
<properties>
|
||||
<property name="sensorCount">1</property>
|
||||
</properties>
|
||||
<config-description>
|
||||
<parameter name="id" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>Sensor ID in format: xx.xxxxxxxxxxxx)</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="refresh" type="integer" min="1">
|
||||
<label>Refresh Time</label>
|
||||
<description>Time in seconds after which the thing is refreshed</description>
|
||||
<default>300</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,29 @@
|
||||
humidity = Number:Dimensionless
|
||||
absolutehumidity = Number:Density
|
||||
dewpoint = Number:Temperature
|
||||
temperature = Number:Temperature
|
||||
light = Number:Illuminance
|
||||
pressure = Number:Pressure
|
||||
voltage = Number:ElectricPotential
|
||||
supplyvoltage = Number:ElectricPotential
|
||||
current = Number:ElectricCurrent
|
||||
counter = Number
|
||||
counter0 = Number
|
||||
counter1 = Number
|
||||
digital = Switch
|
||||
digital0 = Switch
|
||||
digital1 = Switch
|
||||
digital2 = Switch
|
||||
digital3 = Switch
|
||||
digital4 = Switch
|
||||
digital5 = Switch
|
||||
digital6 = Switch
|
||||
digital7 = Switch
|
||||
digital8 = Switch
|
||||
present = Switch
|
||||
pwmduty1 = Number:Dimensionsless
|
||||
pwmduty2 = Number:Dimensionsless
|
||||
pwmduty3 = Number:Dimensionsless
|
||||
pwmduty4 = Number:Dimensionsless
|
||||
pwmfreq1 = Number:Frequency
|
||||
pwmfreq2 = Number:Frequency
|
||||
@@ -0,0 +1,89 @@
|
||||
#
|
||||
# sensor.properties - This file defines the sensor properties
|
||||
#
|
||||
# Format: sensorType.channels = name:type:[label][,name:type:[label]]...
|
||||
# sensorType.label = label
|
||||
# sensorType.thingtype = thingtype
|
||||
#
|
||||
DS1420.channels = present:present:
|
||||
DS1420.label = 1kb EEPROM
|
||||
DS1420.thingtype = basic
|
||||
DS1822.channels = temperature:temperature-por-res:
|
||||
DS1822.label = Temperature Sensor
|
||||
DS1822.thingtype = basic
|
||||
DS18B20.channels = temperature:temperature-por-res:
|
||||
DS18B20.label = Temperature Sensor
|
||||
DS18B20.thingtype = basic
|
||||
DS18S20.channels = temperature:temperature-por:
|
||||
DS18S20.label = Temperature Sensor
|
||||
DS18S20.thingtype = basic
|
||||
DS1923.channels = temperature:temperature:,humidity:humidity:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
|
||||
DS1923.label = Multisensor
|
||||
DS1923.thingtype = ms-tx
|
||||
DS2401.channels = present:present:
|
||||
DS2401.label = iButton
|
||||
DS2401.thingtype = basic
|
||||
DS2405.channels = digital0:dio:Digital I/O 0
|
||||
DS2405.label = Single Digital I/O
|
||||
DS2405.thingtype = basic
|
||||
DS2406.channels = digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
|
||||
DS2406.label = Dual Digital I/O
|
||||
DS2406.thingtype = basic
|
||||
DS2408.channels = digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1,digital2:dio:Digital I/O 2,digital3:dio:Digital I/O 3,digital4:dio:Digital I/O 4,digital5:dio:Digital I/O 5,digital6:dio:Digital I/O 6,digital7:dio:Digital I/O 7
|
||||
DS2408.label = Octal Digital I/O
|
||||
DS2408.thingtype = basic
|
||||
DS2413.channels = digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
|
||||
DS2413.label = Dual Digital I/O
|
||||
DS2413.thingtype = basic
|
||||
DS2423.channels = counter0:counter:Counter 0,counter1:counter:Counter 1
|
||||
DS2423.label = Dual Counter
|
||||
DS2423.thingtype = basic
|
||||
# AMS/BMS: humidity and temperature added by handler
|
||||
AMS.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,voltage:voltage:,digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
|
||||
AMS.label = Multisensor AMS
|
||||
AMS.thingtype = ams
|
||||
AMS_S.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,light:light:,voltage:voltage:,digital0:dio:Digital I/O 0,digital1:dio:Digital I/O 1
|
||||
AMS_S.label = Multisensor AMS
|
||||
AMS_S.thingtype = ams
|
||||
BMS.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
|
||||
BMS.label = Multisensor BMS
|
||||
BMS.thingtype = bms
|
||||
BMS_S.channels = supplyvoltage:voltage:Supplyvoltage,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,light:light:
|
||||
BMS_S.label = Multisensor BMS
|
||||
BMS_S.thingtype = bms
|
||||
# DS2438
|
||||
DS2438.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,voltage:voltage:,current:current:
|
||||
DS2438.label = Multisensor (generic)
|
||||
DS2438.thingtype = ms-tx
|
||||
MS_TC.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,voltage:voltage:
|
||||
MS_TC.label = Multisensor TC
|
||||
MS_TC.thingtype = ms-tx
|
||||
MS_TH.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,humidity:humidityconf:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
|
||||
MS_TH.label = Multisensor TH
|
||||
MS_TH.thingtype = ms-tx
|
||||
MS_TL.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,light:light:
|
||||
MS_TL.label = Multisensor TL
|
||||
MS_TL.thingtype = ms-tx
|
||||
MS_TV.channels = supplyvoltage:voltage:Supplyvoltage,temperature:temperature:,voltage:voltage:
|
||||
MS_TV.label = Multisensor TV
|
||||
MS_TV.thingtype = ms-tx
|
||||
# EDS
|
||||
EDS0064.channels = temperature:temperature:
|
||||
EDS0064.label = Multisensor EDS
|
||||
EDS0064.thingtype = edsenv
|
||||
EDS0065.channels = temperature:temperature:,humidity:humidity:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint
|
||||
EDS0065.label = Multisensor EDS
|
||||
EDS0065.thingtype = edsenv
|
||||
EDS0066.channels = temperature:temperature:,pressure:pressure:
|
||||
EDS0066.label = Multisensor EDS
|
||||
EDS0066.thingtype = edsenv
|
||||
EDS0067.channels = temperature:temperature:,light:light:
|
||||
EDS0067.label = Multisensor EDS
|
||||
EDS0067.thingtype = edsenv
|
||||
EDS0068.channels = temperature:temperature:,humidity:humidity:,absolutehumidity:abshumidity:,dewpoint:temperature:Dewpoint,pressure:pressure:,light:light:
|
||||
EDS0068.label = Multisensor EDS
|
||||
EDS0068.thingtype = edsenv
|
||||
# BAE091x
|
||||
BAE0910.channels =
|
||||
BAE0910.label = Multisensor BAE0910
|
||||
BAE0910.thingtype = bae091x
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* 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.onewire;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.onewire.internal.OwBindingConstants;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.handler.*;
|
||||
|
||||
/**
|
||||
* Tests cases for binding completeness
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CompletenessTest {
|
||||
// internal/temporary types, DS2409 (MicroLAN Coupler), DS2431 (EEPROM)
|
||||
private static final Set<OwSensorType> IGNORED_SENSOR_TYPES = Collections
|
||||
.unmodifiableSet(Stream.of(OwSensorType.DS2409, OwSensorType.DS2431, OwSensorType.EDS, OwSensorType.MS_TH_S,
|
||||
OwSensorType.BAE, OwSensorType.BAE0911, OwSensorType.UNKNOWN).collect(Collectors.toSet()));
|
||||
|
||||
private static final Set<OwSensorType> THINGHANDLER_SENSOR_TYPES = Collections.unmodifiableSet(Stream
|
||||
.of(AdvancedMultisensorThingHandler.SUPPORTED_SENSOR_TYPES,
|
||||
BasicMultisensorThingHandler.SUPPORTED_SENSOR_TYPES, BasicThingHandler.SUPPORTED_SENSOR_TYPES,
|
||||
EDSSensorThingHandler.SUPPORTED_SENSOR_TYPES, BAE091xSensorThingHandler.SUPPORTED_SENSOR_TYPES)
|
||||
.flatMap(Set::stream).collect(Collectors.toSet()));
|
||||
|
||||
@Test
|
||||
public void allSupportedTypesInThingHandlerMap() {
|
||||
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
|
||||
if (!OwBindingConstants.THING_TYPE_MAP.containsKey(sensorType)
|
||||
&& !IGNORED_SENSOR_TYPES.contains(sensorType)) {
|
||||
Assert.fail("missing thing type map for sensor type " + sensorType.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allSupportedTypesInThingChannelsMap() {
|
||||
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
|
||||
if (!OwBindingConstants.SENSOR_TYPE_CHANNEL_MAP.containsKey(sensorType)
|
||||
&& !IGNORED_SENSOR_TYPES.contains(sensorType)) {
|
||||
Assert.fail("missing channel configuration map for sensor type " + sensorType.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allSensorsSupportedByThingHandlers() {
|
||||
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
|
||||
if (!THINGHANDLER_SENSOR_TYPES.contains(sensorType) && !IGNORED_SENSOR_TYPES.contains(sensorType)) {
|
||||
Assert.fail("missing thing handler for sensor type " + sensorType.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allSensorTypesInLabelMap() {
|
||||
for (OwSensorType sensorType : EnumSet.allOf(OwSensorType.class)) {
|
||||
if (!OwBindingConstants.THING_LABEL_MAP.containsKey(sensorType)
|
||||
&& !IGNORED_SENSOR_TYPES.contains(sensorType)) {
|
||||
Assert.fail("missing label for sensor type " + sensorType.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptedItemTypeMapCompleteness() throws OwException {
|
||||
List<String> channels = Arrays.stream(OwBindingConstants.class.getDeclaredFields())
|
||||
.filter(f -> Modifier.isStatic(f.getModifiers()))
|
||||
.filter(f -> f.getName().startsWith("CHANNEL") && !f.getName().startsWith("CHANNEL_TYPE")).map(f -> {
|
||||
try {
|
||||
return (String) f.get(null);
|
||||
} catch (IllegalAccessException e) {
|
||||
Assert.fail("unexpected");
|
||||
return null;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
for (String channel : channels) {
|
||||
if (!OwBindingConstants.ACCEPTED_ITEM_TYPES_MAP.containsKey(channel)) {
|
||||
Assert.fail("missing accepted item type for channel " + channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.onewire;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link SensorId}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwserverDeviceParameterTest {
|
||||
private final SensorId sensorId = new SensorId("/1F.0123456789ab/main/00.1234567890ab");
|
||||
|
||||
@Test
|
||||
public void withoutPrefixTest() {
|
||||
OwserverDeviceParameter owserverDeviceParameter = new OwserverDeviceParameter("/humidity");
|
||||
assertEquals("/1F.0123456789ab/main/00.1234567890ab/humidity", owserverDeviceParameter.getPath(sensorId));
|
||||
|
||||
owserverDeviceParameter = new OwserverDeviceParameter("humidity");
|
||||
assertEquals("/1F.0123456789ab/main/00.1234567890ab/humidity", owserverDeviceParameter.getPath(sensorId));
|
||||
}
|
||||
|
||||
public void withPrefixTest() {
|
||||
OwserverDeviceParameter owserverDeviceParameter = new OwserverDeviceParameter("uncached", "/humidity");
|
||||
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
|
||||
owserverDeviceParameter.getPath(sensorId));
|
||||
|
||||
owserverDeviceParameter = new OwserverDeviceParameter("uncached", "/humidity");
|
||||
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
|
||||
owserverDeviceParameter.getPath(sensorId));
|
||||
|
||||
owserverDeviceParameter = new OwserverDeviceParameter("/uncached", "/humidity");
|
||||
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
|
||||
owserverDeviceParameter.getPath(sensorId));
|
||||
|
||||
owserverDeviceParameter = new OwserverDeviceParameter("/uncached/", "/humidity");
|
||||
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
|
||||
owserverDeviceParameter.getPath(sensorId));
|
||||
|
||||
owserverDeviceParameter = new OwserverDeviceParameter("uncached/", "/humidity");
|
||||
assertEquals("/uncached/1F.0123456789ab/main/00.1234567890ab/humidity",
|
||||
owserverDeviceParameter.getPath(sensorId));
|
||||
}
|
||||
}
|
||||
@@ -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.onewire;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link SensorId}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SensorIdTest {
|
||||
|
||||
@Test
|
||||
public void bareSensorIdConstructionTest() {
|
||||
SensorId sensorId = new SensorId("28.0123456789ab");
|
||||
assertEquals("/28.0123456789ab", sensorId.getFullPath());
|
||||
assertEquals("28.0123456789ab", sensorId.getId());
|
||||
assertEquals("28", sensorId.getFamilyId());
|
||||
|
||||
sensorId = new SensorId("/28.0123456789ab");
|
||||
assertEquals("/28.0123456789ab", sensorId.getFullPath());
|
||||
assertEquals("28.0123456789ab", sensorId.getId());
|
||||
assertEquals("28", sensorId.getFamilyId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hubMainSensorIdConstructionTest() {
|
||||
SensorId sensorId = new SensorId("1F.0123456789ab/main/28.0123456789ab");
|
||||
assertEquals("/1F.0123456789ab/main/28.0123456789ab", sensorId.getFullPath());
|
||||
assertEquals("28.0123456789ab", sensorId.getId());
|
||||
assertEquals("28", sensorId.getFamilyId());
|
||||
|
||||
sensorId = new SensorId("/1F.0123456789ab/main/28.0123456789ab");
|
||||
assertEquals("/1F.0123456789ab/main/28.0123456789ab", sensorId.getFullPath());
|
||||
assertEquals("28.0123456789ab", sensorId.getId());
|
||||
assertEquals("28", sensorId.getFamilyId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hubAuxSensorIdConstructionTest() {
|
||||
SensorId sensorId = new SensorId("1F.0123456789ab/aux/28.0123456789ab");
|
||||
assertEquals("/1F.0123456789ab/aux/28.0123456789ab", sensorId.getFullPath());
|
||||
assertEquals("28.0123456789ab", sensorId.getId());
|
||||
assertEquals("28", sensorId.getFamilyId());
|
||||
|
||||
sensorId = new SensorId("/1F.0123456789ab/aux/28.0123456789ab");
|
||||
assertEquals("/1F.0123456789ab/aux/28.0123456789ab", sensorId.getFullPath());
|
||||
assertEquals("28.0123456789ab", sensorId.getId());
|
||||
assertEquals("28", sensorId.getFamilyId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsTest() {
|
||||
SensorId sensorId1 = new SensorId("1F.0123456789ab/aux/28.0123456789ab");
|
||||
SensorId sensorId2 = new SensorId("1F.0123456789ab/aux/28.0123456789ab");
|
||||
SensorId sensorId3 = new SensorId("1F.0123456789ab/aux/28.0123456789ac");
|
||||
|
||||
assertTrue(sensorId1.equals(sensorId2));
|
||||
assertFalse(sensorId1.equals(sensorId3));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.onewire;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.onewire.internal.Util;
|
||||
import org.openhab.core.library.dimension.Density;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link Util}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UtilTest {
|
||||
|
||||
@Test
|
||||
public void convertAbsoluteHumidityTest() {
|
||||
QuantityType<Temperature> temperature = new QuantityType<>("20 °C");
|
||||
QuantityType<Dimensionless> relativeHumidity = new QuantityType<>("75%");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
QuantityType<Density> absoluteHumidity = (QuantityType<Density>) Util.calculateAbsoluteHumidity(temperature,
|
||||
relativeHumidity);
|
||||
assertEquals(12.93, absoluteHumidity.doubleValue(), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dewPointTest() {
|
||||
QuantityType<Temperature> temperature = new QuantityType<>("20 °C");
|
||||
QuantityType<Dimensionless> relativeHumidity = new QuantityType<>("75%");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
QuantityType<Temperature> dewPoint = (QuantityType<Temperature>) Util.calculateDewpoint(temperature,
|
||||
relativeHumidity);
|
||||
assertEquals(15.43, dewPoint.doubleValue(), 0.01);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* 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.onewire.device;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.BAE0910;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverDeviceParameter;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link BAE0910}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BAE0910Test extends DeviceTestParent<BAE0910> {
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_BAE091X, BAE0910.class);
|
||||
}
|
||||
|
||||
// pin 1: counter
|
||||
|
||||
@Test
|
||||
public void counter() {
|
||||
addChannel(CHANNEL_COUNTER, "Number");
|
||||
final BAE0910 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(
|
||||
mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter("/counter"))))
|
||||
.thenReturn(new DecimalType(34567));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_COUNTER);
|
||||
testDevice.configureChannels(mockBridgeHandler);
|
||||
|
||||
// refresh
|
||||
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter("/counter")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_COUNTER), stateArgumentCaptor.capture());
|
||||
assertEquals(new DecimalType(34567), stateArgumentCaptor.getValue());
|
||||
|
||||
// write
|
||||
assertFalse(testDevice.writeChannel(mockBridgeHandler, CHANNEL_COUNTER, new DecimalType(12345)));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
// pin 2: digital2 or pwm1
|
||||
|
||||
@Test
|
||||
public void digitalOut2() {
|
||||
addChannel(CHANNEL_DIGITAL2, "Switch");
|
||||
digitalBaseChannel(CHANNEL_DIGITAL2, bitSet(3, 4), 0, "/out", bitSet(0), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pwm4() {
|
||||
pwmBaseChannel(CHANNEL_PWM_FREQ2, CHANNEL_PWM_DUTY4, "/period2", "/duty4", 2);
|
||||
}
|
||||
|
||||
// pin 6: pio or pwm 3
|
||||
|
||||
@Test
|
||||
public void digital6PioIn() {
|
||||
Map<String, Object> channelConfig = new HashMap<>();
|
||||
channelConfig.put("pulldevice", "pulldown");
|
||||
channelConfig.put("mode", "input");
|
||||
addChannel(CHANNEL_DIGITAL6, "Switch", new Configuration(channelConfig));
|
||||
digitalBaseChannel(CHANNEL_DIGITAL6, bitSet(1, 2, 3, 4), 1, "/pio", bitSet(0), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void digital6PioOut() {
|
||||
Map<String, Object> channelConfig = new HashMap<>();
|
||||
channelConfig.put("mode", "output");
|
||||
addChannel(CHANNEL_DIGITAL6, "Switch", new Configuration(channelConfig));
|
||||
digitalBaseChannel(CHANNEL_DIGITAL6, bitSet(0, 3, 4), 1, "/pio", bitSet(0), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pwm3() {
|
||||
pwmBaseChannel(CHANNEL_PWM_FREQ1, CHANNEL_PWM_DUTY3, "/period1", "/duty3", 1);
|
||||
}
|
||||
|
||||
// pin 7: analog, output, pwm2
|
||||
|
||||
@Test
|
||||
public void analog() {
|
||||
Map<String, Object> channelConfig = new HashMap<>();
|
||||
channelConfig.put("hires", "true");
|
||||
addChannel(CHANNEL_VOLTAGE, "Number:ElectricPotential", new Configuration(channelConfig));
|
||||
|
||||
final BAE0910 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter("/adc"))))
|
||||
.thenReturn(new DecimalType(5.2));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_VOLTAGE);
|
||||
testDevice.configureChannels(mockBridgeHandler);
|
||||
|
||||
// test configuration
|
||||
assertEquals(bitSet(3, 4), checkConfiguration(2));
|
||||
|
||||
// refresh
|
||||
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter("/adc")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_VOLTAGE), stateArgumentCaptor.capture());
|
||||
assertEquals(new QuantityType<>("5.2 V"), stateArgumentCaptor.getValue());
|
||||
|
||||
// write (should fail)
|
||||
assertFalse(testDevice.writeChannel(mockBridgeHandler, CHANNEL_VOLTAGE, new QuantityType<>("3 V")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void digitalOut7() {
|
||||
addChannel(CHANNEL_DIGITAL7, "Switch");
|
||||
digitalBaseChannel(CHANNEL_DIGITAL7, bitSet(4), 4, "/tpm2c", bitSet(4, 7), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pwm2() {
|
||||
pwmBaseChannel(CHANNEL_PWM_FREQ2, CHANNEL_PWM_DUTY2, "/period2", "/duty2", 2);
|
||||
}
|
||||
|
||||
// pin 8: digital in, digital out or pwm
|
||||
|
||||
@Test
|
||||
public void digitalIn8() {
|
||||
addChannel(CHANNEL_DIGITAL8, "Switch", new ChannelTypeUID(BINDING_ID, "bae-in"));
|
||||
digitalBaseChannel(CHANNEL_DIGITAL8, bitSet(4, 5), 3, "/tpm1c", bitSet(4, 5, 7), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void digitalOut8() {
|
||||
addChannel(CHANNEL_DIGITAL8, "Switch");
|
||||
digitalBaseChannel(CHANNEL_DIGITAL8, bitSet(4), 3, "/tpm1c", bitSet(4, 7), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pwm1() {
|
||||
pwmBaseChannel(CHANNEL_PWM_FREQ1, CHANNEL_PWM_DUTY1, "/period1", "/duty1", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* base test for digital channels
|
||||
*
|
||||
* @param channel channel name
|
||||
* @param configBitSet expected config register
|
||||
* @param configRegister config register number
|
||||
* @param channelParam channel parameter
|
||||
* @param returnBitSet which bitset should be returned on read
|
||||
* @param isOutput if this channel is an output
|
||||
*/
|
||||
private void digitalBaseChannel(String channel, BitSet configBitSet, int configRegister, String channelParam,
|
||||
BitSet returnBitSet, boolean isOutput) {
|
||||
final BAE0910 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), eq(new OwserverDeviceParameter(channelParam))))
|
||||
.thenReturn(returnBitSet);
|
||||
|
||||
testDevice.enableChannel(channel);
|
||||
testDevice.configureChannels(mockBridgeHandler);
|
||||
|
||||
// test configuration
|
||||
assertEquals(configBitSet, checkConfiguration(configRegister));
|
||||
|
||||
// refresh
|
||||
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
inOrder.verify(mockBridgeHandler).readBitSet(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter(channelParam)));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(channel), stateArgumentCaptor.capture());
|
||||
assertEquals(OnOffType.ON, stateArgumentCaptor.getValue());
|
||||
|
||||
// write
|
||||
if (isOutput) {
|
||||
ArgumentCaptor<BitSet> bitSetArgumentCaptor = ArgumentCaptor.forClass(BitSet.class);
|
||||
assertTrue(testDevice.writeChannel(mockBridgeHandler, channel, OnOffType.ON));
|
||||
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter(channelParam)), bitSetArgumentCaptor.capture());
|
||||
assertEquals(returnBitSet, bitSetArgumentCaptor.getValue());
|
||||
} else {
|
||||
assertFalse(testDevice.writeChannel(mockBridgeHandler, channel, OnOffType.ON));
|
||||
}
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* base test case for PWM channels
|
||||
*
|
||||
* @param freqChannel channel name for frequency
|
||||
* @param dutyChannel channel name for duty cycle
|
||||
* @param freqParam owfs parameter for frequency
|
||||
* @param dutyParam owfs parameter for duty cycle
|
||||
* @param registerIndex index for TPM configuration register
|
||||
*/
|
||||
private void pwmBaseChannel(String freqChannel, String dutyChannel, String freqParam, String dutyParam,
|
||||
int registerIndex) {
|
||||
Map<String, Object> channelConfig = new HashMap<>();
|
||||
channelConfig.put("prescaler", 5);
|
||||
addChannel(freqChannel, "Number:Frequency", new Configuration(channelConfig));
|
||||
addChannel(dutyChannel, "Number:Dimensionless");
|
||||
|
||||
final BAE0910 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(
|
||||
mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter(freqParam))))
|
||||
.thenReturn(new DecimalType(32768));
|
||||
Mockito.when(
|
||||
mockBridgeHandler.readDecimalType(eq(testSensorId), eq(new OwserverDeviceParameter(dutyParam))))
|
||||
.thenReturn(new DecimalType(16384));
|
||||
|
||||
testDevice.enableChannel(freqChannel);
|
||||
testDevice.enableChannel(dutyChannel);
|
||||
testDevice.configureChannels(mockBridgeHandler);
|
||||
|
||||
// test configuration
|
||||
assertEquals(bitSet(0, 2), checkConfiguration(registerIndex + 2));
|
||||
|
||||
// refresh
|
||||
ArgumentCaptor<State> stateArgumentCaptor = ArgumentCaptor.forClass(State.class);
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter(freqParam)));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(freqChannel), stateArgumentCaptor.capture());
|
||||
assertEquals(new QuantityType<>("15.2587890625 Hz"), stateArgumentCaptor.getValue());
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter(dutyParam)));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(dutyChannel), stateArgumentCaptor.capture());
|
||||
assertEquals(new QuantityType<>("50 %"), stateArgumentCaptor.getValue());
|
||||
|
||||
// write
|
||||
ArgumentCaptor<DecimalType> decimalTypeArgumentCaptor = ArgumentCaptor.forClass(DecimalType.class);
|
||||
assertTrue(testDevice.writeChannel(mockBridgeHandler, freqChannel, new QuantityType<>("50000 Hz")));
|
||||
inOrder.verify(mockBridgeHandler).writeDecimalType(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter(freqParam)), decimalTypeArgumentCaptor.capture());
|
||||
assertEquals(new DecimalType(10), decimalTypeArgumentCaptor.getValue());
|
||||
testDevice.writeChannel(mockBridgeHandler, dutyChannel, new QuantityType<>("25 %"));
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter(freqParam)));
|
||||
inOrder.verify(mockBridgeHandler).writeDecimalType(eq(testSensorId),
|
||||
eq(new OwserverDeviceParameter(dutyParam)), decimalTypeArgumentCaptor.capture());
|
||||
assertEquals(new DecimalType(8192), decimalTypeArgumentCaptor.getValue());
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if all registers are written and return one
|
||||
*
|
||||
* @param registerIndex number of register to return
|
||||
* @return this register's BitSet
|
||||
* @throws OwException
|
||||
*/
|
||||
private BitSet checkConfiguration(int registerIndex) throws OwException {
|
||||
ArgumentCaptor<BitSet> configArgumentCaptor = ArgumentCaptor.forClass(BitSet.class);
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/outc")),
|
||||
configArgumentCaptor.capture());
|
||||
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/pioc")),
|
||||
configArgumentCaptor.capture());
|
||||
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/adcc")),
|
||||
configArgumentCaptor.capture());
|
||||
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/tpm1c")),
|
||||
configArgumentCaptor.capture());
|
||||
inOrder.verify(mockBridgeHandler).writeBitSet(eq(testSensorId), eq(new OwserverDeviceParameter("/tpm2c")),
|
||||
configArgumentCaptor.capture());
|
||||
return configArgumentCaptor.getAllValues().get(registerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* BitSet with pre-set bits
|
||||
*
|
||||
* @param bits which bits to set
|
||||
* @return the BitSet
|
||||
*/
|
||||
private BitSet bitSet(int... bits) {
|
||||
BitSet bitSet = new BitSet(8);
|
||||
Arrays.stream(bits).forEach(b -> bitSet.set(b));
|
||||
return bitSet;
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.DS18x20;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS18x20}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS18x20Test extends DeviceTestParent<DS18x20> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_BASIC, DS18x20.class);
|
||||
|
||||
Map<String, Object> channelConfig = new HashMap<>();
|
||||
channelConfig.put(CONFIG_IGNORE_POR, true);
|
||||
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature", new Configuration(channelConfig));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void temperatureTest() {
|
||||
final DS18x20 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(15.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_TEMPERATURE);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(1)).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("15.0 °C")));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void temperatureIgnorePORTest() {
|
||||
final DS18x20 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(85.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_TEMPERATURE);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(1)).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler, times(0)).postUpdate(eq(CHANNEL_TEMPERATURE), any());
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.DS1923;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS1923}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
* @author Michał Wójcik - Adapted to DS1923
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS1923Test extends DeviceTestParent<DS1923> {
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_MS_TX, DS1923.class);
|
||||
|
||||
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature");
|
||||
addChannel(CHANNEL_HUMIDITY, "Number:Dimensionless");
|
||||
addChannel(CHANNEL_ABSOLUTE_HUMIDITY, "Number:Density");
|
||||
addChannel(CHANNEL_DEWPOINT, "Number:Temperature");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void temperatureChannel() {
|
||||
final DS1923 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_TEMPERATURE);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("10.0 °C")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void humidityChannel() {
|
||||
final DS1923 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_HUMIDITY);
|
||||
testDevice.enableChannel(CHANNEL_ABSOLUTE_HUMIDITY);
|
||||
testDevice.enableChannel(CHANNEL_DEWPOINT);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(2)).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_HUMIDITY), eq(new QuantityType<>("10.0 %")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_ABSOLUTE_HUMIDITY),
|
||||
eq(new QuantityType<>("0.9381970824113001000 g/m³")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_DEWPOINT),
|
||||
eq(new QuantityType<>("-20.31395053870025 °C")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.device;
|
||||
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_BASIC;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.openhab.binding.onewire.internal.device.DS2401;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS2401}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2401Test extends DeviceTestParent<DS2401> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_BASIC, DS2401.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void presenceTestOn() {
|
||||
presenceTest(OnOffType.ON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void presenceTestOff() {
|
||||
presenceTest(OnOffType.OFF);
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.DS2405;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS2405}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2405Test extends DeviceTestParent<DS2405> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_BASIC, DS2405.class);
|
||||
|
||||
addChannel(channelName(0), "Switch");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void digitalChannel() {
|
||||
digitalChannelTest(OnOffType.ON, 0);
|
||||
digitalChannelTest(OnOffType.OFF, 0);
|
||||
}
|
||||
|
||||
private void digitalChannelTest(OnOffType state, int channelNo) {
|
||||
final DS2405 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
BitSet returnValue = new BitSet(8);
|
||||
if (state == OnOffType.ON) {
|
||||
returnValue.flip(0, 7);
|
||||
}
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), any())).thenReturn(returnValue);
|
||||
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(2)).readBitSet(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(channelNo)), eq(state));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
private String channelName(int channelNo) {
|
||||
return CHANNEL_DIGITAL + channelNo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.DS2406_DS2413;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS2406_DS2413}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2406_DS2413Test extends DeviceTestParent<DS2406_DS2413> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_BASIC, DS2406_DS2413.class);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
addChannel(channelName(i), "Switch");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void digitalChannel() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
digitalChannelTest(OnOffType.ON, i);
|
||||
digitalChannelTest(OnOffType.OFF, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void digitalChannelTest(OnOffType state, int channelNo) {
|
||||
final DS2406_DS2413 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
BitSet returnValue = new BitSet(8);
|
||||
if (state == OnOffType.ON) {
|
||||
returnValue.flip(0, 7);
|
||||
}
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), any())).thenReturn(returnValue);
|
||||
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(2)).readBitSet(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(channelNo)), eq(state));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
private String channelName(int channelNo) {
|
||||
return CHANNEL_DIGITAL + channelNo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.DS2408;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS2408}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2408Test extends DeviceTestParent<DS2408> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_BASIC, DS2408.class);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
addChannel(channelName(i), "Switch");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void digitalChannel() {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
digitalChannelTest(OnOffType.ON, i);
|
||||
digitalChannelTest(OnOffType.OFF, i);
|
||||
}
|
||||
}
|
||||
|
||||
private void digitalChannelTest(OnOffType state, int channelNo) {
|
||||
final DS2408 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
BitSet returnValue = new BitSet(8);
|
||||
if (state == OnOffType.ON) {
|
||||
returnValue.flip(0, 8);
|
||||
}
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readBitSet(eq(testSensorId), any())).thenReturn(returnValue);
|
||||
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(2)).readBitSet(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(channelNo)), eq(state));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
private String channelName(int channelNo) {
|
||||
return CHANNEL_DIGITAL + channelNo;
|
||||
}
|
||||
}
|
||||
@@ -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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.DS2423;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS2423}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2423Test extends DeviceTestParent<DS2423> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_BASIC, DS2423.class);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
addChannel(channelName(i), "Number");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void counterChannelTest() {
|
||||
List<State> returnValue = new ArrayList<>();
|
||||
returnValue.add(new DecimalType(1408));
|
||||
returnValue.add(new DecimalType(3105));
|
||||
|
||||
final DS2423 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalTypeArray(eq(testSensorId), any())).thenReturn(returnValue);
|
||||
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(1)).readDecimalTypeArray(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(0)), eq(returnValue.get(0)));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(channelName(1)), eq(returnValue.get(1)));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
private String channelName(int channelNo) {
|
||||
return CHANNEL_COUNTER + channelNo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* 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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.DS2438;
|
||||
import org.openhab.binding.onewire.internal.device.DS2438.LightSensorType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link DS2438}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DS2438Test extends DeviceTestParent<DS2438> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_MS_TX, DS2438.class);
|
||||
|
||||
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature");
|
||||
addChannel(CHANNEL_HUMIDITY, "Number:Dimensionless");
|
||||
addChannel(CHANNEL_ABSOLUTE_HUMIDITY, "Number:Density");
|
||||
addChannel(CHANNEL_DEWPOINT, "Number:Temperature");
|
||||
addChannel(CHANNEL_VOLTAGE, "Number:Voltage");
|
||||
addChannel(CHANNEL_CURRENT, "Number:Current");
|
||||
addChannel(CHANNEL_LIGHT, "Number:Illuminance");
|
||||
addChannel(CHANNEL_SUPPLYVOLTAGE, "Number:Voltage");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void temperatureChannel() {
|
||||
final DS2438 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_TEMPERATURE);
|
||||
testDevice.configureChannels();
|
||||
inOrder.verify(mockThingHandler).getThing();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("10.0 °C")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void humidityChannel() {
|
||||
final DS2438 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_HUMIDITY);
|
||||
testDevice.enableChannel(CHANNEL_ABSOLUTE_HUMIDITY);
|
||||
testDevice.enableChannel(CHANNEL_DEWPOINT);
|
||||
testDevice.configureChannels();
|
||||
inOrder.verify(mockThingHandler).getThing();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(2)).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_HUMIDITY), eq(new QuantityType<>("10.0 %")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_ABSOLUTE_HUMIDITY),
|
||||
eq(new QuantityType<>("0.9381970824113001000 g/m³")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_DEWPOINT),
|
||||
eq(new QuantityType<>("-20.31395053870025 °C")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voltageChannel() {
|
||||
final DS2438 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_VOLTAGE);
|
||||
testDevice.configureChannels();
|
||||
inOrder.verify(mockThingHandler).getThing();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_VOLTAGE), eq(new QuantityType<>("2.0 V")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentChannel() {
|
||||
final DS2438 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_CURRENT);
|
||||
testDevice.configureChannels();
|
||||
inOrder.verify(mockThingHandler).getThing();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_CURRENT), eq(new QuantityType<>("2.0 mA")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lightChannel() {
|
||||
final DS2438 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(0.1));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_LIGHT);
|
||||
testDevice.configureChannels();
|
||||
inOrder.verify(mockThingHandler).getThing();
|
||||
testDevice.setLightSensorType(LightSensorType.ELABNET_V1);
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_LIGHT), eq(new QuantityType<>("97442 lx")));
|
||||
|
||||
testDevice.setLightSensorType(LightSensorType.ELABNET_V2);
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_LIGHT), eq(new QuantityType<>("134 lx")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supplyVoltageChannel() {
|
||||
final DS2438 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_SUPPLYVOLTAGE);
|
||||
testDevice.configureChannels();
|
||||
inOrder.verify(mockThingHandler).getThing();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_SUPPLYVOLTAGE), eq(new QuantityType<>("2.0 V")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noChannel() {
|
||||
final DS2438 testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
|
||||
|
||||
testDevice.configureChannels();
|
||||
inOrder.verify(mockThingHandler).getThing();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* 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.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.CHANNEL_PRESENT;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.Assert;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.device.AbstractOwDevice;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.*;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
|
||||
/**
|
||||
* Abtract test class for onewire devices.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class DeviceTestParent<T extends AbstractOwDevice> {
|
||||
private @Nullable Class<T> deviceTestClazz;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected OwBaseThingHandler mockThingHandler;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected OwserverBridgeHandler mockBridgeHandler;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected Thing mockThing;
|
||||
|
||||
protected SensorId testSensorId = new SensorId("00.000000000000");
|
||||
|
||||
public void setupMocks(ThingTypeUID thingTypeUID, Class<T> deviceTestClazz) {
|
||||
this.deviceTestClazz = deviceTestClazz;
|
||||
initMocks(this);
|
||||
|
||||
Mockito.when(mockThingHandler.getThing()).thenReturn(mockThing);
|
||||
Mockito.when(mockThing.getUID()).thenReturn(new ThingUID(thingTypeUID, "testsensor"));
|
||||
|
||||
addChannel(CHANNEL_PRESENT, "Switch");
|
||||
}
|
||||
|
||||
public void addChannel(String channelId, String itemType) {
|
||||
Channel channel = ChannelBuilder.create(new ChannelUID(mockThing.getUID(), channelId), itemType).build();
|
||||
Mockito.when(mockThing.getChannel(channelId)).thenReturn(channel);
|
||||
}
|
||||
|
||||
public void addChannel(String channelId, String itemType, Configuration channelConfiguration) {
|
||||
Channel channel = ChannelBuilder.create(new ChannelUID(mockThing.getUID(), channelId), itemType)
|
||||
.withConfiguration(channelConfiguration).build();
|
||||
Mockito.when(mockThing.getChannel(channelId)).thenReturn(channel);
|
||||
}
|
||||
|
||||
public void addChannel(String channelId, String itemType, ChannelTypeUID channelTypeUID) {
|
||||
Channel channel = ChannelBuilder.create(new ChannelUID(mockThing.getUID(), channelId), itemType)
|
||||
.withType(channelTypeUID).build();
|
||||
Mockito.when(mockThing.getChannel(channelId)).thenReturn(channel);
|
||||
}
|
||||
|
||||
public T instantiateDevice() {
|
||||
final Class<T> deviceTestClazz = this.deviceTestClazz;
|
||||
if (deviceTestClazz == null) {
|
||||
throw new IllegalStateException("deviceTestClazz is null");
|
||||
}
|
||||
try {
|
||||
Constructor<T> constructor = deviceTestClazz.getConstructor(SensorId.class, OwBaseThingHandler.class);
|
||||
T testDevice = constructor.newInstance(testSensorId, mockThingHandler);
|
||||
Assert.assertNotNull(testDevice);
|
||||
return testDevice;
|
||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public T instantiateDevice(OwSensorType sensorType) {
|
||||
final Class<T> deviceTestClazz = this.deviceTestClazz;
|
||||
if (deviceTestClazz == null) {
|
||||
throw new IllegalStateException("deviceTestClazz is null");
|
||||
}
|
||||
try {
|
||||
Constructor<T> constructor = deviceTestClazz.getConstructor(SensorId.class, OwSensorType.class,
|
||||
OwBaseThingHandler.class);
|
||||
T testDevice = constructor.newInstance(testSensorId, sensorType, mockThingHandler);
|
||||
Assert.assertNotNull(testDevice);
|
||||
return testDevice;
|
||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void presenceTest(OnOffType state) {
|
||||
final T testDevice = instantiateDevice();
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(state);
|
||||
testDevice.checkPresence(mockBridgeHandler);
|
||||
|
||||
inOrder.verify(mockThingHandler).updatePresenceStatus(eq(state));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.onewire.device;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.device.EDS006x;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link EDS006x}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EDS006xTest extends DeviceTestParent<EDS006x> {
|
||||
|
||||
@Before
|
||||
public void setupMocks() {
|
||||
setupMocks(THING_TYPE_EDS_ENV, EDS006x.class);
|
||||
|
||||
addChannel(CHANNEL_TEMPERATURE, "Number:Temperature");
|
||||
addChannel(CHANNEL_HUMIDITY, "Number:Dimensionless");
|
||||
addChannel(CHANNEL_ABSOLUTE_HUMIDITY, "Number:Density");
|
||||
addChannel(CHANNEL_DEWPOINT, "Number:Temperature");
|
||||
addChannel(CHANNEL_LIGHT, "Number:Illuminance");
|
||||
addChannel(CHANNEL_PRESSURE, "Number:Pressure");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void temperatureChannel() {
|
||||
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_TEMPERATURE);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_TEMPERATURE), eq(new QuantityType<>("10.0 °C")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void humidityChannel() {
|
||||
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(10.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_HUMIDITY);
|
||||
testDevice.enableChannel(CHANNEL_ABSOLUTE_HUMIDITY);
|
||||
testDevice.enableChannel(CHANNEL_DEWPOINT);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler, times(2)).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_HUMIDITY), eq(new QuantityType<>("10.0 %")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_ABSOLUTE_HUMIDITY),
|
||||
eq(new QuantityType<>("0.9381970824113001000 g/m³")));
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_DEWPOINT),
|
||||
eq(new QuantityType<>("-20.31395053870025 °C")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pressureChannel() {
|
||||
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_PRESSURE);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_PRESSURE), eq(new QuantityType<>("2.0 mbar")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lightChannel() {
|
||||
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(100));
|
||||
|
||||
testDevice.enableChannel(CHANNEL_LIGHT);
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verify(mockBridgeHandler).readDecimalType(eq(testSensorId), any());
|
||||
inOrder.verify(mockThingHandler).postUpdate(eq(CHANNEL_LIGHT), eq(new QuantityType<>("100 lx")));
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noChannel() {
|
||||
final EDS006x testDevice = instantiateDevice(OwSensorType.EDS0068);
|
||||
final InOrder inOrder = Mockito.inOrder(mockThingHandler, mockBridgeHandler);
|
||||
|
||||
try {
|
||||
Mockito.when(mockBridgeHandler.checkPresence(testSensorId)).thenReturn(OnOffType.ON);
|
||||
Mockito.when(mockBridgeHandler.readDecimalType(eq(testSensorId), any())).thenReturn(new DecimalType(2.0));
|
||||
|
||||
testDevice.configureChannels();
|
||||
testDevice.refresh(mockBridgeHandler, true);
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.CONFIG_ID;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_BASIC;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.handler.BasicThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.test.AbstractThingHandlerTest;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link BasicThingHandler}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BasicThingHandlerTest extends AbstractThingHandlerTest {
|
||||
private static final String TEST_ID = "00.000000000000";
|
||||
|
||||
@Before
|
||||
public void setup() throws OwException {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
initializeBridge();
|
||||
|
||||
final Bridge bridge = this.bridge;
|
||||
if (bridge == null) {
|
||||
Assert.fail("bridge is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingConfiguration.put(CONFIG_ID, TEST_ID);
|
||||
|
||||
thing = ThingBuilder.create(THING_TYPE_BASIC, "testthing").withLabel("Test thing")
|
||||
.withConfiguration(new Configuration(thingConfiguration)).withProperties(thingProperties)
|
||||
.withBridge(bridge.getUID()).build();
|
||||
|
||||
final Thing thing = this.thing;
|
||||
if (thing == null) {
|
||||
Assert.fail("thing is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingHandler = new BasicThingHandler(thing, stateProvider) {
|
||||
@Override
|
||||
protected @Nullable Bridge getBridge() {
|
||||
return bridge;
|
||||
}
|
||||
};
|
||||
|
||||
initializeHandlerMocks();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializationEndsWithUnknown() throws OwException {
|
||||
final ThingHandler thingHandler = this.thingHandler;
|
||||
if (thingHandler == null) {
|
||||
Assert.fail("thingHandler is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
return OwSensorType.DS2401;
|
||||
}).when(secondBridgeHandler).getType(any());
|
||||
|
||||
thingHandler.initialize();
|
||||
|
||||
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshAnalog() throws OwException {
|
||||
final OwBaseThingHandler thingHandler = this.thingHandler;
|
||||
final InOrder inOrder = this.inOrder;
|
||||
if (thingHandler == null || inOrder == null) {
|
||||
Assert.fail("prerequisite is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
return OwSensorType.DS18B20;
|
||||
}).when(secondBridgeHandler).getType(any());
|
||||
|
||||
thingHandler.initialize();
|
||||
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
|
||||
|
||||
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
|
||||
|
||||
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
|
||||
inOrder.verify(bridgeHandler, times(1)).readDecimalType(eq(new SensorId(TEST_ID)), any());
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefreshDigital() throws OwException {
|
||||
final OwBaseThingHandler thingHandler = this.thingHandler;
|
||||
final InOrder inOrder = this.inOrder;
|
||||
if (thingHandler == null || inOrder == null) {
|
||||
Assert.fail("prerequisite is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
return OwSensorType.DS2408;
|
||||
}).when(secondBridgeHandler).getType(any());
|
||||
|
||||
thingHandler.initialize();
|
||||
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
|
||||
|
||||
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
|
||||
|
||||
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
|
||||
inOrder.verify(bridgeHandler, times(2)).readBitSet(eq(new SensorId(TEST_ID)), any());
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.openhab.binding.onewire.internal.handler.EDSSensorThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.test.AbstractThingHandlerTest;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.thing.*;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link EDSSensorThingHandler}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class EDSSensorThingHandlerTest extends AbstractThingHandlerTest {
|
||||
private static final String TEST_ID = "00.000000000000";
|
||||
private static final ThingUID THING_UID = new ThingUID(THING_TYPE_EDS_ENV, "testthing");
|
||||
private static final ChannelUID CHANNEL_UID_TEMPERATURE = new ChannelUID(THING_UID, CHANNEL_TEMPERATURE);
|
||||
private static final ChannelUID CHANNEL_UID_HUMIDITY = new ChannelUID(THING_UID, CHANNEL_HUMIDITY);
|
||||
private static final ChannelUID CHANNEL_UID_ABSOLUTE_HUMIDITY = new ChannelUID(THING_UID,
|
||||
CHANNEL_ABSOLUTE_HUMIDITY);
|
||||
private static final ChannelUID CHANNEL_UID_DEWPOINT = new ChannelUID(THING_UID, CHANNEL_DEWPOINT);
|
||||
|
||||
@Before
|
||||
public void setup() throws OwException {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
initializeBridge();
|
||||
|
||||
final Bridge bridge = this.bridge;
|
||||
if (bridge == null) {
|
||||
Assert.fail("bridge is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingConfiguration.put(CONFIG_ID, TEST_ID);
|
||||
|
||||
channels.add(ChannelBuilder.create(CHANNEL_UID_TEMPERATURE, "Number:Temperature").build());
|
||||
channels.add(ChannelBuilder.create(CHANNEL_UID_HUMIDITY, "Number:Dimensionless").build());
|
||||
channels.add(ChannelBuilder.create(CHANNEL_UID_ABSOLUTE_HUMIDITY, "Number:Density").build());
|
||||
channels.add(ChannelBuilder.create(CHANNEL_UID_DEWPOINT, "Number:Temperature").build());
|
||||
|
||||
thing = ThingBuilder.create(THING_TYPE_EDS_ENV, "testthing").withLabel("Test thing").withChannels(channels)
|
||||
.withConfiguration(new Configuration(thingConfiguration)).withProperties(thingProperties)
|
||||
.withBridge(bridge.getUID()).build();
|
||||
|
||||
final Thing thing = this.thing;
|
||||
if (thing == null) {
|
||||
Assert.fail("thing is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingHandler = new EDSSensorThingHandler(thing, stateProvider) {
|
||||
@Override
|
||||
protected @Nullable Bridge getBridge() {
|
||||
return bridge;
|
||||
}
|
||||
};
|
||||
|
||||
initializeHandlerMocks();
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
return new OwPageBuffer("EDS0065 ".getBytes());
|
||||
}).when(secondBridgeHandler).readPages(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializationEndsWithUnknown() {
|
||||
final ThingHandler thingHandler = this.thingHandler;
|
||||
if (thingHandler == null) {
|
||||
Assert.fail("thingHandler is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingHandler.initialize();
|
||||
|
||||
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefresh() throws OwException {
|
||||
final OwBaseThingHandler thingHandler = this.thingHandler;
|
||||
final InOrder inOrder = this.inOrder;
|
||||
if (thingHandler == null || inOrder == null) {
|
||||
Assert.fail("prerequisite is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingHandler.initialize();
|
||||
|
||||
// needed to determine initialization is finished
|
||||
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
|
||||
|
||||
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
|
||||
|
||||
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
|
||||
inOrder.verify(bridgeHandler, times(2)).readDecimalType(eq(new SensorId(TEST_ID)), any());
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.CONFIG_ID;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_MS_TX;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.openhab.binding.onewire.internal.device.OwSensorType;
|
||||
import org.openhab.binding.onewire.internal.handler.BasicMultisensorThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.test.AbstractThingHandlerTest;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.builder.ThingBuilder;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link BasicMultisensorThingHandler}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MultisensorThingHandlerTest extends AbstractThingHandlerTest {
|
||||
private static final String TEST_ID = "00.000000000000";
|
||||
|
||||
@Before
|
||||
public void setup() throws OwException {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
initializeBridge();
|
||||
|
||||
final Bridge bridge = this.bridge;
|
||||
if (bridge == null) {
|
||||
Assert.fail("bridge is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingConfiguration.put(CONFIG_ID, TEST_ID);
|
||||
|
||||
thing = ThingBuilder.create(THING_TYPE_MS_TX, "testthing").withLabel("Test thing").withChannels(channels)
|
||||
.withConfiguration(new Configuration(thingConfiguration)).withProperties(thingProperties)
|
||||
.withBridge(bridge.getUID()).build();
|
||||
|
||||
final Thing thing = this.thing;
|
||||
if (thing == null) {
|
||||
Assert.fail("thing is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingHandler = new BasicMultisensorThingHandler(thing, stateProvider) {
|
||||
@Override
|
||||
protected @Nullable Bridge getBridge() {
|
||||
return bridge;
|
||||
}
|
||||
};
|
||||
|
||||
initializeHandlerMocks();
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
return OwSensorType.DS2438;
|
||||
}).when(secondBridgeHandler).getType(any());
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
OwPageBuffer pageBuffer = new OwPageBuffer(8);
|
||||
pageBuffer.setByte(3, 0, (byte) 0x19);
|
||||
return pageBuffer;
|
||||
}).when(secondBridgeHandler).readPages(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializationEndsWithUnknown() {
|
||||
final ThingHandler thingHandler = this.thingHandler;
|
||||
if (thingHandler == null) {
|
||||
Assert.fail("thingHandler is null");
|
||||
return;
|
||||
}
|
||||
thingHandler.initialize();
|
||||
|
||||
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefresh() throws OwException {
|
||||
final OwBaseThingHandler thingHandler = this.thingHandler;
|
||||
final InOrder inOrder = this.inOrder;
|
||||
if (thingHandler == null || inOrder == null) {
|
||||
Assert.fail("prerequisite is null");
|
||||
return;
|
||||
}
|
||||
thingHandler.initialize();
|
||||
|
||||
// needed to determine initialization is finished
|
||||
waitForAssert(() -> assertEquals(ThingStatus.UNKNOWN, thingHandler.getThing().getStatusInfo().getStatus()));
|
||||
|
||||
thingHandler.refresh(bridgeHandler, System.currentTimeMillis());
|
||||
|
||||
inOrder.verify(bridgeHandler, times(1)).checkPresence(new SensorId(TEST_ID));
|
||||
inOrder.verify(bridgeHandler, times(3)).readDecimalType(eq(new SensorId(TEST_ID)), any());
|
||||
|
||||
inOrder.verifyNoMoreInteractions();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* 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.onewire.internal;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverConnection;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverConnectionState;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.binding.builder.BridgeBuilder;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link OwserverBridgeHandler}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwserverBridgeHandlerTest extends JavaTest {
|
||||
|
||||
private static final String TEST_HOST = "foo.bar";
|
||||
private static final int TEST_PORT = 4711;
|
||||
Map<String, Object> bridgeProperties = new HashMap<>();
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
private OwserverConnection owserverConnection;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
private ThingHandlerCallback thingHandlerCallback;
|
||||
|
||||
private @Nullable OwserverBridgeHandler bridgeHandler;
|
||||
private @Nullable Bridge bridge;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
bridgeProperties.put(CONFIG_ADDRESS, TEST_HOST);
|
||||
bridgeProperties.put(CONFIG_PORT, TEST_PORT);
|
||||
|
||||
initMocks(this);
|
||||
|
||||
bridge = BridgeBuilder.create(THING_TYPE_OWSERVER, "owserver").withLabel("owserver")
|
||||
.withConfiguration(new Configuration(bridgeProperties)).build();
|
||||
|
||||
doAnswer(answer -> {
|
||||
((Thing) answer.getArgument(0)).setStatusInfo(answer.getArgument(1));
|
||||
return null;
|
||||
}).when(thingHandlerCallback).statusUpdated(any(), any());
|
||||
|
||||
final Bridge bridge = this.bridge;
|
||||
|
||||
if (bridge == null) {
|
||||
Assert.fail("bridge is null");
|
||||
return;
|
||||
}
|
||||
|
||||
final OwserverBridgeHandler bridgeHandler = new OwserverBridgeHandler(bridge, owserverConnection);
|
||||
bridgeHandler.getThing().setHandler(bridgeHandler);
|
||||
bridgeHandler.setCallback(thingHandlerCallback);
|
||||
this.bridgeHandler = bridgeHandler;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
|
||||
if (bridgeHandler != null) {
|
||||
bridgeHandler.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializationStartsConnectionWithOptions() {
|
||||
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
|
||||
if (bridgeHandler == null) {
|
||||
Assert.fail("bridgeHandler is null");
|
||||
return;
|
||||
}
|
||||
|
||||
bridgeHandler.initialize();
|
||||
|
||||
Mockito.verify(owserverConnection).setHost(TEST_HOST);
|
||||
Mockito.verify(owserverConnection).setPort(TEST_PORT);
|
||||
|
||||
Mockito.verify(owserverConnection, timeout(5000)).start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializationReportsRefreshableOnSuccessfullConnection() {
|
||||
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
|
||||
if (bridgeHandler == null) {
|
||||
Assert.fail("bridgeHandler is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
bridgeHandler.reportConnectionState(OwserverConnectionState.OPENED);
|
||||
return null;
|
||||
}).when(owserverConnection).start();
|
||||
|
||||
bridgeHandler.initialize();
|
||||
|
||||
ArgumentCaptor<ThingStatusInfo> statusCaptor = ArgumentCaptor.forClass(ThingStatusInfo.class);
|
||||
waitForAssert(() -> {
|
||||
verify(thingHandlerCallback, times(2)).statusUpdated(eq(bridge), statusCaptor.capture());
|
||||
});
|
||||
assertThat(statusCaptor.getAllValues().get(0).getStatus(), is(ThingStatus.UNKNOWN));
|
||||
assertThat(statusCaptor.getAllValues().get(1).getStatus(), is(ThingStatus.ONLINE));
|
||||
|
||||
waitForAssert(() -> assertTrue(bridgeHandler.isRefreshable()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitializationReportsNotRefreshableOnFailedConnection() {
|
||||
final OwserverBridgeHandler bridgeHandler = this.bridgeHandler;
|
||||
if (bridgeHandler == null) {
|
||||
Assert.fail("bridgeHandler is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
bridgeHandler.reportConnectionState(OwserverConnectionState.FAILED);
|
||||
return null;
|
||||
}).when(owserverConnection).start();
|
||||
|
||||
bridgeHandler.initialize();
|
||||
|
||||
ArgumentCaptor<ThingStatusInfo> statusCaptor = ArgumentCaptor.forClass(ThingStatusInfo.class);
|
||||
waitForAssert(() -> {
|
||||
verify(thingHandlerCallback, times(2)).statusUpdated(eq(bridge), statusCaptor.capture());
|
||||
});
|
||||
assertThat(statusCaptor.getAllValues().get(0).getStatus(), is(ThingStatus.UNKNOWN));
|
||||
assertThat(statusCaptor.getAllValues().get(1).getStatus(), is(ThingStatus.OFFLINE));
|
||||
|
||||
waitForAssert(() -> assertFalse(bridgeHandler.isRefreshable()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* 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.onewire.owserver;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.MockitoAnnotations.initMocks;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.OwPageBuffer;
|
||||
import org.openhab.binding.onewire.internal.SensorId;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverConnection;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverConnectionState;
|
||||
import org.openhab.binding.onewire.test.OwserverTestServer;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.test.TestPortUtil;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Tests cases for {@link OwserverConnection}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwserverConnectionTest extends JavaTest {
|
||||
private static final String TEST_HOST = "127.0.0.1";
|
||||
|
||||
private @Nullable OwserverTestServer testServer;
|
||||
private @Nullable OwserverConnection owserverConnection;
|
||||
|
||||
@Mock
|
||||
private @NonNullByDefault({}) OwserverBridgeHandler bridgeHandler;
|
||||
|
||||
private int testPort;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
initMocks(this);
|
||||
|
||||
CompletableFuture<Boolean> serverStarted = new CompletableFuture<>();
|
||||
testPort = TestPortUtil.findFreePort();
|
||||
try {
|
||||
final OwserverTestServer testServer = new OwserverTestServer(testPort);
|
||||
testServer.startServer(serverStarted);
|
||||
this.testServer = testServer;
|
||||
} catch (IOException e) {
|
||||
fail("could not start test server");
|
||||
}
|
||||
|
||||
final OwserverConnection owserverConnection = new OwserverConnection(bridgeHandler);
|
||||
owserverConnection.setHost(TEST_HOST);
|
||||
owserverConnection.setPort(testPort);
|
||||
this.owserverConnection = owserverConnection;
|
||||
|
||||
serverStarted.get(); // wait for the server thread to start
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
try {
|
||||
final OwserverTestServer testServer = this.testServer;
|
||||
if (testServer != null) {
|
||||
testServer.stopServer();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail("could not stop test server");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successfullConnectionReportedToBridgeHandler() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.start();
|
||||
|
||||
Mockito.verify(bridgeHandler).reportConnectionState(OwserverConnectionState.OPENED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failedConnectionReportedToBridgeHandler() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.setPort(1);
|
||||
|
||||
owserverConnection.start();
|
||||
|
||||
Mockito.verify(bridgeHandler, timeout(100)).reportConnectionState(OwserverConnectionState.FAILED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDirectory() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.start();
|
||||
try {
|
||||
List<SensorId> directory = owserverConnection.getDirectory("/");
|
||||
|
||||
assertEquals(3, directory.size());
|
||||
assertEquals(new SensorId("/00.0123456789ab"), directory.get(0));
|
||||
assertEquals(new SensorId("/00.0123456789ac"), directory.get(1));
|
||||
assertEquals(new SensorId("/00.0123456789ad"), directory.get(2));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckPresence() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.start();
|
||||
State presence = owserverConnection.checkPresence("present");
|
||||
assertEquals(OnOffType.ON, presence);
|
||||
|
||||
presence = owserverConnection.checkPresence("notpresent");
|
||||
assertEquals(OnOffType.OFF, presence);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDecimalType() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.start();
|
||||
try {
|
||||
DecimalType number = (DecimalType) owserverConnection.readDecimalType("testsensor/decimal");
|
||||
|
||||
assertEquals(17.4, number.doubleValue(), 0.01);
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadDecimalTypeArray() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.start();
|
||||
try {
|
||||
List<State> numbers = owserverConnection.readDecimalTypeArray("testsensor/decimalarray");
|
||||
|
||||
assertEquals(3834, ((DecimalType) numbers.get(0)).intValue());
|
||||
assertEquals(0, ((DecimalType) numbers.get(1)).intValue());
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPages() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.start();
|
||||
try {
|
||||
OwPageBuffer pageBuffer = owserverConnection.readPages("testsensor");
|
||||
|
||||
assertEquals(31, pageBuffer.getByte(5, 7));
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteDecimalType() {
|
||||
final OwserverConnection owserverConnection = this.owserverConnection;
|
||||
if (owserverConnection == null) {
|
||||
Assert.fail("connection is null");
|
||||
return;
|
||||
}
|
||||
owserverConnection.start();
|
||||
try {
|
||||
owserverConnection.writeDecimalType("testsensor/decimal", new DecimalType(2009));
|
||||
|
||||
Mockito.verify(bridgeHandler, never()).reportConnectionState(OwserverConnectionState.FAILED);
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 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.onewire.test;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.openhab.binding.onewire.internal.OwBindingConstants.THING_TYPE_OWSERVER;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.openhab.binding.onewire.internal.OwDynamicStateDescriptionProvider;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.handler.OwBaseThingHandler;
|
||||
import org.openhab.binding.onewire.internal.handler.OwserverBridgeHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.test.java.JavaTest;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.binding.builder.BridgeBuilder;
|
||||
|
||||
/**
|
||||
* Base class for thing handler tests.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractThingHandlerTest extends JavaTest {
|
||||
|
||||
protected Map<String, Object> bridgeProperties = new HashMap<>();
|
||||
protected Map<String, String> thingProperties = new HashMap<>();
|
||||
protected Map<String, Object> thingConfiguration = new HashMap<>();
|
||||
protected Map<String, Object> channelProperties = new HashMap<>();
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected ThingHandlerCallback thingHandlerCallback;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected OwDynamicStateDescriptionProvider stateProvider;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected ThingHandlerCallback bridgeHandlerCallback;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected OwserverBridgeHandler bridgeHandler;
|
||||
|
||||
@Mock
|
||||
@NonNullByDefault({})
|
||||
protected OwserverBridgeHandler secondBridgeHandler;
|
||||
|
||||
protected List<Channel> channels = new ArrayList<>();
|
||||
|
||||
protected @Nullable Bridge bridge;
|
||||
protected @Nullable Thing thing;
|
||||
protected @Nullable OwBaseThingHandler thingHandler;
|
||||
|
||||
protected @Nullable InOrder inOrder;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
final ThingHandler thingHandler = this.thingHandler;
|
||||
if (thingHandler != null) {
|
||||
thingHandler.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected void initializeHandlerMocks() {
|
||||
final ThingHandler thingHandler = this.thingHandler;
|
||||
if (thingHandler == null) {
|
||||
Assert.fail("thingHandler is null");
|
||||
return;
|
||||
}
|
||||
|
||||
thingHandler.getThing().setHandler(thingHandler);
|
||||
thingHandler.setCallback(thingHandlerCallback);
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
((Thing) answer.getArgument(0)).setStatusInfo(answer.getArgument(1));
|
||||
return null;
|
||||
}).when(thingHandlerCallback).statusUpdated(any(), any());
|
||||
|
||||
inOrder = Mockito.inOrder(bridgeHandler);
|
||||
}
|
||||
|
||||
public void initializeBridge() throws OwException {
|
||||
bridgeProperties = new HashMap<>();
|
||||
final Bridge bridge = BridgeBuilder.create(THING_TYPE_OWSERVER, "testbridge").withLabel("Test Bridge")
|
||||
.withConfiguration(new Configuration(bridgeProperties)).build();
|
||||
bridge.setHandler(bridgeHandler);
|
||||
this.bridge = bridge;
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
((Thing) answer.getArgument(0)).setStatusInfo(answer.getArgument(1));
|
||||
return null;
|
||||
}).when(bridgeHandlerCallback).statusUpdated(any(), any());
|
||||
|
||||
Mockito.doAnswer(answer -> OnOffType.ON).when(bridgeHandler).checkPresence(any());
|
||||
|
||||
Mockito.doAnswer(answer -> new DecimalType(10)).when(bridgeHandler).readDecimalType(any(), any());
|
||||
|
||||
Mockito.doAnswer(answer -> new BitSet(8)).when(bridgeHandler).readBitSet(any(), any());
|
||||
|
||||
Mockito.doAnswer(answer -> {
|
||||
final OwBaseThingHandler thingHandler = this.thingHandler;
|
||||
if (thingHandler == null) {
|
||||
Assert.fail("thingHandler is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
thingHandler.updateSensorProperties(secondBridgeHandler);
|
||||
thingHandler.initialize();
|
||||
return null;
|
||||
}).when(bridgeHandler).scheduleForPropertiesUpdate(any());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* 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.onewire.test;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.Assert;
|
||||
import org.openhab.binding.onewire.internal.OwException;
|
||||
import org.openhab.binding.onewire.internal.OwPageBuffer;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverPacket;
|
||||
import org.openhab.binding.onewire.internal.owserver.OwserverPacketType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link OwserverTestServer} defines a server for testing the OwserverConnection class
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OwserverTestServer {
|
||||
private final Logger logger = LoggerFactory.getLogger(OwserverTestServer.class);
|
||||
|
||||
private final ServerSocket serverSocket;
|
||||
private boolean isRunning = false;
|
||||
|
||||
public OwserverTestServer(int port) throws IOException {
|
||||
serverSocket = new ServerSocket(port);
|
||||
}
|
||||
|
||||
public void startServer(CompletableFuture<Boolean> serverStarted) throws IOException {
|
||||
isRunning = true;
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
OwserverPacket receivedPacket;
|
||||
List<OwserverPacket> answerPackets;
|
||||
serverStarted.complete(true);
|
||||
try {
|
||||
while (isRunning) {
|
||||
final Socket connectionSocket = serverSocket.accept();
|
||||
final DataInputStream inputStream = new DataInputStream(connectionSocket.getInputStream());
|
||||
final DataOutputStream outputStream = new DataOutputStream(connectionSocket.getOutputStream());
|
||||
|
||||
receivedPacket = new OwserverPacket(inputStream, OwserverPacketType.REQUEST);
|
||||
logger.debug("received {}", receivedPacket);
|
||||
|
||||
answerPackets = processPacket(receivedPacket);
|
||||
|
||||
answerPackets.forEach(answerPacket -> {
|
||||
logger.debug("answering {}", answerPacket);
|
||||
try {
|
||||
outputStream.write(answerPacket.toBytes());
|
||||
} catch (IOException e) {
|
||||
logger.error("I/O Error: {}", e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("I/O Error: {}", e.getMessage());
|
||||
} catch (OwException e) {
|
||||
Assert.fail("caught unexpected OwException");
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
public void stopServer() throws IOException {
|
||||
isRunning = false;
|
||||
serverSocket.close();
|
||||
}
|
||||
|
||||
private List<OwserverPacket> processPacket(OwserverPacket inputPacket) {
|
||||
List<OwserverPacket> returnPackets = new ArrayList<>();
|
||||
OwserverPacket returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
|
||||
switch (inputPacket.getMessageType()) {
|
||||
case NOP:
|
||||
returnPacket.setPayload("");
|
||||
returnPackets.add(returnPacket);
|
||||
break;
|
||||
case DIRALL:
|
||||
returnPacket.setPayload("/00.0123456789ab,/00.0123456789ac,/00.0123456789ad,/statistics");
|
||||
returnPackets.add(returnPacket);
|
||||
returnPacket = new OwserverPacket(OwserverPacketType.RETURN);
|
||||
break;
|
||||
case PRESENT:
|
||||
switch (inputPacket.getPayloadString()) {
|
||||
case "present":
|
||||
break;
|
||||
default:
|
||||
returnPacket.setReturnCode(-1);
|
||||
}
|
||||
returnPacket.setPayload(inputPacket.getPayloadString());
|
||||
returnPackets.add(returnPacket);
|
||||
break;
|
||||
case READ:
|
||||
switch (inputPacket.getPayloadString()) {
|
||||
case "testsensor/pages/page.ALL":
|
||||
OwPageBuffer pageBuffer = new OwPageBuffer(8);
|
||||
pageBuffer.setByte(5, 7, (byte) 31);
|
||||
returnPacket.setPayload(pageBuffer);
|
||||
returnPackets.add(returnPacket);
|
||||
break;
|
||||
case "testsensor/decimal":
|
||||
returnPacket.setPayload(" 17.4");
|
||||
returnPackets.add(returnPacket);
|
||||
break;
|
||||
case "testsensor/decimalarray":
|
||||
returnPacket.setPayload(" 3834, 0");
|
||||
returnPackets.add(returnPacket);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
break;
|
||||
case WRITE:
|
||||
returnPackets.add(returnPacket);
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
return returnPackets;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user