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,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.zway-${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-zway" description="Z-Way Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle dependency="true">mvn:org.apache.commons/commons-lang3/3.4</bundle>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.zway/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,119 @@
/**
* 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.zway.internal;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link ZWayBinding} class defines common constants, which are
* used across the whole binding.
*
* @author Patrick Hecker - Initial contribution
*/
@NonNullByDefault
public class ZWayBindingConstants {
public static final String BINDING_ID = "zway";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "zwayServer");
public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "zwayDevice");
public static final ThingTypeUID THING_TYPE_VIRTUAL_DEVICE = new ThingTypeUID(BINDING_ID, "zwayVirtualDevice");
public static final Set<ThingTypeUID> SUPPORTED_DEVICE_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_DEVICE, THING_TYPE_VIRTUAL_DEVICE).collect(Collectors.toSet()));
// List of ignored devices for Discovery
public static final Set<String> DISCOVERY_IGNORED_DEVICES = Collections
.unmodifiableSet(Collections.singleton(("BatteryPolling")));
// List of all Channel IDs
public static final String BATTERY_CHANNEL = "battery";
public static final String DOORLOCK_CHANNEL = "doorlock";
public static final String SENSOR_BINARY_CHANNEL = "sensorBinary";
public static final String SENSOR_MULTILEVEL_CHANNEL = "sensorMultilevel";
public static final String SENSOR_DISCRETE_CHANNEL = "sensorDiscrete";
public static final String SWITCH_BINARY_CHANNEL = "switchBinary";
public static final String SWITCH_CONTROL_CHANNEL = "switchControl";
public static final String SWITCH_MULTILEVEL_CHANNEL = "switchMultilevel";
// switch multilevel (color)
public static final String SWITCH_COLOR_CHANNEL = "switchColor";
public static final String SWITCH_COLOR_TEMPERATURE_CHANNEL = "switchColorTemperature";
// thermostat
public static final String THERMOSTAT_MODE_CHANNEL = "thermostatMode";
public static final String THERMOSTAT_SET_POINT_CHANNEL = "thermostatSetPoint";
public static final String THERMOSTAT_MODE_CC_CHANNEL = "thermostatModeCC";
// sensor multilevel
public static final String SENSOR_TEMPERATURE_CHANNEL = "sensorTemperature";
public static final String SENSOR_LUMINOSITY_CHANNEL = "sensorLuminosity";
public static final String SENSOR_HUMIDITY_CHANNEL = "sensorHumidity";
public static final String SENSOR_BAROMETER_CHANNEL = "sensorBarometer";
public static final String SENSOR_ULTRAVIOLET_CHANNEL = "sensorUltraviolet";
public static final String SENSOR_CO2_CHANNEL = "sensorCO2";
public static final String SENSOR_ENERGY_CHANNEL = "sensorEnergy";
// sensor multilevel (meter)
public static final String SENSOR_METER_KWH_CHANNEL = "sensorMeterKWh";
public static final String SENSOR_METER_W_CHANNEL = "sensorMeterW";
// sensor binary
public static final String SENSOR_SMOKE_CHANNEL = "sensorSmoke";
public static final String SENSOR_CO_CHANNEL = "sensorCo";
public static final String SENSOR_FLOOD_CHANNEL = "sensorFlood";
public static final String SENSOR_TAMPER_CHANNEL = "sensorTamper";
public static final String SENSOR_DOOR_WINDOW_CHANNEL = "sensorDoorWindow";
public static final String SENSOR_MOTION_CHANNEL = "sensorMotion";
// switch binary
public static final String SWITCH_POWER_OUTLET_CHANNEL = "switchPowerOutlet";
// switch multilevel
public static final String SWITCH_ROLLERSHUTTER_CHANNEL = "switchBlinds";
// special channels
public static final String ACTIONS_CHANNEL = "actions";
public static final String SECURE_INCLUSION_CHANNEL = "secureInclusion";
public static final String INCLUSION_CHANNEL = "inclusion";
public static final String EXCLUSION_CHANNEL = "exclusion";
public static final String ACTIONS_CHANNEL_OPTION_REFRESH = "REFRESH";
/* Bridge config properties */
public static final String BRIDGE_CONFIG_ZWAY_SERVER_IP_ADDRESS = "zwayServerIpAddress";
public static final String BRIDGE_CONFIG_ZWAY_SERVER_PORT = "zwayServerPort";
public static final String BRIDGE_CONFIG_ZWAY_SERVER_PROTOCOL = "zwayServerProtocol";
public static final String BRIDGE_CONFIG_ZWAY_SERVER_USERNAME = "zwayServerUsername";
public static final String BRIDGE_CONFIG_ZWAY_SERVER_PASSWORD = "zwayServerPassword";
public static final String BRIDGE_CONFIG_POLLING_INTERVAL = "pollingInterval";
public static final String DEVICE_CONFIG_NODE_ID = "nodeId";
public static final String DEVICE_CONFIG_VIRTUAL_DEVICE_ID = "deviceId";
public static final String DEVICE_PROP_LOCATION = "location";
public static final String DEVICE_PROP_MANUFACTURER_ID = "manufacturerId";
public static final String DEVICE_PROP_DEVICE_TYPE = "deviceType";
public static final String DEVICE_PROP_ZDDXMLFILE = "zddxmlfile";
public static final String DEVICE_PROP_SDK = "SDK";
public static final String DEVICE_PROP_LAST_UPDATE = "lastUpdate";
/* Bridge properties */
public static final String BRIDGE_PROP_SOFTWARE_REVISION_VERSION = "softwareRevisionVersion";
public static final String BRIDGE_PROP_SOFTWARE_REVISION_DATE = "softwareRevisionDate";
public static final String BRIDGE_PROP_SDK = "SDK";
public static final String BRIDGE_PROP_MANUFACTURER_ID = "manufacturerId";
public static final String BRIDGE_PROP_SECURE_INCLUSION = "secureInclusion";
public static final String BRIDGE_PROP_FREQUENCY = "frequency";
}

View File

@@ -0,0 +1,89 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.zway.internal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openhab.binding.zway.internal.discovery.ZWayDeviceDiscoveryService;
import org.openhab.binding.zway.internal.handler.ZWayBridgeHandler;
import org.openhab.binding.zway.internal.handler.ZWayZAutomationDeviceHandler;
import org.openhab.binding.zway.internal.handler.ZWayZWaveDeviceHandler;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Component;
/**
* The {@link ZWayHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Patrick Hecker - Initial contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.zway")
public class ZWayHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(ZWayBridgeHandler.SUPPORTED_THING_TYPE, ZWayZAutomationDeviceHandler.SUPPORTED_THING_TYPE,
ZWayZWaveDeviceHandler.SUPPORTED_THING_TYPE).collect(Collectors.toSet()));
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected ThingHandler createHandler(Thing thing) {
if (ZWayBridgeHandler.SUPPORTED_THING_TYPE.equals(thing.getThingTypeUID())) {
ZWayBridgeHandler handler = new ZWayBridgeHandler((Bridge) thing);
registerDeviceDiscoveryService(handler);
return handler;
} else if (ZWayZAutomationDeviceHandler.SUPPORTED_THING_TYPE.equals(thing.getThingTypeUID())) {
return new ZWayZAutomationDeviceHandler(thing);
} else if (ZWayZWaveDeviceHandler.SUPPORTED_THING_TYPE.equals(thing.getThingTypeUID())) {
return new ZWayZWaveDeviceHandler(thing);
} else {
return null;
}
}
@Override
protected synchronized void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof ZWayBridgeHandler) {
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.remove(thingHandler.getThing().getUID());
if (serviceReg != null) {
serviceReg.unregister();
}
}
}
private synchronized void registerDeviceDiscoveryService(ZWayBridgeHandler handler) {
ZWayDeviceDiscoveryService discoveryService = new ZWayDeviceDiscoveryService(handler);
this.discoveryServiceRegs.put(handler.getThing().getUID(),
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
}
}

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.zway.internal.config;
import static org.openhab.binding.zway.internal.ZWayBindingConstants.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* The {@link ZWayBridgeConfiguration} class defines the model for a bridge configuration.
*
* @author Patrick Hecker - Initial contribution, remove openHAB configuration
*/
public class ZWayBridgeConfiguration {
private String zwayServerIpAddress;
private Integer zwayServerPort;
private String zwayServerProtocol;
private String zwayServerUsername;
private String zwayServerPassword;
private Integer pollingInterval;
public String getZWayIpAddress() {
return zwayServerIpAddress;
}
public void setZWayIpAddress(String ipAddress) {
this.zwayServerIpAddress = ipAddress;
}
public Integer getZWayPort() {
return zwayServerPort;
}
public void setZWayPort(Integer port) {
this.zwayServerPort = port;
}
public String getZWayProtocol() {
return zwayServerProtocol;
}
public void setZWayProtocol(String protocol) {
this.zwayServerProtocol = protocol;
}
public String getZWayUsername() {
return zwayServerUsername;
}
public void setZWayUsername(String username) {
this.zwayServerUsername = username;
}
public String getZWayPassword() {
return zwayServerPassword;
}
public void setZWayPassword(String password) {
this.zwayServerPassword = password;
}
public Integer getPollingInterval() {
return pollingInterval;
}
public void setPollingInterval(Integer pollingInterval) {
this.pollingInterval = pollingInterval;
}
@Override
public String toString() {
return new ToStringBuilder(this).append(BRIDGE_CONFIG_ZWAY_SERVER_IP_ADDRESS, this.getZWayIpAddress())
.append(BRIDGE_CONFIG_ZWAY_SERVER_PORT, this.getZWayPort())
.append(BRIDGE_CONFIG_ZWAY_SERVER_PROTOCOL, this.getZWayProtocol())
.append(BRIDGE_CONFIG_ZWAY_SERVER_USERNAME, this.getZWayUsername())
.append(BRIDGE_CONFIG_ZWAY_SERVER_PASSWORD, this.getZWayPassword())
.append(BRIDGE_CONFIG_POLLING_INTERVAL, this.getPollingInterval()).toString();
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.zway.internal.config;
import static org.openhab.binding.zway.internal.ZWayBindingConstants.DEVICE_CONFIG_VIRTUAL_DEVICE_ID;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* The {@link ZWayZAutomationDeviceConfiguration} class defines the model for a Z-Way device configuration.
*
* @author Patrick Hecker - Initial contribution
*/
public class ZWayZAutomationDeviceConfiguration {
private String deviceId;
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
@Override
public String toString() {
return new ToStringBuilder(this).append(DEVICE_CONFIG_VIRTUAL_DEVICE_ID, this.getDeviceId()).toString();
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.zway.internal.config;
import static org.openhab.binding.zway.internal.ZWayBindingConstants.DEVICE_CONFIG_NODE_ID;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* The {@link ZWayZWaveDeviceConfiguration} class defines the model for a Z-Wave device configuration.
*
* @author Patrick Hecker - Initial contribution
*/
public class ZWayZWaveDeviceConfiguration {
private Integer nodeId;
public Integer getNodeId() {
return nodeId;
}
public void setNodeId(Integer nodeId) {
this.nodeId = nodeId;
}
@Override
public String toString() {
return new ToStringBuilder(this).append(DEVICE_CONFIG_NODE_ID, this.getNodeId()).toString();
}
}

View File

@@ -0,0 +1,159 @@
/**
* 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.zway.internal.converter;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
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.thing.Channel;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import de.fh_zwickau.informatik.sensor.model.devices.Color;
import de.fh_zwickau.informatik.sensor.model.devices.Device;
import de.fh_zwickau.informatik.sensor.model.devices.types.Battery;
import de.fh_zwickau.informatik.sensor.model.devices.types.Doorlock;
import de.fh_zwickau.informatik.sensor.model.devices.types.SensorBinary;
import de.fh_zwickau.informatik.sensor.model.devices.types.SensorDiscrete;
import de.fh_zwickau.informatik.sensor.model.devices.types.SensorMultilevel;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchBinary;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchControl;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchMultilevel;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchRGBW;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchToggle;
import de.fh_zwickau.informatik.sensor.model.devices.types.Thermostat;
import de.fh_zwickau.informatik.sensor.model.devices.types.ToggleButton;
/**
* The {@link ZWayDeviceStateConverter} is responsible for converting Z-Way device level to openHAB states
*
* @author Patrick Hecker - Initial contribution
*/
public class ZWayDeviceStateConverter {
public static State toState(Device device, Channel channel) {
// Store level locally
String level = device.getMetrics().getLevel();
// Set item state to level depending on device type
if (device instanceof Battery) {
return getMultilevelState(level);
} else if (device instanceof Doorlock) {
return getBinaryState(level.toLowerCase());
} else if (device instanceof SensorBinary) {
if (channel.getAcceptedItemType().equals("Contact")) {
return getDoorlockState(level.toLowerCase());
} else {
return getBinaryState(level.toLowerCase());
}
} else if (device instanceof SensorMultilevel) {
return getMultilevelState(level);
} else if (device instanceof SwitchBinary) {
return getBinaryState(level.toLowerCase());
} else if (device instanceof SwitchMultilevel) {
if (channel.getAcceptedItemType().equals("Rollershutter")
|| channel.getAcceptedItemType().equals("Dimmer")) {
return getPercentState(level);
} else {
return getMultilevelState(level);
}
} else if (device instanceof SwitchRGBW) {
return getColorState(device.getMetrics().getColor());
} else if (device instanceof Thermostat) {
return getMultilevelState(level);
} else if (device instanceof SwitchControl) {
return getBinaryState(level.toLowerCase());
} else if (device instanceof ToggleButton || device instanceof SwitchToggle) {
return getBinaryState(level.toLowerCase());
} else if (device instanceof SensorDiscrete) {
return getMultilevelState(level);
}
return UnDefType.UNDEF;
}
/**
* Transforms an value in an openHAB type.
*
* @param multilevel sensor value
* @return transformed openHAB state
*/
private static State getMultilevelState(String multilevelValue) {
if (multilevelValue != null) {
return new DecimalType(multilevelValue);
}
return UnDefType.UNDEF;
}
private static State getPercentState(String multilevelValue) {
if (multilevelValue != null) {
return new PercentType(multilevelValue);
}
return UnDefType.UNDEF;
}
/**
* Transforms an value in an openHAB type.
*
* @param binary switch value
* @return transformed openHAB state
*/
private static State getBinaryState(String binarySwitchState) {
if (binarySwitchState != null) {
if (binarySwitchState.equals("on")) {
return OnOffType.ON;
} else if (binarySwitchState.equals("off")) {
return OnOffType.OFF;
}
}
return UnDefType.UNDEF;
}
/**
* Transforms an value in an openHAB type.
* - ON to OPEN
* - OFF to CLOSED
*
* @param binary sensor state
* @return
*/
private static State getDoorlockState(String binarySensorState) {
if (binarySensorState != null) {
if (binarySensorState.equals("on")) {
return OpenClosedType.OPEN;
} else if (binarySensorState.equals("off")) {
return OpenClosedType.CLOSED;
}
}
return UnDefType.UNDEF;
}
/**
* Transforms an value in an openHAB type.
*
* @param Z-Way color value
* @return transformed openHAB state
*/
private static State getColorState(Color colorSwitchState) {
if (colorSwitchState != null && colorSwitchState.getRed() != null && colorSwitchState.getGreen() != null
&& colorSwitchState.getBlue() != null) {
HSBType hsbType = HSBType.fromRGB(colorSwitchState.getRed(), colorSwitchState.getGreen(),
colorSwitchState.getBlue());
return hsbType;
}
return UnDefType.UNDEF;
}
}

View File

@@ -0,0 +1,152 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.zway.internal.discovery;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.util.Enumeration;
import java.util.regex.Pattern;
import org.apache.commons.net.util.SubnetUtils;
import org.openhab.binding.zway.internal.ZWayBindingConstants;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link ZWayBridgeDiscoveryService} is responsible for device discovery.
*
* @author Patrick Hecker - Initial contribution
*/
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.zway")
public class ZWayBridgeDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(getClass());
private static final int SEARCH_TIME = 240;
public ZWayBridgeDiscoveryService() {
super(ZWayBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS, SEARCH_TIME);
logger.debug("Initializing ZWayBridgeDiscoveryService");
}
private void scan() {
logger.debug("Starting scan for Z-Way Server");
ValidateIPV4 validator = new ValidateIPV4();
try {
Enumeration<NetworkInterface> enumNetworkInterface = NetworkInterface.getNetworkInterfaces();
while (enumNetworkInterface.hasMoreElements()) {
NetworkInterface networkInterface = enumNetworkInterface.nextElement();
if (networkInterface.isUp() && !networkInterface.isVirtual() && !networkInterface.isLoopback()) {
for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) {
if (validator.isValidIPV4(address.getAddress().getHostAddress())) {
String ipAddress = address.getAddress().getHostAddress();
Short prefix = address.getNetworkPrefixLength();
logger.debug("Scan IP address for Z-Way Server: {}", ipAddress);
// Search on localhost first
scheduler.execute(new ZWayServerScan(ipAddress));
String subnet = ipAddress + "/" + prefix;
SubnetUtils utils = new SubnetUtils(subnet);
String[] addresses = utils.getInfo().getAllAddresses();
for (String addressInSubnet : addresses) {
scheduler.execute(new ZWayServerScan(addressInSubnet));
}
}
}
}
}
} catch (SocketException e) {
logger.warn("Error occurred while searching Z-Way servers ({})", e.getMessage());
}
}
public boolean pingHost(String host, int port, int timeout) {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), timeout);
return true;
} catch (IOException e) {
return false; // Either timeout or unreachable or failed DNS lookup.
}
}
public class ZWayServerScan implements Runnable {
private String ipAddress;
public ZWayServerScan(String ipAddress) {
this.ipAddress = ipAddress;
}
@Override
public void run() {
if (!pingHost(ipAddress, 8083, 500)) {
return; // Error occurred while searching Z-Way servers (Unreachable)
}
try {
URL url = new URL("http://" + ipAddress + ":8083/ZAutomation/api/v1/status");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (connection.getResponseCode() == 401) {
ThingUID thingUID = new ThingUID(ZWayBindingConstants.THING_TYPE_BRIDGE,
ipAddress.replaceAll("\\.", "_"));
// Attention: if is already present as thing in the ThingRegistry
// the configuration for thing will be updated!
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
.withProperty(ZWayBindingConstants.BRIDGE_CONFIG_ZWAY_SERVER_IP_ADDRESS, ipAddress)
.withLabel("Z-Way Server " + ipAddress).build();
thingDiscovered(discoveryResult);
}
} catch (Exception e) {
logger.warn("Discovery resulted in an unexpected exception", e);
}
}
}
@Override
protected void startScan() {
scan();
}
@Override
protected synchronized void stopScan() {
super.stopScan();
removeOlderResults(getTimestampOfLastScan());
}
class ValidateIPV4 {
private final String ipV4Regex = "^((0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)\\.){3}(0|1\\d?\\d?|2[0-4]?\\d?|25[0-5]?|[3-9]\\d?)$";
private Pattern ipV4Pattern = Pattern.compile(ipV4Regex);
public boolean isValidIPV4(final String s) {
return ipV4Pattern.matcher(s).matches();
}
}
}

