IMG_6583

第2回ではRaspberry Piに接続したLEDを、スマートフォンからBlynkを操作して点滅させました。第3回では逆に、Raspberry Pi側の情報をスマートフォン上で見られるようにします。

Raspberry PiのGPIOポートは全てデジタルのため、GPIOポートの状態を読み取っても値は0(LOW)か1(HIGH)の2種類しかありません。今回扱う CPUの温度や周波数は0と1では足りず、より大きく細かい値が扱えなくてはなりません。そこで登場するのがバーチャルポートです。

Blynk には実際のGPIOポートだけでなく、仮想のバーチャルポートを使用することができます。バーチャルポートで扱える値は0と1だけでなく、大きな整数や小 数点を含む数値、文字列なども扱うことができます。たとえばCPUの温度が56.7℃だった場合、Raspberry Piから「56.7」という値を返してあげれば、それを温度として扱うことができます。

<バーチャルポートのテスト>

バーチャルポートを使うと何が起こるのか、まずは試してみましょう。Buttonのウィジットを追加し、ピンを「Virtual」の「V1」にします。
IMG_6574

Raspberry PiでBlynkを起動していない場合は起動し、Blynkのアプリからも接続します。手順は第2回で説明していますので、起動方法や接続方法はそちらをご覧ください。

ウィジットのボタンを押すと、Raspberry Piのターミナルに次のようなメッセージが表示されると思います。
Got a value: 1
Got a value: 0

これはBlynkのプログラムにサンプルで入っているもので、blynk-library/linux/main.cpp ファイルには以下のようなプログラムが記述されています。
BLYNK_WRITE(V1)
{
  printf("Got a value: %s\n", param[0].asStr());
}

V1ピンに値を出力すると BLYNK_WRITE(V1) 内に記述したプログラムが実行される仕組みです。paramという変数にはスマートフォン側から与えられた値が入っていて、それをprintf文で画面に出力しているだけの簡単なプログラムです。

コントローラー系のウィジット(Button、Slider、Timer、Joystick、Zergba)はスマートフォン側から値を渡されるので、BLYNK_WRITE() が呼び出されます。

ディ スプレイ系のウィジット(Value Display、Labeled Value、Gage、Graph、History Graph)は、BLYNK_READ() が呼び出されます。この中で Blynk.virtualWrite() という関数を実行し、ピン(V1など)に渡したい値を指定すると、スマートフォン側にその値が渡る仕組みになっています。
Blynk.virtualWrite(ピン, 渡したい値);

詳しくはBlynkのドキュメントに説明が載っていますので、興味がある方はこちらを読んでみてください。
http://docs.blynk.cc/


<プログラムの修正>

Blynk のプログラムには上記のサンプルしか入っていないため、今回の目的であるCPUの温度やクロック周波数を取得するには、それぞれの目的に合わせたC言語の プログラムを作らなくてはなりません。しかしC言語のプログラムは修正する度に毎回コンパイルする必要があり面倒です。また、接続したセンサーの値を取得 する場合は、Blynkに合わせてC言語のプログラムを作るより、公開されている他の言語用のライブラリを使用した方が手っ取り早く、簡単に行える場合も あります。

そこで、今回はバーチャルポートを扱いやすくするために、Blynkからシェルスクリプトで橋渡しする方法でいきます。シェル スクリプトに実行したいコマンドを記述するだけなので、PythonでもPerlでもPHPでも、ただのシェルスクリプトでも、これならどんなプログラム とも連携できるようになります。

gateway-flow

blynk-library/linux/main.cpp を編集し、以下の4行の部分を…
BLYNK_WRITE(V1)
{
  printf("Got a value: %s\n", param[0].asStr());
}
以下のように書き換えます。
void blynk_read_exec(int pin) {
  char command[256] = "";
  char buff[256] = "";
  FILE *fp;
  sprintf(command, "/home/pi/blynk/BLYNK_READ_V%d.sh", pin);
  if((fp=popen(command,"r")) != NULL) {
    if(fgets(buff, 255, fp) != NULL) strtok(buff, "\n\0");
  }
  pclose(fp);
  Blynk.virtualWrite(pin, buff);
  BLYNK_LOG("Command: %s -> %s", command, buff);
}

void blynk_write_exec(int pin, const BlynkParam& param) {
  char command[256] = "";
  char buff[256] = "";
  sprintf(command, "/home/pi/blynk/BLYNK_WRITE_V%d.sh", pin);
  for (int i=0; i<3; i++) {
    if(! param[i].isValid()) break;
    sprintf(buff, " %d", param[i].asInt());
    strcat(command, buff);
  }
  BLYNK_LOG("Command: %s", command);
  system(command);
}

