added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.ihc-${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-ihc" description="IHC / ELKO Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle dependency="true">mvn:org.apache.httpcomponents/httpcore-osgi/4.4.10</bundle>
<bundle dependency="true">mvn:org.apache.httpcomponents/httpclient-osgi/4.5.8</bundle>
<bundle dependency="true">mvn:commons-logging/commons-logging/1.2</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.ihc/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,73 @@
/**
* 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.ihc.internal;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle button press durations
*
* @author Pauli Anttila - Initial contribution
*/
public class ButtonPressDurationDetector {
private final Logger logger = LoggerFactory.getLogger(ButtonPressDurationDetector.class);
private boolean shortPress;
private boolean longPress;
private Duration duration;
private long longPressTime;
private long longPressMaxTime;
public boolean isShortPress() {
return shortPress;
}
public boolean isLongPress() {
return longPress;
}
public ButtonPressDurationDetector(Duration duration, long longPressTime, long longPressMaxTime) {
this.duration = duration;
this.longPressTime = longPressTime;
this.longPressMaxTime = longPressMaxTime;
calculate();
}
private void calculate() {
if (duration.toMillis() < 0) {
logger.debug("Button press duration < 0ms");
} else if (isBetween(duration.toMillis(), 0, longPressTime)) {
logger.debug("Button press duration > {}ms and < {}ms", 0, longPressTime);
shortPress = true;
} else if (isBetween(duration.toMillis(), longPressTime, longPressMaxTime)) {
logger.debug("Button press duration > {}ms and < {}ms", longPressTime, longPressMaxTime);
longPress = true;
} else {
logger.debug("Button press duration > {}ms, ignore it", longPressMaxTime);
}
}
private boolean isBetween(long value, long minValue, long maxValueInclusive) {
return (value > minValue && value <= maxValueInclusive);
}
@Override
public String toString() {
return String.format("[ duration=%sms, shortPress=%b, longPress=%b ]", duration.toMillis(), shortPress,
longPress);
}
}

View File

@@ -0,0 +1,241 @@
/**
* 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.ihc.internal;
import static org.openhab.binding.ihc.internal.IhcBindingConstants.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.ihc.internal.config.ChannelParams;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Generic methods related to openHAB channels.
*
* @author Pauli Anttila - Initial contribution
*/
public class ChannelUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(ChannelUtils.class);
public static Set<Integer> getAllChannelsResourceIds(Thing thing) {
Set<Integer> resourceIds = new HashSet<>();
thing.getChannels().forEach(c -> {
try {
ChannelParams params = new ChannelParams(c);
if (params.getResourceId() != null && params.getResourceId() != 0) {
resourceIds.add(params.getResourceId());
}
} catch (ConversionException e) {
LOGGER.warn("Channel param error, reason: {}.", e.getMessage(), e);
}
});
return resourceIds;
}
public static Set<Integer> getAllTriggerChannelsResourceIds(Thing thing) {
Set<Integer> resourceIds = new HashSet<>();
thing.getChannels().forEach(c -> {
try {
ChannelParams params = new ChannelParams(c);
if (params.getChannelTypeId() != null) {
switch (params.getChannelTypeId()) {
case CHANNEL_TYPE_PUSH_BUTTON_TRIGGER:
if (params.getResourceId() != null && params.getResourceId() != 0) {
resourceIds.add(params.getResourceId());
}
break;
}
}
} catch (ConversionException e) {
LOGGER.warn("Channel param error, reason: {}.", e.getMessage(), e);
}
});
return resourceIds;
}
public static void addChannelsFromProjectFile(Thing thing, Document projectFile, List<Channel> thingChannels) {
if (projectFile != null) {
try {
NodeList nodes = projectFile.getElementsByTagName("product_dataline");
if (nodes != null) {
for (int i = 0; i < nodes.getLength(); i++) {
Element node = (Element) nodes.item(i);
addChannelsFromProjectFile(thing, node.getElementsByTagName("dataline_input"), "Switch",
"input", CHANNEL_TYPE_SWITCH, thingChannels);
addChannelsFromProjectFile(thing, node.getElementsByTagName("dataline_output"), "Switch",
"output", CHANNEL_TYPE_SWITCH, thingChannels);
addChannelsFromProjectFile(thing, node.getElementsByTagName("resource_temperature"), "Number",
"temperature", CHANNEL_TYPE_NUMBER, thingChannels);
addChannelsFromProjectFile(thing, node.getElementsByTagName("resource_humidity_level"),
"Number", "humidity", CHANNEL_TYPE_NUMBER, thingChannels);
}
}
} catch (RuntimeException e) {
LOGGER.warn("Error occured when adding channels, reason: {}", e.getMessage(), e);
}
try {
NodeList nodes = projectFile.getElementsByTagName("product_airlink");
if (nodes != null) {
addRFDeviceChannels(thing, nodes, thingChannels);
for (int i = 0; i < nodes.getLength(); i++) {
Element node = (Element) nodes.item(i);
addChannelsFromProjectFile(thing, node.getElementsByTagName("airlink_input"), "Switch", "input",
CHANNEL_TYPE_SWITCH, thingChannels);
addChannelsFromProjectFile(thing, node.getElementsByTagName("airlink_output"), "Switch",
"output", CHANNEL_TYPE_SWITCH, thingChannels);
addChannelsFromProjectFile(thing, node.getElementsByTagName("airlink_relay"), "Switch",
"output", CHANNEL_TYPE_SWITCH, thingChannels);
addChannelsFromProjectFile(thing, node.getElementsByTagName("airlink_dimming"), "Dimmer",
"output", CHANNEL_TYPE_SWITCH, thingChannels);
}
}
} catch (RuntimeException e) {
LOGGER.warn("Error occured when adding channels, reason: {}", e.getMessage(), e);
}
} else {
LOGGER.warn("Project file data doesn't exist, can't automatically create channels!");
}
}
public static void addControllerChannels(Thing thing, List<Channel> thingChannels) {
if (thing != null && thingChannels != null) {
Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), CHANNEL_CONTROLLER_STATE), "String")
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_CONTROLLER_STATE)).build();
addOrUpdateChannel(channel, thingChannels);
channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), CHANNEL_CONTROLLER_UPTIME), "Number")
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_CONTROLLER_UPTIME)).build();
addOrUpdateChannel(channel, thingChannels);
channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), CHANNEL_CONTROLLER_TIME), "DateTime")
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_CONTROLLER_TIME)).build();
addOrUpdateChannel(channel, thingChannels);
}
}
private static void addRFDeviceChannels(Thing thing, NodeList nodes, List<Channel> thingChannels) {
if (thing != null && nodes != null && thingChannels != null) {
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
Long serialNumber = Long.parseLong(element.getAttribute("serialnumber").replace("_0x", ""), 16);
if (serialNumber != 0) {
String name = element.getAttribute("name");
String position = element.getAttribute("position");
String serialNumberHex = Long.toHexString(serialNumber);
Configuration configuration = new Configuration();
configuration.put("serialNumber", serialNumber);
// low battery
String channelId = String.format("%s-lowBattery", serialNumberHex);
String label = createDescription(position, name, serialNumberHex, "Low Battery");
Channel channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), channelId), "Switch")
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_RF_LOW_BATTERY))
.withConfiguration(configuration).withLabel(label).build();
addOrUpdateChannel(channel, thingChannels);
// signal level
channelId = String.format("%s-signalStrength", serialNumberHex);
label = createDescription(position, name, serialNumberHex, "Signal Strength");
channel = ChannelBuilder.create(new ChannelUID(thing.getUID(), channelId), "String")
.withType(new ChannelTypeUID(BINDING_ID, CHANNEL_TYPE_RF_SIGNAL_STRENGTH))
.withConfiguration(configuration).withLabel(label).build();
addOrUpdateChannel(channel, thingChannels);
}
}
}
}
private static void addChannelsFromProjectFile(Thing thing, NodeList nodes, String acceptedItemType, String group,
String channelType, List<Channel> thingChannels) {
if (thing != null && nodes != null && thingChannels != null) {
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
Element parent = (Element) element.getParentNode();
if ("settings".equals(parent.getNodeName())) {
// get settings element parent
parent = (Element) parent.getParentNode();
}
Element parentParent = (Element) parent.getParentNode();
String parentName = parent.getAttribute("name");
String parentPosition = parent.getAttribute("position");
String parentParentName = parentParent.getAttribute("name");
String resourceName = element.getAttribute("name");
int resourceId = Integer.parseInt(element.getAttribute("id").replace("_0x", ""), 16);
String description = createDescription(parentParentName, parentPosition, parentName, resourceName);
ChannelUID channelUID = new ChannelUID(thing.getUID(), group + resourceId);
ChannelTypeUID type = new ChannelTypeUID(BINDING_ID, channelType);
Configuration configuration = new Configuration();
configuration.put(PARAM_RESOURCE_ID, new Integer(resourceId));
Channel channel = ChannelBuilder.create(channelUID, acceptedItemType).withConfiguration(configuration)
.withLabel(description).withType(type).build();
addOrUpdateChannel(channel, thingChannels);
}
}
}
private static String createDescription(String name1, String name2, String name3, String name4) {
String description = "";
if (StringUtils.isNotEmpty(name1)) {
description = name1;
}
if (StringUtils.isNotEmpty(name2)) {
description += String.format(" - %s", name2);
}
if (StringUtils.isNotEmpty(name3)) {
description += String.format(" - %s", name3);
}
if (StringUtils.isNotEmpty(name4)) {
description += String.format(" - %s", name4);
}
return description;
}
private static void addOrUpdateChannel(Channel newChannel, List<Channel> thingChannels) {
removeChannelByUID(thingChannels, newChannel.getUID());
thingChannels.add(newChannel);
}
private static void removeChannelByUID(List<Channel> thingChannels, ChannelUID channelUIDtoRemove) {
Predicate<Channel> channelPredicate = c -> c.getUID().getId().equals(channelUIDtoRemove.getId());
thingChannels.removeIf(channelPredicate);
}
}

View File

@@ -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.ihc.internal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openhab.binding.ihc.internal.ws.projectfile.IhcEnumValue;
/**
* Class for holding enumerations from IHC / ELKO project file.
*
* @author Pauli Anttila - Initial contribution
*/
public class EnumDictionary {
private Map<Integer, List<IhcEnumValue>> enumDictionary = new HashMap<>();
public EnumDictionary(Map<Integer, List<IhcEnumValue>> enums) {
this.enumDictionary = enums;
}
/**
* Returns all possible enumerated values for corresponding enum type.
*
* @param typeDefinititonId Enum type definition identifier.
* @return list of enum values.
*/
public List<IhcEnumValue> getEnumValues(int typeDefinititonId) {
return enumDictionary.get(typeDefinititonId);
}
}

View File

@@ -0,0 +1,86 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link IhcBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Pauli Anttila - Initial contribution
*/
@NonNullByDefault
public class IhcBindingConstants {
public static final String BINDING_ID = "ihc";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_CONTROLLER = new ThingTypeUID(BINDING_ID, "controller");
public static final String PROPERTY_MANUFACTURER = "controllerManufacturer";
public static final String PROPERTY_SERIALNUMBER = "controllerSerialNumber";
public static final String PROPERTY_SW_VERSION = "controllerSwVersion";
public static final String PROPERTY_FW_VERSION = "controllerHwVersion";
public static final String PROPERTY_APP_WITHOUT_VIEWER = "controllerIsWithoutViewer";
public static final String PROPERTY_SW_DATE = "controllerSwDate";
public static final String PROPERTY_PRODUCTION_DATE = "controllerProductionDate";
public static final String PROPERTY_PROJECT_DATE = "projectDate";
public static final String PROPERTY_PROJECT_NUMBER = "projectNumber";
public static final String PROPERTY_DATALINE_VERSION = "controllerDatalineVersion";
public static final String PROPERTY_RF_MODULE_VERSION = "controllerRfModSwVersion";
public static final String PROPERTY_RF_MODULE_SERIALNUMBER = "controllerRfModSerialNumber";
// List of all Channel ids
public static final String CHANNEL_CONTROLLER_STATE = "controllerState";
public static final String CHANNEL_CONTROLLER_UPTIME = "controllerUptime";
public static final String CHANNEL_CONTROLLER_TIME = "controllerTime";
// List of all Channel type ids
public static final String CHANNEL_TYPE_CONTROLLER_STATE = "controller-state";
public static final String CHANNEL_TYPE_CONTROLLER_SW_VER = "controller-sw-version";
public static final String CHANNEL_TYPE_CONTROLLER_HW_VER = "controller-hw-version";
public static final String CHANNEL_TYPE_CONTROLLER_UPTIME = "controller-uptime";
public static final String CHANNEL_TYPE_CONTROLLER_TIME = "controller-time";
public static final String CHANNEL_TYPE_NUMBER = "number";
public static final String CHANNEL_TYPE_SWITCH = "switch";
public static final String CHANNEL_TYPE_CONTACT = "contact";
public static final String CHANNEL_TYPE_DIMMER = "dimmer";
public static final String CHANNEL_TYPE_DATETIME = "datetime";
public static final String CHANNEL_TYPE_STRING = "string";
public static final String CHANNEL_TYPE_ROLLERSHUTTER = "rollershutter";
public static final String CHANNEL_TYPE_RF_SIGNAL_STRENGTH = "rf-device-signal-strength";
public static final String CHANNEL_TYPE_RF_LOW_BATTERY = "rf-device-low-battery";
public static final String CHANNEL_TYPE_PUSH_BUTTON_TRIGGER = "push-button-trigger";
// List of all channel parameters
public static final String PARAM_RESOURCE_ID = "resourceId";
public static final String PARAM_DIRECTION = "direction";
public static final String PARAM_CMD_TO_REACT = "commandToReact";
public static final String PARAM_SERIAL_NUMBER = "serialNumber";
public static final String PARAM_PULSE_WIDTH = "pulseWidth";
public static final String PARAM_LONG_PRESS_TIME = "longPressTime";
public static final String PARAM_INVERTED = "inverted";
public static final String PARAM_ON_LEVEL = "onLevel";
public static final String DIRECTION_READ_WRITE = "ReadWrite";
public static final String DIRECTION_WRITE_ONLY = "WriteOnly";
public static final String DIRECTION_READ_ONLY = "ReadOnly";
public static final String EVENT_PRESSED = "PRESSED";
public static final String EVENT_RELEASED = "RELEASED";
public static final String EVENT_SHORT_PRESS = "SHORT_PRESS";
public static final String EVENT_LONG_PRESS = "LONG_PRESS";
}

View File

@@ -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.ihc.internal;
import static org.openhab.binding.ihc.internal.IhcBindingConstants.THING_CONTROLLER;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.ihc.internal.handler.IhcHandler;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link IhcHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Pauli Anttila - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.ihc")
@NonNullByDefault
public class IhcHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_CONTROLLER).collect(Collectors.toSet()));
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(THING_CONTROLLER)) {
return new IhcHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,85 @@
/**
* 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.ihc.internal;
/**
* Class to convert IHC RF signal level value to openHAB signal level.
*
* @author Pauli Anttila - Initial contribution
*/
public class SignalLevelConverter {
int signalLevel;
public SignalLevelConverter(int signalLevel) {
this.signalLevel = signalLevel;
}
public int getSystemWideSignalLevel() {
return convertSignalLevelToSystemWideLevel(signalLevel);
}
/**
* Convert internal signal level (0-18) to system wide signal level (0-4).
*
* @param signalLevel Internal signal level
* @return Signal level in system wide level
*/
private int convertSignalLevelToSystemWideLevel(int signalLevel) {
int newLevel;
/*
* IHC signal levels are always between 0-18.
*
* Use switch case to make level adaption easier in future if needed.
*/
switch (signalLevel) {
case 0:
case 1:
newLevel = 0;
break;
case 2:
case 3:
case 4:
newLevel = 1;
break;
case 5:
case 6:
case 7:
case 8:
newLevel = 2;
break;
case 9:
case 10:
case 11:
case 12:
case 13:
newLevel = 3;
break;
case 14:
case 15:
case 16:
case 17:
case 18:
default:
newLevel = 4;
}
return newLevel;
}
}

View File

@@ -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.ihc.internal.config;
import static org.openhab.binding.ihc.internal.IhcBindingConstants.*;
import java.math.BigDecimal;
import java.util.Map;
import java.util.function.Function;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.type.ChannelTypeUID;
/**
* Class for holding channel parameterization.
*
* @author Pauli Anttila - Initial contribution
*/
public class ChannelParams {
private String channelTypeId;
private Integer resourceId;
private String direction;
private String commandToReact;
private Integer pulseWidth;
private Boolean inverted;
private Long serialNumber;
private Integer longPressTime;
private Integer onLevel;
public ChannelParams(@NonNull Channel channel) throws ConversionException {
ChannelTypeUID channelTypeUID = channel.getChannelTypeUID();
if (channelTypeUID != null) {
channelTypeId = channelTypeUID.getId();
}
Map<String, Object> map = channel.getConfiguration().getProperties();
for (Map.Entry<String, Object> entry : map.entrySet()) {
switch (entry.getKey()) {
case PARAM_RESOURCE_ID:
resourceId = getChannelParameterAsInteger(entry.getValue());
break;
case PARAM_DIRECTION:
direction = getChannelParameterAsString(entry.getValue());
break;
case PARAM_CMD_TO_REACT:
commandToReact = getChannelParameterAsString(entry.getValue());
break;
case PARAM_SERIAL_NUMBER:
serialNumber = getChannelParameterAsLong(entry.getValue());
break;
case PARAM_PULSE_WIDTH:
pulseWidth = getChannelParameterAsInteger(entry.getValue());
break;
case PARAM_LONG_PRESS_TIME:
longPressTime = getChannelParameterAsInteger(entry.getValue());
break;
case PARAM_INVERTED:
inverted = getChannelParameterAsBoolean(entry.getValue());
break;
case PARAM_ON_LEVEL:
onLevel = getChannelParameterAsInteger(entry.getValue());
break;
}
}
}
public String getChannelTypeId() {
return channelTypeId;
}
public Integer getResourceId() {
return resourceId;
}
public String getDirection() {
return direction;
}
public boolean isDirectionBoth() {
return direction != null && DIRECTION_READ_WRITE.equals(direction);
}
public boolean isDirectionReadOnly() {
return direction != null && DIRECTION_READ_ONLY.equals(direction);
}
public boolean isDirectionWriteOnly() {
return direction != null && DIRECTION_WRITE_ONLY.equals(direction);
}
public String getCommandToReact() {
return commandToReact;
}
public Integer getPulseWidth() {
return pulseWidth;
}
public Boolean getInverted() {
return inverted;
}
public boolean isInverted() {
if (inverted != null) {
return inverted;
}
return false;
}
public Long getSerialNumber() {
return serialNumber;
}
public Integer getLongPressTime() {
return longPressTime;
}
public Integer getOnLevel() {
return onLevel;
}
private static Boolean getChannelParameterAsBoolean(Object value) throws ConversionException {
return convert(value, (v) -> (Boolean) v);
}
private Integer getChannelParameterAsInteger(Object value) throws ConversionException {
return convert(value, (v) -> ((BigDecimal) v).intValue());
}
private Long getChannelParameterAsLong(Object value) throws ConversionException {
return convert(value, (v) -> ((BigDecimal) v).longValue());
}
private String getChannelParameterAsString(Object value) throws ConversionException {
return convert(value, (v) -> (String) v);
}
private static <T> T convert(Object value, Function<Object, T> f) throws ConversionException {
if (value == null) {
return null;
}
try {
return f.apply(value);
} catch (ClassCastException e) {
throw new ConversionException(String.format("Failed to convert, reason %s.", e.getMessage()), e);
}
}
@Override
public String toString() {
return String.format(
"[ channelTypeId=%s, resourceId=%d, direction=%s, commandToReact=%s, pulseWidth=%d, inverted=%b, serialNumber=%d, longPressTime=%d, onLevel=%d ]",
channelTypeId, resourceId, direction, commandToReact, pulseWidth, inverted, serialNumber, longPressTime,
onLevel);
}
}

View File

@@ -0,0 +1,34 @@
/**
* 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.ihc.internal.config;
/**
* Configuration class for {@link IhcBinding} binding.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcConfiguration {
public String hostname;
public String username;
public String password;
public int timeout;
public boolean loadProjectFile;
public boolean createChannelsAutomatically;
@Override
public String toString() {
return "[" + "hostname=" + hostname + ", username=" + username + ", password=******" + ", timeout=" + timeout
+ ", loadProjectFile=" + loadProjectFile + ", createChannelsAutomatically="
+ createChannelsAutomatically + "]";
}
}

View File

@@ -0,0 +1,29 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
/**
* IHC / ELKO <-> openHAB data type converter interface.
*
* @author Pauli Anttila - Initial contribution
*/
public interface Converter<R, T> {
T convertFromResourceValue(@NonNull R from, @NonNull ConverterAdditionalInfo convertData)
throws ConversionException;
R convertFromOHType(@NonNull T from, @NonNull R value, @NonNull ConverterAdditionalInfo convertData)
throws ConversionException;
}

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.converters;
import java.util.List;
import java.util.Map;
import org.openhab.binding.ihc.internal.ws.projectfile.IhcEnumValue;
import org.openhab.core.types.Command;
/**
* Class to hold additional information which is needed for data conversion.
*
* @author Pauli Anttila - Initial contribution
*/
public class ConverterAdditionalInfo {
private List<IhcEnumValue> enumValues;
private Boolean inverted;
private Map<Command, Object> commandLevels;
public ConverterAdditionalInfo(List<IhcEnumValue> enumValues, Boolean inverted,
Map<Command, Object> commandLevels) {
this.enumValues = enumValues;
this.inverted = inverted;
this.commandLevels = commandLevels;
}
public List<IhcEnumValue> getEnumValues() {
return enumValues;
}
public Boolean getInverted() {
return inverted;
}
public Map<Command, Object> getCommandLevels() {
return commandLevels;
}
}

View File

@@ -0,0 +1,143 @@
/**
* 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.ihc.internal.converters;
import java.util.HashMap;
import java.util.Map;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSDateValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSFloatingPointValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimeValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSWeekdayValue;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Type;
/**
* IHC / ELKO <-> openHAB data type converter factory.
*
* @author Pauli Anttila - Initial contribution
*/
public enum ConverterFactory {
INSTANCE;
private static final String ITEM_TYPE_NUMBER = "Number";
private static final String ITEM_TYPE_SWITCH = "Switch";
private static final String ITEM_TYPE_CONTACT = "Contact";
private static final String ITEM_TYPE_DIMMER = "Dimmer";
private static final String ITEM_TYPE_DATETIME = "DateTime";
private static final String ITEM_TYPE_STRING = "String";
private static final String ITEM_TYPE_ROLLERSHUTTER = "Rollershutter";
private class Key {
Class<? extends WSResourceValue> ihcType;
Class<? extends Type> openhabType;
Key(Class<? extends WSResourceValue> ihcType, Class<? extends Type> openhabType) {
this.ihcType = ihcType;
this.openhabType = openhabType;
}
@Override
public int hashCode() {
return ihcType.getClass().hashCode() + openhabType.getClass().hashCode();
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Key)) {
return false;
}
Key key = (Key) o;
return key.ihcType.equals(ihcType) && key.openhabType.equals(openhabType);
}
}
private Map<Key, Converter<? extends WSResourceValue, ? extends Type>> converters;
private ConverterFactory() {
converters = new HashMap<>();
converters.put(new Key(WSDateValue.class, DateTimeType.class), new DateTimeTypeWSDateValueConverter());
converters.put(new Key(WSTimeValue.class, DateTimeType.class), new DateTimeTypeWSTimeValueConverter());
converters.put(new Key(WSBooleanValue.class, DecimalType.class), new DecimalTypeWSBooleanValueConverter());
converters.put(new Key(WSEnumValue.class, DecimalType.class), new DecimalTypeWSEnumValueConverter());
converters.put(new Key(WSFloatingPointValue.class, DecimalType.class),
new DecimalTypeWSFloatingPointValueConverter());
converters.put(new Key(WSIntegerValue.class, DecimalType.class), new DecimalTypeWSIntegerValueConverter());
converters.put(new Key(WSTimerValue.class, DecimalType.class), new DecimalTypeWSTimerValueConverter());
converters.put(new Key(WSWeekdayValue.class, DecimalType.class), new DecimalTypeWSWeekdayValueConverter());
converters.put(new Key(WSBooleanValue.class, OnOffType.class), new OnOffTypeWSBooleanValueConverter());
converters.put(new Key(WSIntegerValue.class, OnOffType.class), new OnOffTypeWSIntegerValueConverter());
converters.put(new Key(WSBooleanValue.class, OpenClosedType.class),
new OpenClosedTypeWSBooleanValueConverter());
converters.put(new Key(WSIntegerValue.class, OpenClosedType.class),
new OpenClosedTypeWSIntegerValueConverter());
converters.put(new Key(WSIntegerValue.class, PercentType.class), new PercentTypeWSIntegerValueConverter());
converters.put(new Key(WSEnumValue.class, StringType.class), new StringTypeWSEnumValueConverter());
converters.put(new Key(WSBooleanValue.class, UpDownType.class), new UpDownTypeWSBooleanValueConverter());
converters.put(new Key(WSIntegerValue.class, UpDownType.class), new UpDownTypeWSIntegerValueConverter());
}
public static ConverterFactory getInstance() {
return INSTANCE;
}
@SuppressWarnings("unchecked")
public Converter<WSResourceValue, Type> getConverter(Class<? extends WSResourceValue> resourceValueType,
Class<? extends Type> type) {
return (Converter<WSResourceValue, Type>) converters.get(new Key(resourceValueType, type));
}
@SuppressWarnings("unchecked")
public Converter<WSResourceValue, Type> getConverter(Class<? extends WSResourceValue> resourceValueType,
String itemType) {
Class<? extends Type> type = null;
switch (itemType) {
case ITEM_TYPE_SWITCH:
type = OnOffType.class;
break;
case ITEM_TYPE_ROLLERSHUTTER:
case ITEM_TYPE_DIMMER:
type = PercentType.class;
break;
case ITEM_TYPE_CONTACT:
type = OpenClosedType.class;
break;
case ITEM_TYPE_STRING:
type = StringType.class;
break;
case ITEM_TYPE_NUMBER:
type = DecimalType.class;
break;
case ITEM_TYPE_DATETIME:
type = DateTimeType.class;
break;
}
return (Converter<WSResourceValue, Type>) converters.get(new Key(resourceValueType, type));
}
}

View File

