thermd - Thermometer Daemon supporting HA7Net, EM1, TEMP08, RoomAlert, TemPageR, WeatherGoose (and their ilk), RacSense, serial port host adapters (ibuttonlink, DS9097E, DS9097, and DS2480B) and USB host adapters (DS9490 or PuceBaboon), QK145, VK011, and EnerSure data collectors, the Poseidon and Damocles series from HWg, LX-4008 and IR5150 from MRV (and other SNMP devices), Veris H8030, H8031, H8035 and H8036, Smart-Watt, Smart-SenseRH, and Smart-PDU from Smart Works, MaxBotix Sonar sensors, and the Proliphix line of IP-enabled thermostats.


Thermd is a four-function program to work with a very large family of environmental monitors.

Currently, thermd supports the following hardware and software devices:

The three operational modes of thermd are:

1 Logging daemon

The program will sample temperature readings and log them to a data file (one log file per sensor). The program will also optionally generate an RSS feed, with graphs (see below). The program will also optionally send weather information to Weather Underground ( for local weather station information.

2 Plotting/Printing/Image-annotating program

The program will also create Portable Network Graphic (PNG) files, text files which plot/list sensor readings, or will annotate an image with sensor readings (using ImageMagick)

3 CGI script

The program will act as a CGI script to interactively plot data, and allow a web surfer to step forwards and backwards in the logged data, looking a different views of the data.


Thermd natively supports English, Swedish, German, Dutch, Russian, and Spanish (translations to other languages will be welcomed). Web pages will be translated to the language of the person viewing them, while all other actions are done in the language in which the host machine resides.

Documentation and configuration error messages remain in English.


You must download and install the following modules from the CPAN in order to get thermd to function (thermd uses other modules, but they are part of the Perl default distribution).


When run from the command line, thermd can run either as a logging daemon, or as a plotting/reporting script. ALL RUNTIME FLAGS MAY BE ABBREVIATED! Note that when a flag is specified, it overrides any corresponding value in the config file (so specifying -width overrides the value of the GraphWidth configuration item).

Logging daemon

    thermd -daemon [-config file] [-nofork [-verbose]]
        -config file    Use this as a config file (default=/etc/thermd.conf)
        -nofork         Don't fork to background (usually only for debugging)
        -verbose        Verbose output (definitely for debugging :-)

Sending a HUP signal to the daemon will cause it to restart and re-read it's configuration file. The daemon automatically restarts every week to avoid possible memory leaks.


    thermd -report [report-args] [config-args, unit-args, range-args]
        -format type    One of CSV (comma separated values), TSV (tab
                        separated values), XML, CER (Eddy Common Event
                        Record) or Excel.
                        Default format is TSV
        -epochtime      When printing time, print Unix time(2), instead of
                        the default human-readable time
        -current        Print current values only
        -raw            Print all current values, in raw form


    thermd -graph [graph-args] [config-args, unit-args, range-args]
        -width pixels   Override the width of the graph.  If not specified
                        here, default value comes from the config file, and
                        that default value is 750
        -height pixels  Override the height of the graph.  If not specified
                        here, default value comes from the config file, and
                        that default value is 300
        -hilo           Graph 24-hour extremes instead of individual datapoints
                            This may get a bit hard to read if you have too
                            many sensors being graphed
        -nosmooth       When graphs get dense (typ. > 1 month of data), graph
                            data is automatically smoothed.  This switch
                            defeats that function.

Image Annotation

    thermd -annotate [annotate-args] [config-args, unit-args]
        -current        Print current temperatures only (default)

Shared arguments available to reporting, graphing and annotating

    Common config-args
        -config file    Use this as a config file (default=/etc/thermd.conf)
        -outfile file   Output graph/table to this file (instead of STDOUT)
        -view name      Show a named view (defined in config file, default=all)
        -all_sensors    Ignore/override any -view, and show *all* sensors
        -nowarn         Do not print configuration warnings

    Common unit-args
        -units {English|Metric}
                        Use English/Metric units (override config file)
        -temperature {C|F}
                        Show temperature values as (override config and -units)
        -windspeed {mph|kph|mps|knots}
                        Show windspeed values as (override config and -units)
        -rainfall {inches|mm}
                        Show rainfall values as (override config and -units)
                        (also affects MaxBotix "range" values)
        -barometer {inHg|mmHg|hPa|kPa|mBar|millibar}
                        Show barometer values as (override config and -units)

    Common range-args
        -from daytime   From date/time *
        -to daytime     To date/time *
        -center daytime Center chart on date/time *
        -span reltime   Span for centered chart **

        * Date/time values may be specified as:
            absolute (ex: "20030228" or "20030228T1535" - actually, any
                format allowed by HTTP::Date)
            relative (ex: 3d, -2.5h, 3w, +5m3d1h, etc., suffixes are y=>year,
                m=>month, w=>week, d=>day, h=>hour)  Note: sign is highly
                significant, and changes what it is relative to...
            named (i.e., "now", "today", "yesterday"), considered absolute
                times as far as discussion below is considered

            If -from and -to are both missing, we assume: -from -1d -to now
            If -from is specified but -to is missing, we assume: -to now
            If -from is missing but -to is specified, we assume that -from
                is 1d before -from
            If -from is relative and -to is absolute, we assume that -from
                is relative to now and comes before -to (which means that
                sign is ignored!), so that if today is 20030327:
                    -from -1m -to 20030228       means the same as:
                    -from 20030227 -to 20030228
                Since sign is ignored here, you could also say:
                    -from 1m -to 20030228       or:
                    -from 1m -to yesterday      or:
                    -from +1m -to 20030228      (counterituitive, but legal)
            If -from is absolute and -to is relative, we assume that -to
                is relative to -from and comes after -from, so that:
                    -from 20030228 -to 1d       means the same as:
                    -from 20030228 -to +1d      means the same as:
                    -from 20030228 -to 20030301
                There is one special case: if -to is negative, it
                is interpreted as relative to "now", so:
                    -from 20030228 -to -1d      (from 20030228 to yesterday)
            If both -from and -to are relative, then both are considered to
                be relative to "now" (with one exception), so that:
                    -from -5d -to -4d           means the same as:
                    -from +5d -to 4d            ignore sign on -from, same as:
                    -from 5d -to 4d             but:
                    -from -4d -to -5d           illegal reverse range!
                There is one special case: if -to is positive (i.e., +time),
                then it is relative to -from, so:
                    -from -5d -to +1d           means the same as:
                    -from -5d -to -4d

        ** Span values may only be relative, see above
            If -center is specified, but -span is missing, then -span
            defaults to 1d (i.e., from 12h before to 12h after -center)

Checking your configuration

    thermd -checkconfig [check-args]
        -checkconfig    Check the validity of the config file, and exit
        -config file    Use this as a config file (default=/etc/thermd.conf)
        -verbose        Output a full config file, with all defaults expressed
        -list           Prints a list of logfiles used by thermd (overrides
                        -verbose, and only prints the list)

CGI Script

Theoretically, just put thermd in your CGI area (or a link to the program, if you want to run the daemon froma different directory), and the rest should happen automatically :-) If you don't know how to set up a CGI script, you'll need to familiarize yourself more with your web server - there are too many variables to deal with in this document.

One word of advice - if it doesn't work as expected, look at the error logs for your web server (a lot of people forget to do this).


The configuration file (located in /etc/thermd.conf by default, and specified by the -config runtime option).

Contents of the file (overview)

The configuration file is read once at program startup.

Global Configuration Attributes

The following attributes are used to configure many of the global attributes of thermd. All of them are optional, and have reasonable default values.

RSS Block

If it is present, then the RSS block defines the directory where the RSS information is written. If the RSS block is missing, no RSS feed will be generated. Note that it is an RSS block, so you must say something like:

    <RSS /var/www/KLEIN/thermd>

Unless some other View is marked as the DefaultView, the View named 'all' is automatically included in the RSS feed. See the View block and the RSSName directive below to learn what else can be shown in the RSS feed.

Collector, Sensor, and Actuator Blocks

Thermd supports multiple collectors (something that has one or more sensors on it), and multiple sensors (something that reports a temperature, humidity, wind speed, etc.). Your sensor network can be homo- or heterogenous (my development network has had dozens of sensors on 9 collectors of 7 different types active at one time).

Collector blocks are named (and the name can be anything you like, as long as each collector has a unique name)), so for example you would say:

    <Collector Fred>
        Type    QK145
        Device  /dev/cuaa0
        Scale   F
        <Sensor 1>
            Name        "Computer exhaust"
        <Sensor 2>
            Name        Refrigerator
            Adjust      -1

    <Collector Ethel>
        Type            HA7Net
        <Sensor 68000800141A8B10>
            Name        Basement
            Type        Temperature