View File

@@ -0,0 +1,239 @@
/**
* 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.zway.internal.discovery;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.zway.internal.ZWayBindingConstants;
import org.openhab.binding.zway.internal.handler.ZWayBridgeHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.fh_zwickau.informatik.sensor.model.devices.Device;
import de.fh_zwickau.informatik.sensor.model.devices.DeviceList;
import de.fh_zwickau.informatik.sensor.model.devices.types.Camera;
import de.fh_zwickau.informatik.sensor.model.devices.types.SensorMultiline;
import de.fh_zwickau.informatik.sensor.model.devices.types.Text;
import de.fh_zwickau.informatik.sensor.model.locations.LocationList;
import de.fh_zwickau.informatik.sensor.model.zwaveapi.devices.ZWaveDevice;
/**
* The {@link ZWayDeviceDiscoveryService} is responsible for device discovery.
*
* @author Patrick Hecker - Initial contribution
*/
public class ZWayDeviceDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(getClass());
private static final int SEARCH_TIME = 60;
private static final int INITIAL_DELAY = 15;
private static final int SCAN_INTERVAL = 240;
private ZWayBridgeHandler mBridgeHandler;
private ZWayDeviceScan mZWayDeviceScanningRunnable;
private ScheduledFuture<?> mZWayDeviceScanningJob;
public ZWayDeviceDiscoveryService(ZWayBridgeHandler bridgeHandler) {
super(ZWayBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS, SEARCH_TIME);
logger.debug("Initializing ZWayBridgeDiscoveryService");
mBridgeHandler = bridgeHandler;
mZWayDeviceScanningRunnable = new ZWayDeviceScan();
activate(null);
}
private void scan() {
logger.debug("Starting scan on Z-Way Server {}", mBridgeHandler.getThing().getUID());
// Z-Way bridge have to be ONLINE because configuration is needed
if (mBridgeHandler == null || !mBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
LocationList locationList = mBridgeHandler.getZWayApi().getLocations();
DeviceList deviceList = mBridgeHandler.getZWayApi().getDevices();
if (deviceList != null) {
Map<Integer, List<Device>> physicalDevices = deviceList.getDevicesGroupByNodeId();
for (Map.Entry<Integer, List<Device>> entry : physicalDevices.entrySet()) {
final Integer nodeId = entry.getKey();
List<Device> devices = entry.getValue();
final ThingUID bridgeUID = mBridgeHandler.getThing().getUID();
String location = "";
String deviceTypes = "";
Integer index = 0;
for (Device device : devices) {
if (index != 0 && index != devices.size()) {
deviceTypes += ", ";
}
deviceTypes += device.getDeviceType();
index++;
// Add location, assuming that each (virtual) device is assigned to the same room
if (locationList != null) {
// Add only the location if this differs from globalRoom (with id 0)
if (device.getLocation() != -1 && device.getLocation() != 0) {
try {
location = locationList.getLocationById(device.getLocation()).getTitle();
} catch (NullPointerException npe) {
location = "";
}
}
}
}
logger.debug("Z-Way device found with {} virtual devices - device types: {}", devices.size(),
deviceTypes);
ZWaveDevice zwaveDevice = mBridgeHandler.getZWayApi().getZWaveDevice(nodeId);
if (zwaveDevice != null) {
String givenName = "Device " + nodeId;
if (!zwaveDevice.getData().getGivenName().getValue().equals("")) {
givenName = zwaveDevice.getData().getGivenName().getValue();
} else if (!zwaveDevice.getData().getDeviceTypeString().getValue().equals("")) {
givenName += " - " + zwaveDevice.getData().getDeviceTypeString().getValue();
}
// Add additional information as properties
String vendorString = zwaveDevice.getData().getVendorString().getValue();
if (!zwaveDevice.getData().getVendorString().getValue().equals("")) {
givenName += " (" + vendorString + ")";
}
String manufacturerId = zwaveDevice.getData().getManufacturerId().getValue();
String deviceType = zwaveDevice.getData().getDeviceTypeString().getValue();
String zddxmlfile = zwaveDevice.getData().getZDDXMLFile().getValue();
String sdk = zwaveDevice.getData().getSDK().getValue();
ThingUID thingUID = new ThingUID(ZWayBindingConstants.THING_TYPE_DEVICE,
mBridgeHandler.getThing().getUID(), nodeId.toString());
/*
* Properties
* - Configuration: DEVICE_CONFIG_NODE_ID
* - ESH default properties:
* --- PROPERTY_VENDOR
* --- other default properties not available
* - Custom properties:
* --- DEVICE_LOCATION
* --- DEVICE_MANUFACTURER_ID
* --- DEVICE_DEVICE_TYPE
* --- DEVICE_ZDDXMLFILE
* --- DEVICE_SDK
*/
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(givenName)
.withBridge(bridgeUID).withProperty(ZWayBindingConstants.DEVICE_CONFIG_NODE_ID, nodeId)
.withProperty(Thing.PROPERTY_VENDOR, vendorString)
.withProperty(ZWayBindingConstants.DEVICE_PROP_LOCATION, location)
.withProperty(ZWayBindingConstants.DEVICE_PROP_MANUFACTURER_ID, manufacturerId)
.withProperty(ZWayBindingConstants.DEVICE_PROP_DEVICE_TYPE, deviceType)
.withProperty(ZWayBindingConstants.DEVICE_PROP_ZDDXMLFILE, zddxmlfile)
.withProperty(ZWayBindingConstants.DEVICE_PROP_SDK, sdk).build();
thingDiscovered(discoveryResult);
} else {
logger.warn("Z-Wave device not loaded");
}
}
for (Device device : deviceList.getDevices()) {
if (device.getVisibility() && !device.getPermanentlyHidden()) {
if (ZWayBindingConstants.DISCOVERY_IGNORED_DEVICES.contains(device.getDeviceId().split("_")[0])) {
logger.debug("Skip device: {}", device.getMetrics().getTitle());
continue;
}
if (device instanceof SensorMultiline || device instanceof Camera || device instanceof Text) {
logger.debug("Skip device because the device type is not supported: {}",
device.getMetrics().getTitle());
continue;
}
ThingUID bridgeUID = mBridgeHandler.getThing().getUID();
String location = "";
// Add location, assuming that each (virtual) device is assigned to the same room
if (locationList != null) {
// Add only the location if this differs from globalRoom (with id 0)
if (device.getLocation() != -1 && device.getLocation() != 0) {
try {
location = locationList.getLocationById(device.getLocation()).getTitle();
} catch (NullPointerException npe) {
location = "";
}
}
}
logger.debug("Z-Way virtual device found with device type: {} - {} - {}", device.getDeviceType(),
device.getMetrics().getProbeTitle(), device.getNodeId());
ThingUID thingUID = new ThingUID(ZWayBindingConstants.THING_TYPE_VIRTUAL_DEVICE,
mBridgeHandler.getThing().getUID(), device.getDeviceId());
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
.withLabel(device.getMetrics().getTitle()).withBridge(bridgeUID)
.withProperty(ZWayBindingConstants.DEVICE_CONFIG_VIRTUAL_DEVICE_ID, device.getDeviceId())
.withProperty(ZWayBindingConstants.DEVICE_PROP_LOCATION, location).build();
thingDiscovered(discoveryResult);
}
}
} else {
logger.warn("Devices not loaded");
}
}
@Override
protected void startScan() {
scan();
}
@Override
protected synchronized void stopScan() {
super.stopScan();
removeOlderResults(getTimestampOfLastScan());
}
@Override
protected void startBackgroundDiscovery() {
if (mZWayDeviceScanningJob == null || mZWayDeviceScanningJob.isCancelled()) {
logger.debug("Starting background scanning job");
mZWayDeviceScanningJob = scheduler.scheduleWithFixedDelay(mZWayDeviceScanningRunnable, INITIAL_DELAY,
SCAN_INTERVAL, TimeUnit.SECONDS);
} else {
logger.debug("Scanning job is allready active");
}
}
@Override
protected void stopBackgroundDiscovery() {
if (mZWayDeviceScanningJob != null && !mZWayDeviceScanningJob.isCancelled()) {
mZWayDeviceScanningJob.cancel(false);
mZWayDeviceScanningJob = null;
}
}
public class ZWayDeviceScan implements Runnable {
@Override
public void run() {
scan();
}
}
}

