#5
LIGPR
Intel Edison

スマホのお天気アプリを使わずにAPIからお天気情報を見る【プログラム編】

ちゃちゃまる


スマホのお天気アプリを使わずにAPIからお天気情報を見る【プログラム編】

どうもこんにちは、ちゃちゃまる(@chachmaru)です。前回の記事ではIntel Edison側の配線をしました。今回はプログラムを書いて、Intel Edisonを動かしましょう!

inteledison2 Intel Edisonとは
Intelが開発している マイコンボード。Wi-FiモジュールやBluetoothモジュールを最初から搭載している。

▼目次

作業環境をセットアップする

コードを書く前に作業をするディレクトリに移動します。まず、

xxxxx:.ssh xxxxx$ ssh root@xxx.xx.xx.x

を実行してEdisonのパスワードをいれます。その後、lsを実行し、

cd nodejs

nodejsディレクトリに移動します。ここに.jsファイルを保存してnode xxxxx.jsで実行します。次に、

touch weather.js

weather.jsというファイルをnodejsディレクトリ内に作ります。これからこのファイルにいろいろ書いていきます。

プログラムを書く準備をする

Vimエディタの使い方

通常パソコンでコードを書くときは、どんなテキストエディタでも大丈夫でした。しかしEdisonには僕たちが日常的に使っているようなエディタはインストールされていないため、Terminalの画面内でテキストを編集できるエディタVimを使用します。

VimはCLI(コマンドラインインターフェース:キーボードのみを用いてパソコンを操作する方法)で動作するため、Vimを立ち上げてもウィンドウはTerminalから変わりません。

試しに、さっき作ったweather.jsになにか書き込んでみましょう。

vim weather.js

と入れると、

~
~
~
~
~
~
~
~
...
"weather.js" 0L, 0C

といった感じの画面が出てくると思います。これがVimエディタです。

Vimはキーボードのみで操作するため、通常のテキストエディタとは少し勝手が違うので気をつけてください。本記事では詳しく説明しませんが、Vimにはモードというものがあり、vimコマンドでVimを立ち上げた直後はコマンドラインモードになっているためキーを叩いても入力ができません。

ファイルにテキストを書き込むには挿入モードに切り替えます。iキーで切り替えをすると、テキストカーソルが点滅して、一番上の行に入力できるようになります。コードを書くときはこのモードでおこないます。

Edison内でNode.jsを実行する

挿入モードのままで

console.log('Hello, Edison!');

と入力します。次はまたコマンドラインモードに切り替えなくてはならないので、エスケープキーを押します。そうするとテキストカーソルが消えるので、その状態のまま

:wq

と入力し、エンターを押します。これは保存して終了するコマンドで、writeしてquitすると覚えましょう。このコマンドを実行すると、元のターミナルの画面に戻ります。

lsweather.jsを確認して、

node weather.js

で実行します。Hello Edison!と表示されれば成功です。

前回書いたプログラム

さて、第1回の記事で書いたコードをおさらいしてみます。

var http = require('http');
var url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=130010';

http.get(url, function(res) {
    var body = '';
    res.setEncoding('utf8');
    res.on('data', function(data) {
        body += data;
    });
    res.on('end', function(data) {
        console.log(JSON.parse(body).forecasts[0].telop);
    })
});

このプログラムでは、最後に

console.log(JSON.parse(body).forecasts[0].telop);

としていますが、今回はその結果を「LEDの色」によって表してみます。

お天気情報を使ってLEDを光らせる

今回作るのは、天気が晴れの場合赤色に、雨の場合は青色に、曇りの場合は緑色に光らせる簡単なプログラムです。この記事でつくるものはあくまで一例なので、お好みの色やAPIなどで試してみてください!

動作確認

とりあえず動作を確認してみましょう!

var http = require('http');
var mraa = require('mraa');

var weather = '';
var url = 'http://weather.livedoor.com/forecast/webservice/json/v1?city=130010';

var redLed = new mraa.Gpio(9);
redLed.dir(mraa.DIR_OUT);
var greenLed = new mraa.Gpio(10);
greenLed.dir(mraa.DIR_OUT);
var blueLed = new mraa.Gpio(11);
blueLed.dir(mraa.DIR_OUT);

getWeather(function(weather){
    setLed(weather);
});

function getWeather(callback){
    http.get(url, function(res) {
        var body = '';
        res.setEncoding('utf8');
        res.on('data', function(data) {
            body += data;
        });
        res.on('end', function(data) {
            var weather = JSON.parse(body).forecasts[0].telop;
            callback(weather);
        });
    });
}

function setLed(weather){
    if(weather === '晴れ'){
        redLed.write(1);
    } else if(weather === '雨'){
        blueLed.write(1);
    } else if (weather === '曇り'){
        greenLed.write(1);
    } else {
        console.log('Mixed weather...');
    }
}

上のコードをコピーして、先ほど作ったweather.jsに貼り付けます。

その後

node weather.js

で実行してみてください。晴れなら赤、雨なら青、曇りなら緑が出るはずです。(コードをシンプルにするために、「晴れのち曇り」といった天気は「Mixed weather……」とターミナルに表示させています)

動作確認をしたところで、コードをさらっと確認していきましょう!

mraaをrequireする

今回のコードの2行目に

var mraa = require('mraa');

とあります。第1回ではあまり説明しませんでしたが、requireという関数はモジュール(部品)を読み込むためにあります。mraaという変数にrequire('mraa');したものの戻り値を代入しています。