Each collector has a number of attributes, and also has included Sensor blocks (one for each sensor that is configured). The attributes for a collector block are as follows:


Sensors report on their environment - for example, temperature, humidity, etc. (some collectors also have Actuators, see below). A sensor block (which must have a name) specifies all the attributes of a specific sensor. The sensor naming system depends on the collector, but each sensor must have a unique name:

Sensor Attributes

Regardless of the collector or sensor type, the sensor attributes are:


An Alarm block defines an extraordinary condition that you want to know about. Each Alarm must be named, and contains one or more alarm-related directives. The name of the alarm is arbitrary, so long as no two alarms for a single sensor have the same name. It is legal to specify multiple alarms per sensor, so you can have an Above and a Below alarm, three different Above alarms, etc. An alarm might look like this:

            <Alarm Roasting>
                Above   95
                ResetAt 90
                Times   08:00 - 23:59
                Notify  Fred Murwick <>
                Syslog  crit
                Close           A1@Mambo
                LockClose       A3@Salsa
                Open            A2@Rhumba
                Exec    "shutdown -h 5"

This would cause an alarm to be sounded when the temperature exceeded 95 degrees, and both Fred and Quincy would receive a pager message (in addition Fred receiving a regular email, a message being recorded in syslog, the switches A1 on the collector named Mambo and A3 on Salsa being closed, the switch A2 on the collector Rhumba being opened, and the "shutdown" program will be run) - but only if the alarm action occurred between 8am and one minute before midnight.

Once triggered, the alarm condition will reset only after the temperature drops below 90 degrees (note that resetting the alarm will also cause the switch A1@Mambo (but not A3@Salsa) to be Opened, and A2@Rhumba to be Closed, but the shutdown program will NOT be stopped if it is still running).

NOTE: See the global configuration options SMTPHost and Sendmail and the switches -checkconfig -email before using email-alarms.

IMPLEMENTATION NOTE: Since some sensors can occasionally give erratic values, Alarms are (generally) only triggered after the average of 5 consecutive readings exceeds the alarm criteria. This means that Alarms are triggered after some delay. If you wish a speedier response, you may consider changing the collector's PollInterval. If you need the ability to have alarms trigger on the first reading that exceeds the alarm criteria, write to, and I will implement the necessary changes as a configuration option.

IMPLEMENTATION NOTE: Alarms are not evaluated in any particular order. Thus if one alarm opens a switch and another alarm closes a switch, and both alarms trigger (or reset) at the same time, the final state of the switch cannot be predicted.

The attributes for Alarm blocks are:

Derived Sensors

There is a special type of pseudo-collector whose type is Derived. Within this collector, there can be a number of special computed sensors (that is, sensors whose value is mathematically based on other sensors). These sensors have all of the standard attributes (Name, Type, GraphColor, Alarm, etc), but also have special attributes found only in derived sensors. The sensor types and their special attributes are:

Actuators and Actuator Attributes

An Actuator block is available for some Collectors (for example, the built-in relays on the Poseidon and Damocles series from HWg, and "relays" for Modbus devices). Presently, actuators are used exclusively with Alarms (so when an alarm is triggered, an actuator can be opened or closed). This functionality may be expanded in the future - suggestions are welcome).

Actuators are also logged (so you can graph when they are actuated or not). With the exception of an Alarm block, all of the attributes that are valid for a Sensor are also valid for an Actuator. This includes the Name, and Type, but also the LogFile, Hide, ReadOnly, OnValue, OffValue, SNMPOnValue, SNMPOffValue, Instance, GraphColor, and LineType attributes (etc).

Actuators change their environment. An Actuator block (which must have a unique name that is distinct from any Sensor names)) specifies all the attributes of a specific actuator. The actuator naming system depends on the collector:

Regardless of the collector or actuator type, the actuator-specific attributes are:

View Block

A View block defines a way of looking at your data. When you have a lot of sensors, you can have multiple Views to allow you to look at your data in a variety of ways (for example, a view of upstairs data and a view of downstairs data, another for inside, outside, etc.) Each View much be named, and contains one or more Show or Show+ declarations. You may use any name for the view except All, which is reserved and automatically defined to contain every sensor (see the Sensor attribute Hide for specific exceptions to this rule).