View File

@@ -0,0 +1,600 @@
/**
* 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.zway.internal.handler;
import static org.openhab.binding.zway.internal.ZWayBindingConstants.*;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.openhab.binding.zway.internal.config.ZWayBridgeConfiguration;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.fh_zwickau.informatik.sensor.IZWayApi;
import de.fh_zwickau.informatik.sensor.IZWayApiCallbacks;
import de.fh_zwickau.informatik.sensor.ZWayApiHttp;
import de.fh_zwickau.informatik.sensor.model.devicehistory.DeviceHistory;
import de.fh_zwickau.informatik.sensor.model.devicehistory.DeviceHistoryList;
import de.fh_zwickau.informatik.sensor.model.devices.Device;
import de.fh_zwickau.informatik.sensor.model.devices.DeviceList;
import de.fh_zwickau.informatik.sensor.model.instances.Instance;
import de.fh_zwickau.informatik.sensor.model.instances.InstanceList;
import de.fh_zwickau.informatik.sensor.model.locations.Location;
import de.fh_zwickau.informatik.sensor.model.locations.LocationList;
import de.fh_zwickau.informatik.sensor.model.modules.ModuleList;
import de.fh_zwickau.informatik.sensor.model.namespaces.NamespaceList;
import de.fh_zwickau.informatik.sensor.model.notifications.Notification;
import de.fh_zwickau.informatik.sensor.model.notifications.NotificationList;
import de.fh_zwickau.informatik.sensor.model.profiles.Profile;
import de.fh_zwickau.informatik.sensor.model.profiles.ProfileList;
import de.fh_zwickau.informatik.sensor.model.zwaveapi.controller.ZWaveController;
import de.fh_zwickau.informatik.sensor.model.zwaveapi.devices.ZWaveDevice;
/**
* The {@link ZWayBridgeHandler} manages the connection between Z-Way API and binding.
*
* During the initialization the following tasks are performed:
* - load and check configuration
* - instantiate a Z-Way API that used in the whole binding
* - authenticate to the Z-Way server
* - initialize all containing device things
*
* @author Patrick Hecker - Initial contribution, remove observer mechanism
* @author Johannes Einig - Bridge now stores DeviceList
*/
public class ZWayBridgeHandler extends BaseBridgeHandler implements IZWayApiCallbacks {
public static final ThingTypeUID SUPPORTED_THING_TYPE = THING_TYPE_BRIDGE;
private final Logger logger = LoggerFactory.getLogger(getClass());
private BridgePolling bridgePolling;
private ScheduledFuture<?> pollingJob;
private ResetInclusionExclusion resetInclusionExclusion;
private ScheduledFuture<?> resetInclusionExclusionJob;
private ZWayBridgeConfiguration mConfig;
private IZWayApi mZWayApi;
private DeviceList deviceList;
/**
* Initializer authenticate the Z-Way API instance with bridge configuration.
*
* If Z-Way API successfully authenticated:
* - check existence of openHAB Connector in Z-Way server and configure openHAB server
* - initialize all containing device things
*/
private class Initializer implements Runnable {
@Override
public void run() {
logger.debug("Authenticate to the Z-Way server ...");
// https://community.openhab.org/t/oh2-major-bug-with-scheduled-jobs/12350/11
// If any execution of the task encounters an exception, subsequent executions are
// suppressed. Otherwise, the task will only terminate via cancellation or
// termination of the executor.
try {
// Authenticate - thing status update with a error message
if (mZWayApi.getLogin() != null) {
// Thing status set to online in login callback
logger.info("Z-Way bridge successfully authenticated");
// Gets the latest deviceList from zWay during bridge initialization
deviceList = mZWayApi.getDevices();
// Initialize bridge polling
if (pollingJob == null || pollingJob.isCancelled()) {
logger.debug("Starting polling job at intervall {}", mConfig.getPollingInterval());
pollingJob = scheduler.scheduleWithFixedDelay(bridgePolling, 10, mConfig.getPollingInterval(),
TimeUnit.SECONDS);
} else {
// Called when thing or bridge updated ...
logger.debug("Polling is allready active");
}
// Initializing all containing device things
logger.debug("Initializing all configured devices ...");
for (Thing thing : getThing().getThings()) {
ThingHandler handler = thing.getHandler();
if (handler != null) {
logger.debug("Initializing device: {}", thing.getLabel());
handler.initialize();
} else {
logger.warn("Initializing device failed (DeviceHandler is null): {}", thing.getLabel());
}
}
} else {
logger.warn("Z-Way bridge couldn't authenticated");
}
} catch (Throwable t) {
if (t instanceof Exception) {
logger.error("{}", t.getMessage());
} else if (t instanceof Error) {
logger.error("{}", t.getMessage());
} else {
logger.error("Unexpected error");
}
if (getThing().getStatus() == ThingStatus.ONLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Error occurred when initialize bridge.");
}
}
}
}
/**
* Disposer clean up openHAB Connector configuration
*/
private class Remover implements Runnable {
@Override
public void run() {
// Removing all containing device things
logger.debug("Removing all configured devices ...");
for (Thing thing : getThing().getThings()) {
ThingHandler handler = thing.getHandler();
if (handler != null) {
logger.debug("Removing device: {}", thing.getLabel());
handler.handleRemoval();
} else {
logger.warn("Removing device failed (DeviceHandler is null): {}", thing.getLabel());
}
}
// status update will finally remove the thing
updateStatus(ThingStatus.REMOVED);
}
}
public ZWayBridgeHandler(Bridge bridge) {
super(bridge);
bridgePolling = new BridgePolling();
resetInclusionExclusion = new ResetInclusionExclusion();
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// possible commands: check Z-Way server, check openHAB Connector, reconnect, ...
logger.debug("Handle command for channel: {} with command: {}", channelUID.getId(), command.toString());
if (channelUID.getId().equals(ACTIONS_CHANNEL)) {
if (command.toString().equals(ACTIONS_CHANNEL_OPTION_REFRESH)) {
logger.debug("Handle bridge refresh command for all configured devices ...");
for (Thing thing : getThing().getThings()) {
ZWayDeviceHandler handler = (ZWayDeviceHandler) thing.getHandler();
if (handler != null) {
logger.debug("Refreshing device: {}", thing.getLabel());
handler.refreshAllChannels();
} else {
logger.warn("Refreshing device failed (DeviceHandler is null): {}", thing.getLabel());
}
}
}
} else if (channelUID.getId().equals(SECURE_INCLUSION_CHANNEL)) {
if (command.equals(OnOffType.ON)) {
logger.debug("Enable bridge secure inclusion ...");
mZWayApi.updateControllerData("secureInclusion", "true");
} else if (command.equals(OnOffType.OFF)) {
logger.debug("Disable bridge secure inclusion ...");
mZWayApi.updateControllerData("secureInclusion", "false");
}
} else if (channelUID.getId().equals(INCLUSION_CHANNEL)) {
if (command.equals(OnOffType.ON)) {
logger.debug("Handle bridge start inclusion command ...");
mZWayApi.getZWaveInclusion(1);
// Start reset job
if (resetInclusionExclusionJob == null || resetInclusionExclusionJob.isCancelled()) {
logger.debug("Starting reset inclusion and exclusion job in 30 seconds");
resetInclusionExclusionJob = scheduler.schedule(resetInclusionExclusion, 30, TimeUnit.SECONDS);
}
} else if (command.equals(OnOffType.OFF)) {
logger.debug("Handle bridge stop inclusion command ...");
mZWayApi.getZWaveInclusion(0);
}
} else if (channelUID.getId().equals(EXCLUSION_CHANNEL)) {
if (command.equals(OnOffType.ON)) {
logger.debug("Handle bridge start exclusion command ...");
mZWayApi.getZWaveExclusion(1);
// Start reset job
if (resetInclusionExclusionJob == null || resetInclusionExclusionJob.isCancelled()) {
logger.debug("Starting reset inclusion and exclusion job in 30 seconds");
resetInclusionExclusionJob = scheduler.schedule(resetInclusionExclusion, 30, TimeUnit.SECONDS);
}
} else if (command.equals(OnOffType.OFF)) {
logger.debug("Handle bridge stop exclusion command ...");
mZWayApi.getZWaveExclusion(0);
}
}
}
@Override
public void initialize() {
logger.info("Initializing Z-Way bridge ...");
// Set thing status to a valid status
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING, "Checking configuration...");
// Configuration - thing status update with a error message
mConfig = loadAndCheckConfiguration();
if (mConfig != null) {
logger.debug("Configuration complete: {}", mConfig);
mZWayApi = new ZWayApiHttp(mConfig.getZWayIpAddress(), mConfig.getZWayPort(), mConfig.getZWayProtocol(),
mConfig.getZWayUsername(), mConfig.getZWayPassword(), -1, false, this);
// Start an extra thread, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
scheduler.execute(new Initializer());
}
}
@Override
public void dispose() {
logger.debug("Disposing Z-Way bridge ...");
if (pollingJob != null && !pollingJob.isCancelled()) {
pollingJob.cancel(true);
pollingJob = null;
}
if (resetInclusionExclusionJob != null && !resetInclusionExclusionJob.isCancelled()) {
resetInclusionExclusionJob.cancel(true);
resetInclusionExclusionJob = null;
}
super.dispose();
}
private class BridgePolling implements Runnable {
@Override
public void run() {
logger.debug("Starting polling for bridge: {}", getThing().getLabel());
if (getThing().getStatus().equals(ThingStatus.ONLINE)) {
updateControllerData();
} else {
logger.debug("Polling not possible, bridge isn't ONLINE");
}
}
}
private void updateControllerData() {
// Add additional information as properties or update channels
ZWaveController zwaveController = mZWayApi.getZWaveController();
if (zwaveController != null) {
Map<String, String> properties = editProperties();
// ESH default properties
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, zwaveController.getData().getAPIVersion().getValue());
properties.put(Thing.PROPERTY_HARDWARE_VERSION, zwaveController.getData().getZWaveChip().getValue());
// Thing.PROPERTY_MODEL_ID not available, only manufacturerProductId
properties.put(Thing.PROPERTY_SERIAL_NUMBER, zwaveController.getData().getUuid().getValue());
properties.put(Thing.PROPERTY_VENDOR, zwaveController.getData().getVendor().getValue());
// Custom properties
properties.put(BRIDGE_PROP_SOFTWARE_REVISION_VERSION,
zwaveController.getData().getSoftwareRevisionVersion().getValue());
properties.put(BRIDGE_PROP_SOFTWARE_REVISION_DATE,
zwaveController.getData().getSoftwareRevisionDate().getValue());
properties.put(BRIDGE_PROP_SDK, zwaveController.getData().getSDK().getValue());
properties.put(BRIDGE_PROP_MANUFACTURER_ID, zwaveController.getData().getManufacturerId().getValue());
properties.put(BRIDGE_PROP_SECURE_INCLUSION, zwaveController.getData().getSecureInclusion().getValue());
properties.put(BRIDGE_PROP_FREQUENCY, zwaveController.getData().getFrequency().getValue());
updateProperties(properties);
// Update channels
if (zwaveController.getData().getSecureInclusion().getValue().equals("true")) {
updateState(SECURE_INCLUSION_CHANNEL, OnOffType.ON);
} else {
updateState(SECURE_INCLUSION_CHANNEL, OnOffType.OFF);
}
}
}
/**
* Inclusion/Exclusion must be reset manually, also channel states.
*/
private class ResetInclusionExclusion implements Runnable {
@Override
public void run() {
logger.debug("Reset inclusion and exclusion for bridge: {}", getThing().getLabel());
if (getThing().getStatus().equals(ThingStatus.ONLINE)) {
mZWayApi.getZWaveInclusion(0);
mZWayApi.getZWaveExclusion(0);
updateState(INCLUSION_CHANNEL, OnOffType.OFF);
updateState(EXCLUSION_CHANNEL, OnOffType.OFF);
} else {
logger.debug("Reset inclusion and exclusion not possible, bridge isn't ONLINE");
}
}
}
@Override
public void handleRemoval() {
logger.debug("Handle removal Z-Way bridge ...");
// Start an extra thread, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
scheduler.execute(new Remover());
// super.handleRemoval() called in every case in scheduled task ...
}
protected ZWayBridgeConfiguration getZWayBridgeConfiguration() {
return mConfig;
}
/*******************************
******* DeviceList handling*****
********************************
* Updates the deviceList every time a
* ChildHandler is initialized or disposed
*/
@Override
public void childHandlerInitialized(ThingHandler childHandler, Thing childThing) {
updateDeviceList();
}
@Override
public void childHandlerDisposed(ThingHandler childHandler, Thing childThing) {
updateDeviceList();
}
private void updateDeviceList() {
if (mZWayApi != null) {
logger.debug("ChildHandler changed. Updating device List");
deviceList = mZWayApi.getDevices();
} else {
logger.debug("Bridge Handler not online. No update of device list performed.");
}
}
private ZWayBridgeConfiguration loadAndCheckConfiguration() {
ZWayBridgeConfiguration config = getConfigAs(ZWayBridgeConfiguration.class);
/****************************************
****** Z-Way server configuration ******
****************************************/
// Z-Way IP address
if (StringUtils.trimToNull(config.getZWayIpAddress()) == null) {
config.setZWayIpAddress("localhost"); // default value
}
// Z-Way Port
if (config.getZWayPort() == null) {
config.setZWayPort(8083);
}
// Z-Way Protocol
if (StringUtils.trimToNull(config.getZWayProtocol()) == null) {
config.setZWayProtocol("http");
}
// Z-Way Password
if (StringUtils.trimToNull(config.getZWayPassword()) == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"The connection to the Z-Way Server can't established, because the Z-Way password is missing. Please set a Z-Way password.");
return null;
}
// Z-Way Username
if (StringUtils.trimToNull(config.getZWayUsername()) == null) {
config.setZWayUsername("admin"); // default value
}
/***********************************
****** General configuration ******
**********************************/
// Polling interval
if (config.getPollingInterval() == null) {
config.setPollingInterval(3600);
}
return config;
}
/**
* @return Z-Way API instance
*/
public IZWayApi getZWayApi() {
return mZWayApi;
}
public DeviceList getDeviceList() {
return deviceList;
}
/********************************
****** Z-Way API callback ******
*******************************/
@Override
public void getStatusResponse(String message) {
}
@Override
public void getRestartResponse(Boolean status) {
}
@Override
public void getLoginResponse(String sessionId) {
logger.debug("New session id: {}", sessionId);
updateStatus(ThingStatus.ONLINE);
}
@Override
public void getNamespacesResponse(NamespaceList namespaces) {
}
@Override
public void getModulesResponse(ModuleList moduleList) {
}
@Override
public void getInstancesResponse(InstanceList instanceList) {
}
@Override
public void postInstanceResponse(Instance instance) {
}
@Override
public void getInstanceResponse(Instance instance) {
}
@Override
public void putInstanceResponse(Instance instance) {
}
@Override
public void deleteInstanceResponse(boolean status) {
}
@Override
public void getDevicesResponse(DeviceList deviceList) {
}
@Override
public void putDeviceResponse(Device device) {
}
@Override
public void getDeviceResponse(Device device) {
}
@Override
public void getDeviceCommandResponse(String message) {
}
@Override
public void getLocationsResponse(LocationList locationList) {
}
@Override
public void postLocationResponse(Location location) {
}
@Override
public void getLocationResponse(Location location) {
}
@Override
public void putLocationResponse(Location location) {
}
@Override
public void deleteLocationResponse(boolean status) {
}
@Override
public void getProfilesResponse(ProfileList profileList) {
}
@Override
public void postProfileResponse(Profile profile) {
}
@Override
public void getProfileResponse(Profile profile) {
}
@Override
public void putProfileResponse(Profile profile) {
}
@Override
public void deleteProfileResponse(boolean status) {
}
@Override
public void getNotificationsResponse(NotificationList notificationList) {
}
@Override
public void getNotificationResponse(Notification notification) {
}
@Override
public void putNotificationResponse(Notification notification) {
}
@Override
public void getDeviceHistoriesResponse(DeviceHistoryList deviceHistoryList) {
}
@Override
public void getDeviceHistoryResponse(DeviceHistory deviceHistory) {
}
@Override
public void apiError(String message, boolean invalidateState) {
if (invalidateState) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
}
}
@Override
public void httpStatusError(int httpStatus, String message, boolean invalidateState) {
if (invalidateState) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
message + "(HTTP status code: " + httpStatus + ").");
}
}
@Override
public void authenticationError() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"Authentication error. Please check username and password.");
}
@Override
public void responseFormatError(String message, boolean invalidateApiState) {
if (invalidateApiState) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
}
}
@Override
public void message(int code, String message) {
}
@Override
public void getZWaveDeviceResponse(ZWaveDevice zwaveDevice) {
}
@Override
public void getZWaveControllerResponse(ZWaveController zwaveController) {
}
}

