Analysis / Culture / Technology / Tutorials

Off-The-Shelf Hacker: Showing Temperatures on an ‘Analog’ Gauge

6 Sep 2017 12:00pm, by

One of the great things about physical computing is that once you get a few basics down, you’ll start to see how you can just plug “modules” together and come up with new projects. Cobble up a few “modules” and you’ll have your own little Off-The-Shelf inventory of useful gadgets, for use in various jobs. Start thinking of modules as software, firmware, hardware, networking, mechanisms, aesthetics, etc. or any/all of the above.

After having decent luck with the ultrasonic range finder gauge last week, I thought it would be useful to try displaying some other values. This week I hooked up the old thermocouple module to the Linux notebook to see how a Processing programming language-based gauge worked with temperatures.

The thermocouple (and amplifier) I used hooks up to an Arduino Duemilanove via the SPI bus. The Arduino was then connected to the Linux notebook by a standard USB cable. Using USB makes the “module” portable between the notebook, a Raspberry Pi and a CHIP computer. The range finder hooked up to an Arduino Pro Mini that then connected to the Raspberry Pi, on the conference badge. Linux is eating the World!

Using a USB port, on any machine, is a little tricky, so let’s start off with a discussion on that topic.

Straightening out the Serial Port

When installing a new version of Linux, a regular user usually doesn’t have access to reading and writing directly to the USB ports. You could change the permissions with the chmod command, although that’s a bit messy and changes as you plug things in and out of the port.

The easiest way to get access is to add the user (rob, in my case) to the “dialout” group. You’ll need to use sudo, for it to work.

rob%  sudo usermod -a -G dialout rob

Once, that’s finished, reboot the machine, to clean up any old, crazy permissions and log back in.

rob%  sudo shutdown -r now

After you’re back at the desktop, open a terminal and execute the stty command. This sets the port speed. If the port speed doesn’t match the data rate coming from the Arduino, you won’t be able to see data coming in using the “cat” command. What’s more, the indicator line on the gauge, won’t show up either:

rob%  stty -icrnl -F /dev/ttyUSB0 11520

Use the following as a quick check, when you are testing data input from the USB port:

rob%  cat /dev/ttyUSB0

With the USB port squared away, it’s time to get the firmware on the Arduino working.

Reading the MAX Thermocouple

At the end of last year, I talked about using a standard K-type thermocouple and amplifier to measure temperature values, in my kitchen oven.

The code for the Arduino came from the MAX3156 example. I modded it a bit, to take out some un-needed “println” statements and add a Celsius to Fahrenheit conversion. I like to see my temperatures in Fahrenheit degrees. Notice too, that I added an “int” type assignment in the conversion. We don’t really need decimals for an analog gauge, so integer temperature values are fine and make the output easier to read.

If you are using a Duemilanove Arduino, go ahead and compile then upload the firmware to the board. If you are using some other Arduino, like a Pro Mini or Uno, make sure you specify the right board under the ‘Tools’ and ‘Board’ drop-down menus.

#include <SPI.h>
#include <Adafruit_MAX31856.h>

// use hardware SPI, pass in the CS pin
Adafruit_MAX31856 max = Adafruit_MAX31856(10);

