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: 5 additions & 0 deletions bundles/org.openhab.binding.avmfritz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ val actions = getActions("avmfritz","avmfritz:Comet_DECT:1:aaaaaabbbbbb")
actions.setBoostMode(300)
```

For power meter devices like FRITZ!DECT 200 or FRITZ!Smart Energy 250 there are actions to enable / disable high refresh polling: `enablePowerMeterHighRefresh(long)` and `disablePowerMeterHighRefresh()`.
In general DECT devices submit their values every two minutes.
Whenever a user visits the detail page of a device in FRITZ!OS the values are requested more often - every ten seconds.
This action forces the high refresh interval of values by calling the related function on the FRITZ!Box interface.

## Full Example

demo.things:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,10 @@ public class AVMFritzBindingConstants {
public static final String CONFIG_AIN = "ain";

// List of all Properties
public static final String PROPERTY_DEVICE_ID = "deviceId";
public static final String PROPERTY_MASTER = "master";
public static final String PROPERTY_MEMBERS = "members";
public static final String PRODUCT_NAME = "productName";
public static final String PROPERTY_PRODUCT_NAME = "productName";

// List of all channel groups
public static final String CHANNEL_GROUP_DEVICE = "device";
Expand Down Expand Up @@ -181,13 +182,15 @@ public class AVMFritzBindingConstants {
public static final String MODE_AUTO = "AUTOMATIC";
public static final String MODE_MANUAL = "MANUAL";
public static final String MODE_VACATION = "VACATION";
public static final String MODE_ON = "ON";
public static final String MODE_OFF = "OFF";
public static final String MODE_COMFORT = "COMFORT";
public static final String MODE_ECO = "ECO";
public static final String MODE_BOOST = "BOOST";
public static final String MODE_WINDOW_OPEN = "WINDOW_OPEN";
public static final String MODE_UNKNOWN = "UNKNOWN";
public static final String HEATING_MODE_ON = "ON";
public static final String HEATING_MODE_OFF = "OFF";
public static final String HEATING_MODE_COMFORT = "COMFORT";
public static final String HEATING_MODE_ECO = "ECO";
public static final String HEATING_MODE_BOOST = "BOOST";
public static final String HEATING_MODE_WINDOW_OPEN = "WINDOW_OPEN";
public static final String HEATING_MODE_UNKNOWN = "UNKNOWN";

public static final String GET_ENERGY_STATS = "GET_ENERGY_STATS";

public static final Set<ThingTypeUID> SUPPORTED_LIGHTING_THING_TYPES = Set.of(DECT500_THING_TYPE,
HAN_FUN_COLOR_BULB_THING_TYPE, HAN_FUN_DIMMABLE_BULB_THING_TYPE);
Expand All @@ -198,21 +201,24 @@ public class AVMFritzBindingConstants {
public static final Set<ThingTypeUID> SUPPORTED_HEATING_THING_TYPES = Set.of(DECT300_THING_TYPE, DECT302_THING_TYPE,
DECT301_THING_TYPE, COMETDECT_THING_TYPE);

public static final Set<ThingTypeUID> SUPPORTED_POWER_METER_THING_TYPES = Set.of(DECT200_THING_TYPE,
DECT210_THING_TYPE);

public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES_UIDS = Set.of(DECT100_THING_TYPE,
DECT200_THING_TYPE, DECT210_THING_TYPE, 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);
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_BRIDGE_THING_TYPES_UIDS = Set.of(BRIDGE_THING_TYPE,
POWERLINE546E_STANDALONE_THING_TYPE);

public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream.of(SUPPORTED_LIGHTING_THING_TYPES,
SUPPORTED_BUTTON_THING_TYPES_UIDS, SUPPORTED_HEATING_THING_TYPES, SUPPORTED_DEVICE_THING_TYPES_UIDS,
SUPPORTED_GROUP_THING_TYPES_UIDS, SUPPORTED_BRIDGE_THING_TYPES_UIDS).flatMap(Set::stream)
.collect(Collectors.toUnmodifiableSet());
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
.of(SUPPORTED_LIGHTING_THING_TYPES, SUPPORTED_BUTTON_THING_TYPES_UIDS, SUPPORTED_HEATING_THING_TYPES,
SUPPORTED_POWER_METER_THING_TYPES, SUPPORTED_DEVICE_THING_TYPES_UIDS,
SUPPORTED_GROUP_THING_TYPES_UIDS, SUPPORTED_BRIDGE_THING_TYPES_UIDS)
.flatMap(Set::stream).collect(Collectors.toUnmodifiableSet());

// Lookup of new (alias) to old product names
public static final Map<String, String> ALIAS_PRODUCT_NAME_MAP = Map.of( //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.openhab.binding.avmfritz.internal.handler.AVMFritzColorLightDeviceHandler;
import org.openhab.binding.avmfritz.internal.handler.AVMFritzHeatingDeviceHandler;
import org.openhab.binding.avmfritz.internal.handler.AVMFritzHeatingGroupHandler;
import org.openhab.binding.avmfritz.internal.handler.AVMFritzPowerMeterDeviceHandler;
import org.openhab.binding.avmfritz.internal.handler.BoxHandler;
import org.openhab.binding.avmfritz.internal.handler.DeviceHandler;
import org.openhab.binding.avmfritz.internal.handler.GroupHandler;
Expand Down Expand Up @@ -83,6 +84,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return new AVMFritzButtonHandler(thing);
} else if (SUPPORTED_HEATING_THING_TYPES.contains(thingTypeUID)) {
return new AVMFritzHeatingDeviceHandler(thing);
} else if (SUPPORTED_POWER_METER_THING_TYPES.contains(thingTypeUID)) {
return new AVMFritzPowerMeterDeviceHandler(thing);
} else if (SUPPORTED_DEVICE_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new DeviceHandler(thing);
} else if (GROUP_HEATING_THING_TYPE.equals(thingTypeUID)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void setBoostMode(
if (duration == null) {
throw new IllegalArgumentException("Cannot set Boost mode as 'duration' is null!");
}
validateDuration(duration.longValue());
actionsHandler.setBoostMode(duration.longValue());
}

Expand All @@ -69,10 +70,17 @@ public void setWindowOpenMode(
if (duration == null) {
throw new IllegalArgumentException("Cannot set Window Open mode as 'duration' is null!");
}
validateDuration(duration.longValue());
actionsHandler.setWindowOpenMode(duration.longValue());
}

public static void setWindowOpenMode(ThingActions actions, @Nullable Long duration) {
((AVMFritzHeatingActions) actions).setWindowOpenMode(duration);
}

private void validateDuration(long duration) {
if (duration < 0 || 86400 < duration) {
throw new IllegalArgumentException("Duration must not be less than zero or greater than 86400");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2010-2025 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.avmfritz.internal.actions;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.avmfritz.internal.handler.AVMFritzPowerMeterActionsHandler;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.RuleAction;
import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.binding.ThingActionsScope;
import org.openhab.core.thing.binding.ThingHandler;

/**
* The {@link AVMFritzPowerMeterActions} defines thing actions for power meter devices / groups of the avmfritz binding.
*
* @author Christoph Weitkamp - Initial contribution
*/
@ThingActionsScope(name = "avmfritz")
@NonNullByDefault
public class AVMFritzPowerMeterActions implements ThingActions {

private @Nullable AVMFritzPowerMeterActionsHandler handler;

@Override
public void setThingHandler(@Nullable ThingHandler handler) {
this.handler = (AVMFritzPowerMeterActionsHandler) handler;
}

@Override
public @Nullable ThingHandler getThingHandler() {
return handler;
}

@RuleAction(label = "@text/enablePowerMeterHighRefreshActionLabel", description = "@text/enablePowerMeterHighRefreshActionDescription")
public void enablePowerMeterHighRefresh(
@ActionInput(name = "Device Id", label = "@text/enablePowerMeterHighRefreshInputLabel", description = "@text/enablePowerMeterHighRefreshInputDescription", type = "java.lang.Long", required = true) @Nullable Long deviceId) {
AVMFritzPowerMeterActionsHandler actionsHandler = handler;
if (actionsHandler == null) {
throw new IllegalArgumentException("AVMFritzPowerMeterDeviceHandler ThingHandler is null!");
}
if (deviceId == null) {
throw new IllegalArgumentException("Cannot enable power meter high refresh as 'deviceId' is null!");
}
actionsHandler.enablePowerMeterHighRefresh(deviceId.longValue());
}

public static void enablePowerMeterHighRefresh(ThingActions actions, @Nullable Long deviceId) {
((AVMFritzPowerMeterActions) actions).enablePowerMeterHighRefresh(deviceId);
}

@RuleAction(label = "@text/disablePowerMeterHighRefreshActionLabel", description = "@text/disablePowerMeterHighRefreshActionDescription")
public void disablePowerMeterHighRefresh() {
AVMFritzPowerMeterActionsHandler actionsHandler = handler;
if (actionsHandler == null) {
throw new IllegalArgumentException("AVMFritzPowerMeterDeviceHandler ThingHandler is null!");
}
actionsHandler.disablePowerMeterHighRefresh();
}

public static void disablePowerMeterHighRefresh(ThingActions actions) {
((AVMFritzPowerMeterActions) actions).disablePowerMeterHighRefresh();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
package org.openhab.binding.avmfritz.internal.discovery;

import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
import static org.openhab.core.thing.Thing.*;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -32,6 +31,7 @@
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.framework.Bundle;
Expand Down Expand Up @@ -59,10 +59,12 @@ public class AVMFritzDiscoveryService extends AbstractThingHandlerDiscoveryServi
@Activate
public AVMFritzDiscoveryService(final @Reference LocaleProvider localeProvider,
final @Reference TranslationProvider i18nProvider) {
super(AVMFritzBaseBridgeHandler.class, Stream
.of(SUPPORTED_LIGHTING_THING_TYPES, SUPPORTED_BUTTON_THING_TYPES_UIDS, SUPPORTED_HEATING_THING_TYPES,
SUPPORTED_DEVICE_THING_TYPES_UIDS, SUPPORTED_GROUP_THING_TYPES_UIDS)
.flatMap(Set::stream).collect(Collectors.toUnmodifiableSet()), 30);
super(AVMFritzBaseBridgeHandler.class,
Stream.of(SUPPORTED_LIGHTING_THING_TYPES, SUPPORTED_BUTTON_THING_TYPES_UIDS,
SUPPORTED_HEATING_THING_TYPES, SUPPORTED_POWER_METER_THING_TYPES,
SUPPORTED_DEVICE_THING_TYPES_UIDS, SUPPORTED_GROUP_THING_TYPES_UIDS).flatMap(Set::stream)
.collect(Collectors.toUnmodifiableSet()),
30);
this.localeProvider = localeProvider;
this.i18nProvider = i18nProvider;
this.bundle = FrameworkUtil.getBundle(AVMFritzDiscoveryService.class);
Expand Down Expand Up @@ -119,10 +121,11 @@ private void onDeviceAddedInternal(ThingUID thingUID, AVMFritzBaseModel device)
if (device.getPresent() == 1) {
Map<String, Object> properties = new HashMap<>();
properties.put(CONFIG_AIN, device.getIdentifier());
properties.put(PROPERTY_VENDOR, device.getManufacturer());
properties.put(PRODUCT_NAME, device.getProductName());
properties.put(PROPERTY_SERIAL_NUMBER, device.getIdentifier());
properties.put(PROPERTY_FIRMWARE_VERSION, device.getFirmwareVersion());
properties.put(PROPERTY_DEVICE_ID, device.getDeviceId());
properties.put(Thing.PROPERTY_VENDOR, device.getManufacturer());
properties.put(PROPERTY_PRODUCT_NAME, device.getProductName());
properties.put(Thing.PROPERTY_SERIAL_NUMBER, device.getIdentifier());
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, device.getFirmwareVersion());
if (device instanceof GroupModel model && model.getGroupinfo() != null) {
properties.put(PROPERTY_MASTER, model.getGroupinfo().getMasterdeviceid());
properties.put(PROPERTY_MEMBERS, model.getGroupinfo().getMembers());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public abstract class AVMFritzBaseModel implements BatteryModel {
private @Nullable SimpleOnOffModel simpleOnOffUnit;

@XmlElement(name = "powermeter")
private PowerMeterModel powermeterModel;
private PowerMeterModel powerMeterModel;

@XmlElement(name = "hkr")
private HeatingModel heatingModel;
Expand All @@ -115,12 +115,12 @@ public abstract class AVMFritzBaseModel implements BatteryModel {
return simpleOnOffUnit;
}

public PowerMeterModel getPowermeter() {
return powermeterModel;
public PowerMeterModel getPowerMeter() {
return powerMeterModel;
}

public void setPowermeter(PowerMeterModel powermeter) {
this.powermeterModel = powermeter;
public void setPowerMeter(PowerMeterModel powerMeter) {
this.powerMeterModel = powerMeter;
}

public HeatingModel getHkr() {
Expand Down Expand Up @@ -179,7 +179,7 @@ public boolean isHumiditySensor() {
return (bitmask & HUMIDITY_SENSOR_BIT) > 0;
}

public boolean isPowermeter() {
public boolean isPowerMeter() {
return (bitmask & POWERMETER_BIT) > 0;
}

Expand Down Expand Up @@ -256,7 +256,7 @@ public String toString() {
.append(",isHANFUNAlarmSensor=").append(isHANFUNAlarmSensor()).append(",isButton=").append(isButton())
.append(",isSwitchableOutlet=").append(isSwitchableOutlet()).append(",isTemperatureSensor=")
.append(isTemperatureSensor()).append(",isHumiditySensor=").append(isHumiditySensor())
.append(",isPowermeter=").append(isPowermeter()).append(",isDectRepeater=").append(isDectRepeater())
.append(",isPowermeter=").append(isPowerMeter()).append(",isDectRepeater=").append(isDectRepeater())
.append(",isHeatingThermostat=").append(isHeatingThermostat()).append(",hasMicrophone=")
.append(hasMicrophone()).append(",isHANFUNUnit=").append(isHANFUNUnit()).append(",isHANFUNOnOff=")
.append(isHANFUNOnOff()).append(",isDimmableLight=").append(isDimmableLight()).append(",isColorLight=")
Expand All @@ -265,7 +265,7 @@ 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(",").toString();
}

public transient boolean isLinked;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
*/
package org.openhab.binding.avmfritz.internal.dto;

import java.util.Collections;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
Expand Down Expand Up @@ -98,7 +97,7 @@ public class DeviceListModel {

public List<AVMFritzBaseModel> getDevicelist() {
if (devices == null) {
devices = Collections.emptyList();
devices = List.of();
}
return devices;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,21 @@ public String getMode() {

public String getRadiatorMode() {
if (isOne(getWindowopenactiv())) {
return MODE_WINDOW_OPEN;
return HEATING_MODE_WINDOW_OPEN;
} else if (isOne(getBoostactive()) || (tsoll != null && TEMP_FRITZ_MAX.compareTo(tsoll) == 0)) {
return MODE_BOOST;
return HEATING_MODE_BOOST;
} else if (tsoll == null) {
return MODE_UNKNOWN;
return HEATING_MODE_UNKNOWN;
} else if (TEMP_FRITZ_ON.compareTo(tsoll) == 0) {
return MODE_ON;
return HEATING_MODE_ON;
} else if (TEMP_FRITZ_OFF.compareTo(tsoll) == 0) {
return MODE_OFF;
return HEATING_MODE_OFF;
} else if (komfort != null && komfort.compareTo(tsoll) == 0) {
return MODE_COMFORT;
return HEATING_MODE_COMFORT;
} else if (absenk != null && absenk.compareTo(tsoll) == 0) {
return MODE_ECO;
return HEATING_MODE_ECO;
} else {
return MODE_ON;
return HEATING_MODE_ON;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2010-2025 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.avmfritz.internal.dto.json;

import com.google.gson.annotations.SerializedName;

/**
*
* @author Christoph Weitkamp - Initial contribution
*/
public class EnergyStats {
@SerializedName("DeviceConnectState")
public String deviceConnectState;
@SerializedName("VoltageStat")
public Values voltageStat;
@SerializedName("MM_Value_Amp")
public int mMValueAmp;
@SerializedName("sum_Year")
public int sumYear;
@SerializedName("sum_Day")
public int sumDay;
@SerializedName("MM_Value_Volt")
public int mMValueVolt;
@SerializedName("MM_Value_Power")
public int mMValuePower;
@SerializedName("tabType")
public String tabType;
@SerializedName("DeviceID")
public String deviceID;
@SerializedName("DeviceSwitchState")
public String deviceSwitchState;
@SerializedName("EnergyStat")
public Values energyStat;
@SerializedName("CurrentDateInSec")
public String currentDateInSec;
@SerializedName("sum_Month")
public int sumMonth;
@SerializedName("RequestResult")
public boolean requestResult;
}
Loading