2012年11月28日水曜日

気温等のグラフ表示


Webからアクセスするときのためのパーツを作りはじめました。
とりあえずCGIでコマンドを投げたり、情報をテキストで取得することは出来るようになっていますが、気温や日照、雨の状態などをグラフで表示するのをどうしようか悩んでました。

将来的にコントロールサーバーをRaspberryPiに移行することを考えるとOS X独自のGraphics描画機構を使うわけにはいかず、そうなると文字とかを書くのが難しくなります。
bitmapで数字等を持たせてコピーして書いていくのも大変なのでどうしようか考えていましたが、ベースになるgifファイルに枠や目盛りを書き込んでおいて、それをメモリーに読み込んでグラフの線だけ描画してgifファイルを生成してapacheに返すようにすることで何とか実現してみました。

iPhoneのSafariからアクセスするとこんな感じになります。

一番上に雨の強さと日照の強さを色で表現し、2F室内、2F南側のエアコン、2F西側のエアコン、1F 室内、屋外の温度をグラフで表現しています。
雨の情報は東京アメッシュと雨センサーと日照(雨センサーが濡れている状態で日照がないとやんでいても雨と判断してしまうため)を元に雨指数を求めています。
日照はグラフには無いですが、屋外南面の気温と北面の気温の差を元に日照指数を求めています。

順番に他のものも作っていくつもりです。




2012年11月25日日曜日

DenyHosts-2.6の導入


結構みんな攻撃されているようで、便利なツールがありました。
DenyHosts-2.6です。
secure.logをチェックしてsshdにトライしてくるIPを/etc/hsots.denyに登録してブロックしてくれるツールです。

installして/usr/share/denyhostsのdenyhosts.cfgを設定します。
OS X用に変更です。


# /usr/share/denyhosts 151 >diff -U0 denyhosts.cfg-dist denyhosts.cfg
--- denyhosts.cfg-dist 2006-08-20 23:09:57.000000000 +0900
+++ denyhosts.cfg 2012-11-25 10:10:35.000000000 +0900
@@ -12 +12 @@
-SECURE_LOG = /var/log/secure
+#SECURE_LOG = /var/log/secure
@@ -22 +22 @@
-#SECURE_LOG = /private/var/log/asl.log
+SECURE_LOG = /private/var/log/secure.log
@@ -195 +195 @@
-LOCK_FILE = /var/lock/subsys/denyhosts
+# LOCK_FILE = /var/lock/subsys/denyhosts
@@ -198 +198 @@
-#LOCK_FILE = /var/run/denyhosts.pid
+LOCK_FILE = /var/run/denyhosts.pid


ただ、そのまま動かしてもなんか/var/log/denyhostsにエラーが出ています。

2012-11-25 09:51:41,486 - denyhosts   : ERROR    regex pattern ( User (?P<user>.*)
 not allowed because not listed in AllowUsers ) is missing 'host' group

googleに聞いてみると、同じ問題に当たっている人がいました。

- DenyHosts/regex.py:FAILED_ENTRY_REGEX7 = re.compile(r"""User (?P<user>.*) not allowed because not listed in AllowUsers""")
+ DenyHosts/regex.py:FAILED_ENTRY_REGEX7 = re.compile(r"""User (?P<user>.*) .*from (?P<host>.*) not allowed because not listed in AllowUsers""")

これでうまく登録されるようになりました。

早速/etc/hosts.denyに幾つか登録されています。
sshd: 120.128.0.83
sshd: 218.196.56.73
sshd: 42.121.33.197
sshd: 218.20.224.17
sshd: 199.195.214.244

sshdへの攻撃


sshdのportを開けて一晩おいておいたら攻撃されていました。

