pcsensor-1.0.3 for TEMPerV1.2/TEMPerV2 with multi device and multi sensor support

昨日、TEMPerV2を使っているユーザから、「githubであなたが改造したpcsensorに対してTERMPerV2対応を加えたものを公開してる人がいる」、ということを教えてもらった。

修正版:https://github.com/waja/pcsensors/blob/master/debian/patches/multiple_temerature_readings

ソースをみてもどういう修正なのかがわからなかったので、教えてくれた人に尋ねた。
TEMPerV2は、温度センサーを2つ持っているが、pcsensor.cの1.0.2では、1つ目の温度センサーの情報しか取得できない。
2つ目の温度センサーからも温度が取得できるようにした修正であるとのこと。

というわけで、自分のところのソース修正を開始

・センサーが2個である、という決め打ち修正はよくないのでMAX_SENSORで定義し
 それ以上の個数がある場合でも容易に対応ができるように変更
・センサーが1個しかないTEMPerV1.2で、2個分取得しようとすると異常な値になるので
 waja’s pcsensor.cの修正だけでは駄目なので、修正

修正したものを「https://github.com/osakanataro/pcsensor」にて公開しました。

また、「http://blog.osakana.net/sw/pcsensor/pcsensor-1.0.3.tar.gz」にtar.gzを置いています。

・マルチデバイス時にデバイス名を出力するオプション “-d”

# ./pcsensor -d
2014/07/11 10:42:13 Bus 002 Device 003 Temperature0 88.47F 31.38C
2014/07/11 10:42:13 Bus 003 Device 003 Temperature0 74.30F 23.50C
#

・接続されているTEMPerのリスト表示 “-D”

# ./pcsensor -D
0 is Bus 002 Device 003
1 is Bus 003 Device 003
#

・接続されているTEMPerの個別表示 “-D番号”

# ./pcsensor -D0
2014/07/11 10:43:48 Temperature0 88.47F 31.38C
# ./pcsensor -D1
2014/07/11 10:44:16 Temperature0 74.30F 23.50C
#

・摂氏/華氏表示の同時指定を可能にした

# ./pcsensor -c
2014/07/11 10:44:49 Temperature0 31.38C
2014/07/11 10:44:49 Temperature0 23.50C
# ./pcsensor -f
2014/07/11 10:44:53 Temperature0 88.47F
2014/07/11 10:44:53 Temperature0 74.30F
# ./pcsensor -f -c
2014/07/11 10:45:02 Temperature0 88.47F 31.38C
2014/07/11 10:45:02 Temperature0 74.30F 23.50C
#

・1つのデバイスに2個の温度センサーがついている場合

# ./pcsensor -c -n2
2014/07/11 10:44:49 Temperature0 31.38C
2014/07/11 10:44:49 Temperature1 23.50C
#

なお、センサーが1つしかないもので、-n2指定すると以下の様な異常値になります。

# ./pcsensor -c -n2
2014/07/11 11:09:41 Temperature0 214.60F 101.45C
2014/07/11 11:09:41 Temperature1 32.00F 0.00C
#

munin向けのpcsensorプラグインを作った

上海問屋のDNSB-35137など、いくつかの販路で取り扱われているUSB接続の温度計 RDing TEMPerV1.2。

その温度をmuninで計測するためにpluginを作った。

今回考慮が必要だった点
・USB温度計を2つつなぐ
・つなぐUSB BUSが同じであるため、CentOS5上で見分けがつかない
 (TEMPerV1.2ではシリアルを含めデバイス内のパラメータが全部一緒で見分ける方法がない)
・2つの温度計の設置位置は違うので、温度差が5度ぐらいある
・pcsensorコマンド実行時、デバイスがオフラインになることが良くある
 (参考→USB温度計 TEMPerV1.2は計測ミスが多い)

あまり複雑なことをするのも嫌だったので、単純な実装としました。

・温度が2つ取得できるまで、再試行する
・温度が低い方から順にソートして「usbtemper0」「usbtemper1」としていく

また、内部で使うコマンドは、うちで作成した「pcsensor-1.0.2 for TEMPerV1.2 with multi device support」を使います。

USB温度計を1個しか繋がない人は「my $maxdevice=1;」に書き換えてください。

#!/usr/bin/perl -w

my $options="-d";
my $maxdevice=2;

my $arg=$ARGV[0];
if(!$arg){ $arg=""; }

if("$arg" eq "config"){
    print "graph_title USB Temperature Sensor\n";
    print "graph_vtitle Celsius\n";
    print "graph_category sensors\n";
    print "graph_args --base 1000 -l 0\n";
}

my @devlist;
my $count=0;
while($count<$maxdevice){
    open(FILE,"/usr/local/bin/pcsensor $options|");
    while(my $line=<FILE>){
        $line =~ s/\n//ig;

        if($line =~ /Temperature/){
            my @strs=split(/ /,$line);

            my $devnumber=$strs[3] ."-". $strs[5];
            my $value=$strs[8];
            $value=~ s/C//ig;
            #$value=int($value);

            $devlist[$count]=$value;
            $count++;
        }
    }
    close(FILE);
}

