IoTノード設置場所のWi-Fi状況をM5StickCで確認

# 1. はじめに
IoTセンサノードを設置する場合、確認すべきことは、電源確保、Wi-Fiが届くか、湿度や粉塵 などです。Wi-Fiの電波強度は、スマホで接続することで、確認が可能だと思います。しかし、実際に通信できるのか？不安になる場合もあるのではないでしょうか。ここでは、Wi-Fiの状況について、node-redとM5StickC(M5StickC-plus)を用いて簡単に確認する方法について紹介します。

# 2. 概要
サーバ側が数字の０から９までを１秒毎にMQTT publishし、それをM5StickCでsubscribeし、表示します。数字が飛んでなければきちんと届いていることが判ります。

# 3. Node-red側

基本的には、injectionノードとMQTT outノードで構成すればokです。ただ、カウントアップさせた数字を送りたいので、一つはnode-red起動時のグローバル変数の定義、もう一つは、０から９までカウントアップさせて、msg.payloadに代入するだけのfunctionノードです。publishできているか、確認のために、MQTT-inとデバッグノードを付けています。
![ss 2021-01-15 6.08.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698531/33c5b4c1-7f64-228d-2b9f-c00f73413f7b.png)
node-redのコードは下記です。

<details><summary>mqtt_pub_digit.json</summary><div>

```json
[
    {
        "id": "c43f5eb9.27838",
        "type": "inject",
        "z": "349f7dec.7ae6b2",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "1",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 170,
        "y": 180,
        "wires": [
            [
                "dc1b2f5a.878a38"
            ]
        ]
    },
    {
        "id": "cbcc72c4.6375b",
        "type": "function",
        "z": "349f7dec.7ae6b2",
        "name": "",
        "func": "var myCounterForMqtt=0;\nglobal.set('myCounterForMqtt',myCounterForMqtt);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 340,
        "y": 120,
        "wires": [
            []
        ]
    },
    {
        "id": "fd0b63aa.6febc8",
        "type": "inject",
        "z": "349f7dec.7ae6b2",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 160,
        "y": 120,
        "wires": [
            [
                "cbcc72c4.6375b"
            ]
        ]
    },
    {
        "id": "dc1b2f5a.878a38",
        "type": "function",
        "z": "349f7dec.7ae6b2",
        "name": "",
        "func": "myCounterForMqtt = global.get('myCounterForMqtt');\nmyCounterForMqtt +=1;\nmyCounterForMqtt = (myCounterForMqtt<10)*myCounterForMqtt;\nglobal.set('myCounterForMqtt',myCounterForMqtt);\nmsg.payload = String(myCounterForMqtt);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 380,
        "y": 180,
        "wires": [
            [
                "6050e393.59d58c"
            ]
        ]
    },
    {
        "id": "6050e393.59d58c",
        "type": "mqtt out",
        "z": "349f7dec.7ae6b2",
        "name": "",
        "topic": "myDispNum",
        "qos": "0",
        "retain": "",
        "broker": "4e38b730.53a58",
        "x": 540,
        "y": 180,
        "wires": []
    },
    {
        "id": "54808ffe.04b598",
        "type": "mqtt in",
        "z": "349f7dec.7ae6b2",
        "name": "",
        "topic": "myDispNum",
        "qos": "2",
        "datatype": "auto",
        "broker": "4e38b730.53a58",
        "x": 130,
        "y": 240,
        "wires": [
            [
                "4e18b4bd.b551f4"
            ]
        ]
    },
    {
        "id": "4e18b4bd.b551f4",
        "type": "debug",
        "z": "349f7dec.7ae6b2",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 370,
        "y": 240,
        "wires": []
    },
    {
        "id": "4e38b730.53a58",
        "type": "mqtt-broker",
        "name": "",
        "broker": "localhost",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": false,
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    }
]
```

</div></details>