/var/log/secure.log
-----
Nov 21 01:06:58 MacMini sshd[30634]: Invalid user oracle from 183.60.143.25
Nov 21 01:06:59 MacMini sshd[30636]: Invalid user test from 183.60.143.25
Nov 21 06:22:53 MacMini sshd[31208]: Invalid user ftpuser from 120.128.0.83
Nov 21 06:22:55 MacMini sshd[31210]: Invalid user ftpuser from 120.128.0.83
Nov 21 06:22:56 MacMini sshd[31212]: Invalid user ftpuser from 120.128.0.83
Nov 21 06:22:57 MacMini sshd[31214]: Invalid user ftpuser from 120.128.0.83
Nov 21 06:22:59 MacMini sshd[31216]: Invalid user ftpuser from 120.128.0.83
Nov 21 06:23:00 MacMini sshd[31218]: Invalid user postgres from 120.128.0.83
Nov 21 06:23:02 MacMini sshd[31220]: Invalid user postgres from 120.128.0.8
……

色々なアカウント名に適当なパスワードで攻撃しているようです。

Nov 22 02:44:34 MacMini sshd[47947]: User root from 222.173.194.34
.......

別のIPからも攻撃されてます。
whoisでIPを引いてみるとどちらも中国からですね。

sshdの設定


外から色々変えられるようにsshdを立ち上げます。
OS Xの場合は共有設定からenableできますが、念のため公開鍵認証で限定されたアカウントのみでアクセスできるように設定します。

sshd_configの設定の変更
-----
--- sshd_config.org 2012-11-25 19:42:03.000000000 +0900
+++ sshd_config 2012-11-25 19:41:39.000000000 +0900
@@ -41 +41 @@
-#PermitRootLogin yes
+PermitRootLogin no
@@ -47,2 +47,2 @@
-#PubkeyAuthentication yes
-#AuthorizedKeysFile .ssh/authorized_keys
+PubkeyAuthentication yes
+AuthorizedKeysFile .ssh/authorized_keys
@@ -51 +51 @@
-#RhostsRSAAuthentication no
+RhostsRSAAuthentication no
@@ -53 +53 @@
-#HostbasedAuthentication no
+HostbasedAuthentication no
@@ -62,2 +62,2 @@
-#PasswordAuthentication no
-#PermitEmptyPasswords no
+PasswordAuthentication no
+PermitEmptyPasswords no
@@ -71 +71 @@
-#ChallengeResponseAuthentication yes
+ChallengeResponseAuthentication no
@@ -75 +75 @@
-#KerberosOrLocalPasswd yes
+KerberosOrLocalPasswd no
@@ -129,0 +130,3 @@
+
+AllowUsers hogehoge
-----

routerのポートマッピングの設定でport22をmac-miniに転送するように設定します。
これで鍵を登録しているクライアントからのみlogin出来るようになります。

うちのLAN環境

これまで設定しているうちの環境を下図にしまします。
この中のMacMiniがWebサーバー件DNS/DHCPサーバーになっています。
routerのATermの方はMacMiniでDHCPサーバーを動かし始めた時点でDHCPをoffに設定しています。

MacBookPro等でDHCPのリース更新をするときちんとDNSサーバーが切り替わりました。
これまではRouterがDNSサーバーになっており、親サーバーがauのDNSだったと思われますが、今回MacMiniのDNSの設定をgoogleのDNSに設定したため気のせいかもしれませんがwebのアクセスが速くなった気がします。

DNSサーバー(bind9)


DNSサーバーはbind9を使います。
LAN内でwebサーバーの名前を引けるようにするのが目的なのでできるだけ簡単な設定にします。


/etc/named.conf
-----
options {
        version "unknown";
        directory "/var/named";
        allow-query { localhost; localnets; };
        allow-query-cache { localhost; localnets; };
        forwarders {
                8.8.8.8; // LAN以外の検索はgoogleのDNSに投げる
                8.8.4.4;
        };
};

zone "hogehoge.dip.jp" IN { // 正引きLAN設定
        type master;
        file "hogehoge.zone"; // 正引き用ファイル
};

zone "0.168.192.in-addr.arpa" IN { // 逆引きLAN設定
        type master;
        file "hogehoge.rev";  // 逆引き用ファイル
};

logging {
        category lame-servers { null; }; // よけいなlogを捨てる
};
-----

