複数のobnizでオフィスの温度分布を自動最適化した

# 「この席寒くない？」をなんとかしたい

オフィスって明らかに場所による温度差がありませんか？
この辺だけやたらと寒いとか。

<img width="855" alt="Screen Shot 2018-06-27 at 12.48.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/258216/54f8503f-7392-de9f-37db-f5ed6be1ed1e.png">

じゃあ、本当なのかセンサーで調べてみよう！
ということで、今回は温度センサーつないだobnizを複数置くことで
**「本当に温度差があるのか」**
を検証し、更に、エアコンの向きを自動的に１つずつ変えて
**「どの角度なら温度分布が少ないのか」**
を自動的に計測するというのをやってみます。

## どうやるのか

まずは温度センサーを各机に置きます。
使うのは手元にあったSH31など、いくつかの温度センサーとobnizです。

obniz(オブナイズって読む)はJavascriptからインターネット経由で使える電子回路です。
これならファームウェアを１こずつ用意しなくても手元で動かすjavascriptのプログラム１つから複数のobnizに接続して温度センサーの値をとって集計することができます。それもインターネット経由でできるので、ケーブルなどを気にしなくていいのがいいです。

<img width="374" alt="Screen Shot 2018-06-27 at 12.53.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/258216/f99385e5-556b-6141-9c73-52bf66f5e4ae.png">

これをそれぞれの机においてみます。

<img width="564" alt="Screen Shot 2018-06-27 at 12.55.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/258216/577c29a5-6dcd-eb4f-7369-a04c65388932.png">

これで温度を測れそうですね。試しに測ってみます。ついでにheatmap.jsを使ってヒートマップ表示してみました。今回はHTMLにjavascriptを書いてブラウザで開くことで実行しています。

```html
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@1.5.1/obniz.js" crossorigin="anonymous"></script>
  <script src="自分でビルドしたheatmap.js"></script>
</head>
<body>

  <div id="obniz-debug"></div>
  <h5 id="A"></h5>
  <h5 id="B"></h5>
  <h5 id="C"></h5>
  <h5 id="result"></h5>
  
  <div id="heatmap" style="width:400px;height:320px;"></div>

<script>
var obnizA = new Obniz("OBNIZその１");
var obnizB = new Obniz("OBNIZその２");
var obnizC = new Obniz("OBNIZその３");
  
var tempA, tempB, tempC;
var tempDiff;
  
var current_direction = 0;
  
obnizA.onconnect = async function () {
  var sensor = obnizA.wired("SHT31", {vcc : 4, sda:3, scl:2, adr:1, gnd:0, addressmode:5});
  obnizA.repeat(async () => {
    var temp = await sensor.getTempWait();
    temp -= 2;
    $("#A").text(''+temp+'℃')
    tempA = temp;
    update()
  })
}

obnizB.onconnect = async function () {
  var sensor = obnizB.wired("ADT7410", {vcc:3, gnd:0, sda:1, scl:2,  addressMode:8});
  obnizB.repeat(async () => {
    var temp = await sensor.getTempWait();
    $("#B").text(''+temp+'℃')
    tempB = temp;
    update()
  });
}

obnizC.onconnect = async function () {
  var tempsens = obnizC.wired("MCP9701",  { gnd:0 , output:1, vcc:2});
  tempsens.onchange = function(temp){
    temp -= 0.5;
    $("#C").text(''+temp+'℃')
    tempC = temp;
    update()
  };
}

var heatmap = h337.create({
  container: document.querySelector('#heatmap'),
  radius: 120
});
  
function update() {
  var avg = (tempA + tempB + tempC)/3
  tempDiff = Math.abs(tempA - avg) + Math.abs(tempA - avg) + Math.abs(tempA - avg);
  $("#result").text('result = '+tempDiff+' ');
  heatmap.setData({
    max: 32,
    min: 20,
    data: [
      { x: 50,  y: 100, value: tempA},
      { x: 200, y: 100, value: tempB},
      { x: 350, y: 100, value: tempC}
    ]
  });
}  

</script>
</body>
</html>
```



指で触ると触ったやつだけ熱くなってるのがわかります。（クリックで再生）