@@ -0,0 +1,66 @@
/**
* 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.ihc.internal.converters;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSDateValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimeValue;
import org.openhab.core.library.types.DateTimeType;
/**
* DateTimeType <-> WSDateValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DateTimeTypeWSDateValueConverter implements Converter<WSDateValue, DateTimeType> {
@Override
public DateTimeType convertFromResourceValue(@NonNull WSDateValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
Calendar cal = dateTimeToCalendar(from, null);
return new DateTimeType(ZonedDateTime.ofInstant(cal.toInstant(), TimeZone.getDefault().toZoneId()));
}
@Override
public WSDateValue convertFromOHType(@NonNull DateTimeType from, @NonNull WSDateValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
Calendar cal = GregorianCalendar.from(from.getZonedDateTime());
short year = (short) cal.get(Calendar.YEAR);
byte month = (byte) (cal.get(Calendar.MONTH) + 1);
byte day = (byte) cal.get(Calendar.DAY_OF_MONTH);
return new WSDateValue(value.resourceID, year, month, day);
}
private Calendar dateTimeToCalendar(WSDateValue date, WSTimeValue time) {
Calendar cal = new GregorianCalendar(2000, 01, 01);
if (date != null) {
short year = date.year;
short month = date.month;
short day = date.day;
cal.set(year, month - 1, day, 0, 0, 0);
}
if (time != null) {
int hour = time.hours;
int minute = time.minutes;
int second = time.seconds;
cal.set(2000, 0, 1, hour, minute, second);
}
return cal;
}
}

View File

@@ -0,0 +1,65 @@
/**
* 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.ihc.internal.converters;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSDateValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimeValue;
import org.openhab.core.library.types.DateTimeType;
/**
* DateTimeType <-> WSTimeValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DateTimeTypeWSTimeValueConverter implements Converter<WSTimeValue, DateTimeType> {
@Override
public DateTimeType convertFromResourceValue(@NonNull WSTimeValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
Calendar cal = dateTimeToCalendar(null, from);
return new DateTimeType(ZonedDateTime.ofInstant(cal.toInstant(), TimeZone.getDefault().toZoneId()));
}
@Override
public WSTimeValue convertFromOHType(@NonNull DateTimeType from, @NonNull WSTimeValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
Calendar cal = GregorianCalendar.from(from.getZonedDateTime());
return new WSTimeValue(value.resourceID, cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE),
cal.get(Calendar.SECOND));
}
private Calendar dateTimeToCalendar(WSDateValue date, WSTimeValue time) {
Calendar cal = new GregorianCalendar(2000, 01, 01);
if (date != null) {
short year = date.year;
short month = date.month;
short day = date.day;
cal.set(year, month - 1, day, 0, 0, 0);
}
if (time != null) {
int hour = time.hours;
int minute = time.minutes;
int second = time.seconds;
cal.set(2000, 0, 1, hour, minute, second);
}
return cal;
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.core.library.types.DecimalType;
/**
* DecimalType <-> WSBooleanValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSBooleanValueConverter implements Converter<WSBooleanValue, DecimalType> {
@Override
public DecimalType convertFromResourceValue(@NonNull WSBooleanValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new DecimalType(from.value ? 1 : 0);
}
@Override
public WSBooleanValue convertFromOHType(@NonNull DecimalType from, @NonNull WSBooleanValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new WSBooleanValue(value.resourceID, from.intValue() > 0);
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
import org.openhab.core.library.types.DecimalType;
/**
* DecimalType <-> WSEnumValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSEnumValueConverter implements Converter<WSEnumValue, DecimalType> {
@Override
public DecimalType convertFromResourceValue(@NonNull WSEnumValue from, @NonNull ConverterAdditionalInfo convertData)
throws ConversionException {
return new DecimalType(from.enumValueID);
}
@Override
public WSEnumValue convertFromOHType(@NonNull DecimalType from, @NonNull WSEnumValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new WSEnumValue(value.resourceID, value.definitionTypeID, from.intValue(), value.enumName);
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.converters;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSFloatingPointValue;
import org.openhab.core.library.types.DecimalType;
/**
* DecimalType <-> WSFloatingPointValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSFloatingPointValueConverter implements Converter<WSFloatingPointValue, DecimalType> {
@Override
public DecimalType convertFromResourceValue(@NonNull WSFloatingPointValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
BigDecimal bd = new BigDecimal(from.value).setScale(2, RoundingMode.HALF_EVEN);
return new DecimalType(bd);
}
@Override
public WSFloatingPointValue convertFromOHType(@NonNull DecimalType from, @NonNull WSFloatingPointValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
if (from.doubleValue() >= value.minimumValue && from.doubleValue() <= value.maximumValue) {
return new WSFloatingPointValue(value.resourceID, from.doubleValue(), value.minimumValue,
value.maximumValue);
} else {
throw new ConversionException("Value is not between acceptable limits (min=" + value.minimumValue + ", max="
+ value.maximumValue + ")");
}
}
}

View File

@@ -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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.core.library.types.DecimalType;
/**
* DecimalType <-> WSIntegerValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSIntegerValueConverter implements Converter<WSIntegerValue, DecimalType> {
@Override
public DecimalType convertFromResourceValue(@NonNull WSIntegerValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new DecimalType(from.value);
}
@Override
public WSIntegerValue convertFromOHType(@NonNull DecimalType from, @NonNull WSIntegerValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
if (from.intValue() >= value.minimumValue && from.intValue() <= value.maximumValue) {
return new WSIntegerValue(value.resourceID, from.intValue(), value.minimumValue, value.maximumValue);
} else {
throw new ConversionException("Value is not between acceptable limits (min=" + value.minimumValue + ", max="
+ value.maximumValue + ")");
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimerValue;
import org.openhab.core.library.types.DecimalType;
/**
* DecimalType <-> WSTimerValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSTimerValueConverter implements Converter<WSTimerValue, DecimalType> {
@Override
public DecimalType convertFromResourceValue(@NonNull WSTimerValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new DecimalType(from.milliseconds);
}
@Override
public WSTimerValue convertFromOHType(@NonNull DecimalType from, @NonNull WSTimerValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new WSTimerValue(value.resourceID, from.longValue());
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSWeekdayValue;
import org.openhab.core.library.types.DecimalType;
/**
* DecimalType <-> WSWeekdayValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSWeekdayValueConverter implements Converter<WSWeekdayValue, DecimalType> {
@Override
public DecimalType convertFromResourceValue(@NonNull WSWeekdayValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new DecimalType(from.weekdayNumber);
}
@Override
public WSWeekdayValue convertFromOHType(@NonNull DecimalType from, @NonNull WSWeekdayValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new WSWeekdayValue(value.resourceID, from.intValue());
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.core.library.types.OnOffType;
/**
* OnOffType <-> WSBooleanValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class OnOffTypeWSBooleanValueConverter implements Converter<WSBooleanValue, OnOffType> {
@Override
public OnOffType convertFromResourceValue(@NonNull WSBooleanValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return from.value ^ convertData.getInverted() ? OnOffType.ON : OnOffType.OFF;
}
@Override
public WSBooleanValue convertFromOHType(@NonNull OnOffType from, @NonNull WSBooleanValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new WSBooleanValue(value.resourceID, from == OnOffType.ON ^ convertData.getInverted());
}
}

View File

@@ -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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.Command;
/**
* OnOffType <-> WSIntegerValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class OnOffTypeWSIntegerValueConverter implements Converter<WSIntegerValue, OnOffType> {
@Override
public OnOffType convertFromResourceValue(@NonNull WSIntegerValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return from.value > 0 ^ convertData.getInverted() ? OnOffType.ON : OnOffType.OFF;
}
@Override
public WSIntegerValue convertFromOHType(@NonNull OnOffType from, @NonNull WSIntegerValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
int onLevel = Math.min(value.maximumValue, getCommandLevel(value, convertData, OnOffType.ON));
int newVal = from == OnOffType.ON ? onLevel : value.minimumValue;
if (convertData.getInverted()) {
newVal = newVal == value.maximumValue ? value.minimumValue : value.maximumValue;
}
if (newVal >= value.minimumValue && newVal <= value.maximumValue) {
return new WSIntegerValue(value.resourceID, newVal, value.minimumValue, value.maximumValue);
} else {
throw new ConversionException("Value is not between acceptable limits (min=" + value.minimumValue + ", max="
+ value.maximumValue + ")");
}
}
private int getCommandLevel(@NonNull WSIntegerValue value, @NonNull ConverterAdditionalInfo convertData,
Command command) throws ConversionException {
try {
if (convertData.getCommandLevels() != null) {
return (int) convertData.getCommandLevels().get(command);
}
return value.maximumValue;
} catch (RuntimeException e) {
throw new ConversionException(e);
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.core.library.types.OpenClosedType;
/**
* OpenClosedType <-> WSBooleanValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class OpenClosedTypeWSBooleanValueConverter implements Converter<WSBooleanValue, OpenClosedType> {
@Override
public OpenClosedType convertFromResourceValue(@NonNull WSBooleanValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return from.value ^ convertData.getInverted() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
}
@Override
public WSBooleanValue convertFromOHType(@NonNull OpenClosedType from, @NonNull WSBooleanValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new WSBooleanValue(value.resourceID, from == OpenClosedType.OPEN ^ convertData.getInverted());
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.core.library.types.OpenClosedType;
/**
* OpenClosedType <-> WSIntegerValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class OpenClosedTypeWSIntegerValueConverter implements Converter<WSIntegerValue, OpenClosedType> {
@Override
public OpenClosedType convertFromResourceValue(@NonNull WSIntegerValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return from.value > 0 ^ convertData.getInverted() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
}
@Override
public WSIntegerValue convertFromOHType(@NonNull OpenClosedType from, @NonNull WSIntegerValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
int newVal = from == OpenClosedType.OPEN ? value.maximumValue : value.minimumValue;
if (convertData.getInverted()) {
newVal = newVal == value.maximumValue ? value.minimumValue : value.maximumValue;
}
if (newVal >= value.minimumValue && newVal <= value.maximumValue) {
return new WSIntegerValue(value.resourceID, newVal, value.minimumValue, value.maximumValue);
} else {
throw new ConversionException("Value is not between acceptable limits (min=" + value.minimumValue + ", max="
+ value.maximumValue + ")");
}
}
}

View File

@@ -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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.core.library.types.PercentType;
/**
* PercentType <-> WSIntegerValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class PercentTypeWSIntegerValueConverter implements Converter<WSIntegerValue, PercentType> {
@Override
public PercentType convertFromResourceValue(@NonNull WSIntegerValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new PercentType(from.value);
}
@Override
public WSIntegerValue convertFromOHType(@NonNull PercentType from, @NonNull WSIntegerValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
if (from.intValue() >= value.minimumValue && from.intValue() <= value.maximumValue) {
return new WSIntegerValue(value.resourceID, from.intValue(), value.minimumValue, value.maximumValue);
} else {
throw new ConversionException("Value is not between acceptable limits (min=" + value.minimumValue + ", max="
+ value.maximumValue + ")");
}
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.projectfile.IhcEnumValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
import org.openhab.core.library.types.StringType;
/**
* StringType <-> WSEnumValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class StringTypeWSEnumValueConverter implements Converter<WSEnumValue, StringType> {
@Override
public StringType convertFromResourceValue(@NonNull WSEnumValue from, @NonNull ConverterAdditionalInfo convertData)
throws ConversionException {
return new StringType(from.enumName);
}
@Override
public WSEnumValue convertFromOHType(@NonNull StringType from, @NonNull WSEnumValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
if (convertData.getEnumValues() != null) {
for (IhcEnumValue item : convertData.getEnumValues()) {
if (item.getName().equals(from.toString())) {
return new WSEnumValue(value.resourceID, value.definitionTypeID, item.getId(), item.getName());
}
}
throw new ConversionException("Can't find enum value for string " + value.toString());
} else {
throw new ConversionException("Enum list is null");
}
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.core.library.types.UpDownType;
/**
* UpDownType <-> WSBooleanValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class UpDownTypeWSBooleanValueConverter implements Converter<WSBooleanValue, UpDownType> {
@Override
public UpDownType convertFromResourceValue(@NonNull WSBooleanValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return from.value ^ convertData.getInverted() ? UpDownType.UP : UpDownType.DOWN;
}
@Override
public WSBooleanValue convertFromOHType(@NonNull UpDownType from, @NonNull WSBooleanValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return new WSBooleanValue(value.resourceID, from == UpDownType.UP ^ convertData.getInverted());
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.converters;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.core.library.types.UpDownType;
/**
* UpDownType <-> WSIntegerValue converter.
*
* @author Pauli Anttila - Initial contribution
*/
public class UpDownTypeWSIntegerValueConverter implements Converter<WSIntegerValue, UpDownType> {
@Override
public UpDownType convertFromResourceValue(@NonNull WSIntegerValue from,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
return from.value > 0 ^ convertData.getInverted() ? UpDownType.UP : UpDownType.DOWN;
}
@Override
public WSIntegerValue convertFromOHType(@NonNull UpDownType from, @NonNull WSIntegerValue value,
@NonNull ConverterAdditionalInfo convertData) throws ConversionException {
int newVal = from == UpDownType.UP ? value.maximumValue : value.minimumValue;
if (convertData.getInverted()) {
newVal = newVal == value.maximumValue ? value.minimumValue : value.maximumValue;
}
if (newVal >= value.minimumValue && newVal <= value.maximumValue) {
return new WSIntegerValue(value.resourceID, newVal, value.minimumValue, value.maximumValue);
} else {
throw new ConversionException("Value is not between acceptable limits (min=" + value.minimumValue + ", max="
+ value.maximumValue + ")");
}
}
}

View File

