Tìm kiếm mã

Hướng dẫn ESP32 43/55 - Trạm thời tiết Internet IoT | Bộ học IoT ESP32 của SunFounder

Hướng dẫn ESP32 43/55 - Trạm thời tiết Internet IoT | Bộ học IoT ESP32 của SunFounder

Trong hướng dẫn này, chúng ta sẽ xây dựng một trạm thời tiết kết nối Internet bằng ESP32 và bảng mở rộng camera của nó từ SunFounder. Dự án này cho phép ESP32 truy xuất dữ liệu thời tiết theo thời gian thực, bao gồm nhiệt độ và độ ẩm, và hiển thị trên màn hình LCD. Ứng dụng này không chỉ thể hiện khả năng của ESP32 mà còn minh họa cách tìm nạp và phân tích dữ liệu từ một API bên ngoài.

Khi chúng ta tiến hành qua hướng dẫn, chúng ta sẽ đấu nối các linh kiện, cấu hình mã và đảm bảo mọi thứ hoạt động liền mạch cùng nhau. Kết quả cuối cùng sẽ là một trạm thời tiết hoạt động đầy đủ, cập nhật số liệu mỗi 10 giây, cung cấp màn hình hiển thị rõ ràng và ngắn gọn về điều kiện thời tiết hiện tại (trong video ở phút 00:30).

Giải thích về Phần cứng

Các thành phần chính được sử dụng trong dự án này bao gồm vi điều khiển ESP32, màn hình LCD và hệ thống dây điện cần thiết. ESP32 được trang bị Wi-Fi và Bluetooth tích hợp, cho phép nó kết nối Internet và truy xuất dữ liệu. Màn hình LCD sẽ hiển thị thông tin thời tiết hiện tại, bao gồm nhiệt độ và độ ẩm.

LCD chúng ta sử dụng là màn hình ký tự 16x2, nghĩa là nó có thể hiển thị hai dòng, mỗi dòng 16 ký tự. Điều này sẽ đủ cho đầu ra thông tin thời tiết của chúng ta. ESP32 sẽ giao tiếp với LCD qua I2C, giúp đơn giản hóa việc đấu dây bằng cách chỉ sử dụng hai đường dữ liệu.

Chi tiết Bảng dữ liệu

Nhà sản xuấtEspressif
Số bộ phậnESP32-WROOM-32
Điện áp Logic/IO3,3 V
Điện áp cấp nguồn3,0–3,6 V
Dòng điện đầu ra (mỗi kênh)Tối đa 12 mA
Dòng điện đỉnh (mỗi kênh)40 mA
Hướng dẫn tần số PWM1 kHz
Ngưỡng logic đầu vào0,3 V (thấp), 0,7 V (cao)
Sụt áp / RDS(on) / bão hòa0,5 V
Giới hạn nhiệt-40 đến 85 °C
Đóng góiQFN48
Ghi chú / biến thểBao gồm nhiều biến thể cho các ứng dụng khác nhau

  • Đảm bảo ESP32 được cấp nguồn ổn định 3,3 V.
  • Sử dụng chung một điểm nối đất cho tất cả các linh kiện để tránh sự cố giao tiếp.
  • Kiểm tra địa chỉ I2C của LCD bằng máy quét I2C.
  • Theo dõi trạng thái kết nối Wi-Fi để tránh mất kết nối trong quá trình tìm nạp dữ liệu.
  • Xử lý lỗi phân tích JSON để đảm bảo độ tin cậy trong việc truy xuất dữ liệu.

Hướng dẫn Đấu nối

esp32-43-weather_station-wiring

Để đấu nối các linh kiện, hãy bắt đầu bằng cách kết nối LCD với ESP32. LCD sẽ sử dụng giao diện I2C, vì vậy hãy kết nối chân SDA của LCD với GPIO21 trên ESP32 và chân SCL với GPIO22. Đảm bảo kết nối các chân nguồn và nối đất của LCD với các chân 5V và GND trên ESP32 tương ứng.