BLYNK_READ(V0) { blynk_read_exec(V0); }
BLYNK_READ(V1) { blynk_read_exec(V1); }
BLYNK_READ(V2) { blynk_read_exec(V2); }
BLYNK_READ(V3) { blynk_read_exec(V3); }
BLYNK_READ(V4) { blynk_read_exec(V4); }
BLYNK_READ(V5) { blynk_read_exec(V5); }
BLYNK_READ(V6) { blynk_read_exec(V6); }
BLYNK_READ(V7) { blynk_read_exec(V7); }
BLYNK_READ(V8) { blynk_read_exec(V8); }
BLYNK_READ(V9) { blynk_read_exec(V9); }
BLYNK_WRITE(V10) { blynk_write_exec(V10,param); }
BLYNK_WRITE(V11) { blynk_write_exec(V11,param); }
BLYNK_WRITE(V12) { blynk_write_exec(V12,param); }
BLYNK_WRITE(V13) { blynk_write_exec(V13,param); }
BLYNK_WRITE(V14) { blynk_write_exec(V14,param); }
BLYNK_WRITE(V15) { blynk_write_exec(V15,param); }
BLYNK_WRITE(V16) { blynk_write_exec(V16,param); }
BLYNK_WRITE(V17) { blynk_write_exec(V17,param); }
BLYNK_WRITE(V18) { blynk_write_exec(V18,param); }
BLYNK_WRITE(V19) { blynk_write_exec(V19,param); }

main.cppの編集が終わったら、再コンパイルします。
$ cd ~/blynk/blynk-library/linux
$ make clean all target=raspberry

今回は例として、
  • V0〜V9 をディスプレイ系のウィジット用
  • V10〜V19 をコントローラー系のウィジット用
に割り当てました。

ウィジットから呼び出されると、以下のパスのシェルスクリプトがRaspberry Pi上で実行されます。こうにすることで、今後は一切C言語のプログラムをいじらずに、シェルスクリプトを編集するだけで済みます。
  • /home/pi/blynk/BLYNK_READ_V*.sh
  • /home/pi/blynk/BLYNK_WRITE_V*.sh

※例ではユーザーpiのホームディレクトリ下で作業をしていますが、これらのシェルスクリプトはスーパーユーザー(root)権限で実行される点にご注意ください。
※Raspberry Piのターミナルには実行しているコマンドや、取得した値が表示されていますが、これが鬱陶しい場合はmain.cpp中の BLYNK_LOG() の行を削除してください。


<測定用のシェルスクリプトの作成>

次は実際にCPUの温度やクロック周波数などの情報を取得するシェルスクリプトを作成します。今回バーチャルポートは次のように割り当てることにします。
  • V0 … CPUの温度
  • V1 … CPUのクロック周波数
  • V2 … CPUの負荷状態

シェルスクリプトはホームディレクトリの blynk の中に保存します。

ファイル名:BLYNK_READ_V0.sh
#!/bin/sh
data=`cat /sys/class/thermal/thermal_zone0/temp | awk '{printf($1/1000)}'`
printf "%3.1f" $data

ファイル名:BLYNK_READ_V1.sh
#!/bin/sh
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq \
  | awk '{print $1 / 1000}'

ファイル名:BLYNK_READ_V2.sh#!/bin/sh
cat /proc/loadavg | awk '{print $1*100}'

シェルスクリプトは単独でも実行できますので、パーミッションを設定して試しに実行してみましょう。
$ chmod 700 BLYNK_READ_V0.sh
$ ./BLYNK_READ_V0.sh
48.3

このようにCPUの温度が表示されれば正常です。同様にV1、V2も実行してみてください。

このシェルスクリプトはblynkに値を橋渡しするためのもので、標準出力に出力された先頭の1行目の内容がblynkに読み込まれます。グラフやゲージで表示する場合は数値を渡す必要がありますので、修正する場合は必ず数値だけが出力されるようにしてください。

これで準備が整いました。Blynkを起動していない場合は、起動します。
$ cd ~/blynk
$ sudo ./blynk --token=自分のAUTH TOKEN

<ウィジットの設定>

スマートフォン側のアプリで、バーチャルポートのV0、V1、V2に接続しましょう。はじめにテストしたButtonのウィジットは削除しておいてください。

CPUの温度を表示するウィジットを追加します。「Value Display M」を選択します。MとSの違いは大きさですので、好きな方でかまいません。
IMG_6575

ピンの選択は「Virtual」の「V0」にします。
IMG_6576

FREQUENCYという設定項目に1secと入っているのは、1秒間隔で実行することを意味します。ただこれだと1秒ごとにシェルスクリプトが実行されるので、Raspberry Piに負担がかかります。実行する間隔はもう少し長くした方がいいかもしれません。

同様にクロック周波数を表示するウィジットを追加します。「V1」を選択します。
IMG_6577

最後にCPUの負荷状態を表示するウィジットを追加します。これは時間と共に刻々と変化するものなので、今回は数値ではなく棒グラフで見てみましょう。「Graph」を選択します。
IMG_6578

このシェルスクリプトでは1分間のロードアベレージを単位(%)で出力しています。ピンは「Virtual」の「V2」を選択し、横のボックスに最小値と最大値を設定します。今回は例として「0」〜「200」と設定しました。
IMG_6581

ウィジットの設定が終わったら、右上の三角ボタンをタップしてRaspberry Piに接続します。マークが四角に変わったら接続完了です。
IMG_6582

問題なければ、CPUの温度やクロック周波数が表示されます。負荷状態(ロードアベレージ)はCPUに負荷かかかると大きくなりますので、ブラウザなどを起動してCPUに負荷をかければ、バーが上に伸びてくるのがわかると思います。
IMG_6583


次回はいよいよ実用的な実験に移ります。GPIOポートに温度センサーを接続して、Raspberry Piの外部から情報を取得してみましょう。


連載 IoTサービス「Blynk」を使ってRaspberry Piをスマホからコントロールしよう