added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.irtrans-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-irtrans" description="IRTrans Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.irtrans/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,75 @@
/**
* 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.irtrans.internal;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link IRtransBindingConstants} contains constants used by the IRtrans
* handler classes
*
* @author Karel Goderis - Initial contribution
*
**/
public class IRtransBindingConstants {
public static final String BINDING_ID = "irtrans";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_ETHERNET_BRIDGE = new ThingTypeUID(BINDING_ID, "ethernet");
public static final ThingTypeUID THING_TYPE_BLASTER = new ThingTypeUID(BINDING_ID, "blaster");
// List of all Channel ids
public static final String CHANNEL_IO = "io";
// List of all Channel types
public static final String BLASTER_CHANNEL_TYPE = "blaster";
public static final String RECEIVER_CHANNEL_TYPE = "receiver";
// List of possible leds on a IRtrans transceiver
public enum Led {
DEFAULT("D"),
INTERNAL("I"),
EXTERNAL("E"),
ALL("B"),
ONE("1"),
TWO("2"),
THREE("3"),
FOUR("4"),
FIVE("5"),
SIX("6"),
SEVEN("7"),
EIGHT("8");
private final String text;
private Led(final String text) {
this.text = text;
}
@Override
public String toString() {
return text;
}
public static Led get(String valueSelectorText) throws IllegalArgumentException {
for (Led c : Led.values()) {
if (c.text.equals(valueSelectorText)) {
return c;
}
}
throw new IllegalArgumentException("Not valid value selector");
}
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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.irtrans.internal;
import static org.openhab.binding.irtrans.internal.IRtransBindingConstants.*;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openhab.binding.irtrans.internal.handler.BlasterHandler;
import org.openhab.binding.irtrans.internal.handler.EthernetBridgeHandler;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
/**
* The {@link IRtransHandlerFactory} is responsible for creating things and
* thing handlers.
*
* @author Karel Goderis - Initial contribution
*
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.irtrans")
public class IRtransHandlerFactory extends BaseThingHandlerFactory {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(THING_TYPE_BLASTER, THING_TYPE_ETHERNET_BRIDGE).collect(Collectors.toSet()));
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
public Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration, ThingUID thingUID,
ThingUID bridgeUID) {
if (IRtransBindingConstants.THING_TYPE_ETHERNET_BRIDGE.equals(thingTypeUID)) {
ThingUID ethernetBridgeUID = getEthernetBridgeThingUID(thingTypeUID, thingUID, configuration);
return super.createThing(thingTypeUID, configuration, ethernetBridgeUID, null);
}
if (IRtransBindingConstants.THING_TYPE_BLASTER.equals(thingTypeUID)) {
ThingUID blasterUID = getBlasterUID(thingTypeUID, thingUID, configuration, bridgeUID);
return super.createThing(thingTypeUID, configuration, blasterUID, bridgeUID);
}
throw new IllegalArgumentException(
"The thing type " + thingTypeUID + " is not supported by the IRtrans binding.");
}
@Override
protected ThingHandler createHandler(Thing thing) {
if (thing.getThingTypeUID().equals(IRtransBindingConstants.THING_TYPE_ETHERNET_BRIDGE)) {
return new EthernetBridgeHandler((Bridge) thing);
} else if (thing.getThingTypeUID().equals(IRtransBindingConstants.THING_TYPE_BLASTER)) {
return new BlasterHandler(thing);
} else {
return null;
}
}
private ThingUID getEthernetBridgeThingUID(ThingTypeUID thingTypeUID, ThingUID thingUID,
Configuration configuration) {
if (thingUID == null) {
String ipAddress = (String) configuration.get(EthernetBridgeHandler.IP_ADDRESS);
return new ThingUID(thingTypeUID, ipAddress);
}
return thingUID;
}
private ThingUID getBlasterUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
ThingUID bridgeUID) {
String ledId = (String) configuration.get(BlasterHandler.LED);
if (thingUID == null) {
return new ThingUID(thingTypeUID, "Led" + ledId, bridgeUID.getId());
}
return thingUID;
}
}

View File

@@ -0,0 +1,367 @@
/**
* 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.irtrans.internal;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link IrCommand} is a structure to store and manipulate infrared command
* in various formats
*
* @author Karel Goderis - Initial contribution
*
*/
public class IrCommand {
private Logger logger = LoggerFactory.getLogger(IrCommand.class);
/**
*
* Each infrared command is in essence a sequence of characters/pointers
* that refer to pulse/pause timing pairs. So, in order to build an infrared
* command one has to collate the pulse/pause timings as defined by the
* sequence
*
* PulsePair is a small datastructure to capture each pulse/pair timing pair
*
*/
private class PulsePair {
public int Pulse;
public int Pause;
}
private String remote;
private String command;
private String sequence;
private List<PulsePair> pulsePairs;
private int numberOfRepeats;
private int frequency;
private int frameLength;
private int pause;
private boolean startBit;
private boolean repeatStartBit;
private boolean noTog;
private boolean rc5;
private boolean rc6;
public String getRemote() {
return remote;
}
public void setRemote(String remote) {
this.remote = remote;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
public String getSequence() {
return sequence;
}
public void setSequence(String sequence) {
this.sequence = sequence;
}
public List<PulsePair> getPulsePairs() {
return pulsePairs;
}
public void setPulsePairs(ArrayList<PulsePair> pulsePairs) {
this.pulsePairs = pulsePairs;
}
public int getNumberOfRepeats() {
return numberOfRepeats;
}
public void setNumberOfRepeats(int numberOfRepeats) {
this.numberOfRepeats = numberOfRepeats;
}
public int getFrequency() {
return frequency;
}
public void setFrequency(int frequency) {
this.frequency = frequency;
}
public int getFrameLength() {
return frameLength;
}
public void setFrameLength(int frameLength) {
this.frameLength = frameLength;
}
public int getPause() {
return pause;
}
public void setPause(int pause) {
this.pause = pause;
}
public boolean isStartBit() {
return startBit;
}
public void setStartBit(boolean startBit) {
this.startBit = startBit;
}
public boolean isRepeatStartBit() {
return repeatStartBit;
}
public void setRepeatStartBit(boolean repeatStartBit) {
this.repeatStartBit = repeatStartBit;
}
public boolean isNoTog() {
return noTog;
}
public void setNoTog(boolean noTog) {
this.noTog = noTog;
}
public boolean isRc5() {
return rc5;
}
public void setRc5(boolean rc5) {
this.rc5 = rc5;
}
public boolean isRc6() {
return rc6;
}
public void setRc6(boolean rc6) {
this.rc6 = rc6;
}
/**
* Matches two IrCommands Commands match if they have the same remote and
* the same command
*
* @param anotherCommand the another command
* @return true, if successful
*/
public boolean matches(IrCommand anotherCommand) {
return (matchRemote(anotherCommand) && matchCommand(anotherCommand));
}
/**
* Match remote fields of two IrCommands In everything we do in the IRtrans
* binding, the "*" stands for a wilcard character and will match anything
*
* @param S the infrared command
* @return true, if successful
*/
private boolean matchRemote(IrCommand S) {
if ("*".equals(getRemote()) || "*".equals(S.getRemote())) {
return true;
} else {
return S.getRemote().equals(getRemote());
}
}
/**
* Match command fields of two IrCommands
*
* @param S the infrared command
* @return true, if successful
*/
private boolean matchCommand(IrCommand S) {
if ("*".equals(command) || "*".equals(S.command)) {
return true;
} else {
return S.command.equals(command);
}
}
/**
* Convert/Parse the IRCommand into a ByteBuffer that is compatible with the
* IRTrans devices
*
* @return the byte buffer
*/
public ByteBuffer toByteBuffer() {
ByteBuffer byteBuffer = ByteBuffer.allocate(44 + 210 + 1);
// skip first byte for length - we will fill it in at the end
byteBuffer.position(1);
// Checksum - 1 byte - not used in the ethernet version of the device
byteBuffer.put((byte) 0);
// Command - 1 byte - not used
byteBuffer.put((byte) 0);
// Address - 1 byte - not used
byteBuffer.put((byte) 0);
// Mask - 2 bytes - not used
byteBuffer.putShort((short) 0);
// Number of pulse pairs - 1 byte
byte[] byteSequence = sequence.getBytes(StandardCharsets.US_ASCII);
byteBuffer.put((byte) (byteSequence.length));
// Frequency - 1 byte
byteBuffer.put((byte) frequency);
// Mode / Flags - 1 byte
byte modeFlags = 0;
if (startBit) {
modeFlags = (byte) (modeFlags | 1);
}
if (repeatStartBit) {
modeFlags = (byte) (modeFlags | 2);
}
if (rc5) {
modeFlags = (byte) (modeFlags | 4);
}
if (rc6) {
modeFlags = (byte) (modeFlags | 8);
}
byteBuffer.put(modeFlags);
// Pause timings - 8 Shorts = 16 bytes
for (int i = 0; i < pulsePairs.size(); i++) {
byteBuffer.putShort((short) Math.round(pulsePairs.get(i).Pause / 8));
}
for (int i = pulsePairs.size(); i <= 7; i++) {
byteBuffer.putShort((short) 0);
}
// Pulse timings - 8 Shorts = 16 bytes
for (int i = 0; i < pulsePairs.size(); i++) {
byteBuffer.putShort((short) Math.round(pulsePairs.get(i).Pulse / 8));
}
for (int i = pulsePairs.size(); i <= 7; i++) {
byteBuffer.putShort((short) 0);
}
// Time Counts - 1 Byte
byteBuffer.put((byte) pulsePairs.size());
// Repeats - 1 Byte
byte repeat = (byte) 0;
repeat = (byte) numberOfRepeats;
if (frameLength > 0) {
repeat = (byte) (repeat | 128);
}
byteBuffer.put(repeat);
// Repeat Pause or Frame Length - 1 byte
if ((repeat & 128) == 128) {
byteBuffer.put((byte) frameLength);
} else {
byteBuffer.put((byte) pause);
}
// IR pulse sequence
try {
byteBuffer.put(sequence.getBytes("ASCII"));
} catch (UnsupportedEncodingException e) {
logger.warn("An exception occurred while encoding the sequence : '{}'", e.getMessage(), e);
}
// Add <CR> (ASCII 13) at the end of the sequence
byteBuffer.put((byte) ((char) 13));
// set the length of the byte sequence
byteBuffer.flip();
byteBuffer.position(0);
byteBuffer.put((byte) (byteBuffer.limit() - 1));
byteBuffer.position(0);
return byteBuffer;
}
/**
* Convert the the infrared command to a Hexadecimal notation/string that
* can be interpreted by the IRTrans device
*
* Convert the first 44 bytes to hex notation, then copy the remainder (= IR
* command piece) as ASCII string
*
* @return the byte buffer in Hex format
*/
public ByteBuffer toHEXByteBuffer() {
byte hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
ByteBuffer byteBuffer = toByteBuffer();
byte[] toConvert = new byte[byteBuffer.limit()];
byteBuffer.get(toConvert, 0, byteBuffer.limit());
byte[] converted = new byte[toConvert.length * 2];
for (int k = 0; k < toConvert.length - 1; k++) {
converted[2 * k] = hexDigit[(toConvert[k] >> 4) & 0x0f];
converted[2 * k + 1] = hexDigit[toConvert[k] & 0x0f];
}
ByteBuffer convertedBuffer = ByteBuffer.allocate(converted.length);
convertedBuffer.put(converted);
convertedBuffer.flip();
return convertedBuffer;
}
/**
* Convert 'sequence' bit of the IRTrans compatible byte buffer to a
* Hexidecimal string
*
* @return the string
*/
public String sequenceToHEXString() {
byte[] byteArray = toHEXByteArray();
return new String(byteArray, 88, byteArray.length - 88 - 2);
}
/**
* Convert the IRTrans compatible byte buffer to a string
*
* @return the string
*/
public String toHEXString() {
return new String(toHEXByteArray());
}
/**
* Convert the IRTrans compatible byte buffer to a byte array.
*
* @return the byte[]
*/
public byte[] toHEXByteArray() {
return toHEXByteBuffer().array();
}
}

View File

@@ -0,0 +1,109 @@
/**
* 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.irtrans.internal.handler;
import static org.openhab.binding.irtrans.internal.IRtransBindingConstants.CHANNEL_IO;
import org.apache.commons.lang.StringUtils;
import org.openhab.binding.irtrans.internal.IRtransBindingConstants.Led;
import org.openhab.binding.irtrans.internal.IrCommand;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link BlasterHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Karel Goderis - Initial contribution
*
*/
public class BlasterHandler extends BaseThingHandler implements TransceiverStatusListener {
// List of Configuration constants
public static final String COMMAND = "command";
public static final String LED = "led";
public static final String REMOTE = "remote";
private Logger logger = LoggerFactory.getLogger(BlasterHandler.class);
public BlasterHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
((EthernetBridgeHandler) getBridge().getHandler()).registerTransceiverStatusListener(this);
}
@Override
public void handleRemoval() {
((EthernetBridgeHandler) getBridge().getHandler()).unregisterTransceiverStatusListener(this);
updateStatus(ThingStatus.REMOVED);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
EthernetBridgeHandler ethernetBridge = (EthernetBridgeHandler) getBridge().getHandler();
if (ethernetBridge == null) {
logger.warn("IRtrans Ethernet bridge handler not found. Cannot handle command without bridge.");
return;
}
if (!(command instanceof RefreshType)) {
if (channelUID.getId().equals(CHANNEL_IO)) {
if (command instanceof StringType) {
String remoteName = StringUtils.substringBefore(command.toString(), ",");
String irCommandName = StringUtils.substringAfter(command.toString(), ",");
IrCommand ircommand = new IrCommand();
ircommand.setRemote(remoteName);
ircommand.setCommand(irCommandName);
IrCommand thingCompatibleCommand = new IrCommand();
thingCompatibleCommand.setRemote((String) getConfig().get(REMOTE));
thingCompatibleCommand.setCommand((String) getConfig().get(COMMAND));
if (ircommand.matches(thingCompatibleCommand)) {
if (!ethernetBridge.sendIRcommand(ircommand, Led.get((String) getConfig().get(LED)))) {
logger.warn("An error occured whilst sending the infrared command '{}' for Channel '{}'",
ircommand, channelUID);
}
}
}
}
}
}
@Override
public void onCommandReceived(EthernetBridgeHandler bridge, IrCommand command) {
logger.debug("Received command {},{} for thing {}", command.getRemote(), command.getCommand(),
this.getThing().getUID());
IrCommand thingCompatibleCommand = new IrCommand();
thingCompatibleCommand.setRemote((String) getConfig().get(REMOTE));
thingCompatibleCommand.setCommand((String) getConfig().get(COMMAND));
if (command.matches(thingCompatibleCommand)) {
StringType stringType = new StringType(command.getRemote() + "," + command.getCommand());
updateState(CHANNEL_IO, stringType);
}
}
}

View File

@@ -0,0 +1,948 @@
/**
* 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.irtrans.internal.handler;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.NoConnectionPendingException;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.openhab.binding.irtrans.internal.IRtransBindingConstants;
import org.openhab.binding.irtrans.internal.IRtransBindingConstants.Led;
import org.openhab.binding.irtrans.internal.IrCommand;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.util.HexUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link EthernetBridgeHandler} is responsible for handling commands, which
* are sent to one of the channels.
*
* @author Karel Goderis - Initial contribution
*
*/
public class EthernetBridgeHandler extends BaseBridgeHandler implements TransceiverStatusListener {
// List of Configuration constants
public static final String BUFFER_SIZE = "bufferSize";
public static final String IP_ADDRESS = "ipAddress";
public static final String IS_LISTENER = "isListener";
public static final String FIRMWARE_VERSION = "firmwareVersion";
public static final String LISTENER_PORT = "listenerPort";
public static final String MODE = "mode";
public static final String PING_TIME_OUT = "pingTimeOut";
public static final String PORT_NUMBER = "portNumber";
public static final String RECONNECT_INTERVAL = "reconnectInterval";
public static final String REFRESH_INTERVAL = "refreshInterval";
public static final String RESPONSE_TIME_OUT = "responseTimeOut";
public static final String COMMAND = "command";
public static final String LED = "led";
public static final String REMOTE = "remote";
public static final int LISTENING_INTERVAL = 100;
private static final Pattern RESPONSE_PATTERN = Pattern.compile("..(\\d{5}) (.*)", Pattern.DOTALL);
private static final Pattern HEX_PATTERN = Pattern.compile("RCV_HEX (.*)");
private static final Pattern IRDB_PATTERN = Pattern.compile("RCV_COM (.*),(.*),(.*),(.*)");
private Logger logger = LoggerFactory.getLogger(EthernetBridgeHandler.class);
private Selector selector;
private Thread pollingThread;
private SocketChannel socketChannel;
protected SelectionKey socketChannelKey;
protected ServerSocketChannel listenerChannel;
protected SelectionKey listenerKey;
protected boolean previousConnectionState;
private final Lock lock = new ReentrantLock();
private List<TransceiverStatusListener> transceiverStatusListeners = new CopyOnWriteArrayList<>();
/**
* Data structure to store the infrared commands that are 'loaded' from the
* configuration files. Command loading from pre-defined configuration files is not supported
* (anymore), but the code is maintained in case this functionality is re-added in the future
**/
protected final Collection<IrCommand> irCommands = new HashSet<>();
public EthernetBridgeHandler(Bridge bridge) {
super(bridge);
// Nothing to do here
}
@Override
public void initialize() {
// register ourselves as a Transceiver Status Listener
registerTransceiverStatusListener(this);
try {
selector = Selector.open();
} catch (IOException e) {
logger.debug("An exception occurred while registering the selector: '{}'", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR, e.getMessage());
}
if (selector != null) {
if (getConfig().get(IP_ADDRESS) != null && getConfig().get(PORT_NUMBER) != null) {
if (pollingThread == null) {
pollingThread = new Thread(pollingRunnable, "ESH-IRtrans-Polling " + getThing().getUID());
pollingThread.start();
}
} else {
logger.debug("Cannot connect to IRtrans Ethernet device. IP address or port number not set.");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"IP address or port number not set.");
}
if (getConfig().get(IS_LISTENER) != null) {
configureListener((String) getConfig().get(LISTENER_PORT));
}
}
}
@Override
public void dispose() {
unregisterTransceiverStatusListener(this);
try {
if (socketChannel != null) {
socketChannel.close();
}
} catch (IOException e) {
logger.warn("An exception occurred while closing the channel '{}': {}", socketChannel, e.getMessage());
}
try {
if (listenerChannel != null) {
listenerChannel.close();
}
} catch (IOException e) {
logger.warn("An exception occurred while closing the channel '{}': {}", listenerChannel, e.getMessage());
}
try {
if (selector != null) {
selector.close();
}
} catch (IOException e) {
logger.debug("An exception occurred while closing the selector: '{}'", e.getMessage());
}
logger.debug("Stopping the IRtrans polling Thread for {}", getThing().getUID());
if (pollingThread != null) {
pollingThread.interrupt();
try {
pollingThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
pollingThread = null;
}
}
public boolean registerTransceiverStatusListener(@NonNull TransceiverStatusListener transceiverStatusListener) {
return transceiverStatusListeners.add(transceiverStatusListener);
}
public boolean unregisterTransceiverStatusListener(@NonNull TransceiverStatusListener transceiverStatusListener) {
return transceiverStatusListeners.remove(transceiverStatusListener);
}
public void onConnectionLost() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
try {
if (socketChannel != null) {
socketChannel.close();
}
} catch (IOException e) {
logger.warn("An exception occurred while closing the channel '{}': {}", socketChannel, e.getMessage());
}
establishConnection();
}
public void onConnectionResumed() {
configureTransceiver();
updateStatus(ThingStatus.ONLINE);
}
private void establishConnection() {
lock.lock();
try {
if (getConfig().get(IP_ADDRESS) != null && getConfig().get(PORT_NUMBER) != null) {
try {
socketChannel = SocketChannel.open();
socketChannel.socket().setKeepAlive(true);
socketChannel.configureBlocking(false);
synchronized (selector) {
selector.wakeup();
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT;
socketChannelKey = socketChannel.register(selector, interestSet);
}
InetSocketAddress remoteAddress = new InetSocketAddress((String) getConfig().get(IP_ADDRESS),
((BigDecimal) getConfig().get(PORT_NUMBER)).intValue());
socketChannel.connect(remoteAddress);
} catch (IOException e) {
logger.debug("An exception occurred while connecting to '{}:{}' : {}", getConfig().get(IP_ADDRESS),
((BigDecimal) getConfig().get(PORT_NUMBER)).intValue(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
try {
Thread.sleep(((BigDecimal) getConfig().get(RESPONSE_TIME_OUT)).intValue());
} catch (NumberFormatException | InterruptedException e) {
Thread.currentThread().interrupt();
logger.debug("An exception occurred while putting a thread to sleep: '{}'", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
onConnectable();
}
} finally {
lock.unlock();
}
}
@Override
public void onCommandReceived(EthernetBridgeHandler bridge, IrCommand command) {
logger.debug("Received infrared command '{},{}' for thing '{}'", command.getRemote(), command.getCommand(),
this.getThing().getUID());
for (Channel channel : getThing().getChannels()) {
Configuration channelConfiguration = channel.getConfiguration();
if (channel.getChannelTypeUID() != null
&& channel.getChannelTypeUID().getId().equals(IRtransBindingConstants.RECEIVER_CHANNEL_TYPE)) {
IrCommand thingCompatibleCommand = new IrCommand();
thingCompatibleCommand.setRemote((String) channelConfiguration.get(REMOTE));
thingCompatibleCommand.setCommand((String) channelConfiguration.get(COMMAND));
if (command.matches(thingCompatibleCommand)) {
StringType stringType = new StringType(command.getRemote() + "," + command.getCommand());
logger.debug("Received a matching infrared command '{}' for channel '{}'", stringType,
channel.getUID());
updateState(channel.getUID(), stringType);
}
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (!(command instanceof RefreshType)) {
Channel channel = this.getThing().getChannel(channelUID.getId());
if (channel != null) {
Configuration channelConfiguration = channel.getConfiguration();
if (channel.getChannelTypeUID() != null
&& channel.getChannelTypeUID().getId().equals(IRtransBindingConstants.BLASTER_CHANNEL_TYPE)) {
if (command instanceof StringType) {
String remoteName = StringUtils.substringBefore(command.toString(), ",");
String irCommandName = StringUtils.substringAfter(command.toString(), ",");
IrCommand ircommand = new IrCommand();
ircommand.setRemote(remoteName);
ircommand.setCommand(irCommandName);
IrCommand thingCompatibleCommand = new IrCommand();
thingCompatibleCommand.setRemote((String) channelConfiguration.get(REMOTE));
thingCompatibleCommand.setCommand((String) channelConfiguration.get(COMMAND));
if (ircommand.matches(thingCompatibleCommand)) {
if (sendIRcommand(ircommand, Led.get((String) channelConfiguration.get(LED)))) {
logger.debug("Sent a matching infrared command '{}' for channel '{}'", command,
channelUID);
} else {
logger.warn(
"An error occured whilst sending the infrared command '{}' for Channel '{}'",
command, channelUID);
}
}
}
}
if (channel.getAcceptedItemType() != null
&& channel.getAcceptedItemType().equals(IRtransBindingConstants.RECEIVER_CHANNEL_TYPE)) {
logger.warn("Receivers can only receive infrared commands, not send them");
}
}
}
}
private void configureListener(String listenerPort) {
try {
listenerChannel = ServerSocketChannel.open();
listenerChannel.socket().bind(new InetSocketAddress(Integer.parseInt(listenerPort)));
listenerChannel.configureBlocking(false);
logger.info("Listening for incoming connections on {}", listenerChannel.getLocalAddress());
synchronized (selector) {
selector.wakeup();
try {
listenerKey = listenerChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException e1) {
logger.debug("An exception occurred while registering a selector: '{}'", e1.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e1.getMessage());
}
}
} catch (IOException e3) {
logger.error(
"An exception occurred while creating configuring the listener channel on port number {}: '{}'",
Integer.parseInt(listenerPort), e3.getMessage());
}
}
protected void configureTransceiver() {
lock.lock();
try {
String putInASCIImode = "ASCI";
ByteBuffer response = sendCommand(putInASCIImode);
String getFirmwareVersion = "Aver" + (char) 13;
response = sendCommand(getFirmwareVersion);
if (response != null) {
String message = stripByteCount(response).split("\0")[0];
if (message != null) {
if (message.contains("VERSION")) {
logger.info("'{}' matches an IRtrans device with firmware {}", getThing().getUID(), message);
getConfig().put(FIRMWARE_VERSION, message);
} else {
logger.debug("Received some non-compliant garbage ({})", message);
onConnectionLost();
}
}
} else {
try {
logger.debug("Did not receive an answer from the IRtrans transceiver '{}' - Parsing is skipped",
socketChannel.getRemoteAddress());
onConnectionLost();
} catch (IOException e1) {
logger.debug("An exception occurred while getting a remote address: '{}'", e1.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e1.getMessage());
}
}
int numberOfRemotes = 0;
int numberOfRemotesProcessed = 0;
int numberOfRemotesInBatch = 0;
String[] remoteList = getRemoteList(0);
if (remoteList.length > 0) {
logger.debug("The IRtrans device for '{}' supports '{}' remotes", getThing().getUID(), remoteList[1]);
numberOfRemotes = Integer.valueOf(remoteList[1]);
numberOfRemotesInBatch = Integer.valueOf(remoteList[2]);
}
while (numberOfRemotesProcessed < numberOfRemotes) {
for (int i = 1; i <= numberOfRemotesInBatch; i++) {
String remote = remoteList[2 + i];
// get remote commands
String[] commands = getRemoteCommands(remote, 0);
StringBuilder result = new StringBuilder();
int numberOfCommands = 0;
int numberOfCommandsInBatch = 0;
int numberOfCommandsProcessed = 0;
if (commands.length > 0) {
numberOfCommands = Integer.valueOf(commands[1]);
numberOfCommandsInBatch = Integer.valueOf(commands[2]);
numberOfCommandsProcessed = 0;
}
while (numberOfCommandsProcessed < numberOfCommands) {
for (int j = 1; j <= numberOfCommandsInBatch; j++) {
String command = commands[2 + j];
result.append(command);
numberOfCommandsProcessed++;
if (numberOfCommandsProcessed < numberOfCommands) {
result.append(", ");
}
}
if (numberOfCommandsProcessed < numberOfCommands) {
commands = getRemoteCommands(remote, numberOfCommandsProcessed);
if (commands.length == 0) {
break;
}
numberOfCommandsInBatch = Integer.valueOf(commands[2]);
} else {
numberOfCommandsInBatch = 0;
}
}
logger.debug("The remote '{}' on '{}' supports '{}' commands: {}", remote, getThing().getUID(),
numberOfCommands, result.toString());
numberOfRemotesProcessed++;
}
if (numberOfRemotesProcessed < numberOfRemotes) {
remoteList = getRemoteList(numberOfRemotesProcessed);
if (remoteList.length == 0) {
break;
}
numberOfRemotesInBatch = Integer.valueOf(remoteList[2]);
} else {
numberOfRemotesInBatch = 0;
}
}
} finally {
lock.unlock();
}
}
private String[] getRemoteCommands(String remote, int index) {
String getCommands = "Agetcommands " + remote + "," + index + (char) 13;
ByteBuffer response = sendCommand(getCommands);
String[] commandList = new String[0];
if (response != null) {
String message = stripByteCount(response).split("\0")[0];
logger.trace("commands returned {}", message);
if (message != null) {
if (message.contains("COMMANDLIST")) {
commandList = message.split(",");
} else {
logger.debug("Received some non-compliant command ({})", message);
onConnectionLost();
}
}
} else {
logger.debug("Did not receive an answer from the IRtrans transceiver for '{}' - Parsing is skipped",
getThing().getUID());
onConnectionLost();
}
return commandList;
}
private String[] getRemoteList(int index) {
String getRemotes = "Agetremotes " + index + (char) 13;
ByteBuffer response = sendCommand(getRemotes);
String[] remoteList = new String[0];
if (response != null) {
String message = stripByteCount(response).split("\0")[0];
logger.trace("remotes returned {}", message);
if (message != null) {
if (message.contains("REMOTELIST")) {
remoteList = message.split(",");
} else {
logger.debug("Received some non-compliant command ({})", message);
onConnectionLost();
}
}
} else {
logger.debug("Did not receive an answer from the IRtrans transceiver for '{}' - Parsing is skipped",
getThing().getUID());
onConnectionLost();
}
return remoteList;
}
public boolean sendIRcommand(IrCommand command, Led led) {
// construct the string we need to send to the IRtrans device
String output = packIRDBCommand(led, command);
lock.lock();
try {
ByteBuffer response = sendCommand(output);
if (response != null) {
String message = stripByteCount(response).split("\0")[0];
if (message != null && message.contains("RESULT OK")) {
return true;
} else {
logger.debug("Received an unexpected response from the IRtrans transceiver: '{}'", message);
return false;
}
}
} finally {
lock.unlock();
}
return false;
}
private ByteBuffer sendCommand(String command) {
if (command != null) {
ByteBuffer byteBuffer = ByteBuffer.allocate(command.getBytes().length);
try {
byteBuffer.put(command.getBytes("ASCII"));
onWritable(byteBuffer);
Thread.sleep(((BigDecimal) getConfig().get(RESPONSE_TIME_OUT)).intValue());
return onReadable(((BigDecimal) getConfig().get(BUFFER_SIZE)).intValue(), true);
} catch (UnsupportedEncodingException | NumberFormatException | InterruptedException e) {
Thread.currentThread().interrupt();
logger.debug("An exception occurred while sending a command to the IRtrans transceiver for '{}': {}",
getThing().getUID(), e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
return null;
}
private Runnable pollingRunnable = new Runnable() {
@Override
public void run() {
while (true) {
try {
if (socketChannel == null) {
previousConnectionState = false;
onConnectionLost();
} else {
if (!previousConnectionState && socketChannel.isConnected()) {
previousConnectionState = true;
onConnectionResumed();
}
if (previousConnectionState && !socketChannel.isConnected()
&& !socketChannel.isConnectionPending()) {
previousConnectionState = false;
onConnectionLost();
}
if (!socketChannel.isConnectionPending() && !socketChannel.isConnected()) {
previousConnectionState = false;
logger.debug("Disconnecting '{}' because of a network error", getThing().getUID());
socketChannel.close();
Thread.sleep(1000 * ((BigDecimal) getConfig().get(RECONNECT_INTERVAL)).intValue());
establishConnection();
}
long stamp = System.currentTimeMillis();
if (!InetAddress.getByName(((String) getConfig().get(IP_ADDRESS)))
.isReachable(((BigDecimal) getConfig().get(PING_TIME_OUT)).intValue())) {
logger.debug(
"Ping timed out after '{}' milliseconds. Disconnecting '{}' because of a ping timeout",
System.currentTimeMillis() - stamp, getThing().getUID());
socketChannel.close();
}
onConnectable();
ByteBuffer buffer = onReadable(((BigDecimal) getConfig().get(BUFFER_SIZE)).intValue(), false);
if (buffer != null && buffer.remaining() > 0) {
onRead(buffer);
}
}
onAcceptable();
if (!Thread.currentThread().isInterrupted()) {
Thread.sleep(LISTENING_INTERVAL);
} else {
return;
}
} catch (IOException e) {
logger.trace("An exception occurred while polling the transceiver : '{}'", e.getMessage(), e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
};
protected void onAcceptable() {
lock.lock();
try {
try {
selector.selectNow();
} catch (IOException e) {
logger.debug("An exception occurred while selecting: {}", e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = it.next();
it.remove();
if (selKey.isValid()) {
if (selKey.isAcceptable() && selKey == listenerKey) {
try {
SocketChannel newChannel = listenerChannel.accept();
newChannel.configureBlocking(false);
logger.trace("Received a connection request from '{}'", newChannel.getRemoteAddress());
synchronized (selector) {
selector.wakeup();
newChannel.register(selector, newChannel.validOps());
}
} catch (IOException e) {
logger.debug("An exception occurred while accepting a connection on channel '{}': {}",
listenerChannel, e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
}
}
}
}
} finally {
lock.unlock();
}
}
protected void onConnectable() {
lock.lock();
SocketChannel aSocketChannel = null;
try {
synchronized (selector) {
selector.selectNow();
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = it.next();
it.remove();
if (selKey.isValid() && selKey.isConnectable()) {
aSocketChannel = (SocketChannel) selKey.channel();
aSocketChannel.finishConnect();
logger.trace("The channel for '{}' is connected", aSocketChannel.getRemoteAddress());
}
}
} catch (IOException | NoConnectionPendingException e) {
if (aSocketChannel != null) {
logger.debug("Disconnecting '{}' because of a socket error : '{}'", getThing().getUID(), e.getMessage(),
e);
try {
aSocketChannel.close();
} catch (IOException e1) {
logger.debug("An exception occurred while closing the channel '{}': {}", socketChannel,
e1.getMessage());
}
}
} finally {
lock.unlock();
}
}
protected ByteBuffer onReadable(int bufferSize, boolean isSelective) {
lock.lock();
try {
synchronized (selector) {
try {
selector.selectNow();
} catch (IOException e) {
logger.error("An exception occurred while selecting: {}", e.getMessage());
}
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = it.next();
it.remove();
if (selKey.isValid() && selKey.isReadable()) {
SocketChannel aSocketChannel = (SocketChannel) selKey.channel();
if ((aSocketChannel.equals(socketChannel) && isSelective) || !isSelective) {
ByteBuffer readBuffer = ByteBuffer.allocate(bufferSize);
int numberBytesRead = 0;
boolean error = false;
try {
numberBytesRead = aSocketChannel.read(readBuffer);
} catch (NotYetConnectedException e) {
logger.warn("The channel '{}' is not yet connected: {}", aSocketChannel, e.getMessage());
if (!aSocketChannel.isConnectionPending()) {
error = true;
}
} catch (IOException e) {
// If some other I/O error occurs
logger.warn("An IO exception occured on channel '{}': {}", aSocketChannel, e.getMessage());
error = true;
}
if (numberBytesRead == -1) {
error = true;
}
if (error) {
logger.debug("Disconnecting '{}' because of a socket error", getThing().getUID());
try {
aSocketChannel.close();
} catch (IOException e1) {
logger.debug("An exception occurred while closing the channel '{}': {}", socketChannel,
e1.getMessage());
}
} else {
readBuffer.flip();
return readBuffer;
}
}
}
}
return null;
} finally {
lock.unlock();
}
}
protected void onWritable(ByteBuffer buffer) {
lock.lock();
try {
synchronized (selector) {
try {
selector.selectNow();
} catch (IOException e) {
logger.error("An exception occurred while selecting: {}", e.getMessage());
}
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = it.next();
it.remove();
if (selKey.isValid() && selKey.isWritable()) {
SocketChannel aSocketChannel = (SocketChannel) selKey.channel();
if (aSocketChannel.equals(socketChannel)) {
boolean error = false;
buffer.rewind();
try {
logger.trace("Sending '{}' on the channel '{}'->'{}'", new String(buffer.array()),
aSocketChannel.getLocalAddress(), aSocketChannel.getRemoteAddress());
aSocketChannel.write(buffer);
} catch (NotYetConnectedException e) {
logger.warn("The channel '{}' is not yet connected: {}", aSocketChannel, e.getMessage());
if (!aSocketChannel.isConnectionPending()) {
error = true;
}
} catch (ClosedChannelException e) {
// If some other I/O error occurs
logger.warn("The channel for '{}' is closed: {}", aSocketChannel, e.getMessage());
error = true;
} catch (IOException e) {
// If some other I/O error occurs
logger.warn("An IO exception occured on channel '{}': {}", aSocketChannel, e.getMessage());
error = true;
}
if (error) {
try {
aSocketChannel.close();
} catch (IOException e) {
logger.warn("An exception occurred while closing the channel '{}': {}", aSocketChannel,
e.getMessage());
}
}
}
}
}
} finally {
lock.unlock();
}
}
protected void onRead(ByteBuffer byteBuffer) {
try {
if (logger.isTraceEnabled()) {
logger.trace("Received bytebuffer : '{}'", HexUtils.bytesToHex(byteBuffer.array()));
}
int byteCount = getByteCount(byteBuffer);
while (byteCount > 0) {
byte[] message = new byte[byteCount];
byteBuffer.get(message, 0, byteCount);
if (logger.isTraceEnabled()) {
logger.trace("Received message : '{}'", HexUtils.bytesToHex(message));
}
String strippedBuffer = stripByteCount(ByteBuffer.wrap(message));
if (strippedBuffer != null) {
String strippedMessage = strippedBuffer.split("\0")[0];
// IRTrans devices return "RESULT OK" when it succeeds to emit an
// infrared sequence
if (strippedMessage.contains("RESULT OK")) {
parseOKMessage(strippedMessage);
}
// IRTrans devices return a string starting with RCV_HEX each time
// it captures an infrared sequence from a remote control
if (strippedMessage.contains("RCV_HEX")) {
parseHexMessage(strippedMessage);
}
// IRTrans devices return a string starting with RCV_COM each time
// it captures an infrared sequence from a remote control that is stored in the device's internal dB
if (strippedMessage.contains("RCV_COM")) {
parseIRDBMessage(strippedMessage);
}
byteCount = getByteCount(byteBuffer);
} else {
logger.warn("Received some non-compliant garbage '{}' - Parsing is skipped",
new String(byteBuffer.array()));
}
}
} catch (Exception e) {
logger.error("An exception occurred while reading bytebuffer '{}' : {}",
HexUtils.bytesToHex(byteBuffer.array()), e.getMessage(), e);
}
}
protected int getByteCount(ByteBuffer byteBuffer) {
String response = new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
response = StringUtils.chomp(response);
Matcher matcher = RESPONSE_PATTERN.matcher(response);
if (matcher.matches()) {
return Integer.parseInt(matcher.group(1));
}
return 0;
}
protected String stripByteCount(ByteBuffer byteBuffer) {
String message = null;
String response = new String(byteBuffer.array(), 0, byteBuffer.limit());
response = StringUtils.chomp(response);
Matcher matcher = RESPONSE_PATTERN.matcher(response);
if (matcher.matches()) {
String byteCountAsString = matcher.group(1);
message = matcher.group(2);
}
return message;
}
protected void parseOKMessage(String message) {
// Nothing to do here
}
protected void parseHexMessage(String message) {
Matcher matcher = HEX_PATTERN.matcher(message);
if (matcher.matches()) {
String command = matcher.group(1);
IrCommand theCommand = null;
for (IrCommand aCommand : irCommands) {
if (aCommand.sequenceToHEXString().equals(command)) {
theCommand = aCommand;
break;
}
}
if (theCommand != null) {
for (TransceiverStatusListener listener : transceiverStatusListeners) {
listener.onCommandReceived(this, theCommand);
}
} else {
logger.error("{} does not match any know infrared command", command);
}
} else {
logger.error("{} does not match the infrared message format '{}'", message, matcher.pattern());
}
}
protected void parseIRDBMessage(String message) {
Matcher matcher = IRDB_PATTERN.matcher(message);
if (matcher.matches()) {
IrCommand command = new IrCommand();
command.setRemote(matcher.group(1));
command.setCommand(matcher.group(2));
for (TransceiverStatusListener listener : transceiverStatusListeners) {
listener.onCommandReceived(this, command);
}
} else {
logger.error("{} does not match the IRDB infrared message format '{}'", message, matcher.pattern());
}
}
/**
* "Pack" the infrared command so that it can be sent to the IRTrans device
*
* @param led the led
* @param command the the command
* @return a string which is the full command to be sent to the device
*/
protected String packIRDBCommand(Led led, IrCommand command) {
String output = new String();
output = "Asnd ";
output += command.getRemote();
output += ",";
output += command.getCommand();
output += ",l";
output += led.toString();
output += "\r\n";
return output;
}
/**
* "Pack" the infrared command so that it can be sent to the IRTrans device
*
* @param led the led
* @param command the the command
* @return a string which is the full command to be sent to the device
*/
protected String packHexCommand(Led led, IrCommand command) {
String output = new String();
output = "Asndhex ";
output += "L";
output += led.toString();
output += ",";
output += "H" + command.toHEXString();
output += (char) 13;
return output;
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.irtrans.internal.handler;
import org.openhab.binding.irtrans.internal.IrCommand;
/**
* The {@link TransceiverStatusListener} is interface that is to be implemented
* by all classes that wish to be informed of events happening to a infrared
* transceiver
*
* @author Karel Goderis - Initial contribution
*
*/
public interface TransceiverStatusListener {
/**
*
* Called when the ethernet transceiver/bridge receives an infrared command
*
* @param bridge
* @param command the infrared command
*/
public void onCommandReceived(EthernetBridgeHandler bridge, IrCommand command);
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="irtrans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>IRtrans Binding</name>
<description>This is the binding for IRtrans (www.irtrans.de) Transceivers</description>
<author>Karel Goderis</author>
</binding:binding>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="irtrans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Blaster/Receiver diode connected to an IRtrans transceiver -->
<thing-type id="blaster">
<supported-bridge-type-refs>
<bridge-type-ref id="ethernet"/>
</supported-bridge-type-refs>
<label>Blaster</label>
<description>This is an infrared transmitter that can send infrared commands</description>
<channels>
<channel id="io" typeId="io"/>
</channels>
<config-description>
<parameter name="led" type="text" required="true">
<label>Led</label>
<description>The Led on which infrared commands will be emitted</description>
</parameter>
<parameter name="remote" type="text" required="true">
<label>Remote</label>
<description>The remote or manufacturer name which's commands will be allowed, as defined in the IRtrans server
database and flashed into the transceiver. Can be '*' for any remote</description>
</parameter>
<parameter name="command" type="text" required="true">
<label>Command</label>
<description>The name of the command will be allowed, as defined in the IRtrans server database and flashed into the
transceiver. Can be '*' for any command</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="io">
<item-type>String</item-type>
<label>Input/Output</label>
<description>Read commands received by the blaster, or write commands to be sent by the blaster</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="irtrans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- Bridge Thing Type -->
<bridge-type id="ethernet">
<label>IRtrans Ethernet Bridge</label>
<description>This is an Ethernet (PoE) IRtrans transceiver equipped with an on-board IRDB database</description>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<label>Network Address</label>
<description>Network address of the ethernet transceiver</description>
<context>network-address</context>
</parameter>
<parameter name="portNumber" type="integer" required="true">
<label>Port Number</label>
<description>TCP port number of the transceiver service</description>
</parameter>
<parameter name="bufferSize" type="integer" required="false">
<label>Buffer Size</label>
<description>Buffer size used by the TCP socket when sending and receiving commands to the transceiver</description>
<default>1024</default>
</parameter>
<parameter name="responseTimeOut" type="integer" required="false">
<label>Response Time Out</label>
<description>Specifies the time milliseconds to wait for a response from the transceiver when sending a command.</description>
<default>100</default>
</parameter>
<parameter name="pingTimeOut" type="integer" required="false">
<label>Ping Time Out</label>
<description>Specifies the time milliseconds to wait for a response from the transceiver when pinging the device</description>
<default>1000</default>
</parameter>
<parameter name="reconnectInterval" type="integer" required="false">
<label>Reconnect Interval</label>
<description>Specifies the time seconds to wait before reconnecting to a transceiver after a communication failure</description>
<default>10</default>
</parameter>
</config-description>
</bridge-type>
<channel-type id="blaster">
<item-type>String</item-type>
<label>Blaster Channel</label>
<description>The Blaster Channel allows to send (filtered) infrared commands over the specified blaster led of the
transceiver</description>
<config-description>
<parameter name="led" type="text" required="true">
<label>Led</label>
<description>The Led on which infrared commands will be emitted</description>
</parameter>
<parameter name="remote" type="text" required="true">
<label>Remote</label>
<description>The remote or manufacturer name which's commands will be allowed, as defined in the IRtrans server
database and flashed into the transceiver. Can be '*' for any remote</description>
</parameter>
<parameter name="command" type="text" required="true">
<label>Command</label>
<description>The name of the command will be allowed, as defined in the IRtrans server database and flashed into the
transceiver. Can be '*' for any command</description>
</parameter>
</config-description>
</channel-type>
<channel-type id="receiver">
<item-type>String</item-type>
<label>Receiver Channel</label>
<description>The Receiver Channel allows to receive (filtered) infrared commands on the receiver led of the
transceiver</description>
<config-description>
<parameter name="remote" type="text" required="true">
<label>Remote</label>
<description>The remote or manufacturer name which's commands will be allowed, as defined in the IRtrans server
database and flashed into the transceiver. Can be '*' for any remote</description>
</parameter>
<parameter name="command" type="text" required="true">
<label>Command</label>
<description>The name of the command will be allowed, as defined in the IRtrans server database and flashed into the
transceiver. Can be '*' for any command</description>
</parameter>
</config-description>
</channel-type>
</thing:thing-descriptions>