View File

@@ -0,0 +1,785 @@
/**
* 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.zway.internal.handler;
import static de.fh_zwickau.informatik.sensor.ZWayConstants.*;
import static org.openhab.binding.zway.internal.ZWayBindingConstants.*;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.zway.internal.ZWayBindingConstants;
import org.openhab.binding.zway.internal.converter.ZWayDeviceStateConverter;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.StopMoveType;
import org.openhab.core.library.types.UpDownType;
import org.openhab.core.thing.Bridge;
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.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.builder.ChannelBuilder;
import org.openhab.core.thing.binding.builder.ThingBuilder;
import org.openhab.core.thing.type.ChannelTypeUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.fh_zwickau.informatik.sensor.model.devices.Device;
import de.fh_zwickau.informatik.sensor.model.devices.DeviceList;
import de.fh_zwickau.informatik.sensor.model.devices.types.Battery;
import de.fh_zwickau.informatik.sensor.model.devices.types.Doorlock;
import de.fh_zwickau.informatik.sensor.model.devices.types.SensorBinary;
import de.fh_zwickau.informatik.sensor.model.devices.types.SensorDiscrete;
import de.fh_zwickau.informatik.sensor.model.devices.types.SensorMultilevel;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchBinary;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchControl;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchMultilevel;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchRGBW;
import de.fh_zwickau.informatik.sensor.model.devices.types.SwitchToggle;
import de.fh_zwickau.informatik.sensor.model.devices.types.Thermostat;
import de.fh_zwickau.informatik.sensor.model.devices.types.ToggleButton;
import de.fh_zwickau.informatik.sensor.model.zwaveapi.devices.ZWaveDevice;
/**
* The {@link ZWayDeviceHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Patrick Hecker - Initial contribution, remove observer mechanism
* @author Johannes Einig - Now uses the bridge handler cached device list
*/
public abstract class ZWayDeviceHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(getClass());
private DevicePolling devicePolling;
private ScheduledFuture<?> pollingJob;
protected Calendar lastUpdate;
protected abstract void refreshLastUpdate();
/**
* Initialize polling job
*/
private class Initializer implements Runnable {
@Override
public void run() {
// https://community.openhab.org/t/oh2-major-bug-with-scheduled-jobs/12350/11
// If any execution of the task encounters an exception, subsequent executions are
// suppressed. Otherwise, the task will only terminate via cancellation or
// termination of the executor.
try {
// Z-Way bridge have to be ONLINE because configuration is needed
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
// Initialize device polling
if (pollingJob == null || pollingJob.isCancelled()) {
logger.debug("Starting polling job at intervall {}",
zwayBridgeHandler.getZWayBridgeConfiguration().getPollingInterval());
pollingJob = scheduler.scheduleWithFixedDelay(devicePolling, 10,
zwayBridgeHandler.getZWayBridgeConfiguration().getPollingInterval(), TimeUnit.SECONDS);
} else {
// Called when thing or bridge updated ...
logger.debug("Polling is allready active");
}
} catch (Throwable t) {
if (t instanceof Exception) {
logger.error("{}", t.getMessage());
} else if (t instanceof Error) {
logger.error("{}", t.getMessage());
} else {
logger.error("Unexpected error");
}
if (getThing().getStatus() == ThingStatus.ONLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Error occurred when starting polling.");
}
}
}
}
private class Disposer implements Runnable {
@Override
public void run() {
// Z-Way bridge have to be ONLINE because configuration is needed
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
// status update will remove finally
updateStatus(ThingStatus.REMOVED);
return;
}
// status update will remove finally
updateStatus(ThingStatus.REMOVED);
}
}
public ZWayDeviceHandler(Thing thing) {
super(thing);
devicePolling = new DevicePolling();
}
protected synchronized ZWayBridgeHandler getZWayBridgeHandler() {
Bridge bridge = getBridge();
if (bridge == null) {
return null;
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof ZWayBridgeHandler) {
return (ZWayBridgeHandler) handler;
} else {
return null;
}
}
@Override
public void initialize() {
setLocation();
// Start an extra thread to check the connection, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
scheduler.execute(new Initializer());
}
@Override
public void dispose() {
if (pollingJob != null && !pollingJob.isCancelled()) {
pollingJob.cancel(true);
pollingJob = null;
}
super.dispose();
}
@Override
public void handleRemoval() {
logger.debug("Handle removal Z-Way device ...");
// Start an extra thread, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
scheduler.execute(new Disposer());
// super.handleRemoval() called in every case in scheduled task ...
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
// Only called if status ONLINE or OFFLINE
logger.debug("Z-Way bridge status changed: {}", bridgeStatusInfo);
if (bridgeStatusInfo.getStatus().equals(ThingStatus.OFFLINE)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, "Bridge status is offline.");
} else if (bridgeStatusInfo.getStatus().equals(ThingStatus.ONLINE)) {
// Initialize thing, if all OK the status of device thing will be ONLINE
// Start an extra thread to check the connection, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
scheduler.execute(new Initializer());
}
}
private class DevicePolling implements Runnable {
@Override
public void run() {
logger.debug("Starting polling for device: {}", getThing().getLabel());
if (getThing().getStatus().equals(ThingStatus.ONLINE)) {
// Refresh device states
for (Channel channel : getThing().getChannels()) {
logger.debug("Checking link state of channel: {}", channel.getLabel());
if (isLinked(channel.getUID().getId())) {
logger.debug("Refresh items that linked with channel: {}", channel.getLabel());
// https://community.openhab.org/t/oh2-major-bug-with-scheduled-jobs/12350/11
// If any execution of the task encounters an exception, subsequent executions are
// suppressed. Otherwise, the task will only terminate via cancellation or
// termination of the executor.
try {
refreshChannel(channel);
} catch (Throwable t) {
if (t instanceof Exception) {
logger.error("Error occurred when performing polling:{}", t.getMessage());
} else if (t instanceof Error) {
logger.error("Error occurred when performing polling:{}", t.getMessage());
} else {
logger.error("Error occurred when performing polling: Unexpected error");
}
if (getThing().getStatus() == ThingStatus.ONLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Error occurred when performing polling.");
}
}
} else {
logger.debug("Polling for device: {} not possible (channel {} not linked", thing.getLabel(),
channel.getLabel());
}
}
// Refresh last update
refreshLastUpdate();
} else {
logger.debug("Polling not possible, Z-Way device isn't ONLINE");
}
}
}
private synchronized void setLocation() {
Map<String, String> properties = getThing().getProperties();
// Load location from properties
String location = properties.get(ZWayBindingConstants.DEVICE_PROP_LOCATION);
if (location != null && !location.equals("") && getThing().getLocation() == null) {
logger.debug("Set location to {}", location);
ThingBuilder thingBuilder = editThing();
thingBuilder.withLocation(location);
thingBuilder.withLabel(thing.getLabel());
updateThing(thingBuilder.build());
}
}
protected void refreshAllChannels() {
scheduler.execute(new DevicePolling());
}
private void refreshChannel(Channel channel) {
// Check Z-Way bridge handler
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
// Check device id associated with channel
String deviceId = channel.getProperties().get("deviceId");
if (deviceId != null) {
// Load and check device from Z-Way server
DeviceList deviceList = zwayBridgeHandler.getZWayApi().getDevices();
if (deviceList != null) {
// 1.) Load only the current value from Z-Way server
Device device = deviceList.getDeviceById(deviceId);
if (device == null) {
logger.debug("ZAutomation device not found.");
return;
}
try {
updateState(channel.getUID(), ZWayDeviceStateConverter.toState(device, channel));
} catch (IllegalArgumentException iae) {
logger.debug(
"IllegalArgumentException ({}) during refresh channel for device: {} (level: {}) with channel: {}",
iae.getMessage(), device.getMetrics().getTitle(), device.getMetrics().getLevel(),
channel.getChannelTypeUID());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
"Channel refresh for device: " + device.getMetrics().getTitle() + " (level: "
+ device.getMetrics().getLevel() + ") with channel: " + channel.getChannelTypeUID()
+ " failed!");
}
// 2.) Trigger update function, soon as the value has been updated, openHAB will be notified
try {
device.update();
} catch (Exception e) {
logger.debug("{} doesn't support update (triggered during refresh channel)",
device.getMetrics().getTitle());
}
} else {
logger.warn("Devices not loaded");
}
} else {
// Check channel for command classes
// Channel thermostat mode
if (channel.getUID().equals(new ChannelUID(getThing().getUID(), THERMOSTAT_MODE_CC_CHANNEL))) {
// Load physical device
Integer nodeId = Integer.parseInt(channel.getProperties().get("nodeId"));
ZWaveDevice physicalDevice = zwayBridgeHandler.getZWayApi().getZWaveDevice(nodeId);
if (physicalDevice != null) {
updateState(channel.getUID(), new DecimalType(physicalDevice.getInstances().get0()
.getCommandClasses().get64().getData().getMode().getValue()));
}
}
}
}
@Override
public void channelLinked(ChannelUID channelUID) {
logger.debug("Z-Way device channel linked: {}", channelUID);
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
// Method called when channel linked and not when server started!!!
super.channelLinked(channelUID); // performs a refresh command
}
@Override
public void channelUnlinked(ChannelUID channelUID) {
logger.debug("Z-Way device channel unlinked: {}", channelUID);
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
super.channelUnlinked(channelUID);
}
@Override
public void handleCommand(ChannelUID channelUID, final Command command) {
logger.debug("Handle command for channel: {} with command: {}", channelUID.getId(), command.toString());
// Check Z-Way bridge handler
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
// Load device id from channel's properties for the compatibility of ZAutomation and ZWave devices
final Channel channel = getThing().getChannel(channelUID.getId());
final String deviceId = channel.getProperties().get("deviceId");
if (deviceId != null) {
DeviceList deviceList = zwayBridgeHandler.getDeviceList();
if (deviceList != null) {
Device device = deviceList.getDeviceById(deviceId);
if (device == null) {
logger.debug("ZAutomation device not found.");
return;
}
try {
if (command instanceof RefreshType) {
logger.debug("Handle command: RefreshType");
refreshChannel(channel);
} else {
if (device instanceof Battery) {
// possible commands: update()
} else if (device instanceof Doorlock) {
// possible commands: open(), close()
if (command instanceof OnOffType) {
logger.debug("Handle command: OnOffType");
if (command.equals(OnOffType.ON)) {
device.open();
} else if (command.equals(OnOffType.OFF)) {
device.close();
}
}
} else if (device instanceof SensorBinary) {
// possible commands: update()
} else if (device instanceof SensorMultilevel) {
// possible commands: update()
} else if (device instanceof SwitchBinary) {
// possible commands: update(), on(), off()
if (command instanceof OnOffType) {
logger.debug("Handle command: OnOffType");
if (command.equals(OnOffType.ON)) {
device.on();
} else if (command.equals(OnOffType.OFF)) {
device.off();
}
}
} else if (device instanceof SwitchMultilevel) {
// possible commands: update(), on(), up(), off(), down(), min(), max(), upMax(),
// increase(), decrease(), exact(level), exactSmooth(level, duration), stop(), startUp(),
// startDown()
if (command instanceof DecimalType || command instanceof PercentType) {
logger.debug("Handle command: DecimalType");
device.exact(command.toString());
} else if (command instanceof UpDownType) {
if (command.equals(UpDownType.UP)) {
logger.debug("Handle command: UpDownType.Up");
device.startUp();
} else if (command.equals(UpDownType.DOWN)) {
logger.debug("Handle command: UpDownType.Down");
device.startDown();
}
} else if (command instanceof StopMoveType) {
logger.debug("Handle command: StopMoveType");
device.stop();
} else if (command instanceof OnOffType) {
logger.debug("Handle command: OnOffType");
if (command.equals(OnOffType.ON)) {
device.on();
} else if (command.equals(OnOffType.OFF)) {
device.off();
}
}
} else if (device instanceof SwitchRGBW) {
// possible commands: on(), off(), exact(red, green, blue)
if (command instanceof HSBType) {
logger.debug("Handle command: HSBType");
HSBType hsb = (HSBType) command;
// first set on/off
if (hsb.getBrightness().intValue() > 0) {
if (device.getMetrics().getLevel().toLowerCase().equals("off")) {
device.on();
}
// then set color
int red = (int) Math.round(255 * (hsb.getRed().doubleValue() / 100));
int green = (int) Math.round(255 * (hsb.getGreen().doubleValue() / 100));
int blue = (int) Math.round(255 * (hsb.getBlue().doubleValue() / 100));
device.exact(red, green, blue);
} else {
device.off();
}
}
} else if (device instanceof Thermostat) {
if (command instanceof DecimalType) {
logger.debug("Handle command: DecimalType");
device.exact(command.toString());
}
} else if (device instanceof SwitchControl) {
// possible commands: on(), off(), exact(level), upstart(), upstop(), downstart(),
// downstop()
if (command instanceof OnOffType) {
logger.debug("Handle command: OnOffType");
if (command.equals(OnOffType.ON)) {
device.on();
} else if (command.equals(OnOffType.OFF)) {
device.off();
}
}
} else if (device instanceof ToggleButton || device instanceof SwitchToggle) {
// possible commands: on(), off(), exact(level), upstart(), upstop(), downstart(),
// downstop()
if (command instanceof OnOffType) {
logger.debug("Handle command: OnOffType");
if (command.equals(OnOffType.ON)) {
device.on();
} // no else - only ON command is sent to Z-Way
}
}
}
} catch (UnsupportedOperationException e) {
logger.warn("Unknown command: {}", e.getMessage());
}
} else {
logger.warn("Devices not loaded");
}
} else if (channel.getUID().equals(new ChannelUID(getThing().getUID(), THERMOSTAT_MODE_CC_CHANNEL))) {
// Load physical device
Integer nodeId = Integer.parseInt(channel.getProperties().get("nodeId"));
if (command instanceof DecimalType) {
logger.debug("Handle command: DecimalType");
zwayBridgeHandler.getZWayApi().getZWaveDeviceThermostatModeSet(nodeId,
Integer.parseInt(command.toString()));
} else if (command instanceof RefreshType) {
logger.debug("Handle command: RefreshType");
refreshChannel(channel);
}
}
}
protected synchronized void addDeviceAsChannel(Device device) {
// Device.probeType
// |
// Device.metrics.probeType
// |
// Device.metrics.icon
// |
// Command class
// |
// Default, depends on device type
if (device != null) {
logger.debug("Add virtual device as channel: {}", device.getMetrics().getTitle());
HashMap<String, String> properties = new HashMap<>();
properties.put("deviceId", device.getDeviceId());
String id = "";
String acceptedItemType = "";
// 1. Set basically channel types without further information
if (device instanceof Battery) {
id = BATTERY_CHANNEL;
acceptedItemType = "Number";
} else if (device instanceof Doorlock) {
id = DOORLOCK_CHANNEL;
acceptedItemType = "Switch";
} else if (device instanceof SensorBinary) {
id = SENSOR_BINARY_CHANNEL;
acceptedItemType = "Switch";
} else if (device instanceof SensorMultilevel) {
id = SENSOR_MULTILEVEL_CHANNEL;
acceptedItemType = "Number";
} else if (device instanceof SwitchBinary) {
id = SWITCH_BINARY_CHANNEL;
acceptedItemType = "Switch";
} else if (device instanceof SwitchMultilevel) {
id = SWITCH_MULTILEVEL_CHANNEL;
acceptedItemType = "Dimmer";
} else if (device instanceof SwitchRGBW) {
id = SWITCH_COLOR_CHANNEL;
acceptedItemType = "Color";
} else if (device instanceof Thermostat) {
id = THERMOSTAT_SET_POINT_CHANNEL;
acceptedItemType = "Number";
} else if (device instanceof SwitchControl) {
id = SWITCH_CONTROL_CHANNEL;
acceptedItemType = "Switch";
} else if (device instanceof ToggleButton || device instanceof SwitchToggle) {
id = SWITCH_CONTROL_CHANNEL;
acceptedItemType = "Switch";
} else if (device instanceof SensorDiscrete) {
id = SENSOR_DISCRETE_CHANNEL;
acceptedItemType = "Number";
}
// 2. Check if device information includes further information about sensor type
if (!device.getProbeType().equals("")) {
if (device instanceof SensorMultilevel) {
switch (device.getProbeType()) {
case PROBE_TYPE_TEMPERATURE:
id = SENSOR_TEMPERATURE_CHANNEL;
acceptedItemType = "Number";
break;
case PROBE_TYPE_LUMINOSITY:
id = SENSOR_LUMINOSITY_CHANNEL;
acceptedItemType = "Number";
break;
case PROBE_TYPE_HUMIDITY:
id = SENSOR_HUMIDITY_CHANNEL;
acceptedItemType = "Number";
break;
case PROBE_TYPE_BAROMETER:
id = SENSOR_BAROMETER_CHANNEL;
acceptedItemType = "Number";
break;
case PROBE_TYPE_ULTRAVIOLET:
id = SENSOR_ULTRAVIOLET_CHANNEL;
acceptedItemType = "Number";
break;
case PROBE_TYPE_ENERGY:
id = SENSOR_ENERGY_CHANNEL;
acceptedItemType = "Number";
break;
case PROBE_TYPE_METER_ELECTRIC_KILOWATT_PER_HOUR:
id = SENSOR_METER_KWH_CHANNEL;
acceptedItemType = "Number";
break;
case PROBE_TYPE_METER_ELECTRIC_WATT:
id = SENSOR_METER_W_CHANNEL;
acceptedItemType = "Number";
break;
default:
break;
}
} else if (device instanceof SensorBinary) {
switch (device.getProbeType()) {
case PROBE_TYPE_GENERAL_PURPOSE:
if (device.getMetrics().getIcon().equals(ICON_MOTION)) {
id = SENSOR_MOTION_CHANNEL;
acceptedItemType = "Switch";
}
break;
case PROBE_TYPE_SMOKE:
id = SENSOR_SMOKE_CHANNEL;
acceptedItemType = "Switch";
break;
case PROBE_TYPE_CO:
id = SENSOR_CO_CHANNEL;
acceptedItemType = "Switch";
break;
case PROBE_TYPE_FLOOD:
id = SENSOR_FLOOD_CHANNEL;
acceptedItemType = "Switch";
break;
case PROBE_TYPE_COOLING:
// TODO
break;
case PROBE_TYPE_TAMPER:
id = SENSOR_TAMPER_CHANNEL;
acceptedItemType = "Switch";
break;
case PROBE_TYPE_DOOR_WINDOW:
id = SENSOR_DOOR_WINDOW_CHANNEL;
acceptedItemType = "Contact";
break;
case PROBE_TYPE_MOTION:
id = SENSOR_MOTION_CHANNEL;
acceptedItemType = "Switch";
break;
default:
break;
}
} else if (device instanceof SwitchMultilevel) {
switch (device.getProbeType()) {
case PROBE_TYPE_SWITCH_COLOR_COLD_WHITE:
id = SWITCH_COLOR_TEMPERATURE_CHANNEL;
acceptedItemType = "Dimmer";
break;
case PROBE_TYPE_SWITCH_COLOR_SOFT_WHITE:
id = SWITCH_COLOR_TEMPERATURE_CHANNEL;
acceptedItemType = "Dimmer";
break;
case PROBE_TYPE_MOTOR:
id = SWITCH_ROLLERSHUTTER_CHANNEL;
acceptedItemType = "Rollershutter";
default:
break;
}
} else if (device instanceof SwitchBinary) {
switch (device.getProbeType()) {
case PROBE_TYPE_THERMOSTAT_MODE:
id = THERMOSTAT_MODE_CHANNEL;
acceptedItemType = "Switch";
break;
default:
break;
}
}
} else if (!device.getMetrics().getProbeTitle().equals("")) {
if (device instanceof SensorMultilevel) {
switch (device.getMetrics().getProbeTitle()) {
case PROBE_TITLE_CO2_LEVEL:
id = SENSOR_CO2_CHANNEL;
acceptedItemType = "Number";
break;
default:
break;
}
}
} else if (!device.getMetrics().getIcon().equals("")) {
if (device instanceof SwitchBinary) {
switch (device.getMetrics().getIcon()) {
case ICON_SWITCH:
id = SWITCH_POWER_OUTLET_CHANNEL;
acceptedItemType = "Switch";
break;
default:
break;
}
}
} else {
// Eventually take account of the command classes
}
// If at least one rule could mapped to a channel
if (!id.equals("")) {
addChannel(id, acceptedItemType, device.getMetrics().getTitle(), properties);
logger.debug(
"Channel for virtual device added with channel id: {}, accepted item type: {} and title: {}",
id, acceptedItemType, device.getMetrics().getTitle());
} else {
// Thing status will not be updated because thing could have more than one channel
logger.warn("No channel for virtual device added: {}", device);
}
}
}
private synchronized void addChannel(String id, String acceptedItemType, String label,
HashMap<String, String> properties) {
boolean channelExists = false;
// Check if a channel for this virtual device exist. Attention: same channel type could multiple assigned to a
// thing. That's why not check the existence of channel type.
List<Channel> channels = getThing().getChannels();
for (Channel channel : channels) {
if (channel.getProperties().get("deviceId") != null
&& channel.getProperties().get("deviceId").equals(properties.get("deviceId"))) {
channelExists = true;
}
}
if (!channelExists) {
ThingBuilder thingBuilder = editThing();
ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, id);
Channel channel = ChannelBuilder
.create(new ChannelUID(getThing().getUID(), id + "-" + properties.get("deviceId")),
acceptedItemType)
.withType(channelTypeUID).withLabel(label).withProperties(properties).build();
thingBuilder.withChannel(channel);
thingBuilder.withLabel(thing.getLabel());
updateThing(thingBuilder.build());
}
}
protected synchronized void addCommandClassThermostatModeAsChannel(Map<Integer, String> modes, Integer nodeId) {
logger.debug("Add command class thermostat mode as channel");
ChannelUID channelUID = new ChannelUID(getThing().getUID(), THERMOSTAT_MODE_CC_CHANNEL);
boolean channelExists = false;
// Check if a channel for this virtual device exist. Attention: same channel type could multiple assigned to a
// thing. That's why not check the existence of channel type.
List<Channel> channels = getThing().getChannels();
for (Channel channel : channels) {
if (channel.getUID().equals(channelUID)) {
channelExists = true;
}
}
if (!channelExists) {
// Prepare properties (convert modes map)
HashMap<String, String> properties = new HashMap<>();
// Add node id (for refresh and command handling)
properties.put("nodeId", nodeId.toString());
// Add channel
ThingBuilder thingBuilder = editThing();
Channel channel = ChannelBuilder.create(channelUID, "Number")
.withType(new ChannelTypeUID(BINDING_ID, THERMOSTAT_MODE_CC_CHANNEL))
.withLabel("Thermostat mode (Command Class)").withDescription("Possible modes: " + modes.toString())
.withProperties(properties).build();
thingBuilder.withChannel(channel);
thingBuilder.withLabel(thing.getLabel());
updateThing(thingBuilder.build());
}
}
}