# 4. M5StickC側
受信した数字をディスプレイに次々と横に並べていくだけのものです。watch dogは行っていません。変だなと思ったら、再起動してください。また、焼き込みした時は、シリアルコンソールで動作を確認してください。

SSID、PASSWORD、192.168.1.1 の部分は、それぞれお使いの環境に合わせて書き換えて下さい。

次は、M5StickC-plus用です。

<details><summary>M5stickCplus_Mqttsub_Digit.ino</summary><div>

```c++
#include <WiFi.h>
#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient
#include <M5StickCPlus.h>

char *ssidC="SSID";
char *passC="PASSWORD";
char *servC="192.168.1.1";

const char* gcTopic = "myDispNum";
const String gsClientId = "myMqttSubCp" ;

WiFiClient myWifiClient;
const int myMqttPort = 1883;
PubSubClient myMqttClient(myWifiClient);
#define MQTT_QOS 0

volatile uint16_t gu16Posx;
volatile uint16_t gu16Posy;
volatile uint16_t gu16Count;

#define N_DOT_FONT_X 16
#define N_DOT_FONT_Y 24

#define MAX_DISP_WIDTH 240
#define MAX_DISP_HEIGHT 135

void initWifiClient(void){
  Serial.print("Connecting to ");
  Serial.println(ssidC);
  uint16_t tmpCount =0;
  
  WiFi.begin( ssidC, passC);
  while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
  tmpCount++;
  if(tmpCount>128)
  {
    Serial.println("failed  ");
    return;
  }
  }
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void connectMqttSub()
{
  myMqttClient.setServer(servC, myMqttPort);
  reconnectMqttSub();
  myMqttClient.setCallback(gotMessageViaMqtt);
}

void reconnectMqttSub()
{
  while( ! myMqttClient.connected() )
  {
    Serial.println("Connecting to MQTT Broker...");
    //String clientId = "myMqttPub" ;
    if ( myMqttClient.connect(gsClientId.c_str()) )
    {
      myMqttClient.subscribe(gcTopic,MQTT_QOS);
      Serial.println("done! connected to Broker and subscribed. "); 
    }
  }
}

void gotMessageViaMqtt(char * pctoic, byte * pbpayload, uint32_t uiLen){
  Serial.print(pctoic);
  Serial.print(" : \t");
  for (uint32_t i = 0; i < uiLen; i++) {
    Serial.print((char)pbpayload[i]);
  }

  const char ccBuf[2]={pbpayload[0],0};

  M5.Lcd.setCursor(gu16Posx, gu16Posy);
  M5.Lcd.printf(ccBuf);
  gu16Posx +=N_DOT_FONT_X;
  if ((gu16Posx+N_DOT_FONT_X)>(MAX_DISP_WIDTH-1)){
    gu16Posx =0;
    gu16Posy +=N_DOT_FONT_Y;
  }
  if ((gu16Posy+N_DOT_FONT_Y)>(MAX_DISP_HEIGHT-1)){
    gu16Posy =5;
    M5.Lcd.fillScreen(BLACK);
  }
  
  Serial.println();
}


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

  M5.begin();
  M5.Lcd.setRotation( 1 );
  M5.Lcd.setTextDatum(0);
  M5.Lcd.fillScreen(BLACK);// WHITE RED GREEN BLUE  BLACK
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(3);

  gu16Posx =0;
  gu16Posy =5;
  gu16Count =0;

  connectMqttSub();
}

void loop(){
  reconnectMqttSub();
  myMqttClient.loop();
  delay(100);

}
```

</div></details>

次のはM5StickCです。（plus無し版です）
<details><summary>M5stickC_Mqttsub_Digit.ino</summary><div>