正引き用の設定ファイル
/var/named/hogehoge.zone
-----
@       IN      SOA     macmini.hogehoge.dip.jp. root.hogehoge.dip.jp. (
                                      2012112200 ; Serial
                                      28800      ; Refresh
                                      14400      ; Retry
                                      3600000    ; Expire
                                      86400 )    ; Minimum
              IN      NS      hogehoge.dip.jp.
              IN      A       192.168.0.2  // hogehoge.dip.jpを引くための設定
router        IN      A       192.168.0.1
macmini       IN      A       192.168.0.2
-----

逆引き用の設定ファイル
/var/named/hogehoge.rev
-----
@       IN      SOA     macmini.hogehoge.dip.jp. root.hogehoge.dip.jp. (
                                      2012112200 ; Serial
                                      28800      ; Refresh
                                      14400      ; Retry
                                      3600000    ; Expire
                                      86400 )    ; Minimum
        IN      NS      hogehoge.dip.jp.
1       IN      PTR     router.hogehoge.dip.jp.
2       IN      PTR     macmini.hogehoge.dip.jp.
-----

あとは、OS X用にlaunchctlのファイルを記述します。
namedもdhcpdと同様に-fオプションでフォアグラウンド実行を指定し、KeepAliveに設定します。

/Library/LaunchDaemon/named.plist
-----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>named</string>
        <key>KeepAlive</key>
        <true/>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/local/sbin/named</string>
                <string>-f</string>
        </array>
</dict>
</plist>
-----

これでLAN内でwebを開くと192.168.0.2に対してrequestし、外からはDDNSでWAN側のアドレスが引けるようになりました。

2012年11月24日土曜日

DHCPサーバー設定


今回のdhcpd.confの設定です。今回は外向きに見せているWebサーバーを家庭内のLANからも同じ名前で引けるようにするのが目的なので内部向けにDNSをmac-miniのnamedになるように設定します。

dhcpd.conf
-----
ddns-update-style none; // LAN内でDDNSは不要なのでnone

default-lease-time 21600; // lease-timeは標準値
max-lease-time 43200;

subnet 192.168.0.0 netmask 255.255.255.0 { // LANのアドレス
  range 192.168.0.64 192.168.0.127;  // DHCP用のアドレス範囲
  option routers 192.168.0.1;  // routerのアドレス
  option subnet-mask 255.255.255.0;  // LANのサブネットマスク
  option domain-name "hogehoge.dip.jp";  // 外向けのdomain nameと同じもの
  option domain-name-servers 192.168.0.2;  // primaryにmac-miniを指定。
}

host living-macmini {  // これが今回はまった設定。ここでfixed-addrとして指定するのでなく、Mac-miniの方でstatic設定にしなくてはなりません。
  hardware ethernet xx:xx:xx:xx:xx:xx;
  fixed-address 192.168.0.2;
}
------

あとはOS-Xのlaunchd用の設定ファイルを作ります。
記述内容はdhcpdを-fオプションでフォアグラウンド起動し、KeepAliveで落ちてしまった時に自動復帰するように設定します。
-fをつけないと、forkして起動プロセスが落ちるたびにKeepAliveで再起動してしまうのでdaemonプロセスが沢山起動してしまいます。

/Library/LaunchDaemon/dhcpd.plist
-----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>Label</key>
        <string>dhcpd</string>
        <key>KeepAlive</key>
        <true/>
        <key>ProgramArguments</key>
        <array>
                <string>/usr/local/sbin/dhcpd</string>
                <string>-f</string>
        </array>
</dict>
</plist>
-----
設定ファイルが出来上がったら
# sudo launchctl load /Library/LaunchDaemon/dhcpd.plist
で起動設定をするとdhcpdが起動します。

2012年11月23日金曜日

DHCPサーバー


auのルーターの設定がDHCPのon/offしか無いせいでDNSサーバーを立てたいだけなのにDHCPサーバーまで立てることになってしまいました。
うちのネットワークは今まではルーターでDHCP+DNSを立てていてサーバーとして使っているMac-miniはルーターのDHCPの静的mappingでアドレスを固定して使っていました。
とりあえず、dhcpdをMac-mini上で動かし、dhcpd.confにルーターの設定内容を移します。

