added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.netatmo-${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-velux" description="Velux Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.velux/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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.velux.internal;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.isNotBlank;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/***
|
||||
* <B>Class for Velux binding which validates the bridge configuration parameters.</B>
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #VeluxBinding constructor}</li>
|
||||
* <li>{@link #checked }</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
* @author Joachim Sauer (@Saua) - fix for isBulkRetrievalEnabled, isSequentialEnforced
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBinding extends VeluxBridgeConfiguration {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/***
|
||||
*** Startup methods
|
||||
***/
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* initializes the interface towards the Velux bridge. Furthermore, the checked configuration can be retrieved by
|
||||
* the method {@link #checked checked}.
|
||||
*
|
||||
* @param uncheckedConfiguration
|
||||
* The configuration of type {@link VeluxBridgeConfiguration}
|
||||
* which shall be checked.
|
||||
*/
|
||||
public VeluxBinding(@Nullable VeluxBridgeConfiguration uncheckedConfiguration) {
|
||||
logger.trace("VeluxBinding(constructor) called.");
|
||||
if (logger.isTraceEnabled()) {
|
||||
for (Field field : VeluxBridgeConfiguration.class.getFields()) {
|
||||
if (!StringUtils.capitalize(field.getName()).contentEquals(field.getName())) {
|
||||
logger.trace("VeluxBinding(): FYI: a potential configuration string is '{}'.", field.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uncheckedConfiguration == null) {
|
||||
logger.debug("No configuration found, using default values.");
|
||||
} else {
|
||||
logger.trace("VeluxBinding(): checking {}.", VeluxBridgeConfiguration.BRIDGE_PROTOCOL);
|
||||
if (isNotBlank(uncheckedConfiguration.protocol)) {
|
||||
this.protocol = uncheckedConfiguration.protocol;
|
||||
}
|
||||
logger.trace("VeluxBinding(): checking {}.", VeluxBridgeConfiguration.BRIDGE_IPADDRESS);
|
||||
if (isNotBlank(uncheckedConfiguration.ipAddress)) {
|
||||
this.ipAddress = uncheckedConfiguration.ipAddress;
|
||||
}
|
||||
logger.trace("VeluxBinding(): checking {}.", VeluxBridgeConfiguration.BRIDGE_TCPPORT);
|
||||
if ((uncheckedConfiguration.tcpPort > 0) && (uncheckedConfiguration.tcpPort <= 65535)) {
|
||||
this.tcpPort = uncheckedConfiguration.tcpPort;
|
||||
}
|
||||
logger.trace("VeluxBinding(): checking {}.", VeluxBridgeConfiguration.BRIDGE_PASSWORD);
|
||||
if (isNotBlank(uncheckedConfiguration.password)) {
|
||||
this.password = uncheckedConfiguration.password;
|
||||
}
|
||||
logger.trace("VeluxBinding(): checking {}.", VeluxBridgeConfiguration.BRIDGE_TIMEOUT_MSECS);
|
||||
if ((uncheckedConfiguration.timeoutMsecs > 0) && (uncheckedConfiguration.timeoutMsecs <= 10000)) {
|
||||
this.timeoutMsecs = uncheckedConfiguration.timeoutMsecs;
|
||||
}
|
||||
logger.trace("VeluxBinding(): checking {}.", VeluxBridgeConfiguration.BRIDGE_RETRIES);
|
||||
if ((uncheckedConfiguration.retries >= 0) && (uncheckedConfiguration.retries <= 10)) {
|
||||
this.retries = uncheckedConfiguration.retries;
|
||||
}
|
||||
logger.trace("VeluxBinding(): checking {}.", VeluxBridgeConfiguration.BRIDGE_REFRESH_MSECS);
|
||||
if ((uncheckedConfiguration.refreshMSecs > 0) && (uncheckedConfiguration.refreshMSecs <= 10000)) {
|
||||
this.refreshMSecs = uncheckedConfiguration.refreshMSecs;
|
||||
}
|
||||
this.isBulkRetrievalEnabled = uncheckedConfiguration.isBulkRetrievalEnabled;
|
||||
this.isSequentialEnforced = uncheckedConfiguration.isSequentialEnforced;
|
||||
this.isProtocolTraceEnabled = uncheckedConfiguration.isProtocolTraceEnabled;
|
||||
|
||||
}
|
||||
logger.trace("VeluxBinding(constructor) done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Access method returning a validated configuration.
|
||||
*
|
||||
* @return bridgeConfiguration of type {@link VeluxBridgeConfiguration
|
||||
* VeluxBridgeConfiguration}.
|
||||
*/
|
||||
public VeluxBridgeConfiguration checked() {
|
||||
logger.trace("checked() called.");
|
||||
logger.debug("{}Config[{}={},{}={},{}={},{}={},{}={},{}={},{}={},{}={},{}={},{}={}]",
|
||||
VeluxBindingConstants.BINDING_ID, VeluxBridgeConfiguration.BRIDGE_PROTOCOL, protocol,
|
||||
VeluxBridgeConfiguration.BRIDGE_IPADDRESS, this.ipAddress, VeluxBridgeConfiguration.BRIDGE_TCPPORT,
|
||||
tcpPort, VeluxBridgeConfiguration.BRIDGE_PASSWORD, password.replaceAll(".", "*"),
|
||||
VeluxBridgeConfiguration.BRIDGE_TIMEOUT_MSECS, timeoutMsecs, VeluxBridgeConfiguration.BRIDGE_RETRIES,
|
||||
retries, VeluxBridgeConfiguration.BRIDGE_REFRESH_MSECS, refreshMSecs,
|
||||
VeluxBridgeConfiguration.BRIDGE_IS_BULK_RETRIEVAL_ENABLED, isBulkRetrievalEnabled,
|
||||
VeluxBridgeConfiguration.BRIDGE_IS_SEQUENTIAL_ENFORCED, isSequentialEnforced,
|
||||
VeluxBridgeConfiguration.BRIDGE_PROTOCOL_TRACE_ENABLED, isProtocolTraceEnabled);
|
||||
logger.trace("checked() done.");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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.velux.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This represents the configuration of a openHAB item that is binded to a Velux
|
||||
* KLF200 Gateway. It contains the following information:
|
||||
*
|
||||
* <ul>
|
||||
* <li><B>bindingItemType</B>
|
||||
* <P>
|
||||
* Accessible via
|
||||
* {@link org.openhab.binding.velux.internal.VeluxBindingConfig#getBindingItemType
|
||||
* getBindingItemType} as representation of the Velux device is filed in the Velux bridge.</li>
|
||||
* <li><B>bindingConfig</B>
|
||||
* <P>
|
||||
* Accessible via
|
||||
* {@link org.openhab.binding.velux.internal.VeluxBindingConfig#getBindingConfig getBindingConfig} containing the
|
||||
* device-specific binding configuration
|
||||
* as declared in the binding configuration (possibly adapted by preprocessing).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class VeluxBindingConfig {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBindingConfig.class);
|
||||
|
||||
/**
|
||||
* The binding type of the velux item described by type {@link org.openhab.binding.velux.internal.VeluxItemType
|
||||
* VeluxItemType}.
|
||||
*/
|
||||
private VeluxItemType bindingItemType;
|
||||
|
||||
/**
|
||||
* Device-specific binding configuration as declared in the binding configuration (possibly adapted by
|
||||
* preprocessing).
|
||||
*/
|
||||
private String bindingConfig;
|
||||
|
||||
/**
|
||||
* Constructor of the VeluxBindingConfig.
|
||||
*
|
||||
* @param bindingItemType
|
||||
* The Velux item type {@link org.openhab.binding.velux.internal.VeluxItemType
|
||||
* VeluxItemType}
|
||||
* which the Velux device is filed in the Velux bridge.
|
||||
* @param bindingConfig
|
||||
* The optional configuration type of the Velux binding.
|
||||
*/
|
||||
public VeluxBindingConfig(VeluxItemType bindingItemType, String bindingConfig) {
|
||||
logger.trace("VeluxBindingConfig(constructor:{},{}) called.", bindingItemType, bindingConfig);
|
||||
|
||||
this.bindingItemType = bindingItemType;
|
||||
this.bindingConfig = bindingConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <b>bindingTypeItem</b> of type {@link org.openhab.binding.velux.internal.VeluxItemType
|
||||
* VeluxItemType}.
|
||||
*/
|
||||
public VeluxItemType getBindingItemType() {
|
||||
return this.bindingItemType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <b>bindingConfig</b> of type {@link String} that
|
||||
* has been declared in the binding configuration,
|
||||
* possibly adapted by preprocessing.
|
||||
*/
|
||||
public String getBindingConfig() {
|
||||
return this.bindingConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 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.velux.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
* <P>
|
||||
* For an in-depth view of the available Item types with description of parameters, take a look onto
|
||||
* {@link org.openhab.binding.velux.internal.VeluxItemType VeluxItemType}.
|
||||
* </P>
|
||||
* This class contains the Thing identifications:
|
||||
* <UL>
|
||||
* <LI>{@link #THING_VELUX_BRIDGE} for the bridge itself,</LI>
|
||||
* <LI>{@link #THING_VELUX_SCENE} for the scenes summarizing a set of actuator states,</LI>
|
||||
* <LI>{@link #THING_VELUX_ACTUATOR} for the general actuators identified on the bridge,</LI>
|
||||
* <LI>{@link #THING_VELUX_ROLLERSHUTTER} for the rollershutters identified on the bridge,</LI>
|
||||
* <LI>{@link #THING_VELUX_WINDOW} for the windows identified on the bridge.</LI>
|
||||
* <LI>{@link #THING_VELUX_VSHUTTER} for the virtual shutters defined in the configuration</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBindingConstants {
|
||||
|
||||
/** Basic binding identification. */
|
||||
public static final String BINDING_ID = "velux";
|
||||
|
||||
// Id of support bridge
|
||||
/**
|
||||
* The Thing identification of the binding.
|
||||
*/
|
||||
private static final String THING_VELUX_BINDING = "binding";
|
||||
/**
|
||||
* The Thing identification of the <B>Velux</B> bridge.
|
||||
*/
|
||||
private static final String THING_VELUX_BRIDGE = "klf200";
|
||||
/**
|
||||
* The Thing identification of a scene defined on the <B>Velux</B> bridge.
|
||||
*/
|
||||
private static final String THING_VELUX_SCENE = "scene";
|
||||
/**
|
||||
* The Thing identification of a generic actuator defined on the <B>Velux</B> bridge.
|
||||
*/
|
||||
private static final String THING_VELUX_ACTUATOR = "actuator";
|
||||
/**
|
||||
* The Thing identification of a rollershutter defined on the <B>Velux</B> bridge.
|
||||
*/
|
||||
private static final String THING_VELUX_ROLLERSHUTTER = "rollershutter";
|
||||
/**
|
||||
* The Thing identification of a window defined on the <B>Velux</B> bridge.
|
||||
*/
|
||||
private static final String THING_VELUX_WINDOW = "window";
|
||||
/**
|
||||
* The Thing identification of a virtual shutter defined on the <B>Velux</B> bridge.
|
||||
*/
|
||||
private static final String THING_VELUX_VSHUTTER = "vshutter";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BINDING = new ThingTypeUID(BINDING_ID, THING_VELUX_BINDING);
|
||||
|
||||
// List of all Bridge Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, THING_VELUX_BRIDGE);
|
||||
|
||||
// List of all Thing Type UIDs beyond the bridge(s)
|
||||
public static final ThingTypeUID THING_TYPE_VELUX_SCENE = new ThingTypeUID(BINDING_ID, THING_VELUX_SCENE);
|
||||
public static final ThingTypeUID THING_TYPE_VELUX_ACTUATOR = new ThingTypeUID(BINDING_ID, THING_VELUX_ACTUATOR);
|
||||
public static final ThingTypeUID THING_TYPE_VELUX_ROLLERSHUTTER = new ThingTypeUID(BINDING_ID,
|
||||
THING_VELUX_ROLLERSHUTTER);
|
||||
public static final ThingTypeUID THING_TYPE_VELUX_WINDOW = new ThingTypeUID(BINDING_ID, THING_VELUX_WINDOW);
|
||||
public static final ThingTypeUID THING_TYPE_VELUX_VSHUTTER = new ThingTypeUID(BINDING_ID, THING_VELUX_VSHUTTER);
|
||||
|
||||
// Definitions of different set of Things
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THINGS_BINDING = new HashSet<>(Arrays.asList(THING_TYPE_BINDING));
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THINGS_BRIDGE = new HashSet<>(Arrays.asList(THING_TYPE_BRIDGE));
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THINGS_ITEMS = new HashSet<>(
|
||||
Arrays.asList(THING_TYPE_VELUX_SCENE, THING_TYPE_VELUX_ACTUATOR, THING_TYPE_VELUX_ROLLERSHUTTER,
|
||||
THING_TYPE_VELUX_WINDOW, THING_TYPE_VELUX_VSHUTTER));
|
||||
|
||||
// *** List of all Channel ids ***
|
||||
|
||||
// List of all binding channel ids
|
||||
|
||||
/** Channel identifier describing the current Binding State. */
|
||||
public static final String CHANNEL_BINDING_INFORMATION = "information";
|
||||
|
||||
// List of all bridge channel ids
|
||||
|
||||
/** Channel/Property identifier describing the current Bridge State. */
|
||||
public static final String CHANNEL_BRIDGE_STATUS = "status";
|
||||
public static final String CHANNEL_BRIDGE_RELOAD = "reload";
|
||||
public static final String CHANNEL_BRIDGE_DOWNTIME = "downtime";
|
||||
public static final String CHANNEL_BRIDGE_DO_DETECTION = "doDetection";
|
||||
|
||||
public static final String PROPERTY_BRIDGE_TIMESTAMP_SUCCESS = "connectionSuccess";
|
||||
public static final String PROPERTY_BRIDGE_TIMESTAMP_ATTEMPT = "connectionAttempt";
|
||||
public static final String PROPERTY_BRIDGE_FIRMWARE = "firmware";
|
||||
public static final String PROPERTY_BRIDGE_IPADDRESS = "ipAddress";
|
||||
public static final String PROPERTY_BRIDGE_SUBNETMASK = "subnetMask";
|
||||
public static final String PROPERTY_BRIDGE_DEFAULTGW = "defaultGW";
|
||||
public static final String PROPERTY_BRIDGE_DHCP = "DHCP";
|
||||
public static final String PROPERTY_BRIDGE_WLANSSID = "WLANSSID";
|
||||
public static final String PROPERTY_BRIDGE_WLANPASSWORD = "WLANPassword";
|
||||
|
||||
public static final String PROPERTY_BRIDGE_CHECK = "check";
|
||||
public static final String PROPERTY_BRIDGE_PRODUCTS = "products";
|
||||
public static final String PROPERTY_BRIDGE_SCENES = "scenes";
|
||||
|
||||
// List of all scene channel ids
|
||||
public static final String CHANNEL_SCENE_ACTION = "action";
|
||||
public static final String CHANNEL_SCENE_SILENTMODE = "silentMode";
|
||||
|
||||
// List of all actuator channel ids
|
||||
public static final String CHANNEL_ACTUATOR_POSITION = "position";
|
||||
public static final String CHANNEL_ACTUATOR_STATE = "state";
|
||||
public static final String CHANNEL_ACTUATOR_SILENTMODE = "silentMode";
|
||||
public static final String CHANNEL_ACTUATOR_LIMIT_MINIMUM = "limitMinimum";
|
||||
public static final String CHANNEL_ACTUATOR_LIMIT_MAXIMUM = "limitMaximum";
|
||||
|
||||
// List of all virtual shutter channel ids
|
||||
public static final String CHANNEL_VSHUTTER_POSITION = "vposition";
|
||||
|
||||
// Helper definitions
|
||||
public static final String BINDING_VALUES_SEPARATOR = ",";
|
||||
public static final String OUTPUT_VALUE_SEPARATOR = ",";
|
||||
public static final String UNKNOWN = "unknown";
|
||||
|
||||
// Critical issues to be reported will use the following message
|
||||
public static final String LOGGING_CONTACT = "Please report to maintainer: ";
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.velux.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBindingProperties} class defines common constants, which are
|
||||
* used within the property definitions.
|
||||
*
|
||||
* This class contains the property identifications:
|
||||
* <UL>
|
||||
* <LI>{@link #PROPERTY_BINDING_BUNDLEVERSION} for identification of the binding,</LI>
|
||||
* <LI>{@link #PROPERTY_BINDING_NOOFBRIDGES} for number of bridges,</LI>
|
||||
* <LI>{@link #PROPERTY_BINDING_NOOFTHINGS} for number of things,</LI>
|
||||
* </UL>
|
||||
* <UL>
|
||||
* <LI>{@link #PROPERTY_SCENE_NAME} for defining the name of a scene,</LI>
|
||||
* <LI>{@link #PROPERTY_SCENE_VELOCITY} for defining the velocity of a scene,</LI>
|
||||
* </UL>
|
||||
* <UL>
|
||||
* <LI>{@link #CONFIG_ACTUATOR_SERIALNUMBER} for defining the serial number of an actuator, a rollershutter and a
|
||||
* window,</LI>
|
||||
* <LI>{@link #PROPERTY_ACTUATOR_NAME} for defining the name of an actuator, a rollershutter and a window,</LI>
|
||||
* <LI>{@link #PROPERTY_ACTUATOR_INVERTED} for modifying the value of a Channel,</LI>
|
||||
* </UL>
|
||||
* <UL>
|
||||
* <LI>{@link #PROPERTY_VSHUTTER_SCENELEVELS} for defining a virtual shutter.</LI>
|
||||
* <LI>{@link #PROPERTY_VSHUTTER_CURRENTLEVEL} for defining a virtual shutter.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBindingProperties {
|
||||
|
||||
public static final String PROPERTY_BINDING_BUNDLEVERSION = "bundleVersion";
|
||||
public static final String PROPERTY_BINDING_NOOFBRIDGES = "numberOfBridges";
|
||||
public static final String PROPERTY_BINDING_NOOFTHINGS = "numberOfThings";
|
||||
|
||||
public static final String PROPERTY_SCENE_NAME = "sceneName";
|
||||
public static final String PROPERTY_SCENE_VELOCITY = "velocity";
|
||||
|
||||
public static final String CONFIG_ACTUATOR_SERIALNUMBER = "serial";
|
||||
public static final String PROPERTY_ACTUATOR_NAME = "name";
|
||||
public static final String PROPERTY_ACTUATOR_INVERTED = "inverted";
|
||||
|
||||
public static final String PROPERTY_VSHUTTER_SCENELEVELS = "sceneLevels";
|
||||
public static final String PROPERTY_VSHUTTER_CURRENTLEVEL = "currentLevel";
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
/**
|
||||
* 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.velux.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.items.GenericItem;
|
||||
import org.openhab.core.library.items.NumberItem;
|
||||
import org.openhab.core.library.items.RollershutterItem;
|
||||
import org.openhab.core.library.items.StringItem;
|
||||
import org.openhab.core.library.items.SwitchItem;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Enumeration of Types of a Velux item.
|
||||
* <br>
|
||||
* Provides information about:
|
||||
* <ul>
|
||||
* <li>associated thing identified by String</li>
|
||||
* <li>defined channel identified by String</li>
|
||||
* <li>{@link #getItemClass} item class,</li>
|
||||
* <li>{@link #isReadable} about a read possibility,</li>
|
||||
* <li>{@link #isWritable} about a write possibility,</li>
|
||||
* <li>{@link #isExecutable} about an execute possibility,</li>
|
||||
* <li>{@link #isToBeRefreshed} about necessarily to be refreshed,</li>
|
||||
* <li>{@link #isToBeRefreshedNow} about necessarily to be refreshed at this time,</li>
|
||||
* <li>{@link #isChannel} as indication of being handled as Channel of a thing,</li>
|
||||
* <li>{@link #isProperty} as indication of being handled as property of a thing.</li>
|
||||
* </ul>
|
||||
*
|
||||
* In addition there are helper methods providing information about:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #getIdentifier} returning the common identifier string,</li>
|
||||
* <li>{@link #getByThingAndChannel} to retrieve an enum instance selected by Thing
|
||||
* and Channel identifier,</li>
|
||||
* <li>{@link #getPropertyEntriesByThing} to retrieve any Thing identifiers as array of
|
||||
* String,</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Within this enumeration, the expected behaviour of the OpenHAB item (resp. Channel or Property) is set. For each kind
|
||||
* of Channel (i.e. bridge or device) parameter a set of information is defined:
|
||||
* <ul>
|
||||
* <li>
|
||||
* Unique identification by:
|
||||
* <ul>
|
||||
* <li>Thing name as string,</li>
|
||||
* <li>Channel name as string,</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>Channel type as OpenHAB type,</li>
|
||||
* <li>ability flag whether this item is to be read,</li>
|
||||
* <li>ability flag whether this item is able to be modified,</li>
|
||||
* <li>ability flag whether this item is to be used as execution trigger.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum VeluxItemType {
|
||||
// @formatter:off
|
||||
UNKNOWN(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.UNKNOWN, TypeFlavor.UNUSABLE),
|
||||
//
|
||||
BINDING_INFORMATION(VeluxBindingConstants.THING_TYPE_BINDING, VeluxBindingConstants.CHANNEL_BINDING_INFORMATION, TypeFlavor.READONLY_VOLATILE_STRING),
|
||||
//
|
||||
BRIDGE_STATUS(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.CHANNEL_BRIDGE_STATUS, TypeFlavor.READONLY_VOLATILE_STRING),
|
||||
BRIDGE_DOWNTIME(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.CHANNEL_BRIDGE_DOWNTIME, TypeFlavor.READONLY_VOLATILE_NUMBER),
|
||||
BRIDGE_RELOAD(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.CHANNEL_BRIDGE_RELOAD, TypeFlavor.INITIATOR),
|
||||
BRIDGE_DO_DETECTION(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.CHANNEL_BRIDGE_DO_DETECTION, TypeFlavor.INITIATOR),
|
||||
|
||||
BRIDGE_FIRMWARE(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_FIRMWARE, TypeFlavor.PROPERTY),
|
||||
BRIDGE_IPADDRESS(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_IPADDRESS, TypeFlavor.PROPERTY),
|
||||
BRIDGE_SUBNETMASK(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_SUBNETMASK, TypeFlavor.PROPERTY),
|
||||
BRIDGE_DEFAULTGW(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_DEFAULTGW, TypeFlavor.PROPERTY),
|
||||
BRIDGE_DHCP(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_DHCP, TypeFlavor.PROPERTY),
|
||||
BRIDGE_WLANSSID(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_WLANSSID, TypeFlavor.PROPERTY),
|
||||
BRIDGE_WLANPASSWORD(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_WLANPASSWORD, TypeFlavor.PROPERTY),
|
||||
BRIDGE_PRODUCTS(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_PRODUCTS, TypeFlavor.PROPERTY),
|
||||
BRIDGE_SCENES(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_SCENES, TypeFlavor.PROPERTY),
|
||||
BRIDGE_CHECK(VeluxBindingConstants.THING_TYPE_BRIDGE, VeluxBindingConstants.PROPERTY_BRIDGE_CHECK, TypeFlavor.PROPERTY),
|
||||
//
|
||||
ACTUATOR_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR, VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
ACTUATOR_STATE(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR, VeluxBindingConstants.CHANNEL_ACTUATOR_STATE, TypeFlavor.MANIPULATOR_SWITCH),
|
||||
ACTUATOR_LIMIT_MINIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR, VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MINIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
ACTUATOR_LIMIT_MAXIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ACTUATOR, VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MAXIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
//
|
||||
ROLLERSHUTTER_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
ROLLERSHUTTER_LIMIT_MINIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MINIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
ROLLERSHUTTER_LIMIT_MAXIMUM(VeluxBindingConstants.THING_TYPE_VELUX_ROLLERSHUTTER,VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MAXIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
//
|
||||
WINDOW_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW, VeluxBindingConstants.CHANNEL_ACTUATOR_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
WINDOW_LIMIT_MINIMUM(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW, VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MINIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
WINDOW_LIMIT_MAXIMUM(VeluxBindingConstants.THING_TYPE_VELUX_WINDOW, VeluxBindingConstants.CHANNEL_ACTUATOR_LIMIT_MAXIMUM,TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
//
|
||||
SCENE_ACTION(VeluxBindingConstants.THING_TYPE_VELUX_SCENE, VeluxBindingConstants.CHANNEL_SCENE_ACTION, TypeFlavor.INITIATOR),
|
||||
SCENE_SILENTMODE(VeluxBindingConstants.THING_TYPE_VELUX_SCENE, VeluxBindingConstants.CHANNEL_SCENE_SILENTMODE, TypeFlavor.WRITEONLY_VOLATILE_SWITCH),
|
||||
//
|
||||
VSHUTTER_POSITION(VeluxBindingConstants.THING_TYPE_VELUX_VSHUTTER, VeluxBindingConstants.CHANNEL_VSHUTTER_POSITION, TypeFlavor.MANIPULATOR_SHUTTER),
|
||||
;
|
||||
// @formatter:on
|
||||
|
||||
private enum TypeFlavor {
|
||||
/**
|
||||
* Used to present read-only non-volatile configuration parameters as StringItem.
|
||||
*/
|
||||
READONLY_STATIC_STRING,
|
||||
/**
|
||||
* Used to present read-only non-volatile configuration parameters as SwitchItem.
|
||||
*/
|
||||
READONLY_STATIC_SWITCH,
|
||||
/**
|
||||
* Used to present volatile configuration parameters as StringItem.
|
||||
*/
|
||||
READONLY_VOLATILE_STRING,
|
||||
/**
|
||||
* Used to present volatile configuration parameters as NumberItem.
|
||||
*/
|
||||
READONLY_VOLATILE_NUMBER,
|
||||
/**
|
||||
* Used to present volatile configuration parameters as NumberItem.
|
||||
*/
|
||||
WRITEONLY_VOLATILE_SWITCH,
|
||||
/**
|
||||
* Used to present volatile configuration parameters as SwitchItem.
|
||||
*/
|
||||
READWRITE_VOLATILE_SWITCH,
|
||||
/**
|
||||
* Used to initiate an action.
|
||||
*/
|
||||
INITIATOR,
|
||||
/**
|
||||
* Used to manipulate an actuator.
|
||||
*/
|
||||
MANIPULATOR_SHUTTER,
|
||||
/**
|
||||
* Used to manipulate an actuator.
|
||||
*/
|
||||
MANIPULATOR_SWITCH,
|
||||
/**
|
||||
* Used to present read-only non-volatile configuration parameter (being handled as property of aThing).
|
||||
*/
|
||||
PROPERTY,
|
||||
/**
|
||||
* Used to define an UNUSABLE entry.
|
||||
*/
|
||||
UNUSABLE,
|
||||
}
|
||||
|
||||
/*
|
||||
* ***************************
|
||||
* ***** Private Objects *****
|
||||
*/
|
||||
|
||||
private ThingTypeUID thingIdentifier;
|
||||
private String channelIdentifier;
|
||||
private Class<? extends GenericItem> itemClass;
|
||||
private boolean itemIsReadable;
|
||||
private boolean itemIsWritable;
|
||||
private boolean itemIsExecutable;
|
||||
private boolean itemIsToBeRefreshed;
|
||||
private int itemsRefreshDivider;
|
||||
private boolean itemIsChannel;
|
||||
private boolean itemIsProperty;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(VeluxItemType.class);
|
||||
|
||||
private static final int REFRESH_CYCLE_FIRST_TIME = 0;
|
||||
private static final int REFRESH_ONCE_A_DAY = 8640;
|
||||
private static final int REFRESH_EACH_HOUR = 360;
|
||||
private static final int REFRESH_EACH_MINUTE = 6;
|
||||
private static final int REFRESH_EVERY_CYCLE = 1;
|
||||
|
||||
/*
|
||||
* ************************
|
||||
* ***** Constructors *****
|
||||
*/
|
||||
|
||||
VeluxItemType(ThingTypeUID thingIdentifier, String channelIdentifier, TypeFlavor typeFlavor) {
|
||||
this.thingIdentifier = thingIdentifier;
|
||||
this.channelIdentifier = channelIdentifier;
|
||||
this.itemIsChannel = true;
|
||||
this.itemIsProperty = false;
|
||||
switch (typeFlavor) {
|
||||
case READONLY_STATIC_STRING:
|
||||
this.itemClass = StringItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = false;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
|
||||
break;
|
||||
case READONLY_STATIC_SWITCH:
|
||||
this.itemClass = SwitchItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = false;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
|
||||
break;
|
||||
|
||||
case READONLY_VOLATILE_STRING:
|
||||
this.itemClass = StringItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = false;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
|
||||
break;
|
||||
case READONLY_VOLATILE_NUMBER:
|
||||
this.itemClass = NumberItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = false;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_EVERY_CYCLE;
|
||||
break;
|
||||
case WRITEONLY_VOLATILE_SWITCH:
|
||||
this.itemClass = SwitchItem.class;
|
||||
this.itemIsReadable = false;
|
||||
this.itemIsWritable = true;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = false;
|
||||
this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
|
||||
break;
|
||||
case READWRITE_VOLATILE_SWITCH:
|
||||
this.itemClass = SwitchItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = true;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_EVERY_CYCLE;
|
||||
break;
|
||||
|
||||
case INITIATOR:
|
||||
this.itemClass = SwitchItem.class;
|
||||
this.itemIsReadable = false;
|
||||
this.itemIsWritable = false;
|
||||
this.itemIsExecutable = true;
|
||||
this.itemIsToBeRefreshed = false;
|
||||
this.itemsRefreshDivider = 1;
|
||||
break;
|
||||
|
||||
case MANIPULATOR_SHUTTER:
|
||||
this.itemClass = RollershutterItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = true;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
|
||||
break;
|
||||
|
||||
case MANIPULATOR_SWITCH:
|
||||
this.itemClass = SwitchItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = true;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_EACH_MINUTE;
|
||||
break;
|
||||
|
||||
case PROPERTY:
|
||||
this.itemClass = StringItem.class;
|
||||
this.itemIsReadable = true;
|
||||
this.itemIsWritable = false;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = true;
|
||||
this.itemsRefreshDivider = REFRESH_EACH_HOUR;
|
||||
this.itemIsChannel = false;
|
||||
this.itemIsProperty = true;
|
||||
break;
|
||||
|
||||
case UNUSABLE:
|
||||
default:
|
||||
this.itemClass = StringItem.class;
|
||||
this.itemIsReadable = false;
|
||||
this.itemIsWritable = false;
|
||||
this.itemIsExecutable = false;
|
||||
this.itemIsToBeRefreshed = false;
|
||||
this.itemsRefreshDivider = REFRESH_ONCE_A_DAY;
|
||||
this.itemIsChannel = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ********************************
|
||||
* ***** Class access methods *****
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.thingIdentifier + "/" + this.channelIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query Identifier on this type of item.
|
||||
*
|
||||
* @return <b>thingIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}
|
||||
* return
|
||||
*/
|
||||
public ThingTypeUID getThingTypeUID() {
|
||||
return this.thingIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query common (channel/property) identifier on this type of item.
|
||||
*
|
||||
* @return <b>channelIdentifier</b> of type String describing the value of the enum {@link VeluxItemType}.
|
||||
*/
|
||||
public String getIdentifier() {
|
||||
return this.channelIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query the appropriate type of item.
|
||||
*
|
||||
* @return <b>itemClass</b> of type Item describing the possible type of this item.
|
||||
*/
|
||||
public Class<? extends GenericItem> getItemClass() {
|
||||
return this.itemClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query Read possibility on this type of item.
|
||||
*
|
||||
* @return <b>itemIsReadable</b> of type boolean describing the ability to perform a write operation.
|
||||
*/
|
||||
public boolean isReadable() {
|
||||
return this.itemIsReadable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query Write possibility on this type of item.
|
||||
*
|
||||
* @return <b>itemIsWritable</b> of type boolean describing the ability to perform a write operation.
|
||||
*/
|
||||
public boolean isWritable() {
|
||||
return this.itemIsWritable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query Execute possibility on this type of item.
|
||||
*
|
||||
* @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
|
||||
*/
|
||||
public boolean isExecutable() {
|
||||
return this.itemIsExecutable;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query the need of refresh on this type of item.
|
||||
*
|
||||
* @return <b>isExecute</b> of type boolean describing the ability to perform a write operation.
|
||||
*/
|
||||
public boolean isToBeRefreshed() {
|
||||
return this.itemIsToBeRefreshed;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query the refreshMSecs interval on this type of item.
|
||||
*
|
||||
* @return <b>refreshDivider</b> of type int describing the factor.
|
||||
*/
|
||||
public int getRefreshDivider() {
|
||||
return this.itemsRefreshDivider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query the type of this item.
|
||||
*
|
||||
* @return <b>isChannel</b> of type boolean describing the need to be handled as channel.
|
||||
*/
|
||||
public boolean isChannel() {
|
||||
return this.itemIsChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to query the type of this item.
|
||||
*
|
||||
* @return <b>itemIsProperty</b> of type boolean describing the need to be handled as property.
|
||||
*/
|
||||
public boolean isProperty() {
|
||||
return this.itemIsProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to find an enum by itemTypeName.
|
||||
*
|
||||
* @param itemTypeName as name of requested Thing of type String.
|
||||
*
|
||||
* @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
|
||||
*/
|
||||
public VeluxItemType getByString(String itemTypeName) {
|
||||
try {
|
||||
return VeluxItemType.valueOf(itemTypeName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to find an enum by name.
|
||||
*
|
||||
* @param thingIdentifier as name of requested Thing of type String.
|
||||
* @param channelIdentifier as name of requested Channel of type String.
|
||||
*
|
||||
* @return <b>veluxItemType</b> of type VeluxItemType describing the appropriate enum.
|
||||
*/
|
||||
public static VeluxItemType getByThingAndChannel(ThingTypeUID thingIdentifier, String channelIdentifier) {
|
||||
for (VeluxItemType v : VeluxItemType.values()) {
|
||||
if (thingIdentifier.equals(v.thingIdentifier) && channelIdentifier.equals(v.channelIdentifier)) {
|
||||
LOGGER.trace("getByThingAndChannel({},{}) returns enum {}.", thingIdentifier, channelIdentifier, v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
LOGGER.trace("getByThingAndChannel({},{}) returns enum UNKNOWN.", thingIdentifier, channelIdentifier);
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to find similar enum entries by thingIdentifier.
|
||||
*
|
||||
* @param thingIdentifier as name of requested Thing of type String.
|
||||
*
|
||||
* @return <b>listOfveluxItemType</b> of type List of VeluxItemType containing all similar enum entries.
|
||||
*/
|
||||
public static List<VeluxItemType> getPropertyEntriesByThing(ThingTypeUID thingIdentifier) {
|
||||
List<VeluxItemType> list = new ArrayList<>();
|
||||
for (VeluxItemType v : VeluxItemType.values()) {
|
||||
if (thingIdentifier.equals(v.thingIdentifier) && v.itemIsProperty) {
|
||||
list.add(v);
|
||||
}
|
||||
}
|
||||
LOGGER.trace("getPropertyEntriesByThing({}) returns {}.", thingIdentifier, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function: Calculate modulo.
|
||||
*
|
||||
* @param a as dividend.
|
||||
* @param b as divisor.
|
||||
*
|
||||
* @return <b>true</b> if zero is remainder after division.
|
||||
*/
|
||||
private static boolean isModulo(int a, int b) {
|
||||
return (a % b) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link VeluxItemType} access method to determine the necessity of being refreshed
|
||||
* within the current refresh cycle.
|
||||
*
|
||||
* @param refreshCycleCounter as identification of the refresh round.
|
||||
* @param thingIdentifier as name of requested Thing.
|
||||
* @param channelIdentifier as name of requested Channel.
|
||||
*
|
||||
* @return <b>boolean</b> value which expresses the need.
|
||||
*/
|
||||
public static boolean isToBeRefreshedNow(int refreshCycleCounter, ThingTypeUID thingIdentifier,
|
||||
String channelIdentifier) {
|
||||
VeluxItemType itemType = getByThingAndChannel(thingIdentifier, channelIdentifier);
|
||||
|
||||
if (itemType == VeluxItemType.UNKNOWN) {
|
||||
LOGGER.warn("isToBeRefreshedNow({},{},{}): returning false, as item is not found.", refreshCycleCounter,
|
||||
thingIdentifier, channelIdentifier);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((refreshCycleCounter == REFRESH_CYCLE_FIRST_TIME) && (itemType.isReadable()))
|
||||
|| (itemType.isToBeRefreshed())) {
|
||||
if ((refreshCycleCounter == REFRESH_CYCLE_FIRST_TIME)
|
||||
|| (isModulo(refreshCycleCounter, itemType.getRefreshDivider()))) {
|
||||
LOGGER.trace("isToBeRefreshedNow(): returning true, as item is to be refreshed, now.");
|
||||
return true;
|
||||
} else {
|
||||
LOGGER.trace("isToBeRefreshedNow(): returning false, as refresh cycle has not yet come for this item.");
|
||||
}
|
||||
} else {
|
||||
LOGGER.trace("isToBeRefreshedNow(): returning false, as item is not refreshable.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 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.velux.internal;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This represents the configuration of a openHAB item that is binded to a Velux
|
||||
* KLF200 Gateway. It contains the following information:
|
||||
*
|
||||
* <ul>
|
||||
* <li><B>bindingItemType</B>
|
||||
* <P>
|
||||
* accessable via
|
||||
* {@link org.openhab.binding.velux.internal.VeluxRSBindingConfig#getBindingItemType
|
||||
* getBindingItemType} as representation of the Velux device is filed in the Velux bridge.</li>
|
||||
* <li><B>bindingConfig</B>
|
||||
* <P>
|
||||
* accessable via
|
||||
* {@link org.openhab.binding.velux.internal.VeluxRSBindingConfig#getBindingConfig getBindingConfig} containing the
|
||||
* device-specific binding configuration
|
||||
* as declared in the binding configuration (possibly adapted by preprocessing).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxRSBindingConfig extends VeluxBindingConfig {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxRSBindingConfig.class);
|
||||
|
||||
/**
|
||||
* The ascending sorted list of generic Objects indexed by an Integer
|
||||
*/
|
||||
private SortedMap<Integer, String> mapAscending = new TreeMap<>(new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* The descending sorted list of generic Objects indexed by an Integer
|
||||
*/
|
||||
private SortedMap<Integer, String> mapDescending = new TreeMap<>(new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o2.compareTo(o1);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The sorted list of generic Objects indexed by an Integer
|
||||
*/
|
||||
private Integer rollershutterLevel = 0;
|
||||
|
||||
private void veluxRollershutterBindingParser(final String channelValue) {
|
||||
logger.debug("VeluxRollershutterBindingParser({}) called.", channelValue);
|
||||
|
||||
String[] channelValueParts = channelValue.trim().split(VeluxBindingConstants.BINDING_VALUES_SEPARATOR);
|
||||
if ((channelValueParts.length % 2) != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Velux Rollershutter binding must contain an even number of configuration parts separated by '"
|
||||
+ VeluxBindingConstants.BINDING_VALUES_SEPARATOR + "' (ignoring binding '" + channelValue
|
||||
+ "').");
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < channelValueParts.length; idx++) {
|
||||
logger.trace("VeluxRollershutterBindingParser() processing {}.", channelValueParts[idx]);
|
||||
|
||||
int degree;
|
||||
try {
|
||||
degree = Integer.parseInt(channelValueParts[idx]);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Velux Rollershutter binding must contain an even number of configuration parts separated by '"
|
||||
+ VeluxBindingConstants.BINDING_VALUES_SEPARATOR
|
||||
+ "' each consisting of a shutter level followed by a scene name (ignoring binding '"
|
||||
+ channelValue + "').");
|
||||
}
|
||||
idx++;
|
||||
mapAscending.put(degree, channelValueParts[idx]);
|
||||
mapDescending.put(degree, channelValueParts[idx]);
|
||||
}
|
||||
for (Map.Entry<Integer, String> nextEntry : mapAscending.entrySet()) {
|
||||
logger.trace("VeluxRollershutterBindingParser({},{}) processed.", nextEntry.getKey(), nextEntry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor of the VeluxBindingConfig.
|
||||
*
|
||||
* @param bindingItemType
|
||||
* The Velux item type {@link org.openhab.binding.velux.internal.VeluxItemType
|
||||
* VeluxItemType} which the Velux device is filed in the Velux bridge.
|
||||
* @param channelValue
|
||||
* The optional configuration type of the Velux binding.
|
||||
* @param rollershutterLevel of type Integer with current position.
|
||||
*/
|
||||
public VeluxRSBindingConfig(VeluxItemType bindingItemType, String channelValue, Integer rollershutterLevel) {
|
||||
super(bindingItemType, channelValue);
|
||||
logger.trace("VeluxRSBindingConfig(constructor:{},{},{}) called.", bindingItemType, channelValue,
|
||||
rollershutterLevel);
|
||||
this.rollershutterLevel = rollershutterLevel;
|
||||
veluxRollershutterBindingParser(channelValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor of the VeluxBindingConfig.
|
||||
*
|
||||
* @param bindingItemType
|
||||
* The Velux item type {@link org.openhab.binding.velux.internal.VeluxItemType
|
||||
* VeluxItemType} which the Velux device is filed in the Velux bridge.
|
||||
* @param channelValue
|
||||
* The optional configuration type of the Velux binding.
|
||||
*/
|
||||
public VeluxRSBindingConfig(VeluxItemType bindingItemType, String channelValue) {
|
||||
super(bindingItemType, channelValue);
|
||||
logger.trace("VeluxRSBindingConfig(constructor:{},{}) called.", bindingItemType, channelValue);
|
||||
veluxRollershutterBindingParser(channelValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next shutter level for an DOWN command w/ adjusting the actual position.
|
||||
*
|
||||
* @return <b>rollershutterLevel</b> of type Integer with next position after DOWN command.
|
||||
*/
|
||||
public Integer getNextAscendingLevel() {
|
||||
logger.trace("getNextAscendingLevel() called.");
|
||||
|
||||
for (Map.Entry<Integer, String> nextEntry : mapAscending.entrySet()) {
|
||||
if (nextEntry.getKey() > this.rollershutterLevel) {
|
||||
this.rollershutterLevel = nextEntry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
logger.trace("getNextAscendingLevel() returning {}.", this.rollershutterLevel);
|
||||
return this.rollershutterLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next shutter level for an UP command w/ adjusting the actual position.
|
||||
*
|
||||
* @return <b>rollershutterLevel</b> of type Integer with next position after UP command.
|
||||
*/
|
||||
public Integer getNextDescendingLevel() {
|
||||
logger.trace("getNextDescendingLevel() called.");
|
||||
|
||||
for (Map.Entry<Integer, String> nextEntry : mapDescending.entrySet()) {
|
||||
if (nextEntry.getKey() < this.rollershutterLevel) {
|
||||
this.rollershutterLevel = nextEntry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
logger.trace("getNextDescendingLevel() returning {}.", this.rollershutterLevel);
|
||||
return this.rollershutterLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current shutter level w/o adjusting the actual positioning.
|
||||
*
|
||||
* @return <b>rollershutterLevel</b> of type Integer with current position.
|
||||
*
|
||||
*/
|
||||
public Integer getLevel() {
|
||||
logger.trace("getLevel() returning {}.", this.rollershutterLevel);
|
||||
return this.rollershutterLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scene name of the current shutter level w/o adjusting the actual positioning.
|
||||
*
|
||||
* @return <B>sceneName</B>
|
||||
* A String describing the next scene.
|
||||
*/
|
||||
public String getSceneName() {
|
||||
return getSceneName(this.rollershutterLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scene name w/o adjusting the actual positioning.
|
||||
*
|
||||
* @param level
|
||||
* The shutter level is be queried.
|
||||
* @return <B>sceneName</B>
|
||||
* A String describing the next scene.
|
||||
*/
|
||||
public String getSceneName(Integer level) {
|
||||
logger.trace("getSceneName({}) called.", level);
|
||||
logger.trace("getSceneName() returning {}.", mapDescending.get(level));
|
||||
return mapDescending.get(level);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Login;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Logout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 2nd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* It provides methods for pre- and post-communication
|
||||
* as well as a common method for the real communication.
|
||||
* The following class access methods exist:
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridge#bridgeLogin} for pre-communication,</LI>
|
||||
* <LI>{@link VeluxBridge#bridgeLogout} for post-communication,</LI>
|
||||
* <LI>{@link VeluxBridge#bridgeCommunicate} as method for the common communication.</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* Each protocol-specific implementation provides a publicly visible
|
||||
* set of supported protocols as variable {@link #supportedProtocols}.
|
||||
* As root of several inheritance levels it predefines an
|
||||
* interfacing method {@link VeluxBridge#bridgeAPI} which
|
||||
* has to be implemented by any kind of protocol-specific
|
||||
* communication returning the appropriate base (1st) level
|
||||
* communication method as well as any other gateway
|
||||
* interaction with {@link #bridgeDirectCommunicate}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class VeluxBridge {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridge.class);
|
||||
|
||||
/*
|
||||
* ***************************
|
||||
* ***** Private Objects *****
|
||||
*/
|
||||
|
||||
private final String emptyAuthenticationToken = "";
|
||||
|
||||
// Type definitions, variables
|
||||
|
||||
/**
|
||||
* Support protocols for the concrete implementation.
|
||||
* <P>
|
||||
* For protocol-specific implementations this value has to be adapted along the inheritance i.e.
|
||||
* with the protocol-specific class values.
|
||||
*/
|
||||
public Set<String> supportedProtocols = Collections.emptySet();
|
||||
|
||||
/** BridgeCommunicationProtocol authentication token for Velux Bridge. */
|
||||
protected String authenticationToken = emptyAuthenticationToken;
|
||||
|
||||
/**
|
||||
* Handler to access global bridge instance methods
|
||||
*
|
||||
*/
|
||||
protected VeluxBridgeInstance bridgeInstance;
|
||||
|
||||
/*
|
||||
* ************************
|
||||
* ***** Constructors *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the binding-wide instance for dealing with common informations and
|
||||
* the Velux bridge connectivity settings by preparing the configuration settings with help
|
||||
* by VeluxBridgeConfiguration.
|
||||
*
|
||||
* @param bridgeInstance refers to the binding-wide instance for dealing for common informations
|
||||
* like existing actuators and predefined scenes.
|
||||
*/
|
||||
public VeluxBridge(VeluxBridgeInstance bridgeInstance) {
|
||||
logger.trace("VeluxBridge(constructor,bridgeInstance={}) called.", bridgeInstance);
|
||||
this.bridgeInstance = bridgeInstance;
|
||||
logger.trace("VeluxBridge(constructor) done.");
|
||||
}
|
||||
|
||||
// Destructor methods
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* <P>
|
||||
* Deinitializes the binding-wide instance.
|
||||
*
|
||||
*/
|
||||
public void shutdown() {
|
||||
logger.trace("shutdown() called.");
|
||||
}
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Determines whether the binding is already authenticated against the bridge so that
|
||||
* any other communication can occur without an additional care about authentication.
|
||||
* <P>
|
||||
* This method automatically decides on availability of the stored authentication
|
||||
* information {@link VeluxBridge#authenticationToken} whether a (re-)authentication is possible.
|
||||
*
|
||||
* @return true if the bridge is authenticated; false otherwise.
|
||||
*/
|
||||
private boolean isAuthenticated() {
|
||||
boolean success = (authenticationToken.length() > 0);
|
||||
logger.trace("isAuthenticated() returns {}.", success);
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares the binding as unauthenticated against the bridge so that the next
|
||||
* communication will take care about (re-)authentication.
|
||||
*/
|
||||
protected void resetAuthentication() {
|
||||
logger.trace("resetAuthentication() called.");
|
||||
authenticationToken = emptyAuthenticationToken;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an authorization request and communicate it with the <b>Velux</b> veluxBridge.
|
||||
* If login is successful, the returned authorization token will be stored within this class
|
||||
* for any further communication via {@link#bridgeCommunicate} up
|
||||
* to an authorization with method {@link VeluxBridge#bridgeLogout}.
|
||||
*
|
||||
* @return true if the login was successful, and false otherwise.
|
||||
*/
|
||||
public synchronized boolean bridgeLogin() {
|
||||
logger.trace("bridgeLogin() called.");
|
||||
|
||||
Login bcp = bridgeAPI().login();
|
||||
bcp.setPassword(bridgeInstance.veluxBridgeConfiguration().password);
|
||||
if (bridgeCommunicate(bcp, false)) {
|
||||
logger.trace("bridgeLogin(): communication succeeded.");
|
||||
if (bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("bridgeLogin(): storing authentication token for further access.");
|
||||
authenticationToken = bcp.getAuthToken();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an authenticated deauthorization request and communicate it with the <b>Velux</b> veluxBridge.
|
||||
* The authorization token stored in this class will be destroyed, so that the
|
||||
* next communication has to start with {@link VeluxBridge#bridgeLogin}.
|
||||
*
|
||||
* @return true if the logout was successful, and false otherwise.
|
||||
*/
|
||||
public synchronized boolean bridgeLogout() {
|
||||
logger.trace("bridgeLogout() called: emptying authentication token.");
|
||||
authenticationToken = "";
|
||||
|
||||
Logout bcp = bridgeAPI().logout();
|
||||
if (bridgeCommunicate(bcp, false)) {
|
||||
logger.trace("bridgeLogout(): communication succeeded.");
|
||||
if (bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("bridgeLogout(): logout successful.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a client/server communication towards <b>Velux</b> veluxBridge
|
||||
* based on the Basic I/O interface {@link VeluxBridge} and parameters
|
||||
* passed as arguments (see below) and provided by VeluxBridgeConfiguration.
|
||||
*
|
||||
* @param communication the intended communication,
|
||||
* that is request and response interactions as well as appropriate URL definition.
|
||||
* @param useAuthentication whether to use authenticated communication.
|
||||
* @return true if communication was successful, and false otherwise.
|
||||
*/
|
||||
private synchronized boolean bridgeCommunicate(BridgeCommunicationProtocol communication,
|
||||
boolean useAuthentication) {
|
||||
logger.trace("bridgeCommunicate({},{}authenticated) called.", communication.name(),
|
||||
useAuthentication ? "" : "un");
|
||||
|
||||
if (!isAuthenticated()) {
|
||||
if (useAuthentication) {
|
||||
logger.trace("bridgeCommunicate(): no auth token available, aborting.");
|
||||
return false;
|
||||
} else {
|
||||
logger.trace("bridgeCommunicate(): no auth token available, continuing.");
|
||||
}
|
||||
}
|
||||
return bridgeDirectCommunicate(communication, useAuthentication);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a client/server communication towards <b>Velux</b> Bridge
|
||||
* based on the Basic I/O interface {@link VeluxBridge} and parameters
|
||||
* passed as arguments (see below) and provided by VeluxBridgeConfiguration.
|
||||
* This method automatically decides to invoke a login communication before the
|
||||
* intended request if there has not been an authentication before.
|
||||
*
|
||||
* @param communication the intended communication, that is request and response interactions as well as appropriate
|
||||
* URL definition.
|
||||
* @return true if communication was successful, and false otherwise.
|
||||
*/
|
||||
public synchronized boolean bridgeCommunicate(BridgeCommunicationProtocol communication) {
|
||||
logger.trace("bridgeCommunicate({}) called.", communication.name());
|
||||
if (!isAuthenticated()) {
|
||||
bridgeLogin();
|
||||
}
|
||||
return bridgeCommunicate(communication, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last communication.
|
||||
* <P>
|
||||
* If possible, it should be overwritten by protocol specific implementation.
|
||||
* </P>
|
||||
*
|
||||
* @return timestamp (default zero).
|
||||
*/
|
||||
public long lastCommunication() {
|
||||
logger.trace("lastCommunication() returns zero.");
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last successful communication.
|
||||
* <P>
|
||||
* If possible, it should be overwritten by protocol specific implementation.
|
||||
* </P>
|
||||
*
|
||||
* @return timestamp (default zero).
|
||||
*/
|
||||
public long lastSuccessfulCommunication() {
|
||||
logger.trace("lastSuccessfulCommunication() returns zero.");
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides information about the base-level communication method and
|
||||
* any kind of available gateway interaction.
|
||||
* <P>
|
||||
* For protocol-specific implementations this method has to be overwritten along the inheritance i.e.
|
||||
* with the protocol-specific class implementations.
|
||||
*
|
||||
* @return bridgeAPI of type {@link org.openhab.binding.velux.internal.bridge.common.BridgeAPI BridgeAPI}.
|
||||
*/
|
||||
public abstract BridgeAPI bridgeAPI();
|
||||
|
||||
/**
|
||||
* Initializes a client/server communication towards <b>Velux</b> veluxBridge
|
||||
* based on the protocol-specific implementations with common parameters
|
||||
* passed as arguments (see below) and provided by VeluxBridgeConfiguration.
|
||||
* <P>
|
||||
* For protocol-specific implementations this method has to be overwritten along the inheritance i.e.
|
||||
* with the protocol-specific class implementations.
|
||||
*
|
||||
* @param communication Structure of interface type {@link BridgeCommunicationProtocol} describing the
|
||||
* intended communication.
|
||||
* @param useAuthentication boolean flag to decide whether to use authenticated communication.
|
||||
* @return <b>success</b> of type boolean which signals the success of the communication.
|
||||
*/
|
||||
protected abstract boolean bridgeDirectCommunicate(BridgeCommunicationProtocol communication,
|
||||
boolean useAuthentication);
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProduct;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProducts;
|
||||
import org.openhab.binding.velux.internal.things.VeluxExistingProducts;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeActuators} represents a complete set of transactions
|
||||
* for retrieving of any available products into a structure {@link #channel}
|
||||
* defined on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getProducts} for retrieval of information from the bridge.
|
||||
* <LI>{@link #getChannel} for accessing the retrieved information.
|
||||
* <LI>{@link #autoRefresh} for retrieval of information for supporting the update the corresponding openHAB items.
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxProduct
|
||||
* @see VeluxExistingProducts
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeActuators {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeActuators.class);
|
||||
|
||||
// Configuration constants
|
||||
|
||||
/**
|
||||
* Limitation of Discovery on parts of the System table
|
||||
*
|
||||
* Whereas the parameter {@link org.openhab.binding.velux.internal.things.VeluxKLFAPI#KLF_SYSTEMTABLE_MAX}
|
||||
* represents the
|
||||
* maximum size of the system table in general, for speed up of the discovery process
|
||||
* a binding-internal limitation of number of possible devices is introduced.
|
||||
*/
|
||||
private static final int VELUXBINDING_SYSTEMTABLE_MAX = 16;
|
||||
|
||||
// Type definitions, class-internal variables
|
||||
|
||||
/**
|
||||
* Actuator information consisting of:
|
||||
* <ul>
|
||||
* <li>isRetrieved (boolean),
|
||||
* <li>existingProducts ({@link VeluxExistingProducts}).
|
||||
* </ul>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Channel {
|
||||
public VeluxExistingProducts existingProducts = new VeluxExistingProducts();
|
||||
}
|
||||
|
||||
private Channel channel;
|
||||
|
||||
// Constructor methods
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the internal data structure {@link #channel} of Velux actuators/products,
|
||||
* which is publicly accessible via the method {@link #getChannel()}.
|
||||
*/
|
||||
public VeluxBridgeActuators() {
|
||||
logger.trace("VeluxBridgeActuators(constructor) called.");
|
||||
channel = new Channel();
|
||||
logger.trace("VeluxBridgeActuators(constructor) done.");
|
||||
}
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Provide access to the internal structure of actuators/products.
|
||||
*
|
||||
* @return a channel describing the overall actuator situation.
|
||||
*/
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login into bridge, retrieve all products and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}. The results
|
||||
* are stored within {@link org.openhab.binding.velux.internal.things.VeluxExistingProducts
|
||||
* VeluxExistingProducts}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge (communication) handler.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean getProducts(VeluxBridge bridge) {
|
||||
logger.trace("getProducts() called.");
|
||||
|
||||
GetProducts bcp = bridge.bridgeAPI().getProducts();
|
||||
GetProduct bcpSbS = bridge.bridgeAPI().getProduct();
|
||||
if ((bcpSbS != null) && !bridge.bridgeInstance.veluxBridgeConfiguration().isBulkRetrievalEnabled) {
|
||||
logger.trace("getProducts() working on step-by-step retrieval.");
|
||||
for (int nodeId = 0; nodeId < VeluxKLFAPI.KLF_SYSTEMTABLE_MAX
|
||||
&& nodeId < VELUXBINDING_SYSTEMTABLE_MAX; nodeId++) {
|
||||
logger.trace("getProducts() working on product number {}.", nodeId);
|
||||
bcpSbS.setProductId(nodeId);
|
||||
if (bridge.bridgeCommunicate(bcpSbS) && bcpSbS.isCommunicationSuccessful()) {
|
||||
VeluxProduct veluxProduct = bcpSbS.getProduct();
|
||||
if (bcpSbS.isCommunicationSuccessful()) {
|
||||
logger.debug("getProducts() found product {}.", veluxProduct);
|
||||
if (!channel.existingProducts.isRegistered(veluxProduct)) {
|
||||
channel.existingProducts.register(veluxProduct);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.trace("getProducts() working on bulk retrieval.");
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
for (VeluxProduct product : bcp.getProducts()) {
|
||||
logger.trace("getProducts() found product {} (type {}).", product.getProductName(),
|
||||
product.getProductType());
|
||||
if (!channel.existingProducts.isRegistered(product)) {
|
||||
logger.debug("getProducts() storing new product {}.", product);
|
||||
channel.existingProducts.register(product);
|
||||
} else {
|
||||
logger.debug("getProducts() storing updates for product {}.", product);
|
||||
channel.existingProducts.update(product);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.trace("getProducts() finished with failure.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
logger.debug("getProducts() finally has found products {}.", channel.existingProducts);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of an empty list of recognized products, the method will
|
||||
* initiate a product retrieval using {@link #getProducts(VeluxBridge)}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge (communication) handler.
|
||||
* @return true if at least one product was found, and false otherwise.
|
||||
*/
|
||||
public boolean autoRefresh(VeluxBridge bridge) {
|
||||
int numberOfActuators = channel.existingProducts.getNoMembers();
|
||||
if (numberOfActuators == 0) {
|
||||
logger.trace("autoRefresh(): is about to fetch existing products.");
|
||||
getProducts(bridge);
|
||||
}
|
||||
return (numberOfActuators > 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetDeviceStatus;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductDiscovery;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState.VeluxGatewaySubState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeDetectProducts} represents a complete set of transactions
|
||||
* for temporary activation of device detection mode on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It therefore provides a method:
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridgeDetectProducts#detectProducts} for starting the detection.
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeDetectProducts {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeDetectProducts.class);
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, start process to detect (new) products, loop until bridge is idle again and logout from bridge
|
||||
* based on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @return <b>success</b>
|
||||
* of type boolean describing the overall result of this interaction.
|
||||
*/
|
||||
public boolean detectProducts(VeluxBridge bridge) {
|
||||
logger.trace("detectProducts() called.");
|
||||
boolean success = false;
|
||||
|
||||
logger.trace("detectProducts() About to activate detection.");
|
||||
RunProductDiscovery bcp1 = bridge.bridgeAPI().runProductDiscovery();
|
||||
if (!(bridge.bridgeCommunicate(bcp1)) || (bcp1.isCommunicationSuccessful())) {
|
||||
while (true) {
|
||||
logger.trace("detectProducts() About to query detection status.");
|
||||
GetDeviceStatus bcp = bridge.bridgeAPI().getDeviceStatus();
|
||||
if (!(bridge.bridgeCommunicate(bcp)) || (bcp.isCommunicationSuccessful())) {
|
||||
logger.trace("detectProducts() finished with failure.");
|
||||
break;
|
||||
}
|
||||
VeluxGwState deviceStatus = bcp.getState();
|
||||
if (deviceStatus.getSubState() == (byte) VeluxGatewaySubState.GW_SS_P1.getStateValue()) {
|
||||
logger.trace("detectProducts() bridge is still busy.");
|
||||
} else if (deviceStatus.getSubState() == (byte) VeluxGatewaySubState.GW_SS_IDLE.getStateValue()) {
|
||||
logger.trace("detectProducts() bridge is idle again, now.");
|
||||
success = true;
|
||||
break;
|
||||
} else {
|
||||
logger.info("detectProducts() unknown devicestatus ({}) received.", deviceStatus);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.trace("detectProducts() activate detection finished with failure.");
|
||||
}
|
||||
|
||||
logger.debug("detectProducts() finished {}.", success ? "successfully" : "with failure");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductSearch;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeDeviceCheckLostNodes} represents a complete set of transactions
|
||||
* for querying device status on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It therefore provides a method
|
||||
* <UL>
|
||||
* <LI>{@link #initiate} for starting the detection.
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeDeviceCheckLostNodes {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeDeviceCheckLostNodes.class);
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, query the bridge for device status and logout from bridge
|
||||
* based on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
*/
|
||||
public void initiate(VeluxBridge bridge) {
|
||||
logger.trace("initiate() called.");
|
||||
RunProductSearch bcp = bridge.bridgeAPI().runProductSearch();
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("initiate() finished successfully.");
|
||||
} else {
|
||||
logger.trace("initiate() finished with failure.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetDeviceStatus;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeDeviceStatus} represents a complete set of transactions
|
||||
* for querying device status on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It therefore provides a method
|
||||
* <UL>
|
||||
* <LI>{@link #retrieve} for starting the detection.
|
||||
* <LI>{@link #getChannel} for accessing the retrieved information.
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeDeviceStatus {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeDeviceStatus.class);
|
||||
|
||||
// Type definitions, class-internal variables
|
||||
|
||||
/**
|
||||
* Bridge information consisting of:
|
||||
* <ul>
|
||||
* <li>{@link #isRetrieved} describing the retrieval state,
|
||||
* <li>{@link #gwState} containing the brief gateway state,
|
||||
* <li>{@link #gwStateDescription} containing the verbose gateway state.
|
||||
* </ul>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Channel {
|
||||
public boolean isRetrieved = false;
|
||||
public StringType gwState = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
public StringType gwStateDescription = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
}
|
||||
|
||||
private Channel channel;
|
||||
|
||||
// Constructor methods
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the internal data structure {@link #channel} of Velux actuators/products,
|
||||
* which is publicly accessible via the method {@link #getChannel()}.
|
||||
*/
|
||||
public VeluxBridgeDeviceStatus() {
|
||||
logger.trace("VeluxBridgeDeviceStatus(constructor) called.");
|
||||
channel = new Channel();
|
||||
}
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Provide access to the internal structure of the device status.
|
||||
*
|
||||
* @return a channel describing the overall actual device status.
|
||||
*/
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete workflow for retrieving the firmware version, consisting of Login into bridge, querying the firmware
|
||||
* version and logout from bridge based on a well-prepared environment of a {@link VeluxBridgeProvider}, where the
|
||||
* results are stored in {@link VeluxBridgeDeviceStatus#channel}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @return <b>channel</b> of type {@link VeluxBridgeDeviceStatus.Channel} describing the overall result of this
|
||||
* interaction.
|
||||
*/
|
||||
public Channel retrieve(VeluxBridge bridge) {
|
||||
logger.trace("retrieve() called. About to query device status.");
|
||||
GetDeviceStatus bcp = bridge.bridgeAPI().getDeviceStatus();
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
VeluxGwState state = bcp.getState();
|
||||
channel.gwState = new StringType(state.toString());
|
||||
channel.gwStateDescription = new StringType(state.toDescription());
|
||||
channel.isRetrieved = true;
|
||||
logger.trace("retrieve() finished successfully with result {}.", state.toDescription());
|
||||
} else {
|
||||
channel.isRetrieved = false;
|
||||
logger.trace("retrieve() finished with failure.");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetFirmware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeGetFirmware} represents a complete set of transactions
|
||||
* for retrieving of firmware version string on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #retrieve} for retrieval of information.
|
||||
* <LI>{@link #getChannel} for accessing the retrieved information.
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeGetFirmware {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeGetFirmware.class);
|
||||
|
||||
// Type definitions, class-internal variables
|
||||
|
||||
/**
|
||||
* Bridge information consisting of:
|
||||
* <ul>
|
||||
* <li>isRetrieved (boolean flag),
|
||||
* <li>firmwareVersion (human readable String).
|
||||
* </ul>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Channel {
|
||||
public boolean isRetrieved = false;
|
||||
public StringType firmwareVersion = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
}
|
||||
|
||||
private Channel channel;
|
||||
|
||||
// Constructor methods
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the internal data structure {@link #channel} of Velux firmware information,
|
||||
* which is publicly accessible via the method {@link #getChannel()}.
|
||||
*/
|
||||
public VeluxBridgeGetFirmware() {
|
||||
logger.trace("VeluxBridgeGetFirmware(constructor) called.");
|
||||
channel = new Channel();
|
||||
}
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Provide access to the internal structure of actuators/products.
|
||||
*
|
||||
* @return {@link Channel} describing the overall actuator situation.
|
||||
*/
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete workflow for retrieving the firmware version, consisting of Login into bridge, querying the firmware
|
||||
* version and logout from bridge based on a well-prepared environment of a {@link VeluxBridgeProvider}, where the
|
||||
* results are stored in {@link VeluxBridgeGetFirmware#channel}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @return <b>channel</b> of type {@link VeluxBridgeGetFirmware.Channel} describing the overall result of this
|
||||
* interaction.
|
||||
*/
|
||||
public Channel retrieve(VeluxBridge bridge) {
|
||||
logger.trace("retrieve() called.");
|
||||
|
||||
GetFirmware bcp = bridge.bridgeAPI().getFirmware();
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
this.channel.firmwareVersion = new StringType(bcp.getFirmware().getfirmwareVersion());
|
||||
this.channel.isRetrieved = true;
|
||||
logger.trace("retrieve() found successfully firmware {}.", this.channel.firmwareVersion);
|
||||
} else {
|
||||
this.channel.isRetrieved = false;
|
||||
logger.trace("retrieve() finished with failure.");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetHouseStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeGetHouseStatus} represents a complete set of transactions
|
||||
* for receiving the current state by the <B>House Status Monitor</B> on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* The HSM is responsible for continuous updates towards the communication initiator
|
||||
* about any changes of actuator states.
|
||||
* <P>
|
||||
* It therefore provides a method {@link VeluxBridgeGetHouseStatus#evaluateState} for check of availability of House
|
||||
* Monitoring Messages.
|
||||
* Any parameters are controlled by {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeGetHouseStatus {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeGetHouseStatus.class);
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, fetch the HSM state and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @return true if successful or false otherwise.
|
||||
*/
|
||||
public boolean evaluateState(VeluxBridge bridge) {
|
||||
logger.trace("evaluateState() called.");
|
||||
|
||||
boolean success = false;
|
||||
GetHouseStatus bcp = bridge.bridgeAPI().getHouseStatus();
|
||||
if (bcp != null) {
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
logger.debug("evaluateState() finished {}.", (success ? "successfully" : "with failure"));
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductPosition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeGetLimitation} represents a complete set of transactions
|
||||
* for retrieval of the limitation of an actuator defined on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It therefore provides the methods
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridgeGetLimitation#getMinimumLimitation} for querying the lower limitation of an actuator,</LI>
|
||||
* <LI>{@link VeluxBridgeGetLimitation#getMaximumLimitation} for querying the high limitation of an actuator.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* Any parameters are controlled by {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeGetLimitation {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeGetLimitation.class);
|
||||
|
||||
// Private Objects
|
||||
|
||||
private VeluxProductPosition limitationResult = VeluxProductPosition.UNKNOWN;
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, instruct the bridge to pass a command towards an actuator based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param nodeId Number of Actuator to be modified.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean getMinimumLimitation(VeluxBridge bridge, int nodeId) {
|
||||
logger.trace("getMinimumLimitation(nodeId={}) called.", nodeId);
|
||||
|
||||
boolean success = false;
|
||||
GetProductLimitation bcp = bridge.bridgeAPI().getProductLimitation();
|
||||
if (bcp != null) {
|
||||
bcp.setActuatorIdAndLimitationType(nodeId, true);
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
success = true;
|
||||
limitationResult = new VeluxProductPosition(bcp.getLimitation());
|
||||
}
|
||||
}
|
||||
logger.debug("getMinimumLimitation() finished {}.", (success ? "successfully" : "with failure"));
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login into bridge, instruct the bridge to pass a command towards an actuator based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param nodeId Number of Actuator to be modified.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean getMaximumLimitation(VeluxBridge bridge, int nodeId) {
|
||||
logger.trace("getMaximumLimitation(nodeId={}) called.", nodeId);
|
||||
|
||||
boolean success = false;
|
||||
GetProductLimitation bcp = bridge.bridgeAPI().getProductLimitation();
|
||||
if (bcp != null) {
|
||||
bcp.setActuatorIdAndLimitationType(nodeId, false);
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
success = true;
|
||||
limitationResult = new VeluxProductPosition(bcp.getLimitation());
|
||||
}
|
||||
}
|
||||
logger.debug("getMaximumLimitation() finished {}.", (success ? "successfully" : "with failure"));
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the limitation value.
|
||||
*
|
||||
* @return limitationResult of type VeluxProductPosition.
|
||||
*/
|
||||
public VeluxProductPosition getLimitation() {
|
||||
return limitationResult;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration;
|
||||
import org.openhab.binding.velux.internal.things.VeluxExistingProducts;
|
||||
import org.openhab.binding.velux.internal.things.VeluxExistingScenes;
|
||||
|
||||
/**
|
||||
* This interface is implemented by classes that deal with a specific Velux bridge and its configuration.
|
||||
* <P>
|
||||
* <B>Configuration</B>
|
||||
* </P>
|
||||
* <UL>
|
||||
* <LI>{@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration VeluxBridgeConfiguration}
|
||||
* for specification by a specific Velux bridge,</LI>
|
||||
* </UL>
|
||||
*
|
||||
* <P>
|
||||
* <B>Status</B>
|
||||
* </P>
|
||||
* Two methods for bridge-internal configuration retrieval:
|
||||
* <UL>
|
||||
* <LI>{@link #existingProducts}
|
||||
* for retrieving scene information,</LI>
|
||||
* <LI>{@link #existingScenes}
|
||||
* for retrieving product information.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface VeluxBridgeInstance {
|
||||
|
||||
/**
|
||||
* Bridge configuration
|
||||
*
|
||||
* @return VeluxBridgeConfiguration containing all bridge configuration settings.
|
||||
*/
|
||||
public VeluxBridgeConfiguration veluxBridgeConfiguration();
|
||||
|
||||
/**
|
||||
* Information retrieved by {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeActuators#getProducts}
|
||||
*
|
||||
* @return VeluxExistingProducts containing all registered products, or <B>null</B> in case of any error.
|
||||
*/
|
||||
public VeluxExistingProducts existingProducts();
|
||||
|
||||
/**
|
||||
* Information retrieved by {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeScenes#getScenes}
|
||||
*
|
||||
* @return VeluxExistingScenes containing all registered scenes, or <B>null</B> in case of any error.
|
||||
*/
|
||||
public VeluxExistingScenes existingScenes();
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetLANConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeLANConfig} represents a complete set of transactions
|
||||
* for retrieving the network configuration of the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #retrieve} for retrieval of information.
|
||||
* <LI>{@link #getChannel} for accessing the retrieved information.
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeLANConfig {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeLANConfig.class);
|
||||
|
||||
// Type definitions, class-internal variables
|
||||
|
||||
/**
|
||||
* IP Network configuration, consisting of:
|
||||
* <ul>
|
||||
* <li>isRetrieved (boolean flag),
|
||||
* <li>ipAddress,
|
||||
* <li>subnetMask,
|
||||
* <li>defaultGW and
|
||||
* <li>enabledDHCP.
|
||||
* </ul>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Channel {
|
||||
public boolean isRetrieved = false;
|
||||
public StringType openHABipAddress = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
public StringType openHABsubnetMask = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
public StringType openHABdefaultGW = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
public OnOffType openHABenabledDHCP = OnOffType.OFF;
|
||||
}
|
||||
|
||||
private Channel channel;
|
||||
|
||||
// Constructor methods
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the internal data structure {@link #channel} of Velux LAN information,
|
||||
* which is publicly accessible via the method {@link #getChannel()}.
|
||||
*/
|
||||
public VeluxBridgeLANConfig() {
|
||||
logger.trace("VeluxBridgeLANConfig(constructor) called.");
|
||||
channel = new Channel();
|
||||
}
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Provide access to the internal structure of LAN information.
|
||||
*
|
||||
* @return a channel describing the overall actual LAN information.
|
||||
*/
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete workflow for retrieving the network configuration, consisting of Login into bridge, querying
|
||||
* the network configuration and logout from bridge based on a well-prepared environment of a
|
||||
* {@link VeluxBridgeProvider}, where the results are stored within as well in
|
||||
* {@link VeluxBridgeLANConfig#channel}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @return <b>channel</b> of type {@link VeluxBridgeLANConfig.Channel} describing the overall result of this
|
||||
* interaction.
|
||||
*/
|
||||
public Channel retrieve(VeluxBridge bridge) {
|
||||
logger.trace("retrieve() called.");
|
||||
|
||||
GetLANConfig bcp = bridge.bridgeAPI().getLANConfig();
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("retrieve() found successfully configuration {}.", bcp.getLANConfig());
|
||||
channel.openHABipAddress = new StringType(bcp.getLANConfig().getIpAddress());
|
||||
channel.openHABsubnetMask = new StringType(bcp.getLANConfig().getSubnetMask());
|
||||
channel.openHABdefaultGW = new StringType(bcp.getLANConfig().getDefaultGW());
|
||||
channel.openHABenabledDHCP = bcp.getLANConfig().getDHCP() ? OnOffType.ON : OnOffType.OFF;
|
||||
channel.isRetrieved = true;
|
||||
} else {
|
||||
channel.isRetrieved = false;
|
||||
logger.trace("retrieve() finished with failure.");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
|
||||
/**
|
||||
* This interface is implemented by classes that provide general communication with the Velux bridge.
|
||||
* <P>
|
||||
* Communication
|
||||
* </P>
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridgeProvider#bridgeCommunicate} for generic communication,</LI>
|
||||
* <LI>{@link VeluxBridgeProvider#bridgeAPI} for access to all interaction/communication methods.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface VeluxBridgeProvider {
|
||||
|
||||
/**
|
||||
* Initializes a client/server communication towards <b>Velux</b> Bridge
|
||||
* based on the Basic I/O interface {@link VeluxBridge} and parameters
|
||||
* passed as arguments (see below) and provided by
|
||||
* {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
* This method automatically decides to invoke a login communication before the
|
||||
* intended request if there has not been an authentication before.
|
||||
*
|
||||
* @param communication {@link BridgeCommunicationProtocol} describing the intended
|
||||
* communication, that is request and response interactions as well as appropriate URL
|
||||
* definition.
|
||||
* @return true if communication was successful, and false otherwise.
|
||||
*/
|
||||
|
||||
public boolean bridgeCommunicate(BridgeCommunicationProtocol communication);
|
||||
|
||||
/**
|
||||
* Returns the class {@link BridgeAPI} which summarizes all interfacing methods.
|
||||
*
|
||||
* @return <b>BridgeAPI</b>
|
||||
* containing all API methods.
|
||||
*/
|
||||
public @Nullable BridgeAPI bridgeAPI();
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductCommand;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductPosition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeRunProductCommand} represents a complete set of transactions
|
||||
* for executing a scene defined on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides a method {@link VeluxBridgeRunProductCommand#sendCommand} for sending a parameter change command.
|
||||
* Any parameters are controlled by {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeRunProductCommand {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeRunProductCommand.class);
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, instruct the bridge to pass a command towards an actuator based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param nodeId Number of Actuator to be modified.
|
||||
* @param value Target value for Actuator main parameter.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean sendCommand(VeluxBridge bridge, int nodeId, VeluxProductPosition value) {
|
||||
logger.trace("sendCommand(nodeId={},value={}) called.", nodeId, value);
|
||||
|
||||
boolean success = false;
|
||||
RunProductCommand bcp = bridge.bridgeAPI().runProductCommand();
|
||||
if (bcp != null) {
|
||||
int veluxValue = value.getPositionAsVeluxType();
|
||||
|
||||
bcp.setNodeAndMainParameter(nodeId, veluxValue);
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
logger.debug("sendCommand() finished {}.", (success ? "successfully" : "with failure"));
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunScene;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeRunScene} represents a complete set of transactions
|
||||
* for executing a scene defined on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides a method {@link VeluxBridgeRunScene#execute} for execution of a scene.
|
||||
* Any parameters are controlled by {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeRunScene {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeRunScene.class);
|
||||
|
||||
/**
|
||||
* Login into bridge, execute a scene and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param sceneNo Number of scene to be executed.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean execute(VeluxBridge bridge, int sceneNo) {
|
||||
logger.trace("execute({}) called.", sceneNo);
|
||||
|
||||
RunScene bcp = bridge.bridgeAPI().runScene().setSceneId(sceneNo);
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.debug("execute() finished successfully.");
|
||||
return true;
|
||||
} else {
|
||||
logger.trace("execute() finished with failure.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login into bridge, execute a scene and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param sceneNo Number of scene to be executed.
|
||||
* @param velocity integer representing the velocity.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean execute(VeluxBridge bridge, int sceneNo, int velocity) {
|
||||
logger.trace("execute({},{}) called.", sceneNo, velocity);
|
||||
|
||||
RunScene bcp = bridge.bridgeAPI().runScene().setVelocity(velocity).setSceneId(sceneNo);
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.debug("execute() finished successfully.");
|
||||
return true;
|
||||
} else {
|
||||
logger.trace("execute() finished with failure.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetScenes;
|
||||
import org.openhab.binding.velux.internal.things.VeluxExistingScenes;
|
||||
import org.openhab.binding.velux.internal.things.VeluxScene;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeScenes} represents a complete set of transactions
|
||||
* for retrieving of any available scenes into a structure {@link VeluxExistingScenes}
|
||||
* defined on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getScenes} for retrieval of information.</LI>
|
||||
* <LI>{@link #getChannel} for accessing the retrieved information.</LI>
|
||||
* <LI>{@link #autoRefresh} for retrieval of information in case of an empty list of actuators.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see VeluxScene
|
||||
* @see VeluxExistingScenes
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeScenes {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeScenes.class);
|
||||
|
||||
// Type definitions, class-internal variables
|
||||
|
||||
/**
|
||||
* Actuator information consisting of:
|
||||
* <ul>
|
||||
* <li>existingScenes ({@link VeluxExistingScenes}).
|
||||
* </ul>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Channel {
|
||||
public VeluxExistingScenes existingScenes = new VeluxExistingScenes();
|
||||
}
|
||||
|
||||
private Channel channel;
|
||||
|
||||
// Constructor methods
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the internal data structure {@link #channel} of Velux scenes,
|
||||
* which is publicly accessible via the method {@link #getChannel()}.
|
||||
*/
|
||||
public VeluxBridgeScenes() {
|
||||
logger.trace("VeluxBridgeScenes(constructor) called.");
|
||||
channel = new Channel();
|
||||
}
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Provide access to the internal structure of scenes.
|
||||
*
|
||||
* @return a channel describing the overall scenes situation.
|
||||
*/
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login into bridge, retrieve all scenes and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}. The results
|
||||
* are stored within a public structure {@link org.openhab.binding.velux.internal.things.VeluxExistingScenes
|
||||
* VeluxExistingScenes}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge (communication) handler.
|
||||
* @return true if successful, or false otherwise.
|
||||
*/
|
||||
public boolean getScenes(VeluxBridge bridge) {
|
||||
logger.trace("getScenes() called.");
|
||||
|
||||
GetScenes bcp = bridge.bridgeAPI().getScenes();
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
for (VeluxScene scene : bcp.getScenes()) {
|
||||
logger.trace("getScenes() found scene {}.", scene.toString());
|
||||
|
||||
VeluxScene veluxScene = new VeluxScene(scene);
|
||||
logger.trace("getScenes() storing scene {}.", veluxScene);
|
||||
if (!channel.existingScenes.isRegistered(veluxScene)) {
|
||||
channel.existingScenes.register(veluxScene);
|
||||
}
|
||||
logger.trace("getScenes() stored scene {}.", veluxScene);
|
||||
}
|
||||
logger.debug("getScenes() finally has found scenes {}.", channel.existingScenes);
|
||||
return true;
|
||||
} else {
|
||||
logger.trace("getScenes() finished with failure.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In case of an empty list of recognized scenes, the method will
|
||||
* initiate a product retrieval using {@link #getScenes(VeluxBridge)}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge (communication) handler.
|
||||
* @return true if at lease one scene was found, and false otherwise.
|
||||
*/
|
||||
public boolean autoRefresh(VeluxBridge bridge) {
|
||||
if (channel.existingScenes.getNoMembers() == 0) {
|
||||
logger.trace("autoRefresh(): is about to fetch existing scenes.");
|
||||
getScenes(bridge);
|
||||
}
|
||||
return (channel.existingScenes.getNoMembers() > 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetHouseStatusMonitor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeSetHouseStatusMonitor} represents a complete set of transactions
|
||||
* for modifying the service state of the <B>House Status Monitor</B> on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* The HSM is responsible for continuous updates towards the communication initiator
|
||||
* about any changes of actuator states.
|
||||
* <P>
|
||||
* It therefore provides a method {@link VeluxBridgeSetHouseStatusMonitor#modifyHSM} for modifying the HSM settings.
|
||||
* Any parameters are controlled by {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeSetHouseStatusMonitor {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeSetHouseStatusMonitor.class);
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, modify HSM and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param enableService Flag whether the HSM should be activated.
|
||||
* @return true if successful or false otherwise.
|
||||
*/
|
||||
public boolean modifyHSM(VeluxBridge bridge, boolean enableService) {
|
||||
logger.trace("modifyHSM({}) called.", enableService);
|
||||
|
||||
boolean success = false;
|
||||
SetHouseStatusMonitor bcp = bridge.bridgeAPI().setHouseStatusMonitor();
|
||||
if (bcp != null) {
|
||||
bcp.serviceActivation(enableService);
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
logger.debug("modifyHSM() finished {}.", (success ? "successfully" : "with failure"));
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductPosition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeSetLimitation} represents a complete set of transactions
|
||||
* for modifying the limitation of an actuator defined on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It therefore provides the methods
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridgeSetLimitation#setMinimumLimitation} for modifying the lower limitation of an actuator,</LI>
|
||||
* <LI>{@link VeluxBridgeSetLimitation#setMaximumLimitation} for modifying the high limitation of an actuator.</LI>
|
||||
* </UL>
|
||||
* Any parameters are controlled by {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeSetLimitation {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeSetLimitation.class);
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, modify the scene parameters and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param nodeId Number of Actuator to be modified.
|
||||
* @param limitationMinimum new value for minimum limit.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean setMinimumLimitation(VeluxBridge bridge, int nodeId, VeluxProductPosition limitationMinimum) {
|
||||
logger.trace("setMinimumLimitation(nodeId={}, limitation={}) called.", nodeId, limitationMinimum);
|
||||
|
||||
SetProductLimitation bcp = bridge.bridgeAPI().setProductLimitation();
|
||||
if (bcp == null) {
|
||||
logger.info("setMinimumLimitation(): aborting processing as there is handler available.");
|
||||
return false;
|
||||
}
|
||||
bcp.setActuatorIdAndMinimumLimitation(nodeId, limitationMinimum.getPositionAsVeluxType());
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("setMinimumLimitation() finished successfully.");
|
||||
return true;
|
||||
}
|
||||
logger.trace("setMinimumLimitation() finished with failure.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login into bridge, modify the scene parameters and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param nodeId Number of Actuator to be modified.
|
||||
* @param limitationMaximum new value for maximum limit.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean setMaximumLimitation(VeluxBridge bridge, int nodeId, VeluxProductPosition limitationMaximum) {
|
||||
logger.trace("setMaximumLimitation(nodeId={}, limitation={}) called.", nodeId, limitationMaximum);
|
||||
|
||||
SetProductLimitation bcp = bridge.bridgeAPI().setProductLimitation();
|
||||
if (bcp == null) {
|
||||
logger.info("setMaximumLimitation(): aborting processing as there is handler available.");
|
||||
return false;
|
||||
}
|
||||
bcp.setActuatorIdAndMaximumLimitation(nodeId, limitationMaximum.getPositionAsVeluxType());
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("setMaximumLimitation() finished successfully.");
|
||||
return true;
|
||||
}
|
||||
logger.trace("setMaximumLimitation() finished with failure.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetSceneVelocity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeSetSceneVelocity} represents a complete set of transactions
|
||||
* for modifying the silent-mode of a scene defined on the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It therefore provides a method
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridgeSetSceneVelocity#setSilentMode} for modifying the behaviour of a scene.
|
||||
* </UL>
|
||||
* Any parameters are controlled by {@link org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration}.
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeSetSceneVelocity {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeSetSceneVelocity.class);
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Login into bridge, modify the scene parameters and logout from bridge based
|
||||
* on a well-prepared environment of a {@link VeluxBridgeProvider}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @param sceneNo Number of scene to be modified.
|
||||
* @param silentMode Mode of this mentioned scene.
|
||||
* @return true if successful, and false otherwise.
|
||||
*/
|
||||
public boolean setSilentMode(VeluxBridge bridge, int sceneNo, boolean silentMode) {
|
||||
logger.trace("setSilentMode({},{}) called.", sceneNo, silentMode);
|
||||
|
||||
SetSceneVelocity bcp = bridge.bridgeAPI().setSceneVelocity();
|
||||
bcp.setMode(sceneNo, silentMode);
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("setSilentMode() finished successfully.");
|
||||
return true;
|
||||
}
|
||||
logger.trace("setSilentMode() finished with failure.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetWLANConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeWLANConfig} represents a complete set of transactions
|
||||
* for retrieving the wireless network configuration of the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #retrieve} for retrieval of information.
|
||||
* <LI>{@link #getChannel} for accessing the retrieved information.
|
||||
* </UL>
|
||||
* <P>
|
||||
*
|
||||
* @see VeluxBridgeProvider
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeWLANConfig {
|
||||
private final Logger logger = LoggerFactory.getLogger(VeluxBridgeWLANConfig.class);
|
||||
|
||||
// Type definitions, class-internal variables
|
||||
|
||||
/**
|
||||
* Wireless network configuration, consisting of:
|
||||
* <ul>
|
||||
* <li>isRetrieved,
|
||||
* <li>wlanSSID,
|
||||
* <li>wlanPassword.
|
||||
* </ul>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Channel {
|
||||
public boolean isRetrieved = false;
|
||||
public StringType openHABwlanSSID = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
public StringType openHABwlanPassword = new StringType(VeluxBindingConstants.UNKNOWN);
|
||||
}
|
||||
|
||||
private Channel channel;
|
||||
|
||||
// Constructor methods
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the internal data structure {@link #channel} of Velux WLAN information,
|
||||
* which is publicly accessible via the method {@link #getChannel()}.
|
||||
*/
|
||||
public VeluxBridgeWLANConfig() {
|
||||
logger.trace("VeluxBridgeWLANConfig(constructor) called.");
|
||||
channel = new Channel();
|
||||
}
|
||||
|
||||
// Class access methods
|
||||
|
||||
/**
|
||||
* Provide access to the internal structure of WLAN information.
|
||||
*
|
||||
* @return a channel describing the overall WLAN situation.
|
||||
*/
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete workflow for retrieving the wireless network configuration, consisting of Login into bridge, querying
|
||||
* the network configuration and logout from bridge based on a well-prepared environment of a
|
||||
* {@link VeluxBridgeProvider}, where the results are stored within {@link VeluxBridgeWLANConfig#channel}.
|
||||
*
|
||||
* @param bridge Initialized Velux bridge handler.
|
||||
* @return <b>channel</b> - or null -
|
||||
* of type {@link VeluxBridgeWLANConfig.Channel} describing the overall result of this interaction.
|
||||
*/
|
||||
public Channel retrieve(VeluxBridge bridge) {
|
||||
logger.trace("retrieve() called.");
|
||||
|
||||
GetWLANConfig bcp = bridge.bridgeAPI().getWLANConfig();
|
||||
if (bridge.bridgeCommunicate(bcp) && bcp.isCommunicationSuccessful()) {
|
||||
logger.trace("retrieve() found successfully configuration {}.", bcp.getWLANConfig());
|
||||
channel.openHABwlanSSID = new StringType(bcp.getWLANConfig().getSSID());
|
||||
channel.openHABwlanPassword = new StringType(bcp.getWLANConfig().getPassword());
|
||||
channel.isRetrieved = true;
|
||||
} else {
|
||||
channel.isRetrieved = false;
|
||||
logger.trace("retrieve() finished with failure.");
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Definition of the 3rd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the one-and-only protocol specific 1st-level communication class.
|
||||
* Additionally it provides all methods for different gateway interactions.
|
||||
* <P>
|
||||
* The following class access methods exist:
|
||||
* <UL>
|
||||
* <LI>{@link #getDeviceStatus} for retrieving the bridge state (i.e. IDLE, BUSY, a.s.o),</LI>
|
||||
* <LI>{@link #getFirmware} for retrieving the firmware version of the bridge,</LI>
|
||||
* <LI>{@link #getHouseStatus} for retrieving the information about device state changes recognized by the
|
||||
* bridge,</LI>
|
||||
* <LI>{@link #getLANConfig} for retrieving the complete LAN information of the bridge,</LI>
|
||||
* <LI>{@link #getProduct} for retrieving the any information about a device behind the bridge,</LI>
|
||||
* <LI>{@link #getProductLimitation} for retrieving the limitation information about a device behind the
|
||||
* bridge,</LI>
|
||||
* <LI>{@link #getProducts} for retrieving the any information for all devices behind the bridge,</LI>
|
||||
* <LI>{@link #getScenes} for retrieving the any information for all scenes defined on the bridge,</LI>
|
||||
* <LI>{@link #getWLANConfig} for retrieving the complete WLAN information of the bridge,</LI>
|
||||
* <LI>{@link #login} for establishing a trusted connectivity by authentication,</LI>
|
||||
* <LI>{@link #logout} for tearing down the trusted connectivity by deauthentication,</LI>
|
||||
* <LI>{@link #runProductCommand} for manipulation of a device behind the bridge (i.e. instructing to
|
||||
* modify a position),</LI>
|
||||
* <LI>{@link #runProductDiscovery} for activation of learning mode of the bridge to discovery new
|
||||
* products,</LI>
|
||||
* <LI>{@link #runProductIdentification} for human-oriented identification a device behind the bridge (i.e.
|
||||
* by winking or switching on-and-off),</LI>
|
||||
* <LI>{@link #runProductSearch} for searching for lost products on the bridge,</LI>
|
||||
* <LI>{@link #runScene} for manipulation of a set of devices behind the bridge which are tied together as scene,</LI>
|
||||
* <LI>{@link #setHouseStatusMonitor} for activation or deactivation of the house monitoring mode to be informed about
|
||||
* device state changes recognized by the bridge,</LI>
|
||||
* <LI>{@link #setSceneVelocity} for changes the velocity of a scene defined on the bridge (i.e. silent or
|
||||
* fast mode).</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* Message semantic: Retrieval of Bridge configuration and information of devices beyond the bridge.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* VeluxBridgeProvider as described by the BridgeCommunicationProtocol.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface BridgeAPI {
|
||||
|
||||
Login login();
|
||||
|
||||
Logout logout();
|
||||
|
||||
@Nullable
|
||||
SetHouseStatusMonitor setHouseStatusMonitor();
|
||||
|
||||
@Nullable
|
||||
GetHouseStatus getHouseStatus();
|
||||
|
||||
RunProductDiscovery runProductDiscovery();
|
||||
|
||||
RunProductSearch runProductSearch();
|
||||
|
||||
RunProductIdentification runProductIdentification();
|
||||
|
||||
GetDeviceStatus getDeviceStatus();
|
||||
|
||||
GetFirmware getFirmware();
|
||||
|
||||
GetLANConfig getLANConfig();
|
||||
|
||||
GetWLANConfig getWLANConfig();
|
||||
|
||||
GetProducts getProducts();
|
||||
|
||||
@Nullable
|
||||
GetProduct getProduct();
|
||||
|
||||
@Nullable
|
||||
GetProductLimitation getProductLimitation();
|
||||
|
||||
@Nullable
|
||||
SetProductLimitation setProductLimitation();
|
||||
|
||||
@Nullable
|
||||
RunProductCommand runProductCommand();
|
||||
|
||||
GetScenes getScenes();
|
||||
|
||||
SetSceneVelocity setSceneVelocity();
|
||||
|
||||
RunScene runScene();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Protocol independent bridge communication supported by the Velux bridge.
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 2nd level interface it defines the methods to help in sending a query and
|
||||
* processing the received answer.
|
||||
* <P>
|
||||
* Methods in this interface for the appropriate interaction:
|
||||
* <UL>
|
||||
* <LI>{@link name} to return the name of the interaction for human interface.</LI>
|
||||
* <LI>{@link isCommunicationSuccessful} to signal the success of the interaction (only available
|
||||
* after storing the response).</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Returns the name of this communication pair.
|
||||
*
|
||||
* @return name of the communication pair for human beings.
|
||||
*/
|
||||
public String name();
|
||||
|
||||
/**
|
||||
* Returns the communication status included within the response message.
|
||||
*
|
||||
* @return true if the communication was successful, and false otherwise.
|
||||
*/
|
||||
public boolean isCommunicationSuccessful();
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getState} for retrieval of information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetDeviceStatus implements BridgeCommunicationProtocol {
|
||||
/**
|
||||
* <B>Parameter of the device state.</B>
|
||||
*
|
||||
* @return <b>thisState</b> as VeluxGwState describing the current status of the bridge.
|
||||
*/
|
||||
public abstract VeluxGwState getState();
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwFirmware;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getFirmware} for retrieving the Velux firmware information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetFirmware implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* <B>Retrieval of firmware version string</B>
|
||||
*
|
||||
* @return <b>firmware</b> as VeluxGwFirmware describing the current software of the bridge.
|
||||
*/
|
||||
public abstract VeluxGwFirmware getFirmware();
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetHouseStatus implements BridgeCommunicationProtocol {
|
||||
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwLAN;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getLANConfig} for retrieving the Velux LAN configuration information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetLANConfig implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* <B>Retrieval of the parameters of the LAN configuration.</B>
|
||||
*
|
||||
* @return <b>lanConfig</b> as VeluxGwLAN describing the current status of the bridge.
|
||||
*/
|
||||
public abstract VeluxGwLAN getLANConfig();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setProductId} for defining the intended product.
|
||||
* <LI>{@link #getProduct} for accessing the retrieved information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetProduct implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Set the intended node identifier to be queried
|
||||
*
|
||||
* @param nodeId Gateway internal node identifier (zero to 199)
|
||||
*/
|
||||
public abstract void setProductId(int nodeId);
|
||||
|
||||
/**
|
||||
* <B>Retrieval of information about the selected product</B>
|
||||
*
|
||||
* @return <b>veluxProduct</b> as VeluxProduct.
|
||||
*/
|
||||
public abstract VeluxProduct getProduct();
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setActuatorIdAndLimitationType} for defining the intended actuator and the query type.
|
||||
* <LI>{@link #getLimitation} for accessing the retrieved information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetProductLimitation implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Set the intended node identifier to be queried
|
||||
*
|
||||
* @param nodeId Gateway internal node identifier (zero to 199).
|
||||
* @param getLimitationMinimum true, if we query for Minimum.
|
||||
*/
|
||||
public abstract void setActuatorIdAndLimitationType(int nodeId, boolean getLimitationMinimum);
|
||||
|
||||
/**
|
||||
* <B>Retrieval of information about the selected product</B>
|
||||
*
|
||||
* @return <b>limitation</b> as int.
|
||||
*/
|
||||
public abstract int getLimitation();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getProducts} for retrieving the Velux products/actuators information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetProducts implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* <B>Retrieval of information about all products</B>
|
||||
*
|
||||
* @return <b>arrayOfVeluxProducts</b> as Array of VeluxProduct.
|
||||
*/
|
||||
public abstract VeluxProduct[] getProducts();
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxScene;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getScenes} for retrieving the Velux scenes information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetScenes implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* <B>Retrieval of information about all defined scenes</B>
|
||||
*
|
||||
* @return <b>arrayOfScenes</b> as Array of VeluxScene describing the current scene configuration of the bridge.
|
||||
*/
|
||||
public abstract VeluxScene[] getScenes();
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwWLAN;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #getWLANConfig} for retrieving the Velux WLAN configuration information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class GetWLANConfig implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* <B>Retrieval of the parameters of the wireless LAN configuration.</B>
|
||||
*
|
||||
* @return <b>wlanConfig</b> as VeluxGwWLAN describing the current status of the bridge.
|
||||
*/
|
||||
public abstract VeluxGwWLAN getWLANConfig();
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Communication to authenticate itself, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setPassword} for defining the intended authentication value.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class Login implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Sets the intended password string to be used for authentication
|
||||
*
|
||||
* @param thisPassword Password passed as String.
|
||||
*/
|
||||
public void setPassword(String thisPassword) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authentication information optionally to be used for later following
|
||||
* messages.
|
||||
*
|
||||
* @return <b>authentication token</b> as String which can be used for next operations.
|
||||
*/
|
||||
public String getAuthToken() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Communication to authenticate itself, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
* Note: even before the deauthentication, an authentication is intended.
|
||||
* <P>
|
||||
* Each protocol-specific implementation has to provide the common
|
||||
* methods defined by {@link BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class Logout implements BridgeCommunicationProtocol {
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setNodeAndMainParameter} for defining the intended node and the main parameter value.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class RunProductCommand implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Modifies the state of an actuator
|
||||
*
|
||||
* @param actuatorId Gateway internal actuator identifier (zero to 199).
|
||||
* @param parameterValue target device state.
|
||||
* @return reference to the class instance.
|
||||
*/
|
||||
public abstract RunProductCommand setNodeAndMainParameter(int actuatorId, int parameterValue);
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* Each protocol-specific implementation has to provide the common
|
||||
* methods defined by {@link BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class RunProductDiscovery implements BridgeCommunicationProtocol {
|
||||
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setProductId} for defining the intended node.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class RunProductIdentification implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Set the intended node identifier to be identified
|
||||
*
|
||||
* @param id Gateway internal node identifier (zero to 199)
|
||||
* @return reference to the class instance.
|
||||
*/
|
||||
public RunProductIdentification setProductId(int id) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* Each protocol-specific implementation has to provide the common
|
||||
* methods defined by {@link BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class RunProductSearch implements BridgeCommunicationProtocol {
|
||||
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setSceneId} for defining the intended scene.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class RunScene implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Sets the intended scene identifier to be executed
|
||||
*
|
||||
* @param id Gateway internal scene identifier
|
||||
* @return reference to the class instance.
|
||||
*/
|
||||
public RunScene setSceneId(int id) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the intended scene velocity for later execution
|
||||
*
|
||||
* @param velocity setting as String.
|
||||
* @return reference to the class instance.
|
||||
*/
|
||||
public RunScene setVelocity(int velocity) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #serviceActivation} for defining the intended parameter value.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class SetHouseStatusMonitor implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Modifies the intended state of the gateway-internal house monitoring settings.
|
||||
*
|
||||
* @param enableService as boolean.
|
||||
* @return reference to the class instance.
|
||||
*/
|
||||
public abstract SetHouseStatusMonitor serviceActivation(boolean enableService);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setActuatorIdAndMinimumLimitation} for defining the intended actuator and the minimum limitation
|
||||
* value,</LI>
|
||||
* <LI>{@link #setActuatorIdAndMaximumLimitation} for defining the intended actuator and the maximum limitation
|
||||
* value.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class SetProductLimitation implements BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Set the intended node identifier to be queried
|
||||
*
|
||||
* @param nodeId Gateway internal node identifier (zero to 199).
|
||||
* @param limitationMinimum Minimum Restriction value.
|
||||
*/
|
||||
public abstract void setActuatorIdAndMinimumLimitation(int nodeId, int limitationMinimum);
|
||||
|
||||
/**
|
||||
* Set the intended node identifier to be queried
|
||||
*
|
||||
* @param nodeId Gateway internal node identifier (zero to 199).
|
||||
* @param limitationMaximum Maximum Restriction value.
|
||||
*/
|
||||
public abstract void setActuatorIdAndMaximumLimitation(int nodeId, int limitationMaximum);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.common;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* <B>Common bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementations according to the different comm paths.
|
||||
* <P>
|
||||
* In addition to the common methods defined by {@link BridgeCommunicationProtocol}
|
||||
* each protocol-specific implementation has to provide the following methods:
|
||||
* <UL>
|
||||
* <LI>{@link #setMode} for retrieval of information.
|
||||
* </UL>
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class SetSceneVelocity implements BridgeCommunicationProtocol {
|
||||
|
||||
public abstract SetSceneVelocity setMode(int id, boolean silent);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
* Interface definitions being used to implement the protocol-dependent interactions to IO-homecontrolled devices.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.bridge.common;
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetDeviceStatus;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState.VeluxGatewayState;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState.VeluxGatewaySubState;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Retrieval of current bridge state.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCgetDeviceStatus extends GetDeviceStatus implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/device";
|
||||
private static final String DESCRIPTION = "get device status";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge
|
||||
* JsonVeluxBridge} for serializing.
|
||||
*
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"getDeviceStatus","params":{}}
|
||||
* </pre>
|
||||
*
|
||||
* NOTE: the gateway software is extremely sensitive to this exact JSON structure.
|
||||
* Any modifications (like omitting empty params) will lead to an gateway error.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "getDeviceStatus";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for deserializing with including component access
|
||||
* methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"discovering", or "IDLE"
|
||||
* "data":{},
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private @Nullable Object data = null;
|
||||
private String[] errors = {};
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public VeluxGwState getState() {
|
||||
String deviceStatus = this.getDeviceStatus();
|
||||
byte stateValue = (byte) VeluxGatewayState.GW_S_GWM.getStateValue();
|
||||
byte subStateValue;
|
||||
if ("discovering".equals(deviceStatus)) {
|
||||
subStateValue = (byte) VeluxGatewaySubState.GW_SS_P1.getStateValue();
|
||||
} else if ("IDLE".equals(deviceStatus)) {
|
||||
subStateValue = (byte) VeluxGatewaySubState.GW_SS_IDLE.getStateValue();
|
||||
} else {
|
||||
subStateValue = (byte) VeluxGatewaySubState.GW_SS_P2.getStateValue();
|
||||
}
|
||||
return new VeluxGwState(stateValue, subStateValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetFirmware;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwFirmware;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Retrieval of Bridge configuration.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCgetFirmware extends GetFirmware implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/settings";
|
||||
private static final String DESCRIPTION = "get firmware version";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge
|
||||
* JsonVeluxBridge} for serializing.
|
||||
* <P>
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"getFirmware","params":{}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "getFirmware";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge Communication Structure containing the version of the firmware.
|
||||
* <P>
|
||||
* Used within structure {@link JCgetFirmware} to describe the software of the Bridge.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class BCfirmwareVersion {
|
||||
/*
|
||||
* "version": "0.1.1.0.41.0"
|
||||
*/
|
||||
private String version = VeluxBindingConstants.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge} for
|
||||
* deserializing with including component access methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"IDLE",
|
||||
* "data":{"version":"0.1.1.0.41.0"},
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
private BCfirmwareVersion data = new BCfirmwareVersion();
|
||||
private String[] errors = {};
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods in addition to interface {@link JsonBridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public VeluxGwFirmware getFirmware() {
|
||||
VeluxGwFirmware gwFirmware = new VeluxGwFirmware(response.data.version);
|
||||
return gwFirmware;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetLANConfig;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwLAN;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Retrieval of LAN configuration.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCgetLANConfig extends GetLANConfig implements BridgeCommunicationProtocol, JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/lan";
|
||||
private static final String DESCRIPTION = "get LAN configuration";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link JsonVeluxBridge}
|
||||
* for serializing.
|
||||
* <P>
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"get","params":{}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "get";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge Communication Structure containing the network parameters.
|
||||
* <P>
|
||||
* Used within structure {@link JCgetLANConfig} to describe the network connectivity of the Bridge.
|
||||
*
|
||||
* <pre>
|
||||
* {"ipAddress":"192.168.45.9","subnetMask":"255.255.255.0","defaultGateway":"192.168.45.129","dhcp":false}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class BCLANConfig {
|
||||
private String ipAddress = VeluxBindingConstants.UNKNOWN;
|
||||
private String subnetMask = VeluxBindingConstants.UNKNOWN;
|
||||
private String defaultGateway = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean dhcp;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("ipAddress=%s,subnetMask=%s,defaultGateway=%s,dhcp=%s", this.ipAddress,
|
||||
this.subnetMask, this.defaultGateway, this.dhcp ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for unmarshalling with including component access
|
||||
* methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"IDLE",
|
||||
* "data":"ipAddress":"192.168.45.9","subnetMask":"255.255.255.0","defaultGateway":"192.168.45.129","dhcp":false},
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
private BCLANConfig data = new BCLANConfig();
|
||||
private String[] errors = {};
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getDeviceStatus() {
|
||||
return deviceStatus;
|
||||
}
|
||||
|
||||
public String[] getErrors() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object response) {
|
||||
this.response = (Response) response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.getDeviceStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.getErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public VeluxGwLAN getLANConfig() {
|
||||
VeluxGwLAN gwLAN = new VeluxGwLAN(response.data.ipAddress, response.data.subnetMask,
|
||||
response.data.defaultGateway, response.data.dhcp);
|
||||
return gwLAN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProducts;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductName;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductType;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Retrieval of products.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCgetProducts extends GetProducts implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/products";
|
||||
private static final String DESCRIPTION = "get Products";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/**
|
||||
* Bridge Communication class describing a product
|
||||
*
|
||||
* <PRE>
|
||||
* "name": "Rolladen Bad",
|
||||
* "category": "Roller shutter",
|
||||
* "id": 2,
|
||||
* "typeId": 2,
|
||||
* "subtype": 0,
|
||||
* "scenes": [
|
||||
* "V_DG_Shutter_Mitte_000",
|
||||
* "V_DG_Shutter_Mitte_085",
|
||||
* "V_DG_Shutter_Mitte_100"
|
||||
* ]
|
||||
* </PRE>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private class BCproduct {
|
||||
private String name = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private String category = VeluxBindingConstants.UNKNOWN;
|
||||
private int id;
|
||||
private int typeId;
|
||||
@SuppressWarnings("unused")
|
||||
private int subtype;
|
||||
@SuppressWarnings("unused")
|
||||
private String[] scenes = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge
|
||||
* JsonVeluxBridge} for serializing.
|
||||
* <P>
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"get","params":{}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "get";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link org.openhab.binding.velux.internal.bridge.VeluxBridge VeluxBridge} for
|
||||
* deserialization with including component access methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token": "pESIc/9zDWa1CJR6hCDzLw==",
|
||||
* "result": true,
|
||||
* "deviceStatus": "IDLE",
|
||||
* "data": [
|
||||
* { "name": "Bad",
|
||||
* "category": "Window opener",
|
||||
* "id": 0,
|
||||
* "typeId": 4,
|
||||
* "subtype": 1,
|
||||
* "scenes": [
|
||||
* "V_DG_Window_Mitte_000",
|
||||
* "V_DG_Window_Mitte_100"
|
||||
* ]
|
||||
* },
|
||||
* ],
|
||||
* "errors": []
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
private JCgetProducts.BCproduct[] data = {};
|
||||
private String[] errors = {};
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods in addition to interface {@link JsonBridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public VeluxProduct[] getProducts() {
|
||||
VeluxProduct[] products = new VeluxProduct[response.data.length];
|
||||
for (int productIdx = 0; productIdx < response.data.length; productIdx++) {
|
||||
products[productIdx] = new VeluxProduct(new VeluxProductName(response.data[productIdx].name),
|
||||
VeluxProductType.get(response.data[productIdx].typeId),
|
||||
new ProductBridgeIndex(response.data[productIdx].id));
|
||||
}
|
||||
return products;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetScenes;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductName;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductReference;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductState;
|
||||
import org.openhab.binding.velux.internal.things.VeluxScene;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Retrieval of scene configurations.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCgetScenes extends GetScenes implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/scenes";
|
||||
private static final String DESCRIPTION = "get Scenes";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/**
|
||||
* Bridge Communication Structure containing the state of a product.
|
||||
* <P>
|
||||
* Therefore it includes the typeId and name identifying the product, as well as actuator and status.
|
||||
* <P>
|
||||
* Used within structure {@link BCscene} to describe the final states of the products belonging to this scene.
|
||||
*
|
||||
* <PRE>
|
||||
* "typeId": 2,
|
||||
* "name": "Rolladen Schlafzimmer",
|
||||
* "actuator": 0,
|
||||
* "status": 0
|
||||
* </PRE>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class BCproductState {
|
||||
private int typeId;
|
||||
private String name = VeluxBindingConstants.UNKNOWN;
|
||||
private int actuator;
|
||||
private int status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge Communication Structure containing a scene with different states of products.
|
||||
* <P>
|
||||
* Therefore it includes the name and id identifying the scene, a flag about silence-mode, as well as the different
|
||||
* states.
|
||||
* <P>
|
||||
* These states are defined by an array of {@link BCproductState} as part of this structure.
|
||||
*
|
||||
* <PRE>
|
||||
* {
|
||||
* "name": "V_DG_Shutter_West_100",
|
||||
* "id": 0,
|
||||
* "silent": true,
|
||||
* "bCproductStates": [
|
||||
* {
|
||||
* "typeId": 2,
|
||||
* "name": "Rolladen Schlafzimmer",
|
||||
* "actuator": 0,
|
||||
* "status": 100
|
||||
* }
|
||||
* ]
|
||||
* },
|
||||
* </PRE>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class BCscene {
|
||||
private String name = VeluxBindingConstants.UNKNOWN;
|
||||
private int id;
|
||||
private boolean silent;
|
||||
private BCproductState[] products = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge
|
||||
* JsonVeluxBridge}
|
||||
* for serializing.
|
||||
* <P>
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"get","params":{}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "get";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge Communication Structure describing a response to be received from the Velux Bridge.
|
||||
*
|
||||
* <PRE>
|
||||
* {
|
||||
* "token": "kWwXRQ5mlwgYfvk23g2zXw==",
|
||||
* "result": true,
|
||||
* "deviceStatus": "IDLE",
|
||||
* "data": [
|
||||
* {
|
||||
* "name": "V_DG_Shutter_West_100",
|
||||
* "id": 0,
|
||||
* "silent": true,
|
||||
* "bCproductStates": [
|
||||
* {
|
||||
* "typeId": 2,
|
||||
* "name": "Rolladen Schlafzimmer",
|
||||
* "actuator": 0,
|
||||
* "status": 100
|
||||
* }
|
||||
* ]
|
||||
* },
|
||||
* "errors": []
|
||||
* }
|
||||
* </PRE>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
private BCscene[] data = {};
|
||||
private String[] errors = {};
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods in addition to interface {@link JsonBridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public VeluxScene[] getScenes() {
|
||||
VeluxScene[] scenes = new VeluxScene[response.data.length];
|
||||
for (int sceneIdx = 0; sceneIdx < response.data.length; sceneIdx++) {
|
||||
|
||||
VeluxProductState[] productStates = new VeluxProductState[response.data[sceneIdx].products.length];
|
||||
for (int productIdx = 0; productIdx < response.data[sceneIdx].products.length; productIdx++) {
|
||||
productStates[productIdx] = new VeluxProductState(
|
||||
new VeluxProductReference(
|
||||
new VeluxProductName(response.data[sceneIdx].products[productIdx].name),
|
||||
response.data[sceneIdx].products[productIdx].typeId),
|
||||
response.data[sceneIdx].products[productIdx].actuator,
|
||||
response.data[sceneIdx].products[productIdx].status);
|
||||
}
|
||||
scenes[sceneIdx] = new VeluxScene(response.data[sceneIdx].name, response.data[sceneIdx].id,
|
||||
response.data[sceneIdx].silent, productStates);
|
||||
}
|
||||
return scenes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetWLANConfig;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwWLAN;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Retrieval of WLAN configuration.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCgetWLANConfig extends GetWLANConfig implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/settings";
|
||||
private static final String DESCRIPTION = "get WLAN configuration";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge
|
||||
* JsonVeluxBridge}
|
||||
* for serializing.
|
||||
* <P>
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"wifi","params":{}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "wifi";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge Communication Structure containing the version of the firmware.
|
||||
* <P>
|
||||
* Used within structure {@link JCgetWLANConfig} to describe the network connectivity of the Bridge.
|
||||
*
|
||||
* <PRE>
|
||||
* {"password":"Esf56mxqFY","name":"VELUX_KLF_847C"}
|
||||
* </PRE>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class BCWLANConfig {
|
||||
|
||||
private String password = VeluxBindingConstants.UNKNOWN;
|
||||
private String name = VeluxBindingConstants.UNKNOWN;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("SSID=%s,password=********", this.name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonBridgeCommunicationProtocol} for deserialization with including
|
||||
* component access
|
||||
* methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"IDLE",
|
||||
* "data":{"password":"Esf56mxqFY","name":"VELUX_KLF_847C"},
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
private BCWLANConfig data = new BCWLANConfig();
|
||||
private String[] errors = {};
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return data.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object response) {
|
||||
this.response = (Response) response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods in addition to interface {@link JsonBridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public VeluxGwWLAN getWLANConfig() {
|
||||
VeluxGwWLAN gwWLAN = new VeluxGwWLAN(response.data.name, response.data.password);
|
||||
return gwWLAN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Login;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Communication to authenticate itself, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JClogin extends Login implements JsonBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(JClogin.class);
|
||||
|
||||
private static final String URL = "/api/v1/auth";
|
||||
private static final String DESCRIPTION = "authenticate / login";
|
||||
|
||||
private static Request request = new Request();
|
||||
private static Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class ParamsLogin {
|
||||
@SuppressWarnings("unused")
|
||||
private String password = VeluxBindingConstants.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link JsonVeluxBridge}
|
||||
* for serializing.
|
||||
* <P>
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"login","params":{"password":"PASSWORD"}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final String action = "login";
|
||||
private ParamsLogin params;
|
||||
|
||||
public Request() {
|
||||
this.params = new ParamsLogin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for deserializing with including component access
|
||||
* methods
|
||||
* <P>
|
||||
* <B>Expected JSON (sample):</B>
|
||||
*
|
||||
* <pre>
|
||||
* '{"token": "PHPnfLda71xfGlxoYEOTGQ==", "result": true, "deviceStatus": "IDLE", "data": {}, "errors": [] }'
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private @Nullable Object data;
|
||||
private String[] errors = {};
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
public JClogin() {
|
||||
logger.trace("JClogin(constructor) called.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setPassword(String thisPassword) {
|
||||
logger.trace("setPassword() called.");
|
||||
request.params.password = thisPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthToken() {
|
||||
return response.getToken();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Logout;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Communication to deauthenticate itself, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JClogout extends Logout implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/auth";
|
||||
private static final String DESCRIPTION = "deauthenticate / logout";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link JsonVeluxBridge} for serializing.
|
||||
* <P>
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"logout","params":{}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "logout";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for deserializing with including component access
|
||||
* methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* '{"token": "PHPnfLda71xfGlxoYEOTGQ==", "result": true, "deviceStatus": "IDLE", "data": {}, "errors": [] }'
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private @Nullable Object data = null;
|
||||
private String[] errors = {};
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductDiscovery;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic:Action to start discovery of products, i.e. Velux devices.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link JsonBridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCrunProductDiscovery extends RunProductDiscovery implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/products";
|
||||
private static final String DESCRIPTION = "discover products";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link JsonVeluxBridge}
|
||||
* for serializing.
|
||||
*
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"discover","params":{}}
|
||||
* </pre>
|
||||
*
|
||||
* NOTE: the gateway software is extremely sensitive to this exact JSON structure.
|
||||
* Any modifications (like omitting empty params) will lead to an gateway error.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "discover";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for deserializing with including component access
|
||||
* methods.
|
||||
*
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"discovering",
|
||||
* "data":{},
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private @Nullable Object data = null;
|
||||
private String[] errors = {};
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getDeviceStatus() {
|
||||
return deviceStatus;
|
||||
}
|
||||
|
||||
public String[] getErrors() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.getDeviceStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.getErrors();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductIdentification;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Trigger action to identify a product, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link JsonBridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
|
||||
class JCrunProductIdentification extends RunProductIdentification implements JsonBridgeCommunicationProtocol {
|
||||
private static final int DEFAULT_IDENTIFY_TIME = 50;
|
||||
|
||||
private static final String URL = "/api/v1/products";
|
||||
private static final String DESCRIPTION = "identify one product";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
private static int productId;
|
||||
private static int identifyTime = DEFAULT_IDENTIFY_TIME;
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class ParamsIdentifyProduct {
|
||||
@SuppressWarnings("unused")
|
||||
private int id;
|
||||
@SuppressWarnings("unused")
|
||||
private int time;
|
||||
|
||||
private ParamsIdentifyProduct(int id, int time) {
|
||||
this.id = id;
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link JsonVeluxBridge} for serializing.
|
||||
* <P>
|
||||
* Resulting JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"identify","params":{"id":23,"time":254}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
@SuppressWarnings("unused")
|
||||
private ParamsIdentifyProduct params;
|
||||
|
||||
public Request() {
|
||||
this.action = "identify";
|
||||
this.params = new ParamsIdentifyProduct(JCrunProductIdentification.productId,
|
||||
JCrunProductIdentification.identifyTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for deserializing with including component access
|
||||
* methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token": "NkR/AA5xXj7iL6NiIW8keA==",
|
||||
* "result": false,
|
||||
* "deviceStatus": "IDLE",
|
||||
* "data": {},
|
||||
* "errors": [ 104 ]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private @Nullable Object data;
|
||||
private String[] errors = {};
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getDeviceStatus() {
|
||||
return deviceStatus;
|
||||
}
|
||||
|
||||
public String[] getErrors() {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object response) {
|
||||
this.response = (Response) response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.getDeviceStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.getErrors();
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public JCrunProductIdentification setProductId(int id) {
|
||||
JCrunProductIdentification.productId = id;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductSearch;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: query for lost nodes, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
* Implementing the abstract class {@link RunProductSearch}.
|
||||
* <P>
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCrunProductSearch extends RunProductSearch implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/device";
|
||||
private static final String DESCRIPTION = "check lost nodes";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge
|
||||
* JsonVeluxBridge}
|
||||
* for serializing.
|
||||
*
|
||||
* Resulting JSON:
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"checkLostNodes","params":{}}
|
||||
* </pre>
|
||||
*
|
||||
* NOTE: the gateway software is extremely sensitive to this exact JSON structure.
|
||||
* Any modifications (like omitting empty params) will lead to an gateway error.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private Map<String, String> params;
|
||||
|
||||
public Request() {
|
||||
this.action = "checkLostNodes";
|
||||
this.params = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge} for
|
||||
* deserializing with including component access methods
|
||||
*
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"IDLE",
|
||||
* "data":[],
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private String[] data = {};
|
||||
private String[] errors = {};
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object thisResponse) {
|
||||
response = (Response) thisResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunScene;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: Trigger activation of a specific scene, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCrunScene extends RunScene implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/scenes";
|
||||
private static final String DESCRIPTION = "run Scene";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class ParamsRunScene {
|
||||
@SuppressWarnings("unused")
|
||||
private int id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link JsonVeluxBridge}
|
||||
* for serializing.
|
||||
* <P>
|
||||
* Resulting JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"run","params":{"id":9}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
private ParamsRunScene params;
|
||||
|
||||
public Request() {
|
||||
this.action = "run";
|
||||
this.params = new ParamsRunScene();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for deserializing with including component access
|
||||
* methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"IDLE",
|
||||
* "data":{},
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private @Nullable Object data;
|
||||
private String[] errors = {};
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object response) {
|
||||
this.response = (Response) response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public JCrunScene setSceneId(int id) {
|
||||
request.params.id = id;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge.json;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetSceneVelocity;
|
||||
|
||||
/**
|
||||
* Specific bridge communication message supported by the Velux bridge.
|
||||
* <P>
|
||||
* Message semantic: setting of scene silent mode, resulting in a return of current bridge state.
|
||||
* <P>
|
||||
*
|
||||
* It defines information how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JCsetSceneVelocity extends SetSceneVelocity implements JsonBridgeCommunicationProtocol {
|
||||
|
||||
private static final String URL = "/api/v1/scenes";
|
||||
private static final String DESCRIPTION = "modify silent mode";
|
||||
|
||||
private Request request = new Request();
|
||||
private Response response = new Response();
|
||||
|
||||
private static int productId;
|
||||
private static boolean silentMode;
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class ParamsRunScene {
|
||||
@SuppressWarnings("unused")
|
||||
private int id;
|
||||
@SuppressWarnings("unused")
|
||||
private boolean silent;
|
||||
|
||||
private ParamsRunScene(int id, boolean silent) {
|
||||
this.id = id;
|
||||
this.silent = silent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Request message used by {@link JsonVeluxBridge}
|
||||
* for serializing.
|
||||
* <P>
|
||||
* Resulting JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {"action":"setSilentMode","params":{"id":9,"silent":false}}}
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Request {
|
||||
@SuppressWarnings("unused")
|
||||
private String action;
|
||||
@SuppressWarnings("unused")
|
||||
private ParamsRunScene params;
|
||||
|
||||
public Request() {
|
||||
this.action = "setSilentMode";
|
||||
this.params = new ParamsRunScene(JCsetSceneVelocity.productId, JCsetSceneVelocity.silentMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge I/O Response message used by {@link JsonVeluxBridge} for deserializing with including component access
|
||||
* methods
|
||||
* <P>
|
||||
* Expected JSON (sample):
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
* "token":"RHIKGlJyZhidI/JSK0a2RQ==",
|
||||
* "result":true,
|
||||
* "deviceStatus":"IDLE",
|
||||
* "data":{},
|
||||
* "errors":[]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
private static class Response {
|
||||
@SuppressWarnings("unused")
|
||||
private String token = VeluxBindingConstants.UNKNOWN;
|
||||
private boolean result;
|
||||
private String deviceStatus = VeluxBindingConstants.UNKNOWN;
|
||||
@SuppressWarnings("unused")
|
||||
private @Nullable Object data;
|
||||
private String[] errors = {};
|
||||
|
||||
public boolean getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObjectOfRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Response> getClassOfResponse() {
|
||||
return Response.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(Object response) {
|
||||
this.response = (Response) response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeviceStatus() {
|
||||
return response.deviceStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getErrors() {
|
||||
return response.errors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
@Override
|
||||
public JCsetSceneVelocity setMode(int id, boolean silent) {
|
||||
JCsetSceneVelocity.productId = id;
|
||||
JCsetSceneVelocity.silentMode = silent;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetDeviceStatus;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetFirmware;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetHouseStatus;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetLANConfig;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProduct;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProducts;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetScenes;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetWLANConfig;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Login;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Logout;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductCommand;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductDiscovery;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductIdentification;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductSearch;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunScene;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetHouseStatusMonitor;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetSceneVelocity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* JSON-based 3rd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the one-and-only protocol specific 1st-level communication class.
|
||||
* Additionally it provides all methods for different gateway interactions.
|
||||
* <P>
|
||||
* The following class access methods exist:
|
||||
* <UL>
|
||||
* <LI>{@link JsonBridgeAPI#getDeviceStatus} for retrieving the bridge state (i.e. IDLE, BUSY, a.s.o),</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getFirmware} for retrieving the firmware version of the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getHouseStatus} for retrieving the information about device state changes recognized by the
|
||||
* bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getLANConfig} for retrieving the complete LAN information of the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getProduct} for retrieving the any information about a device behind the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getProductLimitation} for retrieving the limitation information about a device behind the
|
||||
* bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getProducts} for retrieving the any information for all devices behind the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getScenes} for retrieving the any information for all scenes defined on the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#getWLANConfig} for retrieving the complete WLAN information of the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#login} for establishing a trusted connectivity by authentication,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#logout} for tearing down the trusted connectivity by deauthentication,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#runProductCommand} for manipulation of a device behind the bridge (i.e. instructing to
|
||||
* modify a position),</LI>
|
||||
* <LI>{@link JsonBridgeAPI#runProductDiscovery} for activation of learning mode of the bridge to discovery new
|
||||
* products,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#runProductIdentification} for human-oriented identification a device behind the bridge (i.e.
|
||||
* by winking or switching on-and-off),</LI>
|
||||
* <LI>{@link JsonBridgeAPI#runProductSearch} for searching for lost products on the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#runScene} for manipulation of a set of devices behind the bridge which are tied together as
|
||||
* scene,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#setHouseStatusMonitor} for activation or deactivation of the house monitoring mode to be
|
||||
* informed about device state changes recognized by the bridge,</LI>
|
||||
* <LI>{@link JsonBridgeAPI#setSceneVelocity} for changes the velocity of a scene defined on the bridge (i.e. silent or
|
||||
* fast mode).</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* As most derived class of the several inheritance levels it defines an
|
||||
* interfacing method which returns the JSON-protocol-specific communication for gateway interaction.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class JsonBridgeAPI implements BridgeAPI {
|
||||
private final Logger logger = LoggerFactory.getLogger(JsonBridgeAPI.class);
|
||||
|
||||
private static final GetDeviceStatus GETDEVICESTATUS = new JCgetDeviceStatus();
|
||||
private static final GetFirmware GETFIRMWARE = new JCgetFirmware();
|
||||
private static final GetLANConfig GETLANCONFIG = new JCgetLANConfig();
|
||||
private static final GetProducts GETPRODUCTS = new JCgetProducts();
|
||||
private static final GetScenes GETSCENES = new JCgetScenes();
|
||||
private static final GetWLANConfig GETWLANCONFIG = new JCgetWLANConfig();
|
||||
private static final Login LOGIN = new JClogin();
|
||||
private static final Logout LOGOUT = new JClogout();
|
||||
private static final RunProductDiscovery RUNPRODUCTDISCOVERY = new JCrunProductDiscovery();
|
||||
private static final RunProductIdentification RUNPRODUCTIDENTIFICATION = new JCrunProductIdentification();
|
||||
private static final RunProductSearch RUNPRODUCTSEARCH = new JCrunProductSearch();
|
||||
private static final RunScene RUNSCENE = new JCrunScene();
|
||||
private static final SetSceneVelocity SETSCENEVELOCITY = new JCsetSceneVelocity();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Inherits the initialization of the binding-wide instance for dealing for common information and
|
||||
* initializes the handler {@link org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge#bridgeAPI
|
||||
* JsonVeluxBridge.bridgeAPI}
|
||||
* to pass the interface methods.
|
||||
*
|
||||
* @param bridgeInstance refers to the binding-wide instance for dealing for common informations.
|
||||
*/
|
||||
JsonBridgeAPI(VeluxBridgeInstance bridgeInstance) {
|
||||
logger.trace("JsonBridgeAPI(constructor) called.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetDeviceStatus getDeviceStatus() {
|
||||
return GETDEVICESTATUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetFirmware getFirmware() {
|
||||
return GETFIRMWARE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GetHouseStatus getHouseStatus() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetLANConfig getLANConfig() {
|
||||
return GETLANCONFIG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GetProduct getProduct() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GetProductLimitation getProductLimitation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SetProductLimitation setProductLimitation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetProducts getProducts() {
|
||||
return GETPRODUCTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetScenes getScenes() {
|
||||
return GETSCENES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetWLANConfig getWLANConfig() {
|
||||
return GETWLANCONFIG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Login login() {
|
||||
return LOGIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logout logout() {
|
||||
return LOGOUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable RunProductCommand runProductCommand() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunProductDiscovery runProductDiscovery() {
|
||||
return RUNPRODUCTDISCOVERY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunProductIdentification runProductIdentification() {
|
||||
return RUNPRODUCTIDENTIFICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunProductSearch runProductSearch() {
|
||||
return RUNPRODUCTSEARCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunScene runScene() {
|
||||
return RUNSCENE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SetHouseStatusMonitor setHouseStatusMonitor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetSceneVelocity setSceneVelocity() {
|
||||
return SETSCENEVELOCITY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
|
||||
/**
|
||||
* <B>Common JSON-based bridge communication message scheme supported by the </B><I>Velux</I><B> bridge.</B>
|
||||
* <P>
|
||||
* This bridge communication is an extension of the common
|
||||
* {@link org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol BridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Message semantic will be defined by the implementation of the separate message classes,
|
||||
* which are defined within {@link org.openhab.binding.velux.internal.bridge.json.JsonBridgeAPI JsonBridgeAPI}.
|
||||
* <P>
|
||||
* The implementations will define the information which to send query and receive answer
|
||||
* through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}.
|
||||
* <P>
|
||||
* (Methods in this interface for the appropriate interaction:
|
||||
* <UL>
|
||||
* <LI>{@link #getURL} to return the URL suffix for accessing the specific service access point.</LI>
|
||||
* <LI>{@link #getObjectOfRequest} to return the request object for further JSON serialization.</LI>
|
||||
* <LI>{@link #getClassOfResponse} to retrieve the class of the object of response message for further JSON
|
||||
* deserialization.</LI>
|
||||
* <LI>{@link #setResponse} for storing the response according to the desired class after JSON deserialization.</LI>
|
||||
* <LI>{@link #getDeviceStatus} to retrieve the current device status.</LI>
|
||||
* <LI>{@link #getErrors} to retrieve the current error status.</LI>
|
||||
* </UL>
|
||||
*
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
interface JsonBridgeCommunicationProtocol extends BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Returning the URL suffix for accessing the specific service access point.
|
||||
*
|
||||
* @return <b>sapURL</b>
|
||||
* as String which is to be combined with the bridge address.
|
||||
*/
|
||||
String getURL();
|
||||
|
||||
/**
|
||||
* Returning the request object for further JSON serialization.
|
||||
*
|
||||
* @return <b>ObjectOfRequest</b>
|
||||
* is an Object.
|
||||
*/
|
||||
Object getObjectOfRequest();
|
||||
|
||||
/**
|
||||
* Returning the class of the object of response message for further JSON deserialization.
|
||||
*
|
||||
* @return <b>ClassOfResponseObject</b>
|
||||
* is the appropriate class Object.
|
||||
*/
|
||||
Class<?> getClassOfResponse();
|
||||
|
||||
/**
|
||||
* Storing the response according to the desired class after JSON deserialization.
|
||||
*
|
||||
* @param response is the appropriate object of previously given class Object.
|
||||
*/
|
||||
void setResponse(Object response);
|
||||
|
||||
/**
|
||||
* Returning the communication status included within the response message.
|
||||
*
|
||||
* @return <b>deviceStatus</b> as String describing the current status of the bridge.
|
||||
*/
|
||||
String getDeviceStatus();
|
||||
|
||||
/**
|
||||
* Returning the communication status included within the response message.
|
||||
*
|
||||
* @return <b>errors</b> as String[] describing the status of the operation according to the request in depth.
|
||||
*/
|
||||
String[] getErrors();
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.binding.velux.internal.bridge.VeluxBridge;
|
||||
import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
* JSON-based 2nd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides methods for pre- and postcommunication
|
||||
* as well as a common method for the real communication.
|
||||
* <P>
|
||||
* The following class access methods exist:
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridge#bridgeLogin} for pre-communication,</LI>
|
||||
* <LI>{@link VeluxBridge#bridgeLogout} for post-communication,</LI>
|
||||
* <LI>{@link VeluxBridge#bridgeCommunicate} as method for the common communication.</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* As root of several inheritance levels it predefines an
|
||||
* interfacing method {@link VeluxBridge#bridgeAPI} which
|
||||
* has to be implemented by any kind of protocol-specific
|
||||
* communication returning the appropriate base (1st) level
|
||||
* communication method as well as any other gateway
|
||||
* interaction.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JsonVeluxBridge extends VeluxBridge {
|
||||
private final Logger logger = LoggerFactory.getLogger(JsonVeluxBridge.class);
|
||||
|
||||
/**
|
||||
* Timestamp of last communication in milliseconds.
|
||||
*
|
||||
*/
|
||||
private long lastCommunicationInMSecs = 0;
|
||||
|
||||
/**
|
||||
* Timestamp of last successful communication in milliseconds.
|
||||
*
|
||||
*/
|
||||
private long lastSuccessfulCommunicationInMSecs = 0;
|
||||
|
||||
/**
|
||||
* Handler passing the interface methods to other classes.
|
||||
* Can be accessed via method {@link org.openhab.binding.velux.internal.bridge.common.BridgeAPI BridgeAPI}.
|
||||
*
|
||||
*/
|
||||
private BridgeAPI bridgeAPI;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Inherits the initialization of the binding-wide instance for dealing for common informations and
|
||||
* initializes the Velux bridge connectivity settings.
|
||||
*
|
||||
* @param bridgeInstance refers to the binding-wide instance for dealing for common informations.
|
||||
*/
|
||||
public JsonVeluxBridge(VeluxBridgeInstance bridgeInstance) {
|
||||
super(bridgeInstance);
|
||||
logger.trace("JsonVeluxBridge(constructor) called.");
|
||||
bridgeAPI = new JsonBridgeAPI(bridgeInstance);
|
||||
supportedProtocols = new TreeSet<>();
|
||||
supportedProtocols.add("http");
|
||||
supportedProtocols.add("https");
|
||||
logger.trace("JsonVeluxBridge(constructor) done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides information about the base-level communication method and
|
||||
* any kind of available gateway interactions.
|
||||
* <P>
|
||||
* <B>Note:</B> the implementation within this class {@link JsonVeluxBridge} as inherited from {@link VeluxBridge}
|
||||
* will return the protocol-specific class implementations.
|
||||
* <P>
|
||||
* The information will be initialized by the corresponding API class {@link JsonBridgeAPI}.
|
||||
*
|
||||
* @return <b>bridgeAPI</b> of type {@link BridgeAPI} contains all possible methods.
|
||||
*/
|
||||
@Override
|
||||
public BridgeAPI bridgeAPI() {
|
||||
logger.trace("bridgeAPI() called.");
|
||||
return bridgeAPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* <B>Method as implementation of abstract superclass method.</B>
|
||||
* <P>
|
||||
* Initializes a client/server communication towards <b>Velux</b> veluxBridge
|
||||
* based on the Basic I/O interface {@link #io} and parameters
|
||||
* passed as arguments (see below).
|
||||
*
|
||||
* @param communication Structure of interface type {@link JsonBridgeCommunicationProtocol} describing the intended
|
||||
* communication, that is request and response interactions as well as appropriate URL definition.
|
||||
* @param useAuthentication boolean flag to decide whether to use authenticated communication.
|
||||
* @return <b>success</b> of type boolean which signals the success of the communication.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected boolean bridgeDirectCommunicate(BridgeCommunicationProtocol communication, boolean useAuthentication) {
|
||||
logger.trace("bridgeDirectCommunicate(BCP: {},{}authenticated) called.", communication.name(),
|
||||
useAuthentication ? "" : "un");
|
||||
return bridgeDirectCommunicate((JsonBridgeCommunicationProtocol) communication, useAuthentication);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last (potentially faulty) communication.
|
||||
*
|
||||
* @return timestamp in milliseconds.
|
||||
*/
|
||||
@Override
|
||||
public long lastCommunication() {
|
||||
return lastCommunicationInMSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last successful communication.
|
||||
*
|
||||
* @return timestamp in milliseconds.
|
||||
*/
|
||||
@Override
|
||||
public long lastSuccessfulCommunication() {
|
||||
return lastSuccessfulCommunicationInMSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a client/server communication towards <b>Velux</b> veluxBridge
|
||||
* based on the Basic I/O interface {@link VeluxBridge} and parameters
|
||||
* passed as arguments (see below).
|
||||
*
|
||||
* @param communication Structure of interface type {@link JsonBridgeCommunicationProtocol} describing the
|
||||
* intended
|
||||
* communication,
|
||||
* that is request and response interactions as well as appropriate URL definition.
|
||||
* @param useAuthentication boolean flag to decide whether to use authenticated communication.
|
||||
* @return <b>response</b> of type boolean will indicate the success of the communication.
|
||||
*/
|
||||
private synchronized boolean bridgeDirectCommunicate(JsonBridgeCommunicationProtocol communication,
|
||||
boolean useAuthentication) {
|
||||
logger.trace("bridgeDirectCommunicate({},{}authenticated) called.", communication.name(),
|
||||
useAuthentication ? "" : "un");
|
||||
|
||||
String sapURL = this.bridgeInstance.veluxBridgeConfiguration().protocol.concat("://")
|
||||
.concat(this.bridgeInstance.veluxBridgeConfiguration().ipAddress).concat(":")
|
||||
.concat(Integer.toString(this.bridgeInstance.veluxBridgeConfiguration().tcpPort))
|
||||
.concat(communication.getURL());
|
||||
logger.trace("bridgeCommunicate(): using SAP {}.", sapURL);
|
||||
Object getRequest = communication.getObjectOfRequest();
|
||||
Class<?> classOfResponse = communication.getClassOfResponse();
|
||||
Object response;
|
||||
|
||||
try {
|
||||
if (useAuthentication) {
|
||||
response = ioAuthenticated(sapURL, authenticationToken, getRequest, classOfResponse);
|
||||
} else {
|
||||
response = ioUnauthenticated(sapURL, getRequest, classOfResponse);
|
||||
}
|
||||
communication.setResponse(response);
|
||||
logger.trace("bridgeCommunicate(): communication result is {}, returning details.",
|
||||
communication.isCommunicationSuccessful());
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
logger.warn("bridgeCommunicate(): Exception occurred on accessing {}: {}.", sapURL, ioe.getMessage());
|
||||
return false;
|
||||
} catch (JsonSyntaxException jse) {
|
||||
logger.warn("bridgeCommunicate(): Exception occurred on (de-)serialization during accessing {}: {}.",
|
||||
sapURL, jse.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base level communication with the <b>Velux</b> bridge.
|
||||
*
|
||||
* @param <T> This describes the request type parameter.
|
||||
* @param <U> This describes the response type parameter.
|
||||
* @param url as String describing the Service Access Point location i.e. http://localhost/api .
|
||||
* @param authentication as String providing the Authentication token to be passed with the request header.
|
||||
* @param request as Object representing the structure of the message request body to be converted into
|
||||
* JSON.
|
||||
* @param classOfResponse as Class representing the expected structure of the message response body to be converted
|
||||
* from JSON.
|
||||
* @return <b>response</b> of type Object containing all resulting informations, i.e. device status, errors a.s.o.
|
||||
* Will
|
||||
* return
|
||||
* <B>null</B> in case of communication or decoding error.
|
||||
* @throws java.io.IOException in case of continuous communication I/O failures.
|
||||
* @throws JsonSyntaxException in case of unusual communication failures.
|
||||
*/
|
||||
private <T, U> T io(String url, String authentication, U request, Class<T> classOfResponse)
|
||||
throws JsonSyntaxException, IOException {
|
||||
/** Local handles */
|
||||
int retryCount = 0;
|
||||
|
||||
lastCommunicationInMSecs = System.currentTimeMillis();
|
||||
do {
|
||||
try {
|
||||
Gson gson = new Gson();
|
||||
String jsonRequest = gson.toJson(request);
|
||||
logger.trace("io() to {} using request {}.", url, jsonRequest);
|
||||
|
||||
Properties headerItems = new Properties();
|
||||
if (authentication.length() > 0) {
|
||||
headerItems.setProperty("Authorization", String.format("Bearer %s", authentication));
|
||||
}
|
||||
InputStream content = IOUtils.toInputStream(jsonRequest, StandardCharsets.UTF_8.name());
|
||||
|
||||
String jsonResponse = HttpUtil.executeUrl("PUT", url, headerItems, content, "application/json",
|
||||
this.bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||
if (jsonResponse == null) {
|
||||
throw new IOException("transport error");
|
||||
}
|
||||
logger.trace("io(): wait time {} msecs.", this.bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||
// Give the bridge some time to breathe
|
||||
try {
|
||||
Thread.sleep(this.bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||
} catch (InterruptedException ie) {
|
||||
logger.trace("io() wait interrupted.");
|
||||
}
|
||||
logger.trace("io() got response {}.", jsonResponse.replaceAll("\\p{C}", "."));
|
||||
jsonResponse = jsonResponse.replaceAll("^.+,\n", "");
|
||||
logger.trace("io() cleaned response {}.", jsonResponse);
|
||||
T response = gson.fromJson(jsonResponse, classOfResponse);
|
||||
lastCommunicationInMSecs = lastSuccessfulCommunicationInMSecs = System.currentTimeMillis();
|
||||
return response;
|
||||
|
||||
} catch (IOException ioe) {
|
||||
logger.trace("io(): Exception occurred during I/O: {}.", ioe.getMessage());
|
||||
// Error Retries with Exponential Backoff
|
||||
long waitTime = ((long) Math.pow(2, retryCount)
|
||||
* this.bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||
logger.trace("io(): wait time {} msecs.", waitTime);
|
||||
try {
|
||||
Thread.sleep(waitTime);
|
||||
} catch (InterruptedException ie) {
|
||||
logger.trace("io() wait interrupted.");
|
||||
}
|
||||
} catch (JsonSyntaxException jse) {
|
||||
logger.info("io(): Exception occurred on deserialization: {}, aborting.", jse.getMessage());
|
||||
throw jse;
|
||||
}
|
||||
|
||||
} while (retryCount++ < this.bridgeInstance.veluxBridgeConfiguration().retries);
|
||||
throw new IOException(String.format("io(): socket I/O failed (%d times).",
|
||||
this.bridgeInstance.veluxBridgeConfiguration().retries));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an authenticated communication with the {@link JsonVeluxBridge <b>Velux</b> bridge}.
|
||||
*
|
||||
* @param <T> This describes the request type parameter.
|
||||
* @param <U> This describes the response type parameter.
|
||||
* @param url as String describing the Service Access Point location i.e. http://localhost/api .
|
||||
* @param authentication as String providing the Authentication token to be passed with the request header.
|
||||
* @param request as Object representing the structure of the message request body to be converted into
|
||||
* JSON.
|
||||
* @param classOfResponse as Class representing the expected structure of the message response body to be converted
|
||||
* from JSON.
|
||||
* @return <b>response</b> of type T containing all resulting informations, i.e. device status, errors a.s.o. Will
|
||||
* return
|
||||
* <B>null</B> in case of communication or decoding error.
|
||||
* @throws java.io.IOException in case of continuous communication I/O failures.
|
||||
* @throws JsonSyntaxException in case of unusual communication failures.
|
||||
*/
|
||||
private <T, U> T ioAuthenticated(String url, String authentication, U request, Class<T> classOfResponse)
|
||||
throws JsonSyntaxException, IOException {
|
||||
return io(url, authentication, request, classOfResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an unauthenticated communication with the {@link JsonVeluxBridge <b>Velux</b> bridge}.
|
||||
*
|
||||
* @param <T> This describes the request type parameter.
|
||||
* @param <U> This describes the response type parameter.
|
||||
* @param url as String describing the Service Access Point location i.e. http://localhost/api .
|
||||
* @param request as Object representing the structure of the message request body to be converted into
|
||||
* JSON.
|
||||
* @param classOfResponse as Class representing the expected structure of the message response body to be converted
|
||||
* from JSON.
|
||||
* @return <b>response</b> of type Object containing all resulting informations, i.e. device status, errors a.s.o.
|
||||
* Will
|
||||
* return
|
||||
* <B>null</B> in case of communication or decoding error.
|
||||
* @throws java.io.IOException in case of continuous communication I/O failures.
|
||||
* @throws JsonSyntaxException in case of unusual communication failures.
|
||||
*/
|
||||
private <T, U> T ioUnauthenticated(String url, U request, Class<T> classOfResponse)
|
||||
throws JsonSyntaxException, IOException {
|
||||
return io(url, "", request, classOfResponse);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
* JSON-protocol specific implementations of the interactions to IO-homecontrolled devices.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.bridge.json;
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
* Classes for Generic protocol-independent interactions to IO-homecontrolled devices via the Velux gateway.
|
||||
* This layer is responsible for the transformation of openHAB "objects" into Velux "object" and vice versa.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.bridge;
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetDeviceStatus;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Get Bridge Device Status</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #getState} to retrieve the Velux gateway status.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetDeviceStatus
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetDeviceStatus extends GetDeviceStatus implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetDeviceStatus.class);
|
||||
|
||||
private static final String DESCRIPTION = "Get Bridge Device Status";
|
||||
private static final Command COMMAND = Command.GW_GET_STATE_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int cfmGatewayState;
|
||||
private int cfmSubState;
|
||||
@SuppressWarnings("unused")
|
||||
private int cfmStateData;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
logger.trace("getRequestDataAsArrayOfBytes() returns data.");
|
||||
requestData = new byte[0];
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_GET_STATE_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 6)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
cfmGatewayState = responseData.getOneByteValue(0);
|
||||
cfmSubState = responseData.getOneByteValue(1);
|
||||
cfmStateData = responseData.getFourByteValue(2);
|
||||
finished = true;
|
||||
success = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public VeluxGwState getState() {
|
||||
VeluxGwState thisGwState = new VeluxGwState((byte) cfmGatewayState, (byte) cfmSubState);
|
||||
logger.trace("getState() returns {} ({}).", thisGwState, thisGwState.toDescription());
|
||||
return thisGwState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetFirmware;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwFirmware;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Get Firmware Version</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #getFirmware} to retrieve the Velux firmware version.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetFirmware
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetFirmware extends GetFirmware implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetFirmware.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve firmware version";
|
||||
private static final Command COMMAND = Command.GW_GET_VERSION_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int cfmSoftwareVersionCommand = 0;
|
||||
private int cfmSoftwareVersionWhole = 0;
|
||||
private int cfmSoftwareVersionSub = 0;
|
||||
private int cfmSoftwareVersionBranch = 0;
|
||||
private int cfmSoftwareVersionBuild = 0;
|
||||
private int cfmSoftwareVersionMicroBuild = 0;
|
||||
private int cfmHardwareVersion = 0;
|
||||
private int cfmProductGroup = 0;
|
||||
private int cfmProductType = 0;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
requestData = new byte[1];
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_GET_VERSION_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 9)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
cfmSoftwareVersionCommand = responseData.getOneByteValue(0);
|
||||
cfmSoftwareVersionWhole = responseData.getOneByteValue(1);
|
||||
cfmSoftwareVersionSub = responseData.getOneByteValue(2);
|
||||
cfmSoftwareVersionBranch = responseData.getOneByteValue(3);
|
||||
cfmSoftwareVersionBuild = responseData.getOneByteValue(4);
|
||||
cfmSoftwareVersionMicroBuild = responseData.getOneByteValue(5);
|
||||
cfmHardwareVersion = responseData.getOneByteValue(6);
|
||||
cfmProductGroup = responseData.getOneByteValue(7);
|
||||
cfmProductType = responseData.getOneByteValue(8);
|
||||
success = true;
|
||||
finished = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public VeluxGwFirmware getFirmware() {
|
||||
String result = String.format("Software version %d.%d.%d.%d.%d.%d, Hardware version %d.%d.%d",
|
||||
cfmSoftwareVersionCommand, cfmSoftwareVersionWhole, cfmSoftwareVersionSub, cfmSoftwareVersionBranch,
|
||||
cfmSoftwareVersionBuild, cfmSoftwareVersionMicroBuild, cfmHardwareVersion, cfmProductGroup,
|
||||
cfmProductType);
|
||||
logger.trace("getFirmware() returns {}.", result);
|
||||
return new VeluxGwFirmware(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetHouseStatus;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve House Status</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication from the bridge and storing returned information within the class itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #getNtfNodeID} to retrieve the node identifier which has been changed.</LI>
|
||||
* <LI>{@link #getNtfState} to retrieve the state of the node which has been changed.</LI>
|
||||
* <LI>{@link #getNtfCurrentPosition} to retrieve the actual position of this node.</LI>
|
||||
* <LI>{@link #getNtfTarget} to retrieve the target position of this node.</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* NOTE: the class does NOT define a request as it only works as receiver.
|
||||
*
|
||||
* @see BridgeCommunicationProtocol
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetHouseStatus extends GetHouseStatus implements BridgeCommunicationProtocol, SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetHouseStatus.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve House Status";
|
||||
private static final Command COMMAND = Command.GW_OPENHAB_RECEIVEONLY;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
private int ntfNodeID;
|
||||
private int ntfState;
|
||||
private int ntfCurrentPosition;
|
||||
private int ntfTarget;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = true;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_NODE_STATE_POSITION_CHANGED_NTF:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 20)) {
|
||||
break;
|
||||
}
|
||||
ntfNodeID = responseData.getOneByteValue(0);
|
||||
ntfState = responseData.getOneByteValue(1);
|
||||
ntfCurrentPosition = responseData.getTwoByteValue(2);
|
||||
ntfTarget = responseData.getTwoByteValue(4);
|
||||
@SuppressWarnings("unused")
|
||||
int ntfFP1CurrentPosition = responseData.getTwoByteValue(6);
|
||||
@SuppressWarnings("unused")
|
||||
int ntfFP2CurrentPosition = responseData.getTwoByteValue(8);
|
||||
@SuppressWarnings("unused")
|
||||
int ntfFP3CurrentPosition = responseData.getTwoByteValue(10);
|
||||
@SuppressWarnings("unused")
|
||||
int ntfFP4CurrentPosition = responseData.getTwoByteValue(12);
|
||||
int ntfRemainingTime = responseData.getTwoByteValue(14);
|
||||
int ntfTimeStamp = responseData.getFourByteValue(16);
|
||||
// Extracting information items
|
||||
logger.trace("setResponse(): ntfNodeID={}.", ntfNodeID);
|
||||
logger.trace("setResponse(): ntfState={}.", ntfState);
|
||||
logger.trace("setResponse(): ntfCurrentPosition={}.", ntfCurrentPosition);
|
||||
logger.trace("setResponse(): ntfTarget={}.", ntfTarget);
|
||||
logger.trace("setResponse(): ntfRemainingTime={}.", ntfRemainingTime);
|
||||
logger.trace("setResponse(): ntfTimeStamp={}.", ntfTimeStamp);
|
||||
success = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return <b>ntfNodeID</b> returns the Actuator Id as int.
|
||||
*/
|
||||
public int getNtfNodeID() {
|
||||
return ntfNodeID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <b>ntfState</b> returns the state of the Actuator as int.
|
||||
*/
|
||||
public int getNtfState() {
|
||||
return ntfState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <b>ntfCurrentPosition</b> returns the current position of the Actuator as int.
|
||||
*/
|
||||
public int getNtfCurrentPosition() {
|
||||
return ntfCurrentPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <b>ntfTarget</b> returns the target position of the Actuator as int.
|
||||
*/
|
||||
public int getNtfTarget() {
|
||||
return ntfTarget;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetLANConfig;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwLAN;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve LAN configuration</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #getLANConfig} to retrieve the current LAN configuration.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetLANConfig
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetLANConfig extends GetLANConfig implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetLANConfig.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve LAN configuration";
|
||||
private static final Command COMMAND = Command.GW_GET_NETWORK_SETUP_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int cfmIpAddress;
|
||||
private int cfmMask;
|
||||
private int cfmDefGW;
|
||||
private boolean cfmDHCP;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
requestData = new byte[1];
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_GET_NETWORK_SETUP_CFM:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
|
||||
break;
|
||||
}
|
||||
cfmIpAddress = responseData.getFourByteValue(0);
|
||||
cfmMask = responseData.getFourByteValue(4);
|
||||
cfmDefGW = responseData.getFourByteValue(8);
|
||||
cfmDHCP = responseData.getOneByteValue(12) == 0 ? false : true;
|
||||
success = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public VeluxGwLAN getLANConfig() {
|
||||
logger.trace("getLANConfig() called.");
|
||||
VeluxGwLAN result = new VeluxGwLAN(Packet.intToIPAddressString(cfmIpAddress),
|
||||
Packet.intToIPAddressString(cfmMask), Packet.intToIPAddressString(cfmDefGW), cfmDHCP);
|
||||
logger.debug("getLANConfig() returns {}.", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve Product Limitations</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setActuatorIdAndLimitationType(int,boolean)} to define the one specific product.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetProductLimitation
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetLimitation extends GetProductLimitation implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetLimitation.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve Actuator Limitation";
|
||||
private static final Command COMMAND = Command.GW_GET_LIMITATION_STATUS_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqSessionID = 0;
|
||||
private int reqIndexArrayCount = 1; // One node will be addressed
|
||||
private int reqIndexArray01 = 1; // This is the node
|
||||
private int reqParameterID = 0; // MP = Main parameter
|
||||
private int reqLimitationType = 0; // Resulting minimum limitation. 1= maximum.
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
private int limitationValue = 0;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
public SCgetLimitation() {
|
||||
logger.debug("SCgetLimitation(Constructor) called.");
|
||||
Random rand = new Random();
|
||||
reqSessionID = rand.nextInt(0x0fff);
|
||||
logger.debug("SCgetLimitation(): starting sessions with the random number {}.", reqSessionID);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
Packet request = new Packet(new byte[25]);
|
||||
reqSessionID = (reqSessionID + 1) & 0xffff;
|
||||
request.setTwoByteValue(0, reqSessionID);
|
||||
request.setOneByteValue(2, reqIndexArrayCount);
|
||||
request.setOneByteValue(3, reqIndexArray01);
|
||||
request.setOneByteValue(23, reqParameterID);
|
||||
request.setOneByteValue(24, reqLimitationType);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): ntfSessionID={}.", reqSessionID);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArrayCount={}.", reqIndexArrayCount);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArray01={}.", reqIndexArray01);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqParameterID={}.", reqParameterID);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqLimitationType={}.", reqLimitationType);
|
||||
requestData = request.toByteArray();
|
||||
logger.trace("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_GET_LIMITATION_STATUS_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int cfmSessionID = responseData.getTwoByteValue(0);
|
||||
int cfmStatus = responseData.getOneByteValue(2);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.info("setResponse(): returned status: Error – Command rejected.");
|
||||
finished = true;
|
||||
break;
|
||||
case 1:
|
||||
logger.debug("setResponse(): returned status: OK - Command is accepted.");
|
||||
if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse(): returned status={} (not defined).", cfmStatus);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_LIMITATION_STATUS_NTF:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 10)) {
|
||||
break;
|
||||
}
|
||||
// Extracting information items
|
||||
int ntfSessionID = responseData.getTwoByteValue(0);
|
||||
int ntfNodeID = responseData.getOneByteValue(2);
|
||||
int ntfParameterID = responseData.getOneByteValue(3);
|
||||
int ntfMinValue = responseData.getTwoByteValue(4);
|
||||
int ntfMaxValue = responseData.getTwoByteValue(6);
|
||||
int ntfLimitationOriginator = responseData.getOneByteValue(8);
|
||||
int ntfLimitationTime = responseData.getOneByteValue(9);
|
||||
|
||||
if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
logger.trace("setResponse(): nodeId={}.", ntfNodeID);
|
||||
logger.trace("setResponse(): ntfParameterID={}.", ntfParameterID);
|
||||
logger.trace("setResponse(): ntfMinValue={}.", ntfMinValue);
|
||||
logger.trace("setResponse(): ntfMaxValue={}.", ntfMaxValue);
|
||||
logger.trace("setResponse(): ntfLimitationOriginator={}.", ntfLimitationOriginator);
|
||||
logger.trace("setResponse(): ntfLimitationTime={}.", ntfLimitationTime);
|
||||
|
||||
// Determine the returned value
|
||||
limitationValue = (reqLimitationType == 0) ? ntfMinValue : ntfMaxValue;
|
||||
logger.debug("setResponse(): {} limitation for node {} is {}.",
|
||||
(reqLimitationType == 0) ? "minimum" : "maximum", reqIndexArray01, limitationValue);
|
||||
|
||||
success = true;
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_COMMAND_RUN_STATUS_NTF:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
ntfSessionID = responseData.getTwoByteValue(0);
|
||||
int ntfStatusiD = responseData.getOneByteValue(2);
|
||||
int ntfIndex = responseData.getOneByteValue(3);
|
||||
int ntfNodeParameter = responseData.getOneByteValue(4);
|
||||
int ntfParameterValue = responseData.getTwoByteValue(5);
|
||||
int ntfRunStatus = responseData.getOneByteValue(7);
|
||||
int ntfStatusReply = responseData.getOneByteValue(8);
|
||||
int ntfInformationCode = responseData.getFourByteValue(9);
|
||||
// Extracting information items
|
||||
logger.trace("setResponse(): ntfSessionID={} (requested {}).", ntfSessionID, reqSessionID);
|
||||
logger.trace("setResponse(): ntfStatusiD={}.", ntfStatusiD);
|
||||
logger.trace("setResponse(): ntfIndex={}.", ntfIndex);
|
||||
logger.trace("setResponse(): ntfNodeParameter={}.", ntfNodeParameter);
|
||||
logger.trace("setResponse(): ntfParameterValue={}.", ntfParameterValue);
|
||||
logger.trace("setResponse(): ntfRunStatus={}.", ntfRunStatus);
|
||||
logger.trace("setResponse(): ntfStatusReply={}.", ntfStatusReply);
|
||||
logger.trace("setResponse(): ntfInformationCode={}.", ntfInformationCode);
|
||||
|
||||
if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
}
|
||||
switch (ntfRunStatus) {
|
||||
case 0:
|
||||
logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_COMPLETED.");
|
||||
success = true;
|
||||
break;
|
||||
case 1:
|
||||
logger.info("setResponse(): returned ntfRunStatus: EXECUTION_FAILED.");
|
||||
finished = true;
|
||||
break;
|
||||
case 2:
|
||||
logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_ACTIVE.");
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse(): returned ntfRunStatus={} (not defined).", ntfRunStatus);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
success = true;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_SESSION_FINISHED_NTF:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
|
||||
break;
|
||||
}
|
||||
int finishedNtfSessionID = responseData.getTwoByteValue(0);
|
||||
if (!KLF200Response.check4matchingSessionID(logger, finishedNtfSessionID, reqSessionID)) {
|
||||
break;
|
||||
}
|
||||
logger.debug("setResponse(): finishedNtfSessionID={}.", finishedNtfSessionID);
|
||||
success = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link GetProductLimitation}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setActuatorIdAndLimitationType(int nodeId, boolean limitationMinimum) {
|
||||
logger.trace("setProductId({},{}) called.", nodeId, limitationMinimum);
|
||||
this.reqIndexArray01 = nodeId;
|
||||
this.reqLimitationType = limitationMinimum ? 0 : 1;
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLimitation() {
|
||||
return limitationValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProduct;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductName;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductSerialNo;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve Product</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setProductId(int)} to define the one specific product.</LI>
|
||||
* <LI>{@link #getProduct} to retrieve one specific product.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetProduct
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetProduct extends GetProduct implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetProduct.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve Product";
|
||||
private static final Command COMMAND = Command.GW_GET_NODE_INFORMATION_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqNodeID;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
private VeluxProduct product = VeluxProduct.UNKNOWN;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
logger.trace("getRequestDataAsArrayOfBytes() returns data for retrieving node with id {}.", reqNodeID);
|
||||
Packet request = new Packet(new byte[1]);
|
||||
request.setOneByteValue(0, reqNodeID);
|
||||
requestData = request.toByteArray();
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_GET_NODE_INFORMATION_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int cfmStatus = responseData.getOneByteValue(0);
|
||||
int cfmNodeID = responseData.getOneByteValue(1);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.trace("setResponse(): returned status: OK - Request accepted.");
|
||||
if (!KLF200Response.check4matchingNodeID(logger, reqNodeID, cfmNodeID)) {
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
finished = true;
|
||||
logger.trace("setResponse(): returned status: Error – Request rejected.");
|
||||
break;
|
||||
case 2:
|
||||
finished = true;
|
||||
logger.trace("setResponse(): returned status: Error – Invalid node index.");
|
||||
break;
|
||||
default:
|
||||
finished = true;
|
||||
logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
|
||||
Command.get(responseCommand).toString(), cfmStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_GET_NODE_INFORMATION_NTF:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 124)) {
|
||||
break;
|
||||
}
|
||||
// Extracting information items
|
||||
int ntfNodeID = responseData.getOneByteValue(0);
|
||||
logger.trace("setResponse(): ntfNodeID={}.", ntfNodeID);
|
||||
int ntfOrder = responseData.getTwoByteValue(1);
|
||||
logger.trace("setResponse(): ntfOrder={}.", ntfOrder);
|
||||
int ntfPlacement = responseData.getOneByteValue(3);
|
||||
logger.trace("setResponse(): ntfPlacement={}.", ntfPlacement);
|
||||
String ntfName = responseData.getString(4, 64);
|
||||
logger.trace("setResponse(): ntfName={}.", ntfName);
|
||||
int ntfVelocity = responseData.getOneByteValue(68);
|
||||
logger.trace("setResponse(): ntfVelocity={}.", ntfVelocity);
|
||||
int ntfNodeTypeSubType = responseData.getTwoByteValue(69);
|
||||
logger.trace("setResponse(): ntfNodeTypeSubType={} ({}).", ntfNodeTypeSubType,
|
||||
VeluxProductType.get(ntfNodeTypeSubType));
|
||||
logger.trace("setResponse(): derived product description={}.",
|
||||
VeluxProductType.toString(ntfNodeTypeSubType));
|
||||
int ntfProductGroup = responseData.getTwoByteValue(71);
|
||||
logger.trace("setResponse(): ntfProductGroup={}.", ntfProductGroup);
|
||||
int ntfProductType = responseData.getOneByteValue(72);
|
||||
logger.trace("setResponse(): ntfProductType={}.", ntfProductType);
|
||||
int ntfNodeVariation = responseData.getOneByteValue(73);
|
||||
logger.trace("setResponse(): ntfNodeVariation={}.", ntfNodeVariation);
|
||||
int ntfPowerMode = responseData.getOneByteValue(74);
|
||||
logger.trace("setResponse(): ntfPowerMode={}.", ntfPowerMode);
|
||||
int ntfBuildNumber = responseData.getOneByteValue(75);
|
||||
logger.trace("setResponse(): ntfBuildNumber={}.", ntfBuildNumber);
|
||||
byte[] ntfSerialNumber = responseData.getByteArray(76, 8);
|
||||
logger.trace("setResponse(): ntfSerialNumber={}.", ntfSerialNumber);
|
||||
int ntfState = responseData.getOneByteValue(84);
|
||||
logger.trace("setResponse(): ntfState={}.", ntfState);
|
||||
int ntfCurrentPosition = responseData.getTwoByteValue(85);
|
||||
logger.trace("setResponse(): ntfCurrentPosition={}.", ntfCurrentPosition);
|
||||
int ntfTarget = responseData.getTwoByteValue(87);
|
||||
logger.trace("setResponse(): ntfTarget={}.", ntfTarget);
|
||||
int ntfFP1CurrentPosition = responseData.getTwoByteValue(89);
|
||||
logger.trace("setResponse(): ntfFP1CurrentPosition={}.", ntfFP1CurrentPosition);
|
||||
int ntfFP2CurrentPosition = responseData.getTwoByteValue(91);
|
||||
logger.trace("setResponse(): ntfFP2CurrentPosition={}.", ntfFP2CurrentPosition);
|
||||
int ntfFP3CurrentPosition = responseData.getTwoByteValue(93);
|
||||
logger.trace("setResponse(): ntfFP3CurrentPosition={}.", ntfFP3CurrentPosition);
|
||||
int ntfFP4CurrentPosition = responseData.getTwoByteValue(95);
|
||||
logger.trace("setResponse(): ntfFP4CurrentPosition={}.", ntfFP4CurrentPosition);
|
||||
int ntfRemainingTime = responseData.getFourByteValue(97);
|
||||
logger.trace("setResponse(): ntfRemainingTime={}.", ntfRemainingTime);
|
||||
int ntfTimeStamp = responseData.getFourByteValue(99);
|
||||
logger.trace("setResponse(): ntfTimeStamp={}.", ntfTimeStamp);
|
||||
int ntfNbrOfAlias = responseData.getOneByteValue(103);
|
||||
logger.trace("setResponse(): ntfNbrOfAlias={}.", ntfNbrOfAlias);
|
||||
int ntfAliasOne = responseData.getFourByteValue(104);
|
||||
logger.trace("setResponse(): ntfAliasOne={}.", ntfAliasOne);
|
||||
int ntfAliasTwo = responseData.getFourByteValue(108);
|
||||
logger.trace("setResponse(): ntfAliasTwo={}.", ntfAliasTwo);
|
||||
int ntfAliasThree = responseData.getFourByteValue(112);
|
||||
logger.trace("setResponse(): ntfAliasThree={}.", ntfAliasThree);
|
||||
int ntfAliasFour = responseData.getFourByteValue(116);
|
||||
logger.trace("setResponse(): ntfAliasFour={}.", ntfAliasFour);
|
||||
int ntfAliasFive = responseData.getFourByteValue(120);
|
||||
logger.trace("setResponse(): ntfAliasFive={}.", ntfAliasFive);
|
||||
|
||||
if (!KLF200Response.check4matchingNodeID(logger, reqNodeID, ntfNodeID)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ntfName.length() == 0) || ntfName.startsWith("_")) {
|
||||
ntfName = "#".concat(String.valueOf(ntfNodeID));
|
||||
logger.debug("setResponse(): device provided invalid name, using '{}' instead.", ntfName);
|
||||
}
|
||||
String commonSerialNumber = VeluxProductSerialNo.toString(ntfSerialNumber);
|
||||
if (VeluxProductSerialNo.isInvalid(ntfSerialNumber)) {
|
||||
commonSerialNumber = new String(ntfName);
|
||||
logger.debug("setResponse(): device provided invalid serial number, using name '{}' instead.",
|
||||
commonSerialNumber);
|
||||
}
|
||||
|
||||
product = new VeluxProduct(new VeluxProductName(ntfName), VeluxProductType.get(ntfNodeTypeSubType),
|
||||
new ProductBridgeIndex(ntfNodeID), ntfOrder, ntfPlacement, ntfVelocity, ntfNodeVariation,
|
||||
ntfPowerMode, commonSerialNumber, ntfState, ntfCurrentPosition, ntfTarget, ntfRemainingTime,
|
||||
ntfTimeStamp);
|
||||
success = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link GetProduct}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setProductId(int nodeId) {
|
||||
logger.trace("setProductId({}) called.", nodeId);
|
||||
this.reqNodeID = nodeId;
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VeluxProduct getProduct() {
|
||||
logger.trace("getProduct(): returning product {}.", product);
|
||||
return product;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProducts;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductName;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductSerialNo;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve Products</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #getProducts()} to retrieve the currently registered products.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetProducts
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetProducts extends GetProducts implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetProducts.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve Products";
|
||||
private static final Command COMMAND = Command.GW_GET_ALL_NODES_INFORMATION_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
private VeluxProduct[] productArray = new VeluxProduct[0];
|
||||
private int totalNumberOfProducts = 0;
|
||||
private int nextProductArrayItem = 0;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
requestData = new byte[0];
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_GET_ALL_NODES_INFORMATION_CFM:
|
||||
logger.trace("setResponse(): got GW_GET_ALL_NODES_INFORMATION_CFM.");
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int cfmStatus = responseData.getOneByteValue(0);
|
||||
int cfmTotalNumberOfNodes = responseData.getOneByteValue(1);
|
||||
logger.trace("setResponse(): status={}.", cfmStatus);
|
||||
logger.trace("setResponse(): TotalNumberOfNodes={}.", cfmTotalNumberOfNodes);
|
||||
|
||||
// Initialize storage area
|
||||
productArray = new VeluxProduct[0];
|
||||
nextProductArrayItem = 0;
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.trace("setResponse(): returned status: OK - Request accepted.");
|
||||
totalNumberOfProducts = cfmTotalNumberOfNodes;
|
||||
productArray = new VeluxProduct[totalNumberOfProducts];
|
||||
break;
|
||||
case 1:
|
||||
logger.trace("setResponse(): returned status: Error – System table empty.");
|
||||
finished = true;
|
||||
break;
|
||||
default:
|
||||
finished = true;
|
||||
logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
|
||||
Command.get(responseCommand).toString(), cfmStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GW_GET_ALL_NODES_INFORMATION_NTF:
|
||||
logger.trace("setResponse(): got GW_GET_ALL_NODES_INFORMATION_NTF.");
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 124)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
if (productArray.length == 0) {
|
||||
logger.warn("setResponse({}): sequence of answers unexpected.",
|
||||
Command.get(responseCommand).toString());
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
// Extracting information items
|
||||
int ntfNodeID = responseData.getOneByteValue(0);
|
||||
logger.trace("setResponse(): ntfNodeID={}.", ntfNodeID);
|
||||
int ntfOrder = responseData.getTwoByteValue(1);
|
||||
logger.trace("setResponse(): ntfOrder={}.", ntfOrder);
|
||||
int ntfPlacement = responseData.getOneByteValue(3);
|
||||
logger.trace("setResponse(): ntfPlacement={}.", ntfPlacement);
|
||||
String ntfName = responseData.getString(4, 64);
|
||||
logger.trace("setResponse(): ntfName={}.", ntfName);
|
||||
int ntfVelocity = responseData.getOneByteValue(68);
|
||||
logger.trace("setResponse(): ntfVelocity={}.", ntfVelocity);
|
||||
int ntfNodeTypeSubType = responseData.getTwoByteValue(69);
|
||||
logger.trace("setResponse(): ntfNodeTypeSubType={} ({}).", ntfNodeTypeSubType,
|
||||
VeluxProductType.get(ntfNodeTypeSubType));
|
||||
logger.trace("setResponse(): derived product description={}.",
|
||||
VeluxProductType.toString(ntfNodeTypeSubType));
|
||||
int ntfProductGroup = responseData.getOneByteValue(71);
|
||||
logger.trace("setResponse(): ntfProductGroup={}.", ntfProductGroup);
|
||||
int ntfProductType = responseData.getOneByteValue(72);
|
||||
logger.trace("setResponse(): ntfProductType={}.", ntfProductType);
|
||||
int ntfNodeVariation = responseData.getOneByteValue(73);
|
||||
logger.trace("setResponse(): ntfNodeVariation={}.", ntfNodeVariation);
|
||||
int ntfPowerMode = responseData.getOneByteValue(74);
|
||||
logger.trace("setResponse(): ntfPowerMode={}.", ntfPowerMode);
|
||||
int ntfBuildNumber = responseData.getOneByteValue(75);
|
||||
logger.trace("setResponse(): ntfBuildNumber={}.", ntfBuildNumber);
|
||||
byte[] ntfSerialNumber = responseData.getByteArray(76, 8);
|
||||
logger.trace("setResponse(): ntfSerialNumber={}.", ntfSerialNumber);
|
||||
int ntfState = responseData.getOneByteValue(84);
|
||||
logger.trace("setResponse(): ntfState={}.", ntfState);
|
||||
int ntfCurrentPosition = responseData.getTwoByteValue(85);
|
||||
logger.trace("setResponse(): ntfCurrentPosition={}.", ntfCurrentPosition);
|
||||
int ntfTarget = responseData.getTwoByteValue(87);
|
||||
logger.trace("setResponse(): ntfTarget={}.", ntfTarget);
|
||||
int ntfFP1CurrentPosition = responseData.getTwoByteValue(89);
|
||||
logger.trace("setResponse(): ntfFP1CurrentPosition={}.", ntfFP1CurrentPosition);
|
||||
int ntfFP2CurrentPosition = responseData.getTwoByteValue(91);
|
||||
logger.trace("setResponse(): ntfFP2CurrentPosition={}.", ntfFP2CurrentPosition);
|
||||
int ntfFP3CurrentPosition = responseData.getTwoByteValue(93);
|
||||
logger.trace("setResponse(): ntfFP3CurrentPosition={}.", ntfFP3CurrentPosition);
|
||||
int ntfFP4CurrentPosition = responseData.getTwoByteValue(95);
|
||||
logger.trace("setResponse(): ntfFP4CurrentPosition={}.", ntfFP4CurrentPosition);
|
||||
int ntfRemainingTime = responseData.getTwoByteValue(97);
|
||||
logger.trace("setResponse(): ntfRemainingTime={}.", ntfRemainingTime);
|
||||
int ntfTimeStamp = responseData.getFourByteValue(99);
|
||||
logger.trace("setResponse(): ntfTimeStamp={}.", ntfTimeStamp);
|
||||
int ntfNbrOfAlias = responseData.getOneByteValue(103);
|
||||
logger.trace("setResponse(): ntfNbrOfAlias={}.", ntfNbrOfAlias);
|
||||
int ntfAliasOne = responseData.getFourByteValue(104);
|
||||
logger.trace("setResponse(): ntfAliasOne={}.", ntfAliasOne);
|
||||
int ntfAliasTwo = responseData.getFourByteValue(108);
|
||||
logger.trace("setResponse(): ntfAliasTwo={}.", ntfAliasTwo);
|
||||
int ntfAliasThree = responseData.getFourByteValue(112);
|
||||
logger.trace("setResponse(): ntfAliasThree={}.", ntfAliasThree);
|
||||
int ntfAliasFour = responseData.getFourByteValue(116);
|
||||
logger.trace("setResponse(): ntfAliasFour={}.", ntfAliasFour);
|
||||
int ntfAliasFive = responseData.getFourByteValue(120);
|
||||
logger.trace("setResponse(): ntfAliasFive={}.", ntfAliasFive);
|
||||
|
||||
if ((ntfName.length() == 0) || ntfName.startsWith("_")) {
|
||||
ntfName = "#".concat(String.valueOf(ntfNodeID));
|
||||
logger.debug("setResponse(): device provided invalid name, using '{}' instead.", ntfName);
|
||||
}
|
||||
|
||||
String commonSerialNumber = VeluxProductSerialNo.toString(ntfSerialNumber);
|
||||
if (VeluxProductSerialNo.isInvalid(ntfSerialNumber)) {
|
||||
commonSerialNumber = new String(ntfName);
|
||||
logger.debug("setResponse(): device provided invalid serial number, using name '{}' instead.",
|
||||
commonSerialNumber);
|
||||
}
|
||||
|
||||
VeluxProduct product = new VeluxProduct(new VeluxProductName(ntfName),
|
||||
VeluxProductType.get(ntfNodeTypeSubType), new ProductBridgeIndex(ntfNodeID), ntfOrder,
|
||||
ntfPlacement, ntfVelocity, ntfNodeVariation, ntfPowerMode, commonSerialNumber, ntfState,
|
||||
ntfCurrentPosition, ntfTarget, ntfRemainingTime, ntfTimeStamp);
|
||||
if (nextProductArrayItem < totalNumberOfProducts) {
|
||||
productArray[nextProductArrayItem++] = product;
|
||||
} else {
|
||||
logger.warn("setResponse(): expected {} products, received one more, ignoring it.",
|
||||
totalNumberOfProducts);
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
|
||||
case GW_GET_ALL_NODES_INFORMATION_FINISHED_NTF:
|
||||
logger.trace("setResponse(): got GW_GET_ALL_NODES_INFORMATION_FINISHED_NTF.");
|
||||
logger.debug("setResponse(): finished-packet received.");
|
||||
success = true;
|
||||
finished = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link GetProducts}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public VeluxProduct[] getProducts() {
|
||||
if (success && finished) {
|
||||
logger.trace("getProducts(): returning array of {} products.", productArray.length);
|
||||
return productArray;
|
||||
} else {
|
||||
logger.trace("getProducts(): returning null.");
|
||||
return new VeluxProduct[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetScenes;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductState;
|
||||
import org.openhab.binding.velux.internal.things.VeluxScene;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve Scenes</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #getScenes()} to retrieve the set of current scenes.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetScenes
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetScenes extends GetScenes implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetScenes.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve Scenes";
|
||||
private static final Command COMMAND = Command.GW_GET_SCENE_LIST_REQ;
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private boolean success;
|
||||
private boolean finished;
|
||||
|
||||
private int sceneIdx;
|
||||
private VeluxScene[] scenes = new VeluxScene[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
return EMPTYDATA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_GET_SCENE_LIST_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 1)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int ntfTotalNumberOfObjects = responseData.getOneByteValue(0);
|
||||
scenes = new VeluxScene[ntfTotalNumberOfObjects];
|
||||
if (ntfTotalNumberOfObjects == 0) {
|
||||
logger.trace("setResponse(): no scenes defined.");
|
||||
success = true;
|
||||
finished = true;
|
||||
} else {
|
||||
logger.trace("setResponse(): {} scenes defined.", ntfTotalNumberOfObjects);
|
||||
}
|
||||
sceneIdx = 0;
|
||||
break;
|
||||
case GW_GET_SCENE_LIST_NTF:
|
||||
if (thisResponseData.length < 1) {
|
||||
logger.trace("setResponse(): malformed response packet (length is {} less than one).",
|
||||
thisResponseData.length);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int ntfNumberOfObject = responseData.getOneByteValue(0);
|
||||
logger.trace("setResponse(): NTF number of objects={}.", ntfNumberOfObject);
|
||||
if (ntfNumberOfObject == 0) {
|
||||
logger.trace("setResponse(): finished.");
|
||||
finished = true;
|
||||
success = true;
|
||||
}
|
||||
if (thisResponseData.length != (2 + 65 * ntfNumberOfObject)) {
|
||||
logger.trace("setResponse(): malformed response packet (real length {}, expected length {}).",
|
||||
thisResponseData.length, (2 + 65 * ntfNumberOfObject));
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
for (int objectIndex = 0; objectIndex < ntfNumberOfObject; objectIndex++) {
|
||||
int ntfSceneID = responseData.getOneByteValue(1 + 65 * objectIndex);
|
||||
int beginOfString = 2 + 65 * objectIndex;
|
||||
String ntfSceneName = responseData.getString(beginOfString, 64);
|
||||
logger.trace("setResponse(): scene {}, name {}.", ntfSceneID, ntfSceneName);
|
||||
scenes[sceneIdx++] = new VeluxScene(ntfSceneName, ntfSceneID, false, new VeluxProductState[0]);
|
||||
}
|
||||
int ntfRemainingNumberOfObject = responseData.getOneByteValue(1 + 65 * ntfNumberOfObject);
|
||||
logger.trace("setResponse(): {} scenes remaining.", ntfRemainingNumberOfObject);
|
||||
if (ntfRemainingNumberOfObject == 0) {
|
||||
logger.trace("setResponse(): finished.");
|
||||
finished = true;
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* ===========================================================
|
||||
* <P>
|
||||
* Public Methods required for abstract class {@link GetScenes}.
|
||||
*/
|
||||
@Override
|
||||
public VeluxScene[] getScenes() {
|
||||
logger.trace("getScenes(): returning {} scenes.", scenes.length);
|
||||
return scenes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetWLANConfig;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwWLAN;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve WLAN configuration</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #getWLANConfig} to retrieve the current WLAN configuration.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see GetWLANConfig
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCgetWLANConfig extends GetWLANConfig implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCgetWLANConfig.class);
|
||||
|
||||
private static final String DESCRIPTION = "Retrieve WLAN configuration";
|
||||
private static final Command COMMAND = Command.GW_GET_NETWORK_SETUP_REQ;
|
||||
|
||||
private static final String UNSUPPORTED = "*** unsupported-by-current-gateway-firmware ***";
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
private short responseCommand;
|
||||
@SuppressWarnings("unused")
|
||||
private byte @Nullable [] responseData;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
public SCgetWLANConfig() {
|
||||
logger.trace("SCgetWLANConfig(constructor) called.");
|
||||
requestData = new byte[1];
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short thisResponseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
logger.trace("setResponseCommand({}, {}) called.", thisResponseCommand, new Packet(thisResponseData));
|
||||
responseCommand = thisResponseCommand;
|
||||
responseData = thisResponseData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return (responseCommand == Command.GW_GET_NETWORK_SETUP_CFM.getShort());
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public VeluxGwWLAN getWLANConfig() {
|
||||
logger.trace("getWLANConfig() called.");
|
||||
// Enhancement idea: Velux should provide an enhanced API.
|
||||
return new VeluxGwWLAN(UNSUPPORTED, UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Login;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Authenticate / login</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setPassword(String)} to define the authentication reqPassword to be used.</LI>
|
||||
* <LI>{@link #getAuthToken()} to retrieve the authentication reqPassword.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see Login
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SClogin extends Login implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SClogin.class);
|
||||
|
||||
private static final String DESCRIPTION = "Authenticate / login";
|
||||
private static final Command COMMAND = Command.GW_PASSWORD_ENTER_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private String reqPassword = "";
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
requestData = new byte[32];
|
||||
byte[] password = reqPassword.getBytes();
|
||||
System.arraycopy(password, 0, requestData, 0, password.length);
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = true;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_PASSWORD_ENTER_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 1)) {
|
||||
break;
|
||||
}
|
||||
int cfmStatus = responseData.getOneByteValue(0);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.info("{} bridge connection successfully established (login succeeded).",
|
||||
VeluxBindingConstants.BINDING_ID);
|
||||
logger.debug("setResponse(): returned status: The request was successful.");
|
||||
success = true;
|
||||
break;
|
||||
case 1:
|
||||
logger.warn("{} bridge connection successfully established but login failed.",
|
||||
VeluxBindingConstants.BINDING_ID);
|
||||
logger.debug("setResponse(): returned status: The request failed.");
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse(): returned status={} (not defined).", cfmStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setPassword(String thisPassword) {
|
||||
logger.trace("setPassword({}) called.", thisPassword.replaceAll(".", "*"));
|
||||
reqPassword = thisPassword;
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthToken() {
|
||||
logger.trace("getAuthToken() called, returning {}.", reqPassword.replaceAll(".", "*"));
|
||||
return reqPassword;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Logout;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Retrieve LAN configuration</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* There are no methods in addition to the mentioned interface.
|
||||
*
|
||||
* @see Logout
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SClogout extends Logout implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SClogout.class);
|
||||
|
||||
private static final String DESCRIPTION = "Deauthenticate / logout";
|
||||
private static final Command COMMAND = Command.GW_OPENHAB_CLOSE;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private final byte[] emptyPacket = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
return emptyPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = true;
|
||||
finished = true;
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductCommand;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Send Command to Actuator</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setNodeAndMainParameter} to define the node and intended parameter value.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see RunProductCommand
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCrunProductCommand extends RunProductCommand implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCrunProductCommand.class);
|
||||
|
||||
private static final String DESCRIPTION = "Send Command to Actuator";
|
||||
private static final Command COMMAND = Command.GW_COMMAND_SEND_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqSessionID = 0;
|
||||
private int reqCommandOriginator = 8; // SAAC
|
||||
private int reqPriorityLevel = 5; // Comfort Level 2
|
||||
private int reqParameterActive = 0; // Main Parameter
|
||||
private int reqFPI1 = 0; // Functional Parameter Indicator 1 set of bits
|
||||
private int reqFPI2 = 0; // Functional Parameter Indicator 2 set of bits
|
||||
private int reqMainParameter = 0; // for FunctionalParameterValueArray
|
||||
private int reqIndexArrayCount = 1; // One node will be addressed
|
||||
private int reqIndexArray01 = 1; // This is the node
|
||||
private int reqPriorityLevelLock = 0; // Do not set a new lock on priority level
|
||||
private int reqPL03 = 0; // unused
|
||||
private int reqPL47 = 0; // unused
|
||||
private int reqLockTime = 0; // 30 seconds
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
public SCrunProductCommand() {
|
||||
logger.debug("SCgetProduct(Constructor) called.");
|
||||
Random rand = new Random();
|
||||
reqSessionID = rand.nextInt(0x0fff);
|
||||
logger.debug("SCgetProduct(): starting sessions with the random number {}.", reqSessionID);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {}.", COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
Packet request = new Packet(new byte[66]);
|
||||
reqSessionID = (reqSessionID + 1) & 0xffff;
|
||||
request.setTwoByteValue(0, reqSessionID);
|
||||
request.setOneByteValue(2, reqCommandOriginator);
|
||||
request.setOneByteValue(3, reqPriorityLevel);
|
||||
request.setOneByteValue(4, reqParameterActive);
|
||||
request.setOneByteValue(5, reqFPI1);
|
||||
request.setOneByteValue(6, reqFPI2);
|
||||
request.setTwoByteValue(7, reqMainParameter);
|
||||
request.setOneByteValue(41, reqIndexArrayCount);
|
||||
request.setOneByteValue(42, reqIndexArray01);
|
||||
request.setOneByteValue(62, reqPriorityLevelLock);
|
||||
request.setOneByteValue(63, reqPL03);
|
||||
request.setOneByteValue(64, reqPL47);
|
||||
request.setOneByteValue(65, reqLockTime);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): ntfSessionID={}.", reqSessionID);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqCommandOriginator={}.", reqCommandOriginator);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqPriorityLevel={}.", reqPriorityLevel);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqParameterActive={}.", reqParameterActive);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqFPI1={}.", reqFPI1);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqFPI2={}.", reqFPI2);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqMainParameter={}.", reqMainParameter);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArrayCount={}.", reqIndexArrayCount);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArray01={}.", reqIndexArray01);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqPriorityLevelLock={}.", reqPriorityLevelLock);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqPL03={}.", reqPL03);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqPL47={}.", reqPL47);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqLockTime={}.", reqLockTime);
|
||||
requestData = request.toByteArray();
|
||||
logger.trace("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_COMMAND_SEND_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int cfmSessionID = responseData.getTwoByteValue(0);
|
||||
int cfmStatus = responseData.getOneByteValue(2);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.info("setResponse(): returned status: Error – Command rejected.");
|
||||
finished = true;
|
||||
break;
|
||||
case 1:
|
||||
logger.debug("setResponse(): returned status: OK - Command is accepted.");
|
||||
if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
} else if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
finished = true;
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse(): returned status={} (not defined).", cfmStatus);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_COMMAND_RUN_STATUS_NTF:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int ntfSessionID = responseData.getTwoByteValue(0);
|
||||
int ntfStatusiD = responseData.getOneByteValue(2);
|
||||
int ntfIndex = responseData.getOneByteValue(3);
|
||||
int ntfNodeParameter = responseData.getOneByteValue(4);
|
||||
int ntfParameterValue = responseData.getTwoByteValue(5);
|
||||
int ntfRunStatus = responseData.getOneByteValue(7);
|
||||
int ntfStatusReply = responseData.getOneByteValue(8);
|
||||
int ntfInformationCode = responseData.getFourByteValue(9);
|
||||
// Extracting information items
|
||||
logger.debug("setResponse(): ntfSessionID={} (requested {}).", ntfSessionID, reqSessionID);
|
||||
logger.debug("setResponse(): ntfStatusiD={}.", ntfStatusiD);
|
||||
logger.debug("setResponse(): ntfIndex={}.", ntfIndex);
|
||||
logger.debug("setResponse(): ntfNodeParameter={}.", ntfNodeParameter);
|
||||
logger.debug("setResponse(): ntfParameterValue={}.", ntfParameterValue);
|
||||
logger.debug("setResponse(): ntfRunStatus={}.", ntfRunStatus);
|
||||
logger.debug("setResponse(): ntfStatusReply={}.", ntfStatusReply);
|
||||
logger.debug("setResponse(): ntfInformationCode={}.", ntfInformationCode);
|
||||
|
||||
if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
}
|
||||
switch (ntfRunStatus) {
|
||||
case 0:
|
||||
logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_COMPLETED.");
|
||||
success = true;
|
||||
break;
|
||||
case 1:
|
||||
logger.info("setResponse(): returned ntfRunStatus: EXECUTION_FAILED.");
|
||||
finished = true;
|
||||
break;
|
||||
case 2:
|
||||
logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_ACTIVE.");
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse(): returned ntfRunStatus={} (not defined).", ntfRunStatus);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
success = true;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_COMMAND_REMAINING_TIME_NTF:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 6)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int timeNtfSessionID = responseData.getTwoByteValue(0);
|
||||
int timeNtfIndex = responseData.getOneByteValue(2);
|
||||
int timeNtfNodeParameter = responseData.getOneByteValue(3);
|
||||
int timeNtfSeconds = responseData.getTwoByteValue(4);
|
||||
|
||||
if (!KLF200Response.check4matchingSessionID(logger, timeNtfSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
}
|
||||
|
||||
// Extracting information items
|
||||
logger.debug("setResponse(): timeNtfSessionID={}.", timeNtfSessionID);
|
||||
logger.debug("setResponse(): timeNtfIndex={}.", timeNtfIndex);
|
||||
logger.debug("setResponse(): timeNtfNodeParameter={}.", timeNtfNodeParameter);
|
||||
logger.debug("setResponse(): timeNtfSeconds={}.", timeNtfSeconds);
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
success = true;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_SESSION_FINISHED_NTF:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
|
||||
break;
|
||||
}
|
||||
int finishedNtfSessionID = responseData.getTwoByteValue(0);
|
||||
if (!KLF200Response.check4matchingSessionID(logger, finishedNtfSessionID, reqSessionID)) {
|
||||
break;
|
||||
}
|
||||
logger.debug("setResponse(): finishedNtfSessionID={}.", finishedNtfSessionID);
|
||||
success = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link RunProductCommand}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public SCrunProductCommand setNodeAndMainParameter(int nodeId, int value) {
|
||||
logger.debug("setNodeAndMainParameter({}) called.", nodeId);
|
||||
this.reqIndexArray01 = nodeId;
|
||||
this.reqMainParameter = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductDiscovery;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Ask the Bridge to detect (new) products/actuators</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* There are no methods in addition to the mentioned interface.
|
||||
*
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCrunProductDiscovery extends RunProductDiscovery implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCrunProductDiscovery.class);
|
||||
|
||||
private static final String DESCRIPTION = "Detect Products/Actuators";
|
||||
private static final Command COMMAND = Command.GW_CS_DISCOVER_NODES_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqNodeType = 0; // NO_TYPE (All nodes except controller)
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
logger.trace("getRequestDataAsArrayOfBytes() returns data for detection with type {}.", reqNodeType);
|
||||
Packet request = new Packet(new byte[1]);
|
||||
request.setOneByteValue(0, reqNodeType);
|
||||
requestData = request.toByteArray();
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_CS_DISCOVER_NODES_CFM:
|
||||
logger.trace("setResponse(): received confirmation for discovery mode.");
|
||||
break;
|
||||
|
||||
case GW_CS_DISCOVER_NODES_NTF:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 131)) {
|
||||
break;
|
||||
}
|
||||
int ntfDiscoverStatus = responseData.getOneByteValue(130);
|
||||
switch (ntfDiscoverStatus) {
|
||||
case 0:
|
||||
logger.trace("setResponse(): returned status: OK. Discovered nodes. See bit array.");
|
||||
success = true;
|
||||
break;
|
||||
case 5:
|
||||
logger.warn("setResponse(): returned status: ERROR - Failed. CS not ready.");
|
||||
break;
|
||||
case 6:
|
||||
logger.trace(
|
||||
"setResponse(): returned status: OK. But some nodes were not added to system table (e.g. System table has reached its limit).");
|
||||
break;
|
||||
case 7:
|
||||
logger.warn("setResponse(): returned status: ERROR - CS busy with another task.");
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
|
||||
Command.get(responseCommand).toString(), ntfDiscoverStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductIdentification;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Identify Product</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setProductId(int)} to define the intended product.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see RunProductIdentification
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCrunProductIdentification extends RunProductIdentification implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCrunProductIdentification.class);
|
||||
|
||||
private static final String DESCRIPTION = "Identify Product";
|
||||
private static final Command COMMAND = Command.GW_WINK_SEND_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqSessionID = 0;
|
||||
private int reqCommandOriginator = 8; // SAAC
|
||||
private int reqPriorityLevel = 5; // Comfort Level 2
|
||||
private int reqWinkState = 1; // Enable wink
|
||||
private int reqWinkTime = 2; // Winktime = 2 seconds
|
||||
private int reqIndexArrayCount = 1; // Number of actuators to be winking
|
||||
private int reqIndexValue0 = 0; // Value for the ONE actuator
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the session id {@link #reqSessionID} with a random start value.
|
||||
*/
|
||||
public SCrunProductIdentification() {
|
||||
logger.debug("SCrunProductIdentification(Constructor) called.");
|
||||
Random rand = new Random();
|
||||
reqSessionID = rand.nextInt(0x0fff);
|
||||
logger.debug("SCrunProductIdentification(): starting sessions with the random number {}.", reqSessionID);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
Packet request = new Packet(new byte[27]);
|
||||
reqSessionID = (reqSessionID + 1) & 0xffff;
|
||||
request.setTwoByteValue(0, reqSessionID);
|
||||
request.setOneByteValue(2, reqCommandOriginator);
|
||||
request.setOneByteValue(3, reqPriorityLevel);
|
||||
request.setOneByteValue(4, reqWinkState);
|
||||
request.setOneByteValue(5, reqWinkTime);
|
||||
request.setOneByteValue(6, reqIndexArrayCount);
|
||||
request.setTwoByteValue(7, reqIndexValue0);
|
||||
requestData = request.toByteArray();
|
||||
logger.trace("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_WINK_SEND_CFM:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
|
||||
break;
|
||||
}
|
||||
int cfmSessionID = responseData.getTwoByteValue(0);
|
||||
int cfmStatus = responseData.getOneByteValue(2);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.trace("setResponse(): returned status: Error - Wink is rejected.");
|
||||
break;
|
||||
case 1:
|
||||
if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
|
||||
break;
|
||||
}
|
||||
logger.trace("setResponse(): returned status: OK – Wink is accepted.");
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
|
||||
Command.get(responseCommand).toString(), cfmStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link RunProductIdentification}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor Addon Method.
|
||||
* <P>
|
||||
* Passes the intended Actuator Identifier towards this class for building the request.
|
||||
*
|
||||
* @param actuatorId as type int describing the scene to be processed.
|
||||
* @return <b>this</b> of type {@link SCrunProductIdentification} as class itself.
|
||||
*/
|
||||
@Override
|
||||
public SCrunProductIdentification setProductId(int actuatorId) {
|
||||
logger.trace("setProductId({}) called.", actuatorId);
|
||||
this.reqIndexValue0 = actuatorId;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductSearch;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxGwState;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Check for lost Nodes</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* Implementing the protocol-independent class {@link RunProductSearch}.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link SCrunProductSearch#getState} to retrieve the Velux gateway status.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see RunProductSearch
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCrunProductSearch extends RunProductSearch implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCrunProductSearch.class);
|
||||
|
||||
private static final String DESCRIPTION = "Check for lost Nodes";
|
||||
private static final Command COMMAND = Command.GW_GET_STATE_REQ;
|
||||
|
||||
/*
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
private short responseCommand;
|
||||
private byte[] responseData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link SlipBridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
requestData = new byte[0];
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short thisResponseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
logger.trace("setResponseCommand({}, {}) called.", thisResponseCommand, new Packet(thisResponseData));
|
||||
responseCommand = thisResponseCommand;
|
||||
responseData = thisResponseData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return (responseCommand == Command.GW_GET_STATE_CFM.getShort());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return (responseCommand == Command.GW_GET_STATE_CFM.getShort());
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
public VeluxGwState getState() {
|
||||
byte stateValue = responseData[0];
|
||||
byte subStateValue = responseData[1];
|
||||
VeluxGwState thisGwState = new VeluxGwState(stateValue, subStateValue);
|
||||
logger.trace("getState() returns {} ({}).", thisGwState, thisGwState.toDescription());
|
||||
return thisGwState;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunScene;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Run Scene</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setSceneId} to define the scene to be executed.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see RunScene
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCrunScene extends RunScene implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCrunScene.class);
|
||||
|
||||
private static final String DESCRIPTION = "Run Scene";
|
||||
private static final Command COMMAND = Command.GW_ACTIVATE_SCENE_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqSessionID = 0;
|
||||
private int reqCommandOriginator = 8; // SAAC
|
||||
private int reqPriorityLevel = 5; // Comfort Level 2
|
||||
private int reqSceneID = -1; // SceneID as one unsigned byte number
|
||||
private int reqVelocity = 0; // The product group operates by its default velocity.
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Initializes the session id {@link #reqSessionID} with a random start value.
|
||||
*/
|
||||
public SCrunScene() {
|
||||
logger.debug("SCrunScene(Constructor) called.");
|
||||
Random rand = new Random();
|
||||
reqSessionID = rand.nextInt(0x0fff);
|
||||
logger.debug("SCrunScene(): starting sessions with the random number {}.", reqSessionID);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.trace("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
Packet request = new Packet(new byte[6]);
|
||||
reqSessionID = (reqSessionID + 1) & 0xffff;
|
||||
request.setTwoByteValue(0, reqSessionID);
|
||||
request.setOneByteValue(2, reqCommandOriginator);
|
||||
request.setOneByteValue(3, reqPriorityLevel);
|
||||
request.setOneByteValue(4, reqSceneID);
|
||||
request.setOneByteValue(5, reqVelocity);
|
||||
requestData = request.toByteArray();
|
||||
logger.trace("getRequestCommand(): SessionID={}.", reqSessionID);
|
||||
logger.trace("getRequestCommand(): CommandOriginator={}.", reqCommandOriginator);
|
||||
logger.trace("getRequestCommand(): PriorityLevel={}.", reqPriorityLevel);
|
||||
logger.trace("getRequestCommand(): SceneID={}.", reqSceneID);
|
||||
logger.trace("getRequestCommand(): Velocity={}.", reqVelocity);
|
||||
logger.debug("getRequestCommand() returns {} ({}) with SceneID {}.", COMMAND.name(), COMMAND.getCommand(),
|
||||
reqSceneID);
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_ACTIVATE_SCENE_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int cfmStatus = responseData.getOneByteValue(0);
|
||||
int cfmSessionID = responseData.getTwoByteValue(1);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.trace("setResponse(): returned status: OK - Request accepted.");
|
||||
if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
} else if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
success = true;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
finished = true;
|
||||
logger.trace("setResponse(): returned status: Error – Invalid parameter.");
|
||||
break;
|
||||
case 2:
|
||||
finished = true;
|
||||
logger.trace("setResponse(): returned status: Error – Request rejected.");
|
||||
break;
|
||||
default:
|
||||
finished = true;
|
||||
logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
|
||||
Command.get(responseCommand).toString(), cfmStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_COMMAND_RUN_STATUS_NTF:
|
||||
logger.trace("setResponse(): received GW_COMMAND_RUN_STATUS_NTF, continuing.");
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
|
||||
logger.trace("setResponse(): GW_COMMAND_RUN_STATUS_NTF received with invalid length.");
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
// Extracting information items
|
||||
int ntfSessionID = responseData.getTwoByteValue(0);
|
||||
int ntfStatusID = responseData.getOneByteValue(2);
|
||||
int ntfIndex = responseData.getOneByteValue(3);
|
||||
int ntfNodeParameter = responseData.getOneByteValue(4);
|
||||
int ntfParameterValue = responseData.getTwoByteValue(5);
|
||||
int ntfRunStatus = responseData.getOneByteValue(7);
|
||||
int ntfStatusReply = responseData.getOneByteValue(8);
|
||||
int ntfInformationCode = responseData.getFourByteValue(9);
|
||||
|
||||
logger.trace("setResponse(): SessionID={}.", ntfSessionID);
|
||||
logger.trace("setResponse(): StatusID={}.", ntfStatusID);
|
||||
logger.trace("setResponse(): Index={}.", ntfIndex);
|
||||
logger.trace("setResponse(): NodeParameter={}.", ntfNodeParameter);
|
||||
logger.trace("setResponse(): ParameterValue={}.", ntfParameterValue);
|
||||
logger.trace("setResponse(): RunStatus={}.", ntfRunStatus);
|
||||
logger.trace("setResponse(): StatusReply={}.", ntfStatusReply);
|
||||
logger.trace("setResponse(): InformationCode={}.", ntfInformationCode);
|
||||
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
success = true;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_COMMAND_REMAINING_TIME_NTF:
|
||||
logger.trace("setResponse(): received GW_COMMAND_REMAINING_TIME_NTF, continuing.");
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 6)) {
|
||||
logger.trace("setResponse(): GW_COMMAND_REMAINING_TIME_NTF received with invalid length.");
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
// Extracting information items
|
||||
ntfSessionID = responseData.getTwoByteValue(0);
|
||||
ntfIndex = responseData.getOneByteValue(2);
|
||||
ntfNodeParameter = responseData.getOneByteValue(3);
|
||||
int ntfSeconds = responseData.getTwoByteValue(4);
|
||||
|
||||
logger.trace("setResponse(): SessionID={}.", ntfSessionID);
|
||||
logger.trace("setResponse(): Index={}.", ntfIndex);
|
||||
logger.trace("setResponse(): NodeParameter={}.", ntfNodeParameter);
|
||||
logger.trace("setResponse(): Seconds={}.", ntfSeconds);
|
||||
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
success = true;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_SESSION_FINISHED_NTF:
|
||||
logger.trace("setResponse(): received GW_SESSION_FINISHED_NTF.");
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
|
||||
logger.trace("setResponse(): GW_SESSION_FINISHED_NTF received with invalid length.");
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
// Extracting information items
|
||||
ntfSessionID = responseData.getTwoByteValue(0);
|
||||
|
||||
logger.trace("setResponse(): SessionID={}.", ntfSessionID);
|
||||
|
||||
success = true;
|
||||
finished = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link RunScene}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public SCrunScene setSceneId(int sceneId) {
|
||||
logger.trace("setProductId({}) called.", sceneId);
|
||||
this.reqSceneID = sceneId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SCrunScene setVelocity(int velocity) {
|
||||
logger.trace("setVelocity({}) called.", velocity);
|
||||
this.reqVelocity = velocity;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetHouseStatusMonitor;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Modify HouseStatusMonitor</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #serviceActivation} to define the new service activation state.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see SetHouseStatusMonitor
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCsetHouseStatusMonitor extends SetHouseStatusMonitor implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCsetHouseStatusMonitor.class);
|
||||
|
||||
private static final String DESCRIPTION = "Modify HouseStatusMonitor";
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private boolean activateService = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
Command command = activateService ? Command.GW_HOUSE_STATUS_MONITOR_ENABLE_REQ
|
||||
: Command.GW_HOUSE_STATUS_MONITOR_DISABLE_REQ;
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", command.name(), command.getCommand());
|
||||
return command.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
logger.debug("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = true;
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_HOUSE_STATUS_MONITOR_ENABLE_CFM:
|
||||
logger.trace("setResponse(): service enable confirmed by bridge.");
|
||||
// returned enabled: successful if enable requested
|
||||
success = activateService;
|
||||
break;
|
||||
case GW_HOUSE_STATUS_MONITOR_DISABLE_CFM:
|
||||
logger.trace("setResponse(): service disable confirmed by bridge.");
|
||||
// returned disabled: successful if disable requested
|
||||
success = !activateService;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link SetHouseStatusMonitor}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public SetHouseStatusMonitor serviceActivation(boolean enableService) {
|
||||
this.activateService = enableService;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductPosition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Modify Product Limitations</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setActuatorIdAndMinimumLimitation} to set the lower limitation of one specific product.</LI>
|
||||
* <LI>{@link #setActuatorIdAndMaximumLimitation} to set the higher limitation of one specific product.</LI>
|
||||
* <LI>{@link #setActuatorIdAndResetLimitation} to reset any limitation of one specific product.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see SetProductLimitation
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SCsetLimitation extends SetProductLimitation implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCsetLimitation.class);
|
||||
|
||||
private static final String DESCRIPTION = "Modify Actuator Limitation";
|
||||
private static final Command COMMAND = Command.GW_SET_LIMITATION_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqSessionID = 0;
|
||||
private int reqCommandOriginator = 8; // SAAC
|
||||
private int reqPriorityLevel = 5; // Comfort Level 2
|
||||
private int reqIndexArrayCount = 1; // One node will be addressed
|
||||
private int reqIndexArray01 = 1; // This is the node
|
||||
private int reqParameterID = 0; // MP = Main parameter
|
||||
private int reqLimitationValueMin = VeluxProductPosition.VPP_VELUX_IGNORE; // will be set lateron
|
||||
private int reqLimitationValueMax = VeluxProductPosition.VPP_VELUX_IGNORE; // will be set lateron
|
||||
private int reqLimitationTime = 0; // 0 = 30 seconds, 1 = 60 seconds, ..., 253 = unlimited, 254 = clear entry for
|
||||
// the Master, 255 = clear all
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
public SCsetLimitation() {
|
||||
logger.debug("SCsetLimitation(Constructor) called.");
|
||||
Random rand = new Random();
|
||||
reqSessionID = rand.nextInt(0x0fff);
|
||||
logger.debug("SCsetLimitation(): starting sessions with the random number {}.", reqSessionID);
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {} ({}).", COMMAND.name(), COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
Packet request = new Packet(new byte[31]);
|
||||
reqSessionID = (reqSessionID + 1) & 0xffff;
|
||||
request.setTwoByteValue(0, reqSessionID);
|
||||
request.setOneByteValue(2, reqCommandOriginator);
|
||||
request.setOneByteValue(3, reqPriorityLevel);
|
||||
request.setOneByteValue(4, reqIndexArrayCount);
|
||||
request.setOneByteValue(5, reqIndexArray01);
|
||||
request.setOneByteValue(25, reqParameterID);
|
||||
request.setTwoByteValue(26, reqLimitationValueMin);
|
||||
request.setTwoByteValue(28, reqLimitationValueMax);
|
||||
request.setOneByteValue(30, reqLimitationTime);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): ntfSessionID={}.", reqSessionID);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqCommandOriginator={}.", reqCommandOriginator);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqPriorityLevel={}.", reqPriorityLevel);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArrayCount={}.", reqIndexArrayCount);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqIndexArray01={}.", reqIndexArray01);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqParameterID={}.", reqParameterID);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqLimitationValueMin={}.", reqLimitationValueMin);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqLimitationValueMax={}.", reqLimitationValueMax);
|
||||
logger.trace("getRequestDataAsArrayOfBytes(): reqLimitationTime={}.", reqLimitationTime);
|
||||
requestData = request.toByteArray();
|
||||
logger.trace("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_SET_LIMITATION_CFM:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
int cfmSessionID = responseData.getTwoByteValue(0);
|
||||
int cfmStatus = responseData.getOneByteValue(2);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.info("setResponse(): returned status: Error – Command rejected.");
|
||||
finished = true;
|
||||
break;
|
||||
case 1:
|
||||
logger.debug("setResponse(): returned status: OK - Command is accepted.");
|
||||
if (!KLF200Response.check4matchingSessionID(logger, cfmSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse(): returned status={} (not defined).", cfmStatus);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_LIMITATION_STATUS_NTF:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 10)) {
|
||||
break;
|
||||
}
|
||||
// Extracting information items
|
||||
int ntfSessionID = responseData.getTwoByteValue(0);
|
||||
int ntfNodeID = responseData.getOneByteValue(2);
|
||||
int ntfParameterID = responseData.getOneByteValue(3);
|
||||
int ntfMinValue = responseData.getTwoByteValue(4);
|
||||
int ntfMaxValue = responseData.getTwoByteValue(6);
|
||||
int ntfLimitationOriginator = responseData.getOneByteValue(8);
|
||||
int ntfLimitationTime = responseData.getOneByteValue(9);
|
||||
logger.trace("setResponse(): nodeId={}.", ntfNodeID);
|
||||
logger.trace("setResponse(): ntfParameterID={}.", ntfParameterID);
|
||||
logger.trace("setResponse(): ntfMinValue={}.", ntfMinValue);
|
||||
logger.trace("setResponse(): ntfMaxValue={}.", ntfMaxValue);
|
||||
logger.trace("setResponse(): ntfLimitationOriginator={}.", ntfLimitationOriginator);
|
||||
logger.trace("setResponse(): ntfLimitationTime={}.", ntfLimitationTime);
|
||||
|
||||
if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
success = true;
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_COMMAND_RUN_STATUS_NTF:
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 13)) {
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
ntfSessionID = responseData.getTwoByteValue(0);
|
||||
int ntfStatusiD = responseData.getOneByteValue(2);
|
||||
int ntfIndex = responseData.getOneByteValue(3);
|
||||
int ntfNodeParameter = responseData.getOneByteValue(4);
|
||||
int ntfParameterValue = responseData.getTwoByteValue(5);
|
||||
int ntfRunStatus = responseData.getOneByteValue(7);
|
||||
int ntfStatusReply = responseData.getOneByteValue(8);
|
||||
int ntfInformationCode = responseData.getFourByteValue(9);
|
||||
// Extracting information items
|
||||
logger.trace("setResponse(): ntfSessionID={} (requested {}).", ntfSessionID, reqSessionID);
|
||||
logger.trace("setResponse(): ntfStatusiD={}.", ntfStatusiD);
|
||||
logger.trace("setResponse(): ntfIndex={}.", ntfIndex);
|
||||
logger.trace("setResponse(): ntfNodeParameter={}.", ntfNodeParameter);
|
||||
logger.trace("setResponse(): ntfParameterValue={}.", ntfParameterValue);
|
||||
logger.trace("setResponse(): ntfRunStatus={}.", ntfRunStatus);
|
||||
logger.trace("setResponse(): ntfStatusReply={}.", ntfStatusReply);
|
||||
logger.trace("setResponse(): ntfInformationCode={}.", ntfInformationCode);
|
||||
|
||||
if (!KLF200Response.check4matchingSessionID(logger, ntfSessionID, reqSessionID)) {
|
||||
finished = true;
|
||||
}
|
||||
switch (ntfRunStatus) {
|
||||
case 0:
|
||||
logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_COMPLETED.");
|
||||
success = true;
|
||||
break;
|
||||
case 1:
|
||||
logger.info("setResponse(): returned ntfRunStatus: EXECUTION_FAILED.");
|
||||
finished = true;
|
||||
break;
|
||||
case 2:
|
||||
logger.debug("setResponse(): returned ntfRunStatus: EXECUTION_ACTIVE.");
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse(): returned ntfRunStatus={} (not defined).", ntfRunStatus);
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"setResponse(): skipping wait for more packets as sequential processing is not enforced.");
|
||||
success = true;
|
||||
finished = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case GW_SESSION_FINISHED_NTF:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 2)) {
|
||||
break;
|
||||
}
|
||||
int finishedNtfSessionID = responseData.getTwoByteValue(0);
|
||||
if (!KLF200Response.check4matchingSessionID(logger, finishedNtfSessionID, reqSessionID)) {
|
||||
break;
|
||||
}
|
||||
logger.debug("setResponse(): finishedNtfSessionID={}.", finishedNtfSessionID);
|
||||
success = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link SetProductLimitation}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setActuatorIdAndMinimumLimitation(int nodeId, int limitation) {
|
||||
logger.trace("setActuatorIdAndLimitationTypeAndLimitation({},{}) called.", nodeId, limitation);
|
||||
reqIndexArray01 = nodeId;
|
||||
reqLimitationValueMin = limitation;
|
||||
reqLimitationValueMax = VeluxProductPosition.VPP_VELUX_IGNORE;
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActuatorIdAndMaximumLimitation(int nodeId, int limitation) {
|
||||
logger.trace("setActuatorIdAndLimitationTypeAndLimitation({},{}) called.", nodeId, limitation);
|
||||
reqIndexArray01 = nodeId;
|
||||
reqLimitationValueMin = VeluxProductPosition.VPP_VELUX_IGNORE;
|
||||
reqLimitationValueMax = limitation;
|
||||
return;
|
||||
}
|
||||
|
||||
public void setActuatorIdAndResetLimitation(int nodeId) {
|
||||
logger.trace("setActuatorIdAndResetLimitation({}) called.", nodeId);
|
||||
reqIndexArray01 = nodeId;
|
||||
reqLimitationValueMin = VeluxProductPosition.VPP_VELUX_IGNORE;
|
||||
reqLimitationValueMax = VeluxProductPosition.VPP_VELUX_IGNORE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetSceneVelocity;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.KLF200Response;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductVelocity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Modify Velocity of an Actuator</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 3rd level class it defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the interface {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeCommunicationProtocol
|
||||
* SlipBridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods in addition to the mentioned interface:
|
||||
* <UL>
|
||||
* <LI>{@link #setMode} to define the new silence mode of the intended actuator.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @see SetSceneVelocity
|
||||
* @see SlipBridgeCommunicationProtocol
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
// ToDo: THIS MESSAGE EXCHANGE IS AN UNDOCUMENTED FEATURE. Check the updated Velux doc against this implementation.
|
||||
@NonNullByDefault
|
||||
class SCsetSceneVelocity extends SetSceneVelocity implements SlipBridgeCommunicationProtocol {
|
||||
private final Logger logger = LoggerFactory.getLogger(SCsetSceneVelocity.class);
|
||||
|
||||
private static final String DESCRIPTION = "Modify Velocity of an Actuator";
|
||||
private static final Command COMMAND = Command.GW_SET_NODE_VELOCITY_REQ;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Content Parameters
|
||||
*/
|
||||
|
||||
private int reqNodeID = -1;
|
||||
private int reqNodeVelocity = -1;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Message Objects
|
||||
*/
|
||||
|
||||
private byte[] requestData = new byte[0];
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Result Objects
|
||||
*/
|
||||
|
||||
private boolean success = false;
|
||||
private boolean finished = false;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods required for interface {@link BridgeCommunicationProtocol}.
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return DESCRIPTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandNumber getRequestCommand() {
|
||||
success = false;
|
||||
finished = false;
|
||||
logger.debug("getRequestCommand() returns {}.", COMMAND.getCommand());
|
||||
return COMMAND.getCommand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getRequestDataAsArrayOfBytes() {
|
||||
Packet request = new Packet(new byte[2]);
|
||||
request.setOneByteValue(0, reqNodeID);
|
||||
request.setOneByteValue(1, reqNodeVelocity);
|
||||
requestData = request.toByteArray();
|
||||
logger.trace("getRequestDataAsArrayOfBytes() data is {}.", new Packet(requestData).toString());
|
||||
return requestData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponse(short responseCommand, byte[] thisResponseData, boolean isSequentialEnforced) {
|
||||
KLF200Response.introLogging(logger, responseCommand, thisResponseData);
|
||||
success = false;
|
||||
finished = false;
|
||||
Packet responseData = new Packet(thisResponseData);
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_SET_NODE_VELOCITY_CFM:
|
||||
finished = true;
|
||||
if (!KLF200Response.isLengthValid(logger, responseCommand, thisResponseData, 3)) {
|
||||
break;
|
||||
}
|
||||
int cfmStatus = responseData.getOneByteValue(0);
|
||||
switch (cfmStatus) {
|
||||
case 0:
|
||||
logger.trace("setResponse(): returned status: Error - Wink is rejected.");
|
||||
break;
|
||||
case 1:
|
||||
logger.trace("setResponse(): returned status: OK – Wink is accepted.");
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
logger.warn("setResponse({}): returned status={} (Reserved/unknown).",
|
||||
Command.get(responseCommand).toString(), cfmStatus);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
KLF200Response.errorLogging(logger, responseCommand);
|
||||
finished = true;
|
||||
}
|
||||
KLF200Response.outroLogging(logger, success, finished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommunicationSuccessful() {
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Methods in addition to the interface {@link BridgeCommunicationProtocol}
|
||||
* and the abstract class {@link RunProductIdentification}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor Addon Method.
|
||||
* <P>
|
||||
* Passes the intended Actuator Identifier towards this class for building the request lateron.
|
||||
*
|
||||
* @param actuatorId as type int describing the scene to be processed.
|
||||
* @param silent as type boolean describing the silence mode of this node.
|
||||
* @return <b>this</b> of type {@link SCsetSceneVelocity} as class itself.
|
||||
*/
|
||||
@Override
|
||||
public SCsetSceneVelocity setMode(int actuatorId, boolean silent) {
|
||||
logger.trace("setProductId({},{}) called.", actuatorId, silent);
|
||||
this.reqNodeID = actuatorId;
|
||||
this.reqNodeVelocity = silent ? VeluxProductVelocity.SILENT.getVelocity()
|
||||
: VeluxProductVelocity.FAST.getVelocity();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetDeviceStatus;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetFirmware;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetHouseStatus;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetLANConfig;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProduct;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetProducts;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetScenes;
|
||||
import org.openhab.binding.velux.internal.bridge.common.GetWLANConfig;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Login;
|
||||
import org.openhab.binding.velux.internal.bridge.common.Logout;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductCommand;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductDiscovery;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductIdentification;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunProductSearch;
|
||||
import org.openhab.binding.velux.internal.bridge.common.RunScene;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetHouseStatusMonitor;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetProductLimitation;
|
||||
import org.openhab.binding.velux.internal.bridge.common.SetSceneVelocity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* SLIP-based 3rd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides the one-and-only protocol specific 1st-level communication class.
|
||||
* Additionally it provides all methods for different gateway interactions.
|
||||
* <P>
|
||||
* The following class access methods exist:
|
||||
* <UL>
|
||||
* <LI>{@link SlipBridgeAPI#getDeviceStatus} for retrieving the bridge state (i.e. IDLE, BUSY, a.s.o),</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getFirmware} for retrieving the firmware version of the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getHouseStatus} for retrieving the information about device state changes recognized by the
|
||||
* bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getLANConfig} for retrieving the complete LAN information of the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getProduct} for retrieving the any information about a device behind the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getProductLimitation} for retrieving the limitation information about a device behind the
|
||||
* bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getProducts} for retrieving the any information for all devices behind the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getScenes} for retrieving the any information for all scenes defined on the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#getWLANConfig} for retrieving the complete WLAN information of the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#login} for establishing a trusted connectivity by authentication,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#logout} for tearing down the trusted connectivity by deauthentication,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#runProductCommand} for manipulation of a device behind the bridge (i.e. instructing to
|
||||
* modify a position),</LI>
|
||||
* <LI>{@link SlipBridgeAPI#runProductDiscovery} for activation of learning mode of the bridge to discovery new
|
||||
* products,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#runProductIdentification} for human-oriented identification a device behind the bridge (i.e.
|
||||
* by winking or switching on-and-off),</LI>
|
||||
* <LI>{@link SlipBridgeAPI#runProductSearch} for searching for lost products on the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#runScene} for manipulation of a set of devices behind the bridge which are tied together as
|
||||
* scene,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#setHouseStatusMonitor} for activation or deactivation of the house monitoring mode to be
|
||||
* informed about device state changes recognized by the bridge,</LI>
|
||||
* <LI>{@link SlipBridgeAPI#setSceneVelocity} for changes the velocity of a scene defined on the bridge (i.e. silent or
|
||||
* fast mode).</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* As most derived class of the several inheritance levels it defines an
|
||||
* interfacing method which returns the SLIP-protocol-specific communication for gateway interaction.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SlipBridgeAPI implements BridgeAPI {
|
||||
private final Logger logger = LoggerFactory.getLogger(SlipBridgeAPI.class);
|
||||
|
||||
private static final GetDeviceStatus GETDEVICESTATUS = new SCgetDeviceStatus();
|
||||
private static final GetFirmware GETFIRMWARE = new SCgetFirmware();
|
||||
private static final GetHouseStatus GETHOUSESTATUS = new SCgetHouseStatus();
|
||||
private static final GetLANConfig GETLANCONFIG = new SCgetLANConfig();
|
||||
private static final GetProduct GETPRODUCT = new SCgetProduct();
|
||||
private static final GetProductLimitation GETPRODUCTLIMITATION = new SCgetLimitation();
|
||||
private static final GetProducts GETPRODUCTS = new SCgetProducts();
|
||||
private static final GetScenes GETSCENES = new SCgetScenes();
|
||||
private static final GetWLANConfig GETWLANCONFIG = new SCgetWLANConfig();
|
||||
private static final Login LOGIN = new SClogin();
|
||||
private static final Logout LOGOUT = new SClogout();
|
||||
private static final RunProductCommand RUNPRODUCTCOMMAND = new SCrunProductCommand();
|
||||
private static final RunProductDiscovery RUNPRODUCTDISCOVERY = new SCrunProductDiscovery();
|
||||
private static final RunProductIdentification RUNPRODUCTIDENTIFICATION = new SCrunProductIdentification();
|
||||
private static final RunProductSearch RUNPRODUCTSEARCH = new SCrunProductSearch();
|
||||
private static final RunScene RUNSCENE = new SCrunScene();
|
||||
private static final SetHouseStatusMonitor SETHOUSESTATUSMONITOR = new SCsetHouseStatusMonitor();
|
||||
private static final SetProductLimitation SETPRODUCTLIMITATION = new SCsetLimitation();
|
||||
private static final SetSceneVelocity SETSCENEVELOCITY = new SCsetSceneVelocity();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Inherits the initialization of the binding-wide instance for dealing for common information and
|
||||
* initializes the handler {@link SlipVeluxBridge#bridgeAPI}
|
||||
* to pass the interface methods.
|
||||
*
|
||||
* @param bridgeInstance refers to the binding-wide instance for dealing for common informations.
|
||||
*/
|
||||
SlipBridgeAPI(VeluxBridgeInstance bridgeInstance) {
|
||||
logger.trace("SlipBridgeAPI(constructor) called.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetDeviceStatus getDeviceStatus() {
|
||||
return GETDEVICESTATUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetFirmware getFirmware() {
|
||||
return GETFIRMWARE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GetHouseStatus getHouseStatus() {
|
||||
return GETHOUSESTATUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetLANConfig getLANConfig() {
|
||||
return GETLANCONFIG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GetProduct getProduct() {
|
||||
return GETPRODUCT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GetProductLimitation getProductLimitation() {
|
||||
return GETPRODUCTLIMITATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SetProductLimitation setProductLimitation() {
|
||||
return SETPRODUCTLIMITATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetProducts getProducts() {
|
||||
return GETPRODUCTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetScenes getScenes() {
|
||||
return GETSCENES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetWLANConfig getWLANConfig() {
|
||||
return GETWLANCONFIG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Login login() {
|
||||
return LOGIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logout logout() {
|
||||
return LOGOUT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable RunProductCommand runProductCommand() {
|
||||
return RUNPRODUCTCOMMAND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunProductDiscovery runProductDiscovery() {
|
||||
return RUNPRODUCTDISCOVERY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunProductIdentification runProductIdentification() {
|
||||
return RUNPRODUCTIDENTIFICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunProductSearch runProductSearch() {
|
||||
return RUNPRODUCTSEARCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RunScene runScene() {
|
||||
return RUNSCENE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SetHouseStatusMonitor setHouseStatusMonitor() {
|
||||
return SETHOUSESTATUSMONITOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetSceneVelocity setSceneVelocity() {
|
||||
return SETSCENEVELOCITY;
|
||||
}
|
||||
}
|
||||
@@ -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.velux.internal.bridge.slip;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
|
||||
/**
|
||||
* Protocol specific bridge communication supported by the Velux bridge:
|
||||
* <B>Authentication</B>
|
||||
* <P>
|
||||
* Common Message semantic: Communication with the bridge and (optionally) storing returned information within the class
|
||||
* itself.
|
||||
* <P>
|
||||
* As 2nd level interface it defines the methods to help in sending a query and
|
||||
* processing the received answer.
|
||||
* <P>
|
||||
* (Additional) Methods in this interface for the appropriate interaction:
|
||||
* <UL>
|
||||
* <LI>{@link getRequestCommand} to return the intended command to be sent.</LI>
|
||||
* <LI>{@link getRequestDataAsArrayOfBytes} to return the intended data part to be sent.</LI>
|
||||
* <LI>{@link setResponse} to store the response already separated into response command and data part.</LI>
|
||||
* <LI>{@link isCommunicationFinished} to signal the completeness of the interaction (only available
|
||||
* after storing the response).</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* Other mandatory methods are inherited from {@link BridgeCommunicationProtocol}.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
interface SlipBridgeCommunicationProtocol extends BridgeCommunicationProtocol {
|
||||
|
||||
/**
|
||||
* Provides an empty array of bytes.
|
||||
*
|
||||
*/
|
||||
public static final byte[] EMPTYDATA = new byte[0];
|
||||
|
||||
/**
|
||||
* Returning the command part of the request object for further SLIP serialization.
|
||||
*
|
||||
* @return <b>commandNumber</b>
|
||||
* is of type {@link CommandNumber}.
|
||||
*/
|
||||
public CommandNumber getRequestCommand();
|
||||
|
||||
/**
|
||||
* Returning the data part of the request object for further SLIP serialization.
|
||||
*
|
||||
* @return <b>dataAsArrayOfBytes</b>
|
||||
* is an Array of byte.
|
||||
*/
|
||||
public byte[] getRequestDataAsArrayOfBytes();
|
||||
|
||||
/**
|
||||
* Storing the command and the data part of the response object for further checks.
|
||||
*
|
||||
* @param thisResponseCommand of type short: command part of the response packet.
|
||||
* @param thisResponseData of type Array of bytes: data part of response packet to be processed.
|
||||
* @param isSequentialEnforced of type boolean: enforces the strict handshake sequence even for long duration
|
||||
* interactions.
|
||||
*/
|
||||
public void setResponse(short thisResponseCommand, byte[] thisResponseData, boolean isSequentialEnforced);
|
||||
|
||||
/**
|
||||
* Returning the communication status included within the response message..
|
||||
*
|
||||
* @return <b>isFinished</b>
|
||||
* is a boolean signaling the end of this transaction.
|
||||
*/
|
||||
public boolean isCommunicationFinished();
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.bridge.VeluxBridge;
|
||||
import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
|
||||
import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.io.Connection;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.SlipEncoding;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.SlipRFC1055;
|
||||
import org.openhab.binding.velux.internal.development.Threads;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* SLIP-based 2nd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides methods for pre- and postcommunication
|
||||
* as well as a common method for the real communication.
|
||||
* <P>
|
||||
* In addition to the generic {@link VeluxBridge} methods, i.e.
|
||||
* <UL>
|
||||
* <LI>{@link VeluxBridge#bridgeLogin} for pre-communication,</LI>
|
||||
* <LI>{@link VeluxBridge#bridgeLogout} for post-communication,</LI>
|
||||
* <LI>{@link VeluxBridge#bridgeCommunicate} as method for the common communication,</LI>
|
||||
* <LI>{@link VeluxBridge#bridgeAPI} as interfacing method to all interaction prototypes,</LI>
|
||||
* </UL>
|
||||
* the following class access methods provides the protocol-specific implementation:
|
||||
* <UL>
|
||||
* <LI>{@link #bridgeDirectCommunicate} for SLIP-based communication.</LI>
|
||||
* <LI>{@link #bridgeAPI} for return all defined protocol-specific implementations which are provided by
|
||||
* {@link org.openhab.binding.velux.internal.bridge.slip.SlipBridgeAPI SlipBridgeAPI}.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SlipVeluxBridge extends VeluxBridge {
|
||||
private final Logger logger = LoggerFactory.getLogger(SlipVeluxBridge.class);
|
||||
|
||||
/*
|
||||
* ***************************
|
||||
* ***** Private Objects *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Timeout for sequence of one request with (optional multiple) responses.
|
||||
* <P>
|
||||
* This can only happen if there is an unexpected (undocumented) occurrence of events
|
||||
* which has to be discussed along the Velux API documentation.
|
||||
*/
|
||||
static final long COMMUNICATION_TIMEOUT_MSECS = 60000L;
|
||||
/**
|
||||
* Wait interval within sequence after the request and no immediate response.
|
||||
* <P>
|
||||
* This can happen if the bridge is busy due to a specific command to query and collect information from other
|
||||
* devices via the io-homecontrol protocol.
|
||||
*/
|
||||
static final long COMMUNICATION_RETRY_MSECS = 5000L;
|
||||
|
||||
/*
|
||||
* ***************************
|
||||
* ***** Private Objects *****
|
||||
*/
|
||||
|
||||
private final byte[] emptyPacket = new byte[0];
|
||||
private Connection connection = new Connection();
|
||||
|
||||
/**
|
||||
* Handler passing the interface methods to other classes.
|
||||
* Can be accessed via method {@link org.openhab.binding.velux.internal.bridge.common.BridgeAPI BridgeAPI}.
|
||||
*/
|
||||
private BridgeAPI bridgeAPI;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <P>
|
||||
* Inherits the initialization of the binding-wide instance for dealing for common informations and
|
||||
* initializes the Velux bridge connection settings.
|
||||
*
|
||||
* @param bridgeInstance refers to the binding-wide instance for dealing for common informations.
|
||||
*/
|
||||
public SlipVeluxBridge(VeluxBridgeInstance bridgeInstance) {
|
||||
super(bridgeInstance);
|
||||
logger.trace("SlipVeluxBridge(constructor) called.");
|
||||
bridgeAPI = new SlipBridgeAPI(bridgeInstance);
|
||||
supportedProtocols = new TreeSet<>();
|
||||
supportedProtocols.add("slip");
|
||||
logger.trace("SlipVeluxBridge(constructor) done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* <P>
|
||||
* De-initializes the binding-wide instance.
|
||||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
logger.trace("shutdown() called.");
|
||||
connection.resetConnection();
|
||||
logger.trace("shutdown() done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides information about the base-level communication method and
|
||||
* any kind of available gateway interactions.
|
||||
* <P>
|
||||
* <B>Note:</B> the implementation within this class {@link SlipVeluxBridge} as inherited from {@link VeluxBridge}
|
||||
* will return the protocol-specific class implementations.
|
||||
* <P>
|
||||
* The information will be initialized by the corresponding API class {@link SlipBridgeAPI}.
|
||||
*
|
||||
* @return <b>bridgeAPI</b> of type {@link BridgeAPI} contains all possible methods.
|
||||
*/
|
||||
@Override
|
||||
public BridgeAPI bridgeAPI() {
|
||||
logger.trace("bridgeAPI() called.");
|
||||
return bridgeAPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* <B>Method as implementation of abstract superclass method.</B>
|
||||
* <P>
|
||||
* Initializes a client/server communication towards <b>Velux</b> veluxBridge
|
||||
* based on the Basic I/O interface {@link Connection#io} and parameters
|
||||
* passed as arguments (see below).
|
||||
*
|
||||
* @param communication Structure of interface type {@link SlipBridgeCommunicationProtocol} describing the intended
|
||||
* communication, that is request and response interactions as well as appropriate URL definition.
|
||||
* @param useAuthentication boolean flag to decide whether to use authenticated communication.
|
||||
* @return <b>success</b> of type boolean which signals the success of the communication.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected boolean bridgeDirectCommunicate(BridgeCommunicationProtocol communication, boolean useAuthentication) {
|
||||
logger.trace("bridgeDirectCommunicate(BCP: {},{}authenticated) called.", communication.name(),
|
||||
useAuthentication ? "" : "un");
|
||||
return bridgeDirectCommunicate((SlipBridgeCommunicationProtocol) communication, useAuthentication);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last (potentially faulty) communication.
|
||||
*
|
||||
* @return timestamp in milliseconds.
|
||||
*/
|
||||
@Override
|
||||
public long lastCommunication() {
|
||||
return connection.lastCommunication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last successful communication.
|
||||
*
|
||||
* @return timestamp in milliseconds.
|
||||
*/
|
||||
@Override
|
||||
public long lastSuccessfulCommunication() {
|
||||
return connection.lastSuccessfulCommunication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a client/server communication towards <b>Velux</b> veluxBridge
|
||||
* based on the Basic I/O interface {@link Connection#io} and parameters
|
||||
* passed as arguments (see below).
|
||||
*
|
||||
* @param communication Structure of interface type {@link SlipBridgeCommunicationProtocol} describing the
|
||||
* intended communication, that is request and response interactions as well as appropriate URL
|
||||
* definition.
|
||||
* @param useAuthentication boolean flag to decide whether to use authenticated communication.
|
||||
* @return <b>success</b> of type boolean which signals the success of the communication.
|
||||
*/
|
||||
private synchronized boolean bridgeDirectCommunicate(SlipBridgeCommunicationProtocol communication,
|
||||
boolean useAuthentication) {
|
||||
logger.trace("bridgeDirectCommunicate({},{}authenticated) called.", communication.name(),
|
||||
useAuthentication ? "" : "un");
|
||||
|
||||
assert this.bridgeInstance.veluxBridgeConfiguration().protocol.contentEquals("slip");
|
||||
|
||||
long communicationStartInMSecs = System.currentTimeMillis();
|
||||
|
||||
boolean isSequentialEnforced = this.bridgeInstance.veluxBridgeConfiguration().isSequentialEnforced;
|
||||
boolean isProtocolTraceEnabled = this.bridgeInstance.veluxBridgeConfiguration().isProtocolTraceEnabled;
|
||||
|
||||
// From parameters
|
||||
short command = communication.getRequestCommand().toShort();
|
||||
byte[] data = communication.getRequestDataAsArrayOfBytes();
|
||||
// For further use at different logging statements
|
||||
String commandString = Command.get(command).toString();
|
||||
|
||||
if (isProtocolTraceEnabled) {
|
||||
Threads.findDeadlocked();
|
||||
}
|
||||
|
||||
logger.debug("bridgeDirectCommunicate({},{}authenticated) initiated by {}.", commandString,
|
||||
useAuthentication ? "" : "un", Thread.currentThread());
|
||||
boolean success = false;
|
||||
|
||||
communication: do {
|
||||
if (communicationStartInMSecs + COMMUNICATION_TIMEOUT_MSECS < System.currentTimeMillis()) {
|
||||
logger.warn(
|
||||
"{} bridgeDirectCommunicate({}): communication handshake failed (unexpected sequence of requests/responses).",
|
||||
VeluxBindingConstants.BINDING_VALUES_SEPARATOR, communication.name());
|
||||
break;
|
||||
}
|
||||
|
||||
// Special handling
|
||||
if (Command.get(command) == Command.GW_OPENHAB_CLOSE) {
|
||||
logger.trace("bridgeDirectCommunicate(): special command: shutting down connection.");
|
||||
connection.resetConnection();
|
||||
success = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Normal processing
|
||||
logger.trace("bridgeDirectCommunicate(): working on request {} with {} bytes of data.", commandString,
|
||||
data.length);
|
||||
byte[] sendBytes = emptyPacket;
|
||||
if (Command.get(command) == Command.GW_OPENHAB_RECEIVEONLY) {
|
||||
logger.trace(
|
||||
"bridgeDirectCommunicate(): special command: determine whether there is any message waiting.");
|
||||
logger.trace("bridgeDirectCommunicate(): check for a waiting message.");
|
||||
if (!connection.isMessageAvailable()) {
|
||||
logger.trace("bridgeDirectCommunicate(): no message waiting, aborting.");
|
||||
break communication;
|
||||
}
|
||||
logger.trace("bridgeDirectCommunicate(): there is a message waiting.");
|
||||
} else {
|
||||
SlipEncoding t = new SlipEncoding(command, data);
|
||||
if (!t.isValid()) {
|
||||
logger.warn("bridgeDirectCommunicate(): SlipEncoding() failed, aborting.");
|
||||
break;
|
||||
}
|
||||
logger.trace("bridgeDirectCommunicate(): transportEncoding={}.", t.toString());
|
||||
sendBytes = new SlipRFC1055().encode(t.toMessage());
|
||||
}
|
||||
do {
|
||||
if (communicationStartInMSecs + COMMUNICATION_TIMEOUT_MSECS < System.currentTimeMillis()) {
|
||||
logger.warn("bridgeDirectCommunicate(): receive takes too long. Please report to maintainer.");
|
||||
break communication;
|
||||
}
|
||||
byte[] receivedPacket;
|
||||
try {
|
||||
if (sendBytes.length > 0) {
|
||||
logger.trace("bridgeDirectCommunicate(): sending {} bytes.", sendBytes.length);
|
||||
if (isProtocolTraceEnabled) {
|
||||
logger.info("Sending command {}.", commandString);
|
||||
}
|
||||
} else {
|
||||
logger.trace("bridgeDirectCommunicate(): initiating receive-only.");
|
||||
}
|
||||
// (Optionally) Send and receive packet.
|
||||
receivedPacket = connection.io(this.bridgeInstance, sendBytes);
|
||||
// Once being sent, it should never be sent again
|
||||
sendBytes = emptyPacket;
|
||||
} catch (Exception e) {
|
||||
logger.warn("bridgeDirectCommunicate(): connection.io returns {}", e.getMessage());
|
||||
break communication;
|
||||
}
|
||||
logger.trace("bridgeDirectCommunicate(): received packet {}.", new Packet(receivedPacket).toString());
|
||||
byte[] response;
|
||||
try {
|
||||
response = new SlipRFC1055().decode(receivedPacket);
|
||||
} catch (ParseException e) {
|
||||
logger.warn("bridgeDirectCommunicate(): method SlipRFC1055() raised a decoding error: {}.",
|
||||
e.getMessage());
|
||||
break communication;
|
||||
}
|
||||
SlipEncoding tr = new SlipEncoding(response);
|
||||
if (!tr.isValid()) {
|
||||
logger.warn("bridgeDirectCommunicate(): method SlipEncoding() raised a decoding error.");
|
||||
break communication;
|
||||
}
|
||||
short responseCommand = tr.getCommand();
|
||||
byte[] responseData = tr.getData();
|
||||
logger.debug("bridgeDirectCommunicate(): working on response {} with {} bytes of data.",
|
||||
Command.get(responseCommand).toString(), responseData.length);
|
||||
if (isProtocolTraceEnabled) {
|
||||
logger.info("Received answer {}.", Command.get(responseCommand).toString());
|
||||
}
|
||||
// Handle some common (unexpected) answers
|
||||
switch (Command.get(responseCommand)) {
|
||||
case GW_NODE_INFORMATION_CHANGED_NTF:
|
||||
logger.trace("bridgeDirectCommunicate(): received GW_NODE_INFORMATION_CHANGED_NTF.");
|
||||
logger.trace("bridgeDirectCommunicate(): continue with receiving.");
|
||||
continue;
|
||||
case GW_NODE_STATE_POSITION_CHANGED_NTF:
|
||||
logger.trace(
|
||||
"bridgeDirectCommunicate(): received GW_NODE_STATE_POSITION_CHANGED_NTF, special processing of this packet.");
|
||||
SCgetHouseStatus receiver = new SCgetHouseStatus();
|
||||
receiver.setResponse(responseCommand, responseData, isSequentialEnforced);
|
||||
if (receiver.isCommunicationSuccessful()) {
|
||||
logger.trace("bridgeDirectCommunicate(): existingProducts().update() called.");
|
||||
bridgeInstance.existingProducts().update(new ProductBridgeIndex(receiver.getNtfNodeID()),
|
||||
receiver.getNtfState(), receiver.getNtfCurrentPosition(), receiver.getNtfTarget());
|
||||
}
|
||||
logger.trace("bridgeDirectCommunicate(): continue with receiving.");
|
||||
continue;
|
||||
case GW_ERROR_NTF:
|
||||
switch (responseData[0]) {
|
||||
case 0:
|
||||
logger.warn(
|
||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF on {} (Not further defined error), aborting.",
|
||||
commandString);
|
||||
break communication;
|
||||
case 1:
|
||||
logger.warn(
|
||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Unknown Command or command is not accepted at this state) on {}, aborting.",
|
||||
commandString);
|
||||
break communication;
|
||||
case 2:
|
||||
logger.warn(
|
||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (ERROR on Frame Structure) on {}, aborting.",
|
||||
commandString);
|
||||
break communication;
|
||||
case 7:
|
||||
logger.trace(
|
||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Busy. Try again later) on {}, retrying.",
|
||||
commandString);
|
||||
sendBytes = emptyPacket;
|
||||
continue;
|
||||
case 8:
|
||||
logger.warn(
|
||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Bad system table index) on {}, aborting.",
|
||||
commandString);
|
||||
break communication;
|
||||
case 12:
|
||||
logger.warn(
|
||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Not authenticated) on {}, aborting.",
|
||||
commandString);
|
||||
resetAuthentication();
|
||||
break communication;
|
||||
default:
|
||||
logger.warn("bridgeDirectCommunicate(): received GW_ERROR_NTF ({}) on {}, aborting.",
|
||||
responseData[0], commandString);
|
||||
break communication;
|
||||
}
|
||||
case GW_ACTIVATION_LOG_UPDATED_NTF:
|
||||
logger.info("bridgeDirectCommunicate(): received GW_ACTIVATION_LOG_UPDATED_NTF.");
|
||||
logger.trace("bridgeDirectCommunicate(): continue with receiving.");
|
||||
continue;
|
||||
|
||||
case GW_COMMAND_RUN_STATUS_NTF:
|
||||
case GW_COMMAND_REMAINING_TIME_NTF:
|
||||
case GW_SESSION_FINISHED_NTF:
|
||||
if (!isSequentialEnforced) {
|
||||
logger.trace(
|
||||
"bridgeDirectCommunicate(): response ignored due to activated parallelism, continue with receiving.");
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
}
|
||||
logger.trace("bridgeDirectCommunicate(): passes back command {} and data {}.",
|
||||
new CommandNumber(responseCommand).toString(), new Packet(responseData).toString());
|
||||
communication.setResponse(responseCommand, responseData, isSequentialEnforced);
|
||||
} while (!communication.isCommunicationFinished());
|
||||
success = communication.isCommunicationSuccessful();
|
||||
} while (false); // communication
|
||||
logger.debug("bridgeDirectCommunicate({}) returns {}.", commandString, success ? "success" : "failure");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
|
||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 2nd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* It provides methods for a pure client/server communication.
|
||||
* <P>
|
||||
* The following class access methods exist:
|
||||
* <UL>
|
||||
* <LI>{@link Connection#io} for a complete pair of request and response messages,</LI>
|
||||
* <LI>{@link Connection#isAlive} to check the presence of a connection,</LI>
|
||||
* <LI>{@link Connection#isMessageAvailable} to check the presence of an incoming message,</LI>
|
||||
* <LI>{@link Connection#lastSuccessfulCommunication} returns the timestamp of the last successful communication,</LI>
|
||||
* <LI>{@link Connection#lastCommunication} returns the timestamp of the last communication,</LI>
|
||||
* <LI>{@link Connection#resetConnection} for resetting the current connection.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Connection {
|
||||
private final Logger logger = LoggerFactory.getLogger(Connection.class);
|
||||
|
||||
/*
|
||||
* ***************************
|
||||
* ***** Private Objects *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Timestamp of last successful communication in milliseconds.
|
||||
*/
|
||||
private long lastSuccessfulCommunicationInMSecs = 0;
|
||||
/**
|
||||
* Timestamp of last communication in milliseconds.
|
||||
*/
|
||||
private long lastCommunicationInMSecs = 0;
|
||||
/**
|
||||
* SSL socket for communication.
|
||||
*/
|
||||
private SSLconnection connectivity = SSLconnection.UNKNOWN;
|
||||
|
||||
/*
|
||||
* **************************
|
||||
* ***** Public Methods *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base level communication with the <B>SlipVeluxBridg</B>.
|
||||
*
|
||||
* @param bridgeInstance describing the Service Access Point location i.e. hostname and TCP port.
|
||||
* @param request as Array of bytes representing the structure of the message to be send.
|
||||
* @return <b>response</b> of type Array of byte containing all received informations.
|
||||
* @throws java.net.ConnectException in case of unrecoverable communication failures.
|
||||
* @throws java.io.IOException in case of continuous communication I/O failures.
|
||||
*/
|
||||
public synchronized byte[] io(VeluxBridgeInstance bridgeInstance, byte[] request)
|
||||
throws ConnectException, IOException {
|
||||
logger.trace("io() called.");
|
||||
|
||||
lastCommunicationInMSecs = System.currentTimeMillis();
|
||||
|
||||
/** Local handles */
|
||||
int retryCount = 0;
|
||||
IOException lastIOE = new IOException("Unexpected I/O exception.");
|
||||
|
||||
do {
|
||||
try {
|
||||
if (!connectivity.isReady()) {
|
||||
try {
|
||||
// From configuration
|
||||
String host = bridgeInstance.veluxBridgeConfiguration().ipAddress;
|
||||
int port = bridgeInstance.veluxBridgeConfiguration().tcpPort;
|
||||
int timeoutMsecs = bridgeInstance.veluxBridgeConfiguration().timeoutMsecs;
|
||||
|
||||
logger.trace("io(): connecting to {}:{}.", host, port);
|
||||
connectivity = new SSLconnection(host, port);
|
||||
connectivity.setTimeout(timeoutMsecs);
|
||||
} catch (ConnectException ce) {
|
||||
throw new ConnectException(String
|
||||
.format("raised a non-recoverable error during connection setup: %s", ce.getMessage()));
|
||||
} catch (IOException e) {
|
||||
logger.warn("io(): raised an error during connection setup: {}.", e.getMessage());
|
||||
lastIOE = new IOException(String.format("error during connection setup: %s.", e.getMessage()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (request.length > 0) {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("io(): sending packet with {} bytes: {}", request.length, new Packet(request));
|
||||
} else {
|
||||
logger.debug("io(): sending packet of size {}.", request.length);
|
||||
}
|
||||
if (connectivity.isReady()) {
|
||||
connectivity.send(request);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.info("io(): raised an error during sending: {}.", e.getMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
// Give the bridge some time to breathe
|
||||
if (bridgeInstance.veluxBridgeConfiguration().timeoutMsecs > 0) {
|
||||
logger.trace("io(): wait time {} msecs.",
|
||||
bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||
try {
|
||||
Thread.sleep(bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||
} catch (InterruptedException ie) {
|
||||
logger.trace("io() wait interrupted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
byte[] packet = new byte[0];
|
||||
logger.trace("io(): receiving bytes.");
|
||||
if (connectivity.isReady()) {
|
||||
packet = connectivity.receive();
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("io(): received packet with {} bytes: {}", packet.length, new Packet(packet));
|
||||
} else {
|
||||
logger.debug("io(): received packet with {} bytes.", packet.length);
|
||||
}
|
||||
lastSuccessfulCommunicationInMSecs = System.currentTimeMillis();
|
||||
lastCommunicationInMSecs = lastSuccessfulCommunicationInMSecs;
|
||||
logger.trace("io() finished.");
|
||||
return packet;
|
||||
} catch (IOException ioe) {
|
||||
logger.info("io(): Exception occurred during I/O: {}.", ioe.getMessage());
|
||||
lastIOE = ioe;
|
||||
// Error Retries with Exponential Backoff
|
||||
long waitTime = ((long) Math.pow(2, retryCount)
|
||||
* bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||
logger.trace("io(): wait time {} msecs.", waitTime);
|
||||
try {
|
||||
Thread.sleep(waitTime);
|
||||
} catch (InterruptedException ie) {
|
||||
logger.trace("io(): wait interrupted.");
|
||||
}
|
||||
}
|
||||
} while (retryCount++ < bridgeInstance.veluxBridgeConfiguration().retries);
|
||||
if (retryCount >= bridgeInstance.veluxBridgeConfiguration().retries) {
|
||||
logger.info("io(): socket I/O failed {} times.", bridgeInstance.veluxBridgeConfiguration().retries);
|
||||
}
|
||||
logger.trace("io(): shutting down connection.");
|
||||
if (connectivity.isReady()) {
|
||||
connectivity.close();
|
||||
}
|
||||
logger.trace("io() finishes with failure by throwing exception.");
|
||||
throw lastIOE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the current connection.
|
||||
*
|
||||
* @return state as boolean.
|
||||
*/
|
||||
public boolean isAlive() {
|
||||
logger.trace("isAlive(): called.");
|
||||
return connectivity.isReady();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the availability of an incoming message.
|
||||
*
|
||||
* @return state as boolean.
|
||||
*/
|
||||
public synchronized boolean isMessageAvailable() {
|
||||
logger.trace("isMessageAvailable(): called.");
|
||||
try {
|
||||
if ((connectivity.isReady()) && (connectivity.available())) {
|
||||
logger.trace("isMessageAvailable(): there is a message waiting.");
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.trace("isMessageAvailable(): lost connection due to {}.", e.getMessage());
|
||||
resetConnection();
|
||||
}
|
||||
logger.trace("isMessageAvailable(): no message waiting.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last successful communication.
|
||||
*
|
||||
* @return timestamp in milliseconds.
|
||||
*/
|
||||
public long lastSuccessfulCommunication() {
|
||||
return lastSuccessfulCommunicationInMSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp in milliseconds since Unix epoch
|
||||
* of last communication.
|
||||
*
|
||||
* @return timestamp in milliseconds.
|
||||
*/
|
||||
public long lastCommunication() {
|
||||
return lastCommunicationInMSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets an open connectivity by closing the socket and resetting the authentication information.
|
||||
*/
|
||||
public synchronized void resetConnection() {
|
||||
logger.trace("resetConnection() called.");
|
||||
if (connectivity.isReady()) {
|
||||
logger.trace("resetConnection(): shutting down connection.");
|
||||
try {
|
||||
if (connectivity.isReady()) {
|
||||
connectivity.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.info("resetConnection(): raised an error during connection close: {}.", e.getMessage());
|
||||
}
|
||||
logger.trace("resetConnection(): clearing authentication token.");
|
||||
}
|
||||
logger.trace("resetConnection() done.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* This is an extension of {@link java.io.DataInputStream}, which adds timeouts to receive operation.
|
||||
* <P>
|
||||
* A data input stream lets an application read primitive Java data
|
||||
* types from an underlying input stream in a machine-independent
|
||||
* way. An application uses a data output stream to write data that
|
||||
* can later be read by a data input stream.
|
||||
* <p>
|
||||
* For an in-depth discussion, see:
|
||||
* https://stackoverflow.com/questions/804951/is-it-possible-to-read-from-a-inputstream-with-a-timeout
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class DataInputStreamWithTimeout extends DataInputStream {
|
||||
|
||||
/*
|
||||
* ***************************
|
||||
* ***** Private Objects *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Executor for asynchronous read command
|
||||
*/
|
||||
ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||
|
||||
/**
|
||||
* Creates a DataInputStreamWithTimeout that uses the specified
|
||||
* underlying DataInputStream.
|
||||
*
|
||||
* @param in the specified input stream
|
||||
*/
|
||||
public DataInputStreamWithTimeout(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to <code>len</code> bytes of data from the contained
|
||||
* input stream into an array of bytes. An attempt is made to read
|
||||
* as many as <code>len</code> bytes, but a smaller number may be read,
|
||||
* possibly zero. The number of bytes actually read is returned as an
|
||||
* integer.
|
||||
*
|
||||
* <p>
|
||||
* This method blocks until input data is available, end of file is
|
||||
* detected, or an exception is thrown <B>until</B> the given timeout.
|
||||
*
|
||||
* <p>
|
||||
* If <code>len</code> is zero, then no bytes are read and
|
||||
* <code>0</code> is returned; otherwise, there is an attempt to read at
|
||||
* least one byte. If no byte is available because the stream is at end of
|
||||
* file, the value <code>-1</code> is returned; otherwise, at least one
|
||||
* byte is read and stored into <code>b</code>.
|
||||
*
|
||||
* <p>
|
||||
* The first byte read is stored into element <code>b[off]</code>, the
|
||||
* next one into <code>b[off+1]</code>, and so on. The number of bytes read
|
||||
* is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
|
||||
* bytes actually read; these bytes will be stored in elements
|
||||
* <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
|
||||
* leaving elements <code>b[off+</code><i>k</i><code>]</code> through
|
||||
* <code>b[off+len-1]</code> unaffected.
|
||||
*
|
||||
* <p>
|
||||
* In every case, elements <code>b[0]</code> through
|
||||
* <code>b[off]</code> and elements <code>b[off+len]</code> through
|
||||
* <code>b[b.length-1]</code> are unaffected.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
* @param off the start offset in the destination array <code>b</code>
|
||||
* @param len the maximum number of bytes read.
|
||||
* @param timeoutMSecs the maximum duration of this read before throwing a TimeoutException.
|
||||
* @return the total number of bytes read into the buffer, or
|
||||
* <code>-1</code> if there is no more data because the end
|
||||
* of the stream has been reached.
|
||||
* @exception NullPointerException If <code>b</code> is <code>null</code>.
|
||||
* @exception IndexOutOfBoundsException If <code>off</code> is negative,
|
||||
* <code>len</code> is negative, or <code>len</code> is greater than
|
||||
* <code>b.length - off</code>
|
||||
* @exception IOException if the first byte cannot be read for any reason
|
||||
* other than end of file, the stream has been closed and the underlying
|
||||
* input stream does not support reading after close, or another I/O
|
||||
* error occurs. Additionally it will occur when the timeout happens.
|
||||
* @see java.io.DataInputStream#read
|
||||
*/
|
||||
public synchronized int read(byte b[], int off, int len, int timeoutMSecs) throws IOException {
|
||||
// Definition of Method which encapsulates the Read of data
|
||||
Callable<Integer> readTask = new Callable<Integer>() {
|
||||
@Override
|
||||
public Integer call() throws IOException {
|
||||
return in.read(b, off, len);
|
||||
}
|
||||
};
|
||||
try {
|
||||
Future<Integer> future = executor.submit(readTask);
|
||||
return future.get(timeoutMSecs, TimeUnit.MILLISECONDS);
|
||||
} catch (RejectedExecutionException e) {
|
||||
throw new IOException("executor failed", e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new IOException("execution failed", e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException("read interrupted", e);
|
||||
} catch (TimeoutException e) {
|
||||
throw new IOException("read timeout", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip.io;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Transport layer supported by the Velux bridge.
|
||||
* <P>
|
||||
* SLIP-based 2nd Level I/O interface towards the <B>Velux</B> bridge.
|
||||
* <P>
|
||||
* It provides methods for pre- and post-communication
|
||||
* as well as a common method for the real communication.
|
||||
* <UL>
|
||||
* <LI>{@link SSLconnection#SSLconnection} for establishing the connection,</LI>
|
||||
* <LI>{@link SSLconnection#send} for sending a message to the bridge,</LI>
|
||||
* <LI>{@link SSLconnection#available} for observation whether there are bytes available,</LI>
|
||||
* <LI>{@link SSLconnection#receive} for receiving a message from the bridge,</LI>
|
||||
* <LI>{@link SSLconnection#close} for tearing down the connection.</LI>
|
||||
* <LI>{@link SSLconnection#setTimeout} for adapting communication parameters.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class SSLconnection {
|
||||
private final Logger logger = LoggerFactory.getLogger(SSLconnection.class);
|
||||
|
||||
// Public definition
|
||||
public static final SSLconnection UNKNOWN = new SSLconnection();
|
||||
|
||||
/*
|
||||
* ***************************
|
||||
* ***** Private Objects *****
|
||||
*/
|
||||
|
||||
private static final int CONNECTION_BUFFER_SIZE = 4096;
|
||||
|
||||
private boolean ready = false;
|
||||
private @Nullable SSLSocket socket;
|
||||
private @Nullable DataOutputStream dOut;
|
||||
private @Nullable DataInputStreamWithTimeout dIn;
|
||||
private int ioTimeoutMSecs = 60000;
|
||||
|
||||
/**
|
||||
* Fake trust manager to suppress any certificate errors,
|
||||
* used within {@link #SSLconnection} for seamless operation
|
||||
* even on self-signed certificates like provided by <B>Velux</B>.
|
||||
*/
|
||||
private final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
|
||||
@Override
|
||||
public X509Certificate @Nullable [] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate @Nullable [] arg0, @Nullable String arg1)
|
||||
throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate @Nullable [] arg0, @Nullable String arg1)
|
||||
throws CertificateException {
|
||||
}
|
||||
} };
|
||||
|
||||
/*
|
||||
* ************************
|
||||
* ***** Constructors *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor for initialization of an unfinished connectivity.
|
||||
*/
|
||||
SSLconnection() {
|
||||
logger.debug("SSLconnection() called.");
|
||||
ready = false;
|
||||
logger.trace("SSLconnection() finished.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to setup and establish a connection.
|
||||
*
|
||||
* @param host as String describing the Service Access Point location i.e. hostname.
|
||||
* @param port as String describing the Service Access Point location i.e. TCP port.
|
||||
* @throws java.net.ConnectException in case of unrecoverable communication failures.
|
||||
* @throws java.io.IOException in case of continuous communication I/O failures.
|
||||
* @throws java.net.UnknownHostException in case of continuous communication I/O failures.
|
||||
*/
|
||||
SSLconnection(String host, int port) throws ConnectException, IOException, UnknownHostException {
|
||||
logger.debug("SSLconnection({},{}) called.", host, port);
|
||||
logger.info("Starting {} bridge connection.", VeluxBindingConstants.BINDING_ID);
|
||||
SSLContext ctx = null;
|
||||
try {
|
||||
ctx = SSLContext.getInstance("SSL");
|
||||
ctx.init(null, trustAllCerts, null);
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
throw new IOException(String.format("create of an empty trust store failed: %s.", e.getMessage()));
|
||||
}
|
||||
logger.trace("SSLconnection(): creating socket...");
|
||||
// Just for avoidance of Potential null pointer access
|
||||
SSLSocket socketX = (SSLSocket) ctx.getSocketFactory().createSocket(host, port);
|
||||
logger.trace("SSLconnection(): starting SSL handshake...");
|
||||
if (socketX != null) {
|
||||
socketX.startHandshake();
|
||||
dOut = new DataOutputStream(socketX.getOutputStream());
|
||||
dIn = new DataInputStreamWithTimeout(socketX.getInputStream());
|
||||
ready = true;
|
||||
socket = socketX;
|
||||
}
|
||||
logger.trace("SSLconnection() finished.");
|
||||
}
|
||||
|
||||
/*
|
||||
* **************************
|
||||
* ***** Public Methods *****
|
||||
*/
|
||||
|
||||
/**
|
||||
* Method to query the readiness of the connection.
|
||||
*
|
||||
* @return <b>ready</b> as boolean for an established connection.
|
||||
*/
|
||||
synchronized boolean isReady() {
|
||||
return ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to pass a message towards the bridge.
|
||||
*
|
||||
* @param packet as Array of bytes to be transmitted towards the bridge via the established connection.
|
||||
* @throws java.io.IOException in case of a communication I/O failure.
|
||||
*/
|
||||
@SuppressWarnings("null")
|
||||
synchronized void send(byte[] packet) throws IOException {
|
||||
logger.trace("send() called, writing {} bytes.", packet.length);
|
||||
if (!ready || (dOut == null)) {
|
||||
throw new IOException();
|
||||
}
|
||||
dOut.write(packet, 0, packet.length);
|
||||
if (logger.isTraceEnabled()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : packet) {
|
||||
sb.append(String.format("%02X ", b));
|
||||
}
|
||||
logger.trace("send() finished after having send {} bytes: {}", packet.length, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to verify that there is message from the bridge.
|
||||
*
|
||||
* @return <b>true</b> if there are any bytes ready to be queried using {@link SSLconnection#receive}.
|
||||
* @throws java.io.IOException in case of a communication I/O failure.
|
||||
*/
|
||||
synchronized boolean available() throws IOException {
|
||||
logger.trace("available() called.");
|
||||
if (!ready || (dIn == null)) {
|
||||
throw new IOException();
|
||||
}
|
||||
@SuppressWarnings("null")
|
||||
int availableBytes = dIn.available();
|
||||
logger.trace("available(): found {} bytes ready to be read (> 0 means true).", availableBytes);
|
||||
return availableBytes > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get a message from the bridge.
|
||||
*
|
||||
* @return <b>packet</b> as Array of bytes as received from the bridge via the established connection.
|
||||
* @throws java.io.IOException in case of a communication I/O failure.
|
||||
*/
|
||||
synchronized byte[] receive() throws IOException {
|
||||
logger.trace("receive() called.");
|
||||
if (!ready || (dIn == null)) {
|
||||
throw new IOException();
|
||||
}
|
||||
byte[] message = new byte[CONNECTION_BUFFER_SIZE];
|
||||
@SuppressWarnings("null")
|
||||
int messageLength = dIn.read(message, 0, message.length, ioTimeoutMSecs);
|
||||
byte[] packet = new byte[messageLength];
|
||||
System.arraycopy(message, 0, packet, 0, messageLength);
|
||||
if (logger.isTraceEnabled()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : packet) {
|
||||
sb.append(String.format("%02X ", b));
|
||||
}
|
||||
logger.trace("receive() finished after having read {} bytes: {}", messageLength, sb.toString());
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor to tear down a connection.
|
||||
*
|
||||
* @throws java.io.IOException in case of a communication I/O failure.
|
||||
*/
|
||||
synchronized void close() throws IOException {
|
||||
logger.debug("close() called.");
|
||||
ready = false;
|
||||
logger.info("Shutting down Velux bridge connection.");
|
||||
// Just for avoidance of Potential null pointer access
|
||||
DataInputStreamWithTimeout dInX = dIn;
|
||||
if (dInX != null) {
|
||||
dInX.close();
|
||||
}
|
||||
// Just for avoidance of Potential null pointer access
|
||||
DataOutputStream dOutX = dOut;
|
||||
if (dOutX != null) {
|
||||
dOutX.close();
|
||||
}
|
||||
// Just for avoidance of Potential null pointer access
|
||||
SSLSocket socketX = socket;
|
||||
if (socketX != null) {
|
||||
socketX.close();
|
||||
}
|
||||
logger.trace("close() finished.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter modification.
|
||||
*
|
||||
* @param timeoutMSecs the maximum duration in milliseconds for read operations.
|
||||
*/
|
||||
void setTimeout(int timeoutMSecs) {
|
||||
logger.debug("setTimeout() set timeout to {} milliseconds.", timeoutMSecs);
|
||||
ioTimeoutMSecs = timeoutMSecs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
* SLIP-protocol I/O with the bridge.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.bridge.slip.io;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
* SLIP-protocol specific implementations of the interactions to IO-homecontrolled devices.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.bridge.slip;
|
||||
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip.utils;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.Command;
|
||||
import org.openhab.binding.velux.internal.things.VeluxKLFAPI.CommandNumber;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Utility class for handling of KLF200 response packets.
|
||||
*
|
||||
* <P>
|
||||
* Methods available:
|
||||
* <P>
|
||||
* Static methods are:
|
||||
* <UL>
|
||||
* <LI>{@link #introLogging} for logging used at the beginning of the response handling.</LI>
|
||||
* <LI>{@link #errorLogging} for error logging during processing.</LI>
|
||||
* <LI>{@link #outroLogging} logging used at the end of the response handling.</LI>
|
||||
* <LI>{@link #isLengthValid} for validation of length of the data part of the message.</LI>
|
||||
* <LI>{@link #check4matchingNodeID} for validation of node identifier.</LI>
|
||||
* <LI>{@link #check4matchingSessionID} for validation of session identifier.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class KLF200Response {
|
||||
|
||||
/**
|
||||
* Provides user-oriented logging in two log levels for monitoring KLF behavior.
|
||||
* <P>
|
||||
* Introduction logging used at the beginning of the response handling.
|
||||
*
|
||||
* @param logger Instantiated logging class to be used for output.
|
||||
* @param responseCommand The command byte of the response packet.
|
||||
* @param thisResponseData The array of bytes which are passed back within the response package.
|
||||
*/
|
||||
public static void introLogging(Logger logger, short responseCommand, byte[] thisResponseData) {
|
||||
logger.debug("setResponse({} with {} bytes of data) called.", Command.get(responseCommand).toString(),
|
||||
thisResponseData.length);
|
||||
logger.trace("setResponse(): handling response {} ({}).", Command.get(responseCommand).toString(),
|
||||
new CommandNumber(responseCommand).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides user-oriented logging in two log levels for monitoring KLF behavior.
|
||||
* <P>
|
||||
* Error logging used at the point where an unexpected or unrecognized command has been received.
|
||||
*
|
||||
* @param logger Instantiated logging class to be used for output.
|
||||
* @param responseCommand The command byte of the response packet.
|
||||
*/
|
||||
public static void errorLogging(Logger logger, short responseCommand) {
|
||||
logger.trace("setResponse(): cannot handle response {} ({}).", Command.get(responseCommand).toString(),
|
||||
responseCommand);
|
||||
logger.warn("Gateway response {} ({}) cannot be handled at this point of interaction.",
|
||||
Command.get(responseCommand).toString(), responseCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides user-oriented logging in two log levels for monitoring KLF behavior.
|
||||
* <P>
|
||||
* Conclusion logging used at the end of the response handling.
|
||||
*
|
||||
* @param logger Instantiated logging class to be used for output.
|
||||
* @param success Describes the success of the response processing.
|
||||
* @param finished Describes whether the response processing has come to an end.
|
||||
*/
|
||||
public static void outroLogging(Logger logger, boolean success, boolean finished) {
|
||||
logger.trace("setResponse(): finished={},success={}.", finished, success);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides user-oriented logging in two log levels for monitoring KLF behavior.
|
||||
* <P>
|
||||
* Check the intended length of the response packet.
|
||||
*
|
||||
* @param logger Instantiated logging class to be used for output.
|
||||
* @param responseCommand The command byte of the response packet.
|
||||
* @param thisResponseData The array of bytes which are passed back within the response package.
|
||||
* @param requiredResponseDataLength The expected size of the array of bytes which are passed back within the
|
||||
* response package.
|
||||
* @return <b>isLengthValid</b> of type boolean which signals the validity of the packet length.
|
||||
*/
|
||||
public static boolean isLengthValid(Logger logger, short responseCommand, byte[] thisResponseData,
|
||||
int requiredResponseDataLength) {
|
||||
logger.trace("isLengthValid() called for {} ({}) with {} bytes of data.",
|
||||
Command.get(responseCommand).toString(), new CommandNumber(responseCommand).toString(),
|
||||
thisResponseData.length);
|
||||
if (thisResponseData.length != requiredResponseDataLength) {
|
||||
logger.warn(
|
||||
"Gateway response {} ({}) consists of a malformed packet (effective length is {}, required length is {}).",
|
||||
Command.get(responseCommand).toString(), new CommandNumber(responseCommand).toString(),
|
||||
thisResponseData.length, requiredResponseDataLength);
|
||||
return false;
|
||||
}
|
||||
logger.trace("isLengthValid() returns {}.", true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides user-oriented logging in two log levels for monitoring KLF behavior.
|
||||
* <P>
|
||||
* Internal support method to match two values for equality.
|
||||
*
|
||||
* @param logger Instantiated logging class to be used for output.
|
||||
* @param idName String describing the type of values being compared.
|
||||
* @param requestID Value of type int have been replaced within the request.
|
||||
* @param responseID Value of type int being received within the response.
|
||||
* @return <b>check4matchingAnyID</b> of type boolean which signals the equality.
|
||||
*/
|
||||
private static boolean check4matchingAnyID(Logger logger, String idName, int requestID, int responseID) {
|
||||
logger.trace("check4matchingAnyID() called for request{} {} and response{} {}.", idName, requestID, idName,
|
||||
responseID);
|
||||
if (requestID != responseID) {
|
||||
logger.warn("Gateway response with {} {} unexpected as query asked for {} {}.", idName, requestID, idName,
|
||||
responseID);
|
||||
return false;
|
||||
}
|
||||
logger.trace("check4matchingAnyID() returns {}.", true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the node identifier of the request with the node identifier within the response
|
||||
* with user-oriented logging in two log levels for monitoring KLF behavior.
|
||||
*
|
||||
* @param logger Instantiated logging class to be used for output.
|
||||
* @param reqNodeID Node identifier of the request.
|
||||
* @param cfmNodeID Node identifier of the response.
|
||||
* @return <b>success</b> of type boolean which signals the success of the communication.
|
||||
*/
|
||||
public static boolean check4matchingNodeID(Logger logger, int reqNodeID, int cfmNodeID) {
|
||||
logger.trace("check4matchingNodeID() called for requestNodeID {} and responseNodeID {}.", reqNodeID, cfmNodeID);
|
||||
return check4matchingAnyID(logger, "NodeID", reqNodeID, cfmNodeID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the session identifier of the request with the session identifier within the response
|
||||
* with user-oriented logging in two log levels for monitoring KLF behavior.
|
||||
*
|
||||
* @param logger Instantiated logging class to be used for output.
|
||||
* @param reqSessionID Session identifier of the request.
|
||||
* @param cfmSessionID Session identifier of the response.
|
||||
* @return <b>success</b> of type boolean which signals the success of the communication.
|
||||
*/
|
||||
public static boolean check4matchingSessionID(Logger logger, int reqSessionID, int cfmSessionID) {
|
||||
logger.trace("check4matchingSessionID() called for requestNodeID {} and responseNodeID {}.", reqSessionID,
|
||||
cfmSessionID);
|
||||
return check4matchingAnyID(logger, "SessionID", reqSessionID, cfmSessionID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Utility class for handling of packets i.e. array of bytes.
|
||||
*
|
||||
* <P>
|
||||
* Methods available:
|
||||
* <UL>
|
||||
* <LI>{@link #Packet(byte[])} creates a Packet object based on the array of bytes.</LI>
|
||||
* <LI>{@link #length()} returns the number of bytes contained within this Packet.</LI>
|
||||
* <LI>{@link #toByteArray} returns the complete Packet as array of bytes.</LI>
|
||||
* <LI>{@link #getByteArray} returns the a range of bytes as array of bytes.</LI>
|
||||
* <LI>{@link #toString} returns the complete packet as human-readable String.</LI>
|
||||
* <LI>{@link #getOneByteValue} returns the value of one byte as int.</LI>
|
||||
* <LI>{@link #setOneByteValue} sets the value of one byte within the Packet.</LI>
|
||||
* <LI>{@link #getTwoByteValue} returns the value of two bytes as int.</LI>
|
||||
* <LI>{@link #setTwoByteValue} sets the value of two bytes within the Packet.</LI>
|
||||
* <LI>{@link #getFourByteValue(int)} returns the value of four bytes as int.</LI>
|
||||
* <LI>{@link #setFourByteValue} sets the value of four bytes within the Packet.</LI>
|
||||
* <LI>{@link #getString} returns the value of a range of bytes as String.</LI>
|
||||
* <LI>{@link #setString} sets the value of a range of bytes within the Packet.</LI>
|
||||
* </UL>
|
||||
* Static methods are:
|
||||
* <UL>
|
||||
* <LI>{@link #shortToString} converts a byte into a human-readable hex-String.</LI>
|
||||
* <LI>{@link #byteArrayToInt} converts a range of four bytes into an int.</LI>
|
||||
* <LI>{@link #intToIPAddressString} converts an int into a String.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Packet {
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Internal Objects
|
||||
*/
|
||||
|
||||
private static final String BLANK = " ";
|
||||
|
||||
private byte[] data;
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Constructor Method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructor: Create a {@link org.openhab.binding.velux.internal.bridge.slip.utils.Packet Packet} out of a
|
||||
* sequence of
|
||||
* bytes.
|
||||
*
|
||||
* @param thisData Packet as Array of bytes.
|
||||
*/
|
||||
public Packet(byte[] thisData) {
|
||||
this.data = thisData;
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Access Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the length of the {@link org.openhab.binding.velux.internal.bridge.slip.utils.Packet Packet}..
|
||||
*
|
||||
* @return <b>packetLength</b>
|
||||
* of type int.
|
||||
*/
|
||||
public int length() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete {@link org.openhab.binding.velux.internal.bridge.slip.utils.Packet Packet} as sequence of
|
||||
* bytes.
|
||||
*
|
||||
* @return <b>packet</b>
|
||||
* of type Array-of-byte.
|
||||
*/
|
||||
public byte[] toByteArray() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a part of the {@link org.openhab.binding.velux.internal.bridge.slip.utils.Packet Packet} as sequence of
|
||||
* bytes
|
||||
* starting at position (n) up to the position (n+length-1).
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @param length Length of the intended slice as int.
|
||||
* @return <b>packet</b> of type Array-of-byte.
|
||||
*/
|
||||
public byte[] getByteArray(int position, int length) {
|
||||
return Arrays.copyOfRange(data, position, position + length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete {@link org.openhab.binding.velux.internal.bridge.slip.utils.Packet Packet}
|
||||
* as human-readable sequence of hex bytes each separated by the given separator.
|
||||
*
|
||||
* @param separator as of Type String.
|
||||
* @return <b>packetString</b> of type String.
|
||||
*/
|
||||
public String toString(String separator) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : this.data) {
|
||||
sb.append(String.format("%02X", b));
|
||||
sb.append(separator);
|
||||
}
|
||||
if (sb.lastIndexOf(separator) > 0) {
|
||||
sb.deleteCharAt(sb.lastIndexOf(separator));
|
||||
}
|
||||
return (sb.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete {@link org.openhab.binding.velux.internal.bridge.slip.utils.Packet Packet}
|
||||
* as human-readable sequence of hex bytes each separated by a blank.
|
||||
*
|
||||
* @return <b>packetString</b> of type String.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.toString(BLANK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the byte at (n)th position as int value for convenience.
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @return <b>value</b> of type int.
|
||||
*/
|
||||
public int getOneByteValue(int position) {
|
||||
return (data[position] & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the value of the byte at (n)th position by setting it to the value passed as int.
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @param value of type int.
|
||||
*/
|
||||
public void setOneByteValue(int position, int value) {
|
||||
data[position] = (byte) value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the bytes at the positions (n)th and (n+1) as int value for convenience.
|
||||
* <P>
|
||||
* Note: Big-endian LSB-0 encoding.
|
||||
* </P>
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @return <b>value</b> of type int.
|
||||
*/
|
||||
public int getTwoByteValue(int position) {
|
||||
return 0x00 << 24 | 0x00 << 16 | (data[position] & 0xff) << 8 | (data[position + 1] & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the value of the bytes at the positions (n) and (n+1) by setting it to the value passed as int.
|
||||
* <P>
|
||||
* Note: Big-endian LSB-0 encoding.
|
||||
* </P>
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @param value of type int.
|
||||
*/
|
||||
public void setTwoByteValue(int position, int value) {
|
||||
data[position] = (byte) ((value >>> 8) & 0xFF);
|
||||
data[position + 1] = (byte) (value & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the bytes at the positions (n)th to (n+3) as int value for convenience.
|
||||
* <P>
|
||||
* Note: Big-endian LSB-0 encoding.
|
||||
* </P>
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @return <b>value</b> of type int.
|
||||
*/
|
||||
public int getFourByteValue(int position) {
|
||||
return data[position] << 24 | (data[position + 1] & 0xff) << 16 | (data[position + 2] & 0xff) << 8
|
||||
| (data[position + 3] & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the value of the bytes at the positions (n) to (n+3) by setting it to the value passed as int.
|
||||
* <P>
|
||||
* Note: Big-endian LSB-0 encoding.
|
||||
* </P>
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @param value of type int.
|
||||
*/
|
||||
public void setFourByteValue(int position, int value) {
|
||||
data[position] = (byte) ((value >>> 24) & 0xFF);
|
||||
data[position + 1] = (byte) ((value >>> 16) & 0xFF);
|
||||
data[position + 2] = (byte) ((value >>> 8) & 0xFF);
|
||||
data[position + 3] = (byte) (value & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the char string converted byte-by-byte starting at the position (n) up to (n+length+1).
|
||||
* <P>
|
||||
* Note: Any trailing null char will be eliminated.
|
||||
* </P>
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @param length Length of the intended slice as int.
|
||||
* @return <b>value</b> of type String.
|
||||
*/
|
||||
public String getString(int position, int length) {
|
||||
return new String(Arrays.copyOfRange(data, position, position + length - 1)).replace("\0", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the value of the bytes starting at the position (n) by setting it to the character values passed as
|
||||
* String.
|
||||
* <P>
|
||||
* Note: The trailing null char will not be stored.
|
||||
* </P>
|
||||
*
|
||||
* @param position Position (n) within the packet.
|
||||
* @param text of type String.
|
||||
*/
|
||||
public void setString(int position, String text) {
|
||||
System.arraycopy(text, 0, data, 0, text.length());
|
||||
}
|
||||
|
||||
/*
|
||||
* ===========================================================
|
||||
* Conversion Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the hex char string representing the byte.
|
||||
*
|
||||
* @param oneByte of type byte to be converted.
|
||||
* @return <b>hexByteString</b> of type String.
|
||||
*/
|
||||
static String shortToString(int oneByte) {
|
||||
return String.format("%02X", oneByte);
|
||||
}
|
||||
|
||||
static int byteArrayToInt(byte[] data) {
|
||||
return data[0] << 24 | (data[1] & 0xff) << 16 | (data[2] & 0xff) << 8 | (data[3] & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dotted string representing an IP address.
|
||||
*
|
||||
* @param ipAddress of type int to be converted.
|
||||
* @return <b>ipAddressString</b> of type String.
|
||||
*/
|
||||
public static String intToIPAddressString(int ipAddress) {
|
||||
return String.format("%d.%d.%d.%d", ((ipAddress >>> 24) & 0xFF), ((ipAddress >>> 16) & 0xFF),
|
||||
((ipAddress >>> 8) & 0xFF), (ipAddress & 0xFF));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip.utils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Transport layer supported by the Velux bridge.
|
||||
* <P>
|
||||
* Module semantic: encoding and decoding of frames according to RFC 1055.
|
||||
* <P>
|
||||
* It defines informations how to send query and receive answer through the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider VeluxBridgeProvider}
|
||||
* as described by the {@link org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol
|
||||
* BridgeCommunicationProtocol}.
|
||||
* <P>
|
||||
* Methods available:
|
||||
* <UL>
|
||||
* <LI>{@link #SlipEncoding(short command, byte[] data) } builds a message based on command and data.</LI>
|
||||
* <LI>{@link #SlipEncoding(byte[] thisPacket) } splits a message into command and data.</LI>
|
||||
* <LI>{@link #isValid} returns the number of bytes contained within this Packet.</LI>
|
||||
* <LI>{@link #getCommand} returns the Command part of the message.</LI>
|
||||
* <LI>{@link #getData} returns the data part of the message.</LI>
|
||||
* <LI>{@link #toMessage} returns the complete message.</LI>
|
||||
* <LI>{@link #toString} returns the message in a human-readable way.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SlipEncoding {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SlipEncoding.class);
|
||||
|
||||
private static final byte PROTOCOL_ID = 0;
|
||||
private static boolean encodingValid = false;
|
||||
private static byte[] message = new byte[0];
|
||||
|
||||
/**
|
||||
* Builds a message based on command and parameters.
|
||||
*
|
||||
* @param command Message type as short.
|
||||
* @param data Parameters as Array of bytes.
|
||||
*/
|
||||
public SlipEncoding(short command, byte[] data) {
|
||||
logger.trace("SlipEncoding(constructor) for command 0x{} with data size {} called.",
|
||||
Integer.toHexString(new Short(command).intValue()), data.length);
|
||||
if (data.length > 250) {
|
||||
logger.warn("SlipEncoding(constructor) called with data size {}: too big, aborting.", data.length);
|
||||
encodingValid = false;
|
||||
} else {
|
||||
byte checksum = 0;
|
||||
message = new byte[data.length + 5];
|
||||
message[0] = PROTOCOL_ID;
|
||||
message[1] = (byte) (3 + data.length);
|
||||
message[2] = (byte) (command >>> 8);
|
||||
message[3] = (byte) command;
|
||||
message[4 + data.length] = 0;
|
||||
System.arraycopy(data, 0, message, 4, data.length);
|
||||
for (byte b : message) {
|
||||
checksum = (byte) (checksum ^ b);
|
||||
}
|
||||
message[4 + data.length] = checksum;
|
||||
logger.trace("SlipEncoding(constructor) successfully initialized, storing bytes: {}.", this.toString());
|
||||
encodingValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a message based on transfer syntax as Array-of-bytes.
|
||||
*
|
||||
* @param thisPacket Message as Array of bytes.
|
||||
*/
|
||||
|
||||
public SlipEncoding(byte[] thisPacket) {
|
||||
logger.trace("SlipEncoding(constructor) called for decoding a packet with size {}.", thisPacket.length);
|
||||
message = thisPacket;
|
||||
encodingValid = false;
|
||||
do {
|
||||
// ProtocolID:Length:Command:Data(0-250):Checksum
|
||||
if (message.length < 5) {
|
||||
logger.warn("SlipEncoding(constructor) called with data size {}: Packet too short.", message.length);
|
||||
break;
|
||||
}
|
||||
if (message[0] != PROTOCOL_ID) {
|
||||
logger.warn("SlipEncoding(constructor) called: Unexpected PROTOCOL_ID (got {}).",
|
||||
Packet.shortToString(message[0]));
|
||||
break;
|
||||
}
|
||||
byte checksum = 0;
|
||||
for (int i = 0; i < message.length - 1; i++) {
|
||||
checksum = (byte) (checksum ^ message[i]);
|
||||
}
|
||||
if (message[message.length - 1] != checksum) {
|
||||
logger.warn("SlipEncoding(constructor) Invalid packet checksum (got {} != calculated {}).",
|
||||
Packet.shortToString(message[message.length - 1]), Packet.shortToString(checksum));
|
||||
logger.debug("SlipEncoding(constructor) packet is {}.", new Packet(message).toString(":"));
|
||||
break;
|
||||
}
|
||||
logger.trace("SlipEncoding(constructor) successfully initialized with command 0x{} and data {}.",
|
||||
Packet.shortToString(this.getCommand()), new Packet(this.getData()).toString());
|
||||
encodingValid = true;
|
||||
} while (false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the validity of the message content.
|
||||
*
|
||||
* @return <b>encodingValid</b>
|
||||
* of type boolean as status of the encoding or decoding.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return encodingValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the command.
|
||||
*
|
||||
* @return <b>command</b>
|
||||
* of type short as encoded within the message.
|
||||
*/
|
||||
public short getCommand() {
|
||||
short command = ByteBuffer.wrap(new byte[] { message[2], message[3] }).getShort();
|
||||
logger.trace("getCommand() returns 0x{}.", String.format("%02X ", command));
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the data i.e. parameters to the command.
|
||||
*
|
||||
* @return <b>data</b>
|
||||
* of type Array-of-byte as encoded within the message.
|
||||
*/
|
||||
public byte[] getData() {
|
||||
byte[] data = new byte[message.length - 5];
|
||||
System.arraycopy(message, 4, data, 0, message.length - 5);
|
||||
logger.trace("getData() returns {} bytes: {}.", data.length, new Packet(data).toString());
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the complete message.
|
||||
*
|
||||
* @return <b>message</b>
|
||||
* of type Array-of-byte.
|
||||
*/
|
||||
public byte[] toMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new Packet(message).toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 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.velux.internal.bridge.slip.utils;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Transport layer supported by the Velux bridge:
|
||||
* SLIP wrapping supported by the Velux bridge.
|
||||
* <P>
|
||||
* Methods available:
|
||||
* <UL>
|
||||
* <LI>{@link #encode(byte[] payload) } converts a given payload into transfer byte encoding.</LI>
|
||||
* <LI>{@link #decode(byte[] packet) } converts a given transfer byte encoding into a payload.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class SlipRFC1055 {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(SlipRFC1055.class);
|
||||
|
||||
private static final byte SLIP_BYTE_END = (byte) 0xC0;
|
||||
private static final byte SLIP_BYTE_ESC = (byte) 0xDB;
|
||||
private static final byte SLIP_BYTE_ESC_END = (byte) 0xDC;
|
||||
private static final byte SLIP_BYTE_ESC_ESC = (byte) 0xDD;
|
||||
|
||||
/**
|
||||
* Converts a given payload into transfer byte encoding.
|
||||
*
|
||||
* @param payload Array of bytes to be transmitted.
|
||||
* @return <b>packet</b>
|
||||
* of type Array-of-byte as encoded payload.
|
||||
*/
|
||||
public byte[] encode(byte[] payload) {
|
||||
logger.trace("encode() for data size {} called.", payload.length);
|
||||
|
||||
int additional = 2;
|
||||
for (byte b : payload) {
|
||||
if ((b == SLIP_BYTE_ESC) || (b == SLIP_BYTE_END)) {
|
||||
additional++;
|
||||
}
|
||||
}
|
||||
byte[] packet = new byte[payload.length + additional];
|
||||
int packetIndex = 0;
|
||||
packet[packetIndex++] = SLIP_BYTE_END;
|
||||
|
||||
for (byte b : payload) {
|
||||
if (b == SLIP_BYTE_ESC) {
|
||||
packet[packetIndex++] = SLIP_BYTE_ESC;
|
||||
packet[packetIndex++] = SLIP_BYTE_ESC_ESC;
|
||||
} else if (b == SLIP_BYTE_END) {
|
||||
packet[packetIndex++] = SLIP_BYTE_ESC;
|
||||
packet[packetIndex++] = SLIP_BYTE_ESC_END;
|
||||
} else {
|
||||
packet[packetIndex++] = b;
|
||||
}
|
||||
}
|
||||
packet[packetIndex++] = SLIP_BYTE_END;
|
||||
assert (packetIndex == packet.length);
|
||||
logger.trace("encode() provides transfer encoding: {}.", new Packet(packet));
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given transfer byte encoding into a payload.
|
||||
*
|
||||
* @param packet Array of bytes as being received.
|
||||
* @return <b>payload</b>
|
||||
* of type Array-of-byte as decoded payload.
|
||||
* @throws ParseException in case of decoding errors.
|
||||
*/
|
||||
public byte[] decode(byte[] packet) throws ParseException {
|
||||
logger.trace("decode() for packet size {} called.", packet.length);
|
||||
if (packet.length < 3) {
|
||||
throw new ParseException("Packet too short", 0);
|
||||
}
|
||||
if (packet[0] != SLIP_BYTE_END) {
|
||||
throw new ParseException("Unexpected byte at 1st position", 0);
|
||||
}
|
||||
if (packet[packet.length - 1] != SLIP_BYTE_END) {
|
||||
throw new ParseException("Unexpected byte at last position", 0);
|
||||
}
|
||||
int additional = -2;
|
||||
for (int i = 0; i < packet.length; i++) {
|
||||
if (packet[i] == SLIP_BYTE_ESC) {
|
||||
additional--;
|
||||
}
|
||||
}
|
||||
byte[] payload = new byte[packet.length + additional];
|
||||
|
||||
int packetIndex = 0;
|
||||
for (int i = 0; i < packet.length; i++) {
|
||||
if ((i == 0) || (i == packet.length - 1)) {
|
||||
continue;
|
||||
}
|
||||
if ((packet[i] == SLIP_BYTE_ESC) && (packet[i + 1] == SLIP_BYTE_ESC_ESC)) {
|
||||
payload[packetIndex++] = SLIP_BYTE_ESC;
|
||||
i++;
|
||||
} else if ((packet[i] == SLIP_BYTE_ESC) && (packet[i + 1] == SLIP_BYTE_ESC_END)) {
|
||||
payload[packetIndex++] = SLIP_BYTE_END;
|
||||
i++;
|
||||
} else {
|
||||
payload[packetIndex++] = packet[i];
|
||||
}
|
||||
}
|
||||
logger.trace("decode() provides payload: {}.", new Packet(payload));
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
* Utility classes for the SLIP-protocol.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.bridge.slip.utils;
|
||||
@@ -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.velux.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link VeluxBridgeConfiguration} is a wrapper for
|
||||
* configuration settings needed to access the
|
||||
* {@link org.openhab.binding.velux.internal.bridge.VeluxBridgeProvider}
|
||||
* device.
|
||||
* <p>
|
||||
* It contains the factory default values as well.
|
||||
* <ul>
|
||||
* <li>{@link VeluxBridgeConfiguration#protocol protocol} protocol type
|
||||
* (one of http or https or slip),</li>
|
||||
* <li>{@link VeluxBridgeConfiguration#ipAddress ipAddress} bridge IP address,</li>
|
||||
* <li>{@link VeluxBridgeConfiguration#tcpPort tcpPort} bridge TCP port,</li>
|
||||
* <li>{@link VeluxBridgeConfiguration#password password} bridge password,</li>
|
||||
* <li>{@link VeluxBridgeConfiguration#timeoutMsecs timeoutMsecs} communication timeout in milliseconds,</li>
|
||||
* <li>{@link VeluxBridgeConfiguration#retries retries} number of retries (with exponential backoff algorithm),</li>
|
||||
* <li>{@link VeluxBridgeConfiguration#refreshMSecs refreshMSecs} refreshMSecs interval for retrieval of bridge
|
||||
* information.</li>
|
||||
* <li>{@link VeluxBridgeConfiguration#isBulkRetrievalEnabled isBulkRetrievalEnabled} flag to use bulk product</LI>
|
||||
* <li>{@link VeluxBridgeConfiguration#isSequentialEnforced isSequentialEnforced} flag to enforce sequential control on
|
||||
* actuators.</LI>
|
||||
* <li>{@link VeluxBridgeConfiguration#isProtocolTraceEnabled isProtocolTraceEnabled} flag to enable protocol logging
|
||||
* (via loglevel INFO).</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxBridgeConfiguration {
|
||||
public static final String BRIDGE_PROTOCOL = "protocol";
|
||||
public static final String BRIDGE_IPADDRESS = "ipAddress";
|
||||
public static final String BRIDGE_TCPPORT = "tcpPort";
|
||||
public static final String BRIDGE_PASSWORD = "password";
|
||||
public static final String BRIDGE_TIMEOUT_MSECS = "timeoutMsecs";
|
||||
public static final String BRIDGE_RETRIES = "retries";
|
||||
public static final String BRIDGE_REFRESH_MSECS = "refreshMsecs";
|
||||
public static final String BRIDGE_IS_BULK_RETRIEVAL_ENABLED = "isBulkRetrievalEnabled";
|
||||
public static final String BRIDGE_IS_SEQUENTIAL_ENFORCED = "isSequentialEnforced";
|
||||
public static final String BRIDGE_PROTOCOL_TRACE_ENABLED = "isProtocolTraceEnabled";
|
||||
|
||||
/*
|
||||
* Value to flag any changes towards the getter.
|
||||
*/
|
||||
public boolean hasChanged = true;
|
||||
|
||||
/*
|
||||
* Default values - should not be modified
|
||||
*/
|
||||
public String protocol = "slip";
|
||||
public String ipAddress = "192.168.1.1";
|
||||
public int tcpPort = 51200;
|
||||
public String password = "velux123";
|
||||
public int timeoutMsecs = 1000; // one second
|
||||
public int retries = 5;
|
||||
public long refreshMSecs = 10000L; // 10 seconds
|
||||
public boolean isBulkRetrievalEnabled = true;
|
||||
public boolean isSequentialEnforced = false;
|
||||
public boolean isProtocolTraceEnabled = false;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* 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.velux.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||
import org.openhab.binding.velux.internal.things.VeluxProductSerialNo;
|
||||
|
||||
/**
|
||||
* The {@link VeluxThingConfiguration} is a wrapper for
|
||||
* configuration settings needed to access the <B>Velux</B> device.
|
||||
* <p>
|
||||
* It contains the factory default values as well.
|
||||
* <p>
|
||||
* There are three parts. Information for:
|
||||
* <UL>
|
||||
* <LI>{@link #sceneName} Name of a scene,</LI>
|
||||
* <LI>{@link #serial} Unique identification of type actuator, rollershutter and window,</LI>
|
||||
* <LI>{@link #name} Alternate Unique identification of type actuator, rollershutter and window,</LI>
|
||||
* <LI>{@link #inverted} Value inversion for an actuator, rollershutter or window,</LI>
|
||||
* <LI>{@link #velocity} Speed value for a scene,</LI>
|
||||
* <LI>{@link #sceneLevels} Virtual shutter definition as a set of scenes imitating a shutter,</LI>
|
||||
* <LI>{@link #currentLevel} Initial state of Virtual shutter definition.</LI>
|
||||
* </UL>
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution.
|
||||
* @author Andrew Fiddian-Green - adapted.
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class VeluxThingConfiguration extends Configuration {
|
||||
|
||||
/**
|
||||
* {@link #sceneName} of type {@link String}, identifying a Velux scene by human-readable name.
|
||||
* <P>
|
||||
* <B>Configuration for the channel scene:</B>
|
||||
* </P>
|
||||
* <UL>
|
||||
* <LI>{@link #sceneName} for identification of a set of settings, so called scene.</LI>
|
||||
* </UL>
|
||||
*/
|
||||
String sceneName = VeluxBindingConstants.UNKNOWN;
|
||||
|
||||
/**
|
||||
* {@link #serial} of type {@link String}, identifying a io-homecontrol device by its serial number (i.e.
|
||||
* 43:12:14:5A:12:1C:05:5F).
|
||||
* <P>
|
||||
* <B>Configuration for the channels actuator, rollershutter and window:</B>
|
||||
* </P>
|
||||
* <UL>
|
||||
* <LI>{@link #serial} for identification of a io-homecontrol device,</LI>
|
||||
* <LI>{@link #name} for alternate identification of a io-homecontrol device,</LI>
|
||||
* <LI>{@link #inverted} for modified value behavior.</LI>
|
||||
* <LI>{@link #velocity} for modified action speed.</LI>
|
||||
* </UL>
|
||||
*/
|
||||
public String serial = VeluxProductSerialNo.UNKNOWN;
|
||||
/**
|
||||
* {@link #name} of type {@link String}, identifying a io-homecontrol device by its registration name especially
|
||||
* for <B>somfy</B> as they do not provide a valid serial number.
|
||||
* <P>
|
||||
* Part of the {@link #serial Configuration for the channels actuator, rollershutter and window}.
|
||||
* </P>
|
||||
*/
|
||||
String name = VeluxBindingConstants.UNKNOWN;
|
||||
/**
|
||||
* {@link #inverted} of type {@link Boolean}, inverts each Channel value. This means 0% will be handled as 100%,
|
||||
* and vice versa, 100% will be handled as 0%.
|
||||
* <P>
|
||||
* Part of the {@link #serial Configuration for the channels actuator, rollershutter and window}.
|
||||
* </P>
|
||||
*/
|
||||
Boolean inverted = false;
|
||||
/**
|
||||
* {@link #velocity} of type {@link String}, describes the intended speed of action.
|
||||
* Possible values are defined within VeluxProductVelocity.
|
||||
* <P>
|
||||
* Part of the {@link #serial Configuration for the channels actuator, rollershutter and window}.
|
||||
* </P>
|
||||
*/
|
||||
String velocity = VeluxBindingConstants.UNKNOWN;
|
||||
|
||||
/**
|
||||
* {@link #sceneLevels} of type {@link String}, identifying a number of Velux scenes which act together as a virtual
|
||||
* shutter. Each scene is defined to a corresponding shutter level.
|
||||
* <P>
|
||||
* <B>Configuration for the channel virtualshutter:</B>
|
||||
* </P>
|
||||
* <UL>
|
||||
* <LI>{@link #sceneLevels} for identification of a set of settings, so called scene.</LI>
|
||||
* </UL>
|
||||
* <P>
|
||||
* Additionally it contains an internal variable for keeping the actual virtual shutter level.
|
||||
* </P>
|
||||
* <UL>
|
||||
* <LI>{@link #currentLevel} for identification of a set of settings, so called scene.</LI>
|
||||
* </UL>
|
||||
*/
|
||||
String sceneLevels = VeluxBindingConstants.UNKNOWN;
|
||||
/**
|
||||
* {@link #currentLevel} of type {@link int}, which represents the current shutter level.
|
||||
* <P>
|
||||
* Private part of the {@link #sceneLevels Configuration for the channel virtualshutter}.
|
||||
* </P>
|
||||
*/
|
||||
int currentLevel = 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
* Class with default openHAB configuration definitions.
|
||||
*
|
||||
* @author Guenther Schreiner - Initial contribution
|
||||
*/
|
||||
package org.openhab.binding.velux.internal.config;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user