There are three kinds of View: Graph (the default), which displays a time-based graph of data; Image, which writes only the current temperatures on top of a picture or drawing that you supply; and Wunderground, which sends weather data to Weather Underground ( for personal weather station information (you can also have a collector of type Wunderground - see above). The Graph and Image Views are listed in the output of the CGI script, and are also accessible from the command line via the -view option with -graph, -annotate, and -report. The Wunderground Views are silently sent to Weather Underground every LogInterval.

A sample graphical View block could look as follows. This would cause the View named "Inside" to be created, which would contain three sensors to show. It uses simple Show statements and more complicated Show+ blocks to define how sensors are graphed.

    <View Inside>
        RSSName Inside the House
        Show    1@Upstairs              # Sensor "1" on collector "Upstairs"
        <Show+  3@Upstairs>             # Sensor "3" on collector "Upstairs"
            GraphColor  black
            LineType    dotted
        Show    1@Downstairs

NOTE: The sensor and collector names referenced in Show and Show+ are Case SeNSiTive, and must exactly match the declared names.

Another View block could look as follows. This would create an annotated image, where the values of the same sensors were overlaid on the image of the house (along with the date and time). Image views can only use the more complicated Show+ blocks to define how sensors are displayed.

    <View Overview>
        RSSName Picture View
        Type    Image
        Image   /var/www/images/house.png
            X   400
            Y   402
            X   400
            Y   425
        <Show+  1@Upstairs>
            X   100
            Y   125
        <Show+  3@Upstairs>
            X   327
            Y   125
        <Show+  1@Downstairs>
            X   95
            Y   262

Note that if graphical View contains more than one class of sensor (for example, temperature and humidity), then the y-axis will be adjusted to contain the range of samples. This adjustment does not, of course, apply to annotated images (since there is no axis).

Another View block could look as follows. This would Send data to Weather Underground, where most of the sensor keys are automatically determines, but one of them is specified as sending indoor temperature.

    <View Weather>
        Type Wunderground
        StationID       KPAPITTS33
        Password        smashpunk3
        Show 1500000001622C1D.s@HA7Net  # Wind speed
        Show 1500000001622C1D.g@HA7Net  # Wind gust
        Show C2000000012E0B20@HA7Net    # Wind direction        
        <Show+  3@Upstairs>
            Key indoortempf             # Indoor temperature
        Show B80000004FC30A26@HA7Net    # Outdoor temperature

Common View Attributes

The following attributes can be used in any View:

View attributes for Type=Graph and Type=Image

View attributes for Type=Graph

View attributes for Type=Image

View attributes for Type=Wunderground

SNMP details

SNMP is pretty complicated, and thermd only supports the small fraction of it that it needs to get its job done (namely measuring and logging values). Thermd only supports static OIDs - not OIDs which are based on the contents of other OIDs, or "mapping" as it is sometimes called.

OIDs are expressed one of three ways in a sensor block (for the Poseidon and Damocles series from HWg, the OIDs are automatically determined from the sensor name, and do not need to be specified).

Sample configuration file

This is a simple configuration file, which resembles (but is not exactly the same as) that used on

    MailFrom    Thermometer Daemon <>

    <RSS /var/www/KLEIN/thermd>

    TimeZone    EST

    Location    "Klone's House"
    GPSCoordinates      "N40.441242456 W79.927382469 (WGS84)"
    MapURL              ",+Pittsburgh+PA&spn=0.032227,0.064703&hl=en"

    <Collector CheesePuff>
        Type    QK145
        Device  /dev/cuaa0
        Scale   F
        <Sensor 1>
            Name                "Computer exhaust"
            GraphColor  red
            <Alarm DangerWillRobinson>
                Above   95
                Subject "Maxwell over temp!"
                Message "%.0s%.1f%s"
        <Sensor 2>
            Name        "Basement"
            GraphColor  green
            LineType    dashed
            AdjustBy    +4
        <Sensor 3>
            Name        "Outside 1st floor"
            GraphColor  blue
            AdjustBy    +6
            <Alarm Freezing>
                Below   33
                ResetAt 40
                Dates   1 Apr - 1 Dec
                Times   08:00 - 23:59
            <Alarm Roasting>
                Above   95
                Times   08:00 - 23:59
        <Sensor 4>
            Name        "Inside 3rd floor"
            GraphColor  purple
            AdjustBy    +3

    <Collector BaconBits>
        Type    TEMP08
        Device  /dev/cuaa1
        <Sensor B80000004FC30A26>
            Name        Garage
            Type        Temperature
        <Sensor B80000004FC30A26.1>
            Name        Garage Humidity
            Type        Humidity
        <Sensor 1500000001622C1D.s>
            Name        Wind Speed
            Type        Speed
            <Alarm Hurricane>
                Above   75
                Message "%.0s Hurricane Force Winds - %.1fMPH!"
        <Sensor 1500000001622C1D.g>
            Name        Wind Gusts
            Type        Gust
        <Sensor C2000000012E0B20>
            Name        Wind Direction
            Type        Direction
        <Sensor 4300000005B9FA1D>
            Name        Rainfall
            Type        Rain

    <Collector MRV>
        Type SNMP
        Community ShrimpSalad
        BaseOID .  # mrvBpd.mrvLx.irCharMib
        <Instance Temperature>
            OID 4.1.3.N.1       # irTempValue
            Type Gauge          # Type will be inherited
        <Instance Humidity>
            OID 5.1.3.N.1       # irHumidityValue
            Type Gauge          # Type will be inherited

        # The IR5150 power outlet controller
        <Instance Power>
            OID 6.1.2.N         # PowerCurrentLoad
            Type Gauge
        <Instance Outlet>
            OID 7.1.4.N.M       # irPowerOutletStatus
            Type OnOff

        # T1 uses a relative OID, T2, H2 and the outlets use instances instead
        <Sensor T1>
            OID      # Or . (port 1)
        <Sensor T2>
            Name        Computer Temp
            OID Instance=Temperature, N=2       # port 2
        <Sensor H2>
            Name        Computer Hum
            OID Instance=Humidity, N=2          # port 2
        <Sensor O1>
            Name        Computer Power
            OID Instance=Outlet, N=3, M=1       # port 3, outlet 1
        <Sensor O2>
            Name        Router Power
            OID Instance=Outlet, N=3, M=2       # port 3, outlet 2
            Type        Gauge                   # Overrides Type from Instance
        <Sensor O3>
            Name        Switch Power
            OID Instance=Outlet, N=3, M=3       # port 3, outlet 3

    Blurb = <<EndOfBlurb
    I bought an inexpensive <a target="_blank"
    interface temperature sensor kit</a> (about US$30) from
    <a target="_blank" href="">QKits</a>
    and after I built the kit, I also purchased an extra 3 Dallas
    Semiconductor sensors (another US$18).  It is a very easy kit
    to build (it doesn't even need a power supply, it derives power
    from the RS-232 line it talks on), and the
    <a target="_blank" href="">QKits</a>
    folks are pleasant people to deal with.  Then I wrote a nice
    Perl-based thermometer logging daemon, log dumper, and CGI script
    (one program does all three functions!) available with both
    <a target="_blank" href="">source code</a>
    and <a target="_blank"
    This latest version of the Thermometer Daemon supports multiple sensors.
    <p />

    <View Inside>
        Show    1@CheesePuff
        Show    2@CheesePuff
        Show    4@CheesePuff
        <Show+  T2@MRV>
            LineType    Dashed
            Color       Green

    <View Outside>
        Show    3@CheesePuff
        Show    B80000004FC30A26@BaconBits
        Show    B80000004FC30A26.1@BaconBits

    <View Pix>
        Type            Image
        Image           /home/dvk/house.jpg
        Font            Helvetica
        FontSize        14
        Precision       1
           X            610
           Y            41
           X            620
           Y            58
        <Show+  1@CheesePuff>
            X           15
            Y           125
        <Show+  B80000004FC30A26@BaconBits>
            X           50
            Y           17
            Font        CourierBold
            FontSize    18
            TextColor   red
            Precision   3
            TextAlign   Center
            TextAngle   90


RacSense and WeatherGoose series

Each sensor has a Sensor Name and a Friendly Name (configurable by the Display tab on the device's web interface). Thermd uses the Sensor Name to read the sensors, so you may need to determine what the sensor's name is before configuring thermd.

It is also possible to configure temperature units that the web interfce uses. Since thermd reads the XML values from the device (which provides both Celsius and Fahrenheit), you may set the web interface to whatever you like, without worrying about how it will affect thermd.

Poseidon and Damocles series from HWg


You may specify a SubType of either HTTP (the default) or SNMP. The subtype determines how sensors are read. In SNMP mode, the sensors can be autoconfigured, but we no longer recommend this, as autoconfiguration must be done for every daemon, CGI script, RSS feed, etc.


If you plan on using Actuators on the Poseidon or Damocles, you must:

  1. Create a read-write community in the "SNMP Setup" tab of the device's Flash Setup).

  2. Specify the same community name in the thermd configuration file (see the Community attribute for the collector).

If you specify the name of a read-only Community in your config file, thermd will be unable to change the values of the actuators. Check the syslog files for error messages on daemon startup.

SNMP Traps and fast-reading dry-contact sensors

In order to take advantantage of the SNMP trap information for rapidly changing dry-contact values, a few specific details need to be configured to match on the Poseidon or Damocles and in thermd:

  1. You must have NET-SNMP version 5.3.0 or greater available on the same machine that thermd is running. This version will contain the correct version of snmptrapd.

  2. You must enable trap reception in the thermd configuration file. See the SNMPTrapPort and AllowSNMPTraps directives.

  3. You must enable the generation of traps on the Poseidon or Damocles. This means that in the Sensor Setup tab, you need to select one of the Active alarm states for each sensor you wish to be SNMP-trap monitored.

  4. In the SNMP Setup tab of the Poseidon or Damocles, for one of the SNMP Trap Destinations, you must check the "enable" checkbox and select a trap destination that is the same IP address as the machine upon which thermd is running, with a Port that is specified in the SNMPTrapPort attribute in the thermd configuraion file.



Default location of configuration file for thermometer program


Default directory for logging temperature information (if LogFormat is SQL, then this directory is not used).


Current temperatures (values are updated every 10 seconds or so; if LogFormat is SQL, then this directory is not used).


Default location of process ID of the logging daemon, if daemon is running.


This program was written by Daniel V. Klein, and is Copyright 2001-2009. All rights reserved - this program may be freely distributed so long as all copyright claims are preserved. Neither this program nor any derived programs may be sold without express written agreement by Daniel V. Klein,

Contributions of code have also been made by Aaron J Trevena (the original radial plot module) and Chris Kampmeier (the original image annotation code), along with contributions from numerous sources, as noted in the changelog.

Lars Karlander, Adam Thomas, Michael G. Petry, Nathan Glaser, Mario Berges, Tom Buskey, and Anders Brownworth have provided access to their networks for feature development, and Embedded Data Systems, Midon Design, AVTECH Software, SensaTronics, Trendline Data Systems, HW Group (of the Czech Republic), and Applied Power Technologies (APT) have graciously provided hardware.

Thank you to the following translators for internationalization: Roger Andersson for Swedish; Patrick Ben Koetter for German; Kristian Vilmann for Danish; Frank Kuiper for Dutch; Vladas Leonas for Russian; Mario Berges for Spanish.


 $Revision: 2.85 $
 $Date: 2014/08/24 15:21:31 $


 $Log: thermd,v $
 Revision 2.85  2014/08/24 15:21:31  root
 Wunderground was getting mm listed as in for rainfall

 Revision 2.84  2012/10/28 15:59:34  root
 Fixed bug in Newport/IOmega (thanks!) and in Gauges

 Revision 2.83  2010/02/16 20:00:51  root
 Drat - I forgot to take out the debug essages from the last checkin :-/

 Revision 2.82  2010/02/08 19:39:41  root
 Stupid error - I broke wind plotting before...

 Revision 2.81  2010/01/10 02:53:06  root
 Fixed readings for Omega/Newport iTHX-2 sensors (there were problems when
 there were more than one digit past the decimal point - a common occurance).
 Thank you to John Kielkopf for finding the bug.

 Revision 2.80  2009/12/30 22:37:57  root
 1) Added hPa and kPa (hecto- and kilo-Pascals) as Metric measures of
    barometric pressure, and made the default be hPa for everywhere except
    Canada (which is kPa) and England (which is mBar) - as opposed to my
    original wrong-sighted use of mmHg.
 2) Added XML as a web-based display type (it was previously added in v2.62
    as a command-line option, but now it is on the web).  The web display
    shows the current values for ALL sensors (regardless of View).
 3) Rewrote the interface for the Poseidon and Damocles series of collectors.
    Previously, they used SNMP to autoconfigure, read data, and deal with
    asynchronous events - now HTTP/XML is the default value with SNMP only used
    *optionally* used for asynchronous events (although you can still use SNMP
    for everything if you like)

 Revision 2.79  2009/11/13 01:09:23  root
 Discovered an OLD :-( bug in AdjustBy, wheree if you specified a value in
 degrees C and the sensor was in degrees F (or vise versa), it would asjust
 by the wrong value...

 Also, cleaned up some crap in the RoomAlert code

 Revision 2.78  2009/08/27 18:24:06  root
 1) Although owfs, owhttpd, owshell all read in C by default, the daemon
    can be started to read in F.  I now allow the Scale directive for them.
 2) Improved backgrounding a little.
 3) The 'current' table in MySql is now created with "ENGINE=innodb" to allow
    for table locking (the default is MyISAM, which did not allow locking).

 Revision 2.77  2009/06/16 22:53:35  root
 1) When a child process dies (that is, a poller process), thermd will now
    automatically restart it.  This should help with data dropouts.
 2) Fixed a bug in the Temp08 where rain sensors were being multiplied by .01
   (.01" is the multiplier for all rain sensors EXCEPT the Temp08)
 3) Largely rehacked the way readinglines and timing works in the daemon, so
    as to avoid the occasional data dropouts that I (and others) were seeing
    when the system was loaded.  It works better, but I still see dropouts :-(
 4) Updated the round-robin scheduler when a collector gets "stuck" (a rare,
    but annoying).
 5) Also fixed a bug in Math sensors, where you were penalized for not
    specifying Units.  I whine now, but don't crash.

 Revision 2.76  2009/04/30 14:31:52  root
 Added support for the MaxBotix line of sonar rangefinders

 Revision 2.75  2009/03/09 20:56:54  root
 New data collectors:
 1) Added a new CommandLine collector type.  This type executes shell commands
    to read sensor values, for those systems for which you have existing
    commands to extract values (for example, sysctl can be used to determine
    the temperature of the CPU).  Thanks to Todd Giles for the idea and
    preliminary version of the code!
 2) Added the Newport/Omega Engineering iServer family of collectors (thanks to
    help from Steve Lancaster of Xerox).  This includes the

 New sensors/actuators:
 1) The TAI8560 thermocouple module now works on the HA7Net (previously it
    only worked with owfs/owhttpd).  Thanks to Thomas Olson for the detective
    work needed to figure out the 1wire commands and the link to NIST.
 2) The LED in the TAI8560 thermocouple module now works on the HA7Net as an
    actuator (thanks again to Thomas Olson).

 Bug fixes and enhancements:
 1) Found and fixed a bug in HTTP authorization (thanks to Todd Giles)
 2) Fixed a few bugs in OWFS Sunlight and Barometer sensors (thanks Iain Mason)
 3) Fixed parsing of Wunderground data, so that empty data does not report
    as having the value 0 (but instead reports as "undefined").
 4) It seems that the multiplier tables for the Veris H8030/H8031 are somewhat
    different than the H8035/H8036, so these tables have now been fixed.  Also
    fixed a bug where register 40001 was not being reported (both thanks to
    Dan Hassler).
 5) Alarm thresholds (Above, Below, and ResetAt) and AdjustBy values used to
    be assumed to be in the Scale of the collector (which was an *optional*
    field, and might be C or F depending on the collector).  To avoid possible
    confusion, you must now specify temperature units in all these attributes.
 6) Actuators are now more correctly logged and reported on.

 Revision 2.74  2008/11/30 01:49:16  root
 A small bug in relative-date parsing was found and fixed by Joe Peters

 Revision 2.73  2008/11/23 23:36:06  root
 A new sensor family and some bug fixes

 1) Added support for the Veris Industries H8030, H8031, H8035, and H8036
    energy meters.

 2) Fixed a bug in HUP restart (found thanks to Dan Hassler)

 3) When I originally released them, I orgot to add dewpoint to Wunderground
    remote weather stations (also found thanks to Dan Hassler)

 Revision 2.72  2008/09/22 14:09:50  root
 Fixed two minor bugs in Derived collectors
 1) Would not correctly recognize the F.IC sensor naming format for owfs
 2) Would not properly handle floating point numbers

 Revision 2.71  2008/09/16 12:40:41  root
 This release features a large number of new features but also introduces a
 couple backwards incompatabilities (I apologize, but I feel it is all for the
 best, especially as they all have simple work-arounds).

 1) Added a new collector type Derived, which allows for "computed" sensors
    (that is, sensors whose value is derived from mathematical equations that
    involve other sensors).  The most flexible type is Math (which allows an
    arbitrary expression), but there are also builtin convenience types for
    WindChill, DewPoint, HeatIndex, and Humidex.

 2) Extended the Wunderground Collector (and View) to allow DewPoint

 3) There are six new Counter types, supported with the SubType attribute
    a) AvgRate - the number of clicks/second, averaged over LogInterval
    b) MaxRate - the highest value of clicks/second over LogInterval
    c) MinRate - the lowest value of clicks/second over LogInterval
    d) Count - the number of clicks over LogInterval
    e) Total - the cumulative number of clicks.  Resets to 0 after the time
       specified in InactivityReset has passed with no further increase.
    f) Raw - the number on the dial

    All the old counting types are still supported as special instances of the
    above (Speed is an AvgRate, Gust is a MaxRate, Lightning is a Count, Rain
    is a Total, and Gauge is a Raw).  You can us the old types without change.

 4) In general, you may now specify multiple reads per sensor (this means that
    you can, for example, show the raw and adjusted temperatures, or the CuFt
    and BTU equivalent for your gas meter, etc)

 5) For the HA7Net collector:
    a) The HA7Net firmware must be upgraded to at least version
       Keeping track of special cases was getting too difficult.
    b) For rate calculations, I now use the time field from HA7net (which means
       greater accuracy, since network delays no longer figure in calculations)
    c) You can now read either Channel A or Channel B (or both) on DS2423
       (previously, only Channel A was supported).

 6) For the RacSense collectors:
    a) Added KWh, Volts-Min and Volts-Max sensors for devices that support it.
    b) Cleaned up how sensors are detected (but based on revised information
       from Geist Manufacturing, it is no longer possible to detect impossible
       sensor/collector combinations).

 7) Added a Nice attribute to the RSS block for cycle-saving on low-power CPUs

 8) INCOMPATABILITIES (and work-arounds):
    a) All counters must have a Subtype.  If you want to preserve your existing
       behavior, use Subtype Count.
    b) I changed ResetAfter to InactivityReset (the documentation was confusing
       and I fixed both the attribute and the wording)
    c) The Lightning sensor type no longer allows ResetAfter.  If you *really*
       want that behavior, create a Counter with Subtype Total.
    d) The Combo attribute is gone.  There were very few sensors that needed it,
       it was confusing, and was there to allow a negligible optimization.
       Just delete it from your config files.

 Revision 2.70  2008/08/26 20:08:13  root
 Sigh - when I fixed a bug for thermocouples, I introduced on for other
 temperature sensors, which is now fixed.

 Revision 2.69  2008/08/25 22:46:23  root
 Martin Strandbygaard found a bug with DS18S20 and owhttpd

 Revision 2.68  2008/08/21 20:14:22  root
 Someone finally used the thermocouple code, and uncovered a few bugs, which
 are now fixed.

 Revision 2.67  2008/06/18 00:22:46  root
 Autoconfigure had some problems - if a Poseison collector was not found,
 then daemon startup could be compomised.  Not anymore!

 Revision 2.66  2008/05/10 16:16:20  root
 Fixed a bug with multiple pollers, where one of them exiting (an unusual
 event) might kill the other pollers.  Hopefully fixed another bug where
 the CGI script might report that the daemon was not running.

 Revision 2.65  2008/04/03 04:32:29  root
 Whoops!  Barometric pressure was being incorrectly reported to Wunderground

 Revision 2.64  2008/04/01 03:19:12  root
 1) Documented the PopUp configuration option (it has been available for
    a while now - oops)
 2) Added configuration options SMTPUsername and SMTPPassword for those
    users who need to specify SMTP SASL authentication to send email.

 Revision 2.63  2008/03/25 03:37:41  root
 1) Eliminated "Daemon not running" errors
 2) Added ModbusAddress qualifier for Enersure (and other future devices)
 3) Added experimental use of the MIT Timeplot graphing system (see the
    -format timeplot directive and the TimePlot button in the CGI interface)

 Revision 2.62  2008/03/13 19:49:13  root
 1) Added Excel and XML as an output format.  See the -format option.
 2) Added generic email usage (we no longer rely on Sendmail) as well as the
    configuration option SMTPHost (this and #3 suggested by Anthony Watts).
 3) Added -email flag to -checkconfig, to test email messages.
 4) Any cumulating sensor (rain, lighting, or counter sensor) with a non-zero
    ResetAfter will now retain its value when the daemon is restarted.  This
    used to only apply to rain gauges.  Suggested by Adam Crewe.
 4) Fixed a degenerate case where Wunderground would report a date and
    str2time would fail to parse it correctly.
 5) Fixed a small bug in RSS and "funny characters", found by Adam Crewe.
 6) Fixed a bug in SQL tables (where new sensors could not be created if the
    user has added additional columns to the sensors table), found by Ethan
    Goldman of CMU.
 7) Changed the behavior of -current.  When -current is used now, the -from
    and -to values are both set to "now".  The old behavior of dumping all
    current readings is assumed by the new -raw option.
 8) Although the "why" of it makes no sense, I fixed a bug which would cause
    the daemon to sometimes crash on startup when a previous daemon had just
    been stopped.

 Revision 2.61  2008/03/06 03:19:00  root
 1) Reduced the number of processes used for Wunderground (since all remote
    personal weather stations are read from the same wunderground site, we
    don't need a separate polling collector for each one).
 2) Cosmetic cleanups to wunderground that I missed in the previous version
 3) Fixed an "uninitialized hash" error in the internal GD::Graph::Radial
 4) Fixed a bug where a sensor's Name (if overwritten in a View) would not
    be reflected in the current readings

 Revision 2.60  2008/02/27 01:29:18  root
 The latest revision provides a boatload of new features as well as a bunch
 of bug fixes (and a couple of minor incompatabilities).  Enough of them that
 I felt it was better to divide them up:

 New Features:
  1) Added Actuators.  This is a BIG FEATURE - it means that you can now
     turn switches on or off in response to alarm conditions.  You can also
     run external programs.  Because of the potential for harm to whatever
     system you are controlling, there are special configuration issues that
     must be satisfied before you can use this feature.
  2) Added support for the HWg series of Poseidon data collector (these
     devices have actuators included in them)
  3) Added the ability to publish weather information to Weather Underground as a "personal weather station"
  4) Added support for Weather Underground as a data collector (so you can
     compare your weather data with other stations).
  5) Added support for owshell, in addition to the existing owfs and owhttpd.
  6) Added support for the TAI8570 pressure sensor from AAG to owfs, owhttpd,
     and owshell
  7) Added support for DS2760 (thermocouple-based temperature sensors) for
     owfs, owhhtp, and owshell
  8) Added ability to auto-fetch sensor names from certain collectors (EM1,
     RoomAlert series, SmartWatt and HWg series), which means that you can
     delete the Name attributes from the config file and simply configure
     your collector (eliminating "version skew")
  9) Added Spanish internationalization (thank you to Mario Berges).
 10) Added ability to specify Type in an SNMP Instance declaration (which
     allows Type to be inherited, simplifying SNMP collectors in configuration
 11) Added SNMPOnValue and SNMPOffValue to SNMP OnOff sensors - the default
     values are 1 and 2 respectively, but some MIBs may use different values.
 12) Added SensorOrder global configuration attribute to change how sensors
     are ordered in reports and graphs
 13) Since the USA (and Liberia and Burma) are the only countries that use
     English units, I made Metric be the default units for all other countries.
 14) Thermd now uses the PIDFile as a lockfile, so it will warn you if you are
     trying to start a daemon when one is already running.  I also allow you
     to specify /dev/null for a PID file, which also disables locking.
 15) Added "MultiplyBy" to Gauges (was previously only available for counters).

  1) All relative time values (like ResetAfter, LogInterval, PollInterval, etc)
     must now have associated units (for example, 30s, or 1m30s or 1d6h)

 Bug Fixes:
  1) In alarms - the open mode is "|-" not "|".  This was causing monitoring
     daemon crashes :-(
  2) If SQL logging is enabled, the DB connection is remade every time the
     daemon needs to log data (this becomes necessary if the SQL server is
     restarted without also restarting thermd)
  3) Fixed a small bug in SQL reporting/graphing if there is insufficient
     log data available.
  4) WattHours for the EnerSure and SmartNet are the "wattage values since the
     last reading we made".  We used to (incorrectly) average those values
     over LogInterval minutes - now we (correctly) accumulate them.
  5) Lowered the minimum value of LogInterval to 15s
  6) Some Linux versions of strftime do not recognize "%+", so I reverted to
     "%c" in the internatonalization code
  7) Fixed a bug where we would sometimes erroneously report that the logging
     daemon was not running.
  8) Maybe I have graph limits right this time?  I think I have fixed the
     algorithms properly.
  9) Sometimes, when errors were encountered during -daemon parsing, some
     superflous child processes would be left running (config file parsing
     has been largely overhauled).
 10) PollInterval was being ignored for SNMP collectors
 11) It was possible to start two simultaneous SQL-based daemons (text-based
     daemons were locked out by logfiles).  I changed the pidfile to also be
     a lock, preventing duplicate daemons of any form.
 12) Added a few missing (Slope, Intercept) or unclear (lots) components to
 13) Fixed Metric display of barometer readings (they used to be stuck on inHg)
 14) If a collector is marked as ReadOnly, we don't try to talk to it at all now
     Likewise, if a collector is ReadOnly, all of the sensors on it are also
     ReadOnly (but now you can have a ReadOnly sensor on a read/write collector)
 15) Lots of general code cleanup, getting rid of cruft, modularizing, etc.

 Revision 2.59  2007/12/29 18:27:37  root
 I rethought server I18N.  You may use locale-based month names in yourr
 config file now (for alarms).

 Revision 2.58  2007/12/29 16:40:18  root
 Cleaned up I18N a little (problems with mixed encodings in a single
 string.  Added Russian language encoding.

 It is a known bug that some weird characters may appear in graphs when
 using I18N - I may need to take this up with the author of GD::Graph

 Revision 2.57  2007/12/19 23:50:02  root
 1) Added Danish I18N thanks for Kristian Vilmann
 2) Added Dutch I18N thanks to Frank Kuiper
 3) Deprecated DisplayIn - thermd will now choose the appropriate value based
    on the locale (setting DisplayIn will force an initial scale on all
    viewers, regardless of locale)

 Revision 2.56  2007/11/29 22:02:30  root
 NOTE: You must restart the thermd logging daemon when you install this new
 version, otherwise the CGI script will always report that the daemon is not

 1) Added SmartNet (and SmartWatt, SmartPDU, and SmartSenseTH) XmlRpc sensors.
 2) If the "current" values are too old, the CGI script and other reports will
    advise you that the logging daemon may not be running.
 3) DefaultView was not working - fixed
 4) Added -i18n option to check completeness of internationalization strings

 Revision 2.55  2007/11/14 18:05:58  root
 Thanks to Anders Brownworth, I verified the correctness of the Proliphix
 additions, and also fixed a few minor bugs introduced when I did the

 Revision 2.54  2007/11/10 18:34:20  root
 Cleaned up error mesages a bit, and after much consultation, removed the
 usage message from the internationalized code.

 Revision 2.53  2007/11/07 19:54:28  root
 1)  Internationalization (or I18N).  We now support Swedish (thank you to
     Roger Andersson of and German (thank you to Patrick Ben
     Koetter of state of mind).
 2)  Added support for Proliphix IP enabled thermostats.  The devices themselves
     are read-write (that is, you can program your thermostat from the web), but
     thermd just reads the values from the thermostat.
 3)  Added UserName and Password for IP-based connections (in case your device
     requires it).  This was necessitated by the Proliphix, and is now supported
     for all IP devices.
 4)  Added Baudrate for serial-based devices.  In general, the default is correct
     but when you use a Digi IP-to-serial device in RealPort mode, it is
     sometime necessary to change the baudrate, so baudrate changes are now
     supported for all serial devices.
 5)  Added restart support for the Enersure.  In my setup, my computers are on
     a battery backup, but the Enersure is not.  When my power company drops
     power, the computers stay up, but the enersure resets - and the IP
     connectiion gets all messed up.  I now attempt to fix it.
 6)  Yet again, fixed the boundary conditions of graphs (sometimes graphs would
     print as solid blue blobs).
 7)  Fixed runaway rain sensors (by rejecting counts of > .1"/minute)
 8)  Added the ability to continue with the last Rain value after a restart (so
     it doesn't automatically reset to 0 when you restart the daemon).  I have
     not tested this on SQL, so feedback would be appreciated.  Thermd will make
     a note in syslog if it sees a recent value...
 9)  Cleaned up units code, so expressed values should be more consistent
 10) Cleaned up a few bugs in image annotation (color of text in CGI wrapper,
     units annotation, wind direction values, etc).
 11) Cleaned up SQL a little to guard against injection attacks from the web

 Revision 2.52  2007/09/23 16:46:00  root
 A few minor changes and tweaks:
 1) SNMP sensor names may now also have '-' characters in them
 2) Counters may now have a negative "MultiplyBy" (so you can graph two
    counters against each other up/down
 3) Annotated images are now displayed fullsize, not scaled to the same
    dimensions as the graphs
 4) Counters are now displayed as integers, when appropriate (which is
    usually, since counters are integral unless altered by MultiplyBy)

 Revision 2.51  2007/09/18 16:15:40  root
 1) With thanks to Chris Kampmeier for the concept (and the initial patches!),
    we have an exciting new feature!  It is now possible to annotate an image
    with the current readings from thermd - which means that you can have a
    an image (photo or drawing) of your site, and you can have thermd label
    it.  Look at - the graph is generated by
    thermd, but the diagram under it has been annotated by thermd, too!  Look
    in the documentation for View for details.
 2) Further improved the timeout behavior from the previous version
 3) Added a ButtonOrder attribute to views, so you don't need to have your
    radio buttons in alphabetical order if you don't want.
 4) Changed the (default) maximum sort value for RSSOrder from 999999 to 999,
    so numbers greater than 1000 sort after the default "last" value
 5) An important format change in Views.  Sensors used to be labelled as
    Collector/Sensor, and now they are better specified as Sensor@Collector
    (this is anticipation of a future development of computational sensors).
    The old style will work for a while, and there is a conversion script
    on the main webpage
 6) Changed the scale for Power Factor from "%" to "PF", and for relative
    humidity from "%" to "% RH" to avoid ambiguous readings.
 7) Made Unicode the internal standard, to avoid switching between &deg; in
    HTML, \a in GD::Graph, and \N{U+00b0} in Image::Magick (the latter is now
    used throughout).

 Revision 2.50  2007/09/06 20:22:14  root
 Some BSD and some Linux systems have a highly intermittent bug in select()
 but Linux and BSD have different signal behavior, so this latest fix to
 my_select() just forgets about using signals and does its magic manually.

 Revision 2.49  2007/08/22 04:11:14  root
 What a difference a single character in a regex can make :-)  I messed
 up the RoomAlert humidity readings - and just noticed :-(

 Revision 2.48  2007/08/11 17:26:51  root
 Added a test for TAI humidity sensors for the HA7Net.  Version of
 the HA7Net understands the new EDS humidity sensors, but not the old-style
 TAI version.  EDS was supposed to release a new version of the firmware, but
 have fallen behind, so since one of my users complained, I installed a
 temporary workaround.

 Revision 2.47  2007/07/03 03:27:32  root
 Added support for the RoomAlert 24E and RoomAlert 26W

 Revision 2.46  2007/06/07 15:16:11  root
 1) Added more control over how graphs are rendered, by adding the MinMin,
    MinMax, MaxMin, and MaxMax attributes to View's
 2) Added support for Postgres, in addition to MySQL.  It seems that they are
    very slightly different...
 3) Fixed small bug IXON/IXOFF for enersure that was causing some data to
    be missed
 4) It seems that Linux behaves slightly differently for signals than does
    my FreeBSD system.  This manifested itself in a timeout/my_select bug on
    Linux, which is now fixed.
 5) Eliminated reference to "temperature" in the RSS feed, since some folks
    use thermd for just power monitoring :-)

 Revision 2.45  2007/05/02 21:43:58  root
 The HA7Net code now looks at CRCs of returned data values, and reports when
 the CRC check fails.  Also fixed a small bug in PollInterval.

 Revision 2.44  2007/04/18 00:19:28  root
  1) The EnerSure is now ready for release.  You must now download the
     Modbus::Client module from the CPAN to use it.  A number of additions
     are still planned...
  2) Any serial device may now be addressed by IPAddress/Port in addition to
     Device.  I have a DigiOne SP ether-to-serial interface, and I now provide
     support for that too.
  3) Improved behavior of HA7Net Data aquisition with regards to locking.  We
     now grab the lock once per transaction, instead of once per device, which
     should speed up data acquisition and reduce network traffic.
  4) Better tweaking of graph ranges - the closer together the minimum and
     maximums of a graph, the closer the limits of the axes
  5) Changed format of the "current" logfile - instead of referencing sensors
     by the name gien in the config file, I now use the -> Collector and Sensor
     number.  No one should care, but it's better and faster this way, and lets
     you change a sensor name and still have views work without restarting the
  6) Changed logformat - it no longer pads values with leading zeros (this was
     a holdover from the days of fixed-length logfile records - why waste disk
     space when we don't need to?)
  7) Added the ReadOnly attribute to sensors.
  8) Added PopUp attribute for sensors.
  9) Added PollInterval for changing the scan rate of collectors.
 10) Changed LogFrequency to LogInterval, which is a more accurate term.  I
     still allow LogFrequency, though :-)
 11) Allow European format numbers (0,15) in addition to American format (0.15)

 Revision 2.43  2007/03/15 03:51:37  root
 This version is the preliminary release of support for the Enersure
 power monitor from Trendline.  I have tested it on my system (which is
 operational, but not connected to my circuit-breaker box).

 Revision 2.42  2007/03/14 15:04:47  root
 After a short amount of experience with the barometer, added a custom
 graph type if the only thing being plotted is barometric pressure (so
 you can actually see the changes :-)

 Revision 2.41  2007/03/13 20:12:51  root
 One (important) bug fix, two new sensors!
 1) I now support the Hobby Boards barometer and solar radiation sensors
 2) While implementing them, I discovered a bug in my temperature conversion
    routines for all DS2438 sensors :-(  This would affect humidity sensors
    and temperature readings when the temperature is below 0C

 Revision 2.40  2007/03/12 04:51:27  root
 This month was pretty productive, and a rather large change to thermd is
 the result.  A big THANK YOU goes to Lars Karlander, of N64.45 E20.52 in
 Northern part of Sweden for items 1, 2, and 4 below - he helped specify and
 debug the code as it was being written.  Thank you also to Daniel Johnson of
 Computer Resources who originally suggest the idea, and then was patient
 during the 6 months it took me to get started :-)

 1)  Added support for OWFS (see  This means
     that thermd now supports the serial port host adapters (ibuttonlink,
     DS9097E, DS9097, and DS2480B) or USB host adapters (DS9490 or PuceBaboon),
     available from HobbyBoards and elsewhere.
 2)  Added support for OWHTTPD (see
 3)  Added support for SNMP-based devices, such as the MRV LX-4008 and IR5150
 4)  Added a new sensor type Counter.  This is just a raw counter device (for
     1-Wire and SNMP collectors), and reports how many "clicks" have gone by
     in the past LogMinute interval.
 5)  Added a new sensor type Gauge.  This is just a raw measure, and is only
     available on an SNMP collector.
 6)  Added Units attribute for Counters and Gauges, and MultiplyBy for Counters.
 7)  Refactored how the lightning gauges read.  I used to show them a count of
     strikes over a long interval (like rain) but now that I actually *have*
     a lightning sensor, I see it makes more sense simply to show a count of
     strikes per measurement period.  If you like it better the other way,
     you can fake it with Counter :-)
 8)  Cleaned up the counter code for lightning & rain - they are now just
     special cases of type Counter
 9)  Added support for the low-precision DS1822
 10) Cleaned up logging/error messages (so now they go to STDERR and/or syslog
     as appropriate)
 11) Fixed a bug with upper/lower case hexadecimal strings in the HA7Net
 12) Added a Port directive (for non-standard HTTP connections, and for SNMP)

 Revision 2.39  2007/01/16 14:29:35  root
 Added Blurb2 keyword - someone wanted to be able to add text after the
 chart instead of before it (you can actually use both if you want)

 Revision 2.38  2007/01/14 17:45:21  root
 We had more than 1" of rain in 24 hours, and I discovered a bug in my
 scaling algorithm for graphing rain :-/

 Revision 2.37  2007/01/02 12:47:23  root
 A small graphing improvement: if the graph ends "now", the graphs now
 include the current readings (which have not yet been logged into the
 every-LogInterval-minutes file)

 Revision 2.36  2006/12/27 23:45:16  root
 1) By popular request, log data may now be stored in SQL format.  I have only
    tested the MySQL interface, but I don't do any "funny" SQL calls, so it
    ought to work with any SQL interface.  An external program
    is available to help you translate your logfiles.
 2) Added options -list and -nowarn to -checkconfig, in support of conversion
    of databases to SQL
 3) Fixed a rare crash when the AAG wind sensor is used with the HA7Net.  I
    was correcting for AdjustBy values in the wrong place, and so in addition
    to crashing, I was recording incorrect wind directions IF you tried to
    adjust the wind direction.  Both bugs are fixed.

 Revision 2.35  2006/12/16 00:58:25  root
 A number of changes, enhancements, and bug fixes
 1) Added support for the ITWatchDogs WeatherGoose, MiniGoose, SuperGoose,
    PowerGoose and RacSense data collectors.  Thank you to Adam Thomas for
    his assistance.
 2) A small but noteworthy change to logfile parsing - if you have a sensor
    name that has lowercase letters in it (the sensor names are usually
    16 character 1Wire names with hexadecimal characters), the logfile will
    be stored as an uppercase name (unless you explicitly set a LogFile
    directive, which will be untouched).
 3) Fixed autoscale on a Rain-only graph - now sets limits of 0-1" in English
    mode, and uses 2-digit labels (so you can see small amounts of rain)
 4) Fixed conversion on rain values when displaying in Metric
 5) Fixed one last bug in Rain counting, so the rain values correctly reset
    after ResetAfter hours

 Revision 2.34  2006/12/01 22:50:34  root
 Theoretically, theory is harder than practice.  Practically speaking, it
 is the other way around.

 The rain sensor worked fine on the TEMP08, so theoretically it should have
 worked on the HA7Net.  Practically, that was not true.  I fixed that bug,
 so now it works on both.  Theoretically.

 Revision 2.33  2006/11/27 06:21:54  root
 Fixed bug in wind direction measurement (could have halted daemon)
 Made some diagnostics more friendly

 Revision 2.32  2006/11/26 14:56:42  root
 A few bug fixes to the previous release - you always find them after you
 release the code :-(  Also added autosubmit when you change any radio
 button or checkbox.

 Revision 2.31  2006/11/24 18:30:44  root
 1) Added support for EmbeddedDataSystems D2C switch sensors
 2) Removed the restriction that OnValue need to be larger than OffValue
 3) Added support for new HA7Net high-level humidity-reading to support
    their new sensor design.

 Revision 2.30  2006/10/22 03:54:34  root
 1) Added override of Name in Show+ block
 2) Fixed small bug in overtemp reporting
 3) Fixed up pod documentation a little

 Revision 2.29  2006/10/13 20:49:06  root
 1) AVTECH Software released new firmware for the Room Alert, which changed
    the URL that they used to fetch data.  Updated to allow both new and old
    style URLs
 2) Cleaned up POD documentation (I missed a few closing '>'s before)

 Revision 2.28  2006/09/12 22:49:34  root
 It turns out that in practice, wind direction measured from the OneWire
 Weather station is a lot more erratic than it should be in theory.  So
 the voting average that I implemented did not work well.  I have replaced
 this with a consensus average algorithm which seems to give better results.

 Revision 2.27  2006/09/10 18:02:35  root
 OWW! One big bug, one small one, one new feature
 1) Wind gusts were being accumulated, instead of maximized.  This resulted
    in ridiculously high gust values.  Whoops!
 2) Small bug in View's and Show+
 3) Added a Wind Direction graph to radar, to show the weighted average of
    wind direction (the more measurements in a given direction, the larger
    the measurement shown, so you can see teh predominant wind direction)

 Revision 2.26  2006/09/04 05:02:02  root
 Once a production release is made, it seems that there are always one
 or two bugs.  They are fixed, and not worth mentioning...

 Revision 2.25  2006/09/03 18:24:40  root
 This is a big release with a lot of changes.  I owe a BIG "thank you" to
 Michael G. Petry who reported the bugs addressed in items 2 and 10, and who
 helped me with the low-level OneWire protocol and the code necessary to get
 items 4, 5, and 6 working (all of those mean that thermd now supports the
 OneWireWeather station on the HA7Net! :-)

 1)  Added initial support for the Room Alert 7E, Room Alert 11E, and
     TemPageR systems
 2)  Fixed an off-by-one bug in my HA7Net data-collection code, where thermd
     read too much too often
 3)  Added support for the Lightning and Barometer sensors for TEMP08
 4)  Added support for DS2438-based Humidity sensors for HA7Net
 5)  Added support for DS2423-based windspeed, gust, lighting and rainfall
     sensors to the HA7Net
 6)  Added support for DS2450-based wind directon sensors to the HA7Net
 7)  Added a Show+ block to Views, and added GraphColor and LineType in these
     blocks to override the lines/colors specified in the Sensor blocks
 8)  Added a new GraphType qualifier to Views, to support the new Radar chart
     for wind history
 9)  Added a DefaultView configuration item, to change what the default radio
     button is selected
 10) Version of the HA7Net firmware had a bug where if you read more
     than 10 DS1820 sensors, it would hang.  The bug has been fixed in
     but thermd will currently only read blocks of 10 sensors.
 11) Changed DisplayIn to accept English or Metric (C and F will still work).
     This will change all units of display, but all can be overridden.
 12) Added Temperature, Rainfall and WindSpeed to override DisplayIn.
 13) Changed -units switch to accept English or Metric (C and F will still
     work).  This will change all units of display, overrides the config file,
     but all individual units can be overridden.
 14) Added -temperature, -rainfall, and -windspeed override switches, too.
 15) Improved periodicity of readings for HA7Net and EM1.  New reading starts
     are based on the completion of past readings - now we read darn close to
     every 60 seconds (extremely important for wind seed measurements).
 16) Fixed averaging of wind direction.  Previously, an equal number of N & NW
     readings would correctly yield NNW, but since a compass is round, an
     equal number of NNW and NNE readings would incorrectly yield S!  Now it
     gives the correct value of N.

 Revision 2.24  2006/07/22 19:49:50  root
 The best laid plans... fixed over/under range sensor check.

 Revision 2.23  2006/07/21 21:09:59  root
 Added the RSSOrder attribute to View's

 Revision 2.22  2006/07/21 18:14:40  root
 1) Added support for the EM1
 2) I apologize, but I renamed the BaseURL attribute to IPAddress (and
    slightly changed the semantics).  This was necessary as I find that
    the Trendline power monitoring uses an IP address but not a URL, and
    I wanted to be consistent...
 3) Underdriven sensors (humidity and wind speeds less than 0) will now
    be ignored

 Revision 2.21  2006/07/16 14:37:32  root
 1) Fixed a bug in the rain measurement code - it now works a lot better :-)
 2) Started adding Trendpoint EnerSure and Sensatronics EM1
 3) Deleted some old unused code for decaying stale data

 Revision 2.20  2006/07/05 15:33:17  root
 1) Found a synchronization bug in initializing the TEMP08, fixed.
 2) Wind directions are now represented as a compass point (and not degrees)
    in current log and RSS feed

 Revision 2.19  2006/06/30 16:16:20  root
 1) Fixed a bug in RSS - previously, all the values in the "current readings"
    file were in Degrees F.  They are now in their correct units.
 2) Made a special wind-only graph format.  If a view has only wind speed
    and direction (and optionally gusts), this format is automatically used.
    I don't think it will work if other readings ar used, so it is not a
    selectable type.
 3) If you don't like my choice of named colors, you can now also use an
    RGB 6-digit hexadecimal value.
 4) Occasionally erroneous data will be seen on 1-Wire busses.  Thermd now
    ignores temperatures of 85C/185F, as well as humidities and windspeeds
    that are >= 100 %/MPH.  I may make this a configurable option...
 5) The code has been rock solid without any obvious memory leaks.  I changed
    the automatic restart from weekly to monthly.

 Revision 2.18  2006/06/13 13:22:17  root
 Embedded Data Systems released firmware version, which fixed the
 bug I had to make a workaround for in thermd version 2.12, so this release
 backs out that section of code to the more efficient use of the HA7Net
 code.  Now, if a sensor fails or is simply unplugged, it will "go missing"
 instead of invalidating all of the sensor readings.

 Revision 2.17  2006/05/30 17:44:29  root
 Added start of customized RSS - see the "RSSName" keyword in View's

 Revision 2.16  2006/05/24 15:56:07  root
 One small change, one big one
 1) Added support for the One Wire Weather rain gauge on the Temp08
 2) Completely rethought how I read data fromn sensors (for the THIRD time)
    When I just supported a single QK145, it was easy - just read streaming
    data.  Adding the HA7Net meant changing to a polled structure, and then
    when I saw I was getting data dropouts, I switched to a raw-mode polling
    system.  Dropouts kept occurring, and I discovered what I think is a bug
    in the select() call, *and* I was using a LOT of CPU time, so now I have
    a raw-mode polling system with an exception-raising mechanism if there
    is a blockage in sysread() or select(), and I only collect data every
    30 seconds (although it buffers up in the interval).  This means no more
    heavy CPU load, no more missed data, and no more missed log intervals.

 Revision 2.15  2006/05/02 18:19:48  root
 Someone complained that the new data collection wasn't working, and for
 their flawed logfile, they were right,  We now handle errors in logfiles
 a bit better, as well as fixed an error in default MailFrom.

 Revision 2.14  2006/05/01 20:17:13  root
 1) Added support for the TEMP08 data collector from Midon Design.  Also
    added suppot for the DS2438 temperature (and humidity) sensor, plus the
    DS2423 wind speed and the DS2450 wind direction sensor in the AAG One Wire
    Weather system!  Note that OWW will not be fully supported until I mount
    give a degree value between 0 and 359, instead of something more pretty).
    I have plans to add the rain gauge, too.
 2) Added the Type attribute to <Sensor>.  This is optional for temperature
 3) Completely rethought how data is collected - this was because of yet
 4) Added the Type attribute to <Sensor>.  This is optional for temperature
 5) Completely rethought how to log data and report dead sensors.  Since Perl
    after version 5.7.3 has safe signals, I now use alarm timeouts to do both
    functions, which means enhanced reliability and more accurate logging,
    even when the RSS feature slows down measurements.  This also entailed
    dealing with interrupted selects and restarting system calls.
 6) Reduced the frequency with which I poll the HA7Net.  Originallym this was
    even when the RSS feature slows down measurements.  This also entailed
    dealing with interrupted selects and restarting system calls.
    of continually.  This also helps reduce network traffic from the daemon.
 7) Improved restarting of the daemon when HUPped or on the weekly autorestart.
 8) At the request of a user of the old system, I reincorporated Hi/Lo graphs.
    They are no longer restricted to 1 year, but will show highs and lows for
    every 24-hour period that is graphed.
 9) Changed the way ticks are generated on the X axis.  Now completely general,
    instead of being special-cased for each range.
 10)Graphing now should behave correctly even if you change LogFrequency
 11)Return a special image when no data is available to be plotted in the date
    range specified.

 Revision 2.13  2006/04/18 17:04:22  root
 Added "Combo" keyword to support combination sensors from Embedded Data
 Systems (such as the HMP2001S)

 Revision 2.12  2006/04/18 16:24:52  root
 There is a problem with the HA7Net... It allows you to read multiple
 sensors at one go, but if any single requested sensor is missing, the
 entire request fails.  This means that if you disconnect a sensor, it
 appears that all sensors of that type have failed.  The solution is
 to read each sensor individually, which means slightly more network
 traffic and processing.  No big deal, but it is annoying...

 Revision 2.11  2006/04/14 22:17:32  root
 Correctly handles sensors which do not read temperature - so the relative
 humidity sensor will no longer have readings converted to Fahrenheit :-/

 Revision 2.10  2006/04/13 12:26:27  root
 1) Prettied up latest readings when there are > 5 sensors
 2) Fixed bug where there was no relevant data in the first file looked at
    caused a doubling of dates for the remaining files

 Revision 2.9  2006/04/07 13:45:24  root
 Added LineType attribute - my graphs were getting crowded, and having a
 discriminator was nice

 Revision 2.8  2006/04/07 03:33:45  root
 1) Improved I/O - you aren't supposed to use buffered I/O with select(2),
    and I was.  So now, we use only unbuffered I/O for reading from the
    sensors.  There are no longer any dropouts (I hope)
 2) Fixed a bug where failed sensors would not be detected if they had
    had _any_ previous readings
 3) Closed some unused file descriptors on read

 Revision 2.7  2006/03/28 03:25:29  root
 1) Fixed bugs alluded to in previous version
 2) Added Hide attribute to sensors
 3) Beefed up printing of current temps in graph to only show what is in
    the current View

 Revision 2.6  2006/03/27 04:53:07  root
 First major pass at integrating the HA7Net - but be forewarned, there
 are still some bugs that need to be fixed

 Revision 2.5  2006/03/22 17:36:21  root
 Found an interesting graphing bug when there is no data for a sensor
 (that was not the last sensor examined!) in the selected time period.

 Revision 2.4  2006/03/21 17:04:51  root
 1) Fixed fatal bug when a collector fails (it used to die when it wrote the
    logfiles (I had previously only checked at the update of "current")
 2) Fixed bug where collector log subdirectories were checked before the names
    of the actual logfiles were specified.
 3) Started adding HA7Net from Embedded Data Systems - they say they'll send
    me a unit to evaluate and integrate.

 Revision 2.3  2006/03/12 17:58:15  root
 We now allow fractional relative times (so, -1.5d is the same as -1d12h
 or if you want to be perverse -1.25d6h :-)

 Revision 2.2  2006/02/26 00:13:25  root
 Fixed bad bug in averaging software.  I forgot to zero out the sum and
 count after logging, so it wound up calculating avergage since reboot
 instead of average since last logging.

 Revision 2.1  2006/02/25 00:11:01  root
 There's always one... last... bug... after you make a release :-/

 Revision 2.0  2006/02/25 00:00:45  root
 Massive update and complete rewrite!  Notable changes are:
 0) Complete rewrite of code.  Much more readable and modular, and designed to
    be a new release (instead of a accumulation of features over time :-)
 1) New configuration file format (now resembles Apache config file), and
    all parameters are in config file (no more changing Perl code).  Just
    about everything is tunable.
 2) Supports multiple data collection devices, no limit on number of sensors.
 3) Supports QK145 and VK011 devices from QKits.  Other devices may follow...
 4) Dramatically increased graphing speed.
 5) Enhanced display ranges (arbitrary start/end points).
 6) Named views (so you can choose groups of sensors to display).
 7) Improved alarms - can specify multiple alarms per sensor, with multiple
    delivery options, can also specify when an alarm resets, when it can be
    delivered, etc.
 8) Improved argument processing (uses long options, instead of 1-letter).
 9) Improved documentation (I hope!)
 10) Lots of bug fixes, more robust behavior!

 Revision 1.77  2006/01/06 00:28:05  www
 Final version 1 release - now contains graphics, tracking, trend analysis,
 alarms, and lots more...

 *Revision* 1.1  2001/07/31 20:43:36  www
 Initial release - a pretty simple program


