From 66bb27275d22901f51b3a378b451018dc415fe10 Mon Sep 17 00:00:00 2001 From: Andreas Berger Date: Thu, 19 May 2022 20:52:17 +0200 Subject: [PATCH] [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 --- CODEOWNERS | 1 + bom/openhab-addons/pom.xml | 5 + .../NOTICE | 13 + .../README.md | 307 ++++++++++++++ .../doc/WH2650.png | Bin 0 -> 224587 bytes .../pom.xml | 38 ++ .../src/main/feature/feature.xml | 9 + .../FineOffsetGatewayConfiguration.java | 33 ++ .../FineOffsetSensorConfiguration.java | 30 ++ ...eOffsetWeatherStationBindingConstants.java | 62 +++ ...ineOffsetWeatherStationHandlerFactory.java | 84 ++++ .../internal/Utils.java | 88 ++++ .../FineOffsetGatewayDiscoveryService.java | 308 ++++++++++++++ .../internal/domain/Command.java | 268 ++++++++++++ .../internal/domain/ConversionContext.java | 34 ++ .../internal/domain/Measurand.java | 391 ++++++++++++++++++ .../internal/domain/MeasureType.java | 160 +++++++ .../internal/domain/Sensor.java | 57 +++ .../internal/domain/SensorGatewayBinding.java | 124 ++++++ .../domain/response/BatteryStatus.java | 142 +++++++ .../domain/response/MeasuredValue.java | 68 +++ .../domain/response/SensorDevice.java | 58 +++ .../internal/domain/response/SystemInfo.java | 66 +++ .../handler/FineOffsetGatewayHandler.java | 291 +++++++++++++ .../handler/FineOffsetSensorHandler.java | 88 ++++ .../internal/handler/ThingStatusListener.java | 27 ++ .../service/FineOffsetDataParser.java | 181 ++++++++ .../FineOffsetGatewayQueryService.java | 171 ++++++++ .../main/resources/OH-INF/binding/binding.xml | 9 + .../OH-INF/config/config-descriptions.xml | 40 ++ .../i18n/fineoffsetweatherstation.properties | 187 +++++++++ .../fineoffsetweatherstation_de.properties | 183 ++++++++ .../main/resources/OH-INF/thing/gateway.xml | 181 ++++++++ .../main/resources/OH-INF/thing/sensor.xml | 24 ++ .../service/FineOffsetDataParserTest.java | 56 +++ bundles/pom.xml | 1 + 36 files changed, 3785 insertions(+) create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/NOTICE create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/README.md create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/doc/WH2650.png create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/pom.xml create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/feature/feature.xml create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetGatewayConfiguration.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetSensorConfiguration.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationBindingConstants.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationHandlerFactory.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/Utils.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/discovery/FineOffsetGatewayDiscoveryService.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Command.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/ConversionContext.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurand.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/MeasureType.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/BatteryStatus.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/MeasuredValue.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SensorDevice.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SystemInfo.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetGatewayHandler.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetSensorHandler.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/ThingStatusListener.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParser.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetGatewayQueryService.java create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/binding/binding.xml create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/config/config-descriptions.xml create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation.properties create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation_de.properties create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/gateway.xml create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/sensor.xml create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParserTest.java diff --git a/CODEOWNERS b/CODEOWNERS index 110ba738a..76785db77 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -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 diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml index 3218cb784..155250edf 100644 --- a/bom/openhab-addons/pom.xml +++ b/bom/openhab-addons/pom.xml @@ -466,6 +466,11 @@ org.openhab.binding.feican ${project.version} + + org.openhab.addons.bundles + org.openhab.binding.fineoffsetweatherstation + ${project.version} + org.openhab.addons.bundles org.openhab.binding.flicbutton diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/NOTICE b/bundles/org.openhab.binding.fineoffsetweatherstation/NOTICE new file mode 100644 index 000000000..38d625e34 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/NOTICE @@ -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 diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/README.md b/bundles/org.openhab.binding.fineoffsetweatherstation/README.md new file mode 100644 index 000000000..7fc57f126 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/README.md @@ -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"] +Number SignalWH25 "Signal WH25" (WH25) ["Measurement", "Level"] { channel="fineoffsetweatherstation:sensor:3906700515:WH25:signal" } +Switch BatteryStatusWH25 "Low Battery WH25" (WH25) ["Energy", "LowBattery"] { channel="fineoffsetweatherstation:sensor:3906700515:WH25:lowBattery" } + +Group WH65 "WH65" ["Sensor"] +Number SignalWH65 "Signal WH65" (WH65) ["Measurement", "Level"] { channel="fineoffsetweatherstation:sensor:3906700515:WH65:signal" } +Switch BatteryStatusWH65 "Low Battery WH65" (WH65) ["Energy", "LowBattery"] { channel="fineoffsetweatherstation:sensor:3906700515:WH65:lowBattery" } + +Group gOutdoor "Outdoor" ["Location"] +Number:Temperature weather_temperature_outdoor "Outdoor Temperature" (gOutdoor) ["Measurement", "Temperature"] { channel="fineoffsetweatherstation:gateway:3906700515:temperature-outdoor" } +Number:Temperature weather_temperature_indoor "Inside temperature" ["Measurement", "Temperature"] { channel="fineoffsetweatherstation:gateway:3906700515:temperature-indoor" } +Number:Dimensionless weather_humidity_indoor "Humidity inside" ["Measurement", "Humidity"] { channel="fineoffsetweatherstation:gateway:3906700515:humidity-indoor" } +Number:Pressure weather_pressure_absolute "Absolute pressure" (gOutdoor) ["Measurement", "Pressure"] { channel="fineoffsetweatherstation:gateway:3906700515:pressure-absolute" } +Number:Pressure weather_pressure_relative "Relative pressure" (gOutdoor) ["Measurement", "Pressure"] { channel="fineoffsetweatherstation:gateway:3906700515:pressure-relative" } +Number:Dimensionless weather_humidity_outdoor "Humidity outside" (gOutdoor) ["Measurement", "Humidity"] { channel="fineoffsetweatherstation:gateway:3906700515:humidity-outdoor" } +Number:Angle weather_direction_wind "Wind direction" (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:direction-wind" } +Number:Speed weather_speed_wind "Wind speed" (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:speed-wind" } +Number:Speed weather_speed_gust "Gust speed" (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:speed-gust" } +Number:Illuminance weather_illumination "Light intensity" (gOutdoor) ["Measurement", "Light"] { channel="fineoffsetweatherstation:gateway:3906700515:illumination" } +Number:Intensity weather_irradiation_uv "UV radiation" (gOutdoor) ["Measurement", "Light"] { channel="fineoffsetweatherstation:gateway:3906700515:irradiation-uv" } +Number:Dimensionless weather_uv_index "UV Index" (gOutdoor) ["Measurement", "Light"] { channel="fineoffsetweatherstation:gateway:3906700515:uv-index" } +Number:Speed weather_max_day "Maximum wind speed today" (gOutdoor) ["Measurement", "Wind"] { channel="fineoffsetweatherstation:gateway:3906700515:wind-max-day" } +Number:VolumetricFlowRate weather_rain_rate "Rainfall rate" (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-rate" } +Number:Length weather_rain_day "Rainfall today" (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-day" } +Number:Length weather_rain_week "Rainfall this week" (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-week" } +Number:Length weather_rain_month "Rainfall this month" (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-month" } +Number:Length weather_rain_year "Rainfall this year " (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-year" } +Number:Length weather_rain_event "Amount of rainfall at the last rain" (gOutdoor) ["Measurement", "Rain"] { channel="fineoffsetweatherstation:gateway:3906700515:rain-event" } +``` diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/doc/WH2650.png b/bundles/org.openhab.binding.fineoffsetweatherstation/doc/WH2650.png new file mode 100644 index 0000000000000000000000000000000000000000..965345243473ab42fc3ab531acde12057b0300f1 GIT binary patch literal 224587 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

o_!Tf+$Q$iAnm+ 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%0D_gRXaqTI&5b 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 + + + + + 4.0.0 + + + org.openhab.addons.bundles + org.openhab.addons.reactor.bundles + 3.3.0-SNAPSHOT + + + org.openhab.binding.fineoffsetweatherstation + + openHAB Add-ons :: Bundles :: Fine Offset Weather Station + + + + org.assertj + assertj-core + 3.22.0 + test + + + diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/feature/feature.xml b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/feature/feature.xml new file mode 100644 index 000000000..9a2de9a94 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/feature/feature.xml @@ -0,0 +1,9 @@ + + + mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features + + + openhab-runtime-base + mvn:org.openhab.addons.bundles/org.openhab.binding.fineoffsetweatherstation/${project.version} + + diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetGatewayConfiguration.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetGatewayConfiguration.java new file mode 100644 index 000000000..6c8e43f02 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetGatewayConfiguration.java @@ -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; +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetSensorConfiguration.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetSensorConfiguration.java new file mode 100644 index 000000000..3767f75a5 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetSensorConfiguration.java @@ -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; +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationBindingConstants.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationBindingConstants.java new file mode 100644 index 000000000..6c5950667 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationBindingConstants.java @@ -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 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"; +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationHandlerFactory.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationHandlerFactory.java new file mode 100644 index 000000000..de54049bf --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/FineOffsetWeatherStationHandlerFactory.java @@ -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; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/Utils.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/Utils.java new file mode 100644 index 000000000..c93d1d6dd --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/Utils.java @@ -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])); + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/discovery/FineOffsetGatewayDiscoveryService.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/discovery/FineOffsetGatewayDiscoveryService.java new file mode 100644 index 000000000..10289e095 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/discovery/FineOffsetGatewayDiscoveryService.java @@ -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 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 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"); + } + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Command.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Command.java new file mode 100644 index 000000000..2d47269a5 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Command.java @@ -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); + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/ConversionContext.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/ConversionContext.java new file mode 100644 index 000000000..195a9bcc1 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/ConversionContext.java @@ -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; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurand.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurand.java new file mode 100644 index 000000000..a1b2dc2b1 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurand.java @@ -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 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 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 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 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 result) { + State state = measureType.toState(data, offset, context); + if (state != null) { + result.add(new MeasuredValue(measureType, channelId, channelTypeUID, state, name)); + } + return measureType.getByteSize(); + } + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/MeasureType.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/MeasureType.java new file mode 100644 index 000000000..075c34c9e --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/MeasureType.java @@ -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 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); + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java new file mode 100644 index 000000000..4392d6b05 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java @@ -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); + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java new file mode 100644 index 000000000..380c4ab66 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java @@ -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> SENSOR_LOOKUP = new HashMap<>(); + + static { + for (SensorGatewayBinding sensorGatewayBinding : values()) { + List 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 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; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/BatteryStatus.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/BatteryStatus.java new file mode 100644 index 000000000..97ab2c81c --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/BatteryStatus.java @@ -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; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/MeasuredValue.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/MeasuredValue.java new file mode 100644 index 000000000..ba42b3c0a --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/MeasuredValue.java @@ -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 + '\'' + '}'; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SensorDevice.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SensorDevice.java new file mode 100644 index 000000000..e593084be --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SensorDevice.java @@ -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 + '}'; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SystemInfo.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SystemInfo.java new file mode 100644 index 000000000..8b326b5dc --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/SystemInfo.java @@ -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 + '}'; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetGatewayHandler.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetGatewayHandler.java new file mode 100644 index 000000000..1d37544f0 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetGatewayHandler.java @@ -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 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 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 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 data = query(FineOffsetGatewayQueryService::getLiveData); + if (data == null) { + return; + } + + List 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 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 @Nullable T query(Function 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(); + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetSensorHandler.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetSensorHandler.java new file mode 100644 index 000000000..b81894314 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetSensorHandler.java @@ -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()); + } + } + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/ThingStatusListener.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/ThingStatusListener.java new file mode 100644 index 000000000..039bbea14 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/ThingStatusListener.java @@ -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); +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParser.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParser.java new file mode 100644 index 000000000..5bcfcd8b7 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParser.java @@ -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 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 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 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 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 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; + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetGatewayQueryService.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetGatewayQueryService.java new file mode 100644 index 000000000..32950d16b --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetGatewayQueryService.java @@ -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 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 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(); + } + } +} diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/binding/binding.xml b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/binding/binding.xml new file mode 100644 index 000000000..09d1eb7ea --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/binding/binding.xml @@ -0,0 +1,9 @@ + + + + Fine Offset Weather Station + A binding for the Weather Stations Manufactured by Fine Offset + + diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/config/config-descriptions.xml b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/config/config-descriptions.xml new file mode 100644 index 000000000..72f0ba4c6 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/config/config-descriptions.xml @@ -0,0 +1,40 @@ + + + + + + + The Hostname or IP address of the device + network-address + + + + The network port of the gateway + 45000 + + + + Polling interval for refreshing the data in seconds + 16 + s + true + + + + Interval in seconds to fetch registered sensors, battery status and signal strength + s + 900 + true + + + + + + + + + diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation.properties b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation.properties new file mode 100644 index 000000000..46b30c518 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation.properties @@ -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 diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation_de.properties b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation_de.properties new file mode 100644 index 000000000..0013e70e9 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation_de.properties @@ -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 diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/gateway.xml b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/gateway.xml new file mode 100644 index 000000000..53576ae5c --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/gateway.xml @@ -0,0 +1,181 @@ + + + + + + NetworkAppliance + + + + + Number:Temperature + + Temperature + + Measurement + Temperature + + + + + + Number:Speed + + Wind + + + + + Number:Length + + Rain + + Measurement + Rain + + + + + + Number:Pressure + + Pressure + + Measurement + Pressure + + + + + + Number:Dimensionless + + Humidity + + Measurement + Humidity + + + + + + Number:Dimensionless + + Moisture + + Measurement + Moisture + + + + + + Number:Illuminance + + Sun + + Measurement + Light + + + + + + Number:Intensity + + Sun + + Measurement + Light + + + + + + Number:Dimensionless + + Sun + + Measurement + Light + + + + + + Number:VolumetricFlowRate + + Rain + + Measurement + Rain + + + + + + Number:Density + + AirQuality + + Measurement + AirQuality + + + + + + Number:Density + + AirQuality + + Measurement + AirQuality + + + + + + Number:Dimensionless + + Air quality indicator + CarbonDioxide + + Measurement + CO2 + + + + + + Switch + + Alarm + + Alarm + + + + + + Number + + + + + + DateTime + + Time + + + + + Number:Length + + + + diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/sensor.xml b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/sensor.xml new file mode 100644 index 000000000..8e3668dbc --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/thing/sensor.xml @@ -0,0 +1,24 @@ + + + + + + + + + + A Sensor connected to the gateway (WN1900, GW1000, GW1100, WH2680, WH2650) + Sensor + + + + + + + + + + diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParserTest.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParserTest.java new file mode 100644 index 000000000..269e5d4f2 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParserTest.java @@ -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 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")); + } +} diff --git a/bundles/pom.xml b/bundles/pom.xml index 348736683..61d421499 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -127,6 +127,7 @@ org.openhab.binding.exec org.openhab.binding.feed org.openhab.binding.feican + org.openhab.binding.fineoffsetweatherstation org.openhab.binding.flicbutton org.openhab.binding.fmiweather org.openhab.binding.folderwatcher