[velux] Add an action to simultaneously set main and vane positions (#13199)

* [velux] add moveMainAndVane action
* [velux] add claridications to read me
* [velux] refactor actions and translate
* [velux] fix thing lookup

Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
Andrew Fiddian-Green 2022-08-15 11:36:25 +01:00 committed by GitHub
parent bb3be91981
commit 41fcdd6c71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 223 additions and 81 deletions

View File

@ -14,6 +14,19 @@ For details about the features, see the following websites:
- [Velux](https://www.velux.com) - [Velux](https://www.velux.com)
- [Velux API](https://www.velux.com/api/klf200) - [Velux API](https://www.velux.com/api/klf200)
## Initial Configuration of Devices in the Hub
This guide assumes that you have already configured your devices in the KLF200 hub.
When the KLF200 hub is started it provides a temporary private Wi-Fi Access Point to facilitate this configuration.
The Velux leaflet B) explains how to access the configuration web page via this temporary private Wi-Fi Access Point and configure your devices.
Note: ending the configuration process prematurely might lead to misconfiguration and require factory resetting your hub and/or devices.
If you want to add devices to the hub later, you have to access the configuration web page via the temporary private Wi-Fi Access Point once more.
See the chapter "FAQ and Troubleshooting" below if you have any problems setting up the connection to openHAB again afterwards.
Note: if any device connects to the temporary private Wi-Fi Access Point, it disables the normal LAN connection, thus preventing the binding from connecting.
So make sure this Wi-Fi AP is not permanently running (the default setting is that the AP will turn off after some time).
## Supported Things ## Supported Things
The binding supports the following types of Thing. The binding supports the following types of Thing.
@ -38,10 +51,6 @@ The binding will automatically discover Velux Bridges within the local network,
Once a Velux Bridge has been discovered, you will need to enter the `password` Configuration Parameter (see below) before the binding can communicate with it. Once a Velux Bridge has been discovered, you will need to enter the `password` Configuration Parameter (see below) before the binding can communicate with it.
And once the Velux Bridge is fully configured, the binding will automatically discover all its respective scenes and actuators (like windows and rollershutters), and place them in the Inbox. And once the Velux Bridge is fully configured, the binding will automatically discover all its respective scenes and actuators (like windows and rollershutters), and place them in the Inbox.
Note: When the KLF200 hub is started it provides a temporary private Wi-Fi Access Point for initial configuration.
And if any device connects to this AP, it disables the normal LAN connection, thus preventing the binding from connecting.
So make sure this AP is not permanently on (the default setting is that the AP will turn off after some time).
## Thing Configuration ## Thing Configuration
### Thing Configuration for "bridge" ### Thing Configuration for "bridge"
@ -172,8 +181,6 @@ The supported Channels and their associated channel types are shown below.
The `position`, `limitMinimum`, and `limitMaximum` are the same as described above for "window" Things. The `position`, `limitMinimum`, and `limitMaximum` are the same as described above for "window" Things.
The `vanePosition` Channel only applies to Venetian blinds that have tiltable slats. The `vanePosition` Channel only applies to Venetian blinds that have tiltable slats.
It can only have a valid position value if the main `position` of the Thing is fully down.
So, if `vanePosition` is commanded to a new value, this will automatically cause the main `position` to move to the fully down position.
### Channels for "actuator" Things ### Channels for "actuator" Things
@ -276,6 +283,42 @@ Frame label="Velux Windows" {
See [velux.sitemap](doc/conf/sitemaps/velux.sitemap) for more examples. See [velux.sitemap](doc/conf/sitemaps/velux.sitemap) for more examples.
### Rule for simultaneously moving the main position and the vane position
This applies to shades or shutters that have both a main position and a vane / tilt position.
On such shades if one sends a vane position command followed shortly by a main position command (or vice versa) the second command will cause the first command to stop.
This problem is most problematic when the two commands are issued simultaneously by a single rule.
In order to solve this problem, there is a rule action to simultaneously set the main position and the vane position.
_Warning: use this command carefully..._
The action is a command method that is called from within a rule.
The method is called with the following syntax `moveMainAndVane(thingName, mainPercent, vanePercent)`.
The meaning of the arguments is described in the table below.
The method returns a `Boolean` whose meaning is also described in the table below.
| Argument | Type | Example | Description |
|-------------|---------|-------------------------------------|-----------------------------------------------------------------------------------------|
| thingName | String | "velux:rollershutter:hubid:thingid" | The thing name of the shutter. Must be a valid configured thing in the hub. |
| mainPercent | Integer | 75 | The target main position in percent. Integer between 0 and 100. |
| vanePercent | Integer | 25 | The target vane position in percent. Integer between 0 and 100. |
| return | Boolean | `true` | Is `true` if the command was sent sucessfully or `false` if any arguments were invalid. |
Example:
```java
rule "Simultaneously Move Main and Vane Positions"
when
...
then
// note: "velux:klf200:hubid" shall be the thing name of your KLF 200 hub
val veluxActions = getActions("velux", "velux:klf200:hubid")
if (veluxActions !== null) {
val succeeded = veluxActions.moveMainAndVane("velux:rollershutter:hubid:thingid", 75, 25)
}
end
```
### Rule for closing windows after a period of time ### Rule for closing windows after a period of time
Especially in the colder months, it is advisable to close the window after adequate ventilation. Especially in the colder months, it is advisable to close the window after adequate ventilation.
@ -480,11 +523,15 @@ Notes:
- Velux bridges cannot be returned to version one of the firmware after being upgraded to version two. - Velux bridges cannot be returned to version one of the firmware after being upgraded to version two.
## Is it possible to run the both communication methods in parallel? ## FAQ and troubleshooting
For environments with the firmware version 0.1.* on the gateway, the interaction with the bridge is limited to the HTTP/JSON based communication, of course. On the other hand, after upgrading the gateway firmware to version 2, it is possible to run the binding either using HTTP/JSON if there is a permanent connectivity towards the WLAN interface of the KLF200 or using SLIP towards the LAN interface of the gateway. For example the Raspberry PI can directly be connected via WLAN to the Velux gateway and providing the other services via the LAN interface (but not vice versa). ### Is it possible to run the both communication methods in parallel?
## Known Limitations For environments with the firmware version 0.1.* on the gateway, the interaction with the bridge is limited to the HTTP/JSON based communication, of course.
On the other hand, after upgrading the gateway firmware to version 2, it is possible to run the binding either using HTTP/JSON if there is a permanent connectivity towards the WLAN interface of the KLF200 or using SLIP towards the LAN interface of the gateway.
For example the Raspberry PI can directly be connected via WLAN to the Velux gateway and providing the other services via the LAN interface (but not vice versa).
### Known Limitations
The communication based on HTTP/JSON is limited to one connection: If the binding is operational, you won't get access to the Web Frontend in parallel. The communication based on HTTP/JSON is limited to one connection: If the binding is operational, you won't get access to the Web Frontend in parallel.
@ -493,7 +540,15 @@ The SLIP communication is limited to two connections in parallel, i.e. two diffe
Both interfacing methods, HTTP/JSON and SLIP, can be run in parallel. Both interfacing methods, HTTP/JSON and SLIP, can be run in parallel.
Therefore, on the one hand you can use the Web Frontend for manual control and on the other hand a binding can do all automatic jobs. Therefore, on the one hand you can use the Web Frontend for manual control and on the other hand a binding can do all automatic jobs.
## Unknown Velux devices ### Login sequence fails and Connection Refused
If you get this error first make sure that you entered the right password (the one below SSID on the back of the hub).
If the error persists, it may be due to the temporary Wi-Fi Access Point blocking the LAN (as described above).
To recover from this, first disable the bridge in the UI, disconnect the LAN cable, power cycle your KLF200 and wait a few minutes.
Then reconnect the LAN cable and re-enable the bridge in the UI again.
DO NOT try to connect anything to the temporary Wi-Fi Access Point during this process!!
### Unknown Velux devices
All known <B>Velux</B> devices can be handled by this binding. All known <B>Velux</B> devices can be handled by this binding.
However, there might be some new ones which will be reported within the logfiles. However, there might be some new ones which will be reported within the logfiles.

View File

@ -1,43 +0,0 @@
/**
* 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.velux.internal.action;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link IVeluxActions} defines rule action interface for rebooting the bridge
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public interface IVeluxActions {
/**
* Action to send a reboot command to a Velux Bridge
*
* @return true if the command was sent
* @throws IllegalStateException if something is wrong
*/
Boolean rebootBridge() throws IllegalStateException;
/**
* Action to send a relative move command to a Velux actuator
*
* @param nodeId the node Id in the bridge
* @param relativePercent the target position relative to its current position (-100% <= relativePercent <= +100%)
* @return true if the command was sent
* @throws NumberFormatException if either of the arguments is not an integer, or out of range
* @throws IllegalStateException if anything else is wrong
*/
Boolean moveRelative(String nodeId, String relativePercent) throws NumberFormatException, IllegalStateException;
}

View File

@ -15,9 +15,11 @@ package org.openhab.binding.velux.internal.action;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler; import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler;
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
import org.openhab.core.automation.annotation.ActionInput; import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.ActionOutput; import org.openhab.core.automation.annotation.ActionOutput;
import org.openhab.core.automation.annotation.RuleAction; import org.openhab.core.automation.annotation.RuleAction;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.thing.binding.ThingActions; import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.binding.ThingActionsScope; import org.openhab.core.thing.binding.ThingActionsScope;
import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandler;
@ -31,7 +33,7 @@ import org.slf4j.LoggerFactory;
*/ */
@ThingActionsScope(name = "velux") @ThingActionsScope(name = "velux")
@NonNullByDefault @NonNullByDefault
public class VeluxActions implements ThingActions, IVeluxActions { public class VeluxActions implements ThingActions {
private final Logger logger = LoggerFactory.getLogger(VeluxActions.class); private final Logger logger = LoggerFactory.getLogger(VeluxActions.class);
@ -49,38 +51,42 @@ public class VeluxActions implements ThingActions, IVeluxActions {
return this.bridgeHandler; return this.bridgeHandler;
} }
@Override @RuleAction(label = "@text/action.reboot.label", description = "@text/action.reboot.descr")
@RuleAction(label = "reboot Bridge", description = "issues a reboot command to the KLF200 bridge") public @ActionOutput(name = "running", type = "java.lang.Boolean", label = "@text/action.run.label", description = "@text/action.run.descr") Boolean rebootBridge()
public @ActionOutput(name = "executing", type = "java.lang.Boolean", label = "executing", description = "indicates the command was issued") Boolean rebootBridge()
throws IllegalStateException { throws IllegalStateException {
logger.trace("rebootBridge(): action called"); logger.trace("rebootBridge(): action called");
VeluxBridgeHandler bridge = bridgeHandler; VeluxBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridge == null) { if (bridgeHandler == null) {
throw new IllegalStateException("Bridge instance is null"); throw new IllegalStateException("Bridge instance is null");
} }
return bridge.runReboot(); return bridgeHandler.rebootBridge();
} }
@Override @RuleAction(label = "@text/action.moveRelative.label", description = "@text/action.moveRelative.descr")
@RuleAction(label = "move relative", description = "issues a relative move command to an actuator") public @ActionOutput(name = "running", type = "java.lang.Boolean", label = "@text/action.run.label", description = "@text/action.run.descr") Boolean moveRelative(
public @ActionOutput(name = "executing", type = "java.lang.Boolean", label = "executing", description = "indicates the command was issued") Boolean moveRelative( @ActionInput(name = "nodeId", label = "@text/action.node.label", description = "@text/action.node.descr") @Nullable String nodeId,
@ActionInput(name = "nodeId", required = true, label = "nodeId", description = "actuator id in the bridge", type = "java.lang.String") String nodeId, @ActionInput(name = "relativePercent", label = "@text/action.relative.label", description = "@text/action.relative.descr") @Nullable String relativePercent)
@ActionInput(name = "relativePercent", required = true, label = "relativePercent", description = "position delta from current", type = "java.lang.String") String relativePercent) throws NumberFormatException, IllegalStateException, IllegalArgumentException {
throws NumberFormatException, IllegalStateException {
logger.trace("moveRelative(): action called"); logger.trace("moveRelative(): action called");
VeluxBridgeHandler bridge = bridgeHandler; VeluxBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridge == null) { if (bridgeHandler == null) {
throw new IllegalStateException("Bridge instance is null"); throw new IllegalStateException("Bridge instance is null");
} }
if (nodeId == null) {
throw new IllegalArgumentException("Node Id is null");
}
int node = Integer.parseInt(nodeId); int node = Integer.parseInt(nodeId);
if (node < 0 || node > 200) { if (node < 0 || node > 200) {
throw new NumberFormatException("Node Id out of range"); throw new NumberFormatException("Node Id out of range");
} }
if (relativePercent == null) {
throw new IllegalArgumentException("Relative Percent is null");
}
int relPct = Integer.parseInt(relativePercent); int relPct = Integer.parseInt(relativePercent);
if (Math.abs(relPct) > 100) { if (Math.abs(relPct) > 100) {
throw new NumberFormatException("Relative Percent out of range"); throw new NumberFormatException("Relative Percent out of range");
} }
return bridge.moveRelative(node, relPct); return bridgeHandler.moveRelative(node, relPct);
} }
/** /**
@ -93,10 +99,10 @@ public class VeluxActions implements ThingActions, IVeluxActions {
*/ */
public static Boolean rebootBridge(@Nullable ThingActions actions) public static Boolean rebootBridge(@Nullable ThingActions actions)
throws IllegalArgumentException, IllegalStateException { throws IllegalArgumentException, IllegalStateException {
if (!(actions instanceof IVeluxActions)) { if (!(actions instanceof VeluxActions)) {
throw new IllegalArgumentException("Unsupported action"); throw new IllegalArgumentException("Unsupported action");
} }
return ((IVeluxActions) actions).rebootBridge(); return ((VeluxActions) actions).rebootBridge();
} }
/** /**
@ -107,14 +113,67 @@ public class VeluxActions implements ThingActions, IVeluxActions {
* @param relativePercent the target position relative to its current position (-100% <= relativePercent <= +100%) * @param relativePercent the target position relative to its current position (-100% <= relativePercent <= +100%)
* @return true if the command was sent * @return true if the command was sent
* @throws IllegalArgumentException if actions is invalid * @throws IllegalArgumentException if actions is invalid
* @throws NumberFormatException if either of nodeId or relativePercent is not an integer, or out of range
* @throws IllegalStateException if anything else is wrong * @throws IllegalStateException if anything else is wrong
* @throws NumberFormatException if either of nodeId or relativePercent is not an integer, or out of range
*/ */
public static Boolean moveRelative(@Nullable ThingActions actions, String nodeId, String relativePercent) public static Boolean moveRelative(@Nullable ThingActions actions, @Nullable String nodeId,
@Nullable String relativePercent)
throws IllegalArgumentException, NumberFormatException, IllegalStateException { throws IllegalArgumentException, NumberFormatException, IllegalStateException {
if (!(actions instanceof IVeluxActions)) { if (!(actions instanceof VeluxActions)) {
throw new IllegalArgumentException("Unsupported action"); throw new IllegalArgumentException("Unsupported action");
} }
return ((IVeluxActions) actions).moveRelative(nodeId, relativePercent); return ((VeluxActions) actions).moveRelative(nodeId, relativePercent);
}
@RuleAction(label = "@text/action.moveMainAndVane.label", description = "@text/action.moveMainAndVane.descr")
public @ActionOutput(name = "running", type = "java.lang.Boolean", label = "@text/action.run.label", description = "@text/action.run.descr") Boolean moveMainAndVane(
@ActionInput(name = "thingName", label = "@text/action.thing.label", description = "@text/action.thing.descr") @Nullable String thingName,
@ActionInput(name = "mainPercent", label = "@text/action.main.label", description = "@text/action.main.descr") @Nullable Integer mainPercent,
@ActionInput(name = "vanePercent", label = "@text/action.vane.label", description = "@text/action.vane.descr") @Nullable Integer vanePercent)
throws NumberFormatException, IllegalArgumentException, IllegalStateException {
logger.trace("moveMainAndVane(thingName:'{}', mainPercent:{}, vanePercent:{}) action called", thingName,
mainPercent, vanePercent);
VeluxBridgeHandler bridgeHandler = this.bridgeHandler;
if (bridgeHandler == null) {
throw new IllegalStateException("Bridge instance is null");
}
if (thingName == null) {
throw new IllegalArgumentException("Thing name is null");
}
ProductBridgeIndex node = bridgeHandler.getProductBridgeIndex(thingName);
if (ProductBridgeIndex.UNKNOWN.equals(node)) {
throw new IllegalArgumentException("Bridge does not contain a thing with name " + thingName);
}
if (mainPercent == null) {
throw new IllegalArgumentException("Main perent is null");
}
PercentType mainPercentType = new PercentType(mainPercent);
if (vanePercent == null) {
throw new IllegalArgumentException("Vane perent is null");
}
PercentType vanePercenType = new PercentType(vanePercent);
return bridgeHandler.moveMainAndVane(node, mainPercentType, vanePercenType);
}
/**
* Action to simultaneously move the shade main position and vane positions.
*
*
* @param actions ThingActions from the caller
* @param thingName the name of the thing to be moved (e.g. 'velux:rollershutter:hubid:thingid')
* @param mainPercent the desired main position (range 0..100)
* @param vanePercent the desired vane position (range 0..100)
* @return true if the command was sent
* @throws NumberFormatException if any of the arguments are not an integer
* @throws IllegalArgumentException if any of the arguments are invalid
* @throws IllegalStateException if anything else is wrong
*/
public static Boolean moveMainAndVane(@Nullable ThingActions actions, @Nullable String thingName,
@Nullable Integer mainPercent, @Nullable Integer vanePercent)
throws NumberFormatException, IllegalArgumentException, IllegalStateException {
if (!(actions instanceof VeluxActions)) {
throw new IllegalArgumentException("Unsupported action");
}
return ((VeluxActions) actions).moveMainAndVane(thingName, mainPercent, vanePercent);
} }
} }

