3Dマークアップ言語とIoTを組み合わせてみる

# 目的

ちょっと実用的な例として、WifiにつながるArduino系マイコンボードから、温度湿度などの環境情報をARで空間に提示する仕組みを作ってみます。

# 道具立て

使うマイコンボードは、[ESPr® One](https://www.switch-science.com/catalog/2620/)。
Wifiがついているので、こういう時に、使いやすくて便利な奴です。
APモードで動かし、Hololensからつなぎにいきます。
センサーには、BME280を使います。これは、Amazonで安く買いました。
適当にブレッドボードを使うなどして、SPIでつないで動くようにします。

# 仕組み

マイコンで取得した温度湿度気圧を、マークアップにしてHTTPサーバーとして出力。Wifi経由でHoloLensからアクセスしてレンダリングします。

# プログラム

以下のプログラムを、ArduinoIDEで書き込みました。直近5個の値を保存してグラフにします。HoloLensの方は、5秒間隔で再アクセスするようにUnity側のプログラムを作っています。

```server.ino
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#define WIFI_SSID "orthoverseAP"
#define WIFI_PW "test"

#define BME_SCK 14
#define BME_MISO 12
#define BME_MOSI 13
#define BME_CS 16

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme(BME_CS); // hardware SPI

unsigned long delaytimeBegin;

ESP8266WebServer server(80);
IPAddress ip(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

float temp[5] = {0, 0, 0, 0, 0};
float press[5] = {0, 0, 0, 0, 0};
float hum[5] = {0, 0, 0, 0, 0};
unsigned long timeBegin = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("BME280 test");

  bool status;

  status = bme.begin();
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  } else {
    Serial.println("BME280 found");
  }

  Serial.println("-- Default Test --");
  Serial.println("WiFi initializing");
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(ip, ip, subnet);
  bool apst = WiFi.softAP(WIFI_SSID, WIFI_PW);

  if (apst) {
    Serial.println("Ready WiFi");
  } else {
    Serial.println("Something wrong WiFi");
  }

  server.on("/", []() {
    Serial.println("Access");
    String html = "<homl><head><title>3D Graph of Environment Sensor</title></head><body><a-scene wx=0.5 wy=0.001 wz=0.4>";

    for (int i = 0; i < 5; i++) {
      html += "<a-cylinder height=" + String((temp[i] - 20) / 30) + " r=0.05 x=" + String((i - 2.0) / 10.0) + " y=" + String((temp[i] - 20) / 30) + " z=-0.1 color=red />";
      html += "<a-cylinder height=" + String((press[i] - 1000) / 400000) + " r=0.05 x=" + String((i - 2.0) / 10.0) + " y=" + String((press[i] - 1000) / 400000) + " z=0 color=blue />";
      html += "<a-cylinder height=" + String((hum[i]) / 200) + " r=0.05 x=" + String((i - 2.0) / 10.0) + " y=" + String((hum[i]) / 200) + " z=0.1 color=green />";
    }
    html += "<a-text size=0.1 x=0.25 y=0.1 z=-0.1 color=red>"+ String(temp[4]) +"C</a-text>";
    html += "<a-text size=0.1 x=0.25 y=0.1 z=0    color=blue>"+ String(press[4]/100.0F) +"hPa</a-text>";
    html += "<a-text size=0.1 x=0.25 y=0.1 z=0.1  color=green>"+ String(hum[4]) +"%</a-text>";
    html += "</a-scene></body></homl>";

    server.send(
      200,
      "text/html",
      html);
  });
  Serial.println("WebServer setup done");
  server.begin();
  Serial.println("webserver begin");

  timeBegin = millis();
}


void loop() {
  server.handleClient();

  if (timeBegin < millis() - 5000) {
    for (int i = 0; i < 4; i++) {
      temp[i] = temp[i + 1];
      press[i] = press[i + 1];
      hum[i] = hum[i + 1];
    }
    temp[4] = bme.readTemperature();
    press[4] = bme.readPressure();
    hum[4] = bme.readHumidity();

    timeBegin = millis();
  }
}


void printValues() {
  Serial.print("Temperature = ");
  Serial.print(bme.readTemperature());
  Serial.println(" *C");

  Serial.print("Pressure = ");

  Serial.print(bme.readPressure() / 100.0F);
  Serial.println(" hPa");

  Serial.print("Approx. Altitude = ");
  Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
  Serial.println(" m");

  Serial.print("Humidity = ");
  Serial.print(bme.readHumidity());
  Serial.println(" %");

  Serial.println();
}
```

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30257/bef8b6cb-bc00-4f29-8eca-0cf3fb888139.png)

ちょっと値の振れ幅が少なくて、面白みのないグラフになっていますが、IoT機器の情報をHoloLensで表示することができました。
あともっと表示のかっこよさを考えないといけないですね。ちなみに、写真は2018年のMakerFaireTokyoで会社のブースで展示していた時のものです。