2015年3月15日 星期日

初遇 IoT ( Internet of Thing, 物聯網 ) - 使用 Arduino 控制 ESP8266 無線模組上傳資料到 IoT Server ( ThingSpeak )

網頁最後修改時間:2017/01/07
ThingSpeak 環境溫濕度記錄圖
網路是構成物聯網 ( IoT, Internet of Things ) 其中一項不可或缺的技術,而 IoT Server 就是用來蒐集並記錄由世界各地傳過來的數據資料,這些資料可以自己使用也可以分享給其他人做使用,這對於需要在世界各地蒐集資料的科學家或是程式設計師,善用這些資料可以加速其研究分析的工作,節省很多的時間。例如,對於科技農夫來說,可以蒐集整片土地上面各處土壤的溫溼度、光照程度在特定時間間隔的分佈狀態,以長時間的數據來分析影響土地上各植物的生長狀態的因素,幫助農夫可以做製程改善達到最大的產量輸出。當然,還有很多的應用,可以利用物聯網的方式來實現,而本篇網頁提出一個實際的例子來說明,如何使用賣場的 "ESP8266 IoT 入門學習套件" 每隔 60 秒傳送環境溫濕度到 IoT Server ( ThingSpeak ) 做紀錄。

*********************************************************************************
   物聯網,維基百科的解釋
*********************************************************************************
*********************************************************************************
此網頁所用的材料可自行準備,或選用新版本的升級套件
更多 ESP8266 相關商品,請至分類賣場
*********************************************************************************

我所使用的 IoT Server 是由 ThingSpeak 所提供,支援很多微處理器和控制器,也提供相對應的使用範例做為使用上的參考,上手很快也很方便。重點是:ThingSpeak 是開源的,可以下載並安裝在自己的電腦上做 IoT Server。

*********************************************************************************
Internet of Things - ThingSpeak

ThingSpeak 開放原始碼 - GitHub
ThingSpeak is an open source “Internet of Things” application and API to store and retrieve data from things using HTTP over the Internet or via a Local Area Network. With ThingSpeak, you can create sensor logging applications, location tracking applications, and a social network of things with status updates.
ThingSpeak 教學 - Tutorials

參考網頁:
  • ThingSpeak - Using an Arduino + Ethernet Shield to Update a ThingSpeak Channel
  • Instructable - ESP8266 Wifi Temperature Logger
    網頁主要是參考這篇文章裡的內容,作者給了很大的幫助!但是實際上,照著做並不能成功上傳資料,原因在於:(1) 作者的 ESP8266 韌體有可能是舊版的,或是已事先輸入幾個設定的 AT 指令進入模組,因為沒有出現在程式碼中,直接使用程式碼是無法正常上傳資料的;(2) 作者使用 3V3 的 Arduino 板子和 DS18B20 溫度感測器,線路是不一樣的,程式碼必須重新修改;(3) 作者使用單筆資料而非多筆資料同時上傳,這部分需要上 ThingSpeak 網站上面找一下資料。
*********************************************************************************

下面分為幾個步驟來實現溫溼度上傳到 IoT Server - ThingSpeak 的目的:
  • 申請一個 ThingSpeak 帳號
    .
  • 建立一個給 DHT11 使用的 Channel
    .
  • 取得剛剛建立的 ThingSpeak Channel 的( Write ) API KEY,並手動測試
    .
  • HTTP 方法:POST 和 GET
    .
  • 佈線電路圖說明
    .
  • 程式測試說明
Note:所有這網頁需要的資料全部都已經上傳到賣場雲端硬碟中,請至目錄中下載或是直接移至自己的雲端硬碟。
電路圖:ESP8266 IoT 入門學習套件 / schematics / Arduino_IoT_Demo
程式碼:ESP8266 IoT 入門學習套件 / codes / Arduino / IoT_demo


申請一個 ThingSpeak 帳號:

ThingSpeak 帳號申請很簡單,直接進入 ThingSpeak.com 主網頁點擊右上角的 Sign Up 連結進入註冊頁面。進入頁面後,依照欄位輸入相對應的資料,如下圖所示。
ThingSpeak 新帳號申請頁面

建立一個給 DHT11 使用的 Channel:

完成帳號申請之後,按下 Create Account 按鈕就會跳轉到下面的頁面,這時已經確認產生新的帳號,可以開始設定 Channel
ThingSpeak - My Channels 頁面

Channel Settings 的頁面中,要設定的只有三個地方
  • Name :Channel 的名稱,這裡請設定為 DHT11
  • Field 1:資料欄位的顯示名稱,請設定為 Temperature ( degC )
  • Filed 2:資料欄位的顯示名稱,請設定為 Humidity ( % )
ThingSpeak Channel Settings - 欄位名稱設定
這些設定的文字只是為了辨識輸入的資料欄位是代表什麼,實際從遠端輸入資料到 ThingSpeak IoT Server 時,資料欄位的輸入都是有固定的格式,程式設計師要知道的最重要的東西是這個 Channel 的 Write API Key 和 Read API Key,從遠端輸入資料時,就是傳送這個 API Key 給 ThingSpeak IoT Server,Server 才會知道這資料是屬於哪一個使用者的哪一個 Channel 的欄位資料;每一個 ThingSpeak 的 Channel 最多有 8 個 資料欄位。

輸入完畢後按下最下方的 Save Channel 按鈕儲存資料;另外,Clear Channel 按鈕是用來清除所有以記錄的資料,這等一下會用到,要記得清除資料是在這裡清除!


取得剛剛建立的 ThingSpeak Channel 的( Write ) API KEY,並手動測試:

在同樣的頁面,上方有一顆 API Keys 按鈕,按進去就會出現剛剛這個 Channel 的寫入的 API Key,將 Write API Key 先複製或是記下來,等一下測試會用到!
ThingSpeak - Channel's API Key
假設我們取得剛剛產生的 Channel 的 Write API Key 是 ALSKUJG6DR5PLODE,要設定的溫濕度分別是 25 度 C 與 75 %,那輸入的標準格式是

http://api.thingspeak.com/update?key=[THINGSPEAK_KEY]&field1=[溫度]&field2=[濕度]

根據我們所設定的溫度,則完整的輸入就會變成

http://api.thingspeak.com/update?key=ALSKUJG6DR5PLODE&field1=25&field2=75

打開瀏覽器,複製上面的資料 ( 記得換上自己的 Write API Key ),按下 Enter,若成功傳入資料到剛剛在 ThingSpeak 新增的 Channel,那麼就會在瀏覽器視窗收到 1
傳送測試的溫溼度資料到 ThingSpeak

到底資料傳進去了沒有,我們來確認一下!

同樣在 Channels 頁面下,按下 Private View 就會看到兩個趨勢圖 ( 方便顯示起見,我將下方的圖移到右邊 ),而顯示的結果與我們剛剛輸入的資料相同,這也就表示上面的輸入格式與資料都是正確的。
檢視測試輸入資料的結果
使用上面剛剛建立的資料輸入方式,只要更改 field1= 與 field2= 後面的數值,就可以將資料上傳到 ThingSpeak 所建立的 Channel 相對應的資料欄位中,容易吧!

這段建立的資料格式將會使用到 Arduino 程式碼中,負責將整段格式移交給 ESP8266 無線模組來處理。但是瀏覽器傳送時是使用 HTTP 的方法傳送,類似於我們在網頁輸入表單資料後,需要按下表單按鈕以傳送資料到伺服器去,伺服器再根據資料回傳給我們,所以並不是直接輸入上面的格式就可以。這就是我們下一段要討論的 HTTP Method:GET 和 POST 方法。


HTTP 方法:POST 和 GET

ThingSpeak 提供了使用 Arduino 配合有線網路模組的例子,傳送的 HTTP 方法是 POST,與上面所做測試的方法是不一樣的。因為使用 POST 是看不到傳送的欄位資料出現在瀏覽器的網址列中,所以在上面傳送資料的 HTTP 方法是使用 GET。

這兩種 HTTP 方法主要的不同在於,

GET:查詢字串 ( name / value pairs,名稱  / 值對 ) 是在 GET 請求的 URL 中發送的
  • 請求數據長度有限制
POST:查詢字串 ( name / value pairs,名稱 / 值對 ) 是在 POST 請求的消息主體中發送的
  • 請求數據長度沒有要求
上面只簡單列出跟網頁相關最重要的,其他的可參考 "淺談 HTTP Method:表單中的 GET 與 POST 有什麼差別?" 這篇網頁中的說明。

ThingSpeak 裡面所使用的例子是使用 POST 發送數據,會換成使用 GET 的方式是因為他的傳送格式簡單,只要一行就可以搞定;若是利用 POST 要傳送一堆標頭才能傳送本體 ( 資料放在此 ),有點浪費時間!尤其是在微處理機使用上,盡量簡單就好。等到那一天發現到這方法不適用時,再換成 POST 方式就好。


佈線電路圖說明:
IoT_Demo 電路圖 V0.2 - 包括 UART 除錯
測試時,Arduino 是直接插在筆電,與筆電通訊和供電,所有外部模組和零件所用到的,不管是 3V3 或是 5V電源都是來自 Arduino。雖然我這樣測試是正常的,但不代表其他人就會一樣!若出現問題,請先確認 ESP8266 無線模組所供應的電源是否在範圍內;簡單一點的方法就是換成套件中的電源模組做 ESP8266 的 3V3 電源,這會解決大部分因為電源不穩定所引起的問題。

上面的電路圖中,USB 轉 TTL 模組是用來做除錯用的。程式執行的過程中會送出除錯的訊息,依但程式出現問題時才抓的到;硬體 UART 用來與 ESP8266 直接通訊用,程式寫起來會輕鬆許多。

所需材料:
*********************************************************************************
如果需要中間那個電壓轉換模組,可以依照 "使用 N-Channel MOSFET 做 I2C 電壓準位轉換電路" 網頁中的說明自己佈線,或是到下面連結購買
*********************************************************************************
實際接線圖

程式測試說明:
*********************************************************************************
2016/12/20 更新:
由於使用的感測器並不一定會與網頁上使用的 ( DHT11 ) 相同,因此並未將所使用的 DHT11 函式庫連結附上,主要是考量到這只是 ESP8266 的應用,但因為常有私信問我要,所以檔案連結在下面,不需要再寫信跟我要了!

DHT11 Arduino Library (最新版)

若上面最新版本使用有問題,可改用下面舊版本函式庫使用
DHT11 Arduino Library (網頁程式使用的舊版本 DHT11 函式庫)

直接複製到 "文件/{Arduino IDE}/libraries " 目錄下,重新開啟 Arduino IDE 即可!
*********************************************************************************
接好線路之後 ( USB 轉 TTL 模組的線路可以不接,除非想要看到實際的輸出情形,或是需要除錯 ),完整的程式碼列在下面 ( 雲端硬碟裡面的程式碼裡面有特別做註解 ),將其複製到 Arduino IDE 中。

Note:請注意使用的 ESP8266 板子的通訊速率是使用多少 ? 若是購買賣場藍色板子,就不需要修改下面的程式碼可以直接使用;但若是使用黑色板子,下面的 #define _baudrate 要改成 115200

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

#define DEBUG

#define _ledpin     13

//*-- Hardware Serial
#define _baudrate   9600

//*-- Software Serial
// 
#define _rxpin      2
#define _txpin      3
SoftwareSerial debug( _rxpin, _txpin ); // RX, TX

//*-- DHT11
#define _dhtpin     8
#define _dhttype    DHT11

DHT dht11( _dhtpin, _dhttype );
uint8_t dhtbuf[2];

//*-- IoT Information
#define SSID "[無線網路熱點名稱]"
#define PASS "[無線網路連線密碼]"
#define IP "184.106.153.149" // ThingSpeak IP Address: 184.106.153.149
// 使用 GET 傳送資料的格式
// GET /update?key=[THINGSPEAK_KEY]&field1=[data 1]&filed2=[data 2]...;
String GET = "GET /update?key=[ThingSpeak_(Write)API_KEY]";

