这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换逻辑分析仪】+记录一次使用ESP8266读取心知天气API并且获取和解析天气

共2条 1/1 1 跳转至

【换逻辑分析仪】+记录一次使用ESP8266读取心知天气API并且获取和解析天气情况

菜鸟
2024-10-30 00:20:44   被打赏 35 分(兑奖)     打赏

简介

在前一段时间淘宝每天签到都能领到2-3 元的券, 于是便用这些券花了仅仅一元多买到了ESP8266的模组。 于是便想着来画一个ESP8266的最小系统来学习以下ESP8266电路的设计。 于是便有了这次的帖子。 在这次的帖子中我将会介绍ESP8266的最小系统,以及如何使用ESP8266 发送HTTPS请求来获取心知天气的API从而来实现一个天气助手的功能。 并且通过串口数据发送到STM32 使其 STM32解析来自8266的串口消息,并且将数据显示到 Oled屏幕上。


正文

市面上有很多常见的模块,我这里选择的是ESP12F的模组。 关于相关的原理图应用我们可以从之前代理ESP32 、 ESP8266模组的安信可社区(链接地址 https://docs.ai-thinker.com/%E8%A7%84%E6%A0%BC%E4%B9%A6)进行下载。


image.png


我们可以在上图中下载ESP12F的规格书。之后打开下载好的PDF文件来查看ESP-12F最小系统的应用电路。


image.png


我们来分析以下上面的电路,首先VI-IN 被两个电容进行滤波然后通过上拉电阻将REST和EN进行拉高。 下面红色框内的电路则不可用, 可以直接在原理图上设置为NC。在最小电路的右侧则是为串口通讯和下载电路。 RX和TX反接即可和目标单片机完成通讯。 而GPIO0 拉高的时候则可以保证单片机处于工作的模式, 当GPIO0在上电前被拉低的话,则会进入烧录模式, 我们可以在烧录模式进行代码的下载。 其他的比如GPIO15 则按照官方推荐电路连接即可。


官方手册也有对BOOT模式的说明和解释

image.png

接下来便来到我们的电路设计, 在我实际的工作测量下, ESP12F的工作时候请求心知天气的时候电流大概在70MA, 普通运行的时候电流在40MA左右。 所以可以直接用总的LDO来进行供电。


下图为使用立创EDA绘制的原理图, 在GPIO0出增加了一个按钮,使其按下的时候当前的电平能够被拉到GND从而保证ESP8266进入下载模式。


image.png


PCB的3D渲染图则为以下所示


image.png


心知天气介绍

心知天气是中国气象局官方授权的商业气象服务公司,基于气象数值预报和人工智能技术,提供高精度气象数据、天气监控机器人、气象数据可视化产品等。

当我们在心知天气注册账号后我们可以使用心知天气提供的API接口来获取天气数据等。 


image.png

我们可以在上图的控制台->免费版-> 访问量统计中。 找到免费版支持的API接口。 我们可以点击上图的链接来获取接口的说明信息。


image.png


拷贝下图中的密钥信息填充到上文的KEY中

image.png


下图便是一个有效的请求,并且得到了响应的JSON数据。 由于使用的是免费版,所有只能请求未来三天的天气预报(虽然API上显示的是五天)


image.png


接下来我们便可以通过Arduino IDE来结合WIFI manager , Arduino Json 和 ArduinoHttpClient 和 WiFiClientSecure来发送HTTPS的数据从而实现天气数据的解析。

代码如下

#include <WiFiManager.h>
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>
#include <WiFiClientSecure.h>  // 引入 WiFiClientSecure

char serverAddress[] = "api.seniverse.com";  // 服务器地址
int port = 443;  // HTTPS 默认端口

WiFiClientSecure wifi;  // 使用 WiFiClientSecure 以支持 HTTPS
HttpClient client = HttpClient(wifi, serverAddress, port);

// 天气状态映射表
const char* weatherMap[][2] = {
    {"晴", "Sunny"},
    {"多云", "Cloudy"},
    {"晴间多云", "Partly Cloudy"},
    {"大部多云", "Mostly Cloudy"},
    {"阴", "Overcast"},
    {"阵雨", "Shower"},
    {"雷阵雨", "Thundershower"},
    {"雷阵雨伴有冰雹", "Thundershower with Hail"},
    {"小雨", "Light Rain"},
    {"中雨", "Moderate Rain"},
    {"大雨", "Heavy Rain"},
    {"暴雨", "Storm"},
    {"大暴雨", "Heavy Storm"},
    {"特大暴雨", "Severe Storm"},
    {"冻雨", "Ice Rain"},
    {"雨夹雪", "Sleet"},
    {"阵雪", "Snow Flurry"},
    {"小雪", "Light Snow"},
    {"中雪", "Moderate Snow"},
    {"大雪", "Heavy Snow"},
    {"暴雪", "Snowstorm"},
    {"浮尘", "Dust"},
    {"扬沙", "Sand"},
    {"沙尘暴", "Duststorm"},
    {"强沙尘暴", "Sandstorm"},
    {"雾", "Foggy"},
    {"霾", "Haze"},
    {"风", "Windy"},
    {"大风", "Blustery"},
    {"飓风", "Hurricane"},
    {"热带风暴", "Tropical Storm"},
    {"龙卷风", "Tornado"},
    {"冷", "Cold"},
    {"热", "Hot"},
    {"未知", "Unknown"}
};

const char* translateWeather(const char* weather) {
    for (size_t i = 0; i < sizeof(weatherMap) / sizeof(weatherMap[0]); i++) {
        if (strcmp(weather, weatherMap[i][0]) == 0) {
            return weatherMap[i][1];
        }
    }
    return "Unknown";  // 如果没有找到对应的英文翻译
}

void setup() {
    Serial.begin(115200);
   
    // 使用 WiFiManager 自动连接
    WiFiManager wm;
    bool res = wm.autoConnect();

    if (!res) {
        Serial.println("Failed to connect");
        // ESP.restart(); // Uncomment if you want to restart on failure
    } else {
        Serial.println("Connected... yey :)");
    }

    // 允许所有证书(如果不想验证证书,调试时可以使用)
    wifi.setInsecure();  // 仅用于调试,生产环境中应使用有效证书
}

void loop() {
    // 设置要请求的 URL
    const char* url = "/v3/weather/daily.json?key=你的密钥&location=shanghai&language=zh-Hans&unit=c&start=0&days=2";

    // 开始请求
    client.beginRequest();
    client.get(url);
    client.endRequest();

    // 读取响应状态码和响应体
    int statusCode = client.responseStatusCode();
    String response = client.responseBody();

    if (statusCode > 0) {
        // 解析 JSON 数据
        DynamicJsonDocument doc(2048); // 适当调整大小
        DeserializationError error = deserializeJson(doc, response);
       
        if (!error) {
            // 提取所需的数据
            const char* cityName = doc["results"][0]["location"]["timezone"]; // 使用地点名称
            const char* todayWeather = doc["results"][0]["daily"][0]["text_day"];
            const char* todayHigh = doc["results"][0]["daily"][0]["high"];
            const char* tomorrowWeather = doc["results"][0]["daily"][1]["text_day"];
            const char* tomorrowHigh = doc["results"][0]["daily"][1]["high"];

            // 将天气从中文翻译成英文
            const char* todayWeatherEnglish = translateWeather(todayWeather);
            const char* tomorrowWeatherEnglish = translateWeather(tomorrowWeather);

            // 格式化输出,确保在每个数据项之间添加逗号
            String output = String(cityName) + ", " +
                            todayWeatherEnglish + ", " +
                            todayHigh + ", " +  // 注意在这里添加逗号
                            tomorrowWeatherEnglish + ", " +
                            tomorrowHigh;

            // 打印提取的信息到串口
            Serial.println(output);
        } else {
            Serial.print("JSON Parse Error: ");
            Serial.println(error.f_str());
        }
    } else {
        Serial.print("HTTP Request failed, status code: ");
        Serial.println(statusCode);
    }

    // 每 10 秒请求一次
    delay(10000);
}


由于我们使用的是WIFI manager的库, 那么当ESP8266第一次联网的时候将会进入AP模式(Access point), 它会启动一个热点并且等待用户的设备连接,当用户设备连接上去之后便可以进行配网。 当配网成功后 ESP8266会自动记住这个WIFI的连接信息使其在下一次启动的时候搜索到这个WIFI的时候再自动连接。


注意: 你需要提供上述代码中的KEY成你自己的KEY。并且由于是未来三天的天气数据,实际上请求速度过快没有任何意义。可以手动的调整请求的频率等。


由于本文主要是关于ESP8266的最小电路和HTTPS请求,所以实际上数据的解析和显示我将放到下篇文章中进行展示。下篇文章我将展示如何使用STM32解析来自ESP8266的数据并且将数据显示在I2C协议的OLDE屏幕上 





专家
2024-10-30 01:02:36     打赏
2楼

感谢楼主分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]