Showing posts with label processing. Show all posts
Showing posts with label processing. Show all posts

Monday, 29 March 2010

Processing in Netbeans

If you've ever browsed the Processing learning section you may have seen the article showing how to use Processing from within Eclipse.
How, I'm more of a Netbeans fan myself. This isn't a criticism of Eclipse, which I also use extensively. I just like Netbeans. Therefore, I'd like to share how to get Processing working from within the Netbeans IDE. I'll assume that you already have an installation of the Processing IDE. This howto is based almost directly on the Eclipse tutorial, so differences should be obvious.

Step 1. Download and install Netbeans

Netbeans can be downloaded from netbeans.org. Any of the bundles that contains Java SE will do. I use the 'All' bundle but you can get away with a smaller one.

Step 2. Create a new project

Ctrl-Shift-N creates a new project. For the project type, select Java >> Java Application. On the next page of the New Project dialog, give your project a name; I used 'ProcessingTest'. Also tick 'Create Main class' and enter a new like 'uk.co.mooduino.processingtest.Main'. You should use your own domain (this style of using a backward domain to create a unique namespace is common within java).

Step 3. Import the Processing library

To tell Netbeans about how Processing works, we need to import the Processing core library. Expand the 'ProcessingTest' project and then expend 'Libraries'. There should be one entry already, for the JDK. Right-click on the Libraries icon and select 'Add JAR/Folder...'. Browse wo where you installed the Processing IDE and then descend into the lib folder. Select 'core.jar'.

Step 4. Create a class and write your code!

Ctrl-N opens the New File dialog. Select 'Java Class' and give the class a name like 'MyProcessingSketch'. I'm going to use the same code as the Eclipse example;
package uk.co.mooduino.processingtest;

import processing.core.*;

public class MyProcessingSketch extends PApplet {

  public void setup() {
    size(200,200);
    background(0);
  }

  public void draw() {
    stroke(255);
    if (mousePressed) {
      line(mouseX,mouseY,pmouseX,pmouseY);
    }
  }
}

Step 5. Run!

Before we can run this code, we need to modify the Main class that Netbeans already created. Modify the code as follows:
package uk.co.mooduino.processingtest;

import processing.core.PApplet;

public class Main {

    public static void main(String[] args) {
        PApplet.main(new String[] {"--present", "uk.co.mooduino.processingtest.MyProcessingSketch"});
    }
}
Press F6 to execute the code. Your screen should switch to Processing running in fullscreen mode and the middle section should allow you to draw on it.



Monday, 22 March 2010

Design patterns in Processing applications

This is a follow on to my previous two posts (here and here). In those post I constructed a simple circuit for measuring the ambient temperature and, with the help of an Arduino board, sending the temperature data down a USB cable. I also wrote a program in Processing to read that data and display it on my PC's screen. I program also stores the temperature data in a simple text file in the hopes that I'll find something interesting to do with it.
As I mentioned at the end of the last post, I was unhappy with the quality of the Processing code. It was somewhat spaghetti like, with three distinct functions all being handled by the same bundle of code. So, in this post, I'll discuss how I teased the code apart and in particularly how I used two design patterns.

Design Patterns are easy

Processing as a language makes it really easy to write quick and dirty code, as we've seen, but this doesn't mean you have to. To tidy my code up, I used two design pattterns; singleton and observer. These are two very easy design patterns to use in Java; the observer pattern is built in!

Singleton

The singleton pattern is simple; A class that is a singleton ensures that there is only on instance of that class and also provides a method to get a reference to the single instance. The Singleton pattern is somewhat notorious in Java but it needn't be as it only requires a couple of lines of code to implement. I've used Bill Pugh's solution which is the neatest.
First of all, in the Processing environment, click that right arrow in the tabbed section and select 'new tab' (or Ctl-Shift N). Give the tab the name 'TemperatureObservable' which is also the name of the class. The follow code implements the singleton pattern.
static class TemperatureObservable {
  private TemperatureObservable() {
    super();
  }
  
  private static class SingletonHolder { 
     private static final TemperatureObservable INSTANCE = new TemperatureObservable();
  }
  
