RaspberryPi
Julius
OpenWeatherMap
音声認識
microbit

ラズパイと音声認識でmicro:bitに天気表示してみた

今回用意したもの

  • RaspberryPi3(普通のパソコンで構いません)
  • USBマイク(前回と同じもの)
  • micro:bit(実験で使わせてもらってる借り物です笑) micro:bitは2000円ちょっとで買えちゃうので驚きですね。 小学生向けの直感的プログラミングで組めちゃいます(もちろんコード直書き[python,js]でもOK)

必要な環境

  • 下記2つのAPIキー
  • Node.jsの実行環境
  • Pythonの実行環境 今回は,OpenWeatherMapAPIDarkSkyAPIの2つのAPIを使って天気情報と気温情報を取得します。 コンピュータからmicro:bitへのBLEでの送信はNode.jsを使って行うので、NodeでAPIを叩いて情報をそのままmicro:bitに送るような仕組みにしました。 音声制御部分は前回同様pythonで行い、pythonファイルの中でNodeを実行するという仕組みです。

Nodeの実行環境

今回はRaspberry Pi への Node.js インストールとnvmでのバージョン管理を参考にnvmを使ってインストールしました。ちなみに自分のmacでは初期で使えました。
sudo nodeが使えればOKです。

pythonの実行環境

今回はラズパイを使用して初期でpython2系が使えたので割愛します。

api叩いてみる
--------無料天気予報APIのOpenWeatherMapを使ってみるを参考にapiキーを取得します。
apiキーが取得できたら実際にapiを叩いてみます。
今回OpenWeatherAPIからほしい情報は今日の天気の情報なので、今はそれだけとってきます。(DarkSkyAPIで気温情報を取得します)

micro:bitに組み込むプログラム

今回はBLEをつかって通信します。
マイクロビットのコード作成画面でbluetoothを使えるようにします。
「高度なブロック」→「パッケージを追加する」を順にクリックしbluetoothを選択します。

これが


こうなればOKです。

次にペアリングしていないデバイスとも通信できるように設定を行います。
右上の歯車マークから「プロジェクトの設定」を選択し一番上をONにします。

こんな感じ。

このプロジェクトをmicro:bitに入れて準備完了!

micro:bitに送信する

取得した情報をmicro:bitに送信してみます。今回は天気の情報を絵にしてmicro:bitに送信したいので、16進数で点灯する場所を指定して送ります。
Node.jsのモジュールnode-bbc-microbitを使用します。

$ npm install bbc-microbit --save

インストールします。

json_weather.js
var http = require('http');
var BBCMicrobit = require('../../node_modules/bbc-microbit/index');

var id = '1864518'; //chofu
// var id = '2128295'; //sapporo
// var id = '5128581'; //new york
var appid = '自分のapiキー';

var URL = 'http://api.openweathermap.org/data/2.5/weather?id='+ id +'&appid='+ appid;

var R="";

http.get(URL, function(res) {
  var body = '';
  res.setEncoding('utf8');
  res.on('data', function(chunk) {
    body += chunk;
  });
  res.on('data', function(chunk) {
    res = JSON.parse(body);
    R = res.weather[0].main;
    weather(R)
  });
}).on('error', function(e) {
  console.log(e.message);
});

var PATTERNS = [
  {  //天気に合わせたLEDパターン
    name: 'Clouds',
    value: new Buffer('000609110E', 'hex')
  },
  {
    name: 'Thunderstorm',
    value: new Buffer('060C060C08', 'hex')
  },
  {
    name: 'Snow',
    value: new Buffer('150E040E15', 'hex')
  },
  {
    name: 'Clear',
    value: new Buffer('0E1F1F1F0E', 'hex')
  },
  {
    name: 'Rain',
    value: new Buffer('040E1F040C', 'hex')
  },
];

// search for a micro:bit, to discover a particular micro:bit use:
//  BBCMicrobit.discoverById(id, callback); or BBCMicrobit.discoverByAddress(id, callback);
function weather(str){

  for(var i=0;i<PATTERNS.length;i++){
    if(str==PATTERNS[i].name){ //jsonの結果からほしいパターンを取ってくる
      var pattern = PATTERNS[i];
    }
  }

  console.log('Scanning for microbit');
  BBCMicrobit.discover(function(microbit) {
    console.log('\tdiscovered microbit: id = %s, address = %s', microbit.id, microbit.address);

    microbit.on('disconnect', function() {
      console.log('\tmicrobit disconnected!');
      process.exit(0);
    });

    console.log('connecting to microbit');
    microbit.connectAndSetUp(function() {
      console.log('\tconnected to microbit');

      console.log('sending pattern: "%s"', pattern.name);
      microbit.writeLedMatrixState(pattern.value, function() {
        console.log('\tpattern sent');

        console.log('disconnecting');
        microbit.disconnect();
      });
    });
  });
}

このプログラムを実行したらmicro:bitのLEDに天気のマークが表示されます。今回は電通大の所在地である調布の天気を取得しています。

音声で制御する

あとは、音声で制御するためにpythonファイルを作ります。
juliusのインストールや自作辞書の作成については前回の記事を参考にしてください。
以下のコードを作成します。

weather.py
import os

def main():
    os.system('sudo node json_weather.js')

if __name__ == "__main__":
    main()
juliustest.py
import socket
import string
import subprocess
import weather
import temp_now as now
import temp_min as min
import temp_max as max
import os

host = 'localhost'   # Raspberry PiのIPアドレス
port = 10500         # juliusの待ち受けポート

# パソコンからTCP/IPで、自分PCのjuliusサーバに接続
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))

data = ""
while True:

    # "/RECOGOUT"を受信するまで、一回分の音声データを全部読み込む。
    while (string.find(data, "\n.") == -1):
        data = data + sock.recv(1024)

    # 音声XMLデータから、<WORD>を抽出して音声テキスト文に連結する。
    strTemp = ""
    for line in data.split('\n'):
        index = line.find('WORD="')

        if index != -1:
            line = line[index + 6:line.find('"', index + 6)]
            if line != "[s]":
                strTemp = strTemp + line
    if strTemp != "":
        print("結果:" + strTemp)
    if strTemp == "きょうのてんき":  # if you say Hikaregoma, led will turn on
        #os.system('sudo python ~/irmcli/irmcli.py -p -f ~/irmcli/light_on.json')
    weather.main()
    if strTemp == "さいこうきおん":
        #os.system('sudo python ~/irmcli/irmcli.py -p -f ~/irmcli/light_off.json')
    max.main()
    if strTemp == "さいていきおん":
        min.main()
    if strTemp == "いまのきおん":
        now.main()
    data = ""

temp_now,temp_min,temp_maxはDarkSkyAPIをつかって気温情報を取得するプログラムです。
自分のgithubにあるので参考にしてください。

実際に実行した結果こんな感じになりました!!
実行動画1

実行動画2

参考記事