基于 ESP32-C3 的心知天气 API 实时数据获取实现
项目概述
在物联网应用场景中,获取环境气象数据是一项基础且高频的功能需求。本教程旨在指导开发者如何利用 ESP32-C3 开发板,结合阿里的 SDK 及开源库,实现对心知天气(Seniverse)API 的调用,从而获取实时的温度、天气状况等参数。
前置依赖
在进行代码开发前,请确保 Arduino IDE 环境中已安装以下关键库:
- ESP32 Board Support: 用于管理硬件抽象层。
- ArduinoJson: 提供高效的 JSON 解析能力。
- HTTPClient: ESP32 架构内置的网络请求组件。
此外,您还需要在心知天气官网申请到有效的 API Key,并确认目标城市或地点的 ID。
核心封装文件 (头部分)
创建一个名为 WeatherService.h 的头文件,用于定义接口和数据结构。我们采用了面向对象的设计模式来封装网络交互逻辑。
<code>#ifndef WEATHER_SERVICE_H
#define WEATHER_SERVICE_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
class WeatherService {
public:
// 初始化构造函数,需传入认证密钥和目标位置标识
WeatherService(String api_key, String location);
// 更新当前定位
void updateLocation(String new_loc);
// 获取所有基础地理信息
String getGeoId();
String getGeoCity();
String getGeoCountry();
String getGeoPath();
String getGeoZone();
String getOffsetStr();
// 获取当前气象详情
String getStatusDesc();
String getCodeValue();
String getTempValue();
// 执行数据请求与解析
uint8_t fetchData();
private:
String _authKey;
String _currentLoc;
String _reqUrl;
// 存储解析后的地理位置字段
String _loc_id;
String _loc_name;
String _loc_country;
String _loc_path;
String _loc_zone;
String _loc_offset;
// 存储解析后的气象字段
String _cond_text;
String _cond_code;
String _temp_val;
};
#endif
</code>
逻辑实现文件 (.cpp)
创建同名的 WeatherService.cpp 源文件。在此模块中处理具体的 HTTP 请求构造及 JSON 反序列化逻辑。注意内存分配策略以确保稳定性。
<code>#include "WeatherService.h"
WeatherService::WeatherService(String api_key, String location)
: _authKey(api_key), _currentLoc(location) {}
void WeatherService::updateLocation(String new_loc) {
_currentLoc = new_loc;
}
uint8_t WeatherService::fetchData() {
_reqUrl = "https://api.seniverse.com/v3/weather/now.json?key="
+ _authKey + "&location=" + _currentLoc + "&language=zh-Hans&unit=c";
StaticJsonDocument<2048> doc;
HTTPClient client;
client.begin(_reqUrl);
int statusCode = client.GET();
if (statusCode == HTTP_CODE_OK) {
String payload = client.getString();
DeserializationError err = deserializeJson(doc, payload);
if (!err) {
JsonArray results = doc["results"].as<JsonArray>();
JsonObject locObj = results[0]["location"];
_loc_id = locObj["id"];
_loc_name = locObj["name"];
_loc_country = locObj["country"];
_loc_path = locObj["path"];
_loc_zone = locObj["timezone"];
_loc_offset = locObj["timezone_offset"];
JsonObject nowObj = results[0]["now"];
_cond_text = nowObj["text"];
_cond_code = nowObj["code"];
_temp_val = nowObj["temperature"];
client.end();
return 0;
} else {
client.end();
return 3; // 解析错误
}
} else {
client.end();
return 2; // 网络响应异常
}
return 1;
}
String WeatherService::getGeoId() { return _loc_id; }
String WeatherService::getGeoCity() { return _loc_name; }
String WeatherService::getGeoCountry() { return _loc_country; }
String WeatherService::getGeoPath() { return _loc_path; }
String WeatherService::getGeoZone() { return _loc_zone; }
String WeatherService::getOffsetStr() { return _loc_offset; }
String WeatherService::getStatusDesc() { return _cond_text; }
String WeatherService::getCodeValue() { return _cond_code; }
String WeatherService::getTempValue() { return _temp_val; }
</code>
主程序整合 (Sketch)
在主工程文件中引入上述两个源文件,并完成网络连接及调用流程。注意 Wi-Fi 状态检查。
<code>#include <WiFi.h>
#include "WeatherService.h"
// 网络配置
const char *ssid = "Your_SSID";
const char *pass = "Your_Password";
// 实例化天气服务对象
WeatherService wm("YOUR_API_KEY_HERE", "合肥");
void setup() {
Serial.begin(115200);
Serial.println("System Booting...");
// 连接无线网络
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("\nNetwork Connected.");
Serial.printf("IP Address: %s\n", WiFi.localIP().toString().c_str());
// 获取天气数据
int result = wm.fetchData();
if (result == 0) {
Serial.println("--- Weather Data ---");
Serial.print("Condition: ");
Serial.println(wm.getStatusDesc());
Serial.print("Temperature: ");
Serial.println(wm.getTempValue());
Serial.print("Status Code: ");
Serial.println(wm.getCodeValue());
} else {
Serial.print("Fetch Failed. Code: ");
Serial.println(result);
}
}
void loop() {
// 循环中通常不需要重复操作,除非需要轮询
delay(300000); // 每隔 5 分钟刷新一次可在此处重调 wm.fetchData()
}
</code>
数据说明
在实际应用中,重点关注返回的三个字符串:状态描述文本(Text)、天气代码值(Code)以及气温数值(Temperature)。其中,天气代码值需要对照心知天气官方文档进行转换,以识别具体的阴晴雨雪状态。如果解析失败,请检查密钥有效性及网络连通性。
文件部署规范
将头文件和源文件保存至 IDE 工程目录下的同一层级。务必保证源文件的扩展名为 .cpp,因为 Arduino 框架底层是基于 C++ 实现的,虽然支持兼容 C 语法,但显式声明为 C++ 有助于避免命名冲突及编译器的隐式警告。