Trạm khí tượng dự báo thời tiết với ESP8266

Mình xin chia sẻ với các bạn cách làm trạm khí tượng dự báo thời tiết đơn giản sử dụng ESP8266.

Ở bài trước chúng ta đã thử tạo webserver để lấy dữ liệu nhiệt độ, độ ẩm từ DHT11 , với dữ liệu hiện tại là dữ liệu thực tế tại môi trường mình đang sống, cụ thể nơi mình đang test DHT11 là trong nhà, giờ mình muốn thêm một chút thông tin về nhiệt độ, độ ẩm ngoài trời, các thông tin về áp suất, gió, mây,… thậm chí là mình muốn biết được tình hình thời tiết trong vài giờ, vài ngày tới như thế nào thì phải làm sao ?

Trạm khí tượng

Trước khi vào cách thực hiện thì mình sẽ tìm hiểu một chút về trạm khí tượng, mình chỉ quan tâm tới 2 vấn đề

TKH là gì ?

Trạm khí tượng là một nơi ở trên biển hoặc đất liền, có các dụng cụ và thiết bị để đo lường tình trạng khí quyển và cung cấp các thông tin để nghiên cứu và dự báo thời tiết/ khí hậu.

Vậy chúng ta có thể hiểu đơn giản là các thông tin dự báo thời tiết hàng ngày sau mỗi bản tin thời sự chúng ta nhận được cũng có 1 phần công của các trạm khí tượng này đây.

Thành phần cơ bản

Một trạm khí tượng sẽ có  các thiết bị

  • Nhiệt kế để đo nhiệt độ
  • Thiết bị đo độ ẩm
  • Thiết bị đo khí áp
  • Thiết bị đo gió
  • Thiết bị đo mưa

Chuẩn bị

Nếu bạn chưa biết bắt đầu từ đâu thì có thể xem qua các bài chia sẻ về ESP8266

Phần cứng

  • Node MCU hoặc ESP8266 + USB2UART PL2303
  • DHT11
  • Dây nối

Phần mềm

  • Arduino IDE

OpenWeatherMAP

Để tạo ra được một trạm khí tượng chất lượng đòi hỏi rất nhiều tiền của, với những người như mình chỉ muốn có thông tin thời tiết để sử dụng trong lập trình mà phải mua rất nhiều thiết bị như thế thì đúng là không thể chịu nổi. Thật may mắn là có một cơ sở dữ liệu về thời tiết rất lớn là OpenWeatherMAP cho mình có thể sử dụng các thông tin về thời tiết được cập nhật liên tục mỗi giây thông qua các API.

Về công nghệ của OpenWeatherMAP sử dụng là như thế nào thì bạn có thể tham khảo thêm ở trang của nó, mình hướng dẫn qua về cách lấy API để cho ESP có thể truy cập được thôi

Bước 1: Đăng ký tài khoản tại mục Sign Up

Bước 2: Đăng nhập vơi tài khoản vừa tạo

Bước 3: Vào thẻ API Keys, sử dụng Key default hoặc tạo key mới thông qua Create Key, lưu Key này lại để sử dụng trong chương trình

Nếu chúng ta vào thẳng trang chủ của OpenweatherMAP và nhập địa điểm vào thì có thể xem được dự báo thời tiết luôn, còn sử dụng API thì phải qua trang http://openweathermap.org/api

Ví dụ: muốn lấy thông tin thời tiết tại hà nội

  • Vào google map để lấy tọa độ nơi mình đang ở, nó sẽ có dạng https://www.google.com/maps/@xxxx,yyyy,15z, 2 thông số tô màu sau @ cần quan tâm, đó là kinh độ và vĩ độ
  • Truy cập vào API OpenWeatherMAP: http://api.openweathermap.org/data/2.5/weather?lat=xxx&lon=yyyy&units=metric&appid=api_cua_ban, thay xxx,yyy, và api_cua_ban tương ứng sẽ hiện ra các thông số như hình

Phần khoanh đỏ là phần dữ liệu mà mình cần lấy, nếu bạn cần biết ý nghĩa tất cả dữ liệu có thể xem tại đây

Tạo webserver lấy dữ liệu

Nói qua về webserver thì nó cũng giống với tcp server nhưng sẽ giao tiếp với client (ở đây là máy tính/ điện thoại có web browser) thông qua http responsehttp request. Mỗi khi client muốn lấy thông tin gì từ server thì sẽ gửi một http request cho server và server sẽ trả lời lại bằng một http response, bạn có thể xem hình minh họa

Mỗi khi có request từ Web browser (cụ thể là dùng điện thoại/ laptop truy cập vào địa chỉ IP của ESP8266) thì Web Server này(ESP8266) sẽ tạo ra  một file html với các thông tin lấy từ DHT11 và OpenWeatherMAP hiển thị lên lên trình duyệt.

Các bạn có thể xem thêm về HTTP requestHTTP response, Ajax

Đây là cách html lấy dữ liệu hiển thị lên web browser

/***************************************************
 Chương trình dự báo thời tiết với DHT11 và OpenweatherMAP
 Hocarm.org
****************************************************/

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

// Chan ket noi ESP8266 voi DHT la GPIO5 (chan D1)
#define DHTPIN 5

// Su dung DHT11
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE, 15);

// Thong so Wifi
const char* ssid = "ten_wifi";
const char* password = "password";

// Tao server voi port 80
WiFiServer server(80);

void setup() {

  // Khoi tao voi baud 115200
  Serial.begin(115200);
  delay(10);

  // Khoi tao DHT
  dht.begin();

  // Ket noi vao mang
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // Khoi dong server
  server.begin();
  Serial.println("Server started");

  // In dia chi IP
  Serial.println(WiFi.localIP());
}

void loop() {

  // Kiem tra coi co ai xem ket noi khong
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

  // Doi client gui du lieu
  Serial.println("new client");
  while (!client.available()) {
    delay(1);
  }

  // Reading temperature and humidity
  float h = dht.readHumidity();
  // Read temperature as Celsius
  float t = dht.readTemperature();

  // Doc request
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();

  // Tao web va lay thong tin de hien thi khi truy cap vao ip ESP ket noi
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
  // Tao header file html
  s += "<head>";
  s += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  s += "<meta http-equiv=\"refresh\" content=\"60\" />";
  s += "<script src=\"https://code.jquery.com/jquery-2.1.3.min.js\"></script>";
  s += "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css\">";
  s += "<style>body{font-size: 24px;} .voffset {margin-top: 30px;}</style>";
  s += "</head>";

  s += "<div class=\"container\">";
  s += "<h1>Tram khi tuong</h1>";
  // Thong tin tu DHT
  s += "<div class=\"row voffset\">";
  s += "<div class=\"col-md-3\">Nhiet do: </div><div class=\"col-md-3\">" + String(t) + "</div>";
  s += "<div class=\"col-md-3\">Do am   : </div><div class=\"col-md-3\">" + String(h) + "</div>";
  s += "</div>";
  // Thong tin tu OpenweatherMAP
  s += "<div class=\"row voffset\">";
  s += "<div class=\"col-md-3\">Nhiet do ngoai troi: </div><div id=\"ext_temp\" class=\"col-md-3\"></div>";
  s += "<div class=\"col-md-3\">Do am ngoai troi   : </div><div id=\"ext_humidity\" class=\"col-md-3\"></div>";
  s += "</div>";

  s += "<div class=\"row voffset\">";
  s += "<div class=\"col-md-3\">Ap suat           : </div><div id=\"press\" class=\"col-md-3\"></div>";
  s += "<div class=\"col-md-3\">Ap suat khi quyen : </div><div id=\"sea_press\" class=\"col-md-3\"></div>";
  s += "</div>";
  s += "</div>";
  // Truy cap API OpenweatherMAP
  s += "<script>$.ajax({url: \"http://api.openweathermap.org/data/2.5/weather?lat=xxx&lon=yyyy&units=metric&appid=api_cua_ban\", crossDomain: true})";
  s += ".done(function(result) {$(\"#ext_temp\").html((result.main.temp).toFixed(2)); $(\"#ext_humidity\").html(result.main.humidity);$(\"#min_temp\").html(result.main.temp_min);})";
  s += ".done(function(result) {$(\"#press\").html(result.main.pressure);$(\"#sea_press\").html(result.main.sea_level);})";
  s += "</script>";

  // Gui phan hoi toi client
  client.print(s);
  delay(1);
  Serial.println("Client disconnected");  //ngat ket noi

}

Kết quả

Trên máy tính

Trên điện thoại

Tạm kết

Vậy là mình đã chia sẻ về cách làm một trạm khí tượng dự báo thời tiết vô cùng đơn giản, ở đây mình chỉ đưa ra cách tiếp cận tạo ra một webserver trên ESP8266 để thu thập dữ liệu từ nhiều nguồn khác nhau, đúng ra là mình tận dụng thông tin từ nhiều trạm khí tượng khác nhau đưa lên openweather. Kết hợp thông tin từ openweather với thông tin thực tế từ môi trường mình có thể thực hiện nhiều mục đích khác nhau dựa trên các thông tin về thời tiết.