2012年12月09日

外出先で自宅エアコン電源制御(その4)

 さて、いよいよCGIの話です。CGIと言えばPerlと思われがちですが、実はC言語でCGIを書くことも可能です。ハードウェア制御もあるのでC言語で全部書こうと思いました。しかし、適材適所を意識するとC言語とPerlを組み合わせたほうがよさそうです。

 今回は、ハードウェア制御部はC言語で、Web画面部はPerlで書きます。Perlからsystem関数でハードウェア制御部を呼び出すイメージです。

 とうことで、今回はハードウェア制御部だけの話を書きます。CGIは次回に。。。

 ソースは以下のようになります。コマンドを実行することで電源制御命令を出します。HA端子的に言えば電源制御パルスを出すということですね。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <time.h>

#define DEV_NAME "/dev/ttyUSB1" // デバイスファイル名
#define BAUD_RATE B38400 // RS232C通信ボーレート
#define BUFF_SIZE 512 // 適当

// シリアルポートの初期化
int serial_init(int fd)
{
int ret;
struct termios tio;
memset(&tio,0,sizeof(tio));
tio.c_cflag = CS8 | CLOCAL | CREAD;
tio.c_cc[VTIME] = 0;
// ボーレートの設定
ret=cfsetispeed(&tio,BAUD_RATE);
if(ret!=0)return ret;
ret=cfsetospeed(&tio,BAUD_RATE);
if(ret!=0)return ret;
// デバイスに設定を行う
ret=tcsetattr(fd,TCSANOW,&tio);
if(ret!=0)return ret;
}

int main(int argc,char *argv[]){
int fd;

// デバイスファイル(シリアルポート)オープン
fd = open(DEV_NAME,O_RDWR);
if(fd<0){
// デバイスの open() に失敗したら
perror(argv[1]);
printf("open error.\n");
exit(1);
}

// シリアルポートの初期化
if(serial_init(fd)<0){
printf("serial init error.\n");
}

unsigned char buffer[BUFF_SIZE];
memset(buffer,0,BUFF_SIZE);
write(fd,buffer,BUFF_SIZE);

close(fd);
return 0;
}


 ポイントとしては、シリアルポートもファイルI/Oとして扱うことでしょうか。ファイル関連システムコールだけでは扱えない部分はtcsetattr()などを用いています。

 前回の説明では、300bpsで3バイト送信しておりましたが、このソースでは38400bpsで512バイト送信しています。何故かというと、うまく300bpsに設定できなかったからです。シェルから実行する分には300bpsに設定できていたのですが、CGIから実行すると無視されてしまいます。なんかしらのセキュリティの設定のせいだとは思うのですが、セキュリティを外すよりは、あきらめて初期値の38400bpsのままにしちゃうほうが安全かなと思った次第です。

 38400bpsで100msのパルスを出すには384バイト送信すればいいのですが、512バイト送信しています。これはもう気分だけの問題です。エアコン側との相性もあると思うので、自作される場合は調整してみてください。

 もう一つ、入力側の制御コマンドを示します。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <sys/ioctl.h>

#define DEV_NAME "/dev/ttyUSB1" // デバイスファイル名

int main(int argc,char *argv[]){
int fd;

// デバイスファイル(シリアルポート)オープン
fd = open(DEV_NAME,O_RDWR);
if(fd<0){
// デバイスの open() に失敗したら
perror(argv[1]);
printf("open error.\n");
exit(1);
}

int lstat;
ioctl( fd, TIOCMGET, &lstat );
if( lstat & TIOCM_DSR ){
printf("1\n");
}else{
printf("0\n");
}
close(fd);
return 0;
}


 実行すると、エアコンのON/OFF状態を標準出力に出します。ONなら1、OFFなら0です。これのポイントも、ファイルI/Oとして扱う点ですかね。まったく同じですね。

 入力も出力もまとめて1本のプログラムにして、引数で動作を変えるほうがよいかもしれません。デバイスファイル名が2か所に出てくるのが気持ち悪いですしね。

 しかし、引数のパースが面倒なので、別々のプログラムにしてしまいました。別々のプログラムのほうが読みやすいのではないかと思います。

posted by tech4u at 17:45| Comment(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。