ESP8266 Wifi-Module Wemos D1mini & 温湿度センサーSHT30、mac-ID でMQTT-feed を自動作成＆センサーデータvisualization

# ESP8266 Wifi-Module Wemos D1mini & 温湿度センサーSHT30、mac-ID でMQTT-feed を自動作成＆センサーデータvisualization
##プロジェクトアウトライン：

温度・湿度（アップグレードバーションでCO2、PM2.5濃度）のど空気質を評価するセンサーデータを
WiFiでMQTTなどでサーバーに送ってサーバーで処理するプロジェクトをやりました。
今回はデータ保存、表記の為にAdafruit.ioのMQTTサービスを利用しました。
パート2ではFireBase RTDBとCloud Functionを利用します。

フィーギャー
- セットアップWiFi SSID & P/W WifiManager with ad-hoc access point web page
- use WiFiモジュールmac-address as data ID
- Get time from NTP time Client and attach time Stamp to measurement data

##使用するツール

| Hardware:                |Comment:              |    Link:   |
|:-------------------------|-----------------------------:|:------------------:|
| Wemos D1 Module (ESP8266)|        Arduino IDE 　| https://wiki.wemos.cc/products:retired:d1_mini_v2.3.0       |
| Wemos SHT30 Module　　　　| I2C別当用意が必要     |https://wiki.wemos.cc/products:d1_mini_shields:sht30_shield |
| Wemos OLED-Sield       　|                      |https://wiki.wemos.cc/products:d1_mini_shields:oled_shield |
| Wemos Power-Sheeld V1.1　|  optional            |                 |
| スマホ用の充電器        　|                       |           |
| マイクロUSBケーブル     　|                       |             |

