diff --git a/bundles/org.openhab.binding.danfossairunit/README.md b/bundles/org.openhab.binding.danfossairunit/README.md index 669d08e2827d..d6833f916c7d 100644 --- a/bundles/org.openhab.binding.danfossairunit/README.md +++ b/bundles/org.openhab.binding.danfossairunit/README.md @@ -41,6 +41,7 @@ These are the available configuration parameters: | exhaust_temp | recuperator | Number | RO | Temperature of the air when pushed outside | | battery_life | service | Number | RO | Remaining Air Dial Battery Level (percentage) | | filter_life | service | Number | RO | Remaining life of filter until exchange is necessary (percentage) | +| filter_period | service | Number | RW | Number of months between filter replacements (between 3 and 12). This value affects calculation of filter_life by the unit, and might get overwritten by Air Dial or Link CC Controller. | ## Full Example @@ -63,21 +64,47 @@ updateUnchangedValuesEveryMillis=30000] ### Items ``` -Dimmer Lueftung_Drehzahl_Manuell "Drehzahl Lüftung %" (All,Lueftung) {channel = "danfossairunit:airunit:myairunit:main#manual_fan_speed"} -Number Lueftung_Drehzahl_Supply "Drehzahl Lüftung Zuluft (rpm)" (All,Lueftung) {channel = "danfossairunit:airunit:myairunit:main#supply_fan_speed"} -Number Lueftung_Drehzahl_Extract "Drehzahl Lüftung Abluft (rpm)" (All,Lueftung) {channel = "danfossairunit:airunit:myairunit:main#extract_fan_speed"} -String Lueftung_Mode "Betriebsart Lüftung" (All,Lueftung) {channel = "danfossairunit:airunit:myairunit:main#mode"} -Switch Lueftung_Boost "Stoßlüftung" (All,Lueftung) {channel = "danfossairunit:airunit:myairunit:main#boost"} -Switch Lueftung_Bypass "Lüftung Bypass" (All,Lueftung) {channel = "danfossairunit:airunit:myairunit:recuperator#bypass"} +Dimmer DanfossHRV_ManualFanStep "Manual Fan Step [%s]" {channel = "danfossairunit:airunit:myairunit:main#manual_fan_step"} +Number DanfossHRV_SupplyFanSpeed "Supply Fan Speed" {channel = "danfossairunit:airunit:myairunit:main#supply_fan_speed"} +Number DanfossHRV_ExtractFanSpeed "Extract Fan Speed" {channel = "danfossairunit:airunit:myairunit:main#extract_fan_speed"} +String DanfossHRV_Mode "Operation Mode" {channel = "danfossairunit:airunit:myairunit:main#mode"} +Switch DanfossHRV_Boost "Boost" {channel = "danfossairunit:airunit:myairunit:main#boost"} +Switch DanfossHRV_Bypass "Bypass" {channel = "danfossairunit:airunit:myairunit:recuperator#bypass"} +Number:Dimensionless DanfossHRV_Humidity "Relative humidity" { channel = "danfossairunit:airunit:myairunit:humidity#humidity" } +Number:Temperature DanfossHRV_RoomTemperature "Room air temperatuyre" { channel = "danfossairunit:airunit:myairunit:temps#room_temp" } +Number:Temperature DanfossHRV_OutdoorTemperature "Outdoor air temperature" { channel = "danfossairunit:airunit:myairunit:temps#outdoor_temp" } +Number:Temperature DanfossHRV_SupplyAirTemperature "Supply air temperature" { channel = "danfossairunit:airunit:myairunit:recuperator#supply_temp" } +Number:Temperature DanfossHRV_ExtractAirTemperature "Extract air temperature" { channel = "danfossairunit:airunit:myairunit:recuperator#extract_temp" } +Number:Temperature DanfossHRV_ExhaustAirTemperature "Exhaust air temperature" { channel = "danfossairunit:airunit:myairunit:recuperator#exhaust_temp" } +Number DanfossHRV_RemainingFilterLife "Remaining filter life" { channel = "danfossairunit:airunit:myairunit:service#filter_life" } +Number DanfossHRV_FilterPeriod "Filter period" { channel = "danfossairunit:airunit:myairunit:service#filter_period" } ``` ### Sitemap ``` -Slider item=Lueftung_Drehzahl_Manuell -Text item=Lueftung_Drehzahl_Supply -Text item=Lueftung_Drehzahl_Extract -Selection item=Lueftung_Mode mappings=[DEMAND="Bedarfslüftung", OFF="Aus", PROGRAM="Programm", MANUAL="manuell"] -Switch item=Lueftung_Boost -Switch item=Lueftung_Bypass +sitemap danfoss label="Danfoss" { + Frame label="Control" { + Selection item=DanfossHRV_Mode mappings=[DEMAND="Demand", OFF="Off", PROGRAM="Program", MANUAL="Manual"] + Slider item=DanfossHRV_ManualFanStep step=10 visibility=[DanfossHRV_Mode=="MANUAL"] + Switch item=DanfossHRV_Bypass + Switch item=DanfossHRV_Boost + } + Frame label="Measurements" { + Text item=DanfossHRV_Humidity + Text item=DanfossHRV_RoomTemperature + Text item=DanfossHRV_OutdoorTemperature + Text item=DanfossHRV_SupplyAirTemperature + Text item=DanfossHRV_ExtractAirTemperature + Text item=DanfossHRV_ExhaustAirTemperature + } + Frame label="Fan" { + Text item=DanfossHRV_SupplyFanSpeed + Text item=DanfossHRV_ExtractFanSpeed + } + Frame label="Filter" { + Text item=DanfossHRV_RemainingFilterLife + Slider item=DanfossHRV_FilterPeriod minValue=3 maxValue=12 + } +} ``` diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Channel.java b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Channel.java index ea77d6baf9e2..4aaeeb2b7c6b 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Channel.java +++ b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Channel.java @@ -59,7 +59,9 @@ public enum Channel { // service channels CHANNEL_BATTERY_LIFE("battery_life", ChannelGroup.SERVICE, DanfossAirUnit::getBatteryLife), - CHANNEL_FILTER_LIFE("filter_life", ChannelGroup.SERVICE, DanfossAirUnit::getFilterLife); + CHANNEL_FILTER_LIFE("filter_life", ChannelGroup.SERVICE, DanfossAirUnit::getFilterLife), + CHANNEL_FILTER_PERIOD("filter_period", ChannelGroup.SERVICE, DanfossAirUnit::getFilterPeriod, + DanfossAirUnit::setFilterPeriod); private final String channelName; private final ChannelGroup group; diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Commands.java b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Commands.java index ba98872a2afb..752458d03199 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Commands.java +++ b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/Commands.java @@ -57,6 +57,7 @@ public class Commands { public static byte[] EXHAUST_TEMPERATURE = { 0x14, 0x75 }; public static byte[] BATTERY_LIFE = { 0x03, 0x0f }; public static byte[] FILTER_LIFE = { 0x14, 0x6a }; + public static byte[] FILTER_PERIOD = { 0x14, 0x69 }; public static byte[] CURRENT_TIME = { 0x15, (byte) 0xe0 }; public static byte[] AWAY_TO = { 0x15, 0x20 }; public static byte[] AWAY_FROM = { 0x15, 0x21 }; diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/CommunicationController.java b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/CommunicationController.java index 6d0873762a1d..b240b89bcbc7 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/CommunicationController.java +++ b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/CommunicationController.java @@ -19,7 +19,7 @@ /** * This interface defines a communication controller that can be used to send requests to the Danfoss Air Unit. * - * @author Jacob Laursen - Refactoring, bugfixes and enhancements + * @author Jacob Laursen - Initial contribution */ @NonNullByDefault public interface CommunicationController { diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnit.java b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnit.java index 0e3646281ed1..addb36f25390 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnit.java +++ b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnit.java @@ -213,7 +213,16 @@ public DecimalType getBatteryLife() throws IOException { } public DecimalType getFilterLife() throws IOException { - return new DecimalType(BigDecimal.valueOf(asPercentByte(getByte(REGISTER_1_READ, FILTER_LIFE)))); + BigDecimal value = BigDecimal.valueOf(asPercentByte(getByte(REGISTER_1_READ, FILTER_LIFE))); + return new DecimalType(value.setScale(1, RoundingMode.HALF_UP)); + } + + public DecimalType getFilterPeriod() throws IOException { + return new DecimalType(BigDecimal.valueOf(getByte(REGISTER_1_READ, FILTER_PERIOD))); + } + + public DecimalType setFilterPeriod(Command cmd) throws IOException { + return setNumberTypeRegister(cmd, FILTER_PERIOD); } public DateTimeType getCurrentTime() throws IOException, UnexpectedResponseValueException { @@ -225,6 +234,14 @@ public PercentType setManualFanStep(Command cmd) throws IOException { return setPercentTypeRegister(cmd, MANUAL_FAN_SPEED_STEP); } + private DecimalType setNumberTypeRegister(Command cmd, byte[] register) throws IOException { + if (cmd instanceof DecimalType) { + byte value = (byte) ((DecimalType) cmd).intValue(); + set(REGISTER_1_WRITE, register, value); + } + return new DecimalType(BigDecimal.valueOf(getByte(REGISTER_1_READ, register))); + } + private PercentType setPercentTypeRegister(Command cmd, byte[] register) throws IOException { if (cmd instanceof PercentType) { byte value = (byte) ((((PercentType) cmd).intValue() + 5) / 10); diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/discovery/DanfossAirUnitDiscoveryService.java b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/discovery/DanfossAirUnitDiscoveryService.java index df98da487953..8b96398b197e 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/discovery/DanfossAirUnitDiscoveryService.java +++ b/bundles/org.openhab.binding.danfossairunit/src/main/java/org/openhab/binding/danfossairunit/internal/discovery/DanfossAirUnitDiscoveryService.java @@ -80,7 +80,6 @@ private synchronized void discover() { logger.debug("Try to discover all Danfoss Air CCM devices"); try (DatagramSocket socket = new DatagramSocket()) { - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface networkInterface = interfaces.nextElement(); @@ -96,7 +95,6 @@ private synchronized void discover() { sendBroadcastToDiscoverThing(socket, interfaceAddress.getBroadcast()); } } - } catch (IOException e) { logger.debug("No Danfoss Air CCM device found. Diagnostic: {}", e.getMessage()); } diff --git a/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml index fe22f1e907b9..6fa06e5e0b04 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.danfossairunit/src/main/resources/OH-INF/thing/thing-types.xml @@ -124,6 +124,7 @@ Remaining life of filter until exchange is necessary + @@ -190,6 +191,12 @@ Fan + + Number + + Number of months between filter replacements + + Number diff --git a/bundles/org.openhab.binding.danfossairunit/src/test/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnitTest.java b/bundles/org.openhab.binding.danfossairunit/src/test/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnitTest.java index f515f9d323a3..8bb966b19b92 100644 --- a/bundles/org.openhab.binding.danfossairunit/src/test/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnitTest.java +++ b/bundles/org.openhab.binding.danfossairunit/src/test/java/org/openhab/binding/danfossairunit/internal/DanfossAirUnitTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.QuantityType; @@ -31,7 +32,7 @@ /** * This class provides test cases for {@link DanfossAirUnit} * - * @author Jacob Laursen - Refactoring, bugfixes and enhancements + * @author Jacob Laursen - Initial contribution */ public class DanfossAirUnitTest extends JavaTest { @@ -153,4 +154,12 @@ public void getManualFanStepWhenOutOfRangeThrows() throws IOException { var airUnit = new DanfossAirUnit(communicationController); assertThrows(UnexpectedResponseValueException.class, () -> airUnit.getManualFanStep()); } + + @Test + public void getFilterLifeWhenNearestNeighborIsBelowRoundsDown() throws IOException { + byte[] response = new byte[] { (byte) 0xf0 }; + when(this.communicationController.sendRobustRequest(REGISTER_1_READ, FILTER_LIFE)).thenReturn(response); + var airUnit = new DanfossAirUnit(communicationController); + assertEquals(new DecimalType("94.1"), airUnit.getFilterLife()); + } }