Skip to content

Commit

Permalink
[nikobus] added option to reverse rollershutter commands (#10047)
Browse files Browse the repository at this point in the history
* Added option to reverse rollershutter commands - UP -> DOWN and DOWN -> UP - might happen if rollershuter module's output is wired differently.

* Fixed PR comments.

Signed-off-by: Boris Krivonog <[email protected]>
  • Loading branch information
crnjan authored Feb 4, 2021
1 parent 0d13b8d commit 6878384
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 19 deletions.
2 changes: 2 additions & 0 deletions bundles/org.openhab.binding.nikobus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ Defines a `rollershutter-module` with address `4C6C`.
| output-5 | Rollershutter | Output 5 |
| output-6 | Rollershutter | Output 6 |

In case rollershutters are moving in the oposite direction when sending `UP` or `DOWN` commands, there is a `reverse` parameter, which can be set to `true` in this case to reverse the rollershutter's direction. Defaults to `false`.

##### Estimating Position

Nikobus rollershuter module does not provide information about rollershutter's position. In order to bridge this gap, an optional parameter `duration` can be set per channel, describing the amount of time needed by a rollershutter to get from open to closed state (or vice-versa).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,16 @@ public void requestStatus(SwitchModuleGroup group) {
}

@Override
protected int valueFromCommand(Command command) {
protected int valueFromCommand(String channelId, Command command) {
if (command instanceof PercentType) {
return Math.round(((PercentType) command).floatValue() / 100f * 255f);
}

return super.valueFromCommand(command);
return super.valueFromCommand(channelId, command);
}

@Override
protected State stateFromValue(int value) {
protected State stateFromValue(String channelId, int value) {
int result = Math.round(value * 100f / 255f);
return new PercentType(result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private void updateStateAndCacheValue(String channelId, int value) {
}

if (previousValue == null || previousValue.intValue() != value) {
updateState(channelId, stateFromValue(value));
updateState(channelId, stateFromValue(channelId, value));
}
}

Expand All @@ -195,7 +195,7 @@ private void processWrite(ChannelUID channelUID, Command command) {
Integer digits;

if (channelId.equals(channelUID.getId())) {
digits = valueFromCommand(command);
digits = valueFromCommand(channelId, command);
updateStateAndCacheValue(channelId, digits.intValue());
} else {
synchronized (cachedStates) {
Expand Down Expand Up @@ -233,7 +233,7 @@ private void processWriteCommandResponse(NikobusCommand.Result result) {
}
}

protected abstract int valueFromCommand(Command command);
protected abstract int valueFromCommand(String channelId, Command command);

protected abstract State stateFromValue(int value);
protected abstract State stateFromValue(String channelId, int value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
package org.openhab.binding.nikobus.internal.handler;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -44,6 +46,8 @@ public class NikobusRollershutterModuleHandler extends NikobusModuleHandler {
private final Logger logger = LoggerFactory.getLogger(NikobusRollershutterModuleHandler.class);
private final List<PositionEstimator> positionEstimators = new CopyOnWriteArrayList<>();

private final Map<String, DirectionConfiguration> directionConfigurations = new ConcurrentHashMap<>();

public NikobusRollershutterModuleHandler(Thing thing) {
super(thing);
}
Expand All @@ -57,43 +61,50 @@ public void initialize() {
}

positionEstimators.clear();
directionConfigurations.clear();

for (Channel channel : thing.getChannels()) {
PositionEstimatorConfig config = channel.getConfiguration().as(PositionEstimatorConfig.class);
if (config.delay >= 0 && config.duration > 0) {
positionEstimators.add(new PositionEstimator(channel.getUID(), config));
}

DirectionConfiguration configuration = config.reverse ? DirectionConfiguration.REVERSED
: DirectionConfiguration.NORMAL;
directionConfigurations.put(channel.getUID().getId(), configuration);
}

logger.debug("Position estimators for {} = {}", thing.getUID(), positionEstimators);
}

@Override
protected int valueFromCommand(Command command) {
protected int valueFromCommand(String channelId, Command command) {
if (command == StopMoveType.STOP) {
return 0x00;
}
if (command == UpDownType.DOWN || command == StopMoveType.MOVE) {
return 0x02;
return getDirectionConfiguration(channelId).down;
}
if (command == UpDownType.UP) {
return 0x01;
return getDirectionConfiguration(channelId).up;
}
if (command == StopMoveType.STOP) {
return 0x00;
}

throw new IllegalArgumentException("Command '" + command + "' not supported");
}

@Override
protected State stateFromValue(int value) {
protected State stateFromValue(String channelId, int value) {
if (value == 0x00) {
return OnOffType.OFF;
}
if (value == 0x01) {

DirectionConfiguration configuration = getDirectionConfiguration(channelId);
if (value == configuration.up) {
return UpDownType.UP;
}
if (value == 0x02) {
if (value == configuration.down) {
return UpDownType.DOWN;
}

throw new IllegalArgumentException("Unexpected value " + value + " received");
}

Expand All @@ -119,9 +130,18 @@ private void updateState(ChannelUID channelUID, int percent) {
super.updateState(channelUID, new PercentType(percent));
}

private DirectionConfiguration getDirectionConfiguration(String channelId) {
DirectionConfiguration configuration = directionConfigurations.get(channelId);
if (configuration == null) {
throw new IllegalArgumentException("Direction configuration not found for " + channelId);
}
return configuration;
}

public static class PositionEstimatorConfig {
public int duration = -1;
public int delay = 5;
public boolean reverse = false;
}

private class PositionEstimator {
Expand Down Expand Up @@ -203,4 +223,17 @@ public String toString() {
+ delayInMillis + "ms)";
}
}

private static class DirectionConfiguration {
final int up;
final int down;

final static DirectionConfiguration NORMAL = new DirectionConfiguration(1, 2);
final static DirectionConfiguration REVERSED = new DirectionConfiguration(2, 1);

private DirectionConfiguration(int up, int down) {
this.up = up;
this.down = down;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public NikobusSwitchModuleHandler(Thing thing) {
}

@Override
protected int valueFromCommand(Command command) {
protected int valueFromCommand(String channelId, Command command) {
if (command == OnOffType.ON) {
return 0xff;
}
Expand All @@ -43,7 +43,7 @@ protected int valueFromCommand(Command command) {
}

@Override
protected State stateFromValue(int value) {
protected State stateFromValue(String channelId, int value) {
return value != 0 ? OnOffType.ON : OnOffType.OFF;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
<label>Delay</label>
<description>Delay specifying how many seconds after duration module's output is set to OFF. Defaults to 5 seconds</description>
</parameter>
<parameter name="reverse" type="boolean">
<label>Reverse Direction</label>
<description>Reverse direction of rollershutters. Defaults to false</description>
</parameter>
</config-description>

</config-description:config-descriptions>

0 comments on commit 6878384

Please sign in to comment.