void setup() {
    Serial.begin( _baudrate );
    debug.begin( _baudrate );

    sendDebug("AT");
    delay(5000);
    if(Serial.find("OK"))
    {
        debug.println("RECEIVED: OK\nData ready to sent!");
        connectWiFi();
    }

    // DHT11
    dht11.begin();

    pinMode( _ledpin, OUTPUT );
    digitalWrite( _ledpin, LOW );
}

void loop() {
    dhtbuf[0] = dht11.readHumidity();
    dhtbuf[1] = dht11.readTemperature();

    // 確認取回的溫溼度數據可用
    if( isnan(dhtbuf[0]) || isnan(dhtbuf[1]) )
    {
        debug.println( "Failed to read form DHT11" );
    }
    else
    {
        digitalWrite( _ledpin, HIGH );
        char buf[3];
        String HH, TT;
        buf[0] = 0x30 + dhtbuf[1] / 10;
        buf[1] = 0x30 + dhtbuf[1] % 10;
        TT = (String(buf)).substring( 0, 2 );
        buf[0] = 0x30 + dhtbuf[0] / 10;
        buf[1] = 0x30 + dhtbuf[0] % 10;
        HH = (String(buf)).substring( 0, 2 );

        updateDHT11( TT, HH );
        #ifdef DEBUG
            debug.print("Humidity: "); 
            debug.print( HH );
            debug.print(" %\t");
            debug.print("Temperature: "); 
            debug.print( TT );
            debug.println(" *C\t");
        #endif
        digitalWrite( _ledpin, LOW );
    }

    delay(60000);   // 60 second
}

void updateDHT11( String T, String H )
{
    // 設定 ESP8266 作為 Client 端
    String cmd = "AT+CIPSTART=\"TCP\",\"";
    cmd += IP;
    cmd += "\",80";
    sendDebug(cmd);
    delay(2000);
    if( Serial.find( "Error" ) )
    {
        debug.print( "RECEIVED: Error\nExit1" );
        return;
    }

    cmd = GET + "&field1=" + T + "&field2=" + H +"\r\n";
    Serial.print( "AT+CIPSEND=" );
    Serial.println( cmd.length() );
    if(Serial.find( ">" ) )
    {
        debug.print(">");
        debug.print(cmd);
        Serial.print(cmd);
    }
    else
    {
        sendDebug( "AT+CIPCLOSE" );
    }
    if( Serial.find("OK") )
    {
        debug.println( "RECEIVED: OK" );
    }
    else
    {
        debug.println( "RECEIVED: Error\nExit2" );
    }
}

void sendDebug(String cmd)
{
    debug.print("SEND: ");
    debug.println(cmd);
    Serial.println(cmd);
} 
 
boolean connectWiFi()
{
    Serial.println("AT+CWMODE=1");
    delay(2000);
    String cmd="AT+CWJAP=\"";
    cmd+=SSID;
    cmd+="\",\"";
    cmd+=PASS;
    cmd+="\"";
    sendDebug(cmd);
    delay(5000);
    if(Serial.find("OK"))
    {
        debug.println("RECEIVED: OK");
        return true;
    }
    else
    {
        debug.println("RECEIVED: Error");
        return false;
    }

    cmd = "AT+CIPMUX=0";
    sendDebug( cmd );
    if( Serial.find( "Error") )
    {
        debug.print( "RECEIVED: Error" );
        return false;
    }
}


整段程式中最重要的就是剛剛在 ThingSpeak 所得到的結果,還有就是無線網路名稱  (SSID) 與連線密碼 ( PASS ),這幾個重要的設定都在程式開頭 IoT Information 的地方。

不過除了SSID 和 PASS 修改為你的無線網路 AP 之外,其他的不需要做修改!
//*-- IoT Information
#define SSID "[無線網路熱點名稱]"
#define PASS "[無線網路連線密碼]"
#define IP "184.106.153.149" // ThingSpeak IP Address: 184.106.153.149
// 使用 GET 傳送資料的格式
// GET /update?key=[THINGSPEAK_KEY]&field1=[data 1]&filed2=[data 2]...;
String GET = "GET /update?key=[ThingSpeak_(Write)API_KEY]";

插上 Arduino 板子的線到電腦的 USB 插槽,設定好 Arduino IDE 板子類型 ( 和晶片類型 ) 和通訊埠號碼後,按下 upload 按鈕上傳此 Sketch 到 Arduino 板子上。

如果有裝上 USB 轉 TTL 模組,可以先將其插到 PC,再打開串列埠軟體等待 Arduino 通電之後輸出的數據。

開機之後得到的數據就如下面所示,遮蔽的部分是私有的資料,執行你自己的程式碼之後就會看到完整的輸出
訊息輸出
因為每隔 60 秒才會上傳一次,因此可以過一段時間再上去 ThingSpeak 看。下面是過了差不多20幾分鐘後的數據,我放在電腦的出風口並在旁邊開電風扇循環,不然溫度會變化不大!

ThingSpeak 環境溫濕度記錄圖
結論:

完成這個例子之後,應該對於程式碼裡面的ESP8266 AT 指令有點陌生!但是這不要緊,因為這就是一個實際例子,先知道 ESP8266 無線模組可以做些什麼,再來了解 AT 指令的操作會更容易了解!

ESP8266 無線模組,可當作一般串口轉無線模組使用,也可以利用它開放的 SDK 修改或是自己製作它的韌體,開發成一個具有無線網路功能的產品或是項目,相關的資料會持續地發佈在部落格上與大家做分享!

相信使用一段時間的 AT 指令之後,對於使用 Arduino IDE 與 AT 指令的配合或許不是那麼的滿意!那麼可以試試使用 ESP8266 Arduino AT 函式庫,相關的資料可以參考下面這三個網頁中的說明,與此篇網頁程式的加強版
*********************************************************************************
2017/01/03 更新:
因為很多問與答都是關於無法上傳資料到 Thingspeak 的問題,所以在這邊做個總結回覆,大抵上這個網頁中的問題就是這樣解決。

這個問題除了接線的問題之外,就是在程式執行之前必須確定在網址列手動輸入資料是可以正確成功的,再來就是修改程式碼需要的欄位,基本上就不會出現問題 ! 因為手動可以,程式碼就可以正確地將你的資料網上傳,所以只要出問題,就是檢查剛剛修改的欄位是否出現錯誤,因為這並不是程式出現問題,而是輸入參數設定錯誤造成上傳失敗。在相同的'網路環境之下,只是將手動變成自動而已,出現問題要先檢查這些部分 !

上述的問題都解決之後,另外會出現的問題可能就是上傳一段時間之後會失敗會是回傳 error 的問題。最近一位網友提問了這個問題,並且問到了重點,所以進行了幾封郵件的來回 (原文如附件(若連結失效,請回報),文中遮蔽私人資料),若有相同問題可看裡面的討論 ! 

 "給我一個可操作 AT 指令的 Arduino 函式庫 - 解決 AT 指令處理的蛋疼問題 (親測 AT v1.2.0.0 韌體)" 網頁中,對於程式範例也是採用這個方式解決亂碼或是通訊失敗的問題。
*********************************************************************************

<< 部落格相關文章 >>

