]> git.basschouten.com Git - openhab-addons.git/commitdiff
[fineoffsetweatherstation] Add support for the new GW2001 weather station (#13283)
authorAndreas Berger <Andy2003@users.noreply.github.com>
Wed, 31 Aug 2022 13:27:18 +0000 (15:27 +0200)
committerGitHub <noreply@github.com>
Wed, 31 Aug 2022 13:27:18 +0000 (15:27 +0200)
* [fineoffsetweatherstation] add support for the new GW2001 weather station with its WH90 sensor
* [fineoffsetweatherstation] add missing channel labels
* [fineoffsetweatherstation] remove redundant translations
* [fineoffsetweatherstation] add test data + fix for WH90
* [fineoffsetweatherstation] fix wrong size for `CMD_READ_RAIN`

Signed-off-by: Andreas Berger <andreas@berger-freelancer.com>
16 files changed:
bundles/org.openhab.binding.fineoffsetweatherstation/README.md
bundles/org.openhab.binding.fineoffsetweatherstation/pom.xml
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/discovery/FineOffsetGatewayDiscoveryService.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Command.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurand.java [new file with mode: 0644]
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurands.java [deleted file]
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Protocol.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/response/MeasuredValue.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetGatewayHandler.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/handler/FineOffsetSensorHandler.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParser.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetGatewayQueryService.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/GatewayQueryService.java
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/OH-INF/i18n/fineoffsetweatherstation.properties
bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/measurands.csv [deleted file]
bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/FineOffsetDataParserTest.java

index 67192dfdaa7046db6e2e25ac51f7d98ea3d1aa4b..2759b046b117830a74309134d1055c56d6c020c2 100644 (file)
@@ -23,7 +23,7 @@ This binding works offline by [implementing the wire protocol](https://osswww.ec
 
 ## 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.:
+- `weatherstation`: A Fine Offset gateway device with the ThingTypeUID `fineoffsetweatherstation:weatherstation` which supports the [wire protocol](https://osswww.ecowitt.net/uploads/20220407/WN1900%20GW1000,1100%20WH2680,2650%20telenet%20v1.6.4.pdf) e.g.:
     - HP2550
     - HP3500
     - GW1000
@@ -31,6 +31,7 @@ This binding works offline by [implementing the wire protocol](https://osswww.ec
     - GW1002
     - GW1003
     - GW1100
+    - GW2001
     - WN1900
     - WN1910
     - WH2350
@@ -42,6 +43,7 @@ This binding works offline by [implementing the wire protocol](https://osswww.ec
     - WH2900
     - WH2950
     - WS980 ELV (tested)
+    - WittBoy (tested)
 - `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:
@@ -60,7 +62,7 @@ This binding works offline by [implementing the wire protocol](https://osswww.ec
   - 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
+  - WH90 - 7-in-1 weather station - Ultrasonic sensor for wind speed & direction, solar radiation & light, temperature, humidity and haptic rainfall Sensor
 
 ### Unsupported Devices
 
@@ -263,6 +265,13 @@ Valid sensors:
 | 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                        | 
+| piezo-rain-rate                       | Number:VolumetricFlowRate     | R          | Piezo - Rainfall Rate                          |
+| piezo-rain-event                      | Number:Length                 | R          | Piezo - Amount of Rainfall At the last Rain    |
+| piezo-rain-hour                       | Number:Length                 | R          | Piezo - Rainfall Current Hour                  |
+| piezo-rain-day                        | Number:Length                 | R          | Piezo - Rainfall Today                         |
+| piezo-rain-week                       | Number:Length                 | R          | Piezo - Rainfall this Week                     |
+| piezo-rain-month                      | Number:Length                 | R          | Piezo - Rainfall this Month                    |
+| piezo-rain-year                       | Number:Length                 | R          | Piezo - Rainfall this Year                     |
 
 ### `sensor` Channels
 
index 7eefa47fc3b60a24ba8f571a33fcf150c9dafcad..3f766a2a3514bbc8a0235cefb1e2b08ad734c3b6 100644 (file)
   <name>openHAB Add-ons :: Bundles :: Fine Offset Weather Station</name>
 
   <dependencies>
-    <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-csv</artifactId>
-      <version>1.9.0</version>
-    </dependency>
     <dependency>
       <groupId>org.assertj</groupId>
       <artifactId>assertj-core</artifactId>
index 552c2e6b35c63dc65915fb93e38d85ca11b6c275..92e30db08a7b4e1913c9e319b65427feb7c223b7 100644 (file)
@@ -26,7 +26,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
@@ -200,7 +199,7 @@ public class FineOffsetGatewayDiscoveryService extends AbstractDiscoveryService
         for (Protocol protocol : Protocol.values()) {
             try (GatewayQueryService gatewayQueryService = protocol.getGatewayQueryService(config, null,
                     conversionContext)) {
-                List<MeasuredValue> result = gatewayQueryService.getMeasuredValues();
+                Collection<MeasuredValue> result = gatewayQueryService.getMeasuredValues();
                 logger.trace("found {} measured values via protocol {}", result.size(), protocol);
                 if (!result.isEmpty()) {
                     return protocol;
index 0d044fae92020c5dd5532c4d01881cb64c535951..7f4d1bfd663a0b1b677b25e88ab0bb7ea9cef7c2 100644 (file)
@@ -231,7 +231,17 @@ public enum Command {
     /**
      * write back rain reset time
      */
-    CMD_WRITE_RSTRAIN_TIME((byte) 0x56, 1);
+    CMD_WRITE_RSTRAIN_TIME((byte) 0x56, 1),
+
+    /**
+     * read rain data including piezo (wh90)
+     */
+    CMD_READ_RAIN((byte) 0x57, 2),
+
+    /**
+     * write rain data
+     */
+    CMD_WRITE_RAIN((byte) 0x58, 1);
 
     private final byte code;
     private final int sizeBytes;
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 (file)
index 0000000..bc60013
--- /dev/null
@@ -0,0 +1,344 @@
+/**
+ * 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.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+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", 0x01, "Indoor Temperature", MeasureType.TEMPERATURE,
+            DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_INDOOR_TEMPERATURE),
+
+    OUTTEMP("temperature-outdoor", 0x02, "Outdoor Temperature", MeasureType.TEMPERATURE,
+            DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_OUTDOOR_TEMPERATURE),
+
+    DEWPOINT("temperature-dew-point", 0x03, "Dew point", MeasureType.TEMPERATURE),
+
+    WINDCHILL("temperature-wind-chill", 0x04, "Wind chill", MeasureType.TEMPERATURE),
+
+    HEATINDEX("temperature-heat-index", 0x05, "Heat index", MeasureType.TEMPERATURE),
+
+    INHUMI("humidity-indoor", 0x06, "Indoor Humidity", MeasureType.PERCENTAGE),
+
+    OUTHUMI("humidity-outdoor", 0x07, "Outdoor Humidity", MeasureType.PERCENTAGE,
+            DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_ATMOSPHERIC_HUMIDITY),
+
+    ABSBARO("pressure-absolute", 0x08, "Absolutely pressure", MeasureType.PRESSURE),
+
+    RELBARO("pressure-relative", 0x09, "Relative pressure", MeasureType.PRESSURE,
+            DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_BAROMETRIC_PRESSURE),
+
+    WINDDIRECTION("direction-wind", 0x0A, "Wind Direction", MeasureType.DEGREE,
+            DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_WIND_DIRECTION),
+
+    WINDSPEED("speed-wind", 0x0B, "Wind Speed", MeasureType.SPEED,
+            DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_WIND_SPEED),
+
+    GUSTSPEED("speed-gust", 0x0C, "Gust Speed", MeasureType.SPEED,
+            DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_TYPE_UID_WIND_SPEED),
+
+    RAINEVENT("rain-event", 0x0D, "Rain Event", MeasureType.HEIGHT,
+            new ParserCustomization(ParserCustomizationType.ELV, MeasureType.HEIGHT_BIG)),
+
+    RAINRATE("rain-rate", 0x0E, "Rain Rate", MeasureType.HEIGHT_PER_HOUR,
+            new ParserCustomization(ParserCustomizationType.ELV, MeasureType.HEIGHT_PER_HOUR_BIG)),
+
+    RAINHOUR("rain-hour", 0x0F, "Rain hour", MeasureType.HEIGHT,
+            new ParserCustomization(ParserCustomizationType.ELV, MeasureType.HEIGHT_BIG)),
+
+    RAINDAY("rain-day", 0x10, "Rain Day", MeasureType.HEIGHT,
+            new ParserCustomization(ParserCustomizationType.ELV, MeasureType.HEIGHT_BIG),
+            new ParserCustomization(ParserCustomizationType.RAIN_READING, MeasureType.HEIGHT_BIG)),
+
+    RAINWEEK("rain-week", 0x11, "Rain Week", MeasureType.HEIGHT,
+            new ParserCustomization(ParserCustomizationType.ELV, MeasureType.HEIGHT_BIG),
+            new ParserCustomization(ParserCustomizationType.RAIN_READING, MeasureType.HEIGHT_BIG)),
+
+    RAINMONTH("rain-month", 0x12, "Rain Month", MeasureType.HEIGHT_BIG),
+
+    RAINYEAR("rain-year", 0x13, "Rain Year", MeasureType.HEIGHT_BIG),
+
+    RAINTOTALS("rain-total", 0x14, "Rain Totals", MeasureType.HEIGHT_BIG),
+
+    LIGHT("illumination", 0x15, "Light", MeasureType.LUX),
+
+    UV("irradiation-uv", 0x16, "UV", MeasureType.MILLIWATT_PER_SQUARE_METRE),
+
+    UVI("uv-index", 0x17, "UV index", MeasureType.BYTE, CHANNEL_TYPE_UV_INDEX),
+
+    TIME("time", 0x18, "Date and time", MeasureType.DATE_TIME2),
+
+    DAYLWINDMAX("wind-max-day", 0X19, "Day max wind", MeasureType.SPEED, CHANNEL_TYPE_MAX_WIND_SPEED),
+
+    TEMPX("temperature-channel", new int[] { 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21 }, "Temperature",
+            MeasureType.TEMPERATURE),
+
+    HUMIX("humidity-channel", new int[] { 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29 }, "Humidity",
+            MeasureType.PERCENTAGE),
+
+    SOILTEMPX("temperature-soil-channel",
+            new int[] { 0x2B, 0x2D, 0x2F, 0x31, 0x33, 0x35, 0x37, 0x39, 0x3B, 0x3D, 0x3F, 0x41, 0x43, 0x45, 0x47,
+                    0x49 },
+            "Soil Temperature", MeasureType.TEMPERATURE),
+
+    SOILMOISTUREX("moisture-soil-channel",
+            new int[] { 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, 0x40, 0x42, 0x44, 0x46, 0x48,
+                    0x4A },
+            "Soil Moisture", 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(0x4C, new Skip(1)),
+
+    PM25_24HAVGX("air-quality-24-hour-average-channel", new int[] { 0x4D, 0x4E, 0x4F, 0x50 },
+            "PM2.5 Air Quality 24 hour average", MeasureType.PM25),
+
+    PM25_CHX("air-quality-channel", new int[] { 0x2A, 0x51, 0x52, 0x53 }, "PM2.5 Air Quality", MeasureType.PM25),
+
+    LEAK_CHX("water-leak-channel", new int[] { 0x58, 0x59, 0x5A, 0x5B }, "Leak", MeasureType.WATER_LEAK_DETECTION),
+
+    // `LIGHTNING` is the name in the spec, so we keep it here as it
+    LIGHTNING("lightning-distance", 0x60, "lightning distance 1~40KM", MeasureType.LIGHTNING_DISTANCE),
+
+    LIGHTNING_TIME("lightning-time", 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", 0x62, "lightning counter for the day", MeasureType.LIGHTNING_COUNTER),
+
+    TF_USRX("temperature-external-channel", new int[] { 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A },
+            "Soil or Water temperature", MeasureType.TEMPERATURE),
+
+    ITEM_SENSOR_CO2(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)),
+
+    LEAF_WETNESS_CHX("leaf-wetness-channel", new int[] { 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79 },
+            "Leaf Moisture", MeasureType.PERCENTAGE, CHANNEL_TYPE_MOISTURE),
+
+    PIEZO_RAIN_RATE("piezo-rain-rate", 0x80, "Rain Rate", MeasureType.HEIGHT_PER_HOUR),
+
+    PIEZO_EVENT_RAIN("piezo-rain-event", 0x81, "Rain Event", MeasureType.HEIGHT),
+
+    PIEZO_HOURLY_RAIN("piezo-rain-hour", 0x82, "Rain hour", MeasureType.HEIGHT),
+
+    PIEZO_DAILY_RAIN("piezo-rain-day", 0x83, "Rain Day", MeasureType.HEIGHT_BIG),
+
+    PIEZO_WEEKLY_RAIN("piezo-rain-week", 0x84, "Rain Week", MeasureType.HEIGHT_BIG),
+
+    PIEZO_MONTHLY_RAIN("piezo-rain-month", 0x85, "Rain Month", MeasureType.HEIGHT_BIG),
+
+    PIEZO_YEARLY_RAIN("piezo-rain-year", 0x86, "Rain Year", MeasureType.HEIGHT_BIG),
+
+    PIEZO_GAIN10(0x87, new Skip(2)),
+
+    RST_RAIN_TIME(0x88, new Skip(3)),
+
+    ;
+
+    private static final Map<Byte, SingleChannelMeasurand> MEASURANDS = new HashMap<>();
+
+    static {
+        for (Measurand measurand : values()) {
+            for (int i = 0; i < measurand.codes.length; i++) {
+                int code = measurand.codes[i];
+                // if we get more than one code this measurand has multiple channels
+                Integer channel = measurand.codes.length == 1 ? null : i + 1;
+                MEASURANDS.put((byte) code, new SingleChannelMeasurand(measurand, channel));
+            }
+        }
+    }
+
+    private final int[] codes;
+    private final Parser[] parsers;
+
+    Measurand(String channelId, int code, String name, MeasureType measureType, ParserCustomization... customizations) {
+        this(channelId, code, name, measureType, null, customizations);
+    }
+
+    Measurand(String channelId, int[] codes, String name, MeasureType measureType,
+            ParserCustomization... customizations) {
+        this(channelId, codes, name, measureType, null, customizations);
+    }
+
+    Measurand(String channelId, int code, String name, MeasureType measureType, @Nullable ChannelTypeUID channelTypeUID,
+            ParserCustomization... customizations) {
+        this(code, new MeasurandParser(channelId, name, measureType, channelTypeUID, customizations));
+    }
+
+    Measurand(String channelId, int[] codes, String name, MeasureType measureType,
+            @Nullable ChannelTypeUID channelTypeUID, ParserCustomization... customizations) {
+        this(codes, new MeasurandParser(channelId, name, measureType, channelTypeUID, customizations));
+    }
+
+    Measurand(int code, Parser... parsers) {
+        this(new int[] { code }, parsers);
+    }
+
+    Measurand(int[] codes, Parser... parsers) {
+        this.codes = codes;
+        this.parsers = parsers;
+    }
+
+    public static @Nullable SingleChannelMeasurand getByCode(byte code) {
+        return MEASURANDS.get(code);
+    }
+
+    private int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context,
+            @Nullable ParserCustomizationType customizationType, List<MeasuredValue> result) {
+        int subOffset = 0;
+        for (Parser parser : parsers) {
+            subOffset += parser.extractMeasuredValues(data, offset + subOffset, channel, context, customizationType,
+                    result);
+        }
+        return subOffset;
+    }
+
+    private interface Parser {
+        int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context,
+                @Nullable ParserCustomizationType customizationType, List<MeasuredValue> result);
+    }
+
+    private static class Skip implements Parser {
+        private final int skip;
+
+        public Skip(int skip) {
+            this.skip = skip;
+        }
+
+        @Override
+        public int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context,
+                @Nullable ParserCustomizationType customizationType, List<MeasuredValue> result) {
+            return skip;
+        }
+    }
+
+    public enum ParserCustomizationType {
+        ELV,
+        RAIN_READING
+    }
+
+    private static class ParserCustomization {
+
+        private final ParserCustomizationType type;
+        private final MeasureType measureType;
+
+        public ParserCustomization(ParserCustomizationType type, MeasureType measureType) {
+            this.type = type;
+            this.measureType = measureType;
+        }
+
+        public ParserCustomizationType getType() {
+            return type;
+        }
+
+        public MeasureType getMeasureType() {
+            return measureType;
+        }
+    }
+
+    public static class SingleChannelMeasurand {
+        private final Measurand measurand;
+        private final @Nullable Integer channel;
+
+        public SingleChannelMeasurand(Measurand measurand, @Nullable Integer channel) {
+            this.measurand = measurand;
+            this.channel = channel;
+        }
+
+        public int extractMeasuredValues(byte[] data, int offset, ConversionContext context,
+                @Nullable ParserCustomizationType customizationType, List<MeasuredValue> result) {
+            return measurand.extractMeasuredValues(data, offset, channel, context, customizationType, result);
+        }
+    }
+
+    private static class MeasurandParser implements Parser {
+        private final String name;
+        private final String channelPrefix;
+        private final MeasureType measureType;
+
+        private final @Nullable Map<ParserCustomizationType, ParserCustomization> customizations;
+        private final @Nullable ChannelTypeUID channelTypeUID;
+
+        MeasurandParser(String channelPrefix, String name, MeasureType measureType,
+                ParserCustomization... customizations) {
+            this(channelPrefix, name, measureType, null, customizations);
+        }
+
+        MeasurandParser(String channelPrefix, String name, MeasureType measureType,
+                @Nullable ChannelTypeUID channelTypeUID, ParserCustomization... customizations) {
+            this.channelPrefix = channelPrefix;
+            this.name = name;
+            this.measureType = measureType;
+            this.channelTypeUID = channelTypeUID;
+            if (customizations.length == 0) {
+                this.customizations = null;
+            } else {
+
+                this.customizations = Collections.unmodifiableMap(
+                        Arrays.stream(customizations).collect(Collectors.toMap(ParserCustomization::getType,
+                                customization -> customization, (a, b) -> b, HashMap::new)));
+            }
+        }
+
+        public int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context,
+                @Nullable ParserCustomizationType customizationType, List<MeasuredValue> result) {
+            MeasureType measureType = getMeasureType(customizationType);
+            State state = measureType.toState(data, offset, context);
+            if (state != null) {
+                ChannelTypeUID channelType = channelTypeUID == null ? measureType.getChannelTypeId() : channelTypeUID;
+                result.add(new MeasuredValue(measureType, channelPrefix, channel, channelType, state, name));
+            }
+            return measureType.getByteSize();
+        }
+
+        public MeasureType getMeasureType(@Nullable ParserCustomizationType customizationType) {
+            if (customizationType == null)
+                return measureType;
+            return Optional.ofNullable(customizations).map(m -> m.get(customizationType))
+                    .map(ParserCustomization::getMeasureType).orElse(measureType);
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurands.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Measurands.java
deleted file mode 100644 (file)
index 27658fe..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * 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.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Predicate;
-
-import org.apache.commons.csv.CSVFormat;
-import org.apache.commons.csv.CSVParser;
-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.MeasuredValue;
-import org.openhab.core.thing.type.ChannelTypeUID;
-import org.openhab.core.types.State;
-
-/**
- * Holds all the measurands supported by the gateway.
- *
- * @author Andreas Berger - Initial contribution
- */
-@NonNullByDefault
-public class Measurands {
-
-    private static final Map<Protocol, Measurands> INSTANCES = new HashMap<>();
-    private final Map<Byte, List<Parser>> parsersPerCode = new HashMap<>();
-
-    private Measurands(Protocol protocol) {
-        try (InputStream data = Measurands.class.getResourceAsStream("/measurands.csv")) {
-            if (data == null) {
-                throw new IllegalStateException("Missing measurands.csv");
-            }
-            CSVFormat csvFormat = CSVFormat.Builder.create().setHeader().setSkipHeaderRecord(true).build();
-            CSVParser.parse(new InputStreamReader(data), csvFormat).forEach(row -> {
-
-                byte code = Byte.valueOf(row.get("Code").replace("0x", ""), 16);
-                Optional<Integer> skip = Optional.ofNullable(row.get("Skip")).filter(Predicate.not(String::isBlank))
-                        .map(Integer::valueOf);
-                int index = Optional.ofNullable(row.get("Index")).filter(Predicate.not(String::isBlank))
-                        .map(Integer::valueOf).orElse(0);
-
-                Parser parser;
-                if (skip.isPresent()) {
-                    parser = new Skip(skip.get(), index);
-                } else {
-                    String name = row.get("Name");
-                    String channel = row.get("Channel");
-
-                    ChannelTypeUID channelType = Optional.ofNullable(row.get("ChannelType"))
-                            .filter(Predicate.not(String::isBlank)).map(s -> {
-                                if (s.contains(":")) {
-                                    return new ChannelTypeUID(s);
-                                } else {
-                                    return new ChannelTypeUID(FineOffsetWeatherStationBindingConstants.BINDING_ID, s);
-                                }
-                            }).orElse(null);
-                    String measurandString = protocol == Protocol.DEFAULT ? row.get("MeasureType_DEFAULT")
-                            : Optional.ofNullable(row.get("MeasureType_" + protocol.name()))
-                                    .filter(Predicate.not(String::isBlank))
-                                    .orElseGet(() -> row.get("MeasureType_DEFAULT"));
-                    parser = new MeasurandParser(channel, name, MeasureType.valueOf(measurandString), index,
-                            channelType);
-                }
-
-                List<Parser> parsers = parsersPerCode.computeIfAbsent(code, aByte -> new ArrayList<>());
-                // noinspection ConstantConditions
-                if (parsers != null) {
-                    parsers.add(parser);
-                }
-            });
-            for (List<Parser> parsers : parsersPerCode.values()) {
-                parsers.sort(Comparator.comparing(Parser::getIndex));
-            }
-        } catch (IOException e) {
-            throw new IllegalStateException("Failed to read measurands.csv", e);
-        }
-    }
-
-    public static Measurands getInstance(Protocol protocol) {
-        synchronized (INSTANCES) {
-            return Objects.requireNonNull(INSTANCES.computeIfAbsent(protocol, Measurands::new));
-        }
-    }
-
-    private abstract static class Parser {
-        private final int index;
-
-        public Parser(int index) {
-            this.index = index;
-        }
-
-        public abstract int extractMeasuredValues(byte[] data, int offset, ConversionContext context,
-                List<MeasuredValue> result);
-
-        public int getIndex() {
-            return index;
-        }
-    }
-
-    private static class Skip extends Parser {
-        private final int skip;
-
-        public Skip(int skip, int index) {
-            super(index);
-            this.skip = skip;
-        }
-
-        @Override
-        public int extractMeasuredValues(byte[] data, int offset, ConversionContext context,
-                List<MeasuredValue> result) {
-            return skip;
-        }
-    }
-
-    private static class MeasurandParser extends 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, int index,
-                @Nullable ChannelTypeUID channelTypeUID) {
-            super(index);
-            this.channelId = channelId;
-            this.name = name;
-            this.measureType = measureType;
-            this.channelTypeUID = channelTypeUID == null ? measureType.getChannelTypeId() : channelTypeUID;
-        }
-
-        public int extractMeasuredValues(byte[] data, int offset, ConversionContext context,
-                List<MeasuredValue> result) {
-            State state = measureType.toState(data, offset, context);
-            if (state != null) {
-                result.add(new MeasuredValue(measureType, channelId, channelTypeUID, state, name));
-            }
-            return measureType.getByteSize();
-        }
-    }
-
-    public int extractMeasuredValues(byte code, byte[] data, int offset, ConversionContext context,
-            List<MeasuredValue> result) {
-        List<Parser> parsers = parsersPerCode.get(code);
-        if (parsers == null) {
-            throw new IllegalArgumentException("No measurement for code 0x" + Integer.toHexString(code) + " defined");
-        }
-        int subOffset = 0;
-        for (Parser parser : parsers) {
-            subOffset += parser.extractMeasuredValues(data, offset + subOffset, context, result);
-        }
-        return subOffset;
-    }
-}
index 0ca9da2b63a3b01e02e5a804f2c2debbd4aa9659..1eb9ad301cd5acfe7fbc7d12be78c7bb7bdae5c2 100644 (file)
@@ -27,13 +27,20 @@ import org.openhab.binding.fineoffsetweatherstation.internal.service.GatewayQuer
  */
 @NonNullByDefault
 public enum Protocol {
-    DEFAULT(FineOffsetGatewayQueryService::new),
-    ELV(ELVGatewayQueryService::new);
+    DEFAULT(FineOffsetGatewayQueryService::new, null),
+    ELV(ELVGatewayQueryService::new, Measurand.ParserCustomizationType.ELV);
 
     private final GatewayQueryServiceFactory queryServiceFactory;
+    private final Measurand.@Nullable ParserCustomizationType parserCustomizationType;
 
-    Protocol(GatewayQueryServiceFactory queryServiceFactory) {
+    Protocol(GatewayQueryServiceFactory queryServiceFactory,
+            Measurand.@Nullable ParserCustomizationType parserCustomizationType) {
         this.queryServiceFactory = queryServiceFactory;
+        this.parserCustomizationType = parserCustomizationType;
+    }
+
+    public Measurand.@Nullable ParserCustomizationType getParserCustomizationType() {
+        return parserCustomizationType;
     }
 
     public GatewayQueryService getGatewayQueryService(FineOffsetGatewayConfiguration config,
index ba42b3c0a4be7e6eb3fad6371a652e592c56197f..45cb0e675e59a0562e446cd19e415589641c604b 100644 (file)
@@ -26,26 +26,32 @@ import org.openhab.core.types.State;
 @NonNullByDefault
 public class MeasuredValue {
     private final MeasureType measureType;
-    private final String channelId;
+    private final String channelPrefix;
+    private final @Nullable Integer channelNumber;
     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) {
+    public MeasuredValue(MeasureType measureType, String channelPrefix, @Nullable Integer channelNumber,
+            @Nullable ChannelTypeUID channelTypeUID, State state, String debugName) {
         this.measureType = measureType;
-        this.channelId = channelId;
+        this.channelPrefix = channelPrefix;
+        this.channelNumber = channelNumber;
         this.channelTypeUID = channelTypeUID;
         this.state = state;
         this.debugName = debugName;
     }
 
-    public MeasureType getMeasureType() {
-        return measureType;
+    public String getChannelId() {
+        return channelNumber == null ? channelPrefix : (channelPrefix + "-" + channelNumber);
     }
 
-    public String getChannelId() {
-        return channelId;
+    public String getChannelPrefix() {
+        return channelPrefix;
+    }
+
+    public @Nullable Integer getChannelNumber() {
+        return channelNumber;
     }
 
     public @Nullable ChannelTypeUID getChannelTypeUID() {
@@ -62,7 +68,7 @@ public class MeasuredValue {
 
     @Override
     public String toString() {
-        return "MeasuredValue{" + "measureType=" + measureType + ", channelId='" + channelId + '\''
+        return "MeasuredValue{" + "measureType=" + measureType + ", channelId='" + getChannelId() + '\''
                 + ", channelTypeUID=" + channelTypeUID + ", state=" + state + ", debugName='" + debugName + '\'' + '}';
     }
 }
index aa91798d413d9ab57f63cf591cfba78176760290..55837928ea6e431d75de2957950061144456ab47 100644 (file)
@@ -17,6 +17,7 @@ import static org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetWe
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -30,7 +31,6 @@ 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;
@@ -156,7 +156,7 @@ public class FineOffsetGatewayHandler extends BaseBridgeHandler {
         if (disposed) {
             return;
         }
-        List<MeasuredValue> data = query(GatewayQueryService::getMeasuredValues);
+        Collection<MeasuredValue> data = query(GatewayQueryService::getMeasuredValues);
         if (data == null) {
             getThing().getChannels().forEach(c -> updateState(c.getUID(), UnDefType.UNDEF));
             return;
@@ -189,15 +189,14 @@ public class FineOffsetGatewayHandler extends BaseBridgeHandler {
         }
         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 channelKey = THING_TYPE_GATEWAY.getId() + ".dynamic-channel." + measuredValue.getChannelPrefix();
         String label = translationProvider.getText(bundle, channelKey + ".label", measuredValue.getDebugName(),
-                localeProvider.getLocale());
+                localeProvider.getLocale(), measuredValue.getChannelNumber());
         if (label != null) {
             builder.withLabel(label);
         }
         String description = translationProvider.getText(bundle, channelKey + ".description", null,
-                localeProvider.getLocale());
+                localeProvider.getLocale(), measuredValue.getChannelNumber());
         if (description != null) {
             builder.withDescription(description);
         }
index 88506094bb640e1d7696495196b2155239c49a80..116e22ec46cd8e5066f49b262f11827219b36b8a 100644 (file)
@@ -22,6 +22,7 @@ import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.Sen
 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.Channel;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -31,8 +32,6 @@ import org.openhab.core.thing.binding.BaseThingHandler;
 import org.openhab.core.types.Command;
 import org.openhab.core.types.UnDefType;
 
-import tech.units.indriya.unit.Units;
-
 /**
  * The {@link FineOffsetSensorHandler} keeps track of the signal and battery of the sensor attached to the gateway.
  *
index 5bd28d0c44b0de4dbfa31e6e58375d158fa3a0ed..2acad4a24359acacecd31deccad88830c51461a8 100644 (file)
@@ -27,7 +27,7 @@ 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.Measurands;
+import org.openhab.binding.fineoffsetweatherstation.internal.domain.Measurand;
 import org.openhab.binding.fineoffsetweatherstation.internal.domain.Protocol;
 import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding;
 import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.BatteryStatus;
@@ -174,17 +174,25 @@ public class FineOffsetDataParser {
         if (protocol == Protocol.ELV) {
             idx++; // at index 5 there is an additional Byte being set to 0x04
         }
+        return readMeasuredValues(data, idx, context, protocol.getParserCustomizationType());
+    }
+
+    List<MeasuredValue> getRainData(byte[] data, ConversionContext context) {
+        return readMeasuredValues(data, 5, context, Measurand.ParserCustomizationType.RAIN_READING);
+    }
+
+    private List<MeasuredValue> readMeasuredValues(byte[] data, int idx, ConversionContext context,
+            Measurand.@Nullable ParserCustomizationType protocol) {
         var size = toUInt16(data, 3);
         List<MeasuredValue> result = new ArrayList<>();
-        Measurands measurands = Measurands.getInstance(protocol);
         while (idx < size) {
             byte code = data[idx++];
-            try {
-                idx += measurands.extractMeasuredValues(code, data, idx, context, result);
-            } catch (IllegalArgumentException e) {
-                logger.warn("", e);
+            Measurand.SingleChannelMeasurand 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, protocol, result);
         }
         return result;
     }
index 7520f954087586088bab1db9ba41b1472424aa0d..fdcf5243eeed49d7d1581d63b18ff12219e99cb1 100644 (file)
@@ -12,7 +12,8 @@
  */
 package org.openhab.binding.fineoffsetweatherstation.internal.service;
 
-import java.util.Collections;
+import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -86,12 +87,26 @@ public class FineOffsetGatewayQueryService extends GatewayQueryService {
     }
 
     @Override
-    public List<MeasuredValue> getMeasuredValues() {
+    public Collection<MeasuredValue> getMeasuredValues() {
+        Map<String, MeasuredValue> valuePerChannel = new LinkedHashMap<>();
+
         byte[] data = executeCommand(Command.CMD_GW1000_LIVEDATA);
-        if (data == null) {
-            return Collections.emptyList();
+        if (data != null) {
+            List<MeasuredValue> measuredValues = fineOffsetDataParser.getMeasuredValues(data, conversionContext);
+            for (MeasuredValue measuredValue : measuredValues) {
+                valuePerChannel.put(measuredValue.getChannelId(), measuredValue);
+            }
         }
-        return fineOffsetDataParser.getMeasuredValues(data, conversionContext);
+
+        data = executeCommand(Command.CMD_READ_RAIN);
+        if (data != null) {
+            List<MeasuredValue> measuredRainValues = fineOffsetDataParser.getRainData(data, conversionContext);
+            for (MeasuredValue measuredValue : measuredRainValues) {
+                valuePerChannel.put(measuredValue.getChannelId(), measuredValue);
+            }
+        }
+
+        return valuePerChannel.values();
     }
 
     protected byte @Nullable [] executeCommand(Command command) {
index 4f28ac8f6ce1589be48c13c94b302000bb5a9ac3..94ca5769f3bcc4b19ef5d59cc4befa701022c980 100644 (file)
@@ -16,7 +16,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.Socket;
 import java.util.Arrays;
-import java.util.List;
+import java.util.Collection;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
@@ -63,7 +63,7 @@ public abstract class GatewayQueryService implements AutoCloseable {
     @Nullable
     public abstract SystemInfo fetchSystemInfo();
 
-    public abstract List<MeasuredValue> getMeasuredValues();
+    public abstract Collection<MeasuredValue> getMeasuredValues();
 
     public GatewayQueryService(FineOffsetGatewayConfiguration config,
             @Nullable ThingStatusListener thingStatusListener) {
index 81e8310c6191cd207f0ded6683f54f83b630776f..9ec4c045b256a11b29fc2dedd1107e4b8b04f804 100644 (file)
@@ -76,119 +76,63 @@ thing.sensor.WH68.description = Solar-powered Sensor for Wind Speed & Direction,
 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
+thing.sensor.WH90.description = Ultrasonic sensor for wind speed & direction, solar radiation & light, temperature, humidity and haptic rainfall Sensor
 
 # 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
 thing-type.fineoffsetweatherstation.sensor.channel.batteryVoltage.label = Battery Voltage
+
+# dynamic channels
+
+gateway.dynamic-channel.temperature-indoor.label = Indoor Temperature
+gateway.dynamic-channel.temperature-outdoor.label = Outdoor Temperature
+gateway.dynamic-channel.temperature-dew-point.label = Dew Point
+gateway.dynamic-channel.temperature-wind-chill.label = Perceived Temperature
+gateway.dynamic-channel.temperature-heat-index.label = Heat Index
+gateway.dynamic-channel.humidity-indoor.label = Humidity Inside
+gateway.dynamic-channel.humidity-outdoor.label = Humidity Outside
+gateway.dynamic-channel.pressure-absolute.label = Absolute Pressure
+gateway.dynamic-channel.pressure-relative.label = Relative Pressure
+gateway.dynamic-channel.direction-wind.label = Wind Direction
+gateway.dynamic-channel.speed-wind.label = Wind Speed
+gateway.dynamic-channel.speed-gust.label = Gust Speed
+gateway.dynamic-channel.rain-event.label = Amount of Rainfall At the last Rain
+gateway.dynamic-channel.rain-rate.label = Rainfall Rate
+gateway.dynamic-channel.rain-hour.label = Rainfall Current Hour
+gateway.dynamic-channel.rain-day.label = Rainfall Today
+gateway.dynamic-channel.rain-week.label = Rainfall this Week
+gateway.dynamic-channel.rain-month.label = Rainfall this Month
+gateway.dynamic-channel.rain-year.label = Rainfall this Year
+gateway.dynamic-channel.rain-total.label = Rainfall Total
+gateway.dynamic-channel.illumination.label = Light Intensity
+gateway.dynamic-channel.irradiation-uv.label = UV Irradiation
+gateway.dynamic-channel.uv-index.label = UV Index
+gateway.dynamic-channel.time.label = Date and Time
+gateway.dynamic-channel.wind-max-day.label = Maximum Wind Speed Today
+gateway.dynamic-channel.temperature-channel.label = Temperature Channel {0}
+gateway.dynamic-channel.humidity-channel.label = Humidity Channel {0}
+gateway.dynamic-channel.temperature-soil-channel.label = Soil Temperature Channel {0}
+gateway.dynamic-channel.moisture-soil-channel.label = Soil Moisture Channel {0}
+gateway.dynamic-channel.air-quality-24-hour-average-channel.label = PM2.5 Air Quality 24 Hour Average Channel {0}
+gateway.dynamic-channel.air-quality-channel.label = PM2.5 Air Quality Channel {0}
+gateway.dynamic-channel.water-leak-channel.label = Water Leak Detection Channel {0}
+gateway.dynamic-channel.lightning-distance.label = Lightning Distance
+gateway.dynamic-channel.lightning-time.label = Time of last Lightning Strike
+gateway.dynamic-channel.lightning-counter.label = Lightning Strikes Today
+gateway.dynamic-channel.temperature-external-channel.label = External Temperature Sensor Channel {0}
+gateway.dynamic-channel.sensor-co2-temperature.label = Temperature (CO2-Sensor)
+gateway.dynamic-channel.sensor-co2-humidity.label = Humidity (CO2-Sensor)
+gateway.dynamic-channel.sensor-co2-pm10.label = PM10 Air Quality (CO2-Sensor)
+gateway.dynamic-channel.sensor-co2-pm10-24-hour-average.label = PM10 Air Quality 24 Hour Average (CO2-Sensor)
+gateway.dynamic-channel.sensor-co2-pm25.label = PM2.5 Air Quality (CO2-Sensor)
+gateway.dynamic-channel.sensor-co2-pm25-24-hour-average.label = PM2.5 Air Quality 24 Hour Average (CO2-Sensor)
+gateway.dynamic-channel.sensor-co2-co2.label = CO2
+gateway.dynamic-channel.sensor-co2-co2-24-hour-average.label = CO2 24 Hour Average
+gateway.dynamic-channel.leaf-wetness-channel.label = Leaf Moisture Channel {0}
+gateway.dynamic-channel.piezo-rain-rate.label = Rain Rate
+gateway.dynamic-channel.piezo-rain-event.label = Rain Event
+gateway.dynamic-channel.piezo-rain-hour.label = Rain hour
+gateway.dynamic-channel.piezo-rain-day.label = Rain Day
+gateway.dynamic-channel.piezo-rain-week.label = Rain Week
+gateway.dynamic-channel.piezo-rain-month.label = Rain Month
+gateway.dynamic-channel.piezo-rain-year.label = Rain Year
diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/measurands.csv b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/resources/measurands.csv
deleted file mode 100644 (file)
index 4858263..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-ManufacturerName,Name,Channel,Code,Index,Skip,ChannelType,MeasureType_DEFAULT,MeasureType_ELV
-INTEMP,Indoor Temperature,temperature-indoor,0x1,,,system:indoor-temperature,TEMPERATURE,
-OUTTEMP,Outdoor Temperature,temperature-outdoor,0x2,,,system:outdoor-temperature,TEMPERATURE,
-DEWPOINT,Dew point,temperature-dew-point,0x3,,,,TEMPERATURE,
-WINDCHILL,Wind chill,temperature-wind-chill,0x4,,,,TEMPERATURE,
-HEATINDEX,Heat index,temperature-heat-index,0x5,,,,TEMPERATURE,
-INHUMI,Indoor Humidity,humidity-indoor,0x6,,,,PERCENTAGE,
-OUTHUMI,Outdoor Humidity,humidity-outdoor,0x7,,,system:atmospheric-humidity,PERCENTAGE,
-ABSBARO,Absolutely pressure,pressure-absolute,0x8,,,,PRESSURE,
-RELBARO,Relative pressure,pressure-relative,0x9,,,system:barometric-pressure,PRESSURE,
-WINDDIRECTION,Wind Direction,direction-wind,0xa,,,system:wind-direction,DEGREE,
-WINDSPEED,Wind Speed,speed-wind,0xb,,,system:wind-speed,SPEED,
-GUSTSPEED,Gust Speed,speed-gust,0xc,,,system:wind-speed,SPEED,
-RAINEVENT,Rain Event,rain-event,0xd,,,,HEIGHT,HEIGHT_BIG
-RAINRATE,Rain Rate,rain-rate,0xe,,,,HEIGHT_PER_HOUR,HEIGHT_PER_HOUR_BIG
-RAINHOUR,Rain hour,rain-hour,0xf,,,,HEIGHT,HEIGHT_BIG
-RAINDAY,Rain Day,rain-day,0x10,,,,HEIGHT,HEIGHT_BIG
-RAINWEEK,Rain Week,rain-week,0x11,,,,HEIGHT,HEIGHT_BIG
-RAINMONTH,Rain Month,rain-month,0x12,,,,HEIGHT_BIG,
-RAINYEAR,Rain Year,rain-year,0x13,,,,HEIGHT_BIG,
-RAINTOTALS,Rain Totals,rain-total,0x14,,,,HEIGHT_BIG,
-LIGHT,Light,illumination,0x15,,,,LUX,
-UV,UV,irradiation-uv,0x16,,,,MILLIWATT_PER_SQUARE_METRE,
-UVI,UV index,uv-index,0x17,,,uv-index,BYTE,
-TIME,Date and time,time,0x18,,,,DATE_TIME2,
-DAYLWINDMAX,Day max wind,wind-max-day,0x19,,,max-wind-speed,SPEED,
-TEMP1,Temperature 1,temperature-channel-1,0x1a,,,,TEMPERATURE,
-TEMP2,Temperature 2,temperature-channel-2,0x1b,,,,TEMPERATURE,
-TEMP3,Temperature 3,temperature-channel-3,0x1c,,,,TEMPERATURE,
-TEMP4,Temperature 4,temperature-channel-4,0x1d,,,,TEMPERATURE,
-TEMP5,Temperature 5,temperature-channel-5,0x1e,,,,TEMPERATURE,
-TEMP6,Temperature 6,temperature-channel-6,0x1f,,,,TEMPERATURE,
-TEMP7,Temperature 7,temperature-channel-7,0x20,,,,TEMPERATURE,
-TEMP8,Temperature 8,temperature-channel-8,0x21,,,,TEMPERATURE,
-HUMI1,Humidity 1,humidity-channel-1,0x22,,,,PERCENTAGE,
-HUMI2,Humidity 2,humidity-channel-2,0x23,,,,PERCENTAGE,
-HUMI3,Humidity 3,humidity-channel-3,0x24,,,,PERCENTAGE,
-HUMI4,Humidity 4,humidity-channel-4,0x25,,,,PERCENTAGE,
-HUMI5,Humidity 5,humidity-channel-5,0x26,,,,PERCENTAGE,
-HUMI6,Humidity 6,humidity-channel-6,0x27,,,,PERCENTAGE,
-HUMI7,Humidity 7,humidity-channel-7,0x28,,,,PERCENTAGE,
-HUMI8,Humidity 8,humidity-channel-8,0x29,,,,PERCENTAGE,
-SOILTEMP1,Soil Temperature 1,temperature-soil-channel-1,0x2b,,,,TEMPERATURE,
-SOILTEMP2,Soil Temperature 2,temperature-soil-channel-2,0x2d,,,,TEMPERATURE,
-SOILTEMP3,Soil Temperature 3,temperature-soil-channel-3,0x2f,,,,TEMPERATURE,
-SOILTEMP4,Soil Temperature 4,temperature-soil-channel-4,0x31,,,,TEMPERATURE,
-SOILTEMP5,Soil Temperature 5,temperature-soil-channel-5,0x33,,,,TEMPERATURE,
-SOILTEMP6,Soil Temperature 6,temperature-soil-channel-6,0x35,,,,TEMPERATURE,
-SOILTEMP7,Soil Temperature 7,temperature-soil-channel-7,0x37,,,,TEMPERATURE,
-SOILTEMP8,Soil Temperature 8,temperature-soil-channel-8,0x39,,,,TEMPERATURE,
-SOILTEMP9,Soil Temperature 9,temperature-soil-channel-9,0x3b,,,,TEMPERATURE,
-SOILTEMP10,Soil Temperature 10,temperature-soil-channel-10,0x3d,,,,TEMPERATURE,
-SOILTEMP11,Soil Temperature 11,temperature-soil-channel-11,0x3f,,,,TEMPERATURE,
-SOILTEMP12,Soil Temperature 12,temperature-soil-channel-12,0x41,,,,TEMPERATURE,
-SOILTEMP13,Soil Temperature 13,temperature-soil-channel-13,0x43,,,,TEMPERATURE,
-SOILTEMP14,Soil Temperature 14,temperature-soil-channel-14,0x45,,,,TEMPERATURE,
-SOILTEMP15,Soil Temperature 15,temperature-soil-channel-15,0x47,,,,TEMPERATURE,
-SOILTEMP16,Soil Temperature 16,temperature-soil-channel-16,0x49,,,,TEMPERATURE,
-SOILMOISTURE1,Soil Moisture 1,moisture-soil-channel-1,0x2c,,,moisture,PERCENTAGE,
-SOILMOISTURE2,Soil Moisture 2,moisture-soil-channel-2,0x2e,,,moisture,PERCENTAGE,
-SOILMOISTURE3,Soil Moisture 3,moisture-soil-channel-3,0x30,,,moisture,PERCENTAGE,
-SOILMOISTURE4,Soil Moisture 4,moisture-soil-channel-4,0x32,,,moisture,PERCENTAGE,
-SOILMOISTURE5,Soil Moisture 5,moisture-soil-channel-5,0x34,,,moisture,PERCENTAGE,
-SOILMOISTURE6,Soil Moisture 6,moisture-soil-channel-6,0x36,,,moisture,PERCENTAGE,
-SOILMOISTURE7,Soil Moisture 7,moisture-soil-channel-7,0x38,,,moisture,PERCENTAGE,
-SOILMOISTURE8,Soil Moisture 8,moisture-soil-channel-8,0x3a,,,moisture,PERCENTAGE,
-SOILMOISTURE9,Soil Moisture 9,moisture-soil-channel-9,0x3c,,,moisture,PERCENTAGE,
-SOILMOISTURE10,Soil Moisture 10,moisture-soil-channel-10,0x3e,,,moisture,PERCENTAGE,
-SOILMOISTURE11,Soil Moisture 11,moisture-soil-channel-11,0x40,,,moisture,PERCENTAGE,
-SOILMOISTURE12,Soil Moisture 12,moisture-soil-channel-12,0x42,,,moisture,PERCENTAGE,
-SOILMOISTURE13,Soil Moisture 13,moisture-soil-channel-13,0x44,,,moisture,PERCENTAGE,
-SOILMOISTURE14,Soil Moisture 14,moisture-soil-channel-14,0x46,,,moisture,PERCENTAGE,
-SOILMOISTURE15,Soil Moisture 15,moisture-soil-channel-15,0x48,,,moisture,PERCENTAGE,
-SOILMOISTURE16,Soil Moisture 16,moisture-soil-channel-16,0x4a,,,moisture,PERCENTAGE,
-LOWBATT,Low Battery,,0x4c,,1,,,
-PM25_24HAVG1,PM2.5 Air Quality 24 hour average channel 1,air-quality-24-hour-average-channel-1,0x4d,,,,PM25,
-PM25_24HAVG2,PM2.5 Air Quality 24 hour average channel 2,air-quality-24-hour-average-channel-2,0x4e,,,,PM25,
-PM25_24HAVG3,PM2.5 Air Quality 24 hour average channel 3,air-quality-24-hour-average-channel-3,0x4f,,,,PM25,
-PM25_24HAVG4,PM2.5 Air Quality 24 hour average channel 4,air-quality-24-hour-average-channel-4,0x50,,,,PM25,
-PM25_CH1,PM2.5 Air Quality channel 1,air-quality-channel-1,0x2a,,,,PM25,
-PM25_CH2,PM2.5 Air Quality channel 2,air-quality-channel-2,0x51,,,,PM25,
-PM25_CH3,PM2.5 Air Quality channel 3,air-quality-channel-3,0x52,,,,PM25,
-PM25_CH4,PM2.5 Air Quality channel 4,air-quality-channel-4,0x53,,,,PM25,
-LEAK_CH1,Leak channel 1,water-leak-channel-1,0x58,,,,WATER_LEAK_DETECTION,
-LEAK_CH2,Leak channel 2,water-leak-channel-2,0x59,,,,WATER_LEAK_DETECTION,
-LEAK_CH3,Leak channel 3,water-leak-channel-3,0x5a,,,,WATER_LEAK_DETECTION,
-LEAK_CH4,Leak channel 4,water-leak-channel-4,0x5b,,,,WATER_LEAK_DETECTION,
-LIGHTNING,lightning distance 1~40KM,lightning-distance,0x60,,,,LIGHTNING_DISTANCE,
-LIGHTNING_TIME,lightning happened time,lightning-time,0x61,,,,LIGHTNING_TIME,
-LIGHTNING_POWER,lightning counter for the day,lightning-counter,0x62,,,,LIGHTNING_COUNTER,
-TF_USR1,Soil or Water temperature channel 1,temperature-external-channel-1,0x63,,,,TEMPERATURE,
-TF_USR2,Soil or Water temperature channel 2,temperature-external-channel-2,0x64,,,,TEMPERATURE,
-TF_USR3,Soil or Water temperature channel 3,temperature-external-channel-3,0x65,,,,TEMPERATURE,
-TF_USR4,Soil or Water temperature channel 4,temperature-external-channel-4,0x66,,,,TEMPERATURE,
-TF_USR5,Soil or Water temperature channel 5,temperature-external-channel-5,0x67,,,,TEMPERATURE,
-TF_USR6,Soil or Water temperature channel 6,temperature-external-channel-6,0x68,,,,TEMPERATURE,
-TF_USR7,Soil or Water temperature channel 7,temperature-external-channel-7,0x69,,,,TEMPERATURE,
-TF_USR8,Soil or Water temperature channel 8,temperature-external-channel-8,0x6a,,,,TEMPERATURE,
-ITEM_SENSOR_CO2,Temperature (CO₂-Sensor),sensor-co2-temperature,0x70,0,,,TEMPERATURE,
-ITEM_SENSOR_CO2,Humidity (CO₂-Sensor),sensor-co2-humidity,0x70,1,,,PERCENTAGE,
-ITEM_SENSOR_CO2,PM10 Air Quality (CO₂-Sensor),sensor-co2-pm10,0x70,2,,,PM10,
-ITEM_SENSOR_CO2,PM10 Air Quality 24 hour average (CO₂-Sensor),sensor-co2-pm10-24-hour-average,0x70,3,,,PM10,
-ITEM_SENSOR_CO2,PM2.5 Air Quality (CO₂-Sensor),sensor-co2-pm25,0x70,4,,,PM25,
-ITEM_SENSOR_CO2,PM2.5 Air Quality 24 hour average (CO₂-Sensor),sensor-co2-pm25-24-hour-average,0x70,5,,,PM25,
-ITEM_SENSOR_CO2,CO₂,sensor-co2-co2,0x70,6,,,CO2,
-ITEM_SENSOR_CO2,CO₂ 24 hour average,sensor-co2-co2-24-hour-average,0x70,7,,,CO2,
-ITEM_SENSOR_CO2,Battery Level,,0x70,8,1,,,
-ITEM_LEAF_WETNESS_CH1,Leaf Moisture channel 1,leaf-wetness-channel-1,0x72,,,moisture,PERCENTAGE,
-ITEM_LEAF_WETNESS_CH2,Leaf Moisture channel 2,leaf-wetness-channel-2,0x73,,,moisture,PERCENTAGE,
-ITEM_LEAF_WETNESS_CH3,Leaf Moisture channel 3,leaf-wetness-channel-3,0x74,,,moisture,PERCENTAGE,
-ITEM_LEAF_WETNESS_CH4,Leaf Moisture channel 4,leaf-wetness-channel-4,0x75,,,moisture,PERCENTAGE,
-ITEM_LEAF_WETNESS_CH5,Leaf Moisture channel 5,leaf-wetness-channel-5,0x76,,,moisture,PERCENTAGE,
-ITEM_LEAF_WETNESS_CH6,Leaf Moisture channel 6,leaf-wetness-channel-6,0x77,,,moisture,PERCENTAGE,
-ITEM_LEAF_WETNESS_CH7,Leaf Moisture channel 7,leaf-wetness-channel-7,0x78,,,moisture,PERCENTAGE,
-ITEM_LEAF_WETNESS_CH8,Leaf Moisture channel 8,leaf-wetness-channel-8,0x79,,,moisture,PERCENTAGE,
index 52c765b7f61884de5cddc8b56e2faed7c3b80d22..088d5181912140a8bfa9bf1e6b1420fe8658cad9 100644 (file)
@@ -20,6 +20,7 @@ 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.Command;
 import org.openhab.binding.fineoffsetweatherstation.internal.domain.ConversionContext;
 import org.openhab.binding.fineoffsetweatherstation.internal.domain.Protocol;
 import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue;
@@ -74,6 +75,34 @@ class FineOffsetDataParserTest {
                         new Tuple("irradiation-uv", "215.3 mW/m²"), new Tuple("uv-index", "5"));
     }
 
+    @Test
+    void testRainData() {
+        byte[] data = Hex
+                .decode("FFFF5700290E000010000000001100000024120000003113000005030D00000F0064880000017A017B0030");
+        List<MeasuredValue> measuredValues = new FineOffsetDataParser(Protocol.DEFAULT).getRainData(data,
+                new ConversionContext(ZoneOffset.UTC));
+        Assertions.assertThat(measuredValues)
+                .extracting(MeasuredValue::getChannelId, measuredValue -> measuredValue.getState().toString())
+                .containsExactly(new Tuple("rain-rate", "0 mm/h"), new Tuple("rain-day", "0 mm"),
+                        new Tuple("rain-week", "3.6 mm"), new Tuple("rain-month", "4.9 mm"),
+                        new Tuple("rain-year", "128.3 mm"), new Tuple("rain-event", "0 mm"),
+                        new Tuple("rain-hour", "10 mm"));
+    }
+
+    @Test
+    void testRainDataW90() {
+        byte[] data = Hex.decode(
+                "FFFF5700398000008300000009840000000985000000C786000000C7810000870064006400640064006400640064006400640064880900007A02BF");
+        Assertions.assertThat(Command.CMD_READ_RAIN.isResponseValid(data)).isTrue();
+        List<MeasuredValue> measuredValues = new FineOffsetDataParser(Protocol.DEFAULT).getRainData(data,
+                new ConversionContext(ZoneOffset.UTC));
+        Assertions.assertThat(measuredValues)
+                .extracting(MeasuredValue::getChannelId, measuredValue -> measuredValue.getState().toString())
+                .containsExactly(new Tuple("piezo-rain-rate", "0 mm/h"), new Tuple("piezo-rain-day", "0.9 mm"),
+                        new Tuple("piezo-rain-week", "0.9 mm"), new Tuple("piezo-rain-month", "19.9 mm"),
+                        new Tuple("piezo-rain-year", "19.9 mm"), new Tuple("piezo-rain-event", "0 mm"));
+    }
+
     @Test
     void testFirmware() {
         byte[] data = Hex.decode("FFFF501511456173795765617468657256312E362E3400");