====== How to make a thermometer ======
{{:processing:processing_thermometer.png}}
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 [[http://processing.org/|Processing 2]] and [[http://processingjs.org/|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 =====
{{:processing:processing_get_internet_page.png?nolink&480|}}
The built-in function ''loadStrings'' will load local files or URLs.
/**
* 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:
/**
* 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 =====
{{:processing:processing_get_xml_page.png?nolink&480|}}
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.
/**
* 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 =====
{{:processing:processing_thermometer_digital.png?nolink|}}
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.
/*
* 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:
/**
* 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 =====
{{:processing:processing_thermometer_meter.png?nolink|}}
Representing quantities graphically. Note also the use of Javadoc-style documentation comments for the functions.
/**
* 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.
/**
* 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);
}