非接触温度センサの値をMQTT経由でenebularへ送ってみた

# 実施したこと

- ATOM S3とOMRON製非接触温度センサ(D6T-44L-06)をつなげてみた
- ATOM S3とShifr.ioを連携してMQTT通信を試してみた
- shiftr.ioからenebularへデータを流した

# 使ったもの

主要なコンポーネントだけ軽く説明します。
ちなみに今回は下記のような簡単なデータの流れを組みます。

```mermaid
flowchart LR
    subgraph ide2 [ハードウェア]
    D6T-44L-06--i2c-->ATOMS3
    end
    subgraph ide1 [クラウド]
    ATOMS3--MQTT-->enebular
    end

style D6T-44L-06 fill:#9DCCE0,stroke:#333,stroke-width:2px
style ATOMS3 fill:#FFF,stroke:#333,stroke-width:2px
style enebular fill:#A0CA5A,stroke:#333,stroke-width:2px
linkStyle 0 stroke-width:3px,stroke:blue,color:#000000
linkStyle 1 stroke-width:3px,fill:green,stroke:green,color:#000000
```

## ATOM S3

- M5Stackが出しているケース付きの小さなESP32-Sボード
- カラー液晶がついていたり、加速度センサがついていたりする。
- Switch scienceだと一個3000円ぐらいで買える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/55c30cc4-ba58-206a-49a3-9f82de846a02.png)

https://www.switch-science.com/products/8670

## D6T-44L-06

- OMRONが提供している非接触温度センサ
- 4x4のグリッドで温度を取得してくれる
- I2Cでデータ取得可能
- 9000円あれば買える

https://www.fa.omron.co.jp/products/family/3706/lineup.html

## Shiftr.io

- 多分一番平易に使えるMQTTブローカー
- パブリックインスタンスを使えばログイン無しで使える
- データ量などの制限はあるが、クローズドなMQTTブローカーを無料で作れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/707e489b-bdcc-7d00-76bd-2474e15956eb.png)

https://www.shiftr.io/

今回はパブリックインスタンスの`mqtt://public:public@public.cloud.shiftr.io`を使用する。ちなみにやり取りされているノード情報はリアルタイムに見ることができる。
**なので、絶対に個人情報を入力・設定しないようにしてください。下記リンクから分かる通り、すべての人に丸見えになります。**

https://www.shiftr.io/try

## enebular

- 多分一番手早くNode-REDできるプラットフォーム
- クラウド環境を使っている場合は一定時間で接続が切れますが、更新かければそのまま利用可能
- enebular editorを使えば作成してきたフローをローカルで動かせる。当然ながら接続が切れることもなくなる

https://www.enebular.com/ja/


# M5ATOMとD6T-44L-06の接続方法について

ATOM S3と温度センサを連携する仕組みはこちら。
一応i2cでデータを取得するようにしている。

https://qiita.com/Inoue_Minoru/items/d2a7beff78b0d0a704bd

# node-red側について

enebularだとデフォルトでMQTT用ノードが用意されている。
とりあえずデバッグノードでデータだけ取得する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/afdd7564-c9a5-c861-7d5c-3451885bad82.png)


### mqttサーバー設定

サーバーとして`mqtt://public:public@public.cloud.shiftr.io`を設定する。
これが使用するパブリックインスタンスのMQTTブローカーとなる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/bc021abf-10ba-884a-c548-3d545a10e1c4.png)


### mqtt in側設定

`トピック`に`sub/M5Stack`のみ設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/6ece71c6-30b5-ede6-930b-a7f7e0f1b57f.png)


フロー全文はこちら。

```json:flow.json
[{"id":"72a21c6a252776c8","type":"mqtt in","z":"157d2eb59ec0c836","name":"","topic":"pub/M5Stack","qos":"2","datatype":"auto","broker":"2101c8387dd7f0c1","nl":false,"rap":true,"rh":0,"inputs":0,"x":230,"y":100,"wires":[["141691691fb17918"]]},{"id":"141691691fb17918","type":"debug","z":"157d2eb59ec0c836","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":490,"y":80,"wires":[]},{"id":"2101c8387dd7f0c1","type":"mqtt-broker","name":"Shifter","broker":"mqtt://public:public@public.cloud.shiftr.io","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""}]
```


# ATOM S3に書き込むプログラム

