USBRH+Cactiで室温モニタリング(1)

前置き

蒸し暑い毎日。Strawberry Linux さんで発売している USBRH + Cacti を使って室温モニタリングをしてみる。USBRH を Linux で使うに当たっては既に各所からいろいろな情報が出ているのでそれを参考に。

使う上でのあれこれは id:dayflower の一連のエントリをみるのがよさげ。

なお、今回使用している LinuxDebian GNU/Linux 5.0.4 (Lenny) です。

USBRH デバイス情報の確認

共通する操作として、USBRH を Linux に接続したときにどういう風に見えるのかというのを。

$ lsusb
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 003: ID 1774:1001
Bus 003 Device 002: ID 04ca:0027 Lite-On Technology Corp.
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
    • ID 1774:1001 が USBRH
  • もう少し詳しい情報を出してみる
    • lsusb -v は root で実行しないと Manufacturer とか出ない
    • udevinfo で指定しているパスの .../usbdev3.3/ は Bus:3/Device:3 に対応。これは接続しているUSB機器とかUSB抜き直したりすると変化するので注意。
$ lsusb -v -d 1774:

Bus 003 Device 003: ID 1774:1001
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x1774
  idProduct          0x1001
  bcdDevice            1.00
  iManufacturer           1 Strawberry Linux Co.,Ltd.
  iProduct                2 Hygrometer/Thermometer
  iSerial                 0

(...snip)

$ udevinfo -a -p /sys/class/usb_device/usbdev3.3/

Udevinfo starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/class/usb_device/usbdev3.3':
    KERNEL=="usbdev3.3"
    SUBSYSTEM=="usb_device"
    DRIVER==""

  looking at parent device '/devices/pci0000:00/0000:00:1d.2/usb3/3-2':
    KERNELS=="3-2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bMaxPower}==" 50mA"
    ATTRS{urbnum}=="51"
    ATTRS{idVendor}=="1774"
    ATTRS{idProduct}=="1001"
    ATTRS{bcdDevice}=="0100"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="8"
    ATTRS{speed}=="1.5"
    ATTRS{busnum}=="3"
    ATTRS{devnum}=="3"
    ATTRS{version}==" 1.10"
    ATTRS{maxchild}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="Strawberry Linux Co.,Ltd."
    ATTRS{product}=="Hygrometer/Thermometer"

(snip)

USBRH on Linux を使う

必要最小限の使い方
  • libusb-dev をインストールしていなければ入れる。
$ aptitude search libusb-dev
p   libusb-dev                               - userspace USB programming library development file
$ aptitude install libusb-dev
(...snip)
$ wget http://www.dd.iij4u.or.jp/~briareos/soft/usbrh-0.05.tar.gz
$ tar xvzf usbrh-0.05.tar.gz
$ cd usbrh-0.05
$ ls
Makefile  readme.txt  usbrh_main.c
$ make
gcc -lusb -g -o usbrh usbrh_main.c
$ ./usbrh
usb_set_configuration error
  • このエラーの回避方法はこちらにある。以下のパッチを当てる。