ではmraaとは何か。簡単に言うとEdisonのI/OインターフェースをJavaScriptや他の言語からコントロールできるライブラリということです。詳しくは公式ドキュメンテーションをご覧ください。

GPIOピンを指定する

var redLed = new mraa.Gpio(9);
redLed.dir(mraa.DIR_OUT);
var greenLed = new mraa.Gpio(10);
greenLed.dir(mraa.DIR_OUT);
var blueLed = new mraa.Gpio(11);
blueLed.dir(mraa.DIR_OUT);

上記は、それぞれの天気の色とEdisonのGPIOピンを対応させて、それぞれのピンの方向を設定しています。センサーなど情報を取り入れる場合はDIR_IN、今回のように結果を示す場合はDIR_OUTを使います。

非同期処理とコールバック関数

ものすごい難しいタイトルですよね。そもそも僕みたいな初心者の人がいきなり難しいことを勉強してもモヤモヤしたまま終わってしまうと思うので、簡潔かつ必要最低限のレベルで理解してみます。

まず、「非同期処理」という言葉。僕はいままでプログラムって上から下に実行されていくんだと思っていました。でもこの方法って実はとても非効率的で、プログラムの途中に時間がかかる処理が書かれていた場合、それ以降の処理は何もしていない状態で待っているだけになってしまうんですね。これを同期処理といいます。

これだと困っちゃうので、ある処理が実行されるとき、本来出力したいデータが準備できるまで待つのではなく、一度処理を終えて他の処理をしつつ、データの準備ができたら元の処理に戻りその値を出力する、という仕組みができました。この仕組みを非同期処理と呼び、データの準備ができたら呼び出される関数のことをコールバック関数と呼びます。

この太字の文は5回ぐらい読んでちゃんと噛み砕いた方がいいと思います。結構難しいですよね、わかります、僕も何回も社内のエンジニア・のびすけさんに聞いてやっとぼんやり理解できました。

getWeather(function(weather){
    setLed(weather);
});

function getWeather(callback){
    http.get(url, function(res) {
        var body = '';
        res.setEncoding('utf8');
        res.on('data', function(data) {
            body += data;
        });
        res.on('end', function(data) {
            var weather = JSON.parse(body).forecasts[0].telop;
            callback(weather);
        });
    });
}

ここが該当部分です。このままだとわかりにくいので、省略して書いてみるとこうなります。

getWeather(function(weather){
    setLed(weather);
});

function getWeather(callback){
    //いろいろやって
    //weatherという変数に天気情報を代入して
    //callback(weather); で終わる
}
</pre></div></div>

まず、

<div class="code-frame" data-lang="text"><div class="highlight"><pre>
getWeather(function(weather){
    setLed(weather);
});

の原型は

getWeather();

で、引数としてfunction(weather){setLed(weather);}という関数を呼んでいます。

ここで注目するポイントは、getWeather();の引数が名前のない関数function(weather){} であるところです。僕は、ある関数Aが引数に名前のない関数Bを見つけたとき、とりあえず関数Bを無視して関数Aを処理する、と理解しています。

今回の例でいうと、getWeather()は引数にfunction(weather){setLed(weather);} 、つまり名前のない関数をとっているため、とりあえず引数を無視してgetWeather()の内容を実行します。

次に、function getWeather(callback){}です。この関数ではいろいろな処理をおこなって最終的に天気情報をweatherという変数に代入し、callback(weather);で終わっています。ここで大事なのは、getWeather()の引数と関数内で最後に呼ばれる関数が同じ名前(callback)であることです。callback()が呼ばれたとき、さっき無視した処理を実行します。つまり、setLed(weather);ですね。

かなりごちゃごちゃしてるので、最後に実行される流れをまとめます。

  1. function(weather){setLed(weather);}という名前のない関数を引数にとる関数getWeather()が呼ばれる
  2. 呼ばれたgetWeatherはとりあえず名前のない関数の処理を無視して実行される
  3. 実行された結果weatherという変数に天気情報が代入される
  4. callback(weather)によりさっき無視した名前のない関数の処理をする
  5. setLed(weather)で、setLed()という関数にweatherという引数を渡す

例えばWi-Fiが遅い環境にいたり、リクエストするサーバーが重かったりすると、今回のようにネット経由で情報を取得する場合は時間がかかります。天気情報が取得できていないのにLEDの色を決めることなんてできないですよね? なので、データの準備ができたらコールバックして、LEDの色を判断するのです。

条件分岐で色を決める

function setLed(weather){
    if(weather === '晴れ'){
        redLed.write(1);
    } else if(weather === '雨'){
        blueLed.write(1);
    } else if (weather === '曇り'){
        greenLed.write(1);
    } else {
        console.log('Mixed weather...');
    }
}

この部分は簡単で、weatherが晴れなら赤、雨なら青、曇りなら緑にしているだけです。GPIOピン9、10、11番のいずれかにwrite(1)で電気を送り、対応した色にLEDを光らせます。

おわりに

ということで、Intel Edisonを使い、天気情報をLEDで表す手順をまとめました。これでなんとかスマホを使わずに天気を知ることができそうです。次回以降は次のようなことをやっていきたいと思います。

  • 自動で情報を更新
  • 晴れ、雨、曇り以外の場合の対応を考える
  • 温度センサーを使って気温を計り、ディスプレイに表示

それではまた。

ちゃちゃまる
この記事を書いた人
ちゃちゃまる

大学生エンジニア

関連記事

この記事を読んだ人におすすめ