void setup() {


  switch ( max.getThermocoupleType() ) {
    case MAX31856_TCTYPE_B: break;
    case MAX31856_TCTYPE_E: break;
    case MAX31856_TCTYPE_J: break;
    case MAX31856_TCTYPE_K: break;
    case MAX31856_TCTYPE_N: break;
    case MAX31856_TCTYPE_R: break;
    case MAX31856_TCTYPE_S: break;
    case MAX31856_TCTYPE_T: break;
    case MAX31856_VMODE_G8: break;
    case MAX31856_VMODE_G32: break;
    default: break;

  // mlx.begin(); 


void loop() {

  // thermocouple temp measured by MAX amp board
  uint8_t fault = max.readFault();
  if (fault) {
    if (fault & MAX31856_FAULT_CJRANGE) Serial.println("Cold Junction Range Fault");
    if (fault & MAX31856_FAULT_TCRANGE) Serial.println("Thermocouple Range Fault");
    if (fault & MAX31856_FAULT_CJHIGH)  Serial.println("Cold Junction High Fault");
    if (fault & MAX31856_FAULT_CJLOW)   Serial.println("Cold Junction Low Fault");
    if (fault & MAX31856_FAULT_TCHIGH)  Serial.println("Thermocouple High Fault");
    if (fault & MAX31856_FAULT_TCLOW)   Serial.println("Thermocouple Low Fault");
    if (fault & MAX31856_FAULT_OVUV)    Serial.println("Over/Under Voltage Fault");
    if (fault & MAX31856_FAULT_OPEN)    Serial.println("Thermocouple Open Fault");

  delay(100);  //sample duration - adjusted - gives 1 second per sample with this code

double Celcius2Fahrenheit(double celsius)
  return 1.8 * celsius + 32;

Test that the code works with the serial monitor, built into the Arduino IDE. Alternately, close out the Arduino IDE and use the cat command.

rob%  cat /dev/ttyUSB0

Occasionally, my Arduino IDE setup won’t release the USB port properly. I haven’t run the problem down completely, so if you have continue having problems reading the USB port, log out and restart the machine. Just a heads up.

Displaying a Temperature on the Gauge

The Arduino Pro Mini, in the ultrasonic range finder gauge project sent distance values to the Processing gauge code, registering from 0 to 100 inches. You can have your Arduino output any range that you like. It’s just data.

The particular thermocouple I used can sense temperatures from about -340 to +900 degrees Fahrenheit. That means that the Arduino connected to the thermocouple can send values, in that range out through the USB port.

Now, the ultrasonic range finder Processing gauge program will only swing the needle from 0 to 100. Actually, that’s good enough to prove that the thermocouple can show values on the gauge, to I didn’t even bother to mod the range, for this project. I wanted to show how you could mix-and-match “modules” with minimal changes and still come out with something useful.

All I changed was to replace the “distance” variable with “temperature.” On the face of the gauge, I also changed it to read “Temperature in degrees F” instead of “Distance (in).” Everything else worked pretty much as is.

The lesson here is to get version 1.0 of a new project (even when plugging modules together) working properly. Then you can always go back and change the code for more functionality and capabilities. Don’t try to change too many things at once. Save the files in a version control program or just increment the names, so you can always go back to working code if you get off track.

Here’s the hacked Processing code.

 * Gauge 
 * The angle of each segment (in radians) is controlled by input from the 
 * serial port (/dev/ttyUSB0, /dev/ttyS0, etc.).


PFont font;
float x, y;
String angle = "10"; // angle in degrees
String temperature = "50";  // temperature degrees F
float anglef = 0.0;
float angle1 = 0.0;
float segLength = 110;
BufferedReader reader;
String line;

void setup() {
  size(350, 300);
  stroke(255, 160);
  x = width * 0.5;
  y = height * 0.8;
  font = loadFont("LiberationSans-20.vlw");
  reader = createReader("/dev/ttyUSB0");

void draw() {
  try {
    line = reader.readLine();
  } catch (IOException e) {
    line = null;
  if (line == null) {
    // Stop reading because of an error or file is empty
  } else {
    println("temperature = ", line);
  temperature = line;
  if (angle != null) {
    anglef = (180-(float(temperature))*1.8)*3.1416/180*-1;
    // scale the distance to an angle for the gauge
    println(temperature, " ",  anglef);  //in radians
  segment(x, y, anglef); 
  text("Temperature (deg F)", 175, 50);
  text("0", 35, 250);
  text("25", 65, 150);
  text("50", 175, 100);
  text("75", 285, 150);
  text("100", 320, 250);
  arc(175, 245, 240, 245, PI, TWO_PI);
  delay (100);

void segment(float x, float y, float a) {
  translate(x, y);
  line(0, 0, segLength, 0);

Load the code in the Processing IDE and hit the “Run” button to bring the gauge up on the screen.

Don’t forget to get the USB port in the right state, as previously outlined, otherwise, you won’t see a needle on the gauge.

Here’s a screenshot of the thermocouple/gauge reading the temperature in my freezer. Four degrees Fahrenheit! Maybe I should turn it up a notch and save some electricity. Well, the ice cream is never soupy.

Temperature reading of my freezer.

Going Further

There are tons of upgrade opportunities for this project.

Obviously, expanding the range of the gauge is a good first step. Wouldn’t it be interesting to be able to watch the needle swing from room temperature to 350 degrees F, as the oven warms up?

Another idea might be to mod the Processing code to make the gauge fill the entire notebook screen. I could see using this capability to display the temperature of the Pancake Bot griddle, on the notebook or an auxiliary projector screen, during one of our “Have A Short Stack With The New Stack” breakfast panel discussions.

It might also make sense to convert the Processing gauge program over to Python. Python runs on most Linux machines, including the Raspberry Pi and CHIP computer. The programs run from the command line and don’t need an IDE environment, like Processing. Sure, you can currently create an “application” that runs outside of Processing. I’ve had mixed results running the same code on an Intel Linux notebook or the Raspberry Pi. I could be that Python is more cross-platform capable.

A digest of the week’s most important stories & analyses.

View / Add Comments