From a86adc970574bbaef5ab6cb7d5f8b4ee2661b4b2 Mon Sep 17 00:00:00 2001 From: Andreas Berger Date: Fri, 19 Jun 2026 10:31:38 +0200 Subject: [PATCH] [fineoffsetweatherstation] Fix false low battery for voltage sensors on HTTP API (#21000) * [fineoffsetweatherstation] Fix false low battery for voltage sensors on HTTP API Signed-off-by: Andreas Berger --- .../internal/domain/Sensor.java | 21 +++++++++++++++---- .../internal/domain/SensorGatewayBinding.java | 4 ++++ .../internal/service/EcowittDataParser.java | 2 +- .../service/EcowittDataParserTest.java | 13 ++++++++++++ 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java index 93ec0d1dad..39b8fb4789 100644 --- a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/Sensor.java @@ -50,13 +50,26 @@ public enum Sensor { WN20(LOW_HIGH), WN38(VOLTAGE_FINE_STEPS); - private final BatteryStatus.Type batteryStatusTpe; + private final BatteryStatus.Type batteryStatusType; - Sensor(BatteryStatus.Type batteryStatusTpe) { - this.batteryStatusTpe = batteryStatusTpe; + Sensor(BatteryStatus.Type batteryStatusType) { + this.batteryStatusType = batteryStatusType; } public BatteryStatus getBatteryStatus(byte data) { - return new BatteryStatus(batteryStatusTpe, data); + return new BatteryStatus(batteryStatusType, data); + } + + /** + * Interprets the battery field as reported by the Ecowitt HTTP API. Unlike the binary protocol, the HTTP API + * reports the battery of voltage-based sensors already as a 0-5 level (5 = full) rather than a raw voltage, so + * those are read as {@link BatteryStatus.Type#LEVEL}; all other sensor types share the binary encoding. + */ + public BatteryStatus getHttpBatteryStatus(byte data) { + BatteryStatus.Type type = switch (batteryStatusType) { + case VOLTAGE_BROAD_STEPS, VOLTAGE_FINE_STEPS -> LEVEL; + default -> batteryStatusType; + }; + return new BatteryStatus(type, data); } } diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java index 8415f72a51..9f2eb53db4 100644 --- a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/domain/SensorGatewayBinding.java @@ -138,6 +138,10 @@ public enum SensorGatewayBinding { return sensor.getBatteryStatus(data); } + public BatteryStatus getHttpBatteryStatus(byte data) { + return sensor.getHttpBatteryStatus(data); + } + public Sensor getSensor() { return sensor; } diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParser.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParser.java index 57dae7aa27..c39863d986 100644 --- a/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParser.java +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/main/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParser.java @@ -191,7 +191,7 @@ public class EcowittDataParser { } catch (NumberFormatException e) { return; } - BatteryStatus batteryStatus = sensorGatewayBinding.getBatteryStatus((byte) parseInt(asString(obj, "batt"))); + BatteryStatus batteryStatus = sensorGatewayBinding.getHttpBatteryStatus((byte) parseInt(asString(obj, "batt"))); int signal = parseInt(asString(obj, "signal")); result.put(sensorGatewayBinding, new SensorDevice(id, sensorGatewayBinding, batteryStatus, signal)); } diff --git a/bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParserTest.java b/bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParserTest.java index 9c3644ccfb..41ccabb576 100644 --- a/bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParserTest.java +++ b/bundles/org.openhab.binding.fineoffsetweatherstation/src/test/java/org/openhab/binding/fineoffsetweatherstation/internal/service/EcowittDataParserTest.java @@ -130,6 +130,19 @@ class EcowittDataParserTest { new Tuple("WH25", 0xB9, 4, true)); } + @Test + void testVoltageSensorBatteryReportedAsLevel() { + // unlike the binary protocol, where the WH51 battery field is a raw voltage (val * 0.1 V), the Ecowitt HTTP + // API reports it already as a 0-5 level (5 = full). It must therefore not be misread as 0.5 V and flagged low. + Map sensors = parser.parseSensors(List.of("[{\"img\":\"wh51\"," + + "\"type\":\"14\",\"name\":\"Soil moisture CH1\",\"id\":\"FBF08\",\"batt\":\"5\",\"rssi\":\"-85\"," + + "\"signal\":\"4\",\"idst\":\"1\"}]"), false); + Assertions.assertThat(sensors.values()) + .extracting(device -> device.getSensorGatewayBinding().getSensor().name(), + device -> device.getBatteryStatus().isLow(), device -> device.getBatteryStatus().getLevel()) + .containsExactly(new Tuple("WH51", false, 5)); + } + @Test void testSystemInfo() { @Nullable