Skip to content

Commit

Permalink
[enocean] Implemented ESP2 protocol (openhab#6513)
Browse files Browse the repository at this point in the history
Implemented ESP2 protocol
Fixes openhab#6512

Signed-off-by: Daniel Weber <[email protected]>
Signed-off-by: Hans-Reiner Hoffmann <[email protected]>
  • Loading branch information
fruggy83 authored and Hans-Reiner committed Apr 11, 2020
1 parent 8a7d953 commit 0a90905
Show file tree
Hide file tree
Showing 38 changed files with 1,409 additions and 689 deletions.
13 changes: 11 additions & 2 deletions bundles/org.openhab.binding.enocean/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ This binding can enable the repeater function (level 1 or 2) of these gateways a
First of all you have to configure an EnOcean transceiver (gateway).
A directly connected USB300 can be auto discovered, an EnOceanPi has to be added manually to openHAB.
Both gateways are represented by an _EnOcean gateway_ in openHAB.
If you want to place the gateway for better reception apart from your openHAB server, you can forward its serial messages over TCP/IP (_ser2net_). In this case you have to define the path to the gateway like this rfc2217://x.x.x.x:3001.
If you want to place the gateway for better reception apart from your openHAB server, you can forward its serial messages over TCP/IP (_ser2net_).
In this case you have to define the path to the gateway like this rfc2217://x.x.x.x:3001.
If everything is running fine you should see the _base id_ of your gateway in the properties of your bridge.

Another way to improve sending and reception reliability is to setup a wired connection.
In this case you directly connect to your RS485 EnOcean bus (use USB connection of an Eltako FAM14 e.g.).
However communication on RS485 bus is mostly done with an older ESP2 protocol which does not support advanced telegrams like VLD.
Furthermore you have to be aware that not all radio telegrams are published on the bus.

The vast majority of EnOcean messages are sent as broadcast messages without an explicit receiver address.
However each EnOcean device is identified by an unique id, called EnOceanId, which is used as the sender address in these messages.
To receive messages from an EnOcean device you have to determine its EnOceanId and add an appropriate thing to openHAB.
Expand Down Expand Up @@ -92,7 +98,7 @@ Hence if your device supports one of the following EEPs the chances are good tha
Furthermore following supporting EEP family is available too: A5-11, types 0x03 (rollershutter position status) and 0x04 (extended light status).

A `rockerSwitch` is used to receive messages from a physical EnOcean Rocker Switch.
A `classicDevice` is used to for older EnOcean devices which react only on rocker switch messages (like Opus GN-A-R12V-SR-4).
A `classicDevice` is used for older EnOcean devices which react only on rocker switch messages (like Opus GN-A-R12V-SR-4).
As these devices do not send their current status, you have to add additional listener channels for each physical Rocker Switch to your thing.
In this way you can still sync your item status with the physical status of your device whenever it gets modified by a physical rocker switch.
The classic device simulates a physical Rocker Switch.
Expand Down Expand Up @@ -147,6 +153,9 @@ If you change the SenderId of your thing, you have to pair again the thing with
|---------------------------------|-------------------|-----------------------------|---|
| bridge | path | Path to the EnOcean Gateway | COM3, /dev/ttyAMA0, rfc2217://x.x.x.x:3001 |
| | nextSenderId | Set SenderId of next created thing.<br/>If omitted, the next unused SenderId is taken | 1-127 |
| | espVersion | ESP Version of gateway | ESP3, ESP2 |
| | rs485 | If gateway is directly connected to a RS485 bus the BaseId is set to 0x00 | true, false
| | rs485BaseId | Override BaseId 0x00 if your bus contains a telegram duplicator (FTD14 for ex) | 4 byte hex value |
| pushButton | receivingEEPId | EEP used for receiving msg | F6_01_01, D2_03_0A |
| | enoceanId | EnOceanId of device this thing belongs to | hex value as string |
| rockerSwitch | receivingEEPId | | F6_02_01, F6_02_02 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,4 +384,5 @@ public class EnOceanBindingConstants {

public static final String EMPTYENOCEANID = "00000000";

public static final byte ZERO = (byte) 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2020 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.enocean.internal;

import java.util.Arrays;

/**
*
* @author Daniel Weber - Initial contribution
*/
public class Helper {

public static byte[] concatAll(byte[] a, byte[]... rest) {
if(rest == null) {
return a;
}

int totalLength = a.length;
for (byte[] b : rest) {
if (b != null) {
totalLength += b.length;
}
}

byte[] result = Arrays.copyOf(a, totalLength);
int offset = a.length;
for (byte[] array : rest) {
if (array != null) {
System.arraycopy(array, 0, result, offset, array.length);
offset += array.length;
}
}
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2010-2020 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.enocean.internal.config;

/**
*
* @author Daniel Weber - Initial contribution
*/
public class EnOceanBridgeConfig {

public enum ESPVersion {
UNKNOWN("unknown"),
ESP3("ESP3"),
ESP2("ESP2");

private String version;

ESPVersion(String version) {
this.version = version;
}

public static ESPVersion getESPVersion(String espVersion) {
for (ESPVersion version : values()) {
if (version.version.equalsIgnoreCase (espVersion)) {
return version;
}
}

return ESPVersion.UNKNOWN;
}
}

public String path;

public String espVersion;
public boolean rs485;
public String rs485BaseId;

public int nextSenderId = 0;

public EnOceanBridgeConfig() {
espVersion = "ESP3";
}

public ESPVersion getESPVersion() {
return ESPVersion.getESPVersion(espVersion);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
import org.openhab.binding.enocean.internal.eep.Base.UTEResponse;
import org.openhab.binding.enocean.internal.eep.Base._4BSMessage;
import org.openhab.binding.enocean.internal.handler.EnOceanBridgeHandler;
import org.openhab.binding.enocean.internal.messages.BasePacket;
import org.openhab.binding.enocean.internal.messages.ERP1Message;
import org.openhab.binding.enocean.internal.messages.ERP1Message.RORG;
import org.openhab.binding.enocean.internal.messages.ESP3Packet;
import org.openhab.binding.enocean.internal.transceiver.ESP3PacketListener;
import org.openhab.binding.enocean.internal.transceiver.PacketListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -40,7 +40,7 @@
* @author Daniel Weber - Initial contribution
*/

public class EnOceanDeviceDiscoveryService extends AbstractDiscoveryService implements ESP3PacketListener {
public class EnOceanDeviceDiscoveryService extends AbstractDiscoveryService implements PacketListener {
private final Logger logger = LoggerFactory.getLogger(EnOceanDeviceDiscoveryService.class);

private EnOceanBridgeHandler bridgeHandler;
Expand Down Expand Up @@ -89,14 +89,15 @@ public synchronized void stopScan() {
}

@Override
public void espPacketReceived(ESP3Packet packet) {
public void packetReceived(BasePacket packet) {
ERP1Message msg = (ERP1Message) packet;

logger.info("EnOcean Package discovered, RORG {}, payload {}, additional {}", msg.getRORG().name(),
HexUtils.bytesToHex(msg.getPayload()), HexUtils.bytesToHex(msg.getOptionalPayload()));

EEP eep = EEPFactory.buildEEPFromTeachInERP1(msg);
if (eep == null) {
logger.debug("Could not build EEP for received package");
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ protected void convertFromCommandImpl(String channelId, String channelTypeId, Co

switch (channelId) {
case CHANNEL_ROLLERSHUTTER:
byte db0 = Zero | SEND_NEW_STATE | TeachInBit;
byte db1 = Zero;
byte db2 = Zero;
byte db0 = ZERO | SEND_NEW_STATE | TeachInBit;
byte db1 = ZERO;
byte db2 = ZERO;

byte position;
byte angle = 0; // for now, no angle configuration supported
Expand All @@ -80,7 +80,7 @@ protected void convertFromCommandImpl(String channelId, String channelTypeId, Co
} else if (outputCommand instanceof OnOffType) {
position = (byte) (((OnOffType) outputCommand == OnOffType.ON) ? 0 : 100);
} else if (outputCommand instanceof StopMoveType) {
position = Zero;
position = ZERO;
doStop = true;
} else if (outputCommand instanceof UpDownType) {
position = (byte) (((UpDownType) outputCommand == UpDownType.UP) ? 0 : 100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.binding.enocean.internal.eep.A5_38;

import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.CHANNEL_DIMMER;
import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.ZERO;

import java.util.function.Function;

Expand Down Expand Up @@ -62,20 +63,20 @@ protected void convertFromCommandImpl(String channelId, String channelTypeId, Co
if (outputCommand instanceof DecimalType) {
dimmValue = ((DecimalType) outputCommand).byteValue();
} else if (outputCommand instanceof OnOffType) {
dimmValue = ((OnOffType) outputCommand == OnOffType.ON) ? Switch100Percent : Zero;
dimmValue = ((OnOffType) outputCommand == OnOffType.ON) ? Switch100Percent : ZERO;
} else if (outputCommand instanceof IncreaseDecreaseType) {
dimmValue = ((IncreaseDecreaseType) outputCommand == IncreaseDecreaseType.INCREASE)
? Switch100Percent
: Zero;
: ZERO;
} else if (outputCommand instanceof UpDownType) {
dimmValue = ((UpDownType) outputCommand == UpDownType.UP) ? Switch100Percent : Zero;
dimmValue = ((UpDownType) outputCommand == UpDownType.UP) ? Switch100Percent : ZERO;
} else {
throw new IllegalArgumentException(outputCommand.toFullString() + " is no valid dimming command.");
}

EnOceanChannelDimmerConfig c = config.as(EnOceanChannelDimmerConfig.class);

byte storeByte = 0x00; // "Store final value" (standard) vs. "block value" (Eltako)
byte storeByte = ZERO; // "Store final value" (standard) vs. "block value" (Eltako)

if (!c.eltakoDimmer) {
dimmValue *= 2.55; // 0-100% = 0-255
Expand All @@ -90,7 +91,7 @@ protected void convertFromCommandImpl(String channelId, String channelTypeId, Co
}

byte rampingTime = Integer.valueOf(c.rampingTime).byteValue();
byte switchingCommand = (dimmValue == Zero) ? SwitchOff : SwitchOn;
byte switchingCommand = (dimmValue == ZERO) ? SwitchOff : SwitchOn;

setData(CommandId, dimmValue, rampingTime, (byte) (TeachInBit | storeByte | switchingCommand));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.binding.enocean.internal.eep.A5_38;

import java.util.function.Function;
import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.ZERO;

import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.library.types.OnOffType;
Expand Down Expand Up @@ -44,9 +45,9 @@ protected void convertFromCommandImpl(String channelId, String channelTypeId, Co
Function<String, State> getCurrentStateFunc, Configuration config) {

if ((OnOffType) outputCommand == OnOffType.ON) {
setData(CommandId, Zero, Zero, (byte) (TeachInBit | SwitchOn));
setData(CommandId, ZERO, ZERO, (byte) (TeachInBit | SwitchOn));
} else {
setData(CommandId, Zero, Zero, (byte) (TeachInBit | SwitchOff));
setData(CommandId, ZERO, ZERO, (byte) (TeachInBit | SwitchOff));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.binding.enocean.internal.eep.A5_3F;

import java.util.function.Function;
import static org.openhab.binding.enocean.internal.EnOceanBindingConstants.ZERO;

import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.library.types.PercentType;
Expand Down Expand Up @@ -60,9 +61,9 @@ protected void convertFromCommandImpl(String channelId, String channelTypeId, Co

PercentType target = (PercentType) command;
if (target.intValue() == PercentType.ZERO.intValue()) {
setData(Zero, (byte) shutTime, MoveUp, TeachInBit); // => move completely up
setData(ZERO, (byte) shutTime, MoveUp, TeachInBit); // => move completely up
} else if (target.intValue() == PercentType.HUNDRED.intValue()) {
setData(Zero, (byte) shutTime, MoveDown, TeachInBit); // => move completely down
setData(ZERO, (byte) shutTime, MoveDown, TeachInBit); // => move completely down
} else if (channelState != null) {
PercentType current = channelState.as(PercentType.class);
if (config != null && current != null) {
Expand All @@ -72,20 +73,20 @@ protected void convertFromCommandImpl(String channelId, String channelTypeId, Co
(Math.abs(current.intValue() - target.intValue()) * shutTime)
/ PercentType.HUNDRED.intValue());

setData(Zero, duration, direction, TeachInBit);
setData(ZERO, duration, direction, TeachInBit);
}
}
}

} else if (command instanceof UpDownType) {
if ((UpDownType) command == UpDownType.UP) {
setData(Zero, (byte) shutTime, MoveUp, TeachInBit); // => 0 percent
setData(ZERO, (byte) shutTime, MoveUp, TeachInBit); // => 0 percent
} else if ((UpDownType) command == UpDownType.DOWN) {
setData(Zero, (byte) shutTime, MoveDown, TeachInBit); // => 100 percent
setData(ZERO, (byte) shutTime, MoveDown, TeachInBit); // => 100 percent
}
} else if (command instanceof StopMoveType) {
if ((StopMoveType) command == StopMoveType.STOP) {
setData(Zero, (byte) 0xFF, Stop, TeachInBit);
setData(ZERO, (byte) 0xFF, Stop, TeachInBit);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.openhab.binding.enocean.internal.eep.Base;

import static org.openhab.binding.enocean.internal.messages.ESP3Packet.*;

import org.openhab.binding.enocean.internal.messages.ERP1Message;

/**
Expand All @@ -27,9 +29,9 @@ public class UTEResponse extends _VLDMessage {

public UTEResponse(ERP1Message packet) {

int dataLength = packet.getPayload().length - SenderIdLength - RORGLength - StatusLength;
int dataLength = packet.getPayload().length - ESP3_SENDERID_LENGTH - ESP3_RORG_LENGTH - ESP3_STATUS_LENGTH;

setData(packet.getPayload(RORGLength, dataLength));
setData(packet.getPayload(ESP3_RORG_LENGTH, dataLength));
bytes[0] = (byte) 0x91; // bidirectional communication, teach in accepted, teach in response

setStatus((byte) 0x80);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.openhab.binding.enocean.internal.eep.Base;

import static org.openhab.binding.enocean.internal.messages.ESP3Packet.*;

import org.openhab.binding.enocean.internal.messages.ERP1Message;
import org.openhab.binding.enocean.internal.messages.ERP1Message.RORG;

Expand All @@ -22,7 +24,7 @@
public class _4BSTeachInVariation3Response extends _4BSMessage {

public _4BSTeachInVariation3Response(ERP1Message packet) {
byte[] payload = packet.getPayload(RORGLength, RORG._4BS.getDataLength());
byte[] payload = packet.getPayload(ESP3_RORG_LENGTH, RORG._4BS.getDataLength());

payload[3] = (byte) 0xF0; // telegram with EEP number and Manufacturer ID,
// EEP supported, Sender ID stored, Response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
*/
package org.openhab.binding.enocean.internal.eep.Base;

import static org.openhab.binding.enocean.internal.messages.ESP3Packet.*;

import org.openhab.binding.enocean.internal.eep.EEP;
import org.openhab.binding.enocean.internal.messages.ERP1Message;

Expand All @@ -32,7 +34,7 @@ public _VLDMessage(ERP1Message packet) {
@Override
protected int getDataLength() {
if (packet != null) {
return packet.getPayload().length - SenderIdLength - RORGLength - StatusLength;
return packet.getPayload().length - ESP3_SENDERID_LENGTH - ESP3_RORG_LENGTH - ESP3_STATUS_LENGTH;
} else {
return bytes.length;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.util.function.Function;

import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.eclipse.smarthome.core.library.types.QuantityType;
import org.eclipse.smarthome.core.library.unit.SmartHomeUnits;
import org.eclipse.smarthome.core.thing.CommonTriggerEvents;
Expand Down
Loading

0 comments on commit 0a90905

Please sign in to comment.