forked from openhab/openhab-addons
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[bluetooth.hdpowerview] New binding using Bluetooth Low Energy (openh…
…ab#17099) * [bluetooth.hdpowerview] initial contribution Signed-off-by: AndrewFG <software@whitebear.ch> Signed-off-by: Patrik Gfeller <patrik.gfeller@proton.me>
- Loading branch information
Showing
19 changed files
with
1,627 additions
and
1 deletion.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
This content is produced and maintained by the openHAB project. | ||
|
||
* Project home: https://www.openhab.org | ||
|
||
== Declared Project Licenses | ||
|
||
This program and the accompanying materials are made available under the terms | ||
of the Eclipse Public License 2.0 which is available at | ||
https://www.eclipse.org/legal/epl-2.0/. | ||
|
||
== Source Code | ||
|
||
https://github.com/openhab/openhab-addons |
81 changes: 81 additions & 0 deletions
81
bundles/org.openhab.binding.bluetooth.hdpowerview/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# Hunter Douglas (Luxaflex) PowerView Binding for Bluetooth | ||
|
||
This is an openHAB binding for Bluetooth for [Hunter Douglas PowerView](https://www.hunterdouglas.com/operating-systems/motorized/powerview-motorization/overview) motorized shades via Bluetooth Low Energy (BLE). | ||
In some countries the PowerView system is sold under the brand name [Luxaflex](https://www.luxaflex.com/). | ||
|
||
This binding supports Generation 3 shades connected directly via their in built Bluetooth Low Energy interface. | ||
There is a different binding [here](https://www.openhab.org/addons/bindings/hdpowerview/) for shades that are connected via a hub or gateway. | ||
|
||
PowerView shades have motorization control for their vertical position, and some also have vane controls to change the angle of their slats. | ||
|
||
## Supported Things | ||
|
||
| Thing | Description | | ||
|-------|------------------------------------------------------------------------------------| | ||
| shade | A Powerview Generation 3 motorized shade connected via Bluetooth Low Energy (BLE). | | ||
|
||
## Bluetooth Bridge | ||
|
||
Before you can create `shade` Things, you must first create a Bluetooth Bridge to contain them. | ||
The instructions for creating a Bluetooth Bridge are [here](https://www.openhab.org/addons/bindings/bluetooth/). | ||
|
||
## Discovery | ||
|
||
Make sure your shades are visible via BLE in the PowerView app before attempting discovery. | ||
|
||
The discovery process can be started by pressing the `+` button at the lower right of the Main UI Things page, selecting the Bluetooth binding, and pressing `Scan`. | ||
Any discovered shades will be displayed with the name prefix 'Powerview Shade'. | ||
|
||
## Configuration | ||
|
||
| Configuration Parameter | Type | Description | | ||
|-------------------------|--------------------|---------------------------------------------------------------------------------------------------------------------| | ||
| address | Required | The Bluetooth MAC address of the shade. | | ||
| bleTimeout | Optional, Advanced | The maximum number of seconds to wait before transactions over Bluetooth will time out (default = 6 seconds). | | ||
| heartbeatDelay | Optional, Advanced | The scanning interval in seconds at which the binding checks if the Shade is on- or off- line (default 15 seconds). | | ||
| pollingDelay | Optional, Advanced | The scanning interval in seconds at which the binding checks the battery status (default 300 seconds). | | ||
| encryptionKey | Optional | The key to be used when encrypting commands to the shade. See [next chapter](#encryption-key). | | ||
|
||
## Encryption Key | ||
|
||
If you want to send position commands to a shade, then an encryption key may be required. | ||
If the shade is NOT included in the Powerview App, then an encryption key is not required. | ||
But if it IS in the Powerview App, then openHAB has to use the same encryption key as used by the App. | ||
Currently you can only discover the encryption key by snooping the network traffic between the App and the shade. | ||
Please post on the openHAB community forum for advice about how to do this. | ||
|
||
## Channels | ||
|
||
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 `tilt` 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. | ||
|
||
| Channel | Item Type | Description | | ||
|---------------|----------------------|-------------------------------------------------------| | ||
| position | Rollershutter | The vertical position of the shade's rail. | | ||
| secondary | Rollershutter | The vertical position of the secondary rail (if any). | | ||
| tilt | Dimmer | The degree of opening of the slats or vanes (if any). | | ||
| battery-level | Number:Dimensionless | Battery level (10% = low, 50% = medium, 100% = high). | | ||
| rssi | Number:Power | Received Signal Strength Indication. | | ||
|
||
Note: the channels `secondary` and `tilt` only exist if the shade physically supports such channels. | ||
|
||
## Examples | ||
|
||
```java | ||
// things | ||
Bridge bluetooth:bluegiga:abc123 "Bluetooth Stick" @ "Comms Cabinet" [port="COM3"] { | ||
// shade NOT integrated in Powerview App | ||
Thing bluetooth:shade:112233445566 "North Window Shade" @ "Office" [address="11:22:33:44:55:66"] | ||
|
||
// or, shade integrated in Powerview App | ||
Thing bluetooth:shade:112233445566 "North Window Shade" @ "Office" [address="11:22:33:44:55:66", encryptionKey="59409c980e627e2fc702c2efcbd4064d"] | ||
} | ||
|
||
// items | ||
Rollershutter Shade_Position "Shade Position" {channel="bluetooth:shade:abc123:112233445566:position"} | ||
Dimmer Shade_Position2 "Shade Position" {channel="bluetooth:shade:abc123:112233445566:position"} | ||
Dimmer Shade_Tilt "Shade Tilt" {channel="bluetooth:shade:abc123:112233445566:tilt"} | ||
Number:Dimensionless Shade_Battery_Level "Shade Battery Level" {channel="bluetooth:shade:abc123:112233445566:battery-level"} | ||
Number:Power Shade_RSSI "Shade Signal Strength" {channel="bluetooth:shade:abc123:112233445566:rssi"} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
|
||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.openhab.addons.bundles</groupId> | ||
<artifactId>org.openhab.addons.reactor.bundles</artifactId> | ||
<version>4.3.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>org.openhab.binding.bluetooth.hdpowerview</artifactId> | ||
|
||
<name>openHAB Add-ons :: Bundles :: HD Powerview Bluetooth Adapter</name> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.openhab.addons.bundles</groupId> | ||
<artifactId>org.openhab.binding.bluetooth</artifactId> | ||
<version>${project.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<artifactId>maven-resources-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<phase>generate-sources</phase> | ||
<goals> | ||
<goal>copy-resources</goal> | ||
</goals> | ||
<configuration> | ||
<outputDirectory>${project.build.directory}/import</outputDirectory> | ||
<overwrite>true</overwrite> | ||
<resources> | ||
<resource> | ||
<directory>../org.openhab.binding.hdpowerview/src/main/java</directory> | ||
<includes> | ||
<include>**/ShadeCapabilitiesDatabase.java</include> | ||
</includes> | ||
</resource> | ||
</resources> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
<plugin> | ||
<groupId>org.codehaus.mojo</groupId> | ||
<artifactId>build-helper-maven-plugin</artifactId> | ||
<executions> | ||
<execution> | ||
<phase>generate-sources</phase> | ||
<goals> | ||
<goal>add-source</goal> | ||
</goals> | ||
<configuration> | ||
<sources> | ||
<source>${project.build.directory}/import</source> | ||
</sources> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
12 changes: 12 additions & 0 deletions
12
bundles/org.openhab.binding.bluetooth.hdpowerview/src/main/feature/feature.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<features name="org.openhab.binding.bluetooth.hdpowerview-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0"> | ||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository> | ||
|
||
<feature name="openhab-binding-bluetooth-hdpowerview" description="HD Powerview Bluetooth Binding" version="${project.version}"> | ||
<feature>openhab-runtime-base</feature> | ||
<feature>openhab-transport-serial</feature> | ||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.bluetooth/${project.version}</bundle> | ||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.bluetooth.hdpowerview/${project.version}</bundle> | ||
</feature> | ||
|
||
</features> |
61 changes: 61 additions & 0 deletions
61
...c/main/java/org/openhab/binding/bluetooth/hdpowerview/internal/ShadeBindingConstants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/** | ||
* Copyright (c) 2010-2024 Contributors to the openHAB project | ||
* | ||
* See the NOTICE file(s) distributed with this work for additional | ||
* information. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0 | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
package org.openhab.binding.bluetooth.hdpowerview.internal; | ||
|
||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.UUID; | ||
|
||
import org.eclipse.jdt.annotation.NonNullByDefault; | ||
import org.openhab.binding.bluetooth.BluetoothBindingConstants; | ||
import org.openhab.binding.bluetooth.BluetoothCharacteristic.GattCharacteristic; | ||
import org.openhab.core.thing.Thing; | ||
import org.openhab.core.thing.ThingTypeUID; | ||
|
||
/** | ||
* The {@link ShadeBindingConstants} class defines common constants, which are | ||
* used across the whole binding. | ||
* | ||
* @author Andrew Fiddian-Green - Initial contribution | ||
*/ | ||
@NonNullByDefault | ||
public class ShadeBindingConstants { | ||
|
||
public static final ThingTypeUID THING_TYPE_SHADE = new ThingTypeUID(BluetoothBindingConstants.BINDING_ID, "shade"); | ||
|
||
public static final String CHANNEL_SHADE_PRIMARY = "primary"; | ||
public static final String CHANNEL_SHADE_SECONDARY = "secondary"; | ||
public static final String CHANNEL_SHADE_TILT = "tilt"; | ||
public static final String CHANNEL_SHADE_BATTERY_LEVEL = "battery-level"; | ||
|
||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_SHADE); | ||
|
||
public static final int HUNTER_DOUGLAS_MANUFACTURER_ID = 0x819; | ||
|
||
public static final Map<UUID, String> MAP_UID_PROPERTY_NAMES = Map.of( // | ||
GattCharacteristic.MANUFACTURER_NAME_STRING.getUUID(), Thing.PROPERTY_VENDOR, // | ||
GattCharacteristic.HARDWARE_REVISION_STRING.getUUID(), Thing.PROPERTY_HARDWARE_VERSION, // | ||
GattCharacteristic.FIRMWARE_REVISION_STRING.getUUID(), Thing.PROPERTY_FIRMWARE_VERSION, // | ||
GattCharacteristic.SERIAL_NUMBER_STRING.getUUID(), Thing.PROPERTY_SERIAL_NUMBER, // | ||
GattCharacteristic.MODEL_NUMBER_STRING.getUUID(), Thing.PROPERTY_MODEL_ID); | ||
|
||
public static final String HUNTER_DOUGLAS = "Hunter Douglas"; | ||
public static final String SHADE_LABEL = "PowerView Shade"; | ||
|
||
public static final String PROPERTY_HOME_ID = "homeId"; | ||
public static final String PROPERTY_ENCRYPTION_KEY = "encryptionKey"; | ||
|
||
public static final UUID UUID_SERVICE_SHADE = UUID.fromString("0000FDC1-0000-1000-8000-00805F9B34FB"); | ||
public static final UUID UUID_CHARACTERISTIC_POSITION = UUID.fromString("CAFE1001-C0FF-EE01-8000-A110CA7AB1E0"); | ||
public static final UUID UUID_CHARACTERISTIC_TBD = UUID.fromString("CAFE1002-C0FF-EE01-8000-A110CA7AB1E0"); | ||
} |
112 changes: 112 additions & 0 deletions
112
...g/openhab/binding/bluetooth/hdpowerview/internal/discovery/ShadeDiscoveryParticipant.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/** | ||
* Copyright (c) 2010-2024 Contributors to the openHAB project | ||
* | ||
* See the NOTICE file(s) distributed with this work for additional | ||
* information. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0 | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
package org.openhab.binding.bluetooth.hdpowerview.internal.discovery; | ||
|
||
import static org.openhab.binding.bluetooth.BluetoothBindingConstants.*; | ||
import static org.openhab.binding.bluetooth.hdpowerview.internal.ShadeBindingConstants.*; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import org.eclipse.jdt.annotation.NonNullByDefault; | ||
import org.eclipse.jdt.annotation.Nullable; | ||
import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryDevice; | ||
import org.openhab.binding.bluetooth.discovery.BluetoothDiscoveryParticipant; | ||
import org.openhab.core.config.discovery.DiscoveryResult; | ||
import org.openhab.core.config.discovery.DiscoveryResultBuilder; | ||
import org.openhab.core.thing.Thing; | ||
import org.openhab.core.thing.ThingTypeUID; | ||
import org.openhab.core.thing.ThingUID; | ||
import org.osgi.service.component.annotations.Component; | ||
|
||
/** | ||
* Discovery participant recognizes Hunter Douglas Powerview Shades and create discovery results for them. | ||
* | ||
* @author Andrew Fiddian-Green - Initial contribution | ||
* | ||
*/ | ||
@NonNullByDefault | ||
@Component | ||
public class ShadeDiscoveryParticipant implements BluetoothDiscoveryParticipant { | ||
|
||
@Override | ||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() { | ||
return SUPPORTED_THING_TYPES_UIDS; | ||
} | ||
|
||
@Override | ||
public @Nullable ThingUID getThingUID(BluetoothDiscoveryDevice device) { | ||
Integer manufacturerId = device.getManufacturerId(); | ||
if (manufacturerId != null && manufacturerId.intValue() == HUNTER_DOUGLAS_MANUFACTURER_ID) { | ||
return new ThingUID(THING_TYPE_SHADE, device.getAdapter().getUID(), | ||
device.getAddress().toString().toLowerCase().replace(":", "")); | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
public @Nullable DiscoveryResult createResult(BluetoothDiscoveryDevice device) { | ||
ThingUID thingUID = getThingUID(device); | ||
if (thingUID != null) { | ||
Map<String, Object> properties = new HashMap<>(); | ||
|
||
properties.put(CONFIGURATION_ADDRESS, device.getAddress().toString()); | ||
properties.put(Thing.PROPERTY_VENDOR, HUNTER_DOUGLAS); | ||
properties.put(Thing.PROPERTY_MAC_ADDRESS, device.getAddress().toString()); | ||
|
||
String serialNumber = device.getSerialNumber(); | ||
if (serialNumber != null) { | ||
properties.put(Thing.PROPERTY_SERIAL_NUMBER, serialNumber); | ||
} | ||
|
||
String firmwareRevision = device.getFirmwareRevision(); | ||
if (firmwareRevision != null) { | ||
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, firmwareRevision); | ||
} | ||
|
||
String model = device.getModel(); | ||
if (model != null) { | ||
properties.put(Thing.PROPERTY_MODEL_ID, model); | ||
} | ||
|
||
String hardwareRevision = device.getHardwareRevision(); | ||
if (hardwareRevision != null) { | ||
properties.put(Thing.PROPERTY_HARDWARE_VERSION, hardwareRevision); | ||
} | ||
|
||
Integer txPower = device.getTxPower(); | ||
if (txPower != null) { | ||
properties.put(PROPERTY_TXPOWER, Integer.toString(txPower)); | ||
} | ||
|
||
String label = String.format("%s (%s)", SHADE_LABEL, device.getName()); | ||
|
||
return DiscoveryResultBuilder.create(thingUID).withProperties(properties) | ||
.withRepresentationProperty(CONFIGURATION_ADDRESS).withBridge(device.getAdapter().getUID()) | ||
.withLabel(label).build(); | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
public boolean requiresConnection(BluetoothDiscoveryDevice device) { | ||
return false; | ||
} | ||
|
||
@Override | ||
public int order() { | ||
// we want to go first | ||
return Integer.MIN_VALUE; | ||
} | ||
} |
Oops, something went wrong.