View File

@ -13,8 +13,9 @@
package org.openhab.binding.velux.internal.handler; package org.openhab.binding.velux.internal.handler;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -43,6 +44,7 @@ import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProto
import org.openhab.binding.velux.internal.bridge.common.RunProductCommand; import org.openhab.binding.velux.internal.bridge.common.RunProductCommand;
import org.openhab.binding.velux.internal.bridge.common.RunReboot; import org.openhab.binding.velux.internal.bridge.common.RunReboot;
import org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge; import org.openhab.binding.velux.internal.bridge.json.JsonVeluxBridge;
import org.openhab.binding.velux.internal.bridge.slip.FunctionalParameters;
import org.openhab.binding.velux.internal.bridge.slip.SlipVeluxBridge; import org.openhab.binding.velux.internal.bridge.slip.SlipVeluxBridge;
import org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration; import org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration;
import org.openhab.binding.velux.internal.development.Threads; import org.openhab.binding.velux.internal.development.Threads;
@ -143,14 +145,14 @@ public class VeluxBridgeHandler extends ExtendedBaseBridgeHandler implements Vel
* ***** Default visibility Objects ***** * ***** Default visibility Objects *****
*/ */
VeluxBridge thisBridge = myJsonBridge; public VeluxBridge thisBridge = myJsonBridge;
public BridgeParameters bridgeParameters = new BridgeParameters(); public BridgeParameters bridgeParameters = new BridgeParameters();
Localization localization; public Localization localization;
/** /**
* Mapping from ChannelUID to class Thing2VeluxActuator, which return Velux device information, probably cached. * Mapping from ChannelUID to class Thing2VeluxActuator, which return Velux device information, probably cached.
*/ */
Map<ChannelUID, Thing2VeluxActuator> channel2VeluxActuator = new ConcurrentHashMap<>(); public final Map<ChannelUID, Thing2VeluxActuator> channel2VeluxActuator = new ConcurrentHashMap<>();
/** /**
* Information retrieved by {@link VeluxBinding#VeluxBinding}. * Information retrieved by {@link VeluxBinding#VeluxBinding}.
@ -819,7 +821,7 @@ public class VeluxBridgeHandler extends ExtendedBaseBridgeHandler implements Vel
*/ */
@Override @Override
public Collection<Class<? extends ThingHandlerService>> getServices() { public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singletonList(VeluxActions.class); return Set.of(VeluxActions.class);
} }
/** /**
@ -827,7 +829,7 @@ public class VeluxBridgeHandler extends ExtendedBaseBridgeHandler implements Vel
* *
* @return true if the command could be issued * @return true if the command could be issued
*/ */
public boolean runReboot() { public boolean rebootBridge() {
logger.trace("runReboot() called on {}", getThing().getUID()); logger.trace("runReboot() called on {}", getThing().getUID());
RunReboot bcp = thisBridge.bridgeAPI().runReboot(); RunReboot bcp = thisBridge.bridgeAPI().runReboot();
if (bcp != null) { if (bcp != null) {
@ -907,4 +909,52 @@ public class VeluxBridgeHandler extends ExtendedBaseBridgeHandler implements Vel
public boolean isDisposing() { public boolean isDisposing() {
return disposing; return disposing;
} }
/**
* Exported method (called by an OpenHAB Rules Action) to simultaneously move the shade main position and the vane
* position.
*
* @param node the node index in the bridge.
* @param mainPosition the desired main position.
* @param vanePosition the desired vane position.
* @return true if the command could be issued.
*/
public Boolean moveMainAndVane(ProductBridgeIndex node, PercentType mainPosition, PercentType vanePosition) {
logger.trace("moveMainAndVane() called on {}", getThing().getUID());
RunProductCommand bcp = thisBridge.bridgeAPI().runProductCommand();
if (bcp != null) {
VeluxProduct product = existingProducts().get(node).clone();
FunctionalParameters functionalParameters = null;
if (product.supportsVanePosition()) {
int vanePos = new VeluxProductPosition(vanePosition).getPositionAsVeluxType();
product.setVanePosition(vanePos);
functionalParameters = product.getFunctionalParameters();
}
VeluxProductPosition mainPos = new VeluxProductPosition(mainPosition);
bcp.setNodeIdAndParameters(node.toInt(), mainPos, functionalParameters);
submitCommunicationsJob(() -> {
if (thisBridge.bridgeCommunicate(bcp)) {
logger.trace("moveMainAndVane() command {}sucessfully sent to {}",
bcp.isCommunicationSuccessful() ? "" : "un", getThing().getUID());
}
});
return true;
}
return false;
}
/**
* Get the bridge product index for a given thing name.
*
* @param thingName the thing name
* @return the bridge product index or ProductBridgeIndex.UNKNOWN if not found.
*/
public ProductBridgeIndex getProductBridgeIndex(String thingName) {
for (Entry<ChannelUID, Thing2VeluxActuator> entry : channel2VeluxActuator.entrySet()) {
if (thingName.equals(entry.getKey().getThingUID().getAsString())) {
return entry.getValue().getProductBridgeIndex();
}
}
return ProductBridgeIndex.UNKNOWN;
}
} }

View File

@ -162,3 +162,24 @@ runtime.bridge-offline-login-sequence-failed = Login sequence failed.
# #
channelValue.check-integrity-failed = Integrity check failed: The following scenes are unused: channelValue.check-integrity-failed = Integrity check failed: The following scenes are unused:
channelValue.check-integrity-ok = Integrity check ok. All scenes are used within Items. channelValue.check-integrity-ok = Integrity check ok. All scenes are used within Items.
#
# Actions
#
action.reboot.label = Reboot Bridge
action.reboot.descr = Issues a reboot command to the KLF200 bridge
action.moveRelative.label = Move Relative
action.moveRelative.descr = Issues a relative move command to an actuator
action.moveMainAndVane.label = Move main and vane position simultaneously
action.moveMainAndVane.descr = Issues a simultaneous command to move both the main position and the vane position of a shade
action.run.label = Executing
action.run.descr = Indicates the command was issued
action.node.label = Node Id
action.node.descr = Actuator Id in the bridge
action.relative.label = Relative Percent
action.relative.descr = Position delta from current
action.thing.label = Thing Name
action.thing.descr = UID of the actuator thing to be moved
action.main.label = Main Percent
action.main.descr = Position percentage to move to
action.vane.label = Vane Percent
action.vane.descr = Vane position percentage to move to