🌍 گرفتن داده از اینترنت با ESP32: HTTPClient، خواندن JSON از API و HTTPS

✍️ تیم ووکوی فارسی ·

تا حالا ESP32 بیشتر «جواب‌دهنده» بود: یک وب‌سرور می‌ساخت و مرورگر از آن چیزی می‌خواست. ولی خیلی از پروژه‌های جالب برعکس‌اند؛ برد باید خودش از اینترنت چیزی بپرسد: دمای امروز شهر، نرخ یک ارز، آخرین پیام یک ربات یا تنظیماتی که روی یک سرور گذاشته‌ای. ابزار این کار HTTPClient در ESP32 است. در این آموزش با یک درخواست GET وضعیت هوای تهران را از یک API رایگان می‌گیریم، JSON جواب را با ArduinoJson می‌خوانیم و با HTTPS کار می‌کنیم.

💡 این کد به اینترنت واقعی نیاز دارد و برای برد واقعی است. بخش خواندن JSON را می‌شود در شبیه‌ساز تمرین کرد؛ کدش در ادامه هست.

چه می‌سازیم؟

برنامه‌ای که هر ده دقیقه یک‌بار از سرویس رایگان Open-Meteo، که کلید API نمی‌خواهد، دما و سرعت باد تهران را می‌پرسد و در سریال مانیتور می‌نویسد. جواب این سرویس چیزی شبیه این است:

{
  "latitude": 35.7,
  "longitude": 51.4,
  "current": {
    "time": "2026-10-20T14:30",
    "temperature_2m": 21.4,
    "wind_speed_10m": 7.9
  }
}

ما فقط به سه مقدار داخل current نیاز داریم. ساختن خود API روی برد، یعنی طرف مقابل این ماجرا، را در ساخت API با JSON روی ESP32 یاد گرفتی.

قطعه‌ها و کتابخانه‌ها

کد کامل

// ESP32 HTTP client: read Tehran's weather from a public JSON API over HTTPS.
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>

const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";
const char* url = "https://api.open-meteo.com/v1/forecast"
                  "?latitude=35.69&longitude=51.39"
                  "&current=temperature_2m,wind_speed_10m";

const unsigned long INTERVAL = 10UL * 60UL * 1000UL;   // every 10 minutes
unsigned long lastFetch = 0;
bool firstRun = true;

void fetchWeather() {
  WiFiClientSecure client;
  client.setInsecure();              // learning only: skips the certificate check

  HTTPClient http;
  http.setTimeout(10000);            // give up after 10 s
  if (!http.begin(client, url)) {
    Serial.println("Bad URL");
    return;
  }

  int code = http.GET();
  if (code == HTTP_CODE_OK) {
    String body = http.getString();
    JsonDocument doc;                // ArduinoJson 7
    DeserializationError err = deserializeJson(doc, body);
    if (err) {
      Serial.print("JSON error: ");
      Serial.println(err.c_str());
    } else {
      float temp = doc["current"]["temperature_2m"] | -99.0;
      float wind = doc["current"]["wind_speed_10m"] | -1.0;
      const char* when = doc["current"]["time"] | "?";
      Serial.print("Tehran ");
      Serial.print(when);
      Serial.print(": ");
      Serial.print(temp, 1);
      Serial.print(" C, wind ");
      Serial.print(wind, 1);
      Serial.println(" km/h");
    }
  } else {
    Serial.print("HTTP error ");
    Serial.print(code);
    Serial.print(": ");
    Serial.println(http.errorToString(code));
  }
  http.end();                        // always free the connection
}

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(300);
    Serial.print(".");
  }
  Serial.println(" OK");
}

void loop() {
  if (firstRun || millis() - lastFetch >= INTERVAL) {
    firstRun = false;
    lastFetch = millis();
    if (WiFi.status() == WL_CONNECTED) {
      fetchWeather();
    } else {
      Serial.println("No Wi-Fi, skipping this round");
    }
  }
}

توضیح بخش‌های مهم

HTTPS و گواهی‌ها

تقریباً همه‌ی APIهای امروزی فقط HTTPS دارند. روش درست در پروژه‌ی واقعی این است که گواهی ریشه‌ی سرور (Root CA) را به‌صورت متن در کد بگذاری و به‌جای setInsecure بنویسی client.setCACert(rootCA). این گواهی را می‌شود از مرورگر، با کلیک روی قفل کنار آدرس سایت، صادر کرد. گواهی‌های ریشه معمولاً چند سال اعتبار دارند، ولی وقتی منقضی شوند درخواست‌ها شکست می‌خورند؛ پس اگر پروژه‌ای ناگهان بعد از مدت‌ها از کار افتاد، اول به گواهی شک کن. یک نکته‌ی دیگر: اتصال HTTPS حدود ۴۰ کیلوبایت حافظه می‌گیرد، پس دو اتصال هم‌زمان باز نکن.

معنی کدهای وضعیت

کدمعنیچه کنیم؟
200موفقJSON را بخوان
301 یا 302آدرس عوض شده استآدرس جدید را بگذار یا http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS)
401 یا 403کلید API نداری یا اشتباه استکلید و سربرگ‌ها را چک کن
404این مسیر وجود نداردآدرس را حرف به حرف چک کن
429درخواست زیادی فرستاده‌ایفاصله‌ی درخواست‌ها را بیشتر کن
1-اتصال برقرار نشداینترنت، نام سایت یا HTTPS را چک کن
11-سرور دیر جواب دادsetTimeout را بیشتر کن