  public static TemperatureObservable getInstance() {
    return SingletonHolder.INSTANCE;
  }
}
There are four things to notice.
  • The class is declared as static. Processing complains about the getInstance() method if it isn't.
  • The class's constructor is private. This ensures that only this class can create an instance of it.
  • There is a private static inner class, SingletonHolder, that creates an instance of the singleton class. The inner class is used so that the singleton instance is only constructed when it is needed. This is called lazy initialization and ensures that the singleton isn't constructed if it isn't going to be used.
  • The static method getInstance() returns the singleton; this is the only way that code outside of this class can gain access to the singleton.

Observer

This pattern is built into Java. It consists of two parts. Firstly, there is an object that we call the observable; this is an object that is expected to change as certain points. Other objects, called observers, register their interest in the observable; when the observable object's state changes, it notifies it's observers.
In this application, the TemperatureObservable objects, our singleton, is also the observable object. Java provides a Class called Observable and any classes that extend this base class automatically get the Observer pattern functionality. Of course, we need to pull in the code from TempDisplay that this object taking over; the TemperatureObservable's job will be to read the temperature data from the serial connection and notify it's observers that a new reading is available.
static class TemperatureObservable extends Observable {
  
  private static PApplet pApplet = null;
  private Serial port = null;
  private String temperature = "0";
  
  private TemperatureObservable() {
    super();
  }
  
  public static void setParent(PApplet pApplet) {
    TemperatureObservable.pApplet = pApplet;
  }
  
  public void addObserver(Observer o) {
    super.addObserver(o);
    if (this.countObservers() == 1) {
      this.setup();
    }
  }
  
  public void deleteObserver(Observer o) {
    super.deleteObserver(o);
    if (this.countObservers() == 0) {
      this.tearDown();
    }
  }
  
  public void deleteObservers() {
    super.deleteObservers();
    this.tearDown();
  }
  
  public void setup() {
    if (this.port == null) {
      String portName = Serial.list()[0];
      this.port = new Serial(TemperatureObservable.pApplet, portName, 9600);
      this.port.write("get temp");
      this.tick();
    }
  }
  
  public void tearDown() {
    if (this.port != null) {
      this.port.stop();
      this.port = null;
    }
  }
  
  public void tick() {
    if (this.port.available()>0) {
      TemperatureObservable.pApplet.delay(100);
      this.temperature = port.readString().trim();
      this.setChanged();
      this.notifyObservers(this.temperature);
    }
  }
  
  public String getTemperature() {
    return this.temperature;
  }
  
   private static class SingletonHolder { 
     private static final TemperatureObservable INSTANCE = new TemperatureObservable();
   }
  
  public static TemperatureObservable getInstance() {
    return SingletonHolder.INSTANCE;
  }
  
}
The new code allows a PApplet object to be registered with the TemperatureObservable class; this is only needed because the Serial object constructor expects a PApplet object as it's first argument. Further on, we also use the PApplet's delay() method. PApplet, by the way, is the superclass of the class you enter into the Processing sketch's first tab. How PApplet child class is called TempDisplay.
addObserver(), deleteObserver() and deleteObservers() are all methods in the Observable class that we override so that we can set up and tear down the serial connection on demand. Lastly, the tick() method is needed to tell the TemperatureObservable object to check the serial connection for a new temperature; remember that in the previous version, this check happened in the PApplet's draw() method.
In order to use the Observable singleton, we need an Observer. Java provides an Observer interface which has just one abstract method that we need to implement, update(). Objects that implement this interface can be passed to the Observable object's addObserver(). Our first observer is quite a simple one and is charged with maintaining the main TempDisplay object's copy of the current temperature (the one that it renders each time draw() is called).
static class TempDisplayObserver implements Observer {
  
  private TempDisplay display = null;
  
  public TempDisplayObserver(TempDisplay display) {
    this.display = display;
  }
  
  public void update(Observable o, Object arg) {
    this.display.setTemperature((String)arg);
  }
}
For this to work, the TempDisplay class needs a new method, setTemperature(). The TempDisplay code is as follows. Notice that the is much shorter than the version at the end last post, though I've also removed the code that saves the data to a file and we've yet to replace this.
import processing.serial.*;

String temperature = "0";
PFont font;


TemperatureObservable tempObs = null;

