diff --git a/addons/binding/org.openhab.binding.vera/.classpath b/addons/binding/org.openhab.binding.vera/.classpath new file mode 100644 index 0000000000000..a9d178f069e87 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/addons/binding/org.openhab.binding.vera/.project b/addons/binding/org.openhab.binding.vera/.project new file mode 100644 index 0000000000000..a3d85fe234195 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/.project @@ -0,0 +1,33 @@ + + + org.openhab.binding.vera + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/addons/binding/org.openhab.binding.vera/ESH-INF/binding/binding.xml b/addons/binding/org.openhab.binding.vera/ESH-INF/binding/binding.xml new file mode 100644 index 0000000000000..b6e38d71ace5e --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/ESH-INF/binding/binding.xml @@ -0,0 +1,9 @@ + + + + Vera Binding + Vera (lite/edge/plus/etc version) is a popular Z-Wave controller. Vera binding automatically finds the addresses of all such controllers on the local network, and through HTTP api loads all their devices and scenes. + Dmitriy Ponomarev + + diff --git a/addons/binding/org.openhab.binding.vera/ESH-INF/config/bridge-config.xml b/addons/binding/org.openhab.binding.vera/ESH-INF/config/bridge-config.xml new file mode 100644 index 0000000000000..0cc0800ad1b99 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/ESH-INF/config/bridge-config.xml @@ -0,0 +1,53 @@ + + + + + + + The configuration of the Vera. All the information can be detected during the discovery. + + + + network-address + + The IP address or hostname of the Vera controller. + 192.168.1.10 + + + + + The port of the Vera controller + 3480 + + + + + Refresh all values (name, room, state) for all devices and scenes. + Seconds + 60 + + + + + Remove digits, slashes and double spaces from all names. Good for some voice recognition services. + false + + + + + Default name for room, if no room specified. + No Room + + + + + If enabled, homekit tags are created for all supported devices. Please read Homekit add-on instructions. + true + + + + diff --git a/addons/binding/org.openhab.binding.vera/ESH-INF/thing/bridge.xml b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/bridge.xml new file mode 100644 index 0000000000000..756048493bd29 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/bridge.xml @@ -0,0 +1,16 @@ + + + + + + A popular Z-Wave controller Vera (lite/edge/plus/etc). + + + + + + + + + diff --git a/addons/binding/org.openhab.binding.vera/ESH-INF/thing/channels.xml b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/channels.xml new file mode 100644 index 0000000000000..664408392ae8b --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/channels.xml @@ -0,0 +1,188 @@ + + + + + Number + + Temperature + + + + + Number + + Light + + + + + Number + + Humidity + + + + + Number + + Light + + + + + Number + + Energy + + + + + Number + + Energy + + + + + Number + + Energy + + + + + Switch + + Smoke + + + + + Switch + + Gas + + + + + Switch + + Water + + + + + Contact + + Contact + + + + + Switch + + Motion + + + + + Rollershutter + + Blinds + + + + + Number + + Battery + + + + + Switch + + Door + + + + + + + Switch + + This channel represents a universal channel if no further device information is available. + Switch + + + + + Switch + + This channel represents a universal channel if no further device information is available. + Switch + + + + + Dimmer + + This channel represents a universal channel if no further device information is available. + Switch + + + + + Color + + This channel represents the rgbw switch device type from Vera. + ColorLight + + + + Switch + + 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. + Temperature + + + + + Number + + Temperature + + + + + Number + + The channel allows the control or display of a thermostat (mode) from command class. The modes differ from device to device. + Temperature + + + + + + Switch + + This channel represents a scene button. + Switch + + + + + + + String + + Available actions of the Vera Controller + + + + + + + diff --git a/addons/binding/org.openhab.binding.vera/ESH-INF/thing/device.xml b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/device.xml new file mode 100644 index 0000000000000..4d91ba3089c2b --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/device.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + A Vera device represents one sensor or actor with the one or more channels. + + + + + Id of the Vera device + + + + diff --git a/addons/binding/org.openhab.binding.vera/ESH-INF/thing/scene.xml b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/scene.xml new file mode 100644 index 0000000000000..2f12c2b14c177 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/ESH-INF/thing/scene.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + A Vera scene represents one scene with the one channel. + + + + + Id of the Vera scene + + + + diff --git a/addons/binding/org.openhab.binding.vera/META-INF/MANIFEST.MF b/addons/binding/org.openhab.binding.vera/META-INF/MANIFEST.MF new file mode 100644 index 0000000000000..c6eeb62f6329f --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/META-INF/MANIFEST.MF @@ -0,0 +1,30 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Vera Binding +Bundle-SymbolicName: org.openhab.binding.vera;singleton:=true +Bundle-Vendor: openHAB +Bundle-Version: 2.1.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ClassPath: . +Import-Package: com.google.common.collect, + com.google.gson, + com.google.gson.annotations, + org.apache.commons.lang, + org.apache.commons.lang.builder, + org.apache.commons.net.util, + org.eclipse.smarthome.config.core, + org.eclipse.smarthome.config.discovery, + org.eclipse.smarthome.core.library.types, + org.eclipse.smarthome.core.thing, + org.eclipse.smarthome.core.thing.binding, + org.eclipse.smarthome.core.thing.binding.builder, + org.eclipse.smarthome.core.thing.type, + org.eclipse.smarthome.core.types, + org.openhab.binding.vera, + org.openhab.binding.vera.handler, + org.osgi.framework, + org.slf4j +Service-Component: OSGI-INF/*.xml +Export-Package: org.openhab.binding.vera, + org.openhab.binding.vera.handler +Bundle-ActivationPolicy: lazy diff --git a/addons/binding/org.openhab.binding.vera/OSGI-INF/VeraBridgeDiscovery.xml b/addons/binding/org.openhab.binding.vera/OSGI-INF/VeraBridgeDiscovery.xml new file mode 100644 index 0000000000000..445764099cc02 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/OSGI-INF/VeraBridgeDiscovery.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/addons/binding/org.openhab.binding.vera/OSGI-INF/VeraHandlerFactory.xml b/addons/binding/org.openhab.binding.vera/OSGI-INF/VeraHandlerFactory.xml new file mode 100644 index 0000000000000..aebe0f52e7c73 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/OSGI-INF/VeraHandlerFactory.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/addons/binding/org.openhab.binding.vera/README.md b/addons/binding/org.openhab.binding.vera/README.md new file mode 100644 index 0000000000000..ef06c86753448 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/README.md @@ -0,0 +1,118 @@ +# Vera Binding + +Vera (lite/edge/plus/etc version) is a popular Z-Wave controller. Vera binding automatically finds the addresses of all such controllers on the local network, and through HTTP api loads all their devices and scenes. + +## Supported Things + +Vera binding provides three thing types: controller, devices and scenes. There may be more than one controller. +Each device usually has one channel. But some devices has additional channels, such as battery level, power consumption and others. +Each scene has only one channel, to start scene. + +## Discovery + +A discovery service for Vera controller scans local network and must always be started manually. + +Another discovery service provides available devices. The device discovery service is performed at a specified interval, but can also be started manually. + +Note: devices with type "controller" and "interface" not loaded. + +## Binding Configuration + +No configuration is necessary. + +## Thing Configuration + +The textual configuration (via \*.thing files) isn't useful because the resulting elements are read-only. But the configuration and properties of things are changed at runtime and channels are dynamically added and removed. + +### Vera Controller (Bridge) + +| Name | Type | Description | +|---------------------|---------------|----------------------------------------------------------------------------------------------------------| +| veraIpAddress | string | The IP address or hostname of the Vera controller. | +| veraPort | int | The port of the Vera controller | +| pollingInterval | int | Refresh all values (name, room, state) for all devices and scenes. | +| clearNames | boolean | Remove digits, slashes and double spaces from all names. Good for some voice recognition services. | +| defaulRoomName | string | Default name for room, if no room specified. | +| homekitIntegration | boolean | If enabled, homekit tags are created for all supported devices. Please read Homekit add-on instructions. | + +### Vera Device + +| Name | Type | Description | +|-----------------|---------------|--------------------------| +| deviceId | string | Id of the Vera device | + +### Vera Scene + +| Name | Type | Description | +|-----------------|---------------|--------------------------| +| sceneId | string | Id of the Vera scene | + +## Channels + +### Channels with detailed information for the devices + +The following channels are currently supported. + +| Channel Type ID | Item Type | Category | Vera category-subcategory | +| ------------------------- | ------------- | ------------- | ---------------------------- | +| switchMultilevel | Dimmer | Switch | 2-(1-3): Dimmable Light | +| switchColor | Color | ColorLight | 2-4: Dimmable Light - TODO | +| switchBinary | Switch | Switch | 3: Switch | +| sensorDoorWindow | Contact | Contact | 4-1: Security Sensor | +| sensorFlood | Switch | Water | 4-2: Security Sensor | +| sensorMotion | Switch | Motion | 4-3: Security Sensor | +| sensorSmoke | Switch | Smoke | 4-4: Security Sensor | +| sensorCo | Switch | Gas | 4-5: Security Sensor | +| sensorBinary | Switch | Switch | 4-6: Security Sensor | +| doorlock | Switch | Door | 7: Door Lock | +| switchBlinds | Rollershutter | Blinds | 8: Window Covering | +| sensorBinary | Switch | Switch | 12: Generic Sensor | +| switchBinary | Switch | Switch | 14: Scene Controller | +| sensorHumidity | Number | Humidity | 16: Humidity Sensor | +| sensorTemperature | Number | Temperature | 17: Temperature Sensor | +| sensorLuminosity | Number | Light | 18: Light Sensor | +| sensorEnergy | Number | Energy | 21: Power Meter | +| sensorUltraviolet | Number | Light | 28: UV Sensor | +| sensorMeterKWh | Number | Energy | no category | +| sensorMeterW | Number | Energy | no category | +| thermostatMode | Switch | Temperature | TODO | +| thermostatSetPoint | Number | Temperature | TODO | +| thermostatModeCC | Number | Temperature | TODO | +| sceneButton | Switch | Switch | | + +### Unsupported Vera device categories + +- 6: Camera +- 9: Remote Control +- 10: IR Transmitter +- 11: Generic IO +- 13: Serial Port +- 15: A/V +- 19: Z-Wave Interface +- 20: Insteon Interface +- 22: Alarm Panel +- 23: Alarm Partition +- 24: Siren +- 25: Weather +- 26: Philips Controller +- 27: Appliance + +The integration for most of these types isn't planned. + +Thermostats and colored lamps are also not supported, but will be implemented later. + +## Locations + +The locations are loaded during the discovery and based on the Vera devices rooms. + +## Developer stuff + +### Known issues + +No known issues at that moment. + +### Features + +- Discovery of the Vera controller and devices +- Control of the Vera devices in openHAB +- Receive updates of sensor data and actuator states in openHAB diff --git a/addons/binding/org.openhab.binding.vera/about.html b/addons/binding/org.openhab.binding.vera/about.html new file mode 100644 index 0000000000000..089907bd268e0 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/about.html @@ -0,0 +1,32 @@ + + + + + About + + +

About This Content

+ +

March 30, 2017

+

License

+ +

+ The openHAB community makes available all content in this plug-in ("Content"). Unless otherwise + indicated below, the Content is provided to you under the terms and conditions of the + Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available + at http://www.eclipse.org/legal/epl-v10.html. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the openHAB community, the Content is + being redistributed by another party ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the Redistributor's license that was + provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise + indicated below, the terms and conditions of the EPL still apply to any source code in the Content + and such source code may be obtained at openhab.org. +

+ + + diff --git a/addons/binding/org.openhab.binding.vera/build.properties b/addons/binding/org.openhab.binding.vera/build.properties new file mode 100644 index 0000000000000..0a87c9aa00cea --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/build.properties @@ -0,0 +1,7 @@ +source..=src/main/java/ +output..=target/classes +bin.includes = META-INF/,\ + .,\ + OSGI-INF/,\ + ESH-INF/,\ + about.html diff --git a/addons/binding/org.openhab.binding.vera/pom.xml b/addons/binding/org.openhab.binding.vera/pom.xml new file mode 100644 index 0000000000000..d18438012d3ab --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/pom.xml @@ -0,0 +1,19 @@ + + + + 4.0.0 + + + org.openhab.binding + pom + 2.1.0-SNAPSHOT + + + org.openhab.binding.vera + 2.1.0-SNAPSHOT + + Vera Binding + eclipse-plugin + + diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/VeraBindingConstants.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/VeraBindingConstants.java new file mode 100644 index 0000000000000..dfb50c6877420 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/VeraBindingConstants.java @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera; + +import java.util.Set; + +import org.eclipse.smarthome.core.thing.ThingTypeUID; + +import com.google.common.collect.ImmutableSet; + +/** + * The {@link VeraBinding} class defines common constants, which are + * used across the whole binding. + * + * @author Dmitriy Ponomarev + */ +public class VeraBindingConstants { + + public static final String BINDING_ID = "vera"; + + // List of all Thing Type UIDs + public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "veraController"); + public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "veraDevice"); + public static final ThingTypeUID THING_TYPE_SCENE = new ThingTypeUID(BINDING_ID, "veraScene"); + + public static final Set SUPPORTED_DEVICE_THING_TYPES_UIDS = ImmutableSet.of(THING_TYPE_BRIDGE, + THING_TYPE_DEVICE, THING_TYPE_SCENE); + + // 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 SWITCH_BINARY_CHANNEL = "switchBinary"; + public static final String SWITCH_MULTILEVEL_CHANNEL = "switchMultilevel"; + public static final String SWITCH_COLOR_CHANNEL = "switchColor"; + + // 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_ULTRAVIOLET_CHANNEL = "sensorUltraviolet"; + 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_DOOR_WINDOW_CHANNEL = "sensorDoorWindow"; + public static final String SENSOR_MOTION_CHANNEL = "sensorMotion"; + + // switch multilevel + public static final String SWITCH_ROLLERSHUTTER_CHANNEL = "switchBlinds"; + + // special channels + public static final String ACTIONS_CHANNEL = "actions"; + public static final String ACTIONS_CHANNEL_OPTION_REFRESH = "REFRESH"; + + /* Bridge config properties */ + public static final String BRIDGE_CONFIG_VERA_SERVER_IP_ADDRESS = "veraIpAddress"; + public static final String BRIDGE_CONFIG_VERA_SERVER_PORT = "veraControllerPort"; + public static final String BRIDGE_CONFIG_POLLING_INTERVAL = "pollingInterval"; + public static final String BRIDGE_CONFIG_CLEAR_NAMES = "clearNames"; + public static final String BRIDGE_CONFIG_DEFAULT_ROOM_NAME = "defaultRoomName"; + public static final String BRIDGE_CONFIG_HOMEKIT_INTEGRATION = "homekitIntegration"; + + public static final String DEVICE_CONFIG_ID = "deviceId"; + public static final String DEVICE_PROP_CATEGORY = "category"; + public static final String DEVICE_PROP_SUBCATEGORY = "subcategory"; + + public static final String SCENE_CONFIG_ID = "sceneId"; +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraBridgeConfiguration.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraBridgeConfiguration.java new file mode 100644 index 0000000000000..fd652443d4dd8 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraBridgeConfiguration.java @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.config; + +import static org.openhab.binding.vera.VeraBindingConstants.*; + +import org.apache.commons.lang.builder.ToStringBuilder; + +/** + * The {@link VeraBridgeConfiguration} class defines the model for a bridge configuration. + * + * @author Dmitriy Ponomarev + */ +public class VeraBridgeConfiguration { + private String veraIpAddress; + private Integer veraPort; + private Integer pollingInterval; + private Boolean clearNames; + private String defaulRoomName; + private Boolean homekitIntegration; + + public String getVeraIpAddress() { + return veraIpAddress; + } + + public void setVeraIpAddress(String ipAddress) { + this.veraIpAddress = ipAddress; + } + + public Integer getVeraPort() { + return veraPort; + } + + public void setVeraPort(Integer port) { + this.veraPort = port; + } + + public Integer getPollingInterval() { + return pollingInterval; + } + + public void setPollingInterval(Integer pollingInterval) { + this.pollingInterval = pollingInterval; + } + + public Boolean getClearNames() { + return clearNames; + } + + public void setClearNames(Boolean clearNames) { + this.clearNames = clearNames; + } + + public String getDefaulRoomName() { + return defaulRoomName; + } + + public void setDefaulRoomName(String defaulRoomName) { + this.defaulRoomName = defaulRoomName; + } + + public Boolean getHomekitIntegration() { + return homekitIntegration; + } + + public void setHomekitIntegration(Boolean homekitIntegration) { + this.homekitIntegration = homekitIntegration; + } + + @Override + public String toString() { + return new ToStringBuilder(this).append(BRIDGE_CONFIG_VERA_SERVER_IP_ADDRESS, this.getVeraIpAddress()) + .append(BRIDGE_CONFIG_VERA_SERVER_PORT, this.getVeraPort()) + .append(BRIDGE_CONFIG_POLLING_INTERVAL, this.getPollingInterval()) + .append(BRIDGE_CONFIG_CLEAR_NAMES, this.getClearNames()) + .append(BRIDGE_CONFIG_DEFAULT_ROOM_NAME, this.getDefaulRoomName()) + .append(BRIDGE_CONFIG_HOMEKIT_INTEGRATION, this.getHomekitIntegration()).toString(); + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraDeviceConfiguration.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraDeviceConfiguration.java new file mode 100644 index 0000000000000..f6524081d8706 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraDeviceConfiguration.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.config; + +import static org.openhab.binding.vera.VeraBindingConstants.DEVICE_CONFIG_ID; + +import org.apache.commons.lang.builder.ToStringBuilder; + +/** + * The {@link VeraDeviceConfiguration} class defines the model for a device configuration. + * + * @author Dmitriy Ponomarev + */ +public class VeraDeviceConfiguration { + 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_ID, this.getDeviceId()).toString(); + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraSceneConfiguration.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraSceneConfiguration.java new file mode 100644 index 0000000000000..d382bf904d4e2 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/config/VeraSceneConfiguration.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.config; + +import static org.openhab.binding.vera.VeraBindingConstants.SCENE_CONFIG_ID; + +import org.apache.commons.lang.builder.ToStringBuilder; + +/** + * The {@link VeraSceneConfiguration} class defines the model for a scene configuration. + * + * @author Dmitriy Ponomarev + */ +public class VeraSceneConfiguration { + private String sceneId; + + public String getSceneId() { + return sceneId; + } + + public void setSceneId(String sceneId) { + this.sceneId = sceneId; + } + + @Override + public String toString() { + return new ToStringBuilder(this).append(SCENE_CONFIG_ID, this.getSceneId()).toString(); + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/CategoryType.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/CategoryType.java new file mode 100644 index 0000000000000..fd3bdbd7d99f7 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/CategoryType.java @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller; + +public enum CategoryType { + Controller(0, "Controller"), + Interface(1, "Interface"), + DimmableLight(2, "Dimmable Light"), + Switch(3, "Switch"), + SecuritySensor(4, "Security Sensor"), + HVAC(5, "HVAC"), + Camera(6, "Camera"), + DoorLock(7, "Door Lock"), + WindowCovering(8, "Window Covering"), + RemoteControl(9, "Remote Control"), + IRTransmitter(10, "IR Transmitter"), + GenericIO(11, "Generic I/O"), + GenericSensor(12, "Generic Sensor"), + SerialPort(13, "Serial Port"), + SceneController(14, "Scene Controller"), + AV(15, "A/V"), + HumiditySensor(16, "Humidity Sensor"), + TemperatureSensor(17, "Temperature Sensor"), + LightSensor(18, "Light Sensor"), + ZWaveInterface(19, "Z-Wave Interface"), + InsteonInterface(20, "Insteon Interface"), + PowerMeter(21, "Power Meter"), + AlarmPanel(22, "Alarm Panel"), + AlarmPartition(23, "Alarm Partition"), + Siren(24, "Siren"), + Weather(25, "Weather"), + PhilipsController(26, "Philips Controller"), + Appliance(27, "Appliance"), + UVSensor(28, "UV Sensor"), + Unknown(-1, "Unknown"); + + private int id; + private String name; + + private CategoryType(int id, String name) { + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "{" + id + ", " + name + "}"; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/Controller.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/Controller.java new file mode 100644 index 0000000000000..c50835617ab3a --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/Controller.java @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import org.openhab.binding.vera.config.VeraBridgeConfiguration; +import org.openhab.binding.vera.controller.json.Device; +import org.openhab.binding.vera.controller.json.Room; +import org.openhab.binding.vera.controller.json.Scene; +import org.openhab.binding.vera.controller.json.Sdata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.Gson; + +/** + * The {@link Controller} class used to connect to the Vera + * + * @author Dmitriy Ponomarev + */ +public class Controller { + private Logger logger = LoggerFactory.getLogger(getClass()); + + private final VeraBridgeConfiguration config; + private final String veraHost; + private final String veraPort; + private final Gson gson; + + private Sdata sdata; + + public Controller(VeraBridgeConfiguration config) { + this.config = config; + this.veraHost = config.getVeraIpAddress(); + this.veraPort = "" + config.getVeraPort(); + this.gson = new Gson(); + + updateSdata(); + } + + public Sdata getSdata() { + if (sdata == null) { + updateSdata(); + } + return sdata; + } + + private void denormalizeSdata(Sdata data) { + Map roomMap = new HashMap<>(); + for (Room r : data.getRooms()) { + roomMap.put(r.getId(), r); + } + for (Device d : data.getDevices()) { + if (config.getClearNames()) { + d.setName(replaceTrash(d.getName())); + } + if (d.getRoom() != null && roomMap.get(d.getRoom()) != null) { + d.setRoomName(roomMap.get(d.getRoom()).getName()); + } else { + d.setRoomName(config.getDefaulRoomName()); + } + try { + d.setCategoryType(CategoryType.values()[Integer.parseInt(d.getCategory())]); + } catch (IndexOutOfBoundsException e) { + logger.warn("Unknown category type: {}", d.getCategory()); + } + } + for (Scene s : data.getScenes()) { + if (config.getClearNames()) { + s.setName(replaceTrash(s.getName())); + } + if (s.getRoom() != null && roomMap.get(s.getRoom()) != null) { + s.setRoomName(roomMap.get(s.getRoom()).getName()); + } else { + s.setRoomName(config.getDefaulRoomName()); + } + } + } + + private String request(String request) throws IOException { + String result; + URL url = new URL(request); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Content-Type", "application/json;charset=utf-8"); + connection.connect(); + BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder buffer = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) { + buffer.append(line).append("\n"); + } + br.close(); + result = buffer.toString(); + return result; + } + + private boolean sendCommand(String request) { + try { + URL url = new URL(request); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.getResponseMessage(); + } catch (IOException e) { + logger.warn("Error while get getJson: {} ", request, e); + return false; + } + return true; + } + + private String replaceTrash(String name) { + String sanitizedName = name.replaceAll("[0-9:/-]", ""); + sanitizedName = name.replaceAll("\\s+", " "); + return sanitizedName.trim(); + } + + private String getUrl() { + return "http://" + veraHost + ":" + veraPort + "/data_request"; + } + + private void setStatus(Device d, String status) { + d.setStatus(status); + String service = "urn:upnp-org:serviceId:SwitchPower1"; + if (CategoryType.DoorLock.equals(d.getCategoryType())) { + service = "urn:micasaverde-com:serviceId:DoorLock1"; + } + sendCommand(getUrl() + "?id=action&DeviceNum=" + d.getId() + "&serviceId=" + service + + "&action=SetTarget&newTargetValue=" + status); + } + + public void turnDeviceOn(Device d) { + setStatus(d, "1"); + } + + public void turnDeviceOff(Device d) { + setStatus(d, "0"); + } + + public void setDimLevel(Device d, String level) { + d.setLevel(level); + sendCommand(getUrl() + "?id=action&DeviceNum=" + d.getId() + + "&serviceId=urn:upnp-org:serviceId:Dimming1&action=SetLoadLevelTarget&newLoadlevelTarget=" + level); + } + + public void runScene(String id) { + sendCommand(getUrl() + "?id=action&SceneNum=" + id + + "&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=RunScene"); + } + + public void updateSdata() { + try { + String result = request(getUrl() + "?id=sdata&output_format=json"); + Sdata data = gson.fromJson(result, Sdata.class); + denormalizeSdata(data); + sdata = data; + } catch (IOException e) { + logger.warn("Failed to update sdata: {} ", getUrl(), e); + } + } + + public boolean isConnected() { + return sdata != null; + } + + public Device getDevice(String deviceId) { + for (Device d : sdata.getDevices()) { + if (deviceId.equals(d.getId())) { + return d; + } + } + return null; + } + + public Scene getScene(String sceneId) { + for (Scene s : sdata.getScenes()) { + if (sceneId.equals(s.getId())) { + return s; + } + } + return null; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Category.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Category.java new file mode 100644 index 0000000000000..2cd4cea3b4a82 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Category.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller.json; + +import com.google.gson.annotations.SerializedName; + +/** + * @author Dmitriy Ponomarev + */ +public class Category { + @SerializedName("name") + private String name; + + @SerializedName("id") + private String id; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Device.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Device.java new file mode 100644 index 0000000000000..2e0bfab66490b --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Device.java @@ -0,0 +1,171 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller.json; + +import org.openhab.binding.vera.controller.CategoryType; + +import com.google.gson.annotations.SerializedName; + +/** + * @author Dmitriy Ponomarev + */ +public class Device { + private CategoryType categoryType; + private String roomName; + + @SerializedName("name") + private String name; + + @SerializedName("altid") + private String altid; + + @SerializedName("id") + private String id; + + @SerializedName("category") + private String category; + + @SerializedName("subcategory") + private String subcategory; + + @SerializedName("room") + private String room; + + @SerializedName("parent") + private String parent; + + @SerializedName("kwh") + private String kwh; + + @SerializedName("watts") + private String watts; + + @SerializedName("batterylevel") + private String batterylevel; + + @SerializedName("locked") + private String locked; + + @SerializedName("status") + private String status; + + @SerializedName("level") + private String level; + + @SerializedName("state") + private String state; + + @SerializedName("comment") + private String comment; + + @SerializedName("humidity") + private String humidity; + + @SerializedName("light") + private String light; + + @SerializedName("temperature") + private String temperature; + + @SerializedName("tripped") + private String tripped; + + public CategoryType getCategoryType() { + return categoryType; + } + + public void setCategoryType(CategoryType categoryType) { + this.categoryType = categoryType; + } + + public String getRoomName() { + return roomName; + } + + public void setRoomName(String roomName) { + this.roomName = roomName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public String getCategory() { + return category; + } + + public String getSubcategory() { + return subcategory; + } + + public String getRoom() { + return room; + } + + public String getKwh() { + return kwh; + } + + public String getWatts() { + return watts; + } + + public String getBatterylevel() { + return batterylevel; + } + + public String getLocked() { + return locked; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getLevel() { + return level; + } + + public void setLevel(String level) { + this.level = level; + } + + public String getHumidity() { + return humidity; + } + + public String getLight() { + return light; + } + + public String getTemperature() { + return temperature; + } + + public String getTripped() { + return tripped; + } + + @Override + public String toString() { + return "{" + id + ", " + name + "}"; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Room.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Room.java new file mode 100644 index 0000000000000..b197577bb53b2 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Room.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller.json; + +import com.google.gson.annotations.SerializedName; + +/** + * @author Dmitriy Ponomarev + */ +public class Room { + @SerializedName("name") + private String name; + + @SerializedName("id") + private String id; + + @SerializedName("section") + private String section; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Scene.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Scene.java new file mode 100644 index 0000000000000..0bb00106c9024 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Scene.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller.json; + +import com.google.gson.annotations.SerializedName; + +/** + * @author Dmitriy Ponomarev + */ +public class Scene { + private String roomName; + + @SerializedName("active") + private String active; + + @SerializedName("name") + private String name; + + @SerializedName("id") + private String id; + + @SerializedName("room") + private String room; + + public String getRoomName() { + return roomName; + } + + public void setRoomName(String roomName) { + this.roomName = roomName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getRoom() { + return room; + } + + public void setRoom(String room) { + this.room = room; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Sdata.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Sdata.java new file mode 100644 index 0000000000000..6380fc44815cd --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Sdata.java @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller.json; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +/** + * @author Dmitriy Ponomarev + */ +public class Sdata { + @SerializedName("full") + private String full; + + @SerializedName("version") + private String version; + + @SerializedName("model") + private String model; + + @SerializedName("zwave_heal") + private String zwave_heal; + + @SerializedName("temperature") + private String temperature; + + @SerializedName("serial_number") + private String serial_number; + + @SerializedName("fwd1") + private String fwd1; + + @SerializedName("fwd2") + private String fwd2; + + @SerializedName("ir") + private String ir; + + @SerializedName("irtx") + private String irtx; + + @SerializedName("loadtime") + private String loadtime; + + @SerializedName("dataversion") + private String dataversion; + + @SerializedName("state") + private String state; + + @SerializedName("comment") + private String comment; + + @SerializedName("sections") + private List
sections; + + @SerializedName("rooms") + private List rooms; + + @SerializedName("scenes") + private List scenes; + + @SerializedName("devices") + private List devices; + + @SerializedName("categories") + private List categories; + + public List getRooms() { + return rooms; + } + + public List getScenes() { + return scenes; + } + + public List getDevices() { + return devices; + } + + public List getCategories() { + return categories; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Section.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Section.java new file mode 100644 index 0000000000000..09febd6a82871 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/controller/json/Section.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.controller.json; + +import com.google.gson.annotations.SerializedName; + +/** + * @author Dmitriy Ponomarev + */ +public class Section { + @SerializedName("name") + private String name; + + @SerializedName("id") + private String id; +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraBridgeHandler.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraBridgeHandler.java new file mode 100644 index 0000000000000..000d904889e0b --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraBridgeHandler.java @@ -0,0 +1,166 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.handler; + +import static org.openhab.binding.vera.VeraBindingConstants.*; + +import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingStatusDetail; +import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.vera.config.VeraBridgeConfiguration; +import org.openhab.binding.vera.controller.Controller; +import org.openhab.binding.vera.controller.json.Sdata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link VeraBridgeHandler} manages the connection between Vera and binding. + * + * @author Dmitriy Ponomarev + */ +public class VeraBridgeHandler extends BaseBridgeHandler { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private BridgePolling bridgePolling; + private ScheduledFuture pollingJob; + + private VeraBridgeConfiguration mConfig; + private Controller controller; + + private class Initializer implements Runnable { + @Override + public void run() { + logger.debug("Authenticate to the Vera controller ..."); + + try { + if (controller.isConnected()) { + logger.debug("Vera controller successfully authenticated"); + updateStatus(ThingStatus.ONLINE); + + // 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"); + } + } else { + logger.warn("Can't connect to Vera controller"); + } + } catch (Exception e) { + logger.error("Error occurred when initialize bridge: {}", e); + if (getThing().getStatus() == ThingStatus.ONLINE) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, + "Error occurred when initialize bridge: " + e.getMessage()); + } + } + } + }; + + public VeraBridgeHandler(Bridge bridge) { + super(bridge); + bridgePolling = new BridgePolling(); + } + + @Override + public void initialize() { + logger.debug("Initializing Vera controller ..."); + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING, "Checking configuration..."); + mConfig = getConfigAs(VeraBridgeConfiguration.class); + if (mConfig != null) { + controller = new Controller(mConfig); + scheduler.execute(new Initializer()); + } + } + + @Override + public void dispose() { + logger.debug("Disposing Vera controller ..."); + if (pollingJob != null && !pollingJob.isCancelled()) { + pollingJob.cancel(true); + pollingJob = null; + } + super.dispose(); + } + + @Override + public void handleConfigurationUpdate(Map configurationParameters) { + logger.debug("Handle Vera configuration update ..."); + if (pollingJob != null) { + pollingJob.cancel(false); + } + initialize(); + refreshAllThings(); + super.handleConfigurationUpdate(configurationParameters); + } + + private class BridgePolling implements Runnable { + @Override + public void run() { + getController().updateSdata(); + if (getController().getSdata() != null) { + if (!getThing().getStatus().equals(ThingStatus.ONLINE)) { + updateStatus(ThingStatus.ONLINE); + logger.debug("Connection to bridge {} restored.", getThing().getLabel()); + } + refreshAllThings(); + } else if (getThing().getStatus() == ThingStatus.ONLINE) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, + "Error occurred when polling bridge."); + } + } + }; + + private void refreshAllThings() { + logger.debug("Handle bridge refresh command for all configured things ..."); + for (Thing thing : getThing().getThings()) { + ThingHandler handler = thing.getHandler(); + if (handler instanceof VeraDeviceHandler) { + logger.debug("Refreshing device: {}", thing.getLabel()); + ((VeraDeviceHandler) handler).refreshAllChannels(); + } else if (handler instanceof VeraSceneHandler) { + logger.debug("Refreshing scene: {}", thing.getLabel()); + ((VeraSceneHandler) handler).refreshAllChannels(); + } + } + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + 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)) { + refreshAllThings(); + } + } + } + + protected VeraBridgeConfiguration getVeraBridgeConfiguration() { + return mConfig; + } + + public Controller getController() { + return controller; + } + + public Sdata getData() { + return controller.getSdata(); + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraDeviceHandler.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraDeviceHandler.java new file mode 100644 index 0000000000000..3fb99669fe2e2 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraDeviceHandler.java @@ -0,0 +1,468 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.handler; + +import static org.openhab.binding.vera.VeraBindingConstants.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.library.types.OpenClosedType; +import org.eclipse.smarthome.core.library.types.PercentType; +import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.Channel; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingStatusDetail; +import org.eclipse.smarthome.core.thing.ThingStatusInfo; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.eclipse.smarthome.core.thing.binding.builder.ChannelBuilder; +import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder; +import org.eclipse.smarthome.core.thing.type.ChannelTypeUID; +import org.eclipse.smarthome.core.types.Command; +import org.eclipse.smarthome.core.types.RefreshType; +import org.openhab.binding.vera.config.VeraDeviceConfiguration; +import org.openhab.binding.vera.controller.json.Device; +import org.openhab.binding.vera.internal.converter.VeraDeviceStateConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link VeraDeviceHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Dmitriy Ponomarev + */ +public class VeraDeviceHandler extends BaseThingHandler { + private Logger logger = LoggerFactory.getLogger(getClass()); + + private VeraDeviceConfiguration mConfig; + + public VeraDeviceHandler(Thing thing) { + super(thing); + } + + private class Initializer implements Runnable { + @Override + public void run() { + try { + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler != null && veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + ThingStatusInfo statusInfo = veraBridgeHandler.getThing().getStatusInfo(); + logger.debug("Change device status to bridge status: {}", statusInfo); + + // Set thing status to bridge status + updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription()); + + logger.debug("Add channels"); + Device device = veraBridgeHandler.getController().getDevice(mConfig.getDeviceId()); + if (device != null) { + logger.debug("Found {} device", device.getName()); + updateLabelAndLocation(device.getName(), device.getRoomName()); + addDeviceAsChannel(device, + veraBridgeHandler.getVeraBridgeConfiguration().getHomekitIntegration()); + } + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, + "Controller is not online"); + } + } catch (Exception e) { + logger.error("Error occurred when adding device as channel: ", e); + if (getThing().getStatus() == ThingStatus.ONLINE) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, + "Error occurred when adding device as channel: " + e.getMessage()); + } + } + } + }; + + protected synchronized VeraBridgeHandler getVeraBridgeHandler() { + Bridge bridge = getBridge(); + if (bridge == null) { + return null; + } + ThingHandler handler = bridge.getHandler(); + if (handler instanceof VeraBridgeHandler) { + return (VeraBridgeHandler) handler; + } else { + return null; + } + } + + private VeraDeviceConfiguration loadAndCheckConfiguration() { + VeraDeviceConfiguration config = getConfigAs(VeraDeviceConfiguration.class); + if (config.getDeviceId() == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "Couldn't create device, deviceId is missing."); + return null; + } + return config; + } + + @Override + public void initialize() { + logger.debug("Initializing Vera device handler ..."); + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING, + "Checking configuration and bridge..."); + mConfig = loadAndCheckConfiguration(); + if (mConfig != null) { + logger.debug("Configuration complete: {}", mConfig); + scheduler.schedule(new Initializer(), 2, TimeUnit.SECONDS); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "DeviceId required!"); + } + } + + @Override + public void dispose() { + logger.debug("Dispose Vera device handler ..."); + if (mConfig != null && mConfig.getDeviceId() != null) { + mConfig.setDeviceId(null); + } + super.dispose(); + } + + @Override + public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { + // Only called if status ONLINE or OFFLINE + logger.debug("Vera 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 + scheduler.execute(new Initializer()); + } + } + + private void updateLabelAndLocation(String label, String location) { + if (!label.equals(thing.getLabel()) || !location.equals(thing.getLocation())) { + logger.debug("Set location to {}", location); + ThingBuilder thingBuilder = editThing(); + if (!label.equals(thing.getLabel())) { + thingBuilder.withLabel(thing.getLabel()); + } + if (!location.equals(thing.getLocation())) { + thingBuilder.withLocation(location); + } + updateThing(thingBuilder.build()); + } + } + + private class DevicePolling implements Runnable { + @Override + public void run() { + for (Channel channel : getThing().getChannels()) { + if (isLinked(channel.getUID().getId())) { + refreshChannel(channel); + } else { + logger.debug("Polling for device: {} not possible (channel {} not linked", thing.getLabel(), + channel.getLabel()); + } + } + } + }; + + protected void refreshAllChannels() { + scheduler.execute(new DevicePolling()); + } + + private void refreshChannel(Channel channel) { + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera bridge handler not found or not ONLINE."); + return; + } + + // Check device id associated with channel + String deviceId = channel.getProperties().get(DEVICE_CONFIG_ID); + if (deviceId == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, + "Not found deviceId for channel: " + channel.getChannelTypeUID()); + logger.debug("Vera device disconnected: {}", deviceId); + return; + } + + Device device = veraBridgeHandler.getController().getDevice(deviceId); + if (device == null) { + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Channel refresh for device: " + deviceId + + " with channel: " + channel.getChannelTypeUID() + " failed!"); + logger.debug("Vera device disconnected: {}", deviceId); + return; + } + + updateLabelAndLocation(device.getName(), device.getRoomName()); + updateState(channel.getUID(), VeraDeviceStateConverter.toState(device, channel, logger)); + ThingStatusInfo statusInfo = veraBridgeHandler.getThing().getStatusInfo(); + updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription()); + } + + @Override + public void channelLinked(ChannelUID channelUID) { + logger.debug("Vera device channel linked: {}", channelUID); + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera bridge handler not found or not ONLINE."); + return; + } + super.channelLinked(channelUID); + } + + @Override + public void channelUnlinked(ChannelUID channelUID) { + logger.debug("Vera device channel unlinked: {}", channelUID); + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera 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()); + + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera bridge handler not found or not ONLINE."); + return; + } + + final Channel channel = getThing().getChannel(channelUID.getId()); + final String deviceId = channel.getProperties().get("deviceId"); + + if (deviceId != null) { + Device device = veraBridgeHandler.getController().getDevice(deviceId); + if (device != null) { + if (command instanceof RefreshType) { + logger.debug("Handle command: RefreshType"); + refreshChannel(channel); + } else { + if (command instanceof PercentType) { + logger.debug("Handle command: PercentType"); + veraBridgeHandler.getController().setDimLevel(device, ((PercentType) command).toString()); + } + if (command instanceof DecimalType) { + logger.debug("Handle command: DecimalType"); + veraBridgeHandler.getController().setDimLevel(device, ((DecimalType) command).toString()); + } + if (command instanceof OnOffType) { + logger.debug("Handle command: OnOffType"); + if (command.equals(OnOffType.ON)) { + veraBridgeHandler.getController().turnDeviceOn(device); + } else if (command.equals(OnOffType.OFF)) { + veraBridgeHandler.getController().turnDeviceOff(device); + } + } else if (command instanceof OpenClosedType) { + logger.debug("Handle command: OpenClosedType"); + if (command.equals(OpenClosedType.CLOSED)) { + veraBridgeHandler.getController().turnDeviceOn(device); + } else if (command.equals(OpenClosedType.OPEN)) { + veraBridgeHandler.getController().turnDeviceOff(device); + } + } else { + logger.warn("Unknown command type: {}, {}, {}, {}", command, deviceId, device.getCategory(), + device.getCategoryType()); + } + } + } else { + logger.warn("Device {} not loaded", deviceId); + } + } + } + + protected synchronized void addDeviceAsChannel(Device device, boolean homekitIntegration) { + if (device != null) { + logger.debug("Add device as channel: {}", device.getName()); + + HashMap properties = new HashMap<>(); + properties.put("deviceId", device.getId()); + + String id = null; + String acceptedItemType = ""; + String tag = null; + + int subcategory = Integer.parseInt(device.getSubcategory()); + switch (device.getCategoryType()) { + case Controller: + case Interface: + break; + case DimmableLight: + switch (subcategory) { + case 1: + case 2: + case 3: + id = SWITCH_MULTILEVEL_CHANNEL; + acceptedItemType = "Dimmer"; + tag = "Lighting"; + break; + case 4: + id = SWITCH_COLOR_CHANNEL; + acceptedItemType = "Color"; + tag = "Lighting"; + break; + } + break; + case Switch: + id = SWITCH_BINARY_CHANNEL; + acceptedItemType = "Switch"; + tag = "Switchable"; + break; + case SecuritySensor: + switch (subcategory) { + case 1: + id = SENSOR_DOOR_WINDOW_CHANNEL; + acceptedItemType = "Contact"; + break; + case 2: + id = SENSOR_FLOOD_CHANNEL; + acceptedItemType = "Switch"; + case 3: + id = SENSOR_MOTION_CHANNEL; + acceptedItemType = "Switch"; + break; + case 4: + id = SENSOR_SMOKE_CHANNEL; + acceptedItemType = "Switch"; + break; + case 5: + id = SENSOR_CO_CHANNEL; + acceptedItemType = "Switch"; + break; + case 6: + id = SENSOR_BINARY_CHANNEL; + acceptedItemType = "Switch"; + break; + } + break; + case HVAC: // TODO + logger.warn("TODO: {}, {}", device, device.getCategoryType()); + break; + case DoorLock: + id = DOORLOCK_CHANNEL; + acceptedItemType = "Switch"; + tag = "Switchable"; + break; + case WindowCovering: + id = SWITCH_ROLLERSHUTTER_CHANNEL; + acceptedItemType = "Rollershutter"; + break; + case GenericSensor: + id = SENSOR_BINARY_CHANNEL; + acceptedItemType = "Switch"; + break; + case SceneController: + id = SWITCH_BINARY_CHANNEL; + acceptedItemType = "Switch"; + break; + case HumiditySensor: + id = SENSOR_HUMIDITY_CHANNEL; + acceptedItemType = "Number"; + tag = "CurrentHumidity"; + break; + case TemperatureSensor: + id = SENSOR_TEMPERATURE_CHANNEL; + acceptedItemType = "Number"; + tag = "CurrentTemperature"; + break; + case LightSensor: + id = SENSOR_LUMINOSITY_CHANNEL; + acceptedItemType = "Number"; + break; + case PowerMeter: + id = SENSOR_ENERGY_CHANNEL; + acceptedItemType = "Number"; + break; + case UVSensor: + id = SENSOR_ULTRAVIOLET_CHANNEL; + acceptedItemType = "Number"; + break; + case Camera: + case RemoteControl: + case IRTransmitter: + case GenericIO: + case SerialPort: + case AV: + case ZWaveInterface: + case InsteonInterface: + case AlarmPanel: + case AlarmPartition: + case Siren: + case Weather: + case PhilipsController: + case Appliance: + logger.warn("TODO: {}, {}", device, device.getCategoryType()); + break; + case Unknown: + logger.warn("Unknown device type: {}, {}", device, device.getCategory()); + break; + } + + if (id != null) { + addChannel(id, acceptedItemType, device.getName(), properties, homekitIntegration ? tag : null); + + logger.debug("Channel for device added with channel id: {}, accepted item type: {} and title: {}", id, + acceptedItemType, device.getName()); + + if (device.getBatterylevel() != null && !device.getBatterylevel().isEmpty()) { + addChannel(BATTERY_CHANNEL, "Number", "Battery", properties, null); + } + + if (device.getKwh() != null) { + addChannel(SENSOR_METER_KWH_CHANNEL, "Number", "Energy ALL", properties, null); + } + + if (device.getWatts() != null) { + addChannel(SENSOR_METER_W_CHANNEL, "Number", "Energy Current", properties, null); + } + } else { + // Thing status will not be updated because thing could have more than one channel + logger.warn("No channel for device added: {}", device); + } + } + } + + private synchronized void addChannel(String id, String acceptedItemType, String label, + HashMap properties, String tag) { + String channelId = id + "-" + properties.get("deviceId"); + boolean channelExists = false; + // Check if a channel for this device exist. + List channels = getThing().getChannels(); + for (Channel channel : channels) { + if (channelId.equals(channel.getUID().getId())) { + channelExists = true; + } + } + if (!channelExists) { + ThingBuilder thingBuilder = editThing(); + ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, id); + ChannelBuilder channelBuilder = ChannelBuilder.create(new ChannelUID(getThing().getUID(), channelId), + acceptedItemType); + channelBuilder.withType(channelTypeUID); + channelBuilder.withLabel(label); + channelBuilder.withProperties(properties); + if (tag != null) { + Set tags = new HashSet(); + tags.add(tag); + channelBuilder.withDefaultTags(tags); + } + thingBuilder.withChannel(channelBuilder.build()); + thingBuilder.withLabel(thing.getLabel()); + updateThing(thingBuilder.build()); + } + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraSceneHandler.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraSceneHandler.java new file mode 100644 index 0000000000000..2a14aeab8a2d7 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/handler/VeraSceneHandler.java @@ -0,0 +1,294 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.handler; + +import static org.openhab.binding.vera.VeraBindingConstants.*; + +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.Channel; +import org.eclipse.smarthome.core.thing.ChannelUID; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingStatusDetail; +import org.eclipse.smarthome.core.thing.ThingStatusInfo; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandler; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.eclipse.smarthome.core.thing.binding.builder.ChannelBuilder; +import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder; +import org.eclipse.smarthome.core.thing.type.ChannelTypeUID; +import org.eclipse.smarthome.core.types.Command; +import org.eclipse.smarthome.core.types.RefreshType; +import org.openhab.binding.vera.config.VeraSceneConfiguration; +import org.openhab.binding.vera.controller.json.Scene; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link VeraSceneHandler} is responsible for handling commands, which are + * sent to one of the channels. + * + * @author Dmitriy Ponomarev + */ +public class VeraSceneHandler extends BaseThingHandler { + private Logger logger = LoggerFactory.getLogger(getClass()); + + private VeraSceneConfiguration mConfig; + + public VeraSceneHandler(Thing thing) { + super(thing); + } + + private class Initializer implements Runnable { + @Override + public void run() { + try { + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler != null && veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + ThingStatusInfo statusInfo = veraBridgeHandler.getThing().getStatusInfo(); + logger.debug("Change scene status to bridge status: {}", statusInfo); + + // Set thing status to bridge status + updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription()); + + logger.debug("Add channels"); + Scene scene = veraBridgeHandler.getController().getScene(mConfig.getSceneId()); + if (scene != null) { + logger.debug("Found {} scene", scene.getName()); + updateLabelAndLocation(scene.getName(), scene.getRoomName()); + addSceneAsChannel(scene); + } + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, + "Controller is not online"); + } + } catch (Exception e) { + logger.error("Error occurred when adding scene as channel: {}", e); + if (getThing().getStatus() == ThingStatus.ONLINE) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, + "Error occurred when adding scene as channel: " + e.getMessage()); + } + } + } + }; + + protected synchronized VeraBridgeHandler getVeraBridgeHandler() { + Bridge bridge = getBridge(); + if (bridge == null) { + return null; + } + ThingHandler handler = bridge.getHandler(); + if (handler instanceof VeraBridgeHandler) { + return (VeraBridgeHandler) handler; + } else { + return null; + } + } + + private VeraSceneConfiguration loadAndCheckConfiguration() { + VeraSceneConfiguration config = getConfigAs(VeraSceneConfiguration.class); + if (config.getSceneId() == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "Couldn't create scene, sceneId is missing."); + return null; + } + return config; + } + + @Override + public void initialize() { + logger.debug("Initializing Vera scene handler ..."); + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING, + "Checking configuration and bridge..."); + mConfig = loadAndCheckConfiguration(); + if (mConfig != null) { + logger.debug("Configuration complete: {}", mConfig); + scheduler.schedule(new Initializer(), 2, TimeUnit.SECONDS); + } else { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "SceneId required!"); + } + } + + @Override + public void dispose() { + logger.debug("Dispose Vera scene handler ..."); + if (mConfig.getSceneId() != null) { + mConfig.setSceneId(null); + } + super.dispose(); + } + + @Override + public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) { + // Only called if status ONLINE or OFFLINE + logger.debug("Vera 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 scene thing will be ONLINE + scheduler.execute(new Initializer()); + } + } + + private void updateLabelAndLocation(String label, String location) { + if (!label.equals(thing.getLabel()) || !location.equals(thing.getLocation())) { + logger.debug("Set location to {}", location); + ThingBuilder thingBuilder = editThing(); + if (!label.equals(thing.getLabel())) { + thingBuilder.withLabel(thing.getLabel()); + } + if (!location.equals(thing.getLocation())) { + thingBuilder.withLocation(location); + } + updateThing(thingBuilder.build()); + } + } + + private class ScenePolling implements Runnable { + @Override + public void run() { + for (Channel channel : getThing().getChannels()) { + if (isLinked(channel.getUID().getId())) { + refreshChannel(channel); + } else { + logger.debug("Polling for scene: {} not possible (channel {} not linked", thing.getLabel(), + channel.getLabel()); + } + } + } + }; + + protected void refreshAllChannels() { + scheduler.execute(new ScenePolling()); + } + + private void refreshChannel(Channel channel) { + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera bridge handler not found or not ONLINE."); + return; + } + + // Check scene id associated with channel + String sceneId = channel.getProperties().get(SCENE_CONFIG_ID); + if (sceneId == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, + "Not found sceneId for channel: " + channel.getChannelTypeUID()); + logger.debug("Vera scene disconnected: {}", thing.getLabel()); + return; + } + + Scene scene = veraBridgeHandler.getController().getScene(sceneId); + if (scene == null) { + updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "Channel refresh for sceneId: " + sceneId + + " with channel: " + channel.getChannelTypeUID() + " failed!"); + logger.debug("Vera scene disconnected: {}", sceneId); + return; + } + + updateLabelAndLocation(scene.getName(), scene.getRoomName()); + ThingStatusInfo statusInfo = veraBridgeHandler.getThing().getStatusInfo(); + updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription()); + } + + @Override + public void channelLinked(ChannelUID channelUID) { + logger.debug("Vera scene channel linked: {}", channelUID); + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera bridge handler not found or not ONLINE."); + return; + } + super.channelLinked(channelUID); + } + + @Override + public void channelUnlinked(ChannelUID channelUID) { + logger.debug("Vera scene channel unlinked: {}", channelUID); + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera 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()); + + VeraBridgeHandler veraBridgeHandler = getVeraBridgeHandler(); + if (veraBridgeHandler == null || !veraBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera bridge handler not found or not ONLINE."); + return; + } + + final Channel channel = getThing().getChannel(channelUID.getId()); + final String sceneId = channel.getProperties().get(SCENE_CONFIG_ID); + if (sceneId != null) { + if (command instanceof RefreshType) { + logger.debug("Handle command: RefreshType"); + refreshChannel(channel); + } else { + if (command instanceof OnOffType) { + if (command == OnOffType.ON) { + logger.debug("Handle command: OnOffType"); + veraBridgeHandler.getController().runScene(sceneId); + updateState(channelUID, OnOffType.OFF); + } + } else { + logger.warn("Unknown command type: {}, {}, {}, {}", command, sceneId); + } + } + } else { + logger.warn("Not found sceneId {}", sceneId); + } + } + + protected synchronized void addSceneAsChannel(Scene scene) { + if (scene != null) { + logger.debug("Add scene as channel: {}", scene.getName()); + + HashMap properties = new HashMap<>(); + properties.put(SCENE_CONFIG_ID, scene.getId()); + + addChannel("sceneButton", "Switch", "Run scene", properties); + } + } + + private synchronized void addChannel(String id, String acceptedItemType, String label, + HashMap properties) { + String channelId = id + "-" + properties.get(SCENE_CONFIG_ID); + boolean channelExists = false; + // Check if a channel for this scene exist. + List channels = getThing().getChannels(); + for (Channel channel : channels) { + if (channelId.equals(channel.getUID().getId())) { + channelExists = true; + } + } + if (!channelExists) { + ThingBuilder thingBuilder = editThing(); + ChannelTypeUID channelTypeUID = new ChannelTypeUID(BINDING_ID, id); + ChannelBuilder channelBuilder = ChannelBuilder.create(new ChannelUID(getThing().getUID(), channelId), + acceptedItemType); + channelBuilder.withType(channelTypeUID); + channelBuilder.withLabel(label); + channelBuilder.withProperties(properties); + thingBuilder.withChannel(channelBuilder.build()); + thingBuilder.withLabel(thing.getLabel()); + updateThing(thingBuilder.build()); + } + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/VeraHandlerFactory.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/VeraHandlerFactory.java new file mode 100644 index 0000000000000..3308112ef2549 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/VeraHandlerFactory.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.internal; + +import static org.openhab.binding.vera.VeraBindingConstants.*; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.smarthome.config.discovery.DiscoveryService; +import org.eclipse.smarthome.core.thing.Bridge; +import org.eclipse.smarthome.core.thing.Thing; +import org.eclipse.smarthome.core.thing.ThingTypeUID; +import org.eclipse.smarthome.core.thing.ThingUID; +import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory; +import org.eclipse.smarthome.core.thing.binding.ThingHandler; +import org.openhab.binding.vera.handler.VeraBridgeHandler; +import org.openhab.binding.vera.handler.VeraDeviceHandler; +import org.openhab.binding.vera.handler.VeraSceneHandler; +import org.openhab.binding.vera.internal.discovery.VeraDeviceDiscoveryService; +import org.osgi.framework.ServiceRegistration; + +/** + * The {@link VeraHandlerFactory} is responsible for creating things and thing + * handlers. + * + * @author Dmitriy Ponomarev + */ +public class VeraHandlerFactory extends BaseThingHandlerFactory { + private Map> discoveryServiceRegs = new HashMap<>(); + + @Override + public boolean supportsThingType(ThingTypeUID thingTypeUID) { + return SUPPORTED_DEVICE_THING_TYPES_UIDS.contains(thingTypeUID); + } + + @Override + protected ThingHandler createHandler(Thing thing) { + if (THING_TYPE_BRIDGE.equals(thing.getThingTypeUID())) { + VeraBridgeHandler handler = new VeraBridgeHandler((Bridge) thing); + registerDeviceDiscoveryService(handler); + return handler; + } else if (THING_TYPE_DEVICE.equals(thing.getThingTypeUID())) { + return new VeraDeviceHandler(thing); + } else if (THING_TYPE_SCENE.equals(thing.getThingTypeUID())) { + return new VeraSceneHandler(thing); + } else { + return null; + } + } + + @Override + protected synchronized void removeHandler(ThingHandler thingHandler) { + if (thingHandler instanceof VeraBridgeHandler) { + ServiceRegistration serviceReg = this.discoveryServiceRegs.get(thingHandler.getThing().getUID()); + if (serviceReg != null) { + serviceReg.unregister(); + discoveryServiceRegs.remove(thingHandler.getThing().getUID()); + } + } + } + + private void registerDeviceDiscoveryService(VeraBridgeHandler handler) { + VeraDeviceDiscoveryService discoveryService = new VeraDeviceDiscoveryService(handler); + this.discoveryServiceRegs.put(handler.getThing().getUID(), bundleContext + .registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable())); + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/converter/VeraDeviceStateConverter.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/converter/VeraDeviceStateConverter.java new file mode 100644 index 0000000000000..ac5ead6d65938 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/converter/VeraDeviceStateConverter.java @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.internal.converter; + +import static org.openhab.binding.vera.VeraBindingConstants.*; + +import org.eclipse.smarthome.core.library.types.DecimalType; +import org.eclipse.smarthome.core.library.types.OnOffType; +import org.eclipse.smarthome.core.library.types.OpenClosedType; +import org.eclipse.smarthome.core.library.types.PercentType; +import org.eclipse.smarthome.core.thing.Channel; +import org.eclipse.smarthome.core.types.State; +import org.eclipse.smarthome.core.types.UnDefType; +import org.openhab.binding.vera.controller.json.Device; +import org.slf4j.Logger; + +/** + * The {@link VeraDeviceStateConverter} is responsible for converting Vera device level to openHAB states + * + * @author Dmitriy Ponomarev + */ +public class VeraDeviceStateConverter { + public static State toState(Device device, Channel channel, Logger logger) { + + String channelType = channel.getUID().getId().split("-")[0]; + if (BATTERY_CHANNEL.equals(channelType)) { + return getMultilevelState(device.getBatterylevel()); + } + if (SENSOR_METER_KWH_CHANNEL.equals(channelType)) { + return getMultilevelState(device.getKwh()); + } + if (SENSOR_METER_W_CHANNEL.equals(channelType)) { + return getMultilevelState(device.getWatts()); + } + + int subcategory = Integer.parseInt(device.getSubcategory()); + switch (device.getCategoryType()) { + case Controller: + case Interface: + break; + case DimmableLight: + switch (subcategory) { + case 1: + case 2: + case 3: + return getPercentState(device.getLevel()); + case 4: + return getPercentState(device.getLevel());// TODO getColorState(device.light); + } + break; + case Switch: + return getBinaryState(device.getStatus()); + case SecuritySensor: + switch (subcategory) { + case 1: + return getDoorlockState("1".equals(device.getTripped()) ? "0" : "1"); + default: + return getBinaryState(device.getTripped()); + } + case HVAC: // TODO + logger.warn("TODO: {}, {}", device, device.getCategoryType()); + break; + case DoorLock: + return getBinaryState(device.getLocked()); + case WindowCovering: + return getPercentState(device.getLevel()); + case GenericSensor: + return getMultilevelState(device.getLevel()); + case SceneController: + return getBinaryState(device.getStatus()); + case HumiditySensor: + return getMultilevelState(device.getHumidity()); + case TemperatureSensor: + return getMultilevelState(device.getTemperature()); + case LightSensor: + return getMultilevelState(device.getLight()); + case PowerMeter: + return getMultilevelState(device.getLevel()); + case UVSensor: + return getMultilevelState(device.getLevel()); + case Camera: + case AV: + case ZWaveInterface: + case InsteonInterface: + case RemoteControl: + case IRTransmitter: + case GenericIO: + case SerialPort: + case AlarmPanel: + case AlarmPartition: + case Siren: + case Weather: + case PhilipsController: + case Appliance: + logger.warn("TODO: {}, {}", device, device.getCategoryType()); + break; + case Unknown: + logger.warn("Unknown device type: {}, {}", device, device.getCategory()); + break; + } + return UnDefType.UNDEF; + } + + private static State getMultilevelState(String multilevelValue) { + if (multilevelValue != null) { + if (multilevelValue.isEmpty()) { + return new DecimalType("0"); + } + return new DecimalType(multilevelValue); + } + return UnDefType.UNDEF; + } + + private static State getPercentState(String multilevelValue) { + if (multilevelValue != null) { + if (multilevelValue.isEmpty()) { + return new PercentType("0"); + } + return new PercentType(multilevelValue); + } + return UnDefType.UNDEF; + } + + private static State getBinaryState(String status) { + if (status != null) { + if ("1".equals(status)) { + return OnOffType.ON; + } else if ("0".equals(status)) { + return OnOffType.OFF; + } + } + return UnDefType.UNDEF; + } + + private static State getDoorlockState(String status) { + if (status != null) { + if ("1".equals(status)) { + return OpenClosedType.CLOSED; + } else if ("0".equals(status)) { + return OpenClosedType.OPEN; + } + } + return UnDefType.UNDEF; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/discovery/VeraBridgeDiscoveryService.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/discovery/VeraBridgeDiscoveryService.java new file mode 100644 index 0000000000000..8664c1cc13a4f --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/discovery/VeraBridgeDiscoveryService.java @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.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.eclipse.smarthome.config.discovery.AbstractDiscoveryService; +import org.eclipse.smarthome.config.discovery.DiscoveryResult; +import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; +import org.eclipse.smarthome.config.discovery.DiscoveryServiceCallback; +import org.eclipse.smarthome.config.discovery.ExtendedDiscoveryService; +import org.eclipse.smarthome.core.thing.ThingUID; +import org.openhab.binding.vera.VeraBindingConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link VeraBridgeDiscoveryService} is responsible for device discovery. + * + * @author Dmitriy Ponomarev + */ +public class VeraBridgeDiscoveryService extends AbstractDiscoveryService implements ExtendedDiscoveryService { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private static final int SEARCH_TIME = 240; + + private DiscoveryServiceCallback callback; + + public VeraBridgeDiscoveryService() { + super(VeraBindingConstants.SUPPORTED_DEVICE_THING_TYPES_UIDS, SEARCH_TIME); + logger.debug("Initializing VeraBridgeDiscoveryService"); + } + + private void scan() { + logger.debug("Starting scan for Vera controller"); + + ValidateIPV4 validator = new ValidateIPV4(); + + try { + Enumeration 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 Vera Controller: {}", ipAddress); + + String subnet = ipAddress + "/" + prefix; + SubnetUtils utils = new SubnetUtils(subnet); + String[] addresses = utils.getInfo().getAllAddresses(); + + for (String addressInSubnet : addresses) { + scheduler.execute(new VeraControllerScan(addressInSubnet)); + } + } + } + } + } + } catch (SocketException e) { + logger.warn("Error occurred while searching Vera controller: ", e); + } + } + + 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 VeraControllerScan implements Runnable { + private String ipAddress; + + public VeraControllerScan(String ipAddress) { + this.ipAddress = ipAddress; + } + + @Override + public void run() { + if (!pingHost(ipAddress, 3480, 100)) { + return; + } + + try { + URL url = new URL("http://" + ipAddress + ":3480/data_request?id=sdata&output_format=json"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + if (connection.getResponseCode() == 200) { + ThingUID thingUID = new ThingUID(VeraBindingConstants.THING_TYPE_BRIDGE, + ipAddress.replaceAll("\\.", "_")); + + if (callback != null && callback.getExistingDiscoveryResult(thingUID) == null + && callback.getExistingThing(thingUID) == null) { + DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID) + .withProperty(VeraBindingConstants.BRIDGE_CONFIG_VERA_SERVER_IP_ADDRESS, ipAddress) + .withLabel("Vera controller " + ipAddress).build(); + thingDiscovered(discoveryResult); + } else { + logger.debug("Thing or inbox entry already exists for UID={}, IP={}", thingUID, ipAddress); + } + } + } catch (IOException 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(); + } + } + + @Override + public void setDiscoveryServiceCallback(DiscoveryServiceCallback discoveryServiceCallback) { + callback = discoveryServiceCallback; + } +} diff --git a/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/discovery/VeraDeviceDiscoveryService.java b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/discovery/VeraDeviceDiscoveryService.java new file mode 100644 index 0000000000000..e6313357588f2 --- /dev/null +++ b/addons/binding/org.openhab.binding.vera/src/main/java/org/openhab/binding/vera/internal/discovery/VeraDeviceDiscoveryService.java @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2010-2017 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.binding.vera.internal.discovery; + +import static org.openhab.binding.vera.VeraBindingConstants.*; + +import java.util.List; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.smarthome.config.discovery.AbstractDiscoveryService; +import org.eclipse.smarthome.config.discovery.DiscoveryResult; +import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; +import org.eclipse.smarthome.config.discovery.DiscoveryServiceCallback; +import org.eclipse.smarthome.config.discovery.ExtendedDiscoveryService; +import org.eclipse.smarthome.core.thing.ThingStatus; +import org.eclipse.smarthome.core.thing.ThingUID; +import org.openhab.binding.vera.controller.CategoryType; +import org.openhab.binding.vera.controller.json.Device; +import org.openhab.binding.vera.controller.json.Scene; +import org.openhab.binding.vera.handler.VeraBridgeHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link VeraDeviceDiscoveryService} is responsible for device discovery. + * + * @author Dmitriy Ponomarev + */ +public class VeraDeviceDiscoveryService extends AbstractDiscoveryService implements ExtendedDiscoveryService { + + 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 VeraBridgeHandler mBridgeHandler; + private VeraDeviceScan mVeraDeviceScanningRunnable; + private ScheduledFuture mVeraDeviceScanningJob; + + private DiscoveryServiceCallback callback; + + public VeraDeviceDiscoveryService(VeraBridgeHandler bridgeHandler) { + super(SUPPORTED_DEVICE_THING_TYPES_UIDS, SEARCH_TIME); + logger.debug("Initializing VeraDeviceDiscoveryService"); + mBridgeHandler = bridgeHandler; + mVeraDeviceScanningRunnable = new VeraDeviceScan(); + activate(null); + } + + private void scan() { + logger.debug("Starting scan on Vera Controller {}", mBridgeHandler.getThing().getUID()); + + if (mBridgeHandler == null || !mBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) { + logger.debug("Vera bridge handler not found or not ONLINE."); + return; + } + + final ThingUID bridgeUID = mBridgeHandler.getThing().getUID(); + + List deviceList = mBridgeHandler.getData().getDevices(); + for (Device device : deviceList) { + if (device.getCategoryType().equals(CategoryType.Controller) + || device.getCategoryType().equals(CategoryType.Interface)) { + continue; + } + ThingUID thingUID = new ThingUID(THING_TYPE_DEVICE, mBridgeHandler.getThing().getUID(), device.getId()); + if (callback != null && callback.getExistingDiscoveryResult(thingUID) == null + && callback.getExistingThing(thingUID) == null) { + DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(device.getName()) + .withBridge(bridgeUID).withProperty(DEVICE_CONFIG_ID, device.getId()) + .withProperty(DEVICE_PROP_CATEGORY, device.getCategory()) + .withProperty(DEVICE_PROP_SUBCATEGORY, device.getSubcategory()).build(); + thingDiscovered(discoveryResult); + logger.debug("Vera device found: {}, {}", device.getId(), device.getName()); + } + } + + List sceneList = mBridgeHandler.getData().getScenes(); + for (Scene scene : sceneList) { + ThingUID thingUID = new ThingUID(THING_TYPE_SCENE, mBridgeHandler.getThing().getUID(), scene.getId()); + if (callback != null && callback.getExistingDiscoveryResult(thingUID) == null + && callback.getExistingThing(thingUID) == null) { + DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withLabel(scene.getName()) + .withBridge(bridgeUID).withProperty(SCENE_CONFIG_ID, scene.getId()).build(); + thingDiscovered(discoveryResult); + logger.debug("Vera scene found: {}, {}", scene.getId(), scene.getName()); + } + } + } + + @Override + protected void startScan() { + scan(); + } + + @Override + protected synchronized void stopScan() { + super.stopScan(); + removeOlderResults(getTimestampOfLastScan()); + } + + @Override + protected void startBackgroundDiscovery() { + if (mVeraDeviceScanningJob == null || mVeraDeviceScanningJob.isCancelled()) { + logger.debug("Starting background scanning job"); + mVeraDeviceScanningJob = AbstractDiscoveryService.scheduler.scheduleWithFixedDelay( + mVeraDeviceScanningRunnable, INITIAL_DELAY, SCAN_INTERVAL, TimeUnit.SECONDS); + } else { + logger.debug("Scanning job is allready active"); + } + } + + @Override + protected void stopBackgroundDiscovery() { + if (mVeraDeviceScanningJob != null && !mVeraDeviceScanningJob.isCancelled()) { + mVeraDeviceScanningJob.cancel(false); + mVeraDeviceScanningJob = null; + } + } + + public class VeraDeviceScan implements Runnable { + @Override + public void run() { + scan(); + } + } + + @Override + public void setDiscoveryServiceCallback(DiscoveryServiceCallback discoveryServiceCallback) { + callback = discoveryServiceCallback; + } +} diff --git a/addons/binding/pom.xml b/addons/binding/pom.xml index 93a46b50cc1f5..a9b8125eff8b6 100644 --- a/addons/binding/pom.xml +++ b/addons/binding/pom.xml @@ -95,6 +95,7 @@ org.openhab.binding.tplinksmarthome org.openhab.binding.tplinksmarthome.test org.openhab.binding.urtsi + org.openhab.binding.vera org.openhab.binding.vitotronic org.openhab.binding.wifiled org.openhab.binding.windcentrale diff --git a/features/openhab-addons/src/main/feature/feature.xml b/features/openhab-addons/src/main/feature/feature.xml index 51e981caf0c43..a2a106f749641 100644 --- a/features/openhab-addons/src/main/feature/feature.xml +++ b/features/openhab-addons/src/main/feature/feature.xml @@ -400,6 +400,11 @@ mvn:org.openhab.binding/org.openhab.binding.toon/${project.version} + + openhab-runtime-base + mvn:org.openhab.binding/org.openhab.binding.vera/${project.version} + + openhab-runtime-base mvn:org.openhab.binding/org.openhab.binding.tplinksmarthome/${project.version}