Skip to content

Commit

Permalink
[rme] Use serial transport (openhab#7638)
Browse files Browse the repository at this point in the history
Related to openhab#7573

Signed-off-by: Wouter Born <github@maindrain.net>
  • Loading branch information
wborn authored and andrewfg committed Aug 31, 2020
1 parent 9958e46 commit dd296ec
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 99 deletions.
4 changes: 0 additions & 4 deletions bundles/org.openhab.binding.rme/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,4 @@

<name>openHAB Add-ons :: Bundles :: RME Binding</name>

<properties>
<bnd.importpackage>gnu.io;version="[3.12,6)"</bnd.importpackage>
</properties>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,49 @@
import java.util.Collections;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingTypeUID;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandlerFactory;
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
import org.eclipse.smarthome.core.thing.binding.ThingHandlerFactory;
import org.eclipse.smarthome.io.transport.serial.SerialPortManager;
import org.openhab.binding.rme.internal.handler.RMEThingHandler;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
* The {@link RMEHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Karel Goderis - Initial contribution
*/
@NonNullByDefault
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.rme")
public class RMEHandlerFactory extends BaseThingHandlerFactory {

private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_MANAGER);

private final SerialPortManager serialPortManager;

@Activate
public RMEHandlerFactory(final @Reference SerialPortManager serialPortManager) {
this.serialPortManager = serialPortManager;
}

@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}

@Override
protected ThingHandler createHandler(Thing thing) {
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (thingTypeUID.equals(THING_TYPE_MANAGER)) {
return new RMEThingHandler(thing);
return new RMEThingHandler(thing, serialPortManager);
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.io.transport.serial.SerialPortManager;
import org.openhab.binding.rme.internal.RMEBindingConstants.DataField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -41,8 +42,8 @@ public class RMEThingHandler extends SerialThingHandler {
private static final StringType MANUAL = new StringType("Manual");
private static final StringType RAIN = new StringType("Rain");

public RMEThingHandler(Thing thing) {
super(thing);
public RMEThingHandler(Thing thing, SerialPortManager serialPortManager) {
super(thing, serialPortManager);
}

@Override
Expand Down Expand Up @@ -76,8 +77,8 @@ public void handleCommand(ChannelUID channelUID, Command command) {
}

@Override
public void onDataReceived(String line) {
line = StringUtils.chomp(line);
public void onDataReceived(String receivedLine) {
String line = StringUtils.chomp(receivedLine);

// little hack to overcome Locale limits of the RME Rain Manager
// note to the attentive reader : should we add support for system
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.TooManyListenersException;
import java.util.stream.Collectors;

import org.apache.commons.io.IOUtils;
import org.eclipse.smarthome.core.thing.ChannelUID;
Expand All @@ -28,16 +28,16 @@
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.io.transport.serial.PortInUseException;
import org.eclipse.smarthome.io.transport.serial.SerialPort;
import org.eclipse.smarthome.io.transport.serial.SerialPortEvent;
import org.eclipse.smarthome.io.transport.serial.SerialPortEventListener;
import org.eclipse.smarthome.io.transport.serial.SerialPortIdentifier;
import org.eclipse.smarthome.io.transport.serial.SerialPortManager;
import org.eclipse.smarthome.io.transport.serial.UnsupportedCommOperationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;

/**
* The {@link SerialThingHandler} is responsible for handling commands, which
* are sent to one of the channels. Thing Handler classes that use serial
Expand All @@ -58,34 +58,34 @@ public abstract class SerialThingHandler extends BaseThingHandler implements Ser
private final Logger logger = LoggerFactory.getLogger(SerialThingHandler.class);

private SerialPort serialPort;
private CommPortIdentifier portId;
private SerialPortIdentifier portId;
private final SerialPortManager serialPortManager;
private InputStream inputStream;
private OutputStream outputStream;
protected int baud;
protected String port;
protected int bufferSize;
protected long sleep = 100;
protected long interval = 0;
Thread readerThread = null;
private Thread readerThread = null;

public SerialThingHandler(Thing thing) {
public SerialThingHandler(Thing thing, SerialPortManager serialPortManager) {
super(thing);
this.serialPortManager = serialPortManager;
}

/**
* Called when data is received on the serial port
*
* @param line
* - the received data as a String
* @param line the received data as a String
*
**/
public abstract void onDataReceived(String line);

/**
* Write data to the serial port
*
* @param msg
* - the received data as a String
* @param msg the received data as a String
*
**/
public void writeString(String msg) {
Expand Down Expand Up @@ -127,6 +127,7 @@ public void dispose() {
IOUtils.closeQuietly(outputStream);
if (serialPort != null) {
serialPort.close();
serialPort = null;
}

if (readerThread != null) {
Expand All @@ -142,92 +143,80 @@ public void dispose() {
public void initialize() {
logger.debug("Initializing serial thing handler.");

if (serialPort == null && port != null && baud != 0) {
// parse ports and if the default port is found, initialized the
// reader
@SuppressWarnings("rawtypes")
Enumeration portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
CommPortIdentifier id = (CommPortIdentifier) portList.nextElement();
if (id.getPortType() == CommPortIdentifier.PORT_SERIAL) {
if (id.getName().equals(port)) {
logger.debug("Serial port '{}' has been found.", port);
portId = id;
}
}
}
if (baud == 0) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Baud rate is not configured");
return;
} else if (port == null || port.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Serial port is not configured");
return;
}

if (portId != null) {
// initialize serial port
try {
serialPort = portId.open("openHAB", 2000);
} catch (PortInUseException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + serialPort + ": " + e.getMessage());
return;
}
portId = serialPortManager.getIdentifier(port);

try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + serialPort + ": " + e.getMessage());
return;
}
if (portId == null) {
String availablePorts = serialPortManager.getIdentifiers().map(id -> id.getName())
.collect(Collectors.joining(System.lineSeparator()));
String description = String.format("Serial port '%s' could not be found. Available ports are:%n%s", port,
availablePorts);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, description);
return;

try {
serialPort.addEventListener(this);
} catch (TooManyListenersException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + serialPort + ": " + e.getMessage());
return;
}
}

// activate the DATA_AVAILABLE notifier
serialPort.notifyOnDataAvailable(true);

try {
// set port parameters
serialPort.setSerialPortParams(baud, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not configure serial port " + serialPort + ": " + e.getMessage());
return;
}
// initialize serial port
try {
serialPort = portId.open("openHAB", 2000);
} catch (PortInUseException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + port + ": " + e.getMessage());
return;
}

try {
// get the output stream
outputStream = serialPort.getOutputStream();
updateStatus(ThingStatus.ONLINE);
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not communicate with the serial port " + serialPort + ": " + e.getMessage());
return;
}
try {
inputStream = serialPort.getInputStream();
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + port + ": " + e.getMessage());
return;
}

readerThread = new SerialPortReader(inputStream);
readerThread.start();
try {
serialPort.addEventListener(this);
} catch (TooManyListenersException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not open serial port " + port + ": " + e.getMessage());
return;
}

} else {
StringBuilder sb = new StringBuilder();
portList = CommPortIdentifier.getPortIdentifiers();
while (portList.hasMoreElements()) {
CommPortIdentifier id = (CommPortIdentifier) portList.nextElement();
if (id.getPortType() == CommPortIdentifier.PORT_SERIAL) {
sb.append(id.getName() + "\n");
}
}
logger.error("Serial port '{}' could not be found. Available ports are:\n {}", port, sb);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
}
// activate the DATA_AVAILABLE notifier
serialPort.notifyOnDataAvailable(true);

try {
// set port parameters
serialPort.setSerialPortParams(baud, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
} catch (UnsupportedCommOperationException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not configure serial port " + port + ": " + e.getMessage());
return;
}

try {
// get the output stream
outputStream = serialPort.getOutputStream();
updateStatus(ThingStatus.ONLINE);
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Could not communicate with the serial port " + port + ": " + e.getMessage());
return;
}

readerThread = new SerialPortReader(inputStream);
readerThread.start();
}

@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// by default, we write anything we received as a string to the serial
// port
// by default, we write anything we received as a string to the serial port
writeString(command.toString());
}

Expand Down

0 comments on commit dd296ec

Please sign in to comment.