[![](https://qiita-image-store.s3.amazonaws.com/0/258216/c46d4f4e-878d-684b-d9c1-7e10a9f6d353.png)](https://www.youtube.com/watch?v=uTFpype1u50&feature=youtu.be)

温度が取得できたところで、注目するのは温度の分散（σ^0.5）です。
これがあるのかないのか。あったら一番低いのはどこなのかを調べます。

## エアコンを操作

あとは、エアコンの角度を１ステップずつ動かします。
obnizに赤外線LEDをつけます。
このオフィスのエアコンは富士通ですが、「風向」のコマンドが公開されていないので、
学習リモコンの要領で出ている赤外線を赤外線センサーでobniz経由で受け取って、保存してそのまま送信してみます。

<img width="539" alt="Screen Shot 2018-06-27 at 13.42.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/258216/2283cc46-6f00-6bf9-eaf9-192bf1d44f9f.png">

このオフィスの「風向」はこれで変えられそうです。

```json
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0]
```

## 計測開始！

赤外線の部分も含めた全体のプログラムです。
赤外線LEDはある１つのobnizに温度センサーと一緒につないであります。
こいつだけ1台２役ですね。

10分ごとにエアコンの角度を変えて、次に変える前に計測するということをしています。


```html
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@1.5.1/obniz.js" crossorigin="anonymous"></script>
  <script src="自分でビルドしたheatmap.js"></script>
</head>
<body>

  <div id="obniz-debug"></div>
  <h5 id="A"></h5>
  <h5 id="B"></h5>
  <h5 id="C"></h5>
  <h5 id="result"></h5>
  <button id="change_wind">Change</button>
  
  <div id="heatmap" style="width:400px;height:320px;"></div>

<script>
var obnizA = new Obniz("OBNIZその１");
var obnizB = new Obniz("OBNIZその２");
var obnizC = new Obniz("OBNIZその３");
  
var tempA, tempB, tempC;
var tempDiff;
var led;
  
var current_direction = 0;
  
obnizA.onconnect = async function () {
  var sensor = obnizA.wired("SHT31", {vcc : 4, sda:3, scl:2, adr:1, gnd:0, addressmode:5});
  obnizA.repeat(async () => {
    var temp = await sensor.getTempWait();
    temp -= 2;
    $("#A").text(''+temp+'℃')
    tempA = temp;
    update()
  })
}

obnizB.onconnect = async function () {
  var sensor = obnizB.wired("ADT7410", {vcc:3, gnd:0, sda:1, scl:2,  addressMode:8});
  obnizB.repeat(async () => {
    var temp = await sensor.getTempWait();
    $("#B").text(''+temp+'℃')
    tempB = temp;
    update()
  });
  
  led = obnizB.wired('InfraredLED', {anode: 9, cathode: 11});
  
  return; // 受信するときは外す。
  var irsen = obnizB.wired('IRSensor', {vcc:8, gnd:11, output: 10});
  irsen.start(function (arr) {
    console.log(JSON.stringify(arr));
  })
}

obnizC.onconnect = async function () {
  var tempsens = obnizC.wired("MCP9701",  { gnd:0 , output:1, vcc:2});
  tempsens.onchange = function(temp){
    temp -= 0.5;
    $("#C").text(''+temp+'℃')
    tempC = temp;
    update()
  };
}

var heatmap = h337.create({
  container: document.querySelector('#heatmap'),
  radius: 120
});
  
function update() {
  var avg = (tempA + tempB + tempC)/3
  tempDiff = Math.abs(tempA - avg) + Math.abs(tempA - avg) + Math.abs(tempA - avg);
  $("#result").text('result = '+tempDiff+' ');
  heatmap.setData({
    max: 32,
    min: 20,
    data: [
      { x: 50,  y: 100, value: tempA},
      { x: 200, y: 100, value: tempB},
      { x: 350, y: 100, value: tempC}
    ]
  });
}  
  
function update_wind_directino() {
  
  current_direction++;
  led.send([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0])
}

setInterval(()=>{
  
  console.log(current_direction, tempDiff)
  
  if (current_direction < 8) {
    update_wind_directino();
  } else {
    console.log('DONE!')
  }
  
}, 10 * 60 * 1000); //}, 10 * 1000); // for test
  
$("#change_wind").click(()=>{    // manual direction update
  update_wind_direction();
})

</script>
</body>
</html>
```

## 結果

このようになりました。
最も大きな分散で1.6程度です。
センサーの誤差を悪い方に全部足しても1度に行かないので、1.6ということは本当に席ごとに温度の差があることになります。
そして最も温度差が少なかったのは角度4のときでした。
極値が２つ以上あったのはオフィスが小さく風が回り込んだりするからかなぁと思っています。

<img width="941" alt="Screen Shot 2018-06-27 at 13.50.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/258216/53ad5558-cee7-3c5f-339c-e4572c3bd545.png">

センサーも３つしか使ってなくて、狭いオフィスでしたが、自動最適化を試すことができました。
スタートボタンだけ押せば自動的に調べてくれるのはいいですね。
センサーを増やしたり場所を変えたり、あとは風向だけじゃなく風の強さを変えたりするとより面白い結果になりそうですね！

## 参考

obniz ( [https://obniz.io/](https://obniz.io/) )