October 25, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Play it Cool: Solving Thermal Problems

  • August 30, 2006
  • By Steve Schafer
  • Send Email »
  • More Articles »

Thermal problems have been a major bane of computers since the very first computer was plugged into AC power. This series explores how a system can be built to monitor and report room temperatures using methods that can be duplicated for a variety of uses.

In Review

The previous two articles in this series Play It Cool: Remote Monitoring of Equipment Room Temps and Play It Cool: Incorporating Reporting Mechanisms from Physical Devices showed how a modular scripting system was built around a single temperature sensor connected to a serial port. The system read the temperature from the sensor, reported it in a variety of ways, and could even read the temperature audibly at regular intervals. This article improves upon the serial-port communication between the scripts and the sensor, and shows how an analog button can be added to perform certain functions on demand.

Note: This series of articles uses Linux as the operating system of choice, with scripts written for the shell (Bash) and in Perl. For the tasks outlined within this series, I found Linux to be ideal. If you're using a different programming platform, or if you're unable to replicate these methods on Linux, you'll still gain value from these articles. Where possible, I'll point out analogous possibilities in Windows and other operating systems.

Faulty Readings

After using my temperature-reading mechanism for a few weeks, I noticed some disturbing trends in the data. Sometimes the sensor would report "32 degrees Fahrenheit." After investigating the various pieces involved in the mechanism, I determined that Kermit was the root cause, returning bogus results that the rest of the mechanism interpreted as 32 degrees.

I've never quite determined why Kermit wasn't reading the sensor data correctly, but suspect the way that Kermit initializes the serial port. The temperature sensor relies on power from the RTS and DTR serial lines-I suspect that Kermit might drop those lines when initializing the port. Occasionally the script runs faster or slower than normal, catching the sensor without power, and hence returning bogus readings.

In any case, a new mechanism was needed to read the sensor. For a variety of reasons, I settled on Perl, with the addition of the Device::Serial module to handle the communication.

Note: The Device::Serial Perl module handles most of the rigors of serial-port manipulation, allowing the programmer to concentrate on what to send to and receive from the port. Device::Serial is available packaged for most Linux distributions or from CPAN (Comprehensive Perl Archive Network).

Of course, most languages available today have serial-handling modules available. My choice to use Perl in particular was driven by many factors, but other languages (C, Python, etc.) could be used just as easily.

Implementing Perl and the Device::Serial Object

The Device::Serial module provides an object-oriented interface to serial ports. Using this interface follows the typical methods for such interfaces:

  1. Create a new serial-port object.
  2. Configure the new object.
  3. Manipulate the object as necessary.
  4. Destroy the object.

My original Kermit script wasn't very flexible-it operated only on one serial port, which was hard-coded into the script. At the time I was poised to rewrite the serial-port handling part of the mechanism, my employers were also looking to implement a system for monitoring their server room and lab. I decided to write the new Perl script to be more flexible, by accepting the serial port to poll as an argument on the command line.

Note: As you might recall from the previous articles in this series, it's important to keep the system modular in design and not load any one piece with more than one task. In this case, the modular task is returning data from the sensor connected to a serial port. However, that data has one purpose-to be converted to a temperature value-so this script was designed to read the raw data and convert it to a usable temperature value.

The complete script is shown in Listing 1. The comments included in the script appropriately outline and document its functionality.

Listing 1: The readtemp.pl Perl script

#!/usr/bin/perl -w

# Declarations
use strict;
use Device::SerialPort qw( :PARAM :STAT 0.07 );
use vars qw /$VERSION/;
($VERSION) = '$Revision: 1.0 $' =~ /([d.]+)/;
my ($num, $char, $countchar, $buffer, $argument, $port);

# Get argument(s) from command line
if (@ARGV) {
  $port = "";
  # Note that the server room sensor is connected to 
  #   serial port 1 (ttyS0), lab sensor to serial
  #   serial port 2 (ttyS1)
  $argument = (shift @ARGV);
  if ($argument eq "ttyS0" || $argument eq "server") {
    $port = "/dev/ttyS0" }
  if ($argument eq "ttyS1" || $argument eq "lab" ) {
    $port = "/dev/ttyS1" }

  # If the port is set, proceed
  if ($port ne "" ) {

    # Open port
    my $PortObj = Device::SerialPort->new($port);

    # Init port and protocol vars
    my $STALL_DEFAULT=10;
    my $timeout=$STALL_DEFAULT;
    $PortObj->baudrate(9600);
    $PortObj->parity("none");
    $PortObj->databits(8);
    $PortObj->stopbits(1);
    
    # don't wait for each character
    $PortObj->read_char_time(0);   
    # 1 second per unfulfilled "read" call
    $PortObj->read_const_time(1000); 

    # Raise DTR and RTS
    my $dtr=$PortObj->dtr_active(1);
    my $rts=$PortObj->rts_active(1);

    # Clear buffers
    $PortObj->lookclear;
    $char = $PortObj->read(4);

    # Send temp read command
    $countchar = $PortObj->write("!0RT");

    # Read two-byte response (discard first byte)
    $char = $PortObj->read(1);

    # Close and destroy port
    undef $PortObj;

    # Convert to temp reading and output
    if ($char ne "") {
      $num = (ord($char) / 2 * 9 / 5) + 32;
    } else {
      $num = "Error reading temperature!";
    }
    print "$numn";

  } else {

    # If port not set, wrong params given on 
    #   command line; display usage
    &usage; }

} else {

  # If no arguments are given, display usage
  &usage; }

  # Display usage
sub usage {
  die "nUsage: readtemp.pl ttyS0 | ttyS1 | server | lab$!nn";
}

As the code shows, specifically in the usage() function, the script accepts four parameters to determine the serial port that you want to access. Because the script was meant for Progeny's use, I included "server" and "lab" as shortcuts for the ports to which the appropriate sensor was connected. Users who were unsure of which port was for the lab sensor could simply run the script with "lab" as the parameter, to have the script return the temperature in the lab. An even more flexible construction would have been to create a configuration file that mapped the ports to human-readable forms as needed. However, that was overkill at the time, when the script was intended for limited use.

This one script replaced the use of Kermit and its script, as well as the Perl routine to convert the sensor's reading to a temperature value. The new script functioned much better than the Kermit solution-no errors in reading, and a lot less overhead.



Page 1 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel