利用Arduino+Nodejs制作實時溫度監測警告器

這個專案是利用 Node.js 來做 Back-end Server 負責接受和處理 Arduino 傳來的資訊.  用作記錄和顯示最後溫度資訊及發出提示郵件.
在 Arduino 則駁上溫度濕度模組 AM2302 (DHT22) 再加上WIFI模組 ESP8266 來做將溫度濕度資料上傅到我們的 Back-end Server.

Node.js

安裝 Node.js

我們將會用到相關模組

  • nodemailer (用來發送email)
  • url
  • query-string

這些模組可以利用 npm 指令下載下來.

安裝好 Node.js 之後, 首先可以開一個資料夾來準備放置我們整個專案.

利用 npm init

npm init

去初始化 package.json, 來方便日後安裝不同模組作記錄和方便部署去不同地方 (例如 Azure, Google Cloud, Heroku 這些 Cloud Server).

如上圖顯示會一步步要你輸入相關名稱,介紹等等, 跟著打上就可以了.

接著我們可以先下載定我們所用到的模組


好了, 前置都準備好了.
我都準備 Source code 給大家.
原檔連結  , 你都可以到我 Github 上下載整個 Project

var http = require('http');
var url = require('url');
var querystring = require('querystring');
var port = 3000;
var server;
var token = "P7zlANXN30KXQHaDzzjorQ=="; // token for 

var latestUpdateTime = "";
var currentTemp = "1";
var currentHum = "1";

var emailAddress = "<EMAIL>";
var tempWarning = 40;
var humWarning = 90;

var saveJson = false;
var saveJsonPath = "C:\\data.json";

var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
      user: '<YOUR GMAIL ACCOUNT>',
      pass: '<YOUR GMAIL PASSWORD>'
    }
  });

server = http.createServer((req, res) => {
    console.log("Request from " + req.connection.remoteAddress);
    var body = "";
    var q = url.parse(req.url, true);
    var data = q.query;

    if (token == data.token && data.temp && data.hum) {
        latestUpdateTime = new Date();
        currentTemp = data.temp;
        currentHum = data.hum;

        console.log("Updated.");
        console.log(">" + data.temp + "C " + data.hum + "% @ " + latestUpdateTime );        

        if(currentTemp >= tempWarning)
        {
            SendEmail("[TemperatureMonitor] Temperature Warning", "Temperature : " + currentTemp + " @ " + latestUpdateTime);
        }
        if(currentHum >= humWarning)
        {
            SendEmail("[TemperatureMonitor] Humidity Warning", "Humidity : " + currentHum + " @ " + latestUpdateTime);
        }

        if(saveJson)
        {
            SaveAsJson();
        }
    }

    req.on('data', function (chunk) {
        body += chunk;
    });

    req.on('end', function () {
        body = querystring.parse(body);
        res.statusCode = 200;
        if (data.format == "json") {
            res.setHeader('Content-Type', 'application/json;charset=utf8');
            res.write("{");
            res.write("\"key\":\"1\",\"label\":\"Server\",");
            res.write("\"temp\":\"" + currentTemp + "\",\"hum\":\"" + currentHum + "\",\"date\":\"" + latestUpdateTime + "\"");
            res.write("}");
            res.end("");
        }
        else {
            res.setHeader('Content-Type', 'text/html;charset=utf8');
            res.write("<html><head><title>Temperature Monitor</title></head><body>")
            res.write("== Temperature Monitor ==");
            res.write("<br>");
            res.write("TEMPERATURE : " + currentTemp + "<br> HUMIDITY : " + currentHum + "% <br> " + latestUpdateTime + "<br>");
            res.write("</body></html>");
            res.end("");
        }
    });
});

server.listen(port, () => {
    console.log('Listening on port ' + port);
});

function SendEmail(subject, text)
{
    var mailOptions = {
        from: '"Temperature Monitor" <[email protected]>',
        to: emailAddress,
        subject: subject,
        text: text
      };
      
      transporter.sendMail(mailOptions, function(error, info){
        if (error) {
          console.log(error);
        } else {
          console.log('Email sent: ' + info.response);
        }
      });    
}

function SaveAsJson()
{
    var jsondata = "{" + "\"key\":\"1\",\"label\":\"Server\"," + "\"temp\":\"" + currentTemp + "\",\"hum\":\"" + currentHum + "\",\"date\":\"" + latestUpdateTime + "\"}";
    var fs = require('fs');
    fs.writeFile(saveJsonPath, jsondata, function(err) {
        if(err) {
            return console.log(err);
        }
        console.log("Saved.");
    });     
}

