当前位置:首页 > 技术 > 正文内容

基于 ESP32-C3 的心知天气 API 实时数据获取实现

访客 技术 2026年10月10日 1

项目概述

在物联网应用场景中,获取环境气象数据是一项基础且高频的功能需求。本教程旨在指导开发者如何利用 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++ 有助于避免命名冲突及编译器的隐式警告。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。