```c++
#include <WiFi.h>
#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient
#include <M5StickC.h>

char *ssidC="SSID";
char *passC="PASSWORD";
char *servC="192.168.1.1";

const char* gcTopic = "myDispNum";
const String gsClientId = "myMqttSubCn" ;

WiFiClient myWifiClient;
const int myMqttPort = 1883;
PubSubClient myMqttClient(myWifiClient);
#define MQTT_QOS 0

volatile uint16_t gu16Posx;
volatile uint16_t gu16Posy;
volatile uint16_t gu16Count;

#define N_DOT_FONT_X 16
#define N_DOT_FONT_Y 24

#define MAX_DISP_WIDTH 160
#define MAX_DISP_HEIGHT 80

void initWifiClient(void){
  Serial.print("Connecting to ");
  Serial.println(ssidC);
  uint16_t tmpCount =0;
  
  WiFi.begin( ssidC, passC);
  while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
  tmpCount++;
  if(tmpCount>128)
  {
    Serial.println("failed  ");
    return;
  }
  }
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void connectMqttSub()
{
  myMqttClient.setServer(servC, myMqttPort);
  reconnectMqttSub();
  myMqttClient.setCallback(gotMessageViaMqtt);
}

void reconnectMqttSub()
{
  while( ! myMqttClient.connected() )
  {
    Serial.println("Connecting to MQTT Broker...");
    //String clientId = "myMqttPub" ;
    if ( myMqttClient.connect(gsClientId.c_str()) )
    {
      myMqttClient.subscribe(gcTopic,MQTT_QOS);
      Serial.println("done! connected to Broker and subscribed. "); 
    }
  }
}

void gotMessageViaMqtt(char * pctoic, byte * pbpayload, uint32_t uiLen){
  Serial.print(pctoic);
  Serial.print(" : \t");
  for (uint32_t i = 0; i < uiLen; i++) {
    Serial.print((char)pbpayload[i]);
  }

  const char ccBuf[2]={pbpayload[0],0};

  M5.Lcd.setCursor(gu16Posx, gu16Posy);
  M5.Lcd.printf(ccBuf);
  gu16Posx +=N_DOT_FONT_X;
  if ((gu16Posx+N_DOT_FONT_X)>(MAX_DISP_WIDTH-1)){
    gu16Posx =0;
    gu16Posy +=N_DOT_FONT_Y;
  }
  if ((gu16Posy+N_DOT_FONT_Y)>(MAX_DISP_HEIGHT-1)){
    gu16Posy =5;
    M5.Lcd.fillScreen(BLACK);
  }
  
  Serial.println();
}


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

  M5.begin();
  M5.Lcd.setRotation( 1 );
  M5.Lcd.setTextDatum(0);
  M5.Lcd.fillScreen(BLACK);// WHITE RED GREEN BLUE  BLACK
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(3);

  gu16Posx =0;
  gu16Posy =5;
  gu16Count =0;

  connectMqttSub();
}

void loop(){
  reconnectMqttSub();
  myMqttClient.loop();
  delay(100);

}
```

</div></details>

M5StickCplusやM5StickCは、それぞれArduino-IDEのライブラリでインストールする必要があります。
メニューで、
スケッチ→ ライブラリのインクルード → ライブラリの管理...
から
M5StickCと入力すると候補が出てきますので、インストールしてください。

また、pubsubclientもインストールされてない場合は、インストールしましょう。ここのMQTTの部分を参照してください。  https://qiita.com/dzonesasaki/items/ab904d70fa4b3d4ce7ce

# 5. 確認
Node-red側が動いていることを確認します。
M5StickCにプログラムを焼いたら、シリアルコンソールで動作確認します。その時点でおかしい場合は、Wi-Fiの情報、サーバのIPアドレスが間違っていないか確認してください。
M5StickCは、電池が内蔵されているので、充電されていれば電源無しで現場に持って行けます。
そこで数字が順序に表示されればその場所はMQTTで通信できていると考えて良いでしょう。

数字が途切れるなどの現象があった場合、Wi-Fiのアクセスポイントの設置を検討するなどが必要になります。

# 6. おわりに
IoTを現場で実践するには、細々したことを確認する必要があります。その１つを紹介しました。役に立てればと思います。