黃承毅 HUANG CHENG YI N26111766
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- tags: 單晶片助教 --- # **[10] TCP/IP** ## **課程大綱** [ToC] --- # **1. TCP/IP** ## 簡介 TCP/IP 是一種網際網路的基礎通訊架構,其內容主要分為 TCP (Transmission Control Protocol/傳輸控制協定) 還有 IP (Internet Protocol/網際網路協定)。 TCP/IP架構主要由四個層所組成,分別是: 1. Application Layer (應用層) 2. Transport Layer (傳輸層) 3. Internet Layer (網際網路層、網路層) 4. Network Access Layer (網路存取層) 通常我們在 messenger、Line 等傳送訊息,是在應用層輸入訊息,而這個訊息會經由傳輸層、網際網路層、網路存取層,一層層的將訊息打包成封包,並將這個封包發送出去。就好比在寫信時,必須寫好信件內容,並放入信封,寫上地址、收件者等資訊,才有辦法寄送出去。而 TCP/IP 四層架構,也是在做相同的事。 ![](https://i.imgur.com/IhmFybI.png) | 層級 | 協定種類 | 功能 | | -------- | --------- | -------- | | Application Layer (應用層) | HTTP、FTP、MQTT|定義應用專屬資料格式| | Transport Layer (傳輸層) | TCP、UDP |定義傳輸方式| | Internet Layer (網際網路層) | IP |定義收發位置| | Network Access Layer (網路存取層) | MAC|提供定址及媒體存取的控制方式| 其中,我們會較著眼在 Transport Layer (傳輸層),以及 Internet Layer (網際網路層)。 **傳輸層 Transport Layer** 在傳輸層中有兩種比較常用的協定,分別為UDP (User Datagram Protocol)、TCP (Transmission Control Protocol)。其中以 TCP 為大宗。 大部分的網路協定都是建立在 TCP 協定之上,因為 TCP 有著高度可靠性。而 TCP 的高度可靠是建立在TCP的三次握手 (three-way handshake)規則上。當 TCP 在建立連接通道的過程,資料會互相來回傳送三次,以確保對方是否有接收到。 **網際網路層 Internet Layer** 在此層裡面,是將 IP 資料 (Internet Protocol) 再包裝到訊息封包內,而 IP 資料就是將訊息上標記,該訊息是從誰傳送出來,還有要將訊息傳給誰。 常見的IP協定有兩種,一是 IPv4,二則是 IPv6,兩者最大的差別在於 IPv4 是 32bits,IPv6 則是 64bits。 此協定內有一段資料是 IP Address,IP Address 就是說明該訊息是從哪個位置傳送出來的。其中 IP 有分為以下幾種類型: 固定 IP:固定的 IP,企業、學校等都是使用固定 IP,這樣方能確保使用者可以連上伺服器。 浮動 IP:在每次連網的時的 IP 位置都不一樣,一般的使用者跟家用電腦大部分都是浮動 IP。 虛擬 IP:僅能使用於內部網路 (或是區域網路),外網是連不上的。 # **2. Wi-Fi** WiFi.h 為 Arduino IDE 內建程式庫,提供 4 種 WiFi 模式可用: | 語法 | WI-FI模式 | 功能 | | -------- | -------- | -------- | | WiFi.mode(WIFI_AP); | Access Point (AP) | ESP32 可以讓其他設備透過 Wi-Fi 接入(就像家裡的 Wi-Fi 基地台,可供手機連線)。 | | WiFi.mode(WIFI_STA); | Station(STA) | 無線終端模式,也就是讓 ESP32 可以連接上其他的熱點(就像手機一樣,可以連上家裡 Wi-Fi)。 | | WiFi.mode(WIFI_AP_STA); | AP+STA | 將 ESP32 設置成兩個模式並存。 | | WiFi.mode(WIFI_OFF); | OFF | 關閉 Wi-Fi。 | ## 將 ESP32 連接至 Wi-Fi * 程式碼: ```c++= #include <WiFi.h> //Wi-Fi 程式庫 const char* ssid = "Wi-Fi 網路名稱"; //Wi-Fi 網路名稱 const char* password = "Wi-Fi 密碼"; //Wi-Fi 密碼 void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); //設置 Wi-Fi 模式 WiFi.begin(ssid, password); Serial.print("Wi-Fi Connecting"); //當 Wi-Fi 連線時會回傳 WL_CONNECTED,因此跳出迴圈時代表已成功連線 while(WiFi.status() != WL_CONNECTED){ Serial.print("."); delay(500); } Serial.println(""); Serial.print("Wi-Fi Connected."); } void loop() { } ``` ## Lab 1-1: ### 獲取網路時間 * 實驗目的:學習於 ESP32 上使用 Wi-Fi。 * 實驗目標:透過 Wi-Fi 取得網路時間,並顯示於 LCD 螢幕上。 * 範例程式碼: ```c++= #include <WiFi.h> //Wi-Fi 程式庫 #include <Wire.h> //I2C 程式庫 #include <LiquidCrystal_I2C.h> //LCD_I2C 模組程式庫 LiquidCrystal_I2C lcd(0x27, 16, 2); const char* ssid = "Wi-Fi 網路名稱"; //Wi-Fi 網路名稱 const char* password = "Wi-Fi 密碼"; //Wi-Fi 密碼 const char *ntpServer = "pool.ntp.org"; //校時伺服器 const long gmtOffset_sec = 8*3600; //格林威治時間, GMT+8 就是 8*3600 const int daylightOffset_sec = 0; //日光調節時間, 有為 3600, 沒有則為 0 void setup(){ Serial.begin(115200); //初始化LCD //To do. //Connect to Wi-Fi //To do. //取得網路時間 configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); printLocalTime(); //連上拿到時間資料後就切斷連線 WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } void loop(){ delay(1000); printLocalTime(); } void printLocalTime(){ struct tm timeinfo; if(!getLocalTime(&timeinfo)){ Serial.println("Failed to obtain time"); return; } Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); //顯示於 LCD 螢幕 //To do. } ``` * 結果: <iframe width="560" height="315" src="https://www.youtube.com/embed/eKa7FWkbXng""YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ## LINE Notify ![](https://i.imgur.com/aZh10ba.png) * **LINE Notify 是一項非常方便的服務,用戶可以透過 LINE 接收GitHub、IFTTT 及 Mackerel 等網站服務的提醒。與網站服務連動完成後,LINE 所提供的官方帳號「LINE Notify」將會傳送通知。** ### 登入 Line Notify 取得 Token * 請先打開瀏覽器,並搜尋Line Notify,進入頁面後點擊登入。 ![](https://i.imgur.com/8f7Ltew.png) * 登入後,點擊相同地方,選擇個人頁面。 ![](https://i.imgur.com/yEbzz1V.png) * 點擊發行權杖。 ![](https://i.imgur.com/EcmcWGR.png) * 當出現這畫面時,就是開始申請權杖 (Token),所以請先輸入名稱,及選擇透過 1 對 1 聊天接收 Line Notify 的通知,都選擇好後點擊發行。 ![](https://i.imgur.com/wI410P2.png) * 發行後,會看到一條序號,這序號就是你的權杖(Token),請先把這權杖複製起來,之後會使用到。 ![](https://i.imgur.com/fzaLfXP.png) **<font color="Red">注意,該權杖只會顯示這次,所以請先把這權杖記錄起來,盡量複製起來貼上記事本上</font>** ### Arduino IDE 取得 TridentTD_LineNotify 程式庫 * 至程式庫管理員下載 "TridentTD_LineNotify",版本為 3.0.3 **<font color="Red">其餘版本會導致無法編譯。</font>** ![](https://i.imgur.com/AfFuFMS.png) ### Arduino IDE 取得 DHT11 程式庫 * 至程式庫管理員下載 "DHT sensor library",使用版本為 1.4.4。 ![](https://hackmd.io/_uploads/SyCIMvvE3.png) * 範例程式碼: ```c++= #include <WiFi.h> //Wi-Fi 程式庫 #include <TridentTD_LineNotify.h> //Line 程式庫 #define LINE_TOKEN "xxxxxxxxxxx" //修改成上述的 Token 號碼 const char* ssid = "Wi-Fi 網路名稱"; //Wi-Fi 網路名稱 const char* password = "Wi-Fi 密碼"; //Wi-Fi 密碼 void setup(void) { Serial.begin(115200); WiFi.mode(WIFI_STA); //設置 Wi-Fi 模式 WiFi.begin(ssid, password); Serial.print("Wi-Fi Connecting"); //當 Wi-Fi 連線時會回傳 WL_CONNECTED,因此跳出迴圈時代表已成功連線 while(WiFi.status() != WL_CONNECTED){ Serial.print("."); delay(500); } Serial.println(""); Serial.print("Wi-Fi Connected."); Serial.println(LINE.getVersion()); //顯示 Line 版本 LINE.setToken(LINE_TOKEN); //設定要傳送至的聊天室 Token } void loop(void) { //每一分鐘 (60000ms),傳送 "Hello" 至 Token 指定的聊天室 LINE.notify("Hello"); delay(60000); } ``` ## Lab 1-2: ### IOT 物聯網 * 實驗目的:學習於 ESP32 上使用 Wi-Fi,並透過 Line 傳送訊息。 * 實驗目標:使用 DHT11 讀取環境溫濕度,並透過 Wi-Fi 將訊息傳送至 Line。 * 接線圖: ![](https://i.imgur.com/lAmREQJ.png) * **DHT11 與其他感測器相比較為脆弱,若 VCC、GND 接反很快就會燒毀,在接線上必須特別注意** * 程式碼: <font color="Red">下方僅給予溫度的程式碼,需自行加入濕度的程式碼</font> ```c++= #include <WiFiClient.h> //WiFi 程式庫 #include <Wire.h> // I2C 程式庫 #include <TridentTD_LineNotify.h> //Line 程式庫 #include "DHT.h" // DHT11 程式庫 #define LINE_TOKEN "xxxxxxxxxxx" //修改成上述的 Token 號碼 #define DHTTYPE DHT11 #define DHTPIN 12 const char* ssid = "Wi-Fi 網路名稱"; //Wi-Fi 網路名稱 const char* password = "Wi-Fi 密碼"; //Wi-Fi 密碼 float humidity, temp_c; //從 DHT11 讀取的值 DHT dht(DHTPIN, DHTTYPE); //啟動 DHT 程式庫 void setup(){ Serial.begin(115200); dht.begin(); // Connect to Wi-Fi // To do. Serial.println(LINE.getVersion()); //顯示 Line 版本 LINE.setToken(LINE_TOKEN); //設定要傳送至的聊天室 Token } void loop(){ //讀取環境溫濕度 temp_c = dht.readTemperature(); //讀取溫度(攝氏) //To do. //傳送至 Token 的聊天室 //To do. } ``` * 結果: ![](https://i.imgur.com/xNFLZpu.png) # **3. ESP32 網頁應用** ## Http 介紹 超文字傳輸通訊協定 (HTTP) 是針對在網路上傳送內容而設計的通訊協定。 HTTP 是簡單的通訊協定,利用可靠的傳輸控制通訊協定 (TCP) 服務來執行其內容傳輸功能。 因此,HTTP 是高度可靠的內容傳輸通訊協定。 HTTP 是其中一個最常使用的應用程式協定。 Web 上的所有作業都會使用 HTTP 通訊協定。 ![](https://i.imgur.com/7OY3kOx.jpg) 使用者會發出 HTTP Request 跟伺服器索取資料,伺服器會回傳 HTTP Response 告知使用者網頁讀取的狀態 * HTTP Resuest Headers 儲存每個 HTTP Request 的核心資訊,例如:版本、語言、網址、編碼方式 * HTTP Resuest Method 告知伺服器要執行的動作,有 8 種動作可執行: * OPTIONS * GET:期望返傳回資訊(通常以網站的形式) * HEAD * POST:表示用戶端正在向伺服器提交資訊(例如表單資訊,如提交的使用者名稱和密碼)。 * PUT * DELETE * TRACE * CONNECT 最常使用的是 GET、POST * HTTP Response Status 告知 HTTP Resuest 是否完成的狀態代碼 * 1xx 資訊內容 * 2xx 成功 * 3xx 重新導向 * 4xx 用戶端錯誤 * 5xx 伺服器錯誤 ## Lab 2-1: ### ESP32 Wi-Fi Server * 實驗目的:學習使用 ESP32 建立 Wi-Fi server * 實驗目標:使用 DHT11 讀取環境溫濕度,並使用 ESP32 建立 server,使其他內網裝置的瀏覽器可觀看溫濕度資訊。 * 接線圖: ![](https://i.imgur.com/lAmREQJ.png) * **DHT11 與其他感測器相比較為脆弱,若 VCC、GND 接反很快就會燒毀,在接線上必須特別注意** * 使用 Library * WiFi.h * ESPAsyncWebServer.h * 不需要更新整個網頁就對局部數值更新 * 避免網頁收發延遲造成卡死 * 可以同時處理多個連線的收發 * 因為是非同步伺服器,連線部分不寫在 loop 裡,而是獨立運作的執行緒 * 不可使用讓整個程式停止運作的函數,例如:delay(),若要間隔一段時間要使用 millis() * 一個request只會有一個response * [程式庫連結](https://github.com/me-no-dev/ESPAsyncWebServer) * AsyncTCP * 配合 ESPAsyncWebServer.h 使用 * [程式庫連結](https://github.com/me-no-dev/AsyncTCP) * DHT.h * 程式碼: <font color="Red">下方僅給予溫度的程式碼,需自行加入濕度的程式碼</font> ```c++= #include <WiFi.h> #include <ESPAsyncWebServer.h> #include <DHT.h> // 定義 DHT 資料傳輸的腳位 #define DHTPIN 23 // 選擇使用的 DHT 溫溼度計種類 #define DHTTYPE DHT11 // DHT 11 //#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 //#define DHTTYPE DHT21 // DHT 21 (AM2301) DHT dht(DHTPIN, DHTTYPE); // 啟動 DHT 程式庫 const char* ssid = "Wi-Fi 網路名稱"; // Wi-Fi 網路名稱 const char* password = "Wi-Fi 密碼"; // Wi-Fi 密碼 // 初始化溫度與濕度的變數 float t = 0.0; float h = 0.0; // 建立一個非同步伺服器在通訊埠 80 AsyncWebServer server(80); // 紀錄量測間隔時間,因為數值較大,用 unsigned long unsigned long previousMillis = 0; // 每 n 秒量測,1000->1秒,2000->2秒 const long interval = 2000; // 建立網頁 // 網頁大小相對大但是架構不會變,一般存變數的動態記憶體不足 // 要存在儲存程式程序的flash記憶體中,所以呼叫PROGMEM const char index_html[] PROGMEM = R"rawliteral( <!DOCTYPE HTML><html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <!--設定字體--> <style> html { font-family: Arial; display: inline-block; margin: 0px auto; text-align: center; } h2 { font-size: 3.0rem; } p { font-size: 3.0rem; } .units { font-size: 1.2rem; } .dht-labels{ font-size: 1.5rem; vertical-align:middle; padding-bottom: 15px; } </style> </head> <!--建立網頁內容--> <body> <h2>ESP32 DHT11 Server</h2> <p> <span class="dht-labels">Temperature</span> <span id="temperature">%TEMPERATURE%</span> <sup class="units">&deg;C</sup> </p> </body> <script> setInterval(function ( ) { <!--將溫度資料傳入伺服器顯示在瀏覽器上--> var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("temperature").innerHTML = this.responseText; } }; xhttp.open("GET", "/temperature", true); xhttp.send(); }, 1000 ) ; </script> </html>)rawliteral"; // 抓取最新的溫溼度資料 String processor(const String& var) { //Serial.println(var); if (var == "TEMPERATURE") { return String(t); } return String(); } void setup() { // Serial port for debugging purposes Serial.begin(115200); // Connect to Wi-Fi // To do. // 查詢 ESP32 的 local IP 並印出,在瀏覽器輸入此 IP 即可看到畫面 // To do. server.begin(); // 在伺服器上建立網頁 server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/html", index_html, processor); }); //建立主網頁 server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest * request) { request->send_P(200, "text/plain", String(t).c_str()); }); //建立溫度顯示的網頁 server.begin(); // 啟動伺服器 dht.begin(); // 啟動 DHT 感測器 } void loop() { // 建立量測溫溼度的迴圈 // 因為網頁伺服器不能使用 delay 函數,所以用 millis // millis 用運算的次數來計算時間,更為準確,也不會阻擋程式運作 // delay 函數運作時會完全停止程式運作,使網頁伺服器出錯 //使用 DHT11 讀取環境溫濕度 //使用 millis 做間隔,每 2 秒讀一次 //To do. t = temperature; // t 為要給 server 的溫度變數,temperature 來自 DHT11 的讀值 Serial.print(F("Temperature: ")); Serial.println(t); } } ``` ## Lab 2-2: ### ESP32 外網連接 在 Lab2-1 中使用 ESP32 建立的 server 僅能用於內網 (同一個路由器底下的網路),為了使其他不同網域的裝置也能使用到 ESP32 作為處理器的資料,我們這邊會使用到另一種網路協定:MQTT #### MQTT (Message Queuing Telemetry Transport) * 以 TCP/IP 架構傳輸,專門用在效能低與網路不佳的環境 * MQTT Broker 作為伺服器,其他裝置作為 client 發送與訂閱訊息 * 資訊的傳輸是通過 topic 管理的。發布者發送資料給 broker 時會寫下資料的 topic,broker 則向訂閱此 topic 的客戶端分發此資料 * 發布者與訂閱者不需知道彼此是誰 * 可跨網域遠端運作 ![](https://i.imgur.com/3jYjIfw.png) #### QoS (Quality of Service) * 決定資料傳輸的驗證方式,會影響傳輸效能 | 服務品質 | 傳輸方式 | 說明 | | -------- | -------- | -------- | | QoS0 | 最多一次傳輸 | 只負責發送,送後不理 | | QoS1 | 至少一次傳輸 | 確認資料發送,確認前不停發送 | | QoS2 | 正好一次傳輸 | 保證資料交付成功,且只發送一次 | #### Retained Message * Topic 會保存最新的訊息,確保新連上或重連的訂閱者都能收到最新的訊息 * 使用Library * WiFi.h * PubSubClient.h * 建立 MQTT 連線 * DHT.h * 程式碼: <font color="Red">下方僅給予溫度的程式碼,需自行加入濕度的程式碼</font> ```C++= #include <WiFi.h> #include <PubSubClient.h> #include <DHT.h> #define LED 2 //使用 ESP32 內建 LED #define DHTPIN 23 // 定義 DHT 資料傳輸的腳位 // 選擇使用的 DHT 溫溼度計種類 #define DHTTYPE DHT11 // DHT 11 //#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 //#define DHTTYPE DHT21 // DHT 21 (AM2301) DHT dht(DHTPIN, DHTTYPE); // 啟動 DHT 程式庫 // 紀錄量測間隔時間,因為數值較大,用 unsigned long unsigned long previousMillis = 0; // 每 n 秒量測,1000->1秒,2000->2秒 const long interval = 2000; const char* ssid = "Wi-Fi 網路名稱"; // Wi-Fi 網路名稱 const char* password = "Wi-Fi 密碼"; // Wi-Fi 密碼 // 建立 MQTT 連線所需的 client ID,可使用隨機生成 String mqtt_ClientID = "mqttClientID"; // 定義 MQTT 連線時,用來識別 publish/subscribe 資料類別的 topic // 請依照組別更改groupX const char* sub_topic = "groupX/esp32mqtt"; const char* pub_led_topic = "groupX/esp32s_led_state"; // 控制 ESP32 上的 LED const char* pub_init_topic = "groupX/esp32s_is_back"; // 確認 ESP32 與 MQTT broker 已連線 const char* pub_temp_topic = "groupX/esp32s_temp"; // 傳輸溫度 // EMQX MQTT broker 的連線資訊 const char *mqtt_server = "broker.emqx.io"; // broker 所在的網址 const char *mqtt_userName = "emqx"; // EMQX broker 的公用帳號 const char *mqtt_password = "public"; // EMQX broker 的公用密碼 // 初始 Wi-Fi client 與 MQTT client 連線 WiFiClient espClient; PubSubClient client(espClient); // 初始化儲存溫度與濕度的變數 #define MSG_BUFFER_SIZE (50) char msg[MSG_BUFFER_SIZE]; void setup_wifi() { // 設定 Wi-Fi 連線 delay(10); // Connect to Wi-Fi // To do. randomSeed(micros()); // 連線成功後將連線的 IP 資訊印出 Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } //接收 MQTT broker subscribe 來的資訊 (LED 亮暗) void callback(char *topic, byte *payload, unsigned int length) { // 資訊包含 topic 與 topic 內的資料 Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); payload[length] = '\0'; String message = (char *)payload; // 儲存 topic 內的資料 payload 到 message 裡 // 驗證傳來的 topic 是我定義中要求的 topic // strcmp 會比較()內兩個字串,相同的話回傳 0,不同的話會輸出差幾個字母數,並用正負表示哪邊比較大 if (strcmp(topic, sub_topic) == 0) { if (message == "off") { digitalWrite(LED, LOW); // 收到 off 關掉 ESP32 的 LED client.publish(pub_led_topic, "off"); } if (message == "on") { digitalWrite(LED, HIGH); // 收到 on 開啟 ESP32 的 LED client.publish(pub_led_topic, "on"); } } } void reconnect() { // 對 MQTT 進行連線建立,若未建立成功會持續在此循環 while (!client.connected()) { Serial.println("Attempting EMQX MQTT connection..."); // 用亂數確保建立唯一的 ClientID mqtt_ClientID += String(random(0xffff), HEX); // 嘗試建立連線 if (client.connect((mqtt_ClientID, mqtt_userName, mqtt_password))) { Serial.print(" connected with Client ID: "); Serial.println(mqtt_ClientID); // 若建立成功,可在其他裝置訂閱 pub_init_topic 收到 "Hi, I'm online!" 的訊息 client.publish(pub_init_topic, "Hi, I'm online!"); // 重新接收資料 client.subscribe(sub_topic); } else { Serial.print("failed, rc="); Serial.print(client.state()); // 可於此查詢連線失敗原因編碼 // https://github.com/knolleary/pubsubclient/blob/master/src/PubSubClient.h Serial.println(" try again in 5 seconds"); // 若 MQTT 連線失敗,每 5 秒重試 delay(5000); } } } void setup() { dht.begin(); //啟動 DHT 感測器 pinMode(LED, OUTPUT); // 將 LED Pin 腳位設為輸出 digitalWrite(LED, LOW); // 將 LED Pin 腳位設為數位輸出(0V/5V),並預設為低(0V) Serial.begin(115200); setup_wifi(); // 進入設定 Wi-Fi 連線的 void function client.setServer(mqtt_server, 1883); // 設定 MQTT broker 的連線 client.setCallback(callback); // 接收從其他 MQTT client 傳來的資料 } void loop() { if (!client.connected()) { // 若 MQTT 連線建立失敗就重新連線 reconnect(); } client.loop(); //使用 DHT11 讀取環境溫濕度 //使用 millis 做間隔,每 2 秒讀一次 //To do. if (......) { // 如果上次時間點到這次時間點已經大於間隔時間,就開始量測 // 將上次的時間記錄更新成這次的時間點儲存 // 使用 DHT11 讀取環境溫濕度 if (......) { // 如果讀取到的溫溼度為空,表示 DHT11 有問題 Serial.println(F("Failed to read from DHT sensor!")); return; } else { // 如果溫溼度正常就publish給MQTT broker snprintf(msg, MSG_BUFFER_SIZE, "%.1lf°", temperature); //印出溫度 Serial.print("Publish message: "); Serial.print(msg); client.publish(pub_temp_topic, msg); // 綁定 topic,發送溫度 } } } ``` * 於電腦上開啟 MQTT 方式 Chrome 搜尋 MQTT Lens 並安裝 ![](https://i.imgur.com/aaPWd4B.png) 點選新增 "+" ![](https://i.imgur.com/O0kSkaS.png) 輸入 MQTT Broker 連線資訊 ![](https://i.imgur.com/CoUy4f6.jpg) 訂閱存有溫溼度資訊的 topic ![](https://i.imgur.com/iWgtlj7.png) * 於 Android 手機上開啟 MQTT 方式 Play 商店搜尋 MQTT Dash 安裝 ![](https://i.imgur.com/4drd96S.png) 訂閱存有溫溼度資訊的 topic ![](https://i.imgur.com/NPIJBIP.png) 訂閱開關 LED 的 topic ![](https://i.imgur.com/5K1tqIO.png) ## Lab3 ![](https://hackmd.io/_uploads/By5nxdPNh.png) * 實驗目的:將 ESP32 與 Hololens MR 眼鏡透過 TCP/IP 連接,並在 MR 眼鏡上玩彈跳球小遊戲。 * 實驗目標:將 ESP32 作為 TCP/IP server,接兩顆按鈕,代表方向鍵左與右,向 client 端輸出 "LXRX" 字串,以 0/1 代表左右按鈕是否被按下,如 "L1R0","L0R1"。 * 遊戲畫面:{%youtube liImljSbvM4%} ```C++= #include <WiFi.h> int port = 8888; //Port number WiFiServer server(port); //Server connect to WiFi Network const char *ssid = ""; //Enter your wifi SSID const char *password = ""; //Enter your wifi Password void setup() { Serial.begin(115200); Serial.println(); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); //Connect to wifi // Wait for connection Serial.println("Connecting to Wifi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); delay(500); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); server.begin(); Serial.print("Open Telnet and connect to IP:"); Serial.print(WiFi.localIP()); Serial.print(" on port "); Serial.println(port); } void loop() { /*do something*/ WiFiClient client = server.available(); //Serial.println(sendData.c_str()); if (client) { if(client.connected()) { Serial.println("Client Connected"); } while(client.connected()){ /*do something*/ } client.stop(); Serial.println("Client disconnected"); } } ``` # 課後問題 (3 題) :::info * **Q1. 請簡述什麼是 TCP/IP?** * **Q2. 請簡述 HTTP 與 HTTPS 的差別。** * **Q3. 請簡述什麼是 MQTT?** **回答請勿直接複製上述講義內容!** ::: :::success ## 作業繳交格式 **W10結報_第XX組.zip** 壓縮檔裡包含: 1.W(週數)結報.pdf 2.資料夾:W(週數) Lab1.ino Lab2.ino ... :::

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully