何の話?
サーバ冷却用の扇風機を、サーバのHDDやCPUの温度に連動させて自動的に動かしたり止めたりしましょうというお話。

使うもの
・Hardware
   リレー制御ボード RBIO-3E
   少し大きめのリレーでAC100VをON/OFFする回路

・Software
   hddtemp
     LinuxでハードディスクのS.M.A.R.T.情報から温度を取得するツール。
     デーモンとして起動して、ソケット通信で結果を取得できるので使いやすい。

   mbmon
     Linuxでマザーボードが報告する温度やらファン回転数やらを取得するソフト。
     hddtemp同様、ソケット通信で結果を取得できる。
     同梱されてるxmbmonはX上でグラフを表示してくれるが、
     今回はサーバ用途なのでmbmonしか使わない。

hddtempとmbmonの使い方
・インストール
どちらもソースを落としてきて./configureしてmakeして出来たバイナリを、パスの通った場所に置くだけで完了の簡単インストール。
hddtempは

./configure --with-db-path=/etc/hddtemp.db
みたいにしてHDDデータベースの場所を指定できるらしいので、これしたほうが使いやすいみたい。デフォルトでは/usr/share/misc/hddtemp.dbてな分かりにくい場所になってる。
で、このhddtemp.dbってのに自分の使ってるHDDが入ってなかったら動かないので、上記リンク先にある最新hddtemp.dbを落としておくか、自分の使うHDDだけ抜粋して書いておく。自分の使ってるHDDが無い場合、同じメーカーの近い型番のものを参考に、それっぽく書き換えると一応使える。

・起動
hddtempは

# hddtemp /dev/hda /dev/hdb /dev/hdc /dev/hdd
/dev/hda: Maxtor 6L160P0: 42°C
/dev/hdb: WDC WD2500JB-00REA0: 40°C
/dev/hdc: MAXTOR 6L080L4: 50°C
/dev/hdd: Maxtor 6L080P0: 41°C
てな感じで、hddtempの後に温度を見たいハードディスクデバイスを羅列すれば、こんな風に結果を返してくれる。
ただし、/dev/hdaとかにアクセス権がないとダメなので、rootでやるかsudoでやるかしないとダメ。
# hddtemp /dev/hda /dev/hdb /dev/hdc /dev/hdd -d -p ポート番号
とやってやることで、バックグラウンドで起動して任意のポートで待ち受ける。

mbmonは

$ mbmon

Temp.= 127.0, 20.0, 127.0; Rot.= 0, 0, 0
Vcore = 1.44, 1.49; Volt. = 3.26, 4.97, 11.31, -5.56, -2.19

Temp.= 127.0, 19.0, 127.0; Rot.= 0, 0, 0
Vcore = 1.44, 1.49; Volt. = 3.26, 4.97, 11.37, -7.84, -4.55

てな感じで、5秒ごとにいろんな情報を表示してくれる。
今回欲しいのは温度なわけだが、どれが何の温度かはマザーボードに依存するので分からない。
そして今俺のサーバマシンに使ってるASRocのP4i65Gでは、おそらくCPU温度と思われる2番目の温度が室温以下とかいうあり得ない数字を叩き出す。
まぁ、負荷をかけたら上がるので、絶対的に正確でなくても、基準を設けてそれより高いか低いかの区別は付くので大きな問題ではない。
これもhddtemp同様デーモンとして起動するわけだが、
mbmon -P ポート番号
だけでいい。-dとかは不要。

・データの取得
PHPで

<?php
//hddtemp
$host = localhost;
$port = ****;    //hddtempのポート番号
$socket = fsockopen($host,$port);
$hddtemp_result = fgets($socket,1024);
fclose($socket);

//mbmon
$port = ****;    //mbmonのポート番号
$socket = fsockopen($host,$port);
fgets($socket,1024);
$mbmon_result = fgets($socket,1024);
fclose($socket);

echo <<<EOH
<html>
<head>
</head>
<body>
<pre>{$hddtemp_result}</pre>
<br />
<pre>{$mbmon_result}</pre>
</body>
</html>
EOH;
?>

こうやって書いてやって実行すると、
|/dev/hda|Maxtor 6L160P0|42|C||/dev/hdb|WDC WD2500JB-00REA0|40|C||/dev/hdc|MAXTOR 6L080L4|49|C||/dev/hdd|Maxtor 6L080P0|40|C|

Temp.= 127.0, 19.0, 127.0; Rot.= 0, 0, 0

こんな具合に返ってくるので、適当に整形してやって欲しいデータを得る。
まぁ、見た感じhddtempは、
|デバイスパス1|製品名1|温度1|C||デバイスパス2|製品名2|温度2|C|・・・
となるようなので、『|』でsplitして4n+3番目を集めれば温度が取得できるでしょう。
mbmonは一見じゃまくさそうな形してるけど、幸い俺が欲しいのは2つめの温度なので、『,』でsplitして2つめを取得するだけでいい。

