diff --git a/bundles/org.openhab.binding.avmfritz/README.md b/bundles/org.openhab.binding.avmfritz/README.md index 306aca3aac661..c1c78c6d4c24d 100644 --- a/bundles/org.openhab.binding.avmfritz/README.md +++ b/bundles/org.openhab.binding.avmfritz/README.md @@ -113,10 +113,11 @@ The FRITZ!Box has to run at least on firmware FRITZ!OS 7. ### FRITZ! Groups -The FRITZ!OS supports two different types of groups. -On the one hand there are groups for heating thermostats on the other hand there are groups for switchable outlets and power meters. +The FRITZ!OS supports three different types of groups. +On the one hand there are groups for heating thermostats on the other hand there are groups for switchable outlets and power meters, a third group supports control of roller shutters and blinds. The first one provides the same channels and actions like the [FRITZ!DECT 302 / FRITZ!DECT 301 / FRITZ!DECT 300 / Comet DECT](https://www.openhab.org/addons/bindings/avmfritz/#fritz-dect-302-fritz-dect-301-fritz-dect-300-comet-dect) devices. The latter provides the same channels like the [FRITZ!DECT 200 / FRITZ!DECT 210](https://www.openhab.org/addons/bindings/avmfritz/#fritz-dect-200-fritz-dect-210) / [FRITZ!Powerline 546E](https://www.openhab.org/addons/bindings/avmfritz/#fritz-powerline-546e) devices. +A blind group provides the `rollershutter` channel similar to a `HAN_FUN_BLINDS` thing (e.g. [Becker BoxCTRL](https://becker-antriebe.shop/)). The FRITZ!Box has to run at least on firmware FRITZ!OS 6.69. ## Discovery diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java index 3686ffe296695..4c8798d0e4673 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/AVMFritzBindingConstants.java @@ -66,6 +66,7 @@ public class AVMFritzBindingConstants { public static final String DEVICE_SMART_ENERGY_250 = "FRITZ_Smart_Energy_250"; // List of main group types + public static final String GROUP_BLINDS = "FRITZ_GROUP_BLINDS"; public static final String GROUP_HEATING = "FRITZ_GROUP_HEATING"; public static final String GROUP_SWITCH = "FRITZ_GROUP_SWITCH"; @@ -92,6 +93,7 @@ public class AVMFritzBindingConstants { DEVICE_HAN_FUN_COLOR_BULB); public static final ThingTypeUID HAN_FUN_DIMMABLE_BULB_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_DIMMABLE_BULB); + public static final ThingTypeUID GROUP_BLINDS_THING_TYPE = new ThingTypeUID(BINDING_ID, GROUP_BLINDS); public static final ThingTypeUID GROUP_HEATING_THING_TYPE = new ThingTypeUID(BINDING_ID, GROUP_HEATING); public static final ThingTypeUID GROUP_SWITCH_THING_TYPE = new ThingTypeUID(BINDING_ID, GROUP_SWITCH); public static final ThingTypeUID HAN_FUN_SENSOR_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_SENSOR); @@ -208,8 +210,8 @@ public class AVMFritzBindingConstants { POWERLINE546E_THING_TYPE, HAN_FUN_CONTACT_THING_TYPE, HAN_FUN_ON_OFF_THING_TYPE, HAN_FUN_BLINDS_THING_TYPE, HAN_FUN_SENSOR_THING_TYPE, HAN_FUN_HOST_THING_TYPE, SMART_ENERGY_250_THING_TYPE); - public static final Set SUPPORTED_GROUP_THING_TYPES_UIDS = Set.of(GROUP_HEATING_THING_TYPE, - GROUP_SWITCH_THING_TYPE); + public static final Set SUPPORTED_GROUP_THING_TYPES_UIDS = Set.of(GROUP_BLINDS_THING_TYPE, + GROUP_HEATING_THING_TYPE, GROUP_SWITCH_THING_TYPE); public static final Set SUPPORTED_BRIDGE_THING_TYPES_UIDS = Set.of(BRIDGE_THING_TYPE, POWERLINE546E_STANDALONE_THING_TYPE); diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzBaseModel.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzBaseModel.java index 98ba606049c22..7aaa53e4478f3 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzBaseModel.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/AVMFritzBaseModel.java @@ -111,6 +111,17 @@ public abstract class AVMFritzBaseModel implements BatteryModel { @XmlElement(name = "hkr") private HeatingModel heatingModel; + @XmlElement(name = "levelcontrol") + private @Nullable LevelControlModel levelControlModel; + + public SwitchModel getSwitch() { + return switchModel; + } + + public void setSwitch(SwitchModel switchModel) { + this.switchModel = switchModel; + } + public @Nullable SimpleOnOffModel getSimpleOnOffUnit() { return simpleOnOffUnit; } @@ -131,12 +142,12 @@ public void setHkr(HeatingModel heatingModel) { this.heatingModel = heatingModel; } - public SwitchModel getSwitch() { - return switchModel; + public @Nullable LevelControlModel getLevelControlModel() { + return levelControlModel; } - public void setSwitch(SwitchModel switchModel) { - this.switchModel = switchModel; + public void setLevelcontrol(LevelControlModel levelControlModel) { + this.levelControlModel = levelControlModel; } public String getIdentifier() { @@ -265,7 +276,8 @@ public String toString() { .append(productName).append(",fwversion=").append(firmwareVersion).append(",present=").append(present) .append(",name=").append(name).append(",battery=").append(getBattery()).append(",batterylow=") .append(getBatterylow()).append(",").append(getSwitch()).append(",").append(getSimpleOnOffUnit()) - .append(",").append(getPowerMeter()).append(",").append(getHkr()).append(",").toString(); + .append(",").append(getPowerMeter()).append(",").append(getHkr()).append(",").append(levelControlModel) + .append(",").toString(); } public transient boolean isLinked; diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/DeviceModel.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/DeviceModel.java index 953ab40e912b3..cfa2d033c91e5 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/DeviceModel.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/dto/DeviceModel.java @@ -34,9 +34,6 @@ public class DeviceModel extends AVMFritzBaseModel { private HumidityModel humidity; private AlertModel alert; - @XmlElement(name = "levelcontrol") - private LevelControlModel levelControlModel; - @XmlElement(name = "colorcontrol") private ColorControlModel colorControlModel; @@ -69,14 +66,6 @@ public void setAlert(AlertModel alertModel) { this.alert = alertModel; } - public LevelControlModel getLevelControlModel() { - return levelControlModel; - } - - public void setLevelControlModel(LevelControlModel levelControlModel) { - this.levelControlModel = levelControlModel; - } - public ColorControlModel getColorControlModel() { return colorControlModel; } @@ -104,8 +93,8 @@ public void setEtsiunitinfo(ETSUnitInfoModel etsiunitinfo) { @Override public String toString() { return new StringBuilder(super.toString()).append(temperature).append(",").append(humidity).append(",") - .append(alert).append(",").append(levelControlModel).append(",").append(colorControlModel).append(",") - .append(getButtons()).append(",").append(etsiunitinfo).append("]").toString(); + .append(alert).append(",").append(colorControlModel).append(",").append(getButtons()).append(",") + .append(etsiunitinfo).append("]").toString(); } @XmlAccessorType(XmlAccessType.FIELD) diff --git a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java index 14e6b7d442136..38b12fb122285 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java +++ b/bundles/org.openhab.binding.avmfritz/src/main/java/org/openhab/binding/avmfritz/internal/handler/AVMFritzBaseBridgeHandler.java @@ -323,7 +323,9 @@ public void onDeviceListAdded(List deviceList) { */ public String getThingTypeId(AVMFritzBaseModel device) { if (device instanceof GroupModel) { - if (device.isHeatingThermostat()) { + if (device.isHANFUNBlinds()) { + return GROUP_BLINDS; + } else if (device.isHeatingThermostat()) { return GROUP_HEATING; } else if (device.isSwitchableOutlet()) { return GROUP_SWITCH; 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 32d2f3d890c7a..23f4b00f1b8ef 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 @@ -145,6 +145,9 @@ public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) { if (device.isHeatingThermostat()) { updateHeatingThermostat(device.getHkr()); } + if (device.isHANFUNBlinds()) { + updateLevelControl(device.getLevelControlModel()); + } if (device instanceof DeviceModel deviceModel) { if (deviceModel.isTemperatureSensor()) { updateTemperatureSensor(deviceModel.getTemperature()); @@ -159,9 +162,7 @@ public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) { updateHANFUNAlarmSensor(deviceModel.getAlert()); } } - if (deviceModel.isHANFUNBlinds()) { - updateLevelControl(deviceModel.getLevelControlModel()); - } else if (deviceModel.isColorLight()) { + if (deviceModel.isColorLight()) { updateColorLight(deviceModel.getColorControlModel(), deviceModel.getLevelControlModel(), deviceModel.getSimpleOnOffUnit()); } else if (deviceModel.isDimmableLight() && !deviceModel.isHANFUNBlinds()) { @@ -473,7 +474,7 @@ public void handleCommand(ChannelUID channelUID, Command command) { } else if (command instanceof OnOffType) { fritzBox.setSwitch(ain, OnOffType.ON.equals(command)); } else if (command instanceof IncreaseDecreaseType) { - brightness = ((DeviceModel) currentDevice).getLevelControlModel().getLevelPercentage(); + brightness = currentDevice.getLevelControlModel().getLevelPercentage(); if (IncreaseDecreaseType.INCREASE.equals(command)) { brightness.add(BigDecimal.TEN); } else { diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties index 3553dd0e86c95..963febd4beb8a 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/i18n/avmfritz.properties @@ -47,6 +47,8 @@ thing-type.avmfritz.FRITZ_DECT_500.label = FRITZ!DECT 500 thing-type.avmfritz.FRITZ_DECT_500.description = FRITZ!DECT500 color light. thing-type.avmfritz.FRITZ_DECT_Repeater_100.label = FRITZ!DECT Repeater 100 thing-type.avmfritz.FRITZ_DECT_Repeater_100.description = FRITZ!DECT Repeater 100 DECT repeater. +thing-type.avmfritz.FRITZ_GROUP_BLINDS.label = Blinds Group +thing-type.avmfritz.FRITZ_GROUP_BLINDS.description = Group for blinds. thing-type.avmfritz.FRITZ_GROUP_HEATING.label = Heating Group thing-type.avmfritz.FRITZ_GROUP_HEATING.description = Group for heating thermostats. thing-type.avmfritz.FRITZ_GROUP_HEATING.channel.actual_temp.label = Current Temperature diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml index b208ca9a3052b..7e5556c291576 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml @@ -489,6 +489,24 @@ + + + + + + + + Group for blinds. + Blinds + + + + + 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 f962f327dd1ef..409db331d2bf2 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 @@ -61,6 +61,7 @@ public void setUp() throws JAXBException, XMLStreamException { final String xml = """ \ + 10Schlafzimmer1manuell0002003,2004,2005\ 1Schlafzimmer1manuell00230051020871717,18\ 1Schlafzimmer220-104442284211000000100148434120028020,21,22\ 1FRITZ!DECT 200 #11manuell00230051020872550\ @@ -166,7 +167,7 @@ public void setUp() throws JAXBException, XMLStreamException { @Test public void validateDeviceListModel() { assertNotNull(devices); - assertEquals(19, devices.getDevicelist().size()); + assertEquals(20, devices.getDevicelist().size()); assertEquals("1", devices.getXmlApiVersion()); } @@ -916,6 +917,49 @@ public void validateHANFUNOnOffModel() { assertNull(device.getLevelControlModel()); } + @Test + public void validateBlindsGroupModel() { + Optional optionalGroup = findModelByIdentifier("grpdb3190-4195D62D5"); + assertTrue(optionalGroup.isPresent()); + assertTrue(optionalGroup.get() instanceof GroupModel); + + GroupModel group = (GroupModel) optionalGroup.get(); + assertEquals("", group.getProductName()); + assertEquals("grpdb3190-4195D62D5", group.getIdentifier()); + assertEquals("901", group.getDeviceId()); + assertEquals("1.0", group.getFirmwareVersion()); + assertEquals("AVM", group.getManufacturer()); + + assertEquals(1, group.getPresent()); + assertEquals("Schlafzimmer", group.getName()); + + assertFalse(group.isButton()); + assertFalse(group.isHANFUNButton()); + assertFalse(group.isHANFUNAlarmSensor()); + assertFalse(group.isDectRepeater()); + assertFalse(group.isSwitchableOutlet()); + assertFalse(group.isTemperatureSensor()); + assertFalse(group.isHumiditySensor()); + assertFalse(group.isPowerMeter()); + assertFalse(group.isHeatingThermostat()); + assertTrue(group.isHANFUNBlinds()); + + assertNull(group.getSwitch()); + + assertNull(group.getPowerMeter()); + + assertNull(group.getHkr()); + + LevelControlModel levelcontrol = group.getLevelControlModel(); + assertNotNull(levelcontrol); + assertEquals(BigDecimal.valueOf(0L), levelcontrol.getLevel()); + assertEquals(BigDecimal.valueOf(0L), levelcontrol.getLevelPercentage()); + + assertNotNull(group.getGroupinfo()); + assertEquals("0", group.getGroupinfo().getMasterdeviceid()); + assertEquals("2003,2004,2005", group.getGroupinfo().getMembers()); + } + @Test public void validateHeatingGroupModel() { Optional optionalGroup = findModelByIdentifier("F0:A3:7F-901"); diff --git a/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java b/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java index e08eff1672b5e..2be00ab539f74 100644 --- a/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java +++ b/itests/org.openhab.binding.avmfritz.tests/src/main/java/org/openhab/binding/avmfritz/internal/discovery/AVMFritzDiscoveryServiceOSGiTest.java @@ -95,7 +95,7 @@ public void cleanUp() { @Test public void correctSupportedTypes() { - assertEquals(22, discovery.getSupportedThingTypes().size()); + assertEquals(23, discovery.getSupportedThingTypes().size()); assertTrue(discovery.getSupportedThingTypes().contains(DECT100_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(DECT200_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(DECT210_THING_TYPE)); @@ -115,6 +115,7 @@ public void correctSupportedTypes() { assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_DIMMABLE_BULB_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_SENSOR_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(HAN_FUN_HOST_THING_TYPE)); + assertTrue(discovery.getSupportedThingTypes().contains(GROUP_BLINDS_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(GROUP_HEATING_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(GROUP_SWITCH_THING_TYPE)); assertTrue(discovery.getSupportedThingTypes().contains(SMART_ENERGY_250_THING_TYPE));