A few years ago, a good friend of mine installed a small photovoltaic system on his roof. I'm very exited about installing some solar panels on a roof and start producing electricity. It turned out that the installed inverters have massive quality problems. So the idea was born to monitor the whole setup like i know it from computer systems. Each inverter in this system has a serial port interface to transmit data.
But at this time, the market of low cost and low power consuming computers wasn't distinct as it is nowadays. In February 2012, the Raspberry Pi Foundation started to sell Raspberry Pis. I saw this as a chance to get a cheap computer with a minimal power consumption.
So this blog post is about connecting a Raspberry Pi to inverters (or any other device) via RS232. We will use the Java Communications API to read received data from the inverters. We don't use the integrated RS232 port because we want to monitore more than just a signle inverter, so we have to use USB-RS232 adapters.
Prepare your Pi
To demonstrate this post, I'm using the following hardware setup:
- Raspberry Pi - Model B rev 2
- SDCard SanDisk Ultra SDHC Class 10
- D-Link USB hub
- Micro USB cable
- USB-RS232 adapters
- Alfa Networks USB WIFI adapter
Connect Cables and Stuff
First of all we have to get a Pi ready running a Linux with SSH access. The Raspberry guys recommend using Raspbian “wheezy” with Hard-Float. Follow the Quick start guide http://www.raspberrypi.org/quick-start-guide to setup your Pi.
Plug in all your USB devices into the USB hub, like keyboard, mouse, WIFI adapter, USB-RS232 adapters. The USB hub will be used as a power supply, so plug in the micro USB cable into the hub and into the micro USB port of your Pi. For the first boot, connect also a network cable into your Pi. Power up the USB hub and the Pi is going to boot for the first time.
Now it's time to setup the WIFI connection. Install the wpasupplicant package via
apt-get install wpasupplicant. Then copy paste
/etc/wpa_supplicant/wpa_supplicant.conf from my gists and adapt the files.
The D-Link USB hub has 7 ports (I define port 1 as the one on the left side and port 7 as the port on the right side) and I plugged two USB RS232 adapters into port 1 and port 2.
To check the USB-RS232 adapters are recognized by the Pi, run:
root@raspberrypi:/# lsusb | grep 232 Bus 001 Device 011: ID 0557:2008 ATEN International Co., Ltd UC-232A Serial Port [pl2303] Bus 001 Device 010: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC root@raspberrypi:/# ls /dev/ttyUSB* /dev/ttyUSB0 /dev/ttyUSB1 root@raspberrypi:/#
One important question is, which of the adapters is
/dev/ttyUSB0? Smart people will say,
/dev/ttyUSB0 is the one, plugged in first - that's right.
Lazy people (including myself) are using udev rules to create an alias per USB hub port.
After the rules are applied, all serial ports are accessible via aliases and we have a nice and easy way accessing our serial ports, no matter which port was plugged in first.
root@raspberrypi:/# ls -l /dev/ttySerialPort* lrwxrwxrwx 1 root root 7 Jan 1 1970 /dev/ttySerialPort1 -> ttyUSB1 lrwxrwxrwx 1 root root 7 Jan 1 1970 /dev/ttySerialPort2 -> ttyUSB0
To run the Java application later without root, we need a new user which has the privilege to access serial ports. To do so, just add a new user to group
root@raspberrypi:/# useradd -m -d /home/rxtxpi -s /bin/bash -G dialout rxtxpi
Now we're going to install the required software to communicate via serial adapters. For Java applications, we can use the Java Communications API (JCA). JCA requires some native platform specific code which is called via Java Native Interface (JNI). We also need the Java part of JCA.
The ugly part - JCA is not provided by Oracle via JRE and I couldn't find any downloads from Oracle. The good part - there is an Open Source implementation of JCA called RXTX. The native part can be installed via librxtx-java deb package. As long as there is no RXTX jar in Maven Central you can use this https://github.com/grafjo/rxtx as the Maven repository for RXTX.
We just install a JRE and RXTX on Pi, because compiling software on the Pi is really really slow! Install a Java 1.6 JDK and Gradle > 1.2 on your desktop, build the Java application there and copy it to the Pi.
root@raspberrypi:/# apt-get install openjdk-6-jre librxtx-java
Now the Pi is ready to run a Java application 🙂
Running Sample Application
The sample application just displays the plugged in serial adapters of your Pi. So switch to your desktop and build the sample application:
joo@jgraf:~$ git clone email@example.com:grafjo/rxtxpi.git Cloning into 'rxtxpi'... remote: Counting objects: 25, done. remote: Compressing objects: 100% (16/16), done. remote: Total 25 (delta 1), reused 24 (delta 0) Receiving objects: 100% (25/25), done. Resolving deltas: 100% (1/1), done. joo@jgraf:~$ cd rxtxpi/ joo@jgraf:~/rxtxpi$ gradle distZip :compileJava warning: [options] bootstrap class path not set in conjunction with -source 1.6 1 warning :processResources UP-TO-DATE :classes :jar :startScripts :distZip BUILD SUCCESSFUL Total time: 4.458 secs
Copy the application to your Pi:
joo@jgraf:~/rxtxpi$ scp build/distributions/rxtxpi.zip rxtxpi@raspberry:/home/rxtxpi
Switch back to your Pi, unzip the rxtxpi.zip. To use the predefined aliases for serial ports, we have to modify the default JVM options to
DEFAULT_JVM_OPTS="-Dgnu.io.rxtx.SerialPorts=/dev/ttySerialPort1:/dev/ttySerialPort2" inside the rxtx_pi startup script
Ok - when every thing was installed successfully, we will get this output from our Java application using RXTX
rxtxpi@raspberrypi ~/rxtx_pi/bin $ ./rxtx_pi [main] INFO de.synyx.rxtxpi.SerialPortUtils - Looking for serial ports [main] INFO de.synyx.rxtxpi.SerialPortUtils - Found port: /dev/ttySerialPort1 [main] INFO de.synyx.rxtxpi.SerialPortUtils - Found port: /dev/ttySerialPort2 rxtxpi@raspberrypi ~/rxtx_pi/bin $
So this blog post was about getting a Pi ready to run a RXTX Java application and verified that everything works well. The next post will be about how to use the Java Communications API to read data from an inverter.