Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions bundles/org.openhab.binding.avmfritz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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);
Expand Down Expand Up @@ -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<ThingTypeUID> SUPPORTED_GROUP_THING_TYPES_UIDS = Set.of(GROUP_HEATING_THING_TYPE,
GROUP_SWITCH_THING_TYPE);
public static final Set<ThingTypeUID> SUPPORTED_GROUP_THING_TYPES_UIDS = Set.of(GROUP_BLINDS_THING_TYPE,
GROUP_HEATING_THING_TYPE, GROUP_SWITCH_THING_TYPE);

public static final Set<ThingTypeUID> SUPPORTED_BRIDGE_THING_TYPES_UIDS = Set.of(BRIDGE_THING_TYPE,
POWERLINE546E_STANDALONE_THING_TYPE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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() {
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,9 @@ public void onDeviceListAdded(List<AVMFritzBaseModel> 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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()) {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,24 @@
</thing-type>

<!-- Supported FRITZ! groups and features -->
<thing-type id="FRITZ_GROUP_BLINDS">
<supported-bridge-type-refs>
<bridge-type-ref id="fritzbox"/>
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
</supported-bridge-type-refs>

<label>Blinds Group</label>
<description>Group for blinds.</description>
<semantic-equipment-tag>Blinds</semantic-equipment-tag>
<channels>
<channel id="rollershutter" typeId="rollershutter"/>
</channels>

<representation-property>ain</representation-property>

<config-description-ref uri="thing-type:avmfritz:fritzgroup"/>
</thing-type>

<thing-type id="FRITZ_GROUP_HEATING">
<supported-bridge-type-refs>
<bridge-type-ref id="fritzbox"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public void setUp() throws JAXBException, XMLStreamException {
final String xml =
"""
<devicelist version="1">\
<group synchronized="0" identifier="grpdb3190-4195D62D5" id="901" functionbitmask="331776" fwversion="1.0" manufacturer="AVM" productname=""><present>1</present><txbusy>0</txbusy><name>Schlafzimmer</name><blind><endpositionsset>1</endpositionsset><mode>manuell</mode></blind><levelcontrol><level>0</level><levelpercentage>0</levelpercentage></levelcontrol><groupinfo><masterdeviceid>0</masterdeviceid><members>2003,2004,2005</members></groupinfo></group>\
<group identifier="F0:A3:7F-900" id="20000" functionbitmask="6784" fwversion="1.0" manufacturer="AVM" productname=""><present>1</present><name>Schlafzimmer</name><switch><state>1</state><mode>manuell</mode><lock>0</lock><devicelock>0</devicelock></switch><powermeter><voltage>230051</voltage><power>0</power><energy>2087</energy></powermeter><groupinfo><masterdeviceid>17</masterdeviceid><members>17,18</members></groupinfo></group>\
<group identifier="F0:A3:7F-901" id="20001" functionbitmask="4160" fwversion="1.0" manufacturer="AVM" productname=""><present>1</present><name>Schlafzimmer</name><temperature><celsius>220</celsius><offset>-10</offset></temperature><hkr><tist>44</tist><tsoll>42</tsoll><absenk>28</absenk><komfort>42</komfort><lock>1</lock><devicelock>1</devicelock><errorcode>0</errorcode><windowopenactiv>0</windowopenactiv><windowopenactiveendtime>0</windowopenactiveendtime><boostactive>0</boostactive><boostactiveendtime>0</boostactiveendtime><batterylow>0</batterylow><battery>100</battery><nextchange><endperiod>1484341200</endperiod><tchange>28</tchange></nextchange></hkr><groupinfo><masterdeviceid>0</masterdeviceid><members>20,21,22</members></groupinfo></group>\
<device identifier="08761 0000434" id="17" functionbitmask="35712" fwversion="03.83" manufacturer="AVM" productname="FRITZ!DECT 200"><present>1</present><name>FRITZ!DECT 200 #1</name><switch><state>1</state><mode>manuell</mode><lock>0</lock><devicelock>0</devicelock></switch><powermeter><voltage>230051</voltage><power>0</power><energy>2087</energy></powermeter><temperature><celsius>255</celsius><offset>0</offset></temperature></device>\
Expand Down Expand Up @@ -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());
}

Expand Down Expand Up @@ -916,6 +917,49 @@ public void validateHANFUNOnOffModel() {
assertNull(device.getLevelControlModel());
}

@Test
public void validateBlindsGroupModel() {
Optional<AVMFritzBaseModel> 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<AVMFritzBaseModel> optionalGroup = findModelByIdentifier("F0:A3:7F-901");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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));
Expand Down