Hey! The above document had some coding errors, which are explained below:

Around line 13470:

You can't have =items (as at line 13474) unless the first thing after the =over is an =item

Around line 13515:

You can't have =items (as at line 13519) unless the first thing after the =over is an =item

Around line 13610:

You can't have =items (as at line 13614) unless the first thing after the =over is an =item

Around line 13855:

You can't have =items (as at line 13859) unless the first thing after the =over is an =item

Around line 13892:

You can't have =items (as at line 13896) unless the first thing after the =over is an =item

Around line 14045:

Unterminated C<...> sequence

Around line 14198:

You can't have =items (as at line 14202) unless the first thing after the =over is an =item

Around line 14274:

You can't have =items (as at line 14278) unless the first thing after the =over is an =item

Around line 14508:

You can't have =items (as at line 14512) unless the first thing after the =over is an =item

Around line 14611:

You can't have =items (as at line 14615) unless the first thing after the =over is an =item

Around line 14700:

You can't have =items (as at line 14704) unless the first thing after the =over is an =item

Around line 14753:

You can't have =items (as at line 14757) unless the first thing after the =over is an =item

Around line 14841:

You can't have =items (as at line 14845) unless the first thing after the =over is an =item

Around line 14866:

You can't have =items (as at line 14870) unless the first thing after the =over is an =item

