From fbc412c1dc67a4220979a0bec2ce259173bbc297 Mon Sep 17 00:00:00 2001 From: Andreas Berger Date: Fri, 10 Nov 2023 13:29:25 +0100 Subject: [PATCH] [fineoffsetweatherstation] Fix wrong handling temperature reading for of WH34 (#15853) * [fineoffsetweatherstation] Improve tracing * [fineoffsetweatherstation] Fix wrong handling temperature reading for of WH34 Signed-off-by: Andreas Berger --- .../README.md | 2 +- .../internal/domain/Command.java | 4 + .../internal/domain/DebugDetails.java | 79 +++++++++++++++++++ .../internal/domain/Measurand.java | 35 +++++--- .../service/ELVGatewayQueryService.java | 7 +- .../service/FineOffsetDataParser.java | 18 +++-- .../FineOffsetGatewayQueryService.java | 14 +++- .../internal/service/GatewayQueryService.java | 2 +- .../service/FineOffsetDataParserTest.java | 48 +++++++++-- 9 files changed, 182 insertions(+), 27 deletions(-) create mode 100644 bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/DebugDetails.java diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/README.md b/bundles/org.openhab.binding.fineoffsetweatherstation/README.md index fcfed15c69c71..fa4bb744e67e3 100644 --- a/bundles/org.openhab.binding.fineoffsetweatherstation/README.md +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/README.md @@ -19,7 +19,7 @@ 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. +This binding works offline by [implementing the wire protocol](https://osswww.ecowitt.net/uploads/20220407/WN1900%20GW1000,1100%20WH2680,2650%20telenet%20v1.6.4.pdf) of the WiFi gateway device. ## Discussion 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 index eb2872865154d..dd81779c990ee 100644 --- 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 @@ -275,4 +275,8 @@ public boolean isHeaderValid(byte[] data) { public boolean isResponseValid(byte[] data) { return isHeaderValid(data) && Utils.validateChecksum(data, sizeBytes); } + + public int getSizeBytes() { + return sizeBytes; + } } diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/DebugDetails.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/DebugDetails.java new file mode 100644 index 0000000000000..7d2eb17e709f6 --- /dev/null +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/DebugDetails.java @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2010-2023 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 java.util.Map; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.openhab.binding.fineoffsetweatherstation.internal.Utils; + +/** + * Class to collect debug details + * + * @author Andreas Berger - Initial contribution + */ +public class DebugDetails { + final byte[] data; + + private final Map segments = new TreeMap<>(); + + public DebugDetails(byte[] data, Command command, Protocol protocol) { + this.data = data; + addDebugDetails(0, 2, "header"); + addDebugDetails(2, 1, "command: " + command.name()); + addDebugDetails(3, command.getSizeBytes(), "size"); + if (protocol == Protocol.ELV) { + addDebugDetails(data.length - 2, 1, "ELV checksum"); + } + addDebugDetails(data.length - 1, 1, "checksum"); + } + + public void addDebugDetails(int start, int length, String description) { + segments.put(start, new DebugSegment(start, length, description)); + } + + @Override + public String toString() { + int padding = segments.values().stream().mapToInt(value -> value.length).max().orElse(0) * 2; + return "0x" + Utils.toHexString(data, data.length, "") + "\n" + segments.values().stream() + .map(debugSegment -> debugSegment.toDebugString(padding)).collect(Collectors.joining("\n")); + } + + private class DebugSegment { + final int start; + final int length; + final String description; + + DebugSegment(int start, int length, String description) { + this.start = start; + this.length = length; + this.description = description; + } + + @Override + public String toString() { + return toDebugString(0); + } + + private String toDebugString(int padding) { + String result = "0x"; + String hexString = Utils.toHexString(Arrays.copyOfRange(data, start, start + length), length, ""); + result += StringUtils.rightPad(hexString, padding, " "); + result += ": " + description; + return result; + } + } +} 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 index 1693b73445963..1dbe4935ba83b 100644 --- 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 @@ -138,8 +138,10 @@ public enum Measurand { // `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), + TF_USRX(new int[] { 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A }, + new MeasurandParser("temperature-external-channel", "Soil or Water temperature", MeasureType.TEMPERATURE), + // skip battery-level, since it is read via Command.CMD_READ_SENSOR_ID_NEW + new Skip(1)), ITEM_SENSOR_CO2(0x70, new MeasurandParser("sensor-co2-temperature", "Temperature (CO₂-Sensor)", MeasureType.TEMPERATURE), @@ -240,18 +242,20 @@ public enum Measurand { } private int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context, - @Nullable ParserCustomizationType customizationType, List result) { + @Nullable ParserCustomizationType customizationType, List result, + DebugDetails debugDetails) { int subOffset = 0; for (Parser parser : parsers) { subOffset += parser.extractMeasuredValues(data, offset + subOffset, channel, context, customizationType, - result); + result, debugDetails); } return subOffset; } private interface Parser { int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context, - @Nullable ParserCustomizationType customizationType, List result); + @Nullable ParserCustomizationType customizationType, List result, + DebugDetails debugDetails); } private static class Skip implements Parser { @@ -263,7 +267,9 @@ public Skip(int skip) { @Override public int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context, - @Nullable ParserCustomizationType customizationType, List result) { + @Nullable ParserCustomizationType customizationType, List result, + DebugDetails debugDetails) { + debugDetails.addDebugDetails(offset, skip, "skipped"); return skip; } } @@ -302,8 +308,14 @@ public SingleChannelMeasurand(Measurand measurand, @Nullable Integer channel) { } public int extractMeasuredValues(byte[] data, int offset, ConversionContext context, - @Nullable ParserCustomizationType customizationType, List result) { - return measurand.extractMeasuredValues(data, offset, channel, context, customizationType, result); + @Nullable ParserCustomizationType customizationType, List result, + DebugDetails debugDetails) { + return measurand.extractMeasuredValues(data, offset, channel, context, customizationType, result, + debugDetails); + } + + public String getDebugString() { + return measurand.name() + (channel == null ? "" : " channel " + channel); } } @@ -337,12 +349,17 @@ private static class MeasurandParser implements Parser { @Override public int extractMeasuredValues(byte[] data, int offset, @Nullable Integer channel, ConversionContext context, - @Nullable ParserCustomizationType customizationType, List result) { + @Nullable ParserCustomizationType customizationType, List result, + DebugDetails debugDetails) { MeasureType measureType = getMeasureType(customizationType); State state = measureType.toState(data, offset, context); if (state != null) { + debugDetails.addDebugDetails(offset, measureType.getByteSize(), + measureType.name() + ": " + state.toFullString()); ChannelTypeUID channelType = channelTypeUID == null ? measureType.getChannelTypeId() : channelTypeUID; result.add(new MeasuredValue(measureType, channelPrefix, channel, channelType, state, name)); + } else { + debugDetails.addDebugDetails(offset, measureType.getByteSize(), measureType.name() + ": null"); } return measureType.getByteSize(); } diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/ELVGatewayQueryService.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/ELVGatewayQueryService.java index 2e60c9f2ff27e..02e076e78706b 100644 --- a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/ELVGatewayQueryService.java +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/ELVGatewayQueryService.java @@ -21,6 +21,7 @@ import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetGatewayConfiguration; import org.openhab.binding.fineoffsetweatherstation.internal.domain.Command; import org.openhab.binding.fineoffsetweatherstation.internal.domain.ConversionContext; +import org.openhab.binding.fineoffsetweatherstation.internal.domain.DebugDetails; import org.openhab.binding.fineoffsetweatherstation.internal.domain.Protocol; import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding; import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue; @@ -79,6 +80,10 @@ public List getMeasuredValues() { if (data == null) { return Collections.emptyList(); } - return fineOffsetDataParser.getMeasuredValues(data, conversionContext); + DebugDetails debugDetails = new DebugDetails(data, Command.CMD_WS980_LIVEDATA, Protocol.ELV); + List measuredValues = fineOffsetDataParser.getMeasuredValues(data, conversionContext, + debugDetails); + logger.trace("{}", debugDetails); + return measuredValues; } } 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 index fc8922db53cda..c1ce0fd76ef9f 100644 --- 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 @@ -27,6 +27,7 @@ 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.DebugDetails; import org.openhab.binding.fineoffsetweatherstation.internal.domain.Measurand; import org.openhab.binding.fineoffsetweatherstation.internal.domain.Protocol; import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding; @@ -151,7 +152,7 @@ public Map getRegisteredSensors(byte[] data, return new SystemInfo(frequency, date, dst, useWh24); } - List getMeasuredValues(byte[] data, ConversionContext context) { + List getMeasuredValues(byte[] data, ConversionContext context, DebugDetails debugDetails) { /* * Pos| Length | Description * ------------------------------------------------- @@ -173,26 +174,31 @@ List getMeasuredValues(byte[] data, ConversionContext context) { var idx = 5; if (protocol == Protocol.ELV) { idx++; // at index 5 there is an additional Byte being set to 0x04 + debugDetails.addDebugDetails(5, 1, "ELV extra byte"); } - return readMeasuredValues(data, idx, context, protocol.getParserCustomizationType()); + return readMeasuredValues(data, idx, context, protocol.getParserCustomizationType(), debugDetails); } - List getRainData(byte[] data, ConversionContext context) { - return readMeasuredValues(data, 5, context, Measurand.ParserCustomizationType.RAIN_READING); + List getRainData(byte[] data, ConversionContext context, DebugDetails debugDetails) { + return readMeasuredValues(data, 5, context, Measurand.ParserCustomizationType.RAIN_READING, debugDetails); } private List readMeasuredValues(byte[] data, int idx, ConversionContext context, - Measurand.@Nullable ParserCustomizationType protocol) { + Measurand.@Nullable ParserCustomizationType protocol, DebugDetails debugDetails) { var size = toUInt16(data, 3); + List result = new ArrayList<>(); while (idx < size) { byte code = data[idx++]; Measurand.SingleChannelMeasurand measurand = Measurand.getByCode(code); if (measurand == null) { logger.warn("failed to get measurand 0x{}", Integer.toHexString(code)); + debugDetails.addDebugDetails(idx - 1, 1, "unknown measurand"); return result; + } else { + debugDetails.addDebugDetails(idx - 1, 1, "measurand " + measurand.getDebugString()); } - idx += measurand.extractMeasuredValues(data, idx, context, protocol, result); + idx += measurand.extractMeasuredValues(data, idx, context, protocol, result, debugDetails); } 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 index a5921976a5eee..fd049dea1dbfe 100644 --- 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 @@ -22,6 +22,7 @@ import org.openhab.binding.fineoffsetweatherstation.internal.FineOffsetGatewayConfiguration; import org.openhab.binding.fineoffsetweatherstation.internal.domain.Command; import org.openhab.binding.fineoffsetweatherstation.internal.domain.ConversionContext; +import org.openhab.binding.fineoffsetweatherstation.internal.domain.DebugDetails; import org.openhab.binding.fineoffsetweatherstation.internal.domain.Protocol; import org.openhab.binding.fineoffsetweatherstation.internal.domain.SensorGatewayBinding; import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue; @@ -38,6 +39,7 @@ */ @NonNullByDefault public class FineOffsetGatewayQueryService extends GatewayQueryService { + private static final Protocol PROTOCOL = Protocol.DEFAULT; private final Logger logger = LoggerFactory.getLogger(FineOffsetGatewayQueryService.class); private final FineOffsetDataParser fineOffsetDataParser; @@ -47,7 +49,7 @@ public class FineOffsetGatewayQueryService extends GatewayQueryService { public FineOffsetGatewayQueryService(FineOffsetGatewayConfiguration config, @Nullable ThingStatusListener thingStatusListener, ConversionContext conversionContext) { super(config, thingStatusListener); - this.fineOffsetDataParser = new FineOffsetDataParser(Protocol.DEFAULT); + this.fineOffsetDataParser = new FineOffsetDataParser(PROTOCOL); this.conversionContext = conversionContext; } @@ -92,18 +94,24 @@ public Collection getMeasuredValues() { byte[] data = executeCommand(Command.CMD_GW1000_LIVEDATA); if (data != null) { - List measuredValues = fineOffsetDataParser.getMeasuredValues(data, conversionContext); + DebugDetails debugDetails = new DebugDetails(data, Command.CMD_GW1000_LIVEDATA, PROTOCOL); + List measuredValues = fineOffsetDataParser.getMeasuredValues(data, conversionContext, + debugDetails); for (MeasuredValue measuredValue : measuredValues) { valuePerChannel.put(measuredValue.getChannelId(), measuredValue); } + logger.trace("{}", debugDetails); } data = executeCommand(Command.CMD_READ_RAIN); if (data != null) { - List measuredRainValues = fineOffsetDataParser.getRainData(data, conversionContext); + DebugDetails debugDetails = new DebugDetails(data, Command.CMD_READ_RAIN, PROTOCOL); + List measuredRainValues = fineOffsetDataParser.getRainData(data, conversionContext, + debugDetails); for (MeasuredValue measuredValue : measuredRainValues) { valuePerChannel.put(measuredValue.getChannelId(), measuredValue); } + logger.trace("{}", debugDetails); } return valuePerChannel.values(); diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/GatewayQueryService.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/GatewayQueryService.java index 4edd46dc1526e..e4edd15cbcf29 100644 --- a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/GatewayQueryService.java +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/GatewayQueryService.java @@ -44,7 +44,7 @@ */ @NonNullByDefault public abstract class GatewayQueryService implements AutoCloseable { - private final Logger logger = LoggerFactory.getLogger(this.getClass()); + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); private static final Lock REQUEST_LOCK = new ReentrantLock(); 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 index 4a5e2082de9c3..1625d7fb44f81 100644 --- 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 @@ -21,6 +21,7 @@ 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.DebugDetails; import org.openhab.binding.fineoffsetweatherstation.internal.domain.Protocol; import org.openhab.binding.fineoffsetweatherstation.internal.domain.response.MeasuredValue; import org.openhab.core.util.HexUtils; @@ -32,9 +33,11 @@ class FineOffsetDataParserTest { @Test void testLiveDataWH45() { - List data = new FineOffsetDataParser(Protocol.DEFAULT).getMeasuredValues(HexUtils.hexToBytes( - "FFFF2700510100D306280827EF0927EF020045074F0A00150B00000C0000150000000016000117001900000E0000100000110021120000002113000005850D00007000D12E0060005A005B005502AE028F0633"), - new ConversionContext(ZoneOffset.UTC)); + byte[] bytes = HexUtils.hexToBytes( + "FFFF2700510100D306280827EF0927EF020045074F0A00150B00000C0000150000000016000117001900000E0000100000110021120000002113000005850D00007000D12E0060005A005B005502AE028F0633"); + DebugDetails debugDetails = new DebugDetails(bytes, Command.CMD_GW1000_LIVEDATA, Protocol.DEFAULT); + List data = new FineOffsetDataParser(Protocol.DEFAULT).getMeasuredValues(bytes, + new ConversionContext(ZoneOffset.UTC), debugDetails); Assertions.assertThat(data) .extracting(MeasuredValue::getChannelId, measuredValue -> measuredValue.getState().toString()) .containsExactly(new Tuple("temperature-indoor", "21.1 °C"), new Tuple("humidity-indoor", "40 %"), @@ -54,12 +57,43 @@ void testLiveDataWH45() { new Tuple("sensor-co2-co2", "686 ppm"), new Tuple("sensor-co2-co2-24-hour-average", "655 ppm")); } + @Test + void testLiveDataWH34AndWh45() { + byte[] bytes = HexUtils.hexToBytes( + "FFFF2700540100CA063E0826EC0926EC02007A074C0A002F0B001F0C0023150000032016000017001A0086225558005A00620000000661654A5AF1601B1900266300884B7000CE3F001D00240016001E041A037B0695"); + DebugDetails debugDetails = new DebugDetails(bytes, Command.CMD_GW1000_LIVEDATA, Protocol.DEFAULT); + List data = new FineOffsetDataParser(Protocol.DEFAULT).getMeasuredValues(bytes, + new ConversionContext(ZoneOffset.UTC), debugDetails); + Assertions.assertThat(data) + .extracting(MeasuredValue::getChannelId, measuredValue -> measuredValue.getState().toString()) + .containsExactly(new Tuple("temperature-indoor", "20.2 °C"), new Tuple("humidity-indoor", "62 %"), + new Tuple("pressure-absolute", "996.4 hPa"), new Tuple("pressure-relative", "996.4 hPa"), + new Tuple("temperature-outdoor", "12.2 °C"), new Tuple("humidity-outdoor", "76 %"), + new Tuple("direction-wind", "47 °"), new Tuple("speed-wind", "3.1 m/s"), + new Tuple("speed-gust", "3.5 m/s"), new Tuple("illumination", "80 lx"), + new Tuple("irradiation-uv", "0 mW/m²"), new Tuple("uv-index", "0"), + new Tuple("temperature-channel-1", "13.4 °C"), new Tuple("humidity-channel-1", "85 %"), + new Tuple("water-leak-channel-1", "OFF"), new Tuple("water-leak-channel-3", "OFF"), + new Tuple("lightning-counter", "6"), + new Tuple("lightning-time", "2023-11-07T15:42:41.000+0000"), + new Tuple("lightning-distance", "27 km"), new Tuple("wind-max-day", "3.8 m/s"), + new Tuple("temperature-external-channel-1", "13.6 °C"), + new Tuple("sensor-co2-temperature", "20.6 °C"), new Tuple("sensor-co2-humidity", "63 %"), + new Tuple("sensor-co2-pm10", "2.9 µg/m³"), + new Tuple("sensor-co2-pm10-24-hour-average", "3.6 µg/m³"), + new Tuple("sensor-co2-pm25", "2.2 µg/m³"), + new Tuple("sensor-co2-pm25-24-hour-average", "3 µg/m³"), + new Tuple("sensor-co2-co2", "1050 ppm"), + new Tuple("sensor-co2-co2-24-hour-average", "891 ppm")); + } + @Test void testLiveDataELV() { byte[] data = HexUtils.hexToBytes( "FFFF0B00500401010B0201120300620401120501120629072108254B09254B0A01480B00040C000A0E000000001000000021110000002E120000014F130000100714000012FD15000B4BB816086917056D35"); + DebugDetails debugDetails = new DebugDetails(data, Command.CMD_WS980_LIVEDATA, Protocol.ELV); List measuredValues = new FineOffsetDataParser(Protocol.ELV).getMeasuredValues(data, - new ConversionContext(ZoneOffset.UTC)); + new ConversionContext(ZoneOffset.UTC), debugDetails); Assertions.assertThat(measuredValues) .extracting(MeasuredValue::getChannelId, measuredValue -> measuredValue.getState().toString()) .containsExactly(new Tuple("temperature-indoor", "26.7 °C"), @@ -79,8 +113,9 @@ void testLiveDataELV() { void testRainData() { byte[] data = HexUtils .hexToBytes("FFFF5700290E000010000000001100000024120000003113000005030D00000F0064880000017A017B0030"); + DebugDetails debugDetails = new DebugDetails(data, Command.CMD_READ_RAIN, Protocol.DEFAULT); List measuredValues = new FineOffsetDataParser(Protocol.DEFAULT).getRainData(data, - new ConversionContext(ZoneOffset.UTC)); + new ConversionContext(ZoneOffset.UTC), debugDetails); Assertions.assertThat(measuredValues) .extracting(MeasuredValue::getChannelId, measuredValue -> measuredValue.getState().toString()) .containsExactly(new Tuple("rain-rate", "0 mm/h"), new Tuple("rain-day", "0 mm"), @@ -94,8 +129,9 @@ void testRainDataW90() { byte[] data = HexUtils.hexToBytes( "FFFF5700398000008300000009840000000985000000C786000000C7810000870064006400640064006400640064006400640064880900007A02BF"); Assertions.assertThat(Command.CMD_READ_RAIN.isResponseValid(data)).isTrue(); + DebugDetails debugDetails = new DebugDetails(data, Command.CMD_READ_RAIN, Protocol.DEFAULT); List measuredValues = new FineOffsetDataParser(Protocol.DEFAULT).getRainData(data, - new ConversionContext(ZoneOffset.UTC)); + new ConversionContext(ZoneOffset.UTC), debugDetails); 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"),