User Tools

Site Tools


processing:thermometer_example

How to make a thermometer

The following examples will show you:

  • How to get data from the Internet.
  • How to scrape data.
  • How to draw fonts.
  • How to create a simple graphic meter.
  • How to invoke an action periodically.

You won't find much description below. I may add some later, but my intent here is just to do a structured code dump.

Because applet support has been removed in Processing 2 and Processing.js doesn't allow downloading arbitrary files, linking to live examples that work in the browser from this page is not possible.

Getting files from the Internet

The built-in function loadStrings will load local files or URLs.

get_internet_page_simple.pde
/**
 * Gets a file from a URL and prints it out to the console.
 * 
 * Copyright (C) 2012 Mithat Konar
 */
 
final String THE_URL = "http://www.w3.org";
String[] lines;
 
void setup() {
  lines = loadStrings(THE_URL);
 
  if (lines != null)
  {
    println("there are " + lines.length + " lines");
    for (int i=0; i < lines.length; i++) {
      println(lines[i]);
    }
    println("There were " + lines.length + " lines.");
  }
  else
    println("Problem loading " + THE_URL);
}

This version adds exception handling and graphic feedback:

get_internet_page.pde
/**
 * Gets a file from a URL and prints it out to the console.
 * This version uses exceptions and adds graphic feedback.
 * 
 * Copyright (C) 2012 Mithat Konar
 */
 
// constants
final String THE_URL = "http://www.w3.org";
final int CANVAS_BORDER=10;
 
// global variables
String[] lines;
 