本題
以上の内容を踏まえて、本題である『扇風機を自動でON/OFFする』を実現するPHPスクリプトを書く。

・仕様
1.一定時間ごとに温度を確認してスイッチを切り替える
2.各デバイスごとに温度の閾値を個別設定する
3.常時ONや常時OFFの設定も可能にする

・ソース

<?php
/*************************************************************************************************
    Name : fan_control.php
    Acthion : 温度条件でRBIO-3Eの0番リレーを制御して扇風機をON/OFFする。
         バックグラウンドで動作させる。

                                2008.06.22 Ver.0.01 Genki wrote
                                2008.07.14 Ver.0.02 Genki edit.

    仕様
    ./modeファイルから動作モードを取得する(on,off,auto)
    mbmonとhddtempからの情報で切り替える
    while(1)でループ処理。
    (起動コマンドの最後に&をつけてバックグラウンドで実行する。)

***************************************************************************************************/
while(1){
//各種温度取得
    //vine hddtemp
    $host = "localhost";
    $port = ****;    //hddtempのポート番号
    $sock = fsockopen($host,$port);
    $result = trim(fgets($sock,1024));;
    $result = strtr($result, '|', ',');
    $trim = list(,,,$hdd[0],,,,,$hdd[1],,,,,$hdd[2],,,,,$hdd[3],) = split (",", $result);
    fclose($sock);
    
    //vine mbmon
    $port = ****;    //mbmonのポート番号
    $sock = fsockopen($host,$port);
    fgets($sock,1024);
    $result = trim(fgets($sock,1024));
    list(,$cpu[0],) = split(",",$result,3);
    $cpu[0] = str_replace(' ','',$cpu[0]);
    fclose($sock);
    
    //Firewall hddtemp
    $host = "firewall";
    $port = ****;    //ルータ機のhddtempのポート番号
    $sock = fsockopen($host,$port);
    $result = trim(fgets($sock,1024));;
    $result = strtr($result, '|', ',');
    $trim = list(,,,$hdd[4]) = split (",", $result);
    fclose($sock);

    //Firewall mbmon
    $port = ****;    //ルータ機のmbmonのポート番号
    $sock = fsockopen($host,$port);
    fgets($sock,1024);
    $result = trim(fgets($sock,1024));
    list(,$cpu[1],) = split(",",$result,3);
    $cpu[1] = str_replace(' ','',$cpu[1]);
    fclose($sock);
    
//条件設定
    if($hdd[0] > 45 || $hdd[1] > 42 || $hdd[2] > 52 || $hdd[3] > 45 || $hdd[4] > 35 || $cpu[0] > 27 || $cpu[1] > 38){
        $fan = "on";
    }else{
        $fan = "off";
    }

//RBIO接続
    $host = "rbio";
    $port = ****;    //rbioの待ち受けポート
    while(1){
        $sock = fsockopen($host,$port,$errorno,$errormsg,3);
        if(!$sock){
            sleep(1);
            continue;
        }else{
            break;
        }
    }
    
    //現在のスイッチ状態を把握
    fputs($sock,"PCA0\n");
    fgets($sock,16);
    $status = fgets($sock,16);
    fgets($sock,16);

    //動作モードget
    $mode = file("/etc/rbio/fan_mode");
    $mode = str_replace("\n",null,$mode[0]);

    //スイッチ状態を変化させる必要がある場合に切り替える。
    //################################################
    //#####注意! 0番リレーがONのとき扇風機がOFF #####
    //################################################
    //現状ONの場合、OFFにする作業だけする。
    if(ereg("0",$status)){    //RBIOのリレーがオフということは現在扇風機ON
        if($mode == "off" || $mode == "auto" && $fan == "off"){
            fputs($sock,"PCR01\n");
            fgets($sock,16);
            $res = fgets($sock,16);
        }
    //現状OFFの場合、ONにする作業だけする。
    }else{            
        if($mode == "on" || $mode == "auto" && $fan == "on"){
            fputs($sock,"PCR00\n");
            fgets($sock,16);
            $res[$i] = fgets($sock,16);
        }
    }
    fclose($sock);    //他で使うためにコネクションクローズ
    sleep(300);    //5分ごとのチェックでいいかな。
}
?>

/etc/rbio/fan_modeというファイルを作っておいて、中身をauto,on,offの3種類のどれかに外部から書き換えることで、動作モードを変更できる。
rbioは同時に1つしか接続を受け付けてくれないので、使う直前にfsockopenし、使ったらすぐfcloseする。
while(1)で無限ループするので、起動時に

php ./fan_control.php &
と、起動コマンドの最後にアンパサンドを付けてやってバックグラウンドで起動する。
この起動コマンドを/etc/rc.d/rc.localの下の方にフルパスで付け足して、サーバ再起動時にも動くようにしておく。