void setup() {
  TemperatureObservable.setParent(this);
  this.tempObs = TemperatureObservable.getInstance();
  this.tempObs.addObserver(new TempDisplayObserver(this));

  font = loadFont("Ziggurat-HTF-Black-32.vlw");
  textFont(font);
  textAlign(CENTER);
  size(200, 140);
  background(0);
  fill(0);
  smooth();
}

void draw() {
  background(255);
  this.tempObs.tick();
  text(temperature, width/2, height/2);
}

void setTemperature(String arg) {
  temperature = arg;
}
As you can see, at the start of the setup() method, we register the TempDisplay object with the TemperatureObservable class via it's setParent() method. we then get a reference to the singleton and add a new instance of TempDisplayObserver. Also notice in the draw() method, we call the singleton's tick() method.

File output again.

The second observer object is tasked with writing the data to the text file. Most of this code is simply copied from the previous version of TempDisplay.
static class TempFileObserver implements Observer {
  
  private String dataFolder = null;
  private PrintWriter output = null;
  private TimeZone tz = null;
  private DateFormat stamp = null;
  private Date lastSaveDate = null;
  
  public TempFileObserver(String dataFolder) {
    this.dataFolder = dataFolder;
    tz = TimeZone.getDefault();
    stamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
    stamp.setTimeZone(tz);
    lastSaveDate = new Date();
    String fileName = getFileName(lastSaveDate);
    output = getOutput(dataFolder, fileName);
  }
  
  public void update(Observable o, Object arg) {
    this.writeData((String)arg);
  }
  
  private void writeData(String temp) {
    if (this.output != null) {
      Date currentSaveDate = new Date();
      String message = stamp.format(currentSaveDate) + " " + temp;
      this.output.println(message);
      this.output.flush();
      if (this.isNextDay(this.lastSaveDate, currentSaveDate)) {
        this.output.flush();
        this.output.close();
        String fileName = this.getFileName(currentSaveDate);
        this.output = this.getOutput(dataFolder, fileName);
      }
      this.lastSaveDate = currentSaveDate;
    }
  }
  
  private String getFileName(Date date) {
      DateFormat dfm = new SimpleDateFormat("yyyyMMdd");
      dfm.setTimeZone(tz);
      return dfm.format(date) + ".data";
  }
  
  private PrintWriter getOutput(String folder, String file) {
    PrintWriter pw = null;
    File fileHandle = new File(folder, file);
    try {
      pw = new PrintWriter(new FileOutputStream(fileHandle, true));
    } catch (FileNotFoundException fnfe) {}
    return pw;
  }
  
  private boolean isNextDay(Date earlier, Date later) {
    boolean isNextDay = false;
    Calendar cEarlier = Calendar.getInstance();
    Calendar cLater = Calendar.getInstance();
    cEarlier.setTime(earlier);
    cLater.setTime(later);
    if (cLater.after(cEarlier)) {
      boolean dayIsAfter = cLater.get(Calendar.DAY_OF_YEAR) > cEarlier.get(Calendar.DAY_OF_YEAR);
      boolean yearIsAfter = cLater.get(Calendar.YEAR) > cEarlier.get(Calendar.YEAR);
      isNextDay = dayIsAfter || yearIsAfter;
    }
    return isNextDay;
  }   
}
To make use of this class, we just need to pass an instance of it to the singleton's addObserver() method. The TempDisplay's setup() method becomes:
void setup() {
  TemperatureObservable.setParent(this);
  this.tempObs = TemperatureObservable.getInstance();
  
  String dataFolder = selectFolder("Choose the folder where you want the temperature data to be recorded");
  if (dataFolder != null) {
    this.tempObs.addObserver(new TempFileObserver(dataFolder));
  }
  
  this.tempObs.addObserver(new TempDisplayObserver(this));
  //...
}

One last thing.

There is just one last thing that was bugging me; just occasionally, more than one temperature reading is available in the serial connection and this would cause the display to show more than one reading. This is easily fixed. We know that each reading should contain no white space and that individual reading are separated by a line break. Therefore, I changed the TemperatureObservable's tick method to split the value that it reads from the serial connection using a regular expression. The regular expression that I used is '[\\s]+'. This simply means 'one or more characters of white space.' The tick() method changes to the following:
public void tick() {
    if (this.port.available()>0) {
      TemperatureObservable.pApplet.delay(100);
      String outString = port.readString().trim();
      String[] temps = outString.split("[\\s]+");
      for (int i = 0; i < temps.length; i++) {
        this.temperature = temps[i];
        this.setChanged();
        this.notifyObservers(this.temperature);
      }
    }
  }