ところが、ここでちょっとハマってしまいました。
ちょっと考えてみれば当たり前なのですが、ルーターの設定をそのままdhcpd.confの記述に直して動作させたためMac-miniも動的割り当てのままになっており、dhcpd.confのfixed-addressの記述で固定割り当てするようにしてしまいました。
この場合、Mac-miniがDHCPを更新するとDISCOVERをbroadcastしてdhcpdがそれに対してOFFERを返します。
ところが、Mac-miniがdhcpdを動かしているためOFFERの送信元アドレスが決定できません。
このため、dhcpdが応答できずにMac-miniがNetworkを上げられずDHCPサーバーとして動けません。
これに気が付くまでtcpdumpを追いかけて悩んでしまいました。

Dynumic DNS


家サーバーを外からアクセスできるようにするために無料のDynamic DNSとしてieserver.netに登録しました。
東京アメッシュの雨情報を取得しているdaemonで一緒に10分間隔でWAN側に見えているIPアドレスの確認をして、前回と変更があった場合にiserver.netの方に設定しに行くようにしています。

最初、他のDDNSを使おうとしていたのですが、更新時にサーバー名とパスワードを送るのにhttps対応していなかったのでやめました。
こちらのieserver.netの方はドメインも幾つかから選べて更新時にhttpsで通信するので安心です。

iPhoneのWiFiをoffにして外から登録したドメインをアクセスしたらちゃんと見えるようになりました。
ところが、ここで問題が出ました。家庭内LAN側から見るとWebが見えません。
家の機器を制御するのに接続が3GかWiFiかを考えて接続先を切り替えるのは使い勝手が悪すぎます。

原因を調べてみると
LAN側からnslookupで登録したサーバーを見てみると当然ながらWAN側のIPアドレスが引けます。
ここに対してLANからhttpアクセスをリクエストしても、折り返してLAN側にルーティングしてくれないのが原因のようです。(当たり前ですが)

対応方法としてはLAN内向けにDNSサーバーを立ててwebサーバーを内部のIPアドレスに騙してやればいいかと思うのですが、auひかり回線で配られているルーターではDHCPでルーター自身のIPアドレスを配ってしまうのでうまく対応できません。DHCPの情報を変更できるメニューは無くDHCPのon/offのみの設定です。

仕方がないので、DHCPサーバーとDNSサーバーを立てることにします。
なかなか一筋縄では行きませんね。

2012年11月20日火曜日

CGIの作成

cgi-binにコントロールサーバーにコマンドを投げるコマンドを作成し配置します。
この時、cgi-binのDirectoryはクライアント認証が必要な設定にし、コマンドの内部で環境変数SSL_CLIENT_S_DN_OUをみてコントロールサーバーを切り替えてコマンドを投げるようにしました。またSSL_CLIENT_VERIFYをチェックして認証が成功していることを確認しています。
このSSL_CIIENT_S_DN_OUはクライアント証明書のOrganization Unit Nameに設定された制御サーバー名になります。
これによって、将来的に制御サーバーを複数持った時にクライアントの認証ファイルごとに切り替えられるようになります。

これでまがりなりにもiPhoneからコマンドベースで家の鍵やエアコンの状態、温度などをみたり、制御できるようになりました。

あとはWebのUIを作っていけば取り敢えず完成です。

apache2の設定


まず、httpd.confのhttpd-ssl.confのinludeを有効にします。

# diff -U0 httpd.conf.org httpd.conf
--- httpd.conf.org
+++ httpd.conf
@@ -477 +476 @@
-#Include /private/etc/apache2/extra/httpd-ssl.conf
+Include /private/etc/apache2/extra/httpd-ssl.conf

次にincludeしたhttpd-ssl.confの編集。

diff -U0 extra/httpd-ssl.conf.org extra/httpd-ssl.conf
--- extra/httpd-ssl.conf.org
+++ extra/httpd-ssl.conf