@@ -0,0 +1,979 @@
/**
* 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.ihc.internal.handler;
import static org.openhab.binding.ihc.internal.IhcBindingConstants.*;
import java.io.File;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.openhab.binding.ihc.internal.ButtonPressDurationDetector;
import org.openhab.binding.ihc.internal.ChannelUtils;
import org.openhab.binding.ihc.internal.EnumDictionary;
import org.openhab.binding.ihc.internal.SignalLevelConverter;
import org.openhab.binding.ihc.internal.config.ChannelParams;
import org.openhab.binding.ihc.internal.config.IhcConfiguration;
import org.openhab.binding.ihc.internal.converters.Converter;
import org.openhab.binding.ihc.internal.converters.ConverterAdditionalInfo;
import org.openhab.binding.ihc.internal.converters.ConverterFactory;
import org.openhab.binding.ihc.internal.ws.IhcClient;
import org.openhab.binding.ihc.internal.ws.IhcClient.ConnectionState;
import org.openhab.binding.ihc.internal.ws.IhcEventListener;
import org.openhab.binding.ihc.internal.ws.datatypes.WSControllerState;
import org.openhab.binding.ihc.internal.ws.datatypes.WSProjectInfo;
import org.openhab.binding.ihc.internal.ws.datatypes.WSRFDevice;
import org.openhab.binding.ihc.internal.ws.datatypes.WSSystemInfo;
import org.openhab.binding.ihc.internal.ws.datatypes.WSTimeManagerSettings;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.projectfile.IhcEnumValue;
import org.openhab.binding.ihc.internal.ws.projectfile.ProjectFileUtils;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
/**
* The {@link IhcHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcHandler extends BaseThingHandler implements IhcEventListener {
private final Logger logger = LoggerFactory.getLogger(IhcHandler.class);
/** Maximum pulse width in milliseconds. */
private static final int MAX_PULSE_WIDTH_IN_MS = 4000;
/** Maximum long press time in milliseconds. */
private static final int MAX_LONG_PRESS_IN_MS = 5000;
/** Name of the local IHC / ELKO project file */
private static final String LOCAL_IHC_PROJECT_FILE_NAME_TEMPLATE = "ihc-project-file-%s.xml";
/** Holds runtime notification reorder timeout in milliseconds */
private static final int NOTIFICATIONS_REORDER_WAIT_TIME = 1000;
/** IHC / ELKO LS Controller client */
private IhcClient ihc;
/**
* Reminder to slow down resource value notification ordering from
* controller.
*/
private ScheduledFuture<?> notificationsRequestReminder;
/** Holds local IHC / ELKO project file */
private Document projectFile;
/**
* Store current state of the controller, use to recognize when controller
* state is changed
*/
private String controllerState = "";
private IhcConfiguration conf;
private final Set<Integer> linkedResourceIds = Collections.synchronizedSet(new HashSet<>());
private Map<Integer, LocalDateTime> lastUpdate = new HashMap<>();
private EnumDictionary enumDictionary;
private boolean connecting = false;
private boolean reconnectRequest = false;
private boolean valueNotificationRequest = false;
private ScheduledFuture<?> controlJob;
private ScheduledFuture<?> pollingJobRf;
private Map<String, ScheduledFuture<?>> longPressFutures = new HashMap<>();
public IhcHandler(Thing thing) {
super(thing);
}
protected boolean isValueNotificationRequestActivated() {
synchronized (this) {
return valueNotificationRequest;
}
}
protected void setValueNotificationRequest(boolean valueNotificationRequest) {
synchronized (this) {
this.valueNotificationRequest = valueNotificationRequest;
}
}
protected boolean isReconnectRequestActivated() {
synchronized (this) {
return reconnectRequest;
}
}
protected void setReconnectRequest(boolean reconnect) {
synchronized (this) {
this.reconnectRequest = reconnect;
}
}
protected boolean isConnecting() {
synchronized (this) {
return connecting;
}
}
protected void setConnectingState(boolean value) {
synchronized (this) {
this.connecting = value;
}
}
private String getFilePathInUserDataFolder(String fileName) {
String progArg = System.getProperty("smarthome.userdata");
if (progArg != null) {
return progArg + File.separator + fileName;
}
return fileName;
}
@Override
public void initialize() {
conf = getConfigAs(IhcConfiguration.class);
logger.debug("Using configuration: {}", conf);
linkedResourceIds.clear();
linkedResourceIds.addAll(getAllLinkedChannelsResourceIds());
logger.debug("Linked resources {}: {}", linkedResourceIds.size(), linkedResourceIds);
if (controlJob == null || controlJob.isCancelled()) {
logger.debug("Start control task, interval={}sec", 1);
controlJob = scheduler.scheduleWithFixedDelay(this::reconnectCheck, 0, 1, TimeUnit.SECONDS);
}
}
@Override
public void dispose() {
logger.debug("Stopping thing");
if (controlJob != null && !controlJob.isCancelled()) {
controlJob.cancel(true);
controlJob = null;
}
disconnect();
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("Received channel: {}, command: {}", channelUID, command);
if (ihc == null) {
logger.warn("Connection is not initialized, abort resource value update for channel '{}'!", channelUID);
return;
}
if (ihc.getConnectionState() != ConnectionState.CONNECTED) {
logger.warn("Connection to controller is not open, abort resource value update for channel '{}'!",
channelUID);
return;
}
switch (channelUID.getId()) {
case CHANNEL_CONTROLLER_STATE:
if (command.equals(RefreshType.REFRESH)) {
updateControllerStateChannel();
}
break;
case CHANNEL_CONTROLLER_UPTIME:
if (command.equals(RefreshType.REFRESH)) {
updateControllerInformationChannels();
}
break;
case CHANNEL_CONTROLLER_TIME:
if (command.equals(RefreshType.REFRESH)) {
updateControllerTimeChannels();
}
break;
default:
if (command.equals(RefreshType.REFRESH)) {
refreshChannel(channelUID);
} else {
updateResourceChannel(channelUID, command);
}
break;
}
}
private void refreshChannel(ChannelUID channelUID) {
logger.debug("REFRESH channel {}", channelUID);
Channel channel = thing.getChannel(channelUID.getId());
if (channel != null) {
try {
ChannelParams params = new ChannelParams(channel);
logger.debug("Channel params: {}", params);
if (params.isDirectionWriteOnly()) {
logger.warn("Write only channel, skip refresh command to {}", channelUID);
return;
}
WSResourceValue value = ihc.resourceQuery(params.getResourceId());
resourceValueUpdateReceived(value);
} catch (IhcExecption e) {
logger.warn("Can't update channel '{}' value, reason: {}", channelUID, e.getMessage(), e);
} catch (ConversionException e) {
logger.warn("Channel param error, reason: {}.", e.getMessage(), e);
}
}
}
private void updateControllerStateChannel() {
try {
String state = ihc.getControllerState().getState();
String value;
switch (state) {
case IhcClient.CONTROLLER_STATE_INITIALIZE:
value = "Initialize";
break;
case IhcClient.CONTROLLER_STATE_READY:
value = "Ready";
break;
default:
value = "Unknown state: " + state;
}
updateState(new ChannelUID(getThing().getUID(), CHANNEL_CONTROLLER_STATE), new StringType(value));
} catch (IhcExecption e) {
logger.warn("Controller state information fetch failed, reason: {}", e.getMessage(), e);
}
}
private void updateControllerProperties() {
try {
WSSystemInfo systemInfo = ihc.getSystemInfo();
logger.debug("Controller information: {}", systemInfo);
WSProjectInfo projectInfo = ihc.getProjectInfo();
logger.debug("Project information: {}", projectInfo);
Map<String, String> properties = editProperties();
properties.put(PROPERTY_MANUFACTURER, systemInfo.getBrand());
properties.put(PROPERTY_SERIALNUMBER, systemInfo.getSerialNumber());
properties.put(PROPERTY_SW_VERSION, systemInfo.getVersion());
properties.put(PROPERTY_FW_VERSION, systemInfo.getHwRevision());
properties.put(PROPERTY_APP_WITHOUT_VIEWER, Boolean.toString(systemInfo.getApplicationIsWithoutViewer()));
properties.put(PROPERTY_SW_DATE,
systemInfo.getSwDate().withZoneSameInstant(ZoneId.systemDefault()).toString());
properties.put(PROPERTY_PRODUCTION_DATE, systemInfo.getProductionDate());
if (!systemInfo.getDatalineVersion().isEmpty()) {
properties.put(PROPERTY_DATALINE_VERSION, systemInfo.getDatalineVersion());
}
if (!systemInfo.getRfModuleSerialNumber().isEmpty()) {
properties.put(PROPERTY_RF_MODULE_SERIALNUMBER, systemInfo.getRfModuleSerialNumber());
}
if (!systemInfo.getRfModuleSoftwareVersion().isEmpty()) {
properties.put(PROPERTY_RF_MODULE_VERSION, systemInfo.getRfModuleSoftwareVersion());
}
properties.put(PROPERTY_PROJECT_DATE,
projectInfo.getLastmodified().getAsLocalDateTime().atZone(ZoneId.systemDefault()).toString());
properties.put(PROPERTY_PROJECT_NUMBER, projectInfo.getProjectNumber());
updateProperties(properties);
} catch (IhcExecption e) {
logger.warn("Controller information fetch failed, reason: {}", e.getMessage(), e);
}
}
private void updateControllerInformationChannels() {
try {
WSSystemInfo systemInfo = ihc.getSystemInfo();
logger.debug("Controller information: {}", systemInfo);
updateState(new ChannelUID(getThing().getUID(), CHANNEL_CONTROLLER_UPTIME),
new DecimalType((double) systemInfo.getUptime() / 1000));
} catch (IhcExecption e) {
logger.warn("Controller uptime information fetch failed, reason: {}.", e.getMessage(), e);
}
}
private void updateControllerTimeChannels() {
try {
WSTimeManagerSettings timeSettings = ihc.getTimeSettings();
logger.debug("Controller time settings: {}", timeSettings);
ZonedDateTime time = timeSettings.getTimeAndDateInUTC().getAsZonedDateTime(ZoneId.of("Z"))
.withZoneSameInstant(ZoneId.systemDefault());
updateState(new ChannelUID(getThing().getUID(), CHANNEL_CONTROLLER_TIME), new DateTimeType(time));
} catch (IhcExecption e) {
logger.warn("Controller uptime information fetch failed, reason: {}.", e.getMessage(), e);
}
}
private void updateResourceChannel(ChannelUID channelUID, Command command) {
Channel channel = thing.getChannel(channelUID.getId());
if (channel != null) {
try {
ChannelParams params = new ChannelParams(channel);
logger.debug("Channel params: {}", params);
if (params.isDirectionReadOnly()) {
logger.debug("Read only channel, skip the update to {}", channelUID);
return;
}
updateChannel(channelUID, params, command);
} catch (IhcExecption e) {
logger.warn("Can't update channel '{}' value, cause {}", channelUID, e.getMessage());
} catch (ConversionException e) {
logger.debug("Conversion error for channel {}, reason: {}", channelUID, e.getMessage());
}
}
}
private void updateChannel(ChannelUID channelUID, ChannelParams params, Command command)
throws IhcExecption, ConversionException {
if (params.getCommandToReact() != null) {
if (command.toString().equals(params.getCommandToReact())) {
logger.debug("Command '{}' equal to channel reaction parameter '{}', execute it", command,
params.getCommandToReact());
} else {
logger.debug("Command '{}' doesn't equal to reaction trigger parameter '{}', skip it", command,
params.getCommandToReact());
return;
}
}
WSResourceValue value = ihc.getResourceValueInformation(params.getResourceId());
if (value != null) {
if (params.getPulseWidth() != null) {
sendPulseCommand(channelUID, params, value, Math.min(params.getPulseWidth(), MAX_PULSE_WIDTH_IN_MS));
} else {
sendNormalCommand(channelUID, params, command, value);
}
}
}
private void sendNormalCommand(ChannelUID channelUID, ChannelParams params, Command command, WSResourceValue value)
throws IhcExecption, ConversionException {
logger.debug("Send command '{}' to resource '{}'", command, value.resourceID);
ConverterAdditionalInfo converterAdditionalInfo = new ConverterAdditionalInfo(getEnumValues(value),
params.isInverted(), getCommandLevels(params));
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(value.getClass(),
command.getClass());
if (converter != null) {
WSResourceValue val = converter.convertFromOHType(command, value, converterAdditionalInfo);
logger.debug("Update resource value (inverted output={}): {}", params.isInverted(), val);
if (!updateResource(val)) {
logger.warn("Channel {} update to resource '{}' failed.", channelUID, val);
}
} else {
logger.debug("No converter implemented for {} <-> {}", value.getClass(), command.getClass());
}
}
private List<IhcEnumValue> getEnumValues(WSResourceValue value) {
if (value instanceof WSEnumValue) {
return enumDictionary.getEnumValues(((WSEnumValue) value).definitionTypeID);
}
return null;
}
private void sendPulseCommand(ChannelUID channelUID, ChannelParams params, WSResourceValue value,
Integer pulseWidth) throws IhcExecption, ConversionException {
logger.debug("Send {}ms pulse to resource: {}", pulseWidth, value.resourceID);
logger.debug("Channel params: {}", params);
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(value.getClass(),
OnOffType.class);
if (converter != null) {
ConverterAdditionalInfo converterAdditionalInfo = new ConverterAdditionalInfo(null, params.isInverted(),
getCommandLevels(params));
WSResourceValue valOn = converter.convertFromOHType(OnOffType.ON, value, converterAdditionalInfo);
WSResourceValue valOff = converter.convertFromOHType(OnOffType.OFF, value, converterAdditionalInfo);
// set resource to ON
logger.debug("Update resource value (inverted output={}): {}", params.isInverted(), valOn);
if (updateResource(valOn)) {
logger.debug("Sleeping: {}ms", pulseWidth);
scheduler.schedule(new Runnable() {
@Override
public void run() {
// set resource back to OFF
logger.debug("Update resource value (inverted output={}): {}", params.isInverted(), valOff);
try {
if (!updateResource(valOff)) {
logger.warn("Channel {} update to resource '{}' failed.", channelUID, valOff);
}
} catch (IhcExecption e) {
logger.warn("Can't update channel '{}' value, cause {}", channelUID, e.getMessage());
}
}
}, pulseWidth, TimeUnit.MILLISECONDS);
} else {
logger.warn("Channel {} update failed.", channelUID);
}
} else {
logger.debug("No converter implemented for {} <-> {}", value.getClass(), OnOffType.class);
}
}
/**
* Update resource value to IHC controller.
*/
private boolean updateResource(WSResourceValue value) throws IhcExecption {
boolean result = false;
try {
result = ihc.resourceUpdate(value);
} catch (IhcExecption e) {
logger.warn("Value could not be updated - retrying one time: {}.", e.getMessage(), e);
result = ihc.resourceUpdate(value);
}
return result;
}
@Override
public void channelLinked(ChannelUID channelUID) {
logger.debug("channelLinked: {}", channelUID);
switch (channelUID.getId()) {
case CHANNEL_CONTROLLER_STATE:
updateControllerStateChannel();
break;
case CHANNEL_CONTROLLER_UPTIME:
updateControllerInformationChannels();
break;
case CHANNEL_CONTROLLER_TIME:
updateControllerTimeChannels();
break;
default:
Channel channel = thing.getChannel(channelUID.getId());
if (channel != null) {
try {
ChannelParams params = new ChannelParams(channel);
if (params.getResourceId() != null) {
if (!linkedResourceIds.contains(params.getResourceId())) {
logger.debug("New channel '{}' found, resource id '{}'", channelUID.getAsString(),
params.getResourceId());
linkedResourceIds.add(params.getResourceId());
updateNotificationsRequestReminder();
}
}
} catch (ConversionException e) {
logger.warn("Channel param error, reason: {}.", e.getMessage(), e);
}
}
}
}
@Override
public void channelUnlinked(ChannelUID channelUID) {
logger.debug("channelUnlinked: {}", channelUID);
switch (channelUID.getId()) {
case CHANNEL_CONTROLLER_STATE:
case CHANNEL_CONTROLLER_UPTIME:
case CHANNEL_CONTROLLER_TIME:
break;
default:
Channel channel = thing.getChannel(channelUID.getId());
if (channel != null) {
try {
ChannelParams params = new ChannelParams(channel);
if (params.getResourceId() != null) {
linkedResourceIds.removeIf(c -> c.equals(params.getResourceId()));
updateNotificationsRequestReminder();
}
} catch (ConversionException e) {
logger.warn("Channel param error, reason: {}.", e.getMessage(), e);
}
}
}
}
/**
* Initialize IHC client and open connection to IHC / ELKO LS controller.
*
*/
private void connect() throws IhcExecption {
try {
setConnectingState(true);
logger.debug("Connecting to IHC / ELKO LS controller [hostname='{}', username='{}'].", conf.hostname,
conf.username);
ihc = new IhcClient(conf.hostname, conf.username, conf.password, conf.timeout);
ihc.openConnection();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Initializing communication to the IHC / ELKO controller");
loadProject();
createChannels();
updateControllerProperties();
updateControllerStateChannel();
updateControllerInformationChannels();
updateControllerTimeChannels();
ihc.addEventListener(this);
ihc.startControllerEventListeners();
updateNotificationsRequestReminder();
startRFPolling();
updateStatus(ThingStatus.ONLINE);
} finally {
setConnectingState(false);
}
}
private void loadProject() throws IhcExecption {
if (conf.loadProjectFile) {
String fileName = String.format(LOCAL_IHC_PROJECT_FILE_NAME_TEMPLATE, thing.getUID().getId());
String filePath = getFilePathInUserDataFolder(fileName);
boolean loadProject = false;
if (projectFile == null) {
// try first load project file from local cache file.
try {
projectFile = ProjectFileUtils.readFromFile(filePath);
} catch (IhcExecption e) {
logger.debug("Error occured when read project file from file '{}', reason {}", filePath,
e.getMessage(), e);
loadProject = true;
}
}
if (!ProjectFileUtils.projectEqualsToControllerProject(projectFile, ihc.getProjectInfo())) {
logger.debug(
"Local project file is not same as in the controller, reload project file from controller!");
loadProject = true;
}
if (loadProject) {
logger.debug("Loading IHC /ELKO LS project file from controller...");
byte[] data = ihc.getProjectFileFromController();
logger.debug("Saving project file to local file '{}'", filePath);
try {
ProjectFileUtils.saveToFile(filePath, data);
} catch (IhcExecption e) {
logger.warn("Error occured when trying to write data to file '{}', reason {}", filePath,
e.getMessage(), e);
}
projectFile = ProjectFileUtils.converteBytesToDocument(data);
}
}
enumDictionary = new EnumDictionary(ProjectFileUtils.parseEnums(projectFile));
}
private void createChannels() {
if (conf.loadProjectFile && conf.createChannelsAutomatically) {
logger.debug("Creating channels");
List<Channel> thingChannels = new ArrayList<>();
thingChannels.addAll(getThing().getChannels());
ChannelUtils.addControllerChannels(getThing(), thingChannels);
ChannelUtils.addChannelsFromProjectFile(getThing(), projectFile, thingChannels);
printChannels(thingChannels);
updateThing(editThing().withChannels(thingChannels).build());
} else {
logger.debug("Automatic channel creation disabled");
}
}
private void printChannels(List<Channel> thingChannels) {
if (logger.isDebugEnabled()) {
thingChannels.forEach(channel -> {
if (channel != null) {
String resourceId;
try {
Object id = channel.getConfiguration().get(PARAM_RESOURCE_ID);
resourceId = id != null ? "0x" + Integer.toHexString(((BigDecimal) id).intValue()) : "";
} catch (IllegalArgumentException e) {
resourceId = "";
}
String channelType = channel.getAcceptedItemType() != null ? channel.getAcceptedItemType() : "";
String channelLabel = channel.getLabel() != null ? channel.getLabel() : "";
logger.debug("Channel: {}", String.format("%-55s | %-10s | %-10s | %s", channel.getUID(),
resourceId, channelType, channelLabel));
}
});
}
}
private void startRFPolling() {
if (pollingJobRf == null || pollingJobRf.isCancelled()) {
logger.debug("Start RF device refresh task, interval={}sec", 60);
pollingJobRf = scheduler.scheduleWithFixedDelay(this::updateRfDeviceStates, 10, 60, TimeUnit.SECONDS);
}
}
/**
* Disconnect connection to IHC / ELKO LS controller.
*
*/
private void disconnect() {
cancelAllLongPressTasks();
if (pollingJobRf != null && !pollingJobRf.isCancelled()) {
pollingJobRf.cancel(true);
pollingJobRf = null;
}
if (ihc != null) {
try {
ihc.removeEventListener(this);
ihc.closeConnection();
ihc = null;
} catch (IhcExecption e) {
logger.warn("Couldn't close connection to IHC controller", e);
}
}
clearLastUpdateTimeCache();
}
private void clearLastUpdateTimeCache() {
lastUpdate.clear();
}
@Override
public void errorOccured(IhcExecption e) {
logger.warn("Error occurred on communication to IHC controller: {}", e.getMessage(), e);
logger.debug("Reconnection request");
setReconnectRequest(true);
}
@Override
public void statusUpdateReceived(WSControllerState newState) {
logger.debug("Controller state: {}", newState.getState());
if (!controllerState.equals(newState.getState())) {
logger.debug("Controller state change detected ({} -> {})", controllerState, newState.getState());
switch (newState.getState()) {
case IhcClient.CONTROLLER_STATE_INITIALIZE:
logger.info("Controller state changed to initializing state, waiting for ready state");
updateState(new ChannelUID(getThing().getUID(), CHANNEL_CONTROLLER_STATE),
new StringType("initialize"));
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE,
"Controller is in initializing state");
break;
case IhcClient.CONTROLLER_STATE_READY:
logger.info("Controller state changed to ready state");
updateState(new ChannelUID(getThing().getUID(), CHANNEL_CONTROLLER_STATE), new StringType("ready"));
updateStatus(ThingStatus.ONLINE);
break;
default:
}
if (controllerState.equals(IhcClient.CONTROLLER_STATE_INITIALIZE)
&& newState.getState().equals(IhcClient.CONTROLLER_STATE_READY)) {
logger.debug("Reconnection request");
projectFile = null;
setReconnectRequest(true);
}
}
controllerState = newState.getState();
}
@Override
public void resourceValueUpdateReceived(WSResourceValue value) {
logger.debug("resourceValueUpdateReceived: {}", value);
thing.getChannels().forEach(channel -> {
try {
ChannelParams params = new ChannelParams(channel);
if (params.getResourceId() != null && params.getResourceId().intValue() == value.resourceID) {
updateChannelState(channel, params, value);
}
} catch (ConversionException e) {
logger.warn("Channel param error, reason: {}.", e.getMessage(), e);
} catch (RuntimeException e) {
logger.warn("Unknown error occured, reason: {}.", e.getMessage(), e);
}
});
checkPotentialButtonPresses(value);
}
private void updateChannelState(Channel channel, ChannelParams params, WSResourceValue value) {
if (params.isDirectionWriteOnly()) {
logger.debug("Write only channel, skip update to {}", channel.getUID());
} else {
if (params.getChannelTypeId() != null) {
switch (params.getChannelTypeId()) {
case CHANNEL_TYPE_PUSH_BUTTON_TRIGGER:
break;
default:
try {
logger.debug("Update channel '{}' state, channel params: {}", channel.getUID(), params);
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance()
.getConverter(value.getClass(), channel.getAcceptedItemType());
if (converter != null) {
State state = (State) converter.convertFromResourceValue(value,
new ConverterAdditionalInfo(null, params.isInverted(),
getCommandLevels(params)));
updateState(channel.getUID(), state);
} else {
logger.debug("No converter implemented for {} <-> {}", value.getClass(),
channel.getAcceptedItemType());
}
} catch (ConversionException e) {
logger.debug("Can't convert resource value '{}' to item type {}, reason: {}.", value,
channel.getAcceptedItemType(), e.getMessage(), e);
}
}
}
}
}
private void checkPotentialButtonPresses(WSResourceValue value) {
if (value instanceof WSBooleanValue) {
if (((WSBooleanValue) value).value) {
// potential button press
lastUpdate.put(value.resourceID, LocalDateTime.now());
updateTriggers(value.resourceID, Duration.ZERO);
} else {
// potential button release
LocalDateTime lastUpdateTime = lastUpdate.get(value.resourceID);
if (lastUpdateTime != null) {
Duration duration = Duration.between(lastUpdateTime, LocalDateTime.now());
logger.debug("Time between uddates: {}", duration);
updateTriggers(value.resourceID, duration);
}
}
}
}
private void updateTriggers(int resourceId, Duration duration) {
thing.getChannels().forEach(channel -> {
try {
ChannelParams params = new ChannelParams(channel);
if (params.getResourceId() != null && params.getResourceId().intValue() == resourceId) {
if (params.getChannelTypeId() != null) {
switch (params.getChannelTypeId()) {
case CHANNEL_TYPE_PUSH_BUTTON_TRIGGER:
logger.debug("Update trigger channel '{}', channel params: {}",
channel.getUID().getId(), params);
if (duration.toMillis() == 0) {
triggerChannel(channel.getUID().getId(), EVENT_PRESSED);
createLongPressTask(channel.getUID().getId(), params.getLongPressTime());
} else {
cancelLongPressTask(channel.getUID().getId());
triggerChannel(channel.getUID().getId(), EVENT_RELEASED);
triggerChannel(channel.getUID().getId(), String.valueOf(duration.toMillis()));
ButtonPressDurationDetector button = new ButtonPressDurationDetector(duration,
params.getLongPressTime(), MAX_LONG_PRESS_IN_MS);
logger.debug("resourceId={}, ButtonPressDurationDetector={}", resourceId, button);
if (button.isShortPress()) {
triggerChannel(channel.getUID().getId(), EVENT_SHORT_PRESS);
}
break;
}
}
}
}
} catch (ConversionException e) {
logger.warn("Channel param error, reason: {}", e.getMessage(), e);
}
});
}
private void createLongPressTask(String channelId, long longPressTimeInMs) {
if (longPressFutures.containsKey(channelId)) {
cancelLongPressTask(channelId);
}
logger.debug("Create long press task for channel '{}'", channelId);
longPressFutures.put(channelId, scheduler.schedule(() -> triggerChannel(channelId, EVENT_LONG_PRESS),
longPressTimeInMs, TimeUnit.MILLISECONDS));
}
private void cancelLongPressTask(String channelId) {
if (longPressFutures.containsKey(channelId)) {
logger.debug("Cancel long press task for channel '{}'", channelId);
longPressFutures.get(channelId).cancel(false);
longPressFutures.remove(channelId);
}
}
private void cancelAllLongPressTasks() {
longPressFutures.entrySet().parallelStream().forEach(e -> e.getValue().cancel(true));
longPressFutures.clear();
}
private void updateRfDeviceStates() {
if (ihc != null) {
if (ihc.getConnectionState() != ConnectionState.CONNECTED) {
logger.debug("Controller is connecting, abort subscribe");
return;
}
logger.debug("Update RF device data");
try {
List<WSRFDevice> devs = ihc.getDetectedRFDevices();
logger.debug("RF data: {}", devs);
devs.forEach(dev -> {
thing.getChannels().forEach(channel -> {
try {
ChannelParams params = new ChannelParams(channel);
if (params.getSerialNumber() != null
&& params.getSerialNumber().longValue() == dev.getSerialNumber()) {
String channelId = channel.getUID().getId();
if (params.getChannelTypeId() != null) {
switch (params.getChannelTypeId()) {
case CHANNEL_TYPE_RF_LOW_BATTERY:
updateState(channelId,
dev.getBatteryLevel() == 1 ? OnOffType.OFF : OnOffType.ON);
break;
case CHANNEL_TYPE_RF_SIGNAL_STRENGTH:
int signalLevel = new SignalLevelConverter(dev.getSignalStrength())
.getSystemWideSignalLevel();
updateState(channelId, new StringType(String.valueOf(signalLevel)));
break;
}
}
}
} catch (ConversionException e) {
logger.warn("Channel param error, reason: {}", e.getMessage(), e);
}
});
});
} catch (IhcExecption e) {
logger.debug("Error occured when fetching RF device information, reason: : {} ", e.getMessage(), e);
return;
}
}
}
private void reconnectCheck() {
if (ihc == null || isReconnectRequestActivated()) {
try {
if (ihc != null) {
disconnect();
}
connect();
setReconnectRequest(false);
} catch (IhcExecption e) {
logger.debug("Can't open connection to controller {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
setReconnectRequest(true);
return;
}
}
if (isValueNotificationRequestActivated() && !isConnecting()) {
try {
enableResourceValueNotifications();
} catch (IhcExecption e) {
logger.warn("Can't enable resource value notifications from controller. ", e);
}
}
}
private Set<Integer> getAllLinkedChannelsResourceIds() {
Set<Integer> resourceIds = Collections.synchronizedSet(new HashSet<>());
resourceIds.addAll(this.getThing().getChannels().stream().filter(c -> isLinked(c.getUID())).map(c -> {
try {
ChannelParams params = new ChannelParams(c);
logger.debug("Linked channel '{}' found, resource id '{}'", c.getUID().getAsString(),
params.getResourceId());
return params.getResourceId();
} catch (ConversionException e) {
logger.warn("Channel param error, reason: {}.", e.getMessage(), e);
return null;
}
}).filter(c -> c != null && c != 0).collect(Collectors.toSet()));
return resourceIds;
}
/**
* Order resource value notifications from IHC controller.
*/
private void enableResourceValueNotifications() throws IhcExecption {
logger.debug("Subscribe resource runtime value notifications");
if (ihc != null) {
if (ihc.getConnectionState() != ConnectionState.CONNECTED) {
logger.debug("Controller is connecting, abort subscribe");
return;
}
setValueNotificationRequest(false);
Set<Integer> resourceIds = ChannelUtils.getAllTriggerChannelsResourceIds(getThing());
logger.debug("Enable runtime notfications for {} trigger(s)", resourceIds.size());
logger.debug("Enable runtime notfications for {} channel(s)", linkedResourceIds.size());
resourceIds.addAll(linkedResourceIds);
resourceIds.addAll(getAllLinkedChannelsResourceIds());
logger.debug("Enable runtime notfications for {} resources: {}", resourceIds.size(), resourceIds);
if (!resourceIds.isEmpty()) {
try {
ihc.enableRuntimeValueNotifications(resourceIds);
} catch (IhcExecption e) {
logger.debug("Reconnection request");
setReconnectRequest(true);
}
}
} else {
logger.warn("Controller is not initialized!");
logger.debug("Reconnection request");
setReconnectRequest(true);
}
}
private synchronized void updateNotificationsRequestReminder() {
if (notificationsRequestReminder != null) {
notificationsRequestReminder.cancel(false);
}
logger.debug("Rechedule resource runtime value notifications order by {}ms", NOTIFICATIONS_REORDER_WAIT_TIME);
notificationsRequestReminder = scheduler.schedule(new Runnable() {
@Override
public void run() {
logger.debug("Delayed resource value notifications request is now enabled");
setValueNotificationRequest(true);
}
}, NOTIFICATIONS_REORDER_WAIT_TIME, TimeUnit.MILLISECONDS);
}
private Map<Command, Object> getCommandLevels(ChannelParams params) {
if (params.getOnLevel() != null) {
Map<Command, Object> commandLevels = new HashMap<>();
commandLevels.put(OnOffType.ON, params.getOnLevel());
return Collections.unmodifiableMap(commandLevels);
}
return null;
}
}

View File

@@ -0,0 +1,67 @@
/**
* 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.ihc.internal.profiles;
import java.util.Collection;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.profiles.Profile;
import org.openhab.core.thing.profiles.ProfileCallback;
import org.openhab.core.thing.profiles.ProfileContext;
import org.openhab.core.thing.profiles.ProfileFactory;
import org.openhab.core.thing.profiles.ProfileType;
import org.openhab.core.thing.profiles.ProfileTypeProvider;
import org.openhab.core.thing.profiles.ProfileTypeUID;
import org.osgi.service.component.annotations.Component;
/**
* A factory for IHC / ELKO profiles.
*
* @author Pauli Anttila - initial contribution.
*
*/
@NonNullByDefault
@Component(service = { ProfileFactory.class, ProfileTypeProvider.class })
public class IhcProfileFactory implements ProfileFactory, ProfileTypeProvider {
private static final Set<ProfileType> SUPPORTED_PROFILE_TYPES = Stream.of(IhcProfiles.PUSHBUTTON_COMMAND_TYPE)
.collect(Collectors.toSet());
private static final Set<ProfileTypeUID> SUPPORTED_PROFILE_TYPE_UIDS = Stream.of(IhcProfiles.PUSHBUTTON_COMMAND)
.collect(Collectors.toSet());
@Nullable
@Override
public Profile createProfile(ProfileTypeUID profileTypeUID, ProfileCallback callback, ProfileContext context) {
if (IhcProfiles.PUSHBUTTON_COMMAND.equals(profileTypeUID)) {
return new PushButtonToCommandProfile(callback, context);
} else {
return null;
}
}
@Override
public Collection<ProfileType> getProfileTypes(@Nullable Locale locale) {
return SUPPORTED_PROFILE_TYPES;
}
@Override
public Collection<ProfileTypeUID> getSupportedProfileTypeUIDs() {
return SUPPORTED_PROFILE_TYPE_UIDS;
}
}

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.profiles;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.CoreItemFactory;
import org.openhab.core.thing.profiles.ProfileTypeBuilder;
import org.openhab.core.thing.profiles.ProfileTypeUID;
import org.openhab.core.thing.profiles.TriggerProfileType;
/**
* IHC / ELKO profile constants.
*
* @author Pauli Anttila - initial contribution.
*
*/
@NonNullByDefault
public interface IhcProfiles {
ProfileTypeUID PUSHBUTTON_COMMAND = new ProfileTypeUID("ihc", "pushbutton-to-command");
TriggerProfileType PUSHBUTTON_COMMAND_TYPE = ProfileTypeBuilder
.newTrigger(PUSHBUTTON_COMMAND, "Push Button To Command")
.withSupportedItemTypes(CoreItemFactory.DIMMER, CoreItemFactory.ROLLERSHUTTER, CoreItemFactory.CONTACT,
CoreItemFactory.SWITCH, CoreItemFactory.PLAYER)
.build();
}

View File

@@ -0,0 +1,249 @@
/**
* 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.ihc.internal.profiles;
import java.math.BigDecimal;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.ihc.internal.IhcBindingConstants;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.NextPreviousType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PlayPauseType;
import org.openhab.core.library.types.RewindFastforwardType;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.thing.profiles.ProfileCallback;
import org.openhab.core.thing.profiles.ProfileContext;
import org.openhab.core.thing.profiles.ProfileTypeUID;
import org.openhab.core.thing.profiles.TriggerProfile;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link PushButtonToCommandProfile} transforms push button channel events to commands.
*
* @author Pauli Anttila - Initial contribution
*/
@NonNullByDefault
public class PushButtonToCommandProfile implements TriggerProfile {
private final Logger logger = LoggerFactory.getLogger(PushButtonToCommandProfile.class);
private static final String PARAM_SHORT_PRESS_COMMAND = "short-press-command";
private static final String PARAM_LONG_PRESS_COMMAND = "long-press-command";
private static final String PARAM_LONG_PRESS_TIME = "long-press-time";
private static final String PARAM_REPEAT_TIME = "repeat-time";
private static final String PARAM_TIMEOUT_TIME = "timeout";
private static final Command DEF_SHORT_PRESS_COMMAND = OnOffType.ON;
private static final Command DEF_LONG_PRESS_COMMAND = IncreaseDecreaseType.INCREASE;
private static final long DEF_LONG_PRESS_TIME = 1000;
private static final long DEF_REPEAT_TIME = 200;
private static final long DEF_TIMEOUT_TIME = 10000;
private final ProfileCallback callback;
private final ProfileContext context;
@Nullable
private Command shortPressCommand;
@Nullable
private Command longPressCommand;
@Nullable
private ScheduledFuture<?> dimmFuture;
@Nullable
private ScheduledFuture<?> timeoutFuture;
@Nullable
private State previousState;
private long pressedTime = 0;
private long longPressTime;
private long repeatTime;
private long timeout;
PushButtonToCommandProfile(ProfileCallback callback, ProfileContext context) {
this.callback = callback;
this.context = context;
shortPressCommand = getParamAsCommand(PARAM_SHORT_PRESS_COMMAND, DEF_SHORT_PRESS_COMMAND);
longPressCommand = getParamAsCommand(PARAM_LONG_PRESS_COMMAND, DEF_LONG_PRESS_COMMAND);
longPressTime = getParamAsLong(PARAM_LONG_PRESS_TIME, DEF_LONG_PRESS_TIME);
repeatTime = getParamAsLong(PARAM_REPEAT_TIME, DEF_REPEAT_TIME);
timeout = getParamAsLong(PARAM_TIMEOUT_TIME, DEF_TIMEOUT_TIME);
}
private long getParamAsLong(String param, long defValue) {
long retval;
Object paramValue = context.getConfiguration().get(param);
logger.debug("Configuring profile with {} parameter '{}'", param, paramValue);
if (paramValue instanceof BigDecimal) {
retval = ((BigDecimal) paramValue).longValue();
} else {
logger.debug("Parameter '{}' is not of type BigDecimal, using default value '{}'", param, defValue);
retval = defValue;
}
return retval;
}
private @Nullable Command getParamAsCommand(String param, Command defValue) {
Command retval;
Object paramValue = context.getConfiguration().get(param);
logger.debug("Configuring profile with {} parameter '{}'", param, paramValue);
if (paramValue instanceof String) {
try {
retval = convertStringToCommand(String.valueOf(paramValue));
} catch (IllegalArgumentException e) {
logger.warn("Parameter '{}' is not a valid command type, using default value '{}'", param, defValue);
retval = defValue;
}
} else {
logger.debug("Parameter '{}' is not of type String, using default value '{}'", param, defValue);
retval = defValue;
}
return retval;
}
private @Nullable Command convertStringToCommand(String str) throws IllegalArgumentException {
Command retval = null;
switch (str) {
case "ON":
retval = OnOffType.ON;
break;
case "OFF":
retval = OnOffType.OFF;
break;
case "STOP":
retval = StopMoveType.STOP;
break;
case "MOVE":
retval = StopMoveType.MOVE;
break;
case "PLAY":
retval = PlayPauseType.PLAY;
break;
case "PAUSE":
retval = PlayPauseType.PAUSE;
break;
case "NEXT":
retval = NextPreviousType.NEXT;
break;
case "PREVIOUS":
retval = NextPreviousType.PREVIOUS;
break;
case "FASTFORWARD":
retval = RewindFastforwardType.FASTFORWARD;
break;
case "REWIND":
retval = RewindFastforwardType.REWIND;
break;
case "INCREASE":
retval = IncreaseDecreaseType.INCREASE;
break;
case "DECREASE":
retval = IncreaseDecreaseType.DECREASE;
break;
case "UP":
retval = UpDownType.UP;
break;
case "DOWN":
retval = UpDownType.DOWN;
break;
case "TOGGLE":
break; // return null
default:
throw new IllegalArgumentException("Illegal argument '" + str + "'");
}
return retval;
}
@Override
public ProfileTypeUID getProfileTypeUID() {
return IhcProfiles.PUSHBUTTON_COMMAND;
}
@Override
public void onStateUpdateFromItem(State state) {
previousState = state;
}
@Override
public void onTriggerFromHandler(String event) {
if (IhcBindingConstants.EVENT_PRESSED.equals(event)) {
buttonPressed(toggleCommandIfNeeded(longPressCommand));
} else if (IhcBindingConstants.EVENT_RELEASED.equals(event)) {
buttonReleased(toggleCommandIfNeeded(shortPressCommand));
}
}
private Command toggleCommandIfNeeded(@Nullable Command command) {
if (command == null) {
logger.debug("Toggling command: previous state is '{}'", previousState);
return OnOffType.ON.equals(previousState) ? OnOffType.OFF : OnOffType.ON;
}
return command;
}
private synchronized void buttonPressed(Command commandToSend) {
cancelTimeoutFuture();
cancelDimmFuture();
if (repeatTime > 0) {
// run repeatedly
dimmFuture = context.getExecutorService().scheduleWithFixedDelay(() -> callback.sendCommand(commandToSend),
longPressTime + 50, repeatTime, TimeUnit.MILLISECONDS);
timeoutFuture = context.getExecutorService().schedule(() -> this.cancelDimmFuture(), timeout,
TimeUnit.MILLISECONDS);
} else {
// run only ones
dimmFuture = context.getExecutorService().schedule(() -> callback.sendCommand(commandToSend),
longPressTime + 50, TimeUnit.MILLISECONDS);
}
pressedTime = System.currentTimeMillis();
}
private synchronized void buttonReleased(Command commandToSend) {
cancelTimeoutFuture();
cancelDimmFuture();
if (System.currentTimeMillis() - pressedTime <= longPressTime) {
callback.sendCommand(commandToSend);
}
}
private synchronized void cancelDimmFuture() {
if (dimmFuture != null) {
dimmFuture.cancel(false);
}
}
private synchronized void cancelTimeoutFuture() {
if (timeoutFuture != null) {
timeoutFuture.cancel(false);
}
}
}