Conclusion

I was really pleased with the work I did here. Implementing these two design patterns was straight forward. It is just great that Processing allows me to simple programmes quickly while being able to leverage my Java knowledge. Maybe next time I'll do something more visually exciting.



Sunday, 7 March 2010

File output with Processing

In my last post, I discussed how I put together a simple temperature probe, using an Arduino board, how the Arduino pushed the current temperature down a USB cable and finally how I consumed that data with a Processing application.
In this article I wanted to share my next steps. I want to be able to use the data from the sensor in a number of ways, not just in Processing, but in any language or platform. Therefore this week I investigated how to write the data to a permanent file on my hard drive. My initial plan had been to write an original program in Java that read the data from the serial port but I soon discovered that getting Java to talk to the serial port (at least on my Linux PC) wasn't exactly easy. Obviously it is possible because Processing is written in Java and this works find on my PC and so to save pulling my hair out, I decided at this time to continue with the Processing application that I started last time.

The task

I set my self the following tasks that I'd like the application to do.
  • The application must ask the user at runtime where on the hard drive the data files are to be stored.
  • The data file must be simple text that any file can read.
  • The data file mustn't individually get to large. Ideally, the application should generated one file per day, and automatically 'roll over' at the start of each day.
  • The data should be appended at the end of the data file if the file already exists.

The Code

First, I looked at how to choose a folder. Processing conveniently provides a function called selectFolder() that prompts the user to select a directory, so this was my starting point. There is also a function called createWriter() that is used to open a PrintWriter object pointing at a given file name.
String dataFolder;
PrintWriter output;

void setup() {
 dataFolder = selectFolder("Choose the folder where you want the temperature data to be recorded");
 if (dataFolder != null) {
  String fileName = "/" + year() + month() + day() + ".data";
  output = createWriter(dataFolder + fileName);
 }
}
The only issue with this code is the use of month() and day(); These return an integer value, meaning that on the day that I write this, the newly created file would be called '201037.data' when of course it should be called 20100307.data'. We could easily fix this by checking whether each value is less than 10 and adding the 0 if necessary but there is a more flexible way.
Processing allows us to make use of the normal Java classes that are part of the JVM. In this instance, the class that I want to use is called DateFormat and this allows you to take a Date object and create a formated string based on it. In Java, a Date object records a moment in time and by default when you instantiate a new Date object, it records the moment that it was created.
String dataFolder;
PrintWriter output;
TimeZone tz;

void setup() {
 dataFolder = selectFolder("Choose the folder where you want the temperature data to be recorded");
 if (dataFolder != null) {
  tz = TimeZone.getDefault();
  DateFormat dfm = new SimpleDateFormat("yyyyMMdd");
  dfm.setTimeZone(tz);
  String fileName = "/" + dfm.format(new Date()) + ".data";
  output = createWriter(dataFolder + fileName);
 }
}
This code creates the output file with the correctly formatted name.
Next, outputting the data to the file. I wanted each line in the data file to show the moment that the reading was received as well as the actual temperature. To time stamp each reading, I created another instance of DateFormat, this time with the hours, minutes, second and milliseconds at the end. I created a new function, writeData(), which is called from within draw() whenever a new temperature reading is received.
DateFormat stamp;

void setup() {
 stamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
 stamp.setTimeZone(tz);
}

void draw() {
 if (port.available()>0) {
  delay(100);
  temperature = port.readString().trim();
  writeData(temperature);
 }
 background(255);
 text(temperature, width/2, height/2);
}