--- usbrh_main.c.orig   2010-07-10 17:20:44.000000000 +0900
+++ usbrh_main.c        2010-07-10 17:22:33.000000000 +0900
@@ -230,9 +230,12 @@
     }

     if((rc = usb_set_configuration(dh, dev->config->bConfigurationValue))<0){
-        puts("usb_set_configuration error");
-        usb_close(dh);
-        exit(3);
+        if( rc = usb_detach_kernel_driver_np(dh, dev->config->interface->altsetting->bInterfaceNumber)<0 ){
+
+            puts("usb_set_configuration error");
+            usb_close(dh);
+            exit(3);
+        }
     }

     if((rc =usb_claim_interface(dh, dev->config->interface->altsetting->bInterfaceNumber))<0){
  • もう一度 Make して試す。
$ make
gcc -lusb -g -o usbrh usbrh_main.c
$ ./usbrh
31.67 56.91
$ ./usbrh -v
Temperature: 32.54 C
Humidity: 50.42 %

OK

一般ユーザでも使えるようにする

あまりこだわらないならこれで十分使える。が、root じゃないと動いてくれないとかちょっと使いにくいので、一般ユーザでも利用できるようにした方がよいでしょう。で、どうやったらよいかは以下のページに書いてある。

結論だけ書くと、udev でデバイスが追加されたときに permission を変更してあげましょう、と。

  • こういうファイルを追加
/etc/udev/rules.d
$ cat 99-udev-local.rules
BUS=="usb", SYSFS{idVendor}=="1774", SYSFS{idProduct}=="1001", MODE="0666"
  • テスト
$ udevadm test /sys/class/usb_device/usbdev3.3
This program is for debugging only, it does not run any program,
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

add_matching_files: unable to open '/lib/udev/rules.d': No such file or directory
parse_file: reading '/etc/udev/rules.d/025_libgphoto2.rules' as rules file
parse_file: reading '/etc/udev/rules.d/11-hplj10xx.rules' as rules file

(...snip...)

parse_file: reading '/etc/udev/rules.d/z60_libsane.rules' as rules file
parse_file: reading '/etc/udev/rules.d/z60_xserver-xorg-input-wacom.rules' as rules file
import_uevent_var: import into environment: 'MAJOR=189'
import_uevent_var: import into environment: 'MINOR=258'
import_uevent_var: import into environment: 'PHYSDEVPATH=/devices/pci0000:00/0000:00:1d.2/usb3/3-2'
import_uevent_var: import into environment: 'PHYSDEVBUS=usb'
import_uevent_var: import into environment: 'PHYSDEVDRIVER=usb'
udevtest: looking at device '/class/usb_device/usbdev3.3' from subsystem 'usb_device'
run_program: 'check-ptp-camera 06/01/01'
run_program: '/lib/udev/check-ptp-camera' returned with status 1
udev_rules_get_name: add symlink 'char/189:258'
run_program: '/bin/sh -c 'K=usbdev3.3; K=${K#usbdev}; printf bus/usb/%03i/%03i ${K%%.*} ${K#*.}''
run_program: '/bin/sh' (stdout) 'bus/usb/003/003'
run_program: '/bin/sh' returned with status 0
udev_rules_get_name: rule applied, 'usbdev3.3' becomes 'bus/usb/003/003'
udev_device_event: device '/class/usb_device/usbdev3.3' already in database, cleanup
udev_node_add: creating device node '/dev/bus/usb/003/003', major=189, minor=258, mode=0666, uid=0, gid=0
udev_node_update_symlinks: update symlink 'char/189:258' of '/class/usb_device/usbdev3.3'
udev_db_get_devices_by_name: found index directory '/dev/.udev/names/char\x2f189:258'
update_link: found 2 devices with name 'char/189:258'
update_link: found '/class/usb_device/usbdev3.3' for 'char/189:258'
update_link: compare (our own) priority of '/class/usb_device/usbdev3.3' 0 >= 0
update_link: found '/devices/pci0000:00/0000:00:1d.2/usb3/3-2' for 'char/189:258'
update_link: compare priority of '/devices/pci0000:00/0000:00:1d.2/usb3/3-2' 0 > 0
update_link: 'char/189:258' with target 'bus/usb/003/003' has the highest priority 0, create it
udevtest: run: 'socket:/org/freedesktop/hal/udev_event'
udevtest: run: 'socket:@/org/kernel/udev/monitor'
    • mode=0666 になっていることを確認したら設定ファイルの reload を実行
$ udevadm control --reload_rules
  • 一度抜いて指し直し。確認。これで一般ユーザも usbrh を使える。
$ lsusb
Bus 001 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 004: ID 1774:1001
Bus 003 Device 002: ID 04ca:0027 Lite-On Technology Corp.
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
$ ls -l /dev/bus/usb/003/
total 0
crw-rw-r-- 1 root root 189, 256 May 20 00:07 001
crw-rw-r-- 1 root root 189, 257 May 20 00:07 002
crw-rw-rw- 1 root root 189, 259 Jul 10 18:14 004

USBRH driver for Linuxを使う。

usbrh-0.05 でも用は足りるのだけど、driver の方は LED の制御やヒータの制御なんかができたりして高機能なのだ。どうせならこっちを使いたい。

必要最小限の使い方
  • Linux Kernel Header が入っていない場合は入れておく。/lib/modules//build がなければインストールされていない。
$ aptitude install linux-headers-2.6.26-2-all
(...snip)
$ ls -l /lib/modules/2.6.26-2-686/
total 1872
lrwxrwxrwx 1 root root     35 Jul 11 20:11 build -> /usr/src/linux-headers-2.6.26-2-686/
drwxr-xr-x 9 root root   4096 Mar 13 14:09 kernel/
(...snip)
$ wget http://acapulco.dyndns.org/usbrh/dist/usbrh-0.0.8.tgz
$ make
make -C src all
make[1]: Entering directory `/root/usbrh/usbrh-0.0.8/src'
make -C /lib/modules/2.6.26-2-686/build M=/root/usbrh/usbrh-0.0.8/src modules
make[2]: Entering directory `/usr/src/linux-headers-2.6.26-2-686'
  CC [M]  /root/usbrh/usbrh-0.0.8/src/usbrh.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /root/usbrh/usbrh-0.0.8/src/usbrh.mod.o
  LD [M]  /root/usbrh/usbrh-0.0.8/src/usbrh.ko
make[2]: Leaving directory `/usr/src/linux-headers-2.6.26-2-686'
make[1]: Leaving directory `/root/usbrh/usbrh-0.0.8/src'
  • インストール
$ make install
make -C src install
make[1]: Entering directory `/root/usbrh/usbrh-0.0.8/src'
make -C /lib/modules/2.6.26-2-686/build M=/root/usbrh/usbrh-0.0.8/src modules_install
make[2]: Entering directory `/usr/src/linux-headers-2.6.26-2-686'
  INSTALL /root/usbrh/usbrh-0.0.8/src/usbrh.ko
  DEPMOD  2.6.26-2-686
make[2]: Leaving directory `/usr/src/linux-headers-2.6.26-2-686'
make[1]: Leaving directory `/root/usbrh/usbrh-0.0.8/src'
cp -f util/10-usbrh.rules /etc/udev/rules.d/
cp -f util/usbrh.conf /etc/modprobe.d/
  • これでカーネルモジュールがインストールされているので depmod コマンドを実行してモジュールを組み込む。
$ /sbin/depmod -a
$ modprobe usbrh
$ lsmod | grep usb
usbrh                   6020  0
usbhid                 35904  0
hid                    33184  1 usbhid
ff_memless              4392  1 usbhid
usbcore               118192  5 usbrh,usbhid,ehci_hcd,uhci_hcd
$ rmmod usbhid; modprobe usbhid
  • 確認
$ ls -la /proc/usbrh/0/
total 0
dr-xr-xr-x 2 root root 0 Jul 11 21:22 ./
dr-xr-xr-x 3 root root 0 Jul 11 21:22 ../
-rw-r--r-- 1 root root 0 Jul 11 21:22 heater
-r--r--r-- 1 root root 0 Jul 11 21:22 humidity
-rw-r--r-- 1 root root 0 Jul 11 21:22 led
-r--r--r-- 1 root root 0 Jul 11 21:22 status
-r--r--r-- 1 root root 0 Jul 11 21:22 temperature
$ cat /proc/usbrh/0/temperature
30.32
$ cat /proc/usbrh/0/humidity
60.33
$ cat /proc/usbrh/0/status
t:30.32 h:60.37
一般ユーザにも LED 操作させたい
  • で。USBRH driver は情報の取得 (Read) については一般ユーザでもできるのだけど、Write については root じゃないとできない。でもどうせだったら LED も一般ユーザから点滅させたいなあと思ったりする。*1 今回の場合、udev は usbrh kernel module を組み込むところだけをやっていて、/proc/usbrh 以下の内容は組み込まれたドライバが実施しているので、udev の設定ではいじれない……はず(方法はあるかもしれないけど udev の話とかそんなに知らないので…)
  • ではどうするかというと、driver で /proc にエントリ登録するところでパーミッションを指定している箇所があるので、それを書き換えてしまう、と。
--- usbrh.c.orig        2010-07-11 23:44:33.000000000 +0900
+++ usbrh.c     2010-07-11 23:44:47.000000000 +0900
@@ -405,7 +405,7 @@
                                                dev);
         } else {
             proc_file = create_proc_entry(USBRH_ENTRY_LIST[i].name,
-                                          S_IFREG|S_IRUGO|S_IWUSR, proc_dir);
+                                          S_IFREG|S_IRUGO|S_IWUGO, proc_dir);

             if (proc_file != NULL) {
                 proc_file->read_proc = USBRH_ENTRY_LIST[i].read_proc;
  • このパッチ当てて make && make install して、usbrh を unload/load する。
    • 要は、フラグの値を変えているだけ (S_IWUSR : Write User を S_IWUGO : Write User/Group/Other) : 参照 Manpage of STAT
  • で、こうなっていれば ok
$ ls -l /proc/usbrh/0/
total 0
-rw-rw-rw- 1 root root 0 Jul 11 23:51 heater
-r--r--r-- 1 root root 0 Jul 11 23:51 humidity
-rw-rw-rw- 1 root root 0 Jul 11 23:51 led
-r--r--r-- 1 root root 0 Jul 11 23:51 status
-r--r--r-- 1 root root 0 Jul 11 23:51 temperature
  • usbhid とのドライバ読み込み順でどうしても面倒なあたりについては USBRH driver for Linux を CentOS 5 で使う あたりで説明されている方法を使うと良さそうではあるけどまだ試してません…。

で、Cacti でモニタリングしよう…という話になるのだけど、それはまたあとで。

USBRH+Cactiで室温モニタリング(2) へ続く。

*1:今回接続する機械は複数ユーザで使うことを想定していない機械なので…