ラズベリーアラーム制作第3回目!後半戦に突入しました!
前回、アラームを止めると日時と室温を読み上げてくれる機能を実装しましたが、今回はさらにもう1つ情報をプラス。お天気情報を提供してくれるAPIと連携して、今日の天気予報を読み上げてもらいます!ラズベリーアラームは忙しい朝の救世主になってくれるでしょうか?
そして、機能が揃ってきたところで、ケースを作りました!機能追加の前に、まずはケースのご紹介です!
ケースを作りました!
最初に作ったケースはナノブロックを使ったので、今回はレゴを使いました。ナノブロックに比べると大きいので、以前よりも短時間で完成!
こちらが正面から見たところです。中にブレッドボードが収納されているのが見えるでしょうか?
ストップボタンを押すためには……
ドアをオープン!
ケースに入れるとボタンが押しにくくなってしまいそうなので、横から押せるようにドアを付けました。入り口を狭くしたことで、ボタン以外のところに手が当たりにくくなったので、寝ぼけてうっかり配線が外れてしまうことも防げそうです。
写真3は、ふたを開けて、上から見たところです。できるだけコンパクトにするために、小さいブレッドボードを使用しました。ブレッドボード上は短いワイヤーで配線をまとめて、ラズベリーパイに接続するワイヤーは外に出しやすいように後方にまとめています。
後ろから見るとこんなかんじです。両サイドからワイヤーを出しています。温度センサがあるので、通気性を考慮して大きめに窓を開けました。
レゴ製ケースはブロックが大きいので、組み換えが気軽にできるのが魅力!今回は小さいブレッドボードを使っているので、箱型のものであれば、市販のキットに収めることもできそうですね。
天気情報を取得するAPIについて
お天気情報の取得には、livedoorから提供されている第三者向け気象データ提供サービス「Weather Hacks」のお天気webサービスAPIを使用しました。こちらのAPIは商用利用は不可となっていますので、個人的な範囲での利用に留めてくださいね。
お天気Webサービス – Weather Hacks
お天気Webサービス(Livedoor Weather Web Service / LWWS)は、現在全国142カ所の今日・明日・あさっての天気予報・予想気温と都道府県の天気概況情報を提供しています。
使い方は簡単!「 http://weather.livedoor.com/forecast/webservice/json/v1 」のURLに地域別に定義されたID番号をパラメータとして渡すだけでOKです!
各地域のID番号は「全国の地点定義表」で確認することができます。
うまく表示されない場合は、ブラウザでHTMLソースを表示してみてください。図1のようなXML形式のデータが表示されます。「city」タグ内の「id」の値がID番号です。たとえば、東京であれば「130010」となります。
リクエストURLは次のようになります。
例:東京(ID番号130010)の場合
http://weather.livedoor.com/forecast/webservice/json/v1?city=130010
お天気データ取得プログラム
お天気Webサービスで取得できるデータは、図2のようなJSON形式となっています。データのプロパティ名や詳しい内容はこちらのページの「レスポンスフィールド」の項を参考にしてください。
実際に取得できるデータを見てみたい!という方は下記のコードをどうぞ。
/var/www/weather_json.php
<?php $id = '130010'; $url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city='.$id; $json = @file_get_contents($url); $obj = json_decode($json); echo "<pre>"; var_dump($obj); echo "</pre>";
APIから取得したJSON形式のデータをデコードして、オブジェクトの中身を表示するサンプルプログラムです。「$id」の値は、任意の地域のID番号に差し替えてくださいね。
ラズベリーパイまたは同じネットワーク内のパソコンのブラウザからアクセスすると、図3のように表示されます(図3は画面の一部を抜粋したものです)。
多くのデータが取得できるので、この中から必要なものを選んで、Open JTalkに読み上げてもらう文章を作っていきます。今回は目覚まし時計で使うので、「title」「forecasts」「description」のデータを使って文章を作成しています。
/var/www/weather_test.php
<?php $txt = weather(); exec('/root/bin/jsay.sh '.$txt); function weather(){ $id = '130010'; $url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city='.$id; $json = @file_get_contents($url); $obj = json_decode($json); $txt = ''; if($obj==null){ $str .= "天気情報がありません。"; }else{ if(isset($obj->title)){ $txt .= $obj->title.'は、'; } if(isset($obj->forecasts[0]->telop)){ $txt .= $obj->forecasts[0]->telop.'です。'; } if(isset($obj->description->text)){ $txt .= $obj->description->text; } } $txt = preg_replace('/(\s| )/','',$txt); $txt = preg_replace('/\n|\r|\r\n/', '', $txt); return $txt; }
実行コマンド
php /var/www/weather_test.php
お天気情報APIから天気データを取得し、地域名、天気、天気の概況をOpen JTalkで読み上げるプログラムです。半角スペースや改行が含まれている場合、Open JTalkではうまく再生されない場合がありますので、余分な文字を削除しています。
目覚まし時計プログラムと連携
前回までに作ったプログラムに、天気予報読み上げ機能を追加していきます。
/var/www/morning_call.php
<?php start(); wait(); /* アラーム */ function start(){ exec('mpg321 -l 0 -q /var/www/alerm1.mp3 > /dev/null &'); } /* ストップボタン待機 */ function wait(){ $interval_sec = 0.25; //スイッチのチェック間隔(秒) $wait_sec = 60; //最大待機時間(秒) exec('echo 2 > /sys/class/gpio/export'); exec('echo in > /sys/class/gpio/gpio2/direction'); for($i=0; $i<($wait_sec / $interval_sec); $i++){ if(exec('cat /sys/class/gpio/gpio2/value')==1){ break; } usleep($interval_sec * 1000000); echo $i.PHP_EOL; } exec('killall mpg321'); exec('echo 2 > /sys/class/gpio/unexport'); morning_call(); } /* モーニングコール */ function morning_call(){ $weekday = array('日','月','火','水','木','金','土'); $date = date('n月j日'); $dow = $weekday[ date('w') ].'曜日'; $time = date('G時i分'); $txt = 'おはようございます。'.$date.'、'.$dow.'、'.$time.'です。'; $temp = get_temperature(); if($temp!=null){ $txt .= '現在の室温は、'.$temp.'度です。'; } $txt .= weather(); if(strlen($txt) >= 980){ $txt= mb_strcut($txt,0,980); $txt = substr($txt, 0, strrpos($txt, "。")); } echo $txt.PHP_EOL; exec('/root/bin/jsay.sh '.$txt); return; } /* 温度を取得 */ function get_temperature(){ $deviceId = '28-000006470bec'; $sensor_path = '/sys/bus/w1/devices/'.$deviceId.'/w1_slave'; $t = null; exec("cat ".$sensor_path, $w1_slave); if(isset($w1_slave[1])){ $arr = explode('t=', $w1_slave[1]); if(isset($arr[1])) $t = $arr[1] / 1000; } return $t; } /* 天気を取得 */ function weather(){ $id = '130010'; $url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city='.$id; $json = @file_get_contents($url); $obj = json_decode($json); $txt = ''; if($obj==null){ $str .= "天気情報がありません。"; }else{ if(isset($obj->title)){ $txt .= $obj->title.'は、'; } if(isset($obj->forecasts[0]->telop)){ $txt .= $obj->forecasts[0]->telop.'です。'; } if(isset($obj->description->text)){ $txt .= $obj->description->text; } } $txt = preg_replace('/(\s| )/','',$txt); $txt = preg_replace('/\n|\r|\r\n/', '', $txt); return $txt; }
実行コマンド
php /var/www/morning_call.php
APIを使用しているので、インターネット回線の環境によっては、お天気情報の取得に少々時間がかかることがあります。また、概況のデータを含めて長い文章になった分、音声ファイルの生成時間も増加しました。
動画では350文字程度の文章で、Open JTalkでの再生時間は約1分となりました。ストップボタンを押してから読み上げが始まるまでにタイムラグがあるものの、Open JTalkは長文でも問題なく読み上げてくれました。
天気予報の「概要」の文章量によっては「Segmentation fault」というエラーが発生することがありました。これは、Open JTalkが生成できる音声データの制限が、デフォルトでは1024バイトまでとなっているためです。それ以上の文字列を渡すとエラーとなってしまいます。上記のプログラムでは、少し余裕を持たせて、「jsay.sh」に渡す前に980バイト以内に文字列を調整しています(40~43行目)。
まとめ
お天気情報お知らせ機能が新たに追加されたラズベリーアラーム!
ケースに入れると愛着がわいてきますね!ナノブロックで細かく作りこむのも良いですが、レゴで気軽にカスタマイズできるのもまた楽しい!インテリアに合わせてブロックを組み替えて、ちょっとした模様替え気分を味わうのも良いですね!
最後にやってみたいのは、スヌーズ機能の実装です。一度しか起こしてくれない目覚まし時計では、日常的に使うには不安が残りますよね……そんなわけで二度寝防止対策機能を付けましょう!
ラズベリーアラーム編は、いよいよ次回で最終回!やりたいことを詰め込んで、理想の目覚まし時計に仕上げましょう!