Skip to content

Commit

Permalink
[velbus] Add new functionality PRESSED and LONG PRESSED (openhab#10664)
Browse files Browse the repository at this point in the history
* [velbus] Add new functionality PRESSED and LONG PRESSED and fix bug

New functionality:
Add the the possibility to simulate the PRESSED and LONG PRESSED message of an input.

Module supported with button simulation :
VMB1RYS (button : CH6)
VMB6IN (buttons : CH1 ... CH6)
VMB2PBN, VMB6PBN, VMB7IN, VMB8IR, VMB8PB, VMB8PBU, VMBEL1, VMBEL2, VMBEL4, VMBGP1, VMBGP1-2, VMBGP2, VMBGP2-2, VMBGP4, VMBGP4-2, VMBGP4PIR, VMBGP4PIR-2 (buttons : CH1 ... CH8)
VMBELO, VMBGPOD, VMBGPOD-2 (buttons : CH1 ... CH32)

Fix bug:
The channels names were not correctly assigned to the thing properties. The last channel had the default name, not the one retrieved from the module.

Also-by: cedricboon <cedric.boon@hotmail.com>
Signed-off-by: Daniel Rosengarten <github@praetorians.be>
  • Loading branch information
Rosen01 authored May 29, 2021
1 parent d175de7 commit 55c0a10
Show file tree
Hide file tree
Showing 9 changed files with 362 additions and 13 deletions.
32 changes: 28 additions & 4 deletions bundles/org.openhab.binding.velbus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,18 +152,30 @@ OnOff command types are supported.
For thing type `vmb4ry` 4 channels are available `CH1` ... `CH4`.
OnOff command types are supported.

For thing types `vmb1ryno`, `vmb1rynos`, `vmb1rys`, `vmb4ryld` and `vmb4ryno` 5 channels are available `CH1` ... `CH5`.
For thing types `vmb1ryno`, `vmb1rynos`, `vmb4ryld` and `vmb4ryno` 5 channels are available `CH1` ... `CH5`.
OnOff command types are supported.

For thing types `vmb1rys` 6 channels are available `CH1` ... `CH6`.
OnOff command types are supported on channels `CH1` ... `CH5`.
Pressed and Long_Pressed command types are supported on channel `CH6`.
1 trigger channel on `CH6t`.

The module `vmb1ts` has a number of channels to set the module's thermostat (`thermostat:currentTemperatureSetpoint`, `thermostat:heatingModeComfortTemperatureSetpoint`, `thermostat:heatingModeDayTemperatureSetpoint`, `thermostat:heatingModeNightTemperatureSetpoint`, `thermostat:heatingModeAntiFrostTemperatureSetpoint`, `thermostat:coolingModeComfortTemperatureSetpoint`, `thermostat:coolingModeDayTemperatureSetpoint`, `thermostat:coolingModeNightTemperatureSetpoint`, `thermostat:coolingModeSafeTemperatureSetpoint`, `operatingMode` and `thermostat:mode`) and thermostat trigger channels: `thermostat:heater`, `thermostat:boost`, `thermostat:pump`, `thermostat:cooler`, `thermostat:alarm1`, `thermostat:alarm2`, `thermostat:alarm3`, `thermostat:alarm4`.

For thing types `vmb2bl` and `vmb2ble` the supported channels are `CH1` and `CH2`. UpDown, StopMove and Percent command types are supported.

Thing type `vmb6in` has 6 trigger channels `input#CH1` ... `input#CH6`.
For thing type `vmb6in` 6 channels are available `CH1` ... `CH6`.
Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH6`.
6 trigger channels on channels `input#CH1` ... `input#CH6`.

For thing type `vmb7in` 8 channels are available `CH1` ... `CH8`.
Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH8`.
8 trigger channels on channels `input#CH1` ... `input#CH8`.

Thing type `vmb7in` has 8 trigger channels `input#CH1` ... `input#CH8`.
For thing types `vmb2pbn`, `vmb6pbn`, `vmb7in`, `vmb8ir`, `vmb8pb`, `vmb8pbu`, `vmbrfr8s` and `vmbvp1` 8 channels are available `CH1` ... `CH8`.
Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH8`.
8 trigger channels on channels `input:CH1` ... `input:CH8`.

Thing types `vmb2pbn`, `vmb6pbn`, `vmb7in`, `vmb8ir`, `vmb8pb`, `vmb8pbu`, `vmbrfr8s` and `vmbvp1` have 8 trigger channels (`input:CH1` ... `input:CH8`).
Thing types `vmb2pbn`, `vmb6pbn`, `vmb7in`, `vmb8pb`, `vmb8pbu`, `vmbrfr8s` and `vmbvp1` also have and 2 channels to steer the button LED feedback (`feedback:CH1` and `feedback:CH2`).
Additionally, the modules `vmb2pbn`, `vmb6pbn`, `vmb7in`, `vmb8pbu`, `vmbrfr8s` and `vmbvp1` have a number of channels to set the module's alarms: `clockAlarm:clockAlarm1Enabled`, `clockAlarm:clockAlarm1Type`, `clockAlarm:clockAlarm1WakeupHour`, `clockAlarm:clockAlarm1WakeupMinute`, `clockAlarm:clockAlarm1BedtimeHour`, `clockAlarm:clockAlarm1BedtimeMinute`, `clockAlarm:clockAlarm2Enabled`, `clockAlarm:clockAlarm2Type`, `clockAlarm:clockAlarm2WakeupHour`, `clockAlarm:clockAlarm2WakeupMinute`, `clockAlarm:clockAlarm2BedtimeHour` and `clockAlarm:clockAlarm2BedtimeMinute`.

Expand All @@ -181,6 +193,7 @@ For thing type `vmb4ry` 4 channels are available `CH1` ... `CH4`.
OnOff command types are supported.

Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbgp1`, `vmbgp2`, `vmbgp4`, `vmbgp4pir` and `vmbpiro` have 8 trigger channels `input:CH1` ... `input:CH8` and one temperature channel `input:CH9`.
Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH8`.
The thing types `vmbel1` and `vmbgp1` have one channel to steer the button LED feedback `feedback:CH1`.
The thing types `vmbel2` and `vmbgp2` have two channels to steer the button LED feedback `feedback:CH1` and `feedback:CH2`.
The thing types `vmbel4`, `vmbgp4` and `vmbgp4pir` have four channels to steer the button LED feedback `feedback:CH1` ... `feedback:CH4`.
Expand All @@ -189,6 +202,7 @@ Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbgp1`, `vmbgp2`, `vmbgp4` and `vmbg
Thing types `vmbel1`, `vmbel2`, `vmbel4`, `vmbgp1`, `vmbgp2`, `vmbgp4` and `vmbgp4pir` also have a number of channels to set the module's thermostat (`thermostat:currentTemperatureSetpoint`, `thermostat:heatingModeComfortTemperatureSetpoint`, `thermostat:heatingModeDayTemperatureSetpoint`, `thermostat:heatingModeNightTemperatureSetpoint`, `thermostat:heatingModeAntiFrostTemperatureSetpoint`, `thermostat:coolingModeComfortTemperatureSetpoint`, `thermostat:coolingModeDayTemperatureSetpoint`, `thermostat:coolingModeNightTemperatureSetpoint`, `thermostat:coolingModeSafeTemperatureSetpoint`, `operatingMode` and `thermostat:mode`) and thermostat trigger channels: `thermostat:heater`, `thermostat:boost`, `thermostat:pump`, `thermostat:cooler`, `thermostat:alarm1`, `thermostat:alarm2`, `thermostat:alarm3`, `thermostat:alarm4`.

Thing types `vmbelo`, `vmbgpo` and `vmbgpod` have 32 trigger channels `input:CH1` ... `input:CH32` and one temperature channel `input:CH33`.
Pressed and Long_Pressed command types are supported on channels `button#CH1` ... `button#CH32`.
They have have 32 channels to steer the button LED feedback `feedback:CH1` ... `feedback:CH32`.
They have a number of channels to set the module's alarms: `clockAlarm:clockAlarm1Enabled`, `clockAlarm:clockAlarm1Type`, `clockAlarm:clockAlarm1WakeupHour`, `clockAlarm:clockAlarm1WakeupMinute`, `clockAlarm:clockAlarm1BedtimeHour`, `clockAlarm:clockAlarm1BedtimeMinute`, `clockAlarm:clockAlarm2Enabled`, `clockAlarm:clockAlarm2Type`, `clockAlarm:clockAlarm2WakeupHour`, `clockAlarm:clockAlarm2WakeupMinute`, `clockAlarm:clockAlarm2BedtimeHour` and `clockAlarm:clockAlarm2BedtimeMinute`.
They have a number of channels to set the module's thermostat thermostat (`thermostat:currentTemperatureSetpoint`, `thermostat:heatingModeComfortTemperatureSetpoint`, `thermostat:heatingModeDayTemperatureSetpoint`, `thermostat:heatingModeNightTemperatureSetpoint`, `thermostat:heatingModeAntiFrostTemperatureSetpoint`, `thermostat:coolingModeComfortTemperatureSetpoint`, `thermostat:coolingModeDayTemperatureSetpoint`, `thermostat:coolingModeNightTemperatureSetpoint`, `thermostat:coolingModeSafeTemperatureSetpoint`, `operatingMode` and `thermostat:mode`) and thermostat trigger channels: `thermostat:heater`, `thermostat:boost`, `thermostat:pump`, `thermostat:cooler`, `thermostat:alarm1`, `thermostat:alarm2`, `thermostat:alarm3`, `thermostat:alarm4`.
Expand All @@ -203,6 +217,9 @@ Additionally, these modules have a number of channels to set the module's alarms

The trigger channels can be used as a trigger to rules. The event message can be `PRESSED`, `RELEASED`or `LONG_PRESSED`.

To remove the state of the Item in the Sitemap for a `button` channel.
Go to the Items list, select the Item, add a State Description Metadata, and set the Pattern value to a blank space.

## Full Example

.things:
Expand Down Expand Up @@ -230,6 +247,7 @@ Bridge velbus:bridge:1 [ port="COM1"] {

```
Switch LivingRoom {channel="velbus:vmb4ryld:1:06:CH1"} # Switch for onOff type action
Switch KitchenButton {velbus:vmb2pbn:1:05:button#CH1} # Switch for Pressed and Long_Pressed type actions
Dimmer TVRoom {channel="velbus:vmb4dc:1:07:CH2"} # Changing brightness dimmer type action
Rollershutter Kitchen {channel="velbus:vmb2ble:1:01"} # Controlling rollershutter or blind type action
Expand All @@ -245,6 +263,12 @@ Switch item=LivingRoom
Slider item=TVRoom
Switch item=TVRoom # allows switching dimmer item off or on
Rollershutter item=Kitchen
Switch item=KitchenButton # Press and Long_Pressed message are available
# or
Switch item=KitchenButton mappings=[PRESSED="Push"] # only the Pressed message is send on the bus
# or
Switch item=KitchenButton mappings=[LONG_PRESSED="Push"] # only the Long_Pressed message is send on the bus
```

Example trigger rule:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.openhab.binding.velbus.internal.handler.VelbusDimmerHandler;
import org.openhab.binding.velbus.internal.handler.VelbusNetworkBridgeHandler;
import org.openhab.binding.velbus.internal.handler.VelbusRelayHandler;
import org.openhab.binding.velbus.internal.handler.VelbusRelayWithInputHandler;
import org.openhab.binding.velbus.internal.handler.VelbusSensorHandler;
import org.openhab.binding.velbus.internal.handler.VelbusSensorWithAlarmClockHandler;
import org.openhab.binding.velbus.internal.handler.VelbusSerialBridgeHandler;
Expand Down Expand Up @@ -77,6 +78,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
thingHandler = velbusBridgeHandler;
} else if (VelbusRelayHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusRelayHandler(thing);
} else if (VelbusRelayWithInputHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusRelayWithInputHandler(thing);
} else if (VelbusDimmerHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
thingHandler = new VelbusDimmerHandler(thing);
} else if (VelbusBlindsHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public String getLabel() {
protected String getChannelName(int channelIndex) {
String channelName = "";

Integer key = channelIndex - 1;
Integer key = channelIndex;
if (channelNames.containsKey(key)) {
for (int i = 0; i < 3; i++) {
String channelNamePart = channelNames.get(key)[i];
Expand Down Expand Up @@ -147,7 +147,7 @@ public Map<String, Object> getProperties() {
for (Integer key : keys) {
String channelName = getChannelName(key);
if (channelName.length() > 0) {
properties.put(CHANNEL + key, channelName);
properties.put(CHANNEL + (key + 1), channelName);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
Expand All @@ -48,7 +47,7 @@
*/
@NonNullByDefault
public class VelbusThingDiscoveryService extends AbstractDiscoveryService
implements DiscoveryService, ThingHandlerService, VelbusPacketListener {
implements ThingHandlerService, VelbusPacketListener {
private static final int SEARCH_TIME = 60;

private final Logger logger = LoggerFactory.getLogger(VelbusThingDiscoveryService.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@
*/
@NonNullByDefault
public class VelbusRelayHandler extends VelbusThingHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(
Arrays.asList(THING_TYPE_VMB1RY, THING_TYPE_VMB1RYNO, THING_TYPE_VMB1RYNOS, THING_TYPE_VMB1RYS,
THING_TYPE_VMB4RY, THING_TYPE_VMB4RYLD, THING_TYPE_VMB4RYNO));
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB1RY,
THING_TYPE_VMB1RYNO, THING_TYPE_VMB1RYNOS, THING_TYPE_VMB4RY, THING_TYPE_VMB4RYLD, THING_TYPE_VMB4RYNO));

public VelbusRelayHandler(Thing thing) {
super(thing, 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**
* Copyright (c) 2010-2021 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.velbus.internal.handler;

import static org.openhab.binding.velbus.internal.VelbusBindingConstants.*;

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

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.packets.VelbusButtonPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.CommonTriggerEvents;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.types.Command;

/**
* The {@link VelbusRelayWithInputHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Daniel Rosengarten - Initial contribution
*/
@NonNullByDefault
public class VelbusRelayWithInputHandler extends VelbusRelayHandler {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = new HashSet<>(Arrays.asList(THING_TYPE_VMB1RYS));

private static final StringType PRESSED = new StringType("PRESSED");
private static final StringType LONG_PRESSED = new StringType("LONG_PRESSED");

public VelbusRelayWithInputHandler(Thing thing) {
super(thing);
}

@Override
public void handleCommand(ChannelUID channelUID, Command command) {
super.handleCommand(channelUID, command);

VelbusBridgeHandler velbusBridgeHandler = getVelbusBridgeHandler();
if (velbusBridgeHandler == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
return;
}

if (isButtonChannel(channelUID) && command instanceof StringType) {
StringType stringTypeCommand = (StringType) command;

if (stringTypeCommand.equals(PRESSED) || stringTypeCommand.equals(LONG_PRESSED)) {
VelbusButtonPacket packet = new VelbusButtonPacket(getModuleAddress().getChannelIdentifier(channelUID));

packet.Pressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
triggerChannel("CH6t", CommonTriggerEvents.PRESSED);

if (stringTypeCommand.equals(LONG_PRESSED)) {
packet.LongPressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
triggerChannel("CH6t", CommonTriggerEvents.LONG_PRESSED);
}

packet.Released();
velbusBridgeHandler.sendPacket(packet.getBytes());
triggerChannel("CH6t", CommonTriggerEvents.RELEASED);
} else {
throw new UnsupportedOperationException(
"The command '" + command + "' is not supported on channel '" + channelUID + "'.");
}
}
}

private boolean isButtonChannel(ChannelUID channelUID) {
return "CH6".equals(channelUID.toString().substring(channelUID.toString().length() - 3));
}

private boolean isTriggerChannel(byte address, byte channel) {
VelbusChannelIdentifier velbusChannelIdentifier = new VelbusChannelIdentifier(address, channel);

if (getModuleAddress().getChannelNumber(velbusChannelIdentifier) == 6) {
return true;
} else {
return false;
}
}

@Override
public void onPacketReceived(byte[] packet) {
super.onPacketReceived(packet);

if (packet[0] == VelbusPacket.STX && packet.length >= 5) {
byte command = packet[4];

if (command == COMMAND_PUSH_BUTTON_STATUS && packet.length >= 6) {
byte address = packet[2];

byte channelJustPressed = packet[5];
if (isTriggerChannel(address, channelJustPressed)) {
triggerChannel("CH6t", CommonTriggerEvents.PRESSED);
}

byte channelJustReleased = packet[6];
if (isTriggerChannel(address, channelJustReleased)) {
triggerChannel("CH6t", CommonTriggerEvents.RELEASED);
}

byte channelLongPressed = packet[7];
if (isTriggerChannel(address, channelLongPressed)) {
triggerChannel("CH6t", CommonTriggerEvents.LONG_PRESSED);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.velbus.internal.VelbusChannelIdentifier;
import org.openhab.binding.velbus.internal.packets.VelbusButtonPacket;
import org.openhab.binding.velbus.internal.packets.VelbusFeedbackLEDPacket;
import org.openhab.binding.velbus.internal.packets.VelbusPacket;
import org.openhab.core.library.types.StringType;
Expand All @@ -36,6 +37,7 @@
* sent to one of the channels.
*
* @author Cedric Boon - Initial contribution
* @author Daniel Rosengarten - Add button simulation
*/
@NonNullByDefault
public class VelbusSensorHandler extends VelbusThingHandler {
Expand All @@ -48,6 +50,9 @@ public class VelbusSensorHandler extends VelbusThingHandler {
private static final StringType VERY_FAST_BLINK_LED = new StringType("VERY_FAST_BLINK_LED");
private static final StringType CLEAR_LED = new StringType("CLEAR_LED");

private static final StringType PRESSED = new StringType("PRESSED");
private static final StringType LONG_PRESSED = new StringType("LONG_PRESSED");

public VelbusSensorHandler(Thing thing) {
this(thing, 0);
}
Expand Down Expand Up @@ -89,12 +94,44 @@ public void handleCommand(ChannelUID channelUID, Command command) {
byte[] packetBytes = packet.getBytes();
velbusBridgeHandler.sendPacket(packetBytes);
}

if (isButtonChannel(channelUID) && command instanceof StringType) {
StringType stringTypeCommand = (StringType) command;

if (stringTypeCommand.equals(PRESSED) || stringTypeCommand.equals(LONG_PRESSED)) {
VelbusButtonPacket packet = new VelbusButtonPacket(getModuleAddress().getChannelIdentifier(channelUID));

packet.Pressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
triggerChannel("input#CH" + getModuleAddress().getChannelNumber(channelUID),
CommonTriggerEvents.PRESSED);

if (stringTypeCommand.equals(LONG_PRESSED)) {
packet.LongPressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
triggerChannel("input#CH" + getModuleAddress().getChannelNumber(channelUID),
CommonTriggerEvents.LONG_PRESSED);
}

packet.Released();
velbusBridgeHandler.sendPacket(packet.getBytes());
triggerChannel("input#CH" + getModuleAddress().getChannelNumber(channelUID),
CommonTriggerEvents.RELEASED);
} else {
throw new UnsupportedOperationException(
"The command '" + command + "' is not supported on channel '" + channelUID + "'.");
}
}
}

private boolean isFeedbackChannel(ChannelUID channelUID) {
return "feedback".equals(channelUID.getGroupId());
}

private boolean isButtonChannel(ChannelUID channelUID) {
return "button".equals(channelUID.getGroupId());
}

@Override
public void onPacketReceived(byte[] packet) {
logger.trace("onPacketReceived() was called");
Expand Down
Loading

0 comments on commit 55c0a10

Please sign in to comment.