From 32c76898c1e51cc17e7202cba4f547fa12694d0c Mon Sep 17 00:00:00 2001 From: Christoph Weitkamp Date: Sat, 3 Sep 2022 14:42:31 +0200 Subject: [PATCH] [avmfritz] Allow to set every userdefined color (#13317) * Added INCREASE/DECREASE commands for brightness/color Channels * Fixed NPE in HeatingModel * Use set unmapped color command for color control of bulbs Signed-off-by: Christoph Weitkamp --- .../internal/dto/ColorControlModel.java | 9 +++++++- .../avmfritz/internal/dto/HeatingModel.java | 4 ++-- .../handler/AVMFritzBaseThingHandler.java | 9 +++++++- .../hardware/FritzAhaWebInterface.java | 7 +++++- .../callbacks/FritzAhaSetColorCallback.java | 22 ++++++++++++++++++- .../dto/AVMFritzDeviceListModelTest.java | 2 ++ .../internal/dto/ColorControlModelTest.java | 10 +++++++++ .../internal/dto/HeatingModelTest.java | 15 ++++++++++++- 8 files changed, 71 insertions(+), 7 deletions(-) diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java index 9a12ed674..b77b63cd6 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModel.java @@ -15,8 +15,10 @@ package org.openhab.binding.avmfritz.internal.dto; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.library.types.PercentType; /** @@ -36,6 +38,10 @@ public class ColorControlModel { public int currentMode; public int hue; public int saturation; + @XmlElement(name = "unmapped_hue") + public @Nullable Integer unmappedHue; + @XmlElement(name = "unmapped_saturation") + public @Nullable Integer unmappedSaturation; public int temperature; /** @@ -62,7 +68,8 @@ public class ColorControlModel { @Override public String toString() { return new StringBuilder("[supportedModes=").append(supportedModes).append(",currentMode=").append(currentMode) - .append(",hue=").append(hue).append(",saturation=").append(saturation).append(",temperature=") + .append(",hue=").append(hue).append(",saturation=").append(saturation).append(",unmapped_hue=") + .append(unmappedHue).append(",unmapped_saturation=").append(unmappedSaturation).append(",temperature=") .append(temperature).append("]").toString(); } diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java index 424e25693..f5bd7e872 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/HeatingModel.java @@ -111,9 +111,9 @@ public class HeatingModel implements BatteryModel { return MODE_OFF; } else if (BigDecimal.ONE.equals(getWindowopenactiv())) { return MODE_WINDOW_OPEN; - } else if (tsoll.compareTo(komfort) == 0) { + } else if (komfort != null && komfort.compareTo(tsoll) == 0) { return MODE_COMFORT; - } else if (tsoll.compareTo(absenk) == 0) { + } else if (absenk != null && absenk.compareTo(tsoll) == 0) { return MODE_ECO; } else if (BigDecimal.ONE.equals(getBoostactive()) || TEMP_FRITZ_MAX.compareTo(tsoll) == 0) { return MODE_BOOST; diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java index 3d404ec55..664174997 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseThingHandler.java @@ -411,12 +411,19 @@ public abstract class AVMFritzBaseThingHandler extends BaseThingHandler implemen if (command instanceof HSBType) { HSBType hsbType = (HSBType) command; brightness = hsbType.getBrightness().toBigDecimal(); - fritzBox.setHueAndSaturation(ain, hsbType.getHue().intValue(), + fritzBox.setUnmappedHueAndSaturation(ain, hsbType.getHue().intValue(), ColorControlModel.fromPercent(hsbType.getSaturation()), 0); } else if (command instanceof PercentType) { brightness = ((PercentType) command).toBigDecimal(); } else if (command instanceof OnOffType) { fritzBox.setSwitch(ain, OnOffType.ON.equals(command)); + } else if (command instanceof IncreaseDecreaseType) { + brightness = ((DeviceModel) currentDevice).getLevelControlModel().getLevelPercentage(); + if (IncreaseDecreaseType.INCREASE.equals(command)) { + brightness.add(BigDecimal.TEN); + } else { + brightness.subtract(BigDecimal.TEN); + } } if (brightness != null) { fritzBox.setLevelPercentage(ain, brightness); diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/FritzAhaWebInterface.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/FritzAhaWebInterface.java index d53b3817e..4dbb6a66a 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/FritzAhaWebInterface.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/FritzAhaWebInterface.java @@ -330,11 +330,16 @@ public class FritzAhaWebInterface { return asyncGet(callback); } - public FritzAhaContentExchange setHueAndSaturation(String ain, int hue, int saturation, int duration) { + public FritzAhaContentExchange setMappedHueAndSaturation(String ain, int hue, int saturation, int duration) { FritzAhaSetColorCallback callback = new FritzAhaSetColorCallback(this, ain, hue, saturation, duration); return asyncGet(callback); } + public FritzAhaContentExchange setUnmappedHueAndSaturation(String ain, int hue, int saturation, int duration) { + FritzAhaSetColorCallback callback = new FritzAhaSetColorCallback(this, ain, hue, saturation, duration, false); + return asyncGet(callback); + } + public FritzAhaContentExchange setBlind(String ain, BlindCommand command) { FritzAhaSetBlindTargetCallback callback = new FritzAhaSetBlindTargetCallback(this, ain, command); return asyncGet(callback); diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/callbacks/FritzAhaSetColorCallback.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/callbacks/FritzAhaSetColorCallback.java index 66dea6b7e..ed78836f5 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/callbacks/FritzAhaSetColorCallback.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/hardware/callbacks/FritzAhaSetColorCallback.java @@ -27,6 +27,9 @@ import org.slf4j.LoggerFactory; @NonNullByDefault public class FritzAhaSetColorCallback extends FritzAhaReauthCallback { + private static final String WEBSERVICE_SET_COLOR_COMMAND = "switchcmd=setcolor"; + private static final String WEBSERVICE_SET_UNMAPPED_COLOR_COMMAND = "switchcmd=setunmappedcolor"; + private final Logger logger = LoggerFactory.getLogger(FritzAhaSetColorCallback.class); private final String ain; @@ -41,8 +44,25 @@ public class FritzAhaSetColorCallback extends FritzAhaReauthCallback { * @param duration Duration of the change in 100ms. 0 immediately. */ public FritzAhaSetColorCallback(FritzAhaWebInterface webIface, String ain, int hue, int saturation, int duration) { + this(webIface, ain, hue, saturation, duration, true); + } + + /** + * Constructor + * + * @param webIface Interface to FRITZ!Box + * @param ain AIN of the device that should be switched + * @param hue New hue + * @param saturation New saturation + * @param duration Duration of the change in 100ms. 0 immediately. + * @param mapped Use mapped or unmapped color command + */ + public FritzAhaSetColorCallback(FritzAhaWebInterface webIface, String ain, int hue, int saturation, int duration, + boolean mapped) { super(WEBSERVICE_PATH, - "switchcmd=setcolor&ain=" + ain + "&hue=" + hue + "&saturation=" + saturation + "&duration=" + duration, + mapped ? WEBSERVICE_SET_COLOR_COMMAND + : WEBSERVICE_SET_UNMAPPED_COLOR_COMMAND + "&ain=" + ain + "&hue=" + hue + "&saturation=" + + saturation + "&duration=" + duration, webIface, GET, 1); this.ain = ain; } diff --git a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java index d6ca008c2..b479d8d1a 100644 --- a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java +++ b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzDeviceListModelTest.java @@ -725,6 +725,8 @@ public class AVMFritzDeviceListModelTest { assertNotNull(colorModel); assertEquals(254, colorModel.hue); assertEquals(100, colorModel.saturation); + assertEquals(0, colorModel.unmappedHue); + assertEquals(0, colorModel.unmappedSaturation); assertEquals(2700, colorModel.temperature); } diff --git a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java index 4d7ec7255..820608507 100644 --- a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java +++ b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/ColorControlModelTest.java @@ -37,6 +37,16 @@ class ColorControlModelTest { } } + @Test + public void testColorControlModelPercentConversionRestrictsToLowerBounds() { + assertThat(ColorControlModel.toPercent(-1), is(PercentType.ZERO)); + } + + @Test + public void testColorControlModelPercentConversionRestrictsToUpperBounds() { + assertThat(ColorControlModel.toPercent(999), is(PercentType.HUNDRED)); + } + @Test public void hsbSaturationAlwaysGreaterThanZero() { // a saturation greater than 1 should result in a percentage greater than 1 diff --git a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/HeatingModelTest.java b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/HeatingModelTest.java index 0ea218247..90590b587 100644 --- a/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/HeatingModelTest.java +++ b/bundles/org.openhab.binding.avmfritz/src/test/java/org/openhab/binding/avmfritz/internal/dto/HeatingModelTest.java @@ -12,7 +12,8 @@ */ package org.openhab.binding.avmfritz.internal.dto; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*; import java.math.BigDecimal; @@ -60,4 +61,16 @@ public class HeatingModelTest { assertEquals(BIGDECIMAL_FOURTEEN_POINT_FIVE, HeatingModel.normalizeCelsius(new BigDecimal("14.4"))); assertEquals(BIGDECIMAL_FOURTEEN_POINT_FIVE, HeatingModel.normalizeCelsius(new BigDecimal("14.6"))); } + + @Test + public void validateGetRadiatorModeReturnsValidMode() { + HeatingModel heatingModel = new HeatingModel(); + assertEquals(MODE_UNKNOWN, heatingModel.getRadiatorMode()); + + heatingModel.setTsoll(BigDecimal.ONE); + assertEquals(MODE_ON, heatingModel.getRadiatorMode()); + + heatingModel.setKomfort(BigDecimal.ONE); + assertEquals(MODE_COMFORT, heatingModel.getRadiatorMode()); + } }