[Helios] Remove support for obsolete firmware 2.7 including SOAP base… (#12721)

* Helios] Remove support for obsolete firmware 2.7 including SOAP based communication

Signed-off-by: Karel Goderis <karel.goderis@me.com>
pull/12848/head
Karel Goderis 2022-05-29 16:25:43 +02:00 committed by GitHub
parent a0c3e7a88a
commit 020db307bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 7 additions and 1191 deletions

View File

@ -4,7 +4,7 @@ This binding integrates the Heliop door/videophone system (https://www.2n.cz).
## Supported Things
Currently, the Helios IP Vario is supported by this binding, running the 2.7 or 2.21 version of the firmware
Currently, the Helios IP Vario is supported by this binding, running the 2.21 version of the firmware
## Binding Configuration
@ -14,7 +14,7 @@ There is no specific binding configuration
## Thing Configuration
The ipvario221 (or ipvario27) Thing requires the IP address of the videophone, and the username and password as a configuration value in order for the binding to log into the videophone.
The ipvario221 Thing requires the IP address of the videophone, and the username and password as a configuration value in order for the binding to log into the videophone.
In the thing file, this looks e.g. like
@ -55,7 +55,7 @@ For switchstate, there are as well the switchstateswitch and switchstateoriginat
demo.Things:
```
Thing helios:ipvario213:gate [ipAddress="192.168.0.14", username="admin", password="mypassword"]
Thing helios:ipvario221:gate [ipAddress="192.168.0.14", username="admin", password="mypassword"]
```
demo.items:

View File

@ -14,37 +14,4 @@
<name>openHAB Add-ons :: Bundles :: Helios Binding</name>
<dependencies>
<dependency>
<groupId>org.apache.servicemix.specs</groupId>
<artifactId>org.apache.servicemix.specs.jaxws-api-2.2</artifactId>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
<version>1.1.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.ws.xmlschema</groupId>
<artifactId>xmlschema-core</artifactId>
<version>2.2.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
<version>3.1.14</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf.services.wsn</groupId>
<artifactId>cxf-services-wsn-api</artifactId>
<version>3.1.14</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,16 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.helios-${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>
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features
</repository>
<feature name="openhab-binding-helios" description="Helios Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle dependency="true">mvn:org.apache.ws.xmlschema/xmlschema-core/2.2.4</bundle>
<bundle dependency="true">mvn:org.apache.servicemix.specs/org.apache.servicemix.specs.jaxws-api-2.2/2.9.0</bundle>
<bundle dependency="true">mvn:org.apache.servicemix.specs/org.apache.servicemix.specs.saaj-api-1.3/2.9.0</bundle>
<bundle dependency="true">mvn:org.apache.cxf/cxf-core/3.1.14</bundle>
<bundle dependency="true">mvn:org.apache.cxf.services.wsn/cxf-services-wsn-api/3.1.14</bundle>
<bundle dependency="true">mvn:org.apache.felix/org.apache.felix.framework/6.0.2</bundle>
<bundle dependency="true">mvn:org.apache.geronimo.specs/geronimo-ws-metadata_2.0_spec/1.1.3</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.helios/${project.version}</bundle>
</feature>
</features>

View File

@ -27,7 +27,6 @@ public class HeliosBindingConstants {
public static final String BINDING_ID = "helios";
// List of all Thing Type UIDs
public static final ThingTypeUID HELIOS_VARIO_IP_2_7_TYPE = new ThingTypeUID(BINDING_ID, "ipvario27");
public static final ThingTypeUID HELIOS_VARIO_IP_2_21_TYPE = new ThingTypeUID(BINDING_ID, "ipvario221");
// List of all Channel ids

View File

@ -12,7 +12,7 @@
*/
package org.openhab.binding.helios.internal;
import static org.openhab.binding.helios.internal.HeliosBindingConstants.*;
import static org.openhab.binding.helios.internal.HeliosBindingConstants.HELIOS_VARIO_IP_2_21_TYPE;
import java.util.Collections;
import java.util.Set;
@ -20,7 +20,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openhab.binding.helios.internal.handler.HeliosHandler221;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
@ -37,8 +36,7 @@ import org.osgi.service.component.annotations.Component;
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.helios")
public class HeliosHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(HELIOS_VARIO_IP_2_7_TYPE, HELIOS_VARIO_IP_2_21_TYPE).collect(Collectors.toSet()));
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(HELIOS_VARIO_IP_2_21_TYPE);
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
@ -49,10 +47,6 @@ public class HeliosHandlerFactory extends BaseThingHandlerFactory {
protected ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(HELIOS_VARIO_IP_2_7_TYPE)) {
return new HeliosHandler27(thing);
}
if (thingTypeUID.equals(HELIOS_VARIO_IP_2_21_TYPE)) {
return new HeliosHandler221(thing);
}

View File

@ -1,450 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.handler;
import static org.openhab.binding.helios.internal.HeliosBindingConstants.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.transform.dom.DOMResult;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.BindingType;
import javax.xml.ws.Endpoint;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.wsn.wsdl.WSNWSDLLocator;
import org.oasis_open.docs.wsn.b_2.FilterType;
import org.oasis_open.docs.wsn.b_2.Notify;
import org.oasis_open.docs.wsn.b_2.Renew;
import org.oasis_open.docs.wsn.b_2.RenewResponse;
import org.oasis_open.docs.wsn.b_2.Subscribe;
import org.oasis_open.docs.wsn.b_2.SubscribeResponse;
import org.oasis_open.docs.wsn.b_2.TopicExpressionType;
import org.oasis_open.docs.wsn.b_2.Unsubscribe;
import org.oasis_open.docs.wsn.bw_2.InvalidFilterFault;
import org.oasis_open.docs.wsn.bw_2.InvalidMessageContentExpressionFault;
import org.oasis_open.docs.wsn.bw_2.InvalidProducerPropertiesExpressionFault;
import org.oasis_open.docs.wsn.bw_2.InvalidTopicExpressionFault;
import org.oasis_open.docs.wsn.bw_2.NotificationConsumer;
import org.oasis_open.docs.wsn.bw_2.NotificationProducer;
import org.oasis_open.docs.wsn.bw_2.NotifyMessageNotSupportedFault;
import org.oasis_open.docs.wsn.bw_2.PausableSubscriptionManager;
import org.oasis_open.docs.wsn.bw_2.SubscribeCreationFailedFault;
import org.oasis_open.docs.wsn.bw_2.TopicExpressionDialectUnknownFault;
import org.oasis_open.docs.wsn.bw_2.TopicNotSupportedFault;
import org.oasis_open.docs.wsn.bw_2.UnableToDestroySubscriptionFault;
import org.oasis_open.docs.wsn.bw_2.UnacceptableInitialTerminationTimeFault;
import org.oasis_open.docs.wsn.bw_2.UnacceptableTerminationTimeFault;
import org.oasis_open.docs.wsn.bw_2.UnrecognizedPolicyRequestFault;
import org.oasis_open.docs.wsn.bw_2.UnsupportedPolicyRequestFault;
import org.oasis_open.docs.wsrf.rw_2.ResourceUnknownFault;
import org.openhab.binding.helios.internal.ws.soap.SOAPActionHandler;
import org.openhab.binding.helios.internal.ws.soap.SOAPCallStateChanged;
import org.openhab.binding.helios.internal.ws.soap.SOAPCardEntered;
import org.openhab.binding.helios.internal.ws.soap.SOAPCodeEntered;
import org.openhab.binding.helios.internal.ws.soap.SOAPDeviceState;
import org.openhab.binding.helios.internal.ws.soap.SOAPEvent;
import org.openhab.binding.helios.internal.ws.soap.SOAPKeyPressed;
import org.openhab.binding.helios.internal.ws.soap.SOAPObjectFactory;
import org.openhab.binding.helios.internal.ws.soap.SOAPSubscriptionActionHandler;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.StringType;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* The {@link HeliosHandler27} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Karel Goderis - Initial contribution
*/
@WebService(endpointInterface = "org.oasis_open.docs.wsn.bw_2.NotificationConsumer")
@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
public class HeliosHandler27 extends BaseThingHandler implements NotificationConsumer {
// List of Configuration constants
public static final String IP_ADDRESS = "ipAddress";
public static final String OPENHAB_IP_ADDRESS = "openHABipAddress";
public static final String OPENHAB_PORT_NUMBER = "openHABportNumber";
private final Logger logger = LoggerFactory.getLogger(HeliosHandler27.class);
private static final String SUBSCRIPTION_PERIOD = "PT1H";
private JAXBContext context = null;
private Endpoint endpoint = null;
private NotificationProducer notificationProducer = null;
private PausableSubscriptionManager subscription = null;
private GregorianCalendar currentTime;
private GregorianCalendar terminationTime;
private W3CEndpointReference subscriptionReference;
private String subscriptionID;
private SOAPEvent previousEvent = null;
public static final String HELIOS_URI = "http://www.2n.cz/2013/event";
public static final String DIALECT_URI = "http://www.2n.cz/2013/TopicExpression/Multiple";
public static final String WSN_URI = "http://docs.oasis-open.org/wsn/b-2";
public static final QName TOPIC_EXPRESSION = new QName(WSN_URI, "TopicExpression");
public static final QName INITIAL_TERMINATION_TIME = new QName(WSN_URI, "InitialTerminationTime");
public static final QName MAXIMUM_NUMBER = new QName(HELIOS_URI, "MaximumNumber");
public static final QName SIMPLE_MESSAGES = new QName(HELIOS_URI, "SimpleMessages");
public static final QName START_TIME_STAMP = new QName(HELIOS_URI, "StartTimestamp");
public static final QName START_RECORD_ID = new QName(HELIOS_URI, "StartRecordId");
public HeliosHandler27(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (!(command instanceof RefreshType)) {
// 2N.cz has not yet released the automation part of the Helios IP HTTP/SOAP based API. Only the
// notification part has been documented, so for now there is nothing to do
// here
logger.debug("The Helios IP is a read-only device and can not handle commands");
}
}
public String getSubscriptionID() {
return subscriptionID;
}
@SuppressWarnings("rawtypes")
@Override
public void initialize() {
logger.debug("Initializing Helios IP handler.");
List<Handler> handlerChain = new ArrayList<>();
handlerChain.add(new SOAPActionHandler());
try {
context = JAXBContext.newInstance(SOAPObjectFactory.class, SOAPEvent.class, SOAPKeyPressed.class,
SOAPCallStateChanged.class, SOAPCodeEntered.class, SOAPCardEntered.class, SOAPDeviceState.class);
} catch (JAXBException e) {
logger.error("An exception occurred while setting up the JAXB Context factory: {}", e.getMessage(), e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
throw new RuntimeException();
}
try {
if (endpoint == null || (endpoint != null && !endpoint.isPublished())) {
String address = "http://" + (String) getConfig().get(OPENHAB_IP_ADDRESS) + ":"
+ ((BigDecimal) getConfig().get(OPENHAB_PORT_NUMBER)).toString() + "/notification"
+ System.currentTimeMillis();
logger.debug("Publishing the notification consumer webservice on '{}", address);
endpoint = Endpoint.publish(address, this);
((javax.xml.ws.soap.SOAPBinding) endpoint.getBinding()).setHandlerChain(handlerChain);
}
} catch (WebServiceException e1) {
logger.debug("An exception occurred while setting up the notification consumer webservice: {}",
e1.getMessage(), e1);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e1.getMessage());
return;
}
try {
String heliosAddress = "http://" + (String) getConfig().get(IP_ADDRESS) + "/notification";
Service notificationProducerService = Service.create(WSNWSDLLocator.getWSDLUrl(),
new QName("http://cxf.apache.org/wsn/jaxws", "NotificationProducerService"));
notificationProducer = notificationProducerService.getPort(
new W3CEndpointReferenceBuilder().address(heliosAddress).build(), NotificationProducer.class);
((BindingProvider) notificationProducer).getBinding().setHandlerChain(handlerChain);
} catch (WebServiceException e1) {
logger.debug("An exception occurred while setting up the notification webservice client: {}",
e1.getMessage(), e1);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e1.getMessage());
return;
}
try {
// set up the access to the subscription manager on the Helios IP
// Vario so that we can renew in the future
String heliosAddress = "http://" + (String) getConfig().get(IP_ADDRESS) + "/notification";
Service subscriptionService = Service.create(WSNWSDLLocator.getWSDLUrl(),
new QName("http://cxf.apache.org/wsn/jaxws", "PausableSubscriptionManagerService"));
subscription = subscriptionService.getPort(new W3CEndpointReferenceBuilder().address(heliosAddress).build(),
PausableSubscriptionManager.class);
handlerChain = new ArrayList<>();
handlerChain.add(new SOAPSubscriptionActionHandler(this));
((BindingProvider) subscription).getBinding().setHandlerChain(handlerChain);
} catch (WebServiceException e1) {
logger.debug("An exception occurred while setting up the subscription manager client: {}", e1.getMessage(),
e1);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e1.getMessage());
return;
}
try {
subscribe(endpoint.getEndpointReference(W3CEndpointReference.class));
} catch (WebServiceException | TopicNotSupportedFault | InvalidFilterFault | TopicExpressionDialectUnknownFault
| UnacceptableInitialTerminationTimeFault | SubscribeCreationFailedFault
| InvalidMessageContentExpressionFault | InvalidTopicExpressionFault | UnrecognizedPolicyRequestFault
| UnsupportedPolicyRequestFault | ResourceUnknownFault | NotifyMessageNotSupportedFault
| InvalidProducerPropertiesExpressionFault e) {
logger.debug("An exception occurred while subscribing to the notifications for thing '{}': {}",
getThing().getUID(), e.getMessage(), e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
return;
}
updateStatus(ThingStatus.ONLINE);
}
@Override
public void dispose() {
logger.debug("Disposing Helios IP handler.");
try {
unsubscribe();
if (endpoint != null) {
endpoint.stop();
}
endpoint = null;
terminationTime = null;
context = null;
notificationProducer = null;
subscription = null;
} catch (Exception e) {
logger.error("An exception occurred while disposing the Helios Thing Handler : {}", e.getMessage(), e);
}
}
@Override
public void notify(
@WebParam(partName = "Notify", name = "Notify", targetNamespace = "http://docs.oasis-open.org/wsn/b-2") Notify notify) {
for (Object object : notify.getAny()) {
try {
this.processNotification(context.createUnmarshaller().unmarshal((Element) object, SOAPEvent.class));
} catch (JAXBException e) {
logger.error("An exception occurred while processing a notification message : {}", e.getMessage(), e);
}
}
}
public void processNotification(JAXBElement<SOAPEvent> message) {
if (getThing().getStatus() == ThingStatus.ONLINE) {
SOAPEvent event = message.getValue();
// WS-Notification does not provide a mechanism to query existing
// subscriptions established before, so these keep lingering on the
// remote device. Therefore, when restarting the OH runtime, we
// might receive events more than one time, we need to filter these
// out
if (previousEvent == null || !previousEvent.equals(event)) {
previousEvent = event;
Object data = event.getData();
if (data instanceof SOAPKeyPressed) {
StringType valueType = new StringType(((SOAPKeyPressed) data).getKeyCode());
updateState(new ChannelUID(getThing().getUID(), KEY_PRESSED), valueType);
DateTimeType stampType = new DateTimeType(event.getTimestamp());
updateState(new ChannelUID(getThing().getUID(), KEY_PRESSED_STAMP), stampType);
}
if (data instanceof SOAPCallStateChanged) {
StringType valueType = new StringType(((SOAPCallStateChanged) data).getState());
updateState(new ChannelUID(getThing().getUID(), CALL_STATE), valueType);
valueType = new StringType(((SOAPCallStateChanged) data).getDirection());
updateState(new ChannelUID(getThing().getUID(), CALL_DIRECTION), valueType);
DateTimeType stampType = new DateTimeType(event.getTimestamp());
updateState(new ChannelUID(getThing().getUID(), CALL_STATE_STAMP), stampType);
}
if (data instanceof SOAPCardEntered) {
StringType valueType = new StringType(((SOAPCardEntered) data).getCard());
updateState(new ChannelUID(getThing().getUID(), CARD), valueType);
valueType = new StringType(((SOAPCardEntered) data).getValid());
updateState(new ChannelUID(getThing().getUID(), CARD_VALID), valueType);
DateTimeType stampType = new DateTimeType(event.getTimestamp());
updateState(new ChannelUID(getThing().getUID(), CARD_STAMP), stampType);
}
if (data instanceof SOAPCodeEntered) {
StringType valueType = new StringType(((SOAPCodeEntered) data).getCode());
updateState(new ChannelUID(getThing().getUID(), CODE), valueType);
valueType = new StringType(((SOAPCodeEntered) data).getValid());
updateState(new ChannelUID(getThing().getUID(), CODE_VALID), valueType);
DateTimeType stampType = new DateTimeType(event.getTimestamp());
updateState(new ChannelUID(getThing().getUID(), CODE_STAMP), stampType);
}
if (data instanceof SOAPDeviceState) {
StringType valueType = new StringType(((SOAPDeviceState) data).getState());
updateState(new ChannelUID(getThing().getUID(), DEVICE_STATE), valueType);
DateTimeType stampType = new DateTimeType(event.getTimestamp());
updateState(new ChannelUID(getThing().getUID(), DEVICE_STATE_STAMP), stampType);
}
} else {
logger.warn("Duplicate event received due to lingering subscriptions: '{}':'{}'", event.getEventName(),
event.getTimestamp());
}
}
}
public void renew(String newTerminationTime) throws ResourceUnknownFault, UnacceptableTerminationTimeFault {
if (subscription != null) {
Renew renew = new Renew();
renew.setTerminationTime(newTerminationTime);
RenewResponse response = subscription.renew(renew);
currentTime = response.getCurrentTime().toGregorianCalendar();
terminationTime = response.getTerminationTime().toGregorianCalendar();
SimpleDateFormat pFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
logger.debug("Renewed the subscription with ID '{}' for '{}' from {} until {}",
new Object[] { getSubscriptionID(), getThing().getUID(), pFormatter.format(currentTime.getTime()),
pFormatter.format(terminationTime.getTime()) });
}
}
public void unsubscribe() {
if (subscription != null) {
try {
subscription.unsubscribe(new Unsubscribe());
logger.debug("Unsubscribing the subscription with ID '{}' for '{}' ", getSubscriptionID(),
getThing().getUID());
} catch (UnableToDestroySubscriptionFault | ResourceUnknownFault e) {
logger.error("An exception occurred while unsubscribing from the subscription : {}", e.getMessage(), e);
}
}
}
public void subscribe(W3CEndpointReference epr)
throws TopicNotSupportedFault, InvalidFilterFault, TopicExpressionDialectUnknownFault,
UnacceptableInitialTerminationTimeFault, SubscribeCreationFailedFault, InvalidMessageContentExpressionFault,
InvalidTopicExpressionFault, UnrecognizedPolicyRequestFault, UnsupportedPolicyRequestFault,
ResourceUnknownFault, NotifyMessageNotSupportedFault, InvalidProducerPropertiesExpressionFault {
if (notificationProducer != null) {
Subscribe subscribeRequest = new Subscribe();
subscribeRequest.setConsumerReference(epr);
subscribeRequest.setFilter(new FilterType());
TopicExpressionType topicExp = new TopicExpressionType();
topicExp.getContent().add("");
topicExp.setDialect(DIALECT_URI);
subscribeRequest.getFilter().getAny()
.add(new JAXBElement<>(TOPIC_EXPRESSION, TopicExpressionType.class, topicExp));
subscribeRequest.setInitialTerminationTime(
new JAXBElement<>(INITIAL_TERMINATION_TIME, String.class, SUBSCRIPTION_PERIOD));
subscribeRequest.setSubscriptionPolicy(new Subscribe.SubscriptionPolicy());
subscribeRequest.getSubscriptionPolicy().getAny().add(new JAXBElement<>(MAXIMUM_NUMBER, Integer.class, 1));
subscribeRequest.getSubscriptionPolicy().getAny().add(new JAXBElement<>(SIMPLE_MESSAGES, Integer.class, 1));
GregorianCalendar now = new GregorianCalendar();
SimpleDateFormat pFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
subscribeRequest.getSubscriptionPolicy().getAny()
.add(new JAXBElement<>(START_TIME_STAMP, String.class, pFormatter.format(now.getTime())));
SubscribeResponse response = notificationProducer.subscribe(subscribeRequest);
if (response != null) {
currentTime = response.getCurrentTime().toGregorianCalendar();
terminationTime = response.getTerminationTime().toGregorianCalendar();
subscriptionReference = response.getSubscriptionReference();
Element element = DOMUtils.createDocument().createElement("elem");
subscriptionReference.writeTo(new DOMResult(element));
NodeList nl = element.getElementsByTagNameNS("http://www.2n.cz/2013/event", "SubscriptionId");
if (nl != null && nl.getLength() > 0) {
Element e = (Element) nl.item(0);
subscriptionID = DOMUtils.getContent(e).trim();
}
logger.debug("Established a subscription with ID '{}' for '{}' as from {} until {}",
new Object[] { subscriptionID, getThing().getUID(), pFormatter.format(currentTime.getTime()),
pFormatter.format(terminationTime.getTime()) });
java.util.Calendar triggerTime = terminationTime;
triggerTime.add(Calendar.MINUTE, -1);
logger.debug("Scheduling a renewal of the subscription with ID '{}' for '{}' to happen on {}",
new Object[] { subscriptionID, getThing().getUID(), pFormatter.format(triggerTime.getTime()) });
try {
scheduler.schedule(renewRunnable, triggerTime.getTimeInMillis() - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException e) {
logger.error("An exception occurred while scheduling a renewal : '{}'", e.getMessage(), e);
}
}
}
}
protected Runnable renewRunnable = new Runnable() {
@Override
public void run() {
SimpleDateFormat pFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
boolean result = false;
try {
((HeliosHandler27) getThing().getHandler()).renew(SUBSCRIPTION_PERIOD);
result = true;
} catch (Exception e) {
logger.error("An exception occurred while renewing the subscription : {}", e.getMessage(), e);
((HeliosHandler27) getThing().getHandler()).dispose();
((HeliosHandler27) getThing().getHandler()).initialize();
return;
}
if (result) {
java.util.Calendar triggerTime = terminationTime;
triggerTime.add(Calendar.MINUTE, -1);
logger.debug("Scheduling a renewal of the subscription with ID '{}' for '{}' to happen on {}",
new Object[] { subscriptionID, getThing().getUID(), pFormatter.format(triggerTime.getTime()) });
try {
scheduler.schedule(renewRunnable, triggerTime.getTimeInMillis() - System.currentTimeMillis(),
TimeUnit.MILLISECONDS);
} catch (RejectedExecutionException e) {
logger.error("An exception occurred while scheduling a renewal : '{}'", e.getMessage(), e);
}
}
}
};
}

View File

@ -1,56 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import java.util.HashSet;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
/**
* The {@link SOAPActionHandler} is a custom SOAP handler that modifies some SOAP
* headers in order to get the Helios comm. working
*
* @author Karel Goderis - Initial contribution
*/
public class SOAPActionHandler implements SOAPHandler<SOAPMessageContext> {
@Override
public boolean handleMessage(SOAPMessageContext context) {
// Nothing to do here
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
// Nothing to do here
return false;
}
@Override
public void close(MessageContext context) {
// Nothing to do here
}
@Override
public Set<QName> getHeaders() {
Set<QName> set = new HashSet<>();
// Make sure the '[{http://www.w3.org/2005/08/addressing}]Action' header
// is handled in case the device set the 'MustUnderstand' attribute to
// '1'
set.add(new QName("http://www.w3.org/2005/08/addressing", "Action"));
return set;
}
}

View File

@ -1,52 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
/**
* Helios SOAP Protocol Message
*
* @author Karel Goderis - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Data", namespace = HeliosHandler27.HELIOS_URI)
public class SOAPCallStateChanged extends SOAPDataField {
@XmlElement(name = "State", namespace = HeliosHandler27.HELIOS_URI)
protected String state;
@XmlElement(name = "Direction", namespace = HeliosHandler27.HELIOS_URI)
protected String direction;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
this.direction = direction;
}
}

View File

@ -1,52 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
/**
* Helios SOAP Protocol Message
*
* @author Karel Goderis - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Data", namespace = HeliosHandler27.HELIOS_URI)
public class SOAPCardEntered extends SOAPDataField {
@XmlElement(name = "Card", namespace = HeliosHandler27.HELIOS_URI)
protected String card;
@XmlElement(name = "Valid", namespace = HeliosHandler27.HELIOS_URI)
protected String valid;
public String getCard() {
return card;
}
public void setCard(String card) {
this.card = card;
}
public String getValid() {
return valid;
}
public void setValid(String valid) {
this.valid = valid;
}
}

View File

@ -1,52 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
/**
* Helios SOAP Protocol Message
*
* @author Karel Goderis - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Data", namespace = HeliosHandler27.HELIOS_URI)
public class SOAPCodeEntered extends SOAPDataField {
@XmlElement(name = "Code", namespace = HeliosHandler27.HELIOS_URI)
protected String code;
@XmlElement(name = "Valid", namespace = HeliosHandler27.HELIOS_URI)
protected String valid;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getValid() {
return valid;
}
public void setValid(String valid) {
this.valid = valid;
}
}

View File

@ -1,24 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/**
* Helios SOAP Protocol Message
*
* @author Karel Goderis - Initial contribution
*/
@XmlJavaTypeAdapter(SOAPDataFieldAdapter.class)
public abstract class SOAPDataField {
}

View File

@ -1,87 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
* The {@link SOAPDataFieldAdapter} is a helper class that is used to
* unmarshal some 'variable' SOAP messages
*
* @author Karel Goderis - Initial contribution
*/
public class SOAPDataFieldAdapter extends XmlAdapter<SOAPDataFieldAdapter.AdaptedHeliosDataField, SOAPDataField> {
public static class AdaptedHeliosDataField {
@XmlElement
public String State;
@XmlElement
public String Direction;
@XmlElement
public String Code;
@XmlElement
public String Valid;
@XmlElement
public String Key;
@XmlElement
public String Card;
}
@Override
public AdaptedHeliosDataField marshal(SOAPDataField arg0) throws Exception {
return null;
}
@Override
public SOAPDataField unmarshal(AdaptedHeliosDataField arg0) throws Exception {
if (null == arg0) {
return null;
}
if (null != arg0.Card && null != arg0.Valid) {
SOAPCardEntered heliosCardEntered = new SOAPCardEntered();
heliosCardEntered.setCard(arg0.Card);
heliosCardEntered.setValid(arg0.Valid);
return heliosCardEntered;
}
if (null != arg0.Code && null != arg0.Valid) {
SOAPCodeEntered heliosCodeEntered = new SOAPCodeEntered();
heliosCodeEntered.setCode(arg0.Code);
heliosCodeEntered.setValid(arg0.Valid);
return heliosCodeEntered;
}
if (null != arg0.Key) {
SOAPKeyPressed heliosKeyPressed = new SOAPKeyPressed();
heliosKeyPressed.setKeyCode(arg0.Key);
return heliosKeyPressed;
}
if (null != arg0.State && null != arg0.Direction) {
SOAPCallStateChanged heliosCallStateChanged = new SOAPCallStateChanged();
heliosCallStateChanged.setState(arg0.State);
heliosCallStateChanged.setDirection(arg0.Direction);
return heliosCallStateChanged;
}
if (null != arg0.State) {
SOAPDeviceState heliosDeviceState = new SOAPDeviceState();
heliosDeviceState.setState(arg0.State);
return heliosDeviceState;
}
return null;
}
}

View File

@ -1,41 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
/**
* Helios SOAP Protocol Message
*
* @author Karel Goderis - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Data", namespace = HeliosHandler27.HELIOS_URI)
public class SOAPDeviceState extends SOAPDataField {
@XmlElement(name = "State", namespace = HeliosHandler27.HELIOS_URI)
protected String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}

View File

@ -1,108 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
/**
* Helios SOAP Protocol Message
*
* @author Karel Goderis - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "HeliosEvent", namespace = HeliosHandler27.HELIOS_URI, propOrder = { "timestamp", "eventName", "data" })
@XmlRootElement(name = "Msg")
public class SOAPEvent {
@XmlElement(name = "Timestamp", namespace = HeliosHandler27.HELIOS_URI)
protected String timestamp;
@XmlElement(name = "EventName", namespace = HeliosHandler27.HELIOS_URI)
protected String eventName;
@XmlElement(name = "Data", namespace = HeliosHandler27.HELIOS_URI)
protected SOAPDataField data;
public SOAPDataField getData() {
return data;
}
public void setData(SOAPDataField data) {
this.data = data;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SOAPEvent)) {
return false;
}
if (obj == this) {
return true;
}
SOAPEvent event = (SOAPEvent) obj;
if (event.getEventName().equals(eventName) && event.getTimestamp().equals(timestamp)) {
Object eventData = event.getData();
if (data instanceof SOAPKeyPressed) {
return ((SOAPKeyPressed) data).getKeyCode().equals(((SOAPKeyPressed) eventData).getKeyCode());
}
if (data instanceof SOAPCallStateChanged) {
return ((SOAPCallStateChanged) data).getDirection()
.equals(((SOAPCallStateChanged) eventData).getDirection())
&& ((SOAPCallStateChanged) data).getState()
.equals(((SOAPCallStateChanged) eventData).getState());
}
if (data instanceof SOAPCardEntered) {
return ((SOAPCardEntered) data).getCard().equals(((SOAPCardEntered) eventData).getCard())
&& ((SOAPCardEntered) data).getValid().equals(((SOAPCardEntered) eventData).getValid());
}
if (data instanceof SOAPCodeEntered) {
return ((SOAPCodeEntered) data).getCode().equals(((SOAPCodeEntered) eventData).getCode())
&& ((SOAPCodeEntered) data).getValid().equals(((SOAPCodeEntered) eventData).getValid());
}
if (data instanceof SOAPDeviceState) {
return ((SOAPDeviceState) data).getState().equals(((SOAPDeviceState) eventData).getState());
}
}
return false;
}
}

View File

@ -1,41 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
/**
* Helios SOAP Protocol Message
*
* @author Karel Goderis - Initial contribution
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Data", namespace = HeliosHandler27.HELIOS_URI)
public class SOAPKeyPressed extends SOAPDataField {
@XmlElement(name = "Key", namespace = HeliosHandler27.HELIOS_URI)
protected String keyCode;
public String getKeyCode() {
return keyCode;
}
public void setKeyCode(String code) {
this.keyCode = code;
}
}

View File

@ -1,57 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
/**
* The {@link SOAPObjectFactory} is a helper class that is used to generate JAXB
* Elements
*
* @author Karel Goderis - Initial contribution
*/
@XmlRegistry
public class SOAPObjectFactory {
private static final QName DATA_QNAME = new QName(HeliosHandler27.HELIOS_URI, "Data");
@XmlElementDecl(namespace = HeliosHandler27.HELIOS_URI, name = "CallStateChanged")
public JAXBElement<SOAPCallStateChanged> createHeliosCallStateChanged(SOAPCallStateChanged value) {
return new JAXBElement<>(DATA_QNAME, SOAPCallStateChanged.class, null, value);
}
@XmlElementDecl(namespace = HeliosHandler27.HELIOS_URI, name = "CodeEntered")
public JAXBElement<SOAPCodeEntered> createHeliosCodeEntered(SOAPCodeEntered value) {
return new JAXBElement<>(DATA_QNAME, SOAPCodeEntered.class, null, value);
}
@XmlElementDecl(namespace = HeliosHandler27.HELIOS_URI, name = "CardEntered")
public JAXBElement<SOAPCardEntered> createHeliosCardEntered(SOAPCardEntered value) {
return new JAXBElement<>(DATA_QNAME, SOAPCardEntered.class, null, value);
}
@XmlElementDecl(namespace = HeliosHandler27.HELIOS_URI, name = "DeviceState")
public JAXBElement<SOAPDeviceState> createHeliosDeviceState(SOAPDeviceState value) {
return new JAXBElement<>(DATA_QNAME, SOAPDeviceState.class, null, value);
}
@XmlElementDecl(namespace = HeliosHandler27.HELIOS_URI, name = "KeyPressed")
public JAXBElement<SOAPKeyPressed> createHeliosKeyPressedd(SOAPKeyPressed value) {
return new JAXBElement<>(DATA_QNAME, SOAPKeyPressed.class, null, value);
}
}

View File

@ -1,73 +0,0 @@
/**
* Copyright (c) 2010-2022 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.helios.internal.ws.soap;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import org.openhab.binding.helios.internal.handler.HeliosHandler27;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SOAPSubscriptionActionHandler} is a custom SOAP handler that modifies
* some SOAP headers in order to get the Helios comm. working
*
* @author Karel Goderis - Initial contribution
*/
public class SOAPSubscriptionActionHandler extends SOAPActionHandler {
private Logger logger = LoggerFactory.getLogger(SOAPSubscriptionActionHandler.class);
private HeliosHandler27 handler;
public SOAPSubscriptionActionHandler(HeliosHandler27 heliosHandler) {
this.handler = heliosHandler;
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isRequest) {
try {
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
SOAPHeader soapHeader = soapEnv.getHeader();
if (soapHeader == null) {
soapHeader = soapEnv.addHeader();
}
QName qname = new QName("http://www.2n.cz/2013/event", "SubscriptionId");
SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(qname);
soapHeaderElement.addAttribute(
new QName("http://www.w3.org/2005/08/addressing", "IsReferenceParameter"), "true");
if (handler.getSubscriptionID() != null) {
soapHeaderElement.addTextNode(handler.getSubscriptionID());
}
soapMsg.saveChanges();
} catch (Exception e) {
logger.debug("An exception occurred while formatting a SOAP header : '{}'", e.getMessage());
}
}
return true;
}
}

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="helios"
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="ipvario27">
<label>Helios IP Vario</label>
<description>Helios IP Vario Door Station / Intercom with Firmware v2.7</description>
<channels>
<channel id="keypressed" typeId="keypressed"/>
<channel id="keypressedstamp" typeId="keypressedstamp"/>
<channel id="callstate" typeId="callstate"/>
<channel id="calldirection" typeId="calldirection"/>
<channel id="callstatestamp" typeId="callstatestamp"/>
<channel id="card" typeId="card"/>
<channel id="cardvalid" typeId="cardvalid"/>
<channel id="cardstamp" typeId="cardstamp"/>
<channel id="code" typeId="code"/>
<channel id="codevalid" typeId="codevalid"/>
<channel id="codestamp" typeId="codestamp"/>
<channel id="devicestate" typeId="devicestate"/>
<channel id="devicestatestamp" typeId="devicestatestamp"/>
</channels>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the Helios IP device</description>
</parameter>
<parameter name="openHABipAddress" type="text" required="true">
<context>network-address</context>
<label>Network Address</label>
<description>Network address of the openHAB host</description>
</parameter>
<parameter name="openHABportNumber" type="integer" required="true">
<label>Port Number</label>
<description>TCP port number the notification web service will be registered on</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>