サーバーのhttps用のDocumentRootの設定、サーバー名等の設定
@@ -77,3 +77,3 @@
-DocumentRoot "/Library/WebServer/Documents"
-ServerName www.example.com:443
-ServerAdmin you@example.com
+DocumentRoot "/Library/WebServer/SecureDocuments"
+ServerName hogehoge.com:443
+ServerAdmin hoge@hogehoge.com

CA認証ファイルの指定
@@ -128,0 +129,4 @@
+#SSLCACertificatePath "/private/etc/apache2"
+SSLCACertificateFile "/private/etc/apache2/cacert.pem"

Client認証の要求設定
@@ -144,2 +148,2 @@
-#SSLVerifyClient require
-#SSLVerifyDepth  10
+SSLVerifyClient require
+SSLVerifyDepth  1

SecureDocumentのディレクトリ設定
@@ -195,0 +200,24 @@
+<Directory "/Library/WebServer/SecureDocuments">
+    Order allow,deny
+    Allow from all
+    SSLRequireSSL
+    SSLVerifyClient require
+</Directory>

将来のために各制御サーバー毎にdirectoryを切っておきます。
+<Directory "/Library/WebServer/SecureDocuments/control1">
+    AuthUserFile /private/etc/apache2/htpasswd/control1
+    AuthName "Please Your ID Passwd"
+    AuthType Basic
+    require valid-user
+    SSLRequireSSL
+    SSLVerifyClient require
+    SSLOptions +StdEnvVars +FakeBasicAuth
+</Directory>
+
+<Directory "/Library/WebServer/SecureDocuments/control2">
+    AuthUserFile /private/etc/apache2/htpasswd/control2
+    AuthName "Please Your ID Passwd"
+    AuthType Basic
+    require valid-user
+    SSLOptions +StdEnvVars +FakeBasicAuth
+</Directory>

各制御サーバーごとにパスワードファイルを作成します。
クライアント証明書のbackupのディレクトリへ行き

# openssl x509 -noout -subject -in newcert.pem

を実行するとsubjectが出力されます。
このsubject=を除いた部分をアカウントとしてhtpasswdを実行します。
control1用のアカウント1つめtest1

# htpasswd -c /private/etc/apache2/htpasswd/contro1 "/C=JP/ST….."

-cをつけるとパスワードファイルを新規に作成します。
2つ目のアカウントtest2

# htpasswd /private/etc/apache2/htpasswd/contro1 "/C=JP/ST….."

これを制御サーバーごとに繰り返します。

cgiの実行に関してはSSL関連の環境変数を実行時に確認してセキュリティを確保します。
これに関しては別途。

クライアント証明書の発行


まずopensslの設定をクライアント証明書発行用に修正します。
# diff -U0 /System/Library/OpenSSL/openssl.cnf.org /System/Library/OpenSSL/openssl.cnf
--- /System/Library/OpenSSL/openssl.cnf.org
+++ /System/Library/OpenSSL/openssl.cnf
@@ -101 +101 @@
-default_bits = 1024
+default_bits = 2048
@@ -172 +172 @@
-nsCertType = server
+# nsCertType = server
@@ -178 +178 @@
-# nsCertType = client, email
+nsCertType = client, email

次にクライアント証明書のbackup用ディレクトリを作成します。revokeする時に必要になります。
# mkdir demoCA/certs/test1
# mkdir demoCA/certs/test2
# mkdir demoCA/certs/test3

次に各クライアント証明書の作成です。
# /System/Library/OpenSSL/misc/CA.sh -newreq
pass phraseは個別に設定して下さい。
countryName,stateOrProvinceName,LocalNameはJP,Tokyo,など適当に。
OrganizationNameはhogehoge Server
Organization Unit Nameは後々のために制御先のサーバー名を入れておきます。ここではcontrol1としておきます。
Common Nameはあとで配信先が区別できる名前をつけます。先ほどのdirectory名と同じが無難かと。
Emailは端末の管理者のアドレス。
extraは空。

出来上がった証明書をPrivateCAで認証します。