何度も言いますが、**shftr.ioはパブリックインスタンスを使用しているため、個人情報などは流さないように。**

なお、画面描写はlovyanGFX(Version 1.1.2)を使用していて、チラツキ防止にスプライト表示をしています。

```c++:code.ino
#include <Arduino.h>
#define LGFX_AUTODETECT 
#include <LovyanGFX.hpp>
#include <LGFX_AUTODETECT.hpp>

#include <WiFi.h>
#include <MQTT.h>
#include <ArduinoJson.h>

#include <M5AtomS3.h>
#include "OmronD6T.h"
#include <math.h>

#define WIDTH (128 / 4)
#define HEIGHT (128 / 4)

static LGFX lcd;
static LGFX_Sprite sprite(&lcd);
unsigned long lastMillis = 0;

// Wi-FiのSSID
char *ssid = "xxxxxxx";
// Wi-Fiのパスワード
char *pass = "xxxxxxxx";

WiFiClient httpsClient;
MQTTClient client;

OmronD6T sensor;

float gain = 10.0;
float offset_x = 0.2;
float offset_green = 0.6;

float sigmoid(float x, float g, float o) {
  return (tanh((x + o) * g / 2) + 1) / 2;
}

uint16_t heat(float x) {
  x = x * 2 - 1;

  float r = sigmoid(x, gain, -1 * offset_x);
  float b = 1.0 - sigmoid(x, gain, offset_x);
  float g = sigmoid(x, gain, offset_green) + (1.0 - sigmoid(x, gain, -1 * offset_green)) - 1;

  return (((int)(r * 255) >> 3) << 11) | (((int)(g * 255) >> 2) << 5) | ((int)(b * 255) >> 3);
}

void connect() {
  Serial.print("checking wifi...");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }

  Serial.print("\nconnecting...");
  while (!client.connect("M5Stack", "public", "public")) {
    Serial.print(".");
    delay(1000);
  }

  Serial.println("\nconnected!");

  client.subscribe("hello");
}

void messageReceived(String &topic, String &payload) {
  Serial.println(topic + ": " + payload);
}

void setup() {
  Serial.begin(115200);
  M5.begin();

  lcd.init();
  lcd.clear();
  sprite.createSprite(128, 128);
  sprite.fillRect(0,0,128,128,TFT_BLACK);
  sprite.pushSprite(0,0);

  // Start WiFi
  Serial.println("Connecting to ");
  Serial.print(ssid);

  // start wifi and mqtt
  WiFi.begin(ssid, pass);
  client.begin("public.cloud.shiftr.io", httpsClient);
  client.onMessage(messageReceived);

  connect();
}

void loop() {

  StaticJsonDocument<192> doc;
  JsonArray temps = doc.createNestedArray("temps");  
  client.loop();
  delay(10);

  if (!client.connected()) {
    connect();
  }

  sensor.scanTemp();
  sprite.createSprite(128, 128);
  sprite.fillRect(0,0,128,128,TFT_BLACK);
  int x, y;

  for (y = 0; y < 4; y++) {
    for (x = 0; x < 4; x++) {
      float temp = sensor.temp[x][y];
      if (temp > 100.0) {
        return;
      }
      float t = map(constrain((int)temp, 0, 60), 0, 60, 0, 100);
      uint16_t color = heat(t / 100.0);
      sprite.fillRect(y * WIDTH, x * HEIGHT, WIDTH, HEIGHT, color);
      sprite.setCursor(y * WIDTH + WIDTH / 2, x * HEIGHT + HEIGHT / 2);
      sprite.setTextColor(BLACK, color);
      sprite.printf("%.1f", temp);
      temps.add((int)floor(temp*10));
    }
  }

  sprite.pushSprite(0,0);

  String output;
  serializeJson(doc, output);

  client.publish("/pub/M5Stack", output.c_str());

  delay(500);
}
```

# 結果

<iframe width="560" height="315" src="https://www.youtube.com/embed/W-KK1EJjyIA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

# おわりに

- ATOM S3でも普通にMQTT通信できた。今までのATOM liteやM5Stack Grayと同じ手順でも大丈夫っぽい。
- Shiftr.ioやenebularのおかげもあって、速攻でIoTできた。
- パブリックインスタンスむっちゃ便利。
- 4x4のセンサ値がせっかく取れているし、フロント側でいい感じに見える化したらカッコよさそう？