added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.avmfritz-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-avmfritz" description="AVM FRITZ!Box Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-upnp</feature>
|
||||
<feature dependency="true">openhab.tp-jaxb</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.avmfritz/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.actions;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.avmfritz.internal.actions.IAVMFritzHeatingActions;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzHeatingActionsHandler;
|
||||
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;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AVMFritzHeatingActions} defines thing actions for heating devices / groups of the avmfritz binding.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@ThingActionsScope(name = "avmfritz")
|
||||
@NonNullByDefault
|
||||
public class AVMFritzHeatingActions implements ThingActions, IAVMFritzHeatingActions {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AVMFritzHeatingActions.class);
|
||||
|
||||
private @Nullable AVMFritzHeatingActionsHandler handler;
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.handler = (AVMFritzHeatingActionsHandler) handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
@RuleAction(label = "@text/setBoostModeModeActionLabel", description = "@text/setBoostModeActionDescription")
|
||||
public void setBoostMode(
|
||||
@ActionInput(name = "Duration", label = "@text/setBoostModeDurationInputLabel", description = "@text/setBoostModeDurationInputDescription", type = "java.lang.Long", required = true) @Nullable Long duration) {
|
||||
AVMFritzHeatingActionsHandler actionsHandler = handler;
|
||||
if (actionsHandler == null) {
|
||||
throw new IllegalArgumentException("AVMFritzHeatingActions ThingHandler is null!");
|
||||
}
|
||||
if (duration == null) {
|
||||
throw new IllegalArgumentException("Cannot set Boost mode as 'duration' is null!");
|
||||
}
|
||||
actionsHandler.setBoostMode(duration.longValue());
|
||||
}
|
||||
|
||||
public static void setBoostMode(@Nullable ThingActions actions, @Nullable Long duration) {
|
||||
invokeMethodOf(actions).setBoostMode(duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@RuleAction(label = "@text/setWindowOpenModeActionLabel", description = "@text/setWindowOpenModeActionDescription")
|
||||
public void setWindowOpenMode(
|
||||
@ActionInput(name = "Duration", label = "@text/setWindowOpenModeDurationInputLabel", description = "@text/setWindowOpenModeDurationInputDescription", type = "java.lang.Long", required = true) @Nullable Long duration) {
|
||||
AVMFritzHeatingActionsHandler actionsHandler = handler;
|
||||
if (actionsHandler == null) {
|
||||
throw new IllegalArgumentException("AVMFritzHeatingActions ThingHandler is null!");
|
||||
}
|
||||
if (duration == null) {
|
||||
throw new IllegalArgumentException("Cannot set Window Open mode as 'duration' is null!");
|
||||
}
|
||||
actionsHandler.setWindowOpenMode(duration.longValue());
|
||||
}
|
||||
|
||||
public static void setWindowOpenMode(@Nullable ThingActions actions, @Nullable Long duration) {
|
||||
invokeMethodOf(actions).setWindowOpenMode(duration);
|
||||
}
|
||||
|
||||
private static IAVMFritzHeatingActions invokeMethodOf(@Nullable ThingActions actions) {
|
||||
if (actions == null) {
|
||||
throw new IllegalArgumentException("actions cannot be null");
|
||||
}
|
||||
if (actions.getClass().getName().equals(AVMFritzHeatingActions.class.getName())) {
|
||||
if (actions instanceof IAVMFritzHeatingActions) {
|
||||
return (IAVMFritzHeatingActions) actions;
|
||||
} else {
|
||||
return (IAVMFritzHeatingActions) Proxy.newProxyInstance(IAVMFritzHeatingActions.class.getClassLoader(),
|
||||
new Class[] { IAVMFritzHeatingActions.class }, (Object proxy, Method method, Object[] args) -> {
|
||||
Method m = actions.getClass().getDeclaredMethod(method.getName(),
|
||||
method.getParameterTypes());
|
||||
return m.invoke(actions, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Actions is not an instance of AVMFritzHeatingActions");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* This class defines common constants, which are used across the whole binding.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet DECT
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
* @author Christoph Weitkamp - Added channels 'voltage' and 'battery_level'
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AVMFritzBindingConstants {
|
||||
|
||||
public static final String INVALID_PATTERN = "[^a-zA-Z0-9_]";
|
||||
|
||||
public static final String BINDING_ID = "avmfritz";
|
||||
public static final String BRIDGE_FRITZBOX = "fritzbox";
|
||||
public static final String BOX_MODEL_NAME = "FRITZ!Box";
|
||||
public static final String POWERLINE_MODEL_NAME = "FRITZ!Powerline";
|
||||
|
||||
// List of main device types
|
||||
public static final String DEVICE_DECT400 = "FRITZ_DECT_400";
|
||||
public static final String DEVICE_DECT301 = "FRITZ_DECT_301";
|
||||
public static final String DEVICE_DECT300 = "FRITZ_DECT_300";
|
||||
public static final String DEVICE_DECT210 = "FRITZ_DECT_210";
|
||||
public static final String DEVICE_DECT200 = "FRITZ_DECT_200";
|
||||
public static final String DEVICE_DECT100 = "FRITZ_DECT_Repeater_100";
|
||||
public static final String DEVICE_PL546E = "FRITZ_Powerline_546E";
|
||||
public static final String DEVICE_PL546E_STANDALONE = "FRITZ_Powerline_546E_Solo";
|
||||
public static final String DEVICE_COMETDECT = "Comet_DECT";
|
||||
public static final String DEVICE_HAN_FUN_CONTACT = "HAN_FUN_CONTACT";
|
||||
public static final String DEVICE_HAN_FUN_SWITCH = "HAN_FUN_SWITCH";
|
||||
|
||||
// List of main group types
|
||||
public static final String GROUP_HEATING = "FRITZ_GROUP_HEATING";
|
||||
public static final String GROUP_SWITCH = "FRITZ_GROUP_SWITCH";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, BRIDGE_FRITZBOX);
|
||||
public static final ThingTypeUID DECT400_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT400);
|
||||
public static final ThingTypeUID DECT301_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT301);
|
||||
public static final ThingTypeUID DECT300_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT300);
|
||||
public static final ThingTypeUID DECT210_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT210);
|
||||
public static final ThingTypeUID DECT200_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT200);
|
||||
public static final ThingTypeUID DECT100_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_DECT100);
|
||||
public static final ThingTypeUID PL546E_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_PL546E);
|
||||
public static final ThingTypeUID PL546E_STANDALONE_THING_TYPE = new ThingTypeUID(BINDING_ID,
|
||||
DEVICE_PL546E_STANDALONE);
|
||||
public static final ThingTypeUID COMETDECT_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_COMETDECT);
|
||||
public static final ThingTypeUID HAN_FUN_CONTACT_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_CONTACT);
|
||||
public static final ThingTypeUID HAN_FUN_SWITCH_THING_TYPE = new ThingTypeUID(BINDING_ID, DEVICE_HAN_FUN_SWITCH);
|
||||
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);
|
||||
|
||||
// List of all Thing config ids
|
||||
public static final String CONFIG_IP_ADDRESS = "ipAddress";
|
||||
public static final String CONFIG_PROTOCOL = "protocol";
|
||||
public static final String CONFIG_USER = "user";
|
||||
public static final String CONFIG_PASSWORD = "password";
|
||||
public static final String CONFIG_POLLING_INTERVAL = "pollingInterval";
|
||||
public static final String CONFIG_SYNC_TIMEOUT = "syncTimeout";
|
||||
public static final String CONFIG_AIN = "ain";
|
||||
|
||||
// List of all Properties
|
||||
public static final String PROPERTY_MASTER = "master";
|
||||
public static final String PROPERTY_MEMBERS = "members";
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_CALL_INCOMING = "incoming_call";
|
||||
public static final String CHANNEL_CALL_OUTGOING = "outgoing_call";
|
||||
public static final String CHANNEL_CALL_ACTIVE = "active_call";
|
||||
public static final String CHANNEL_CALL_STATE = "call_state";
|
||||
|
||||
public static final String CHANNEL_MODE = "mode";
|
||||
public static final String CHANNEL_LOCKED = "locked";
|
||||
public static final String CHANNEL_DEVICE_LOCKED = "device_locked";
|
||||
public static final String CHANNEL_APPLY_TEMPLATE = "apply_template";
|
||||
public static final String CHANNEL_TEMPERATURE = "temperature";
|
||||
public static final String CHANNEL_ENERGY = "energy";
|
||||
public static final String CHANNEL_POWER = "power";
|
||||
public static final String CHANNEL_VOLTAGE = "voltage";
|
||||
public static final String CHANNEL_OUTLET = "outlet";
|
||||
public static final String CHANNEL_ACTUALTEMP = "actual_temp";
|
||||
public static final String CHANNEL_SETTEMP = "set_temp";
|
||||
public static final String CHANNEL_ECOTEMP = "eco_temp";
|
||||
public static final String CHANNEL_COMFORTTEMP = "comfort_temp";
|
||||
public static final String CHANNEL_RADIATOR_MODE = "radiator_mode";
|
||||
public static final String CHANNEL_NEXT_CHANGE = "next_change";
|
||||
public static final String CHANNEL_NEXTTEMP = "next_temp";
|
||||
public static final String CHANNEL_BATTERY_LOW = "battery_low";
|
||||
public static final String CHANNEL_BATTERY = "battery_level";
|
||||
public static final String CHANNEL_CONTACT_STATE = "contact_state";
|
||||
public static final String CHANNEL_PRESS = "press";
|
||||
public static final String CHANNEL_LAST_CHANGE = "last_change";
|
||||
|
||||
// List of all Channel config ids
|
||||
public static final String CONFIG_CHANNEL_TEMP_OFFSET = "offset";
|
||||
|
||||
// List of all Input tags
|
||||
public static final String INPUT_PRESENT = "present";
|
||||
public static final String INPUT_ACTUALTEMP = "tist";
|
||||
public static final String INPUT_SETTEMP = "tsoll";
|
||||
public static final String INPUT_ECOTEMP = "absenk";
|
||||
public static final String INPUT_COMFORTTEMP = "komfort";
|
||||
public static final String INPUT_NEXTCHANGE = "endperiod";
|
||||
public static final String INPUT_NEXTTEMP = "tchange";
|
||||
public static final String INPUT_BATTERY = "batterylow";
|
||||
|
||||
// List of all call states
|
||||
public static final StringType CALL_STATE_IDLE = new StringType("IDLE");
|
||||
public static final StringType CALL_STATE_RINGING = new StringType("RINGING");
|
||||
public static final StringType CALL_STATE_DIALING = new StringType("DIALING");
|
||||
public static final StringType CALL_STATE_ACTIVE = new StringType("ACTIVE");
|
||||
|
||||
// List of all Mode types
|
||||
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 Set<ThingTypeUID> SUPPORTED_BUTTON_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(DECT400_THING_TYPE, HAN_FUN_SWITCH_THING_TYPE).collect(Collectors.toSet()));
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_HEATING_THING_TYPES = Collections.unmodifiableSet(
|
||||
Stream.of(DECT300_THING_TYPE, DECT301_THING_TYPE, COMETDECT_THING_TYPE).collect(Collectors.toSet()));
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(DECT100_THING_TYPE, DECT200_THING_TYPE, DECT210_THING_TYPE, PL546E_THING_TYPE,
|
||||
HAN_FUN_CONTACT_THING_TYPE).collect(Collectors.toSet()));
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_GROUP_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(GROUP_HEATING_THING_TYPE, GROUP_SWITCH_THING_TYPE).collect(Collectors.toSet()));
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_BRIDGE_THING_TYPES_UIDS = Collections
|
||||
.unmodifiableSet(Stream.of(BRIDGE_THING_TYPE, PL546E_STANDALONE_THING_TYPE).collect(Collectors.toSet()));
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(Stream
|
||||
.of(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.toSet()));
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.binding.BaseDynamicCommandDescriptionProvider;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.type.DynamicCommandDescriptionProvider;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* Dynamic provider of command options.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@Component(service = { DynamicCommandDescriptionProvider.class, AVMFritzDynamicCommandDescriptionProvider.class })
|
||||
@NonNullByDefault
|
||||
public class AVMFritzDynamicCommandDescriptionProvider extends BaseDynamicCommandDescriptionProvider {
|
||||
|
||||
@Activate
|
||||
public AVMFritzDynamicCommandDescriptionProvider(
|
||||
final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
|
||||
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzButtonHandler;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzHeatingDeviceHandler;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzHeatingGroupHandler;
|
||||
import org.openhab.binding.avmfritz.internal.handler.BoxHandler;
|
||||
import org.openhab.binding.avmfritz.internal.handler.DeviceHandler;
|
||||
import org.openhab.binding.avmfritz.internal.handler.GroupHandler;
|
||||
import org.openhab.binding.avmfritz.internal.handler.Powerline546EHandler;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AVMFritzHandlerFactory} is responsible for creating things and thing handlers.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.avmfritz")
|
||||
@NonNullByDefault
|
||||
public class AVMFritzHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AVMFritzHandlerFactory.class);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final AVMFritzDynamicCommandDescriptionProvider commandDescriptionProvider;
|
||||
|
||||
@Activate
|
||||
public AVMFritzHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
||||
final @Reference AVMFritzDynamicCommandDescriptionProvider stateDescriptionProvider) {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
this.commandDescriptionProvider = stateDescriptionProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the supported thing types
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create handler of things.
|
||||
*/
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
if (BRIDGE_THING_TYPE.equals(thingTypeUID)) {
|
||||
return new BoxHandler((Bridge) thing, httpClient, commandDescriptionProvider);
|
||||
} else if (PL546E_STANDALONE_THING_TYPE.equals(thingTypeUID)) {
|
||||
return new Powerline546EHandler((Bridge) thing, httpClient, commandDescriptionProvider);
|
||||
} else if (SUPPORTED_BUTTON_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
||||
return new AVMFritzButtonHandler(thing);
|
||||
} else if (SUPPORTED_HEATING_THING_TYPES.contains(thingTypeUID)) {
|
||||
return new AVMFritzHeatingDeviceHandler(thing);
|
||||
} else if (SUPPORTED_DEVICE_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
||||
return new DeviceHandler(thing);
|
||||
} else if (GROUP_HEATING_THING_TYPE.equals(thingTypeUID)) {
|
||||
return new AVMFritzHeatingGroupHandler(thing);
|
||||
} else if (SUPPORTED_GROUP_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
||||
return new GroupHandler(thing);
|
||||
} else {
|
||||
logger.error("ThingHandler not found for {}", thingTypeUID);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
|
||||
import org.openhab.core.io.net.http.TrustAllTrustMananger;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* Provides a TrustManager to allow secure connections to any FRITZ!Box
|
||||
*
|
||||
* @author Chritoph Weitkamp - Initial Contribution
|
||||
*/
|
||||
@Component
|
||||
@NonNullByDefault
|
||||
public class AVMFritzTlsTrustManagerProvider implements TlsTrustManagerProvider {
|
||||
|
||||
@Override
|
||||
public String getHostName() {
|
||||
return "fritz.box";
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509ExtendedTrustManager getTrustManager() {
|
||||
return TrustAllTrustMananger.getInstance();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.actions.AVMFritzHeatingActions;
|
||||
|
||||
/**
|
||||
* The {@link IAVMFritzHeatingActions} defines the interface for all thing actions supported by the binding.
|
||||
* These methods, parameters, and return types are explained in {@link AVMFritzHeatingActions}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface IAVMFritzHeatingActions {
|
||||
|
||||
void setBoostMode(@Nullable Long duration);
|
||||
|
||||
void setWindowOpenMode(@Nullable Long duration);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.callmonitor;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Call Events received from a fritzbox.
|
||||
*
|
||||
* 12.07.20 09:11:30;RING;0;0171123456;888888;SIP2;
|
||||
* 12.07.20 09:13:40;DISCONNECT;0;0;
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CallEvent {
|
||||
|
||||
private final String rawEvent;
|
||||
private final String timestamp;
|
||||
private final String callType;
|
||||
private final String id;
|
||||
private @Nullable String externalNo;
|
||||
private @Nullable String internalNo;
|
||||
private @Nullable String connectionType;
|
||||
private @Nullable String line;
|
||||
|
||||
public CallEvent(String rawEvent) {
|
||||
this.rawEvent = rawEvent;
|
||||
|
||||
String[] fields = rawEvent.split(";");
|
||||
if (fields.length < 4) {
|
||||
throw new IllegalArgumentException("Cannot parse call event: " + rawEvent);
|
||||
}
|
||||
|
||||
timestamp = fields[0];
|
||||
callType = fields[1];
|
||||
id = fields[2];
|
||||
|
||||
if (callType.equals("RING")) {
|
||||
externalNo = fields[3];
|
||||
internalNo = fields[4];
|
||||
connectionType = fields[5];
|
||||
} else if (callType.equals("CONNECT")) {
|
||||
line = fields[3];
|
||||
if (fields.length > 4) {
|
||||
externalNo = fields[4];
|
||||
} else {
|
||||
externalNo = "Unknown";
|
||||
}
|
||||
} else if (callType.equals("CALL")) {
|
||||
line = fields[3];
|
||||
internalNo = fields[4];
|
||||
externalNo = fields[5];
|
||||
connectionType = fields[6];
|
||||
} else if (callType.equals("DISCONNECT")) {
|
||||
// no fields to set
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid call type: " + callType);
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable String getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public String getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public String getCallType() {
|
||||
return callType;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @Nullable String getExternalNo() {
|
||||
return externalNo;
|
||||
}
|
||||
|
||||
public @Nullable String getInternalNo() {
|
||||
return internalNo;
|
||||
}
|
||||
|
||||
public @Nullable String getConnectionType() {
|
||||
return connectionType;
|
||||
}
|
||||
|
||||
public String getRaw() {
|
||||
return rawEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CallEvent [timestamp=" + timestamp + ", callType=" + callType + ", id=" + id + ", externalNo="
|
||||
+ externalNo + ", internalNo=" + internalNo + ", connectionType=" + connectionType + ", line=" + line
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.callmonitor;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants;
|
||||
import org.openhab.binding.avmfritz.internal.handler.BoxHandler;
|
||||
import org.openhab.core.library.types.StringListType;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class handles all communication with the call monitor port of the fritzbox.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class CallMonitor {
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(CallMonitor.class);
|
||||
|
||||
// port number to connect to fritzbox
|
||||
private final int MONITOR_PORT = 1012;
|
||||
|
||||
private @Nullable CallMonitorThread monitorThread;
|
||||
private ScheduledFuture<?> reconnectJob;
|
||||
|
||||
private String ip;
|
||||
private BoxHandler handler;
|
||||
|
||||
public CallMonitor(String ip, BoxHandler handler, ScheduledExecutorService scheduler) {
|
||||
this.ip = ip;
|
||||
this.handler = handler;
|
||||
reconnectJob = scheduler.scheduleWithFixedDelay(() -> {
|
||||
stopThread();
|
||||
|
||||
// Wait before reconnect
|
||||
try {
|
||||
Thread.sleep(5000L);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
// create a new thread for listening to the FritzBox
|
||||
CallMonitorThread thread = new CallMonitorThread();
|
||||
thread.setName("OH-binding-" + handler.getThing().getUID().getAsString());
|
||||
thread.start();
|
||||
this.monitorThread = thread;
|
||||
}, 0, 2, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the reconnect job.
|
||||
*/
|
||||
public void dispose() {
|
||||
reconnectJob.cancel(true);
|
||||
}
|
||||
|
||||
public class CallMonitorThread extends Thread {
|
||||
|
||||
// Socket to connect
|
||||
private @Nullable Socket socket;
|
||||
|
||||
// Thread control flag
|
||||
private boolean interrupted = false;
|
||||
|
||||
// time to wait before reconnecting
|
||||
private long reconnectTime = 60000L;
|
||||
|
||||
public CallMonitorThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!interrupted) {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
logger.debug("Callmonitor thread [{}] attempting connection to FritzBox on {}:{}.",
|
||||
Thread.currentThread().getId(), ip, MONITOR_PORT);
|
||||
socket = new Socket(ip, MONITOR_PORT);
|
||||
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
// reset the retry interval
|
||||
reconnectTime = 60000L;
|
||||
} catch (Exception e) {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Cannot connect to Fritz!Box call monitor - make sure to enable it by dialing '#96*5'!");
|
||||
logger.debug("Error attempting to connect to FritzBox. Retrying in {} seconds",
|
||||
reconnectTime / 1000L, e);
|
||||
try {
|
||||
Thread.sleep(reconnectTime);
|
||||
} catch (InterruptedException ex) {
|
||||
interrupted = true;
|
||||
}
|
||||
// wait another more minute the next time
|
||||
reconnectTime += 60000L;
|
||||
}
|
||||
if (reader != null) {
|
||||
logger.debug("Connected to FritzBox call monitor at {}:{}.", ip, MONITOR_PORT);
|
||||
handler.setStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
while (!interrupted) {
|
||||
try {
|
||||
String line = reader.readLine();
|
||||
if (line != null) {
|
||||
logger.debug("Received raw call string from fbox: {}", line);
|
||||
CallEvent ce = new CallEvent(line);
|
||||
handleCallEvent(ce);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (interrupted) {
|
||||
logger.debug("Lost connection to Fritzbox because of an interrupt.");
|
||||
} else {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Lost connection to Fritz!Box: " + e.getMessage());
|
||||
}
|
||||
break;
|
||||
} finally {
|
||||
try {
|
||||
sleep(1000L);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close socket and stop running thread.
|
||||
*/
|
||||
@Override
|
||||
public void interrupt() {
|
||||
interrupted = true;
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
logger.debug("Socket to FritzBox closed.");
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to close connection to FritzBox.", e);
|
||||
}
|
||||
} else {
|
||||
logger.debug("Socket to FritzBox not open, therefore not closing it.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle call event and update item as required.
|
||||
*
|
||||
* @param ce call event to process
|
||||
*/
|
||||
private void handleCallEvent(CallEvent ce) {
|
||||
if (ce.getCallType().equals("DISCONNECT")) {
|
||||
// reset states of call monitor channels
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_INCOMING, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_OUTGOING, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_ACTIVE, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_STATE,
|
||||
AVMFritzBindingConstants.CALL_STATE_IDLE);
|
||||
} else if (ce.getCallType().equals("RING")) { // first event when call is incoming
|
||||
StringListType state = new StringListType(ce.getInternalNo(), ce.getExternalNo());
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_INCOMING, state);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_OUTGOING, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_ACTIVE, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_STATE,
|
||||
AVMFritzBindingConstants.CALL_STATE_RINGING);
|
||||
} else if (ce.getCallType().equals("CONNECT")) { // when call is answered/running
|
||||
StringListType state = new StringListType(ce.getExternalNo(), "");
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_ACTIVE, state);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_INCOMING, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_OUTGOING, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_STATE,
|
||||
AVMFritzBindingConstants.CALL_STATE_ACTIVE);
|
||||
} else if (ce.getCallType().equals("CALL")) { // outgoing call
|
||||
StringListType state = new StringListType(ce.getExternalNo(), ce.getInternalNo());
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_INCOMING, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_OUTGOING, state);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_ACTIVE, UnDefType.UNDEF);
|
||||
handler.updateState(AVMFritzBindingConstants.CHANNEL_CALL_STATE,
|
||||
AVMFritzBindingConstants.CALL_STATE_DIALING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopThread() {
|
||||
logger.debug("Stopping call monitor thread...");
|
||||
if (monitorThread != null) {
|
||||
monitorThread.interrupt();
|
||||
monitorThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void startThread() {
|
||||
logger.debug("Starting call monitor thread...");
|
||||
if (monitorThread != null) {
|
||||
monitorThread.interrupt();
|
||||
monitorThread = null;
|
||||
}
|
||||
// create a new thread for listening to the FritzBox
|
||||
monitorThread = new CallMonitorThread();
|
||||
monitorThread.start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Bean holding configuration data for FRITZ! Box.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AVMFritzBoxConfiguration {
|
||||
|
||||
public @NonNullByDefault({}) String ipAddress;
|
||||
public @Nullable Integer port;
|
||||
public String protocol = "http";
|
||||
|
||||
public @Nullable String user;
|
||||
public @NonNullByDefault({}) String password;
|
||||
|
||||
public long pollingInterval = 15;
|
||||
public long asyncTimeout = 10000;
|
||||
public long syncTimeout = 2000;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[IP=").append(ipAddress).append(",port=").append(port).append(",protocol=")
|
||||
.append(protocol).append(",user=").append(user).append(",pollingInterval=").append(pollingInterval)
|
||||
.append(",asyncTimeout=").append(asyncTimeout).append(",syncTimeout=").append(syncTimeout).append("]")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Bean holding configuration data for FRITZ! devices.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AVMFritzDeviceConfiguration {
|
||||
|
||||
public @Nullable String ain;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[identifier=").append(ain).append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.discovery;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
import static org.openhab.core.thing.Thing.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.GroupModel;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzBaseBridgeHandler;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaStatusListener;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Discover all AHA (AVM Home Automation) devices connected to a FRITZ!Box device.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AVMFritzDiscoveryService extends AbstractDiscoveryService
|
||||
implements FritzAhaStatusListener, DiscoveryService, ThingHandlerService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AVMFritzDiscoveryService.class);
|
||||
/**
|
||||
* Handler of the bridge of which devices have to be discovered.
|
||||
*/
|
||||
private @NonNullByDefault({}) AVMFritzBaseBridgeHandler bridgeHandler;
|
||||
|
||||
public AVMFritzDiscoveryService() {
|
||||
super(Collections
|
||||
.unmodifiableSet(Stream
|
||||
.of(SUPPORTED_BUTTON_THING_TYPES_UIDS, SUPPORTED_HEATING_THING_TYPES,
|
||||
SUPPORTED_DEVICE_THING_TYPES_UIDS, SUPPORTED_GROUP_THING_TYPES_UIDS)
|
||||
.flatMap(Set::stream).collect(Collectors.toSet())),
|
||||
30);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
super.activate(null);
|
||||
bridgeHandler.registerStatusListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
bridgeHandler.unregisterStatusListener(this);
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startScan() {
|
||||
logger.debug("Start manual scan on bridge {}", bridgeHandler.getThing().getUID());
|
||||
bridgeHandler.handleRefreshCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
logger.debug("Stop manual scan on bridge {}", bridgeHandler.getThing().getUID());
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@NonNullByDefault({}) ThingHandler handler) {
|
||||
if (handler instanceof AVMFritzBaseBridgeHandler) {
|
||||
bridgeHandler = (AVMFritzBaseBridgeHandler) handler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceAdded(AVMFritzBaseModel device) {
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, bridgeHandler.getThingTypeId(device));
|
||||
if (getSupportedThingTypes().contains(thingTypeUID)) {
|
||||
ThingUID thingUID = new ThingUID(thingTypeUID, bridgeHandler.getThing().getUID(),
|
||||
bridgeHandler.getThingName(device));
|
||||
onDeviceAddedInternal(thingUID, device);
|
||||
} else {
|
||||
logger.debug("Discovered unsupported device: {}", device);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) {
|
||||
onDeviceAddedInternal(thingUID, device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceGone(ThingUID thingUID) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
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(PROPERTY_MODEL_ID, device.getDeviceId());
|
||||
properties.put(PROPERTY_SERIAL_NUMBER, device.getIdentifier());
|
||||
properties.put(PROPERTY_FIRMWARE_VERSION, device.getFirmwareVersion());
|
||||
if (device instanceof GroupModel && ((GroupModel) device).getGroupinfo() != null) {
|
||||
properties.put(PROPERTY_MASTER, ((GroupModel) device).getGroupinfo().getMasterdeviceid());
|
||||
properties.put(PROPERTY_MEMBERS, ((GroupModel) device).getGroupinfo().getMembers());
|
||||
}
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||
.withRepresentationProperty(CONFIG_AIN).withBridge(bridgeHandler.getThing().getUID())
|
||||
.withLabel(device.getName()).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
} else {
|
||||
thingRemoved(thingUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.discovery;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
import static org.openhab.core.thing.Thing.PROPERTY_VENDOR;
|
||||
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.jupnp.model.meta.DeviceDetails;
|
||||
import org.jupnp.model.meta.ModelDetails;
|
||||
import org.jupnp.model.meta.RemoteDevice;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Modified;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link AVMFritzUpnpDiscoveryParticipant} is responsible for discovering new and removed FRITZ!Box devices. It
|
||||
* uses the central {@link UpnpDiscoveryService}.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
* @author Christoph Weitkamp - Use "discovery.avmfritz:background=false" to disable discovery service
|
||||
*/
|
||||
@Component(immediate = true, configurationPid = "discovery.avmfritz")
|
||||
@NonNullByDefault
|
||||
public class AVMFritzUpnpDiscoveryParticipant implements UpnpDiscoveryParticipant {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AVMFritzUpnpDiscoveryParticipant.class);
|
||||
|
||||
private boolean isAutoDiscoveryEnabled = true;
|
||||
|
||||
@Activate
|
||||
protected void activate(ComponentContext componentContext) {
|
||||
activateOrModifyService(componentContext);
|
||||
}
|
||||
|
||||
@Modified
|
||||
protected void modified(ComponentContext componentContext) {
|
||||
activateOrModifyService(componentContext);
|
||||
}
|
||||
|
||||
private void activateOrModifyService(ComponentContext componentContext) {
|
||||
Dictionary<String, @Nullable Object> properties = componentContext.getProperties();
|
||||
String autoDiscoveryPropertyValue = (String) properties.get("background");
|
||||
if (autoDiscoveryPropertyValue != null && autoDiscoveryPropertyValue.length() != 0) {
|
||||
isAutoDiscoveryEnabled = Boolean.valueOf(autoDiscoveryPropertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return SUPPORTED_BRIDGE_THING_TYPES_UIDS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
|
||||
if (isAutoDiscoveryEnabled) {
|
||||
ThingUID uid = getThingUID(device);
|
||||
if (uid != null) {
|
||||
logger.debug("discovered: {} ({}) at {}", device.getDisplayString(),
|
||||
device.getDetails().getFriendlyName(), device.getIdentity().getDescriptorURL().getHost());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(CONFIG_IP_ADDRESS, device.getIdentity().getDescriptorURL().getHost());
|
||||
properties.put(PROPERTY_VENDOR, device.getDetails().getManufacturerDetails().getManufacturer());
|
||||
|
||||
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withLabel(device.getDetails().getFriendlyName()).withRepresentationProperty(CONFIG_IP_ADDRESS)
|
||||
.build();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
||||
// newer FRITZ!OS versions return several upnp services (e.g. Mediaserver)
|
||||
if (device.getType().getType().equals(BRIDGE_FRITZBOX)) {
|
||||
DeviceDetails details = device.getDetails();
|
||||
if (details != null) {
|
||||
ModelDetails modelDetails = details.getModelDetails();
|
||||
if (modelDetails != null) {
|
||||
String modelName = modelDetails.getModelName();
|
||||
if (modelName != null) {
|
||||
// It would be better to use udn but in my case FB is discovered twice
|
||||
// .getIdentity().getUdn().getIdentifierString()
|
||||
String id = device.getIdentity().getDescriptorURL().getHost().replaceAll(INVALID_PATTERN, "_");
|
||||
if (modelName.startsWith(BOX_MODEL_NAME)) {
|
||||
logger.debug("discovered on {}", device.getIdentity().getDiscoveredOnLocalAddress());
|
||||
return new ThingUID(BRIDGE_THING_TYPE, id);
|
||||
} else if (modelName.startsWith(POWERLINE_MODEL_NAME)) {
|
||||
logger.debug("discovered on {}", device.getIdentity().getDiscoveredOnLocalAddress());
|
||||
return new ThingUID(PL546E_STANDALONE_THING_TYPE, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* In the functionbitmask element value the following bits are used:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Bit 0: HAN-FUN Gerät</li>
|
||||
* <li>Bit 3: Button</li>
|
||||
* <li>Bit 4: Alarm-Sensor</li>
|
||||
* <li>Bit 6: Comet DECT, Heizkörperregler</li>
|
||||
* <li>Bit 7: Energie Messgerät</li>
|
||||
* <li>Bit 8: Temperatursensor</li>
|
||||
* <li>Bit 9: Schaltsteckdose</li>
|
||||
* <li>Bit 10: AVM DECT Repeater</li>
|
||||
* <li>Bit 11: Mikrofon</li>
|
||||
* <li>Bit 13: HAN-FUN Unit</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet DECT
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
public abstract class AVMFritzBaseModel implements BatteryModel {
|
||||
protected static final int HAN_FUN_DEVICE_BIT = 1; // Bit 0
|
||||
protected static final int HAN_FUN_BUTTON_BIT = 1 << 3; // Bit 3 - undocumented
|
||||
protected static final int HAN_FUN_ALARM_SENSOR_BIT = 1 << 4; // Bit 4
|
||||
protected static final int BUTTON_BIT = 1 << 5; // Bit 5 - undocumented
|
||||
protected static final int HEATING_THERMOSTAT_BIT = 1 << 6; // Bit 6
|
||||
protected static final int POWERMETER_BIT = 1 << 7; // Bit 7
|
||||
protected static final int TEMPSENSOR_BIT = 1 << 8; // Bit 8
|
||||
protected static final int OUTLET_BIT = 1 << 9; // Bit 9
|
||||
protected static final int DECT_REPEATER_BIT = 1 << 10; // Bit 10
|
||||
protected static final int MICROPHONE_BIT = 1 << 11; // Bit 11
|
||||
protected static final int HAN_FUN_UNIT_BIT = 1 << 13; // Bit 13
|
||||
|
||||
@XmlAttribute(name = "identifier")
|
||||
private String ident;
|
||||
|
||||
@XmlAttribute(name = "id")
|
||||
private String deviceId;
|
||||
|
||||
@XmlAttribute(name = "functionbitmask")
|
||||
private int bitmask;
|
||||
|
||||
@XmlAttribute(name = "fwversion")
|
||||
private String firmwareVersion;
|
||||
|
||||
@XmlAttribute(name = "manufacturer")
|
||||
private String deviceManufacturer;
|
||||
|
||||
@XmlAttribute(name = "productname")
|
||||
private String productName;
|
||||
|
||||
@XmlElement(name = "present")
|
||||
private Integer present;
|
||||
|
||||
@XmlElement(name = "name")
|
||||
private String name;
|
||||
|
||||
@XmlElement(name = "battery")
|
||||
private BigDecimal battery;
|
||||
|
||||
@XmlElement(name = "batterylow")
|
||||
private BigDecimal batterylow;
|
||||
|
||||
@XmlElement(name = "switch")
|
||||
private SwitchModel switchModel;
|
||||
|
||||
@XmlElement(name = "powermeter")
|
||||
private PowerMeterModel powermeterModel;
|
||||
|
||||
@XmlElement(name = "hkr")
|
||||
private HeatingModel heatingModel;
|
||||
|
||||
public PowerMeterModel getPowermeter() {
|
||||
return powermeterModel;
|
||||
}
|
||||
|
||||
public void setPowermeter(PowerMeterModel powermeter) {
|
||||
this.powermeterModel = powermeter;
|
||||
}
|
||||
|
||||
public HeatingModel getHkr() {
|
||||
return heatingModel;
|
||||
}
|
||||
|
||||
public void setHkr(HeatingModel heatingModel) {
|
||||
this.heatingModel = heatingModel;
|
||||
}
|
||||
|
||||
public SwitchModel getSwitch() {
|
||||
return switchModel;
|
||||
}
|
||||
|
||||
public void setSwitch(SwitchModel switchModel) {
|
||||
this.switchModel = switchModel;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return ident != null ? ident.replace(" ", "") : null;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.ident = identifier;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public boolean isHANFUNDevice() {
|
||||
return (bitmask & HAN_FUN_DEVICE_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isHANFUNButton() {
|
||||
return (bitmask & HAN_FUN_BUTTON_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isHANFUNAlarmSensor() {
|
||||
return (bitmask & HAN_FUN_ALARM_SENSOR_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isButton() {
|
||||
return (bitmask & BUTTON_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isSwitchableOutlet() {
|
||||
return (bitmask & OUTLET_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isTempSensor() {
|
||||
return (bitmask & TEMPSENSOR_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isPowermeter() {
|
||||
return (bitmask & POWERMETER_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isDectRepeater() {
|
||||
return (bitmask & DECT_REPEATER_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isHeatingThermostat() {
|
||||
return (bitmask & HEATING_THERMOSTAT_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isMicrophone() {
|
||||
return (bitmask & MICROPHONE_BIT) > 0;
|
||||
}
|
||||
|
||||
public boolean isHANFUNUnit() {
|
||||
return (bitmask & HAN_FUN_UNIT_BIT) > 0;
|
||||
}
|
||||
|
||||
public String getFirmwareVersion() {
|
||||
return firmwareVersion;
|
||||
}
|
||||
|
||||
public String getManufacturer() {
|
||||
return deviceManufacturer;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public int getPresent() {
|
||||
return present;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBattery() {
|
||||
return battery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBatterylow() {
|
||||
return batterylow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[ain=").append(ident).append(",bitmask=").append(bitmask)
|
||||
.append(",isHANFUNDevice=").append(isHANFUNDevice()).append(",isHANFUNButton=").append(isHANFUNButton())
|
||||
.append(",isHANFUNAlarmSensor=").append(isHANFUNAlarmSensor()).append(",isButton").append(isButton())
|
||||
.append(",isSwitchableOutlet=").append(isSwitchableOutlet()).append(",isTempSensor=")
|
||||
.append(isTempSensor()).append(",isPowermeter=").append(isPowermeter()).append(",isDectRepeater=")
|
||||
.append(isDectRepeater()).append(",isHeatingThermostat=").append(isHeatingThermostat())
|
||||
.append(",isMicrophone=").append(isMicrophone()).append(",isHANFUNUnit=").append(isHANFUNUnit())
|
||||
.append(",id=").append(deviceId).append(",manufacturer=").append(deviceManufacturer)
|
||||
.append(",productname=").append(productName).append(",fwversion=").append(firmwareVersion)
|
||||
.append(",present=").append(present).append(",name=").append(name).append(",battery")
|
||||
.append(getBattery()).append(",batterylow").append(getBatterylow()).append(getSwitch())
|
||||
.append(getPowermeter()).append(getHkr()).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = { "state" })
|
||||
@XmlRootElement(name = "alert")
|
||||
public class AlertModel {
|
||||
public static final BigDecimal ON = BigDecimal.ONE;
|
||||
public static final BigDecimal OFF = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal state;
|
||||
|
||||
public BigDecimal getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(BigDecimal state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[state=").append(state).append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* See {@link AVMFritzBaseModel} -> {@link DeviceModel} and {@link HeatingModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public interface BatteryModel {
|
||||
|
||||
public static final BigDecimal BATTERY_OFF = BigDecimal.ZERO;
|
||||
public static final BigDecimal BATTERY_ON = BigDecimal.ONE;
|
||||
|
||||
BigDecimal getBattery();
|
||||
|
||||
BigDecimal getBatterylow();
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "button")
|
||||
public class ButtonModel {
|
||||
|
||||
@XmlAttribute(name = "identifier")
|
||||
private String identifier;
|
||||
|
||||
@XmlAttribute(name = "id")
|
||||
private String buttonId;
|
||||
|
||||
@XmlElement(name = "name")
|
||||
private String name;
|
||||
|
||||
@XmlElement(name = "lastpressedtimestamp")
|
||||
private int lastpressedtimestamp;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier != null ? identifier.replace(" ", "") : null;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public String getButtonId() {
|
||||
return buttonId;
|
||||
}
|
||||
|
||||
public void setButtonId(String buttonId) {
|
||||
this.buttonId = buttonId;
|
||||
}
|
||||
|
||||
public int getLastpressedtimestamp() {
|
||||
return lastpressedtimestamp;
|
||||
}
|
||||
|
||||
public void setLastpressedtimestamp(int lastpressedtimestamp) {
|
||||
this.lastpressedtimestamp = lastpressedtimestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (identifier != null ? identifier.hashCode() : 0);
|
||||
result = prime * result + (buttonId != null ? buttonId.hashCode() : 0);
|
||||
result = prime * result + (name != null ? name.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ButtonModel other = (ButtonModel) obj;
|
||||
return (identifier != null ? identifier.equals(other.identifier) : other.identifier == null) && //
|
||||
(buttonId != null ? buttonId.equals(other.buttonId) : other.buttonId == null) && //
|
||||
(name != null ? name.equals(other.name) : other.name == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[identifier=").append(getIdentifier()).append(",id=").append(buttonId)
|
||||
.append(",name=").append(name).append(",lastpressedtimestamp=").append(lastpressedtimestamp).append("]")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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.XmlElements;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* This JAXB model class maps the XML response to an <b>getdevicelistinfos</b>
|
||||
* command on a FRITZ!Box device. As of today, this class is able to to bind the
|
||||
* devicelist version 1 (currently used by AVM) response:
|
||||
*
|
||||
* <pre>
|
||||
* <devicelist version="1">
|
||||
* <device identifier="##############" id="##" functionbitmask="2944" fwversion="03.83" manufacturer="AVM" productname=
|
||||
* "FRITZ!DECT 200">
|
||||
* <present>1</present>
|
||||
* <name>FRITZ!DECT 200 #1</name>
|
||||
* <switch>
|
||||
* <state>0</state>
|
||||
* <mode>manuell</mode>
|
||||
* <lock>0</lock>
|
||||
* <devicelock>1</devicelock>
|
||||
* </switch>
|
||||
* <powermeter>
|
||||
* <power>0</power>
|
||||
* <energy>166</energy>
|
||||
* </powermeter>
|
||||
* <temperature>
|
||||
* <celsius>255</celsius>
|
||||
* <offset>0</offset>
|
||||
* </temperature>
|
||||
* </device>
|
||||
* <device identifier="##############" id="xx" functionbitmask="320" fwversion="03.50" manufacturer="AVM" productname=
|
||||
* "Comet DECT">
|
||||
* <present>1</present>
|
||||
* <name>Comet DECT #1</name>
|
||||
* <temperature>
|
||||
* <celsius>220</celsius>
|
||||
* <offset>-10</offset>
|
||||
* </temperature>
|
||||
* <hkr>
|
||||
* <tist>44</tist>
|
||||
* <tsoll>42</tsoll>
|
||||
* <absenk>28</absenk>
|
||||
* <komfort>42</komfort>
|
||||
* <lock>0</lock>
|
||||
* <devicelock>0</devicelock>
|
||||
* <errorcode>0</errorcode>
|
||||
* <batterylow>0</batterylow>
|
||||
* <nextchange>
|
||||
* <endperiod>1484341200</endperiod>
|
||||
* <tchange>28</tchange>
|
||||
* </nextchange>
|
||||
* </hkr>
|
||||
* </device>
|
||||
* </devicelist>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType
|
||||
@XmlRootElement(name = "devicelist")
|
||||
public class DeviceListModel {
|
||||
|
||||
@XmlAttribute(name = "version")
|
||||
private String apiVersion;
|
||||
|
||||
//@formatter:off
|
||||
@XmlElements({
|
||||
@XmlElement(name = "device", type = DeviceModel.class),
|
||||
@XmlElement(name = "group", type = GroupModel.class)
|
||||
})
|
||||
//@formatter:on
|
||||
private List<AVMFritzBaseModel> devices;
|
||||
|
||||
public List<AVMFritzBaseModel> getDevicelist() {
|
||||
if (devices == null) {
|
||||
devices = Collections.emptyList();
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
public void setDevicelist(List<AVMFritzBaseModel> devices) {
|
||||
this.devices = devices;
|
||||
}
|
||||
|
||||
public String getXmlApiVersion() {
|
||||
return apiVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[devices=").append(devices).append(",version=").append(apiVersion)
|
||||
.append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* See {@link AVMFritzBaseModel}.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "device")
|
||||
public class DeviceModel extends AVMFritzBaseModel {
|
||||
|
||||
private TemperatureModel temperature;
|
||||
private AlertModel alert;
|
||||
|
||||
@XmlElement(name = "button", type = ButtonModel.class)
|
||||
private List<ButtonModel> buttons;
|
||||
|
||||
private ETSUnitInfoModel etsiunitinfo;
|
||||
|
||||
public TemperatureModel getTemperature() {
|
||||
return temperature;
|
||||
}
|
||||
|
||||
public void setTemperature(TemperatureModel temperatureModel) {
|
||||
this.temperature = temperatureModel;
|
||||
}
|
||||
|
||||
public AlertModel getAlert() {
|
||||
return alert;
|
||||
}
|
||||
|
||||
public void setAlert(AlertModel alertModel) {
|
||||
this.alert = alertModel;
|
||||
}
|
||||
|
||||
public List<ButtonModel> getButtons() {
|
||||
if (buttons == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public void setButtons(List<ButtonModel> buttons) {
|
||||
this.buttons = buttons;
|
||||
}
|
||||
|
||||
public ETSUnitInfoModel getEtsiunitinfo() {
|
||||
return etsiunitinfo;
|
||||
}
|
||||
|
||||
public void setEtsiunitinfo(ETSUnitInfoModel etsiunitinfo) {
|
||||
this.etsiunitinfo = etsiunitinfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append(super.toString()).append(temperature).append(alert).append(getButtons())
|
||||
.append(etsiunitinfo).append("]").toString();
|
||||
}
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = { "etsideviceid", "unittype", "interfaces" })
|
||||
public static class ETSUnitInfoModel {
|
||||
public static final String HAN_FUN_UNITTYPE_SIMPLE_BUTTON = "273";
|
||||
public static final String HAN_FUN_UNITTYPE_SIMPLE_DETECTOR = "512";
|
||||
public static final String HAN_FUN_UNITTYPE_MAGNETIC_CONTACT = "513";
|
||||
public static final String HAN_FUN_UNITTYPE_OPTICAL_CONTACT = "514";
|
||||
public static final String HAN_FUN_UNITTYPE_MOTION_DETECTOR = "515";
|
||||
public static final String HAN_FUN_UNITTYPE_SMOKE_DETECTOR = "516";
|
||||
public static final String HAN_FUN_UNITTYPE_FLOOD_DETECTOR = "518";
|
||||
public static final String HAN_FUN_UNITTYPE_GLAS_BREAK_DETECTOR = "519";
|
||||
public static final String HAN_FUN_UNITTYPE_VIBRATION_DETECTOR = "520";
|
||||
|
||||
public static final String HAN_FUN_INTERFACE_ALERT = "256";
|
||||
public static final String HAN_FUN_INTERFACE_KEEP_ALIVE = "277";
|
||||
public static final String HAN_FUN_INTERFACE_SIMPLE_BUTTON = "772";
|
||||
|
||||
private String etsideviceid;
|
||||
private String unittype;
|
||||
private String interfaces;
|
||||
|
||||
public String getEtsideviceid() {
|
||||
return etsideviceid;
|
||||
}
|
||||
|
||||
public void setEtsideviceid(String etsideviceid) {
|
||||
this.etsideviceid = etsideviceid;
|
||||
}
|
||||
|
||||
public String getUnittype() {
|
||||
return unittype;
|
||||
}
|
||||
|
||||
public void setUnittype(String unittype) {
|
||||
this.unittype = unittype;
|
||||
}
|
||||
|
||||
public String getInterfaces() {
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
public void setInterfaces(String interfaces) {
|
||||
this.interfaces = interfaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[etsideviceid=").append(etsideviceid).append(",unittype=")
|
||||
.append(unittype).append(",interfaces=").append(interfaces).append("]").toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* See {@link AVMFritzBaseModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "group")
|
||||
public class GroupModel extends AVMFritzBaseModel {
|
||||
|
||||
private GroupInfoModel groupinfo;
|
||||
|
||||
public GroupInfoModel getGroupinfo() {
|
||||
return groupinfo;
|
||||
}
|
||||
|
||||
public void setGroupinfo(GroupInfoModel groupinfo) {
|
||||
this.groupinfo = groupinfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append(super.toString()).append(groupinfo).append("]").toString();
|
||||
}
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = { "masterdeviceid", "members" })
|
||||
public static class GroupInfoModel {
|
||||
private String masterdeviceid;
|
||||
private String members;
|
||||
|
||||
public String getMasterdeviceid() {
|
||||
return masterdeviceid;
|
||||
}
|
||||
|
||||
public void setMasterdeviceid(String masterdeviceid) {
|
||||
this.masterdeviceid = masterdeviceid;
|
||||
}
|
||||
|
||||
public String getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public void setMembers(String members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[masterdeviceid=").append(masterdeviceid).append(",members=")
|
||||
.append(members).append("]").toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet DECT
|
||||
* @author Christoph Weitkamp - Added channel 'battery_level'
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "hkr")
|
||||
public class HeatingModel implements BatteryModel {
|
||||
public static final BigDecimal TEMP_FACTOR = new BigDecimal("0.5");
|
||||
public static final BigDecimal BIG_DECIMAL_TWO = new BigDecimal("2.0");
|
||||
public static final BigDecimal TEMP_CELSIUS_MIN = new BigDecimal("8.0");
|
||||
public static final BigDecimal TEMP_CELSIUS_MAX = new BigDecimal("28.0");
|
||||
public static final BigDecimal TEMP_FRITZ_MIN = new BigDecimal("16.0");
|
||||
public static final BigDecimal TEMP_FRITZ_MAX = new BigDecimal("56.0");
|
||||
public static final BigDecimal TEMP_FRITZ_OFF = new BigDecimal("253.0");
|
||||
public static final BigDecimal TEMP_FRITZ_ON = new BigDecimal("254.0");
|
||||
public static final BigDecimal TEMP_FRITZ_UNDEFINED = new BigDecimal("255.0");
|
||||
|
||||
private BigDecimal tist;
|
||||
private BigDecimal tsoll;
|
||||
private BigDecimal absenk;
|
||||
private BigDecimal komfort;
|
||||
private BigDecimal lock;
|
||||
private BigDecimal devicelock;
|
||||
private String errorcode;
|
||||
private BigDecimal batterylow;
|
||||
private @Nullable BigDecimal windowopenactiv;
|
||||
private @Nullable BigDecimal windowopenactiveendtime;
|
||||
private @Nullable BigDecimal boostactive;
|
||||
private @Nullable BigDecimal boostactiveendtime;
|
||||
private BigDecimal battery;
|
||||
private NextChangeModel nextchange;
|
||||
private BigDecimal summeractive;
|
||||
private BigDecimal holidayactive;
|
||||
|
||||
public BigDecimal getTist() {
|
||||
return tist;
|
||||
}
|
||||
|
||||
public void setTist(BigDecimal tist) {
|
||||
this.tist = tist;
|
||||
}
|
||||
|
||||
public BigDecimal getTsoll() {
|
||||
return tsoll;
|
||||
}
|
||||
|
||||
public void setTsoll(BigDecimal tsoll) {
|
||||
this.tsoll = tsoll;
|
||||
}
|
||||
|
||||
public BigDecimal getKomfort() {
|
||||
return komfort;
|
||||
}
|
||||
|
||||
public void setKomfort(BigDecimal komfort) {
|
||||
this.komfort = komfort;
|
||||
}
|
||||
|
||||
public BigDecimal getAbsenk() {
|
||||
return absenk;
|
||||
}
|
||||
|
||||
public void setAbsenk(BigDecimal absenk) {
|
||||
this.absenk = absenk;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
if (BigDecimal.ONE.equals(getHolidayactive())) {
|
||||
return MODE_VACATION;
|
||||
} else if (getNextchange() != null && getNextchange().getEndperiod() != 0) {
|
||||
return MODE_AUTO;
|
||||
} else {
|
||||
return MODE_MANUAL;
|
||||
}
|
||||
}
|
||||
|
||||
public String getRadiatorMode() {
|
||||
if (tsoll == null) {
|
||||
return MODE_UNKNOWN;
|
||||
} else if (TEMP_FRITZ_ON.compareTo(tsoll) == 0) {
|
||||
return MODE_ON;
|
||||
} else if (TEMP_FRITZ_OFF.compareTo(tsoll) == 0) {
|
||||
return MODE_OFF;
|
||||
} else if (BigDecimal.ONE.equals(getWindowopenactiv())) {
|
||||
return MODE_WINDOW_OPEN;
|
||||
} else if (tsoll.compareTo(komfort) == 0) {
|
||||
return MODE_COMFORT;
|
||||
} else if (tsoll.compareTo(absenk) == 0) {
|
||||
return MODE_ECO;
|
||||
} else if (BigDecimal.ONE.equals(getBoostactive()) || TEMP_FRITZ_MAX.compareTo(tsoll) == 0) {
|
||||
return MODE_BOOST;
|
||||
} else {
|
||||
return MODE_ON;
|
||||
}
|
||||
}
|
||||
|
||||
public BigDecimal getLock() {
|
||||
return lock;
|
||||
}
|
||||
|
||||
public void setLock(BigDecimal lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
|
||||
public BigDecimal getDevicelock() {
|
||||
return devicelock;
|
||||
}
|
||||
|
||||
public void setDevicelock(BigDecimal devicelock) {
|
||||
this.devicelock = devicelock;
|
||||
}
|
||||
|
||||
public String getErrorcode() {
|
||||
return errorcode;
|
||||
}
|
||||
|
||||
public void setErrorcode(String errorcode) {
|
||||
this.errorcode = errorcode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBatterylow() {
|
||||
return batterylow;
|
||||
}
|
||||
|
||||
public void setBatterylow(BigDecimal batterylow) {
|
||||
this.batterylow = batterylow;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getWindowopenactiv() {
|
||||
return windowopenactiv;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getWindowopenactiveendtime() {
|
||||
return windowopenactiveendtime;
|
||||
}
|
||||
|
||||
public void setWindowopenactiv(BigDecimal windowopenactiv) {
|
||||
this.windowopenactiv = windowopenactiv;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getBoostactive() {
|
||||
return boostactive;
|
||||
}
|
||||
|
||||
public @Nullable BigDecimal getBoostactiveendtime() {
|
||||
return boostactiveendtime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBattery() {
|
||||
return battery;
|
||||
}
|
||||
|
||||
public void setBattery(BigDecimal battery) {
|
||||
this.battery = battery;
|
||||
}
|
||||
|
||||
public NextChangeModel getNextchange() {
|
||||
return nextchange;
|
||||
}
|
||||
|
||||
public void setNextchange(NextChangeModel nextchange) {
|
||||
this.nextchange = nextchange;
|
||||
}
|
||||
|
||||
public BigDecimal getSummeractive() {
|
||||
return summeractive;
|
||||
}
|
||||
|
||||
public void setSummeractive(BigDecimal summeractive) {
|
||||
this.summeractive = summeractive;
|
||||
}
|
||||
|
||||
public BigDecimal getHolidayactive() {
|
||||
return holidayactive;
|
||||
}
|
||||
|
||||
public void setHolidayactive(BigDecimal holidayactive) {
|
||||
this.holidayactive = holidayactive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[tist=").append(tist).append(",tsoll=").append(tsoll).append(",absenk=")
|
||||
.append(absenk).append(",komfort=").append(komfort).append(",lock=").append(lock).append(",devicelock=")
|
||||
.append(devicelock).append(",errorcode=").append(errorcode).append(",batterylow=").append(batterylow)
|
||||
.append(",windowopenactiv=").append(windowopenactiv).append(",windowopenactiveendtime=")
|
||||
.append(windowopenactiveendtime).append(",boostactive=").append(boostactive)
|
||||
.append(",boostactiveendtime=").append(boostactiveendtime).append(",battery=").append(battery)
|
||||
.append(",nextchange=").append(nextchange).append(",summeractive=").append(summeractive)
|
||||
.append(",holidayactive=").append(holidayactive).append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a celsius value to a FRITZ!Box value.
|
||||
* Valid celsius values: 8 to 28 °C > 16 to 56
|
||||
* 16 <= 8°C, 17 = 8.5°C...... 56 >= 28°C, 254 = ON, 253 = OFF
|
||||
*
|
||||
* @param celsiusValue The celsius value to be converted
|
||||
* @return The FRITZ!Box value
|
||||
*/
|
||||
public static BigDecimal fromCelsius(BigDecimal celsiusValue) {
|
||||
if (celsiusValue == null) {
|
||||
return BigDecimal.ZERO;
|
||||
} else if (TEMP_CELSIUS_MIN.compareTo(celsiusValue) == 1) {
|
||||
return TEMP_FRITZ_MIN;
|
||||
} else if (TEMP_CELSIUS_MAX.compareTo(celsiusValue) == -1) {
|
||||
return TEMP_FRITZ_MAX;
|
||||
}
|
||||
return BIG_DECIMAL_TWO.multiply(celsiusValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a celsius value to a FRITZ!Box value.
|
||||
* Valid celsius values: 8 to 28 °C > 16 to 56
|
||||
* 16 <= 8°C, 17 = 8.5°C...... 56 >= 28°C, 254 = ON, 253 = OFF
|
||||
*
|
||||
* @param celsiusValue The celsius value to be converted
|
||||
* @return The FRITZ!Box value
|
||||
*/
|
||||
public static BigDecimal toCelsius(BigDecimal fritzValue) {
|
||||
if (fritzValue == null) {
|
||||
return BigDecimal.ZERO;
|
||||
} else if (TEMP_FRITZ_ON.compareTo(fritzValue) == 0) {
|
||||
return TEMP_CELSIUS_MAX.add(BIG_DECIMAL_TWO);
|
||||
} else if (TEMP_FRITZ_OFF.compareTo(fritzValue) == 0) {
|
||||
return TEMP_CELSIUS_MIN.subtract(BIG_DECIMAL_TWO);
|
||||
}
|
||||
return TEMP_FACTOR.multiply(fritzValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a celsius value.
|
||||
* Valid celsius steps: 0.5°C
|
||||
*
|
||||
* @param celsiusValue The celsius value to be normalized
|
||||
* @return The normalized celsius value
|
||||
*/
|
||||
public static BigDecimal normalizeCelsius(BigDecimal celsiusValue) {
|
||||
BigDecimal divisor = celsiusValue.divide(TEMP_FACTOR, 0, RoundingMode.HALF_UP);
|
||||
return TEMP_FACTOR.multiply(divisor);
|
||||
}
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class NextChangeModel {
|
||||
private int endperiod;
|
||||
private BigDecimal tchange;
|
||||
|
||||
public int getEndperiod() {
|
||||
return endperiod;
|
||||
}
|
||||
|
||||
public void setEndperiod(int endperiod) {
|
||||
this.endperiod = endperiod;
|
||||
}
|
||||
|
||||
public BigDecimal getTchange() {
|
||||
return tchange;
|
||||
}
|
||||
|
||||
public void setTchange(BigDecimal tchange) {
|
||||
this.tchange = tchange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[endperiod=").append(endperiod).append(",tchange=").append(tchange)
|
||||
.append("]").toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added channel 'voltage'
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = { "voltage", "power", "energy" })
|
||||
@XmlRootElement(name = "powermeter")
|
||||
public class PowerMeterModel {
|
||||
public static final BigDecimal VOLTAGE_FACTOR = new BigDecimal("0.001");
|
||||
public static final BigDecimal POWER_FACTOR = new BigDecimal("0.001");
|
||||
|
||||
private BigDecimal voltage;
|
||||
private BigDecimal power;
|
||||
private BigDecimal energy;
|
||||
|
||||
public BigDecimal getVoltage() {
|
||||
return voltage != null ? VOLTAGE_FACTOR.multiply(voltage) : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void setVoltage(BigDecimal voltage) {
|
||||
this.voltage = voltage;
|
||||
}
|
||||
|
||||
public BigDecimal getPower() {
|
||||
return power != null ? POWER_FACTOR.multiply(power) : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void setPower(BigDecimal power) {
|
||||
this.power = power;
|
||||
}
|
||||
|
||||
public BigDecimal getEnergy() {
|
||||
return energy != null ? energy : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void setEnergy(BigDecimal energy) {
|
||||
this.energy = energy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[voltage=").append(getVoltage()).append(",power=").append(getPower())
|
||||
.append(",energy=").append(getEnergy()).append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added new channels `locked`, `mode` and `radiator_mode`
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = { "state", "mode", "lock", "devicelock" })
|
||||
@XmlRootElement(name = "switch")
|
||||
public class SwitchModel {
|
||||
public static final BigDecimal ON = BigDecimal.ONE;
|
||||
public static final BigDecimal OFF = BigDecimal.ZERO;
|
||||
public static final String MODE_FRITZ_AUTO = "auto";
|
||||
public static final String MODE_FRITZ_MANUAL = "manuell";
|
||||
|
||||
private BigDecimal state;
|
||||
private String mode;
|
||||
private BigDecimal lock;
|
||||
private BigDecimal devicelock;
|
||||
|
||||
public BigDecimal getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(BigDecimal state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
if (MODE_FRITZ_AUTO.equals(mode)) {
|
||||
return MODE_AUTO;
|
||||
} else {
|
||||
return MODE_MANUAL;
|
||||
}
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public BigDecimal getLock() {
|
||||
return lock;
|
||||
}
|
||||
|
||||
public void setLock(BigDecimal lock) {
|
||||
this.lock = lock;
|
||||
}
|
||||
|
||||
public BigDecimal getDevicelock() {
|
||||
return devicelock;
|
||||
}
|
||||
|
||||
public void setDevicelock(BigDecimal devicelock) {
|
||||
this.devicelock = devicelock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[state=").append(state).append(",mode=").append(getMode()).append(",lock=")
|
||||
.append(lock).append(",devicelock=").append(devicelock).append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Refactoring of temperature conversion from celsius to FRITZ!Box values
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(propOrder = { "celsius", "offset" })
|
||||
@XmlRootElement(name = "temperature")
|
||||
public class TemperatureModel {
|
||||
public static final BigDecimal TEMP_FACTOR = new BigDecimal("0.1");
|
||||
|
||||
private BigDecimal celsius;
|
||||
private BigDecimal offset;
|
||||
|
||||
public BigDecimal getCelsius() {
|
||||
return celsius != null ? TEMP_FACTOR.multiply(celsius) : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void setCelsius(BigDecimal celsius) {
|
||||
this.celsius = celsius;
|
||||
}
|
||||
|
||||
public BigDecimal getOffset() {
|
||||
return offset != null ? TEMP_FACTOR.multiply(offset) : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public void setOffset(BigDecimal offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[celsius=").append(getCelsius()).append(",offset=").append(getOffset())
|
||||
.append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.templates;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* See {@ TemplateModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "applymask")
|
||||
public class ApplyMaskListModel {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.templates;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* See {@ TemplateModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "devices")
|
||||
public class DeviceListModel {
|
||||
|
||||
@XmlElement(name = "device")
|
||||
private List<DeviceModel> devices;
|
||||
|
||||
public List<DeviceModel> getDevices() {
|
||||
if (devices == null) {
|
||||
devices = Collections.emptyList();
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[devices=").append(devices).append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.templates;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* See {@link DeviceListModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "device")
|
||||
public class DeviceModel {
|
||||
|
||||
@XmlAttribute(name = "identifier")
|
||||
private String identifier;
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier != null ? identifier.replace(" ", "") : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[identifier=").append(identifier).append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.templates;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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 javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* This JAXB model class maps the XML response to an <b>gettemplatelistinfos</b> command on a FRITZ!Box device.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType
|
||||
@XmlRootElement(name = "templatelist")
|
||||
public class TemplateListModel {
|
||||
|
||||
@XmlAttribute(name = "version")
|
||||
private String version;
|
||||
|
||||
@XmlElement(name = "template")
|
||||
private List<TemplateModel> templates;
|
||||
|
||||
public List<TemplateModel> getTemplates() {
|
||||
if (templates == null) {
|
||||
templates = Collections.emptyList();
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[templates=").append(templates).append(",version=").append(version)
|
||||
.append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.templates;
|
||||
|
||||
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.XmlType;
|
||||
|
||||
import org.openhab.core.types.CommandOption;
|
||||
|
||||
/**
|
||||
* See {@link TemplateListModel}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "template")
|
||||
public class TemplateModel {
|
||||
|
||||
@XmlAttribute(name = "identifier")
|
||||
private String identifier;
|
||||
|
||||
@XmlAttribute(name = "id")
|
||||
private String templateId;
|
||||
|
||||
@XmlAttribute(name = "functionbitmask")
|
||||
private int functionbitmask;
|
||||
|
||||
@XmlAttribute(name = "applymask")
|
||||
private int applymask;
|
||||
|
||||
@XmlElement(name = "name")
|
||||
private String name;
|
||||
|
||||
@XmlElement(name = "devices")
|
||||
private DeviceListModel deviceList;
|
||||
|
||||
@XmlElement(name = "applymask")
|
||||
private ApplyMaskListModel applyMaskList;
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier != null ? identifier.replace(" ", "") : null;
|
||||
}
|
||||
|
||||
public String getTemplateId() {
|
||||
return templateId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public DeviceListModel getDeviceList() {
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
public ApplyMaskListModel getApplyMaskList() {
|
||||
return applyMaskList;
|
||||
}
|
||||
|
||||
public CommandOption toCommandOption() {
|
||||
return new CommandOption(getIdentifier(), getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder().append("[identifier=").append(identifier).append(",id=").append(templateId)
|
||||
.append(",functionbitmask=").append(functionbitmask).append(",applymask=").append(applymask)
|
||||
.append(",name=").append(name).append(",devices=").append(deviceList).append(",applymasks=")
|
||||
.append(applyMaskList).append("]").toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
import static org.openhab.binding.avmfritz.internal.dto.DeviceModel.ETSUnitInfoModel.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants;
|
||||
import org.openhab.binding.avmfritz.internal.AVMFritzDynamicCommandDescriptionProvider;
|
||||
import org.openhab.binding.avmfritz.internal.config.AVMFritzBoxConfiguration;
|
||||
import org.openhab.binding.avmfritz.internal.discovery.AVMFritzDiscoveryService;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.DeviceModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.GroupModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.templates.TemplateModel;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaStatusListener;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaApplyTemplateCallback;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaUpdateCallback;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaUpdateTemplatesCallback;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract handler for a FRITZ! bridge. Handles polling of values from AHA devices.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet DECT
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AVMFritzBaseBridgeHandler extends BaseBridgeHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AVMFritzBaseBridgeHandler.class);
|
||||
|
||||
/**
|
||||
* Initial delay in s for polling job.
|
||||
*/
|
||||
private static final int INITIAL_DELAY = 1;
|
||||
|
||||
/**
|
||||
* Refresh interval which is used to poll values from the FRITZ!Box web interface (optional, defaults to 15 s)
|
||||
*/
|
||||
private long refreshInterval = 15;
|
||||
|
||||
/**
|
||||
* Interface object for querying the FRITZ!Box web interface
|
||||
*/
|
||||
protected @Nullable FritzAhaWebInterface connection;
|
||||
|
||||
/**
|
||||
* Schedule for polling
|
||||
*/
|
||||
private @Nullable ScheduledFuture<?> pollingJob;
|
||||
|
||||
/**
|
||||
* Shared instance of HTTP client for asynchronous calls
|
||||
*/
|
||||
protected final HttpClient httpClient;
|
||||
|
||||
private final AVMFritzDynamicCommandDescriptionProvider commandDescriptionProvider;
|
||||
|
||||
protected final List<FritzAhaStatusListener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
* keeps track of the {@link ChannelUID} for the 'apply_template' {@link Channel}
|
||||
*/
|
||||
private final ChannelUID applyTemplateChannelUID;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param bridge Bridge object representing a FRITZ!Box
|
||||
*/
|
||||
public AVMFritzBaseBridgeHandler(Bridge bridge, HttpClient httpClient,
|
||||
AVMFritzDynamicCommandDescriptionProvider commandDescriptionProvider) {
|
||||
super(bridge);
|
||||
this.httpClient = httpClient;
|
||||
this.commandDescriptionProvider = commandDescriptionProvider;
|
||||
|
||||
applyTemplateChannelUID = new ChannelUID(bridge.getUID(), CHANNEL_APPLY_TEMPLATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
boolean configValid = true;
|
||||
|
||||
AVMFritzBoxConfiguration config = getConfigAs(AVMFritzBoxConfiguration.class);
|
||||
|
||||
String localIpAddress = config.ipAddress;
|
||||
if (localIpAddress == null || localIpAddress.trim().isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"The 'ipAddress' parameter must be configured.");
|
||||
configValid = false;
|
||||
}
|
||||
refreshInterval = config.pollingInterval;
|
||||
if (refreshInterval < 5) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"The 'pollingInterval' parameter must be greater then at least 5 seconds.");
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
if (configValid) {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
manageConnections();
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void manageConnections() {
|
||||
AVMFritzBoxConfiguration config = getConfigAs(AVMFritzBoxConfiguration.class);
|
||||
if (this.connection == null) {
|
||||
this.connection = new FritzAhaWebInterface(config, this, httpClient);
|
||||
stopPolling();
|
||||
startPolling();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelLinked(ChannelUID channelUID) {
|
||||
manageConnections();
|
||||
super.channelLinked(channelUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelUnlinked(ChannelUID channelUID) {
|
||||
manageConnections();
|
||||
super.channelUnlinked(channelUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
stopPolling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
|
||||
if (childHandler instanceof FritzAhaStatusListener) {
|
||||
registerStatusListener((FritzAhaStatusListener) childHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
|
||||
if (childHandler instanceof FritzAhaStatusListener) {
|
||||
unregisterStatusListener((FritzAhaStatusListener) childHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(AVMFritzDiscoveryService.class);
|
||||
}
|
||||
|
||||
public boolean registerStatusListener(FritzAhaStatusListener listener) {
|
||||
return listeners.add(listener);
|
||||
}
|
||||
|
||||
public boolean unregisterStatusListener(FritzAhaStatusListener listener) {
|
||||
return listeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the polling.
|
||||
*/
|
||||
protected void startPolling() {
|
||||
ScheduledFuture<?> localPollingJob = pollingJob;
|
||||
if (localPollingJob == null || localPollingJob.isCancelled()) {
|
||||
logger.debug("Start polling job at interval {}s", refreshInterval);
|
||||
pollingJob = scheduler.scheduleWithFixedDelay(this::poll, INITIAL_DELAY, refreshInterval, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the polling.
|
||||
*/
|
||||
protected void stopPolling() {
|
||||
ScheduledFuture<?> localPollingJob = pollingJob;
|
||||
if (localPollingJob != null && !localPollingJob.isCancelled()) {
|
||||
logger.debug("Stop polling job");
|
||||
localPollingJob.cancel(true);
|
||||
pollingJob = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls the bridge.
|
||||
*/
|
||||
private void poll() {
|
||||
FritzAhaWebInterface webInterface = getWebInterface();
|
||||
if (webInterface != null) {
|
||||
logger.debug("Poll FRITZ!Box for updates {}", thing.getUID());
|
||||
FritzAhaUpdateCallback updateCallback = new FritzAhaUpdateCallback(webInterface, this);
|
||||
webInterface.asyncGet(updateCallback);
|
||||
if (isLinked(applyTemplateChannelUID)) {
|
||||
logger.debug("Poll FRITZ!Box for templates {}", thing.getUID());
|
||||
FritzAhaUpdateTemplatesCallback templateCallback = new FritzAhaUpdateTemplatesCallback(webInterface,
|
||||
this);
|
||||
webInterface.asyncGet(templateCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from {@link FritzAhaWebInterface#authenticate()} to update the bridge status because updateStatus is
|
||||
* protected.
|
||||
*
|
||||
* @param status Bridge status
|
||||
* @param statusDetail Bridge status detail
|
||||
* @param description Bridge status description
|
||||
*/
|
||||
public void setStatusInfo(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
|
||||
updateStatus(status, statusDetail, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from {@link FritzAhaApplyTemplateCallback} to provide new templates for things.
|
||||
*
|
||||
* @param templateList list of template models
|
||||
*/
|
||||
public void addTemplateList(List<TemplateModel> templateList) {
|
||||
commandDescriptionProvider.setCommandOptions(applyTemplateChannelUID,
|
||||
templateList.stream().map(TemplateModel::toCommandOption).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from {@link FritzAhaUpdateCallback} to provide new devices.
|
||||
*
|
||||
* @param deviceList list of devices
|
||||
*/
|
||||
public void onDeviceListAdded(List<AVMFritzBaseModel> deviceList) {
|
||||
final Map<String, AVMFritzBaseModel> deviceIdentifierMap = deviceList.stream()
|
||||
.collect(Collectors.toMap(it -> it.getIdentifier(), Function.identity()));
|
||||
getThing().getThings().forEach(childThing -> {
|
||||
final AVMFritzBaseThingHandler childHandler = (AVMFritzBaseThingHandler) childThing.getHandler();
|
||||
if (childHandler != null) {
|
||||
final Optional<AVMFritzBaseModel> optionalDevice = Optional
|
||||
.ofNullable(deviceIdentifierMap.get(childHandler.getIdentifier()));
|
||||
if (optionalDevice.isPresent()) {
|
||||
final AVMFritzBaseModel device = optionalDevice.get();
|
||||
deviceList.remove(device);
|
||||
listeners.forEach(listener -> listener.onDeviceUpdated(childThing.getUID(), device));
|
||||
} else {
|
||||
listeners.forEach(listener -> listener.onDeviceGone(childThing.getUID()));
|
||||
}
|
||||
} else {
|
||||
logger.debug("Handler missing for thing '{}'", childThing.getUID());
|
||||
}
|
||||
});
|
||||
deviceList.forEach(device -> {
|
||||
listeners.forEach(listener -> listener.onDeviceAdded(device));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link ThingUID} from a device model. The UID is build from the
|
||||
* {@link AVMFritzBindingConstants#BINDING_ID} and
|
||||
* value of {@link AVMFritzBaseModel#getProductName()} in which all characters NOT matching the RegEx [^a-zA-Z0-9_]
|
||||
* are replaced by "_".
|
||||
*
|
||||
* @param device Discovered device model
|
||||
* @return ThingUID without illegal characters.
|
||||
*/
|
||||
public @Nullable ThingUID getThingUID(AVMFritzBaseModel device) {
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, getThingTypeId(device));
|
||||
ThingUID bridgeUID = thing.getUID();
|
||||
String thingName = getThingName(device);
|
||||
|
||||
if (SUPPORTED_BUTTON_THING_TYPES_UIDS.contains(thingTypeUID)
|
||||
|| SUPPORTED_HEATING_THING_TYPES.contains(thingTypeUID)
|
||||
|| SUPPORTED_DEVICE_THING_TYPES_UIDS.contains(thingTypeUID)) {
|
||||
return new ThingUID(thingTypeUID, bridgeUID, thingName);
|
||||
} else if (device.isHeatingThermostat()) {
|
||||
return new ThingUID(GROUP_HEATING_THING_TYPE, bridgeUID, thingName);
|
||||
} else if (device.isSwitchableOutlet()) {
|
||||
return new ThingUID(GROUP_SWITCH_THING_TYPE, bridgeUID, thingName);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param device Discovered device model
|
||||
* @return ThingTypeId without illegal characters.
|
||||
*/
|
||||
public String getThingTypeId(AVMFritzBaseModel device) {
|
||||
if (device instanceof GroupModel) {
|
||||
if (device.isHeatingThermostat()) {
|
||||
return GROUP_HEATING;
|
||||
} else if (device.isSwitchableOutlet()) {
|
||||
return GROUP_SWITCH;
|
||||
}
|
||||
} else if (device instanceof DeviceModel && device.isHANFUNUnit()) {
|
||||
List<String> interfaces = Arrays
|
||||
.asList(((DeviceModel) device).getEtsiunitinfo().getInterfaces().split(","));
|
||||
if (interfaces.contains(HAN_FUN_INTERFACE_ALERT)) {
|
||||
return DEVICE_HAN_FUN_CONTACT;
|
||||
} else if (interfaces.contains(HAN_FUN_INTERFACE_SIMPLE_BUTTON)) {
|
||||
return DEVICE_HAN_FUN_SWITCH;
|
||||
}
|
||||
}
|
||||
return device.getProductName().replaceAll(INVALID_PATTERN, "_");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param device Discovered device model
|
||||
* @return Thing name without illegal characters.
|
||||
*/
|
||||
public String getThingName(AVMFritzBaseModel device) {
|
||||
return device.getIdentifier().replaceAll(INVALID_PATTERN, "_");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
logger.debug("Handle command '{}' for channel {}", command, channelId);
|
||||
if (command == RefreshType.REFRESH) {
|
||||
handleRefreshCommand();
|
||||
return;
|
||||
}
|
||||
FritzAhaWebInterface fritzBox = getWebInterface();
|
||||
if (fritzBox == null) {
|
||||
logger.debug("Cannot handle command '{}' because connection is missing", command);
|
||||
return;
|
||||
}
|
||||
if (CHANNEL_APPLY_TEMPLATE.equals(channelId)) {
|
||||
if (command instanceof StringType) {
|
||||
fritzBox.applyTemplate(command.toString());
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received unknown channel {}", channelId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the web interface object.
|
||||
*
|
||||
* @return The web interface object
|
||||
*/
|
||||
public @Nullable FritzAhaWebInterface getWebInterface() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a refresh command.
|
||||
*/
|
||||
public void handleRefreshCommand() {
|
||||
scheduler.submit(this::poll);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
import static org.openhab.binding.avmfritz.internal.dto.HeatingModel.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.avmfritz.internal.config.AVMFritzDeviceConfiguration;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AlertModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.BatteryModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.DeviceModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.HeatingModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.HeatingModel.NextChangeModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.PowerMeterModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.SwitchModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.TemperatureModel;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaStatusListener;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.DefaultSystemChannelTypeProvider;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.BridgeHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract handler for a FRITZ! thing. Handles commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet DECT
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AVMFritzBaseThingHandler extends BaseThingHandler implements FritzAhaStatusListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AVMFritzBaseThingHandler.class);
|
||||
|
||||
/**
|
||||
* keeps track of the current state for handling of increase/decrease
|
||||
*/
|
||||
private @Nullable AVMFritzBaseModel state;
|
||||
private @NonNullByDefault({}) AVMFritzDeviceConfiguration config;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param thing Thing object representing a FRITZ! device
|
||||
*/
|
||||
public AVMFritzBaseThingHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(AVMFritzDeviceConfiguration.class);
|
||||
|
||||
String newIdentifier = config.ain;
|
||||
if (newIdentifier == null || newIdentifier.trim().isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"The 'ain' parameter must be configured.");
|
||||
} else {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceAdded(AVMFritzBaseModel device) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) {
|
||||
if (thing.getUID().equals(thingUID)) {
|
||||
logger.debug("Update thing '{}' with device model: {}", thingUID, device);
|
||||
if (device.getPresent() == 1) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Device not present");
|
||||
}
|
||||
state = device;
|
||||
|
||||
updateProperties(device, editProperties());
|
||||
|
||||
if (device.isPowermeter()) {
|
||||
updatePowermeter(device.getPowermeter());
|
||||
}
|
||||
if (device.isSwitchableOutlet()) {
|
||||
updateSwitchableOutlet(device.getSwitch());
|
||||
}
|
||||
if (device.isHeatingThermostat()) {
|
||||
updateHeatingThermostat(device.getHkr());
|
||||
}
|
||||
if (device instanceof DeviceModel) {
|
||||
DeviceModel deviceModel = (DeviceModel) device;
|
||||
if (deviceModel.isTempSensor()) {
|
||||
updateTemperatureSensor(deviceModel.getTemperature());
|
||||
}
|
||||
if (deviceModel.isHANFUNAlarmSensor()) {
|
||||
updateHANFUNAlarmSensor(deviceModel.getAlert());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHANFUNAlarmSensor(@Nullable AlertModel alertModel) {
|
||||
if (alertModel != null) {
|
||||
updateThingChannelState(CHANNEL_CONTACT_STATE,
|
||||
AlertModel.ON.equals(alertModel.getState()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTemperatureSensor(@Nullable TemperatureModel temperatureModel) {
|
||||
if (temperatureModel != null) {
|
||||
updateThingChannelState(CHANNEL_TEMPERATURE,
|
||||
new QuantityType<>(temperatureModel.getCelsius(), SIUnits.CELSIUS));
|
||||
updateThingChannelConfiguration(CHANNEL_TEMPERATURE, CONFIG_CHANNEL_TEMP_OFFSET,
|
||||
temperatureModel.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHeatingThermostat(@Nullable HeatingModel heatingModel) {
|
||||
if (heatingModel != null) {
|
||||
updateThingChannelState(CHANNEL_MODE, new StringType(heatingModel.getMode()));
|
||||
updateThingChannelState(CHANNEL_LOCKED,
|
||||
BigDecimal.ZERO.equals(heatingModel.getLock()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
updateThingChannelState(CHANNEL_DEVICE_LOCKED,
|
||||
BigDecimal.ZERO.equals(heatingModel.getDevicelock()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
updateThingChannelState(CHANNEL_ACTUALTEMP,
|
||||
new QuantityType<>(toCelsius(heatingModel.getTist()), SIUnits.CELSIUS));
|
||||
updateThingChannelState(CHANNEL_SETTEMP,
|
||||
new QuantityType<>(toCelsius(heatingModel.getTsoll()), SIUnits.CELSIUS));
|
||||
updateThingChannelState(CHANNEL_ECOTEMP,
|
||||
new QuantityType<>(toCelsius(heatingModel.getAbsenk()), SIUnits.CELSIUS));
|
||||
updateThingChannelState(CHANNEL_COMFORTTEMP,
|
||||
new QuantityType<>(toCelsius(heatingModel.getKomfort()), SIUnits.CELSIUS));
|
||||
updateThingChannelState(CHANNEL_RADIATOR_MODE, new StringType(heatingModel.getRadiatorMode()));
|
||||
NextChangeModel nextChange = heatingModel.getNextchange();
|
||||
if (nextChange != null) {
|
||||
int endPeriod = nextChange.getEndperiod();
|
||||
updateThingChannelState(CHANNEL_NEXT_CHANGE, endPeriod == 0 ? UnDefType.UNDEF
|
||||
: new DateTimeType(
|
||||
ZonedDateTime.ofInstant(Instant.ofEpochSecond(endPeriod), ZoneId.systemDefault())));
|
||||
BigDecimal nextTemperature = nextChange.getTchange();
|
||||
updateThingChannelState(CHANNEL_NEXTTEMP, TEMP_FRITZ_UNDEFINED.equals(nextTemperature) ? UnDefType.UNDEF
|
||||
: new QuantityType<>(toCelsius(nextTemperature), SIUnits.CELSIUS));
|
||||
}
|
||||
updateBattery(heatingModel);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateBattery(BatteryModel batteryModel) {
|
||||
BigDecimal batteryLevel = batteryModel.getBattery();
|
||||
updateThingChannelState(CHANNEL_BATTERY,
|
||||
batteryLevel == null ? UnDefType.UNDEF : new DecimalType(batteryLevel));
|
||||
BigDecimal lowBattery = batteryModel.getBatterylow();
|
||||
if (lowBattery == null) {
|
||||
updateThingChannelState(CHANNEL_BATTERY_LOW, UnDefType.UNDEF);
|
||||
} else {
|
||||
updateThingChannelState(CHANNEL_BATTERY_LOW,
|
||||
BatteryModel.BATTERY_ON.equals(lowBattery) ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSwitchableOutlet(@Nullable SwitchModel switchModel) {
|
||||
if (switchModel != null) {
|
||||
updateThingChannelState(CHANNEL_MODE, new StringType(switchModel.getMode()));
|
||||
updateThingChannelState(CHANNEL_LOCKED,
|
||||
BigDecimal.ZERO.equals(switchModel.getLock()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
updateThingChannelState(CHANNEL_DEVICE_LOCKED,
|
||||
BigDecimal.ZERO.equals(switchModel.getDevicelock()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
BigDecimal state = switchModel.getState();
|
||||
if (state == null) {
|
||||
updateThingChannelState(CHANNEL_OUTLET, UnDefType.UNDEF);
|
||||
} else {
|
||||
updateThingChannelState(CHANNEL_OUTLET, SwitchModel.ON.equals(state) ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePowermeter(@Nullable PowerMeterModel powerMeterModel) {
|
||||
if (powerMeterModel != null) {
|
||||
updateThingChannelState(CHANNEL_ENERGY,
|
||||
new QuantityType<>(powerMeterModel.getEnergy(), SmartHomeUnits.WATT_HOUR));
|
||||
updateThingChannelState(CHANNEL_POWER, new QuantityType<>(powerMeterModel.getPower(), SmartHomeUnits.WATT));
|
||||
updateThingChannelState(CHANNEL_VOLTAGE,
|
||||
new QuantityType<>(powerMeterModel.getVoltage(), SmartHomeUnits.VOLT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates thing properties.
|
||||
*
|
||||
* @param device the {@link AVMFritzBaseModel}
|
||||
* @param editProperties map of existing properties
|
||||
*/
|
||||
protected void updateProperties(AVMFritzBaseModel device, Map<String, String> editProperties) {
|
||||
editProperties.put(Thing.PROPERTY_FIRMWARE_VERSION, device.getFirmwareVersion());
|
||||
updateProperties(editProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates thing channels and creates dynamic channels if missing.
|
||||
*
|
||||
* @param channelId ID of the channel to be updated.
|
||||
* @param state State to be set.
|
||||
*/
|
||||
protected void updateThingChannelState(String channelId, State state) {
|
||||
Channel channel = thing.getChannel(channelId);
|
||||
if (channel != null) {
|
||||
updateState(channel.getUID(), state);
|
||||
} else {
|
||||
logger.debug("Channel '{}' in thing '{}' does not exist, recreating thing.", channelId, thing.getUID());
|
||||
createChannel(channelId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new channels for the thing.
|
||||
*
|
||||
* @param channelId ID of the channel to be created.
|
||||
*/
|
||||
private void createChannel(String channelId) {
|
||||
ThingHandlerCallback callback = getCallback();
|
||||
if (callback != null) {
|
||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
|
||||
ChannelTypeUID channelTypeUID = CHANNEL_BATTERY.equals(channelId)
|
||||
? DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_BATTERY_LEVEL.getUID()
|
||||
: new ChannelTypeUID(BINDING_ID, channelId);
|
||||
Channel channel = callback.createChannelBuilder(channelUID, channelTypeUID).build();
|
||||
updateThing(editThing().withoutChannel(channelUID).withChannel(channel).build());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates thing channel configurations.
|
||||
*
|
||||
* @param channelId ID of the channel which configuration to be updated.
|
||||
* @param configId ID of the configuration to be updated.
|
||||
* @param value Value to be set.
|
||||
*/
|
||||
private void updateThingChannelConfiguration(String channelId, String configId, Object value) {
|
||||
Channel channel = thing.getChannel(channelId);
|
||||
if (channel != null) {
|
||||
Configuration editConfig = channel.getConfiguration();
|
||||
editConfig.put(configId, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceGone(ThingUID thingUID) {
|
||||
if (thing.getUID().equals(thingUID)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "Device not present in response");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
logger.debug("Handle command '{}' for channel {}", command, channelId);
|
||||
if (command == RefreshType.REFRESH) {
|
||||
handleRefreshCommand();
|
||||
return;
|
||||
}
|
||||
FritzAhaWebInterface fritzBox = getWebInterface();
|
||||
if (fritzBox == null) {
|
||||
logger.debug("Cannot handle command '{}' because connection is missing", command);
|
||||
return;
|
||||
}
|
||||
String ain = getIdentifier();
|
||||
if (ain == null) {
|
||||
logger.debug("Cannot handle command '{}' because AIN is missing", command);
|
||||
return;
|
||||
}
|
||||
switch (channelId) {
|
||||
case CHANNEL_MODE:
|
||||
case CHANNEL_LOCKED:
|
||||
case CHANNEL_DEVICE_LOCKED:
|
||||
case CHANNEL_TEMPERATURE:
|
||||
case CHANNEL_ENERGY:
|
||||
case CHANNEL_POWER:
|
||||
case CHANNEL_VOLTAGE:
|
||||
case CHANNEL_ACTUALTEMP:
|
||||
case CHANNEL_ECOTEMP:
|
||||
case CHANNEL_COMFORTTEMP:
|
||||
case CHANNEL_NEXT_CHANGE:
|
||||
case CHANNEL_NEXTTEMP:
|
||||
case CHANNEL_BATTERY:
|
||||
case CHANNEL_BATTERY_LOW:
|
||||
case CHANNEL_CONTACT_STATE:
|
||||
case CHANNEL_LAST_CHANGE:
|
||||
logger.debug("Channel {} is a read-only channel and cannot handle command '{}'", channelId, command);
|
||||
break;
|
||||
case CHANNEL_OUTLET:
|
||||
if (command instanceof OnOffType) {
|
||||
fritzBox.setSwitch(ain, OnOffType.ON.equals(command));
|
||||
if (state != null) {
|
||||
state.getSwitch().setState(OnOffType.ON.equals(command) ? SwitchModel.ON : SwitchModel.OFF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SETTEMP:
|
||||
BigDecimal temperature = null;
|
||||
if (command instanceof DecimalType) {
|
||||
temperature = normalizeCelsius(((DecimalType) command).toBigDecimal());
|
||||
} else if (command instanceof QuantityType) {
|
||||
temperature = normalizeCelsius(
|
||||
((QuantityType<Temperature>) command).toUnit(SIUnits.CELSIUS).toBigDecimal());
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
temperature = state.getHkr().getTsoll();
|
||||
if (IncreaseDecreaseType.INCREASE.equals(command)) {
|
||||
temperature.add(BigDecimal.ONE);
|
||||
} else {
|
||||
temperature.subtract(BigDecimal.ONE);
|
||||
}
|
||||
} else if (command instanceof OnOffType) {
|
||||
temperature = OnOffType.ON.equals(command) ? TEMP_FRITZ_ON : TEMP_FRITZ_OFF;
|
||||
}
|
||||
if (temperature != null) {
|
||||
fritzBox.setSetTemp(ain, fromCelsius(temperature));
|
||||
HeatingModel heatingModel = state.getHkr();
|
||||
heatingModel.setTsoll(temperature);
|
||||
updateState(CHANNEL_RADIATOR_MODE, new StringType(heatingModel.getRadiatorMode()));
|
||||
}
|
||||
break;
|
||||
case CHANNEL_RADIATOR_MODE:
|
||||
BigDecimal targetTemperature = null;
|
||||
if (command instanceof StringType) {
|
||||
switch (command.toString()) {
|
||||
case MODE_ON:
|
||||
targetTemperature = TEMP_FRITZ_ON;
|
||||
break;
|
||||
case MODE_OFF:
|
||||
targetTemperature = TEMP_FRITZ_OFF;
|
||||
break;
|
||||
case MODE_COMFORT:
|
||||
targetTemperature = state.getHkr().getKomfort();
|
||||
break;
|
||||
case MODE_ECO:
|
||||
targetTemperature = state.getHkr().getAbsenk();
|
||||
break;
|
||||
case MODE_BOOST:
|
||||
targetTemperature = TEMP_FRITZ_MAX;
|
||||
break;
|
||||
case MODE_UNKNOWN:
|
||||
case MODE_WINDOW_OPEN:
|
||||
logger.debug("Command '{}' is a read-only command for channel {}.", command, channelId);
|
||||
break;
|
||||
}
|
||||
if (targetTemperature != null) {
|
||||
fritzBox.setSetTemp(ain, targetTemperature);
|
||||
state.getHkr().setTsoll(targetTemperature);
|
||||
updateState(CHANNEL_SETTEMP, new QuantityType<>(toCelsius(targetTemperature), SIUnits.CELSIUS));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug("Received unknown channel {}", channelId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a command for a given action.
|
||||
*
|
||||
* @param action
|
||||
* @param duration
|
||||
*/
|
||||
protected void handleAction(String action, long duration) {
|
||||
FritzAhaWebInterface fritzBox = getWebInterface();
|
||||
if (fritzBox == null) {
|
||||
logger.debug("Cannot handle action '{}' because connection is missing", action);
|
||||
return;
|
||||
}
|
||||
String ain = getIdentifier();
|
||||
if (ain == null) {
|
||||
logger.debug("Cannot handle action '{}' because AIN is missing", action);
|
||||
return;
|
||||
}
|
||||
if (duration < 0 || 86400 < duration) {
|
||||
throw new IllegalArgumentException("Duration must not be less than zero or greater than 86400");
|
||||
}
|
||||
switch (action) {
|
||||
case MODE_BOOST:
|
||||
fritzBox.setBoostMode(ain,
|
||||
duration > 0 ? ZonedDateTime.now().plusSeconds(duration).toEpochSecond() : 0);
|
||||
break;
|
||||
case MODE_WINDOW_OPEN:
|
||||
fritzBox.setWindowOpenMode(ain,
|
||||
duration > 0 ? ZonedDateTime.now().plusSeconds(duration).toEpochSecond() : 0);
|
||||
break;
|
||||
default:
|
||||
logger.debug("Received unknown action '{}'", action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the web interface object.
|
||||
*
|
||||
* @return The web interface object
|
||||
*/
|
||||
private @Nullable FritzAhaWebInterface getWebInterface() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
BridgeHandler handler = bridge.getHandler();
|
||||
if (handler instanceof AVMFritzBaseBridgeHandler) {
|
||||
return ((AVMFritzBaseBridgeHandler) handler).getWebInterface();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a refresh command.
|
||||
*/
|
||||
private void handleRefreshCommand() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
BridgeHandler handler = bridge.getHandler();
|
||||
if (handler instanceof AVMFritzBaseBridgeHandler) {
|
||||
((AVMFritzBaseBridgeHandler) handler).handleRefreshCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AIN.
|
||||
*
|
||||
* @return the AIN
|
||||
*/
|
||||
public @Nullable String getIdentifier() {
|
||||
return config.ain;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.ButtonModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.DeviceModel;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.CommonTriggerEvents;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a FRITZ! buttons. Handles commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AVMFritzButtonHandler extends DeviceHandler {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AVMFritzButtonHandler.class);
|
||||
/**
|
||||
* keeps track of the last timestamp for handling trigger events
|
||||
*/
|
||||
private Instant lastTimestamp;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param thing Thing object representing a FRITZ! button
|
||||
*/
|
||||
public AVMFritzButtonHandler(Thing thing) {
|
||||
super(thing);
|
||||
lastTimestamp = Instant.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) {
|
||||
if (thing.getUID().equals(thingUID)) {
|
||||
super.onDeviceUpdated(thingUID, device);
|
||||
|
||||
if (device instanceof DeviceModel) {
|
||||
DeviceModel deviceModel = (DeviceModel) device;
|
||||
if (deviceModel.isHANFUNButton()) {
|
||||
updateHANFUNButton(deviceModel.getButtons());
|
||||
}
|
||||
if (deviceModel.isButton()) {
|
||||
updateShortLongPressButton(deviceModel.getButtons());
|
||||
updateBattery(deviceModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateShortLongPressButton(List<ButtonModel> buttons) {
|
||||
ButtonModel shortPressButton = buttons.size() > 0 ? buttons.get(0) : null;
|
||||
ButtonModel longPressButton = buttons.size() > 1 ? buttons.get(1) : null;
|
||||
ButtonModel lastPressedButton = shortPressButton != null && (longPressButton == null
|
||||
|| shortPressButton.getLastpressedtimestamp() > longPressButton.getLastpressedtimestamp())
|
||||
? shortPressButton
|
||||
: longPressButton;
|
||||
if (lastPressedButton != null) {
|
||||
updateButton(lastPressedButton,
|
||||
lastPressedButton.equals(shortPressButton) ? CommonTriggerEvents.SHORT_PRESSED
|
||||
: CommonTriggerEvents.LONG_PRESSED);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHANFUNButton(List<ButtonModel> buttons) {
|
||||
if (!buttons.isEmpty()) {
|
||||
updateButton(buttons.get(0), CommonTriggerEvents.PRESSED);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateButton(ButtonModel buttonModel, String event) {
|
||||
int lastPressedTimestamp = buttonModel.getLastpressedtimestamp();
|
||||
if (lastPressedTimestamp == 0) {
|
||||
updateThingChannelState(CHANNEL_LAST_CHANGE, UnDefType.UNDEF);
|
||||
} else {
|
||||
ZonedDateTime timestamp = ZonedDateTime.ofInstant(Instant.ofEpochSecond(lastPressedTimestamp),
|
||||
ZoneId.systemDefault());
|
||||
Instant then = timestamp.toInstant();
|
||||
// Avoid dispatching events if "lastpressedtimestamp" is older than now "lastTimestamp" (e.g. during
|
||||
// restart)
|
||||
if (then.isAfter(lastTimestamp)) {
|
||||
lastTimestamp = then;
|
||||
triggerThingChannel(CHANNEL_PRESS, event);
|
||||
}
|
||||
updateThingChannelState(CHANNEL_LAST_CHANGE, new DateTimeType(timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers thing channels.
|
||||
*
|
||||
* @param channelId ID of the channel to be triggered.
|
||||
* @param event Event to emit
|
||||
*/
|
||||
private void triggerThingChannel(String channelId, String event) {
|
||||
Channel channel = thing.getChannel(channelId);
|
||||
if (channel != null) {
|
||||
triggerChannel(channel.getUID(), event);
|
||||
} else {
|
||||
logger.debug("Channel '{}' in thing '{}' does not exist.", channelId, thing.getUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.actions.AVMFritzHeatingActions;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
|
||||
/**
|
||||
* The {@link AVMFritzHeatingActionsHandler} defines interface handlers to handle heating thing actions.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface AVMFritzHeatingActionsHandler extends ThingHandler {
|
||||
|
||||
@Override
|
||||
default Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(AVMFritzHeatingActions.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the "Boost" mode of the heating thermostat or heating group.
|
||||
*
|
||||
* @param duration Duration in seconds, min. 1, max. 86400, 0 for deactivation.
|
||||
*/
|
||||
void setBoostMode(long duration);
|
||||
|
||||
/**
|
||||
* Activates the "Window Open" mode of the heating thermostat or heating group.
|
||||
*
|
||||
* @param duration Duration in seconds, min. 1, max. 86400, 0 for deactivation.
|
||||
*/
|
||||
void setWindowOpenMode(long duration);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Handler for a FRITZ! heating device. Handles commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AVMFritzHeatingDeviceHandler extends DeviceHandler implements AVMFritzHeatingActionsHandler {
|
||||
|
||||
public AVMFritzHeatingDeviceHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoostMode(long duration) {
|
||||
handleAction(MODE_BOOST, duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowOpenMode(long duration) {
|
||||
handleAction(MODE_WINDOW_OPEN, duration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Handler for a FRITZ! heating group. Handles commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AVMFritzHeatingGroupHandler extends GroupHandler implements AVMFritzHeatingActionsHandler {
|
||||
|
||||
public AVMFritzHeatingGroupHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoostMode(long duration) {
|
||||
handleAction(MODE_BOOST, duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWindowOpenMode(long duration) {
|
||||
handleAction(MODE_WINDOW_OPEN, duration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants;
|
||||
import org.openhab.binding.avmfritz.internal.AVMFritzDynamicCommandDescriptionProvider;
|
||||
import org.openhab.binding.avmfritz.internal.callmonitor.CallMonitor;
|
||||
import org.openhab.binding.avmfritz.internal.config.AVMFritzBoxConfiguration;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.State;
|
||||
|
||||
/**
|
||||
* Handler for a FRITZ!Box device. Handles polling of values from AHA devices.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
* @author Kai Kreuzer - Added call monitor support
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BoxHandler extends AVMFritzBaseBridgeHandler {
|
||||
|
||||
protected static final Set<String> CALL_CHANNELS = new HashSet<>();
|
||||
static {
|
||||
// TODO: We are still on Java 8 and cannot use Set.of
|
||||
CALL_CHANNELS.add(AVMFritzBindingConstants.CHANNEL_CALL_ACTIVE);
|
||||
CALL_CHANNELS.add(AVMFritzBindingConstants.CHANNEL_CALL_INCOMING);
|
||||
CALL_CHANNELS.add(AVMFritzBindingConstants.CHANNEL_CALL_OUTGOING);
|
||||
CALL_CHANNELS.add(AVMFritzBindingConstants.CHANNEL_CALL_STATE);
|
||||
}
|
||||
|
||||
private @Nullable CallMonitor callMonitor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param bridge Bridge object representing a FRITZ!Box
|
||||
*/
|
||||
public BoxHandler(Bridge bridge, HttpClient httpClient,
|
||||
AVMFritzDynamicCommandDescriptionProvider commandDescriptionProvider) {
|
||||
super(bridge, httpClient, commandDescriptionProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void manageConnections() {
|
||||
AVMFritzBoxConfiguration config = getConfigAs(AVMFritzBoxConfiguration.class);
|
||||
if (this.callMonitor == null && callChannelsLinked()) {
|
||||
this.callMonitor = new CallMonitor(config.ipAddress, this, scheduler);
|
||||
} else if (this.callMonitor != null && !callChannelsLinked()) {
|
||||
CallMonitor cm = this.callMonitor;
|
||||
cm.dispose();
|
||||
this.callMonitor = null;
|
||||
}
|
||||
if (this.connection == null) {
|
||||
if (config.password != null) {
|
||||
this.connection = new FritzAhaWebInterface(config, this, httpClient);
|
||||
stopPolling();
|
||||
startPolling();
|
||||
} else {
|
||||
if (!callChannelsLinked()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"The 'password' parameter must be configured to use the AHA features.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean callChannelsLinked() {
|
||||
return getThing().getChannels().stream()
|
||||
.filter(c -> isLinked(c.getUID()) && CALL_CHANNELS.contains(c.getUID().getId())).count() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (callMonitor != null) {
|
||||
callMonitor.dispose();
|
||||
callMonitor = null;
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(String channelID, State state) {
|
||||
super.updateState(channelID, state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Handler for a FRITZ! device. Handles commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet DECT
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DeviceHandler extends AVMFritzBaseThingHandler {
|
||||
|
||||
public DeviceHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.GroupModel;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* Handler for a FRITZ! group. Handles commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class GroupHandler extends AVMFritzBaseThingHandler {
|
||||
|
||||
public GroupHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateProperties(AVMFritzBaseModel device, Map<String, String> editProperties) {
|
||||
if (device instanceof GroupModel) {
|
||||
GroupModel groupModel = (GroupModel) device;
|
||||
if (groupModel.getGroupinfo() != null) {
|
||||
editProperties.put(PROPERTY_MASTER, groupModel.getGroupinfo().getMasterdeviceid());
|
||||
editProperties.put(PROPERTY_MEMBERS, groupModel.getGroupinfo().getMembers());
|
||||
}
|
||||
}
|
||||
super.updateProperties(device, editProperties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.handler;
|
||||
|
||||
import static org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.avmfritz.internal.AVMFritzBindingConstants;
|
||||
import org.openhab.binding.avmfritz.internal.AVMFritzDynamicCommandDescriptionProvider;
|
||||
import org.openhab.binding.avmfritz.internal.config.AVMFritzBoxConfiguration;
|
||||
import org.openhab.binding.avmfritz.internal.config.AVMFritzDeviceConfiguration;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.PowerMeterModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.SwitchModel;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaStatusListener;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.DefaultSystemChannelTypeProvider;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandlerCallback;
|
||||
import org.openhab.core.thing.type.ChannelTypeUID;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler for a FRITZ!Powerline 546E device. Handles polling of values from AHA devices and commands, which are sent to
|
||||
* one of the channels.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Powerline546EHandler extends AVMFritzBaseBridgeHandler implements FritzAhaStatusListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(Powerline546EHandler.class);
|
||||
|
||||
/**
|
||||
* keeps track of the current state for handling of increase/decrease
|
||||
*/
|
||||
private @Nullable AVMFritzBaseModel state;
|
||||
private @Nullable AVMFritzDeviceConfiguration config;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param bridge Bridge object representing a FRITZ!Powerline 546E
|
||||
*/
|
||||
public Powerline546EHandler(Bridge bridge, HttpClient httpClient,
|
||||
AVMFritzDynamicCommandDescriptionProvider commandDescriptionProvider) {
|
||||
super(bridge, httpClient, commandDescriptionProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(AVMFritzDeviceConfiguration.class);
|
||||
|
||||
registerStatusListener(this);
|
||||
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
unregisterStatusListener(this);
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceListAdded(List<AVMFritzBaseModel> devicelist) {
|
||||
final String identifier = getIdentifier();
|
||||
final Predicate<AVMFritzBaseModel> predicate = identifier == null ? it -> thing.getUID().equals(getThingUID(it))
|
||||
: it -> identifier.equals(it.getIdentifier());
|
||||
final Optional<AVMFritzBaseModel> optionalDevice = devicelist.stream().filter(predicate).findFirst();
|
||||
if (optionalDevice.isPresent()) {
|
||||
final AVMFritzBaseModel device = optionalDevice.get();
|
||||
devicelist.remove(device);
|
||||
listeners.stream().forEach(listener -> listener.onDeviceUpdated(thing.getUID(), device));
|
||||
} else {
|
||||
listeners.stream().forEach(listener -> listener.onDeviceGone(thing.getUID()));
|
||||
}
|
||||
super.onDeviceListAdded(devicelist);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceAdded(AVMFritzBaseModel device) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device) {
|
||||
if (thing.getUID().equals(thingUID)) {
|
||||
// save AIN to config for FRITZ!Powerline 546E stand-alone
|
||||
if (config == null) {
|
||||
updateConfiguration(device);
|
||||
}
|
||||
|
||||
logger.debug("Update self '{}' with device model: {}", thingUID, device);
|
||||
if (device.getPresent() == 1) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "Device not present");
|
||||
}
|
||||
state = device;
|
||||
|
||||
updateProperties(device);
|
||||
|
||||
if (device.isPowermeter()) {
|
||||
updatePowermeter(device.getPowermeter());
|
||||
}
|
||||
if (device.isSwitchableOutlet()) {
|
||||
updateSwitchableOutlet(device.getSwitch());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSwitchableOutlet(@Nullable SwitchModel switchModel) {
|
||||
if (switchModel != null) {
|
||||
updateThingChannelState(CHANNEL_MODE, new StringType(switchModel.getMode()));
|
||||
updateThingChannelState(CHANNEL_LOCKED,
|
||||
BigDecimal.ZERO.equals(switchModel.getLock()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
updateThingChannelState(CHANNEL_DEVICE_LOCKED,
|
||||
BigDecimal.ZERO.equals(switchModel.getDevicelock()) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
|
||||
BigDecimal state = switchModel.getState();
|
||||
if (state == null) {
|
||||
updateThingChannelState(CHANNEL_OUTLET, UnDefType.UNDEF);
|
||||
} else {
|
||||
updateThingChannelState(CHANNEL_OUTLET, SwitchModel.ON.equals(state) ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePowermeter(@Nullable PowerMeterModel powerMeterModel) {
|
||||
if (powerMeterModel != null) {
|
||||
updateThingChannelState(CHANNEL_ENERGY,
|
||||
new QuantityType<>(powerMeterModel.getEnergy(), SmartHomeUnits.WATT_HOUR));
|
||||
updateThingChannelState(CHANNEL_POWER, new QuantityType<>(powerMeterModel.getPower(), SmartHomeUnits.WATT));
|
||||
updateThingChannelState(CHANNEL_VOLTAGE,
|
||||
new QuantityType<>(powerMeterModel.getVoltage(), SmartHomeUnits.VOLT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates thing properties.
|
||||
*
|
||||
* @param device the {@link AVMFritzBaseModel}
|
||||
*/
|
||||
private void updateProperties(AVMFritzBaseModel device) {
|
||||
Map<String, String> editProperties = editProperties();
|
||||
editProperties.put(Thing.PROPERTY_FIRMWARE_VERSION, device.getFirmwareVersion());
|
||||
updateProperties(editProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates thing configuration.
|
||||
*
|
||||
* @param device the {@link AVMFritzBaseModel}
|
||||
*/
|
||||
private void updateConfiguration(AVMFritzBaseModel device) {
|
||||
Configuration editConfig = editConfiguration();
|
||||
editConfig.put(CONFIG_AIN, device.getIdentifier());
|
||||
updateConfiguration(editConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates thing channels and creates dynamic channels if missing.
|
||||
*
|
||||
* @param channelId ID of the channel to be updated.
|
||||
* @param state State to be set.
|
||||
*/
|
||||
private void updateThingChannelState(String channelId, State state) {
|
||||
Channel channel = thing.getChannel(channelId);
|
||||
if (channel != null) {
|
||||
updateState(channel.getUID(), state);
|
||||
} else {
|
||||
logger.debug("Channel '{}' in thing '{}' does not exist, recreating thing.", channelId, thing.getUID());
|
||||
createChannel(channelId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new channels for the thing.
|
||||
*
|
||||
* @param channelId ID of the channel to be created.
|
||||
*/
|
||||
private void createChannel(String channelId) {
|
||||
ThingHandlerCallback callback = getCallback();
|
||||
if (callback != null) {
|
||||
ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
|
||||
ChannelTypeUID channelTypeUID = CHANNEL_BATTERY.equals(channelId)
|
||||
? DefaultSystemChannelTypeProvider.SYSTEM_CHANNEL_BATTERY_LEVEL.getUID()
|
||||
: new ChannelTypeUID(BINDING_ID, channelId);
|
||||
Channel channel = callback.createChannelBuilder(channelUID, channelTypeUID).build();
|
||||
updateThing(editThing().withoutChannel(channelUID).withChannel(channel).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceGone(ThingUID thingUID) {
|
||||
if (thing.getUID().equals(thingUID)) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "Device not present in response");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link ThingUID} from a device model. The UID is build from the
|
||||
* {@link AVMFritzBindingConstants#BINDING_ID} and value of
|
||||
* {@link AVMFritzBaseModel#getProductName()} in which all characters NOT matching
|
||||
* the regex [^a-zA-Z0-9_] are replaced by "_".
|
||||
*
|
||||
* @param device Discovered device model
|
||||
* @return ThingUID without illegal characters.
|
||||
*/
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(AVMFritzBaseModel device) {
|
||||
ThingTypeUID thingTypeUID = new ThingTypeUID(BINDING_ID, getThingTypeId(device).concat("_Solo"));
|
||||
String ipAddress = getConfigAs(AVMFritzBoxConfiguration.class).ipAddress;
|
||||
|
||||
if (PL546E_STANDALONE_THING_TYPE.equals(thingTypeUID)) {
|
||||
String thingName = "fritz.powerline".equals(ipAddress) ? ipAddress
|
||||
: ipAddress.replaceAll(INVALID_PATTERN, "_");
|
||||
return new ThingUID(thingTypeUID, thingName);
|
||||
} else {
|
||||
return super.getThingUID(device);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
String channelId = channelUID.getIdWithoutGroup();
|
||||
logger.debug("Handle command '{}' for channel {}", command, channelId);
|
||||
if (command == RefreshType.REFRESH) {
|
||||
handleRefreshCommand();
|
||||
return;
|
||||
}
|
||||
FritzAhaWebInterface fritzBox = getWebInterface();
|
||||
if (fritzBox == null) {
|
||||
logger.debug("Cannot handle command '{}' because connection is missing", command);
|
||||
return;
|
||||
}
|
||||
String ain = getIdentifier();
|
||||
if (ain == null) {
|
||||
logger.debug("Cannot handle command '{}' because AIN is missing", command);
|
||||
return;
|
||||
}
|
||||
switch (channelId) {
|
||||
case CHANNEL_MODE:
|
||||
case CHANNEL_LOCKED:
|
||||
case CHANNEL_DEVICE_LOCKED:
|
||||
case CHANNEL_ENERGY:
|
||||
case CHANNEL_POWER:
|
||||
case CHANNEL_VOLTAGE:
|
||||
logger.debug("Channel {} is a read-only channel and cannot handle command '{}'", channelId, command);
|
||||
break;
|
||||
case CHANNEL_APPLY_TEMPLATE:
|
||||
if (command instanceof StringType) {
|
||||
fritzBox.applyTemplate(command.toString());
|
||||
}
|
||||
break;
|
||||
case CHANNEL_OUTLET:
|
||||
fritzBox.setSwitch(ain, OnOffType.ON.equals(command));
|
||||
if (command instanceof OnOffType) {
|
||||
if (state != null) {
|
||||
state.getSwitch().setState(OnOffType.ON.equals(command) ? SwitchModel.ON : SwitchModel.OFF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.handleCommand(channelUID, command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AIN.
|
||||
*
|
||||
* @return the AIN
|
||||
*/
|
||||
public @Nullable String getIdentifier() {
|
||||
AVMFritzDeviceConfiguration localConfig = config;
|
||||
return localConfig != null ? localConfig.ain : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Response.CompleteListener;
|
||||
import org.eclipse.jetty.client.api.Response.ContentListener;
|
||||
import org.eclipse.jetty.client.api.Response.FailureListener;
|
||||
import org.eclipse.jetty.client.api.Response.SuccessListener;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.BufferingResponseListener;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaCallback;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Implementation of Jetty ContextExchange to handle callbacks
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaContentExchange extends BufferingResponseListener
|
||||
implements SuccessListener, FailureListener, ContentListener, CompleteListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaContentExchange.class);
|
||||
|
||||
/**
|
||||
* Callback to execute on complete response
|
||||
*/
|
||||
private final FritzAhaCallback callback;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param callback Callback which execute method has to be called.
|
||||
*/
|
||||
public FritzAhaContentExchange(FritzAhaCallback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(@NonNullByDefault({}) Response response) {
|
||||
logger.debug("{} response: {}", response.getRequest().getScheme().toUpperCase(), response.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNullByDefault({}) Response response, @NonNullByDefault({}) Throwable failure) {
|
||||
logger.debug("response failed: {}", failure.getLocalizedMessage(), failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(@NonNullByDefault({}) Result result) {
|
||||
String content = getContentAsString();
|
||||
logger.debug("response complete: {}", content);
|
||||
callback.execute(result.getResponse().getStatus(), content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.dto.AVMFritzBaseModel;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
|
||||
/**
|
||||
* The {@link FritzAhaStatusListener} is notified when a new device has been added, removed or its status has changed.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface FritzAhaStatusListener {
|
||||
|
||||
/**
|
||||
* This method is called whenever a device is added.
|
||||
*
|
||||
* @param device the {@link AVMFritzBaseModel}
|
||||
*/
|
||||
void onDeviceAdded(AVMFritzBaseModel device);
|
||||
|
||||
/**
|
||||
* This method is called whenever a device is updated.
|
||||
*
|
||||
* @param thingUID the {@link ThingUID}
|
||||
* @param device the {@link AVMFritzBaseModel}
|
||||
*/
|
||||
void onDeviceUpdated(ThingUID thingUID, AVMFritzBaseModel device);
|
||||
|
||||
/**
|
||||
* This method is called whenever a device is gone.
|
||||
*
|
||||
* @param thingUID the {@link ThingUID}
|
||||
*/
|
||||
void onDeviceGone(ThingUID thingUID);
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpMethod.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.openhab.binding.avmfritz.internal.config.AVMFritzBoxConfiguration;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzBaseBridgeHandler;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaApplyTemplateCallback;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaCallback;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaSetHeatingModeCallback;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaSetHeatingTemperatureCallback;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.callbacks.FritzAhaSetSwitchCallback;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class handles requests to a FRITZ!OS web interface for interfacing with AVM home automation devices. It manages
|
||||
* authentication and wraps commands.
|
||||
*
|
||||
* @author Robert Bausdorf, Christian Brauers - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet
|
||||
* DECT
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaWebInterface {
|
||||
|
||||
private static final String WEBSERVICE_PATH = "login_sid.lua";
|
||||
/**
|
||||
* RegEx Pattern to grab the session ID from a login XML response
|
||||
*/
|
||||
private static final Pattern SID_PATTERN = Pattern.compile("<SID>([a-fA-F0-9]*)</SID>");
|
||||
/**
|
||||
* RegEx Pattern to grab the challenge from a login XML response
|
||||
*/
|
||||
private static final Pattern CHALLENGE_PATTERN = Pattern.compile("<Challenge>(\\w*)</Challenge>");
|
||||
/**
|
||||
* RegEx Pattern to grab the access privilege for home automation functions from a login XML response
|
||||
*/
|
||||
private static final Pattern ACCESS_PATTERN = Pattern.compile("<Name>HomeAuto</Name>\\s*?<Access>([0-9])</Access>");
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaWebInterface.class);
|
||||
/**
|
||||
* Configuration of the bridge from {@link AVMFritzBaseBridgeHandler}
|
||||
*/
|
||||
private final AVMFritzBoxConfiguration config;
|
||||
/**
|
||||
* Bridge thing handler for updating thing status
|
||||
*/
|
||||
private final AVMFritzBaseBridgeHandler handler;
|
||||
/**
|
||||
* Shared instance of HTTP client for asynchronous calls
|
||||
*/
|
||||
private final HttpClient httpClient;
|
||||
/**
|
||||
* Current session ID
|
||||
*/
|
||||
private @Nullable String sid;
|
||||
|
||||
/**
|
||||
* This method authenticates with the FRITZ!OS Web Interface and updates the session ID accordingly
|
||||
*/
|
||||
public void authenticate() {
|
||||
sid = null;
|
||||
String localPassword = config.password;
|
||||
if (localPassword == null || localPassword.trim().isEmpty()) {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"Please configure the password.");
|
||||
return;
|
||||
}
|
||||
String loginXml = syncGet(getURL(WEBSERVICE_PATH, addSID("")));
|
||||
if (loginXml == null) {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"FRITZ!Box does not respond.");
|
||||
return;
|
||||
}
|
||||
Matcher sidmatch = SID_PATTERN.matcher(loginXml);
|
||||
if (!sidmatch.find()) {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"FRITZ!Box does not respond with SID.");
|
||||
return;
|
||||
}
|
||||
String localSid = sidmatch.group(1);
|
||||
Matcher accmatch = ACCESS_PATTERN.matcher(loginXml);
|
||||
if (accmatch.find()) {
|
||||
if ("2".equals(accmatch.group(1))) {
|
||||
sid = localSid;
|
||||
handler.setStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Matcher challengematch = CHALLENGE_PATTERN.matcher(loginXml);
|
||||
if (!challengematch.find()) {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"FRITZ!Box does not respond with challenge for authentication.");
|
||||
return;
|
||||
}
|
||||
String challenge = challengematch.group(1);
|
||||
String response = createResponse(challenge);
|
||||
String localUser = config.user;
|
||||
loginXml = syncGet(getURL(WEBSERVICE_PATH,
|
||||
(localUser == null || localUser.isEmpty() ? "" : ("username=" + localUser + "&")) + "response="
|
||||
+ response));
|
||||
if (loginXml == null) {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"FRITZ!Box does not respond.");
|
||||
return;
|
||||
}
|
||||
sidmatch = SID_PATTERN.matcher(loginXml);
|
||||
if (!sidmatch.find()) {
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"FRITZ!Box does not respond with SID.");
|
||||
return;
|
||||
}
|
||||
localSid = sidmatch.group(1);
|
||||
accmatch = ACCESS_PATTERN.matcher(loginXml);
|
||||
if (accmatch.find()) {
|
||||
if ("2".equals(accmatch.group(1))) {
|
||||
sid = localSid;
|
||||
handler.setStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "User "
|
||||
+ (localUser == null ? "" : localUser) + " has no access to FRITZ!Box home automation functions.");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the authentication status of the web interface
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAuthenticated() {
|
||||
return sid != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the proper response to a given challenge based on the password stored
|
||||
*
|
||||
* @param challenge Challenge string as returned by the FRITZ!OS login script
|
||||
* @return Response to the challenge
|
||||
*/
|
||||
protected String createResponse(String challenge) {
|
||||
String response = challenge.concat("-");
|
||||
String handshake = response.concat(config.password);
|
||||
MessageDigest md5;
|
||||
try {
|
||||
md5 = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.error("This version of Java does not support MD5 hashing");
|
||||
return "";
|
||||
}
|
||||
byte[] handshakeHash = md5.digest(handshake.getBytes(StandardCharsets.UTF_16LE));
|
||||
for (byte handshakeByte : handshakeHash) {
|
||||
response = response.concat(String.format("%02x", handshakeByte));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to set up interface
|
||||
*
|
||||
* @param config Bridge configuration
|
||||
*/
|
||||
public FritzAhaWebInterface(AVMFritzBoxConfiguration config, AVMFritzBaseBridgeHandler handler,
|
||||
HttpClient httpClient) {
|
||||
this.config = config;
|
||||
this.handler = handler;
|
||||
this.httpClient = httpClient;
|
||||
authenticate();
|
||||
logger.debug("Starting with SID {}", sid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an URL from the stored information and a specified path
|
||||
*
|
||||
* @param path Path to include in URL
|
||||
* @return URL
|
||||
*/
|
||||
public String getURL(String path) {
|
||||
return config.protocol + "://" + config.ipAddress + (config.port == null ? "" : ":" + config.port) + "/" + path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an URL from the stored information, a specified path and a specified argument string
|
||||
*
|
||||
* @param path Path to include in URL
|
||||
* @param args String of arguments, in standard HTTP format (arg1=value1&arg2=value2&...)
|
||||
* @return URL
|
||||
*/
|
||||
public String getURL(String path, String args) {
|
||||
return getURL(args.isEmpty() ? path : path + "?" + args);
|
||||
}
|
||||
|
||||
public String addSID(String path) {
|
||||
if (sid == null) {
|
||||
return path;
|
||||
} else {
|
||||
return (path.isEmpty() ? "" : path + "&") + "sid=" + sid;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a HTTP GET request using the synchronous client
|
||||
*
|
||||
* @param path Path of the requested resource
|
||||
* @return response
|
||||
*/
|
||||
public @Nullable String syncGet(String url) {
|
||||
try {
|
||||
ContentResponse contentResponse = httpClient.newRequest(url)
|
||||
.timeout(config.syncTimeout, TimeUnit.MILLISECONDS).method(GET).send();
|
||||
String content = contentResponse.getContentAsString();
|
||||
logger.debug("GET response complete: {}", content);
|
||||
return content;
|
||||
} catch (ExecutionException | InterruptedException | TimeoutException e) {
|
||||
logger.debug("response failed: {}", e.getLocalizedMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a HTTP GET request using the asynchronous client
|
||||
*
|
||||
* @param path Path of the requested resource
|
||||
* @param args Arguments for the request
|
||||
* @param callback Callback to handle the response with
|
||||
*/
|
||||
public FritzAhaContentExchange asyncGet(String path, String args, FritzAhaCallback callback) {
|
||||
if (!isAuthenticated()) {
|
||||
authenticate();
|
||||
}
|
||||
FritzAhaContentExchange getExchange = new FritzAhaContentExchange(callback);
|
||||
httpClient.newRequest(getURL(path, addSID(args))).method(GET).onResponseSuccess(getExchange)
|
||||
.onResponseFailure(getExchange).send(getExchange);
|
||||
return getExchange;
|
||||
}
|
||||
|
||||
public FritzAhaContentExchange asyncGet(FritzAhaCallback callback) {
|
||||
return asyncGet(callback.getPath(), callback.getArgs(), callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a HTTP POST request using the asynchronous client
|
||||
*
|
||||
* @param path Path of the requested resource
|
||||
* @param args Arguments for the request
|
||||
* @param callback Callback to handle the response with
|
||||
*/
|
||||
public FritzAhaContentExchange asyncPost(String path, String args, FritzAhaCallback callback) {
|
||||
if (!isAuthenticated()) {
|
||||
authenticate();
|
||||
}
|
||||
FritzAhaContentExchange postExchange = new FritzAhaContentExchange(callback);
|
||||
httpClient.newRequest(getURL(path)).timeout(config.asyncTimeout, TimeUnit.MILLISECONDS).method(POST)
|
||||
.onResponseSuccess(postExchange).onResponseFailure(postExchange)
|
||||
.content(new StringContentProvider(addSID(args), StandardCharsets.UTF_8)).send(postExchange);
|
||||
return postExchange;
|
||||
}
|
||||
|
||||
public FritzAhaContentExchange applyTemplate(String ain) {
|
||||
FritzAhaApplyTemplateCallback callback = new FritzAhaApplyTemplateCallback(this, ain);
|
||||
return asyncGet(callback);
|
||||
}
|
||||
|
||||
public FritzAhaContentExchange setSwitch(String ain, boolean switchOn) {
|
||||
FritzAhaSetSwitchCallback callback = new FritzAhaSetSwitchCallback(this, ain, switchOn);
|
||||
return asyncGet(callback);
|
||||
}
|
||||
|
||||
public FritzAhaContentExchange setSetTemp(String ain, BigDecimal temperature) {
|
||||
FritzAhaSetHeatingTemperatureCallback callback = new FritzAhaSetHeatingTemperatureCallback(this, ain,
|
||||
temperature);
|
||||
return asyncGet(callback);
|
||||
}
|
||||
|
||||
public FritzAhaContentExchange setBoostMode(String ain, long endTime) {
|
||||
return setHeatingMode(ain, FritzAhaSetHeatingModeCallback.BOOST_COMMAND, endTime);
|
||||
}
|
||||
|
||||
public FritzAhaContentExchange setWindowOpenMode(String ain, long endTime) {
|
||||
return setHeatingMode(ain, FritzAhaSetHeatingModeCallback.WINDOW_OPEN_COMMAND, endTime);
|
||||
}
|
||||
|
||||
private FritzAhaContentExchange setHeatingMode(String ain, String command, long endTime) {
|
||||
FritzAhaSetHeatingModeCallback callback = new FritzAhaSetHeatingModeCallback(this, ain, command, endTime);
|
||||
return asyncGet(callback);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpMethod.GET;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Callback implementation for applying templates.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaApplyTemplateCallback extends FritzAhaReauthCallback {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaApplyTemplateCallback.class);
|
||||
|
||||
private static final String WEBSERVICE_COMMAND = "switchcmd=applytemplate";
|
||||
|
||||
private final String ain;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param webInterface web interface to FRITZ!Box
|
||||
* @param ain AIN of the template that should be applied
|
||||
*/
|
||||
public FritzAhaApplyTemplateCallback(FritzAhaWebInterface webInterface, String ain) {
|
||||
super(WEBSERVICE_PATH, WEBSERVICE_COMMAND + "&ain=" + ain, webInterface, GET, 1);
|
||||
this.ain = ain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(int status, String response) {
|
||||
super.execute(status, response);
|
||||
if (isValidRequest()) {
|
||||
logger.trace("Received response '{}' for item '{}'", response, ain);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Interface for callbacks in asynchronous requests.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface FritzAhaCallback {
|
||||
/**
|
||||
* Runs callback code after response completion.
|
||||
*/
|
||||
void execute(int status, String response);
|
||||
|
||||
/**
|
||||
* Get the URI path
|
||||
*
|
||||
* @return URI path as String
|
||||
*/
|
||||
public String getPath();
|
||||
|
||||
/**
|
||||
* Get the query String
|
||||
*
|
||||
* @return Query string as String
|
||||
*/
|
||||
public String getArgs();
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
|
||||
/**
|
||||
* Callback implementation for reauthorization and retry
|
||||
*
|
||||
* @author Robert Bausdorf, Christian Brauers - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaReauthCallback implements FritzAhaCallback {
|
||||
|
||||
public static final String WEBSERVICE_PATH = "webservices/homeautoswitch.lua";
|
||||
/**
|
||||
* Path to HTTP interface
|
||||
*/
|
||||
private final String path;
|
||||
/**
|
||||
* Arguments to use
|
||||
*/
|
||||
private final String args;
|
||||
/**
|
||||
* Web interface to use
|
||||
*/
|
||||
private final FritzAhaWebInterface webIface;
|
||||
/**
|
||||
* Method used
|
||||
*/
|
||||
private final HttpMethod httpMethod;
|
||||
/**
|
||||
* Number of remaining retries
|
||||
*/
|
||||
private int retries;
|
||||
/**
|
||||
* Callback to execute on next retry
|
||||
*/
|
||||
private FritzAhaCallback retryCallback;
|
||||
/**
|
||||
* Whether the request returned a valid response
|
||||
*/
|
||||
private boolean validRequest;
|
||||
|
||||
/**
|
||||
* Returns whether the request returned a valid response
|
||||
*
|
||||
* @return Validity of response
|
||||
*/
|
||||
public boolean isValidRequest() {
|
||||
return validRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether there will be another retry on an invalid response
|
||||
*
|
||||
* @return true if there will be no more retries, false otherwise
|
||||
*/
|
||||
public boolean isFinalAttempt() {
|
||||
return retries <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets different Callback to use on retry (initial value: same callback after decremented retry counter)
|
||||
*
|
||||
* @param retryCallback Callback to retry with
|
||||
*/
|
||||
public void setRetryCallback(FritzAhaCallback retryCallback) {
|
||||
this.retryCallback = retryCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public FritzAhaWebInterface getWebIface() {
|
||||
return webIface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(int status, String response) {
|
||||
if (status != 200 || "".equals(response) || ".".equals(response)) {
|
||||
validRequest = false;
|
||||
if (retries >= 1) {
|
||||
webIface.authenticate();
|
||||
retries--;
|
||||
switch (httpMethod) {
|
||||
case GET:
|
||||
webIface.asyncGet(path, args, retryCallback);
|
||||
break;
|
||||
case POST:
|
||||
webIface.asyncPost(path, args, retryCallback);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
validRequest = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for retryable authentication
|
||||
*
|
||||
* @param path
|
||||
* Path to HTTP interface
|
||||
* @param args
|
||||
* Arguments to use
|
||||
* @param webIface
|
||||
* Web interface to use
|
||||
* @param httpMethod
|
||||
* Method used
|
||||
* @param retries
|
||||
* Number of retries
|
||||
*/
|
||||
public FritzAhaReauthCallback(String path, String args, FritzAhaWebInterface webIface, HttpMethod httpMethod,
|
||||
int retries) {
|
||||
this.path = path;
|
||||
this.args = args;
|
||||
this.webIface = webIface;
|
||||
this.httpMethod = httpMethod;
|
||||
this.retries = retries;
|
||||
retryCallback = this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Callback implementation for updating heating modes
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaSetHeatingModeCallback extends FritzAhaReauthCallback {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaSetHeatingModeCallback.class);
|
||||
|
||||
public static final String BOOST_COMMAND = "sethkrboost";
|
||||
public static final String WINDOW_OPEN_COMMAND = "sethkrwindowopen";
|
||||
|
||||
private final String ain;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param webInterface connection to FRITZ!Box
|
||||
* @param ain AIN of the device
|
||||
* @param command the mode to set or deactivate
|
||||
* @param endTimestamp the end timestamp in seconds, maximum allowed value is now + 24h in the future, 0 to
|
||||
* deactivate the mode
|
||||
*/
|
||||
public FritzAhaSetHeatingModeCallback(FritzAhaWebInterface webInterface, String ain, String command,
|
||||
long endTimestamp) {
|
||||
super(WEBSERVICE_PATH, String.format("switchcmd=%s&ain=%s&endtimestamp=%d", command, ain, endTimestamp),
|
||||
webInterface, HttpMethod.GET, 1);
|
||||
this.ain = ain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(int status, String response) {
|
||||
super.execute(status, response);
|
||||
if (isValidRequest()) {
|
||||
logger.debug("Received response '{}' for item '{}'", response, ain);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpMethod.GET;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Callback implementation for updating heating values Supports reauthorization
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for AVM FRITZ!DECT 300 and Comet
|
||||
* DECT
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaSetHeatingTemperatureCallback extends FritzAhaReauthCallback {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaSetHeatingTemperatureCallback.class);
|
||||
|
||||
private static final String WEBSERVICE_COMMAND = "switchcmd=sethkrtsoll";
|
||||
|
||||
private final String ain;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param webIface Interface to FRITZ!Box
|
||||
* @param ain AIN of the device that should be switched
|
||||
* @param temperature New temperature
|
||||
*/
|
||||
public FritzAhaSetHeatingTemperatureCallback(FritzAhaWebInterface webIface, String ain, BigDecimal temperature) {
|
||||
super(WEBSERVICE_PATH, WEBSERVICE_COMMAND + "&ain=" + ain + "¶m=" + temperature, webIface, GET, 1);
|
||||
this.ain = ain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(int status, String response) {
|
||||
super.execute(status, response);
|
||||
if (isValidRequest()) {
|
||||
logger.debug("Received response '{}' for item '{}'", response, ain);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpMethod.GET;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Callback implementation for updating switch states Supports reauthorization
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaSetSwitchCallback extends FritzAhaReauthCallback {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaSetSwitchCallback.class);
|
||||
|
||||
private final String ain;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param webIface Interface to FRITZ!Box
|
||||
* @param ain AIN of the device that should be switched
|
||||
* @param switchOn true - switch on, false - switch off
|
||||
*/
|
||||
public FritzAhaSetSwitchCallback(FritzAhaWebInterface webIface, String ain, boolean switchOn) {
|
||||
super(WEBSERVICE_PATH, "switchcmd=" + (switchOn ? "setswitchon" : "setswitchoff") + "&ain=" + ain, webIface,
|
||||
GET, 1);
|
||||
this.ain = ain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(int status, String response) {
|
||||
super.execute(status, response);
|
||||
if (isValidRequest()) {
|
||||
logger.debug("Received response '{}' for item '{}'", response, ain);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpMethod.GET;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.dto.DeviceListModel;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzBaseBridgeHandler;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.openhab.binding.avmfritz.internal.util.JAXBUtils;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Callback implementation for updating multiple numbers decoded from a xml
|
||||
* response. Supports reauthorization.
|
||||
*
|
||||
* @author Robert Bausdorf - Initial contribution
|
||||
* @author Christoph Weitkamp - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaUpdateCallback extends FritzAhaReauthCallback {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaUpdateCallback.class);
|
||||
|
||||
private static final String WEBSERVICE_COMMAND = "switchcmd=getdevicelistinfos";
|
||||
|
||||
private final AVMFritzBaseBridgeHandler handler;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param webIface Webinterface to FRITZ!Box
|
||||
* @param handler Bridge handler that will update things.
|
||||
*/
|
||||
public FritzAhaUpdateCallback(FritzAhaWebInterface webIface, AVMFritzBaseBridgeHandler handler) {
|
||||
super(WEBSERVICE_PATH, WEBSERVICE_COMMAND, webIface, GET, 1);
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(int status, String response) {
|
||||
super.execute(status, response);
|
||||
logger.trace("Received State response {}", response);
|
||||
if (isValidRequest()) {
|
||||
try {
|
||||
Unmarshaller unmarshaller = JAXBUtils.JAXBCONTEXT_DEVICES.createUnmarshaller();
|
||||
DeviceListModel model = (DeviceListModel) unmarshaller.unmarshal(new StringReader(response));
|
||||
if (model != null) {
|
||||
handler.onDeviceListAdded(model.getDevicelist());
|
||||
} else {
|
||||
logger.debug("no model in response");
|
||||
}
|
||||
handler.setStatusInfo(ThingStatus.ONLINE, ThingStatusDetail.NONE, null);
|
||||
} catch (JAXBException e) {
|
||||
logger.error("Exception creating Unmarshaller: {}", e.getLocalizedMessage(), e);
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
e.getLocalizedMessage());
|
||||
}
|
||||
} else {
|
||||
logger.debug("request is invalid: {}", status);
|
||||
handler.setStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Request is invalid");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.hardware.callbacks;
|
||||
|
||||
import static org.eclipse.jetty.http.HttpMethod.GET;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.avmfritz.internal.dto.templates.TemplateListModel;
|
||||
import org.openhab.binding.avmfritz.internal.handler.AVMFritzBaseBridgeHandler;
|
||||
import org.openhab.binding.avmfritz.internal.hardware.FritzAhaWebInterface;
|
||||
import org.openhab.binding.avmfritz.internal.util.JAXBUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Callback implementation for updating templates from a xml response.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FritzAhaUpdateTemplatesCallback extends FritzAhaReauthCallback {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FritzAhaUpdateTemplatesCallback.class);
|
||||
|
||||
private static final String WEBSERVICE_COMMAND = "switchcmd=gettemplatelistinfos";
|
||||
|
||||
private final AVMFritzBaseBridgeHandler handler;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param webInterface web interface to FRITZ!Box
|
||||
* @param handler handler that will update things
|
||||
*/
|
||||
public FritzAhaUpdateTemplatesCallback(FritzAhaWebInterface webInterface, AVMFritzBaseBridgeHandler handler) {
|
||||
super(WEBSERVICE_PATH, WEBSERVICE_COMMAND, webInterface, GET, 1);
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(int status, String response) {
|
||||
super.execute(status, response);
|
||||
logger.trace("Received response '{}'", response);
|
||||
if (isValidRequest()) {
|
||||
try {
|
||||
Unmarshaller unmarshaller = JAXBUtils.JAXBCONTEXT_TEMPLATES.createUnmarshaller();
|
||||
TemplateListModel model = (TemplateListModel) unmarshaller.unmarshal(new StringReader(response));
|
||||
if (model != null) {
|
||||
handler.addTemplateList(model.getTemplates());
|
||||
} else {
|
||||
logger.debug("no template in response");
|
||||
}
|
||||
} catch (JAXBException e) {
|
||||
logger.error("Exception creating Unmarshaller: {}", e.getLocalizedMessage(), e);
|
||||
}
|
||||
} else {
|
||||
logger.debug("request is invalid: {}", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 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.util;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.avmfritz.internal.dto.DeviceListModel;
|
||||
import org.openhab.binding.avmfritz.internal.dto.templates.TemplateListModel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Implementation for a static use of JAXBContext as singleton instance.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JAXBUtils {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JAXBUtils.class);
|
||||
|
||||
public static final @Nullable JAXBContext JAXBCONTEXT_DEVICES = initJAXBContextDevices();
|
||||
public static final @Nullable JAXBContext JAXBCONTEXT_TEMPLATES = initJAXBContextTemplates();
|
||||
|
||||
private static @Nullable JAXBContext initJAXBContextDevices() {
|
||||
try {
|
||||
return JAXBContext.newInstance(DeviceListModel.class);
|
||||
} catch (JAXBException e) {
|
||||
LOGGER.error("Exception creating JAXBContext for devices: {}", e.getLocalizedMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable JAXBContext initJAXBContextTemplates() {
|
||||
try {
|
||||
return JAXBContext.newInstance(TemplateListModel.class);
|
||||
} catch (JAXBException e) {
|
||||
LOGGER.error("Exception creating JAXBContext for templates: {}", e.getLocalizedMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="avmfritz" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>AVM FRITZ! Binding</name>
|
||||
<description>This is the binding for AVM FRITZ! devices.</description>
|
||||
<author>Robert Bausdorf</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="bridge-type:avmfritz:fritzbox">
|
||||
<parameter-group name="network">
|
||||
<label>Network</label>
|
||||
<description>Network settings.</description>
|
||||
</parameter-group>
|
||||
<parameter-group name="authentication">
|
||||
<label>Authentication</label>
|
||||
<description>Authentication settings.</description>
|
||||
</parameter-group>
|
||||
<parameter-group name="connection">
|
||||
<label>Connection</label>
|
||||
<description>Connection settings.</description>
|
||||
</parameter-group>
|
||||
<parameter name="ipAddress" type="text" required="true" groupName="network">
|
||||
<context>network-address</context>
|
||||
<label>IP Address</label>
|
||||
<description>The local IP address or hostname of the FRITZ!Box.</description>
|
||||
<default>fritz.box</default>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" min="1" max="65535" groupName="network">
|
||||
<label>Port</label>
|
||||
<description>Port of the FRITZ!Box.</description>
|
||||
</parameter>
|
||||
<parameter name="protocol" type="text" groupName="network">
|
||||
<label>Protocol</label>
|
||||
<description>Protocol to connect to the FRITZ!Box (http or https).</description>
|
||||
<default>http</default>
|
||||
<options>
|
||||
<option value="http">HTTP</option>
|
||||
<option value="https">HTTPS</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="user" type="text" groupName="authentication">
|
||||
<label>Username</label>
|
||||
<description>User name which has HomeAuto permissions on the given FRITZ!Box.</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" groupName="authentication">
|
||||
<context>password</context>
|
||||
<label>Password</label>
|
||||
<description>Password to access the FRITZ!Box.</description>
|
||||
</parameter>
|
||||
<parameter name="pollingInterval" type="integer" min="5" max="60" unit="s" groupName="connection">
|
||||
<label>Polling Interval</label>
|
||||
<description>Interval polling the FRITZ!Box (in seconds).</description>
|
||||
<default>15</default>
|
||||
</parameter>
|
||||
<parameter name="asyncTimeout" type="integer" min="1000" max="60000" unit="ms" groupName="connection">
|
||||
<label>Async Timeout</label>
|
||||
<description>Timeout for asynchronous connections (in milliseconds).</description>
|
||||
<default>10000</default>
|
||||
</parameter>
|
||||
<parameter name="syncTimeout" type="integer" min="500" max="15000" unit="ms" groupName="connection">
|
||||
<label>Timeout</label>
|
||||
<description>Timeout for synchronous connections (in milliseconds).</description>
|
||||
<default>2000</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="bridge-type:avmfritz:fritzpowerline">
|
||||
<parameter-group name="network">
|
||||
<label>Network</label>
|
||||
<description>Network settings.</description>
|
||||
</parameter-group>
|
||||
<parameter-group name="authentication">
|
||||
<label>Authentication</label>
|
||||
<description>Authentication settings.</description>
|
||||
</parameter-group>
|
||||
<parameter-group name="connection">
|
||||
<label>Connection</label>
|
||||
<description>Connection settings.</description>
|
||||
</parameter-group>
|
||||
<parameter name="ain" type="text">
|
||||
<label>AIN</label>
|
||||
<description>The AHA id (AIN) that identifies one specific FRITZ! device.</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="ipAddress" type="text" required="true" groupName="network">
|
||||
<context>network-address</context>
|
||||
<label>IP Address</label>
|
||||
<description>The localIP address or hostname of the FRITZ!Powerline.</description>
|
||||
<default>fritz.powerline</default>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" min="1" max="65535" groupName="network">
|
||||
<label>Port</label>
|
||||
<description>Port of the FRITZ!Powerline.</description>
|
||||
</parameter>
|
||||
<parameter name="protocol" type="text" groupName="network">
|
||||
<label>Protocol</label>
|
||||
<description>Protocol to connect to the FRITZ!Powerline (http or https).</description>
|
||||
<default>http</default>
|
||||
<options>
|
||||
<option value="http">HTTP</option>
|
||||
<option value="https">HTTPS</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true" groupName="authentication">
|
||||
<context>password</context>
|
||||
<label>Password</label>
|
||||
<description>Password to access the FRITZ!Powerline.</description>
|
||||
</parameter>
|
||||
<parameter name="pollingInterval" type="integer" min="5" max="60" unit="s" groupName="connection">
|
||||
<label>Polling Interval</label>
|
||||
<description>Interval polling the FRITZ!Powerline (in seconds).</description>
|
||||
<default>15</default>
|
||||
</parameter>
|
||||
<parameter name="asyncTimeout" type="integer" min="1000" max="60000" unit="ms" groupName="connection">
|
||||
<label>Async Timeout</label>
|
||||
<description>Timeout for asynchronous connections (in milliseconds).</description>
|
||||
<default>10000</default>
|
||||
</parameter>
|
||||
<parameter name="syncTimeout" type="integer" min="500" max="15000" unit="ms" groupName="connection">
|
||||
<label>Timeout</label>
|
||||
<description>Timeout for synchronous connections (in milliseconds).</description>
|
||||
<default>2000</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:avmfritz:fritzdevice">
|
||||
<parameter name="ain" type="text" required="true">
|
||||
<label>AIN</label>
|
||||
<description>The AHA id (AIN) that identifies one specific FRITZ! device.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="thing-type:avmfritz:fritzgroup">
|
||||
<parameter name="ain" type="text" required="true">
|
||||
<label>AIN</label>
|
||||
<description>The AHA id (AIN) that identifies one specific FRITZ! group.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
<config-description uri="channel-type:avmfritz:temperature">
|
||||
<parameter name="offset" type="decimal" readOnly="true" unit="Cel">
|
||||
<label>Temperature Offset</label>
|
||||
<description>Current temperature offset (in °C).</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
||||
@@ -0,0 +1,10 @@
|
||||
# thing actions
|
||||
setBoostModeModeActionLabel = Set Boost Mode
|
||||
setBoostModeActionDescription = Activates the Boost mode of the heating thermostat.
|
||||
setBoostModeDurationInputLabel = Duration
|
||||
setBoostModeDurationInputDescription = Duration in seconds, min. 1, max. 86400, 0 for deactivation.
|
||||
|
||||
setWindowOpenModeActionLabel = Set Window Open Mode
|
||||
setWindowOpenModeActionDescription = Activates the Window Open mode of the heating thermostat.
|
||||
setWindowOpenModeDurationInputLabel = Duration
|
||||
setWindowOpenModeDurationInputDescription = Duration in seconds, min. 1, max. 86400, 0 for deactivation.
|
||||
@@ -0,0 +1,208 @@
|
||||
# binding
|
||||
binding.avmfritz.name = AVM FRITZ! Binding
|
||||
binding.avmfritz.description = Dieses Binding integriert AVM FRITZ! Geräte (z.B DECT 100/200/210/300/301, Comet DECT, Powerline 546E).
|
||||
|
||||
# bridge types
|
||||
thing-type.avmfritz.fritzbox.description = FRITZ!Box
|
||||
|
||||
thing-type.avmfritz.FRITZ_Powerline_546E_Solo.description = FRITZ!Powerline 546E schaltbare Steckdose im stand-alone Modus. Dient zur Steuerung der integrierten Steckdose und liefert Daten wie z.B. Temperatur.
|
||||
|
||||
thing-type.avmfritz.HAN_FUN_CONTACT.label = HAN-FUN Kontakt
|
||||
thing-type.avmfritz.HAN_FUN_CONTACT.description = HAN-FUN Kontakt (e.g. SmartHome Tür-/Fensterkontakt or SmartHome Bewegungsmelder).
|
||||
|
||||
thing-type.avmfritz.HAN_FUN_SWITCH.label = HAN-FUN Schalter
|
||||
thing-type.avmfritz.HAN_FUN_SWITCH.description = HAN-FUN Schalter (e.g. SmartHome Wandtaster).
|
||||
|
||||
# bridge types config groups
|
||||
bridge-type.config.avmfritz.fritzbox.group.network.label = Netzwerk
|
||||
bridge-type.config.avmfritz.fritzbox.group.network.description = Einstellungen für das Netzwerk.
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.group.authentication.label = Authentifizierung
|
||||
bridge-type.config.avmfritz.fritzbox.group.authentication.description = Einstellungen für die Authentifizierung.
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.group.connection.label = Verbindung
|
||||
bridge-type.config.avmfritz.fritzbox.group.connection.description = Einstellungen für die Verbindung.
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.group.network.label = Netzwerk
|
||||
bridge-type.config.avmfritz.fritzpowerline.group.network.description = Einstellungen für das Netzwerk.
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.group.authentication.label = Authentifizierung
|
||||
bridge-type.config.avmfritz.fritzpowerline.group.authentication.description = Einstellungen für die Authentifizierung.
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.group.connection.label = Verbindung
|
||||
bridge-type.config.avmfritz.fritzpowerline.group.connection.description = Einstellungen für die Verbindung.
|
||||
|
||||
# bridge types config
|
||||
bridge-type.config.avmfritz.fritzbox.ipAddress.label = IP-Adresse
|
||||
bridge-type.config.avmfritz.fritzbox.ipAddress.description = Lokale IP-Adresse oder Hostname der FRITZ!Box.
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.port.label = Port
|
||||
bridge-type.config.avmfritz.fritzbox.port.description = Port der FRITZ!Box.
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.protocol.label = Protokoll
|
||||
bridge-type.config.avmfritz.fritzbox.protocol.description = Protokoll für den Verbindungsaufbau zur FRITZ!Box (http or https).
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.password.label = Passwort
|
||||
bridge-type.config.avmfritz.fritzbox.password.description = Passwort zur Authentifizierung an der FRITZ!Box.
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.user.label = Benutzer
|
||||
bridge-type.config.avmfritz.fritzbox.user.description = Benutzer zur Authentifizierung an der FRITZ!Box.
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.pollingInterval.label = Abfrageintervall
|
||||
bridge-type.config.avmfritz.fritzbox.pollingInterval.description = Intervall zur Abfrage der FRITZ!Box (in Sekunden).
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.asyncTimeout.label = Asynchroner Timeout
|
||||
bridge-type.config.avmfritz.fritzbox.asyncTimeout.description = Timeout für asynchrone Abfragen der FRITZ!Box (in Millisekunden).
|
||||
|
||||
bridge-type.config.avmfritz.fritzbox.syncTimeout.label = Synchroner Timeout
|
||||
bridge-type.config.avmfritz.fritzbox.syncTimeout.description = Timeout für synchrone Abfragen der FRITZ!Box (in Millisekunden).
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.ain.description = Die AHA ID (AIN) zur Identifikation des FRITZ!Powerline Gerätes.
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.ipAddress.label = IP-Adresse
|
||||
bridge-type.config.avmfritz.fritzpowerline.ipAddress.description = Lokale IP-Adresse oder Hostname des FRITZ!Powerline Gerätes.
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.port.label = Port
|
||||
bridge-type.config.avmfritz.fritzpowerline.port.description = Port des FRITZ!Powerline Gerätes.
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.protocol.label = Protokoll
|
||||
bridge-type.config.avmfritz.fritzpowerline.protocol.description = Protokoll für den Verbindungsaufbau zum FRITZ!Powerline Gerät (http or https).
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.password.label = Passwort
|
||||
bridge-type.config.avmfritz.fritzpowerline.password.description = Passwort zur Authentifizierung an dem FRITZ!Powerline Gerät.
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.pollingInterval.label = Abfrageintervall
|
||||
bridge-type.config.avmfritz.fritzpowerline.pollingInterval.description = Intervall zur Abfrage des FRITZ!Powerline Gerät (in Sekunden).
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.asyncTimeout.label = Asynchroner Timeout
|
||||
bridge-type.config.avmfritz.fritzpowerline.asyncTimeout.description = Timeout für asynchrone Abfragen des FRITZ!Powerline Gerät (in Millisekunden).
|
||||
|
||||
bridge-type.config.avmfritz.fritzpowerline.syncTimeout.label = Synchroner Timeout
|
||||
bridge-type.config.avmfritz.fritzpowerline.syncTimeout.description = Timeout für synchrone Abfragen des FRITZ!Powerline Gerät (in Millisekunden).
|
||||
|
||||
# thing types
|
||||
thing-type.avmfritz.FRITZ_DECT_Repeater_100.description = FRITZ!DECT Repeater 100 DECT Repeater. Liefert Daten wie z.B. Temperatur.
|
||||
|
||||
thing-type.avmfritz.FRITZ_DECT_200.description = FRITZ!DECT 200 schaltbare Steckdose. Dient zur Steuerung der integrierten Steckdose und liefert Daten wie z.B. Temperatur und Energie.
|
||||
|
||||
thing-type.avmfritz.FRITZ_DECT_210.description = FRITZ!DECT 210 schaltbare Steckdose. Dient zur Steuerung der integrierten Steckdose und liefert Daten wie z.B. Temperatur und Energie.
|
||||
|
||||
thing-type.avmfritz.FRITZ_DECT_300.description = FRITZ!DECT 300 Heizkörperregler. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur.
|
||||
|
||||
thing-type.avmfritz.FRITZ_DECT_301.description = FRITZ!DECT 301 Heizkörperregler. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur.
|
||||
|
||||
thing-type.avmfritz.Comet_DECT.description = Comet DECT Heizkörperregler. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur.
|
||||
|
||||
thing-type.avmfritz.FRITZ_DECT_400.description = FRITZ!DECT 400 Taster. Dient zur komfortablen Bedienung von FRITZ! Smart-Home-Geräten.
|
||||
|
||||
thing-type.avmfritz.FRITZ_Powerline_546E.description = FRITZ!Powerline 546E schaltbare Steckdose. Dient zur Steuerung der integrierten Steckdose und liefert Daten wie z.B. Temperatur.
|
||||
|
||||
# thing types config groups
|
||||
thing-type.avmfritz.FRITZ_GROUP_HEATING.label = Heizkörperregler
|
||||
thing-type.avmfritz.FRITZ_GROUP_HEATING.description = Gruppe für Heizkörperregler. Dient zur Steuerung von Heizkörpern und liefert Daten wie z.B. Temperatur.
|
||||
|
||||
thing-type.avmfritz.FRITZ_GROUP_SWITCH.label = Schaltaktoren
|
||||
thing-type.avmfritz.FRITZ_GROUP_SWITCH.description = Gruppe für Schaltaktoren und Energie Messgeräte. Dient zur Steuerung von Steckdosen und liefert Daten wie z.B. Energie.
|
||||
|
||||
# thing types config
|
||||
thing-type.config.avmfritz.fritzdevice.ain.description = Die AHA ID (AIN) zur Identifikation des FRITZ! Gerätes.
|
||||
|
||||
thing-type.config.avmfritz.fritzgroup.ain.description = Die AHA ID (AIN) zur Identifikation der FRITZ! Gruppe.
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.avmfritz.incoming_call.label = Eingehender Anruf
|
||||
channel-type.avmfritz.incoming_call.description = Informationen zu anrufender und angerufener Telefonnummer.
|
||||
channel-type.avmfritz.outgoing_call.label = Ausgehender Anruf
|
||||
channel-type.avmfritz.outgoing_call.description = Informationen zu angerufener und genutzter Telefonnummer.
|
||||
channel-type.avmfritz.active_call.label = Aktiver Anruf
|
||||
channel-type.avmfritz.active_call.description = Informationen zur aktuell bestehenden Verbindung.
|
||||
channel-type.avmfritz.call_state.label = Anrufzustand
|
||||
channel-type.avmfritz.call_state.description = Gibt an, ob derzeit eine Anrufaktivität stattfindet.
|
||||
channel-type.avmfritz.call_state.state.option.IDLE = Inaktiv
|
||||
channel-type.avmfritz.call_state.state.option.RINGING = Eingehener Anruf
|
||||
channel-type.avmfritz.call_state.state.option.DIALING = Ausgehender Anruf
|
||||
channel-type.avmfritz.call_state.state.option.ACTIVE = Verbunden
|
||||
|
||||
channel-type.avmfritz.mode.label = Modus des Gerätes
|
||||
channel-type.avmfritz.mode.description = Zeigt den aktuellen Modus des Gerätes an (MANUAL/AUTOMATIC/VACATION).
|
||||
channel-type.avmfritz.mode.state.option.MANUAL = Manuell
|
||||
channel-type.avmfritz.mode.state.option.AUTOMATIC = Automatisch
|
||||
channel-type.avmfritz.mode.state.option.VACATION = Urlaubsmodus
|
||||
|
||||
channel-type.avmfritz.locked.label = Externes Schalten
|
||||
channel-type.avmfritz.locked.description = Zeigt an, ob das Schalten des Gerätes per Telefon, App oder Benutzeroberfläche aktiviert ist.
|
||||
|
||||
channel-type.avmfritz.device_locked.label = Tastensperre
|
||||
channel-type.avmfritz.device_locked.description = Zeigt an, ob das Schalten per Taste am Gerät aktiviert ist.
|
||||
|
||||
channel-type.avmfritz.apply_template.label = Vorlage anwenden
|
||||
channel-type.avmfritz.apply_template.description = Ermöglicht die Anwendung einer Vorlage.
|
||||
|
||||
channel-type.avmfritz.temperature.label = Temperatur
|
||||
channel-type.avmfritz.temperature.description = Zeigt die aktuelle Temperatur an.
|
||||
|
||||
channel-type.avmfritz.energy.label = Gesamtverbrauch
|
||||
channel-type.avmfritz.energy.description = Zeigt den akkumulierten Gesamtverbrauch an.
|
||||
|
||||
channel-type.avmfritz.power.label = Leistung
|
||||
channel-type.avmfritz.power.description = Zeigt die aktuelle Leistung an.
|
||||
|
||||
channel-type.avmfritz.voltage.label = Spannung
|
||||
channel-type.avmfritz.voltage.description = Zeigt die aktuelle Spannung an.
|
||||
|
||||
channel-type.avmfritz.outlet.label = Steckdose
|
||||
channel-type.avmfritz.outlet.description = Ermöglicht die Steuerung der Steckdose (ON/OFF).
|
||||
|
||||
channel-type.avmfritz.actual_temp.label = Temperatur
|
||||
channel-type.avmfritz.actual_temp.description = Zeigt die aktuell gemessene Temperatur des Heizkörperreglers an.
|
||||
|
||||
channel-type.avmfritz.set_temp.label = Solltemperatur
|
||||
channel-type.avmfritz.set_temp.description = Ermöglicht die Steuerung der Solltemperatur des Heizkörperreglers.
|
||||
|
||||
channel-type.avmfritz.eco_temp.label = Absenktemperatur
|
||||
channel-type.avmfritz.eco_temp.description = Zeigt die aktuell eingestellte Absenktemperatur des Heizkörperreglers an.
|
||||
|
||||
channel-type.avmfritz.comfort_temp.label = Komforttemperatur
|
||||
channel-type.avmfritz.comfort_temp.description = Zeigt die aktuell eingestellte Komforttemperatur des Heizkörperreglers an.
|
||||
|
||||
channel-type.avmfritz.radiator_mode.label = Modus des Heizkörperreglers
|
||||
channel-type.avmfritz.radiator_mode.description = Ermöglicht die Steuerung des aktuellen Modus des Heizkörperreglers (ON/OFF/COMFORT/ECO/BOOST/WINDOW_OPEN).
|
||||
channel-type.avmfritz.radiator_mode.state.option.ON = An
|
||||
channel-type.avmfritz.radiator_mode.state.option.OFF = Aus
|
||||
channel-type.avmfritz.radiator_mode.state.option.COMFORT = Komfort
|
||||
channel-type.avmfritz.radiator_mode.state.option.ECO = Absenk
|
||||
channel-type.avmfritz.radiator_mode.state.option.BOOST = Boost
|
||||
channel-type.avmfritz.radiator_mode.state.option.WINDOW_OPEN = Fenster-Auf
|
||||
|
||||
channel-type.avmfritz.next_change.label = Nächste Änderung
|
||||
channel-type.avmfritz.next_change.description = Zeigt den Zeitpunkt der nächsten Änderung der Solltemperatur des Heizkörperreglers an.
|
||||
channel-type.avmfritz.next_change.pattern = pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
|
||||
channel-type.avmfritz.next_temp.label = Nächste Solltemperatur
|
||||
channel-type.avmfritz.next_temp.description = Zeigt die nächste Solltemperatur des Heizkörperreglers an.
|
||||
|
||||
channel-type.avmfritz.contact_state.label = Tür-/Fenster-Zustand
|
||||
channel-type.avmfritz.contact_state.description = Zeigt an, ob die Tür oder das Fester offen oder geschlossen ist (OPEN/CLOSED).
|
||||
|
||||
thing-type.avmfritz.HAN_FUN_SWITCH.channel.press.label = Tastendruck
|
||||
thing-type.avmfritz.HAN_FUN_SWITCH.channel.press.description = Wird ausgelöst, wenn eine Taste gedrückt wird.
|
||||
|
||||
channel-type.avmfritz.last_change.label = Letzte Änderung
|
||||
channel-type.avmfritz.last_change.description = Zeigt an, wann der Schalter zuletzt gedrückt wurde.
|
||||
channel-type.avmfritz.last_change.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
|
||||
# channel types config
|
||||
channel-type.config.avmfritz.temperature.offset.label = Temperatur-Offset
|
||||
channel-type.config.avmfritz.temperature.offset.description = Zeigt den aktuell eingestellten Temperatur-Offset (in °C) an.
|
||||
|
||||
# thing actions
|
||||
setBoostModeModeActionLabel = Boost-Modus Aktivieren
|
||||
setBoostModeActionDescription = Aktiviert den Boost-Modus des Heizkörperregler.
|
||||
setBoostModeDurationInputLabel = Dauer
|
||||
setBoostModeDurationInputDescription = Dauer in Sekunden, min. 1, max. 86400, 0 zur Deaktivierung.
|
||||
|
||||
setWindowOpenModeActionLabel = Fenster-Auf-Modus Aktivieren
|
||||
setWindowOpenModeActionDescription = Aktiviert den Fenster-Auf-Modus des Heizkörperregler.
|
||||
setWindowOpenModeDurationInputLabel = Dauer
|
||||
setWindowOpenModeDurationInputDescription = Dauer in Sekunden, min. 1, max. 86400, 0 zur Deaktivierung.
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="avmfritz"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Supported FRITZ!Box and FRITZ!Powerline -->
|
||||
<bridge-type id="fritzbox">
|
||||
<label>FRITZ!Box</label>
|
||||
<description>A FRITZ!Box router.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="incoming_call" typeId="incoming_call"/>
|
||||
<channel id="outgoing_call" typeId="outgoing_call"/>
|
||||
<channel id="active_call" typeId="active_call"/>
|
||||
<channel id="call_state" typeId="call_state"/>
|
||||
<channel id="apply_template" typeId="apply_template"/>
|
||||
</channels>
|
||||
|
||||
<config-description-ref uri="bridge-type:avmfritz:fritzbox"/>
|
||||
</bridge-type>
|
||||
|
||||
<bridge-type id="FRITZ_Powerline_546E_Solo">
|
||||
<label>FRITZ!Powerline 546E</label>
|
||||
<description>A FRITZ!Powerline 546E with switchable outlet in stand-alone mode.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="apply_template" typeId="apply_template"/>
|
||||
<channel id="energy" typeId="energy"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="outlet" typeId="outlet"/>
|
||||
</channels>
|
||||
|
||||
<config-description-ref uri="bridge-type:avmfritz:fritzpowerline"/>
|
||||
</bridge-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="avmfritz"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Channel definitions of FRITZ!Box -->
|
||||
<channel-type id="incoming_call">
|
||||
<item-type>Call</item-type>
|
||||
<label>Incoming Call</label>
|
||||
<description>Details about incoming call.</description>
|
||||
<state pattern="%1$s to %2$s" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="outgoing_call">
|
||||
<item-type>Call</item-type>
|
||||
<label>Outgoing Call</label>
|
||||
<description>Details about outgoing call.</description>
|
||||
<state pattern="%1$s to %2$s" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="active_call">
|
||||
<item-type>Call</item-type>
|
||||
<label>Active Call</label>
|
||||
<description>Details about active call.</description>
|
||||
<state pattern="%1$s" readOnly="true"/>
|
||||
</channel-type>
|
||||
<channel-type id="call_state">
|
||||
<item-type>String</item-type>
|
||||
<label>Call State</label>
|
||||
<description>Details about current call state.</description>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="IDLE">Idle</option>
|
||||
<option value="RINGING">Ringing</option>
|
||||
<option value="DIALING">Dialing</option>
|
||||
<option value="ACTIVE">Active</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
<channel-type id="apply_template" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Apply Template</label>
|
||||
<description>Apply template for device(s).</description>
|
||||
<state pattern="%s"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Channel definitions of all FRITZ! devices -->
|
||||
<channel-type id="mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Mode</label>
|
||||
<description>States the mode of the device (MANUAL/AUTOMATIC/VACATION).</description>
|
||||
<state pattern="%s" readOnly="true">
|
||||
<options>
|
||||
<option value="MANUAL">Manual</option>
|
||||
<option value="AUTOMATIC">Automatic</option>
|
||||
<option value="VACATION">Vacation</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="locked" advanced="true">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Device Locked (external)</label>
|
||||
<description>Device is locked for switching over external sources.</description>
|
||||
<category>Contact</category>
|
||||
<state pattern="%s" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="device_locked" advanced="true">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Locked (manual)</label>
|
||||
<description>Device is locked for switching by pressing the button on the device.</description>
|
||||
<category>Contact</category>
|
||||
<state pattern="%s" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Channel definitions of specific FRITZ! devices -->
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Current Temperature</label>
|
||||
<description>Current measured temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
|
||||
<config-description-ref uri="channel-type:avmfritz:temperature"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="energy">
|
||||
<item-type>Number:Energy</item-type>
|
||||
<label>Energy Consumption</label>
|
||||
<description>Accumulated energy consumption.</description>
|
||||
<category>Energy</category>
|
||||
<state pattern="%.3f kWh" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="power">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>Power</label>
|
||||
<description>Current power consumption.</description>
|
||||
<category>Energy</category>
|
||||
<state pattern="%.2f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="voltage">
|
||||
<item-type>Number:ElectricPotential</item-type>
|
||||
<label>Voltage</label>
|
||||
<description>Current voltage.</description>
|
||||
<category>Energy</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="outlet">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Outlet</label>
|
||||
<description>Switched outlet (ON/OFF).</description>
|
||||
<category>PowerOutlet</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="actual_temp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Current Temperature</label>
|
||||
<description>Current measured temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="set_temp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Setpoint Temperature</label>
|
||||
<description>Thermostat Setpoint temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="eco_temp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Eco Temperature</label>
|
||||
<description>Thermostat Eco temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="comfort_temp">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Comfort Temperature</label>
|
||||
<description>Thermostat Comfort temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="radiator_mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Radiator Mode</label>
|
||||
<description>States the mode of the radiator (ON/OFF/COMFORT/ECO/BOOST/WINDOW_OPEN).</description>
|
||||
<state pattern="%s">
|
||||
<options>
|
||||
<option value="ON">On</option>
|
||||
<option value="OFF">Off</option>
|
||||
<option value="COMFORT">Comfort</option>
|
||||
<option value="ECO">Eco</option>
|
||||
<option value="BOOST">Boost</option>
|
||||
<option value="WINDOW_OPEN">Window Open</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="next_change" advanced="true">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Next Setpoint Change</label>
|
||||
<description>Next change of Setpoint Temperature.</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="next_temp" advanced="true">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Next Setpoint Temperature</label>
|
||||
<description>Next Setpoint Temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="contact_state">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Contact State</label>
|
||||
<description>Contact state information (OPEN/CLOSED).</description>
|
||||
<category>Contact</category>
|
||||
<state pattern="%s" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="last_change">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Change</label>
|
||||
<description>States the last time the button was pressed.</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,300 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="avmfritz"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Supported FRITZ! devices and features -->
|
||||
<thing-type id="FRITZ_DECT_400">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>FRITZ!DECT 400</label>
|
||||
<description>FRITZ!DECT400 switch.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="press" typeId="system.button">
|
||||
<label>Button press</label>
|
||||
<description>Triggered SHORT_PRESSED or LONG_PRESSED when a button was pressed.</description>
|
||||
</channel>
|
||||
<channel id="last_change" typeId="last_change"/>
|
||||
<channel id="battery_level" typeId="system.battery-level"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="Comet_DECT">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Comet DECT</label>
|
||||
<description>Comet DECT heating thermostat.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="actual_temp" typeId="actual_temp"/>
|
||||
<channel id="set_temp" typeId="set_temp"/>
|
||||
<channel id="eco_temp" typeId="eco_temp"/>
|
||||
<channel id="comfort_temp" typeId="comfort_temp"/>
|
||||
<channel id="radiator_mode" typeId="radiator_mode"/>
|
||||
<channel id="next_change" typeId="next_change"/>
|
||||
<channel id="next_temp" typeId="next_temp"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="FRITZ_DECT_301">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>FRITZ!DECT 301</label>
|
||||
<description>FRITZ!DECT 301 heating thermostat.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="actual_temp" typeId="actual_temp"/>
|
||||
<channel id="set_temp" typeId="set_temp"/>
|
||||
<channel id="eco_temp" typeId="eco_temp"/>
|
||||
<channel id="comfort_temp" typeId="comfort_temp"/>
|
||||
<channel id="radiator_mode" typeId="radiator_mode"/>
|
||||
<channel id="next_change" typeId="next_change"/>
|
||||
<channel id="next_temp" typeId="next_temp"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="FRITZ_DECT_300">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>FRITZ!DECT 300</label>
|
||||
<description>FRITZ!DECT 300 heating thermostat.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="actual_temp" typeId="actual_temp"/>
|
||||
<channel id="set_temp" typeId="set_temp"/>
|
||||
<channel id="eco_temp" typeId="eco_temp"/>
|
||||
<channel id="comfort_temp" typeId="comfort_temp"/>
|
||||
<channel id="radiator_mode" typeId="radiator_mode"/>
|
||||
<channel id="next_change" typeId="next_change"/>
|
||||
<channel id="next_temp" typeId="next_temp"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="FRITZ_DECT_210">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>FRITZ!DECT 210</label>
|
||||
<description>FRITZ!DECT210 switchable outlet.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="energy" typeId="energy"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="outlet" typeId="outlet"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="FRITZ_DECT_200">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>FRITZ!DECT 200</label>
|
||||
<description>FRITZ!DECT200 switchable outlet.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="energy" typeId="energy"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="outlet" typeId="outlet"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="FRITZ_Powerline_546E">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>FRITZ!Powerline 546E</label>
|
||||
<description>FRITZ!Powerline 546E with switchable outlet.
|
||||
</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="energy" typeId="energy"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="outlet" typeId="outlet"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="FRITZ_DECT_Repeater_100">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>FRITZ!DECT Repeater 100</label>
|
||||
<description>FRITZ!DECT Repeater 100 DECT repeater.</description>
|
||||
|
||||
<channels>
|
||||
<channel typeId="temperature" id="temperature"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="HAN_FUN_CONTACT">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>HAN-FUN Contact</label>
|
||||
<description>HAN-FUN contact (e.g. SmartHome Tür-/Fensterkontakt or SmartHome Bewegungsmelder).</description>
|
||||
|
||||
<channels>
|
||||
<channel typeId="contact_state" id="contact_state"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="HAN_FUN_SWITCH">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>HAN-FUN Switch</label>
|
||||
<description>HAN-FUN switch (e.g. SmartHome Wandtaster).</description>
|
||||
|
||||
<channels>
|
||||
<channel id="press" typeId="system.rawbutton">
|
||||
<label>Button Press</label>
|
||||
<description>Triggered when a button was pressed.</description>
|
||||
</channel>
|
||||
<channel typeId="last_change" id="last_change"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzdevice"/>
|
||||
</thing-type>
|
||||
|
||||
<!-- Supported FRITZ! groups and features -->
|
||||
<thing-type id="FRITZ_GROUP_HEATING">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Heating Group</label>
|
||||
<description>Group for heating thermostats.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="actual_temp" typeId="actual_temp"/>
|
||||
<channel id="set_temp" typeId="set_temp"/>
|
||||
<channel id="eco_temp" typeId="eco_temp"/>
|
||||
<channel id="comfort_temp" typeId="comfort_temp"/>
|
||||
<channel id="radiator_mode" typeId="radiator_mode"/>
|
||||
<channel id="next_change" typeId="next_change"/>
|
||||
<channel id="next_temp" typeId="next_temp"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzgroup"/>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="FRITZ_GROUP_SWITCH">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="fritzbox"/>
|
||||
<bridge-type-ref id="FRITZ_Powerline_546E_Solo"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Switch Group</label>
|
||||
<description>Group for switchable outlets and power meters.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="mode" typeId="mode"/>
|
||||
<channel id="locked" typeId="locked"/>
|
||||
<channel id="device_locked" typeId="device_locked"/>
|
||||
<channel id="energy" typeId="energy"/>
|
||||
<channel id="power" typeId="power"/>
|
||||
<channel id="outlet" typeId="outlet"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>ain</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:avmfritz:fritzgroup"/>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user