延續上一篇文章的說明,本文將使用ESP8266控制板(如:NodeMCU或Wemos D1 mini),經由Wi-Fi網路和MQTT協定傳送DHT11的溫濕度值到ThingSpeak雲端平台。底下是本文的硬體接線:
使用ESP8266控制板發布MQTT訊息的程式架構,和Arduino乙太網路程式相似,同樣採用PubSubClient程式庫(參閱《MQTT教學(六):使用PubSubClient程式庫開發Arduino MQTT應用》);兩者程式架構不同之處如下圖裡的紅字,登入ThingSpeak網站需要輸入使用者名稱和密碼。
發布MQTT主題訊息的ESP8266 Arduino程式
程式開頭首先宣告一些變數,DHT11溫濕度感測器沿用書本裡的程式庫:
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <dht11.h> #define DHT11PIN 5 // DHT11資料接腳 const char* ssid = "你的Wi-Fi網路名稱"; const char* password = "你的Wi-Fi網路密碼"; const char* mqttServer = "mqtt.thingspeak.com"; // MQTT伺服器位址 const char* mqttUserName = "cubie"; // 使用者名稱,隨意設定。 const char* mqttPwd = "你的MQTT API Key"; // MQTT密碼 const char* clientID = "yard001"; // 用戶端ID,隨意設定。 const char* topic = "channels/頻道ID/publish/你的寫入API KEY"; unsigned long prevMillis = 0; // 暫存經過時間(毫秒) const long interval = 20000; // 上傳資料的間隔時間,20秒。 String msgStr = ""; // 暫存MQTT訊息字串 int temp; // 暫存溫度 int hum; // 暫存濕度
底下是建立設定Wi-Fi連線的自訂函式:
void setup_wifi() { delay(10); WiFi.begin(ssid, password); // 連接到Wi-Fi基地台 // 如果尚未連上Wi-Fi,則每隔0.5秒顯示一個‘.’。 while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); // 顯示「Wi-Fi已連線」 }
連結MQTT伺服器的reconnect()自訂函式,要加入使用者名稱和密碼:
完整的程式碼如下,請自行修改必要的參數:
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <dht11.h> #define DHT11PIN 5 // DHT11資料接腳 const char* ssid = "你的Wi-Fi網路名稱"; const char* password = "你的Wi-Fi網路密碼"; const char* mqttServer = "mqtt.thingspeak.com"; // MQTT伺服器位址 const char* mqttUserName = "cubie"; // 使用者名稱,隨意設定。 const char* mqttPwd = "你的MQTT API Key"; // MQTT密碼 const char* clientID = "yard001"; // 用戶端ID,隨意設定。 const char* topic = "channels/頻道ID/publish/你的寫入API KEY"; unsigned long prevMillis = 0; // 暫存經過時間(毫秒) const long interval = 20000; // 上傳資料的間隔時間,20秒。 String msgStr = ""; // 暫存MQTT訊息字串 int temp; // 暫存溫度 int hum; // 暫存濕度 WiFiClient espClient; PubSubClient client(espClient); dht11 DHT11; void setup_wifi() { delay(10); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); } void reconnect() { while (!client.connected()) { if (client.connect(clientID, mqttUserName, mqttPwd)) { Serial.println("MQTT connected"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); // 等5秒之後再重試 } } } void setup() { Serial.begin(9600); setup_wifi(); client.setServer(mqttServer, 1883); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); // 等待20秒 if (millis() - prevMillis > interval) { prevMillis = millis(); // 讀取DHT11的溫濕度資料 int chk = DHT11.read(DHT11PIN); if (chk == 0) { temp = DHT11.temperature; hum = DHT11.humidity; } // 組合MQTT訊息;field1填入溫度、field2填入濕度 msgStr=msgStr+"field1="+temp+"&field2="+hum; // 宣告字元陣列 byte arrSize = msgStr.length() + 1; char msg[arrSize]; Serial.print("Publish message: "); Serial.println(msgStr); msgStr.toCharArray(msg, arrSize); // 把String字串轉換成字元陣列格式 client.publish(topic, msg); // 發布MQTT主題與訊息 msgStr = ""; } }
編譯並上傳程式到ESP8266控制板,它將每隔20秒上傳溫濕度資料到你的ThingSpeak通道。
請問在Node-RED mqtt broker server 可以自定設定 username 、 password 、server port
來源:https://flows.nodered.org/node/node-red-contrib-mqtt-broker
在 pubsubclient.h 裡面有 boolean connect(const char* id, const char* user, const char* pass);
可以由 Arduino 直接傳送 clientID、username、 password 字串嗎?
資料來源:
https://pubsubclient.knolleary.net/index.html
可是只要加上 username 、 password Arduino Connect .. 就斷線
拍謝,我沒有使用Node-RED,但我相信它肯定有支援MQTT帳號密碼設置。
thanks,
jeffrey
插画不错,请问用什么软件画的?
谢谢,我是用Adobe Flash(现已改名Animate) 软件,搭配鼠标(偶尔用第一代微软Surface Pro平板的Wacom笔)徒手绘制的。
thanks,
jeffrey
我跟隨了你上面的所有做法 是用得了的
可是我的DHT 出來的溫度濕度 不知道為什麼不怎麼動,我吹氣或者用電腦的發熱都改變不了數值,
過了一段時間才會有一些的變化(就幾度) ,是因為那20S出來的數值DELAY?
但我用點arduino uno 就完全沒問題,我這Wemos 用其他功能也是沒問題
請問會不會是我的板子有問題? 還是其他問題?
赵老师,你好!
请问Thingspeak平台现在登录是不是有问题?
我注册了但总登录不上去。
谢谢!
剛才測試登入沒問題~
thanks,
jeffrey
請問如果我想讓nodemcu讀到的數值傳到arduino的序列埠監控視窗要如何辦到?我希望用vb讀取序列埠監控視窗的數值
執行 Serial.print(資料) 或 Serial.println(資料) 即可。
thanks,
jeffrey
sorry,老師我沒表達清楚,我是想讓nodemcu用wifi無線的方式傳到序列埠監控視窗,懇請指點 : )
「用wifi無線的方式傳到序列埠監控視窗」,我猜想你的意思是:
從nodemcu透過wi-fi,傳遞資料給某個裝置(如:PC),該裝置再將接收到的資料輸出到序列埠。
你可以在兩端寫個網路socket程式,互傳訊息,或者用HTTP前端和後端的概念,以nodemcu當前端,電腦上執行HTTP伺服器程式接收資料,再轉發到序列埠。
thanks,
jeffrey
老師 請問
最近剛學習ESP8266 ,要傳到Thingspeak,已經可以順利傳上去了,
但是不知道要怎麼做才能使用另外一塊ESP8266去Thingspeak上讀取數值
上傳的程式是這樣
if (client.connect(server,80)) // “184.106.153.149” or api.thingspeak.com
{
String postStr = apiKey;
postStr +=”&field1=”;
postStr += String(t);
postStr +=”&field2=”;
postStr += String(h);
postStr +=”&field3=”;
postStr += String(BPM);
postStr += “\r\n\r\n”;
client.print(“POST /update HTTP/1.1\n”);
client.print(“Host: api.thingspeak.com\n”);
client.print(“Connection: close\n”);
client.print(“X-THINGSPEAKAPIKEY: “+apiKey+”\n”);
client.print(“Content-Type: application/x-www-form-urlencoded\n”);
client.print(“Content-Length: “);
client.print(postStr.length());
client.print(“\n\n”);
client.print(postStr);
但是使用另一塊板子讀取時,我改成這樣
client.print(“GET /channels//1.json?&results=2 HTTP/1.1\n”);
client.print(“Host: api.thingspeak.com\n”);
client.print(“Connection: close\n”);
client.println();
while (client.available() == 0);
unsigned long lastRead = millis();
while (millis() – lastRead < 2000) {
while (client.available()) {
Serial.print(client.read());
lastRead = millis();
}
}
在序列埠監控視窗會出現一大串數字,不知道要怎麼修改才能得到我要的每個Field的值
先謝謝老師
你有先嘗試使用MQTTLens訂閱MQTT訊息嗎?
訂閱ThingSpeak MQTT主題的API語法格式為:channels/頻道ID/subscribe/格式/你的讀取API KEY
相關說明請參閱官網的Subscribe to a Channel Feed說明。
thanks
jeffrey
請問老師您有連過AWS IOT嗎?
AWS IOT 連線據我所知只支援憑證認證,請問老師知不知道有甚麼支援憑證認證的Library
抱歉,我沒用過AWS IOT。
thanks,
jeffrey
請問老師,可以將nodemcu的資料上傳至mcs嗎?
程式的寫法,是不是跟Thingspeak類似?
程式概念都一樣,只是API要查閱說明。
thanks,
jeffrey
請問老師要怎麼把keypad的值上傳至mcs上,序列埠有出現值,但網站上卻沒有?
#include
#include
#include
const char* ssid = “EE420”;
const char* password = “xxxxxx”;
const char* mqttServer = “mqtt.mcs.mediatek.com”; // MQTT伺服器位址
const char* mqttUserName = “nodemcu”; // 使用者名稱,隨意設定。
const char* mqttPwd = “J0Gsxxxxxx”; // MQTT密碼
const char* clientID = “nodemcu”; // 用戶端ID,隨意設定。
const char* topic = “channels/nodemcu/publish/DUCADaW9”;
unsigned long prevMillis = 0;
const long interval = 500;
String msgStr = “”;
#define n_rows 4
#define n_cols 4
char keys[n_rows][n_cols] = {
{‘1′,’2′,’3’},
{‘4′,’5′,’6’},
{‘7′,’8′,’9’},
{‘-‘,’0’}
};
byte colPins[n_rows] = {D3, D2, D1, D0};
byte rowPins[n_cols] = {D7, D6, D5, D4};
Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, n_rows, n_cols);
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“.”);
}
Serial.println(“”);
Serial.println(“WiFi connected”);
}
void reconnect() {
while (!client.connected()) {
if (client.connect(clientID, mqttUserName, mqttPwd)) {
Serial.println(“MQTT connected”);
} else {
Serial.print(“failed, rc=”);
Serial.print(client.state());
Serial.println(” try again in 5 seconds”);
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqttServer, 1883);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
if (millis() – prevMillis > interval) {
prevMillis = millis();
char myKey = myKeypad.getKey();
if (myKey){
Serial.println(myKey);
}
msgStr=msgStr+”number=”+myKey;
byte arrSize = msgStr.length() + 1;
char msg[arrSize];
Serial.print(“Publish message: “);
Serial.println(msgStr);
client.publish(topic, msg);
msgStr = “”;
}
}
建議先上傳一個簡單的數值或字串測試連線程式是否正確執行,我沒用過mcs,煩請自行查閱相關API文件。
thanks,
jeffrey
老師您好 平常我使用THINGSPEAK後
會將數值至data import/export下方有一個下載CSV檔
但是我今日在用時發現他竟然改成要寄信過去他們那邊
這功能導致我無法對100筆之前的數值進行觀看
這是他們最近改的新功能嗎?如果想要再直接載成CSV檔的話要怎麼做呢
咦?我按底下的Data Export按鈕,可以選擇匯出JSON, XML或CSV;按右上角的連結才需要發送Channel ID和Read API Key給他們(我相信這只需要發送一次,由程式自動認可)。
thanks,
jeffrey
老師 感謝您的回覆
因實驗需要
我要下載的就是右上方的 而也只有右上方的才能匯出我全部的數值
您底下的那個可以下載 ,不過那個下載按鈕卻只有最後的100筆數值(沒記錯筆數的話)
而剛剛我試著寄信過去確的到這樣的回覆
{
Your mail message to the following address(es) could not be delivered.
This is a permanent error. Please verify the address(es) and try again.
:
The e-mail message could not be delivered because the user’s mailfolder is full.
}
他跟我說信箱已經爆炸了…
看來大家也都在嘗試寄信給他,寄到他的信箱都已經爆滿了…
在這特別感謝您願意回復 謝謝您
原來審核不是自動化的啊…這應該是最近才修改的政策,感謝告知!
請試試它的Read API Key,後面加上results參數;results參數預設值是100,底下的請求將能傳回最多前1000筆資料:
https://api.thingspeak.com/channels/你的通道ID/feeds.json?api_key=你的Read_API_Key&results=1000
thanks,
jeffrey
老師 您好
我之前都採用HTTP協定傳輸資料上去THINGSPEAK
近期看到您MQTT協定的寫法 最近也剛完成CODE
HTTP我可以上傳最多8組都沒什麼問題
MQTT模式目前測得最高上傳4組數值,超過後竟然莫名的不能上傳
剛剛前去您的MQTT協定介紹那邊觀看他最高上傳65536個字元
根據規定我也沒超過 想請問一下這個狀況還有甚麼可能性呢
下方是我愈的字串
msgStr=msgStr+”field1=”+temp1+”&field2=”+temp2+”&field3=”+temp3+”&field4=”+temp4+”&field5=”+temp5+”&field6=”+temp6+”&field7=”+temp7+”&field8=”+temp8
你有用MQTTLens測試過嗎?我之前上傳6個欄位資料沒問題。
thanks,
jeffrey
老師 您好
剛剛使用MQTTLens教學操作發現到我竟然是使用頻道內之APIKEY 故而按照您的教學前往申請一MQTT APIKEY
不過這時卻發現不管怎麼使用都會失敗,在無他法的情況改成頻道內APIKEY竟然意外成功了,且能傳8個值
這時改用ESP8266再次上傳仍然最多只能6個值,這還真令我覺得困惑。
另外上次跟您詢問的全部DATA下載之功能,目前ThingSpeak已經將之前的下載按鈕加回來了,特此通知一下
感謝告知!
thanks,
jeffrey
想請問如何在arduino 開發版上使用ESP8266,AT+CWMODE=3 狀況下,在thingspeak做上傳及下載
目前皆可以做到兩隻上下傳程式,但將兩組程式,整合共同使用,發現下載的副程式不能動
請參閱「燒錄與執行ESP8266 AT指令韌體/固件(二):連結與上傳資料到ThingSpeak網站」說明。
thanks,
jeffrey
第一次玩NodeMCU+DHT11,參考您的資料,受益良多。
發現一個方法,應該可以更省電的使用DHT11,可參考:
https://70tw.blogspot.com/2019/06/iot-dht11.html
比較好的省電方法是讓控制器進入睡眠模式。
thanks,
jeffrey
老師您好,我使用的程式是motoduino mqtt publish, 我想要把超音波感測器的數值上傳資料,但似乎不知道哪裡接錯了,想請問老師我該如何將感測器資料上傳呢?
請參閱上文先用簡單的數據上傳測試。
thanks,
jeffrey
請問您用的dht11.h是哪個函式庫啊? 搜尋dht相關的都安裝一輪了還是找不到XD
我是沿用《超圖解Arduino 互動設計入門》書本裡的dht11程式庫,你可以用其他程式庫,只要改一下讀取溫濕度的指令即可。
thanks,
jeffrey
請問程式中的MQTT密碼是指thingspeak的密碼嗎?
MQTT API Key,請參閱這篇貼文說明。
thanks,
jeffrey
老師您好,想請問3行程式碼:
const char* mqttUserName = “cubie”; // 使用者名稱,隨意設定
const char* clientID = “yard001”; // 用戶端ID,隨意設定
const char* topic = “channels/頻道ID/publish/你的寫入API KEY”;
使用者名稱以及用戶端ID是只要隨便打就好嗎? 需要按照thingspeak上面的甚麼去打嗎? 還是怎麼樣?
topic的部分是 channels或頻道ID或寫入的API KEY 其中選一個就好嗎?
謝謝老師
請參閱:
MQTT教學(八):使用MQTTlens上傳資料到ThingSpeak的MQTT伺服器
thanks,
jeffrey
請問老師我的序列埠有出現數值,但網站上卻沒有是哪裡有問題嗎?
#include
#include
#include “Timer.h”
#define random(num) (rand() % (num))
#define realtype float
#define NearZero 1.0e-10
#define MoreZero 1.0e-5
#define NearInfi 1.0e10
#define LessInfi 1.0e5
#define pi 3.141592654
uint8_t DACH[]={25, 26};
uint8_t ADCH[]={32, 33, 34, 35, 36, 39, 12, 13, 14, 25, 26, 27};
uint16_t AD_VAL[20];
#define PWM_LED 19
#define BLINK_LED 23
#define LED_BUILTIN 2
#define SERIAL_BAUDRATE 9600
Timer T;
uint32_t TS;
// Replace the next variables with your SSID/Password combination
//const char* ssid = “astrom_wifi”;
//const char* ssid = “astrom1211”;
const char* ssid = “00000000”;
const char* password = “00000000”;
// Add your MQTT Broker IP address, example:
const char* mqttServer = “mqtt3.thingspeak.com”; //ThingSpeak MQTT Server
const char* mqttUserName = “yu”;
//const char* mqttServer = “3.139.80.99”; // NOT WORK
const char* mqttPwd = “kSXyHw/tANI6Rg45SiW8/jpI”; //ThingSpeak MQTT API_Key
const char* clientID = “ExANOjkVFyYCGgcROAgUKwk”;
const char* mqttTopic = “channels/1712894/publish/8MU9ROL8UUQE1UR9”;
WiFiClient espClient;
PubSubClient client(espClient);
uint32_t lastMsg = 0;
char msg[50];
int value = 0;
TaskHandle_t Task[4];
void DaqTask(uint16_t dt)
{
static uint32_t Millis, Micros;
uint32_t nMillis, nMicros;
nMillis = millis();
uint16_t millis_ts = nMillis-Millis;
nMicros = micros();
uint16_t micros_ts = nMicros-Micros;
if (millis_ts>=dt) {
for (uint8_t i=0; i 15000) {
lastMsg = now;
for (uint8_t i=0; i<5; i++) {
msgStr += field[i]+String(AD_VAL[i]); // By "mqtt.thingspeak.com", ThingSpeak MQTT Server to upload datas
}
byte arrSize = msgStr.length() + 1;
char msg[arrSize];
Serial.print("Publish message: ");
Serial.println(msgStr);
msgStr.toCharArray(msg, arrSize);
client.publish(mqttTopic, msg);
}
vTaskDelay(1);
}