# /System/Library/OpenSSL/misc/CA.sh -sign

PrivateCAのpass phraseを入れます。
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y

ブラウザ用にクライアント証明書をpkcs12形式で作成

# openssl pkcs12 -export -inkey newkey.pem -in newcert.pem -certfile ./demoCA/cacert.pem -out test1.p12

先ほどのクライアント証明書用のpass phrase、配信した時に入力するpass phraseを2回入力します。

出来上がったクライアント証明書一式をbackup

# mv new* demoCA/certs/test1
# mv test1.p12 demoCA/cverts/test1

demoCA/cacert.der, demoCA/certs/test1/test1.p12の2つのファイルを端末にコピーします。
iPhoneの場合はメール等に添付して送信し、iPhoneで2つのファイルを選択することでinstallできます。
installされた証明書は 設定 -> 一般 -> プロファイル から確認できます。

以上を必要な数分繰り返します。

サーバー用の証明書関連の作成


まずopensslの設定をserver証明書用に修正します。

# diff -U0 /System/Library/OpenSSL/openssl.cnf.org /System/Library/OpenSSL/openssl.cnf
--- /System/Library/OpenSSL/openssl.cnf.org
+++ /System/Library/OpenSSL/openssl.cnf
@@ -101 +101 @@
-default_bits = 1024
+default_bits = 2048
@@ -172 +172 @@
-# nsCertType = server
+nsCertType = server


最初にサーバー用の秘密鍵を作成します。

# openssl genrsa -out server.key 2048

server.keyが出来上がります。

次にサーバー用の証明書要求ファイルを作成します。

# openssl req -new -key server.key -out server.csr

countryName,stateOrProvinceName,LocalNameはJP,Tokyo,など適当に。
OrganizationNameはhogehoge Server
Organization Unit Nameはhogehoge
Common NameはサーバーのDNS名 (www.xxx.comなど)これが合っていないとwebアクセス時に偽装サーバーの警告が出ます。
Emailは自分のアドレス。
extraは空欄

本来はここまでがサーバー管理者の仕事で、ここで作成したserver.csrを認証局に送って認証してもらいます。

サーバー用の証明書作成

# openssl x509 -CA ./demoCA/cacert.pem -CAkey ./demoCA/private/cakey.pem -CAserial ./demoCA/serial -req -days 365 -in server.csr -out server.crt

PrivateCAのpass phraseを入力することで認証されます。
ここは本来認証局の仕事。今回はPrivateCAなので自分でやります。

出来上がったserver.key, server.crtとCAのファイルdemoCA/cacert.pemをapache2の設定directory /private/etc/apach2/にコピーします。

PrivateCA(オレオレ認証局)の作成


webサーバーにするMac miniではなく、手元のMacBookProの方で作業をします。
同じマシンでもいいのですが、念のためCAは別マシンでやっています。
OS Xにはopensslが入っているので自己認証局は簡単です。

作業directoryを掘って移動します。

# /System/Library/OpenSSL/misc/CA.sh -newca

を実行し、CA用のpass phraseを2度入力します。
countryName,stateOrProvinceName,LocalNameはJP,Tokyo,など適当に。
OrganizationNameはhogehoge PrivateCA
Organization Unit Nameはhoge
Common Nameもhogehoge PrivateCA
Email Addrは自分のアドレス
extraの方は空欄で構いません。
もう一度pass phraseを聞かれるので先ほどのpass phraseを入力します。
demoCA/の下にcacert.pemが出来上がります。

次に、

# openssl x509 -in cacert.pem -outform der -out cacert.der

を実行し、PrivateCAの認証局証明書を作成します。
demoCAの下にcacert.derが出来上がります。
あとで、クライアント証明書と一緒にアクセスする端末に配ります。

Web経由の外からの制御