تابع http.errorToString(code) برای کدهای منفی یک توضیح انگلیسی کوتاه چاپ می‌کند. اگر کد منفی می‌گیری و مطمئنی برد به وای‌فای وصل است، یک نکته‌ی محلی را هم در نظر بگیر: Open-Meteo یک سرویس خارجی است و وقتی فقط اینترنت داخلی در دسترس است، به آن نمی‌رسی. در آن شرایط یک سرویس داخلی یا سرور خودت را به‌جایش بگذار؛ کد تغییری نمی‌کند جز آدرس.

فرستادن داده با POST

گاهی باید داده را بفرستی، مثلاً دمای اتاق را به سرور خودت. شکل کلی همان است، فقط به‌جای GET از http.addHeader("Content-Type", "application/json") و بعد http.POST(text) استفاده می‌کنی که text را با serializeJson از یک JsonDocument ساخته‌ای. جواب سرور هم مثل قبل با getString خوانده می‌شود. اگر داده‌ها مدام و زیاد است، به‌جای HTTP سراغ MQTT برو که برای همین کار ساخته شده است.

تمرین بخش JSON در شبیه‌ساز

وای‌فای شبیه‌ساز به شبکه‌ی Wokwi-GUEST وصل می‌شود ولی به اینترنت واقعی نمی‌رسد، پس درخواست به Open-Meteo آن‌جا جواب نمی‌گیرد. اما بیشتر اشکال‌ها در خواندن JSON است و آن را می‌شود کامل تمرین کرد: همان جواب نمونه را به‌صورت یک رشته در کد بگذار و پردازشش کن.

// Practise JSON parsing without internet: the API answer as a fixed string.
#include <ArduinoJson.h>

const char* sample = R"({"current":{"time":"2026-10-20T14:30","temperature_2m":21.4,"wind_speed_10m":7.9}})";

void setup() {
  Serial.begin(115200);
  JsonDocument doc;
  DeserializationError err = deserializeJson(doc, sample);
  if (err) {
    Serial.print("JSON error: ");
    Serial.println(err.c_str());
    return;
  }
  float temp = doc["current"]["temperature_2m"] | -99.0;
  const char* when = doc["current"]["time"] | "?";
  Serial.print("At ");
  Serial.print(when);
  Serial.print(" it is ");
  Serial.print(temp, 1);
  Serial.println(" C");
  if (temp > 30) Serial.println("Hot: turn the fan on");
  else Serial.println("Fine: fan stays off");
}

void loop() {
}

شبیه‌ساز تینکرکد فارسی کتابخانه‌ی ArduinoJson را می‌شناسد. دو پروژه‌ی آماده‌ی JSON هم آن‌جا هست: API با JSON روی ESP32 و API سنسور با JSON، همراه با درس «داده‌ی JSON». خواندن همه رایگان است و برای اجرای ESP32 اشتراک Plus لازم است.

اشکال‌های رایج

حالا که برد می‌تواند از اینترنت داده بگیرد، کنار آن یک ساعت NTP به وقت تهران بساز، یا داده‌ها را با MQTT به داشبورد بفرست. برای کتابخانه‌هایی مثل ArduinoJson در شبیه‌ساز، صفحه‌ی کتابخانه‌ها و برای همه‌ی پروژه‌های شبکه، وای‌فای و اینترنت اشیا را ببین.

خواندن JSON را در تینکرکد فارسی تمرین کن 🧩

سؤال‌های رایج

فرق HTTPClient با WebServer در ESP32 چیست؟

با WebServer خود ESP32 سرور می‌شود و به مرورگر جواب می‌دهد. با HTTPClient برعکس است: ESP32 مثل یک مرورگر از یک سرور دیگر در اینترنت چیزی می‌خواهد، مثلاً وضعیت هوا یا قیمت یک کالا.

setInsecure در WiFiClientSecure امن است؟

برای یادگیری و تست اشکالی ندارد، ولی گواهی سرور را بررسی نمی‌کند و در محصول واقعی بهتر است گواهی ریشه‌ی سرور را با setCACert به برد بدهی تا کسی نتواند خودش را جای سرور جا بزند.

آیا HTTPClient در شبیه‌ساز به اینترنت وصل می‌شود؟

نه. وای‌فای شبیه‌ساز به اینترنت واقعی نمی‌رسد. بخش پردازش JSON را می‌توانی با یک رشته‌ی نمونه در شبیه‌ساز تمرین کنی و درخواست واقعی را روی برد امتحان کنی.

مقاله‌های مرتبط

🧠

FreeRTOS و دو هسته‌ی ESP32: اجرای چند کار هم‌زمان با xTaskCreatePinnedToCore

📡

ESP32 به وای‌فای وصل نمی‌شود؟ عیب‌یابی قدم به قدم با یک کد تشخیص

🛠️

خطای آپلود ESP32: حل Failed to connect و Timed out waiting for packet header

📌

پین اوت رزبری پای پیکو: نقشه‌ی کامل ۴۰ پایه، GP، ADC، I2C، SPI، UART و تغذیه

همه‌ی آموزش‌های ESP32 و اینترنت اشیا ← · همه‌ی مقاله‌ها