Edisonに天気予報をしゃべらせてみる [edison]
前回,Open JTalkを使ってEdisonをしゃべらせることができるようになったので,今回は天気予報をしゃべらせてみる.
天気予報の情報はlivedoorの,お天気Webサービス - Weather Hacksからスクレイピングすることにする.
で,天気予報情報を取得したら,Open JTalkで合成音声を出力するようにしておく.
あとは,Edisonにスイッチをつけて,スイッチを押したら天気予報をしゃべるようにする.
今回は,node.jsでやってみた.
では,早速だがコードを示そう.
まず,main.js
次に,package.json
この2つのファイルを,たとえばホームディレクトリ下にweather_infoディレクトリを作成して保存しておく.
なお,Open JTalkは前回のとおり,ホームディレクトリ下のopenjtalkディレクトリにインストールされてる前提で書かれているので,もし変更してるなら環境に合わせて変更が必要だ.
これで,10分おきにWeather Hacksから天気予報を取得してくる.上記のコードでは横浜の天気予報を取得するようになっている.main.js:5でvar city = '140010';としているが,これはWeather Hacksのcityパラメータそのものだ.なので地域を変更したければこの値を変更すればよい.定義はWeather Hacksのページに情報がある.
天気予報の合成音声は,取得した天気予報情報のうち,天気と最高気温と最低気温から,
「横浜の今日の天気は,XXXでしょう.最高気温はYY度です.最低気温はZZ度です.」
といった感じで生成され,/tmp/weather_info.wavとして保存されるようにしてある.最高気温と最低気温は(データが有効なときだけ)出力されるので,天気だけしかしゃべらないときもある.
Edisonにつなぐスイッチは,(回路図にするほどのこともないが)以下のように接続してやる.Edisonの内蔵プルアップを使用するので,単にスイッチをつなぐだけだ.
スイッチが押されたかどうかは割り込みで監視していて,押されたらあらかじめ生成してあるweather_info.wavを再生するようになっている.
最初はスイッチが押されたら天気予報を取得して,wather_info.wavを生成して再生するようにしようと思ったのだが,情報取得と音声生成の処理があるのでスイッチを押しても若干待たされる.というわけで,あらかじめwather_info.wavの作成まで定期的に行っておいて,スイッチが押されたら単に生成済みのweather_info.wavを再生するだけにしてある.これならスイッチを押したらすぐに天気予報をしゃべるようになる.
そしたら最後に,Edison起動時に自動実行するようにしておく.
まず,weather_infoのディレクトリに,start_weather_info.shというスクリプトを用意しておく.
で実行権限付与.
そしたら次に,/lib/systemd/system/下に,weather_info.serviceというファイルを作成してやる.
そしたら自動起動ONにして起動させてみる.
これでOK.
ただ,これで試してみると,Edisonが起動したときの実行1回目でエラーが出るようだ.どうやらWheather HacksにアクセスしようとするがDNSでエラーになっているっぽい.実行タイミングが早すぎる感じだ.weather_info.serviceのAfter=network.targetあたりを変更するといいような気がするのだが,具体的にどうすればよいのか分からない.
とりあえず,最初の1回はエラーになるが10分後の実行からは問題なく動作するので気にしないことにしておく.
というわけで,これで完了.
お試しあれ.
2015.05.02追記
SyntaxHighlighterを使ったらコードのvar url = の部分の表記がおかしくなったので修正.
天気予報の情報はlivedoorの,お天気Webサービス - Weather Hacksからスクレイピングすることにする.
で,天気予報情報を取得したら,Open JTalkで合成音声を出力するようにしておく.
あとは,Edisonにスイッチをつけて,スイッチを押したら天気予報をしゃべるようにする.
今回は,node.jsでやってみた.
では,早速だがコードを示そう.
まず,main.js
var http = require('http'); var exec = require('child_process').exec; var mraa = require('mraa'); var city = '140010'; var url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=' + city; var weather_info = ''; var waveFilePath = '/tmp/'; var waveFileName = 'weather_info.wav'; var createWetherInfo = function(data) { var location_city = data.location.city; var forecasts_dateLabel = data.forecasts[0].dateLabel; var forecasts_telop = data.forecasts[0].telop; var forecasts_temp_max = '-'; if (data.forecasts[0].temperature.max != null) { forecasts_temp_max = data.forecasts[0].temperature.max.celsius; } var forecasts_temp_min = '-'; if (data.forecasts[0].temperature.min != null) { forecasts_temp_min = data.forecasts[0].temperature.min.celsius; } weather_info = location_city + "の" + forecasts_dateLabel + "の天気は," + forecasts_telop + "でしょう."; if (forecasts_temp_max != '-') { weather_info += "最高気温は" + forecasts_temp_max + "度です."; } if (forecasts_temp_min != '-') { weather_info += "最低気温は" + forecasts_temp_min + "度です."; } }; var createWaveFile = function() { var openjtalkShellCmd = '/home/root/openjtalk/openjtalk.sh'; var cmd = openjtalkShellCmd + ' ' + weather_info + ' ' + waveFilePath + waveFileName; exec(cmd, function(err, stdout, stderr) { if (err) { console.log(err); console.log(err.code); console.log(err.signal); } }); }; var callback = function(data) { createWetherInfo(data); console.log(weather_info); createWaveFile(); }; var playWaveFile = function() { var cmd = 'aplay -D plughw:1 ' + waveFilePath + waveFileName; exec(cmd, function(err, stdout, stderr) { if (err) { console.log(err); console.log(err.code); console.log(err.signal); } }); }; x = new mraa.Gpio(14); x.dir(mraa.DIR_IN); x.mode(mraa.MODE_PULLUP); x.isr(mraa.EDGE_FALLING, playWaveFile); weatherInfo(callback); setInterval(function() { weatherInfo(callback); }, 10 * 60 * 1000); function weatherInfo(callback) { http.get(url, function(res) { var body = ''; res.setEncoding('utf8'); res.on('data', function(chunk) { body += chunk; }); res.on('end', function() { callback(JSON.parse(body)); }); }).on('error', function(e) { console.log(e.message); }); }
次に,package.json
{ "name": "weather_info", "description": "", "version": "0.0.0", "main": "main.js", "engines": { "node": ">=0.10.0" }, "dependencies": { } }
この2つのファイルを,たとえばホームディレクトリ下にweather_infoディレクトリを作成して保存しておく.
なお,Open JTalkは前回のとおり,ホームディレクトリ下のopenjtalkディレクトリにインストールされてる前提で書かれているので,もし変更してるなら環境に合わせて変更が必要だ.
これで,10分おきにWeather Hacksから天気予報を取得してくる.上記のコードでは横浜の天気予報を取得するようになっている.main.js:5でvar city = '140010';としているが,これはWeather Hacksのcityパラメータそのものだ.なので地域を変更したければこの値を変更すればよい.定義はWeather Hacksのページに情報がある.
天気予報の合成音声は,取得した天気予報情報のうち,天気と最高気温と最低気温から,
「横浜の今日の天気は,XXXでしょう.最高気温はYY度です.最低気温はZZ度です.」
といった感じで生成され,/tmp/weather_info.wavとして保存されるようにしてある.最高気温と最低気温は(データが有効なときだけ)出力されるので,天気だけしかしゃべらないときもある.
Edisonにつなぐスイッチは,(回路図にするほどのこともないが)以下のように接続してやる.Edisonの内蔵プルアップを使用するので,単にスイッチをつなぐだけだ.
スイッチが押されたかどうかは割り込みで監視していて,押されたらあらかじめ生成してあるweather_info.wavを再生するようになっている.
最初はスイッチが押されたら天気予報を取得して,wather_info.wavを生成して再生するようにしようと思ったのだが,情報取得と音声生成の処理があるのでスイッチを押しても若干待たされる.というわけで,あらかじめwather_info.wavの作成まで定期的に行っておいて,スイッチが押されたら単に生成済みのweather_info.wavを再生するだけにしてある.これならスイッチを押したらすぐに天気予報をしゃべるようになる.
そしたら最後に,Edison起動時に自動実行するようにしておく.
まず,weather_infoのディレクトリに,start_weather_info.shというスクリプトを用意しておく.
#!/bin/sh /usr/bin/node /home/root/weather_info/main.js
で実行権限付与.
chmod 755 start_weather_info.sh
そしたら次に,/lib/systemd/system/下に,weather_info.serviceというファイルを作成してやる.
[Unit] Description=Weather_Info After=network.target [Service] Environment="NODE_PATH=/usr/lib/node_modules" Environment="NODE_ENV=production" Environment="HOME=/home/root" ExecStart=/home/root/weather_info/start_weather_info.sh [Install] WantedBy=multi-user.target
そしたら自動起動ONにして起動させてみる.
systemctl enable weather_info.service
systemctl start weather_info.service
これでOK.
ただ,これで試してみると,Edisonが起動したときの実行1回目でエラーが出るようだ.どうやらWheather HacksにアクセスしようとするがDNSでエラーになっているっぽい.実行タイミングが早すぎる感じだ.weather_info.serviceのAfter=network.targetあたりを変更するといいような気がするのだが,具体的にどうすればよいのか分からない.
とりあえず,最初の1回はエラーになるが10分後の実行からは問題なく動作するので気にしないことにしておく.
というわけで,これで完了.
お試しあれ.
2015.05.02追記
SyntaxHighlighterを使ったらコードのvar url = の部分の表記がおかしくなったので修正.