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,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.opengarage-${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-opengarage" description="OpenGarage Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.opengarage/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,45 @@
/**
* 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.opengarage.internal;
import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link OpenGarageBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Paul Smedley - Initial contribution
*/
@NonNullByDefault
public class OpenGarageBindingConstants {
private static final String BINDING_ID = "opengarage";
// List of all Thing Type UIDs
public static final ThingTypeUID OPENGARAGE_THING = new ThingTypeUID(BINDING_ID, "opengarage");
// List of all Channel ids
public static final String CHANNEL_OG_DISTANCE = "distance";
public static final String CHANNEL_OG_STATUS = "status"; // now deprecated
public static final String CHANNEL_OG_STATUS_SWITCH = "status-switch";
public static final String CHANNEL_OG_STATUS_CONTACT = "status-contact";
public static final String CHANNEL_OG_STATUS_ROLLERSHUTTER = "status-rollershutter";
public static final String CHANNEL_OG_VEHICLE = "vehicle"; // now deprecated
public static final String CHANNEL_OG_VEHICLE_STATUS = "vehicle-status";
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(OPENGARAGE_THING);
}

View File

@@ -0,0 +1,25 @@
/**
* 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.opengarage.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The OpenGarageChannelConfiguration class contains fields mapping thing configuration parameters.
*
* @author Dan Cunningham - Initial contribution
*/
@NonNullByDefault
public class OpenGarageChannelConfiguration {
public boolean invert = false;
}

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.opengarage.internal;
import java.io.IOException;
/**
* Exception for when an unexpected response is received from the OpenGarage controller.
*
* @author Paul Smedley - Initial contribution
*
*/
public class OpenGarageCommunicationException extends IOException {
private static final long serialVersionUID = 529232811860854017L;
public OpenGarageCommunicationException(String message) {
super(message);
}
public OpenGarageCommunicationException(Throwable ex) {
super(ex);
}
public OpenGarageCommunicationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,25 @@
/**
* 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.opengarage.internal;
/**
* The OpenGarageConfiguration class contains fields mapping thing configuration parameters.
*
* @author Paul Smedley - Initial contribution
*/
public class OpenGarageConfiguration {
public String hostname;
public long port = 80;
public String password = "opendoor";
public long refresh = 10;
}

View File

@@ -0,0 +1,193 @@
/**
* 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.opengarage.internal;
import java.io.IOException;
import java.util.concurrent.Future;
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.opengarage.internal.api.ControllerVariables;
import org.openhab.binding.opengarage.internal.api.Enums.OpenGarageCommand;
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.QuantityType;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.library.unit.MetricPrefix;
import org.openhab.core.library.unit.SIUnits;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link OpenGarageHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Paul Smedley - Initial contribution
* @author Dan Cunningham - Minor improvements to vehicle state and invert option
*/
@NonNullByDefault
public class OpenGarageHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(OpenGarageHandler.class);
private long refreshInterval;
private @NonNullByDefault({}) OpenGarageWebTargets webTargets;
private @Nullable ScheduledFuture<?> pollFuture;
public OpenGarageHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
try {
logger.debug("Received command {} for thing '{}' on channel {}", command, thing.getUID().getAsString(),
channelUID.getId());
boolean invert = isChannelInverted(channelUID.getId());
switch (channelUID.getId()) {
case OpenGarageBindingConstants.CHANNEL_OG_STATUS:
case OpenGarageBindingConstants.CHANNEL_OG_STATUS_SWITCH:
case OpenGarageBindingConstants.CHANNEL_OG_STATUS_ROLLERSHUTTER:
if (command.equals(OnOffType.ON) || command.equals(UpDownType.UP)) {
changeStatus(invert ? OpenGarageCommand.CLOSE : OpenGarageCommand.OPEN);
return;
} else if (command.equals(OnOffType.OFF) || command.equals(UpDownType.DOWN)) {
changeStatus(invert ? OpenGarageCommand.OPEN : OpenGarageCommand.CLOSE);
return;
} else if (command.equals(StopMoveType.STOP) || command.equals(StopMoveType.MOVE)) {
changeStatus(OpenGarageCommand.CLICK);
return;
}
break;
default:
}
} catch (OpenGarageCommunicationException ex) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
}
}
@Override
public void initialize() {
OpenGarageConfiguration config = getConfigAs(OpenGarageConfiguration.class);
logger.debug("config.hostname = {}, refresh = {}, port = {}", config.hostname, config.refresh, config.port);
if (config.hostname == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Hostname/IP address must be set");
} else {
webTargets = new OpenGarageWebTargets(config.hostname, config.port, config.password);
refreshInterval = config.refresh;
schedulePoll();
}
}
@Override
public void dispose() {
super.dispose();
stopPoll();
}
private void schedulePoll() {
if (pollFuture != null) {
pollFuture.cancel(false);
}
logger.debug("Scheduling poll for 1 second out, then every {} s", refreshInterval);
pollFuture = scheduler.scheduleWithFixedDelay(this::poll, 1, refreshInterval, TimeUnit.SECONDS);
}
private void poll() {
try {
logger.debug("Polling for state");
pollStatus();
} catch (IOException e) {
logger.debug("Could not connect to OpenGarage controller", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
} catch (RuntimeException e) {
logger.warn("Unexpected error connecting to OpenGarage controller", e);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
private void stopPoll() {
final Future<?> future = pollFuture;
if (future != null && !future.isCancelled()) {
future.cancel(true);
pollFuture = null;
}
}
private void pollStatus() throws IOException {
ControllerVariables controllerVariables = webTargets.getControllerVariables();
updateStatus(ThingStatus.ONLINE);
if (controllerVariables != null) {
updateState(OpenGarageBindingConstants.CHANNEL_OG_DISTANCE,
new QuantityType<>(controllerVariables.dist, MetricPrefix.CENTI(SIUnits.METRE)));
boolean invert = isChannelInverted(OpenGarageBindingConstants.CHANNEL_OG_STATUS_SWITCH);
switch (controllerVariables.door) {
case 0:
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS, invert ? OnOffType.ON : OnOffType.OFF);
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS_SWITCH,
invert ? OnOffType.ON : OnOffType.OFF);
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS_ROLLERSHUTTER, UpDownType.DOWN);
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS_CONTACT, OpenClosedType.CLOSED);
break;
case 1:
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS, invert ? OnOffType.OFF : OnOffType.ON);
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS_SWITCH,
invert ? OnOffType.OFF : OnOffType.ON);
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS_ROLLERSHUTTER, UpDownType.UP);
updateState(OpenGarageBindingConstants.CHANNEL_OG_STATUS_CONTACT, OpenClosedType.OPEN);
break;
default:
logger.warn("Received unknown door value: {}", controllerVariables.door);
}
switch (controllerVariables.vehicle) {
case 0:
updateState(OpenGarageBindingConstants.CHANNEL_OG_VEHICLE, new StringType("No vehicle detected"));
break;
case 1:
updateState(OpenGarageBindingConstants.CHANNEL_OG_VEHICLE, new StringType("Vehicle detected"));
break;
case 2:
updateState(OpenGarageBindingConstants.CHANNEL_OG_VEHICLE,
new StringType("Vehicle status unknown"));
break;
default:
logger.warn("Received unknown vehicle value: {}", controllerVariables.vehicle);
}
updateState(OpenGarageBindingConstants.CHANNEL_OG_VEHICLE_STATUS,
new DecimalType(controllerVariables.vehicle));
}
}
private void changeStatus(OpenGarageCommand status) throws OpenGarageCommunicationException {
webTargets.setControllerVariables(status);
}
private boolean isChannelInverted(String channelUID) {
Channel channel = getThing().getChannel(channelUID);
return channel != null && channel.getConfiguration().as(OpenGarageChannelConfiguration.class).invert;
}
}

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.opengarage.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
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 OpenGarageHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Paul Smedley - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.opengarage")
@NonNullByDefault
public class OpenGarageHandlerFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return OpenGarageBindingConstants.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(OpenGarageBindingConstants.OPENGARAGE_THING)) {
return new OpenGarageHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,91 @@
/**
* 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.opengarage.internal;
import java.io.IOException;
import org.openhab.binding.opengarage.internal.api.ControllerVariables;
import org.openhab.binding.opengarage.internal.api.Enums.OpenGarageCommand;
import org.openhab.core.io.net.http.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Handles performing the actual HTTP requests for communicating with Opengarage units.
*
* @author Paul Smedley - Initial Contribution
*
*/
public class OpenGarageWebTargets {
private static final int TIMEOUT_MS = 30000;
private String getControllerVariablesUri;
private String changeControllerVariablesUri;
private final Logger logger = LoggerFactory.getLogger(OpenGarageWebTargets.class);
public OpenGarageWebTargets(String ipAddress, long port, String password) {
String baseUri = "http://" + ipAddress + ":" + port + "/";
getControllerVariablesUri = baseUri + "jc";
changeControllerVariablesUri = baseUri + "cc?dkey=" + password;
}
public ControllerVariables getControllerVariables() throws OpenGarageCommunicationException {
String response = invoke(getControllerVariablesUri);
return ControllerVariables.parse(response);
}
public void setControllerVariables(OpenGarageCommand request) throws OpenGarageCommunicationException {
logger.debug("Received request: {}", request);
String queryParams = null;
switch (request) {
case OPEN:
queryParams = "&open=1";
break;
case CLOSE:
queryParams = "&close=1";
break;
case CLICK:
queryParams = "&click=1";
break;
}
if (queryParams != null) {
invoke(changeControllerVariablesUri, queryParams);
}
}
private String invoke(String uri) throws OpenGarageCommunicationException {
return invoke(uri, "");
}
private String invoke(String uri, String params) throws OpenGarageCommunicationException {
String uriWithParams = uri + params;
logger.debug("Calling url: {}", uriWithParams);
String response;
synchronized (this) {
try {
response = HttpUtil.executeUrl("GET", uriWithParams, TIMEOUT_MS);
} catch (IOException ex) {
logger.debug("{}", ex.getLocalizedMessage(), ex);
// Response will also be set to null if parsing in executeUrl fails so we use null here to make the
// error check below consistent.
response = null;
}
}
if (response == null) {
throw new OpenGarageCommunicationException(
String.format("OpenGaragecontroller returned error while invoking %s", uriWithParams));
}
return response;
}
}

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.opengarage.internal.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* Class for holding the set of parameters used to read the controller variables.
*
* @author Paul Smedley - Initial Contribution
*
*/
public class ControllerVariables {
private static Logger LOGGER = LoggerFactory.getLogger(ControllerVariables.class);
public int dist;
public int door;
public int vehicle;
public int rcnt;
public int fwv;
public String name;
public String mac;
public String cid;
public int rssi;
private ControllerVariables() {
}
public static ControllerVariables parse(String response) {
LOGGER.debug("Parsing string: \"{}\"", response);
/* parse json string */
JsonObject jsonObject = new JsonParser().parse(response).getAsJsonObject();
ControllerVariables info = new ControllerVariables();
info.dist = jsonObject.get("dist").getAsInt();
info.door = jsonObject.get("door").getAsInt();
info.vehicle = jsonObject.get("vehicle").getAsInt();
info.rcnt = jsonObject.get("rcnt").getAsInt();
info.fwv = jsonObject.get("fwv").getAsInt();
info.name = jsonObject.get("name").getAsString();
info.mac = jsonObject.get("mac").getAsString();
info.cid = jsonObject.get("cid").getAsString();
info.rssi = jsonObject.get("rssi").getAsInt();
return info;
}
}

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.opengarage.internal.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Container class for enums related to opengarage
*
* @author Paul Smedley <paul@smedley.id.au> - Initial contribution
*
*/
public class Enums {
public enum OpenGarageCommand {
OPEN("open"),
CLOSE("close"),
CLICK("click");
private static final Logger LOGGER = LoggerFactory.getLogger(OpenGarageCommand.class);
private final String value;
OpenGarageCommand(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="opengarage" 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>OpenGarage Binding</name>
<description>This is the binding for OpenGarage.</description>
<author>Paul Smedley</author>
</binding:binding>

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="opengarage"
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="opengarage">
<label>OpenGarage</label>
<description>OpenGarage Controller</description>
<channels>
<channel id="distance" typeId="opengarage-distance"/>
<channel id="status" typeId="opengarage-status"/>
<channel id="status-switch" typeId="opengarage-status-switch"/>
<channel id="status-contact" typeId="opengarage-status-contact"/>
<channel id="status-rollershutter" typeId="opengarage-status-rollershutter"/>
<channel id="vehicle" typeId="opengarage-vehicle"/>
<channel id="vehicle-status" typeId="opengarage-vehicle-status"/>
</channels>
<config-description>
<parameter name="hostname" type="text" required="true">
<label>Hostname/IP Address</label>
<description>The host name or IP address of the OpenGarage Web API interface.</description>
</parameter>
<parameter name="port" type="integer" min="1" max="65535">
<label>Port</label>
<description>Port of the OpenGarage Web API interface.</description>
<default>80</default>
</parameter>
<parameter name="password" type="text">
<label>Password</label>
<description>The admin password used to access the Web API interface.</description>
<context>password</context>
<default>opendoor</default>
</parameter>
<parameter name="refresh" type="integer">
<label>Refresh Interval</label>
<description>Specifies the refresh interval in seconds.</description>
<default>60</default>
</parameter>
</config-description>
</thing-type>
<channel-type id="opengarage-distance">
<item-type>Number:Length</item-type>
<label>Distance</label>
<description>Distance Reading from the OG unit</description>
<state readOnly="true" pattern="%d %unit%"/>
</channel-type>
<channel-type id="opengarage-status" advanced="true">
<item-type>Switch</item-type>
<label>Status</label>
<description>On/Off Status of the OG unit (now deprecated, use status-switch instead)</description>
<config-description>
<parameter name="invert" type="boolean">
<label>Invert Switch</label>
<description>Invert switch to ON=Closed, OFF=Open</description>
<default>false</default>
<options>
<option value="true">Yes</option>
<option value="false">No</option>
</options>
<limitToOptions>true</limitToOptions>
</parameter>
</config-description>
</channel-type>
<channel-type id="opengarage-status-switch">
<item-type>Switch</item-type>
<label>Status</label>
<description>On/Off Status of the OG unit</description>
<config-description>
<parameter name="invert" type="boolean">
<label>Invert Switch</label>
<description>Invert switch to ON=Closed, OFF=Open</description>
<default>false</default>
<options>
<option value="true">Yes</option>
<option value="false">No</option>
</options>
<limitToOptions>true</limitToOptions>
</parameter>
</config-description>
</channel-type>
<channel-type id="opengarage-status-contact">
<item-type>Contact</item-type>
<label>Contact Status</label>
<description>Contact Status of the OG unit</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="opengarage-status-rollershutter">
<item-type>Rollershutter</item-type>
<label>Rollershutter Status</label>
<description>Roller Shutter Status of the OG unit</description>
</channel-type>
<channel-type id="opengarage-vehicle" advanced="true">
<item-type>String</item-type>
<label>Vehicle Presence</label>
<description>Is a vehicle present or not (now deprecated, use vehicle-status instead)</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="opengarage-vehicle-status">
<item-type>Number</item-type>
<label>Vehicle Presence</label>
<description>Vehicle presence detection</description>
<state readOnly="true">
<options>
<option value="0">No vehicle detected</option>
<option value="1">Vehicle detected</option>
<option value="2">Vehicle status unknown</option>
</options>
</state>
</channel-type>
</thing:thing-descriptions>