色々とやり方を検討してみたのですが、今のところ一番安く(追加費用が無料)上がるのでXBeeの制御をさせているMac miniにapacheを立ててDynamic DNSで外に見せることにしました。
ただ、単純に外に開放すると色々と危ないのでセキュリティを厳しくしなくてはなりません。
ちょっと面倒臭いですが、自己認証CA(いわゆるオレオレ認証)を立てて、サーバー認証と操作する端末ごとにクライアント認証をかけることでセキュリティを確保します。
今回の使い方では、アクセスしてきた端末の正当性が確保できて、落としたりした時にrevokeできればよいので十分かと思います。
色々とハマりましたが、ひと通り動くようになったので順次やったことを書いていきます。

2012年11月19日月曜日

温度センサーが増えました

エアコンのコントロールモジュールに温度センサーを入れ、温度センサーをエアコン本体の温度センサー付近に取り付けました。

エアコンは18°Cの設定で暖房を使用していますが、グラフをみるとonしている期間がよく分かります。
西側のエアコンはちゃんと18°C付近になるように一生懸命制御していますね。
南側のエアコンは人がいる辺りは暖まっても暖房し続けているのでoffしまうことが多いのですが、窓のすぐ下にあるせいか冷気が降りてきて温度センサーの温度が低めに出ているようです。

2012年11月18日日曜日

XBeeの入力トリガー機能の対応

XBeeのモジュールはデジタル入力の状態変化を検知して通知してくる機能があります。
この機能を使って、状態変化に応じてコマンドを実行できる機能を追加しました。

設定ファイルに下記のような記述を追加しています。


sensor:
#wait_port                     event   command
north_window_stat       open    aircon_off
south_window_stat       open    aircon_off
aircon_south_stat          on       window_close
aircon_west_stat           on       window_close

北側、南側の窓がclose->openに変化したらエアコンをoffにする
南側、西側のエアコンがoff->onに変化したら窓を閉める
という事を自動でするようにしました。


エアコンにも取り付けました

寒くなってきたので、エアコンも制御できるようにモジュールを取り付けました。


ついでに、エアコン付近の温度も計測できるように温度センサーも付けておきました。
写真のオレンジ色のものが温度センサーです。


2012年11月10日土曜日

ZigBeeと電子レンジ


XBeeのシステムを組んで2週間くらい様子を見ていますが、定期的にZigBeeネットワークが通信できない状態が観測されています。
傾向的に朝の6時~8時くらいと、夕方の4時~7時くらいに何度かエラー4(Remote Command Transmission Failed)が連続して発生します。
Retry動作を連続しても暫くは復帰しないのでどんどんQueueに溜まっておかしな状態になっていきます。電子レンジかと思っているのですが、使っていない時にも発生しています。
もしかすると近所の家の電子レンジからも影響を受けてるのかもしれません。

Retry動作を少し間を開けながら実行するように変更し、コマンドを投げて応答待ちしている場合は、応答が帰ってくるかTimeoutするまでは次を投げないようにして様子をみています。
ここ3日くらいは、たまにエラー4が発生していますが、連続してはっせいしてQueueに溜まってしまっているような状況にはならなくなりました。

もう暫く様子をみて問題無さそうならこのQueue管理の仕方で行こうかと思います。

2012年11月3日土曜日

pselectの罠


XBeeからの通信とsocketからのコマンド通信、iRemoconとの通信の応答、アメッシュ監視processからの通信を待つためにpselectを使用していたのですが、OSXはrace conditonがあるようではまってしまいました。
たまに時間指定で開くはずのシャッターが開かなかったりしていたので、仕込みを入れて追っていたのですがようやく原因にたどり着きました。

pselectの通信待ちの間にtimer eventを受けるためにsetitimerでSIGALRM通知を受けているのですが、タイミングによってはpselectから戻って来ません。
仕込みを入れてみるとsigactionで設定しているhandlerには飛んでいるのですが、pselectがblockしたままになっているケースがありました。
pselectがatomicにできていないようで、SIGALRMを受けるタイミングがうまく合ってしまうと判別できないことがあるようです。

ネットで検索してみるとよく知られている現象のようで、selfpipeでhandlerからselectの監視portにnonblock ioでwriteすることで通知することで回避できるようです。
直したところ取りこぼすことがなくなりました。