View File

@@ -0,0 +1,194 @@
/**
* 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.zway.internal.handler;
import static org.openhab.binding.zway.internal.ZWayBindingConstants.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.openhab.binding.zway.internal.config.ZWayZAutomationDeviceConfiguration;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.fh_zwickau.informatik.sensor.model.devices.Device;
import de.fh_zwickau.informatik.sensor.model.devices.DeviceList;
/**
* The {@link ZWayZAutomationDeviceHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Patrick Hecker - Initial contribution
*/
public class ZWayZAutomationDeviceHandler extends ZWayDeviceHandler {
public static final ThingTypeUID SUPPORTED_THING_TYPE = THING_TYPE_VIRTUAL_DEVICE;
private final Logger logger = LoggerFactory.getLogger(getClass());
private ZWayZAutomationDeviceConfiguration mConfig;
private class Initializer implements Runnable {
@Override
public void run() {
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler != null && zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
ThingStatusInfo statusInfo = zwayBridgeHandler.getThing().getStatusInfo();
logger.debug("Change Z-Way device status to bridge status: {}", statusInfo.getStatus());
// Set thing status to bridge status
updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
// Add all available channels
DeviceList deviceList = getZWayBridgeHandler().getZWayApi().getDevices();
if (deviceList != null) {
logger.debug("Z-Way devices loaded ({} virtual devices)", deviceList.getDevices().size());
// https://community.openhab.org/t/oh2-major-bug-with-scheduled-jobs/12350/11
// If any execution of the task encounters an exception, subsequent executions are
// suppressed. Otherwise, the task will only terminate via cancellation or
// termination of the executor.
try {
Device device = deviceList.getDeviceById(mConfig.getDeviceId());
if (device != null) {
logger.debug("Add channel for virtual device: {}", device.getMetrics().getTitle());
addDeviceAsChannel(device);
// Starts polling job and register all linked items
completeInitialization();
} else {
logger.warn("Initializing Z-Way device handler failed (virtual device not found): {}",
getThing().getLabel());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Z-Way virtual device with id " + mConfig.getDeviceId() + " not found.");
}
} catch (Throwable t) {
if (t instanceof Exception) {
logger.error("{}", t.getMessage());
} else if (t instanceof Error) {
logger.error("{}", t.getMessage());
} else {
logger.error("Unexpected error");
}
if (getThing().getStatus() == ThingStatus.ONLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Error occurred when adding device as channel.");
}
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Devices not loaded");
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Z-Way bridge handler not found or not ONLINE.");
}
}
}
public ZWayZAutomationDeviceHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing Z-Way ZAutomation device handler ...");
// Set thing status to a valid status
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"Checking configuration and bridge...");
// Configuration - thing status update with a error message
mConfig = loadAndCheckConfiguration();
if (mConfig != null) {
logger.debug("Configuration complete: {}", mConfig);
// Start an extra thread to check the connection, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
scheduler.schedule(new Initializer(), 2, TimeUnit.SECONDS);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Z-Way device id required!");
}
}
private void completeInitialization() {
super.initialize(); // starts polling job and register all linked items
}
private ZWayZAutomationDeviceConfiguration loadAndCheckConfiguration() {
ZWayZAutomationDeviceConfiguration config = getConfigAs(ZWayZAutomationDeviceConfiguration.class);
if (StringUtils.trimToNull(config.getDeviceId()) == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Z-Wave device couldn't create, because the device id is missing.");
return null;
}
return config;
}
@Override
public void dispose() {
logger.debug("Dispose Z-Way ZAutomation handler ...");
if (mConfig.getDeviceId() != null) {
mConfig.setDeviceId(null);
}
super.dispose();
}
@Override
protected void refreshLastUpdate() {
logger.debug("Refresh last update for virtual device");
// Check Z-Way bridge handler
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
// Load and check device from Z-Way server
DeviceList deviceList = zwayBridgeHandler.getZWayApi().getDevices();
if (deviceList != null) {
Device device = deviceList.getDeviceById(mConfig.getDeviceId());
if (device == null) {
logger.debug("ZAutomation device not found.");
return;
}
Calendar lastUpdateOfDevice = Calendar.getInstance();
lastUpdateOfDevice.setTimeInMillis(new Long(device.getUpdateTime()) * 1000);
if (lastUpdate == null || lastUpdateOfDevice.after(lastUpdate)) {
lastUpdate = lastUpdateOfDevice;
}
DateFormat formatter = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
updateProperty(DEVICE_PROP_LAST_UPDATE, formatter.format(lastUpdate.getTime()));
}
}
}