void writeData(String temp) {
 if (output != null) {
  String message = stamp.format(new Date()) + " " + temp;
  output.println(message);
  output.flush();
 }
}
Notice also that in draw(), there is a call to trim() on the string returned from the serial port. This is to ensure that extra end of line characters are passed through to the data file. output.flush() is required to flush the data to the hard drive; if we didn't do this, the file wouldn't get written until some internal buffer was filled.
Next up, making sure that at the end of each day, the file name 'rolls over' and a new output file is created. In order to do this, we note the current time each time a temperature is recorded. if the current time is one calendar day after the previous time, then a new file has to be created. First, I wrote a function that would determine is one date is one calendar day later than another.
boolean isNextDay(Date earlier, Date later) {
 boolean isNextDay = false;
 Calendar cEarlier = Calendar.getInstance();
 Calendar cLater = Calendar.getInstance();
 cEarlier.setTime(earlier);
 cLater.setTime(later);
 if (cLater.after(cEarlier)) {
  boolean dayIsAfter = cLater.get(Calendar.DAY_OF_YEAR) > cEarlier.get(Calendar.DAY_OF_YEAR);
  boolean yearIsAfter = cLater.get(Calendar.YEAR) > cEarlier.get(Calendar.YEAR);
  isNextDay = dayIsAfter || yearIsAfter;
 }
 return isNextDay;
}
As you can see, this function makes use of another Java class, this time the Calendar class. The way Java handles dates, time and location specific information about date and time is quite confusing at first. Its important to remember that a Date object only records a moment in time. It isn't aware of what this moment means; whether it is a Tuesday or even which year it is. This is because different parts of the world have different names of Tuesday and even different names of the years (we're all used to the Gregorian calendar but this isn't the only calendar in use). Therefore Java gives us the Calendar class. With one of these, you can ask time specific questions and get answers that are correct for the PC that is running your software.
With this function in place, it was easy to update the writeData() function create a new file at the start of each day. I also created two other functions; These are simply refactored code from the setup() function:
Date lastSaveDate;

void setup() {
 dataFolder = selectFolder("Choose the folder where you want the temperature data to be recorded");
 if (dataFolder != null) {
  tz = TimeZone.getDefault();
  stamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
  stamp.setTimeZone(tz);
  lastSaveDate = new Date();
  String fileName = getFileName(lastSaveDate);
  output = getOutput(dataFolder, fileName);
 }
}

void writeData(String temp) {
 if (output != null) {
  Date currentSaveDate = new Date();
  String message = stamp.format(currentSaveDate) + " " + temp;
  output.println(message);
  output.flush();
  if (isNextDay(lastSaveDate, currentSaveDate)) {
   output.flush();
   output.close();
   String fileName = getFileName(currentSaveDate);
   output = getOutput(dataFolder, fileName);
  }
  lastSaveDate = currentSaveDate;
 }
}

String getFileName(Date date) {
 DateFormat dfm = new SimpleDateFormat("yyyyMMdd");
 dfm.setTimeZone(tz);
 return "/" + dfm.format(date) + ".data";
}

PrintWriter getOutput(String folder, String file) {
 return createWriter(folder + file);
}
With this code in place this last item on my list is to append new data to existing data. At the moment, when the application is started, the call to createWriter() deletes any data already in the target file. It is much better to add the new data to the end of what is already there. Processing doesn't seem to give us any help in this area so I again dived into Java, this time for the File and FileOutputStream classes.
Whereas the createWriter() function takes the absolute file name and returns the PrintWriter object, the new code builds the PrintWriter up in stages. First, we pass the folder and filename to the File constructor. This creates a pointer to a file location but doesn't actually create the file on the hard drive. Then were create an instance of FileOutputStream(). To this we pass the file handle and, importantly, we also pass the boolean true; This tells the FileOutputStream to open in append mode. Lastly, we create the PrintWriter, passing in the FileOutputStream.
These changes are to the getOutput() function declared in the last refactoring. No other changes were required.
PrintWriter getOutput(String folder, String file) {
 PrintWriter pw = null;
 File fileHandle = new File(folder, file);
 try {
  pw = new PrintWriter(new FileOutputStream(fileHandle, true));
 } catch (FileNotFoundException fnfe) {}
 return pw;
}

All together now

Putting this all together, we end up with the following code, which includes the code from the previous article.
String temperature = "0";
PFont font;
Serial port;
String dataFolder;
PrintWriter output;
TimeZone tz;
DateFormat stamp;
Date lastSaveDate;