my $counttmp=0;
foreach $value (sort @devlist){
    if("$arg" eq "config"){
        print "usbtemper".$counttmp.".label USB temper".$counttmp."\n";
    }else{
        print "usbtemper".$counttmp.".value ".$value."\n";
    }
    $counttmp++;
}

これ、仕掛けて3時間ぐらいしたら、kernel panic起こしやがった・・・

pcsensor-1.0.2 for TEMPerV1.2 with multi device support

USB温度計 TEMPer V1.2向けの温度計測ソフトウェアpcsensorを、自分の使い道にあうように改造しました。

http://blog.osakana.net/sw/pcsensor/pcsensor-1.0.2.tar.gz

元となったプログラムは以下の2つ。
・Juan Carlos Perezさん製作: http://www.isp-sl.com/pcsensor-1.0.1.tgz
・Momtchil Momtchevさん製作: pcsensor-1.0.0-multi.tgz (Juanさんのpcsensor-0.0.1.tgzを元にしている)からマルチデバイスサポートのやり方

追加した機能
・マルチデバイス時にデバイス名を出力するオプション “-d”

# ./pcsensor -d
2013/01/20 14:42:13 Bus 002 Device 003 Temperature 88.47F 31.38C
2013/01/20 14:42:13 Bus 003 Device 003 Temperature 74.30F 23.50C
#

・接続されているTEMPerのリスト表示 “-D”

# ./pcsensor -D
0 is Bus 002 Device 003
1 is Bus 003 Device 003
#

・接続されているTEMPerの個別表示 “-D番号”

# ./pcsensor -D0
2013/01/20 14:43:48 Temperature 88.47F 31.38C
# ./pcsensor -D1
2013/01/20 14:44:16 Temperature 74.30F 23.50C
#

・摂氏/華氏表示の同時指定を可能にした

# ./pcsensor -c
2013/01/20 14:44:49 Temperature 31.38C
2013/01/20 14:44:49 Temperature 23.50C
# ./pcsensor -f
2013/01/20 14:44:53 Temperature 88.47F
2013/01/20 14:44:53 Temperature 74.30F
# ./pcsensor -f -c
2013/01/20 14:45:02 Temperature 88.47F 31.38C
2013/01/20 14:45:02 Temperature 74.30F 23.50C
#

USB温度計 TEMPerV1.2は計測ミスが多い

(注意: TEMPer V1.2のドライバは→「ここ」にあります)
USB温度計TEMPer V1.2で温度取得をおこなっていると、以下の様な形で、エラーとなることがある。

 $ ./pcsensor
USB interrupt read: Resource temporarily unavailable
Fatal error> USB read failed
$

しかも、これが発生すると該当デバイスは一度offlineとなり、別のデバイスとして認識されてしまいます。

どれくらいの確率で発生するのかを、スクリプト組んで確かめてみました。

作成したスクリプト

#!/bin/bash

SUCCESS=0
FAILED=0
I=0
while [ $I -lt 1000 ]
do
        echo -n "$I "
        ./pcsensor > /dev/null 2>&1
        if [ $? -eq 0 ];
        then
                SUCCESS=`expr $SUCCESS + 1`
        else
                FAILED=`expr $FAILED + 1`
        fi
        sleep 5
        I=`expr $I + 1`
done
echo ""
echo "successed: $SUCCESS"
echo "failed:    $FAILED"

pcsensorを実行して5秒待つ、というのを繰り返すという、まぁ、素直なものですね。

USB温度計を2つつなげて、1000回の測定を開始!

$ ./test.sh
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
<略>
7 988 989 990 991 992 993 994 995 996 997 998 999
successed: 879
failed:    121
$

2個のうちどちらか片方こけただけでも、両方アウトになるので、失敗確率が結構いってしまいます。

また、エラーが発生すると、offlineになるので、ログには以下の様な記録がずらずらっと・・・

# tail /var/log/messages
Jan 17 15:02:27 temperserver kernel: usb 2-2: configuration #1 chosen from 1 choice
Jan 17 15:02:27 temperserver kernel: input: RDing TEMPerV1.2 as /class/input/input174
Jan 17 15:02:27 temperserver kernel: input,hidraw0: USB HID v1.10 Keyboard [RDing TEMPerV1.2] on usb-0000:00:1d.0-2
Jan 17 15:02:27 temperserver kernel: hiddev96,hidraw96: USB HID v1.10 Device [RDing TEMPerV1.2] on usb-0000:00:1d.0-2
Jan 17 15:03:02 temperserver kernel: usb 3-1: USB disconnect, address 90
Jan 17 15:03:03 temperserver kernel: usb 3-1: new low speed USB device using uhci_hcd and address 91
Jan 17 15:03:03 temperserver kernel: usb 3-1: configuration #1 chosen from 1 choice
Jan 17 15:03:03 temperserver kernel: input: RDing TEMPerV1.2 as /class/input/input175
Jan 17 15:03:03 temperserver kernel: input,hidraw0: USB HID v1.10 Keyboard [RDing TEMPerV1.2] on usb-0000:00:1d.1-1
Jan 17 15:03:03 temperserver kernel: hiddev96,hidraw96: USB HID v1.10 Device [RDing TEMPerV1.2] on usb-0000:00:1d.1-1

