USBRH+Cactiで室温モニタリング(1)
前置き
蒸し暑い毎日。Strawberry Linux さんで発売している USBRH + Cacti を使って室温モニタリングをしてみる。USBRH を Linux で使うに当たっては既に各所からいろいろな情報が出ているのでそれを参考に。
- USB温湿度計 - PukiWiki
- だいたいこのページから情報がたどれる。
- USBRH on Linux
- Linux用 USBRH 操作アプリ
- USBRH driver for Linux
使う上でのあれこれは id:dayflower の一連のエントリをみるのがよさげ。
- USB-RH で遊ぶ - daily dayflower
- USB-RH で温湿度を収集しグラフ化(collectd & rrdtool) - daily dayflower
- USBRH driver for Linux を CentOS 5 で使う - daily dayflower
なお、今回使用している Linux は Debian GNU/Linux 5.0.4 (Lenny) です。
USBRH デバイス情報の確認
共通する操作として、USBRH を Linux に接続したときにどういう風に見えるのかというのを。
- USB デバイスの一覧
$ 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)
- usbrh-0.05.tar.gz をダウンロードしてコンパイル
$ 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
- で、一度デバイスを挿し直してみるのだけど、USBRH ドライバではなく USB HID ドライバがロードされてしまっている にある状況に引っかかってしまった。一旦 usbhid ドライバの unload/load する。
$ 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 でモニタリングしよう…という話になるのだけど、それはまたあとで。
*1:今回接続する機械は複数ユーザで使うことを想定していない機械なので…