void setup() {
 dataFolder = selectFolder("Choose the folder where you want the temperature data to be recorded");
 if (dataFolder != null) {
  tz = TimeZone.getDefault();
  stamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
  stamp.setTimeZone(tz);
  lastSaveDate = new Date();
  String fileName = getFileName(lastSaveDate);
  output = getOutput(dataFolder, fileName);
 }
 String portName = Serial.list()[0];
 port = new Serial(this, portName, 9600);
 port.write("get temp");
 font = loadFont("Ziggurat-HTF-Black-32.vlw");
 textFont(font);
 textAlign(CENTER);
 size(200, 140);
 background(0);
 fill(0);
 smooth();
}

void draw() {
 if (port.available()>0) {
  delay(100);
  temperature = port.readString().trim();
  writeData(temperature);
 }
 background(255);
 text(temperature, width/2, height/2);
}

void writeData(String temp) {
 if (output != null) {
  Date currentSaveDate = new Date();
  String message = stamp.format(currentSaveDate) + " " + temp;
  output.println(message);
  output.flush();
  if (isNextDay(lastSaveDate, currentSaveDate)) {
   output.flush();
   output.close();
   String fileName = getFileName(currentSaveDate);
   output = getOutput(dataFolder, fileName);
  }
  lastSaveDate = currentSaveDate;
 }
}

String getFileName(Date date) {
 DateFormat dfm = new SimpleDateFormat("yyyyMMdd");
 dfm.setTimeZone(tz);
 return dfm.format(date) + ".data";
}

PrintWriter getOutput(String folder, String file) {
 PrintWriter pw = null;
 File fileHandle = new File(folder, file);
 try {
  pw = new PrintWriter(new FileOutputStream(fileHandle, true));
 } catch (FileNotFoundException fnfe) {}
 return pw;
}

boolean isNextDay(Date earlier, Date later) {
 boolean isNextDay = false;
 Calendar cEarlier = Calendar.getInstance();
 Calendar cLater = Calendar.getInstance();
 cEarlier.setTime(earlier);
 cLater.setTime(later);
 if (cLater.after(cEarlier)) {
  boolean dayIsAfter = cLater.get(Calendar.DAY_OF_YEAR) > cEarlier.get(Calendar.DAY_OF_YEAR);
  boolean yearIsAfter = cLater.get(Calendar.YEAR) > cEarlier.get(Calendar.YEAR);
  isNextDay = dayIsAfter || yearIsAfter;
 }
 return isNextDay;
}

Next?

This code is all about saving the data from the temperature sensor to the hard drive so that I can use the data in other ways, and that is what I plan to do next. Two ideas have occurred to me; One suggestion that Hari made about the previous article was this it would be nice to graph the data, and so that's one thing I want to look at. As I'm a web developer to pay the bills, I also want to look at how I can consume the data in PHP to create a website showing the temperature data.
Before this, though, I think the code above desperately needs refactoring to separate out the three concerns of reading the data from the serial port, showing the data on the monitor and recording the data to the file.
So, until next time, stay happy.

Sunday, 28 February 2010

Using Processing and Arduino to display room temperature.

I've recently been getting into the Arduino project. For those who don't know, this is an open source project for prototyping electronic hardware. The Arduino board itself contains a microprocessor, which you can program in a version of c/c++ called Wiring; the board also has a USB port making it really easy to connect to your computer and get started. It also makes it easy to connect to the Arduino from other programs or hardware.

I've been playing around with my Arduino board for a while (just making LEDs blink and such) but today I did my first serious application and I'd like to share how I did this. Please remember, I'm just getting started with my Arduino, so this isn't a master class, but the application does everything that I set out to do (just maybe not the best way). I guess I should also point out that this isn't 'getting started with Arduino tutorial' even though it isn't too advanced; I have only maybe 10 hours experience but I'm going to assume that you've already got your Arduino development environment set up. If you haven't, not to worry, there are tons of excellent tutorials on the web, such as this one.

The hardware measures the ambient room temperature, my Arduino board takes the output from the sensor, transforms it to Centigrade, and pushes it down the USB serial port. The final part is a desktop program written the the Processing language, and this reads the value from the USB serial port and displays it in a window.

Hardware

