mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[fineoffsetweatherstation] Initial contribution (#12464)
* [fineoffsetweatherstation] initial commit * [fineoffsetweatherstation] add missing measure type for air quality * [fineoffsetweatherstation] add names to sensors * [fineoffsetweatherstation] add missing channel types for lightning and water leak * [fineoffsetweatherstation] adjust label names and replaced images + pdf so there are no copyright issues * [fineoffsetweatherstation] remove wrong semantic tags * [fineoffsetweatherstation] add missing measurands for WH45 (CO2) and WH35 (Leaf wetness) * [fineoffsetweatherstation] fix typos * [fineoffsetweatherstation] improve error handling for unstable connections * [fineoffsetweatherstation] set online status after successful discovery * [fineoffsetweatherstation] adjustments after review * [fineoffsetweatherstation] adjustments after review * Fix typo * use `system.wind-speed` where applicable * fix naming of channel type constants Signed-off-by: Andreas Berger <andreas@berger-freelancer.com>
This commit is contained in:
parent
4372c007cd
commit
66bb27275d
@ -95,6 +95,7 @@
|
||||
/bundles/org.openhab.binding.exec/ @kgoderis
|
||||
/bundles/org.openhab.binding.feed/ @svilenvul
|
||||
/bundles/org.openhab.binding.feican/ @Hilbrand
|
||||
/bundles/org.openhab.binding.fineoffsetweatherstation/ @Andy2003
|
||||
/bundles/org.openhab.binding.flicbutton/ @pfink
|
||||
/bundles/org.openhab.binding.fmiweather/ @ssalonen
|
||||
/bundles/org.openhab.binding.folderwatcher/ @goopilot
|
||||
|
@ -466,6 +466,11 @@
|
||||
<artifactId>org.openhab.binding.feican</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.fineoffsetweatherstation</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.flicbutton</artifactId>
|
||||
|
13
bundles/org.openhab.binding.fineoffsetweatherstation/NOTICE
Normal file
13
bundles/org.openhab.binding.fineoffsetweatherstation/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
|
307
bundles/org.openhab.binding.fineoffsetweatherstation/README.md
Normal file
307
bundles/org.openhab.binding.fineoffsetweatherstation/README.md
Normal file
@ -0,0 +1,307 @@
|
||||
# Fine Offset Weather Station Binding
|
||||
|
||||
This binding is for weather stations manufactured by [Fine Offset](http://www.foshk.com/).
|
||||
These weather stations are white labeled products which are re-branded by many distribution companies around the world.
|
||||
Some of these brands are e.g.:
|
||||
|
||||
* Aercus
|
||||
* Ambient Weather
|
||||
* Ecowitt
|
||||
* Frogitt
|
||||
* Misol
|
||||
* Pantech
|
||||
* Sainlogic
|
||||
* Steinberg Systems
|
||||
* Waldbeck Halley
|
||||
|
||||
Here is a product picture of how this Weather Station looks like:
|
||||
|
||||
![WH2650](doc/WH2650.png)
|
||||
|
||||
This binding works offline by [implementing the wire protocol](https://osswww.ecowitt.net/uploads/20210716/WN1900%20GW1000,1100%20WH2680,2650%20telenet%20v1.6.0%20.pdf) of the WiFi gateway device.
|
||||
|
||||
## Supported Things
|
||||
|
||||
- `weatherstation`: A Fine Offset gateway device with the ThingTypeUID `fineoffsetweatherstation:weatherstation` wich supports the [wire protocol](https://osswww.ecowitt.net/uploads/20210716/WN1900%20GW1000,1100%20WH2680,2650%20telenet%20v1.6.0%20.pdf) e.g.:
|
||||
- HP2550
|
||||
- HP3500
|
||||
- GW1000
|
||||
- GW1001
|
||||
- GW1002
|
||||
- GW1003
|
||||
- GW1100
|
||||
- WN1900
|
||||
- WN1910
|
||||
- WH2350
|
||||
- WH2600
|
||||
- WH2610
|
||||
- WH2620
|
||||
- WH2650 (tested)
|
||||
- WH2680
|
||||
- WH2900
|
||||
- WH2950
|
||||
- `sensor`: A Fine Offset sensor which is connected to the bridge with the ThingTypeUID `fineoffsetweatherstation:sensor`.
|
||||
Since the gateway collects all the sensor data and harmonizes them, the sensor thing itself will only hold information about the signal and battery status.
|
||||
This is a list of sensors supported by the protocol:
|
||||
- WH24 - 7-in-1 weather station, Sensor for wind speed & direction, solar radiation & light, temperature, humidity, rainfall
|
||||
- WH25 - 3-in-1 sensor temperature, humidity, pressure
|
||||
- WH26 - 2-in-1 sensor temperature, humidity
|
||||
- WH31 - 2-in-1 sensor temperature, humidity
|
||||
- WH34 - External temperature sensor
|
||||
- WH35 - Leaf wetness sensor
|
||||
- WH40 - Rainfall sensor
|
||||
- WH41 - Outdoor air quality sensor
|
||||
- WH45 - Air quality sensor
|
||||
- WH51 - Soil moisture sensor
|
||||
- WH55 - Water leak detection sensor
|
||||
- WH57 - Lightning detection sensor
|
||||
- WH65 - 7-in-1 weather station for wind speed & direction, solar radiation & light, temperature, humidity and rainfall
|
||||
- WH68 - 4-in-1 weather station - Solar-powered sensor for wind speed & direction, solar radiation & light
|
||||
- WH80 - 6-in-1 weather station - Ultrasonic sensor for wind speed & direction, solar radiation & light, temperature & humidity
|
||||
- WH90 - A new weather station
|
||||
|
||||
## Discovery
|
||||
|
||||
This binding support discovery of Fine Offset gateway devices by sending a broadcast message.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
### `gateway` Thing Configuration
|
||||
|
||||
| Name | Type | Description | Default | Required | Advanced |
|
||||
|-------------------|---------|-------------------------------------------------------------------------------------|---------|----------|----------|
|
||||
| ip | text | The Hostname or IP address of the device | N/A | yes | no |
|
||||
| port | integer | The network port of the gateway | 45000 | yes | no |
|
||||
| pollingInterval | integer | Polling period for refreshing the data in seconds | 16 | yes | yes |
|
||||
| discoverInterval | integer | Interval in seconds to fetch registered sensors, battery status and signal strength | 900 | yes | yes |
|
||||
|
||||
### `sensor` Thing Configuration
|
||||
|
||||
| Name | Type | Description | Default | Required | Advanced |
|
||||
|------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------|---------|----------|----------|
|
||||
| sensor | text | The name of sensor attached to the gateway (multiple sensors of the same type may have different names according to the bound channel) | N/A | yes | no |
|
||||
|
||||
Valid sensors:
|
||||
|
||||
- WH24
|
||||
- WH65
|
||||
- WH68
|
||||
- WH80
|
||||
- WH40
|
||||
- WH25
|
||||
- WH26
|
||||
- WH31_CH1
|
||||
- WH31_CH2
|
||||
- WH31_CH3
|
||||
- WH31_CH4
|
||||
- WH31_CH5
|
||||
- WH31_CH6
|
||||
- WH31_CH7
|
||||
- WH31_CH8
|
||||
- WH51_CH1
|
||||
- WH51_CH2
|
||||
- WH51_CH3
|
||||
- WH51_CH4
|
||||
- WH51_CH5
|
||||
- WH51_CH6
|
||||
- WH51_CH7
|
||||
- WH51_CH8
|
||||
- WH41_CH1
|
||||
- WH41_CH2
|
||||
- WH41_CH3
|
||||
- WH41_CH4
|
||||
- WH57
|
||||
- WH55_CH1
|
||||
- WH55_CH2
|
||||
- WH55_CH3
|
||||
- WH55_CH4
|
||||
- WH34_CH1
|
||||
- WH34_CH2
|
||||
- WH34_CH3
|
||||
- WH34_CH4
|
||||
- WH34_CH5
|
||||
- WH34_CH6
|
||||
- WH34_CH7
|
||||
- WH34_CH8
|
||||
- WH45
|
||||
- WH35_CH1
|
||||
- WH35_CH2
|
||||
- WH35_CH3
|
||||
- WH35_CH4
|
||||
- WH35_CH5
|
||||
- WH35_CH6
|
||||
- WH35_CH7
|
||||
- WH35_CH8
|
||||
- WH90
|
||||
|
||||
## Channels
|
||||
|
||||
### `gateway` Channels
|
||||
|
||||
| Channel | Type | Read/Write | Description |
|
||||
|---------------------------------------|-------------------------------|------------|------------------------------------------------|
|
||||
| temperature-indoor | Number:Temperature | R | Indoor Temperature |
|
||||
| temperature-outdoor | Number:Temperature | R | Outdoor Temperature |
|
||||
| temperature-dew-point | Number:Temperature | R | Dew Point |
|
||||
| temperature-wind-chill | Number:Temperature | R | Perceived Temperature |
|
||||
| temperature-heat-index | Number:Temperature | R | Heat Index |
|
||||
| humidity-indoor | Number:Dimensionless | R | Humidity Inside |
|
||||
| humidity-outdoor | Number:Dimensionless | R | Humidity Outside |
|
||||
| pressure-absolute | Number:Pressure | R | Absolute Pressure |
|
||||
| pressure-relative | Number:Pressure | R | Relative Pressure |
|
||||
| direction-wind | Number:Angle | R | Wind Direction |
|
||||
| speed-wind | Number:Speed | R | Wind Speed |
|
||||
| speed-gust | Number:Speed | R | Gust Speed |
|
||||
| rain-event | Number:Length | R | Amount of Rainfall At the last Rain |
|
||||
| rain-rate | Number:VolumetricFlowRate | R | Rainfall Rate |
|
||||
| rain-hour | Number:Length | R | Rainfall Current Hour |
|
||||
| rain-day | Number:Length | R | Rainfall Today |
|
||||
| rain-week | Number:Length | R | Rainfall this Week |
|
||||
| rain-month | Number:Length | R | Rainfall this Month |
|
||||
| rain-year | Number:Length | R | Rainfall this Year |
|
||||
| rain-total | Number:Length | R | Rainfall Total |
|
||||
| illumination | Number:Illuminance | R | Light Intensity |
|
||||
| irradiation-uv | Number:Intensity | R | UV Irradiation |
|
||||
| uv-index | Number:Dimensionless | R | UV Index |
|
||||
| wind-max-day | Number:Speed | R | Maximum Wind Speed Today |
|
||||
| temperature-channel-1 | Number:Temperature | R | Temperature Channel 1 |
|
||||
| temperature-channel-2 | Number:Temperature | R | Temperature Channel 2 |
|
||||
| temperature-channel-3 | Number:Temperature | R | Temperature Channel 3 |
|
||||
| temperature-channel-4 | Number:Temperature | R | Temperature Channel 4 |
|
||||
| temperature-channel-5 | Number:Temperature | R | Temperature Channel 5 |
|
||||
| temperature-channel-6 | Number:Temperature | R | Temperature Channel 6 |
|
||||
| temperature-channel-7 | Number:Temperature | R | Temperature Channel 7 |
|
||||
| temperature-channel-8 | Number:Temperature | R | Temperature Channel 8 |
|
||||
| humidity-channel-1 | Number:Dimensionless | R | Humidity Channel 1 |
|
||||
| humidity-channel-2 | Number:Dimensionless | R | Humidity Channel 2 |
|
||||
| humidity-channel-3 | Number:Dimensionless | R | Humidity Channel 3 |
|
||||
| humidity-channel-4 | Number:Dimensionless | R | Humidity Channel 4 |
|
||||
| humidity-channel-5 | Number:Dimensionless | R | Humidity Channel 5 |
|
||||
| humidity-channel-6 | Number:Dimensionless | R | Humidity Channel 6 |
|
||||
| humidity-channel-7 | Number:Dimensionless | R | Humidity Channel 7 |
|
||||
| humidity-channel-8 | Number:Dimensionless | R | Humidity Channel 8 |
|
||||
| temperature-soil-channel-1 | Number:Temperature | R | Soil Temperature Channel 1 |
|
||||
| temperature-soil-channel-2 | Number:Temperature | R | Soil Temperature Channel 2 |
|
||||
| temperature-soil-channel-3 | Number:Temperature | R | Soil Temperature Channel 3 |
|
||||
| temperature-soil-channel-4 | Number:Temperature | R | Soil Temperature Channel 4 |
|
||||
| temperature-soil-channel-5 | Number:Temperature | R | Soil Temperature Channel 5 |
|
||||
| temperature-soil-channel-6 | Number:Temperature | R | Soil Temperature Channel 6 |
|
||||
| temperature-soil-channel-7 | Number:Temperature | R | Soil Temperature Channel 7 |
|
||||
| temperature-soil-channel-8 | Number:Temperature | R | Soil Temperature Channel 8 |
|
||||
| temperature-soil-channel-9 | Number:Temperature | R | Soil Temperature Channel 9 |
|
||||
| temperature-soil-channel-10 | Number:Temperature | R | Soil Temperature Channel 10 |
|
||||
| temperature-soil-channel-11 | Number:Temperature | R | Soil Temperature Channel 11 |
|
||||
| temperature-soil-channel-12 | Number:Temperature | R | Soil Temperature Channel 12 |
|
||||
| temperature-soil-channel-13 | Number:Temperature | R | Soil Temperature Channel 13 |
|
||||
| temperature-soil-channel-14 | Number:Temperature | R | Soil Temperature Channel 14 |
|
||||
| temperature-soil-channel-15 | Number:Temperature | R | Soil Temperature Channel 15 |
|
||||
| temperature-soil-channel-16 | Number:Temperature | R | Soil Temperature Channel 16 |
|
||||
| moisture-soil-channel-1 | Number:Dimensionless | R | Soil Moisture Channel 1 |
|
||||
| moisture-soil-channel-2 | Number:Dimensionless | R | Soil Moisture Channel 2 |
|
||||
| moisture-soil-channel-3 | Number:Dimensionless | R | Soil Moisture Channel 3 |
|
||||
| moisture-soil-channel-4 | Number:Dimensionless | R | soil Moisture Channel 4 |
|
||||
| moisture-soil-channel-5 | Number:Dimensionless | R | Soil Moisture Channel 5 |
|
||||
| moisture-soil-channel-6 | Number:Dimensionless | R | Soil Moisture Channel 6 |
|
||||
| moisture-soil-channel-7 | Number:Dimensionless | R | Soil Moisture Channel 7 |
|
||||
| moisture-soil-channel-8 | Number:Dimensionless | R | Soil Moisture Channel 8 |
|
||||
| moisture-soil-channel-9 | Number:Dimensionless | R | Soil Moisture Channel 9 |
|
||||
| moisture-soil-channel-10 | Number:Dimensionless | R | Soil Moisture Channel 10 |
|
||||
| moisture-soil-channel-11 | Number:Dimensionless | R | Soil Moisture Channel 11 |
|
||||
| moisture-soil-channel-12 | Number:Dimensionless | R | Soil Moisture Channel 12 |
|
||||
| moisture-soil-channel-13 | Number:Dimensionless | R | soil Moisture Channel 13 |
|
||||
| moisture-soil-channel-14 | Number:Dimensionless | R | Soil Moisture Channel 14 |
|
||||
| moisture-soil-channel-15 | Number:Dimensionless | R | Soil Moisture Channel 15 |
|
||||
| moisture-soil-channel-16 | Number:Dimensionless | R | Soil Moisture Channel 16 |
|
||||
| air-quality-24-hour-average-channel-1 | Number:Density | R | PM2.5 Air Quality 24 Hour Average Channel 1 |
|
||||
| air-quality-24-hour-average-channel-2 | Number:Density | R | PM2.5 Air Quality 24 Hour Average Channel 2 |
|
||||
| air-quality-24-hour-average-channel-3 | Number:Density | R | PM2.5 Air Quality 24 Hour Average Channel 3 |
|
||||
| air-quality-24-hour-average-channel-4 | Number:Density | R | PM2.5 Air Quality 24 Hour Average Channel 4 |
|
||||
| air-quality-channel-1 | Number:Density | R | PM2.5 Air Quality Channel 1 |
|
||||
| air-quality-channel-2 | Number:Density | R | PM2.5 Air Quality Channel 2 |
|
||||
| air-quality-channel-3 | Number:Density | R | PM2.5 Air Quality Channel 3 |
|
||||
| air-quality-channel-4 | Number:Density | R | PM2.5 Air Quality Channel 4 |
|
||||
| water-leak-channel-1 | Switch | R | Water Leak Detection Channel 1 |
|
||||
| water-leak-channel-2 | Switch | R | Water Leak Detection Channel 2 |
|
||||
| water-leak-channel-3 | Switch | R | Water Leak Detection Channel 3 |
|
||||
| water-leak-channel-4 | Switch | R | Water Leak Detection Channel 4 |
|
||||
| lightning-distance | Number:Length | R | Lightning Distance |
|
||||
| lightning-time | DateTime | R | Time of last Lightning Strike |
|
||||
| lightning-counter | Number | R | Lightning Strikes Today |
|
||||
| temperature-external-channel-1 | Number:Temperature | R | External Temperature Sensor Channel 1 |
|
||||
| temperature-external-channel-2 | Number:Temperature | R | External Temperature Sensor Channel 2 |
|
||||
| temperature-external-channel-3 | Number:Temperature | R | External Temperature Sensor Channel 3 |
|
||||
| temperature-external-channel-4 | Number:Temperature | R | External Temperature Sensor Channel 4 |
|
||||
| temperature-external-channel-5 | Number:Temperature | R | External Temperature Sensor Channel 5 |
|
||||
| temperature-external-channel-6 | Number:Temperature | R | External Temperature Sensor Channel 6 |
|
||||
| temperature-external-channel-7 | Number:Temperature | R | External Temperature Sensor Channel 7 |
|
||||
| temperature-external-channel-8 | Number:Temperature | R | External Temperature Sensor Channel 8 |
|
||||
| sensor-co2-temperature | Number:Temperature | R | Temperature (CO2-Sensor) |
|
||||
| sensor-co2-humidity | Number:Dimensionless | R | Humidity (CO2-Sensor) |
|
||||
| sensor-co2-pm10 | Number:Density | R | PM10 Air Quality (CO2-Sensor) |
|
||||
| sensor-co2-pm10-24-hour-average | Number:Density | R | PM10 Air Quality 24 Hour Average (CO2-Sensor) |
|
||||
| sensor-co2-pm25 | Number:Density | R | PM2.5 Air Quality (CO2-Sensor) |
|
||||
| sensor-co2-pm25-24-hour-average | Number:Density | R | PM2.5 Air Quality 24 Hour Average (CO2-Sensor) |
|
||||
| sensor-co2-co2 | Number:Dimensionless | R | CO2 |
|
||||
| sensor-co2-co2-24-hour-average | Number:Dimensionless | R | CO2 24 Hour Average |
|
||||
| leaf-wetness-channel-1 | Number:Dimensionless | R | Leaf Moisture Channel 1 |
|
||||
| leaf-wetness-channel-2 | Number:Dimensionless | R | Leaf Moisture Channel 2 |
|
||||
| leaf-wetness-channel-3 | Number:Dimensionless | R | Leaf Moisture Channel 3 |
|
||||
| leaf-wetness-channel-4 | Number:Dimensionless | R | Leaf Moisture Channel 4 |
|
||||
| leaf-wetness-channel-5 | Number:Dimensionless | R | Leaf Moisture Channel 5 |
|
||||
| leaf-wetness-channel-6 | Number:Dimensionless | R | Leaf Moisture Channel 6 |
|
||||
| leaf-wetness-channel-7 | Number:Dimensionless | R | Leaf Moisture Channel 7 |
|
||||
| leaf-wetness-channel-8 | Number:Dimensionless | R | Leaf Moisture Channel 8 |
|
||||
|
||||
### `sensor` Channels
|
||||
|
||||
| Channel | Type | Read/Write | Description |
|
||||
|--------------|--------|------------|-----------------------------|
|
||||
| signal | Number | R | The sensors signal strenght |
|
||||
| batteryLevel | Number | R | The sensors battery level |
|
||||
| lowBattery | Switch | R | The sensors battery status |
|
||||
|
||||
## Full Example
|
||||
|
||||
This is an example configuration for the WH2650 gateway
|
||||
|
||||
_weatherstation.things_:
|
||||
|
||||
```xtend
|
||||
Bridge fineoffsetweatherstation:gateway:3906700515 "Weather station" [ip="192.168.1.42", port="45000", discoverInterval="900", pollingInterval="16"] {
|
||||
Thing sensor WH25 "WH25" [sensor="WH25"]
|
||||
Thing sensor WH65 "WH65" [sensor="WH65"]
|
||||
}
|
||||
```
|
||||
|
||||
_weatherstation.items_:
|
||||
|
||||
```xtend
|
||||
Group WH25 "WH25" <Sensor> ["Sensor"]
|
||||
Number SignalWH25 "Signal WH25" <QualityOfService> (WH25) ["Measurement", "Level"] { channel="fineoffsetweatherstation:sensor:3906700515:WH25:signal" }
|
||||
Switch BatteryStatusWH25 "Low Battery WH25" <LowBattery> (WH25) ["Energy", "LowBattery"] { channel="fineoffsetweatherstation:sensor:3906700515:WH25:lowBattery" }
|
||||
|
||||
Group WH65 "WH65" <Sensor> ["Sensor"]
|
||||
Number SignalWH65 "Signal WH65" <QualityOfService> (WH65) ["Measurement", "Level"] { channel="fineoffsetweatherstation:sensor:3906700515:WH65:signal" }
|
||||
Switch BatteryStatusWH65 "Low Battery WH65" <LowBattery> (WH65) ["Energy", "LowBattery"] { channel="fineoffsetweatherstation:sensor:3906700515:WH65:lowBattery" }
|
||||
|
||||
Group gOutdoor "Outdoor" ["Location"]
|
||||
Number:Temperature weather_temperature_outdoor "Outdoor Temperature" <Temperature> (gOutdoor) ["Measurement", "Temperature"] { channel="fineoffsetweatherstation:gateway:3906700515:temperature-outdoor" }
|
||||
Number:Temperature weather_temperature_indoor "Inside temperature" <Temperature> ["Measurement", "Temperature"] { channel="fineoffsetweatherstation:gateway:3906700515:temperature-indoor" }
|
||||
Number:Dimensionless weather_humidity_indoor "Humidity inside" <Humidity> ["Measurement", "Humidity"] { channel="fineoffsetweatherstation:gateway:3906700515:humidity-indoor" }
|
||||
Number:Pressure weather_pressure_absolute "Absolute pressure" <Pressure> (gOutdoor) ["Measurement", "Pressure"] { channel="fineoffsetweatherstation:gateway:3906700515:pressure-absolute" }
|
||||
Number:Pressure weather_pressure_relative "Relative pressure" <Pressure> (gOutdoor) ["Measurement", "Pressure"] { channel="fineoffsetweatherstation:gateway:3906700515:pressure-relative" }
|
||||
Number:Dimensionless weather_humidity_outdoor "Humidity outside" <Humidity> (gOutdoor) ["Measurement", "Humidity"] { channel="fineoffsetweatherstation:gateway:3906700515:humidity-outdoor" }
|
||||
Number:Angle weather_direction_wind "Wind direction" <Wind> (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:direction-wind" }
|
||||
Number:Speed weather_speed_wind "Wind speed" <Wind> (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:speed-wind" }
|
||||
Number:Speed weather_speed_gust "Gust speed" <Wind> (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:speed-gust" }
|
||||
Number:Illuminance weather_illumination "Light intensity" <Sun> (gOutdoor) ["Measurement", "Light"] { channel="fineoffsetweatherstation:gateway:3906700515:illumination" }
|
||||
Number:Intensity weather_irradiation_uv "UV radiation" <Sun> (gOutdoor) ["Measurement", "Light"] { channel="fineoffsetweatherstation:gateway:3906700515:irradiation-uv" }
|
||||
Number:Dimensionless weather_uv_index "UV Index" <Sun> (gOutdoor) ["Measurement", "Light"] { channel="fineoffsetweatherstation:gateway:3906700515:uv-index" }
|
||||
Number:Speed weather_max_day "Maximum wind speed today" <Wind> (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:wind-max-day" }
|
||||
Number:VolumetricFlowRate weather_rain_rate "Rainfall rate" <Rain> (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-rate" }
|
||||
Number:Length weather_rain_day "Rainfall today" <Rain> (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-day" }
|
||||
Number:Length weather_rain_week "Rainfall this week" <Rain> (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-week" }
|
||||
Number:Length weather_rain_month "Rainfall this month" <Rain> (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-month" }
|
||||
Number:Length weather_rain_year "Rainfall this year " <Rain> (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-year" }
|
||||
Number:Length weather_rain_event "Amount of rainfall at the last rain" <Rain> (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-event" }
|
||||
```
|
Binary file not shown.
After Width: | Height: | Size: 219 KiB |
38
bundles/org.openhab.binding.fineoffsetweatherstation/pom.xml
Normal file
38
bundles/org.openhab.binding.fineoffsetweatherstation/pom.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2022 Contributors to the openHAB project
|
||||
~ <p>
|
||||
~ See the NOTICE file(s) distributed with this work for additional
|
||||
~ information.
|
||||
~ <p>
|
||||
~ 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
|
||||
~ <p>
|
||||
~ SPDX-License-Identifier: EPL-2.0
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.fineoffsetweatherstation</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Fine Offset Weather Station</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.22.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.fineoffsetweatherstation-${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-fineoffsetweatherstation" description="FineOffsetWeatherStation Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.fineoffsetweatherstation/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link FineOffsetGatewayConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FineOffsetGatewayConfiguration {
|
||||
|
||||
public static final String IP = "ip";
|
||||
public static final String PORT = "port";
|
||||
|
||||
public @Nullable String ip;
|
||||
public int port = 45000;
|
||||
public int pollingInterval = 16;
|
||||
public int discoverInterval = 900;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding;
|
||||
|
||||
/**
|
||||
* The {@link FineOffsetSensorConfiguration} class contains the fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FineOffsetSensorConfiguration {
|
||||
|
||||
public static final String SENSOR = "sensor";
|
||||
|
||||
public @Nullable SensorGatewayBinding sensor;
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link FineOffsetWeatherStationBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FineOffsetWeatherStationBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "fineoffsetweatherstation";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_GATEWAY = new ThingTypeUID(BINDING_ID, "gateway");
|
||||
public static final ThingTypeUID THING_TYPE_SENSOR = new ThingTypeUID(BINDING_ID, "sensor");
|
||||
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_TEMPERATURE = new ChannelTypeUID(BINDING_ID, "temperature");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_HUMIDITY = new ChannelTypeUID(BINDING_ID, "humidity");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_MOISTURE = new ChannelTypeUID(BINDING_ID, "moisture");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_MAX_WIND_SPEED = new ChannelTypeUID(BINDING_ID, "max-wind-speed");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_RAIN = new ChannelTypeUID(BINDING_ID, "rain");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_PRESSURE = new ChannelTypeUID(BINDING_ID, "pressure");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_ILLUMINATION = new ChannelTypeUID(BINDING_ID, "illumination");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UV_INDEX = new ChannelTypeUID(BINDING_ID, "uv-index");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_UV_RADIATION = new ChannelTypeUID(BINDING_ID, "uv-radiation");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_RAIN_RATE = new ChannelTypeUID(BINDING_ID, "rain-rate");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_PM25 = new ChannelTypeUID(BINDING_ID, "pm25");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_PM10 = new ChannelTypeUID(BINDING_ID, "pm10");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_CO2 = new ChannelTypeUID(BINDING_ID, "co2");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_WATER_LEAK_DETECTION = new ChannelTypeUID(BINDING_ID,
|
||||
"water-leak-detection");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_LIGHTNING_COUNTER = new ChannelTypeUID(BINDING_ID,
|
||||
"lightning-counter");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_LIGHTNING_TIME = new ChannelTypeUID(BINDING_ID, "lightning-time");
|
||||
public static final ChannelTypeUID CHANNEL_TYPE_LIGHTNING_DISTANCE = new ChannelTypeUID(BINDING_ID,
|
||||
"lightning-distance");
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_GATEWAY, THING_TYPE_SENSOR);
|
||||
|
||||
public static final String SENSOR_CHANNEL_SIGNAL = "signal";
|
||||
public static final String SENSOR_CHANNEL_BATTERY_LEVEL = "batteryLevel";
|
||||
public static final String SENSOR_CHANNEL_LOW_BATTERY = "lowBattery";
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal;
|
||||
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.SUPPORTED_THING_TYPES_UIDS;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.THING_TYPE_GATEWAY;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.THING_TYPE_SENSOR;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.discovery.FineOffsetGatewayDiscoveryService;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.handler.FineOffsetGatewayHandler;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.handler.FineOffsetSensorHandler;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link FineOffsetWeatherStationHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.fineoffsetweatherstation", service = ThingHandlerFactory.class)
|
||||
public class FineOffsetWeatherStationHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final FineOffsetGatewayDiscoveryService gatewayDiscoveryService;
|
||||
private final ChannelTypeRegistry channelTypeRegistry;
|
||||
private final TranslationProvider translationProvider;
|
||||
private final LocaleProvider localeProvider;
|
||||
private final TimeZoneProvider timeZoneProvider;
|
||||
|
||||
@Activate
|
||||
public FineOffsetWeatherStationHandlerFactory(@Reference FineOffsetGatewayDiscoveryService gatewayDiscoveryService,
|
||||
@Reference ChannelTypeRegistry channelTypeRegistry, @Reference TranslationProvider translationProvider,
|
||||
@Reference LocaleProvider localeProvider, @Reference TimeZoneProvider timeZoneProvider) {
|
||||
this.gatewayDiscoveryService = gatewayDiscoveryService;
|
||||
this.channelTypeRegistry = channelTypeRegistry;
|
||||
this.translationProvider = translationProvider;
|
||||
this.localeProvider = localeProvider;
|
||||
this.timeZoneProvider = timeZoneProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (THING_TYPE_GATEWAY.equals(thingTypeUID) && thing instanceof Bridge) {
|
||||
return new FineOffsetGatewayHandler((Bridge) thing, gatewayDiscoveryService, channelTypeRegistry,
|
||||
translationProvider, localeProvider, timeZoneProvider);
|
||||
}
|
||||
if (THING_TYPE_SENSOR.equals(thingTypeUID)) {
|
||||
return new FineOffsetSensorHandler(thing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Utility class.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Utils {
|
||||
|
||||
public static String toHexString(byte[] hex, int length, String delimiter) {
|
||||
String[] hexadecimal = new String[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
hexadecimal[i] = String.format("%02X", hex[i]);
|
||||
}
|
||||
return String.join(delimiter, hexadecimal);
|
||||
}
|
||||
|
||||
public static boolean validateChecksum(byte[] data, int sizeBytes) {
|
||||
int size;
|
||||
|
||||
// general response
|
||||
// | 1 byte size | 2 byte size
|
||||
// | -----------------------------|--------------------
|
||||
// | 0 - 0xff - header | 0 - 0xff - header
|
||||
// | 1 - 0xff | 1 - 0xff
|
||||
// | 2 - command | 2 - command
|
||||
// | 3 - total size of response | 3 - size1
|
||||
// | 4-X - data | 4 - size2
|
||||
// | X+1 - checksum | 5-X - data
|
||||
// | | X+1 - checksum
|
||||
|
||||
if (sizeBytes == 1) {
|
||||
size = Utils.toUInt8(data[3]);
|
||||
} else {
|
||||
size = toUInt16(data, 3);
|
||||
}
|
||||
|
||||
byte checksum = sum(data, 2, size);
|
||||
return checksum == data[size + 1];
|
||||
}
|
||||
|
||||
private static byte sum(byte[] data, int start, int end) {
|
||||
byte checksum = 0;
|
||||
for (var i = start; i <= end; i++) {
|
||||
checksum += data[i];
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public static int toUInt8(byte data) {
|
||||
return Byte.toUnsignedInt(data);
|
||||
}
|
||||
|
||||
public static int toInt16(byte[] array, int start) {
|
||||
int result = ((int) array[start]) << 24;
|
||||
result |= Utils.toUInt8(array[start + 1]) << 16;
|
||||
return result >> 16;
|
||||
}
|
||||
|
||||
public static int toUInt16(byte[] array, int start) {
|
||||
return (Utils.toUInt8(array[start]) << 8 | Utils.toUInt8(array[start + 1]));
|
||||
}
|
||||
|
||||
public static int toUInt32(byte[] array, int start) {
|
||||
return (Utils.toUInt8(array[start++]) << 24 | Utils.toUInt8(array[start++]) << 16
|
||||
| Utils.toUInt8(array[start++]) << 8 | Utils.toUInt8(array[start]));
|
||||
}
|
||||
|
||||
public static long toUInt64(byte[] array, int start) {
|
||||
return ((long) Utils.toUInt8(array[start++]) << 24 | (long) toUInt8(array[start++]) << 16
|
||||
| (long) toUInt8(array[start++]) << 8 | Utils.toUInt8(array[start]));
|
||||
}
|
||||
}
|
@ -0,0 +1,308 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.THING_TYPE_GATEWAY;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toUInt16;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
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.fineoffsetweatherstation.internal.FineOffsetGatewayConfiguration;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetSensorConfiguration;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.Utils;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.Command;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SensorDevice;
|
||||
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.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.net.NetUtil;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = { DiscoveryService.class, FineOffsetGatewayDiscoveryService.class }, immediate = true)
|
||||
public class FineOffsetGatewayDiscoveryService extends AbstractDiscoveryService {
|
||||
public static final int DISCOVERY_PORT = 46000;
|
||||
private static final int BUFFER_LENGTH = 255;
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FineOffsetGatewayDiscoveryService.class);
|
||||
|
||||
private static final long REFRESH_INTERVAL = 600;
|
||||
private static final int DISCOVERY_TIME = 5;
|
||||
private final TranslationProvider translationProvider;
|
||||
private final LocaleProvider localeProvider;
|
||||
private final @Nullable Bundle bundle;
|
||||
private @Nullable DatagramSocket clientSocket;
|
||||
private @Nullable Thread socketReceiveThread;
|
||||
private @Nullable ScheduledFuture<?> discoveryJob;
|
||||
|
||||
@Activate
|
||||
public FineOffsetGatewayDiscoveryService(@Reference TranslationProvider translationProvider,
|
||||
@Reference LocaleProvider localeProvider) throws IllegalArgumentException {
|
||||
super(Collections.singleton(THING_TYPE_GATEWAY), DISCOVERY_TIME, true);
|
||||
this.translationProvider = translationProvider;
|
||||
this.localeProvider = localeProvider;
|
||||
this.bundle = FrameworkUtil.getBundle(FineOffsetGatewayDiscoveryService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startBackgroundDiscovery() {
|
||||
final @Nullable ScheduledFuture<?> discoveryJob = this.discoveryJob;
|
||||
if (discoveryJob == null || discoveryJob.isCancelled()) {
|
||||
this.discoveryJob = scheduler.scheduleWithFixedDelay(this::discover, 0, REFRESH_INTERVAL, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopBackgroundDiscovery() {
|
||||
final @Nullable ScheduledFuture<?> discoveryJob = this.discoveryJob;
|
||||
if (discoveryJob != null) {
|
||||
discoveryJob.cancel(true);
|
||||
this.discoveryJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
stopReceiverThreat();
|
||||
final DatagramSocket clientSocket = this.clientSocket;
|
||||
if (clientSocket != null) {
|
||||
clientSocket.close();
|
||||
}
|
||||
this.clientSocket = null;
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
final DatagramSocket clientSocket = getSocket();
|
||||
if (clientSocket != null) {
|
||||
logger.debug("Discovery using socket on port {}", clientSocket.getLocalPort());
|
||||
discover();
|
||||
} else {
|
||||
logger.debug("Discovery not started. Client DatagramSocket null");
|
||||
}
|
||||
}
|
||||
|
||||
private void discover() {
|
||||
startReceiverThread();
|
||||
NetUtil.getAllBroadcastAddresses().forEach(this::sendDiscoveryRequest);
|
||||
}
|
||||
|
||||
public void addSensors(ThingUID bridgeUID, Collection<SensorDevice> sensorDevices) {
|
||||
for (SensorDevice sensorDevice : sensorDevices) {
|
||||
ThingUID uid = new ThingUID(FineOffsetWeatherStationBindingConstants.THING_TYPE_SENSOR, bridgeUID,
|
||||
sensorDevice.getSensorGatewayBinding().name());
|
||||
|
||||
String model = sensorDevice.getSensorGatewayBinding().getSensor().name();
|
||||
String prefix = "thing.sensor." + model;
|
||||
@Nullable
|
||||
String name = translationProvider.getText(bundle, prefix + ".label", model, localeProvider.getLocale());
|
||||
DiscoveryResultBuilder builder = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID)
|
||||
.withProperty(FineOffsetSensorConfiguration.SENSOR, sensorDevice.getSensorGatewayBinding().name())
|
||||
.withProperty(Thing.PROPERTY_MODEL_ID, model)
|
||||
.withRepresentationProperty(FineOffsetSensorConfiguration.SENSOR);
|
||||
|
||||
@Nullable
|
||||
Integer channel = sensorDevice.getSensorGatewayBinding().getChannel();
|
||||
if (channel != null) {
|
||||
builder.withProperty("channel", channel);
|
||||
name += " " + translationProvider.getText(bundle, "channel", "channel", localeProvider.getLocale())
|
||||
+ " " + channel;
|
||||
}
|
||||
builder.withLabel(name);
|
||||
@Nullable
|
||||
String description = translationProvider.getText(bundle, prefix + ".description", model,
|
||||
localeProvider.getLocale());
|
||||
if (description != null) {
|
||||
builder.withProperty("description", description);
|
||||
}
|
||||
|
||||
DiscoveryResult result = builder.build();
|
||||
thingDiscovered(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void discovered(String ip, int port, byte[] macAddr, String name) {
|
||||
String id = String.valueOf(Utils.toUInt64(macAddr, 0));
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(Thing.PROPERTY_MAC_ADDRESS, Utils.toHexString(macAddr, macAddr.length, ":"));
|
||||
properties.put(FineOffsetGatewayConfiguration.IP, ip);
|
||||
properties.put(FineOffsetGatewayConfiguration.PORT, port);
|
||||
|
||||
ThingUID uid = new ThingUID(THING_TYPE_GATEWAY, id);
|
||||
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withLabel(translationProvider.getText(bundle, "thing.gateway.label", name, localeProvider.getLocale()))
|
||||
.build();
|
||||
thingDiscovered(result);
|
||||
logger.debug("Thing discovered '{}'", result);
|
||||
}
|
||||
|
||||
synchronized @Nullable DatagramSocket getSocket() {
|
||||
DatagramSocket clientSocket = this.clientSocket;
|
||||
if (clientSocket != null && clientSocket.isBound()) {
|
||||
return clientSocket;
|
||||
}
|
||||
try {
|
||||
logger.debug("Getting new socket for discovery");
|
||||
clientSocket = new DatagramSocket();
|
||||
clientSocket.setReuseAddress(true);
|
||||
clientSocket.setBroadcast(true);
|
||||
this.clientSocket = clientSocket;
|
||||
return clientSocket;
|
||||
} catch (SocketException | SecurityException e) {
|
||||
logger.debug("Error getting socket for discovery: {}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void closeSocket() {
|
||||
final @Nullable DatagramSocket clientSocket = this.clientSocket;
|
||||
if (clientSocket != null) {
|
||||
clientSocket.close();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
this.clientSocket = null;
|
||||
}
|
||||
|
||||
private void sendDiscoveryRequest(String broadcastAddress) {
|
||||
final @Nullable DatagramSocket socket = getSocket();
|
||||
if (socket != null) {
|
||||
byte[] requestMessage = Command.CMD_BROADCAST.getPayload();
|
||||
InetSocketAddress addr = new InetSocketAddress(broadcastAddress, DISCOVERY_PORT);
|
||||
DatagramPacket datagramPacket = new DatagramPacket(requestMessage, requestMessage.length, addr);
|
||||
try {
|
||||
socket.send(datagramPacket);
|
||||
} catch (IOException e) {
|
||||
logger.trace("Discovery on {} error: {}", broadcastAddress, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* starts the {@link ReceiverThread} thread
|
||||
*/
|
||||
private synchronized void startReceiverThread() {
|
||||
final Thread srt = socketReceiveThread;
|
||||
if (srt != null) {
|
||||
if (srt.isAlive() && !srt.isInterrupted()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
stopReceiverThreat();
|
||||
Thread socketReceiveThread = new ReceiverThread();
|
||||
socketReceiveThread.start();
|
||||
this.socketReceiveThread = socketReceiveThread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the {@link ReceiverThread} thread
|
||||
*/
|
||||
private synchronized void stopReceiverThreat() {
|
||||
final Thread socketReceiveThread = this.socketReceiveThread;
|
||||
if (socketReceiveThread != null) {
|
||||
socketReceiveThread.interrupt();
|
||||
this.socketReceiveThread = null;
|
||||
}
|
||||
closeSocket();
|
||||
}
|
||||
|
||||
/**
|
||||
* The thread, which waits for data and submits the unique results addresses to the discovery results
|
||||
*/
|
||||
private class ReceiverThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
DatagramSocket socket = getSocket();
|
||||
if (socket != null) {
|
||||
logger.debug("Starting discovery receiver thread for socket on port {}", socket.getLocalPort());
|
||||
receiveData(socket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method waits for data and submits the unique results addresses to the discovery results
|
||||
*
|
||||
* @param socket - The multicast socket to (re)use
|
||||
*/
|
||||
private void receiveData(DatagramSocket socket) {
|
||||
DatagramPacket receivePacket = new DatagramPacket(new byte[BUFFER_LENGTH], BUFFER_LENGTH);
|
||||
try {
|
||||
while (!interrupted()) {
|
||||
logger.trace("Thread {} waiting for data on port {}", this, socket.getLocalPort());
|
||||
socket.receive(receivePacket);
|
||||
String hostAddress = receivePacket.getAddress().getHostAddress();
|
||||
logger.trace("Received {} bytes response from {}:{} on Port {}", receivePacket.getLength(),
|
||||
hostAddress, receivePacket.getPort(), socket.getLocalPort());
|
||||
|
||||
byte[] messageBuf = Arrays.copyOfRange(receivePacket.getData(), receivePacket.getOffset(),
|
||||
receivePacket.getOffset() + receivePacket.getLength());
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Discovery response received: {}",
|
||||
Utils.toHexString(messageBuf, messageBuf.length, ""));
|
||||
}
|
||||
|
||||
if (Command.CMD_BROADCAST.isHeaderValid(messageBuf)) {
|
||||
String ip = InetAddress.getByAddress(Arrays.copyOfRange(messageBuf, 11, 15)).getHostAddress();
|
||||
var macAddr = Arrays.copyOfRange(messageBuf, 5, 5 + 6);
|
||||
var port = toUInt16(messageBuf, 15);
|
||||
var len = Utils.toUInt8(messageBuf[17]);
|
||||
String name = new String(messageBuf, 18, len);
|
||||
scheduler.schedule(() -> {
|
||||
try {
|
||||
discovered(ip, port, macAddr, name);
|
||||
} catch (Exception e) {
|
||||
logger.debug("Error submitting discovered device at {}", ip, e);
|
||||
}
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
logger.debug("Receiver thread received SocketException: {}", e.getMessage());
|
||||
} catch (IOException e) {
|
||||
logger.trace("Receiver thread was interrupted");
|
||||
}
|
||||
logger.debug("Receiver thread ended");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.Utils;
|
||||
|
||||
/**
|
||||
* The Commands supported by the gateway.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Command {
|
||||
/**
|
||||
* send SSID and Password to WIFI module
|
||||
*/
|
||||
CMD_WRITE_SSID((byte) 0x11, 1),
|
||||
|
||||
/**
|
||||
* UDP cast for device echo,answer back data size is 2 Bytes
|
||||
*/
|
||||
CMD_BROADCAST((byte) 0x12, 2),
|
||||
|
||||
/**
|
||||
* read aw.net setting
|
||||
*/
|
||||
CMD_READ_ECOWITT((byte) 0x1E, 1),
|
||||
|
||||
/**
|
||||
* write back awt.net setting
|
||||
*/
|
||||
CMD_WRITE_ECOWITT((byte) 0x1F, 1),
|
||||
|
||||
/**
|
||||
* read Wunderground setting
|
||||
*/
|
||||
CMD_READ_WUNDERGROUND((byte) 0x20, 1),
|
||||
|
||||
/**
|
||||
* write back Wunderground setting
|
||||
*/
|
||||
CMD_WRITE_WUNDERGROUND((byte) 0x21, 1),
|
||||
|
||||
/**
|
||||
* read WeatherObservationsWebsite setting
|
||||
*/
|
||||
CMD_READ_WOW((byte) 0x22, 1),
|
||||
|
||||
/**
|
||||
* write back WeatherObservationsWebsite setting
|
||||
*/
|
||||
CMD_WRITE_WOW((byte) 0x23, 1),
|
||||
|
||||
/**
|
||||
* read Weathercloud setting
|
||||
*/
|
||||
CMD_READ_WEATHERCLOUD((byte) 0x24, 1),
|
||||
|
||||
/**
|
||||
* write back Weathercloud setting
|
||||
*/
|
||||
CMD_WRITE_WEATHERCLOUD((byte) 0x25, 1),
|
||||
|
||||
/**
|
||||
* read MAC address
|
||||
*/
|
||||
CMD_READ_SATION_MAC((byte) 0x26, 1),
|
||||
|
||||
/**
|
||||
* read Customized sever setting
|
||||
*/
|
||||
CMD_READ_CUSTOMIZED((byte) 0x2A, 1),
|
||||
|
||||
/**
|
||||
* write back Customized sever setting
|
||||
*/
|
||||
CMD_WRITE_CUSTOMIZED((byte) 0x2B, 1),
|
||||
|
||||
/**
|
||||
* firmware upgrade
|
||||
*/
|
||||
CMD_WRITE_UPDATE((byte) 0x43, 1),
|
||||
|
||||
/**
|
||||
* read current firmware version number
|
||||
*/
|
||||
CMD_READ_FIRMWARE_VERSION((byte) 0x50, 1),
|
||||
|
||||
CMD_READ_USR_PATH((byte) 0x51, 1),
|
||||
|
||||
CMD_WRITE_USR_PATH((byte) 0x52, 1),
|
||||
|
||||
// the following command is only valid for GW1000, WH2650 and wn1900
|
||||
|
||||
/**
|
||||
* read current data,reply data size is 2bytes.
|
||||
*/
|
||||
CMD_GW1000_LIVEDATA((byte) 0x27, 2),
|
||||
|
||||
/**
|
||||
* read Soilmoisture Sensor calibration parameters
|
||||
*/
|
||||
CMD_GET_SOILHUMIAD((byte) 0x28, 1),
|
||||
|
||||
/**
|
||||
* write back Soilmoisture Sensor calibration parameters
|
||||
*/
|
||||
CMD_SET_SOILHUMIAD((byte) 0x29, 1),
|
||||
|
||||
/**
|
||||
* read multi channel sensor offset value
|
||||
*/
|
||||
CMD_GET_MulCH_OFFSET((byte) 0x2C, 1),
|
||||
|
||||
/**
|
||||
* write back multi channel sensor OFFSET value
|
||||
*/
|
||||
CMD_SET_MulCH_OFFSET((byte) 0x2D, 1),
|
||||
|
||||
/**
|
||||
* read PM2.5OFFSET calibration data
|
||||
*/
|
||||
CMD_GET_PM25_OFFSET((byte) 0x2E, 1),
|
||||
|
||||
/**
|
||||
* writeback PM2.5OFFSET calibration data
|
||||
*/
|
||||
CMD_SET_PM25_OFFSET((byte) 0x2F, 1),
|
||||
|
||||
/**
|
||||
* read system info
|
||||
*/
|
||||
CMD_READ_SSSS((byte) 0x30, 1),
|
||||
|
||||
/**
|
||||
* write back system info
|
||||
*/
|
||||
CMD_WRITE_SSSS((byte) 0x31, 1),
|
||||
|
||||
/**
|
||||
* read rain data
|
||||
*/
|
||||
CMD_READ_RAINDATA((byte) 0x34, 1),
|
||||
|
||||
/**
|
||||
* write back rain data
|
||||
*/
|
||||
CMD_WRITE_RAINDATA((byte) 0x35, 1),
|
||||
|
||||
/**
|
||||
* read rain gain
|
||||
*/
|
||||
CMD_READ_GAIN((byte) 0x36, 1),
|
||||
|
||||
/**
|
||||
* write back rain gain
|
||||
*/
|
||||
CMD_WRITE_GAIN((byte) 0x37, 1),
|
||||
|
||||
/**
|
||||
* read sensor set offset calibration value
|
||||
*/
|
||||
CMD_READ_CALIBRATION((byte) 0x38, 1),
|
||||
|
||||
/**
|
||||
* write back sensor set offset value
|
||||
*/
|
||||
CMD_WRITE_CALIBRATION((byte) 0x39, 1),
|
||||
|
||||
/**
|
||||
* read Sensors ID
|
||||
*/
|
||||
CMD_READ_SENSOR_ID((byte) 0x3A, 1),
|
||||
|
||||
/**
|
||||
* write back Sensors ID
|
||||
*/
|
||||
CMD_WRITE_SENSOR_ID((byte) 0x3B, 1),
|
||||
|
||||
/**
|
||||
* this is reserved for newly added sensors
|
||||
*/
|
||||
CMD_READ_SENSOR_ID_NEW((byte) 0x3C, 2),
|
||||
|
||||
/**
|
||||
* system restart
|
||||
*/
|
||||
CMD_WRITE_REBOOT((byte) 0x40, 1),
|
||||
|
||||
/**
|
||||
* reset to default
|
||||
*/
|
||||
CMD_WRITE_RESET((byte) 0x41, 1),
|
||||
|
||||
CMD_READ_CUSTOMIZED_PATH((byte) 0x51, 1),
|
||||
|
||||
CMD_WRITE_CUSTOMIZED_PATH((byte) 0x52, 1),
|
||||
|
||||
/**
|
||||
* CO2 OFFSET
|
||||
*/
|
||||
CMD_GET_CO2_OFFSET((byte) 0x53, 1),
|
||||
|
||||
/**
|
||||
* CO2 OFFSET
|
||||
*/
|
||||
CMD_SET_CO2_OFFSET((byte) 0x54, 1),
|
||||
|
||||
/**
|
||||
* read rain reset time
|
||||
*/
|
||||
CMD_READ_RSTRAIN_TIME((byte) 0x55, 1),
|
||||
|
||||
/**
|
||||
* write back rain reset time
|
||||
*/
|
||||
CMD_WRITE_RSTRAIN_TIME((byte) 0x56, 1);
|
||||
|
||||
private final byte code;
|
||||
private final int sizeBytes;
|
||||
|
||||
Command(byte code, int sizeBytes) {
|
||||
this.code = code;
|
||||
this.sizeBytes = sizeBytes;
|
||||
}
|
||||
|
||||
public byte getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public int getSizeBytes() {
|
||||
return sizeBytes;
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
byte size = 3; // + rest of payload / not yet implemented
|
||||
return new byte[] { (byte) 0xff, (byte) 0xff, code, size, (byte) (code + size) };
|
||||
}
|
||||
|
||||
public static @Nullable Command findByCode(byte code) {
|
||||
return Arrays.stream(values()).filter(command -> command.getCode() == code).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public boolean isHeaderValid(byte[] data) {
|
||||
if (data.length < 4 + sizeBytes) {
|
||||
return false;
|
||||
}
|
||||
return data[0] == (byte) 0xff && data[1] == (byte) 0xff && data[2] == code;
|
||||
}
|
||||
|
||||
public boolean isResponseValid(byte[] data) {
|
||||
return isHeaderValid(data) && Utils.validateChecksum(data, sizeBytes);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain;
|
||||
|
||||
import java.time.ZoneId;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ConversionContext {
|
||||
|
||||
private final ZoneId zoneId;
|
||||
|
||||
public ConversionContext(ZoneId zoneId) {
|
||||
this.zoneId = zoneId;
|
||||
}
|
||||
|
||||
public ZoneId getZoneId() {
|
||||
return zoneId;
|
||||
}
|
||||
}
|
@ -0,0 +1,391 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain;
|
||||
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_MAX_WIND_SPEED;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_MOISTURE;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_UV_INDEX;
|
||||
|
||||
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.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue;
|
||||
import org.openhab.core.thing.DefaultSystemChannelTypeProvider;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* The measurands of supported by the gateway.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Measurand {
|
||||
|
||||
INTEMP("temperature-indoor", (byte) 0x01, "Indoor Temperature", MeasureType.TEMPERATURE,
|
||||
DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_INDOOR_TEMPERATURE),
|
||||
|
||||
OUTTEMP("temperature-outdoor", (byte) 0x02, "Outdoor Temperature", MeasureType.TEMPERATURE,
|
||||
DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_OUTDOOR_TEMPERATURE),
|
||||
|
||||
DEWPOINT("temperature-dew-point", (byte) 0x03, "Dew point", MeasureType.TEMPERATURE),
|
||||
|
||||
WINDCHILL("temperature-wind-chill", (byte) 0x04, "Wind chill", MeasureType.TEMPERATURE),
|
||||
|
||||
HEATINDEX("temperature-heat-index", (byte) 0x05, "Heat index", MeasureType.TEMPERATURE),
|
||||
|
||||
INHUMI("humidity-indoor", (byte) 0x06, "Indoor Humidity", MeasureType.PERCENTAGE),
|
||||
|
||||
OUTHUMI("humidity-outdoor", (byte) 0x07, "Outdoor Humidity", MeasureType.PERCENTAGE,
|
||||
DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_ATMOSPHERIC_HUMIDITY),
|
||||
|
||||
ABSBARO("pressure-absolute", (byte) 0x08, "Absolutely pressure", MeasureType.PRESSURE),
|
||||
|
||||
RELBARO("pressure-relative", (byte) 0x09, "Relative pressure", MeasureType.PRESSURE,
|
||||
DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_BAROMETRIC_PRESSURE),
|
||||
|
||||
WINDDIRECTION("direction-wind", (byte) 0x0A, "Wind Direction", MeasureType.DEGREE,
|
||||
DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_WIND_DIRECTION),
|
||||
|
||||
WINDSPEED("speed-wind", (byte) 0x0B, "Wind Speed", MeasureType.SPEED,
|
||||
DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_WIND_SPEED),
|
||||
|
||||
GUSTSPEED("speed-gust", (byte) 0x0C, "Gust Speed", MeasureType.SPEED,
|
||||
DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_WIND_SPEED),
|
||||
|
||||
RAINEVENT("rain-event", (byte) 0x0D, "Rain Event", MeasureType.HEIGHT),
|
||||
|
||||
RAINRATE("rain-rate", (byte) 0x0E, "Rain Rate", MeasureType.HEIGHT_PER_HOUR),
|
||||
|
||||
RAINHOUR("rain-hour", (byte) 0x0F, "Rain hour", MeasureType.HEIGHT),
|
||||
|
||||
RAINDAY("rain-day", (byte) 0x10, "Rain Day", MeasureType.HEIGHT),
|
||||
|
||||
RAINWEEK("rain-week", (byte) 0x11, "Rain Week", MeasureType.HEIGHT),
|
||||
|
||||
RAINMONTH("rain-month", (byte) 0x12, "Rain Month", MeasureType.HEIGHT_BIG),
|
||||
|
||||
RAINYEAR("rain-year", (byte) 0x13, "Rain Year", MeasureType.HEIGHT_BIG),
|
||||
|
||||
RAINTOTALS("rain-total", (byte) 0x14, "Rain Totals", MeasureType.HEIGHT_BIG),
|
||||
|
||||
LIGHT("illumination", (byte) 0x15, "Light", MeasureType.LUX),
|
||||
|
||||
UV("irradiation-uv", (byte) 0x16, "UV", MeasureType.MICROWATT_PER_SQUARE_CENTIMETRE),
|
||||
|
||||
UVI("uv-index", (byte) 0x17, "UV index", MeasureType.BYTE, CHANNEL_TYPE_UV_INDEX),
|
||||
|
||||
TIME("time", (byte) 0x18, "Date and time", MeasureType.DATE_TIME2),
|
||||
|
||||
DAYLWINDMAX("wind-max-day", (byte) 0X19, "Day max wind", MeasureType.SPEED, CHANNEL_TYPE_MAX_WIND_SPEED),
|
||||
|
||||
TEMP1("temperature-channel-1", (byte) 0x1A, "Temperature 1", MeasureType.TEMPERATURE),
|
||||
|
||||
TEMP2("temperature-channel-2", (byte) 0x1B, "Temperature 2", MeasureType.TEMPERATURE),
|
||||
|
||||
TEMP3("temperature-channel-3", (byte) 0x1C, "Temperature 3", MeasureType.TEMPERATURE),
|
||||
|
||||
TEMP4("temperature-channel-4", (byte) 0x1D, "Temperature 4", MeasureType.TEMPERATURE),
|
||||
|
||||
TEMP5("temperature-channel-5", (byte) 0x1E, "Temperature 5", MeasureType.TEMPERATURE),
|
||||
|
||||
TEMP6("temperature-channel-6", (byte) 0x1F, "Temperature 6", MeasureType.TEMPERATURE),
|
||||
|
||||
TEMP7("temperature-channel-7", (byte) 0x20, "Temperature 7", MeasureType.TEMPERATURE),
|
||||
|
||||
TEMP8("temperature-channel-8", (byte) 0x21, "Temperature 8", MeasureType.TEMPERATURE),
|
||||
|
||||
HUMI1("humidity-channel-1", (byte) 0x22, "Humidity 1", MeasureType.PERCENTAGE),
|
||||
|
||||
HUMI2("humidity-channel-2", (byte) 0x23, "Humidity 2", MeasureType.PERCENTAGE),
|
||||
|
||||
HUMI3("humidity-channel-3", (byte) 0x24, "Humidity 3", MeasureType.PERCENTAGE),
|
||||
|
||||
HUMI4("humidity-channel-4", (byte) 0x25, "Humidity 4", MeasureType.PERCENTAGE),
|
||||
|
||||
HUMI5("humidity-channel-5", (byte) 0x26, "Humidity 5", MeasureType.PERCENTAGE),
|
||||
|
||||
HUMI6("humidity-channel-6", (byte) 0x27, "Humidity 6", MeasureType.PERCENTAGE),
|
||||
|
||||
HUMI7("humidity-channel-7", (byte) 0x28, "Humidity 7", MeasureType.PERCENTAGE),
|
||||
|
||||
HUMI8("humidity-channel-8", (byte) 0x29, "Humidity 8", MeasureType.PERCENTAGE),
|
||||
|
||||
SOILTEMP1("temperature-soil-channel-1", (byte) 0x2B, "Soil Temperature 1", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP2("temperature-soil-channel-2", (byte) 0x2D, "Soil Temperature 2", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP3("temperature-soil-channel-3", (byte) 0x2F, "Soil Temperature 3", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP4("temperature-soil-channel-4", (byte) 0x31, "Soil Temperature 4", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP5("temperature-soil-channel-5", (byte) 0x33, "Soil Temperature 5", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP6("temperature-soil-channel-6", (byte) 0x35, "Soil Temperature 6", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP7("temperature-soil-channel-7", (byte) 0x37, "Soil Temperature 7", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP8("temperature-soil-channel-8", (byte) 0x39, "Soil Temperature 8", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP9("temperature-soil-channel-9", (byte) 0x3B, "Soil Temperature 9", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP10("temperature-soil-channel-10", (byte) 0x3D, "Soil Temperature 10", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP11("temperature-soil-channel-11", (byte) 0x3F, "Soil Temperature 11", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP12("temperature-soil-channel-12", (byte) 0x41, "Soil Temperature 12", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP13("temperature-soil-channel-13", (byte) 0x43, "Soil Temperature 13", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP14("temperature-soil-channel-14", (byte) 0x45, "Soil Temperature 14", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP15("temperature-soil-channel-15", (byte) 0x47, "Soil Temperature 15", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILTEMP16("temperature-soil-channel-16", (byte) 0x49, "Soil Temperature 16", MeasureType.TEMPERATURE),
|
||||
|
||||
SOILMOISTURE1("moisture-soil-channel-1", (byte) 0x2C, "Soil Moisture 1", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE2("moisture-soil-channel-2", (byte) 0x2E, "Soil Moisture 2", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE3("moisture-soil-channel-3", (byte) 0x30, "Soil Moisture 3", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE4("moisture-soil-channel-4", (byte) 0x32, "Soil Moisture 4", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE5("moisture-soil-channel-5", (byte) 0x34, "Soil Moisture 5", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE6("moisture-soil-channel-6", (byte) 0x36, "Soil Moisture 6", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE7("moisture-soil-channel-7", (byte) 0x38, "Soil Moisture 7", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE8("moisture-soil-channel-8", (byte) 0x3A, "Soil Moisture 8", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE9("moisture-soil-channel-9", (byte) 0x3C, "Soil Moisture 9", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE10("moisture-soil-channel-10", (byte) 0x3E, "Soil Moisture 10", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE11("moisture-soil-channel-11", (byte) 0x40, "Soil Moisture 11", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE12("moisture-soil-channel-12", (byte) 0x42, "Soil Moisture 12", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE13("moisture-soil-channel-13", (byte) 0x44, "Soil Moisture 13", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE14("moisture-soil-channel-14", (byte) 0x46, "Soil Moisture 14", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE15("moisture-soil-channel-15", (byte) 0x48, "Soil Moisture 15", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
SOILMOISTURE16("moisture-soil-channel-16", (byte) 0x4A, "Soil Moisture 16", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
// will no longer be used
|
||||
// skip battery-level, since it is read via Command.CMD_READ_SENSOR_ID_NEW
|
||||
LOWBATT((byte) 0x4C, new Skip(1)),
|
||||
|
||||
PM25_24HAVG1("air-quality-24-hour-average-channel-1", (byte) 0x4D, "PM2.5 Air Quality 24 hour average channel 1",
|
||||
MeasureType.PM25),
|
||||
|
||||
PM25_24HAVG2("air-quality-24-hour-average-channel-2", (byte) 0x4E, "PM2.5 Air Quality 24 hour average channel 2",
|
||||
MeasureType.PM25),
|
||||
|
||||
PM25_24HAVG3("air-quality-24-hour-average-channel-3", (byte) 0x4F, "PM2.5 Air Quality 24 hour average channel 3",
|
||||
MeasureType.PM25),
|
||||
|
||||
PM25_24HAVG4("air-quality-24-hour-average-channel-4", (byte) 0x50, "PM2.5 Air Quality 24 hour average channel 4",
|
||||
MeasureType.PM25),
|
||||
|
||||
PM25_CH1("air-quality-channel-1", (byte) 0x2A, "PM2.5 Air Quality channel 1", MeasureType.PM25),
|
||||
|
||||
PM25_CH2("air-quality-channel-2", (byte) 0x51, "PM2.5 Air Quality channel 2", MeasureType.PM25),
|
||||
|
||||
PM25_CH3("air-quality-channel-3", (byte) 0x52, "PM2.5 Air Quality channel 3", MeasureType.PM25),
|
||||
|
||||
PM25_CH4("air-quality-channel-4", (byte) 0x53, "PM2.5 Air Quality channel 4", MeasureType.PM25),
|
||||
|
||||
LEAK_CH1("water-leak-channel-1", (byte) 0x58, "Leak channel 1", MeasureType.WATER_LEAK_DETECTION),
|
||||
|
||||
LEAK_CH2("water-leak-channel-2", (byte) 0x59, "Leak channel 2", MeasureType.WATER_LEAK_DETECTION),
|
||||
|
||||
LEAK_CH3("water-leak-channel-3", (byte) 0x5A, "Leak channel 3", MeasureType.WATER_LEAK_DETECTION),
|
||||
|
||||
LEAK_CH4("water-leak-channel-4", (byte) 0x5B, "Leak channel 4", MeasureType.WATER_LEAK_DETECTION),
|
||||
|
||||
// `LIGHTNING` is the name in the spec, so we keep it here as it
|
||||
LIGHTNING("lightning-distance", (byte) 0x60, "lightning distance 1~40KM", MeasureType.LIGHTNING_DISTANCE),
|
||||
|
||||
LIGHTNING_TIME("lightning-time", (byte) 0x61, "lightning happened time", MeasureType.LIGHTNING_TIME),
|
||||
|
||||
// `LIGHTNING_POWER` is the name in the spec, so we keep it here as it
|
||||
LIGHTNING_POWER("lightning-counter", (byte) 0x62, "lightning counter for the day", MeasureType.LIGHTNING_COUNTER),
|
||||
|
||||
TF_USR1("temperature-external-channel-1", (byte) 0x63, "Soil or Water temperature channel 1",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
TF_USR2("temperature-external-channel-2", (byte) 0x64, "Soil or Water temperature channel 2",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
TF_USR3("temperature-external-channel-3", (byte) 0x65, "Soil or Water temperature channel 3",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
TF_USR4("temperature-external-channel-4", (byte) 0x66, "Soil or Water temperature channel 4",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
TF_USR5("temperature-external-channel-5", (byte) 0x67, "Soil or Water temperature channel 5",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
TF_USR6("temperature-external-channel-6", (byte) 0x68, "Soil or Water temperature channel 6",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
TF_USR7("temperature-external-channel-7", (byte) 0x69, "Soil or Water temperature channel 7",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
TF_USR8("temperature-external-channel-8", (byte) 0x6A, "Soil or Water temperature channel 8",
|
||||
MeasureType.TEMPERATURE),
|
||||
|
||||
ITEM_SENSOR_CO2((byte) 0x70,
|
||||
new MeasurandParser("sensor-co2-temperature", "Temperature (CO₂-Sensor)", MeasureType.TEMPERATURE),
|
||||
new MeasurandParser("sensor-co2-humidity", "Humidity (CO₂-Sensor)", MeasureType.PERCENTAGE),
|
||||
new MeasurandParser("sensor-co2-pm10", "PM10 Air Quality (CO₂-Sensor)", MeasureType.PM10),
|
||||
new MeasurandParser("sensor-co2-pm10-24-hour-average", "PM10 Air Quality 24 hour average (CO₂-Sensor)",
|
||||
MeasureType.PM10),
|
||||
new MeasurandParser("sensor-co2-pm25", "PM2.5 Air Quality (CO₂-Sensor)", MeasureType.PM25),
|
||||
new MeasurandParser("sensor-co2-pm25-24-hour-average", "PM2.5 Air Quality 24 hour average (CO₂-Sensor)",
|
||||
MeasureType.PM25),
|
||||
new MeasurandParser("sensor-co2-co2", "CO₂", MeasureType.CO2),
|
||||
new MeasurandParser("sensor-co2-co2-24-hour-average", "CO₂ 24 hour average", MeasureType.CO2),
|
||||
// skip battery-level, since it is read via Command.CMD_READ_SENSOR_ID_NEW
|
||||
new Skip(1)),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH1("leaf-wetness-channel-1", (byte) 0x72, "Leaf Moisture channel 1", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH2("leaf-wetness-channel-2", (byte) 0x73, "Leaf Moisture channel 2", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH3("leaf-wetness-channel-3", (byte) 0x74, "Leaf Moisture channel 3", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH4("leaf-wetness-channel-4", (byte) 0x75, "Leaf Moisture channel 4", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH5("leaf-wetness-channel-5", (byte) 0x76, "Leaf Moisture channel 5", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH6("leaf-wetness-channel-6", (byte) 0x77, "Leaf Moisture channel 6", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH7("leaf-wetness-channel-7", (byte) 0x78, "Leaf Moisture channel 7", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),
|
||||
|
||||
ITEM_LEAF_WETNESS_CH8("leaf-wetness-channel-8", (byte) 0x79, "Leaf Moisture channel 8", MeasureType.PERCENTAGE,
|
||||
CHANNEL_TYPE_MOISTURE),;
|
||||
|
||||
private static final Map<Byte, Measurand> MEASURANDS = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Measurand value : values()) {
|
||||
MEASURANDS.put(value.code, value);
|
||||
}
|
||||
}
|
||||
|
||||
private final byte code;
|
||||
private final Parser[] parsers;
|
||||
|
||||
Measurand(String channelId, byte code, String name, MeasureType measureType) {
|
||||
this(channelId, code, name, measureType, null);
|
||||
}
|
||||
|
||||
Measurand(String channelId, byte code, String name, MeasureType measureType,
|
||||
@Nullable ChannelTypeUID channelTypeUID) {
|
||||
this(code, new MeasurandParser(channelId, name, measureType, channelTypeUID));
|
||||
}
|
||||
|
||||
Measurand(byte code, Parser... parsers) {
|
||||
this.code = code;
|
||||
this.parsers = parsers;
|
||||
}
|
||||
|
||||
public static @Nullable Measurand getByCode(byte code) {
|
||||
return MEASURANDS.get(code);
|
||||
}
|
||||
|
||||
public int extractMeasuredValues(byte[] data, int offset, ConversionContext context, List<MeasuredValue> result) {
|
||||
int subOffset = 0;
|
||||
for (Parser parser : parsers) {
|
||||
subOffset += parser.extractMeasuredValues(data, offset + subOffset, context, result);
|
||||
}
|
||||
return subOffset;
|
||||
}
|
||||
|
||||
private interface Parser {
|
||||
int extractMeasuredValues(byte[] data, int offset, ConversionContext context, List<MeasuredValue> result);
|
||||
}
|
||||
|
||||
private static class Skip implements Parser {
|
||||
private final int skip;
|
||||
|
||||
public Skip(int skip) {
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int extractMeasuredValues(byte[] data, int offset, ConversionContext context,
|
||||
List<MeasuredValue> result) {
|
||||
return skip;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MeasurandParser implements Parser {
|
||||
private final String name;
|
||||
private final String channelId;
|
||||
private final MeasureType measureType;
|
||||
private final @Nullable ChannelTypeUID channelTypeUID;
|
||||
|
||||
MeasurandParser(String channelId, String name, MeasureType measureType) {
|
||||
this(channelId, name, measureType, null);
|
||||
}
|
||||
|
||||
MeasurandParser(String channelId, String name, MeasureType measureType,
|
||||
@Nullable ChannelTypeUID channelTypeUID) {
|
||||
this.channelId = channelId;
|
||||
this.name = name;
|
||||
this.measureType = measureType;
|
||||
this.channelTypeUID = channelTypeUID == null ? measureType.getChannelTypeId() : channelTypeUID;
|
||||
}
|
||||
|
||||
public int extractMeasuredValues(byte[] data, int offset, ConversionContext context,
|
||||
List<MeasuredValue> result) {
|
||||
State state = measureType.toState(data, offset, context);
|
||||
if (state != null) {
|
||||
result.add(new MeasuredValue(measureType, channelId, channelTypeUID, state, name));
|
||||
}
|
||||
return measureType.getByteSize();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain;
|
||||
|
||||
import static javax.measure.MetricPrefix.HECTO;
|
||||
import static javax.measure.MetricPrefix.KILO;
|
||||
import static javax.measure.MetricPrefix.MILLI;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_CO2;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_HUMIDITY;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_ILLUMINATION;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_LIGHTNING_COUNTER;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_LIGHTNING_DISTANCE;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_LIGHTNING_TIME;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_PM10;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_PM25;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_PRESSURE;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_RAIN;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_RAIN_RATE;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_TEMPERATURE;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_UV_RADIATION;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.CHANNEL_TYPE_WATER_LEAK_DETECTION;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toInt16;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toUInt16;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toUInt32;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toUInt8;
|
||||
import static org.openhab.core.library.unit.SIUnits.CELSIUS;
|
||||
import static org.openhab.core.library.unit.SIUnits.METRE;
|
||||
import static org.openhab.core.library.unit.SIUnits.PASCAL;
|
||||
import static org.openhab.core.library.unit.Units.DEGREE_ANGLE;
|
||||
import static org.openhab.core.library.unit.Units.METRE_PER_SECOND;
|
||||
import static org.openhab.core.library.unit.Units.MICROGRAM_PER_CUBICMETRE;
|
||||
import static org.openhab.core.library.unit.Units.MILLIMETRE_PER_HOUR;
|
||||
import static org.openhab.core.library.unit.Units.PARTS_PER_MILLION;
|
||||
import static org.openhab.core.library.unit.Units.PERCENT;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import javax.measure.Unit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.Utils;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
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.Units;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Represents the measured type with conversion from the sensors' bytes to the openHAB state.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum MeasureType {
|
||||
|
||||
TEMPERATURE(CELSIUS, 2, CHANNEL_TYPE_TEMPERATURE, (data, offset) -> toInt16(data, offset) / 10.),
|
||||
|
||||
PERCENTAGE(PERCENT, 1, CHANNEL_TYPE_HUMIDITY, (data, offset) -> toUInt8(data[offset])),
|
||||
|
||||
PRESSURE(HECTO(PASCAL), 2, CHANNEL_TYPE_PRESSURE, Utils::toUInt16),
|
||||
|
||||
DEGREE(DEGREE_ANGLE, 2, null, Utils::toUInt16),
|
||||
|
||||
SPEED(METRE_PER_SECOND, 2, null, (data, offset) -> toUInt16(data, offset) / 10.),
|
||||
|
||||
HEIGHT(MILLI(METRE), 2, CHANNEL_TYPE_RAIN, (data, offset) -> toUInt16(data, offset) / 10.),
|
||||
|
||||
HEIGHT_BIG(MILLI(METRE), 4, CHANNEL_TYPE_RAIN, (data, offset) -> toUInt32(data, offset) / 10.),
|
||||
|
||||
HEIGHT_PER_HOUR(MILLIMETRE_PER_HOUR, 2, CHANNEL_TYPE_RAIN_RATE, (data, offset) -> toUInt16(data, offset) / 10.),
|
||||
|
||||
LUX(Units.LUX, 4, CHANNEL_TYPE_ILLUMINATION, (data, offset) -> toUInt32(data, offset) / 10.),
|
||||
|
||||
PM25(MICROGRAM_PER_CUBICMETRE, 2, CHANNEL_TYPE_PM25, (data, offset) -> toUInt16(data, offset) / 10.),
|
||||
|
||||
PM10(MICROGRAM_PER_CUBICMETRE, 2, CHANNEL_TYPE_PM10, (data, offset) -> toUInt16(data, offset) / 10.),
|
||||
|
||||
CO2(PARTS_PER_MILLION, 2, CHANNEL_TYPE_CO2, Utils::toUInt16),
|
||||
|
||||
WATER_LEAK_DETECTION(1, CHANNEL_TYPE_WATER_LEAK_DETECTION,
|
||||
(data, offset, context) -> toUInt8(data[offset]) != 0 ? OnOffType.ON : OnOffType.OFF),
|
||||
|
||||
LIGHTNING_DISTANCE(KILO(METRE), 1, CHANNEL_TYPE_LIGHTNING_DISTANCE, (data, offset) -> toUInt8(data[offset])),
|
||||
|
||||
LIGHTNING_COUNTER(4, CHANNEL_TYPE_LIGHTNING_COUNTER,
|
||||
(data, offset, context) -> new DecimalType(toUInt32(data, offset))),
|
||||
|
||||
LIGHTNING_TIME(4, CHANNEL_TYPE_LIGHTNING_TIME,
|
||||
(data, offset, context) -> new DateTimeType(
|
||||
ZonedDateTime.ofInstant(Instant.ofEpochSecond(toUInt32(data, offset)), context.getZoneId()))),
|
||||
|
||||
MICROWATT_PER_SQUARE_CENTIMETRE(Units.MICROWATT_PER_SQUARE_CENTIMETRE, 2, CHANNEL_TYPE_UV_RADIATION,
|
||||
Utils::toUInt16),
|
||||
|
||||
BYTE(1, null, (data, offset, context) -> new DecimalType(toUInt8(data[offset]))),
|
||||
|
||||
DATE_TIME2(6, null, (data, offset, context) -> new DateTimeType(
|
||||
ZonedDateTime.ofInstant(Instant.ofEpochSecond(toUInt32(data, offset)), context.getZoneId())));
|
||||
|
||||
private final int byteSize;
|
||||
private final @Nullable ChannelTypeUID channelTypeUID;
|
||||
private final StateConverter stateConverter;
|
||||
|
||||
/**
|
||||
* @param unit the unit
|
||||
* @param byteSize the size in the sensors' payload
|
||||
* @param channelTypeUID the channel type
|
||||
* @param valueExtractor a function to extract the sensor data into a number of the dimension defined by the unit
|
||||
*/
|
||||
MeasureType(Unit<?> unit, int byteSize, @Nullable ChannelTypeUID channelTypeUID,
|
||||
BiFunction<byte[], Integer, @Nullable Number> valueExtractor) {
|
||||
this(byteSize, channelTypeUID, (bytes, offset, context) -> {
|
||||
Number value = valueExtractor.apply(bytes, offset);
|
||||
return value == null ? null : new QuantityType<>(value, unit);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byteSize the size in the sensors' payload
|
||||
* @param channelTypeUID the channel type
|
||||
* @param stateConverter a function to extract the sensor data into the openHAB's state
|
||||
*/
|
||||
MeasureType(int byteSize, @Nullable ChannelTypeUID channelTypeUID, StateConverter stateConverter) {
|
||||
this.byteSize = byteSize;
|
||||
this.channelTypeUID = channelTypeUID;
|
||||
this.stateConverter = stateConverter;
|
||||
}
|
||||
|
||||
public int getByteSize() {
|
||||
return byteSize;
|
||||
}
|
||||
|
||||
public @Nullable ChannelTypeUID getChannelTypeId() {
|
||||
return channelTypeUID;
|
||||
}
|
||||
|
||||
public @Nullable State toState(byte[] data, int offset, ConversionContext context) {
|
||||
return stateConverter.toState(data, offset, context);
|
||||
}
|
||||
|
||||
private interface StateConverter {
|
||||
@Nullable
|
||||
State toState(byte[] data, int offset, ConversionContext context);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain;
|
||||
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus.Type.LEVEL;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus.Type.LEVEL_OR_DC;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus.Type.LOW_HIGH;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus.Type.VOLTAGE_BROAD_STEPS;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus.Type.VOLTAGE_FINE_STEPS;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus;
|
||||
|
||||
/**
|
||||
* The Sensors supported by the gateway.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum Sensor {
|
||||
WH24(LOW_HIGH),
|
||||
WH25(LOW_HIGH),
|
||||
WH26(LOW_HIGH),
|
||||
WH31(LOW_HIGH),
|
||||
WH34(VOLTAGE_FINE_STEPS),
|
||||
WH35(VOLTAGE_FINE_STEPS),
|
||||
WH40(VOLTAGE_BROAD_STEPS),
|
||||
WH41(LEVEL_OR_DC),
|
||||
WH45(LEVEL_OR_DC),
|
||||
WH51(VOLTAGE_BROAD_STEPS),
|
||||
WH55(LEVEL),
|
||||
WH57(LEVEL),
|
||||
WH65(LOW_HIGH),
|
||||
WH68(VOLTAGE_FINE_STEPS),
|
||||
WH80(VOLTAGE_FINE_STEPS),
|
||||
WH90(VOLTAGE_FINE_STEPS);
|
||||
|
||||
private final BatteryStatus.Type batteryStatusTpe;
|
||||
|
||||
Sensor(BatteryStatus.Type batteryStatusTpe) {
|
||||
this.batteryStatusTpe = batteryStatusTpe;
|
||||
}
|
||||
|
||||
public BatteryStatus getBatteryStatus(byte data) {
|
||||
return new BatteryStatus(batteryStatusTpe, data);
|
||||
}
|
||||
}
|
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus;
|
||||
|
||||
/**
|
||||
* The binding of a sensor to the gateway.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum SensorGatewayBinding {
|
||||
/**
|
||||
* wh24 + wh65 share the same id, they are distinguished by user set flag, see also {@link Command#CMD_READ_SSSS}
|
||||
*/
|
||||
WH24((byte) 0, Sensor.WH24, null),
|
||||
WH65((byte) 0, Sensor.WH65, null),
|
||||
// also wh69
|
||||
WH68((byte) 1, Sensor.WH68, null),
|
||||
WH80((byte) 2, Sensor.WH80, null),
|
||||
WH40((byte) 3, Sensor.WH40, null),
|
||||
WH25((byte) 4, Sensor.WH25, null),
|
||||
WH26((byte) 5, Sensor.WH26, null),
|
||||
WH31_CH1((byte) 6, Sensor.WH31, 1),
|
||||
WH31_CH2((byte) 7, Sensor.WH31, 2),
|
||||
WH31_CH3((byte) 8, Sensor.WH31, 3),
|
||||
WH31_CH4((byte) 9, Sensor.WH31, 4),
|
||||
WH31_CH5((byte) 10, Sensor.WH31, 5),
|
||||
WH31_CH6((byte) 11, Sensor.WH31, 6),
|
||||
WH31_CH7((byte) 12, Sensor.WH31, 7),
|
||||
WH31_CH8((byte) 13, Sensor.WH31, 8),
|
||||
WH51_CH1((byte) 14, Sensor.WH51, 1),
|
||||
WH51_CH2((byte) 15, Sensor.WH51, 2),
|
||||
WH51_CH3((byte) 16, Sensor.WH51, 3),
|
||||
WH51_CH4((byte) 17, Sensor.WH51, 4),
|
||||
WH51_CH5((byte) 18, Sensor.WH51, 5),
|
||||
WH51_CH6((byte) 19, Sensor.WH51, 6),
|
||||
WH51_CH7((byte) 20, Sensor.WH51, 7),
|
||||
WH51_CH8((byte) 21, Sensor.WH51, 8),
|
||||
WH41_CH1((byte) 22, Sensor.WH41, 1),
|
||||
WH41_CH2((byte) 23, Sensor.WH41, 2),
|
||||
WH41_CH3((byte) 24, Sensor.WH41, 3),
|
||||
WH41_CH4((byte) 25, Sensor.WH41, 4),
|
||||
WH57((byte) 26, Sensor.WH57, null),
|
||||
WH55_CH1((byte) 27, Sensor.WH55, 1),
|
||||
WH55_CH2((byte) 28, Sensor.WH55, 2),
|
||||
WH55_CH3((byte) 29, Sensor.WH55, 3),
|
||||
WH55_CH4((byte) 30, Sensor.WH55, 4),
|
||||
WH34_CH1((byte) 31, Sensor.WH34, 1),
|
||||
WH34_CH2((byte) 32, Sensor.WH34, 2),
|
||||
WH34_CH3((byte) 33, Sensor.WH34, 3),
|
||||
WH34_CH4((byte) 34, Sensor.WH34, 4),
|
||||
WH34_CH5((byte) 35, Sensor.WH34, 5),
|
||||
WH34_CH6((byte) 36, Sensor.WH34, 6),
|
||||
WH34_CH7((byte) 37, Sensor.WH34, 7),
|
||||
WH34_CH8((byte) 38, Sensor.WH34, 8),
|
||||
WH45((byte) 39, Sensor.WH45, null),
|
||||
WH35_CH1((byte) 40, Sensor.WH35, 1),
|
||||
WH35_CH2((byte) 41, Sensor.WH35, 2),
|
||||
WH35_CH3((byte) 42, Sensor.WH35, 3),
|
||||
WH35_CH4((byte) 43, Sensor.WH35, 4),
|
||||
WH35_CH5((byte) 44, Sensor.WH35, 5),
|
||||
WH35_CH6((byte) 45, Sensor.WH35, 6),
|
||||
WH35_CH7((byte) 46, Sensor.WH35, 7),
|
||||
WH35_CH8((byte) 47, Sensor.WH35, 8),
|
||||
WH90((byte) 48, Sensor.WH90, null);
|
||||
|
||||
private static final Map<Byte, List<SensorGatewayBinding>> SENSOR_LOOKUP = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (SensorGatewayBinding sensorGatewayBinding : values()) {
|
||||
List<SensorGatewayBinding> bindings = SENSOR_LOOKUP.computeIfAbsent(sensorGatewayBinding.id,
|
||||
ArrayList::new);
|
||||
// noinspection ConstantConditions
|
||||
if (bindings != null) {
|
||||
bindings.add(sensorGatewayBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final byte id;
|
||||
private final Sensor sensor;
|
||||
private final @Nullable Integer channel;
|
||||
|
||||
SensorGatewayBinding(byte id, Sensor sensor, @Nullable Integer channel) {
|
||||
this.id = id;
|
||||
this.sensor = sensor;
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public static @Nullable List<SensorGatewayBinding> forIndex(byte idx) {
|
||||
return SENSOR_LOOKUP.get(idx);
|
||||
}
|
||||
|
||||
public BatteryStatus getBatteryStatus(byte data) {
|
||||
return sensor.getBatteryStatus(data);
|
||||
}
|
||||
|
||||
public Sensor getSensor() {
|
||||
return sensor;
|
||||
}
|
||||
|
||||
public @Nullable Integer getChannel() {
|
||||
return channel;
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain.response;
|
||||
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toUInt8;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The status of the sensors' battery.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BatteryStatus {
|
||||
|
||||
public enum Type {
|
||||
/**
|
||||
* 1: BATT low, 0: normal
|
||||
*/
|
||||
LOW_HIGH,
|
||||
|
||||
/**
|
||||
* level0~5,<=1 for BATT low
|
||||
*/
|
||||
LEVEL,
|
||||
|
||||
/**
|
||||
* level0~6,<=1 for BATT low, 6 = dc power supply
|
||||
*/
|
||||
LEVEL_OR_DC,
|
||||
|
||||
/**
|
||||
* val * 0.1v
|
||||
*/
|
||||
VOLTAGE_BROAD_STEPS,
|
||||
|
||||
/**
|
||||
* val*0.02V if v<=1.2V BATT low
|
||||
*/
|
||||
VOLTAGE_FINE_STEPS
|
||||
}
|
||||
|
||||
private @Nullable Integer level;
|
||||
private @Nullable Double voltage;
|
||||
private final boolean low;
|
||||
private boolean dc;
|
||||
|
||||
public BatteryStatus(Type type, byte data) {
|
||||
int value = toUInt8(data);
|
||||
double voltage;
|
||||
switch (type) {
|
||||
case LOW_HIGH:
|
||||
low = value == 1;
|
||||
break;
|
||||
case LEVEL:
|
||||
level = value;
|
||||
low = value <= 1;
|
||||
break;
|
||||
case LEVEL_OR_DC:
|
||||
dc = value == 6;
|
||||
level = value;
|
||||
low = value <= 1;
|
||||
break;
|
||||
case VOLTAGE_BROAD_STEPS:
|
||||
this.voltage = voltage = value * 0.1;
|
||||
low = voltage <= 1.2;
|
||||
break;
|
||||
case VOLTAGE_FINE_STEPS:
|
||||
this.voltage = voltage = value * 0.02;
|
||||
low = voltage <= 1.2;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return level 0 - 5 or null f not available
|
||||
*/
|
||||
public @Nullable Integer getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return voltage of the battery or null if not available
|
||||
*/
|
||||
public @Nullable Double getVoltage() {
|
||||
return voltage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if the battery is low
|
||||
*/
|
||||
public boolean isLow() {
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true, if device is DC connected
|
||||
*/
|
||||
public boolean isDc() {
|
||||
return dc;
|
||||
}
|
||||
|
||||
public @Nullable Integer getPercentage() {
|
||||
if (dc) {
|
||||
return 100;
|
||||
}
|
||||
Integer currentLevel = level;
|
||||
if (currentLevel != null) {
|
||||
return (currentLevel * 100 / 5);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String status = low ? "LOW" : "OK";
|
||||
if (dc) {
|
||||
return "DC connected";
|
||||
}
|
||||
if (voltage != null) {
|
||||
return "Battery " + voltage + " V " + status;
|
||||
}
|
||||
if (level != null) {
|
||||
return "Battery " + level + "/ 5" + " " + status;
|
||||
}
|
||||
return "Battery " + status;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain.response;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.MeasureType;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* A certain measured value.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MeasuredValue {
|
||||
private final MeasureType measureType;
|
||||
private final String channelId;
|
||||
private final @Nullable ChannelTypeUID channelTypeUID;
|
||||
private final State state;
|
||||
private final String debugName;
|
||||
|
||||
public MeasuredValue(MeasureType measureType, String channelId, @Nullable ChannelTypeUID channelTypeUID,
|
||||
State state, String debugName) {
|
||||
this.measureType = measureType;
|
||||
this.channelId = channelId;
|
||||
this.channelTypeUID = channelTypeUID;
|
||||
this.state = state;
|
||||
this.debugName = debugName;
|
||||
}
|
||||
|
||||
public MeasureType getMeasureType() {
|
||||
return measureType;
|
||||
}
|
||||
|
||||
public String getChannelId() {
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public @Nullable ChannelTypeUID getChannelTypeUID() {
|
||||
return channelTypeUID;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getDebugName() {
|
||||
return debugName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MeasuredValue{" + "measureType=" + measureType + ", channelId='" + channelId + '\''
|
||||
+ ", channelTypeUID=" + channelTypeUID + ", state=" + state + ", debugName='" + debugName + '\'' + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain.response;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding;
|
||||
|
||||
/**
|
||||
* HHolds all available information of a sensor device.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SensorDevice {
|
||||
private final int id;
|
||||
private final SensorGatewayBinding sensorGatewayBinding;
|
||||
private final BatteryStatus batteryStatus;
|
||||
private final int signal;
|
||||
|
||||
public SensorDevice(int id, SensorGatewayBinding sensorGatewayBinding, BatteryStatus batteryStatus, int signal) {
|
||||
this.id = id;
|
||||
this.sensorGatewayBinding = sensorGatewayBinding;
|
||||
this.batteryStatus = batteryStatus;
|
||||
this.signal = signal;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public SensorGatewayBinding getSensorGatewayBinding() {
|
||||
return sensorGatewayBinding;
|
||||
}
|
||||
|
||||
public BatteryStatus getBatteryStatus() {
|
||||
return batteryStatus;
|
||||
}
|
||||
|
||||
public int getSignal() {
|
||||
return signal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SensorDevice{" + "id=" + id + ", sensor=" + sensorGatewayBinding + ", batteryStatus=" + batteryStatus
|
||||
+ ", signal=" + signal + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.domain.response;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Information about the gateway
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SystemInfo {
|
||||
/**
|
||||
* in MHz
|
||||
*/
|
||||
private final @Nullable Integer frequency;
|
||||
private final LocalDateTime dateTime;
|
||||
/**
|
||||
* Daylight saving time
|
||||
*/
|
||||
private final boolean dst;
|
||||
private final boolean useWh24;
|
||||
|
||||
public SystemInfo(@Nullable Integer frequency, LocalDateTime dateTime, boolean dst, boolean useWh24) {
|
||||
this.frequency = frequency;
|
||||
this.dateTime = dateTime;
|
||||
this.dst = dst;
|
||||
this.useWh24 = useWh24;
|
||||
}
|
||||
|
||||
public @Nullable Integer getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public LocalDateTime getDateTime() {
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
public boolean isDst() {
|
||||
return dst;
|
||||
}
|
||||
|
||||
public boolean isUseWh24() {
|
||||
return useWh24;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SystemInfo{" + "frequency=" + frequency + " MHz" + ", dateTime=" + dateTime + ", dst=" + dst
|
||||
+ ", useWh24=" + useWh24 + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.handler;
|
||||
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.THING_TYPE_GATEWAY;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants.THING_TYPE_SENSOR;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetGatewayConfiguration;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetSensorConfiguration;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.discovery.FineOffsetGatewayDiscoveryService;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.ConversionContext;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SensorDevice;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SystemInfo;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.service.FineOffsetGatewayQueryService;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.i18n.TimeZoneProvider;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
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.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.builder.BridgeBuilder;
|
||||
import org.openhab.core.thing.binding.builder.ChannelBuilder;
|
||||
import org.openhab.core.thing.type.ChannelKind;
|
||||
import org.openhab.core.thing.type.ChannelType;
|
||||
import org.openhab.core.thing.type.ChannelTypeRegistry;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link FineOffsetGatewayHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FineOffsetGatewayHandler extends BaseBridgeHandler {
|
||||
|
||||
private static final String PROPERTY_FREQUENCY = "frequency";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FineOffsetGatewayHandler.class);
|
||||
private final Bundle bundle;
|
||||
private final ConversionContext conversionContext;
|
||||
|
||||
private @Nullable FineOffsetGatewayQueryService gatewayQueryService;
|
||||
|
||||
private final FineOffsetGatewayDiscoveryService gatewayDiscoveryService;
|
||||
private final ChannelTypeRegistry channelTypeRegistry;
|
||||
private final TranslationProvider translationProvider;
|
||||
private final LocaleProvider localeProvider;
|
||||
|
||||
private final ThingUID bridgeUID;
|
||||
|
||||
private @Nullable Map<SensorGatewayBinding, SensorDevice> sensorDeviceMap;
|
||||
private @Nullable ScheduledFuture<?> pollingJob;
|
||||
private @Nullable ScheduledFuture<?> discoverJob;
|
||||
private boolean disposed;
|
||||
|
||||
public FineOffsetGatewayHandler(Bridge bridge, FineOffsetGatewayDiscoveryService gatewayDiscoveryService,
|
||||
ChannelTypeRegistry channelTypeRegistry, TranslationProvider translationProvider,
|
||||
LocaleProvider localeProvider, TimeZoneProvider timeZoneProvider) {
|
||||
super(bridge);
|
||||
bridgeUID = bridge.getUID();
|
||||
this.gatewayDiscoveryService = gatewayDiscoveryService;
|
||||
this.channelTypeRegistry = channelTypeRegistry;
|
||||
this.translationProvider = translationProvider;
|
||||
this.localeProvider = localeProvider;
|
||||
this.bundle = FrameworkUtil.getBundle(FineOffsetGatewayDiscoveryService.class);
|
||||
this.conversionContext = new ConversionContext(timeZoneProvider.getTimeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
FineOffsetGatewayConfiguration config = getConfigAs(FineOffsetGatewayConfiguration.class);
|
||||
gatewayQueryService = new FineOffsetGatewayQueryService(config, this::updateStatus, conversionContext);
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
fetchAndUpdateSensors();
|
||||
disposed = false;
|
||||
updateBridgeInfo();
|
||||
startDiscoverJob();
|
||||
startPollingJob();
|
||||
}
|
||||
|
||||
private void fetchAndUpdateSensors() {
|
||||
@Nullable
|
||||
Map<SensorGatewayBinding, SensorDevice> deviceMap = query(FineOffsetGatewayQueryService::getRegisteredSensors);
|
||||
sensorDeviceMap = deviceMap;
|
||||
updateSensors();
|
||||
if (deviceMap != null) {
|
||||
gatewayDiscoveryService.addSensors(bridgeUID, deviceMap.values());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSensors() {
|
||||
((Bridge) thing).getThings().forEach(this::updateSensorThing);
|
||||
}
|
||||
|
||||
private void updateSensorThing(Thing thing) {
|
||||
Map<SensorGatewayBinding, SensorDevice> sensorMap = sensorDeviceMap;
|
||||
if (!THING_TYPE_SENSOR.equals(thing.getThingTypeUID()) || sensorMap == null) {
|
||||
return;
|
||||
}
|
||||
SensorGatewayBinding sensor = thing.getConfiguration().as(FineOffsetSensorConfiguration.class).sensor;
|
||||
Optional.ofNullable(thing.getHandler()).filter(FineOffsetSensorHandler.class::isInstance)
|
||||
.map(FineOffsetSensorHandler.class::cast)
|
||||
.ifPresent(sensorHandler -> sensorHandler.updateSensorState(sensorMap.get(sensor)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
|
||||
updateSensorThing(childThing);
|
||||
}
|
||||
|
||||
private void updateLiveData() {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
List<MeasuredValue> data = query(FineOffsetGatewayQueryService::getLiveData);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Channel> channels = new ArrayList<>();
|
||||
for (MeasuredValue measuredValue : data) {
|
||||
@Nullable
|
||||
Channel channel = thing.getChannel(measuredValue.getChannelId());
|
||||
if (channel == null) {
|
||||
channel = createChannel(measuredValue);
|
||||
if (channel != null) {
|
||||
channels.add(channel);
|
||||
}
|
||||
} else {
|
||||
State state = measuredValue.getState();
|
||||
updateState(channel.getUID(), state);
|
||||
}
|
||||
}
|
||||
if (!channels.isEmpty()) {
|
||||
updateThing(editThing().withChannels(channels).build());
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable Channel createChannel(MeasuredValue measuredValue) {
|
||||
ChannelTypeUID channelTypeId = measuredValue.getChannelTypeUID();
|
||||
if (channelTypeId == null) {
|
||||
logger.debug("cannot create channel for {}", measuredValue.getDebugName());
|
||||
return null;
|
||||
}
|
||||
ChannelBuilder builder = ChannelBuilder.create(new ChannelUID(thing.getUID(), measuredValue.getChannelId()))
|
||||
.withKind(ChannelKind.STATE).withType(channelTypeId);
|
||||
String channelKey = "thing-type." + FineOffsetWeatherStationBindingConstants.BINDING_ID + "."
|
||||
+ THING_TYPE_GATEWAY.getId() + ".channel." + measuredValue.getChannelId();
|
||||
String label = translationProvider.getText(bundle, channelKey + ".label", measuredValue.getDebugName(),
|
||||
localeProvider.getLocale());
|
||||
if (label != null) {
|
||||
builder.withLabel(label);
|
||||
}
|
||||
String description = translationProvider.getText(bundle, channelKey + ".description", null,
|
||||
localeProvider.getLocale());
|
||||
if (description != null) {
|
||||
builder.withDescription(description);
|
||||
}
|
||||
@Nullable
|
||||
ChannelType type = channelTypeRegistry.getChannelType(channelTypeId);
|
||||
if (type != null) {
|
||||
builder.withAcceptedItemType(type.getItemType());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void updateBridgeInfo() {
|
||||
@Nullable
|
||||
String firmware = query(FineOffsetGatewayQueryService::getFirmwareVersion);
|
||||
Map<String, String> properties = new HashMap<>(thing.getProperties());
|
||||
if (firmware != null) {
|
||||
var fwString = firmware.split("_V");
|
||||
if (fwString.length > 1) {
|
||||
properties.put(Thing.PROPERTY_MODEL_ID, fwString[0]);
|
||||
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, fwString[1]);
|
||||
}
|
||||
}
|
||||
|
||||
SystemInfo systemInfo = query(FineOffsetGatewayQueryService::fetchSystemInfo);
|
||||
if (systemInfo != null && systemInfo.getFrequency() != null) {
|
||||
properties.put(PROPERTY_FREQUENCY, systemInfo.getFrequency() + " MHz");
|
||||
}
|
||||
if (!thing.getProperties().equals(properties)) {
|
||||
BridgeBuilder bridge = editThing();
|
||||
bridge.withProperties(properties);
|
||||
updateThing(bridge.build());
|
||||
}
|
||||
}
|
||||
|
||||
private void startDiscoverJob() {
|
||||
ScheduledFuture<?> job = discoverJob;
|
||||
if (job == null || job.isCancelled()) {
|
||||
int discoverInterval = thing.getConfiguration().as(FineOffsetGatewayConfiguration.class).discoverInterval;
|
||||
discoverJob = scheduler.scheduleWithFixedDelay(this::fetchAndUpdateSensors, 0, discoverInterval,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopDiscoverJob() {
|
||||
ScheduledFuture<?> job = this.discoverJob;
|
||||
if (job != null) {
|
||||
job.cancel(true);
|
||||
}
|
||||
this.discoverJob = null;
|
||||
}
|
||||
|
||||
private void startPollingJob() {
|
||||
ScheduledFuture<?> job = pollingJob;
|
||||
if (job == null || job.isCancelled()) {
|
||||
int pollingInterval = thing.getConfiguration().as(FineOffsetGatewayConfiguration.class).pollingInterval;
|
||||
pollingJob = scheduler.scheduleWithFixedDelay(this::updateLiveData, 5, pollingInterval, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void stopPollingJob() {
|
||||
ScheduledFuture<?> job = this.pollingJob;
|
||||
if (job != null) {
|
||||
job.cancel(true);
|
||||
}
|
||||
this.pollingJob = null;
|
||||
}
|
||||
|
||||
private <T> @Nullable T query(Function<FineOffsetGatewayQueryService, T> delegate) {
|
||||
@Nullable
|
||||
FineOffsetGatewayQueryService queryService = this.gatewayQueryService;
|
||||
if (queryService == null) {
|
||||
return null;
|
||||
}
|
||||
return delegate.apply(queryService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposed = true;
|
||||
@Nullable
|
||||
FineOffsetGatewayQueryService queryService = this.gatewayQueryService;
|
||||
if (queryService != null) {
|
||||
try {
|
||||
queryService.close();
|
||||
} catch (IOException e) {
|
||||
logger.debug("failed to close queryService", e);
|
||||
}
|
||||
}
|
||||
this.gatewayQueryService = null;
|
||||
this.sensorDeviceMap = null;
|
||||
stopPollingJob();
|
||||
stopDiscoverJob();
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.handler;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWeatherStationBindingConstants;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SensorDevice;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link FineOffsetSensorHandler} keeps track of the signal and battery of the sensor attached to the gateway.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FineOffsetSensorHandler extends BaseThingHandler {
|
||||
private boolean disposed;
|
||||
|
||||
public FineOffsetSensorHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
disposed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public void updateSensorState(@Nullable SensorDevice sensorDevice) {
|
||||
if (disposed) {
|
||||
return;
|
||||
}
|
||||
if (sensorDevice == null) {
|
||||
updateStatus(ThingStatus.OFFLINE);
|
||||
return;
|
||||
}
|
||||
if (sensorDevice.getSignal() == 0) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
} else {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
updateState(FineOffsetWeatherStationBindingConstants.SENSOR_CHANNEL_SIGNAL,
|
||||
new DecimalType(sensorDevice.getSignal()));
|
||||
updateState(FineOffsetWeatherStationBindingConstants.SENSOR_CHANNEL_LOW_BATTERY,
|
||||
sensorDevice.getBatteryStatus().isLow() ? OnOffType.ON : OnOffType.OFF);
|
||||
Integer percentage = sensorDevice.getBatteryStatus().getPercentage();
|
||||
if (percentage != null) {
|
||||
updateState(FineOffsetWeatherStationBindingConstants.SENSOR_CHANNEL_BATTERY_LEVEL,
|
||||
new DecimalType(new BigDecimal(percentage)));
|
||||
} else {
|
||||
@Nullable
|
||||
Channel channel = thing.getChannel(FineOffsetWeatherStationBindingConstants.SENSOR_CHANNEL_BATTERY_LEVEL);
|
||||
if (channel != null) {
|
||||
updateThing(editThing().withoutChannels(channel).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
|
||||
/**
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ThingStatusListener {
|
||||
|
||||
void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description);
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.service;
|
||||
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toUInt16;
|
||||
import static org.openhab.binding.fineoffsetweatherstation.internal.Utils.toUInt32;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.Utils;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.ConversionContext;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.Measurand;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SensorDevice;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SystemInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Class to Convert the protocol data
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FineOffsetDataParser {
|
||||
private final Logger logger = LoggerFactory.getLogger(FineOffsetDataParser.class);
|
||||
|
||||
public @Nullable String getFirmwareVersion(byte[] data) {
|
||||
if (data.length > 0) {
|
||||
return new String(data, 5, data[4]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<SensorGatewayBinding, SensorDevice> getRegisteredSensors(byte[] data,
|
||||
Supplier<@Nullable Boolean> isUseWh24) {
|
||||
/*
|
||||
* Pos | Length | Description
|
||||
* -------------------------------------------------
|
||||
* 0 | 2 | fixed header (0xffff)
|
||||
* 2 | 1 | command (0x3c)
|
||||
* 3 | 2 | size
|
||||
* -------------------------------------------------
|
||||
* (n * 7) + 5 | 1 | index of sensor n
|
||||
* (n * 7) + 6 | 4 | id of sensor n
|
||||
* (n * 7) + 10 | 1 | battery status of sensor n
|
||||
* (n * 7) + 11 | 1 | signal of sensor n
|
||||
* -------------------------------------------------
|
||||
* (n * 7) + 12 | 1 | checksum
|
||||
*/
|
||||
|
||||
Map<SensorGatewayBinding, SensorDevice> result = new HashMap<>();
|
||||
var len = toUInt16(data, 3);
|
||||
int entry = 0;
|
||||
int entrySize = 7;
|
||||
while (entry * entrySize + 11 <= len) {
|
||||
int idx = entry++ * entrySize + 5;
|
||||
int id = toUInt32(data, idx + 1);
|
||||
List<SensorGatewayBinding> sensorCandidates = SensorGatewayBinding.forIndex(data[idx]);
|
||||
if (sensorCandidates == null || sensorCandidates.isEmpty()) {
|
||||
logger.debug("unknown sensor (id={}) for index {}", id, data[idx]);
|
||||
continue;
|
||||
}
|
||||
SensorGatewayBinding sensorGatewayBinding = null;
|
||||
if (sensorCandidates.size() == 1) {
|
||||
sensorGatewayBinding = sensorCandidates.get(0);
|
||||
} else if (sensorCandidates.size() == 2 && data[idx] == 0) {
|
||||
sensorGatewayBinding = Boolean.TRUE.equals(isUseWh24.get()) ? SensorGatewayBinding.WH24
|
||||
: SensorGatewayBinding.WH65;
|
||||
}
|
||||
if (sensorGatewayBinding == null) {
|
||||
logger.debug("too many sensor candidates for (id={}) and index {}: {}", id, data[idx],
|
||||
sensorCandidates);
|
||||
continue;
|
||||
}
|
||||
switch (id) {
|
||||
case 0xFFFFFFFE:
|
||||
logger.trace("sensor {} = disabled", sensorGatewayBinding);
|
||||
continue;
|
||||
case 0xFFFFFFFF:
|
||||
logger.trace("sensor {} = registering", sensorGatewayBinding);
|
||||
continue;
|
||||
}
|
||||
|
||||
BatteryStatus batteryStatus = sensorGatewayBinding.getBatteryStatus(data[idx + 5]);
|
||||
int signal = Utils.toUInt8(data[idx + 6]);
|
||||
|
||||
result.put(sensorGatewayBinding, new SensorDevice(id, sensorGatewayBinding, batteryStatus, signal));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public @Nullable SystemInfo fetchSystemInfo(byte[] data) {
|
||||
// expected response
|
||||
// 0 - 0xff - header
|
||||
// 1 - 0xff - header
|
||||
// 2 - 0x30 - system info
|
||||
// 3 - 0x?? - size of response
|
||||
// 4 - frequency - 0=433, 1=868MHz, 2=915MHz, 3=920MHz
|
||||
// 5 - sensor type - 0=WH24, 1=WH65
|
||||
// 6-9 - UTC time
|
||||
// 10 - time zone index (?)
|
||||
// 11 - DST 0-1 - false/true
|
||||
// 12 - 0x?? - checksum
|
||||
Integer frequency = null;
|
||||
switch (data[4]) {
|
||||
case 0:
|
||||
frequency = 433;
|
||||
break;
|
||||
case 1:
|
||||
frequency = 868;
|
||||
break;
|
||||
case 2:
|
||||
frequency = 915;
|
||||
break;
|
||||
case 3:
|
||||
frequency = 920;
|
||||
break;
|
||||
|
||||
}
|
||||
boolean useWh24 = data[5] == 0;
|
||||
var unix = toUInt32(data, 6);
|
||||
var date = LocalDateTime.ofEpochSecond(unix, 0, ZoneOffset.UTC);
|
||||
var dst = data[11] != 0;
|
||||
return new SystemInfo(frequency, date, dst, useWh24);
|
||||
}
|
||||
|
||||
List<MeasuredValue> getLiveData(byte[] data, ConversionContext context) {
|
||||
/*
|
||||
* Pos| Length | Description
|
||||
* -------------------------------------------------
|
||||
* 0 | 2 | fixed header (0xffff)
|
||||
* 2 | 1 | command (0x27)
|
||||
* 3 | 2 | size
|
||||
* -------------------------------------------------
|
||||
* 5 | 1 | code of item (item defines n)
|
||||
* 6 | n | value of item
|
||||
* -------------------------------------------------
|
||||
* 6 + n | 1 | code of item (item defines m)
|
||||
* 7 + n | m | value of item
|
||||
* -------------------------------------------------
|
||||
* ...
|
||||
* -------------------------------------------------
|
||||
*
|
||||
* | 1 | checksum
|
||||
*/
|
||||
var idx = 5;
|
||||
var size = toUInt16(data, 3);
|
||||
List<MeasuredValue> result = new ArrayList<>();
|
||||
while (idx < size) {
|
||||
byte code = data[idx++];
|
||||
Measurand measurand = Measurand.getByCode(code);
|
||||
if (measurand == null) {
|
||||
logger.warn("failed to get measurand 0x{}", Integer.toHexString(code));
|
||||
return result;
|
||||
}
|
||||
idx += measurand.extractMeasuredValues(data, idx, context, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetGatewayConfiguration;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.Utils;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.Command;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.ConversionContext;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SensorDevice;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.SystemInfo;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.handler.ThingStatusListener;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service to query the gateway device.
|
||||
*
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FineOffsetGatewayQueryService implements AutoCloseable {
|
||||
private final Logger logger = LoggerFactory.getLogger(FineOffsetGatewayQueryService.class);
|
||||
|
||||
private @Nullable Socket socket;
|
||||
private final FineOffsetGatewayConfiguration config;
|
||||
private final ThingStatusListener thingStatusListener;
|
||||
private final FineOffsetDataParser fineOffsetDataParser;
|
||||
|
||||
private final ConversionContext conversionContext;
|
||||
|
||||
public FineOffsetGatewayQueryService(FineOffsetGatewayConfiguration config, ThingStatusListener thingStatusListener,
|
||||
ConversionContext conversionContext) {
|
||||
this.config = config;
|
||||
this.thingStatusListener = thingStatusListener;
|
||||
this.fineOffsetDataParser = new FineOffsetDataParser();
|
||||
this.conversionContext = conversionContext;
|
||||
}
|
||||
|
||||
public @Nullable String getFirmwareVersion() {
|
||||
var data = executeCommand(Command.CMD_READ_FIRMWARE_VERSION);
|
||||
if (null != data) {
|
||||
return fineOffsetDataParser.getFirmwareVersion(data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<SensorGatewayBinding, SensorDevice> getRegisteredSensors() {
|
||||
var data = executeCommand(Command.CMD_READ_SENSOR_ID_NEW);
|
||||
if (null == data) {
|
||||
return Map.of();
|
||||
}
|
||||
return fineOffsetDataParser.getRegisteredSensors(data, () -> {
|
||||
@Nullable
|
||||
SystemInfo systemInfo = fetchSystemInfo();
|
||||
if (systemInfo != null) {
|
||||
return systemInfo.isUseWh24();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public @Nullable SystemInfo fetchSystemInfo() {
|
||||
var data = executeCommand(Command.CMD_READ_SSSS);
|
||||
if (data == null) {
|
||||
logger.debug("Unexpected response to System Info!");
|
||||
return null;
|
||||
}
|
||||
return fineOffsetDataParser.fetchSystemInfo(data);
|
||||
}
|
||||
|
||||
public List<MeasuredValue> getLiveData() {
|
||||
byte[] data = executeCommand(Command.CMD_GW1000_LIVEDATA);
|
||||
if (data == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return fineOffsetDataParser.getLiveData(data, conversionContext);
|
||||
}
|
||||
|
||||
private synchronized byte @Nullable [] executeCommand(Command command) {
|
||||
byte[] buffer = new byte[2028];
|
||||
int bytesRead;
|
||||
byte[] request = command.getPayload();
|
||||
|
||||
try {
|
||||
Socket socket = getConnection();
|
||||
if (socket == null) {
|
||||
return null;
|
||||
}
|
||||
InputStream in = socket.getInputStream();
|
||||
socket.getOutputStream().write(request);
|
||||
if ((bytesRead = in.read(buffer)) == -1) {
|
||||
return null;
|
||||
}
|
||||
if (!command.isResponseValid(buffer)) {
|
||||
if (bytesRead > 0) {
|
||||
logger.debug("executeCommand({}), invalid response: {}", command,
|
||||
Utils.toHexString(buffer, bytesRead, ""));
|
||||
} else {
|
||||
logger.debug("executeCommand({}): no response", command);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (IOException ex) {
|
||||
thingStatusListener.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
ex.getMessage());
|
||||
try {
|
||||
close();
|
||||
} catch (IOException e) {
|
||||
// ignored
|
||||
}
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
logger.warn("executeCommand({})", command, ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = Arrays.copyOfRange(buffer, 0, bytesRead);
|
||||
logger.trace("executeCommand({}): received: {}", command, Utils.toHexString(data, data.length, ""));
|
||||
return data;
|
||||
}
|
||||
|
||||
private synchronized @Nullable Socket getConnection() {
|
||||
Socket socket = this.socket;
|
||||
if (socket == null) {
|
||||
try {
|
||||
socket = new Socket(config.ip, config.port);
|
||||
socket.setSoTimeout(5000);
|
||||
this.socket = socket;
|
||||
thingStatusListener.updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
} catch (IOException e) {
|
||||
thingStatusListener.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Socket socket = this.socket;
|
||||
this.socket = null;
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="fineoffsetweatherstation" 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>Fine Offset Weather Station</name>
|
||||
<description>A binding for the Weather Stations Manufactured by Fine Offset</description>
|
||||
|
||||
</binding:binding>
|
@ -0,0 +1,40 @@
|
||||
<?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:fineoffsetweatherstation:gateway">
|
||||
<parameter name="ip" type="text" required="true">
|
||||
<label>IP Address</label>
|
||||
<description>The Hostname or IP address of the device</description>
|
||||
<context>network-address</context>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" required="true">
|
||||
<label>Port</label>
|
||||
<description>The network port of the gateway</description>
|
||||
<default>45000</default>
|
||||
</parameter>
|
||||
<parameter name="pollingInterval" type="integer" required="true">
|
||||
<label>Polling Interval</label>
|
||||
<description>Polling interval for refreshing the data in seconds</description>
|
||||
<default>16</default>
|
||||
<unitLabel>s</unitLabel>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="discoverInterval" type="integer" required="true">
|
||||
<label>Discover Interval</label>
|
||||
<description>Interval in seconds to fetch registered sensors, battery status and signal strength</description>
|
||||
<unitLabel>s</unitLabel>
|
||||
<default>900</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:fineoffsetweatherstation:sensor">
|
||||
<parameter name="sensor" type="text" required="true">
|
||||
<label>Sensor</label>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
@ -0,0 +1,187 @@
|
||||
# binding
|
||||
|
||||
binding.fineoffsetweatherstation.name = Fine Offset Weather Station
|
||||
binding.fineoffsetweatherstation.description = A binding for the Weather Stations Manufactured by Fine Offset
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.fineoffsetweatherstation.gateway.label = Gateway Device
|
||||
thing-type.fineoffsetweatherstation.gateway.description = A WiFi connected gateway device (WN1900, GW1000, GW1100, WH2680, WH2650) to bridge Sensors
|
||||
thing-type.fineoffsetweatherstation.sensor.label = Sensor Device
|
||||
thing-type.fineoffsetweatherstation.sensor.description = A Sensor connected to the gateway (WN1900, GW1000, GW1100, WH2680, WH2650)
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.fineoffsetweatherstation.gateway.discoverInterval.label = Discover Interval
|
||||
thing-type.config.fineoffsetweatherstation.gateway.discoverInterval.description = Interval in seconds to fetch registered sensors, battery status and signal strength
|
||||
thing-type.config.fineoffsetweatherstation.gateway.ip.label = IP Address
|
||||
thing-type.config.fineoffsetweatherstation.gateway.ip.description = The Hostname or IP address of the device
|
||||
thing-type.config.fineoffsetweatherstation.gateway.pollingInterval.label = Polling Interval
|
||||
thing-type.config.fineoffsetweatherstation.gateway.pollingInterval.description = Polling interval for refreshing the data in seconds
|
||||
thing-type.config.fineoffsetweatherstation.gateway.port.label = Port
|
||||
thing-type.config.fineoffsetweatherstation.gateway.port.description = The network port of the gateway
|
||||
thing-type.config.fineoffsetweatherstation.sensor.sensor.label = Sensor
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.fineoffsetweatherstation.co2.label = CO₂
|
||||
channel-type.fineoffsetweatherstation.co2.description = Air quality indicator
|
||||
channel-type.fineoffsetweatherstation.humidity.label = Humidity
|
||||
channel-type.fineoffsetweatherstation.illumination.label = Illumination
|
||||
channel-type.fineoffsetweatherstation.lightning-counter.label = Lightning Counter
|
||||
channel-type.fineoffsetweatherstation.lightning-distance.label = Lightning Distance
|
||||
channel-type.fineoffsetweatherstation.lightning-time.label = Lightning Time
|
||||
channel-type.fineoffsetweatherstation.max-wind-speed.label = Maximum Wind Speed
|
||||
channel-type.fineoffsetweatherstation.moisture.label = Moisture
|
||||
channel-type.fineoffsetweatherstation.pm10.label = PM10 Air Quality
|
||||
channel-type.fineoffsetweatherstation.pm25.label = PM2.5 Air Quality
|
||||
channel-type.fineoffsetweatherstation.pressure.label = Pressure
|
||||
channel-type.fineoffsetweatherstation.rain-rate.label = Rain Rate
|
||||
channel-type.fineoffsetweatherstation.rain.label = Rain
|
||||
channel-type.fineoffsetweatherstation.temperature.label = Temperature
|
||||
channel-type.fineoffsetweatherstation.uv-index.label = UV-Index
|
||||
channel-type.fineoffsetweatherstation.uv-radiation.label = UV-Irradiation
|
||||
channel-type.fineoffsetweatherstation.water-leak-detection.label = Water Leak Detection
|
||||
|
||||
channel = Channel
|
||||
thing.gateway.label = Weather Station
|
||||
thing.sensor.WH24.label = Weather Station - Outdoor Unit
|
||||
thing.sensor.WH24.description = Sensor for Wind Speed & Direction, Solar Radiation & Light, Temperature, Humidity, Rainfall
|
||||
thing.sensor.WH25.label = Sensor for Temperature, Humidity and Pressure
|
||||
thing.sensor.WH25.description = Multi-Channel Sensor for Temperature, Humidity and pressure
|
||||
thing.sensor.WH26.label = Sensor for Temperature and Humidity
|
||||
thing.sensor.WH26.description = Multi-Channel Sensor for Temperature and Humidity
|
||||
thing.sensor.WH31.label = Sensor for Temperature and Humidity
|
||||
thing.sensor.WH31.description = Multi-Channel Sensor for Temperature and Humidity
|
||||
thing.sensor.WH34.label = Temperature Sensor with external probe
|
||||
thing.sensor.WH35.label = Leaf Wetness Sensor
|
||||
thing.sensor.WH40.label = Rainfall Sensor
|
||||
thing.sensor.WH41.label = Air Quality Sensor - outdoor
|
||||
thing.sensor.WH41.description = An outdoor PM2.5 Air Quality Sensor
|
||||
thing.sensor.WH45.label = Air Quality Sensor
|
||||
thing.sensor.WH45.description = 5-in-1 Air Quality Sensor for CO2, PM2.5, PM10, Temperature and Humidity
|
||||
thing.sensor.WH51.label = Soil Moisture Sensor
|
||||
thing.sensor.WH55.label = Water Leak Detection Sensor
|
||||
thing.sensor.WH57.label = Lightning Detection Sensor
|
||||
thing.sensor.WH65.label = Weather Station - outdoor unit
|
||||
thing.sensor.WH65.description = Sensor for Wind Speed & Direction, Solar Radiation & Light, Temperature, Humidity and Rainfall
|
||||
thing.sensor.WH68.label = Weather Station - outdoor unit
|
||||
thing.sensor.WH68.description = Solar-powered Sensor for Wind Speed & Direction, Solar Radiation & Light
|
||||
thing.sensor.WH80.label = Weather Station - outdoor unit
|
||||
thing.sensor.WH80.description = Ultrasonic Sensor for Wind Speed & Direction, Solar Radiation & Light, Temperature & Humidity
|
||||
thing.sensor.WH90.label = Weather Station - outdoor unit
|
||||
|
||||
# channels
|
||||
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-indoor.label = Indoor Temperature
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-outdoor.label = Outdoor Temperature
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-dew-point.label = Dew Point
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-wind-chill.label = Perceived Temperature
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-heat-index.label = Heat Index
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-indoor.label = Humidity Inside
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-outdoor.label = Humidity Outside
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.pressure-absolute.label = Absolute Pressure
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.pressure-relative.label = Relative Pressure
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.direction-wind.label = Wind Direction
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.speed-wind.label = Wind Speed
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.speed-gust.label = Gust Speed
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-event.label = Amount of Rainfall At the last Rain
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-rate.label = Rainfall Rate
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-hour.label = Rainfall Current Hour
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-day.label = Rainfall Today
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-week.label = Rainfall this Week
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-month.label = Rainfall this Month
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-year.label = Rainfall this Year
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-total.label = Rainfall Total
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.illumination.label = Light Intensity
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.irradiation-uv.label = UV Irradiation
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.uv-index.label = UV Index
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.time.label = Date and Time
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.wind-max-day.label = Maximum Wind Speed Today
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-1.label = Temperature Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-2.label = Temperature Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-3.label = Temperature Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-4.label = Temperature Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-5.label = Temperature Channel 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-6.label = Temperature Channel 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-7.label = Temperature Channel 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-8.label = Temperature Channel 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-1.label = Humidity Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-2.label = Humidity Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-3.label = Humidity Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-4.label = Humidity Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-5.label = Humidity Channel 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-6.label = Humidity Channel 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-7.label = Humidity Channel 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-8.label = Humidity Channel 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-1.label = Soil Temperature Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-2.label = Soil Temperature Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-3.label = Soil Temperature Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-4.label = Soil Temperature Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-5.label = Soil Temperature Channel 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-6.label = Soil Temperature Channel 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-7.label = Soil Temperature Channel 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-8.label = Soil Temperature Channel 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-9.label = Soil Temperature Channel 9
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-10.label = Soil Temperature Channel 10
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-11.label = Soil Temperature Channel 11
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-12.label = Soil Temperature Channel 12
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-13.label = Soil Temperature Channel 13
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-14.label = Soil Temperature Channel 14
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-15.label = Soil Temperature Channel 15
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-16.label = Soil Temperature Channel 16
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-1.label = Soil Moisture Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-2.label = Soil Moisture Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-3.label = Soil Moisture Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-4.label = soil Moisture Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-5.label = Soil Moisture Channel 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-6.label = Soil Moisture Channel 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-7.label = Soil Moisture Channel 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-8.label = Soil Moisture Channel 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-9.label = Soil Moisture Channel 9
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-10.label = Soil Moisture Channel 10
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-11.label = Soil Moisture Channel 11
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-12.label = Soil Moisture Channel 12
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-13.label = soil Moisture Channel 13
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-14.label = Soil Moisture Channel 14
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-15.label = Soil Moisture Channel 15
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-16.label = Soil Moisture Channel 16
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-1.label = PM2.5 Air Quality 24 Hour Average Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-2.label = PM2.5 Air Quality 24 Hour Average Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-3.label = PM2.5 Air Quality 24 Hour Average Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-4.label = PM2.5 Air Quality 24 Hour Average Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-1.label = PM2.5 Air Quality Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-2.label = PM2.5 Air Quality Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-3.label = PM2.5 Air Quality Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-4.label = PM2.5 Air Quality Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-1.label = Water Leak Detection Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-2.label = Water Leak Detection Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-3.label = Water Leak Detection Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-4.label = Water Leak Detection Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.lightning-distance.label = Lightning Distance
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.lightning-time.label = Time of last Lightning Strike
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.lightning-counter.label = Lightning Strikes Today
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-1.label = External Temperature Sensor Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-2.label = External Temperature Sensor Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-3.label = External Temperature Sensor Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-4.label = External Temperature Sensor Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-5.label = External Temperature Sensor Channel 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-6.label = External Temperature Sensor Channel 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-7.label = External Temperature Sensor Channel 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-8.label = External Temperature Sensor Channel 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-temperature.label = Temperature (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-humidity.label = Humidity (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm10.label = PM10 Air Quality (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm10-24-hour-average.label = PM10 Air Quality 24 Hour Average (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm25.label = PM2.5 Air Quality (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm25-24-hour-average.label = PM2.5 Air Quality 24 Hour Average (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-co2.label = CO2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-co2-24-hour-average.label = CO2 24 Hour Average
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-1.label = Leaf Moisture Channel 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-2.label = Leaf Moisture Channel 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-3.label = Leaf Moisture Channel 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-4.label = Leaf Moisture Channel 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-5.label = Leaf Moisture Channel 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-6.label = Leaf Moisture Channel 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-7.label = Leaf Moisture Channel 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-8.label = Leaf Moisture Channel 8
|
@ -0,0 +1,183 @@
|
||||
# binding
|
||||
binding.fineoffsetweatherstation.name = Fine Offset Wetterstation
|
||||
binding.fineoffsetweatherstation.description = Eine Anbindung für die von Fine Offset hergestellten Wetterstationen
|
||||
|
||||
# thing types
|
||||
thing-type.fineoffsetweatherstation.gateway.label = Wetterstation
|
||||
thing-type.fineoffsetweatherstation.gateway.description = Ein mit WiFi verbundenes Gateway-Gerät (WN1900, GW1000, GW1100, WH2680, WH2650) zur Verbindung von Sensoren
|
||||
thing-type.fineoffsetweatherstation.sensor.label = Sensor
|
||||
thing-type.fineoffsetweatherstation.sensor.description = Ein mit dem Gateway verbundener Sensor (WN1900, GW1000, GW1100, WH2680, WH2650)
|
||||
|
||||
# thing types config
|
||||
thing-type.config.fineoffsetweatherstation.gateway.discoverInterval.label = Intervall in Sekunden zum Abrufen von registrierten Sensoren, Batteriestatus und Signalstärke
|
||||
thing-type.config.fineoffsetweatherstation.gateway.ip.label = IP-Adresse
|
||||
thing-type.config.fineoffsetweatherstation.gateway.ip.description = Der Hostname oder die IP-Adresse des Gateways
|
||||
thing-type.config.fineoffsetweatherstation.gateway.pollingInterval.label = Abfragezeitraum
|
||||
thing-type.config.fineoffsetweatherstation.gateway.pollingInterval.description = Abfragezeitraum für die Auffrischung der Daten in Sekunden
|
||||
thing-type.config.fineoffsetweatherstation.gateway.port.label = Port
|
||||
thing-type.config.fineoffsetweatherstation.gateway.port.description = Der Netzwerk-Port des Gateways
|
||||
thing-type.config.fineoffsetweatherstation.sensor.sensor.label = Sensor
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.fineoffsetweatherstation.co2.label = CO2
|
||||
channel-type.fineoffsetweatherstation.co2.description = Indikator für die Luftqualität
|
||||
channel-type.fineoffsetweatherstation.humidity.label = Luftfeuchtigkeit
|
||||
channel-type.fineoffsetweatherstation.illumination.label = Lichtstärke
|
||||
channel-type.fineoffsetweatherstation.lightning-counter.label = Anzahl Blitzschläge
|
||||
channel-type.fineoffsetweatherstation.lightning-distance.label = Gewitter Entfernung
|
||||
channel-type.fineoffsetweatherstation.lightning-time.label = Zeitpunkt des letzten Blitzschlags
|
||||
channel-type.fineoffsetweatherstation.max-wind-speed.label = Maximale Windgeschwindigkeit
|
||||
channel-type.fineoffsetweatherstation.moisture.label = Feuchtigkeit
|
||||
channel-type.fineoffsetweatherstation.pm10.label = PM10 Luftqualität
|
||||
channel-type.fineoffsetweatherstation.pm25.label = PM2.5 Luftqualität
|
||||
channel-type.fineoffsetweatherstation.pressure.label = Druck
|
||||
channel-type.fineoffsetweatherstation.rain-rate.label = Niederschlagsrate
|
||||
channel-type.fineoffsetweatherstation.rain.label = Niederschlagsmenge
|
||||
channel-type.fineoffsetweatherstation.temperature.label = Temperatur
|
||||
channel-type.fineoffsetweatherstation.uv-index.label = UV-Index
|
||||
channel-type.fineoffsetweatherstation.uv-radiation.label = UV-Strahlung
|
||||
channel-type.fineoffsetweatherstation.water-leak-detection.label = Wasserleckerkennung
|
||||
|
||||
channel=Kanal
|
||||
thing.gateway.label=Wetterstation
|
||||
thing.sensor.WH24.label=Wetterstation - Außeneinheit
|
||||
thing.sensor.WH24.description=Sensor für Windgeschwindigkeit & Richtung, Sonneneinstrahlung & Licht, Temperatur, Luftfeuchtigkeit, Niederschlag
|
||||
thing.sensor.WH25.label=Sensor für Temperatur, Luftfeuchtigkeit und Druck
|
||||
thing.sensor.WH25.description=Mehrkanalsensor für Temperatur, Feuchte und Druck
|
||||
thing.sensor.WH26.label=Sensor für Temperatur und Luftfeuchtigkeit
|
||||
thing.sensor.WH26.description=Mehrkanalsensor für Temperatur und Feuchte
|
||||
thing.sensor.WH31.label=Sensor für Temperatur und Feuchte
|
||||
thing.sensor.WH31.description=Mehrkanalsensor für Temperatur und Feuchte
|
||||
thing.sensor.WH34.label=Temperatursensor mit externem Fühler
|
||||
thing.sensor.WH35.label=Blattnässe-Sensor
|
||||
thing.sensor.WH40.label=Niederschlagssensor
|
||||
thing.sensor.WH41.label=Außenluftqualitätssensor
|
||||
thing.sensor.WH41.description=Ein Außenluftqualitätssensor für PM2,5
|
||||
thing.sensor.WH45.label=Luftqualitätssensor
|
||||
thing.sensor.WH45.description=5-in-1-Luftqualitätssensor für CO2, PM2.5, PM10, Temperatur und Feuchtigkeit
|
||||
thing.sensor.WH51.label=Bodenfeuchte-Sensor
|
||||
thing.sensor.WH55.label=Wasserleck-Sensor
|
||||
thing.sensor.WH57.label=Blitzerkennungs-Sensor
|
||||
thing.sensor.WH65.label=Wetterstation - Außeneinheit
|
||||
thing.sensor.WH65.description=Sensor für Windgeschwindigkeit & -richtung, Sonneneinstrahlung & Licht, Temperatur, Luftfeuchtigkeit und Niederschlag
|
||||
thing.sensor.WH68.label=Wetterstation - Außengerät
|
||||
thing.sensor.WH68.description=Solarbetriebener Sensor für Windgeschwindigkeit und -richtung, Sonneneinstrahlung und Licht
|
||||
thing.sensor.WH80.label=Wetterstation - Außengerät
|
||||
thing.sensor.WH80.description=Ultraschallsensor für Windgeschwindigkeit & -richtung, Sonneneinstrahlung & Licht, Temperatur & Feuchtigkeit
|
||||
thing.sensor.WH90.label=Wetterstation - Außengerät
|
||||
|
||||
# channels
|
||||
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-indoor.label = Innentemperatur
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-outdoor.label = Außentemperatur
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-dew-point.label = Taupunkt
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-wind-chill.label = Gefühlte Temperatur
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-heat-index.label = Wärmeindex
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-indoor.label = Luftfeuchtigkeit innen
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-outdoor.label = Luftfeuchtigkeit außen
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.pressure-absolute.label = Absoluter Druck
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.pressure-relative.label = Relativer Druck
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.direction-wind.label = Windrichtung
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.speed-wind.label = Windgeschwindigkeit
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.speed-gust.label = Böengeschwindigkeit
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-event.label = Niederschlagsmenge beim letzten Regen
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-rate.label = Niederschlagsrate
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-hour.label = Niederschlagsmenge aktuelle Stunde
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-day.label = Niederschlagsmenge Heute
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-week.label = Niederschlagsmenge diese Woche
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-month.label = Niederschlagsmenge diesen Monat
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-year.label = Niederschlagsmenge dieses Jahr
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.rain-total.label = Niederschlagsmenge gesamt
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.illumination.label = Lichtstärke
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.irradiation-uv.label = UV-Strahlung
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.uv-index.label = UV-Index
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.time.label = Datum und Uhrzeit
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.wind-max-day.label = Maximaler Windgeschwindigkeit heute
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-1.label = Temperatur Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-2.label = Temperatur Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-3.label = Temperatur Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-4.label = Temperatur Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-5.label = Temperatur Kanal 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-6.label = Temperatur Kanal 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-7.label = Temperatur Kanal 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-channel-8.label = Temperatur Kanal 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-1.label = Luftfeuchtigkeit Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-2.label = Luftfeuchtigkeit Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-3.label = Luftfeuchtigkeit Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-4.label = Luftfeuchtigkeit Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-5.label = Luftfeuchtigkeit Kanal 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-6.label = Luftfeuchtigkeit Kanal 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-7.label = Luftfeuchtigkeit Kanal 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.humidity-channel-8.label = Luftfeuchtigkeit Kanal 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-1.label = Bodentemperatur Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-2.label = Bodentemperatur Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-3.label = Bodentemperatur Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-4.label = Bodentemperatur Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-5.label = Bodentemperatur Kanal 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-6.label = Bodentemperatur Kanal 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-7.label = Bodentemperatur Kanal 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-8.label = Bodentemperatur Kanal 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-9.label = Bodentemperatur Kanal 9
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-10.label = Bodentemperatur Kanal 10
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-11.label = Bodentemperatur Kanal 11
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-12.label = Bodentemperatur Kanal 12
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-13.label = Bodentemperatur Kanal 13
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-14.label = Bodentemperatur Kanal 14
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-15.label = Bodentemperatur Kanal 15
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-soil-channel-16.label = Bodentemperatur Kanal 16
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-1.label = Bodenfeuchtigkeit Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-2.label = Bodenfeuchtigkeit Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-3.label = Bodenfeuchtigkeit Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-4.label = Bodenfeuchtigkeit Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-5.label = Bodenfeuchtigkeit Kanal 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-6.label = Bodenfeuchtigkeit Kanal 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-7.label = Bodenfeuchtigkeit Kanal 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-8.label = Bodenfeuchtigkeit Kanal 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-9.label = Bodenfeuchtigkeit Kanal 9
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-10.label = Bodenfeuchtigkeit Kanal 10
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-11.label = Bodenfeuchtigkeit Kanal 11
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-12.label = Bodenfeuchtigkeit Kanal 12
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-13.label = Bodenfeuchtigkeit Kanal 13
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-14.label = Bodenfeuchtigkeit Kanal 14
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-15.label = Bodenfeuchtigkeit Kanal 15
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.moisture-soil-channel-16.label = Bodenfeuchtigkeit Kanal 16
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-1.label = PM2.5 Luftqualität 24 Stunden Durchschnitt Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-2.label = PM2.5 Luftqualität 24 Stunden Durchschnitt Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-3.label = PM2.5 Luftqualität 24 Stunden Durchschnitt Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-24-hour-average-channel-4.label = PM2.5 Luftqualität 24 Stunden Durchschnitt Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-1.label = PM2.5 Luftqualität Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-2.label = PM2.5 Luftqualität Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-3.label = PM2.5 Luftqualität Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.air-quality-channel-4.label = PM2.5 Luftqualität Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-1.label = Wasserleckerkennung Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-2.label = Wasserleckerkennung Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-3.label = Wasserleckerkennung Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.water-leak-channel-4.label = Wasserleckerkennung Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.lightning-distance.label = Gewitter Entfernung
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.lightning-time.label = Zeitpunkt des letzten Blitzschlags
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.lightning-counter.label = Blitzschläge heute
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-1.label = Externer Temperaturfühler Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-2.label = Externer Temperaturfühler Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-3.label = Externer Temperaturfühler Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-4.label = Externer Temperaturfühler Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-5.label = Externer Temperaturfühler Kanal 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-6.label = Externer Temperaturfühler Kanal 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-7.label = Externer Temperaturfühler Kanal 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.temperature-external-channel-8.label = Externer Temperaturfühler Kanal 8
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-temperature.label=Temperatur (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-humidity.label=Luftfeuchtigkeit (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm10.label=PM10 Luftqualität (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm10-24-hour-average.label=PM10 Luftqualität 24-Stunden-Mittelwert (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm25.label=PM2.5 Luftqualität (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-pm25-24-hour-average.label=PM2.5 Luftqualität 24-Stunden-Mittelwert (CO2-Sensor)
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-co2.label=CO2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.sensor-co2-co2-24-hour-average.label=CO2 24-Stunden-Mittelwert
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-1.label=Blattfeuchtigkeit Kanal 1
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-2.label=Blattfeuchtigkeit Kanal 2
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-3.label=Blattfeuchtigkeit Kanal 3
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-4.label=Blattfeuchtigkeit Kanal 4
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-5.label=Blattfeuchtigkeit Kanal 5
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-6.label=Blattfeuchtigkeit Kanal 6
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-7.label=Blattfeuchtigkeit Kanal 7
|
||||
thing-type.fineoffsetweatherstation.gateway.channel.leaf-wetness-channel-8.label=Blattfeuchtigkeit Kanal 8
|
@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="fineoffsetweatherstation"
|
||||
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="gateway">
|
||||
<label>Gateway Device</label>
|
||||
<category>NetworkAppliance</category>
|
||||
<config-description-ref uri="thing-type:fineoffsetweatherstation:gateway"/>
|
||||
</bridge-type>
|
||||
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<category>Temperature</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="max-wind-speed">
|
||||
<item-type>Number:Speed</item-type>
|
||||
<label>Max Wind Speed</label>
|
||||
<category>Wind</category>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Rain</label>
|
||||
<category>Rain</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Rain</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pressure">
|
||||
<item-type>Number:Pressure</item-type>
|
||||
<label>Pressure</label>
|
||||
<category>Pressure</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Pressure</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<category>Humidity</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Humidity</tag>
|
||||
</tags>
|
||||
<state pattern="%.0f %%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="moisture">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Moisture</label>
|
||||
<category>Moisture</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Moisture</tag>
|
||||
</tags>
|
||||
<state pattern="%.0f %%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="illumination">
|
||||
<item-type>Number:Illuminance</item-type>
|
||||
<label>Illumination</label>
|
||||
<category>Sun</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Light</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uv-radiation">
|
||||
<item-type>Number:Intensity</item-type>
|
||||
<label>UV-Irradiation</label>
|
||||
<category>Sun</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Light</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="uv-index">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>UV-Index</label>
|
||||
<category>Sun</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Light</tag>
|
||||
</tags>
|
||||
<state pattern="%.0f" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="rain-rate">
|
||||
<item-type>Number:VolumetricFlowRate</item-type>
|
||||
<label>Rain Rate</label>
|
||||
<category>Rain</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>Rain</tag>
|
||||
</tags>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm25">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>PM2.5 Air Quality</label>
|
||||
<category>AirQuality</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>AirQuality</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="pm10">
|
||||
<item-type>Number:Density</item-type>
|
||||
<label>PM10 Air Quality</label>
|
||||
<category>AirQuality</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>AirQuality</tag>
|
||||
</tags>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="co2">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>CO₂</label>
|
||||
<description>Air quality indicator</description>
|
||||
<category>CarbonDioxide</category>
|
||||
<tags>
|
||||
<tag>Measurement</tag>
|
||||
<tag>CO2</tag>
|
||||
</tags>
|
||||
<state pattern="%.0f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="water-leak-detection">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Water Leak Detection</label>
|
||||
<category>Alarm</category>
|
||||
<tags>
|
||||
<tag>Alarm</tag>
|
||||
</tags>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lightning-counter">
|
||||
<item-type>Number</item-type>
|
||||
<label>Lightning Counter</label>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lightning-time">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Lightning Time</label>
|
||||
<category>Time</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lightning-distance">
|
||||
<item-type>Number:Length</item-type>
|
||||
<label>Lightning Distance</label>
|
||||
<state pattern="%.0f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="fineoffsetweatherstation"
|
||||
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="sensor" listed="false">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="gateway"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Sensor Device</label>
|
||||
<description>A Sensor connected to the gateway (WN1900, GW1000, GW1100, WH2680, WH2650)</description>
|
||||
<category>Sensor</category>
|
||||
|
||||
<channels>
|
||||
<channel id="signal" typeId="system.signal-strength"/>
|
||||
<channel id="batteryLevel" typeId="system.battery-level"/>
|
||||
<channel id="lowBattery" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<config-description-ref uri="thing-type:fineoffsetweatherstation:sensor"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2022 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.fineoffsetweatherstation.internal.service;
|
||||
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.groups.Tuple;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.ConversionContext;
|
||||
import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue;
|
||||
|
||||
/**
|
||||
* @author Andreas Berger - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class FineOffsetDataParserTest {
|
||||
private final FineOffsetDataParser parser = new FineOffsetDataParser();
|
||||
|
||||
@Test
|
||||
void testLiveDataWH45() {
|
||||
List<MeasuredValue> data = parser.getLiveData(Hex.decode(
|
||||
"FFFF2700510100D306280827EF0927EF020045074F0A00150B00000C0000150000000016000117001900000E0000100000110021120000002113000005850D00007000D12E0060005A005B005502AE028F0633"),
|
||||
new ConversionContext(ZoneOffset.UTC));
|
||||
Assertions.assertThat(data)
|
||||
.extracting(MeasuredValue::getChannelId, measuredValue -> measuredValue.getState().toString())
|
||||
.containsExactly(new Tuple("temperature-indoor", "21.1 °C"), new Tuple("humidity-indoor", "40 %"),
|
||||
new Tuple("pressure-absolute", "10223 hPa"), new Tuple("pressure-relative", "10223 hPa"),
|
||||
new Tuple("temperature-outdoor", "6.9 °C"), new Tuple("humidity-outdoor", "79 %"),
|
||||
new Tuple("direction-wind", "21 °"), new Tuple("speed-wind", "0 m/s"),
|
||||
new Tuple("speed-gust", "0 m/s"), new Tuple("illumination", "0 lx"),
|
||||
new Tuple("irradiation-uv", "1 µW/cm²"), new Tuple("uv-index", "0"),
|
||||
new Tuple("wind-max-day", "0 m/s"), new Tuple("rain-rate", "0 mm/h"),
|
||||
new Tuple("rain-day", "0 mm"), new Tuple("rain-week", "3.3 mm"),
|
||||
new Tuple("rain-month", "3.3 mm"), new Tuple("rain-year", "141.3 mm"),
|
||||
new Tuple("rain-event", "0 mm"), new Tuple("sensor-co2-temperature", "20.9 °C"),
|
||||
new Tuple("sensor-co2-humidity", "46 %"), new Tuple("sensor-co2-pm10", "9.6 µg/m³"),
|
||||
new Tuple("sensor-co2-pm10-24-hour-average", "9 µg/m³"),
|
||||
new Tuple("sensor-co2-pm25", "9.1 µg/m³"),
|
||||
new Tuple("sensor-co2-pm25-24-hour-average", "8.5 µg/m³"),
|
||||
new Tuple("sensor-co2-co2", "686 ppm"), new Tuple("sensor-co2-co2-24-hour-average", "655 ppm"));
|
||||
}
|
||||
}
|
@ -127,6 +127,7 @@
|
||||
<module>org.openhab.binding.exec</module>
|
||||
<module>org.openhab.binding.feed</module>
|
||||
<module>org.openhab.binding.feican</module>
|
||||
<module>org.openhab.binding.fineoffsetweatherstation</module>
|
||||
<module>org.openhab.binding.flicbutton</module>
|
||||
<module>org.openhab.binding.fmiweather</module>
|
||||
<module>org.openhab.binding.folderwatcher</module>
|
||||
|
Loading…
Reference in New Issue
Block a user