memorandums

日々の生活で問題解決したこと、知ってよかったことなどを自分が思い出すために記録しています。

Arduino YunのWebサーバーにアクセスするHTTPクライアントの実現の一試行

経緯はいいから本題を早く知りたいというかたは以下の本題へお進みくださいな。

背景

少し前に学生支援のため以下の調査をしました。

Arduino YunのTemperature Web Panelを図にしてみた - memorandums

このプロジェクトでは、Yunに接続した加速度センサーに関する情報をWifi経由でAndroidクライアントが取得する予定でした。

プロジェクトの納期が近く中でなかなか進まず、また、少し支援のため調査したログが以下です。

Androidアプリを1から作るのは大変なのでProcessingのAndroidモードを利用したら?と伝えていました。そのための本も用意していますし、これまで卒業研究などで活用してきた経緯もありました。

で、本日、調べてみたのですが。。。結論を先に書きますと、難しい。。。ということがわかりました。もちろん、実現できなくはないけど。。。大変。一応、ログまで試したこととその結果は以下です。

  • HTTP Requests for Processing ライブラリを使おうとしたら以下のエラーをはいて落ちてしまいました。Androidモードではあ動作しないのかな。。。追っていません。

f:id:ke_takahashi:20171116210247p:plain

  • ProcessingでTCP/IPクライアントを利用しようとしたら、processing.netライブラリはAndroidモードでは使えないことがわかりました。

卒業研究くらい時間があれば、じっくりAndroidアプリでも作ればいいのでしょうが、あと3週間くらい(といっても授業時間しかないので基本的には3コマ!?)しかない状態では無理でしょう。

そこで思いついたのはProcessingつながりでP5.jsを利用する手です。p5.jsはもちろんJSですからWebサーバーへのアクセスだってできるはずです。案の定httpGetなる関数が用意されていることがわかりました。で、早速試したわけです。

すると。。。アクセスできない。

ブラウザのエラーメッセージは以下。ああ。。。クロスドメインかぁ。。。アプリからサーバーアクセスが許可されていないってやつか。

f:id:ke_takahashi:20171116210403p:plain

そこから、いろいろと調査したり試したりしました。1時間くらいはやっていたでしょうか。。。もういい加減できないなぁ。。。諦めようと思いました。サーバーからAccess-Control-Allow-Origin:*をヘッダーとして返せばいいことはわかるのですが、YunのWebサーバーを書き換えることはできるのかな。。。と。

ダメ元で以下のようにYunのスケッチを書き換えてみたんですね。すると。。。うまくいくじゃん。。。

<抜粋>(元々はYunのBridgeサンプルです)

    if (command == "brightness") {
      int sensorValue = analogRead(A0);

      //修正前
      //client.print(sensorValue);
      
      //修正後:CORS問題に対応するため
      client.println("Status: 200");
      client.println("Content-type: text/plain");
      client.println("Access-Control-Allow-Origin: *");
      client.println();
      client.print(sensorValue);
    }

本題

Yunのプログラム(サーバー)は以下です(Bridge/TemperatureWebPanelをもとに修正したものです)

#include <Bridge.h>
#include <BridgeServer.h>
#include <BridgeClient.h>

BridgeServer server;

void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Bridge.begin();
  digitalWrite(13, HIGH);

  pinMode(A0, INPUT);

  server.listenOnLocalhost();
  server.begin();
}

void loop() {
  BridgeClient client = server.accept();

  if (client) {
    String command = client.readString();
    command.trim();

    if (command == "brightness") {
      int sensorValue = analogRead(A0);

      //修正前
      //client.print(sensorValue);
      
      //修正後:CORS問題に対応するため
      client.println("Status: 200");
      client.println("Content-type: text/plain");
      client.println("Access-Control-Allow-Origin: *");
      client.println();
      client.print(sensorValue);
    }

    client.stop();
  }

  delay(50); // Poll every 50ms
}


p5.jsのプログラム(クライアント)は以下です。3秒ごとYunにアクセスして値を取得します。YunのアドレスはBonjourに対応していればarduino.localで解決できるはずですが、私のAndroidでは解決エラーになりましたので直で入れています。たぶん、これも解決方法があるのだと思いますが。。。とりあえず本題ではないので。

var b = 0;

function setup() {
  createCanvas(400, 400);
  fill(0);
  textSize(64);
}

function draw() {
  background(255);
  text(b, 0, 100);
  if (second() % 3 == 0) {
    getDataFromYun();
  }
}

function getDataFromYun() {
  var url = 'http://192.168.2.17/arduino/brightness';
  httpGet(url, "text", false, function(res) {
    b = res;
    console.log(b);
  });
}

実行結果は以下のような感じです。p5.jsをMacで動作させた状態です。もちろん、Androidのブラウザで動作させれば結果は同様になります。具体的には、例えば、Mac上などでWebサーバーを起動し、ドキュメントルートにp5.jsのファイルをおきます。そこにAndroidのブラウザでアクセスにいけばいいわけです。

f:id:ke_takahashi:20171116211747j:plain