Skip to content

Commit

Permalink
Extract interface from DanfossAirUnitCommunicationController.
Browse files Browse the repository at this point in the history
Inject CommunicationController through DanfossAirUnit constructor.

Add unit test coverage for DanfossAirUnit class.

Fixes openhab#11167

Signed-off-by: Jacob Laursen <[email protected]>
  • Loading branch information
jlaur committed Aug 29, 2021
1 parent 540021b commit 99b659e
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2021 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.danfossairunit.internal;

import java.io.IOException;

import org.eclipse.jdt.annotation.NonNullByDefault;

@NonNullByDefault
public interface CommunicationController {
public void connect() throws IOException;

public void disconnect();

public byte[] sendRobustRequest(byte[] operation, byte[] register) throws IOException;

public byte[] sendRobustRequest(byte[] operation, byte[] register, byte[] value) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.time.DateTimeException;
import java.time.ZoneId;
Expand Down Expand Up @@ -48,14 +47,10 @@
@NonNullByDefault
public class DanfossAirUnit {

private final DanfossAirUnitCommunicationController communicationController;
private final CommunicationController communicationController;

public DanfossAirUnit(InetAddress inetAddr, int port) {
this.communicationController = new DanfossAirUnitCommunicationController(inetAddr, port);
}

public void cleanUp() {
this.communicationController.disconnect();
public DanfossAirUnit(CommunicationController communicationController) {
this.communicationController = communicationController;
}

private boolean getBoolean(byte[] operation, byte[] register) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
*/

@NonNullByDefault
public class DanfossAirUnitCommunicationController {
public class DanfossAirUnitCommunicationController implements CommunicationController {

private final Logger logger = LoggerFactory.getLogger(DanfossAirUnitCommunicationController.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class DanfossAirUnitHandler extends BaseThingHandler {
private @NonNullByDefault({}) DanfossAirUnitConfiguration config;
private @Nullable ValueCache valueCache;
private @Nullable ScheduledFuture<?> pollingJob;
private @Nullable DanfossAirUnitCommunicationController communicationController;
private @Nullable DanfossAirUnit hrv;

public DanfossAirUnitHandler(Thing thing) {
Expand Down Expand Up @@ -88,7 +89,10 @@ public void initialize() {
config = getConfigAs(DanfossAirUnitConfiguration.class);
valueCache = new ValueCache(config.updateUnchangedValuesEveryMillis);
try {
DanfossAirUnit danfossAirUnit = new DanfossAirUnit(InetAddress.getByName(config.host), TCP_PORT);
var communicationController = new DanfossAirUnitCommunicationController(InetAddress.getByName(config.host),
TCP_PORT);
this.communicationController = communicationController;
var danfossAirUnit = new DanfossAirUnit(communicationController);
hrv = danfossAirUnit;
scheduler.execute(() -> {
try {
Expand Down Expand Up @@ -145,11 +149,12 @@ public void dispose() {

stopPolling();

DanfossAirUnit danfossAirUnit = hrv;
if (danfossAirUnit != null) {
danfossAirUnit.cleanUp();
}
hrv = null;

DanfossAirUnitCommunicationController communicationController = this.communicationController;
if (communicationController != null) {
communicationController.disconnect();
}
}

private synchronized void startPolling() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* Copyright (c) 2010-2021 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.danfossairunit.internal;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import static org.openhab.binding.danfossairunit.internal.Commands.*;

import java.io.IOException;
import java.time.ZoneId;
import java.time.ZonedDateTime;

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.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.test.java.JavaTest;

/**
* This class provides test cases for {@link DanfossAirUnit}
*
* @author Ralf Duckstein - Initial contribution
* @author Robert Bach - heavy refactorings
*/
public class DanfossAirUnitTest extends JavaTest {

private CommunicationController communicationController;

@BeforeEach
private void setUp() {
this.communicationController = mock(CommunicationController.class);
}

@Test
public void getUnitNameIsReturned() throws IOException {
byte[] response = new byte[] { (byte) 0x05, (byte) 'w', (byte) '2', (byte) '/', (byte) 'a', (byte) '2' };
when(this.communicationController.sendRobustRequest(REGISTER_1_READ, UNIT_NAME)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals("w2/a2", airUnit.getUnitName());
}

@Test
public void getHumidityWhenNearestNeighborIsBelowRoundsDown() throws IOException {
byte[] response = new byte[] { (byte) 0x64 };
when(this.communicationController.sendRobustRequest(REGISTER_1_READ, HUMIDITY)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals(new QuantityType<>("39.2 %"), airUnit.getHumidity());
}

@Test
public void getHumidityWhenNearestNeighborIsAboveRoundsUp() throws IOException {
byte[] response = new byte[] { (byte) 0x67 };
when(this.communicationController.sendRobustRequest(REGISTER_1_READ, HUMIDITY)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals(new QuantityType<>("40.4 %"), airUnit.getHumidity());
}

@Test
public void getSupplyTemperatureWhenNearestNeighborIsBelowRoundsDown()
throws IOException, UnexpectedResponseValueException {
byte[] response = new byte[] { (byte) 0x09, (byte) 0xf0 }; // 0x09f0 = 2544 => 25.44
when(this.communicationController.sendRobustRequest(REGISTER_4_READ, SUPPLY_TEMPERATURE)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals(new QuantityType<>("25.4 °C"), airUnit.getSupplyTemperature());
}

@Test
public void getSupplyTemperatureWhenBothNeighborsAreEquidistantRoundsUp()
throws IOException, UnexpectedResponseValueException {
byte[] response = new byte[] { (byte) 0x09, (byte) 0xf1 }; // 0x09f1 = 2545 => 25.45
when(this.communicationController.sendRobustRequest(REGISTER_4_READ, SUPPLY_TEMPERATURE)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals(new QuantityType<>("25.5 °C"), airUnit.getSupplyTemperature());
}

@Test
public void getSupplyTemperatureWhenBelowValidRangeThrows() throws IOException {
byte[] response = new byte[] { (byte) 0x94, (byte) 0xf8 }; // 0x94f8 = -27400 => -274
when(this.communicationController.sendRobustRequest(REGISTER_4_READ, SUPPLY_TEMPERATURE)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertThrows(UnexpectedResponseValueException.class, () -> airUnit.getSupplyTemperature());
}

@Test
public void getSupplyTemperatureWhenAboveValidRangeThrows() throws IOException {
byte[] response = new byte[] { (byte) 0x27, (byte) 0x11 }; // 0x2711 = 10001 => 100,01
when(this.communicationController.sendRobustRequest(REGISTER_4_READ, SUPPLY_TEMPERATURE)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertThrows(UnexpectedResponseValueException.class, () -> airUnit.getSupplyTemperature());
}

@Test
public void getCurrentTimeWhenWellFormattedIsParsed() throws IOException, UnexpectedResponseValueException {
byte[] response = new byte[] { (byte) 0x03, (byte) 0x02, (byte) 0x0f, (byte) 0x1d, (byte) 0x08, (byte) 0x15 }; // 29.08.21
// 15:02:03
when(this.communicationController.sendRobustRequest(REGISTER_1_READ, CURRENT_TIME)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals(new DateTimeType(ZonedDateTime.of(2021, 8, 29, 15, 2, 3, 0, ZoneId.systemDefault())),
airUnit.getCurrentTime());
}

@Test
public void getBootstWhenZeroIsOff() throws IOException {
byte[] response = new byte[] { (byte) 0x00 };
when(this.communicationController.sendRobustRequest(REGISTER_1_READ, BOOST)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals(OnOffType.OFF, airUnit.getBoost());
}

@Test
public void getBootstWhenNonZeroIsOn() throws IOException {
byte[] response = new byte[] { (byte) 0x66 };
when(this.communicationController.sendRobustRequest(REGISTER_1_READ, BOOST)).thenReturn(response);
var airUnit = new DanfossAirUnit(communicationController);
assertEquals(OnOffType.ON, airUnit.getBoost());
}
}

0 comments on commit 99b659e

Please sign in to comment.