###完成したモジュールのイメージ：
![IMG_20181209_003025s25.jpg](https://qiita-image-store.s3.amazonaws.com/0/262129/4ddb1d66-ccee-6435-660c-3ae4fa926c54.jpeg)

###使用した基盤：
![IMG_20181209_001315.jpg](https://qiita-image-store.s3.amazonaws.com/0/262129/97020f77-7756-e183-7736-211eacd93a92.jpeg)
温湿度センサーはI2Cケーブルでフックアップします：
![IMG_20181209_002528s10.jpg](https://qiita-image-store.s3.amazonaws.com/0/262129/0698811a-8854-83b1-9a77-b79098bf480c.jpeg)
###モジュールケースのSTLデータfor ３Dプリンティング：
[Link to STL-file @ Thingiverse.com](https://www.thingiverse.com/thing:3269140)

##Create a free Adafruit.io MQTT acount:
[Link to adafruit.io](https://io.adafruit.com)

Serviceメニューから
-Username
-Active Key
コピーしてArduinoのコードに張り付けって下さい。


###使用するArduino library

| Hardware:                |Version:              |    Link:   |
|:-------------------------|-----------------------:|:------------------:|
| ESP8266WiFi.h |  |  |
|Adafruit_MQTT.h|  |  |
|Adafruit_MQTT_Client.h|  |  |
|WiFiManager.h|  |  |
|ArduinoJson.h| Version 5.13.2  |  |
|ESP8266httpUpdate.h|  |  |
|ESP8266HTTPClient.h|  |  |
|time.h|  |  |
|WiFiUdp.h|  |  |
|stdio.h|  |  |
|NTPClient.h|  |  |
|ESP8266WiFiMesh.h|  |  |
|ESP8266WiFiMulti.h|  |  |
|DNSServer.h|  |  |
|ESP8266WebServer.h|  |  |
|Adafruit_GFX.h|  |  |
|Adafruit_SSD1306.h|  |  |
|Adafruit_GFX.h|  |  |
|Adafruit_SSD1306.h|  |  |

###Source Code

```arduino:mqtt_esp8266.ino
/***************************************************
  Adafruit MQTT Library ESP8266 Example　Must use ESP8266 Arduino from:
    https://github.com/esp8266/Arduino
  Works great with Adafruit's Huzzah ESP board & Feather
  ----> https://www.adafruit.com/product/2471
  ----> https://www.adafruit.com/products/2821
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing products from Adafruit!
  Written by Tony DiCola for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/
#include <ESP8266WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include <WiFiManager.h>
#include <ArduinoJson.h> // Version 5.13.2
#include <ESP8266httpUpdate.h>
#include <ESP8266HTTPClient.h>
#include <time.h>
#include <WiFiUdp.h>
#include <stdio.h>
#include <NTPClient.h>
#include <ESP8266WiFiMesh.h>
#include <ESP8266WiFiMulti.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
//------
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 0  // GPIO0
//------
#include <WEMOS_SHT3X.h>
#define USE_SERIAL Serial      //from ESP32
#define NTP_OFFSET   9 * 3600      // In seconds
#define NTP_INTERVAL 60 * 1000    // In miliseconds
#define NTP_ADDRESS  "europe.pool.ntp.org"

WiFiManager wifiManager;
ESP8266WiFiMulti WiFiMulti;
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);
SHT3X sht30(0x45);
HTTPClient http;
Adafruit_SSD1306 display(OLED_RESET);

/************************* MAC ADD and Time Setup *********************************/
uint8_t mac[6];
String macToStr(const uint8_t* mac) {
  String result;
  char sbuf[30] = "/0";

  //sprintf(sbuf, "%02X:%02X:%02X:%02X:%02X:%02X",

  sprintf(sbuf, "%02X%02X%02X%02X%02X%02X",
          mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  result = sbuf;
  return result;
}
String macID = macToStr(mac);//MAC as String
String formattedTime = timeClient.getFormattedTime();
int timezone = 9 * 3600;
int dst = 0;
time_t now = time(nullptr);
struct tm* p_tm = localtime(&now);
String tDay = String(p_tm->tm_mday);
String tMon = String(p_tm->tm_mon + 1);
String tYear = String(p_tm->tm_year + 1900);
String tHour = String(p_tm->tm_hour);
String tMin = String(p_tm->tm_min);
String tSec = String(p_tm->tm_sec);

String timeStamp; // = tDay +"-"+tMon +"-"+ tYear;// +" "+ tHour +":"+tMin+":"+tSec;

void printTime() {
  Serial.print((*p_tm).tm_mday);
  Serial.print("/");
  Serial.print(p_tm->tm_mon + 1);
  Serial.print("/");
  Serial.print(p_tm->tm_year + 1900);
  Serial.print(" ");
  Serial.print(p_tm->tm_hour);
  Serial.print(":");
  Serial.print(p_tm->tm_min);
  Serial.print(":");
  Serial.println(p_tm->tm_sec);
  String timeStamp = tDay + "-" + tMon + "-" + tYear; // +" "+ tHour +":"+tMin+":"+tSec;
  // Serial.println(timeStamp);
  Serial.println(formattedTime);
  Serial.print(time(nullptr));
}

uint32_t x = 0;
unsigned long timeEP = millis();
unsigned long timeOld = timeEP;
unsigned long timeIOA = millis();
unsigned long timeOldIOA = timeIOA;

/************************* Firebase Setup *********************************/
// Generate Temperatuer feed name based on MAC address
String    feedName;              //use for Firebase
String    feedNameTemp;
String    feedNameHyum;
char      CharfeedName[20];      //use for MQTT
char      CharfeedNameTemp[20];
char      CharfeedNameHyum[20];

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883                   // use 8883 for SSL
#define AIO_USERNAME    "XXX"     // enter your user name
#define AIO_KEY         "XXX" // enter your Key

/********************* Wifi Manager Setting  *********************************/
String        getSSID();
String        getPassword();

bool shouldSaveConfig = false;
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}
void setConfigPortalBlocking(boolean shouldBlock);
WiFiManagerParameter custom_text("<p>Select your home-network, enter password and press [save]. Then continue with the other Units.</p>");

/************ Global State (you don't need to change this!) ******************/

// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;
// or... use WiFiFlientSecure for SSL
//WiFiClientSecure client;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

/****************************** Feeds ***************************************/

// Setup mqtt feed for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
Adafruit_MQTT_Publish swUpgradeCompleat = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME CharfeedName );
Adafruit_MQTT_Publish temperature = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME CharfeedNameTemp );
Adafruit_MQTT_Publish hyumidity = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME CharfeedNameHyum );

// Setup a feed called by mac-address for subscribing to changes.
Adafruit_MQTT_Subscribe softwareUpgrade = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME CharfeedName, MQTT_QOS_1);

/*************************** Random voids for Sketch Code ************************************/

void MQTT_connect();

/************************* Get Time  *********************************/

String getTime() {
  WiFiClient client;
  while (!!!client.connect("google.com", 80)) {
    Serial.println("connection failed, retrying...");
  }

  client.print("HEAD / HTTP/1.1\r\n\r\n");
  while(!!!client.available()) {
     yield();
  }

  while(client.available()){
    if (client.read() == '\n') {    
      if (client.read() == 'D') {    
        if (client.read() == 'a') {    
          if (client.read() == 't') {    
            if (client.read() == 'e') {    
              if (client.read() == ':') {    
                client.read();
                String theDate = client.readStringUntil('\r');
                client.stop();
                return theDate;
              }
            }
          }
        }
      }
    }
  }
}

/************************* gettingdata from SHT30 and putting in io.Adafruit *********************************/

void SHTGet()  {

  if (sht30.get() == 0) {
    ////Temperature in Celsius :
    initDisplay();
    display.setTextSize(1);
    display.print("T: ");//display.println("T: ");
    display.setTextSize(1);//2
    display.println(sht30.cTemp);
    //----
    Serial.print(F("\nSending temperature val "));
    Serial.println("");
    //Serial.println(getTime() );
    //Serial.println(formattedTime);
    Serial.println(sht30.cTemp);
    temperature.publish(sht30.cTemp);
    time(nullptr);

    ////hyumidity in rH :
    display.setTextSize(1);
    display.print("H: ");// display.println("H: ");
    display.setTextSize(1);//2
    display.println(sht30.humidity);
    display.println(WiFi.localIP());
    display.println(WiFi.macAddress());

    //----
    Serial.print(F("\nSending hyumidity val "));
    Serial.println("");
    Serial.println(sht30.humidity); 
    hyumidity.publish(sht30.humidity);
    // update value
    //    Serial.println(timeStamp);
    display.display();
    //    delay(10);
  }
}

/************************* Update Software *********************************/

void firmwareUpdate() {
  delay(100);
  Serial.println("Updating...");
  swUpgradeCompleat.publish("Updating...");
  t_httpUpdate_return ret = ESPhttpUpdate.update("XXX"); //enter path to file location


  switch (ret) {
    case HTTP_UPDATE_FAILED:
      swUpgradeCompleat.publish("FAILED");
      Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
      swUpgradeCompleat.publish("FAILED");
      break;

    case HTTP_UPDATE_NO_UPDATES:
      swUpgradeCompleat.publish("HTTP_UPDATE_NO_UPDATES");
      Serial.println("HTTP_UPDATE_NO_UPDATES");
      swUpgradeCompleat.publish("HTTP_UPDATE_NO_UPDATES");
      break;

    case HTTP_UPDATE_OK:
      swUpgradeCompleat.publish("done");
      Serial.println("HTTP_UPDATE_OK");
      swUpgradeCompleat.publish("done");
      break;
  }
}

/************************* MQTT Connect *********************************/

void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }
  Serial.print("");
  Serial.print("Connecting to MQTT... ");

  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);  // wait 5 seconds
    return;
  }
  Serial.println("MQTT Connected!");
}

/************************* Initializing Display *********************************/
void initDisplay() {
  // Clear the buffer.
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.setTextColor(WHITE);
}

void setup() {
  Serial.begin(115200);
  delay(10);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  initDisplay();
  // --------------------------------------------------------------------------------------------------
  wifiManager.addParameter(&custom_text);
  wifiManager.setConfigPortalBlocking(false);
  WiFi.begin(wifiManager.getConfigPortalSSID().c_str(), wifiManager.getPass().c_str());
  if (wifiManager.autoConnect("TempHyumSensMod")) {
    Serial.println("connected...yeey :)");
    WiFi.begin(wifiManager.getConfigPortalSSID().c_str(), wifiManager.getPass().c_str());
  }
  else {
    Serial.println("Configportal running");
  }
  WiFi.begin(wifiManager.getConfigPortalSSID().c_str(), wifiManager.getPass().c_str());
  Serial.println("WiFi connected");
  Serial.println("IP address: "); Serial.println(WiFi.localIP());
  // --------------------------------------------------------------------------------------------------
  //printTime();
  // confirm successful SW-upgrade via MQTT subscription.
  swUpgradeCompleat.publish("done");
  // Setup MQTT subscription for onoff feed.
  softwareUpgrade.setCallback(softwarecallback);
  mqtt.subscribe(&softwareUpgrade);
  // --------------------------------------------------------------------------------------------------
  Serial.println("WiFi connected");
  Serial.println("MAC address: ");
  WiFi.macAddress(mac);
  Serial.print("MAC: ");
  Serial.print(mac[5], HEX);
  Serial.print(":");
  Serial.print(mac[4], HEX);
  Serial.print(":");
  Serial.print(mac[3], HEX);
  Serial.print(":");
  Serial.print(mac[2], HEX);
  Serial.print(":");
  Serial.print(mac[1], HEX);
  Serial.print(":");
  Serial.println(mac[0], HEX);
  // --------------------------------------------------------------------------------------------------
  //Starting Interrupt
  attachInterrupt(PWM_IN, RiseTime, CHANGE);

}// Setup

/********************************************* Loop ******************************************************/

void loop() {
  wifiManager.process();
  FirebaseFeedName();
  timeEP = millis() - timeOld;
  timeIOA = millis() - timeOldIOA;
  if (timeEP >= 1000) {
    timeOld = millis();
    PWM_Output(); // Reads PWM Input and Give Output based on a fixed array
    if (WiFi.status() == WL_CONNECTED && mqtt.connected()) {
      FirebaseFeed();
    }
  }

  if (timeIOA >= 60000) {
    timeOldIOA = millis();
    if (WiFi.status() == WL_CONNECTED && mqtt.connected()) {
      SHTGet();
    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    MQTT_connect();
  }

  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(5000))) {
    if (subscription == &softwareUpgrade) {
      Serial.print(F("Got: "));
      Serial.println((char *)softwareUpgrade.lastread);
      if (strcmp((char *)softwareUpgrade.lastread, "ON") == 0) {
        firmwareUpdate();
      }
    }
    if (subscription == &OuterTemperature) {
      Serial.print(F("OT Got: "));
      Serial.println((char *)OuterTemperature.lastread);
      if (strcmp((char *)OuterTemperature.lastread, "ON") == 0) {
        Outertemperature();
      }
      delay(1000);
    }
  }
} // Loop


```


##プロジェクトの実現
大量でセンサーモジュールの作成して
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262129/ada7d6d6-3a9a-4fef-e8d0-044b06e80574.png)
住宅に配置して各部屋及び外気の変換を測定する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262129/40297c69-ab10-9939-d60f-0c0d42330320.png)
各データを一つのグラフに同時表示する。 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262129/745ae2f5-9a51-a013-3717-5a412ab052ed.png)
continue will follow...