Tiếp theo, đảm bảo ESP32 được cấp nguồn chính xác bằng pin lithium đi kèm hoặc kết nối USB. Pin cung cấp tính di động, trong khi kết nối USB hữu ích cho việc lập trình và gỡ lỗi. Cuối cùng, kiểm tra tất cả các kết nối được chắc chắn để tránh các vấn đề dây lỏng lẻo có thể làm gián đoạn chức năng.

Ví dụ Mã & Hướng dẫn Chi tiết

Trong giai đoạn thiết lập của chương trình, chúng ta khởi tạo giao tiếp nối tiếp và kết nối với mạng Wi-Fi bằng SSID và mật khẩu được cung cấp. Đoạn mã sau xử lý kết nối Wi-Fi:

WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("Đã kết nối với mạng Wi-Fi có Địa chỉ IP: ");
Serial.println(WiFi.localIP());

Mã này đảm bảo ESP32 kết nối với mạng Wi-Fi được chỉ định trước khi tiến hành bất kỳ việc tìm nạp dữ liệu nào. Nếu kết nối thất bại, nó sẽ liên tục cố gắng kết nối lại.

Tiếp theo, chúng ta cần gửi yêu cầu HTTP GET để truy xuất dữ liệu thời tiết. Điều này được thực hiện bằng đoạn mã sau:

String serverPath = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&units=metric" + "&APPID=" + openWeatherMapApiKey;
jsonBuffer = httpGETRequest(serverPath.c_str());

Ở đây, chúng ta xây dựng URL cho yêu cầu API, bao gồm thành phố, mã quốc gia và khóa API của chúng ta. Hàm httpGETRequest sau đó được gọi để tìm nạp dữ liệu thời tiết.

Cuối cùng, chúng ta phân tích phản hồi JSON và hiển thị dữ liệu liên quan trên LCD:

lcd.clear(); 
lcd.setCursor(0, 0); 
lcd.print(time);
lcd.print(" ");        
lcd.print(myObject["weather"][0]["main"]);             
lcd.setCursor(0, 1);
lcd.print("T:");    
lcd.print(myObject["main"]["temp"]); 
lcd.print("\xDF");  // ký tự "°"
lcd.print("C ");    
lcd.print("H:");    
lcd.print(myObject["main"]["humidity"]);  
lcd.print("%");

Đoạn mã này cập nhật màn hình LCD với thời gian hiện tại, điều kiện thời tiết, nhiệt độ và độ ẩm. Nó xóa màn hình trước đó và đặt con trỏ vào các vị trí thích hợp cho mỗi dòng.

Trình diễn / Điều mong đợi

Sau khi đấu nối và lập trình thành công, trạm thời tiết của bạn sẽ kết nối với Wi-Fi và bắt đầu tìm nạp dữ liệu thời tiết mỗi 10 giây. Bạn sẽ thấy nhiệt độ, độ ẩm và điều kiện thời tiết hiện tại được hiển thị trên màn hình LCD. Nếu ESP32 không kết nối được với Wi-Fi, nó sẽ in thông báo lỗi ra màn hình nối tiếp.

Hãy chú ý đến giới hạn số lần gọi API để tránh bị chặn khỏi dịch vụ OpenWeatherMap. Nếu bạn gặp bất kỳ sự cố nào khi truy xuất dữ liệu, hãy kiểm tra khóa API của bạn và đảm bảo mã thành phố và quốc gia được chỉ định chính xác (trong video tại 15:45).

Mốc thời gian video

  • 00:00 Bắt đầu
  • 2:00 Giới thiệu về dự án
  • 5:04 Tài khoản OpenWeather
  • 6:11 Đấu dây
  • 8:05 Giải thích mã Arduino
  • 14:13 Các phần tử JSON trong mã
  • 20:23 Chọn bo mạch ESP32 và cổng COM trong Arduino IDE
  • 22:05 Trình diễn Trạm thời tiết trên LCD1602
  • 23:45 Trình diễn Trạm thời tiết trên LCD2004

Hình ảnh