View File

@@ -0,0 +1,223 @@
/**
* 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.zway.internal.handler;
import static org.openhab.binding.zway.internal.ZWayBindingConstants.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.zway.internal.config.ZWayZWaveDeviceConfiguration;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.ThingTypeUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.fh_zwickau.informatik.sensor.model.devices.Device;
import de.fh_zwickau.informatik.sensor.model.devices.DeviceList;
import de.fh_zwickau.informatik.sensor.model.zwaveapi.devices.ZWaveDevice;
/**
* The {@link ZWayZWaveDeviceHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Patrick Hecker - Initial contribution
*/
public class ZWayZWaveDeviceHandler extends ZWayDeviceHandler {
public static final ThingTypeUID SUPPORTED_THING_TYPE = THING_TYPE_DEVICE;
private final Logger logger = LoggerFactory.getLogger(getClass());
private ZWayZWaveDeviceConfiguration mConfig;
private class Initializer implements Runnable {
@Override
public void run() {
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler != null && zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
ThingStatusInfo statusInfo = zwayBridgeHandler.getThing().getStatusInfo();
logger.debug("Change Z-Way Z-Wave device status to bridge status: {}", statusInfo);
// Set thing status to bridge status
updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
// Add all available channels
logger.debug("Add all available channels");
DeviceList deviceList = getZWayBridgeHandler().getZWayApi().getDevices();
if (deviceList != null) {
logger.debug("Z-Way devices loaded ({} physical devices)",
deviceList.getDevicesGroupByNodeId().size());
// https://community.openhab.org/t/oh2-major-bug-with-scheduled-jobs/12350/11
// If any execution of the task encounters an exception, subsequent executions are
// suppressed. Otherwise, the task will only terminate via cancellation or
// termination of the executor.
try {
// physical device means all virtual devices grouped by physical device
Map<Integer, List<Device>> physicalDevice = deviceList.getDevicesByNodeId(mConfig.getNodeId());
if (physicalDevice != null) {
logger.debug("Z-Wave device with node id {} found with {} virtual devices",
mConfig.getNodeId(), physicalDevice.get(mConfig.getNodeId()).size());
for (Map.Entry<Integer, List<Device>> entry : physicalDevice.entrySet()) {
logger.debug("Add channels for physical device with node id: {}", mConfig.getNodeId());
List<Device> devices = entry.getValue();
for (Device device : devices) {
if (device.getVisibility() && !device.getPermanentlyHidden()) {
logger.debug("Add channel for virtual device: {}",
device.getMetrics().getTitle());
addDeviceAsChannel(device);
} else {
logger.debug("Device {} has been skipped, because it was hidden in Z-Way.",
device.getMetrics().getTitle());
}
}
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Z-Way physical device with node id " + mConfig.getNodeId() + " not found.");
}
// Check command classes (only for ThermostatMode)
ZWaveDevice zwaveDevice = getZWayBridgeHandler().getZWayApi()
.getZWaveDevice(mConfig.getNodeId());
if (!zwaveDevice.getInstances().get0().getCommandClasses().get64().getName().equals("")) {
// Load available thermostat modes
Map<Integer, String> modes = zwaveDevice.getInstances().get0().getCommandClasses().get64()
.getThermostatModes();
logger.debug(
"Z-Wave device implements command class ThermostatMode with the following modes: {}",
modes.toString());
addCommandClassThermostatModeAsChannel(modes, mConfig.getNodeId());
}
// Starts polling job and register all linked items
completeInitialization();
} catch (Throwable t) {
if (t instanceof Exception) {
logger.error("{}", t.getMessage());
} else if (t instanceof Error) {
logger.error("{}", t.getMessage());
} else {
logger.error("Unexpected error");
}
if (getThing().getStatus() == ThingStatus.ONLINE) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Error occurred when adding device as channel.");
}
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Devices not loaded");
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
"Z-Way bridge handler not found or not ONLINE.");
}
}
}
public ZWayZWaveDeviceHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing Z-Way device handler ...");
// Set thing status to a valid status
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
"Checking configuration and bridge...");
// Configuration - thing status update with a error message
mConfig = loadAndCheckConfiguration();
if (mConfig != null) {
logger.debug("Configuration complete: {}", mConfig);
// Start an extra thread to check the connection, because it takes sometimes more
// than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
scheduler.schedule(new Initializer(), 2, TimeUnit.SECONDS);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Z-Way node id required!");
}
}
private void completeInitialization() {
super.initialize(); // starts polling job and register all linked items
}
private ZWayZWaveDeviceConfiguration loadAndCheckConfiguration() {
ZWayZWaveDeviceConfiguration config = getConfigAs(ZWayZWaveDeviceConfiguration.class);
if (config.getNodeId() == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Z-Wave device couldn't create, because the node id is missing.");
return null;
}
return config;
}
@Override
public void dispose() {
logger.debug("Dispose Z-Way Z-Wave handler ...");
if (mConfig.getNodeId() != null) {
mConfig.setNodeId(null);
}
super.dispose();
}
@Override
protected void refreshLastUpdate() {
logger.debug("Refresh last update for Z-Wave device");
// Check Z-Way bridge handler
ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
logger.debug("Z-Way bridge handler not found or not ONLINE.");
return;
}
// Load and check Z-Wave device from Z-Way server (Z-Wave API)
ZWaveDevice zwaveDevice = zwayBridgeHandler.getZWayApi().getZWaveDevice(mConfig.getNodeId());
if (zwaveDevice == null) {
logger.debug("Z-Wave device not found.");
return;
}
Calendar lastUpdateOfDevice = Calendar.getInstance();
lastUpdateOfDevice.setTimeInMillis(new Long(zwaveDevice.getData().getLastReceived().getUpdateTime()) * 1000);
if (lastUpdate == null || lastUpdateOfDevice.after(lastUpdate)) {
lastUpdate = lastUpdateOfDevice;
}
DateFormat formatter = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
updateProperty(DEVICE_PROP_LAST_UPDATE, formatter.format(lastUpdate.getTime()));
}
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="zway" 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>Z-Way Binding</name>
<description>
<![CDATA[
Z-Way is a home automation software to configure and control a Z-Wave network. The ZAutomation interface provides
all Z-Wave devices and handles incoming commands. The Z-Way Binding uses this HTTP interface to load all device
and make them available during the discovery process.<br>
Currently only a continuous polling is available!
]]>
</description>
<author>Patrick Hecker</author>
</binding:binding>

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<config-description:config-descriptions
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
https://openhab.org/schemas/config-description-1.0.0.xsd">
<config-description uri="binding:zway:zwayServer">
<parameter-group name="zwayServer">
<label>Z-Way Server</label>
<description>The configuration of the Z-Way server. Except for the username and password all the information detected
during the discovery.</description>
</parameter-group>
<parameter-group name="binding">
<label>Options</label>
<description>These settings affect functions of the binding.</description>
</parameter-group>
<parameter name="zwayServerIpAddress" groupName="zwayServer" type="text">
<context>network-address</context>
<label>IP Address</label>
<description>The IP address or hostname of the Z-Way server. If Z-Way and openHAB are running on the same machine,
the default value can be used.</description>
<default>localhost</default>
</parameter>
<parameter name="zwayServerPort" groupName="zwayServer" type="integer" required="false" min="1" max="65535">
<label>Port</label>
<description>The port of the Z-Way server</description>
<default>8083</default>
</parameter>
<parameter name="zwayServerProtocol" groupName="zwayServer" type="text" required="false">
<label>Protocol</label>
<description>Protocol to connect to the Z-Way server (http or https)</description>
<default>http</default>
<options>
<option value="http">HTTP</option>
<option value="https">HTTPS</option>
</options>
</parameter>
<parameter name="zwayServerUsername" groupName="zwayServer" type="text">
<label>Username</label>
<description>Username to access the Z-Way server.</description>
<default>admin</default>
</parameter>
<parameter name="zwayServerPassword" groupName="zwayServer" type="text" required="true">
<context>password</context>
<label>Password</label>
<description>Password to access the Z-Way server.</description>
</parameter>
<parameter name="pollingInterval" groupName="binding" type="integer" required="false" min="60" max="3600"
unit="s">
<label>Polling Interval</label>
<description>Refresh device states and registration from Z-Way server.</description>
<unitLabel>Seconds</unitLabel>
<default>3600</default>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -0,0 +1,92 @@
# binding
binding.zway.name = Z-Way Binding
binding.zway.description = Z-Way is a home automation software to configure and control a Z-Wave network. The ZAutomation interface provides all Z-Wave devices and handles incoming commands. The Z-Way Binding uses this HTTP interface to load all device and make them available during the discovery process.<br> Currently only a continuous polling is available!
# thing types
thing-type.zway.zwayServer.label = Z-Way Server
thing-type.zway.zwayServer.description = The Z-Way server represents a bridge with general settings and communication tasks.
thing-type.config.zway.zwayServer.zwayServer.label = Z-Way server
thing-type.config.zway.zwayServer.zwayServer.description = The configuration of the Z-Way server. Except for the username and password all the information detected during the discovery.
thing-type.config.zway.zwayServer.binding.label = Options
thing-type.config.zway.zwayServer.binding.description = These settings affect functions of the binding.
thing-type.config.zway.zwayServer.zwayServerIpAddress.label = IP address
thing-type.config.zway.zwayServer.zwayServerIpAddress.description = The IP address or hostname of the Z-Way server. If Z-Way and openHAB are running on the same machine, the default value can be used.
thing-type.config.zway.zwayServer.zwayServerPort.label = Port
thing-type.config.zway.zwayServer.zwayServerPort.description = The port of the Z-Way server
thing-type.config.zway.zwayServer.zwayServerProtocol.label = Protocol
thing-type.config.zway.zwayServer.zwayServerProtocol.description = Protocol to connect to the Z-Way server (http or https)
thing-type.config.zway.zwayServer.zwayServerUsername.label = Username
thing-type.config.zway.zwayServer.zwayServerUsername.description = Username to access the Z-Way server.
thing-type.config.zway.zwayServer.zwayServerPassword.label = Password
thing-type.config.zway.zwayServer.zwayServerPassword.description = Password to access the Z-Way server.
thing-type.config.zway.zwayServer.pollingInterval.label = Polling Interval
thing-type.config.zway.zwayServer.pollingInterval.description = Refresh device states and registration from Z-Way server.
thing-type.zway.zwayDevice.label = Z-Wave Device
thing-type.zway.zwayDevice.description = A Z-Wave device represents a device of real world. Each device function will be mapped to a separate channel. The bridge is necessary as an intermediary between openHAB thing and Z-Way device.
thing-type.config.zway.zwayDevice.nodeId.label = Node Id
thing-type.config.zway.zwayDevice.nodeId.description = Node Id of the Z-Wave device
thing-type.zway.zwayVirtualDevice.label = Z-Way Virtual Device
thing-type.zway.zwayVirtualDevice.description = A Z-Way virtual device represents one sensor, actor or Z-Way App with the corresponding channel. The bridge is necessary as an intermediary between openHAB thing and Z-Way device.
thing-type.config.zway.zwayVirtualDevice.deviceId.label = Device Id
thing-type.config.zway.zwayVirtualDevice.deviceId.description = Device Id of virtual device
# channel types
channel-type.zway.sensorTemperature.label = Temperature
channel-type.zway.sensorLuminosity.label = Luminiscence
channel-type.zway.sensorHumidity.label = Humidity
channel-type.zway.sensorBarometer.label = Barometer
channel-type.zway.sensorUltraviolet.label = Ultraviolet
channel-type.zway.sensorCO2.label = CarbonDioxide
channel-type.zway.sensorEnergy.label = Energy
channel-type.zway.sensorMeterKWh.label = Energy
channel-type.zway.sensorMeterW.label = Energy
channel-type.zway.sensorSmoke.label = Smoke
channel-type.zway.sensorCo.label = Gas
channel-type.zway.sensorFlood.label = Flood
channel-type.zway.sensorTamper.label = Tamper
channel-type.zway.sensorDoorWindow.label = DoorWindow
channel-type.zway.sensorMotion.label = Motion
channel-type.zway.switchPowerOutlet.label = PowerOutlet
channel-type.zway.switchColorTemperature.label = Color Temperature
# channel type without further information
channel-type.zway.battery.label = Battery
channel-type.zway.doorlock.label = Doorlock
channel-type.zway.sensorBinary.label = Sensor binary
channel-type.zway.sensorBinary.description = This channel represents a universal channel if no further device information is available.
channel-type.zway.sensorMultilevel.label = Sensor multilevel
channel-type.zway.sensorMultilevel.description = This channel represents a universal channel if no further device information is available.
channel-type.zway.switchBinary.label = Switch binary
channel-type.zway.switchBinary.description = This channel represents a universal channel if no further device information is available.
channel-type.zway.switchMultilevel.label = Switch multilevel
channel-type.zway.switchMultilevel.description = This channel represents a universal channel if no further device information is available.
channel-type.zway.switchColor.label = Switch color
channel-type.zway.switchColor.description = This channel represents the RGBW switch device type from Z-Way.
channel-type.zway.switchControl.label = Switch control
channel-type.zway.switchControl.description = This channel represents a universal channel if no further device information is available.
channel-type.zway.sensorDiscrete.label = Sensor discrete
channel-type.zway.sensorDiscrete.description = This channel represents a two-digit value. The first digit is the button/scene number and the second digit points to action/keyAttribute (have a look at http://z-wave.sigmadesigns.com/wp-content/uploads/2016/08/SDS12657-12-Z-Wave-Command-Class-Specification-A-M.pdf, p. 153).
channel-type.zway.thermostatMode.label = Thermostat mode
channel-type.zway.thermostatMode.description = The channel allows the control or display of a thermostat (mode). A thermostat can have up to three states (modes): off, heating and cooling. The state of heating and cooling is alternately set at the state on.
channel-type.zway.thermostatSetPoint.label = Thermostat set point
channel-type.zway.thermostatModeV2.label = Thermostat mode (Command Class)
channel-type.zway.thermostatModeV2.description = The channel allows the control or display of a thermostat (mode) from command class. The modes differ from device to device.
channel-type.zway.actions.label = Actions
channel-type.zway.actions.description = Available actions of the Z-Wave Controller
channel-type.zway.actions.option.REFRESH = Refresh all things
channel-type.zway.secureInclusion.label = Secure inclusion
channel-type.zway.secureInclusion.description = Change inclusion type for further inclusions.
channel-type.zway.inclusion.label = Inclusion
channel-type.zway.inclusion.description = Start inclusion mode (after a timeout the inclusion will be automatically finished).
channel-type.zway.exclusion.label = Exclusion
channel-type.zway.exclusion.description = Start exclusion mode (after a timeout the exclusion will be automatically finished).

View File

@@ -0,0 +1,92 @@
# binding
binding.zway.name = Z-Way Binding
binding.zway.description = Das Z-Way-System ist ein Softwarepaket für den Z-Wave Funkstandard. Das System besteht im wesentlichen aus einer Firmware für Z-Wave Transceiver, einer Kommunikations- und einer Automatisierungskomponente zur Steuerung und Konfiguration des Netzwerks. Das Z-Way Binding nutzt die HTTP-Schnittstelle um alle Geräte zu laden und im Discovery-Prozess zur Verfügung zu stellen.<br>Aktuell wird nur Polling zum Aktualisieren der Gerätezustände verwendet!
# thing types
thing-type.zway.zwayServer.label = Z-Way Server
thing-type.zway.zwayServer.description = Der Z-Way Server repräsentiert das Z-Way System als Bridge mit der grundlegendene Konfiguration zum Verbindungsaufbau. Die gesamte Kommunikation mit Z-Way organisiert diese Komponente.
thing-type.config.zway.zwayServer.zwayServer.label = Z-Way Server
thing-type.config.zway.zwayServer.zwayServer.description = Die Konfiguration des Z-Way Server wird bis auf den Benutzername und das Passwort während des Discovery-Prozesses ermittlt.
thing-type.config.zway.zwayServer.binding.label = Optionen
thing-type.config.zway.zwayServer.binding.description = Diese Einstellungen betreffen Funktionen des Bindings.
thing-type.config.zway.zwayServer.zwayServerIpAddress.label = IP-Adresse
thing-type.config.zway.zwayServer.zwayServerIpAddress.description = Die Adresse unter der Z-Way erreichbar ist. Sollte sich der Z-Way Server und openHAB auf dem selben Rechner befinden, kann der Standardwert beibehalten werden.
thing-type.config.zway.zwayServer.zwayServerPort.label = Port
thing-type.config.zway.zwayServer.zwayServerPort.description = Der Port unter dem das openHAB-System erreichbar ist.
thing-type.config.zway.zwayServer.zwayServerProtocol.label = Protokoll
thing-type.config.zway.zwayServer.zwayServerProtocol.description = HTTP/HTTPS
thing-type.config.zway.zwayServer.zwayServerUsername.label = Benutzername
thing-type.config.zway.zwayServer.zwayServerUsername.description = Benutzername für den Zugriff auf das Z-Way System.
thing-type.config.zway.zwayServer.zwayServerPassword.label = Passwort
thing-type.config.zway.zwayServer.zwayServerPassword.description = Passwort für den Zugriff auf das Z-Way System.
thing-type.config.zway.zwayServer.pollingInterval.label = Polling Interval
thing-type.config.zway.zwayServer.pollingInterval.description = Aktualisiert den Gerätezustand und die Registrierung beim <i>OpenHAB Konnektor</i>
thing-type.zway.zwayDevice.label = Z-Wave Gerät
thing-type.zway.zwayDevice.description = Ein Z-Wave Gerät repräsentiert ein physisch existierendes Gerät. Dabei wird jede Gerätefunktion (Temperatursensor, Luftfeuchtigkeitsmesser usw.) einem Channel zugeordnet. Eine Bridge (Z-Way Server) wird als Vermittler zwischen openHAB und Z-Way benötigt.
thing-type.config.zway.zwayDevice.nodeId.label = Node Id
thing-type.config.zway.zwayDevice.nodeId.description = Node Id des Geräts im Z-Wave Netzwerk
thing-type.zway.zwayVirtualDevice.label = Z-Way virtuelles Gerät
thing-type.zway.zwayVirtualDevice.description = Ein virtuelles Gerät repräsentiert genau eine Sensor, Aktor oder ein Z-Way App mit einem Channel. Eine Bridge (Z-Way Server) wird als Vermittler zwischen openHAB und Z-Way benötigt.
thing-type.config.zway.zwayVirtualDevice.deviceId.label = Device Id
thing-type.config.zway.zwayVirtualDevice.deviceId.description = Device Id des virtuellen Geräts
# channel types
channel-type.zway.sensorTemperature.label = Temperatur
channel-type.zway.sensorLuminosity.label = Helligkeit
channel-type.zway.sensorHumidity.label = Luftfeuchtigkeit
channel-type.zway.sensorBarometer.label = Luftdruck
channel-type.zway.sensorUltraviolet.label = Lichtintensität
channel-type.zway.sensorCO2.label = Kohlendioxid
channel-type.zway.sensorEnergy.label = Energie
channel-type.zway.sensorMeterKWh.label = Energie (kWh)
channel-type.zway.sensorMeterW.label = Energie (W)
channel-type.zway.sensorSmoke.label = Rauch
channel-type.zway.sensorCo.label = Gas
channel-type.zway.sensorFlood.label = Überflutung
channel-type.zway.sensorTamper.label = Manipulation
channel-type.zway.sensorDoorWindow.label = Tür-/Fensterkontakt
channel-type.zway.sensorMotion.label = Bewegung
channel-type.zway.switchPowerOutlet.label = Steckdose
channel-type.zway.switchColorTemperature.label = Farbtemperatur
# channel type without further information
channel-type.zway.battery.label = Batterie
channel-type.zway.doorlock.label = Türschloss
channel-type.zway.sensorBinary.label = Binärsensor
channel-type.zway.sensorBinary.description = Dieser Channel ist allgemeingültig für verschiedene Geräte des gleichen Gerätetyps, wenn keine weiteren Informationen zur Verfügung stehen.
channel-type.zway.sensorMultilevel.label = Multilevel-Sensor
channel-type.zway.sensorMultilevel.description = Dieser Channel ist allgemeingültig für verschiedene Geräte des gleichen Gerätetyps, wenn keine weiteren Informationen zur Verfügung stehen.
channel-type.zway.switchBinary.label = Binärschalter
channel-type.zway.switchBinary.description = Dieser Channel ist allgemeingültig für verschiedene Geräte des gleichen Gerätetyps, wenn keine weiteren Informationen zur Verfügung stehen.
channel-type.zway.switchMultilevel.label = Multilevel-Schalter
channel-type.zway.switchMultilevel.description = Dieser Channel ist allgemeingültig für verschiedene Geräte des gleichen Gerätetyps, wenn keine weiteren Informationen zur Verfügung stehen.
channel-type.zway.switchColor.label = RGB-Schalter
channel-type.zway.switchColor.description = Dieser Channel repräsentiert einen RGB-Schalter von Z-Way.
channel-type.zway.switchControl.label = Binärschalter
channel-type.zway.switchControl.description = Dieser Channel ist allgemeingültig für verschiedene Geräte des gleichen Gerätetyps, wenn keine weiteren Informationen zur Verfügung stehen.
channel-type.zway.sensorDiscrete.label = Diskreter Sensor
channel-type.zway.sensorDiscrete.description = Dieser Channel repräsentiert einen zweistelligen Wert. Die erste Zahl ist der Button/Szene und der zweite Wert beschreibt die Aktion/KeyAttribute (siehe auch http://z-wave.sigmadesigns.com/wp-content/uploads/2016/08/SDS12657-12-Z-Wave-Command-Class-Specification-A-M.pdf, S. 153).
channel-type.zway.thermostatMode.label = Thermostat Modus
channel-type.zway.thermostatMode.description = Dieser Channel erlaubt die Steuerung und Anzeige eines Thermostats (Modus). Ein Thermostat kann einer der drei Zustände einnehmen (Modi): "Aus", "Heizen" oder "Kühlen". Der Zustand "Heizen" und "Kühlen" wird wechselweise im Zustand "An" gesetzt.
channel-type.zway.thermostatSetPoint.label = Thermostat Sollwert
channel-type.zway.thermostatModeV2.label = Thermostat Modus (Kommandoklasse)
channel-type.zway.thermostatModeV2.description = Dieser Channel erlaubt die Steuerung und Anzeige eines Thermostats (Modus) auf Basis der Kommandoklasse. Die verfügbaren Modi variieren von Gerät zu Gerät.
channel-type.zway.actions.label = Aktionen
channel-type.zway.actions.description = Aktionen des Z-Wave Controller
channel-type.zway.actions.option.REFRESH = Alle Geräte aktualisieren
channel-type.zway.secureInclusion.label = Sichere Inklusion
channel-type.zway.secureInclusion.description = ändert den Inklusionsmodus für folgende Inklusionen.
channel-type.zway.inclusion.label = Inklusionsmodus
channel-type.zway.inclusion.description = Starten des Inklusionsmodus (nach einem Timeout wird der Modus automatisch verlassen).
channel-type.zway.exclusion.label = Exklusionsmodus
channel-type.zway.exclusion.description = Starten des Exklusionsmodus (nach einem Timeout wird der Modus automatisch verlassen).

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="zway"
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">
<bridge-type id="zwayServer">
<label>Z-Way Server</label>
<description>
<![CDATA[
The Z-Way server represents a bridge with general settings and communication tasks.
]]>
</description>
<channels>
<channel id="actions" typeId="actions"/>
<channel id="secureInclusion" typeId="secureInclusion"/>
<channel id="inclusion" typeId="inclusion"/>
<channel id="exclusion" typeId="exclusion"/>
</channels>
<config-description-ref uri="binding:zway:zwayServer"/>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,266 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="zway"
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="sensorTemperature">
<item-type>Number</item-type>
<label>Temperature</label>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f °C"/>
</channel-type>
<channel-type id="sensorLuminosity">
<item-type>Number</item-type>
<label>Luminiscence</label>
<category>Light</category>
<state readOnly="true" pattern="%.1f Lux"/>
</channel-type>
<channel-type id="sensorHumidity">
<item-type>Number</item-type>
<label>Humidity</label>
<category>Humidity</category>
<state readOnly="true" pattern="%.1f %%"/>
</channel-type>
<channel-type id="sensorBarometer">
<item-type>Number</item-type>
<label>Barometer</label>
<category>Pressure</category>
<state readOnly="true" pattern="%.1f"/>
</channel-type>
<channel-type id="sensorUltraviolet">
<item-type>Number</item-type>
<label>Ultraviolet</label>
<category>Light</category>
<state readOnly="true" pattern="%.1f UV index"/>
</channel-type>
<channel-type id="sensorCO2">
<item-type>Number</item-type>
<label>CO2</label>
<category>CarbonDioxide</category>
<state readOnly="true" pattern="%.1f ppm"/>
</channel-type>
<channel-type id="sensorEnergy">
<item-type>Number</item-type>
<label>Energy</label>
<category>Energy</category>
<state readOnly="true" pattern="%.1f W"/>
</channel-type>
<channel-type id="sensorMeterKWh">
<item-type>Number</item-type>
<label>Energy</label>
<category>Energy</category>
<state readOnly="true" pattern="%.1f kWh"/>
</channel-type>
<channel-type id="sensorMeterW">
<item-type>Number</item-type>
<label>Energy</label>
<category>Energy</category>
<state readOnly="true" pattern="%.1f W"/>
</channel-type>
<channel-type id="sensorSmoke">
<item-type>Switch</item-type>
<label>Smoke</label>
<category>Smoke</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorCo">
<item-type>Switch</item-type>
<label>Gas</label>
<category>Gas</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorFlood">
<item-type>Switch</item-type>
<label>Flood</label>
<category>Water</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorTamper">
<item-type>Switch</item-type>
<label>Tamper</label>
<category>Alarm</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorDoorWindow">
<item-type>Contact</item-type>
<label>DoorWindow</label>
<category>Contact</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorMotion">
<item-type>Switch</item-type>
<label>Motion</label>
<category>Motion</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="switchPowerOutlet">
<item-type>Switch</item-type>
<label>PowerOutlet</label>
<category>PowerOutlet</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="switchColorTemperature">
<item-type>Dimmer</item-type>
<label>Color Temperature</label>
<category>ColorLight</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="switchBlinds">
<item-type>Rollershutter</item-type>
<label>Rollshutter</label>
<category>Blinds</category>
<state readOnly="false"/>
</channel-type>
<!-- Channel types without further information -->
<channel-type id="battery">
<item-type>Number</item-type>
<label>Battery</label>
<category>Battery</category>
<state readOnly="true" pattern="%.1f %%"/>
</channel-type>
<channel-type id="doorlock">
<item-type>Switch</item-type>
<label>Doorlock</label>
<category>Door</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="sensorBinary">
<item-type>Switch</item-type>
<label>Sensor Binary</label>
<description>This channel represents a universal channel if no further device information is available.</description>
<category>Switch</category>
<state readOnly="true"/>
</channel-type>
<channel-type id="sensorMultilevel">
<item-type>Number</item-type>
<label>Sensor Multilevel</label>
<description>This channel represents a universal channel if no further device information is available.</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="switchBinary">
<item-type>Switch</item-type>
<label>Switch Binary</label>
<description>This channel represents a universal channel if no further device information is available.</description>
<category>Switch</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="switchMultilevel">
<item-type>Dimmer</item-type>
<label>Switch Multilevel</label>
<description>This channel represents a universal channel if no further device information is available.</description>
<state readOnly="false"/>
</channel-type>
<channel-type id="switchColor">
<item-type>Color</item-type>
<label>Switch Color</label>
<description>This channel represents the rgbw switch device type from Z-Way.</description>
<category>ColorLight</category>
</channel-type>
<channel-type id="thermostatMode">
<item-type>Switch</item-type>
<label>Thermostat Mode</label>
<description>The channel allows the control or display of a thermostat (mode). A thermostat can have up to three
states (modes): off, heating and cooling. The state of heating and cooling is alternately set at the state on.</description>
<category>Temperature</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="thermostatSetPoint">
<item-type>Number</item-type>
<label>Thermostat Set Point</label>
<category>Temperature</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="switchControl">
<item-type>Switch</item-type>
<label>Switch Control</label>
<description>This channel represents a universal channel if no further device information is available.</description>
<category>Switch</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="sensorDiscrete">
<item-type>Number</item-type>
<label>Sensor Discrete</label>
<description>This channel represents a two-digit value. The first digit is the button/scene number and the second
digit points to action/keyAttribute (have a look at
http://z-wave.sigmadesigns.com/wp-content/uploads/2016/08/SDS12657-12-Z-Wave-Command-Class-Specification-A-M.pdf, p.
153).</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="thermostatModeCC">
<item-type>Number</item-type>
<label>Thermostat Mode (Command Class)</label>
<description>The channel allows the control or display of a thermostat (mode) from command class. The modes differ
from device to device.</description>
<category>Temperature</category>
<state readOnly="false"/>
</channel-type>
<!-- Special channel types -->
<channel-type id="actions">
<item-type>String</item-type>
<label>Actions</label>
<description>Available actions of the Z-Wave Controller</description>
<state>
<options>
<option value="REFRESH">Refresh all things</option>
</options>
</state>
</channel-type>
<channel-type id="secureInclusion">
<item-type>Switch</item-type>
<label>Secure Inclusion</label>
<description>Change inclusion type for further inclusions.</description>
<category>Switch</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="inclusion">
<item-type>Switch</item-type>
<label>Inclusion</label>
<description>Start inclusion mode (after a timeout the inclusion will be automatically finished).</description>
<category>Switch</category>
<state readOnly="false"/>
</channel-type>
<channel-type id="exclusion">
<item-type>Switch</item-type>
<label>Exclusion</label>
<description>Start exclusion mode (after a timeout the exclusion will be automatically finished).</description>
<category>Switch</category>
<state readOnly="false"/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="zway"
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="zwayDevice">
<supported-bridge-type-refs>
<bridge-type-ref id="zwayServer"/>
</supported-bridge-type-refs>
<label>Z-Wave Device</label>
<description>
<![CDATA[
A Z-Wave device represents a device of real world. Each device function will be mapped to
a separate channel. The bridge is necessary as an intermediary between openHAB thing
and Z-Way device.
]]>
</description>
<config-description>
<parameter name="nodeId" type="integer" required="true">
<label>Node Id</label>
<description>Node Id of the Z-Wave device</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="zway"
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="zwayVirtualDevice">
<supported-bridge-type-refs>
<bridge-type-ref id="zwayServer"/>
</supported-bridge-type-refs>
<label>Z-Way Virtual Device</label>
<description>
<![CDATA[
A Z-Way virtual device represents one sensor, actor or Z-Way App with the corresponding channel.
The bridge is necessary as an intermediary between openHAB thing and Z-Way device.
]]>
</description>
<config-description>
<parameter name="deviceId" type="text" required="true">
<label>Device Id</label>
<description>Device Id of virtual device</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>