Around line 15109:

You can't have =items (as at line 15113) unless the first thing after the =over is an =item

Around line 15494:

You can't have =items (as at line 15500) unless the first thing after the =over is an =item

Around line 15526:

You can't have =items (as at line 15532) unless the first thing after the =over is an =item

Around line 15657:

You can't have =items (as at line 15661) unless the first thing after the =over is an =item

Around line 15668:

You can't have =items (as at line 15672) unless the first thing after the =over is an =item

Around line 15766:

You can't have =items (as at line 15770) unless the first thing after the =over is an =item

Around line 15794:

You can't have =items (as at line 15798) unless the first thing after the =over is an =item

Around line 15821:

You can't have =items (as at line 15825) unless the first thing after the =over is an =item

Around line 15846:

You can't have =items (as at line 15850) unless the first thing after the =over is an =item

Around line 15888:

You can't have =items (as at line 15892) unless the first thing after the =over is an =item

Around line 15919:

You can't have =items (as at line 15925) unless the first thing after the =over is an =item

Around line 15938:

You can't have =items (as at line 15942) unless the first thing after the =over is an =item

Around line 16073:

You can't have =items (as at line 16079) unless the first thing after the =over is an =item

Around line 16127:

You can't have =items (as at line 16131) unless the first thing after the =over is an =item

Around line 16158:

You can't have =items (as at line 16162) unless the first thing after the =over is an =item

Around line 16214:

You can't have =items (as at line 16218) unless the first thing after the =over is an =item

Around line 16304:

You can't have =items (as at line 16308) unless the first thing after the =over is an =item

Around line 16337:

You can't have =items (as at line 16341) unless the first thing after the =over is an =item