[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 <github@christophweitkamp.de>
This commit is contained in:
Christoph Weitkamp 2022-09-03 14:42:31 +02:00 committed by GitHub
parent df432a7fbc
commit 32c76898c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 7 deletions

View File

@ -15,8 +15,10 @@ package org.openhab.binding.avmfritz.internal.dto;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.PercentType;
/** /**
@ -36,6 +38,10 @@ public class ColorControlModel {
public int currentMode; public int currentMode;
public int hue; public int hue;
public int saturation; public int saturation;
@XmlElement(name = "unmapped_hue")
public @Nullable Integer unmappedHue;
@XmlElement(name = "unmapped_saturation")
public @Nullable Integer unmappedSaturation;
public int temperature; public int temperature;
/** /**
@ -62,7 +68,8 @@ public class ColorControlModel {
@Override @Override
public String toString() { public String toString() {
return new StringBuilder("[supportedModes=").append(supportedModes).append(",currentMode=").append(currentMode) 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(); .append(temperature).append("]").toString();
} }

View File

@ -111,9 +111,9 @@ public class HeatingModel implements BatteryModel {
return MODE_OFF; return MODE_OFF;
} else if (BigDecimal.ONE.equals(getWindowopenactiv())) { } else if (BigDecimal.ONE.equals(getWindowopenactiv())) {
return MODE_WINDOW_OPEN; return MODE_WINDOW_OPEN;
} else if (tsoll.compareTo(komfort) == 0) { } else if (komfort != null && komfort.compareTo(tsoll) == 0) {
return MODE_COMFORT; return MODE_COMFORT;
} else if (tsoll.compareTo(absenk) == 0) { } else if (absenk != null && absenk.compareTo(tsoll) == 0) {
return MODE_ECO; return MODE_ECO;
} else if (BigDecimal.ONE.equals(getBoostactive()) || TEMP_FRITZ_MAX.compareTo(tsoll) == 0) { } else if (BigDecimal.ONE.equals(getBoostactive()) || TEMP_FRITZ_MAX.compareTo(tsoll) == 0) {
return MODE_BOOST; return MODE_BOOST;

View File

@ -411,12 +411,19 @@ public abstract class AVMFritzBaseThingHandler extends BaseThingHandler implemen
if (command instanceof HSBType) { if (command instanceof HSBType) {
HSBType hsbType = (HSBType) command; HSBType hsbType = (HSBType) command;
brightness = hsbType.getBrightness().toBigDecimal(); brightness = hsbType.getBrightness().toBigDecimal();
fritzBox.setHueAndSaturation(ain, hsbType.getHue().intValue(), fritzBox.setUnmappedHueAndSaturation(ain, hsbType.getHue().intValue(),
ColorControlModel.fromPercent(hsbType.getSaturation()), 0); ColorControlModel.fromPercent(hsbType.getSaturation()), 0);
} else if (command instanceof PercentType) { } else if (command instanceof PercentType) {
brightness = ((PercentType) command).toBigDecimal(); brightness = ((PercentType) command).toBigDecimal();
} else if (command instanceof OnOffType) { } else if (command instanceof OnOffType) {
fritzBox.setSwitch(ain, OnOffType.ON.equals(command)); 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) { if (brightness != null) {
fritzBox.setLevelPercentage(ain, brightness); fritzBox.setLevelPercentage(ain, brightness);

View File

@ -330,11 +330,16 @@ public class FritzAhaWebInterface {
return asyncGet(callback); 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); FritzAhaSetColorCallback callback = new FritzAhaSetColorCallback(this, ain, hue, saturation, duration);
return asyncGet(callback); 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) { public FritzAhaContentExchange setBlind(String ain, BlindCommand command) {
FritzAhaSetBlindTargetCallback callback = new FritzAhaSetBlindTargetCallback(this, ain, command); FritzAhaSetBlindTargetCallback callback = new FritzAhaSetBlindTargetCallback(this, ain, command);
return asyncGet(callback); return asyncGet(callback);

View File

@ -27,6 +27,9 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault @NonNullByDefault
public class FritzAhaSetColorCallback extends FritzAhaReauthCallback { 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 Logger logger = LoggerFactory.getLogger(FritzAhaSetColorCallback.class);
private final String ain; private final String ain;
@ -41,8 +44,25 @@ public class FritzAhaSetColorCallback extends FritzAhaReauthCallback {
* @param duration Duration of the change in 100ms. 0 immediately. * @param duration Duration of the change in 100ms. 0 immediately.
*/ */
public FritzAhaSetColorCallback(FritzAhaWebInterface webIface, String ain, int hue, int saturation, int duration) { 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, 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); webIface, GET, 1);
this.ain = ain; this.ain = ain;
} }

View File

@ -725,6 +725,8 @@ public class AVMFritzDeviceListModelTest {
assertNotNull(colorModel); assertNotNull(colorModel);
assertEquals(254, colorModel.hue); assertEquals(254, colorModel.hue);
assertEquals(100, colorModel.saturation); assertEquals(100, colorModel.saturation);
assertEquals(0, colorModel.unmappedHue);
assertEquals(0, colorModel.unmappedSaturation);
assertEquals(2700, colorModel.temperature); assertEquals(2700, colorModel.temperature);
} }

View File

@ -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 @Test
public void hsbSaturationAlwaysGreaterThanZero() { public void hsbSaturationAlwaysGreaterThanZero() {
// a saturation greater than 1 should result in a percentage greater than 1 // a saturation greater than 1 should result in a percentage greater than 1

View File

@ -12,7 +12,8 @@
*/ */
package org.openhab.binding.avmfritz.internal.dto; 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; 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.4")));
assertEquals(BIGDECIMAL_FOURTEEN_POINT_FIVE, HeatingModel.normalizeCelsius(new BigDecimal("14.6"))); 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());
}
} }