119 則留言:

  1. Hello, can you help me add the code for the DS18B20 sensor to this please?

    回覆刪除
    回覆
    1. Someone already done this!

      http://www.instructables.com/id/ESP8266-Wifi-Temperature-Logger/

      刪除
    2. 您好 我在使用esp8226搭配DS18B20時無法傳訊息到thingspeak,能否幫忙解答一下哪裡出錯,以下為我得程式碼
      #include
      #include
      #define ONE_WIRE_BUS 2
      OneWire oneWire(ONE_WIRE_BUS);
      DallasTemperature sensors(&oneWire);

      //esp8266設定
      #define SSID "704"
      #define PASSWORD "07040377"

      #include "uartWIFI.h"
      #include
      WIFI wifi;

      #define IP "184.106.153.149" // thingspeak.com
      String GET = "GET /update?key=OABNXN650G0AHNID=";

      void setup()
      {
      sensors.begin(); // Start up the ds18b20 library
      wifi.begin();
      bool b = wifi.Initialize(STA, SSID, PASSWORD);
      if(!b)
      {
      DebugSerial.println("Init error");
      }
      delay(8000); //make sure the module can have enough time to get an IP address
      String ipstring = wifi.showIP();
      DebugSerial.println("My IP address:");
      DebugSerial.println(ipstring); //show the ip address of module

      String wifistring = wifi.showJAP();
      DebugSerial.println(wifistring); //show the name of current wifi access port

      }
      void loop()
      {
      //DS18B20讀取
      sensors.requestTemperatures();
      float sensor_ds18temp = sensors.getTempCByIndex(0);

      String cmd = "AT+CIPSTART=\"TCP\",\"";
      cmd += IP;
      cmd += "\",80";
      Serial.println(cmd);

      delay(5000);
      if(Serial.find("Error")){
      return;
      }
      cmd = GET;
      cmd += "&field1=";
      cmd += sensor_ds18temp;
      cmd += "\r\n";
      Serial.print("AT+CIPSEND=");
      Serial.println(cmd.length());
      if(Serial.find(">")){
      Serial.print(cmd);
      }else{
      Serial.println("AT+CIPCLOSE");
      }
      delay(6000);

      出現的問題為重複出現以片字串AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=47
      AT+CIPCLOSE
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=47
      AT+CIPCLOSE

      刪除
    3. sensor_ds18temp 要轉成字元陣列或是字串型態

      刪除
    4. 感謝作者回覆,後來我參考了下一篇AT指令的教學文章後,搞懂了程式碼中的內容,也自己重打了新的程式碼,最後終於順利的成功連線到thingspeak,真是由衷的感謝。

      刪除
  2. 不好意思 如果使用mega 2560的板子的話 會有哪些接腳位置的差異? library會有差嗎?
    如果可以有供參考的配線圖嗎?

    回覆刪除
    回覆
    1. Arduino 程式碼裡面已經指定了接腳,只要照著接腳號碼接在板子上就可以,使用的板子基本上只是多了接腳與多了其他功能的支援!

      線路圖就是網頁提供的那張,著著指定的接腳號碼接在你的 MEGA2560 上相對應的接腳位置上,就可以使用!

      刪除
    2. 我用土壤濕度和DHT11搭配繼電器作控制,但目前遇到沒辦法上傳的狀況,想知道是哪裡寫錯
      謝謝!
      序列埠監控視窗顯示

      DHTxx test!
      AT
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=63
      AT+CIPCLOSE
      Humidity: 50 % Temperature: 48 *C 82 *F Heat index: 82.77 *F

      刪除
    3. 我的程式碼:
      #include
      #include "DHT.h"

      #define DEBUG

      #define _ledpin 13

      //*-- Hardware Serial
      #define _baudrate 9600

      //*-- Software Serial
      //
      #define _rxpin 2
      #define _txpin 3
      SoftwareSerial debug( _rxpin, _txpin ); // RX, TX

      //*-- DHT11
      #define _dhtpin 8
      #define _dhttype DHT11

      DHT dht11( _dhtpin, _dhttype );
      uint8_t dhtbuf[2];

      //*-- IoT Information
      #define SSID "rainbow"
      #define PASS "eric33302"
      #define IP "184.106.153.149" // ThingSpeak IP Address: 184.106.153.149
      String GET = "GET /update?key=E0UT0LYS5UBIZ1O0=";

      int sensorPin = 0;
      int sensorValue = 0;

      const int relay1 = 22;
      const int relay2 = 24;

      void setup() {
      Serial.begin( _baudrate );
      Serial.println("DHTxx test!");
      pinMode(relay1,OUTPUT);
      dht11.begin();

      pinMode(relay2,OUTPUT);


      debug.begin( _baudrate );

      sendDebug("AT");
      delay(5000);
      if(Serial.find("OK"))
      {
      debug.println("RECEIVED: OK\nData ready to sent!");
      connectWiFi();
      }
      dht11.begin();
      }

      void loop()
      {
      delay(500);
      sensorValue = analogRead(sensorPin);

      dhtbuf[0] = dht11.readHumidity();
      dhtbuf[1] = dht11.readTemperature();
      dhtbuf[5] = dht11.readTemperature(true);

      if( isnan(dhtbuf[0]) || isnan(dhtbuf[1]))
      {
      debug.println( "Failed to read form DHT11" );
      }
      else if (isnan(sensorValue))
      {
      Serial.println("Failed to read from soil moist sensor!");
      return;
      }
      else
      {
      digitalWrite( _ledpin, HIGH );
      char buf[3], sensorValue;
      String HH, TT, SW ;
      dhtbuf[0]= 0x30 + dhtbuf[1] / 10;
      dhtbuf[1]= 0x30 + dhtbuf[0]% 10;
      TT = (String(buf)).substring( 0, 2 );
      buf[0] = 0x30 + dhtbuf[0] / 10;
      buf[1] = 0x30 + dhtbuf[0] % 10;
      HH = (String(buf)).substring( 0, 2 );
      SW = String(sensorValue);

      updateDHT11( TT, HH, SW);
      #ifdef DEBUG
      debug.print("Humidity: ");
      debug.print( HH );
      debug.print(" %\t");
      debug.print("Temperature: ");
      debug.print( TT );
      debug.println(" *C\t");
      debug.print("sensorValue");
      debug.println( SW );
      #endif
      digitalWrite( _ledpin, LOW );
      }

      delay(20000);
      // Compute heat index
      // Must send in temp in Fahrenheit!
      float hi = dht11.computeHeatIndex(dhtbuf[5], dhtbuf[0]);
      int openFanT;
      int openFanH;
      int openPadpump;
      int openWaterpump;
      int PopenFanT=1;
      int PopenFanH=1;
      int PopenPadpump=1;
      int PopenWaterpump=1;

      if(dhtbuf[1]>=35.6){
      openFanT = 1;
      openPadpump = 1;
      PopenFanT = 1;
      PopenPadpump = 1;
      }else if(dhtbuf[1]<32.6){
      openFanT = 0;
      openPadpump = 0;
      PopenFanT = 0;
      PopenPadpump = 0;
      }else {openFanT = PopenFanT;}

      if(dhtbuf[0]>=90.5){
      openFanH = 1;
      PopenFanH =1;
      }else if(dhtbuf[0]<70.5){
      openFanH = 0;
      PopenFanH = 0;
      }else{openFanH = PopenFanH;}

      switch(openFanT+openFanH){
      case 0:
      digitalWrite(relay1,LOW);
      break;
      case 1:
      digitalWrite(relay1,HIGH);
      break;
      case 2:
      digitalWrite(relay1,HIGH);
      break;
      default:
      break;

      }

      if(sensorValue<300){
      openWaterpump = 1;
      PopenWaterpump = 1;
      }else if(sensorValue>=700){
      openWaterpump = 0;
      PopenWaterpump = 0;
      }else {openWaterpump = PopenWaterpump;}
      Serial.print("Humidity: ");
      Serial.print(dhtbuf[0]);
      Serial.print(" %\t");
      Serial.print("Temperature: ");
      Serial.print(dhtbuf[1]);
      Serial.print(" *C ");
      Serial.print(dhtbuf[5]);
      Serial.print(" *F\t");
      Serial.print("Heat index: ");
      Serial.print(hi);
      Serial.println(" *F");

      Serial.print("soilsenor=");
      Serial.println(sensorValue);
      }

      刪除
    4. void updateDHT11( String T, String H, String SW )
      {
      String cmd = "AT+CIPSTART=\"TCP\",\"";
      cmd += IP;
      cmd += "\",80";
      sendDebug(cmd);
      delay(2000);
      if( Serial.find( "Error" ) )
      {
      debug.print( "RECEIVED: Error\nExit1" );
      return;
      }

      cmd = GET + "&field1=" + T + "&field2=" + H +"&field3="+SW+"\r\n";
      Serial.print( "AT+CIPSEND=" );
      Serial.println( cmd.length() );
      if(Serial.find( ">" ) )
      {
      debug.print(">");
      debug.print(cmd);
      Serial.print(cmd);
      }
      else
      {
      sendDebug( "AT+CIPCLOSE" );
      }
      if( Serial.find("OK") )
      {
      debug.println( "RECEIVED: OK" );
      }
      else
      {
      debug.println( "RECEIVED: Error\nExit2" );
      }
      }

      void sendDebug(String cmd)
      {
      debug.print("SEND: ");
      debug.println(cmd);
      Serial.println(cmd);
      }

      boolean connectWiFi()
      {
      Serial.println("AT+CWMODE=1");
      delay(2000);
      String cmd="AT+CWJAP=\"";
      cmd+=SSID;
      cmd+="\",\"";
      cmd+=PASS;
      cmd+="\"";
      sendDebug(cmd);
      delay(5000);
      if(Serial.find("OK"))
      {
      debug.println("RECEIVED: OK");
      return true;
      }
      else
      {
      debug.println("RECEIVED: Error");
      return false;
      }

      cmd = "AT+CIPMUX=0";
      sendDebug( cmd );
      if( Serial.find( "Error") )
      {
      debug.print( "RECEIVED: Error" );
      return false;
      }
      }

      刪除
    5. 您好:
      當程式正常執行的狀況下,不能上傳資料到 ThingSpeak 可能有下面兩個原因:
      1. 取得的數據錯誤。看一下取得的 DHT11 和土壤類比輸入的數值對不對 ?
      2. ThingSpeak 的 Channel 裡面的 Field# 設定錯誤

      您應該要先手動測試是否可以正確上傳資料到 ThingSpeak ( 資料格式在網頁上面有說到 ),使用所提供的程式碼做測試 (假設程式中所提供的 KEY 是正確的 ),得到的回傳數值是 0
      http://api.thingspeak.com/update?key=E0UT0LYS5UBIZ1O0=&field1=30&field2=75&field3=223
      所以不管程式是否正常運作,數據還是傳不上去 ThingSpeak

      只要手動測試成功,就只是差在輸入到 ESP8266 後,後面要加 "\r\n" 而已。檢查一下 KEY 有沒錯誤,和檢查 Channel 裡面的設定是否正確。

      刪除
  3. 不好意思 DHT library的載點掛掉了 可以麻煩在PO一次嗎?謝謝

    回覆刪除
    回覆
    1. 剛剛確認過了,已經更新連結,可以再次下載了!
      謝謝提醒!

      刪除
    2. 謝謝你這麼快就回我,我使用了程式發現我的esp8266並沒有像你一樣出現recevied:OK,請問這是我的ESP8266要更新嗎?
      AT
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=55
      AT+CIPCLOSE
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=55
      AT+CIPCLOSE


      刪除
    3. 不好意思我剛剛發現我的是黑板要用115200bps,但是我的DHT11要用的是9600bps,請問程式要如何去做更改才能讓兩者的bps同時不一樣

      刪除
    4. A1:沒有出現 receive:OK,表示 ESP8266 沒有回應給微處理器!網頁中有標明一開始所使用的韌體版本,即便現在是使用新版本的韌體,但沒收到任何舊版本韌體不能使用的訊息!
      你應該要先確認板子是否正常可以使用,在檢查線路接線是否正確 ? 若是硬體出現問題,請向你的販售者詢問!
      A2:ESP8266 使用的是 UART,DHT11 使用的是單線通訊,兩者通訊是不一樣的,跟程式完全沒有關係!

      刪除
    5. 經過幾次測試之後我已經能夠RECEIVE了,但是
      SEND: AT+CIPSTART="TCP","184.106.153.149",80
      就直接跳到
      SEND: AT+CIPCLOSE
      RECEIVED: ErrorExit2
      請問這是什麼原因呢?

      刪除
    6. 從程式碼看,會發生這種錯誤是因為沒有取得 ESP8266 的回應符號 ">",在你送出下面兩行程式碼之後
      Serial.print( "AT+CIPSEND=" );
      Serial.println( cmd.length() );
      查一下 CIPSEND 的說明就可以知道
      /*-------------------
      響應:
      發送指定長度的數據。

      收到此命令後先換行返回“ > ” ,然後開始接收串口數據,當數據長度滿 length 長時發送數據,回到普通指令模式,等待下一條AT指令。

      如果未建立連接或連接被斷開,返回
      ERROR

      如果數據發送成功,返回
      SEND OK
      -------------------*/

      所以應該是連線沒有建立成功導致!

      刪除
  4. 在此分享一下我如何讓它出現 receive:OK,首先我的ESP8266是最新版程式碼baud率要設置115200,而且SSCOM也要設置到3.2也要設置到115200。
    接著如果你照著接線方法上傳卻出現avrdude: stk500_getsync(): not in sync: resp=0x00,那就表示你的程式碼要改成
    void setup() {
    Serial.begin( _baudrate );
    debug.begin( _baudrate );
    delay(10000);
    sendDebug("AT");

    if(Serial.find("OK"))
    {
    debug.println("RECEIVED: OK\nData ready to sent!");
    connectWiFi();
    }
    並且CH_PD線要先拔掉在上傳如此一來便能成功,之後再十秒內插上去。

    回覆刪除
    回覆
    1. 應該要這樣解釋:
      如果在線路中沒有特別為了 Arduino 的 TX 或是 RX 做佈線的話,只要有在線路中直接使用 Arduino 的硬體 UART,在燒錄時建議拔掉 TX 與 RX 兩隻接腳,因為這會導致 Arduino 燒錄時會出現問題。

      刪除
    2. 我試了很久均沒有改善
      SEND: AT+CIPCLOSE
      RECEIVED: ErrorExit2還是會一直出現,
      但是如果我使用USB轉TTL直接接esp8266照著程式碼裡的指令輸入是能連上thingspeak的。
      請問這是因為我沒有使用麵包版電源模組的緣故嗎?

      刪除
    3. 我改了一下程式碼
      String cmd = "AT+CIPSTART=\"TCP\",\"";
      cmd += IP;
      cmd += "\",80";
      sendDebug(cmd);
      delay(2000);
      if(Serial.find("OK"))
      {
      debug.println("RECEIVED: OK");
      }
      else
      {
      debug.println("RECEIVED: Error");
      }
      來幫助我是哪部分做錯,結果發現是沒連上thingspeak,SSCOM3.2送出這段訊息
      SEND: AT+CIPMUX=0
      SEND: AT+CIPSTART="TCP","184.106.153.149",80
      RECEIVED: Error
      奇怪的是我使用USB轉TTL直接接esp8266並且打出 AT+CIPSTART="TCP","184.106.153.149",80的時候可以直接連上。請問這是原因呢?

      刪除
    4. 我發現我在更早之前的程式並沒有成功,我將它改成OK但是卻也沒有回傳出東西,究竟要怎麼改才能讓cmd = "AT+CIPMUX=0";下達成功,以下是我的程式碼。
      cmd = "AT+CIPMUX=0";
      sendDebug( cmd );
      if( Serial.find( "OK") )
      {
      debug.print( "RECEIVED: Error" );
      return false;
      }

      刪除
    5. 這是我從arduino的COM觀看來的
      AT
      AT+CWMODE=1
      AT+CWJAP="[FLOWER-PC_Network]","[401440044]"
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=54
      GET /update?key=5O0EN53RYL89LM59&field1=00&field2=00
      我發現他似乎少了cmd = "AT+CIPMUX=0";來寫入進去為什麼會這樣呢?

      刪除
    6. 還是同樣的問題:沒有連上有效的網路!

      AT+CWJAP="[FLOWER-PC_Network]","[401440044]"
      這一行改成下面試試,或許就可以連上網路
      AT+CWJAP="FLOWER-PC_Network","401440044"

      刪除
    7. 太神啦!!!沒想到居然是錯在這麼小的一個地方,謝謝你。

      刪除
    8. 但是thingspeak的橫軸沒辦法輸出成以分鐘為單位,他現在是以日期為單位。因此呢同一天的數據全部都會擠在一個點。有辦法把它改為分鐘嗎?

      刪除
    9. ThingSpeak 的問題,要自己解決!Thingspeak 網站上面有使用說明,自己搞定吧!

      刪除
    10. 請問一下由於ESP8266要用115200的baudrate但是DHT11卻是要用9600的baud,否則的話數值會不正常。請問這要如何去解決呢?

      刪除
    11. Serial.begin(115200)用在與 ESP8266 的串列通訊上;debig.begin(115200) 用在輸出除錯的字串到 USB轉 TTL 上,跟 DHT11 的通訊上完全沒有關係。DHT11 沒有使用到 UART!

      刪除
  5. 您好,這是我送給ESP8266的AT指令(重覆部分)
    AT+CIPSTART="TCP","184.106.153.149",80
    AT+CIPSEND=58
    GET /update?key=QNX742O9CGSTV3YC&field1=26.0&field2=58.0
    ThingSpeak按照您教學的做法做的,但我一直無法順利將資料上傳(ThingSpeak沒收到資料)
    而且就算不通過Arduino 直接用 USB →TTL 模組寫入ESP8266也沒辦法
    想請教可能的原因或己決辦法。
    謝謝

    回覆刪除
    回覆
    1. 1. 有沒使用網址列上傳過資料,結果如何 ?
      這一個網址在瀏覽器中會得到數字的回應,但不是 thingspeak 伺服器回應的錯誤號碼
      http://api.thingspeak.com/update?key=QNX742O9CGSTV3YC&field1=26.0&field2=58.0
      檢查一下是不是已經有資料上傳,我得到的回傳是數字 6,表示資料已經有 6 筆
      2. 如果不能使用網址列上傳表示 Thingspeak 設定有問題,檢查一下!
      3. USB轉TTL模組寫入有問題
      4. 如果不是使用賣場的電源模組,請先確認你的電源是否穩定和電流足夠!

      可以的話,進詳細列出你的錯誤訊息與測試過程出來,不然簡單的問題也會搞很久!


      刪除
    2. 您好,謝謝您的回覆
      1. 若直接透過瀏覽器可順利寫入 thingspeak
      3. 直接使用USB轉TTL模組寫入AT與回應如下
      AT


      OK
      AT+CWMODE=1


      OK
      AT+CWJAP="Angela","12121212"


      OK
      AT+CIPMUX=0


      OK
      AT+CIPSTART="TCP","184.106.153.149",80

      CONNECT

      OK
      AT+CIPSEND=50


      OK
      > GET /update?key=QNX742O9CGSTV3YC&field1=0&field2=0
      busy s...

      SEND OK

      【沒有資料上傳thingspeak】

      4. 我使用的是實驗室電源供應器

      刪除
    3. 因使用的DHT函式庫不同,小弟將您提供的程式稍做更改如下
      #include "SoftwareSerial.h"
      #include "DHT.h"

      #define DEBUG

      #define _ledpin 13

      #define _SerialBaudrate 115200
      #define _DebugBaudrate 9600

      //-------*USB 除錯
      #define _rxpin 10
      #define _txpin 11
      SoftwareSerial debug(_rxpin, _txpin); // RX, TX

      //-------*DHTXX 溫濕度感測器
      #define DHTPIN 2 // what pin we're connected to
      #define DHTTYPE DHT11 // DHT 11 (AM2302)

      DHT dht(DHTPIN, DHTTYPE); // Initialize DHT sensor.

      //uint8_t dhtbuf[2]; //0~255

      //-------*聯網資訊
      #define SSID "Angela"
      #define PASS "12121212"
      #define IP "184.106.153.149" //ThingSpeak 的 IP

      //Add data by sending a POST or GET to:
      //https://api.thingspeak.com/update
      //Please include your write API key and some data, for example:
      //https://api.thingspeak.com/update?key=QNX742O9CGSTV3YC&field1=0&field2=0
      //GET 傳送格式
      String GET = "GET /update?key=QNX742O9CGSTV3YC";


      void setup() {
      Serial.begin(_SerialBaudrate);
      debug.begin(_DebugBaudrate);

      //ESP8266 check
      sendDebug("AT");
      if(Serial.find("OK"))
      {
      debug.println("Send AT\n\tESP8266 received: ok!(Date read to send)");
      connectWifi();
      }

      //DHTXX 溫濕度感測器
      dht.begin();

      pinMode(_ledpin, OUTPUT);
      digitalWrite(_ledpin, LOW);

      }

      void loop() {
      delay(250);
      float h = dht.readHumidity();
      float t = dht.readTemperature();

      float hic = dht.computeHeatIndex(t, h, false);

      // Check if any reads failed and exit early (to try again).
      if (isnan(h) || isnan(t))
      {
      debug.println("Failed to read from DHT sensor!");
      }
      else
      {
      digitalWrite(_ledpin, HIGH);

      String HH, TT;
      HH +=String(int(h))+ "."+String(getDecimal(h));
      TT +=String(int(t))+ "."+String(getDecimal(t));

      updataDHT(TT, HH);

      #ifdef DEBUG
      debug.print("Hum: ");
      debug.print(HH);
      debug.print(" %\t");
      debug.print("Tmp: ");
      debug.print(TT);
      debug.println(" *C\t");
      #endif
      digitalWrite(_ledpin, LOW);
      }

      delay(5000);
      }

      刪除
    4. boolean connectWifi()
      {
      //將WiFi設為Station: 【AT+CWMODE=1】
      Serial.println("AT+CWMODE=1");
      delay(5000);

      //連線指令: 【AT+CWJAP="SSID","PASS"】
      String cmd = "AT+CWJAP=\"";
      cmd += SSID;
      cmd += "\",\"";
      cmd += PASS;
      cmd += "\"";
      sendDebug(cmd);
      if(Serial.find("OK"))
      {
      debug.println("Send AT+CWJAP=,\n\tESP8266 received: ok!");
      return true;
      }
      else
      {
      debug.println("Send AT+CWJAP=,\n\tESP8266 received: error!");
      return false;
      }

      //關閉多重連線: 【AT+CIPMUX=0】
      cmd = "AT+CIPMUX=0";
      sendDebug(cmd);
      if(Serial.find("Error"))
      {
      debug.println("Send AT+CIPMUX=0\n\tESP8266 received: Error...");
      return false;
      }
      }

      void sendDebug(String cmd)
      {
      debug.print("Send: ");
      debug.print(cmd);
      cmd+="\r\n";
      Serial.print(cmd);
      //Serial.print("\r\n");
      }

      long getDecimal(float val)
      {
      int intPart = int(val);
      long decPart = 1000*(val-intPart); //I am multiplying by 1000 assuming that the foat values will have a maximum of 3 decimal places
      //Change to match the number of decimal places you need
      if(decPart>0)return(decPart); //return the decimal part of float number if it is available
      else if(decPart<0)return((-1)*decPart); //if negative, multiply by -1
      else if(decPart=0)return(00); //return 0 if decimal part of float number is not available
      }

      void updataDHT(String T, String H)
      {
      //讓 ESP8266 扮演 Client: 【AT+CIPSTART=,,】CIPMUX=0
      String cmd = "AT+CIPSTART=\"TCP\",\"";
      cmd += IP;
      cmd += "\",80";
      sendDebug(cmd);
      if(Serial.find("Error"))
      {
      debug.println("Send AT+CIPSTART=,,\n\tESP8266 received: Error...");
      return;
      }

      //發送TCP/IP資料: 【AT+CIPSEND=】CIPMUX=0
      //https://api.thingspeak.com/update?key=QNX742O9CGSTV3YC&field1=0&field2=0
      cmd = GET + "&field1=" + T + "&field2=" + H + "\r\n";
      Serial.print("AT+CIPSEND=");
      Serial.println(cmd.length());
      if(Serial.find(">"))
      {
      debug.print(">");
      sendDebug(cmd);
      //Serial.print(cmd);
      }
      else
      {
      //關閉TCP/IP: 【AT+CIPCLOSE= or AT+CIPCLOSE】
      sendDebug("AT+CIPCLOSE");
      }
      if(Serial.find("OK"))
      {
      debug.println("Send AT+CIPCLOSE\n\tESP8266 received: OK!");
      }
      else
      {
      debug.println("Send AT+CIPCLOSE\n\tESP8266 received: Error...");
      }

      }

      刪除
    5. 【Arduino with ESP8266】
      AT
      AT+CWMODE=1
      AT+CWJAP="Angela","12121212"
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=58
      AT+CIPCLOSE
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=58
      GET /update?key=QNX742O9CGSTV3YC&field1=29.0&field2=62.0

      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=58
      GET /update?key=QNX742O9CGSTV3YC&field1=29.0&field2=63.0

      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=58
      GET /update?key=QNX742O9CGSTV3YC&field1=29.0&field2=62.0

      刪除
    6. 【Arduino with USB/TTL】
      Send: ATSend AT
      ESP8266 received: ok!(Date read to send)
      Send: AT+CWJAP="Angela","12121212"Send AT+CWJAP=,
      ESP8266 received: ok!
      Send: AT+CIPSTART="TCP","184.106.153.149",80Send: AT+CIPCLOSESend AT+CIPCLOSE
      ESP8266 received: OK!
      Hum: 62.0 % Tmp: 29.0 *C
      Send: AT+CIPSTART="TCP","184.106.153.149",80>Send: GET /update?key=QNX742O9CGSTV3YC&field1=29.0&field2=62.0
      Send AT+CIPCLOSE
      ESP8266 received: OK!
      Hum: 62.0 % Tmp: 29.0 *C
      Send: AT+CIPSTART="TCP","184.106.153.149",80>Send: GET /update?key=QNX742O9CGSTV3YC&field1=29.0&field2=63.0
      Send AT+CIPCLOSE
      ESP8266 received: OK!
      Hum: 63.0 % Tmp: 29.0 *C

      刪除
    7. 不知道你是否直接使用網頁中原始的程式測試過 ? 在出現問題的時候,其實應該要去使用原始可動作的程式做測試,以釐清自己寫的程式是否出現錯誤!

      建議與想法:
      (A)..........................................................
      1. 使用原使網頁中所附的程式做測試,修改程式中的 API KEY
      2. 取消 setup() 中的 dht11.begin
      // dht11.begin();
      3. 修改 loop() 中的 dht 呼叫函式,直接賦值給
      dhtbuf[0] = 65.5;
      dhtbuf[1] = 28.5;
      完成上面三個之後,在線路確認沒問題之後就可以上傳程式做測試!程式沒有出現編譯錯誤的話,就可以直接上傳數據到 ThingSpeak。確認一下 Thingspeak 收到數據沒 ?
      (B)..........................................................
      (A) 若是成功,比較一下輸出訊息與你自己的輸出訊息有什麼不一樣,就知道問題出在哪裡 !
      Send: AT+CIPSTART="TCP","184.106.153.149",80>Send: GET /update?key=QNX742O9CGSTV3YC&field1=29.0&field2=62.0
      Send AT+CIPCLOSE <------ "成功傳送出去數據到 ThingSpeak 這一行不應該出現"
      ESP8266 received: OK!
      ------------------------------------------------
      自己先測試一下 (A),做完之後若還需要討論,請將 ( A ) 的訊息先 POST 上來!

      刪除
    8. 您好,感謝您的建議,我已於作天測試成功(之前自己弄卡了好幾天)
      目前仍有幾個小問題
      1. wifi分享器疑似訊號不穩:使用指令【AT+CWJAP="SSID","PASS"】OK,指令【AT+CIPSTART=長度】無反應
      2. wifi分享器疑似本身問題:使用第一台無論如何都無法上傳資料至thingspeak,但以同樣的線路、程式換了另一台wifi分享器就成功了

      刪除
  6. 請問 如果沒有 Level Shifter ( 3V3 / 5V 電壓準位轉換模組)是不是就沒辦法傳資料到 ThingSpeak呢?

    回覆刪除
  7. 應該是說:只要微控制器使用的是 3V3 準位的就不需要!但因為我使用的 arduino 是使用 5V 準位,所以必須要加才能安全的傳送命令給 ESP8266。

    回覆刪除
  8. 目前使用 arduino mega 板 有用賣場3v3電源供應器來供應ESP8266
    通訊速率:9600
    接法是: 【Arduino】TX→【ESP8266】URXD
    【Arduino】RX→【ESP8266】UTXD
    【穩壓器(電源模組)】3.3v → 【ESP8266】VCC
    【穩壓器(電源模組)】3.3v → 【ESP8266】CH_PD
    【穩壓器(電源模組)】GND → 【ESP8266】GND
    【穩壓器(電源模組)】GND → 【Arduino】GND
    USB 轉 TTL 模組的RXD →UTXD
    USB 轉 TTL 模組的TXD →URXD
    DHT接法跟上述一樣
    沒開ESP826的電源
    SSCOM3.2的內容為
    SEND: AT
    SEND: AT+CIPCLOSE
    RECEIVED: Error Exit2
    Humidity: 43 % Temperature: 25 *C


    -----------------------------------
    開電源後,重跑 SSCOM內容為空白
    是什麼問題??







    回覆刪除
    回覆
    1. 看起來應該是接線接錯了!
      請再確認線路是否與網頁中的電路圖相同。
      ESP8266 -> Arduino TX, RX;USB 轉 TTL -> Arduino D2, D3
      ESP8266 與 Arduino 相接,至少 ESP8266 URXD 要接 level shifter.

      刪除
  9. 新手發問
    ESP8266透過終端機或Arduino的Serial手動下達指令,動作都正常
    ThingSpeak也能正確收到資料
    但使用範例程式自動完成動作時
    就連loop內的第一句AT都無法正確收到"OK"的回應
    想請問一下該如何解決這個問題?
    電源部分使用電源供應器,沒有電壓/電流不足的疑慮
    程式則採用和範例相同,DH11可正確取得溫濕度
    麻煩大大求助!!

    回覆刪除
    回覆
    1. 網頁的範例是早前的通訊速率 9600 bps,確認一下終端機連線時所使用的速率是不是跟下面程式碼中的一樣,不一樣就把程式碼改成你現在ESP8266通訊的速率。

      //*-- Hardware Serial
      #define _baudrate 9600

      刪除
  10. 我ESP8266是黑色版子
    Arduino對ESP8266是設定115200
    Arduino對電腦是設定9600(也嘗試過115200)

    #include

    //*-- Software Serial
    //
    #define _RX 11
    #define _TX 10
    SoftwareSerial esp8266( _RX, _TX );

    void setup() {
    Serial.begin(9600);
    Serial.println("Hi!");
    esp8266.begin(115200);

    SendData("AT");
    delay(5000);
    if(esp8266.find("OK"))
    {
    Serial.println("RECEIVED: OK\nData ready to sent!");
    }
    }

    void loop() {

    }

    void SendData(String cmd)
    {
    Serial.print("SEND: ");
    Serial.println(cmd);
    esp8266.println(cmd);
    }

    這隻程式碼可以正確收到"OK"後回傳訊息

    回覆刪除
  11. #include
    #include "DHT.h"

    #define DEBUG

    #define _ledpin 13

    //*-- Software Serial
    //
    #define _RX 11
    #define _TX 10
    SoftwareSerial esp8266( _RX, _TX );

    //*-- DHT11
    #define _dhtpin 8
    #define _dhttype DHT11

    DHT dht11( _dhtpin, _dhttype );
    uint8_t dhtbuf[2];

    //*-- IoT Information
    #define SSID "LIU-WiFi"
    #define PASS "m0301111"
    #define IP "184.106.153.149" // ThingSpeak IP Address: 184.106.153.149
    // 使用 GET 傳送資料的格式
    // GET /update?key=[THINGSPEAK_KEY]&field1=[data 1]&filed2=[data 2]...;
    String GET = "GET /update?key=OQU6V72ZTZQG3P4F";

    void setup() {
    Serial.begin(115200);
    esp8266.begin(115200);
    Serial.println("Hi!");


    Serial.flush();
    SendData("AT");
    if(esp8266.find("OK"))
    {
    Serial.println("RECEIVED: OK\nData ready to sent!");
    connectWiFi();
    }
    else
    Serial.println("RECEIVED: AT,FAIL");


    // DHT11
    dht11.begin();

    pinMode( _ledpin, OUTPUT );
    digitalWrite( _ledpin, LOW );
    }

    void loop() {
    // DHT11 溫濕度讀取時間不要小於 1 秒
    // DHT11 溫溼度不需要小數位,也沒有小數位
    dhtbuf[0] = dht11.readHumidity();
    dhtbuf[1] = dht11.readTemperature();

    // 確認取回的溫溼度數據可用
    if( isnan(dhtbuf[0]) || isnan(dhtbuf[1]) )
    {
    Serial.println( "Failed to read form DHT11" );
    }
    else
    {
    digitalWrite( _ledpin, HIGH );
    char buf[3];
    String HH, TT;
    // 轉換為 10 進位,並轉換為字串
    buf[0] = 0x30 + dhtbuf[1] / 10;
    buf[1] = 0x30 + dhtbuf[1] % 10;
    TT = (String(buf)).substring( 0, 2 );
    buf[0] = 0x30 + dhtbuf[0] / 10;
    buf[1] = 0x30 + dhtbuf[0] % 10;
    HH = (String(buf)).substring( 0, 2 );

    // DHT11 溫度與濕度傳送
    updateDHT11( TT, HH );
    #ifdef DEBUG
    Serial.print("Humidity: ");
    Serial.print( HH );
    Serial.print(" %\t");
    Serial.print("Temperature: ");
    Serial.print( TT );
    Serial.println(" *C\t");
    #endif
    digitalWrite( _ledpin, LOW );
    }

    // 每隔多久傳送一次資料
    delay(5000); // 60 second

    }

    void SendData(String cmd)
    {
    Serial.print("SEND: ");
    Serial.println(cmd);
    esp8266.println(cmd);
    }

    //----------------------------------------------------------

    boolean connectWiFi()
    {
    esp8266.println("AT+CWMODE=1");
    delay(2000);
    String cmd="AT+CWJAP=\"";
    cmd+=SSID;
    cmd+="\",\"";
    cmd+=PASS;
    cmd+="\"";
    SendData(cmd);
    delay(5000);
    if(esp8266.find("OK"))
    {
    Serial.println("RECEIVED: OK");
    //return true;
    }
    else
    {
    Serial.println("RECEIVED: WiFi connect Error");
    //return false;
    }

    cmd = "AT+CIPMUX=0";
    SendData( cmd );
    if(esp8266.find("Error"))
    {
    Serial.println( "RECEIVED: AT+CIPMUX=0 Error" );
    //return false;
    }
    }

    //----------------------------------------------------------

    void updateDHT11( String T, String H )
    {
    // 設定 ESP8266 作為 Client 端
    String cmd = "AT+CIPSTART=\"TCP\",\"";
    cmd += IP;
    cmd += "\",80";
    SendData(cmd);
    delay(2000);
    if(esp8266.find("Error"))
    {
    Serial.println( "RECEIVED: Error\nExit1" );
    return;
    }

    cmd = GET + "&field1=" + T + "&field2=" + H +"\r\n";
    esp8266.println( "AT+CIPSEND=" );
    esp8266.println( cmd.length() );
    if(esp8266.find(">"))
    {
    Serial.print(">");
    Serial.println(cmd);
    esp8266.println(cmd);
    }
    else
    {
    SendData( "AT+CIPCLOSE" );
    }
    if(esp8266.find("OK"))
    {
    Serial.println( "RECEIVED: OK" );
    }
    else
    {
    Serial.println( "RECEIVED: Error\nExit2" );
    }
    }

    這隻程式DH11可正確取得溫濕度
    但第一個"AT"就收不到"OK"
    上傳資料也無法正確抵達
    麻煩大大幫忙找錯誤,感謝!!

    回覆刪除
    回覆
    1. 若是連 AT 送出都收不到回應,那錯誤就出現 setup() 函式中。比較一下跟網頁中的程式有什麼不同!
      請先使用網頁中的例子試試結果,例子中只要修改應該修改的參數設定就好,試試看是否正常!

      刪除
  12. 一個網友問的,上面名字沒顯示出來,我也不知道是誰! 發佈的時候也不知為什麼就不見了,所以我補在這邊,請自己認領一下 !
    -----------------------------------------
    編譯時出現以下錯誤:
    警告:程式庫'DHT sensor library'裡有偽造資料夾.github
    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino: In function 'void setup()':

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino:38:24: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

    if(Serial.find("OK"))

    ^

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino: In function 'void updateDHT11(String, String)':

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino:95:30: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

    if( Serial.find( "Error" ) )

    ^

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino:104:25: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

    if(Serial.find( ">" ) )

    ^

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino:114:25: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

    if( Serial.find("OK") )

    ^

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino: In function 'boolean connectWiFi()':

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino:142:24: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

    if(Serial.find("OK"))

    ^

    C:\Users\han\Documents\Arduino\DHT11_ThingSpeak\DHT11_ThingSpeak.ino:155:29: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]

    if( Serial.find( "Error") )

    回應的指令
    AT
    AT+CIPSTART="TCP","184.106.153.149",80
    AT+CIPSEND=54
    AT+CIPCLOSE
    之後就沒有反應了

    請問是哪裡出了問題呢

    回覆刪除
    回覆
    1. 我重新使用 Arduino IDE 1.6.9 編譯了網頁的程式,沒有看到上面的編譯出現的警告! 那些編譯訊息沒什麼關係,可以忽略掉! 若真的受不了這些東西,可以試著改成 Serial.find((static const char*)"OK") 試試 !

      你的問題在上面就有討論到,問之前可以先去看看是不是對你有幫助!

      若是輸出到 AT+CIPCLOSE 就斷掉,那問題就是出現 updateDHT11() 函式裡面,最大的原因可能是 ESP8266 根本沒有連上你指定的路由器,所以不能連到 thingspeak.

      可以在程式執行的時候登入路由器看看是否有正確連接上。

      刪除
    2. 你好是我提出的問題 真是抱歉
      我的版子是UNO版 程式上有差異嗎
      今天試了一下還是只收到
      AT
      AT+CWMODE=1
      AT+CWJAP="XXX","XXX"
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=54
      AT+CIPCLOSE
      溫濕度也一直讀不到

      刪除
    3. 如果只有上面輸出,連 SEND: OK 都沒有就是你的接線有問題,因為連不上 ESP8266,它沒有回覆!
      另外,要貼 Log 要貼完整的!如果上面不是完整的 Log,請重貼上!

      刪除
    4. 上面是完整的log沒錯喔
      問題已解決
      只是一定要接USB轉TTL 然後UNO版一定要RESET才能收到SEND: OK

      刪除
  13. 您好,想請問一下
    #define SSID "[無線網路熱點名稱]"
    #define PASS "[無線網路連線密碼]"
    這邊是輸入隨便一個帳號密碼就可以嗎?
    例如
    HELLOWORLD
    helloworld

    還是說應該要輸入什麼特定的內容?

    回覆刪除
    回覆
    1. [無線網路熱點名稱]:家中無線網路的名稱
      [無線網路連線密碼]:家中無線網路的連線密碼

      刪除
  14. 你好,想請問一下
    #define SSID "[無線網路熱點名稱]"
    #define PASS "[無線網路連線密碼]"
    這邊的SSID和PASS是隨意給就好嗎?
    例如
    SSID HELLOWORLD
    PASS helloworld

    或是有特定要設定的內容嗎?
    謝謝。

    回覆刪除
    回覆
    1. SSID 與 PASS 不可以隨便給! 用你手機產生一個一個可攜式無線基地台,點進去設定就可以看到名稱,SSID 就是這個基地台的名稱;再點擊配置進去可以設定連線密碼,這個就是 PASS。沒有這兩個,ESP8266 要連到哪裡去 ? 也不能與外界通訊 !

      刪除
  15. 您好,請問那如果要使用wifi esp8266上傳資料到thingspeak

    它的概念是:
    Arduino 讀取Sensor數據→傳送到ESP8266→ESP8266連接到路由器(一般筆電連接的wifi)→上傳到thingspeak
    是這樣的嗎?

    所以這樣的話SSID、PASS是設為路由器的嗎?
    但是路由器wifi不只有一台電腦在連接,這樣是怎麼辨識的呢的?
    目前使用手機的熱點,是可以連接的,
    以上,再麻煩您了,謝謝。

    回覆刪除
    回覆
    1. 你手機是用 3G 吃到飽的呀 ? 我舉這個例子好像讓你搞混了 !
      反正,因為 thingspeak 是位在網路的遠方,要從家裡面傳到那裏去,就需要一個中介的裝置幫忙,讓 ESP8266 可以將資料往網路遠方送;手機上面搜尋一下家裡面或是附近可以連上網的網路,看名稱與密碼是多少設上去就可以了。你只要負責設定這些東西就好,連上去之後它怎麼處理多方連線就不需要去管,因為它會自己處理。

      刪除
  16. 為甚麼我的總是顯示:
    AT
    AT+CIPSTART="TCP","184.106.153.149",80
    AT+CIPSEND=54
    AT+CIPCLOSE

    是因為ESP8266沒有回應嗎?該怎麼解決,我用好久喔...
    code:
    http://paste.ofcode.org/JUPJUQBcwaUmQLuvx7yy3s

    回覆刪除
    回覆
    1. Serial Port 是接 ESP-01,所以通訊速度要改成 115200 bps(除非你是使用9600bps 的通訊速度),debug port 接 "USB 轉 TTL模組",資料要從這邊看。
      仔細看一下電路圖比對你接的電路,我想你的線路應該裝反了 !

      刪除
  17. 請問,DHT11+DS18B20兩個感測器在ThingSpeak上要顯示數值的話用一個頻道就可以了嗎?

    回覆刪除
    回覆
    1. 一個頻道 (channel) 可以使用 6 個欄位 (field),DHT11+DS18B20 用一個頻道就夠用 !

      刪除
  18. 我想問一下有辦法利用thingspeak來控制燈泡之類的嗎???還是esp8266就只能用區網來控制家電?

    回覆刪除
    回覆
    1. 當然可以! 將狀態丟到 thingspeak 去,然後 ESP8266 再去讀取資料集中最後一筆資料來變更燈泡狀態。thingspeak 一般用來儲存與時間有關係的數據,若是要從遠端控制燈泡狀態,可以使用 MQTT,這比較符合你的需要。
      若是要使用外部網路與 ESP8266 連線,直接控制 ESP8266 當然也可以,類似在電腦架 WebServer 一樣 ! 使用 ESP8266 它本身就可以是 WebServer,但是為了讓外部網路知道它的連線網址,那麼就需要登記一個網路名稱才能讓人連進來(DNS);再者,由於 ESP8266 是掛在路由器下面的內部網路,所以要在路由器設定轉址,這樣連進到你的路由器 IP,路由器根據傳進來的 PORT 就會轉到你的 ESP8266 去。
      大抵上就是這樣 !

      刪除
  19. 版主

    上傳成功 IoT_Demo 程式執行 在 COM 視窗反覆出現下列提示 ThingSpeak 毫無動靜 請問 如何修改才對? 謝謝你!!


    AT+CIPSTART="TCP","184.106.153.149",80
    AT+CIPSEND=65
    AT+CIPCLOSE
    AT+CIPSTART="TCP","184.106.153.149",80
    AT+CIPSEND=65
    AT+CIPCLOSE

    回覆刪除
  20. 感謝 試好了 現在看到的問題是 TTL-->USB 雖然連上, 但是在 PC 跑 SSCOM3.2,exe 卻抓不到資料. 已經把 TX/RX 交換, 重開機, 切換 COM6/COM7, Baudrate 9600/115200 都試過了, 無效! 不知道漏了什麼步驟? 請指點一下 謝謝!!

    回覆刪除
    回覆
    1. 先確認裝置管理員有正確安裝 "USB轉 TTL 模組",COM Port 旁邊不能有驚嘆號!

      刪除
  21. In file included from C:\Users\Administrator\Documents\Arduino\libraries\DHT-sensor-library-master\DHT_U.cpp:22:0:

    C:\Users\Administrator\Documents\Arduino\libraries\DHT-sensor-library-master\DHT_U.h:25:29: fatal error: Adafruit_Sensor.h: No such file or directory

    #include

    不好意思 請問一下這是什麼狀況..

    回覆刪除
    回覆
    1. 你應該是下載到最新的版本 1.3.0 ! 因為網頁提供的是最新下載版本的連結,我剛剛去查了一下發現現在這個版本有 Bug,而且我下載編譯之後會出現其他的錯誤,詳細可看這個連結的(http://bit.ly/2i66Gy4)中的討論。

      為了方便使用者使用最新的版本,所以網頁連結放上最新版的下載連結;不過既然有出現問題,我會在上面網頁再增加一個可用的下載連結,等一下就可以上去下載試試 !

      刪除
  22. #include
    #include 3
    #include
    LiquidCrystal_I2C lcd(0x27,16,2);
    #define red 7
    #define green 8
    #define blue 9
    #define DEBUG
    #define _baudrate 9600

    // USB TTL 偵錯用
    #define _rxpin 0
    #define _txpin 1
    SoftwareSerial debug( 0,1); // RX, TX

    // DHT溫溼度感測器
    #include
    #define dht_dpin A0
    dht DHT;
    byte bGlobalErr;
    byte dht_dat[5];

    // ESP8266 Wifi晶片
    #define SSID "ASUS"
    #define PASS "38902147"
    #define IP "184.106.153.149" // ThingSpeak的IP
    // 使用 GET 傳送資料的格式
    String GET = "GET /update?key=QOZDLWAW635QA4UK";

    void setup() {
    InitDHT();
    Serial.begin( _baudrate );
    debug.begin( _baudrate );
    delay(300);
    sendDebug("AT");
    delay(5000);
    if(Serial.find("OK"))
    {
    debug.println("RECEIVED: OK\nData ready to sent!");
    connectWiFi();
    }
    delay(700);
    lcd.init(); // initialize the lcd
    //pinMode(FAN,OUTPUT);
    pinMode(4,OUTPUT);
    pinMode(5,OUTPUT);
    pinMode(7,OUTPUT);
    pinMode(8,OUTPUT);
    pinMode(9,OUTPUT);
    // Print a message to the LCD.
    lcd.backlight();

    Serial.begin(9600);
    delay(700);//Wait rest of 1000ms recommended delay before
    DHT.read11(dht_dpin); //去library裡面找DHT.read11
    int A=DHT.humidity;
    lcd.setCursor(0,0);
    lcd.print("Hum= ");
    lcd.print(A);
    lcd.print("% ");
    lcd.setCursor(0,1);
    lcd.print("tem= ");
    int TEMP=DHT.temperature;
    lcd.print(DHT.temperature);
    lcd.println("C ");
    delay(1000); //每1000ms更新一次
    if((TEMP<20)){
    digitalWrite(blue,HIGH);
    digitalWrite(green,LOW);
    digitalWrite(red,LOW);
    }
    else if((TEMP>=21)&&(TEMP<=35)){
    digitalWrite(green,HIGH);
    digitalWrite(blue,LOW);
    digitalWrite(red,LOW);
    analogWrite(3, 127);


    }
    else {
    digitalWrite(red,HIGH);
    digitalWrite(green,LOW);
    digitalWrite(blue,LOW);
    analogWrite(3, 255);

    }
    }
    void loop() {
    ReadDHT();


    String TT,HH;
    HH = String(dht_dat[0])+'.'+String(dht_dat[1]);
    TT = String(dht_dat[2])+'.'+String(dht_dat[3]);
    updateDHT11( TT, HH );
    #ifdef DEBUG
    debug.print("Humidity: ");
    debug.print( HH );
    debug.print(" %\t");
    debug.print("Temperature: ");
    debug.print( TT );
    debug.println(" *C\t");
    #endif


    delay(60000); // 一分鐘一次
    }

    回覆刪除
    回覆
    1. void updateDHT11( String T, String H )
      {
      // 使用AT指令上傳
      String cmd = "AT+CIPSTART=\"TCP\",\"";
      cmd += IP;
      cmd += "\",80";
      sendDebug(cmd);
      delay(2000);


      cmd = GET + "&field1=" + T + "&field2=" + H +"\r\n";
      Serial.print( "AT+CIPSEND=" );
      Serial.println( cmd.length() );
      if(Serial.find( ">" ) )
      {
      debug.print(">");
      debug.print(cmd);
      Serial.print(cmd);
      }
      else
      {
      sendDebug( "AT+CIPCLOSE" );
      }
      if( Serial.find("OK") )
      {
      debug.println( "RECEIVED: OK" );
      }
      else
      {
      debug.println( "RECEIVED: Error\nExit2" );
      }
      }

      void sendDebug(String cmd)
      {
      // 傳到 USB TTL
      debug.print("SEND: ");
      debug.println(cmd);
      Serial.println(cmd);
      }

      boolean connectWiFi()
      {
      // 連線到Wifi
      Serial.println("AT+CWMODE=1");
      delay(2000);
      String cmd="AT+CWJAP=\"";
      cmd+=SSID;
      cmd+="\",\"";
      cmd+=PASS;
      cmd+="\"";
      sendDebug(cmd);
      delay(5000);
      if(Serial.find("OK"))
      {
      debug.println("RECEIVED: OK");
      return true;
      }
      else
      {
      debug.println("RECEIVED: Error");
      return false;
      }

      cmd = "AT+CIPMUX=0";
      sendDebug( cmd );
      if( Serial.find( "Error") )
      {
      debug.print( "RECEIVED: Error" );
      return false;
      }
      }
      void InitDHT(){
      // 初始化DHT
      pinMode(dht_dpin,OUTPUT);
      digitalWrite(dht_dpin,HIGH);
      }

      void ReadDHT(){
      bGlobalErr=0;
      byte dht_in;
      byte i;
      digitalWrite(dht_dpin,LOW);
      delay(20);

      digitalWrite(dht_dpin,HIGH);
      delayMicroseconds(40);
      pinMode(dht_dpin,INPUT);

      dht_in=digitalRead(dht_dpin);

      if(dht_in){
      bGlobalErr=1;
      return;
      }
      delayMicroseconds(80);
      dht_in=digitalRead(dht_dpin);

      if(!dht_in){
      bGlobalErr=2;
      return;
      }
      delayMicroseconds(80);
      for (i=0; i<5; i++)
      dht_dat[i] = read_dht_dat();
      pinMode(dht_dpin,OUTPUT);
      digitalWrite(dht_dpin,HIGH);
      byte dht_check_sum =
      dht_dat[0]+dht_dat[1]+dht_dat[2]+dht_dat[3];
      if(dht_dat[4]!= dht_check_sum)
      {bGlobalErr=3;}
      };

      byte read_dht_dat(){
      byte i = 0;
      byte result=0;
      for(i=0; i< 8; i++){
      while(digitalRead(dht_dpin)==LOW);
      delayMicroseconds(30);
      if (digitalRead(dht_dpin)==HIGH)
      result |=(1<<(7-i));
      while (digitalRead(dht_dpin)==HIGH);
      }
      return result;
      }

      刪除
    2. 上面兩個是我的程式請問他有什麼衝突嗎??
      只能顯示在LCD上,不能上傳溫溼度值

      刪除
    3. 以上兩個是我的程式
      他只能顯示到LCD不能上傳thingspeak值
      我該如何修改??

      刪除
  23. 上面兩個是我的程式,他只能顯示在LCD不能上傳到thingspeak值
    程式有什麼衝突嗎??因為程式沒有顯示在LCD時是可以上傳值
    我該如何修改?

    回覆刪除
    回覆
    1. 要先確認手動連線到 Thingspeak 是否可以手動輸入值。再來就是確認你的網路端連線都是正常的;否則能抓到溫溼度的值,不表示能夠連線到 thingspeak 上傳資料!

      刪除
  24. 版主您好:
    我有在賣場購買IOT套件,目前在測試這個網頁的程式碼
    我遇到的問題比較奇怪,我有先設定一組SSID與密碼,並且有成功連線
    但是我將手機密碼換掉後(程式內有同步更改),卻沒有成功連線,換了2~3組都一樣不行
    但再換回一開始設定那組又連成功了
    想請問這個問題可能發生的原因,或我該如何解決?

    感謝幫忙



    回覆刪除
    回覆
    1. 如果是將手機設成無線基地台,要開啟"可供搜尋"的選項,不然可能找不到!
      但也有可能是你的手機與 ESP8266 都是連線到家中同一台無線 AP 上,所以就需要設定該無線 AP 的 SSID 與密碼,而不是手機的密碼。
      這兩個地方要確認一下,應該就沒有問題了!

      刪除
  25. 版主你好! 我想請教關於您所寫的程式
    void sendDebug(String cmd)
    {
    debug.print("SEND: ");
    debug.println(cmd);
    Serial.println(cmd);
    }
    可以幫我解釋一下其中的CMD是跟前面的CMD是同一個東西嗎?
    還有寫這段的用意為何?
    小的我第一次接觸IOT所以還請賜教

    回覆刪除
    回覆
    1. debug.println(cmd); // 將 cmd 裡的內容輸出到 bebug 串列埠
      Serial.println(cmd); // 將 cmd 裡的內容輸出到與 esp8266

      刪除
    2. 傳送到esp8266不是使用這個?SoftwareSerial debug( _rxpin, _txpin ); // RX, TX
      所以應該是 debug.println(cmd); // 將 cmd 裡的內容輸出到 esp8266串列埠 才是吧?
      還是說SoftwareSerial debug( _rxpin, _txpin ); // RX, TX這個宣告是做USB轉ttl的監控腳位?

      刪除
    3. 程式要對應電路圖去看,程式中腳位的宣告對應到電路圖上就不難了解! 既然寫 debug 就是作為除錯用,ESP8266 是接到 Arduino 板上面的硬體 TX = D0 跟 RX = D1,一些文字訊息則是由 D2/D3 這個串列埠輸出。

      刪除
    4. 所以esp8266是直接用0、1這兩腳座傳送和接收?
      然而debug是用宣告的兩隻腳位做接收盒傳送就對了!

      刪除
    5. 對! 直接接好線燒好程式做測試,就會比較清楚了!

      刪除
    6. 說道測試,版主我一直有個問題,就是我使用AT指令測試的程式碼如下,不管輸入何種指令,都沒有反應,TX RX都確定沒接錯,但是從監控列窗做AT測試,ESP8266完全沒有任何反應和回復,但使用USB轉TTL卻是可以下達AT指令,並且正常回復,不知版主使否遇過這種問題,或是知道該如何解決,我也參考過 操控 ESP8266 無線模組 - 經由 AP、STA 和 AP+STA 三種模式,學習 ESP8266 AT 指令 這篇文章
      程式碼 :
      #include // 引用程式庫

      SoftwareSerial ESP(3, 2); // 接收腳, 傳送腳

      void setup() {
      Serial.begin(9600); // 與電腦序列埠連線,也能改成115200
      ESP.begin(9600); // 與ESP-01模組連線或採用115200
      Serial.println("Serial is ready!");
      Serial.println("");
      }

      void loop() {
      // 若收到「序列埠監控視窗」的資料,則送到ESP-01模組。
      if (Serial.available()) {
      ESP.print(Serial.read());
      }

      // 若收到ESP-01模組的資料,則送到「序列埠監控視窗」。
      if (ESP.available()) {
      Serial.print(ESP.read());
      }
      }

      刪除
    7. 如果你有仔細讀過網頁與問與答中的討論,你提出的這個問題應該不論是在網頁中或是問與答中已經有解答與解決方法 !
      網頁最下面補充的更新裡有附上這個問題討論與解決方法的討論郵件。

      刪除
    8. AT+CIPSTART="TCP","184.106.153.149",80

      CONNECT

      OK
      AT+CIPSEND=


      OK
      > ET /update?key=DUKST8GWAURKK1R0&field1=1

      busy s...

      Recv 0 bytes
      SEND FAIL
      CLOSED
      是哪裡出錯?我測試了好久,都出現FAILD,我是用USB轉TTL模組測試,也已經連上WIFI

      刪除
    9. 這個輸出好像不對 > ET /update?key=DUKST8GWAURKK1R0&field1=1
      如果有修改程式過,檢查一下吧!

      刪除
    10. 我重試了一下 結果如下:
      AT+CIPSTART="TCP","184.106.153.149",80

      CONNECT

      OK
      AT+CIPSEND=


      OK
      > GET/update?key=DUKST8GWAURKK1R0&field2=1

      busy s...

      Recv 0 bytes
      SEND FAIL
      一樣usb轉ttl模組測試
      以下是我的指令
      1 AT+CIPSTART="TCP","184.106.153.149",80
      2 AT+CIPSEND=
      3 GET/update?key=DUKST8GWAURKK1R0&field2=1

      刪除
    11. 像這種指令的問題,網頁一開始就說的很清楚了! 一定要先確認可以由網址列手動輸入這些數值成功之後,才能確保接下來使用 AT 指令和執行程式時能夠正確!

      AT+CIPSEND=## 後面要接要輸入的字元數目,但你後面沒有加,不曉得你是省略還是忘了寫! AT 指令的操作請參考部落格另一個網頁中的說明,上面有實際操作範例;這網頁的問與答也有其他使用者的操作,自己看看吧!

      刪除
    12. 我經過網頁測試都正常
      另外字元數我更改之後 指令如下
      AT+CIPSEND=40


      OK
      > 5

      busy s...

      Recv 40 bytes

      SEND OK

      +IPD,323:HTTP/1.1 400 Bad Request
      Server: nginx/1.7.5
      Date: Sat, 11 Mar 2017 15:55:07 GMT
      Content-Type: text/html
      Content-Length: 172
      Connection: close
      和一串HTML文字(不接受HTML 這網站)

      CLOSED
      我上thingspeak發現數值並未改變 跪求教學

      刪除
    13. GET /update?key=DUKST8GWAURKK1R0&field2=1
      ^ 空一格
      最後面還要加上 \r\n 兩個字元,所以應該是 AT+CIPSEND=43

      網址手動輸入如果是正常,那麼最大的問題就是 AT 指令輸入有問題;其實值接使用程式碼測試應該就可以成功!

      刪除
    14. 測試成功!
      我應用了版主的程式如下:
      if(digitalRead(re1) == 0 && digitalRead(HG_switch) == 1)
      {
      digitalWrite(LED_R1 ,LOW);
      digitalWrite(LED_G1 , HIGH);
      String cmd1 = "AT+CIPSTART=\"TCP\",\"";
      cmd1 += IP;
      cmd1 += "\",80";
      sendDebug(cmd1);
      delay(1000);
      if( Serial.find( "Error" ) )
      {
      debug.print( "RECEIVED: Error\nExit1" );
      return;
      }
      cmd1 = GET + "&field1=1" +"\r\n";
      Serial.print( "AT+CIPSEND=" );
      Serial.println( cmd1.length() );
      delay(100);
      if(Serial.find( ">" ) )
      {
      debug.print(">");
      debug.print(cmd1);
      Serial.print(cmd1);
      }
      else
      {
      sendDebug( "AT+CIPCLOSE" );
      }
      delay(100);
      if( Serial.find("OK") )
      {
      debug.println( "RECEIVED: OK" );
      }
      else
      {
      debug.println( "RECEIVED: Error\nExit2" );
      }
      }
      if(digitalRead(re2) == 0 && digitalRead(HG_switch) == 1)
      {
      digitalWrite(LED_R2 ,LOW);
      digitalWrite(LED_G2 , HIGH);
      String cmd2 = "AT+CIPSTART=\"TCP\",\"";
      cmd2 += IP;
      cmd2 += "\",80";
      sendDebug(cmd2);
      delay(1000);
      if( Serial.find( "Error" ) )
      {
      debug.print( "RECEIVED: Error\nExit1" );
      return;
      }
      cmd2 = GET + "&field2=1" +"\r\n";
      Serial.print( "AT+CIPSEND=" );
      Serial.println( cmd2.length() );
      delay(100);
      if(Serial.find( ">" ) )
      {
      debug.print(">");
      debug.print(cmd2);
      Serial.print(cmd2);
      }
      else
      {
      sendDebug( "AT+CIPCLOSE" );
      }
      delay(100);
      if( Serial.find("OK") )
      {
      debug.println( "RECEIVED: OK" );
      }
      else
      {
      debug.println( "RECEIVED: Error\nExit2" );
      }
      }
      我所遇到的問題如下:
      我將 re1接地、hg_switch 接HIGH ,並且有成功上傳THINGSPEAK
      然後我將 re1、hg_switch復位(re1 high、hg_switch low)
      但是我將re2接地、hg_switch接high,但在監控序列卻傳回
      AT+CIPSTART="TCP","184.106.153.149",80
      AT+CIPSEND=43
      AT+CIPCLOSE
      這是怎麼回事?要如何解決?

      刪除
  26. 他們是 輸入角位
    我是要讓他們達到我所設定的狀態才做上傳動作
    所以簡單來說我做了一次的上傳,做第二次時卻會失敗出現
    AT+CIPSTART="TCP","184.106.153.149",80
    AT+CIPSEND=43
    AT+CIPCLOSE

    回覆刪除
    回覆
    1. 可以反過來試一下先做第二個條件是再做第一個,看看是不是一樣的情況!

      刪除
    2. 那跟我猜測的結果一樣!最大的可能是因為資料上傳間隔的問題造成,其實可以試一下拉長切換的時間試試,應該就不會,但也有可能時好時壞 !

      那兩個 if 判斷式可以整合成一個副程式來用,應該就可以解決這個問題 ! 如果不行,就要看一下程式是不是在時間間隔未到之前就重復上傳資料到 thingspeak, 這會造成錯誤的!

      刪除
    3. 謝謝版主指導,已經解決了這個問題,但問題一波未平一波起
      我現在做上傳的動作,在VOID SETUP的區塊做以下指令:
      String cmd0 = "AT+CIPSTART=\"TCP\",\"";
      cmd0 += IP;
      cmd0 += "\",80";
      sendDebug(cmd0);
      delay(200);
      if( Serial.find( "Error" ) )
      {
      debug.print( "RECEIVED: Error\nExit1" );
      return;
      }
      cmd0 = GET + "&field1=0&field2=0&field3=0&field4=0" + "r/n";
      Serial.print( "AT+CIPSEND=" );
      Serial.println( cmd0.length() );
      delay(100);
      if(Serial.find( ">" ) )
      {
      debug.print(">");
      debug.print(cmd0);
      Serial.print(cmd0);
      }
      else
      {
      sendDebug( "AT+CIPCLOSE" );
      }
      if( Serial.find("OK") )
      {
      debug.println( "RECEIVED: OK" );
      }
      else
      {
      debug.println( "RECEIVED: Error\nExit2" );
      }
      但是我從thingspeak中看field4的狀態卻出現field4:0r
      這是怎麼回事?

      刪除
    4. cmd0 = GET + "&field1=0&field2=0&field3=0&field4=0" + "r/n";
      仔細看一下上面這一行,對照一下,就不難發現哪邊寫錯了!

      刪除
    5. 恩....我發現了....
      實在是演殘...

      刪除
  27. 版主您好
    以下是我用 Realterm 叫 esp8266 傳給 Thingspeak 的情況
    但 Thingspeak 卻回傳 400 Bad Request
    之前試過一樣的步驟似乎沒問題 但是之後卻不行了
    是不是有遺失字元或其他原因
    麻煩版主指導 ((一個小新手看網頁做的實驗

    OK
    > // GET /update?api_key=ZKANMZVA3YINU7L9&field1=5&field2=7
    Recv 56 bytes

    SEND OK

    +IPD,172:
    400 Bad Request

    400 Bad Request
    nginx/1.7.5


    CLOSED

    回覆刪除
    回覆
    1. http://api.thingspeak.com/update?api_key=ZKANMZVA3YINU7L9&field1=10&field2=15
      這個的格式是對的,剩餘的就是指令下的問題,這參照上面的問與答,有相關的例子可以參考!

      刪除
  28. 版主你好
    請問如果想要自己寫一個asp.net的網站,接收arduino的資料
    有相關的資訊嗎? 謝謝

    回覆刪除
  29. 沒有!
    若是單純要用電腦架 web server 來接收 Arduino 的資料,主要就是要看怎麼去收 Arduino 傳過來的資料,可以是直接由 Serial 接收,也可以經由網路的方式。
    前者應該就是寫 PC 端的 RS232 程式接收資料再反應到網站上;後者的處理就是使用 CGI 的方式去處理後台,也就是處理傳送過來 Get 或是 post 資料,可以用 PHP 或是 JavaScript 去處理或是其他可用的程式語言。
    以上,提供作參考 !

    回覆刪除
  30. 版主,你好
    我想請問,我手機可以連的wifi和密碼,套用到這裡的SSID、PASS 是可以的嗎??
    UART 我的畫面都沒有AT+CWJAP

    UART指令畫面如下:
    SEND: AT

    OK
    SEND: AT+CIPSTART="TCP","184.106.153.149",80

    OK
    Linked
    SEND: AT+CIPCLOSE

    OK
    Unlink
    RECEIVED: Error
    Error
    Exit2

    Error
    Humidity: 48 % Temperature: 24 *C


    回覆刪除
    回覆
    1. 若照著網頁中的步驟做,且確定手動輸入沒有問題,但輸出與網頁不一樣時,就是與 ESP8266 間的接線出現問題!
      相關檢查的步驟請自行參閱問與答中的說明。

      刪除
  31. 您好 我最近收集了一批資料,之前可以從DATA import/export處進行下載
    不過今日卻發現他無法直接下載,而且還需要寄信給到他們的信箱
    我剛剛計過去後系統告訴我他們的信箱已經滿了
    想請問一下您對這問題有解答嗎 感恩

    回覆刪除
    回覆
    1. 即使不能直接下載,但是在 "DATA import / export" 網頁頁面下的右半部說明了可以使用 HTTP GET 的方式來取得 Channel 上面的部分或是全部的數據,例如使用下面網頁中所提及的方法
      https://www.mathworks.com/help/thingspeak/readdata.html
      假設 channel 號碼是 14725,要取得所有 Fields 的數據 (假設數據點共有 350 點),並以 CSV 的方式回傳,可在網址列輸入:
      https://api.thingspeak.com/channels/14725/feeds.csv?results=350
      可得到類似下面的 CSV 數據資料
      -------------------------------------
      created_at,entry_id,field1,field2
      2017-01-04 09:10:31 UTC,1,23,60
      2017-01-04 09:11:32 UTC,2,23,61
      2017-01-04 09:12:32 UTC,3,23,61
      ...
      2017-01-04 15:02:11 UTC,348,28,44
      2017-01-04 15:03:10 UTC,349,28,44
      2017-01-04 15:04:11 UTC,350,29,43
      -------------------------------------
      若要限定時間點(2018/08/20 10:01:02 ~ 2018/08/26 15:04:05,則輸入
      https://api.thingspeak.com/channels/14725/feeds.csv?start=2018-08-20%2010:01:02&end=2018-08-26%2015:04:05
      使用這樣的方式就可取得 Channel 裡面的資料,更詳細的資料請自行參考上述網頁裡面的說明。

      刪除
  32. 老師您好~ 我想請教老師為什麼資料上傳一段時間之後會失敗會是回傳 error 的問題,硬體的部分,有接電源模組以及電壓準位轉換器,所以排除電源不足的問題,還是說會是esp8266模組韌體的問題,我有用AT v1.2.0.0 SDK v1.5.4.1版本是過也一樣,會是程式上的問題嗎?我不太清楚什麼原因造成的,這問題我卡很久了,希望老師能幫我解答,該如何解決 謝謝~
    SSID跟PASS就略過,上傳的資料是簡單的電阻分壓,再透過MCU去讀取它的AD值
    ----------------------------------------------------------------------------------------------------------------
    #include
    #include
    #define _baudrate 9600
    #define _rxpin 3
    #define _txpin 2
    SoftwareSerial debug( _rxpin, _txpin ); // RX, TX
    //*-- IoT Information
    #define SSID "帳" //WIFI的AP Name
    #define PASS "密" //WIFI的AP pwsd
    #define IP "184.106.153.149" // ThingSpeak IP Address: 184.106.153.149
    // 使用 GET 傳送資料的格式
    // GET /update?key=[THINGSPEAK_KEY]&field1=[data 1]&filed2=[data 2]...;
    String GET = "GET /update?key=WZB4X9K5GDIOBLUH";
    float deg=0;
    float rad=deg*PI/180;
    byte i=0;

    void setup() {
    Serial.begin( _baudrate );
    debug.begin( _baudrate );
    sendDebug("AT");
    Loding("sent AT");
    connectWiFi();
    }
    void loop() {
    delay(5000); // 60 second 5000 , 2500 =30sec
    SentOnCloud( String(analogRead(15)), String(analogRead(15)) ); //SEND DATA 5 AND 9
    //delay(2500); // 60 second 5000 ,, 2500 =30sec
    //SentOnCloud( String(-5), String(-9) ); //SEND DATA 5 AND 9

    /*
    for (i=100;i<=200;i=i+5) {
    randomSeed(i);
    deg==random(180);
    rad=deg*PI/180;
    SentOnCloud( String(10*sin(rad)), String(-10*cos(rad))); //SEND DATA sin(rad) AND cos(rad)
    delay(2500); // 60 second 5000 ,, 2500 =30sec

    } */

    }
    boolean connectWiFi()
    {
    debug.println("AT+CWMODE=1");
    Wifi_connect();
    }

    void SentOnCloud( String T, String H )
    {
    // 設定 ESP8266 作為 Client 端
    String cmd = "AT+CIPSTART=\"TCP\",\"";
    cmd += IP;
    cmd += "\",80";
    sendDebug(cmd);
    if( debug.find( "Error" ) )
    {
    Serial.print( "RECEIVED: Error\nExit1" );
    return;

    }
    cmd = GET + "&field1=" + T + "&field2=" + H +"\r\n";
    debug.print( "AT+CIPSEND=" );
    debug.println( cmd.length() );
    if(debug.find( ">" ) )
    {
    Serial.print(">");
    Serial.print(cmd);
    debug.print(cmd);
    }
    else
    {
    debug.print( "AT+CIPCLOSE" );
    }
    if( debug.find("OK") )
    {
    Serial.println( "RECEIVED: OK" );
    }
    else
    {
    Serial.println( "RECEIVED: Error\nExit2" );
    }
    }
    void Wifi_connect()
    {
    String cmd="AT+CWJAP=\"";
    cmd+=SSID;
    cmd+="\",\"";
    cmd+=PASS;
    cmd+="\"";
    sendDebug(cmd);
    Loding("Wifi_connect");
    }
    void Loding(String state){
    for (int timeout=0 ; timeout<10 ; timeout++)
    {
    if(debug.find("OK"))
    {
    Serial.println("RECEIVED: OK");
    break;
    }
    else if(timeout==9){
    Serial.print( state );
    Serial.println(" fail...\nExit2");
    }
    else
    {
    Serial.print("Wifi Loading...");
    delay(500);
    }
    }
    }
    void sendDebug(String cmd)
    {
    Serial.print("SEND: ");
    Serial.println(cmd);
    debug.println(cmd);
    }

    回覆刪除
    回覆
    1. 抱歉 我不懂老師意思,什麼是LOG?

      刪除
    2. 就是程式執行時候的輸出!
      請先花時間看一下上面的問與答,或許就會有你要的答案。

      刪除
  33. 老師你好 我想問一下
    目前我先把WIFI 燒到ESP-01s裡面了
    那我上傳THINGSPEAK的語法是要打在UNO上嗎?
    還是ESP裡面??
    謝老師

    回覆刪除
    回覆
    1. 這網頁裡面的程式碼式是上傳到 Arduino UNO 開發板的,ESP-01S 是被 AT 指令控制的受控端,不需要對它上傳任何程式。

      刪除
  34. 您好,我本身不會寫程式...但看了您的文章學Arduino之後,我用ESP32抓取JSON資料和溫溼度上傳hingSpeak,目前想結合2個程式碼,抓取雨量資料的JSON然後上傳hingSpeak,但怎樣編譯都失敗請問可以教我該怎麼弄嗎? 以下是我改的
    #include
    #include
    #include
    #include
    #include
    LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
    //請修改以下參數--------------------------------------------
    char ssid[] = "a310";//
    char password[] = "01919803";//
    char url[] = "https://data.wra.gov.tw/Service/OpenData.aspx?format=json&id=F7C0788D-F513-472D-A80E-1C6372C2FBA5"; //讀取的網址
    String url = "http://api.thingspeak.com/update?api_key=H8KG3DK1IT0ETUXA&field1=0";//請修改為自己的API Key,並將https改為http
    //---------------------------------------------------------

    void setup()
    {
    // wait for WiFi connection
    if ((WiFiMulti.run() == WL_CONNECTED))
    {
    Serial.println("Connected...");
    HTTPClient http;//啟動http client物件
    Serial.println("開始讀取資料");
    http.begin(url); //HTTP取得網頁內容

    Serial.print("[HTTP] GET...\n");
    // start connection and send HTTP header
    int httpCode = http.GET();//了解連線狀態

    // httpCode will be negative on error
    if (httpCode > 0)
    {
    Serial.println(httpCode);
    // file found at server
    if (httpCode == HTTP_CODE_OK)
    {
    String payload = http.getString();//讀取網頁內容到payload
    Serial.print("payload=");
    //payload=payload.substring(0,200);//只擷取前面兩百個字
    Serial.println(payload);
    }
    }
    else //讀取失敗
    {
    Serial.println("[HTTP] GET... failed");
    }

    http.end();
    }

    delay(20000);
    }
    {
    Serial.begin(115200);
    lcd.init(); // initialize the lcd
    lcd.backlight();//open light
    Serial.print("開始連線到無線網路SSID:");
    Serial.println(ssid);
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
    }
    Serial.println("連線完成");
    }

    void loop()
    {
    Serial.print("使用核心編號:");
    Serial.println(xPortGetCoreID());
    //嘗試讀取雨量內容
    byte HourlyRain = 0;
    byte EffectiveWaterStorageCapacity = 0;
    int err = SimpleDHTErrSuccess;
    Serial.print("雨量讀取失敗,錯誤碼="); Serial.println(err); delay(1000);
    return;
    }
    //讀取成功,將溫濕度顯示在序列視窗
    Serial.print("雨量讀取成功: ");
    Serial.print((int)HourlyRain); Serial.print(" *C, ");
    Serial.print((int)EffectiveWaterStorageCapacity); Serial.println(" H");
    lcd.init();
    lcd.setCursor(0, 0);
    lcd.print("HourlyRain:");
    lcd.setCursor(12, 0);
    lcd.print((int)EffectiveWaterStorageCapacity);
    lcd.setCursor(14, 0);
    lcd.print("\xDF""C");


    lcd.setCursor(0, 1);
    lcd.print("HourlyRain:");
    lcd.setCursor(12, 1);
    lcd.print((int)EffectiveWaterStorageCapacity);
    lcd.setCursor(14, 1);
    lcd.print("%");
    //開始傳送到thingspeak
    Serial.println("啟動網頁連線");
    HTTPClient http;
    //將溫度及濕度以http get參數方式補入網址後方
    String url1 = url + "&field1=" + (int)HourlyRain + "&field2=" + (int)EffectiveWaterStorageCapacity;//請修改為你自己想上傳的參數
    //http client取得網頁內容
    http.begin(url1);
    int httpCode = http.GET();
    if (httpCode == HTTP_CODE_OK) {
    //讀取網頁內容到payload
    String payload = http.getString();
    //將內容顯示出來
    Serial.print("網頁內容=");
    Serial.println(payload);
    } else {
    //讀取失敗
    Serial.println("網路傳送失敗");
    }
    http.end();
    delay(20000);//休息20秒
    }

    回覆刪除
    回覆
    1. 我重新整理了一下上面的程式碼,發現這程式基本上的架構已經不對,應該連編譯都過不了!

      如果是初學者,建議直接使用部落格上的程式碼下去改,去了解整個流程後再試著自己去做內部修改才會比較不容易出錯!

      刪除

留言屬名為"Unknown"或"不明"的用戶,大多這樣的留言都會直接被刪除掉,不會得到任何回覆!

發問問題,請描述清楚你(妳)的問題,別人回答前不會想去 "猜" 問題是什麼?

不知道怎麼發問,請看 [公告] 部落格提問須知 - 如何問問題 !