Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[velbus] Add new functionality PRESSED and LONG PRESSED #10664

Merged
merged 12 commits into from
May 29, 2021
30 changes: 27 additions & 3 deletions bundles/org.openhab.binding.velbus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,27 @@ OnOff command types are supported.
For thing types `vmb1ryno`, `vmb1rynos`, `vmb1rys`, `vmb4ryld` and `vmb4ryno` 5 channels are available `CH1` ... `CH5`.
Rosen01 marked this conversation as resolved.
Show resolved Hide resolved
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`
Rosen01 marked this conversation as resolved.
Show resolved Hide resolved
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 the Items list, select the Item, add a State Description Mettadata, and set the Pattern value to a blank space.
Rosen01 marked this conversation as resolved.
Show resolved Hide resolved

## 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 @@ -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,131 @@
/**
* 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));

try {
packet.Pressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
Thread.sleep(20);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you are allowed to let the thread sleep here.
But you could use the scheduler, like here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I d'idn't check this part of your code, the 20 ms delay is useless then. I've remove this from my code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. I didn't thought of that when reviewing the code :-)


if (stringTypeCommand.equals(LONG_PRESSED)) {
packet.LongPressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
Thread.sleep(20);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you are allowed to let the thread sleep here.
But you could use the scheduler, like here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I d'idn't check this part of your code, the 20 ms delay is useless then. I've remove this from my code.

}

packet.Released();
velbusBridgeHandler.sendPacket(packet.getBytes());
} catch (InterruptedException e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This empty catch clause will probably become obsolete if you use the scheduler instead of a Thread.sleep.

Copy link
Contributor Author

@Rosen01 Rosen01 May 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've remove this from my code.

// do nothing
}
} 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));

try {
packet.Pressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
Thread.sleep(20);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you are allowed to let the thread sleep here.
But you could use the scheduler, like here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I d'idn't check this part of your code, the 20 ms delay is useless then. I've remove this from my code.


if (stringTypeCommand.equals(LONG_PRESSED)) {
packet.LongPressed();
velbusBridgeHandler.sendPacket(packet.getBytes());
Thread.sleep(20);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you are allowed to let the thread sleep here.
But you could use the scheduler, like here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I d'idn't check this part of your code, the 20 ms delay is useless then. I've remove this from my code.

}

packet.Released();
velbusBridgeHandler.sendPacket(packet.getBytes());
} catch (InterruptedException e) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This empty catch clause will probably become obsolete if you use the scheduler instead of a Thread.sleep.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've remove this from my code.

// do nothing
}
} 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