From 03bfbe6bac4700f9030b72cc10a34687a7e08103 Mon Sep 17 00:00:00 2001 From: Jacob Laursen Date: Mon, 24 Jan 2022 22:42:53 +0100 Subject: [PATCH] [hdpowerview] Add support for repeaters (#12061) * Add support for repeaters. Fixes #12060 Signed-off-by: Jacob Laursen * Simplify thing type filtering. Signed-off-by: Jacob Laursen * Improve robustness of configuration ID validation/initialization. Signed-off-by: Jacob Laursen * Convert repeater-identify to command channel. Signed-off-by: Jacob Laursen * Fix logged warning. Signed-off-by: Jacob Laursen * Skip unneeded bridge status logic. Signed-off-by: Jacob Laursen * Skip redundant logging. Signed-off-by: Jacob Laursen * Fix chanenl type label for blinking enabled. Signed-off-by: Jacob Laursen --- .../org.openhab.binding.hdpowerview/README.md | 55 +++-- .../internal/HDPowerViewBindingConstants.java | 15 +- .../internal/HDPowerViewHandlerFactory.java | 11 +- .../internal/HDPowerViewWebTargets.java | 100 +++++++++ .../api/requests/RepeaterBlinking.java | 39 ++++ .../internal/api/responses/Repeater.java | 26 +++ .../internal/api/responses/RepeaterData.java | 38 ++++ .../internal/api/responses/Repeaters.java | 29 +++ .../HDPowerViewRepeaterConfiguration.java | 28 +++ .../config/HDPowerViewShadeConfiguration.java | 3 +- ...=> HDPowerViewDeviceDiscoveryService.java} | 91 +++++--- .../handler/HDPowerViewHubHandler.java | 48 ++-- .../handler/HDPowerViewRepeaterHandler.java | 212 ++++++++++++++++++ .../handler/HDPowerViewShadeHandler.java | 15 +- .../OH-INF/i18n/hdpowerview.properties | 9 + .../OH-INF/i18n/hdpowerview_da.properties | 13 ++ .../resources/OH-INF/thing/thing-types.xml | 46 +++- 17 files changed, 682 insertions(+), 96 deletions(-) create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/requests/RepeaterBlinking.java create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeater.java create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/RepeaterData.java create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeaters.java create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewRepeaterConfiguration.java rename bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/{HDPowerViewShadeDiscoveryService.java => HDPowerViewDeviceDiscoveryService.java} (54%) create mode 100644 bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewRepeaterHandler.java diff --git a/bundles/org.openhab.binding.hdpowerview/README.md b/bundles/org.openhab.binding.hdpowerview/README.md index 46f0e27e8926c..c777915c4681e 100644 --- a/bundles/org.openhab.binding.hdpowerview/README.md +++ b/bundles/org.openhab.binding.hdpowerview/README.md @@ -13,10 +13,11 @@ By using a scene to control multiple shades at once, the shades will all begin m ## Supported Things -| Thing | Thing Type | Description | -|-------|------------|-------------| -| 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. | -| shade | Thing | A motorized shade. | +| Thing | Thing Type | Description | +|----------|------------|-------------| +| 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. | +| shade | Thing | A motorized shade. | +| repeater | Thing | A PowerView signal repeater. | ## Discovery @@ -46,16 +47,25 @@ If in the future, you add additional shades or scenes to your system, the bindin | 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). | | hardRefreshBatteryLevel | The number of hours between hard refreshes of battery levels from the PowerView Hub (or 0 to disable, defaulting to weekly). See [Refreshing the PowerView Hub Cache](#Refreshing-the-PowerView-Hub-Cache). | -### Thing Configuration for PowerView Shades +### Thing Configuration for PowerView Shades and Accessories -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: +PowerView shades and repeaters should preferably be configured via the automatic discovery process. +It is quite difficult to configure manually as the `id` of the shade or repeater is not exposed in the +PowerView app. However, the configuration parameters are described below. + +#### Thing Configuration for PowerView Shades | Configuration Parameter | Description | |-------------------------|-------------| | id | The ID of the PowerView shade in the app. Must be an integer. | +#### Thing Configuration for PowerView Repeaters + + +| Configuration Parameter | Description | +|-------------------------|-------------| +| id | The ID of the PowerView repeater in the app. Must be an integer. | + ## Channels ### Channels for Hub (Thing type `hub`) @@ -88,6 +98,13 @@ All of these channels appear in the binding, but only those which have a physica | batteryVoltage | Number:ElectricPotential | Battery voltage reported by the shade. | | signalStrength | Number | Signal strength (0 for no or unknown signal, 1 for weak, 2 for average, 3 for good or 4 for excellent) | +### Channels for Repeaters (Thing type `repeater`) + +| Channel | Item Type | Description | +|-----------------|-----------|-------------------------------| +| identify | String | Flash repeater to identify. Valid values are: IDENTIFY | +| blinkingEnabled | Switch | Blink during commands. | + ### Roller Shutter Up/Down Position vs. Open/Close State The `position` and `secondary` channels are Rollershutter types. @@ -191,6 +208,7 @@ For single shades the refresh takes the item's channel into consideration: ``` Bridge hdpowerview:hub:g24 "Luxaflex Hub" @ "Living Room" [host="192.168.1.123"] { Thing shade s50150 "Living Room Shade" @ "Living Room" [id="50150"] + Thing repeater r16384 "Bedroom Repeater" @ "Bedroom" [id="16384"] } ``` @@ -200,16 +218,19 @@ 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"} - Switch Living_Room_Shade_Calibrate "Living Room Shade Calibrate" {channel="hdpowerview:shade:g24:s50150:calibrate", autoupdate="false"} ``` +Repeater items: + +``` +String Bedroom_Repeater_Identify "Bedroom Repeater Identify" {channel="hdpowerview:repeater:g24:r16384:identify"} +Switch Bedroom_Repeater_BlinkingEnabled "Bedroom Repeater Blinking Enabled [%s]" {channel="hdpowerview:repeater:g24:r16384:blinkingEnabled"} +``` + Scene items: ``` @@ -219,8 +240,12 @@ Switch Living_Room_Shades_Scene_Heart "Living Room Shades Scene Heart" ### `demo.sitemap` File ``` -Frame label="Living Room Shades" { - Switch item=Living_Room_Shades_Scene_Open - Slider item=Living_Room_Shade_1_Position  +Frame label="Living Room Shades" { + Switch item=Living_Room_Shades_Scene_Open + Slider item=Living_Room_Shade_1_Position +} +Frame label="Bedroom" { + Switch item=Bedroom_Repeater_Identify mappings=[IDENTIFY="Identify"] + Switch item=Bedroom_Repeater_BlinkingEnabled } ``` diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java index 371f63d717635..0d45171d8adea 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewBindingConstants.java @@ -13,7 +13,6 @@ package org.openhab.binding.hdpowerview.internal; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -26,7 +25,7 @@ * * @author Andy Lintner - Initial contribution * @author Andrew Fiddian-Green - Added support for secondary rail positions - * @author Jacob Laursen - Add support for scene groups and automations + * @author Jacob Laursen - Added support for scene groups, automations and repeaters */ @NonNullByDefault public class HDPowerViewBindingConstants { @@ -36,6 +35,7 @@ public class HDPowerViewBindingConstants { // List of all Thing Type UIDs public static final ThingTypeUID THING_TYPE_HUB = new ThingTypeUID(BINDING_ID, "hub"); public static final ThingTypeUID THING_TYPE_SHADE = new ThingTypeUID(BINDING_ID, "shade"); + public static final ThingTypeUID THING_TYPE_REPEATER = new ThingTypeUID(BINDING_ID, "repeater"); // List of all Channel ids public static final String CHANNEL_SHADE_POSITION = "position"; @@ -47,6 +47,9 @@ public class HDPowerViewBindingConstants { public static final String CHANNEL_SHADE_BATTERY_VOLTAGE = "batteryVoltage"; public static final String CHANNEL_SHADE_SIGNAL_STRENGTH = "signalStrength"; + public static final String CHANNEL_REPEATER_IDENTIFY = "identify"; + public static final String CHANNEL_REPEATER_BLINKING_ENABLED = "blinkingEnabled"; + public static final String CHANNEL_GROUP_SCENES = "scenes"; public static final String CHANNEL_GROUP_SCENE_GROUPS = "sceneGroups"; public static final String CHANNEL_GROUP_AUTOMATIONS = "automations"; @@ -68,10 +71,6 @@ public class HDPowerViewBindingConstants { public static final List NETBIOS_NAMES = Arrays.asList("PDBU-Hub3.0", "PowerView-Hub"); - public static final Set SUPPORTED_THING_TYPES_UIDS = new HashSet<>(); - - static { - SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_HUB); - SUPPORTED_THING_TYPES_UIDS.add(THING_TYPE_SHADE); - } + public static final Set SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_HUB, THING_TYPE_SHADE, + THING_TYPE_REPEATER); } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewHandlerFactory.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewHandlerFactory.java index 819adc11df4aa..af8c201b99ff4 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewHandlerFactory.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewHandlerFactory.java @@ -17,8 +17,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; -import org.openhab.binding.hdpowerview.internal.discovery.HDPowerViewShadeDiscoveryService; +import org.openhab.binding.hdpowerview.internal.discovery.HDPowerViewDeviceDiscoveryService; import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewHubHandler; +import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewRepeaterHandler; import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewShadeHandler; import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.i18n.LocaleProvider; @@ -67,12 +68,14 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected @Nullable ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (thingTypeUID.equals(HDPowerViewBindingConstants.THING_TYPE_HUB)) { + if (HDPowerViewBindingConstants.THING_TYPE_HUB.equals(thingTypeUID)) { HDPowerViewHubHandler handler = new HDPowerViewHubHandler((Bridge) thing, httpClient, translationProvider); - registerService(new HDPowerViewShadeDiscoveryService(handler)); + registerService(new HDPowerViewDeviceDiscoveryService(handler)); return handler; - } else if (thingTypeUID.equals(HDPowerViewBindingConstants.THING_TYPE_SHADE)) { + } else if (HDPowerViewBindingConstants.THING_TYPE_SHADE.equals(thingTypeUID)) { return new HDPowerViewShadeHandler(thing); + } else if (HDPowerViewBindingConstants.THING_TYPE_REPEATER.equals(thingTypeUID)) { + return new HDPowerViewRepeaterHandler(thing); } return null; diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java index 344dc6ab1e485..dd1748fafbfbd 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/HDPowerViewWebTargets.java @@ -27,11 +27,15 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.openhab.binding.hdpowerview.internal.api.ShadePosition; +import org.openhab.binding.hdpowerview.internal.api.requests.RepeaterBlinking; import org.openhab.binding.hdpowerview.internal.api.requests.ShadeCalibrate; import org.openhab.binding.hdpowerview.internal.api.requests.ShadeMove; import org.openhab.binding.hdpowerview.internal.api.requests.ShadeStop; import org.openhab.binding.hdpowerview.internal.api.responses.FirmwareVersion; import org.openhab.binding.hdpowerview.internal.api.responses.FirmwareVersions; +import org.openhab.binding.hdpowerview.internal.api.responses.Repeater; +import org.openhab.binding.hdpowerview.internal.api.responses.RepeaterData; +import org.openhab.binding.hdpowerview.internal.api.responses.Repeaters; import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections; import org.openhab.binding.hdpowerview.internal.api.responses.SceneCollections.SceneCollection; import org.openhab.binding.hdpowerview.internal.api.responses.Scenes; @@ -83,6 +87,7 @@ public class HDPowerViewWebTargets { private final String sceneCollectionActivate; private final String sceneCollections; private final String scheduledEvents; + private final String repeaters; private final Gson gson = new Gson(); private final HttpClient httpClient; @@ -135,6 +140,9 @@ public HDPowerViewWebTargets(HttpClient httpClient, String ipAddress) { sceneCollections = base + "scenecollections/"; scheduledEvents = base + "scheduledevents"; + + repeaters = base + "repeaters/"; + this.httpClient = httpClient; } @@ -385,6 +393,98 @@ public void enableScheduledEvent(int scheduledEventId, boolean enable) } } + /** + * Fetches a JSON package that describes all repeaters in the hub, and wraps it in + * a Repeaters class instance + * + * @return Repeaters class instance + * @throws HubInvalidResponseException if response is invalid + * @throws HubProcessingException if there is any processing error + * @throws HubMaintenanceException if the hub is down for maintenance + */ + public Repeaters getRepeaters() + throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException { + String json = invoke(HttpMethod.GET, repeaters, null, null); + try { + Repeaters repeaters = gson.fromJson(json, Repeaters.class); + if (repeaters == null) { + throw new HubInvalidResponseException("Missing repeaters response"); + } + List repeaterData = repeaters.repeaterData; + if (repeaterData == null) { + throw new HubInvalidResponseException("Missing 'repeaters.repeaterData' element"); + } + return repeaters; + } catch (JsonParseException e) { + throw new HubInvalidResponseException("Error parsing repeaters response", e); + } + } + + /** + * Fetches a JSON package that describes a specific repeater in the hub, and wraps it + * in a RepeaterData class instance + * + * @param repeaterId id of the repeater to be fetched + * @return RepeaterData class instance + * @throws HubInvalidResponseException if response is invalid + * @throws HubProcessingException if there is any processing error + * @throws HubMaintenanceException if the hub is down for maintenance + */ + public RepeaterData getRepeater(int repeaterId) + throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException { + String jsonResponse = invoke(HttpMethod.GET, repeaters + Integer.toString(repeaterId), null, null); + return repeaterDataFromJson(jsonResponse); + } + + private RepeaterData repeaterDataFromJson(String json) throws HubInvalidResponseException { + try { + Repeater repeater = gson.fromJson(json, Repeater.class); + if (repeater == null) { + throw new HubInvalidResponseException("Missing repeater response"); + } + RepeaterData repeaterData = repeater.repeater; + if (repeaterData == null) { + throw new HubInvalidResponseException("Missing 'repeater.repeater' element"); + } + return repeaterData; + } catch (JsonParseException e) { + throw new HubInvalidResponseException("Error parsing repeater response", e); + } + } + + /** + * Instructs the hub to identify a specific repeater by blinking + * + * @param repeaterId id of the repeater to be identified + * @return RepeaterData class instance + * @throws HubInvalidResponseException if response is invalid + * @throws HubProcessingException if there is any processing error + * @throws HubMaintenanceException if the hub is down for maintenance + */ + public RepeaterData identifyRepeater(int repeaterId) + throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException { + String jsonResponse = invoke(HttpMethod.GET, repeaters + repeaterId, + Query.of("identify", Boolean.toString(true)), null); + return repeaterDataFromJson(jsonResponse); + } + + /** + * Enables or disables blinking for a repeater + * + * @param repeaterId id of the repeater for which to be enable or disable blinking + * @param enable true to enable blinking, false to disable + * @return RepeaterData class instance + * @throws HubInvalidResponseException if response is invalid + * @throws HubProcessingException if there is any processing error + * @throws HubMaintenanceException if the hub is down for maintenance + */ + public RepeaterData enableRepeaterBlinking(int repeaterId, boolean enable) + throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException { + String jsonRequest = gson.toJson(new RepeaterBlinking(repeaterId, enable)); + String jsonResponse = invoke(HttpMethod.PUT, repeaters + repeaterId, null, jsonRequest); + return repeaterDataFromJson(jsonResponse); + } + /** * Invoke a call on the hub server to retrieve information or send a command * diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/requests/RepeaterBlinking.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/requests/RepeaterBlinking.java new file mode 100644 index 0000000000000..ea3886af1f1c4 --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/requests/RepeaterBlinking.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2010-2022 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.hdpowerview.internal.api.requests; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * State of a single Repeater for being updated by an HD PowerView Hub + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class RepeaterBlinking { + public Repeater repeater; + + public class Repeater { + public int id; + public boolean blinkEnabled; + + public Repeater(int id, boolean enable) { + this.id = id; + this.blinkEnabled = enable; + } + } + + public RepeaterBlinking(int id, boolean enable) { + repeater = new Repeater(id, enable); + } +} diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeater.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeater.java new file mode 100644 index 0000000000000..55ba66665b14f --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeater.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2010-2022 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.hdpowerview.internal.api.responses; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * State of a single Repeater, as returned by an HD PowerView Hub + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class Repeater { + public @Nullable RepeaterData repeater; +} diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/RepeaterData.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/RepeaterData.java new file mode 100644 index 0000000000000..8b0c255309ec3 --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/RepeaterData.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2010-2022 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.hdpowerview.internal.api.responses; + +import java.util.Base64; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hdpowerview.internal.api.Firmware; + +/** + * Repeater data for a single Repeater, as returned by an HD PowerView Hub + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class RepeaterData { + public int id; + public @Nullable String name; + public int roomId; + public int groupId; + public boolean blinkEnabled; + public @Nullable Firmware firmware; + + public String getName() { + return new String(Base64.getDecoder().decode(name)); + } +} diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeaters.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeaters.java new file mode 100644 index 0000000000000..8b5f15b12fd69 --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/api/responses/Repeaters.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2010-2022 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.hdpowerview.internal.api.responses; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * Repeaters connected to an HD PowerView Hub + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class Repeaters { + public @Nullable List repeaterData; + public @Nullable List repeaterIds; +} diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewRepeaterConfiguration.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewRepeaterConfiguration.java new file mode 100644 index 0000000000000..29fd594cb9064 --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewRepeaterConfiguration.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2022 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.hdpowerview.internal.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * Basic configuration for an HD PowerView Repeater + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class HDPowerViewRepeaterConfiguration { + + public static final String ID = "id"; + + public int id; +} diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewShadeConfiguration.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewShadeConfiguration.java index 164d1d5a5a741..570aeeff14463 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewShadeConfiguration.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/config/HDPowerViewShadeConfiguration.java @@ -13,7 +13,6 @@ package org.openhab.binding.hdpowerview.internal.config; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; /** * Basic configuration for an HD PowerView Shade @@ -25,5 +24,5 @@ public class HDPowerViewShadeConfiguration { public static final String ID = "id"; - public @Nullable String id; + public int id; } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/HDPowerViewShadeDiscoveryService.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/HDPowerViewDeviceDiscoveryService.java similarity index 54% rename from bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/HDPowerViewShadeDiscoveryService.java rename to bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/HDPowerViewDeviceDiscoveryService.java index 0eecec1379444..f61be9f9a9b62 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/HDPowerViewShadeDiscoveryService.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/discovery/HDPowerViewDeviceDiscoveryService.java @@ -21,12 +21,15 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants; import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets; +import org.openhab.binding.hdpowerview.internal.api.responses.RepeaterData; import org.openhab.binding.hdpowerview.internal.api.responses.Shades; import org.openhab.binding.hdpowerview.internal.api.responses.Shades.ShadeData; +import org.openhab.binding.hdpowerview.internal.config.HDPowerViewRepeaterConfiguration; import org.openhab.binding.hdpowerview.internal.config.HDPowerViewShadeConfiguration; import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase; import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase.Capabilities; import org.openhab.binding.hdpowerview.internal.exceptions.HubException; +import org.openhab.binding.hdpowerview.internal.exceptions.HubInvalidResponseException; import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException; import org.openhab.binding.hdpowerview.internal.exceptions.HubProcessingException; import org.openhab.binding.hdpowerview.internal.handler.HDPowerViewHubHandler; @@ -42,15 +45,15 @@ * @author Andy Lintner - Initial contribution */ @NonNullByDefault -public class HDPowerViewShadeDiscoveryService extends AbstractDiscoveryService { +public class HDPowerViewDeviceDiscoveryService extends AbstractDiscoveryService { - private final Logger logger = LoggerFactory.getLogger(HDPowerViewShadeDiscoveryService.class); + private final Logger logger = LoggerFactory.getLogger(HDPowerViewDeviceDiscoveryService.class); private final HDPowerViewHubHandler hub; private final Runnable scanner; private @Nullable ScheduledFuture backgroundFuture; private final ShadeCapabilitiesDatabase db = new ShadeCapabilitiesDatabase(); - public HDPowerViewShadeDiscoveryService(HDPowerViewHubHandler hub) { + public HDPowerViewDeviceDiscoveryService(HDPowerViewHubHandler hub) { super(Collections.singleton(HDPowerViewBindingConstants.THING_TYPE_SHADE), 600, true); this.hub = hub; this.scanner = createScanner(); @@ -87,34 +90,8 @@ private Runnable createScanner() { if (webTargets == null) { throw new HubProcessingException("Web targets not initialized"); } - Shades shades = webTargets.getShades(); - if (shades.shadeData != null) { - ThingUID bridgeUID = hub.getThing().getUID(); - List shadesData = shades.shadeData; - if (shadesData != null) { - for (ShadeData shadeData : shadesData) { - if (shadeData.id != 0) { - String id = Integer.toString(shadeData.id); - ThingUID thingUID = new ThingUID(HDPowerViewBindingConstants.THING_TYPE_SHADE, - bridgeUID, id); - Integer caps = shadeData.capabilities; - Capabilities capabilities = db.getCapabilities((caps != null) ? caps.intValue() : -1); - - DiscoveryResultBuilder builder = DiscoveryResultBuilder.create(thingUID) - .withLabel(shadeData.getName()).withBridge(bridgeUID) - .withProperty(HDPowerViewShadeConfiguration.ID, id) - .withProperty(HDPowerViewBindingConstants.PROPERTY_SHADE_TYPE, - db.getType(shadeData.type).toString()) - .withProperty(HDPowerViewBindingConstants.PROPERTY_SHADE_CAPABILITIES, - capabilities.toString()) - .withRepresentationProperty(HDPowerViewShadeConfiguration.ID); - - logger.debug("Hub discovered shade '{}'", id); - thingDiscovered(builder.build()); - } - } - } - } + discoverShades(webTargets); + discoverRepeaters(webTargets); } catch (HubMaintenanceException e) { // exceptions are logged in HDPowerViewWebTargets } catch (HubException e) { @@ -123,4 +100,56 @@ private Runnable createScanner() { stopScan(); }; } + + private void discoverShades(HDPowerViewWebTargets webTargets) + throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException { + Shades shades = webTargets.getShades(); + List shadesData = shades.shadeData; + if (shadesData == null) { + return; + } + ThingUID bridgeUid = hub.getThing().getUID(); + for (ShadeData shadeData : shadesData) { + if (shadeData.id == 0) { + continue; + } + String id = Integer.toString(shadeData.id); + ThingUID thingUID = new ThingUID(HDPowerViewBindingConstants.THING_TYPE_SHADE, bridgeUid, id); + Integer caps = shadeData.capabilities; + Capabilities capabilities = db.getCapabilities((caps != null) ? caps.intValue() : -1); + + DiscoveryResultBuilder builder = DiscoveryResultBuilder.create(thingUID).withLabel(shadeData.getName()) + .withBridge(bridgeUid).withProperty(HDPowerViewShadeConfiguration.ID, id) + .withProperty(HDPowerViewBindingConstants.PROPERTY_SHADE_TYPE, + db.getType(shadeData.type).toString()) + .withProperty(HDPowerViewBindingConstants.PROPERTY_SHADE_CAPABILITIES, capabilities.toString()) + .withRepresentationProperty(HDPowerViewShadeConfiguration.ID); + + logger.debug("Hub discovered shade '{}'", id); + thingDiscovered(builder.build()); + } + } + + private void discoverRepeaters(HDPowerViewWebTargets webTargets) + throws HubInvalidResponseException, HubProcessingException, HubMaintenanceException { + List repeaters = webTargets.getRepeaters().repeaterData; + if (repeaters == null) { + return; + } + ThingUID bridgeUid = hub.getThing().getUID(); + for (RepeaterData repeaterData : repeaters) { + if (repeaterData.id == 0) { + continue; + } + String id = Integer.toString(repeaterData.id); + ThingUID thingUid = new ThingUID(HDPowerViewBindingConstants.THING_TYPE_REPEATER, bridgeUid, id); + + DiscoveryResultBuilder builder = DiscoveryResultBuilder.create(thingUid).withLabel(repeaterData.getName()) + .withBridge(bridgeUid).withProperty(HDPowerViewRepeaterConfiguration.ID, id) + .withRepresentationProperty(HDPowerViewRepeaterConfiguration.ID); + + logger.debug("Hub discovered repeater '{}'", id); + thingDiscovered(builder.build()); + } + } } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java index b1f4de389ade6..ebe36df33a162 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewHubHandler.java @@ -325,17 +325,17 @@ private void pollShades() throws HubInvalidResponseException, HubProcessingExcep updateStatus(ThingStatus.ONLINE); logger.debug("Received data for {} shades", shadesData.size()); - Map idShadeDataMap = getIdShadeDataMap(shadesData); - Map thingIdMap = getThingIdMap(); - for (Entry item : thingIdMap.entrySet()) { + Map idShadeDataMap = getIdShadeDataMap(shadesData); + Map thingIdMap = getShadeThingIdMap(); + for (Entry item : thingIdMap.entrySet()) { Thing thing = item.getKey(); - String shadeId = item.getValue(); + int shadeId = item.getValue(); ShadeData shadeData = idShadeDataMap.get(shadeId); updateShadeThing(shadeId, thing, shadeData); } } - private void updateShadeThing(String shadeId, Thing thing, @Nullable ShadeData shadeData) { + private void updateShadeThing(int shadeId, Thing thing, @Nullable ShadeData shadeData) { HDPowerViewShadeHandler thingHandler = ((HDPowerViewShadeHandler) thing.getHandler()); if (thingHandler == null) { logger.debug("Shade '{}' handler not initialized", shadeId); @@ -533,50 +533,52 @@ private void updateAutomationStates(List scheduledEvents) { } } - private Map getThingIdMap() { - Map ret = new HashMap<>(); - for (Thing thing : getThing().getThings()) { - String id = thing.getConfiguration().as(HDPowerViewShadeConfiguration.class).id; - if (id != null && !id.isEmpty()) { - ret.put(thing, id); - } - } + private Map getShadeThingIdMap() { + Map ret = new HashMap<>(); + getThing().getThings().stream() + .filter(thing -> HDPowerViewBindingConstants.THING_TYPE_SHADE.equals(thing.getThingTypeUID())) + .forEach(thing -> { + int id = thing.getConfiguration().as(HDPowerViewShadeConfiguration.class).id; + if (id > 0) { + ret.put(thing, id); + } + }); return ret; } - private Map getIdShadeDataMap(List shadeData) { - Map ret = new HashMap<>(); + private Map getIdShadeDataMap(List shadeData) { + Map ret = new HashMap<>(); for (ShadeData shade : shadeData) { - if (shade.id != 0) { - ret.put(Integer.toString(shade.id), shade); + if (shade.id > 0) { + ret.put(shade.id, shade); } } return ret; } private void requestRefreshShadePositions() { - Map thingIdMap = getThingIdMap(); - for (Entry item : thingIdMap.entrySet()) { + Map thingIdMap = getShadeThingIdMap(); + for (Entry item : thingIdMap.entrySet()) { Thing thing = item.getKey(); ThingHandler handler = thing.getHandler(); if (handler instanceof HDPowerViewShadeHandler) { ((HDPowerViewShadeHandler) handler).requestRefreshShadePosition(); } else { - String shadeId = item.getValue(); + int shadeId = item.getValue(); logger.debug("Shade '{}' handler not initialized", shadeId); } } } private void requestRefreshShadeBatteryLevels() { - Map thingIdMap = getThingIdMap(); - for (Entry item : thingIdMap.entrySet()) { + Map thingIdMap = getShadeThingIdMap(); + for (Entry item : thingIdMap.entrySet()) { Thing thing = item.getKey(); ThingHandler handler = thing.getHandler(); if (handler instanceof HDPowerViewShadeHandler) { ((HDPowerViewShadeHandler) handler).requestRefreshShadeBatteryLevel(); } else { - String shadeId = item.getValue(); + int shadeId = item.getValue(); logger.debug("Shade '{}' handler not initialized", shadeId); } } diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewRepeaterHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewRepeaterHandler.java new file mode 100644 index 0000000000000..36a8dad8c63e5 --- /dev/null +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewRepeaterHandler.java @@ -0,0 +1,212 @@ +/** + * Copyright (c) 2010-2022 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.hdpowerview.internal.handler; + +import static org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants.*; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.hdpowerview.internal.HDPowerViewWebTargets; +import org.openhab.binding.hdpowerview.internal.api.Firmware; +import org.openhab.binding.hdpowerview.internal.api.responses.RepeaterData; +import org.openhab.binding.hdpowerview.internal.config.HDPowerViewRepeaterConfiguration; +import org.openhab.binding.hdpowerview.internal.exceptions.HubException; +import org.openhab.binding.hdpowerview.internal.exceptions.HubInvalidResponseException; +import org.openhab.binding.hdpowerview.internal.exceptions.HubMaintenanceException; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.thing.Bridge; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.types.Command; +import org.openhab.core.types.UnDefType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handles commands for an HD PowerView Repeater + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class HDPowerViewRepeaterHandler extends AbstractHubbedThingHandler { + + private final Logger logger = LoggerFactory.getLogger(HDPowerViewRepeaterHandler.class); + + private static final int REFRESH_INTERVAL_MINUTES = 5; + private static final int IDENTITY_PERIOD_SECONDS = 3; + private static final String COMMAND_IDENTIFY = "IDENTIFY"; + + private @Nullable ScheduledFuture refreshStatusFuture = null; + private @Nullable ScheduledFuture resetIdentifyStateFuture = null; + private int repeaterId; + + public HDPowerViewRepeaterHandler(Thing thing) { + super(thing); + } + + @Override + public void initialize() { + repeaterId = getConfigAs(HDPowerViewRepeaterConfiguration.class).id; + logger.debug("Initializing repeater handler for repeater {}", repeaterId); + if (repeaterId <= 0) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, + "@text/offline.conf-error.invalid-id"); + return; + } + Bridge bridge = getBridge(); + if (bridge == null) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED); + return; + } + if (!(bridge.getHandler() instanceof HDPowerViewHubHandler)) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED, + "@text/offline.conf-error.invalid-bridge-handler"); + return; + } + updateStatus(ThingStatus.UNKNOWN); + scheduleRefreshJob(); + } + + @Override + public void dispose() { + logger.debug("Disposing repeater handler for repeater {}", repeaterId); + cancelRefreshJob(); + cancelResetIdentifyStateJob(); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + HDPowerViewHubHandler bridge = getBridgeHandler(); + if (bridge == null) { + logger.warn("Missing bridge handler"); + return; + } + HDPowerViewWebTargets webTargets = bridge.getWebTargets(); + if (webTargets == null) { + logger.warn("Web targets not initialized"); + return; + } + + try { + RepeaterData repeaterData; + + switch (channelUID.getId()) { + case CHANNEL_REPEATER_IDENTIFY: + if (command instanceof StringType) { + if (COMMAND_IDENTIFY.equals(((StringType) command).toString())) { + repeaterData = webTargets.identifyRepeater(repeaterId); + scheduler.submit(() -> updatePropertyAndState(repeaterData)); + cancelResetIdentifyStateJob(); + resetIdentifyStateFuture = scheduler.schedule(() -> { + updateState(CHANNEL_REPEATER_IDENTIFY, UnDefType.UNDEF); + }, IDENTITY_PERIOD_SECONDS, TimeUnit.SECONDS); + } else { + logger.warn("Unsupported command: {}. Supported commands are: " + COMMAND_IDENTIFY, + command); + } + } + break; + case CHANNEL_REPEATER_BLINKING_ENABLED: + repeaterData = webTargets.enableRepeaterBlinking(repeaterId, OnOffType.ON == command); + scheduler.submit(() -> updatePropertyAndState(repeaterData)); + break; + } + } catch (HubInvalidResponseException e) { + Throwable cause = e.getCause(); + if (cause == null) { + logger.warn("Bridge returned a bad JSON response: {}", e.getMessage()); + } else { + logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage()); + } + } catch (HubMaintenanceException e) { + // exceptions are logged in HDPowerViewWebTargets + } catch (HubException e) { + logger.warn("Unexpected error: {}", e.getMessage()); + } + } + + private void cancelResetIdentifyStateJob() { + ScheduledFuture scheduledJob = resetIdentifyStateFuture; + if (scheduledJob != null) { + scheduledJob.cancel(true); + } + resetIdentifyStateFuture = null; + } + + private void scheduleRefreshJob() { + cancelRefreshJob(); + logger.debug("Scheduling poll for repeater {} now, then every {} minutes", repeaterId, + REFRESH_INTERVAL_MINUTES); + this.refreshStatusFuture = scheduler.scheduleWithFixedDelay(this::poll, 0, REFRESH_INTERVAL_MINUTES, + TimeUnit.MINUTES); + } + + private void cancelRefreshJob() { + ScheduledFuture future = this.refreshStatusFuture; + if (future != null) { + future.cancel(false); + } + this.refreshStatusFuture = null; + } + + private synchronized void poll() { + HDPowerViewHubHandler bridge = getBridgeHandler(); + if (bridge == null) { + logger.warn("Missing bridge handler"); + return; + } + HDPowerViewWebTargets webTargets = bridge.getWebTargets(); + if (webTargets == null) { + logger.warn("Web targets not initialized"); + return; + } + try { + logger.debug("Polling for status information"); + + RepeaterData repeaterData = webTargets.getRepeater(repeaterId); + updatePropertyAndState(repeaterData); + + } catch (HubInvalidResponseException e) { + Throwable cause = e.getCause(); + if (cause == null) { + logger.warn("Bridge returned a bad JSON response: {}", e.getMessage()); + } else { + logger.warn("Bridge returned a bad JSON response: {} -> {}", e.getMessage(), cause.getMessage()); + } + } catch (HubMaintenanceException e) { + // exceptions are logged in HDPowerViewWebTargets + } catch (HubException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, e.getMessage()); + } + } + + private void updatePropertyAndState(RepeaterData repeaterData) { + updateStatus(ThingStatus.ONLINE); + + Firmware firmware = repeaterData.firmware; + if (firmware != null) { + logger.debug("Repeater firmware version received: {}", firmware.toString()); + updateProperty(Thing.PROPERTY_FIRMWARE_VERSION, firmware.toString()); + } else { + logger.warn("Repeater firmware version missing in response"); + } + + updateState(CHANNEL_REPEATER_BLINKING_ENABLED, repeaterData.blinkEnabled ? OnOffType.ON : OnOffType.OFF); + } +} diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java index 6b42bf7d01319..30ab73e700856 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java +++ b/bundles/org.openhab.binding.hdpowerview/src/main/java/org/openhab/binding/hdpowerview/internal/handler/HDPowerViewShadeHandler.java @@ -86,11 +86,10 @@ public HDPowerViewShadeHandler(Thing thing) { @Override public void initialize() { - logger.debug("Initializing shade handler"); isDisposing = false; - try { - shadeId = getShadeId(); - } catch (NumberFormatException e) { + shadeId = getConfigAs(HDPowerViewShadeConfiguration.class).id; + logger.debug("Initializing shade handler for shade {}", shadeId); + if (shadeId <= 0) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "@text/offline.conf-error.invalid-id"); return; @@ -459,14 +458,6 @@ private void updateShadePositions(ShadeData shadeData) { updatePositionStates(shadePosition); } - private int getShadeId() throws NumberFormatException { - String str = getConfigAs(HDPowerViewShadeConfiguration.class).id; - if (str == null) { - throw new NumberFormatException("null input string"); - } - return Integer.parseInt(str); - } - /** * Request that the shade shall undergo a 'hard' refresh for querying its current position */ diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties index b9b8efc4c9cbc..38a186b2589af 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties +++ b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview.properties @@ -7,6 +7,8 @@ binding.hdpowerview.description = The Hunter Douglas PowerView binding provides thing-type.hdpowerview.hub.label = PowerView Hub thing-type.hdpowerview.hub.description = Hunter Douglas (Luxaflex) PowerView Hub +thing-type.hdpowerview.repeater.label = PowerView Repeater +thing-type.hdpowerview.repeater.description = Hunter Douglas (Luxaflex) PowerView Repeater thing-type.hdpowerview.shade.label = PowerView Shade thing-type.hdpowerview.shade.description = Hunter Douglas (Luxaflex) PowerView Shade thing-type.hdpowerview.shade.channel.secondary.label = Secondary Position @@ -22,6 +24,8 @@ thing-type.config.hdpowerview.hub.host.label = Host thing-type.config.hdpowerview.hub.host.description = The Host address of the PowerView Hub thing-type.config.hdpowerview.hub.refresh.label = Refresh Interval thing-type.config.hdpowerview.hub.refresh.description = The number of milliseconds between fetches of the PowerView Hub shade state +thing-type.config.hdpowerview.repeater.id.label = ID +thing-type.config.hdpowerview.repeater.id.description = The numeric ID of the PowerView Repeater in the Hub thing-type.config.hdpowerview.shade.id.label = ID thing-type.config.hdpowerview.shade.id.description = The numeric ID of the PowerView Shade in the Hub @@ -29,6 +33,11 @@ thing-type.config.hdpowerview.shade.id.description = The numeric ID of the Power channel-type.hdpowerview.battery-voltage.label = Battery Voltage channel-type.hdpowerview.battery-voltage.description = Battery voltage reported by the shade +channel-type.hdpowerview.repeater-blinking-enabled.label = Blinking Enabled +channel-type.hdpowerview.repeater-blinking-enabled.description = Blink during commands +channel-type.hdpowerview.repeater-identify.label = Identify +channel-type.hdpowerview.repeater-identify.description = Flash repeater to identify +channel-type.hdpowerview.repeater-identify.command.option.IDENTIFY = Identify channel-type.hdpowerview.shade-calibrate.label = Calibrate channel-type.hdpowerview.shade-calibrate.description = Perform calibration of the shade channel-type.hdpowerview.shade-position.label = Position diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties index 7f3a7fdf0c1f0..c245b59b96eb0 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties +++ b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/i18n/hdpowerview_da.properties @@ -1,3 +1,16 @@ +# thing types + +thing-type.hdpowerview.repeater.label = PowerView Repeater +thing-type.hdpowerview.repeater.description = Hunter Douglas (Luxaflex) PowerView Repeater + +# channel types + +channel-type.hdpowerview.repeater-blinking-enabled.label = Blink aktiveret +channel-type.hdpowerview.repeater-blinking-enabled.description = Blink når kommandoer aktiveres +channel-type.hdpowerview.repeater-identify.label = Identificer +channel-type.hdpowerview.repeater-identify.description = Identificer ved at lade repeater blinke +channel-type.hdpowerview.repeater-identify.command.option.IDENTIFY = Identificer + # dynamic channels dynamic-channel.scene-activate.description = Aktiverer scenen ''{0}'' diff --git a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml index 595392183ac75..2a33e90d458ba 100644 --- a/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.hdpowerview/src/main/resources/OH-INF/thing/thing-types.xml @@ -75,13 +75,40 @@ id - + The numeric ID of the PowerView Shade in the Hub + + + + + + Hunter Douglas (Luxaflex) PowerView Repeater + + + + + + + + Hunter Douglas (Luxaflex) + PowerView Repeater + + + id + + + + + The numeric ID of the PowerView Repeater in the Hub + + + + Rollershutter @@ -122,6 +149,23 @@ + + String + + Flash repeater to identify + + + + + + + + + Switch + + Blink during commands + +