For this project, you'll need the following items:
  • An Arduino board
  • A solderless breadboard
  • A temperature sensor (I used a LM35DT)
  • Wires to connect the various components
  • A USB cable

I got all these part in my initial Arduino box that I purchased from EarthShine Design.
Setting up the hardware is really easy. Plug the temperature sensor into your breadboard so that the three legs are on separate columns. The sensor needs 5 volts to power it. The front of the sensor has the name on and a little dot above leg number one which takes five volts so should be connected to the 5V pin on the Arduino. The middle leg should be connected to the GND pin, next to the 5V pin. The third leg should then be connected to the pin marked ANALOG IN 0, just right of the 5V and GND pins.

Wiring (version 1)

This is the first version of the software that I pushed to the Arduino. Once installed, it pushes the current temperature reading down the serial port every half a second. There are a few parts that it is worth pointing out.
  1. The loop function doesn't use a delay in order to read every half second. Instead, it stores when it last checked the temperature in the variable 'previousMillis' and doesn't check again until the current time is greater than 'previousMillis' plus 'interval' (which is 500 millisecond). I did it this way so that the code can be used alongside other code that also needs to loop; if delay() had been used, that other code would be delayed too.
  2. Wiring's version of sprintf doesn't support floats, so the code has to work out the temperature times 10 (so 30 degrees is stored as 300) and then in printTemperature() we put the period in manually by using the modulus operator.
  3. The last line in the setup() function sets the Arduino's reference voltage to 1.1 volts. This is done because the sensor module's third leg produces up to 1 volt; the sensor component measures from 0 to 100 degrees. 0 degrees is indicated by 0 volts and 100 degrees is indicated by 1 volt. Arduino automatically converts this voltage to a number between 0 and 1023.
const byte potPin = 0;         //pin that the temperature sensor is attached to
long temperature = 0;         //the current temperature
long previousMillis = 0;       // will store last time temperature was updated
const long interval = 500;     // interval at which to check the temperature

void setup() {
 Serial.begin(9600);
 Serial.flush();
 analogReference(INTERNAL);
}

void loop() {
 unsigned long currentMillis = millis();
 if(currentMillis - previousMillis > interval) {
  doTemperatureMeasurement();
  previousMillis = currentMillis; 
 }
}

void printTemperature(int value) {
 byte len = 4;
 if (value == 100) len = 5;
 char buffer[len];
 sprintf(buffer, "%3i.%1i", value / 10, value % 10);
 Serial.println(buffer);
}

int readAverage() {
 int span = 20;
 int aRead = 0;
 for (int i = 0; i < span; i++) {
  aRead = aRead+analogRead(potPin);
 }
 return aRead / span;
}

void doTemperatureMeasurement() {
 int aRead = readAverage();
 temperature = ((100*1.1*aRead)/1024)*10;
 printTemperature(temperature);
}
Once you have this code installed on your Arduino, you can open the serial monitor and should see the current temperature rattled back at you.

Processing (version 1)

With the Arduino now communicating the temperature down the USB serial cable I wanted to display this value on my monitor.
A project related to Arduino and Wiring is Processing. Actually, the Processing environment is virtually the same as the Wiring environment and the language is very similar too. Once you have the Processing environment installed and running, start a new project and save it (I called mine 'TempDisplay').

In order to display the temperature on the screen, we need a special font file that Processing uses to render text; a suitable file ships with Processing. From within Processing, click 'Add File...' on the Sketch menu. Open the directory where you installed Processing and then descend into 'examples/Basics/Typography/Words/data/'. Here you'll find a file called 'Ziggurat-HTF-Black-32.vlw'. Select this file.
import processing.serial.*;

String temperature = "0";
PFont font;
Serial port;

void setup() {
 String portName = Serial.list()[0];
 port = new Serial(this, portName, 9600);
 font = loadFont("Ziggurat-HTF-Black-32.vlw");
 textFont(font);
 textAlign(CENTER);
 size(200, 140);
 background(0);
 fill(0);
 smooth();
}

void draw() {
 if (port.available()>0) {
  delay(100);
  temperature = port.readString();
 }
 background(255); // Set background to dark gray
 text(temperature, width/2, height/2);
}
Before launching the application, you'll need to quit out of the Arduino environment, as the serial communication can't be opened by both programs at the same time.
The only line of code here that might cause a problem is the first line of the function setup(). It assumes that the USB serial connection is the first returned by Serial.list(). If yours isn't, you may have to play around with the number in the square brackets.