View File

@@ -0,0 +1,566 @@
/**
* 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.ihc.internal.ws;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import org.apache.commons.io.IOUtils;
import org.openhab.binding.ihc.internal.ws.datatypes.WSControllerState;
import org.openhab.binding.ihc.internal.ws.datatypes.WSFile;
import org.openhab.binding.ihc.internal.ws.datatypes.WSLoginResult;
import org.openhab.binding.ihc.internal.ws.datatypes.WSProjectInfo;
import org.openhab.binding.ihc.internal.ws.datatypes.WSRFDevice;
import org.openhab.binding.ihc.internal.ws.datatypes.WSSystemInfo;
import org.openhab.binding.ihc.internal.ws.datatypes.WSTimeManagerSettings;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.binding.ihc.internal.ws.services.IhcAirlinkManagementService;
import org.openhab.binding.ihc.internal.ws.services.IhcAuthenticationService;
import org.openhab.binding.ihc.internal.ws.services.IhcConfigurationService;
import org.openhab.binding.ihc.internal.ws.services.IhcControllerService;
import org.openhab.binding.ihc.internal.ws.services.IhcResourceInteractionService;
import org.openhab.binding.ihc.internal.ws.services.IhcTimeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* IhcClient provides interface to communicate IHC / ELKO LS Controller.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcClient {
/** Current state of the connection */
public enum ConnectionState {
DISCONNECTED,
CONNECTING,
CONNECTED
}
public static final String CONTROLLER_STATE_READY = "text.ctrl.state.ready";
public static final String CONTROLLER_STATE_INITIALIZE = "text.ctrl.state.initialize";
private static final int NOTIFICATION_WAIT_TIMEOUT_IN_SEC = 5;
private final Logger logger = LoggerFactory.getLogger(IhcClient.class);
private ConnectionState connState = ConnectionState.DISCONNECTED;
private IhcConnectionPool ihcConnectionPool;
/** Controller services */
private IhcAuthenticationService authenticationService;
private IhcResourceInteractionService resourceInteractionService;
private IhcControllerService controllerService;
private IhcConfigurationService configurationService;
private IhcAirlinkManagementService airlinkManagementService;
private IhcTimeService timeService;
/** Thread to handle resource value notifications from the controller */
private IhcResourceValueNotificationListener resourceValueNotificationListener;
/** Thread to handle controller's state change notifications */
private IhcControllerStateListener controllerStateListener;
private String username;
private String password;
private String host;
/** Timeout in milliseconds */
private int timeout;
private Map<Integer, WSResourceValue> resourceValues = new HashMap<>();
private List<IhcEventListener> eventListeners = new ArrayList<>();
public IhcClient(String host, String username, String password) {
this(host, username, password, 5000);
}
public IhcClient(String host, String username, String password, int timeout) {
this.host = host;
this.username = username;
this.password = password;
this.timeout = timeout;
}
public synchronized ConnectionState getConnectionState() {
return connState;
}
private synchronized void setConnectionState(ConnectionState newState) {
connState = newState;
}
public void addEventListener(IhcEventListener listener) {
eventListeners.add(listener);
}
public void removeEventListener(IhcEventListener listener) {
eventListeners.remove(listener);
}
/**
* Open connection and authenticate session to IHC / ELKO LS controller.
*
* @throws IhcExecption
*/
public void closeConnection() throws IhcExecption {
logger.debug("Closing connection");
// interrupt
if (resourceValueNotificationListener != null) {
resourceValueNotificationListener.setInterrupted(true);
}
if (controllerStateListener != null) {
controllerStateListener.setInterrupted(true);
}
// wait to stop
if (resourceValueNotificationListener != null) {
logger.debug("Waiting resource value notification listener to stop");
try {
resourceValueNotificationListener.join(NOTIFICATION_WAIT_TIMEOUT_IN_SEC * 1000);
} catch (InterruptedException e) {
// do nothing
}
}
if (controllerStateListener != null) {
logger.debug("Waiting controller state listener to stop");
try {
controllerStateListener.join(NOTIFICATION_WAIT_TIMEOUT_IN_SEC * 1000);
} catch (InterruptedException e) {
// do nothing
}
}
logger.debug("Connection closed");
setConnectionState(ConnectionState.DISCONNECTED);
}
/**
* Open connection and authenticate session to IHC / ELKO LS controller.
*
* @throws IhcExecption
*/
public void openConnection() throws IhcExecption {
logger.debug("Opening connection");
setConnectionState(ConnectionState.CONNECTING);
ihcConnectionPool = new IhcConnectionPool();
authenticationService = new IhcAuthenticationService(host, timeout, ihcConnectionPool);
WSLoginResult loginResult = authenticationService.authenticate(username, password, "treeview");
if (!loginResult.isLoginWasSuccessful()) {
// Login failed
setConnectionState(ConnectionState.DISCONNECTED);
if (loginResult.isLoginFailedDueToAccountInvalid()) {
throw new IhcExecption("login failed because of invalid account");
}
if (loginResult.isLoginFailedDueToConnectionRestrictions()) {
throw new IhcExecption("login failed because of connection restrictions");
}
if (loginResult.isLoginFailedDueToInsufficientUserRights()) {
throw new IhcExecption("login failed because of insufficient user rights");
}
throw new IhcExecption("login failed because of unknown reason");
}
logger.debug("Connection successfully opened");
resourceInteractionService = new IhcResourceInteractionService(host, timeout, ihcConnectionPool);
controllerService = new IhcControllerService(host, timeout, ihcConnectionPool);
configurationService = new IhcConfigurationService(host, timeout, ihcConnectionPool);
airlinkManagementService = new IhcAirlinkManagementService(host, timeout, ihcConnectionPool);
timeService = new IhcTimeService(host, timeout, ihcConnectionPool);
setConnectionState(ConnectionState.CONNECTED);
}
/**
* Start event listener to get notifications from IHC / ELKO LS controller.
*
* @throws IhcExecption
*
*/
public void startControllerEventListeners() throws IhcExecption {
if (getConnectionState() == ConnectionState.CONNECTED) {
logger.debug("Start IHC / ELKO listeners");
resourceValueNotificationListener = new IhcResourceValueNotificationListener();
resourceValueNotificationListener.start();
controllerStateListener = new IhcControllerStateListener();
controllerStateListener.start();
} else {
throw new IhcExecption("Connection to controller not open");
}
}
/**
* Query project information from the controller.
*
* @return project information.
* @throws IhcExecption
*/
public synchronized WSProjectInfo getProjectInfo() throws IhcExecption {
return controllerService.getProjectInfo();
}
/**
* Query system information from the controller.
*
* @return system information.
* @throws IhcExecption
*/
public synchronized WSSystemInfo getSystemInfo() throws IhcExecption {
return configurationService.getSystemInfo();
}
/**
* Query time settings from the controller.
*
* @return time settings.
* @throws IhcExecption
*/
public synchronized WSTimeManagerSettings getTimeSettings() throws IhcExecption {
return timeService.getTimeSettings();
}
/**
* Query detected RF devices from the controller.
*
* @return List of RF devices.
* @throws IhcExecption
*/
public synchronized List<WSRFDevice> getDetectedRFDevices() throws IhcExecption {
return airlinkManagementService.getDetectedDeviceList();
}
/**
* Query controller current state.
*
* @return controller's current state.
*/
public WSControllerState getControllerState() throws IhcExecption {
return controllerService.getControllerState();
}
/**
* Query project number of segments.
*
* @return number of segments.
*/
public int getProjectNumberOfSegments() throws IhcExecption {
return controllerService.getProjectNumberOfSegments();
}
/**
* Query project segmentation size.
*
* @return segmentation size in bytes.
*/
public int getProjectSegmentationSize() throws IhcExecption {
return controllerService.getProjectSegmentationSize();
}
/**
* Query project segments data.
*
* @return segments data.
*/
public WSFile getProjectSegment(int index, int major, int minor) throws IhcExecption {
return controllerService.getProjectSegment(index, major, minor);
}
/**
* Fetch project file from controller.
*
* @return project file.
*/
public byte[] getProjectFileFromController() throws IhcExecption {
try {
WSProjectInfo projectInfo = getProjectInfo();
int numberOfSegments = getProjectNumberOfSegments();
int segmentationSize = getProjectSegmentationSize();
logger.debug("Number of segments: {}", numberOfSegments);
logger.debug("Segmentation size: {}", segmentationSize);
try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
for (int i = 0; i < numberOfSegments; i++) {
logger.debug("Downloading segment {}", i);
WSFile data = getProjectSegment(i, projectInfo.getProjectMajorRevision(),
projectInfo.getProjectMinorRevision());
byteStream.write(data.getData());
}
if (logger.isDebugEnabled()) {
logger.debug("File size before base64 encoding: {} bytes", byteStream.size());
}
byte[] decodedBytes = Base64.getDecoder().decode(byteStream.toString());
logger.debug("File size after base64 encoding: {} bytes", decodedBytes.length);
try (GZIPInputStream gzis = new GZIPInputStream(new ByteArrayInputStream(decodedBytes))) {
try (InputStreamReader in = new InputStreamReader(gzis, "ISO-8859-1")) {
return IOUtils.toByteArray(in, "ISO-8859-1");
}
}
}
} catch (IOException | IllegalArgumentException e) {
throw new IhcExecption(e);
}
}
/**
* Wait controller state change notification.
*
* @param previousState Previous controller state.
* @param timeoutInSecondscHow many seconds to wait notifications.
* @return current controller state.
*/
private WSControllerState waitStateChangeNotifications(WSControllerState previousState, int timeoutInSeconds)
throws IhcExecption {
return controllerService.waitStateChangeNotifications(previousState, timeoutInSeconds);
}
/**
* Enable resources runtime value notifications.
*
* @param resourceIdList List of resource Identifiers.
* @return True is connection successfully opened.
*/
public synchronized void enableRuntimeValueNotifications(Set<Integer> resourceIdList) throws IhcExecption {
resourceInteractionService.enableRuntimeValueNotifications(resourceIdList);
}
/**
* Wait runtime value notifications.
*
* Runtime value notification should firstly be activated by
* enableRuntimeValueNotifications function.
*
* @param timeoutInSeconds How many seconds to wait notifications.
* @return List of received runtime value notifications.
* @throws SocketTimeoutException
*/
private List<WSResourceValue> waitResourceValueNotifications(int timeoutInSeconds) throws IhcExecption {
List<WSResourceValue> list = resourceInteractionService.waitResourceValueNotifications(timeoutInSeconds);
for (WSResourceValue val : list) {
resourceValues.put(val.resourceID, val);
}
return list;
}
/**
* Query resource value from controller.
*
*
* @param resoureId Resource Identifier.
* @return Resource value.
*/
public WSResourceValue resourceQuery(int resoureId) throws IhcExecption {
return resourceInteractionService.resourceQuery(resoureId);
}
/**
* Get resource value information.
*
* Function return resource value from internal memory, if data is not
* available information is read from the controller.
*
* Resource value's value field (e.g. floatingPointValue) could be old
* information.
*
* @param resoureId Resource Identifier.
* @return Resource value.
*/
public WSResourceValue getResourceValueInformation(int resourceId) throws IhcExecption {
if (resourceId != 0) {
WSResourceValue data = resourceValues.get(resourceId);
if (data == null) {
// data is not available, read it from the controller
data = resourceInteractionService.resourceQuery(resourceId);
}
return data;
} else {
return null;
}
}
/**
* Update resource value to controller.
*
*
* @param value Resource value.
* @return True if value is successfully updated.
*/
public boolean resourceUpdate(WSResourceValue value) throws IhcExecption {
return resourceInteractionService.resourceUpdate(value);
}
/**
* The IhcReader runs as a separate thread.
*
* Thread listen resource value notifications from IHC / ELKO LS controller.
*/
private class IhcResourceValueNotificationListener extends Thread {
private volatile boolean interrupted = false;
public void setInterrupted(boolean interrupted) {
this.interrupted = interrupted;
this.interrupt();
}
@Override
public void run() {
logger.debug("IHC resource value listener started");
// as long as no interrupt is requested, continue running
while (!interrupted) {
waitResourceNotifications();
}
logger.debug("IHC resource value listener stopped");
}
private void waitResourceNotifications() {
try {
logger.trace("Wait new resource value notifications from controller");
List<WSResourceValue> resourceValueList = waitResourceValueNotifications(
NOTIFICATION_WAIT_TIMEOUT_IN_SEC);
logger.debug("{} new notifications received from controller", resourceValueList.size());
for (WSResourceValue value : resourceValueList) {
sendResourceValueUpdateEvent(value);
}
} catch (IhcExecption e) {
if (!interrupted) {
logger.warn("New notifications wait failed...", e);
sendErrorEvent(e);
mysleep(1000L);
}
}
}
private void mysleep(long milli) {
try {
sleep(milli);
} catch (InterruptedException e) {
interrupted = true;
}
}
}
/**
* The IhcReader runs as a separate thread.
*
* Thread listen controller state change notifications from IHC / ELKO LS
* controller.
*
*/
private class IhcControllerStateListener extends Thread {
private volatile boolean interrupted = false;
public void setInterrupted(boolean interrupted) {
this.interrupted = interrupted;
this.interrupt();
}
@Override
public void run() {
logger.debug("IHC controller state listener started");
WSControllerState previousState = null;
// as long as no interrupt is requested, continue running
while (!interrupted) {
try {
if (previousState == null) {
// initialize previous state
previousState = controllerService.getControllerState();
logger.debug("Controller initial state {}", previousState.getState());
}
logger.trace("Wait new state change notification from controller");
WSControllerState currentState = waitStateChangeNotifications(previousState,
NOTIFICATION_WAIT_TIMEOUT_IN_SEC);
logger.trace("Controller state {}", currentState.getState());
if (!previousState.getState().equals(currentState.getState())) {
logger.debug("Controller state change detected ({} -> {})", previousState.getState(),
currentState.getState());
sendControllerStateUpdateEvent(currentState);
previousState.setState(currentState.getState());
}
} catch (IhcExecption e) {
if (!interrupted) {
logger.error("New controller state change notification wait failed...", e);
sendErrorEvent(e);
mysleep(1000L);
}
}
}
logger.debug("IHC controller state listener stopped");
}
private void mysleep(long milli) {
try {
sleep(milli);
} catch (InterruptedException e) {
interrupted = true;
}
}
}
private void sendErrorEvent(IhcExecption err) {
eventListeners.forEach(listener -> {
try {
listener.errorOccured(err);
} catch (RuntimeException e) {
logger.debug("Event listener invoking error.", e);
}
});
}
private void sendControllerStateUpdateEvent(WSControllerState state) {
eventListeners.forEach(listener -> {
try {
listener.statusUpdateReceived(state);
} catch (RuntimeException e) {
logger.debug("Event listener invoking error.", e);
}
});
}
private void sendResourceValueUpdateEvent(WSResourceValue value) {
eventListeners.forEach(listener -> {
try {
listener.resourceValueUpdateReceived(value);
} catch (RuntimeException e) {
logger.debug("Event listener invoking error.", e);
}
});
}
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws;
import org.openhab.binding.ihc.internal.ws.datatypes.WSControllerState;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
/**
* This interface defines interface to receive updates from IHC controller.
*
* @author Pauli Anttila - Initial contribution
*/
public interface IhcEventListener {
/**
* Event for receive status update from IHC controller.
*
* @param status Received status update from controller.
*/
void statusUpdateReceived(WSControllerState status);
/**
* Event for receive resource value updates from IHC controller.
*
* @param value Received value update from controller.
*/
void resourceValueUpdateReceived(WSResourceValue value);
/**
* Event for fatal error on communication to IHC controller.
*
* @param e IhcException occurred.
*/
void errorOccured(IhcExecption e);
}

View File

