UPDATE (2015):
These days, if you want to measure temperature, humidity and other environmental variables cheaply, there's no need to mess around with unreliable USB-sensors. It's more reliable (and not that much more difficult) to simply use a Raspberry Pi or an Arduino and connect sensors directly using I2C, SPI or a 1-wire bus. See my git repository for a simple Raspberry Pi temperature measuring example using a DS18B20-sensor. There are plenty of other resources out there, for instance on Adafruit or Sparkfun.
Original post:
Recently I had the chance to play around a bit with a relatively cheap USB thermometer / temperature logger, the TEMPerHum, manufactured by Shenzhen RDing Tech Co., Ltd. This little device is basically a USB-key with a WinChipHead CH341 USB-to-serial converter, a Sensirion SHT11 temperature/humidity sensor, and a 24xx02 I2C EEPROM on board.
The predecessor of the TEMPerHum is the TEMPer. The devices are similar, but the TEMPer is equipped with a National Semiconductor LM75 temperature sensor instead of the SHT11, so it doesn't do humidity.
Of course these devices are only shipped with a Windows driver and a point-and-click Windows application. Luckily several people have written alternative programs, such as this little C# program by Levanter30, and the excellent UTAC (USB TEMPer Advanced Control) application by Björn "bof" Böttcher.
Although Linux has a kernel driver for the CH341, it doesn't yet implement the DTR/RTS/CTS signals used to emulate an I2C bus. A kernel patch from Werner Cornelius and Tollef Fog Heen against kernel version 2.6.26 adds the missing features. An additional patch prevents the Prolific pl2303 driver from from conflicting with the ch341 driver.
These patches can in theory be easily applied to the ch341 module in the
Ubuntu kernel sources using a little shell script. (Run it using
sudo
. Please do check the script before you do this, as it may contain
bugs, and anyway it is very unwise to run an unknown script as
root. ;-) Unfortunately it doesn't seem to work with the kernels in
Ubuntu 8.04 and 8.10 (kernel versions 2.6.24 and 2.6.27). Update
(2009-02-07): Tollef's patch was rejected for several reasons, but
a new patch to the ch341 driver has been submitted by Boris Hajduk for
the 2.6.29 kernel.
Tollef Fog Heen wrote a little Linux program to read out the TEMPer. There is apparently also a Linux-program that works with the TEMPer Hum, but unfortunately it hasn't been released yet. Watch this thread for further updates.
Anyway, for the time being I cannot get the device to work in Ubuntu. So in order to test the TEMPer Hum, I used Windows. I performed some measurements using both the "official" TEMPerHum program and Levanter30's C# program mentioned above.
To install the device under Windows, it's best to use a recent .NET 2.0 distribution, and download a recent version of the driver and program from the manufacturer's website.
Oddly enough, readings differ between the two applications, and also between different versions of the "official" application. In general Levanter30's program reads out the device much more frequently (once every 0.65 seconds on my P4 laptop), and gives lower temperature values.
Here are some results from the temperature in my working room, logged using Levanter30's TEMPerHum.exe. The first one should be around 20 degrees:
The data was obtained by running TEMPerHum.exe >templog.txt
from
the Windows shell, and then running
cut -d ' ' -f 5,10,15 templog.txt >templog-selection.txt
in a Linux
shell to extract the columns needed. The graph was made using Gnuplot.
These temperature-reading looks fairly reasonable, apart from the bit at the start and a few strange peaks. The graph would however benefit from applying a moving-average filter. I can't really say if the humidity values are reasonable, as I haven't got anything to compare them with.
Next, I compared the readings to measurements made using two simple "analog" thermometers (and the rather questionable electronic thermometer in my desk-clock):
Two discrepancies can be noticed from these graphs. The first is the fact that it seems to take around 10-15 minutes for the device to reach a realistic temperature value. In this time you can feel the ICs in the device heat up a bit, so perhaps the SHT11 is calibrated for that -- I should check.
The second oddity are the sudden drops and jumps in the logged temperature and humidity. I have no idea what causes these. Perhaps some kind of automatic recalibration? Or perhaps it's an artefact caused by Levanter30's program reading too frequently (it should wait 0.8 seconds between readings, according to the Sensirion website, but it doesn't). I'll have a look at the Data Sheet and Application Notes of the SHT11 to see if they have anything useful to say.
Measurements made using RDing's official TEMPerHum program (V 9.4, from the website) and a time interval of 5 seconds, unfortunately also show the same sudden jumps in temperature:
Additionally, the temperature values obtained by this program seem to be around 4-6 degrees C too high. So the temperature jumps appear to be hardware-related. I'm curious to hear if others have also experienced this behaviour...
Finally, I just noticed some example C code for the SHT11 (also available as ZIPped .c-file) that might be worth having a look at. With some minor modifications (driving the serial RTS/CTS lines instead of a microcontroller, and adding timed delays with e.g. the POSIX nanosleep() call) it can be used for the TEMPerHum. (Compare with Tollef's TEMPer (LM75) C code and Levanter30's LM75 & SHT11 C# code. I can't compile C# though. ;-)
Note 1:
This is what happens when I patch Ubuntu's 2.6.24 kernel modules using Tollef's patch, and then try to access /dev/ttyUSB0. The kernel goes OOPS. :-/ (Sigh, monolithic kernels...)
[ 0.000000] Linux version 2.6.24-21-generic (buildd@palmer) (gcc version 4.2.3 (Ubuntu 4.2.3-2ubuntu7)) #1 SMP Tue Oct 21 23:43:45 UTC 2008 (Ubuntu 2.6.24-21.43-generic)
[...]
[ 314.956171] BUG: unable to handle kernel NULL pointer dereference at virtual address 00000028
[ 314.956184] printing eip: e0ac473a *pde = 00000000
[ 314.956193] Oops: 0002 [#1] SMP
[ 314.956199] Modules linked in: nls_iso8859_1 nls_cp437 vfat fat binfmt_misc radeon drm af_packet cpufreq_ondemand acpi_cpufreq freq_table rfcomm l2cap bluetooth nfsd lockd nfs_acl auth_rpcgss sunrpc exportfs ppdev ipv6 snd_atiixp_modem snd_via82xx_modem snd_intel8x0m container dock sbs sbshc iptable_filter ip_tables x_tables sbp2 lp pcmcia joydev snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm_oss snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_seq_midi snd_rawmidi snd_seq_midi_event ch341(F) snd_seq usbserial snd_timer snd_seq_device wacom yenta_socket snd wbsd irtty_sir asus_laptop video output i2c_sis96x rsrc_nonstatic parport_pc soundcore serio_raw sis_agp sir_dev led_class battery ac button i2c_core shpchp pci_hotplug pcmcia_core parport snd_page_alloc agpgart mmc_core evdev irda psmouse pcspkr crc_ccitt ext3 jbd mbcache usbhid hid usb_storage libusual sg sr_mod cdrom sd_mod ata_generic ohci1394 ehci_hcd ieee1394 ohci_hcd pata_sis pata_acpi sis900 mii usbcore libata scsi_mod thermal processor fan fuse fbcon tileblit font bitblit softcursor
[ 314.956320]
[ 314.956326] Pid: 6859, comm: TEMPer Tainted: GF (2.6.24-21-generic #1)
[ 314.956331] EIP: 0060:[] EFLAGS: 00010246 CPU: 0
[ 314.956344] EIP is at ch341_open+0x9a/0x1f0 [ch341]
[ 314.956348] EAX: 00000000 EBX: deeb5be0 ECX: c1407508 EDX: df911400
[ 314.956353] ESI: df9f6600 EDI: de89ba00 EBP: c38d8900 ESP: cabede74
[ 314.956357] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
[ 314.956362] Process TEMPer (pid: 6859, ti=cabec000 task=c98ed700 task.ti=cabec000)
[ 314.956365] Stack: dfa94000 00000286 c0261797 00000000 c02626ad de89ba00 df9f6600 de448000
[ 314.956377] de89ba0c e0ae43aa c0261614 c021535f dd410680 c38d8900 ffffffed 00000000
[ 314.956388] 0bc00000 c38d8900 00000100 c02653f3 010200fe 00000000 de448000 dfa94004
[ 314.956400] Call Trace:
[ 314.956413] [] tty_ldisc_enable+0x27/0x30
[ 314.956432] [] init_dev+0x22d/0x580
[ 314.956463] [] serial_open+0xca/0x160 [usbserial]
[ 314.956480] [] check_tty_count+0x14/0xb0
[ 314.956487] [] kobject_get+0xf/0x20
[ 314.956530] [] tty_open+0x143/0x2f0
[ 314.956561] [] tty_open+0x0/0x2f0
[ 314.956573] [] chrdev_open+0xa3/0x190
[ 314.956611] [] __dentry_open+0xbf/0x1c0
[ 314.956642] [] nameidata_to_filp+0x35/0x40
[ 314.956654] [] chrdev_open+0x0/0x190
[ 314.956666] [] do_filp_open+0x50/0x60
[ 314.956758] [] get_unused_fd_flags+0x52/0xd0
[ 314.956794] [] do_sys_open+0x4c/0xe0
[ 314.956834] [] sys_open+0x1c/0x20
[ 314.956845] [] sysenter_past_esp+0x6b/0xa9
[ 314.956897] [] unix_destruct_fds+0x40/0x50
[ 314.956943] =======================
[ 314.956946] Code: 00 0f b6 53 14 8b 06 e8 75 fa ff ff 85 c0 75 c4 8b 06 89 da e8 c8 fa ff ff 85 c0 75 b7 a1 80 5c ac e0 85 c0 75 37 8b 47 24 8b 16 <89> 50 28 8b 47 24 ba d0 00 00 00 e8 76 d9 e2 ff 85 c0 89 c3 75
[ 314.957004] EIP: [] ch341_open+0x9a/0x1f0 [ch341] SS:ESP 0068:cabede74
[ 314.957039] ---[ end trace d42c5555d0f76f81 ]---
Note 2:
Gnuplot code used to produce one of the figures above:
set xlabel "time (minutes)"
set ylabel "T (deg C)"
set y2label "RH (%)"
set ytics auto nomirror
set y2tics auto nomirror
set xtics 15
set grid
plot "temp-1122.dat" using 2:6 title "reference temperature measurements" with points, "temperhum-1122.dat" using ($0*0.65/60):1 title "temperature (deg C)" with line, "temperhum-1122.dat" using ($0*0.65/60):2 axis x1y2 title "relative humidity (%)" with line
Note 3:
Of course, if you want to do things properly, build it yourself... ;-)