void setup() {
  size(160, 90);
  smooth();
  try {
    lines = loadStrings(THE_URL);
 
    for (int i=0; i < lines.length; i++) {
      println(lines[i]);
    }
    println("There were " + lines.length + " lines.");
 
    // Turn the canvas green to show that all went well.
    background(#00cc00);
  }
  catch (Exception e) {
    // In case there is an error, print out the error to the console and
    // turn the canvas red with a big 'X' in it.
    println("Problem loading " + THE_URL);
    println(e);
 
    // Turn the canvas red with a big 'X' in it to indicate error.
    background(#ff0000);
    strokeWeight(5);
    line(CANVAS_BORDER, CANVAS_BORDER, width-CANVAS_BORDER, height-CANVAS_BORDER);
    line(CANVAS_BORDER, height-CANVAS_BORDER, width-CANVAS_BORDER, CANVAS_BORDER);
  }
  println("Exiting app.");
}

Scraping XML for data

Grabbing selected data from an XML source is easy with Processing's XML class. In this example, we load an RSS feed (which is XML) and extract some data from it.

get_xml_page.pde
/**
 * Gets data from Yahoo RSS weather feed, picks off some information,
 * and prints it to the console.
 * 
 * Copyright (C) 2012-2013 Mithat Konar
 */
 
// Constants:
// change the URL to get the desired location and units
// (see http://developer.yahoo.com/weather/).
final String URL = "http://weather.yahooapis.com/forecastrss?w=12781882&u=f";
 
// path in XML data to current conditions:
final String ELEMENT_CONDITION="channel/item/yweather:condition";
 
// attribute name in element above for current temperature:
final String ATTRIBUTE_CONDITION_TEMPERATURE = "temp";
 
// path in XML data to element that holds units of measurement:
final String ELEMENT_UNITS = "channel/yweather:units";
 
// attribute name in element above that holds units for temperature:
final String ATTRIBUTE_UNIT_TEMPERATURE = "temperature";
 
// misc.
final int CANVAS_BORDER=10;
 
// Functions:
void setup() {
  size(160, 90);
  smooth(); 
 
  try {
    XML weather = loadXML(URL);  // instantiate an XML object from URL.
    XML condition = weather.getChild(ELEMENT_CONDITION);  // pull current cond.
    XML units = weather.getChild(ELEMENT_UNITS);  // pull units data
 
    // Turn the canvas green to show that all went well.
    background(#00cc00);
 
    // "\u00b0" is the degree symbol
    println("The content:");
    println(condition.getInt(ATTRIBUTE_CONDITION_TEMPERATURE) + "\u00b0 "
            + units.getString(ATTRIBUTE_UNIT_TEMPERATURE));
    println("End content.");
  }
  catch (Exception e) {
    println("Problem loading " + URL);
    println(e);
 
    // Turn the canvas red with a big 'X' in it to indicate error.
    background(#ff0000);
    strokeWeight(5);
    line(CANVAS_BORDER, CANVAS_BORDER, width-CANVAS_BORDER, height-CANVAS_BORDER);
    line(CANVAS_BORDER, height-CANVAS_BORDER, width-CANVAS_BORDER, CANVAS_BORDER);
  }
 
  println("Exiting app.");
}

A digital thermometer

Fonts are graphics in Processing. To get the following to work, you'll need to create the *.vlw file using the Tools > Create Font… menu item.

thermometer_digital.pde
/*
 * Gets temperature data from Yahoo RSS feed and displays it numerically
 * on the canvas.
 * 
 * Copyright (C) 2012-2013 Mithat Konar
 */
 
// Constants:
// change the URL to get the desired location and units
// (see http://developer.yahoo.com/weather/).
final String URL = "http://weather.yahooapis.com/forecastrss?w=12781882&u=f";
 
// path in XML data to current conditions:
final String ELEMENT_CONDITION="channel/item/yweather:condition";
 
// attribute name in element above for current temperature:
final String ATTRIBUTE_CONDITION_TEMPERATURE = "temp";
 
// path in XML data to element that holds units of measurement:
final String ELEMENT_UNITS = "channel/yweather:units";
 
// attribute name in element above that holds units for temperature:
final String ATTRIBUTE_UNIT_TEMPERATURE = "temperature";
 
// misc.
final int CANVAS_BORDER=10;
 
// Functions:
void setup() {
  size(250, 140);
  smooth(); 
 
  try {
    XML weather = loadXML(URL);  // instantiate an XML object from URL
    XML condition = weather.getChild(ELEMENT_CONDITION);  // pull current cond.
    XML units = weather.getChild(ELEMENT_UNITS);  // pull units data
 
    background(#296783);
 
    PFont font;  // we'll use this to hold font data
    font = loadFont("Monospaced.bold-48.vlw"); 
    textFont(font, 48);
    textAlign(CENTER, CENTER);
    fill(#ffffff);
    text(condition.getInt(ATTRIBUTE_CONDITION_TEMPERATURE) + "\u00b0" + units.getString(ATTRIBUTE_UNIT_TEMPERATURE), width/2, height/2);
  }
  catch (Exception e) {
    println("Problem loading " + URL);
    println(e);
 
    // Turn the canvas red with a big 'X' in it to indicate error.
    background(#ff0000);
    strokeWeight(5);
    line(CANVAS_BORDER, CANVAS_BORDER, width-CANVAS_BORDER, height-CANVAS_BORDER);
    line(CANVAS_BORDER, height-CANVAS_BORDER, width-CANVAS_BORDER, CANVAS_BORDER);
  }
 
  println("Exiting app.");
}

Abstracting the drawing with a function:

thermometer_digital_func.pde
/**
 * Gets temperature data from Yahoo RSS feed and displays it numerically
 * on the canvas. This version uses a function to abstract the drawing.
 *
 * Copyright (C) 2012-2013 Mithat Konar
 */
 
// Constants:
// change the URL to get the desired location and units
// (see http://developer.yahoo.com/weather/).
final String URL = "http://weather.yahooapis.com/forecastrss?w=12781882&u=f";
 
// path in XML data to current conditions:
final String ELEMENT_CONDITION="channel/item/yweather:condition";
 
// attribute name in element above for current temperature:
final String ATTRIBUTE_CONDITION_TEMPERATURE = "temp";
 
// path in XML data to element that holds units of measurement:
final String ELEMENT_UNITS = "channel/yweather:units";
 
// attribute name in element above that holds units for temperature:
final String ATTRIBUTE_UNIT_TEMPERATURE = "temperature";
 
// misc.
final int CANVAS_BORDER=10;
 
// Functions:
void setup() {
  size(250, 140);
  smooth(); 
 
  try {
    XML weather = loadXML(URL);  // instantiate an XML object from URL
    XML condition = weather.getChild(ELEMENT_CONDITION);  // pull current cond.
    XML units = weather.getChild(ELEMENT_UNITS);  // pull units data
 
    background(#296783);
    drawDigitalTemp(condition.getInt(ATTRIBUTE_CONDITION_TEMPERATURE), 
        units.getString(ATTRIBUTE_UNIT_TEMPERATURE), width/2, height/2);
  }
  catch (Exception e) {
    println("Problem loading " + URL);
    println(e);
 
    // Turn the canvas red with a big 'X' in it to indicate error.
    background(#ff0000);
    strokeWeight(5);
    line(CANVAS_BORDER, CANVAS_BORDER, width-CANVAS_BORDER, height-CANVAS_BORDER);
    line(CANVAS_BORDER, height-CANVAS_BORDER, width-CANVAS_BORDER, CANVAS_BORDER);
  }
 
  println("Exiting app.");
}
 
/**
 * Render the temperature numerically at a given canvas location.
 */
void drawDigitalTemp(int temperature, String units, int x, int y)
{
  PFont font;
  font = loadFont("Monospaced.bold-48.vlw"); 
  textFont(font, 48);
  textAlign(CENTER, CENTER);
  fill(#ffffff);
  text(temperature + "\u00b0" + units, x, y);
}

Adding a graphic meter

Representing quantities graphically. Note also the use of Javadoc-style documentation comments for the functions.

thermometer_meter.pde
/**
 * Gets temperature data from Yahoo RSS feed and displays it in a meter
 * as well as numerically.
 *
 * Copyright (C) 2012-2013 Mithat Konar
 */
 
// Constants:
// change the URL to get the desired location and units
// (see http://developer.yahoo.com/weather/).
final String URL = "http://weather.yahooapis.com/forecastrss?w=12781882&u=f";
 
// path in XML data to current conditions:
final String ELEMENT_CONDITION="channel/item/yweather:condition";
 
// attribute name in element above for current temperature:
final String ATTRIBUTE_CONDITION_TEMPERATURE = "temp";
 
// path in XML data to element that holds units of measurement:
final String ELEMENT_UNITS = "channel/yweather:units";
 
// attribute name in element above that holds units for temperature:
final String ATTRIBUTE_UNIT_TEMPERATURE = "temperature";
 
// misc.
final int BORDER=10;
 
// Functions:
void setup() {
  size(200, 100);
  smooth(); 
 
  try {
    XML weather = loadXML(URL);  // instantiate an XML object from URL
    XML condition = weather.getChild(ELEMENT_CONDITION);  // pull current cond.
    XML units = weather.getChild(ELEMENT_UNITS);  // pull units data
 
    background(#296783);
 
    int temperature = condition.getInt(ATTRIBUTE_CONDITION_TEMPERATURE);
    drawDigitalTemp(temperature, units.getString(ATTRIBUTE_UNIT_TEMPERATURE),
                    width/2, height/2);
    drawMeter(temperature, -40, 120, 10, height-2*BORDER, width-10-BORDER, BORDER);
  }
  catch (Exception e) {
    println("Problem loading " + URL);
    println(e);
 
    // Turn the canvas red with a big 'X' in it to indicate error.
    background(#ff0000);
    strokeWeight(5);
    line(BORDER, BORDER, width-BORDER, height-BORDER);
    line(BORDER, height-BORDER, width-BORDER, BORDER);
  }
 
  println("Exiting app.");
}
 
/**
 * Render a temperature numerically at a given canvas location.
 *
 * @param temperature the temperature to be drawn (int)
 * @param units       the units of measure used for temperatre (String)
 * @param x           the horizontal location of the display (int)
 * @param y           the vertical location of the display (int)
 *
 * @return void
 */
void drawDigitalTemp(int temperature, String units, int x, int y)
{
  PFont font;
  font = loadFont("Monospaced.bold-48.vlw"); 
  textFont(font, 48);
  textAlign(CENTER, CENTER);
  fill(#ffffff);
  text(temperature + "\u00b0" + units, x, y);
}
 
/**
 * Render a value on a vertical meter.
 *
 * @param val      the value to be drawn (float)
 * @param minimum  val's value that corresponds to no deflection (float)
 * @param minimum  val's value that corresponds to maximum deflection (float)
 * @param w        the width of the meter (int)
 * @param h        the height of the meter (int)
 * @param x        the horizontal location of the meter (int)
 * @param y        the vertical location of the meter (int)
 *
 * @return void
 */
void drawMeter(float val, float minimum, float maximum, int w, int h, int x, int y)
{
  // calculate height of indicator in pixels
  float barHeight=map(val, minimum, maximum, 0, h);
 
  // draw the indicator
  strokeWeight(1);
  stroke(#ff0000);
  fill(#e00000);
  rect(x, y+(h-barHeight), w, barHeight);
 
  // draw the frame
  noFill();
  stroke(#1F4D62);
  rect(x, y, w, h);
}

Updating the data

Don't sleep. Poll instead. The following updates the temperature display every minute.

thermometer_update.pde
/**
 * Gets temperature data from Yahoo RSS feed and displays it in a meter
 * as well as numerically; updates periodically.
 * 
 * Copyright (C) 2012-2013 Mithat Konar
 */
 
// Constants:
// change the URL to get the desired location and units
// (see http://developer.yahoo.com/weather/).
final String URL = "http://weather.yahooapis.com/forecastrss?w=12781882&u=f";
 
// path in XML data to current conditions:
final String ELEMENT_CONDITION="channel/item/yweather:condition";
 
// attribute name in element above for current temperature:
final String ATTRIBUTE_CONDITION_TEMPERATURE = "temp";
 
// path in XML data to element that holds units of measurement:
final String ELEMENT_UNITS = "channel/yweather:units";
 
// attribute name in element above that holds units for temperature:
final String ATTRIBUTE_UNIT_TEMPERATURE = "temperature";
 
// misc.
final int BORDER=10;
 
// Global variables:
int oldMinute;  // used to keep track of time last update was made.
 
// Functions:
void setup() {
  size(200, 100);
  smooth(); 
  background(#296783); 
  oldMinute = minute();
  updateTemp();
}
 
void draw() {
  // updateTemp every minute
  int currentMinute = minute();
  if (oldMinute != currentMinute) {
    updateTemp();
    oldMinute = currentMinute;
  }
}
 
/**
 * Update the display of the current temperature.
 *
 * @return void
 */
void updateTemp() {
  try {
    XML weather = loadXML(URL);  // instantiate an XML object from URL
    XML condition = weather.getChild(ELEMENT_CONDITION);  // pull current cond.
    XML units = weather.getChild(ELEMENT_UNITS);  // pull units data
 
    background(#296783);
    int temperature = condition.getInt(ATTRIBUTE_CONDITION_TEMPERATURE);
    drawDigitalTemp(temperature, units.getString(ATTRIBUTE_UNIT_TEMPERATURE),
                    width/2, height/2);
    drawMeter(temperature, -40, 120, 10, height-2*BORDER, width-10-BORDER, BORDER);
 
    // uncomment println below for debugging. 
    // println("updateTemp() called at " + hour() + ":" + minute() + ":" + second() + 
    //         ". " + condition.getInt(ATTRIBUTE_CONDITION_TEMPERATURE) + " degrees.");
  }
  catch (Exception e) {
    println("Problem loading " + URL);
    println(e);
 
    // Turn the canvas red with a big 'X' in it to indicate error.
    background(#ff0000);
    strokeWeight(5);
    line(BORDER, BORDER, width-BORDER, height-BORDER);
    line(BORDER, height-BORDER, width-BORDER, BORDER);
  }
}
 
/**
 * Render the temperature numerically at a given canvas location.
 *
 * @param temperature the temperature to be drawn (int)
 * @param units       the units of measure used for temperatre (String)
 * @param x           the horizontal location of the display (int)
 * @param y           the vertical location of the display (int)
 *
 * @return void
 */
void drawDigitalTemp(int temperature, String units, int x, int y)
{
  PFont font;
  font = loadFont("Monospaced.bold-48.vlw"); 
  textFont(font, 48);
  textAlign(CENTER, CENTER);
  fill(#ffffff);
  text(temperature + "\u00b0" + units, x, y);
}
 
/**
 * Render a value on a vertical meter.
 *
 * @param val      the value to be drawn (float)
 * @param minimum  val's value that corresponds to no deflection (float)
 * @param minimum  val's value that corresponds to maximum deflection (float)
 * @param w        the width of the meter (int)
 * @param h        the height of the meter (int)
 * @param x        the horizontal location of the meter (int)
 * @param y        the vertical location of the meter (int)
 *
 * @return void
 */
void drawMeter(float val, float minimum, float maximum, int w, int h, int x, int y)
{
  // calculate height of indicator in pixels
  float barHeight=map(val, minimum, maximum, 0, h);
 
  // draw the indicator
  strokeWeight(1);
  stroke(#ff0000);
  fill(#e00000);
  rect(x, y+(h-barHeight), w, barHeight);
 
  // draw the frame
  noFill();
  stroke(#1F4D62);
  rect(x, y, w, h);
}
processing/thermometer_example.txt · Last modified: 2013/08/04 04:55 by mithat