直接用的話都要設定一下 Server Port, email account

以下是定義我們所用到的 Port 和給 Aruino 利用的 token 
點解會用做token都是想只有我們知道token的人才可以更新資訊

var port = 3000; 
var token = "P7zlANXN30KXQHaDzzjorQ==";

Nodemailer 是可以利用 gmail 來做 email 發信者.
(建議開一個新的gmail來使用)
注意要在gmail設定允許低安全性應用程式存取您的帳戶
所以我們只要set好相關帳號資料就可以.

      user: '<YOUR GMAIL ACCOUNT>',
      pass: '<YOUR GMAIL PASSWORD>'

還有我們要設定要提示發送給那個 email ,
這裡修改設定溫度超過40度或濕度超過90就會發出提示.

var emailAddress = "<EMAIL>";
var tempWarning = 40;
var humWarning = 90;

設定好就可以嘗試運行, 在cmd輸入

node main

如果成功見到 Listening on port  3000
證明已經成運行, 你用瀏覽器上 http://localhost:3000 會見到溫度頁面

Arduino

希望你已經基本 Arduino 知識, 認識用 Arduino IDE 去上載到 Arduino 上運行

新手都不用怕上官網下載 IDE , 不過駁線可以爬一下GOOGLE

接駁 ESP8266 (WIFI模組) 到 Arduno

Esp8266 | Arduino 
-----------------
     RX | 10  
     TX | 11   
    GND | GND
    VCC | 3.3v    
  CH_PD | 3.3v    
 GPIO 0 | None   
 GPIO 2 | None 

接駁 AM2302 (溫度濕度模組) 到 Arduno

AM2302  | Arduino 
-----------------
    GND | GND
    VCC | 3.3v    
   DATA | 7

接駁好後就可以去 Arduino IDE 上傅程序到 Arduino 上.

設定每30秒間隔問 AM2302 拿現時溫度濕度資訊.
再經 ESP8266 調用 AT COMMAND 來發送 WIFI 連接和發送資料.

Source code 已經準備好給大家

原檔連結  , 你都可以到我 Github 上下載整個 Project

#include <SoftwareSerial.h>
#include <DHT.h>;

#define RX 10
#define TX 11
String AP = "<YOUR WIFI SSID>";
String PASS = "<YOUR WIFI PASSWORD>";
String token = "P7zlANXN30KXQHaDzzjorQ==";
String HOST = "<YOUR URL>";
String PORT = "3000";
float updateInterval = 30000;
SoftwareSerial esp8266(RX, TX);

#define DHTPIN 7     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino
float temp = 0;
float hum = 0;

void setup() {
  Serial.begin(9600);
  esp8266.begin(115200);
  esp8266.println("AT");
  esp8266.println("AT+CWMODE=1");
  esp8266.println("AT+CWJAP=\"" + AP + "\",\"" + PASS + "\"");
  dht.begin();
}

unsigned long lastTimeMillis = 0;
void printResponse() {
  while (esp8266.available()) {
    Serial.println(esp8266.readStringUntil('\n')); 
  }
}

void loop() {
  if (millis() - lastTimeMillis > updateInterval) {
    lastTimeMillis = millis();

    esp8266.println("AT+CIPMUX=1");
    delay(1000);
    printResponse();

    esp8266.println("AT+CIPSTART=4,\"TCP\",\"" + HOST + "\"," + PORT + "");
    delay(1000);
    printResponse();

    temp = dht.readTemperature();
    hum = dht.readHumidity();
    String cmd = "GET /?token=" + token + "&temp=" + String(temp) + "&hum=" + String(hum) + " HTTP/1.1";
    esp8266.println("AT+CIPSEND=4," + String(cmd.length() + 4));
    delay(1000);

    esp8266.println(cmd);
    delay(1000);
    esp8266.println(""); 
  }

  if (esp8266.available()) {
    Serial.write(esp8266.read());
  }
}

你只要設定好 WIFI SSID, WIFI 密碼,
HOST 是指 Node.js 的伺服器 IP, Token 則是剛才在 Node.js 上設定的那個.
完成之後你就可以去 http://localhost:3000 觀望變化.

這裡有我完成正在運行的頁面, 有興趣去看看

參考

Using the ESP8266 WiFi Module with Arduino Uno publishing to ThingSpeak

api_get-request_at-commands.ino

Node.js Email

發佈回覆

你的電郵地址並不會被公開。 必要欄位標記為 *

This site uses Akismet to reduce spam. Learn how your comment data is processed.