Skip to content

Commit

Permalink
[hdpowerview] extensions, improvements, bug-fixes (openhab#8061)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Fiddian-Green <[email protected]>
  • Loading branch information
andrewfg authored and markus7017 committed Sep 18, 2020
1 parent 244221c commit 2b21016
Show file tree
Hide file tree
Showing 33 changed files with 1,947 additions and 366 deletions.
6 changes: 6 additions & 0 deletions bundles/org.openhab.binding.hdpowerview/.classpath
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,11 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
214 changes: 165 additions & 49 deletions bundles/org.openhab.binding.hdpowerview/README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,185 @@
# Hunter Douglas PowerView Binding
# Hunter Douglas (Luxaflex) PowerView Binding

This is an openHAB binding for the [Hunter Douglas PowerView Motorized Shades](https://www.hunterdouglas.com/operating-systems/motorized/powerview-motorization/overview) via the PowerView Hub.
This is an openHAB binding for [Hunter Douglas PowerView](https://www.hunterdouglas.com/operating-systems/motorized/powerview-motorization/overview) motorized shades via their PowerView hub.
In some countries the PowerView system is sold under the brand name [Luxaflex](https://www.luxaflex.com/)

PowerView shades have motorization control for their vertical position, as well as vane controls on the shade's slats.
Make sure your Shades are visible in the dedicated PowerView app before attempting discovery.
This binding also supports Scenes that are defined via the PowerView app.
This helps to work around a limitation of the Hub - commands are executed serially with a several second delay between executions.
By using a Scene to control multiple shades at once, the shades will all begin moving at the same time.
![PowerView](doc/hdpowerview.png)

PowerView shades have motorization control for their vertical position, and some also have vane controls to change the angle of their slats.

This binding also supports scenes that are defined in the PowerView app.
This helps to work around a limitation of the hub; commands are executed serially with a several second delay between executions.
By using a scene to control multiple shades at once, the shades will all begin moving at the same time.

## Supported Things

| Thing | Thing Type | Description |
|-----------------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| PowerView Hub | Bridge | The PowerView Hub provides the interface between your network and the shade's radio network. It also contains channels used to interact with scenes. |
| PowerView Shade | Thing | A single motorized shade |
| Thing | Thing Type | Description |
|-----------------|------------|--------------------|
| PowerView Hub | Bridge | The PowerView hub provides the interface between your network and the shade's radio network. It also contains channels used to interact with scenes. |
| PowerView Shade | Thing | A motorized shade. |

## Discovery

The PowerView Hub is discovered via a NetBIOS query.
This is the same method used by the dedicated PowerView app.
After the Hub is added, Shades and Scenes will be discovered by querying the Hub.
Make sure your shades are visible in the PowerView app before attempting discovery.

The binding can automatically discover the PowerView hub.
The discovery process can be started by pressing the refresh button in the Main Configuration UI Inbox.
However you can also manually create a (bridge) thing for the hub, and enter the required configuration parameters (see Thing Configuration below).
If the configuration parameters are all valid, the binding will then automatically attempt to connect to the hub.
If the connection succeeds, the hub will indicate its status as Online, otherwise it will show an error status.

Once the hub thing has been created and successfully connected, the binding will automatically discover all shades and scenes that are in it.

- For each shade discovered: the binding will create a new dedicated thing with its own channels.
- For each scene discovered: the binding will create a new channel dynamically within the hub thing.

If in the future, you add additional shades or scenes to your system, the binding will discover them too.

## Thing Configuration

PowerView things should be configured via discovery - it would be difficult to configure manually as the IDs of the shades and scenes are not exposed via the dedicated app.
### Thing Configuration for PowerView Hub

| Configuration Parameter | Description |
|-------------------------|---------------|
| host | The host name or IP address of the hub on your network. |
| refresh | The number of milli-seconds between fetches of the PowerView hub's shade state (default 60'000 one minute). |
| hardRefresh | The number of minutes between hard refreshes of the PowerView hub's shade state (default 180 three hours). See [Refreshing the PowerView Hub Cache](#Refreshing-the-PowerView-Hub-Cache). |

### Thing Configuration for PowerView Shades

PowerView shades should preferably be configured via the automatic discovery process.
It is quite difficult to configure manually as the `id` of the shade is not exposed in the PowerView app.
However, the configuration parameters are described below:

<table>
<tr>
<td><b>Thing</b></td>
<td><b>Configuration Parameters</b></td>
</tr>
<tr>
<td>PowerView Hub</td>
<td>
<table>
<tr><td><b>host</b> - the hostname or IP address of the Hub on your network.</td></tr>
<tr><td><b>refresh</b> - the number of milliseconds between fetches of the PowerView Hub's shade state. Defaults to 60,000 (one minute).</td></tr>
</table>
</td>
</tr>
<tr>
<td>PowerView Shade</td>
<td>
<table>
<tr><td><b>id</b> - the ID of the PowerView Shade on the Hub.</td></tr>
</table>
</td>
</tr>
</table>
| Configuration Parameter | Description |
|-------------------------|---------------------------------------------------------------|
| id | The ID of the PowerView shade in the app. Must be an integer. |

## Channels

### PowerView Shade
### Channels for PowerView Hub

Scene channels will be added dynamically to the binding as they are discovered in the hub.
Each scene channel will have an entry in the hub as shown below, whereby different scenes have different `id` values:

| Channel | Item Type | Description |
|----------|-----------| ------------|
| id | Switch | Turning this to ON will activate the scene. Scenes are stateless in the PowerView hub; they have no on/off state. Note: include `{autoupdate="false"}` in the item configuration to avoid having to reset it to off after use. |

### Channels for PowerView Shade

A shade always implements a roller shutter channel `position` which controls the vertical position of the shade's (primary) rail.
If the shade has slats or rotatable vanes, there is also a dimmer channel `vane` which controls the slat / vane position.
If it is a dual action (top-down plus bottom-up) shade, there is also a roller shutter channel `secondary` which controls the vertical position of the secondary rail.
All of these channels appear in the binding, but only those which have a physical implementation in the shade, will have any physical effect.

| Channel | Item Type | Description |
|------------|---------------|------------|
| position | Rollershutter | The vertical position of the shade's rail -- see [next chapter](#Roller-Shutter-Up/Down-Position-vs.-Open/Close-State). Up/Down commands will move the rail completely up or completely down. Percentage commands will move the rail to an intermediate position. Stop commands will halt any current movement of the rail. |
| secondary | Rollershutter | The vertical position of the secondary rail (if any). Its function is basically identical to the `position` channel above -- but see [next chapter](#Roller-Shutter-Up/Down-Position-vs.-Open/Close-State). |
| vane | Dimmer | The degree of opening of the slats or vanes. Setting this to a non-zero value will first move the shade `position` fully down, since the slats or vanes can only have a defined state if the shade is in its down position -- see [Interdependency between Channel positions](#Interdependency-between-Channel-positions). |
| batteryLow | Switch | Indicates ON when the battery level of the shade is low, as determined by the hub's internal rules. |

### Roller Shutter Up/Down Position vs. Open/Close State

The `position` and `secondary` channels are Rollershutter types.
For vertical shades, the binding maps the vertical position of the "rail" to the Rollershutter ▲ / ▼ commands, and its respective percent value.
And for horizontal shades, it maps the horizontal position of the "truck" to the Rollershutter ▲ / ▼ commands, and its respective percent value.

Depending on whether the shade is a top-down, bottom-up, left-right, right-left, or dual action shade, the `OPEN` and `CLOSED` position of the shades may differ from the ▲ / ▼ commands follows..

| Type of Shade | Channel | Rollershutter Command | Motion direction | Shade State | Percent |
|--------------------------|-------------------|-----------------------|------------------|----------------|---------|
| Single action bottom-up | `position` || Up | `OPEN` | 0% |
| | || Down | `CLOSED` | 100% |
| Single action top-down | `position` || Up | ***`CLOSED`*** | 0% |
| | || Down | ***`OPEN`*** | 100% |
| Single action right-left | `position` || ***Left*** | `OPEN` | 0% |
| | || ***Right*** | `CLOSED` | 100% |
| Single action left-right | `position` || ***Right*** | `OPEN` | 0% |
| | || ***Left*** | `CLOSED` | 100% |
| Dual action (lower rail) | `position` || Up | `OPEN` | 0% |
| | || Down | `CLOSED` | 100% |
| Dual action (upper rail) | ***`secondary`*** || ***Down*** | `OPEN` | 0% |
| | || ***Up*** | `CLOSED` | 100% |

### Interdependency between Channel positions

On some types of shades with movable vanes, the vanes cannot be moved unless the shade is down.
So there is an interdependency between the value of `vane` and the value of `position` as follows..

| Case | State of `position` | State of `vane` |
|----------------------------|---------------------|-----------------|
| Shade up | 0% = `UP` | `UNDEFINED` |
| Shade 50% down | 50% | `UNDEFINED` |
| Shade 100% down, Vane 0% | 100% = `DOWN` | 0% |
| Shade 100% down, Vane 50% | 100% = `DOWN` | 50% |
| Shade 100% down, Vane 100% | 100% = `DOWN` | 100% |

On dual action shades, the top rail cannot move below the position of the bottom rail.
So the value of `secondary` may be constrained by the value of `position`.

## Refreshing the PowerView Hub Cache

The hub maintains a cache of the last known state of its shades, and this binding delivers those values.
Usually the shades will be moved by this binding, so since the hub is always involved in the moving process, it updates this cache accordingly.

However shades can also be moved manually without the hub’s knowledge.
A person can manually move a shade by pressing a button on the side of the shade or via a remote control.
In neither case will the hub be aware of the shade’s new position.

The hub periodically does a _**"hard refresh"**_ in order to overcome this issue.
The time interval between hard refreshes is set in the `hardRefresh` configuration parameter.
To disable periodic hard refreshes, set `hardRefresh` to zero.

Note: You can also force the hub to refresh itself by sending a `REFRESH` command in a rule to an item that is connected to a channel in the hub as follows:

```
rule "Hub Refresh (every 20 minutes)"
when
Time cron "0 1/20 0 ? * * *"
then
sendCommand(HUB_ITEM_NAME, "REFRESH") // refresh all shades in HUB
sendCommand(SHADE_ITEM_NAME, "REFRESH") // refresh single shade that ITEM is bound to
end
```

## Full Example

### `demo.things` File

```
Bridge hdpowerview:hub:g24 "Luxaflex Hub" @ "Living Room" [host="192.168.1.123"] {
Thing shade s50150 "Living Room Shade" @ "Living Room" [id="50150"]
}
```

### `demo.items` File

Shade items:

```
Rollershutter Living_Room_Shade_Position "Living Room Shade Position [%.0f %%]" {channel="hdpowerview:shade:g24:s50150:position"}
Rollershutter Living_Room_Shade_Secondary "Living Room Shade Secondary Position [%.0f %%]" {channel="hdpowerview:shade:g24:s50150:secondary"}
Dimmer Living_Room_Shade_Vane "Living Room Shade Vane [%.0f %%]" {channel="hdpowerview:shade:g24:s50150:vane"}
Switch Living_Room_Shade_Battery_Low_Alarm "Living Room Shade Battery Low Alarm [%s]" {channel="hdpowerview:shade:g24:s50150:lowBattery"}
```

| Channel | Item Type | Description |
|------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| position | Rollershutter | The vertical position of the shade. Up/Down commands will move the shade to its completely up or completely down position. Move/Stop commands are ignored. |
| vane | Dimmer | The amount the slats on the shade are open. Setting this value will completely close the shade first, as the slats can only be controlled in that position. |
| batteryLow | Switch | Indicates ON when the battery level of the shade is low, as determined by the Hub's internal rules |
Scene items:

### PowerView Scene
```
Switch Living_Room_Shades_Scene_Heart "Living Room Shades Scene Heart" <blinds> (g_Shades_Scene_Trigger) {channel="hdpowerview:hub:g24:22663", autoupdate="false"}
```

Scenes channels are added to the Hub as they are discovered.
### `demo.sitemap` File

| Channel | Item Type | Description |
|----------|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| activate | Switch | Turning this to ON will activate the scene. Scenes are stateless in the PowerView hub - they have no on/off state. Include { autoupdate="false" } on your item configuration to avoid needing to toggle off and on. |
```
Frame label="Living Room Shades" {
Switch item=Living_Room_Shades_Scene_Open
Slider item=Living_Room_Shade_1_Position 
}
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion bundles/org.openhab.binding.hdpowerview/pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
*/
package org.openhab.binding.hdpowerview.internal;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand All @@ -23,6 +25,7 @@
* used across the whole binding.
*
* @author Andy Lintner - Initial contribution
* @author Andrew Fiddian-Green - Added support for secondary rail positions
*/
@NonNullByDefault
public class HDPowerViewBindingConstants {
Expand All @@ -37,10 +40,11 @@ public class HDPowerViewBindingConstants {
public static final String CHANNEL_SHADE_POSITION = "position";
public static final String CHANNEL_SHADE_VANE = "vane";
public static final String CHANNEL_SHADE_LOW_BATTERY = "lowBattery";
public static final String CHANNEL_SHADE_SECONDARY_POSITION = "secondary";

public static final String CHANNELTYPE_SCENE_ACTIVATE = "scene-activate";

public static final String NETBIOS_NAME = "PDBU-Hub3.0";
public static final List<String> NETBIOS_NAMES = Arrays.asList("PDBU-Hub3.0", "PowerView-Hub");

public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import java.util.Hashtable;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.config.discovery.DiscoveryService;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.Thing;
Expand All @@ -32,6 +34,7 @@
*
* @author Andy Lintner - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.hdpowerview")
public class HDPowerViewHandlerFactory extends BaseThingHandlerFactory {

Expand All @@ -41,7 +44,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
}

@Override
protected ThingHandler createHandler(Thing thing) {
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (thingTypeUID.equals(HDPowerViewBindingConstants.THING_TYPE_HUB)) {
Expand Down
Loading

0 comments on commit 2b21016

Please sign in to comment.