Java and Real-time Raspberry Pi Sensors

I am a fan of Java even when it is not the best language for the job. The Java language is by far one of the most popular and widely used languages out there.  Unfortunately one language cannot do everything perfectly and in fact when working with the Raspberry Pi I have ran into a serious fundamental issue.  Java is not a real-time language; the sensors run their processes faster than Java can read the responses.

In this blog I will show you how to EASILY use Java and still use real-time sensors such as the temperature sensor.  If you are like me and do not want to abandon Java as your platform then here is the high level strategy for bridging this small gap.  We are going to build a small C++ script to basically make the call and return the data to our Java application then do the rest of the work in Java.

Look I know this sounds spotty and it is to a degree but there are so many advantages to retaining Java so your platform especially if you are truly building a device that talks to web services and external entities.  There is so so so so much great support, libraries and tutorials on how to do virtually anything and everything in Java.  You CANNOT compare the support and functionality of Java to C++, Python, etc.  (My Java rant is now done… sorry if you disagree, on some levels your opinion may be correct)

Lets get started!  Here is a basic Java application which we will use to obtain the Temperature and Humidity of the environment as well as the range of an object in front of our range finder sensor.

public class TestClass {
    public static void main(String[] args) {
        System.out.println("This is my console app");
        System.out.println("Reading from my sensor:" + giveWeatherData());
    }
	 
    public static String giveWeatherData() {
        //Here is where we will call our sensor and return data
        return "";
    }
}

Now lets take a break from Java and build our C++ app that makes the actual call to our sensor.  I would recommend compiling this on your Raspberry Pi to ensure all of your dependencies are already there; its super easy to do and can be done via a quick SSH session.

Create a basic text file and drop the code below into it; you will want to name this file testweather.c  then paste the code below into it.

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define MAXTIMINGS	85
#define DHTPIN		7
int dht11_dat[5] = { 0, 0, 0, 0, 0 };

//Compile
//gcc -o testweather testweather.c -lwiringPi -lwiringPiDev
 
int read_dht11_dat()
{
	uint8_t laststate	= HIGH;
	uint8_t counter		= 0;
	uint8_t j		= 0, i;
	float	f; 
	int ret = 0;
 
	dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0;
 
	pinMode( DHTPIN, OUTPUT );
	digitalWrite( DHTPIN, LOW );
	delay( 18 );
	digitalWrite( DHTPIN, HIGH );
	delayMicroseconds( 40 );
	pinMode( DHTPIN, INPUT );
 
	for ( i = 0; i < MAXTIMINGS; i++ )
	{
		counter = 0;
		while ( digitalRead( DHTPIN ) == laststate )
		{
			counter++;
			delayMicroseconds( 1 );
			if ( counter == 255 )
			{
				break;
			}
		}
		laststate = digitalRead( DHTPIN );
 
		if ( counter == 255 )
			break;
 
		if ( (i >= 4) && (i % 2 == 0) )
		{
			dht11_dat[j / 8] <<= 1;
			if ( counter > 16 )
				dht11_dat[j / 8] |= 1;
			j++;
		}
	}
 
	if ( (j >= 40) &&
	     (dht11_dat[4] == ( (dht11_dat[0] + dht11_dat[1] + dht11_dat[2] + dht11_dat[3]) & 0xFF) ) )
	{
		f = dht11_dat[2] * 9. / 5. + 32;
		printf( "Hum:%.0d%% Temp:%.0fF\n",
			dht11_dat[0], f );
	ret = 1;
	}
	return ret;
}
 
int main( void )
{ 
	if ( wiringPiSetup() == -1 )
		exit( 1 );
 
	int getRes = 0;
	while ( getRes == 0 )
	{
		
		getRes = read_dht11_dat();
		delay( 1000 ); 
	}
 
	return(0);
}

We need to compile and run this on our Raspberry Pi so if you created it locally then you will want to transfer it to your Pi.  On your Raspberry Pi you will want to run the following command to compile this code in a console window.  I have put this code at the top of the code block above in a comment; if you are anything like me then you will not remember the full command later on.

gcc -o testweather testweather.c -lwiringPi -lwiringPiDev

Now that this is compiled, we just need to test it real quick; just log onto your Pi and run the command below from a command prompt. (Make sure your sensor is hooked up)

./testweather

You should get this output if you have your sensors hooked up to the right pins

So we have proven that our C++ app can successfully call the sensor and receive feedback from it.  We now need to call this app from Java and read that output.  This part is relatively simple because we are basically going to have Java create a command prompt in memory, run the application and parse the output that you would normally see if you executed it manually.  I created a function called giveWeatherData that does just that!

  public static String giveWeatherData() {
	 //Here is where we will call our sensor and return data
	String ret = "";
    	
	Runtime rt = Runtime.getRuntime();
	String[] commands = {"/home/pi/pew/testweather","-get t"};
	Process proc = null;
	try {
		proc = rt.exec(commands);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
	BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

	// read the output from the command
	String s = null;
	try {
		while ((s = stdInput.readLine()) != null) {
			ret = s;
		    System.out.println(s);
		}
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	// read any errors from the attempted command
	try {
		while ((s = stdError.readLine()) != null) {
		    System.out.println(s);
		}
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	return ret;
 }

That is pretty much all of the major moving pieces for this blog; all that is left to do is put it all together.  Here is the Java code with everything that you need!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class TestClass {
	
public static void main(String[] args) {
    System.out.println("This is my console app");
    System.out.println("Reading from my sensor:" + giveWeatherData());
}
	 
 public static String giveWeatherData() {
	 //Here is where we will call our sensor and return data
	String ret = "";
    	
	Runtime rt = Runtime.getRuntime();
	String[] commands = {"/home/pi/pew/testweather","-get t"};
	Process proc = null;
	try {
		proc = rt.exec(commands);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
	BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

	// read the output from the command
	String s = null;
	try {
		while ((s = stdInput.readLine()) != null) {
			ret = s;
		    System.out.println(s);
		}
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	// read any errors from the attempted command
	try {
		while ((s = stdError.readLine()) != null) {
		    System.out.println(s);
		}
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	return ret;
 }

}

Let run our Java Application and see it all in action.  Make sure that the C++ application is in the same directory as the Java App; if so then you should be good to go.

Now you can continue to use Java and leverage its strong points with a fairly simple way to bridge a weakness in this language.

Leave a comment

Leave a Reply

Your email address will not be published. Required fields are marked *