從ESP8266連結Node.js並傳送JSON數據

本單元旨在補充《超圖解物聯網IoT實作入門》第12章「讓NodeMCU扮演網路前端上傳資料(IFTTT)」單元。IFTTT網站在2016年底做了小改版原本的Recipe(方案)改名成Applet(小程式)、channel(管道)改成service(服務)。IFTTT的Maker服務看似不受影響,原有的觸發(trigger)連結仍可運作,只是之前設定的Gmail信箱沒有送出通知郵件,而且我也無法進入如12-41頁所示的參數設定畫面。

IFTTT的Maker服務

使用Node.js建立一個接收來自NodeMCU(ES8266微控制板)前端傳入的JSON資料,並且把資料透過e-mail轉寄的伺服器端程式。在IFTTT的問題修復之前,讀者可以先用此程式進行實驗。當然,你也可以把此Node.js程式佈署在家裡的小電腦(自建雲)或者像Heroku, koding,…等,支援Node.js的web hosting(網站主機)或雲端運算平台。

本單元程式修改自第三章「接收與處理POST資料」,以及第六章「透過Node傳送電子郵件」單元,解析JSON資料的Node.js程式,請參閱「從Arduino透過POST方法傳遞JSON資料給Node.js伺服器程式的補充說明」這一篇貼文。

Node.js + NodeMCU (ESP8266) + Gmail

接收與解析POST傳送的JSON數據的Node.js程式

底下是此Node.js程式需要使用的套件,請先在你的node程式資料夾新增一個如下內容的package.json檔,再透過npm進行安裝:

{
  "name": "email-node",
  "version": "0.0.1",
  "dependencies": {
  "nodemailer": "^0.7.1",
  "express": "^4.12.0",
  "body-parser": "^1.12.3"
  }
}

Node.js(伺服器端)程式碼如下,筆者把接收JSON數據的路徑設置成“/json”:

var express = require("express");
var bodyParser = require("body-parser");
var nodemailer = require('nodemailer');
var app = express();

var transporter = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
        user: '你的gmail帳號',
        pass: '你的gmail密碼'
    }
});

// 寄送信件的函式,接收溫度和濕度兩個函式。
function sendMail(temp, humid) {
  // 郵件訊息設定
  var mailOptions = {
from: '寄信人(你)的gmail',
    to: '收信人的e-mail',
    subject: '物聯網裝置事件觸發了',
    html: '<p>溫度:' + temp + '</p>' +
          '<p>濕度:'+ humid + '</p>'
  };

  // 寄送信件
  transporter.sendMail(mailOptions, function(error, info){
    if(error){
      return console.log(error);
	  }
  });
}

app.use(bodyParser.urlencoded({ extended: true }));

app.use(bodyParser.json());       // 解析POST參數的JSON資料

app.post('/json',function(req,res){   // JSON資料的處理程式
  var json=req.body;   // 取出POST資料本體
  var temp = json.temp;
  var humid = json.humid;

  console.log("溫度:" + temp);   // 在控制台顯示溫度值
  console.log("濕度:" + humid);  // 顯示濕度值

  sendMail(temp, humid);
  res.send('data captured!');     // 傳回訊息(網頁)給用戶端
});

app.get('*', function(req, res) {
  res.status(404);
  res.send('找不到網頁!');
});

app.listen(5438, function(req, res) {
  console.log("網站伺服器在5438埠口開工了!");
});

筆者把上面的Node.js程式命名成ifttt.js儲存

以POST方法傳送JSON數據的NodeMCU程式

修改12-44頁的IFTTT自訂函式,把原本連結IFTTT的URL路徑和埠號,改成Node.js程式的主機路徑和埠號,GET方法也改成POST。請將其中的“192.168.1.19”改成你自己的Node.js主機IP位址。

void IFTTT() {
http.begin("192.168.1.19", 5438, "/json");   // 請自行修改IP位址
  :
int httpCode = http.POST("{\"temp\":22, \"humid\":56}");
  :
}

修改完畢後,編譯並上傳到NodeMCU控制板。

從NodeMCU連結Node.js

先執行Node.js程式,再按下NodeMCU控制板上的“FLASH”按鈕,Node.js將顯示如下的溫濕度值,並且透過Gmail送出郵件通知:

Node.js程式執行結果

NodeMCU也將在Arduino的序列埠監控視窗,顯示如下的回應:

序列埠監控視窗

如果在執行過程中,Node.js回應如下的錯誤訊息,代表Gmail的帳號密碼設定錯誤:

{ [Error: Invalid login]
  code: 'EAUTH',
  response: '535-5.7.8 Username and Password not accepted. Learn more at\n535 5.7.8 https://support.google.com/mail/?p=BadCredentials y67sm26.96 - gsmtp',
  responseCode: 535 }

請參閱第五章「啟用Gmail的兩步驟認證寄送郵件」單元,設定Gmail帳號。

延伸閱讀

Posts created 467

6 thoughts on “從ESP8266連結Node.js並傳送JSON數據

  1. 老師您好 請問int httpCode = http.POST(“{\”temp\”:22, \”humid\”:56}”)這段程式,怎麼把傳送資料作為變數來使用

    1. 你可以宣告一個String類型的變數,即可在其中儲存、連結字串和數字。

      thanks,
      jeffrey

  2. 老師您好:
    最近在練習您寫的超圖解物聯網IoT實作入門,我用的板子是nodeMCU。
    我正在實驗從nodeMCU透過POST發出json數據給我架設的node js伺服器。
    我碰到的問題是,node js伺服器接收到下面的 POST方法1傳出的資料的溫溼度都在console顥示undefiend。
    若改用POST方法2 則讀取到的值都正常。
    我想請問老師原因出在哪呢?
    謝謝老師

    // POST方法1
    client.println(“POST /temp HTTP/1.1”);
    client.println(“Content-Type: application/json”);
    client.print(“Conten-Length: “);
    client.println(jsonStr.length());
    client.println();
    client.print(jsonStr);

    // POST方法2
    http.begin(IoTServer,IoTPort,”/temp”);
    http.addHeader(“Content-Type”,”application/json”);
    int httpCode = http.POST(jsonStr);

    1. 應該”Conten-Length: “拼寫錯誤吧:
      “Content-Length: ”
      直接使用書本範例的POST方法即可。

      thanks,
      jeffrey

  3. 老師您好,我之前有提出希望能透過nodencu將讀取到的數值傳到雲端上再傳回序列埠監控視窗的問題,我看到老師的這篇文章內容已經接近了我所想的,node.js讀取到數值了以後會回傳一個字串給序列埠監控視窗表示已經讀取到了,是不是代表我也可以把node.js讀取到的值回傳給序列埠監控視窗,另外想請問如果以上的想法做得到,從nodemcu讀取到數值至傳數值到序列埠監控視窗會需要很久的延遲時間嗎?我希望不要超過10秒

    1. 可以辦到,從node.js接收網路前端資料轉發到序列埠,瞬間就完成了。

      thanks,
      jeffrey

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top