@@ -0,0 +1,70 @@
/**
* 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.ihc.internal.ws.datatypes;
import java.io.IOException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSControllerState complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSControllerState {
private String state;
public WSControllerState() {
}
public WSControllerState(String state) {
this.state = state;
}
/**
* Gets the state value for this WSControllerState.
*
* @return state
*/
public String getState() {
return state;
}
/**
* Sets the state value for this WSControllerState.
*
* @param state
*/
public void setState(String state) {
this.state = state;
}
public WSControllerState parseXMLData(String data) throws IhcExecption {
try {
if (data.contains("getState1")) {
state = XPathUtils.parseXMLValue(data, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getState1/ns1:state");
} else if (data.contains("waitForControllerStateChange3")) {
state = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:waitForControllerStateChange3/ns1:state");
} else {
throw new IhcExecption("Encoding error, unsupported data");
}
return this;
} catch (IOException | XPathExpressionException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
}

View File

@@ -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.ihc.internal.ws.datatypes;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
/**
* Class for WSDate complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSDate {
private int hours;
private int minutes;
private int seconds;
private int year;
private int day;
private int monthWithJanuaryAsOne;
public WSDate() {
}
public WSDate(int hours, int minutes, int seconds, int year, int day, int monthWithJanuaryAsOne) {
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
this.year = year;
this.day = day;
this.monthWithJanuaryAsOne = monthWithJanuaryAsOne;
}
/**
* Gets the hours value for this WSDate.
*
* @return hours
*/
public int getHours() {
return hours;
}
/**
* Sets the hours value for this WSDate.
*
* @param hours
*/
public void setHours(int hours) {
this.hours = hours;
}
/**
* Gets the minutes value for this WSDate.
*
* @return minutes
*/
public int getMinutes() {
return minutes;
}
/**
* Sets the minutes value for this WSDate.
*
* @param minutes
*/
public void setMinutes(int minutes) {
this.minutes = minutes;
}
/**
* Gets the seconds value for this WSDate.
*
* @return seconds
*/
public int getSeconds() {
return seconds;
}
/**
* Sets the seconds value for this WSDate.
*
* @param seconds
*/
public void setSeconds(int seconds) {
this.seconds = seconds;
}
/**
* Gets the year value for this WSDate.
*
* @return year
*/
public int getYear() {
return year;
}
/**
* Sets the year value for this WSDate.
*
* @param year
*/
public void setYear(int year) {
this.year = year;
}
/**
* Gets the day value for this WSDate.
*
* @return day
*/
public int getDay() {
return day;
}
/**
* Sets the day value for this WSDate.
*
* @param day
*/
public void setDay(int day) {
this.day = day;
}
/**
* Gets the monthWithJanuaryAsOne value for this WSDate.
*
* @return monthWithJanuaryAsOne
*/
public int getMonthWithJanuaryAsOne() {
return monthWithJanuaryAsOne;
}
/**
* Sets the monthWithJanuaryAsOne value for this WSDate.
*
* @param monthWithJanuaryAsOne
*/
public void setMonthWithJanuaryAsOne(int monthWithJanuaryAsOne) {
this.monthWithJanuaryAsOne = monthWithJanuaryAsOne;
}
/**
* Gets WSDate as LocalDateTime.
*
* @return LocalDateTime
*/
public LocalDateTime getAsLocalDateTime() {
return LocalDateTime.of(year, monthWithJanuaryAsOne, day, hours, minutes, seconds);
}
/**
* Gets WSDate as ZonedDateTime.
*
* @return LocalDateTime
*/
public ZonedDateTime getAsZonedDateTime(ZoneId zoneId) {
return ZonedDateTime.of(getAsLocalDateTime(), zoneId);
}
}

View File

@@ -0,0 +1,86 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws.datatypes;
import java.io.IOException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSFile complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSFile {
private byte[] data;
private String filename;
public WSFile() {
}
public WSFile(byte[] data, String filename) {
this.data = data;
this.filename = filename;
}
/**
* Gets the data value for this WSFile.
*
* @return data
*/
public byte[] getData() {
return data;
}
/**
* Sets the data value for this WSFile.
*
* @param data
*/
public void setData(byte[] data) {
this.data = data;
}
/**
* Gets the filename value for this WSFile.
*
* @return filename
*/
public String getFilename() {
return filename;
}
/**
* Sets the filename value for this WSFile.
*
* @param filename
*/
public void setFilename(String filename) {
this.filename = filename;
}
public WSFile parseXMLData(String data) throws IhcExecption {
try {
filename = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getIHCProjectSegment4/ns1:filename");
this.data = XPathUtils
.parseXMLValue(data, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getIHCProjectSegment4/ns1:data")
.getBytes();
return this;
} catch (IOException | XPathExpressionException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
}

View File

@@ -0,0 +1,150 @@
/**
* 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.ihc.internal.ws.datatypes;
import java.io.IOException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSLoginResult complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSLoginResult {
protected WSUser loggedInUser;
protected boolean loginWasSuccessful;
protected boolean loginFailedDueToConnectionRestrictions;
protected boolean loginFailedDueToInsufficientUserRights;
protected boolean loginFailedDueToAccountInvalid;
public WSLoginResult() {
}
public WSLoginResult(WSUser loggedInUser, boolean loginWasSuccessful,
boolean loginFailedDueToConnectionRestrictions, boolean loginFailedDueToInsufficientUserRights,
boolean loginFailedDueToAccountInvalid) {
this.loggedInUser = loggedInUser;
this.loginWasSuccessful = loginWasSuccessful;
this.loginFailedDueToConnectionRestrictions = loginFailedDueToConnectionRestrictions;
this.loginFailedDueToInsufficientUserRights = loginFailedDueToInsufficientUserRights;
this.loginFailedDueToAccountInvalid = loginFailedDueToAccountInvalid;
}
/**
* Gets the value of the loggedInUser property.
*
* @return possible object is {@link WSUser }
*
*/
public WSUser getLoggedInUser() {
return loggedInUser;
}
/**
* Sets the value of the loggedInUser property.
*
* @param value allowed object is {@link WSUser }
*
*/
public void setLoggedInUser(WSUser value) {
this.loggedInUser = value;
}
/**
* Gets the value of the loginWasSuccessful property.
*
*/
public boolean isLoginWasSuccessful() {
return loginWasSuccessful;
}
/**
* Sets the value of the loginWasSuccessful property.
*
*/
public void setLoginWasSuccessful(boolean value) {
this.loginWasSuccessful = value;
}
/**
* Gets the value of the loginFailedDueToConnectionRestrictions property.
*
*/
public boolean isLoginFailedDueToConnectionRestrictions() {
return loginFailedDueToConnectionRestrictions;
}
/**
* Sets the value of the loginFailedDueToConnectionRestrictions property.
*
*/
public void setLoginFailedDueToConnectionRestrictions(boolean value) {
this.loginFailedDueToConnectionRestrictions = value;
}
/**
* Gets the value of the loginFailedDueToInsufficientUserRights property.
*
*/
public boolean isLoginFailedDueToInsufficientUserRights() {
return loginFailedDueToInsufficientUserRights;
}
/**
* Sets the value of the loginFailedDueToInsufficientUserRights property.
*
*/
public void setLoginFailedDueToInsufficientUserRights(boolean value) {
this.loginFailedDueToInsufficientUserRights = value;
}
/**
* Gets the value of the loginFailedDueToAccountInvalid property.
*
*/
public boolean isLoginFailedDueToAccountInvalid() {
return loginFailedDueToAccountInvalid;
}
/**
* Sets the value of the loginFailedDueToAccountInvalid property.
*
*/
public void setLoginFailedDueToAccountInvalid(boolean value) {
this.loginFailedDueToAccountInvalid = value;
}
public WSLoginResult parseXMLData(String data) throws IhcExecption {
try {
loginWasSuccessful = XPathUtils.parseValueToBoolean(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:authenticate2/ns1:loginWasSuccessful");
loginFailedDueToConnectionRestrictions = XPathUtils.parseValueToBoolean(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:authenticate2/ns1:loginFailedDueToConnectionRestrictions");
loginFailedDueToInsufficientUserRights = XPathUtils.parseValueToBoolean(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:authenticate2/ns1:loginFailedDueToInsufficientUserRights");
loginFailedDueToAccountInvalid = XPathUtils.parseValueToBoolean(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:authenticate2/ns1:loginFailedDueToAccountInvalid");
return this;
} catch (IOException | XPathExpressionException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
}

View File

@@ -0,0 +1,65 @@
/**
* 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.ihc.internal.ws.datatypes;
import java.io.IOException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSNumberOfSegments complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSNumberOfSegments {
private int segments;
public WSNumberOfSegments() {
}
public WSNumberOfSegments(int segments) {
this.segments = segments;
}
/**
* Gets the number of segments.
*
* @return segmentation size
*/
public int getNumberOfSegments() {
return segments;
}
/**
* Sets the number of segmentations.
*
* @param value
*/
public void setNumberOfSegments(int segments) {
this.segments = segments;
}
public WSNumberOfSegments parseXMLData(String data) throws IhcExecption {
try {
String value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getIHCProjectNumberOfSegments1");
setNumberOfSegments(Integer.parseInt(value));
return this;
} catch (IOException | XPathExpressionException | NumberFormatException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
}

View File

@@ -0,0 +1,268 @@
/**
* 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.ihc.internal.ws.datatypes;
import java.io.IOException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSProjectInfo complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSProjectInfo {
private int visualMinorVersion;
private int visualMajorVersion;
private int projectMajorRevision;
private int projectMinorRevision;
private WSDate lastmodified;
private String projectNumber;
private String customerName;
private String installerName;
public WSProjectInfo() {
}
public WSProjectInfo(int visualMinorVersion, int visualMajorVersion, int projectMajorRevision,
int projectMinorRevision, WSDate lastmodified, String projectNumber, String customerName,
String installerName) {
this.visualMinorVersion = visualMinorVersion;
this.visualMajorVersion = visualMajorVersion;
this.projectMajorRevision = projectMajorRevision;
this.projectMinorRevision = projectMinorRevision;
this.lastmodified = lastmodified;
this.projectNumber = projectNumber;
this.customerName = customerName;
this.installerName = installerName;
}
/**
* Gets the visualMinorVersion value for this WSProjectInfo.
*
* @return visualMinorVersion
*/
public int getVisualMinorVersion() {
return visualMinorVersion;
}
/**
* Sets the visualMinorVersion value for this WSProjectInfo.
*
* @param visualMinorVersion
*/
public void setVisualMinorVersion(int visualMinorVersion) {
this.visualMinorVersion = visualMinorVersion;
}
/**
* Gets the visualMajorVersion value for this WSProjectInfo.
*
* @return visualMajorVersion
*/
public int getVisualMajorVersion() {
return visualMajorVersion;
}
/**
* Sets the visualMajorVersion value for this WSProjectInfo.
*
* @param visualMajorVersion
*/
public void setVisualMajorVersion(int visualMajorVersion) {
this.visualMajorVersion = visualMajorVersion;
}
/**
* Gets the projectMajorRevision value for this WSProjectInfo.
*
* @return projectMajorRevision
*/
public int getProjectMajorRevision() {
return projectMajorRevision;
}
/**
* Sets the projectMajorRevision value for this WSProjectInfo.
*
* @param projectMajorRevision
*/
public void setProjectMajorRevision(int projectMajorRevision) {
this.projectMajorRevision = projectMajorRevision;
}
/**
* Gets the projectMinorRevision value for this WSProjectInfo.
*
* @return projectMinorRevision
*/
public int getProjectMinorRevision() {
return projectMinorRevision;
}
/**
* Sets the projectMinorRevision value for this WSProjectInfo.
*
* @param projectMinorRevision
*/
public void setProjectMinorRevision(int projectMinorRevision) {
this.projectMinorRevision = projectMinorRevision;
}
/**
* Gets the lastmodified value for this WSProjectInfo.
*
* @return lastmodified
*/
public WSDate getLastmodified() {
return lastmodified;
}
/**
* Sets the lastmodified value for this WSProjectInfo.
*
* @param lastmodified
*/
public void setLastmodified(WSDate lastmodified) {
this.lastmodified = lastmodified;
}
/**
* Gets the projectNumber value for this WSProjectInfo.
*
* @return projectNumber
*/
public java.lang.String getProjectNumber() {
return projectNumber;
}
/**
* Sets the projectNumber value for this WSProjectInfo.
*
* @param projectNumber
*/
public void setProjectNumber(String projectNumber) {
this.projectNumber = projectNumber;
}
/**
* Gets the customerName value for this WSProjectInfo.
*
* @return customerName
*/
public java.lang.String getCustomerName() {
return customerName;
}
/**
* Sets the customerName value for this WSProjectInfo.
*
* @param customerName
*/
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
/**
* Gets the installerName value for this WSProjectInfo.
*
* @return installerName
*/
public java.lang.String getInstallerName() {
return installerName;
}
/**
* Sets the installerName value for this WSProjectInfo.
*
* @param installerName
*/
public void setInstallerName(String installerName) {
this.installerName = installerName;
}
public WSProjectInfo parseXMLData(String data) throws IhcExecption {
try {
String value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:visualMinorVersion");
setVisualMinorVersion(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:visualMajorVersion");
setVisualMajorVersion(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:projectMajorRevision");
setProjectMajorRevision(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:projectMinorRevision");
setProjectMinorRevision(Integer.parseInt(value));
WSDate lastmodified = new WSDate();
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:lastmodified/ns1:day");
lastmodified.setDay(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:lastmodified/ns1:monthWithJanuaryAsOne");
lastmodified.setMonthWithJanuaryAsOne(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:lastmodified/ns1:hours");
lastmodified.setHours(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:lastmodified/ns1:minutes");
lastmodified.setMinutes(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:lastmodified/ns1:seconds");
lastmodified.setSeconds(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:lastmodified/ns1:year");
lastmodified.setYear(Integer.parseInt(value));
setLastmodified(lastmodified);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:projectNumber");
setProjectNumber(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:customerName");
setCustomerName(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getProjectInfo1/ns1:installerName");
setInstallerName(value);
return this;
} catch (IOException | XPathExpressionException | NumberFormatException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
@Override
public String toString() {
return String.format(
"[ visualMinorVersion=%d, visualMajorVersion=%d, projectMajorRevision=%d, projectMinorRevision=%d, lastmodified=%s, projectNumber=%s, customerName=%s, installerName=%s ]",
visualMinorVersion, visualMajorVersion, projectMajorRevision, projectMinorRevision,
lastmodified.getAsLocalDateTime(), projectNumber, customerName, installerName);
}
}

View File

@@ -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.ihc.internal.ws.datatypes;
/**
* Class for WSRFDevice complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSRFDevice {
private int batteryLevel;
private int deviceType;
private long serialNumber;
private int signalStrength;
private int version;
private boolean detected;
public WSRFDevice() {
}
public WSRFDevice(int batteryLevel, int deviceType, long serialNumber, int signalStrength, int version,
boolean detected) {
this.batteryLevel = batteryLevel;
this.deviceType = deviceType;
this.serialNumber = serialNumber;
this.signalStrength = signalStrength;
this.version = version;
this.detected = detected;
}
/**
* Gets the battery level value for this WSRFDevice.
*
* @return Battery Level
*/
public int getBatteryLevel() {
return batteryLevel;
}
/**
* Sets the battery level value for this WSRFDevice.
*
* @param batteryLevel battery level
*/
public void setBatteryLevel(int batteryLevel) {
this.batteryLevel = batteryLevel;
}
/**
* Gets the device type value for this WSRFDevice.
*
* @return device type
*/
public int getDeviceType() {
return deviceType;
}
/**
* Sets the device type value for this WSRFDevice.
*
* @param device type
*/
public void setDeviceType(int deviceType) {
this.deviceType = deviceType;
}
/**
* Gets the serial number value for this WSRFDevice.
*
* @return Serial number
*/
public long getSerialNumber() {
return serialNumber;
}
/**
* Sets the serial number value for this WSRFDevice.
*
* @param Serial number
*/
public void setSerialNumber(long serialNumber) {
this.serialNumber = serialNumber;
}
/**
* Gets the signal strength value for this WSRFDevice.
*
* @return Signal strength
*/
public int getSignalStrength() {
return signalStrength;
}
/**
* Sets the signal strength value for this WSRFDevice.
*
* @param signalStrength Signal strength
*/
public void setSignalStrength(int signalStrength) {
this.signalStrength = signalStrength;
}
/**
* Gets the version value for this WSRFDevice.
*
* @return version
*/
public int getVersion() {
return version;
}
/**
* Sets the version value for this WSRFDevice.
*
* @param version
*/
public void setVersion(int version) {
this.version = version;
}
/**
* Gets the detected value for this WSRFDevice.
*
* @return Detected
*/
public boolean getDetected() {
return detected;
}
/**
* Sets the detected value for this WSRFDevice.
*
* @param detected
*/
public void setdetected(boolean detected) {
this.detected = detected;
}
@Override
public String toString() {
return String.format(
"[ batteryLevel=%d, deviceType=%d, serialNumber=%d, signalStrength=%d, version=%d, detected=%b ]",
batteryLevel, deviceType, serialNumber, signalStrength, version, detected);
}
}

View File

@@ -0,0 +1,65 @@
/**
* 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.ihc.internal.ws.datatypes;
import java.io.IOException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSSegmentationSize complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSSegmentationSize {
private int size;
public WSSegmentationSize() {
}
public WSSegmentationSize(int size) {
this.size = size;
}
/**
* Gets the segmentation size value.
*
* @return segmentation size
*/
public int getSegmentationSize() {
return size;
}
/**
* Sets the segmentation size value.
*
* @param size
*/
public void setSegmentationSize(int size) {
this.size = size;
}
public WSSegmentationSize parseXMLData(String data) throws IhcExecption {
try {
String value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getIHCProjectSegmentationSize1");
setSegmentationSize(Integer.parseInt(value));
return this;
} catch (IOException | XPathExpressionException | NumberFormatException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
}

View File

@@ -0,0 +1,339 @@
/**
* 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.ihc.internal.ws.datatypes;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSProjectInfo complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSSystemInfo {
private long uptime;
private ZonedDateTime realtimeclock;
private String serialNumber;
private String brand;
private String version;
private String hwRevision;
private ZonedDateTime swDate;
private boolean applicationIsWithoutViewer;
private String productionDate;
private String datalineVersion;
private String rfModuleSoftwareVersion;
private String rfModuleSerialNumber;
public WSSystemInfo() {
}
public WSSystemInfo(long uptime, ZonedDateTime realtimeclock, String serialNumber, String brand, String version,
String hwRevision, ZonedDateTime swDate, boolean applicationIsWithoutViewer, String productionDate,
String datalineVersion, String rfModuleSoftwareVersion, String rfModuleSerialNumber) {
this.uptime = uptime;
this.realtimeclock = realtimeclock;
this.serialNumber = serialNumber;
this.brand = brand;
this.version = version;
this.hwRevision = hwRevision;
this.swDate = swDate;
this.applicationIsWithoutViewer = applicationIsWithoutViewer;
this.productionDate = productionDate;
this.datalineVersion = datalineVersion;
this.rfModuleSoftwareVersion = rfModuleSoftwareVersion;
this.rfModuleSerialNumber = rfModuleSerialNumber;
}
/**
* Gets the uptime value for this WSSystemInfo.
*
* @return uptime in milliseconds
*/
public long getUptime() {
return uptime;
}
/**
* Sets the uptime value for this WSSystemInfo.
*
* @param uptime uptime in milliseconds
*/
public void setUptime(long uptime) {
this.uptime = uptime;
}
/**
* Gets the RealTimeClock value for this WSSystemInfo.
*
* @return Real Time Clock
*/
public ZonedDateTime getRealTimeClock() {
return realtimeclock;
}
/**
* Sets the RealTimeClock value for this WSSystemInfo.
*
* @param RealTimeClock
*/
public void setRealTimeClock(ZonedDateTime realtimeclock) {
this.realtimeclock = realtimeclock;
}
/**
* Gets the SerialNumber value for this WSSystemInfo.
*
* @return SerialNumber
*/
public String getSerialNumber() {
return serialNumber;
}
/**
* Sets the SerialNumber value for this WSSystemInfo.
*
* @param SerialNumber
*/
public void setSerialNumber(String serialNumber) {
this.serialNumber = serialNumber;
}
/**
* Gets the brand value for this WSSystemInfo.
*
* @return brand
*/
public String getBrand() {
return brand;
}
/**
* Sets the brand value for this WSSystemInfo.
*
* @param brand
*/
public void setBrand(String brand) {
this.brand = brand;
}
/**
* Gets the version value for this WSSystemInfo.
*
* @return version
*/
public String getVersion() {
return version;
}
/**
* Sets the version value for this WSSystemInfo.
*
* @param version
*/
public void setVersion(String version) {
this.version = version;
}
/**
* Gets the hwRevision value for this WSSystemInfo.
*
* @return hwRevision
*/
public String getHwRevision() {
return hwRevision;
}
/**
* Sets the hwRevision value for this WSSystemInfo.
*
* @param hwRevision
*/
public void setHwRevision(String hwRevision) {
this.hwRevision = hwRevision;
}
/**
* Gets the swDate value for this WSSystemInfo.
*
* @return swDate
*/
public ZonedDateTime getSwDate() {
return swDate;
}
/**
* Sets the swDate value for this WSSystemInfo.
*
* @param swDate
*/
public void setSwDate(ZonedDateTime swDate) {
this.swDate = swDate;
}
/**
* Gets the applicationIsWithoutViewer value for this WSSystemInfo.
*
* @return applicationIsWithoutViewer
*/
public boolean getApplicationIsWithoutViewer() {
return applicationIsWithoutViewer;
}
/**
* Sets the applicationIsWithoutViewer value for this WSSystemInfo.
*
* @param applicationIsWithoutViewer
*/
public void setApplicationIsWithoutViewer(boolean applicationIsWithoutViewer) {
this.applicationIsWithoutViewer = applicationIsWithoutViewer;
}
/**
* Gets the productionDate value for this WSSystemInfo.
*
* @return productionDate
*/
public String getProductionDate() {
return productionDate;
}
/**
* Sets the productionDate value for this WSSystemInfo.
*
* @param productionDate
*/
public void setProductionDate(String productionDate) {
this.productionDate = productionDate;
}
/**
* Gets the datalineVersion value for this WSSystemInfo.
*
* @return datalineVersion
*/
public String getDatalineVersion() {
return datalineVersion;
}
/**
* Sets the datalineVersion value for this WSSystemInfo.
*
* @param datalineVersion
*/
public void setDatalineVersion(String datalineVersion) {
this.datalineVersion = datalineVersion;
}
/**
* Gets the rfModuleSoftwareVersion value for this WSSystemInfo.
*
* @return rfModuleSoftwareVersion
*/
public String getRfModuleSoftwareVersion() {
return rfModuleSoftwareVersion;
}
/**
* Sets the rfModuleSoftwareVersion value for this WSSystemInfo.
*
* @param rfModuleSoftwareVersion
*/
public void setRfModuleSoftwareVersion(String rfModuleSoftwareVersion) {
this.rfModuleSoftwareVersion = rfModuleSoftwareVersion;
}
/**
* Gets the rfModuleSerialNumber value for this WSSystemInfo.
*
* @return rfModuleSerialNumber
*/
public String getRfModuleSerialNumber() {
return rfModuleSerialNumber;
}
/**
* Sets the rfModuleSerialNumber value for this WSSystemInfo.
*
* @param rfModuleSerialNumber
*/
public void setRfModuleSerialNumber(String rfModuleSerialNumber) {
this.rfModuleSerialNumber = rfModuleSerialNumber;
}
public WSSystemInfo parseXMLData(String data) throws IhcExecption {
try {
String value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:uptime");
setUptime(Long.parseLong(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:serialNumber");
setSerialNumber(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:realtimeclock");
setRealTimeClock(ZonedDateTime.parse(value));
value = XPathUtils.parseXMLValue(data, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:brand");
setBrand(value);
value = XPathUtils.parseXMLValue(data, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:version");
setVersion(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:hwRevision");
setHwRevision(value);
value = XPathUtils.parseXMLValue(data, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:swDate");
setSwDate(ZonedDateTime.parse(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:applicationIsWithoutViewer");
setApplicationIsWithoutViewer(Boolean.parseBoolean(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:productionDate");
setProductionDate(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:datalineVersion");
setDatalineVersion(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:rfModuleSoftwareVersion");
setRfModuleSoftwareVersion(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSystemInfo1/ns1:rfModuleSerialNumber");
setRfModuleSerialNumber(value);
return this;
} catch (IOException | XPathExpressionException | NumberFormatException | DateTimeParseException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
@Override
public String toString() {
return String.format(
"[ uptime=%d, realtimeclock=%s, serialNumber=%s, brand=%s, version=%s, hwRevision=%s, swDate=%s, applicationIsWithoutViewer=%b, productionDate=%s, datalineVersion=%s, rfModuleSoftwareVersion=%s, rfModuleSerialNumber=%s ]",
uptime, realtimeclock, serialNumber, brand, version, hwRevision, swDate, applicationIsWithoutViewer,
productionDate, datalineVersion, rfModuleSoftwareVersion, rfModuleSerialNumber);
}
}

View File

@@ -0,0 +1,157 @@
/**
* 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.ihc.internal.ws.datatypes;
import java.io.IOException;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Class for WSTimeManagerSettings complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSTimeManagerSettings {
private boolean synchroniseTimeAgainstServer;
private boolean useDST;
private int gmtOffsetInHours;
private String serverName;
private int syncIntervalInHours;
private WSDate timeAndDateInUTC;
public WSTimeManagerSettings() {
}
public WSTimeManagerSettings(boolean synchroniseTimeAgainstServer, boolean useDST, int gmtOffsetInHours,
String serverName, int syncIntervalInHours, WSDate timeAndDateInUTC) {
this.synchroniseTimeAgainstServer = synchroniseTimeAgainstServer;
this.useDST = useDST;
this.gmtOffsetInHours = gmtOffsetInHours;
this.serverName = serverName;
this.syncIntervalInHours = syncIntervalInHours;
this.timeAndDateInUTC = timeAndDateInUTC;
}
public boolean getSynchroniseTimeAgainstServer() {
return synchroniseTimeAgainstServer;
}
public void setSynchroniseTimeAgainstServer(boolean synchroniseTimeAgainstServer) {
this.synchroniseTimeAgainstServer = synchroniseTimeAgainstServer;
}
public boolean getUseDST() {
return useDST;
}
public void setUseDST(boolean useDST) {
this.useDST = useDST;
}
public int getGmtOffsetInHours() {
return gmtOffsetInHours;
}
public void setGmtOffsetInHours(int gmtOffsetInHours) {
this.gmtOffsetInHours = gmtOffsetInHours;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public int getSyncIntervalInHours() {
return syncIntervalInHours;
}
public void setSyncIntervalInHours(int syncIntervalInHours) {
this.syncIntervalInHours = syncIntervalInHours;
}
public WSDate getTimeAndDateInUTC() {
return timeAndDateInUTC;
}
public void setTimeAndDateInUTC(WSDate timeAndDateInUTC) {
this.timeAndDateInUTC = timeAndDateInUTC;
}
public WSTimeManagerSettings parseXMLData(String data) throws IhcExecption {
try {
String value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:synchroniseTimeAgainstServer");
setSynchroniseTimeAgainstServer(Boolean.parseBoolean(value));
value = XPathUtils.parseXMLValue(data, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:useDST");
setUseDST(Boolean.parseBoolean(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:gmtOffsetInHours");
setGmtOffsetInHours(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:serverName");
setServerName(value);
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:syncIntervalInHours");
setSyncIntervalInHours(Integer.parseInt(value));
WSDate timeAndDateInUTC = new WSDate();
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:timeAndDateInUTC/ns1:day");
timeAndDateInUTC.setDay(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:timeAndDateInUTC/ns1:monthWithJanuaryAsOne");
timeAndDateInUTC.setMonthWithJanuaryAsOne(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:timeAndDateInUTC/ns1:hours");
timeAndDateInUTC.setHours(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:timeAndDateInUTC/ns1:minutes");
timeAndDateInUTC.setMinutes(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:timeAndDateInUTC/ns1:seconds");
timeAndDateInUTC.setSeconds(Integer.parseInt(value));
value = XPathUtils.parseXMLValue(data,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getSettings1/ns1:timeAndDateInUTC/ns1:year");
timeAndDateInUTC.setYear(Integer.parseInt(value));
setTimeAndDateInUTC(timeAndDateInUTC);
return this;
} catch (IOException | XPathExpressionException | NumberFormatException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
@Override
public String toString() {
return String.format(
"[ synchroniseTimeAgainstServer=%b, useDST=%b, gmtOffsetInHours=%d, serverName=%s, syncIntervalInHours=%d, timeAndDateInUTC=%s ]",
synchroniseTimeAgainstServer, useDST, gmtOffsetInHours, serverName, syncIntervalInHours,
timeAndDateInUTC.getAsLocalDateTime());
}
}

View File

@@ -0,0 +1,250 @@
/**
* 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.ihc.internal.ws.datatypes;
/**
* Class for WSUser complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSUser {
protected WSDate createdDate;
protected WSDate loginDate;
protected String username;
protected String password;
protected String email;
protected String firstname;
protected String lastname;
protected String phone;
protected WSUserGroup group;
protected String project;
public WSUser() {
}
public WSUser(WSDate createdDate, WSDate loginDate, String username, String password, String email,
String firstname, String lastname, String phone, WSUserGroup group, String project) {
this.createdDate = createdDate;
this.loginDate = loginDate;
this.username = username;
this.password = password;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.phone = phone;
this.group = group;
this.project = project;
}
/**
* Gets the value of the createdDate property.
*
* @return possible object is {@link WSDate }
*
*/
public WSDate getCreatedDate() {
return createdDate;
}
/**
* Sets the value of the createdDate property.
*
* @param value allowed object is {@link WSDate }
*
*/
public void setCreatedDate(WSDate value) {
this.createdDate = value;
}
/**
* Gets the value of the loginDate property.
*
* @return possible object is {@link WSDate }
*
*/
public WSDate getLoginDate() {
return loginDate;
}
/**
* Sets the value of the loginDate property.
*
* @param value allowed object is {@link WSDate }
*
*/
public void setLoginDate(WSDate value) {
this.loginDate = value;
}
/**
* Gets the value of the username property.
*
* @return possible object is {@link String }
*
*/
public String getUsername() {
return username;
}
/**
* Sets the value of the username property.
*
* @param value allowed object is {@link String }
*
*/
public void setUsername(String value) {
this.username = value;
}
/**
* Gets the value of the password property.
*
* @return possible object is {@link String }
*
*/
public String getPassword() {
return password;
}
/**
* Sets the value of the password property.
*
* @param value allowed object is {@link String }
*
*/
public void setPassword(String value) {
this.password = value;
}
/**
* Gets the value of the email property.
*
* @return possible object is {@link String }
*
*/
public String getEmail() {
return email;
}
/**
* Sets the value of the email property.
*
* @param value allowed object is {@link String }
*
*/
public void setEmail(String value) {
this.email = value;
}
/**
* Gets the value of the firstname property.
*
* @return possible object is {@link String }
*
*/
public String getFirstname() {
return firstname;
}
/**
* Sets the value of the firstname property.
*
* @return possible object is {@link String }
*
*/
public void setFirstname(String value) {
this.firstname = value;
}
/**
* Gets the value of the lastname property.
*
* @return possible object is {@link String }
*
*/
public String getLastname() {
return lastname;
}
/**
* Sets the value of the lastname property.
*
* @param value allowed object is {@link String }
*
*/
public void setLastname(String value) {
this.lastname = value;
}
/**
* Gets the value of the phone property.
*
* @param value allowed object is {@link String }
*
*/
public String getPhone() {
return phone;
}
/**
* Sets the value of the phone property.
*
* @param value allowed object is {@link String }
* {@link String }
*
*/
public void setPhone(String value) {
this.phone = value;
}
/**
* Gets the value of the group property.
*
* @return possible object is {@link WSUserGroup }
*
*/
public WSUserGroup getGroup() {
return group;
}
/**
* Sets the value of the group property.
*
* @param value allowed object is {@link WSUserGroup }
*
*/
public void setGroup(WSUserGroup value) {
this.group = value;
}
/**
* Gets the value of the project property.
*
* @return possible object is {@link String }
*
*/
public String getProject() {
return project;
}
/**
* Sets the value of the project property.
*
* @param value allowed object is {@link String }
*
*/
public void setProject(String value) {
this.project = value;
}
}

View File

@@ -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.ihc.internal.ws.datatypes;
/**
* Class for WSUserGroup complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSUserGroup {
protected String type;
public WSUserGroup() {
}
public WSUserGroup(String type) {
this.type = type;
}
/**
* Gets the value of the type property.
*
* @return possible object is {@link String }
*
*/
public String getType() {
return type;
}
/**
* Sets the value of the type property.
*
* @param value allowed object is {@link String }
*
*/
public void setType(String value) {
this.type = value;
}
}

View File

@@ -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.ihc.internal.ws.datatypes;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* Class for XPath utils.
*
*
* @author Pauli Anttila - Initial contribution
*/
public class XPathUtils {
private static NamespaceContext ihcNamespaceContext = new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if (prefix == null) {
throw new IllegalArgumentException("Prefix argument can't be null");
} else if ("SOAP-ENV".equals(prefix)) {
return "http://schemas.xmlsoap.org/soap/envelope/";
} else if ("ns1".equals(prefix)) {
return "utcs";
}
return "utcs.values";
}
@Override
public String getPrefix(String uri) {
return null;
}
@Override
@SuppressWarnings("rawtypes")
public Iterator getPrefixes(String uri) {
throw new UnsupportedOperationException();
}
};
public static String parseXMLValue(String xml, String xpathExpression)
throws IOException, XPathExpressionException {
try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8.name()))) {
XPath xpath = XPathFactory.newInstance().newXPath();
InputSource inputSource = new InputSource(is);
xpath.setNamespaceContext(ihcNamespaceContext);
return (String) xpath.evaluate(xpathExpression, inputSource, XPathConstants.STRING);
}
}
public static boolean parseValueToBoolean(String xml, String xpathExpression)
throws IOException, XPathExpressionException {
return Boolean.parseBoolean(parseXMLValue(xml, xpathExpression));
}
public static String createIgnoreNameSpaceSyntaxExpr(String name) {
return "*[local-name() = '" + name + "']";
}
public static String getSpeficValueFromNode(Node n, String xpathExpr) throws XPathExpressionException {
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(ihcNamespaceContext);
XPathExpression pathExpr = xpath.compile(xpathExpr);
return (String) pathExpr.evaluate(n, XPathConstants.STRING);
}
public static NodeList parseList(String xml, String xpathExpression) throws XPathExpressionException, IOException {
try (InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8.name()))) {
XPath xpath = XPathFactory.newInstance().newXPath();
InputSource inputSource = new InputSource(is);
xpath.setNamespaceContext(ihcNamespaceContext);
return (NodeList) xpath.evaluate(xpathExpression, inputSource, XPathConstants.NODESET);
}
}
public static String getValueFromNode(Node n, String value) throws XPathExpressionException {
return getSpeficValueFromNode(n, XPathUtils.createIgnoreNameSpaceSyntaxExpr(value));
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.ws.exeptions;
/**
* Exception for conversion errors.
*
* @author Pauli Anttila - Initial contribution
*/
public class ConversionException extends Exception {
private static final long serialVersionUID = 1;
public ConversionException() {
}
public ConversionException(String message) {
super(message);
}
public ConversionException(String message, Throwable cause) {
super(message, cause);
}
public ConversionException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.ws.exeptions;
/**
* Exception for handling communication errors to controller.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcExecption extends Exception {
private static final long serialVersionUID = -8048415193494625295L;
public IhcExecption() {
}
public IhcExecption(String message) {
super(message);
}
public IhcExecption(String message, Throwable cause) {
super(message, cause);
}
public IhcExecption(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,147 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws.http;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Custom HTTP connection pool, which install all-trusting trust manager.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcConnectionPool {
private final Logger logger = LoggerFactory.getLogger(IhcConnectionPool.class);
/**
* Controller TLS certificate is self signed, which means that certificate
* need to be manually added to java key store as a trusted certificate.
* This is special SSL context which will be configured to trust all
* certificates and manual work is not required.
*/
private SSLContext sslContext;
/** Holds and share cookie information (session id) from authentication procedure */
private CookieStore cookieStore;
private HttpClientBuilder httpClientBuilder;
private HttpClientContext localContext;
public IhcConnectionPool() {
init();
}
private void init() {
// Create a local instance of cookie store
cookieStore = new BasicCookieStore();
// Create local HTTP context
localContext = HttpClientContext.create();
// Bind custom cookie store to the local context
localContext.setCookieStore(cookieStore);
httpClientBuilder = HttpClientBuilder.create();
// Setup a Trust Strategy that allows all certificates.
logger.debug("Initialize SSL context");
// Create a trust manager that does not validate certificate chains, but accept all.
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
logger.trace("Trusting server cert: {}", certs[0].getIssuerDN());
}
} };
// Install the all-trusting trust manager
try {
// Controller supports only SSLv3 and TLSv1
sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, trustAllCerts, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
logger.warn("Exception", e);
} catch (KeyManagementException e) {
logger.warn("Exception", e);
}
// Controller accepts only HTTPS connections and because normally IP address are used on home network rather
// than DNS names, create custom host name verifier.
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
logger.trace("HostnameVerifier: arg0 = {}, arg1 = {}", arg0, arg1);
return true;
}
};
// Create an SSL Socket Factory, to use our weakened "trust strategy"
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[] { "TLSv1" }, null, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", sslSocketFactory).build();
// Create connection-manager using our Registry. Allows multi-threaded use
PoolingHttpClientConnectionManager connMngr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// Increase max connection counts
connMngr.setMaxTotal(20);
connMngr.setDefaultMaxPerRoute(6);
httpClientBuilder.setConnectionManager(connMngr);
}
public HttpClient getHttpClient() {
return httpClientBuilder.build();
}
public HttpClientContext getHttpContext() {
return localContext;
}
}

View File

@@ -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.ihc.internal.ws.http;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.http.HttpResponse;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple HTTP Client for IHC / ELKO LS Controller connection purposes.
*
* @author Pauli Anttila - Initial contribution
*/
public abstract class IhcHttpsClient {
private final Logger logger = LoggerFactory.getLogger(IhcHttpsClient.class);
private IhcConnectionPool ihcConnectionPool;
private HttpClient client;
private HttpPost postReq;
private AtomicInteger counter = new AtomicInteger();
public IhcHttpsClient(IhcConnectionPool ihcConnectionPool) {
this.ihcConnectionPool = ihcConnectionPool;
}
/**
* Init HTTP connection.
*
* @param url Url to connect.
*/
private void initConnection(String url) throws IhcExecption {
if (client == null) {
client = ihcConnectionPool.getHttpClient();
}
postReq = new HttpPost(url);
}
/**
* Send HTTP request and wait response from the server.
*
*/
public String sendQuery(String url, Map<String, String> requestProperties, String query, int timeout)
throws IhcExecption {
initConnection(url);
setRequestProperty(requestProperties);
try {
return sendQ(query, timeout);
} catch (NoHttpResponseException | SocketTimeoutException e) {
try {
logger.debug("No response received, resend query");
return sendQ(query, timeout);
} catch (IOException ee) {
throw new IhcExecption(ee);
}
} catch (IOException e) {
throw new IhcExecption(e);
}
}
private String sendQ(String query, int timeout)
throws ClientProtocolException, IOException, NoHttpResponseException {
postReq.setEntity(new StringEntity(query, StandardCharsets.UTF_8.name()));
postReq.addHeader("content-type", "text/xml");
int requestId = 0;
if (logger.isTraceEnabled()) {
requestId = counter.getAndIncrement();
logger.trace("Send query (url={}, connectionPool={}, clientId={} requestId={}, timeout={}, headers={}): {}",
postReq.getURI(), ihcConnectionPool.hashCode(), client.hashCode(), requestId, timeout,
postReq.getAllHeaders(), query);
}
final RequestConfig params = RequestConfig.custom().setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).build();
postReq.setConfig(params);
// Execute POST
LocalDateTime start = LocalDateTime.now();
try {
HttpResponse response = client.execute(postReq, ihcConnectionPool.getHttpContext());
String resp = EntityUtils.toString(response.getEntity());
if (logger.isTraceEnabled()) {
logger.trace("Received response (connectionPool={}, clientId={} requestId={}, in {}, headers={}): {}",
ihcConnectionPool.hashCode(), client.hashCode(), requestId,
Duration.between(start, LocalDateTime.now()), response.getAllHeaders(), resp);
}
return resp;
} catch (Exception e) {
if (logger.isTraceEnabled()) {
logger.trace("Exception occured (connectionPool={}, clientId={} requestId={}, in {}): {}",
ihcConnectionPool.hashCode(), client.hashCode(), requestId,
Duration.between(start, LocalDateTime.now()), e.getMessage());
}
throw (e);
}
}
/**
* Set request properties.
*
*/
private void setRequestProperty(Map<String, String> requestProperties) {
if (postReq != null && requestProperties != null) {
requestProperties.forEach((k, v) -> postReq.setHeader(k, v));
}
}
}

View File

@@ -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.ihc.internal.ws.projectfile;
/**
* Class to store IHC / ELKO LS controller's enum value information.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcEnumValue {
private final int id;
private final String name;
public IhcEnumValue(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return String.format("[ id=%d, name='%s' ]", id, name);
}
}

View File

@@ -0,0 +1,173 @@
/**
* 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.ihc.internal.ws.projectfile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.FileUtils;
import org.openhab.binding.ihc.internal.ws.datatypes.WSProjectInfo;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Generic methods related to IHC / ELKO project file handling.
*
* @author Pauli Anttila - Initial contribution
*/
public class ProjectFileUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(ProjectFileUtils.class);
/**
* Read IHC project file from local file.
*
* @param filePath File to read.
* @return XML document.
* @throws IhcExecption when file read fails.
*/
public static Document readFromFile(String filePath) throws IhcExecption {
File fXmlFile = new File(filePath);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
return doc;
} catch (IOException | ParserConfigurationException | SAXException e) {
throw new IhcExecption(e);
}
}
/**
* Save IHC project file to local file.
*
* @param filePath File path.
* @param data Data to write
* @throws IhcExecption when file write fails.
*/
public static void saveToFile(String filePath, byte[] data) throws IhcExecption {
try {
FileUtils.writeByteArrayToFile(new File(filePath), data);
} catch (IOException e) {
throw new IhcExecption(e);
}
}
/**
* Convert bytes to XML document.
*
* @return XML document or null if conversion fails.
*/
public static Document converteBytesToDocument(byte[] data) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
try {
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(data));
} catch (ParserConfigurationException | SAXException | IOException e) {
LOGGER.warn("Error occured when trying to convert data to XML, reason {}", e.getMessage());
}
return null;
}
/**
* Compare XML document header information to project info.
*
* @return true if information is equal and false if not.
*/
public static boolean projectEqualsToControllerProject(Document projectfile, WSProjectInfo projectInfo) {
if (projectInfo != null) {
try {
NodeList nodes = projectfile.getElementsByTagName("modified");
if (nodes.getLength() == 1) {
Element node = (Element) nodes.item(0);
int year = Integer.parseInt(node.getAttribute("year"));
int month = Integer.parseInt(node.getAttribute("month"));
int day = Integer.parseInt(node.getAttribute("day"));
int hour = Integer.parseInt(node.getAttribute("hour"));
int minute = Integer.parseInt(node.getAttribute("minute"));
LOGGER.debug("Project file from file, date: {}.{}.{} {}:{}", year, month, day, hour, minute);
LOGGER.debug("Project file in controller, date: {}.{}.{} {}:{}",
projectInfo.getLastmodified().getYear(),
projectInfo.getLastmodified().getMonthWithJanuaryAsOne(),
projectInfo.getLastmodified().getDay(), projectInfo.getLastmodified().getHours(),
projectInfo.getLastmodified().getMinutes());
if (projectInfo.getLastmodified().getYear() == year
&& projectInfo.getLastmodified().getMonthWithJanuaryAsOne() == month
&& projectInfo.getLastmodified().getDay() == day
&& projectInfo.getLastmodified().getHours() == hour
&& projectInfo.getLastmodified().getMinutes() == minute) {
return true;
}
}
} catch (RuntimeException e) {
LOGGER.debug("Error occured during project file date comparasion, reason {}.", e.getMessage(), e);
// There is no documentation available for XML content. This is part of inessential feature, so do
// nothing, but return false
}
}
return false;
}
/**
* Parse all enum values from IHC project file.
*
* @param doc IHC project file in XML format.
* @return enum dictionary.
*/
public static Map<Integer, List<IhcEnumValue>> parseEnums(Document doc) {
Map<Integer, List<IhcEnumValue>> enumDictionary = new HashMap<>();
if (doc != null) {
NodeList nodes = doc.getElementsByTagName("enum_definition");
// iterate enum definitions from project
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
int typedefId = Integer.parseInt(element.getAttribute("id").replace("_0x", ""), 16);
String enumName = element.getAttribute("name");
List<IhcEnumValue> enumValues = new ArrayList<>();
NodeList name = element.getElementsByTagName("enum_value");
for (int j = 0; j < name.getLength(); j++) {
Element val = (Element) name.item(j);
int id = Integer.parseInt(val.getAttribute("id").replace("_0x", ""), 16);
String n = val.getAttribute("name");
IhcEnumValue enumVal = new IhcEnumValue(id, n);
enumValues.add(enumVal);
}
LOGGER.debug("Enum values found: typedefId={}, name={}: {}", typedefId, enumName, enumValues);
enumDictionary.put(typedefId, enumValues);
}
}
return enumDictionary;
}
}

View File

@@ -0,0 +1,33 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSBooleanValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSBooleanValue extends WSResourceValue {
public final boolean value;
public WSBooleanValue(int resourceID, boolean value) {
super(resourceID);
this.value = value;
}
@Override
public String toString() {
return String.format("[resourceId=%d, value=%b]", super.resourceID, value);
}
}

View File

@@ -0,0 +1,37 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws.resourcevalues;
/**
* Class for WSDateValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSDateValue extends WSResourceValue {
public final short year;
public final byte month;
public final byte day;
public WSDateValue(int resourceID, short year, byte month, byte day) {
super(resourceID);
this.year = year;
this.month = month;
this.day = day;
}
@Override
public String toString() {
return String.format("[resourceId=%d, year=%d, month=%d, day=%d]", super.resourceID, year, month, day);
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSEnumValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSEnumValue extends WSResourceValue {
public final int definitionTypeID;
public final int enumValueID;
public final String enumName;
public WSEnumValue(int resourceID, int definitionTypeID, int enumValueID, String enumName) {
super(resourceID);
this.definitionTypeID = definitionTypeID;
this.enumValueID = enumValueID;
this.enumName = enumName;
}
@Override
public String toString() {
return String.format("[resourceId=%d, definitionTypeID=%d, enumValueID=%d, enumName=%s]", super.resourceID,
definitionTypeID, enumValueID, enumName);
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSFloatingPointValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSFloatingPointValue extends WSResourceValue {
public final double maximumValue;
public final double minimumValue;
public final double value;
public WSFloatingPointValue(int resourceID, double value, double minimumValue, double maximumValue) {
super(resourceID);
this.value = value;
this.minimumValue = minimumValue;
this.maximumValue = maximumValue;
}
@Override
public String toString() {
return String.format("[resourceId=%d, value=%.2f, min=%.2f, max=%.2f]", super.resourceID, value, minimumValue,
maximumValue);
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSIntegerValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSIntegerValue extends WSResourceValue {
public final int value;
public final int maximumValue;
public final int minimumValue;
public WSIntegerValue(int resourceID, int value, int minimumValue, int maximumValue) {
super(resourceID);
this.value = value;
this.minimumValue = minimumValue;
this.maximumValue = maximumValue;
}
@Override
public String toString() {
return String.format("[resourceId=%d, value=%d, min=%d, max=%d]", super.resourceID, value, minimumValue,
maximumValue);
}
}

View File

@@ -0,0 +1,33 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSPhoneNumberValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSPhoneNumberValue extends WSResourceValue {
public final String number;
public WSPhoneNumberValue(int resourceID, String number) {
super(resourceID);
this.number = number;
}
@Override
public String toString() {
return String.format("[resourceId=%d, number=%s]", super.resourceID, number);
}
}

View File

@@ -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.ihc.internal.ws.resourcevalues;
/**
* Class for WSResourceValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSResourceValue {
public final int resourceID;
public WSResourceValue(int resourceID) {
this.resourceID = resourceID;
}
@Override
public String toString() {
return String.format("[resourceId=%d]", resourceID);
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSSceneDimmerValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSSceneDimmerValue extends WSResourceValue {
public final int delayTime;
public final int dimmerPercentage;
public final int rampTime;
public WSSceneDimmerValue(int resourceID, int delayTime, int dimmerPercentage, int rampTime) {
super(resourceID);
this.delayTime = delayTime;
this.dimmerPercentage = dimmerPercentage;
this.rampTime = rampTime;
}
@Override
public String toString() {
return String.format("[resourceId=%d, delayTime=%d, dimmerPercentage=%d, rampTime=%d]", super.resourceID,
delayTime, dimmerPercentage, rampTime);
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSSceneRelayValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSSceneRelayValue extends WSResourceValue {
public final int delayTime;
public final boolean relayValue;
public WSSceneRelayValue(int resourceID, int delayTime, boolean relayValue) {
super(resourceID);
this.delayTime = delayTime;
this.relayValue = relayValue;
}
@Override
public String toString() {
return String.format("[resourceId=%d, value=%b, delayTime=%d]", super.resourceID, relayValue, delayTime);
}
}

View File

@@ -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.ihc.internal.ws.resourcevalues;
/**
* Class for WSSceneShutterSimpleValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSSceneShutterSimpleValue extends WSResourceValue {
public final int delayTime;
public final boolean shutterPositionIsUp;
public WSSceneShutterSimpleValue(int resourceID, int delayTime, boolean shutterPositionIsUp) {
super(resourceID);
this.delayTime = delayTime;
this.shutterPositionIsUp = shutterPositionIsUp;
}
@Override
public String toString() {
return String.format("[resourceId=%d, shutterPositionIsUp=%b, delayTime=%d]", super.resourceID,
shutterPositionIsUp, delayTime);
}
}

View File

@@ -0,0 +1,38 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSTimeValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSTimeValue extends WSResourceValue {
public final int hours;
public final int minutes;
public final int seconds;
public WSTimeValue(int resourceID, int hours, int minutes, int seconds) {
super(resourceID);
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
}
@Override
public String toString() {
return String.format("[resourceId=%d, hours=%d, minutes=%d, seconds=%d]", super.resourceID, hours, minutes,
seconds);
}
}

View File

@@ -0,0 +1,33 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSTimerValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSTimerValue extends WSResourceValue {
public final long milliseconds;
public WSTimerValue(int resourceID, long milliseconds) {
super(resourceID);
this.milliseconds = milliseconds;
}
@Override
public String toString() {
return String.format("[resourceId=%d, milliseconds=%b]", super.resourceID, milliseconds);
}
}

View File

@@ -0,0 +1,33 @@
/**
* 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.ihc.internal.ws.resourcevalues;
/**
* Class for WSWeekdayValue complex type.
*
* @author Pauli Anttila - Initial contribution
*/
public class WSWeekdayValue extends WSResourceValue {
public final int weekdayNumber;
public WSWeekdayValue(int resourceID, int weekdayNumber) {
super(resourceID);
this.weekdayNumber = weekdayNumber;
}
@Override
public String toString() {
return String.format("[resourceId=%d, weekdayNumber=%d]", super.resourceID, weekdayNumber);
}
}

View File

@@ -0,0 +1,87 @@
/**
* 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.ihc.internal.ws.services;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.xpath.XPathExpressionException;
import org.openhab.binding.ihc.internal.ws.datatypes.WSRFDevice;
import org.openhab.binding.ihc.internal.ws.datatypes.XPathUtils;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Class to handle IHC / ELKO LS Controller's airlink management service.
*
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcAirlinkManagementService extends IhcBaseService {
public IhcAirlinkManagementService(String host, int timeout, IhcConnectionPool ihcConnectionPool) {
super(ihcConnectionPool, timeout, host, "AirlinkManagementService");
}
/**
* Query system information from the controller.
*
* @return system information.
* @throws IhcExecption
*/
public synchronized List<WSRFDevice> getDetectedDeviceList() throws IhcExecption {
String response = sendSoapQuery("getDetectedDeviceList", EMPTY_QUERY);
List<WSRFDevice> resourceValueList = new ArrayList<>();
try {
NodeList nodeList = XPathUtils.parseList(response,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getDetectedDeviceList1/ns1:arrayItem");
if (nodeList != null) {
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node != null) {
WSRFDevice dev = parseResourceValue(node);
if (dev != null) {
resourceValueList.add(dev);
}
}
}
} else {
throw new IhcExecption("Illegal resource value notification response received");
}
return resourceValueList;
} catch (IOException | XPathExpressionException | NumberFormatException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
private WSRFDevice parseResourceValue(Node n) throws XPathExpressionException, NumberFormatException {
try {
int batteryLevel = Integer.parseInt(XPathUtils.getValueFromNode(n, "batteryLevel"));
int deviceType = Integer.parseInt(XPathUtils.getValueFromNode(n, "deviceType"));
long serialNumber = Long.parseLong(XPathUtils.getValueFromNode(n, "serialNumber"));
int signalStrength = Integer.parseInt(XPathUtils.getValueFromNode(n, "signalStrength"));
int version = Integer.parseInt(XPathUtils.getValueFromNode(n, "version"));
boolean detected = Boolean.valueOf(XPathUtils.getValueFromNode(n, "detected"));
return new WSRFDevice(batteryLevel, deviceType, serialNumber, signalStrength, version, detected);
} catch (NumberFormatException e) {
return null;
}
}
}

View File

@@ -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.ihc.internal.ws.services;
import org.openhab.binding.ihc.internal.ws.datatypes.WSLoginResult;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class to handle IHC / ELKO LS Controller's authentication service.
*
* Communication to controller need to be authenticated. On successful
* authentication Controller returns session id which need to be used further
* communication.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcAuthenticationService extends IhcBaseService {
private final Logger logger = LoggerFactory.getLogger(IhcAuthenticationService.class);
public IhcAuthenticationService(String host, int timeout, IhcConnectionPool ihcConnectionPool) {
super(ihcConnectionPool, timeout, host, "AuthenticationService");
}
public WSLoginResult authenticate(String username, String password, String application) throws IhcExecption {
logger.debug("Authenticate");
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
+ " <soapenv:Body>\n"
+ " <authenticate1 xmlns=\"utcs\">\n"
+ " <password>%s</password>\n"
+ " <username>%s</username>\n"
+ " <application>%s</application>\n"
+ " </authenticate1>\n"
+ " </soapenv:Body>\n"
+ "</soapenv:Envelope>";
// @formatter:on
String query = String.format(soapQuery, password, username, application);
String response = sendSoapQuery(null, query);
return new WSLoginResult().parseXMLData(response);
}
}

View File

@@ -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.ihc.internal.ws.services;
import java.util.HashMap;
import java.util.Map;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
import org.openhab.binding.ihc.internal.ws.http.IhcHttpsClient;
/**
* Base class for all IHC / ELKO services.
*
*
* @author Pauli Anttila - Initial contribution
*/
public abstract class IhcBaseService extends IhcHttpsClient {
// @formatter:off
protected static final String EMPTY_QUERY =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soapenv:Body>\n"
+ " </soapenv:Body>\n"
+ "</soapenv:Envelope>";
// @formatter:on
private String url;
private int timeout;
public IhcBaseService(IhcConnectionPool ihcConnectionPool, int timeout, String host, String service) {
super(ihcConnectionPool);
this.timeout = timeout;
this.url = createUrl(host, service);
}
private String createUrl(String host, String service) {
return "https://" + host + "/ws/" + service;
}
protected String sendSoapQuery(String soapAction, String query) throws IhcExecption {
return sendSoapQuery(soapAction, query, timeout);
}
protected String sendSoapQuery(String soapAction, String query, int timeout) throws IhcExecption {
Map<String, String> reqProperties = null;
if (soapAction != null) {
reqProperties = new HashMap<>();
reqProperties.put("SOAPAction", soapAction);
}
return sendQuery(url, reqProperties, query, timeout);
}
protected int getTimeout() {
return timeout;
}
}

View File

@@ -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.ihc.internal.ws.services;
import org.openhab.binding.ihc.internal.ws.datatypes.WSSystemInfo;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
/**
* Class to handle IHC / ELKO LS Controller's configuration service.
*
* Controller service is used to fetch system information from the controller.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcConfigurationService extends IhcBaseService {
public IhcConfigurationService(String host, int timeout, IhcConnectionPool ihcConnectionPool) {
super(ihcConnectionPool, timeout, host, "ConfigurationService");
}
/**
* Query system information from the controller.
*
* @return system information.
* @throws IhcExecption
*/
public synchronized WSSystemInfo getSystemInfo() throws IhcExecption {
String response = sendSoapQuery("getSystemInfo", EMPTY_QUERY);
return new WSSystemInfo().parseXMLData(response);
}
}

View File

@@ -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.ihc.internal.ws.services;
import org.openhab.binding.ihc.internal.ws.datatypes.WSControllerState;
import org.openhab.binding.ihc.internal.ws.datatypes.WSFile;
import org.openhab.binding.ihc.internal.ws.datatypes.WSNumberOfSegments;
import org.openhab.binding.ihc.internal.ws.datatypes.WSProjectInfo;
import org.openhab.binding.ihc.internal.ws.datatypes.WSSegmentationSize;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
/**
* Class to handle IHC / ELKO LS Controller's controller service.
*
* Controller service is used to fetch information from the controller.
* E.g. Project file or controller status.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcControllerService extends IhcBaseService {
public IhcControllerService(String host, int timeout, IhcConnectionPool ihcConnectionPool) {
super(ihcConnectionPool, timeout, host, "ControllerService");
}
/**
* Query project information from the controller.
*
* @return project information.
* @throws IhcExecption
*/
public synchronized WSProjectInfo getProjectInfo() throws IhcExecption {
String response = sendSoapQuery("getProjectInfo", EMPTY_QUERY);
return new WSProjectInfo().parseXMLData(response);
}
/**
* Query number of segments project contains.
*
* @return number of segments.
* @throws IhcExecption
*/
public synchronized int getProjectNumberOfSegments() throws IhcExecption {
String response = sendSoapQuery("getIHCProjectNumberOfSegments", EMPTY_QUERY);
return new WSNumberOfSegments().parseXMLData(response).getNumberOfSegments();
}
/**
* Query segmentation size.
*
* @return segmentation size in bytes.
* @throws IhcExecption
*/
public synchronized int getProjectSegmentationSize() throws IhcExecption {
String response = sendSoapQuery("getIHCProjectSegmentationSize", EMPTY_QUERY);
return new WSSegmentationSize().parseXMLData(response).getSegmentationSize();
}
/**
* Query project segment data.
*
* @param index segments index.
* @param major project major revision number.
* @param minor project minor revision number.
* @return segments data.
* @throws IhcExecption
*/
public synchronized WSFile getProjectSegment(int index, int major, int minor) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <ns1:getIHCProjectSegment1 xmlns:ns1=\"utcs\" xsi:type=\"xsd:int\">%s</ns1:getIHCProjectSegment1>\n"
+ " <ns2:getIHCProjectSegment2 xmlns:ns2=\"utcs\" xsi:type=\"xsd:int\">%s</ns2:getIHCProjectSegment2>\n"
+ " <ns3:getIHCProjectSegment3 xmlns:ns3=\"utcs\" xsi:type=\"xsd:int\">%s</ns3:getIHCProjectSegment3>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, index, major, minor);
String response = sendSoapQuery("getIHCProjectSegment", query);
return new WSFile().parseXMLData(response);
}
/**
* Query controller current state.
*
* @return controller's current state.
* @throws IhcExecption
*/
public synchronized WSControllerState getControllerState() throws IhcExecption {
String response = sendSoapQuery("getState", EMPTY_QUERY);
return new WSControllerState().parseXMLData(response);
}
/**
* Wait controller state change notification.
*
* @param previousState Previous controller state.
* @param timeoutInSeconds How many seconds to wait notifications.
* @return current controller state.
* @throws IhcExecption
*/
public synchronized WSControllerState waitStateChangeNotifications(WSControllerState previousState,
int timeoutInSeconds) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soapenv:Body>\n"
+ " <ns1:waitForControllerStateChange1 xmlns:ns1=\"utcs\" xsi:type=\"ns1:WSControllerState\">\n"
+ " <ns1:state xsi:type=\"xsd:string\">%s</ns1:state>\n"
+ " </ns1:waitForControllerStateChange1>\n"
+ " <ns2:waitForControllerStateChange2 xmlns:ns2=\"utcs\" xsi:type=\"xsd:int\">%s</ns2:waitForControllerStateChange2>\n"
+ " </soapenv:Body>\n"
+ "</soapenv:Envelope>";
// @formatter:on
String query = String.format(soapQuery, previousState.getState(), timeoutInSeconds);
String response = sendSoapQuery("waitForControllerStateChange", query, getTimeout() + timeoutInSeconds * 1000);
return new WSControllerState().parseXMLData(response);
}
}

View File

@@ -0,0 +1,470 @@
/**
* 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.ihc.internal.ws.services;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.xml.xpath.XPathExpressionException;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.ihc.internal.ws.datatypes.XPathUtils;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSDateValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSFloatingPointValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimeValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSWeekdayValue;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Class to handle IHC / ELKO LS Controller's resource interaction service.
*
* Service is used to fetch or update resource values from/to controller.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcResourceInteractionService extends IhcBaseService {
public IhcResourceInteractionService(String host, int timeout, IhcConnectionPool ihcConnectionPool) {
super(ihcConnectionPool, timeout, host, "ResourceInteractionService");
}
/**
* Query resource value from controller.
*
* @param resoureId Resource Identifier.
* @return Resource value.
*/
public WSResourceValue resourceQuery(int resoureId) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soapenv:Body>\n"
+ " <ns1:getRuntimeValue1 xmlns:ns1=\"utcs\">%s</ns1:getRuntimeValue1>\n"
+ " </soapenv:Body>\n"
+ "</soapenv:Envelope>";
// @formatter:on
String query = String.format(soapQuery, String.valueOf(resoureId));
String response = sendSoapQuery(null, query);
NodeList nodeList;
try {
nodeList = XPathUtils.parseList(response, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:getRuntimeValue2");
if (nodeList != null && nodeList.getLength() == 1) {
WSResourceValue val = parseResourceValue(nodeList.item(0));
if (val != null && val.resourceID == resoureId) {
return val;
} else {
throw new IhcExecption("No resource id found");
}
} else {
throw new IhcExecption("No resource value found");
}
} catch (XPathExpressionException | NumberFormatException | IOException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
private WSResourceValue parseResourceValue(Node n) throws XPathExpressionException, NumberFormatException {
// parse resource id
String resourceId = XPathUtils.getSpeficValueFromNode(n, "ns1:resourceID");
if (StringUtils.isNotBlank(resourceId)) {
int id = Integer.parseInt(resourceId);
// Parse floating point value
String floatingPointValue = getValue(n, "floatingPointValue");
if (StringUtils.isNotBlank(floatingPointValue)) {
String min = getValue(n, "minimumValue");
String max = getValue(n, "maximumValue");
return new WSFloatingPointValue(id, Double.valueOf(floatingPointValue), Double.valueOf(min),
Double.valueOf(max));
}
// Parse boolean value
String value = getValue(n, "value");
if (StringUtils.isNotBlank(value)) {
return new WSBooleanValue(id, Boolean.valueOf(value));
}
// Parse integer value
String integer = getValue(n, "integer");
if (StringUtils.isNotBlank(integer)) {
String min = getValue(n, "minimumValue");
String max = getValue(n, "maximumValue");
return new WSIntegerValue(id, Integer.valueOf(integer), Integer.valueOf(min), Integer.valueOf(max));
}
// Parse timer value
String milliseconds = getValue(n, "milliseconds");
if (StringUtils.isNotBlank(milliseconds)) {
return new WSTimerValue(id, Integer.valueOf(milliseconds));
}
// Parse time value
String hours = getValue(n, "hours");
if (StringUtils.isNotBlank(hours)) {
String minutes = getValue(n, "minutes");
String seconds = getValue(n, "seconds");
return new WSTimeValue(id, Integer.valueOf(hours), Integer.valueOf(minutes), Integer.valueOf(seconds));
}
// Parse date value
String year = getValue(n, "year");
if (StringUtils.isNotBlank(year)) {
String month = getValue(n, "month");
String day = getValue(n, "day");
return new WSDateValue(id, Short.valueOf(year), Byte.valueOf(month), Byte.valueOf(day));
}
// Parse enum value
String definitionTypeID = getValue(n, "definitionTypeID");
if (StringUtils.isNotBlank(definitionTypeID)) {
String enumValueID = getValue(n, "enumValueID");
String enumName = getValue(n, "enumName");
return new WSEnumValue(id, Integer.valueOf(definitionTypeID), Integer.valueOf(enumValueID), enumName);
}
// Parse week day value
value = getValue(n, "weekdayNumber");
if (StringUtils.isNotBlank(value)) {
return new WSWeekdayValue(id, Integer.valueOf(value));
}
// Unknown value type
throw new IllegalArgumentException("Unsupported value type");
}
return null;
}
private String getValue(Node n, String value) throws XPathExpressionException {
return XPathUtils.getSpeficValueFromNode(n, "ns1:value/" + XPathUtils.createIgnoreNameSpaceSyntaxExpr(value));
}
/**
* Update resource value to controller.
*
*
* @param value Resource value.
* @return True if value is successfully updated.
*/
public boolean resourceUpdate(WSResourceValue value) throws IhcExecption {
boolean retval = false;
if (value instanceof WSFloatingPointValue) {
retval = resourceUpdate((WSFloatingPointValue) value);
} else if (value instanceof WSBooleanValue) {
retval = resourceUpdate((WSBooleanValue) value);
} else if (value instanceof WSIntegerValue) {
retval = resourceUpdate((WSIntegerValue) value);
} else if (value instanceof WSTimerValue) {
retval = resourceUpdate((WSTimerValue) value);
} else if (value instanceof WSWeekdayValue) {
retval = resourceUpdate((WSWeekdayValue) value);
} else if (value instanceof WSEnumValue) {
retval = resourceUpdate((WSEnumValue) value);
} else if (value instanceof WSTimeValue) {
retval = resourceUpdate((WSTimeValue) value);
} else if (value instanceof WSDateValue) {
retval = resourceUpdate((WSDateValue) value);
} else {
throw new IhcExecption("Unsupported value type " + value.getClass().toString());
}
return retval;
}
public boolean resourceUpdate(WSBooleanValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSBooleanValue\">\n"
+ " <q1:value>%s</q1:value>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.value ? "true" : "false", value.resourceID);
return doResourceUpdate(query);
}
public boolean resourceUpdate(WSFloatingPointValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSFloatingPointValue\">\n"
+ " <q1:maximumValue>%s</q1:maximumValue>\n"
+ " <q1:minimumValue>%s</q1:minimumValue>\n"
+ " <q1:floatingPointValue>%s</q1:floatingPointValue>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.maximumValue, value.minimumValue, value.value, value.resourceID);
return doResourceUpdate(query);
}
public boolean resourceUpdate(WSIntegerValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSIntegerValue\">\n"
+ " <q1:maximumValue>%s</q1:maximumValue>\n"
+ " <q1:minimumValue>%s</q1:minimumValue>\n"
+ " <q1:integer>%s</q1:integer>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.maximumValue, value.minimumValue, value.value, value.resourceID);
return doResourceUpdate(query);
}
public boolean resourceUpdate(WSTimerValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSTimerValue\">\n"
+ " <q1:milliseconds>%s</q1:milliseconds>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.milliseconds, value.resourceID);
return doResourceUpdate(query);
}
public boolean resourceUpdate(WSWeekdayValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSWeekdayValue\">\n"
+ " <q1:weekdayNumber>%s</q1:weekdayNumber>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.weekdayNumber, value.resourceID);
return doResourceUpdate(query);
}
public boolean resourceUpdate(WSEnumValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSEnumValue\">\n"
+ " <q1:definitionTypeID>%s</q1:definitionTypeID>\n"
+ " <q1:enumValueID>%s</q1:enumValueID>\n"
+ " <q1:enumName>%s</q1:enumName>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.definitionTypeID, value.enumValueID, value.enumName,
value.resourceID);
return doResourceUpdate(query);
}
public boolean resourceUpdate(WSTimeValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSTimeValue\">\n"
+ " <q1:hours>%s</q1:hours>\n"
+ " <q1:minutes>%s</q1:minutes>\n"
+ " <q1:seconds>%s</q1:seconds>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.hours, value.minutes, value.seconds, value.resourceID);
return doResourceUpdate(query);
}
public boolean resourceUpdate(WSDateValue value) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <setResourceValue1 xmlns=\"utcs\">\n"
+ " <value xmlns:q1=\"utcs.values\" xsi:type=\"q1:WSDateValue\">\n"
+ " <q1:month>%s</q1:month>\n"
+ " <q1:year>%s</q1:year>\n"
+ " <q1:day>%s</q1:day>\n"
+ " </value>\n"
+ " <resourceID>%s</resourceID>\n"
+ " <isValueRuntime>true</isValueRuntime>\n"
+ " </setResourceValue1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = String.format(soapQuery, value.month, value.year, value.day, value.resourceID);
return doResourceUpdate(query);
}
private boolean doResourceUpdate(String query) throws IhcExecption {
String response = sendSoapQuery(null, query);
try {
return Boolean.parseBoolean(
XPathUtils.parseXMLValue(response, "/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:setResourceValue2"));
} catch (IOException | XPathExpressionException e) {
throw new IhcExecption(e);
}
}
/**
* Enable resources runtime value notifications.
*
* @param resourceIdList List of resource Identifiers.
* @return True is connection successfully opened.
*/
public void enableRuntimeValueNotifications(Set<Integer> resourceIdList) throws IhcExecption {
// @formatter:off
final String soapQueryPrefix =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n"
+ " <soap:Body>\n"
+ " <enableRuntimeValueNotifications1 xmlns=\"utcs\">\n";
final String soapQuerySuffix =
" </enableRuntimeValueNotifications1>\n"
+ " </soap:Body>\n"
+ "</soap:Envelope>";
// @formatter:on
String query = soapQueryPrefix;
for (int i : resourceIdList) {
query += " <xsd:arrayItem>" + i + "</xsd:arrayItem>\n";
}
query += soapQuerySuffix;
sendSoapQuery(null, query);
}
/**
* Wait runtime value notifications.
*
* Runtime value notification should firstly be activated by
* enableRuntimeValueNotifications function.
*
* @param timeoutInSeconds How many seconds to wait notifications.
* @return List of received runtime value notifications.
* @throws SocketTimeoutException
* @throws IhcTimeoutExecption
*/
public List<WSResourceValue> waitResourceValueNotifications(int timeoutInSeconds) throws IhcExecption {
// @formatter:off
final String soapQuery =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:utcs=\"utcs\">\n"
+ " <soapenv:Body>\n"
+ " <utcs:waitForResourceValueChanges1>%s</utcs:waitForResourceValueChanges1>\n"
+ " </soapenv:Body>\n"
+ "</soapenv:Envelope>";
// @formatter:on
String query = String.format(soapQuery, timeoutInSeconds);
String response = sendSoapQuery(null, query, getTimeout() + timeoutInSeconds * 1000);
List<WSResourceValue> resourceValueList = new ArrayList<>();
try {
NodeList nodeList = XPathUtils.parseList(response,
"/SOAP-ENV:Envelope/SOAP-ENV:Body/ns1:waitForResourceValueChanges2/ns1:arrayItem");
if (nodeList != null) {
if (nodeList.getLength() == 1) {
String resourceId = XPathUtils.getSpeficValueFromNode(nodeList.item(0), "ns1:resourceID");
if (resourceId == null || resourceId.isEmpty()) {
// IHC controller indicates timeout, return empty list
return resourceValueList;
}
}
for (int i = 0; i < nodeList.getLength(); i++) {
WSResourceValue newVal = parseResourceValue(nodeList.item(i));
if (newVal != null) {
resourceValueList.add(newVal);
}
}
} else {
throw new IhcExecption("Illegal resource value notification response received");
}
return resourceValueList;
} catch (XPathExpressionException | NumberFormatException | IOException e) {
throw new IhcExecption("Error occured during XML data parsing", e);
}
}
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws.services;
import org.openhab.binding.ihc.internal.ws.datatypes.WSTimeManagerSettings;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
/**
* Class to handle IHC / ELKO LS Controller's time service.
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcTimeService extends IhcBaseService {
public IhcTimeService(String host, int timeout, IhcConnectionPool ihcConnectionPool) {
super(ihcConnectionPool, timeout, host, "TimeManagerService");
}
/**
* Query time settings from the controller.
*
* @return time settings.
* @throws IhcExecption
*/
public synchronized WSTimeManagerSettings getTimeSettings() throws IhcExecption {
String response = sendSoapQuery("getSettings", EMPTY_QUERY);
return new WSTimeManagerSettings().parseXMLData(response);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="ihc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>IHC / ELKO Binding</name>
<description>Binding to communicate IHC / ELKO controller</description>
<author>Pauli Anttila</author>
</binding:binding>

View File

@@ -0,0 +1,291 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="ihc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<channel-type id="controller-state" advanced="true">
<item-type>String</item-type>
<label>Controller State</label>
<description>Displays IHC / ELKO controller state</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="controller-uptime" advanced="true">
<item-type>Number</item-type>
<label>Controller Uptime</label>
<description>Displays IHC / ELKO controller uptime in seconds</description>
<state readOnly="true" pattern="%.3f sec"></state>
</channel-type>
<channel-type id="controller-time" advanced="true">
<item-type>DateTime</item-type>
<label>Controller Date and Time</label>
<description>Displays IHC / ELKO controller date and time</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="switch">
<item-type>Switch</item-type>
<label>Generic Switch</label>
<description>Generic switch channel</description>
<state readOnly="false"></state>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="direction" type="text" required="false">
<label>Channel Direction</label>
<description>Direction of the channel. By default, channel is synchronized in both directions.</description>
<default>ReadWrite</default>
<options>
<option value="ReadWrite">Read Write</option>
<option value="WriteOnly">Write only</option>
<option value="ReadOnly">Read only</option>
</options>
</parameter>
<parameter name="commandToReact" type="text" required="false">
<label>Command to React</label>
<description>Command to react. If not defined, channel react to all commands.</description>
</parameter>
<parameter name="pulseWidth" type="integer" required="false" min="0" max="4000" step="100" unit="ms">
<label>Pulse Width</label>
<description>Pulse width in milliseconds. If defined, binding send pulse rather than command value to IHC
controller.</description>
</parameter>
<parameter name="inverted" type="boolean" required="false">
<label>Inverted Signal</label>
<description>openHAB state is inverted compared to IHC output/input signal</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="contact">
<item-type>Contact</item-type>
<label>Generic Contact</label>
<description>Generic contact channel</description>
<state readOnly="true"></state>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="inverted" type="boolean" required="false">
<label>Inverted Signal</label>
<description>openHAB state is inverted compared to IHC output/input signal</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="number">
<item-type>Number</item-type>
<label>Generic Number</label>
<description>Generic number channel</description>
<state readOnly="false"></state>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="direction" type="text" required="false">
<label>Channel Direction</label>
<description>Direction of the channel. By default, channel is synchronized in both directions.</description>
<default>ReadWrite</default>
<options>
<option value="ReadWrite">Read Write</option>
<option value="WriteOnly">Write only</option>
<option value="ReadOnly">Read only</option>
</options>
</parameter>
<parameter name="commandToReact" type="text" required="false">
<label>Command to React</label>
<description>Command to react. If not defined, channel react to all commands.</description>
</parameter>
<parameter name="pulseWidth" type="integer" required="false" min="0" max="4000" step="100" unit="ms">
<label>Pulse Width</label>
<description>If defined, binding send pulse rather than command value to IHC controller.</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="dimmer">
<item-type>Dimmer</item-type>
<label>Generic Dimmer</label>
<description>Generic dimmer channel</description>
<state readOnly="false"></state>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="direction" type="text" required="false">
<label>Channel Direction</label>
<description>Direction of the channel. By default, channel is synchronized in both directions.</description>
<default>ReadWrite</default>
<options>
<option value="ReadWrite">Read Write</option>
<option value="WriteOnly">Write only</option>
<option value="ReadOnly">Read only</option>
</options>
</parameter>
<parameter name="commandToReact" type="text" required="false">
<label>Command to React</label>
<description>Command to react. If not defined, channel react to all commands.</description>
</parameter>
<parameter name="pulseWidth" type="integer" required="false" min="0" max="4000" step="100" unit="ms">
<label>Pulse Width</label>
<description>If defined, binding send pulse rather than command value to IHC controller.</description>
</parameter>
<parameter name="onLevel" type="integer" required="false" min="0" max="100" step="1">
<label>ON Command Level</label>
<description>If defined, binding use this level when ON command is received rather than resource maximum value.
Level is anyhow limited to resource maximum value.</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="datetime">
<item-type>DateTime</item-type>
<label>Generic Datetime</label>
<description>Generic datetime channel</description>
<state readOnly="false"></state>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="direction" type="text" required="false">
<label>Channel Direction</label>
<description>Direction of the channel. By default, channel is synchronized in both directions.</description>
<default>ReadWrite</default>
<options>
<option value="ReadWrite">Read Write</option>
<option value="WriteOnly">Write only</option>
<option value="ReadOnly">Read only</option>
</options>
</parameter>
<parameter name="commandToReact" type="text" required="false">
<label>Command to React</label>
<description>Command to react. If not defined, channel react to all commands.</description>
</parameter>
<parameter name="pulseWidth" type="integer" required="false" min="0" max="4000" step="100" unit="ms">
<label>Pulse Width</label>
<description>If defined, binding send pulse rather than command value to IHC controller.</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="string">
<item-type>String</item-type>
<label>Generic String</label>
<description>Generic string channel</description>
<state readOnly="false"></state>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="direction" type="text" required="false">
<label>Channel Direction</label>
<description>Direction of the channel. By default, channel is synchronized in both directions.</description>
<default>ReadWrite</default>
<options>
<option value="ReadWrite">Read Write</option>
<option value="WriteOnly">Write only</option>
<option value="ReadOnly">Read only</option>
</options>
</parameter>
<parameter name="commandToReact" type="text" required="false">
<label>Command to React</label>
<description>Command to react. If not defined, channel react to all commands.</description>
</parameter>
<parameter name="pulseWidth" type="integer" required="false" min="0" max="4000" step="100" unit="ms">
<label>Pulse Width</label>
<description>If defined, binding send pulse rather than command value to IHC controller.</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="rollershutter">
<item-type>RollerShutter</item-type>
<label>Generic Roller Shutter</label>
<description>Generic roller shutter channel</description>
<state readOnly="false"></state>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="direction" type="text" required="false">
<label>Channel Direction</label>
<description>Direction of the channel. By default, channel is synchronized in both directions.</description>
<default>ReadWrite</default>
<options>
<option value="ReadWrite">Read Write</option>
<option value="WriteOnly">Write only</option>
<option value="ReadOnly">Read only</option>
</options>
</parameter>
<parameter name="commandToReact" type="text" required="false">
<label>Command to React</label>
<description>Command to react. If not defined, channel react to all commands.</description>
</parameter>
<parameter name="pulseWidth" type="integer" required="false" min="0" max="4000" step="100" unit="ms">
<label>Pulse Width</label>
<description>If defined, binding send pulse rather than command value to IHC controller.</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="rf-device-low-battery">
<item-type>Switch</item-type>
<label>RF Device Low Battery Warning</label>
<description>RF device low battery warning.</description>
<category>Battery</category>
<state readOnly="true"></state>
<config-description>
<parameter name="serialNumber" type="integer" required="true">
<label>RF Device Serial Number</label>
<description>Serial Number of RF device in decimal format.</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="rf-device-signal-strength">
<item-type>String</item-type>
<label>RF Device Signal Strength</label>
<description>RF device signal strength.</description>
<category>QualityOfService</category>
<state readOnly="true" min="0" max="4">
<options>
<option value="0">No signal</option>
<option value="1">Weak</option>
<option value="2">Average</option>
<option value="3">Good</option>
<option value="4">Excellent</option>
</options>
</state>
<config-description>
<parameter name="serialNumber" type="integer" required="true">
<label>RF Device Serial Number</label>
<description>Serial number of RF device in decimal format.</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="push-button-trigger">
<kind>trigger</kind>
<label>Push Button Trigger Channel</label>
<event>
<options>
<option value="PRESSED">Pressed</option>
<option value="RELEASED">Released</option>
<option value="SHORT_PRESS">Short press</option>
<option value="LONG_PRESS">Long press</option>
</options>
</event>
<config-description>
<parameter name="resourceId" type="integer" required="true">
<label>Resource Id</label>
<description></description>
</parameter>
<parameter name="longPressTime" type="integer" required="true" step="1000" min="0" max="5000" unit="ms">
<label>Long Press Time</label>
<description>Long press time in milliseconds.</description>
<default>1000</default>
</parameter>
</config-description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="ihc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="controller"
extensible="switch, contact, number, dimmmer, datetime, string, rollershutter, pulse-output, rf-device-battery-level, rf-device-signal-strength, push-button-trigger">
<label>IHC / ELKO Controller</label>
<description></description>
<channels>
<channel typeId="controller-state" id="controllerState"/>
<channel typeId="controller-uptime" id="controllerUptime"/>
<channel typeId="controller-time" id="controllerTime"/>
</channels>
<properties>
<property name="controllerManufacturer"/>
<property name="controllerSerialNumber"/>
<property name="controllerSwVersion"/>
<property name="controllerHwVersion"/>
<property name="controllerIsWithoutViewer"/>
<property name="controllerSwDate"/>
<property name="controllerProductionDate"/>
<property name="projectDate"/>
<property name="projectNumber"/>
</properties>
<config-description>
<parameter name="hostname" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network/IP address of the IHC / ELKO controller without https prefix, but can contain TCP port if
default port is not used</description>
</parameter>
<parameter name="username" type="text" required="true">
<label>User Name</label>
<description>User name to login to the IHC / ELKO controller.</description>
</parameter>
<parameter name="password" type="text" required="true">
<context>password</context>
<label>Password</label>
<description>Password to login to the IHC / ELKO controller.</description>
</parameter>
<parameter name="timeout" type="integer" required="false" step="1000" unit="ms">
<label>Timeout</label>
<description>Timeout to communicate to IHC / ELKO controller.</description>
<default>5000</default>
</parameter>
<parameter name="loadProjectFile" type="boolean" required="false">
<label>Load Project File</label>
<description>Load project file from controller.</description>
<default>true</default>
</parameter>
<parameter name="createChannelsAutomatically" type="boolean" required="false">
<label>Create Channels Automatically</label>
<description>Create channels automatically from project file. Project file loading parameter should be enabled as
well.</description>
<default>true</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -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.ihc.internal;
import static org.junit.Assert.*;
import java.time.Duration;
import org.junit.Test;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class ButtonPressDurationDetectorTest {
@Test
public void testShortPress() {
Duration duration = Duration.ofMillis(450);
long longPressTime = 1000;
long longPressMaxTime = 2000;
ButtonPressDurationDetector button = new ButtonPressDurationDetector(duration, longPressTime, longPressMaxTime);
assertTrue(button.isShortPress());
assertFalse(button.isLongPress());
}
@Test
public void testLongPress() {
Duration duration = Duration.ofMillis(1003);
long longPressTime = 1000;
long longPressMaxTime = 2000;
ButtonPressDurationDetector button = new ButtonPressDurationDetector(duration, longPressTime, longPressMaxTime);
assertFalse(button.isShortPress());
assertTrue(button.isLongPress());
}
@Test
public void testExtraLongPress() {
Duration duration = Duration.ofMillis(2423);
long longPressTime = 1000;
long longPressMaxTime = 2000;
ButtonPressDurationDetector button = new ButtonPressDurationDetector(duration, longPressTime, longPressMaxTime);
assertFalse(button.isShortPress());
assertFalse(button.isLongPress());
}
@Test
public void testTooLongPress() {
Duration duration = Duration.ofMillis(5001);
long longPressTime = 1000;
long longPressMaxTime = 2000;
ButtonPressDurationDetector button = new ButtonPressDurationDetector(duration, longPressTime, longPressMaxTime);
assertFalse(button.isShortPress());
assertFalse(button.isLongPress());
}
}

View File

@@ -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.ihc.internal;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class SignalLevelConverterTest {
@Test
public void checkSignalLevelConverter() {
// IHC signal levels are between 0-18.
assertEquals(0, new SignalLevelConverter(0).getSystemWideSignalLevel());
assertEquals(0, new SignalLevelConverter(1).getSystemWideSignalLevel());
assertEquals(1, new SignalLevelConverter(2).getSystemWideSignalLevel());
assertEquals(1, new SignalLevelConverter(3).getSystemWideSignalLevel());
assertEquals(1, new SignalLevelConverter(4).getSystemWideSignalLevel());
assertEquals(2, new SignalLevelConverter(5).getSystemWideSignalLevel());
assertEquals(2, new SignalLevelConverter(6).getSystemWideSignalLevel());
assertEquals(2, new SignalLevelConverter(7).getSystemWideSignalLevel());
assertEquals(2, new SignalLevelConverter(8).getSystemWideSignalLevel());
assertEquals(3, new SignalLevelConverter(9).getSystemWideSignalLevel());
assertEquals(3, new SignalLevelConverter(10).getSystemWideSignalLevel());
assertEquals(3, new SignalLevelConverter(11).getSystemWideSignalLevel());
assertEquals(3, new SignalLevelConverter(12).getSystemWideSignalLevel());
assertEquals(3, new SignalLevelConverter(13).getSystemWideSignalLevel());
assertEquals(4, new SignalLevelConverter(14).getSystemWideSignalLevel());
assertEquals(4, new SignalLevelConverter(15).getSystemWideSignalLevel());
assertEquals(4, new SignalLevelConverter(16).getSystemWideSignalLevel());
assertEquals(4, new SignalLevelConverter(17).getSystemWideSignalLevel());
assertEquals(4, new SignalLevelConverter(18).getSystemWideSignalLevel());
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSDateValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DateTimeTypeWSDateValueConverterTest {
@Test
public void testConversion() throws ConversionException {
final DateTimeType dateTimeType = new DateTimeType("2000-12-30T00:00:00");
WSDateValue val = new WSDateValue(12345, (short) 1999, (byte) 1, (byte) 1);
val = convertFromOHType(val, dateTimeType, null);
assertEquals(12345, val.resourceID);
assertEquals(2000, val.year);
assertEquals(12, val.month);
assertEquals(30, val.day);
DateTimeType type = convertFromResourceValue(val, null);
assertEquals(dateTimeType.format("yyyy-MM-dd"), type.format("yyyy-MM-dd"));
}
private WSDateValue convertFromOHType(WSDateValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DateTimeType.class);
return (WSDateValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DateTimeType convertFromResourceValue(WSDateValue IHCvalue, ConverterAdditionalInfo converterAdditionalInfo)
throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DateTimeType.class);
return (DateTimeType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimeValue;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DateTimeTypeWSTimeValueConverterTest {
@Test
public void testConversion() throws ConversionException {
final DateTimeType dateTimeType = new DateTimeType("2000-12-30T13:59:30");
WSTimeValue val = new WSTimeValue(12345, 0, 0, 0);
val = convertFromOHType(val, dateTimeType, null);
assertEquals(12345, val.resourceID);
assertEquals(13, val.hours);
assertEquals(59, val.minutes);
assertEquals(30, val.seconds);
DateTimeType type = convertFromResourceValue(val, null);
assertEquals(dateTimeType.format("HH:mm:ss"), type.format("HH:mm:ss"));
}
private WSTimeValue convertFromOHType(WSTimeValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DateTimeType.class);
return (WSTimeValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DateTimeType convertFromResourceValue(WSTimeValue IHCvalue, ConverterAdditionalInfo converterAdditionalInfo)
throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DateTimeType.class);
return (DateTimeType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSBooleanValueConverterTest {
@Test
public void testOn() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, false);
val = convertFromOHType(val, new DecimalType(1), new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(true, val.value);
DecimalType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(new DecimalType(1), type);
}
@Test
public void testOff() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, true);
val = convertFromOHType(val, new DecimalType(0), new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(false, val.value);
DecimalType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(new DecimalType(0), type);
}
private WSBooleanValue convertFromOHType(WSBooleanValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (WSBooleanValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DecimalType convertFromResourceValue(WSBooleanValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (DecimalType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSEnumValueConverterTest {
@Test
public void testConversion() throws ConversionException {
WSEnumValue val = new WSEnumValue(12345, 100, 0, "testB");
val = convertFromOHType(val, new DecimalType(2), new ConverterAdditionalInfo(null, false, null));
assertEquals(12345, val.resourceID);
assertEquals(100, val.definitionTypeID);
assertEquals(2, val.enumValueID);
assertEquals("testB", val.enumName);
DecimalType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, false, null));
assertEquals(new DecimalType(2), type);
}
private WSEnumValue convertFromOHType(WSEnumValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (WSEnumValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DecimalType convertFromResourceValue(WSEnumValue IHCvalue, ConverterAdditionalInfo converterAdditionalInfo)
throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (DecimalType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSFloatingPointValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSFloatingPointValueConverterTest {
@Test
public void testConversion() throws ConversionException {
WSFloatingPointValue val = new WSFloatingPointValue(12345, 0, -100, 100);
val = convertFromOHType(val, new DecimalType(2.54), new ConverterAdditionalInfo(null, false, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.minimumValue, 0.001);
assertEquals(100, val.maximumValue, 0.001);
assertEquals(2.54, val.value, 0.001);
DecimalType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, false, null));
assertEquals(new DecimalType(2.54), type);
}
@Test(expected = ConversionException.class)
public void testMinExceed() throws ConversionException {
WSFloatingPointValue val = new WSFloatingPointValue(12345, 0, -100, 100);
val = convertFromOHType(val, new DecimalType(-101.5), new ConverterAdditionalInfo(null, false, null));
}
@Test(expected = ConversionException.class)
public void testMaxExceed() throws ConversionException {
WSFloatingPointValue val = new WSFloatingPointValue(12345, 0, -100, 100);
val = convertFromOHType(val, new DecimalType(101.5), new ConverterAdditionalInfo(null, false, null));
}
private WSFloatingPointValue convertFromOHType(WSFloatingPointValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (WSFloatingPointValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DecimalType convertFromResourceValue(WSFloatingPointValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (DecimalType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,70 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSIntegerValueConverterTest {
@Test
public void testConversion() throws ConversionException {
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, new DecimalType(2), new ConverterAdditionalInfo(null, false, null));
assertEquals(12345, val.resourceID);
assertEquals(2, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
DecimalType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, false, null));
assertEquals(new DecimalType(2), type);
}
@Test(expected = ConversionException.class)
public void testMinExceed() throws ConversionException {
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, new DecimalType(-101.5), new ConverterAdditionalInfo(null, false, null));
}
@Test(expected = ConversionException.class)
public void testMaxExceed() throws ConversionException {
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, new DecimalType(101.5), new ConverterAdditionalInfo(null, false, null));
}
private WSIntegerValue convertFromOHType(WSIntegerValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (WSIntegerValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DecimalType convertFromResourceValue(WSIntegerValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (DecimalType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,56 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSTimerValue;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSTimerValueConverterTest {
@Test
public void testConversion() throws ConversionException {
WSTimerValue val = new WSTimerValue(12345, 0);
val = convertFromOHType(val, new DecimalType(123456), new ConverterAdditionalInfo(null, false, null));
assertEquals(12345, val.resourceID);
assertEquals(123456, val.milliseconds);
DecimalType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, false, null));
assertEquals(new DecimalType(123456), type);
}
private WSTimerValue convertFromOHType(WSTimerValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (WSTimerValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DecimalType convertFromResourceValue(WSTimerValue IHCvalue, ConverterAdditionalInfo converterAdditionalInfo)
throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (DecimalType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,56 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSWeekdayValue;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class DecimalTypeWSWeekdayValueConverterTest {
@Test
public void testConversion() throws ConversionException {
WSWeekdayValue val = new WSWeekdayValue(12345, 0);
val = convertFromOHType(val, new DecimalType(6), new ConverterAdditionalInfo(null, false, null));
assertEquals(12345, val.resourceID);
assertEquals(6, val.weekdayNumber);
DecimalType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, false, null));
assertEquals(new DecimalType(6), type);
}
private WSWeekdayValue convertFromOHType(WSWeekdayValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (WSWeekdayValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private DecimalType convertFromResourceValue(WSWeekdayValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
DecimalType.class);
return (DecimalType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class OnOffTypeWSBooleanValueConverterTest {
@Test
public void testOn() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, false);
val = convertFromOHType(val, OnOffType.ON, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(true, val.value);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.ON, type);
}
@Test
public void testOff() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, true);
val = convertFromOHType(val, OnOffType.OFF, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(false, val.value);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.OFF, type);
}
@Test
public void testOnInverted() throws ConversionException {
final boolean inverted = true;
WSBooleanValue val = new WSBooleanValue(12345, true);
val = convertFromOHType(val, OnOffType.ON, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(false, val.value);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.ON, type);
}
@Test
public void testOffInverted() throws ConversionException {
final boolean inverted = true;
WSBooleanValue val = new WSBooleanValue(12345, false);
val = convertFromOHType(val, OnOffType.OFF, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(true, val.value);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.OFF, type);
}
private WSBooleanValue convertFromOHType(WSBooleanValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OnOffType.class);
return (WSBooleanValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private OnOffType convertFromResourceValue(WSBooleanValue IHCvalue, ConverterAdditionalInfo converterAdditionalInfo)
throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OnOffType.class);
return (OnOffType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,141 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.Command;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class OnOffTypeWSIntegerValueConverterTest {
@Test
public void testOn() throws ConversionException {
final boolean inverted = false;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OnOffType.ON, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.ON, type);
}
@Test
public void testOnLevelled() throws ConversionException {
final boolean inverted = false;
final int onLevel = 70;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
Map<Command, Object> commandLevels = new HashMap<>();
commandLevels.put(OnOffType.ON, onLevel);
val = convertFromOHType(val, OnOffType.ON,
new ConverterAdditionalInfo(null, inverted, Collections.unmodifiableMap(commandLevels)));
assertEquals(12345, val.resourceID);
assertEquals(onLevel, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.ON, type);
}
@Test(expected = ConversionException.class)
public void testOnLevelledError() throws ConversionException {
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
Map<Command, Object> commandLevels = new HashMap<>();
commandLevels.put(OnOffType.ON, "70");
val = convertFromOHType(val, OnOffType.ON,
new ConverterAdditionalInfo(null, false, Collections.unmodifiableMap(commandLevels)));
}
@Test
public void testOff() throws ConversionException {
final boolean inverted = false;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OnOffType.OFF, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.OFF, type);
}
@Test
public void testOnInverted() throws ConversionException {
final boolean inverted = true;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OnOffType.ON, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.ON, type);
}
@Test
public void testOffInverted() throws ConversionException {
final boolean inverted = true;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OnOffType.OFF, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OnOffType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OnOffType.OFF, type);
}
private WSIntegerValue convertFromOHType(WSIntegerValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OnOffType.class);
return (WSIntegerValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private OnOffType convertFromResourceValue(WSIntegerValue IHCvalue, ConverterAdditionalInfo converterAdditionalInfo)
throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OnOffType.class);
return (OnOffType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class OpenClosedTypeWSBooleanValueConverterTest {
@Test
public void testOpen() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, false);
val = convertFromOHType(val, OpenClosedType.OPEN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(true, val.value);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.OPEN, type);
}
@Test
public void testClosed() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, true);
val = convertFromOHType(val, OpenClosedType.CLOSED, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(false, val.value);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.CLOSED, type);
}
@Test
public void testOpenInverted() throws ConversionException {
final boolean inverted = true;
WSBooleanValue val = new WSBooleanValue(12345, true);
val = convertFromOHType(val, OpenClosedType.OPEN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(false, val.value);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.OPEN, type);
}
@Test
public void testClosedInverted() throws ConversionException {
final boolean inverted = true;
WSBooleanValue val = new WSBooleanValue(12345, false);
val = convertFromOHType(val, OpenClosedType.CLOSED, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(true, val.value);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.CLOSED, type);
}
private WSBooleanValue convertFromOHType(WSBooleanValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OpenClosedType.class);
return (WSBooleanValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private OpenClosedType convertFromResourceValue(WSBooleanValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OpenClosedType.class);
return (OpenClosedType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class OpenClosedTypeWSIntegerValueConverterTest {
@Test
public void testOpen() throws ConversionException {
final boolean inverted = false;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OpenClosedType.OPEN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.OPEN, type);
}
@Test
public void testClosed() throws ConversionException {
final boolean inverted = false;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OpenClosedType.CLOSED, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.CLOSED, type);
}
@Test
public void testOpenInverted() throws ConversionException {
final boolean inverted = true;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OpenClosedType.OPEN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.OPEN, type);
}
@Test
public void testClosedInverted() throws ConversionException {
final boolean inverted = true;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, OpenClosedType.CLOSED, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(100, val.value);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
OpenClosedType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(OpenClosedType.CLOSED, type);
}
private WSIntegerValue convertFromOHType(WSIntegerValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OpenClosedType.class);
return (WSIntegerValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private OpenClosedType convertFromResourceValue(WSIntegerValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
OpenClosedType.class);
return (OpenClosedType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class PercentTypeWSIntegerValueConverterTest {
@Test
public void test() throws ConversionException {
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, new PercentType(2), new ConverterAdditionalInfo(null, false, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
assertEquals(2, val.value);
PercentType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, false, null));
assertEquals(new PercentType(2), type);
}
private WSIntegerValue convertFromOHType(WSIntegerValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
PercentType.class);
return (WSIntegerValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private PercentType convertFromResourceValue(WSIntegerValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
PercentType.class);
return (PercentType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,67 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.projectfile.IhcEnumValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSEnumValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class StringTypeWSEnumValueConverterTest {
@Test
public void test() throws ConversionException {
ArrayList<IhcEnumValue> enumValues = new ArrayList<>();
enumValues.add(new IhcEnumValue(101, "testA"));
enumValues.add(new IhcEnumValue(102, "testB"));
enumValues.add(new IhcEnumValue(103, "testC"));
enumValues.add(new IhcEnumValue(104, "testD"));
WSEnumValue val = new WSEnumValue(12345, 5555, 0, "");
val = convertFromOHType(val, new StringType("testC"), new ConverterAdditionalInfo(enumValues, false, null));
assertEquals(12345, val.resourceID);
assertEquals(5555, val.definitionTypeID);
assertEquals(103, val.enumValueID);
assertEquals("testC", val.enumName);
StringType type = convertFromResourceValue(val, new ConverterAdditionalInfo(enumValues, false, null));
assertEquals(new StringType("testC"), type);
}
private WSEnumValue convertFromOHType(WSEnumValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
StringType.class);
return (WSEnumValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private StringType convertFromResourceValue(WSEnumValue IHCvalue, ConverterAdditionalInfo converterAdditionalInfo)
throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
StringType.class);
return (StringType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSBooleanValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class UpDownTypeWSBooleanValueConverterTest {
@Test
public void testOpen() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, false);
val = convertFromOHType(val, UpDownType.UP, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(true, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.UP, type);
}
@Test
public void testClosed() throws ConversionException {
final boolean inverted = false;
WSBooleanValue val = new WSBooleanValue(12345, true);
val = convertFromOHType(val, UpDownType.DOWN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(false, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.DOWN, type);
}
@Test
public void testOpenInverted() throws ConversionException {
final boolean inverted = true;
WSBooleanValue val = new WSBooleanValue(12345, true);
val = convertFromOHType(val, UpDownType.UP, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(false, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.UP, type);
}
@Test
public void testClosedInverted() throws ConversionException {
final boolean inverted = true;
WSBooleanValue val = new WSBooleanValue(12345, false);
val = convertFromOHType(val, UpDownType.DOWN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(true, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.DOWN, type);
}
private WSBooleanValue convertFromOHType(WSBooleanValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
UpDownType.class);
return (WSBooleanValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private UpDownType convertFromResourceValue(WSBooleanValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
UpDownType.class);
return (UpDownType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -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.ihc.internal.converters;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.exeptions.ConversionException;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSIntegerValue;
import org.openhab.binding.ihc.internal.ws.resourcevalues.WSResourceValue;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.types.Type;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class UpDownTypeWSIntegerValueConverterTest {
@Test
public void testOpen() throws ConversionException {
final boolean inverted = false;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, UpDownType.UP, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
assertEquals(100, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.UP, type);
}
@Test
public void testClosed() throws ConversionException {
final boolean inverted = false;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, UpDownType.DOWN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
assertEquals(-100, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.DOWN, type);
}
@Test
public void testOpenInverted() throws ConversionException {
final boolean inverted = true;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, UpDownType.UP, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
assertEquals(-100, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.UP, type);
}
@Test
public void testClosedInverted() throws ConversionException {
final boolean inverted = true;
WSIntegerValue val = new WSIntegerValue(12345, 0, -100, 100);
val = convertFromOHType(val, UpDownType.DOWN, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(12345, val.resourceID);
assertEquals(-100, val.minimumValue);
assertEquals(100, val.maximumValue);
assertEquals(100, val.value);
UpDownType type = convertFromResourceValue(val, new ConverterAdditionalInfo(null, inverted, null));
assertEquals(UpDownType.DOWN, type);
}
private WSIntegerValue convertFromOHType(WSIntegerValue IHCvalue, Type OHval,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
UpDownType.class);
return (WSIntegerValue) converter.convertFromOHType(OHval, IHCvalue, converterAdditionalInfo);
}
private UpDownType convertFromResourceValue(WSIntegerValue IHCvalue,
ConverterAdditionalInfo converterAdditionalInfo) throws ConversionException {
Converter<WSResourceValue, Type> converter = ConverterFactory.getInstance().getConverter(IHCvalue.getClass(),
UpDownType.class);
return (UpDownType) converter.convertFromResourceValue(IHCvalue, converterAdditionalInfo);
}
}

View File

@@ -0,0 +1,66 @@
/**
* 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.ihc.internal.ws;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.openhab.binding.ihc.internal.ws.datatypes.WSFile;
import org.openhab.binding.ihc.internal.ws.datatypes.WSProjectInfo;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcClientTest {
private IhcClient ihcClient;
@Before
public void setUp() throws IhcExecption, SocketTimeoutException {
ihcClient = spy(new IhcClient("test1", "test2", "test3"));
WSProjectInfo projectInfo = new WSProjectInfo();
projectInfo.setProjectMajorRevision(111);
projectInfo.setProjectMinorRevision(222);
doReturn(projectInfo).when(ihcClient).getProjectInfo();
doReturn(2).when(ihcClient).getProjectNumberOfSegments();
doReturn(100).when(ihcClient).getProjectSegmentationSize();
final String segment0 = ResourceFileUtils.getFileContent("Segment0.base64");
final String segment1 = ResourceFileUtils.getFileContent("Segment1.base64");
WSFile file0 = new WSFile(segment0.getBytes(), "");
doReturn(file0).when(ihcClient).getProjectSegment(ArgumentMatchers.eq(0), ArgumentMatchers.eq(111),
ArgumentMatchers.eq(222));
WSFile file1 = new WSFile(segment1.getBytes(), "");
doReturn(file1).when(ihcClient).getProjectSegment(ArgumentMatchers.eq(1), ArgumentMatchers.eq(111),
ArgumentMatchers.eq(222));
}
@Test
public void loadProjectFileFromControllerTest() throws IhcExecption, UnsupportedEncodingException {
final String expectedFileContent = ResourceFileUtils.getFileContent("ProjectFileContent.txt");
final byte[] result = ihcClient.getProjectFileFromController();
assertEquals(expectedFileContent, new String(result, "UTF-8"));
}
}

View File

@@ -0,0 +1,40 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws;
import static org.junit.Assert.fail;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.stream.Collectors;
/**
* Util class to load file content from resource files.
*
* @author Pauli Anttila - Initial contribution
*/
public class ResourceFileUtils {
public static String getFileContent(String resourceFile) {
try (InputStream inputStream = ResourceFileUtils.class.getClassLoader().getResourceAsStream(resourceFile);
Reader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
return bufferedReader.lines().collect(Collectors.joining("\n"));
} catch (IOException e) {
fail("IOException reading xml file '" + resourceFile + "': " + e);
}
return "";
}
}

View File

@@ -0,0 +1,83 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.ihc.internal.ws.services;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.ResourceFileUtils;
import org.openhab.binding.ihc.internal.ws.datatypes.WSRFDevice;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcAirlinkManagementServiceTest {
private IhcAirlinkManagementService ihcAirlinkManagementService;
private final String host = "1.1.1.1";
private final String url = "https://1.1.1.1/ws/AirlinkManagementService";
private Map<String, String> requestProps = new HashMap<>();
private String query;
private final int timeout = 100;
@Before
public void setUp() throws IhcExecption, SocketTimeoutException {
ihcAirlinkManagementService = spy(new IhcAirlinkManagementService(host, timeout, new IhcConnectionPool()));
query = ResourceFileUtils.getFileContent("EmptyQuery.xml");
requestProps.clear();
requestProps.put("SOAPAction", "getDetectedDeviceList");
}
@Test
public void test() throws IhcExecption {
final String response = ResourceFileUtils.getFileContent("GetDetectedDeviceListResponse.xml");
doReturn(response).when(ihcAirlinkManagementService).sendQuery(eq(url), eq(requestProps), eq(query),
eq(timeout));
final List<WSRFDevice> result = ihcAirlinkManagementService.getDetectedDeviceList();
assertEquals(1, result.size());
assertEquals(1, result.get(0).getBatteryLevel());
assertEquals(true, result.get(0).getDetected());
assertEquals(2049, result.get(0).getDeviceType());
assertEquals(123456789, result.get(0).getSerialNumber());
assertEquals(10, result.get(0).getSignalStrength());
assertEquals(1, result.get(0).getVersion());
}
@Test
public void testEmptyList() throws IhcExecption {
final String response = ResourceFileUtils.getFileContent("GetEmptyDetectedDeviceListResponse.xml");
doReturn(response).when(ihcAirlinkManagementService).sendQuery(eq(url), eq(requestProps), eq(query),
eq(timeout));
final List<WSRFDevice> result = ihcAirlinkManagementService.getDetectedDeviceList();
assertEquals(0, result.size());
}
}

View File

@@ -0,0 +1,74 @@
/**
* 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.ihc.internal.ws.services;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.net.SocketTimeoutException;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.ResourceFileUtils;
import org.openhab.binding.ihc.internal.ws.datatypes.WSLoginResult;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcAuthenticationServiceTest {
private IhcAuthenticationService ihcAuthenticationService;
private final String host = "1.1.1.1";
private final String url = "https://1.1.1.1/ws/AuthenticationService";
private final int timeout = 100;
@Before
public void setUp() throws IhcExecption, SocketTimeoutException {
ihcAuthenticationService = spy(new IhcAuthenticationService(host, timeout, new IhcConnectionPool()));
final String querySuccesfulLogin = ResourceFileUtils.getFileContent("SuccesfulLoginQuery.xml");
final String responseSuccesfulLogin = ResourceFileUtils.getFileContent("SuccesfulLoginResponse.xml");
doReturn(responseSuccesfulLogin).when(ihcAuthenticationService).sendQuery(eq(url), any(),
eq(querySuccesfulLogin), eq(timeout));
final String queryLoginFailed = ResourceFileUtils.getFileContent("LoginFailedQuery.xml");
final String responseLoginFailed = ResourceFileUtils.getFileContent("LoginFailedResponse.xml");
doReturn(responseLoginFailed).when(ihcAuthenticationService).sendQuery(eq(url), any(), eq(queryLoginFailed),
eq(timeout));
}
@Test
public void testSuccesfulLogin() throws IhcExecption {
final WSLoginResult result = ihcAuthenticationService.authenticate("user", "pass", "treeview");
assertEquals(true, result.isLoginWasSuccessful());
assertEquals(false, result.isLoginFailedDueToAccountInvalid());
assertEquals(false, result.isLoginFailedDueToConnectionRestrictions());
assertEquals(false, result.isLoginFailedDueToInsufficientUserRights());
}
@Test
public void testFailedLogin() throws IhcExecption {
final WSLoginResult result = ihcAuthenticationService.authenticate("user", "wrong", "treeview");
assertEquals(false, result.isLoginWasSuccessful());
assertEquals(true, result.isLoginFailedDueToAccountInvalid());
assertEquals(false, result.isLoginFailedDueToConnectionRestrictions());
assertEquals(false, result.isLoginFailedDueToInsufficientUserRights());
}
}

View File

@@ -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.ihc.internal.ws.services;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import java.net.SocketTimeoutException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.ResourceFileUtils;
import org.openhab.binding.ihc.internal.ws.datatypes.WSSystemInfo;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcConfigurationServiceTest {
private IhcConfigurationService ihcConfigurationService;
private final String host = "1.1.1.1";
private final String url = "https://1.1.1.1/ws/ConfigurationService";
final String query = ResourceFileUtils.getFileContent("EmptyQuery.xml");
private Map<String, String> requestProps = new HashMap<>();
private final int timeout = 100;
@Before
public void setUp() throws IhcExecption, SocketTimeoutException {
ihcConfigurationService = spy(new IhcConfigurationService(host, timeout, new IhcConnectionPool()));
requestProps.clear();
requestProps.put("SOAPAction", "getSystemInfo");
}
@Test
public void testv2() throws IhcExecption {
final String response = ResourceFileUtils.getFileContent("GetSystemInfoResponse.xml");
doReturn(response).when(ihcConfigurationService).sendQuery(eq(url), eq(requestProps), eq(query), eq(timeout));
final WSSystemInfo result = ihcConfigurationService.getSystemInfo();
assertEquals(false, result.getApplicationIsWithoutViewer());
assertEquals("ELKOFI", result.getBrand());
assertEquals("6.2", result.getHwRevision());
assertEquals(LocalDateTime.parse("2018-06-28T17:02:29", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")),
result.getRealTimeClock().toLocalDateTime());
assertEquals("1234567890", result.getSerialNumber());
assertEquals(LocalDateTime.parse("2011-03-04T09:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")),
result.getSwDate().toLocalDateTime());
assertEquals(3980146956L, result.getUptime());
assertEquals("2.7.144", result.getVersion());
assertEquals("2011-04-28T09:00:00Z", result.getProductionDate());
assertEquals("", result.getDatalineVersion());
assertEquals("", result.getRfModuleSoftwareVersion());
assertEquals("", result.getRfModuleSerialNumber());
}
@Test
public void testv3() throws IhcExecption {
final String response = ResourceFileUtils.getFileContent("GetSystemInfoResponse2.xml");
doReturn(response).when(ihcConfigurationService).sendQuery(eq(url), eq(requestProps), eq(query), eq(timeout));
final WSSystemInfo result = ihcConfigurationService.getSystemInfo();
assertEquals(false, result.getApplicationIsWithoutViewer());
assertEquals("LK", result.getBrand());
assertEquals("7.1", result.getHwRevision());
assertEquals(
LocalDateTime.parse("2018-12-15T13:15:00Z", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")),
result.getRealTimeClock().toLocalDateTime());
assertEquals("CN1734000000", result.getSerialNumber());
assertEquals(
LocalDateTime.parse("2018-07-23T10:00:00Z", DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")),
result.getSwDate().toLocalDateTime());
assertEquals(164057634L, result.getUptime());
assertEquals("3.3.9", result.getVersion());
assertEquals("2017/34", result.getProductionDate());
assertEquals("IOB.B.03.02.01", result.getDatalineVersion());
assertEquals("3.06.c", result.getRfModuleSoftwareVersion());
assertEquals("640C10140000", result.getRfModuleSerialNumber());
}
}

View File

@@ -0,0 +1,143 @@
/**
* 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.ihc.internal.ws.services;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.ihc.internal.ws.IhcClient;
import org.openhab.binding.ihc.internal.ws.ResourceFileUtils;
import org.openhab.binding.ihc.internal.ws.datatypes.WSControllerState;
import org.openhab.binding.ihc.internal.ws.datatypes.WSFile;
import org.openhab.binding.ihc.internal.ws.datatypes.WSProjectInfo;
import org.openhab.binding.ihc.internal.ws.exeptions.IhcExecption;
import org.openhab.binding.ihc.internal.ws.http.IhcConnectionPool;
/**
* Test for IHC / ELKO binding
*
* @author Pauli Anttila - Initial contribution
*/
public class IhcControllerServiceTest {
private IhcControllerService ihcControllerService;
private final String host = "1.1.1.1";
private final String url = "https://1.1.1.1/ws/ControllerService";
private Map<String, String> requestProps = new HashMap<>();
private String query;
private final int timeout = 100;
@Before
public void setUp() throws IhcExecption, SocketTimeoutException {
ihcControllerService = spy(new IhcControllerService(host, timeout, new IhcConnectionPool()));
query = ResourceFileUtils.getFileContent("EmptyQuery.xml");
requestProps.clear();
}
@Test
public void projectInfoTest() throws IhcExecption {
requestProps.put("SOAPAction", "getProjectInfo");
final String projectInfoResponse = ResourceFileUtils.getFileContent("GetProjectInfoResponse.xml");
doReturn(projectInfoResponse).when(ihcControllerService).sendQuery(eq(url), eq(requestProps), eq(query),
eq(timeout));
final WSProjectInfo result = ihcControllerService.getProjectInfo();
assertEquals("Pertti 'Speedy' Keinonen", result.getCustomerName());
}
@Test
public void projectNumberOfSegmentsTest() throws IhcExecption {
final String projectNumberOfSegmentsResponse = ResourceFileUtils
.getFileContent("GetProjectNumberOfSegmentsResponse.xml");
requestProps.put("SOAPAction", "getIHCProjectNumberOfSegments");
doReturn(projectNumberOfSegmentsResponse).when(ihcControllerService).sendQuery(eq(url), eq(requestProps),
eq(query), eq(timeout));
final int result = ihcControllerService.getProjectNumberOfSegments();
assertEquals(28, result);
}
@Test
public void projectSegmentationSizeTest() throws IhcExecption {
final String projectSegmentationSizeResponse = ResourceFileUtils
.getFileContent("GetProjectSegmentationSizeResponse.xml");
requestProps.put("SOAPAction", "getIHCProjectSegmentationSize");
doReturn(projectSegmentationSizeResponse).when(ihcControllerService).sendQuery(eq(url), eq(requestProps),
eq(query), anyInt());
final int result = ihcControllerService.getProjectSegmentationSize();
assertEquals(7500, result);
}
@Test
public void controllerStateTest() throws IhcExecption {
final String controllerStateResponse = ResourceFileUtils.getFileContent("ControllerStateResponse.xml");
requestProps.put("SOAPAction", "getState");
doReturn(controllerStateResponse).when(ihcControllerService).sendQuery(eq(url), eq(requestProps), eq(query),
anyInt());
final WSControllerState result = ihcControllerService.getControllerState();
assertEquals(IhcClient.CONTROLLER_STATE_READY, result.getState());
}
@Test
public void waitForControllerStateChangeQueryTest() throws IhcExecption {
final String waitForControllerStateChangeQuery = ResourceFileUtils
.getFileContent("WaitForControllerStateChangeQuery.xml");
final String waitForControllerStateChangeResponse = ResourceFileUtils
.getFileContent("WaitForControllerStateChangeResponse.xml");
requestProps.put("SOAPAction", "waitForControllerStateChange");
doReturn(waitForControllerStateChangeResponse).when(ihcControllerService).sendQuery(eq(url), eq(requestProps),
eq(waitForControllerStateChangeQuery), anyInt());
WSControllerState previousState = new WSControllerState();
previousState.setState(IhcClient.CONTROLLER_STATE_INITIALIZE);
final WSControllerState result = ihcControllerService.waitStateChangeNotifications(previousState, 5);
assertEquals(IhcClient.CONTROLLER_STATE_READY, result.getState());
}
@Test
public void projectSegmentQueryTest() throws IhcExecption {
final String projectSegmentQuery = ResourceFileUtils.getFileContent("GetProjectSegmentQuery.xml");
final String projectSegmentResponse = ResourceFileUtils.getFileContent("GetProjectSegmentResponse.xml");
requestProps.put("SOAPAction", "getIHCProjectSegment");
doReturn(projectSegmentResponse).when(ihcControllerService).sendQuery(eq(url), eq(requestProps),
eq(projectSegmentQuery), anyInt());
final byte[] expectedResult = "LvVF4VWSi0WqRKps7lGH6U....OBCl1gwKGbvYM1SDh".getBytes();
final WSFile result = ihcControllerService.getProjectSegment(1, 1001, 2002);
assertTrue("Result bytes doesn't match to expected bytes", Arrays.equals(expectedResult, result.getData()));
}
}

Some files were not shown because too many files have changed in this diff Show More