esp32-43-weather_station-main
esp32-43-weather_station-main
esp32-43-weather_station-wiring
esp32-43-weather_station-wiring
844-ESP32 Tutorial 43/55- Arduino code for IoT Internet Weather Station
Ngôn ngữ: C++
/*
  Rui Santos
  Complete project details at Complete project details at https://RandomNerdTutorials.com/esp32-http-get-open-weather-map-thingspeak-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>


// Replace the next variables with your SSID/Password combination
const char* ssid = "SSID";
const char* password = "PASSWORD";

// Your Domain name with URL path or IP address with path
String openWeatherMapApiKey = "openWeatherMapApiKey";

// Replace with your country code and city
// Fine the country code by https://openweathermap.org/find
String city = "CITY";
String countryCode = "COUNTRY CODE";

// THE DEFAULT TIMER IS SET TO 10 SECONDS FOR TESTING PURPOSES
// For a final application, check the API call limits per hour/minute to avoid getting blocked/banned
unsigned long lastTime = 0;
// Timer set to 10 minutes (600000)
//unsigned long timerDelay = 600000;
// Set timer to 10 seconds (10000)
unsigned long timerDelay = 10000;

String jsonBuffer;

// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// SDA -> GPIO21, SCL -> GPIO22
// lcd address is 0x27, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  

// NTP Server time
const char* ntpServer = "pool.ntp.org";
long  gmtOffset_sec = 0;
int   daylightOffset_sec = 0; //3600;

void setup() {
  Serial.begin(115200);

  // WiFi 
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println("Timer set to 10 seconds (timerDelay variable), it will take 10 seconds before publishing the first reading.");

  // initialize LCD
  lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();

}

void loop() {
  // Send an HTTP GET request
  if ((millis() - lastTime) > timerDelay) {
    // Check WiFi connection status
    if(WiFi.status()== WL_CONNECTED){
      String serverPath = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&units=metric" + "&APPID=" + openWeatherMapApiKey;
      
      jsonBuffer = httpGETRequest(serverPath.c_str());
      Serial.println(jsonBuffer);
      JSONVar myObject = JSON.parse(jsonBuffer);
  
      // JSON.typeof(jsonVar) can be used to get the type of the var
      if (JSON.typeof(myObject) == "undefined") {
        Serial.println("Parsing input failed!");
        return;
      }
    
      // Serial.print("JSON object = ");
      // Serial.println(myObject);
      // Serial.print("Temperature: ");
      // Serial.println(myObject["main"]["temp"]);
      // Serial.print("Pressure: ");
      // Serial.println(myObject["main"]["pressure"]);
      // Serial.print("Humidity: ");
      // Serial.println(myObject["main"]["humidity"]);
      // Serial.print("Wind Speed: ");
      // Serial.println(myObject["wind"]["speed"]);

      // Get time
      gmtOffset_sec =  myObject["timezone"]; 
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
      // time =  
      String time = printLocalTime();                     
  
      // LCD Print
      lcd.clear(); 
      lcd.setCursor(0, 0); 
      lcd.print(time);
      lcd.print(" ");        
      lcd.print(myObject["weather"][0]["main"]);             
      lcd.setCursor(0, 1);
      lcd.print("T:");    
      lcd.print(myObject["main"]["temp"]); 
      lcd.print("\xDF");  // "°" char
      lcd.print("C ");    
      lcd.print("H:");    
      lcd.print(myObject["main"]["humidity"]);  
      lcd.print("%");          
      
    }
    else {
      Serial.println("WiFi Disconnected");
    }
    lastTime = millis();
  }
}

String printLocalTime(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return "null";
  }
  // Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  // get time format HH:MM
  char timeHour[3];
  strftime(timeHour,3, "%H", &timeinfo);
  char timeMinute[3];
  strftime(timeMinute,3, "%M", &timeinfo); 
  String time = String(timeHour) + ":" + String(timeMinute);
  Serial.println(time)  
;  return time;
}


String httpGETRequest(const char* serverName) {
  WiFiClient client;
  HTTPClient http;
    
  // Your Domain name with URL path or IP address with path
  http.begin(client, serverName);
  
  // Send HTTP POST request
  int httpResponseCode = http.GET();
  
  String payload = "{}"; 
  
  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  // Free resources
  http.end();

  return payload;
}

Tài nguyên & tài liệu tham khảo

Tập tin📁

Không có tệp nào khả dụng.