Java Libraries to Use for Serial and USB Devices

Tags: #<Tag:0x00007faed90a6b00>

Hello,

I’m attempting to write a binding for Openhab. There are two different bridges, and the the bridge devices for the binding connect to Openhab via either a RS232 port or a USB port. What Java serial and USB libraries should I use with my project?

Regards,
Burzin

There is no consensus as Java miss support for sierial/USB ports in standard library. Each and every binding uses own way. General recommendation (I guess) is to use https://github.com/openhab/nrjavaserial which is bundled together with openhab.
It is available with esh-io-transport-serial-rxtx (<=2.5.0) or openhab-io-transport-serial-rxtx (>2.5.0) feature within openhab/karaf shell console.

For serial you should use not use the libraries directly but via the abstracted interface in openHAB via org.eclipse.smarthome.io.transport.serial.SerialPortManager.

1 Like

Thanks All

I tried to use “org.eclipse.smarthome.io.transport.serial.SerialPortManager” on my Windows-Installation.

Unfortunately, the "getIdentifier(“COM3”) -call never succeeds, even this Serial-port exists (USB-Serial)

With “gnu.io.SerialPort” (or jssc) the same port works!!

What can be the reason?

Thanks for your support!

Regards
Thomas

@Fischert did you find a solution? Even though I am developing on Linux and will finally run on a RaspberryPi I face the same problem. serialPortManager.getIdentifiers() returns an empty stream so it seems for me that I have a general library issue, but have no clue how to fix that.

Any idea is warmly welcome!

Here are some ideas when using openHAB 2.5.0-SNAPSHOT:

Properly configure the serial port

Make sure you have sufficient permissions to access the serial port. On Linux you need to be in the right group (usually dialout).

See also: Serial Port Configuration.

If you’re using udev rules to create (non-standard) aliases for serial ports you need to add these to the -Dgnu.io.rxtx.SerialPorts= list. That’s because the serial library (nrjavaserial) cannot assume each and every file in /dev/ is a serial port. :wink:

It’s depending on the OS/distribution which files are considered for serial ports. You can find this logic in RXTXCommDriver.java.

Make sure the serial transport is installed

If you’re adding your binding JAR to an existing openHAB instance, make sure the serial transport is installed.

You can check if it is installed on the Karaf Console as follows:

openhab> bundle:list -s | grep serial
209 │ Active │  80 │ 3.15.0.OH2            │ com.neuronrobotics.nrjavaserial
211 │ Active │  80 │ 2.5.0.201906040317    │ org.openhab.core.io.transport.serial
212 │ Active │  80 │ 2.5.0.201906040321    │ org.openhab.core.io.transport.serial.rxtx

If these are not there, install them using:

feature:install openhab-core-io-transport-serial

You can also install them by installing an existing binding with these dependencies.

E.g. on 2.5.0-SNAPSHOT:

DSMR, EnOcean, PowerMax, RFXCom, Serial Button, Smartmeter, Plugwise, ZWave

Make sure the serial transports are part of the “Run Requirements” when debugging with Eclipse

Besides adding your binding bundle, the org.openhab.core.io.transport.serial and org.openhab.core.io.transport.serial.rxtx bundles need to be added to the “Run Requirements” of app.bndrun:

Then click “Resolve”, save the file and “Debug OSGi”.

If you’re using a non-standard serial port name (udev rules) you’ll probably need to setup the environment variable for these in the app.bndrun "Run Configuration ", e.g. right click app.bndrun and select “Debug As” -> “Debug Configurations…”:

3 Likes

If you use more than one, all serial ports that you want to use need to be added. If not, when you make a selection, the list will collapse to the port you’ve selected and you won’t be able to use the other port.

2 Likes

Hello Raphael,

this are parts of my current implementation, I hope, it helps:

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

//=======================================================
// class LCNSerialHandler
//
//=======================================================
public class LCNSerialHandler extends BaseThingHandler
{

private final Logger logger = LoggerFactory.getLogger(LCNSerialHandler.class); 
private static SerialPort serialPort = null;
private static LCNPort    myLCNPort  = null;
//==================================
// Constructor
//
//=================================== 	
public LCNSerialHandler(Thing thing) 
{
    super(thing);
}


//==================================
// void initialize()
//
//=================================== 
@Override
public void initialize() 
{
    instCount ++;	// Increment InstanceCounter
    
    String port  = (String) getConfig().get(LCNSerialBindingConstants.CONFIG_PORT); 
    
    String lcn_IdStr = (String) getConfig().get(LCNSerialBindingConstants.CONFIG_LCN_ID);
    lcnAdress = Integer.parseInt(lcn_IdStr);
        
    if (port == null | lcn_IdStr == null) 
    {
        updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "Parameter must be set!");
        return;
    }
           
    try 
    {
		initPort( port, this);
	} 
    catch (Exception e1) 
    {
    	e1.printStackTrace();
	}

	try 
	{
		myLCNPort.Read_Modul_All(lcnAdress);
	} 
	catch (InterruptedException | IOException e) 
	{
    	e.printStackTrace();
	}

	logger.info("Update ThingStatus LCNSerial: ok");
	
    updateStatus(ThingStatus.ONLINE);
    
               
}

//============================================================
// void initPort( String port,  LCNSerialHandler handler)
//
//============================================================
private void initPort( String port, LCNSerialHandler handler) throws Exception
{
	if (serialPort != null)
	{
		myLCNPort.SetLCNSerialHandler(lcnAdress, handler);
		return;
	}
	  	
	CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(port);
	if (portIdentifier.isCurrentlyOwned()) 
	{
		throw new Exception("Port is currently in use");
	}

	CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000); // timeout 2 s.
	if (!(commPort instanceof SerialPort)) 
	{
		throw new Exception("Only serial port is supported");
	}
	
	serialPort = (SerialPort) commPort;
	
	// 9600 bit/s, 8 bits, stop bit length 1, no parity bit   
    serialPort.setSerialPortParams(9600, 8,1,0);
    
    serialPort.disableReceiveTimeout();
        
    serialPort.setRTS(false);
    serialPort.setDTR(true);
    
    
}

}

Beside that, it’s correct, what wborn mentioned: These features must be activated:

209 │ Active │ 80 │ 3.15.0.OH2 │ com.neuronrobotics.nrjavaserial
211 │ Active │ 80 │ 2.5.0.201906040317 │ org.openhab.core.io.transport.serial
212 │ Active │ 80 │ 2.5.0.201906040321 │ org.openhab.core.io.transport.serial.rxtx

In the “runbundles” of app.bndrun, “com.neuronrobotics.nrjavaserial;version=’[3.15.0,3.15.1)’,”
is added.

Please don’t provide this code as a (good) example. Besides the openHAB styling/naming is incorrect, throws not allowed generic Exception, printStrackTrace which is bad. Has non final static fields. Doesn’t use getConfigAs (So you have to parse the config values yourself). You should not use the gnu serial library directly but use the openHAB added layer via org.eclipse.smarthome.io.transport.serial.SerialPortManager
I don’t want to discourage you, but this code makes me, as a reviewer, very sad :frowning_face:. If you want to see how to implement serial take a look at the DSMR binding.

2 Likes

Hello Hilbrand,

Pls keep in mind and think about my comments

  1. The OpenHAB-Topic is the first time, I ever in my live had contact to a development community
  2. I only wanted to help with my answer
  3. Until now, I never used Eclipse, Java, maven and all these things - so I‘m a complete beginner
  4. Nevertheless I have the goal to create a LCN-Binding, which will help other users of OpenHAB. On my machine, this binding works meanwhile
  5. I can understand, that it‘s a challenge to keep Code-quality in an open-source community high.
  6. But pls. give a beginner like me the chance, to become better.
  7. Beginners like me need the feedback from the experts like you. But to say, that you‘re sad about what you see can only lead to frustration, not motivation. But Motivation is the base for the community…

Hi Thomas,

Don’t get frustrated by comments like this. Remember, even those hard core coders sometimes show actual signs of human emotion. :laughing::wink::laughing:
Keep in mind that the Dutch - being one myself - are known for being candit and to the point, right @hilbrand
Actually, you should feel honored. Normally they only respond in JSON-format or some abstract class or interface! :rofl::rofl::rofl:

I also started my first steps in the world of binding development and it has a steep learning curve for newcomers like me, I can say. Especially on the library usage and framework ‘interaction’ part.

So, keep up the good work. There are never enough bindings in the world of OH!

:+1::+1::+1:

qft

Thanks for all the feedback, and sorry for not responding for a long time. I don’t remember what exactly made it work finally, but I definitely @wborn’s comment about adding Run requirements was involved. Now I have
Run Requirements: org.openhab.core.io.transport.serial.rxtx
Run Bundles:

org.openhab.core.io.transport.serial;version=’[2.5.0,2.5.1)’,
com.neuronrobotics.nrjavaserial;version=’[3.15.0,3.15.1)’,
org.openhab.core.io.transport.serial.rxtx;version=’[2.5.0,2.5.1)’

and
-runvm: -Dgnu.io.rxtx.SerialPorts=/dev/ttyUSB0

for development in eclipse and I’ll see what I need on the target RaspberryPi.

edit: fix formatting

As you most likely spotted on, there are ongoing changes in how IDE is set up. Moreover, there are few technologies (Maven, OSGi, Karaf, Bnd/Bndtools, JSON processing) beside plain Java, which cause quite steep learning curve. You can follow the documentation about these to be ready for eventual traps and troubles.

Do you intend to swap existing LCN1 binding and provide version valid for oopenHAB2? If so then we can have a separate chat. :slight_smile:

Cheers,
Łukasz

Hello Lukasz,

My LCN Binding is for OpenHAB-2, it‘s completely different - LCN-PCHK is not needed.I’m doing the LCN-Bus communication directly.

Cheers
Thomas

1 Like