Wiring (version 2)

There were two things that I wasn't happy with in this solution.
  1. The Arduino communication is too chatty, by which I mean, the Arduino pushes the temperature down the wire even when it hasn't changed.
  2. When the Processing application starts up, there is a notable delay before it gets an update from the serial port during which time the temperature is displayed as zero.
The first problem is easy to fix. I simply changed the code for 'doTemperatureMeasurement()' to only update the temperature if it has changed since last time it was determined.
void doTemperatureMeasurement() {
 int aRead = readAverage();
 long newTemperature = ((100*1.1*aRead)/1024)*10;
 if (newTemperature != temperature) {
  temperature = newTemperature;
  printTemperature(temperature);
 }
}
This code change has an unfortunate side effect; The Processing application now has an even more noticeable delay when it starts up before it shows the real temperature. This is obviously because it is now waiting not for the half second to pass but for the temperature sensor to read that the room temperature has changed.

Wiring (version 3)

This is the final version of the Arduino software, so I've copied the whole thing again. The only change though is that the software listens (in the loop() function) for a message on the serial port. The message it is listening for is 'get temp' and when it hears this, it pushing the current temperature down the wire regardless of whether it has changed since last time.
Most of the code is to do with handling the character buffer but I've also refactored doTemperatureMeasurement(), separating out the code that determines the actual temperature into a new function, readTemperature(). This is used in the loop() function if the new message is heard on the wire.
const byte potPin = 0;         //pin that the temperature sensor is attached to
long temperature = 0;         //the current temperature
long previousMillis = 0;       // will store last time temperature was updated
const long interval = 500;     // interval at which to check the temperature
const byte maxSerialChars = 8;
char buffer[maxSerialChars];

void setup() {
 Serial.begin(9600);
 Serial.flush();
 analogReference(INTERNAL);
}

void loop() {
 if (Serial.available()>0) {
  delay(100);
  int numChars = Serial.available();
  int index = 0;
  if (numChars > maxSerialChars) {
   numChars = maxSerialChars;
  }
  while (numChars--) {
   buffer[index++] = Serial.read();
  }
  if (buffer[0] == 'g' && buffer[4] == 't') {
   printTemperature(readTemperature());
  }
  for (byte x=0; x<maxSerialChars; x++) {
   buffer[x] = '\0';
  }
 }

 unsigned long currentMillis = millis();
 if(currentMillis - previousMillis > interval) {
  doTemperatureMeasurement();
  previousMillis = currentMillis;
 }
}

void printTemperature(int value) {
 byte len = 4;
 if (value == 100) len = 5;
 char buffer[len];
 sprintf(buffer, "%3i.%1i", value / 10, value % 10);
 Serial.println(buffer);
}

int readAverage() {
 int span = 20;
 int aRead = 0;
 for (int i = 0; i < span; i++) {
  aRead = aRead+analogRead(potPin);
 }
 return aRead / span;
}

long readTemperature() {
 int aRead = readAverage();
 return ((100*1.1*aRead)/1024)*10;
}

void doTemperatureMeasurement() {
 long newTemperature = readTemperature();
 if (newTemperature != temperature) {
  temperature = newTemperature;
  printTemperature(temperature);
 }
}

Processing(version 2)

This this new code in place you can test the special message by opening the serial monitor and typing in 'get temp' but lets update the Processing application to make use of this new feature. Actually, we only need to add one extra line of code to the Processing application! On the line after we open the serial port and before we load the font, add the line:
port.write("get temp");
That's it. The Processing application will now load the temperature almost straight away. Not only will it not have to wait for the thermo sensor to register a temperature change but it also won't have to wait for the half second to pass as it did in the first version.

Next?

So, what's next? I'm not sure where I'll take the this thermo sensor device but a few thoughts occur to me. It would be nice to make the device perminent, perhaps by popping the microprocessor off the Arduino board (you can replace the chip fairly easily) and getting rid of the breadboard too.
It also might be interesting to investigate replacing the USB serial connection with perhaps a bluetooth connection or even a WiFi connection.