そして、lsusbを実行すると、以下のように、デバイス番号がすごいことに・・・

# lsusb
Protocol spec without prior Class and Subclass spec at line 4297
Bus 003 Device 091: ID 0c45:7401 Microdia
Bus 003 Device 001: ID 0000:0000
Bus 002 Device 084: ID 0c45:7401 Microdia
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 001: ID 0000:0000

(1000回スクリプト実行前にも、テストとかをおこなっているので・・・)

運用に当たっては、いろいろ配慮が必要なようです。

LinuxサーバにUSB温度計を2つつけてみた

dealextremeから、USB温度計が届いたので、Linuxサーバに複数取り付けてみた。
(ちなみに、上海問屋では欠品ですが、Dealextremeの公式ショップで買うと送料込みで$9.2で、3週間~4週間で到着します。)

いままでは、Relavk Labsの「TEMPer Temperature Sensor Linux Driver」のCrayさんコメントにある「pcsensor-0.0.1.tgz」を使っていましたが、これは1つのみの対応でした。
(ちなみに、Crayさんが「pcsensor-1.0.1.tgz」にアップデートしたとコメントしていましたが、相変わらず1個のみの対応でした。http://www.isp-sl.com/pcsensor-1.0.1.tgz

複数のUSB温度計をつけた場合に対応しているものを探したところ、同じコメント欄に発見しました。
Momtchil Momtchevさんが「pcsensor-1.0.0-multi.tgz」を作ったとコメントしています。
コメント内のリンク先は消えていましたが、「A modified TemperUSB driver that supports multiple devices」にて配布されていました。

(2013/01/24追記: デバイス指定ができる改良版をpcsensor-1.0.2 for TEMPerV1.2 with multi device supportにて公開中)

 $  ./pcsensor
2013/01/16 18:30:12 Temperature 77.45F 25.25C
2013/01/16 18:30:12 Temperature 91.18F 32.88C
$

が・・・デバイスの指定はできないようです。

詳細オプションをつけるとこんな感じです。

$ ./pcsensor -v
usb_set_debug: Setting debugging level to 255 (on)
usb_os_init: Found USB VFS at /dev/bus/usb
usb_os_find_busses: Found 003
usb_os_find_busses: Found 002
usb_os_find_busses: Found 001
usb_os_find_devices: Found 004 on 003
skipped 1 class/vendor specific interface descriptors
skipped 1 class/vendor specific interface descriptors
usb_os_find_devices: Found 001 on 003
error obtaining child information: Inappropriate ioctl for device
usb_os_find_devices: Found 003 on 002
skipped 1 class/vendor specific interface descriptors
skipped 1 class/vendor specific interface descriptors
usb_os_find_devices: Found 001 on 002
error obtaining child information: Inappropriate ioctl for device
usb_os_find_devices: Found 001 on 001
lvr_winusb with Vendor Id: c45 and Product Id: 7401 found.
lvr_winusb with Vendor Id: c45 and Product Id: 7401 found.
USB error: could not detach kernel driver from interface 0: No data available
Device already detached
USB error: could not detach kernel driver from interface 1: No data available
Device already detached
USB error: could not detach kernel driver from interface 0: No data available
Device already detached
USB error: could not detach kernel driver from interface 1: No data available
Device already detached
01 01 6f 20 64 61 74 61
01 80 33 01 00 00 00 00
80 02 19 40 65 72 46 31
01 82 77 01 00 00 00 00
82 01 00 40 65 72 46 31
01 86 ff 01 00 00 00 00
54 45 4d 50 65 72 46 31
2e 32 4d 50 65 72 46 31
01 01 4a d6 ff 7f 00 00
01 80 33 01 00 00 00 00
80 02 20 e0 65 72 46 31
01 82 77 01 00 00 00 00
82 01 00 e0 65 72 46 31
01 86 ff 01 00 00 00 00
54 45 4d 50 65 72 46 31
2e 32 4d 50 65 72 46 31
01 80 33 01 00 00 00 00
80 02 19 40 65 72 46 31
2013/01/16 18:30:49 Temperature 77.45F 25.25C
01 80 33 01 00 00 00 00
80 02 20 e0 65 72 46 31
2013/01/16 18:30:49 Temperature 91.18F 32.88C
$