PlatformIO+ESP32S3学习:通过WIFI与和风天气API获取指定地点的天气情况并显示

news2024/12/28 18:04:08

1. 硬件准备


你只需要有一个ESP32S3开发板。我目前使用的是:

购买地址:立创·ESP32S3R8N8 开发板

在这里插入图片描述

2. 和风天气API


2.1. 和风天气介绍

和⻛天气是中国领先的气象科技服务商、国家高新技术 企业,致力于运用先进气象模型结合大数据、人工智能 技术发展智慧型气象服务。
他们的业务包括气象数据分发、地理信息、气象可视 化、个人气象服务等,在全球10个国家建有数据中心, 为300余家中国及全球企业、50万开发者提供优质的数 据服务。

另外的话

和风天气支持用户免费使用订阅,只是一个用户只能创建一个项目API,但是对我们来说已经足够了,感谢和风天气!

2.2. 创建自己的天气API

请前往 和风天气API 官网,注册账号并进入控制台。

在这里插入图片描述

关于和风天气的API介绍和开发文档,参考控制台处的介绍:

在这里插入图片描述

开始创建属于我们的API !

在这里插入图片描述

和风天气项目创建参数填写:

在这里插入图片描述

完成创建!

在这里插入图片描述

2.3. API介绍

和风天气的 API介绍网页 如下:

在这里插入图片描述

本文将用的API是城市天气 -> 每日天气预报 -> 3天预报API 。【API的详细介绍页点我】

在这里插入图片描述

需要注意的是,如果是免费订阅,要将API Host更改为 devapi.qweather.com

这里以获取深圳3天的天气预报为例,关键的API参数说明如下:

https://devapi.qweather.com/v7/weather/3d?location=101280601&key=YOUR_KEY

请求参数包括必选和可选参数,参数之间使用&进行分隔。这里只给大家介绍必填项。
1. key(必选) : 用户认证key,请参考如何获取你的KEY。
2. location(必选) : 需要查询地区的LocationID或以英文逗号分隔的经度,纬度坐标(十进制,最多支持小数点后两位),LocationID可通过GeoAPI获取。例如 location=101010100 或 location=116.41,39.92

关于这个LocationID需要各位自行根据和风天气官方的github地址查询,这里我找到深圳的LocationID为:101280601

在这里插入图片描述

2.4. 手动验证API是否正确

首先回到你的和风天气管理台。你会看到你新建的项目。

在这里插入图片描述
复制你的密钥KEY
在这里插入图片描述

然后将你的KEY填充到下方API的YOUR_KEY

下方这个是获取深圳3天的天气预报API,只剩KEY没有填写

https://devapi.qweather.com/v7/weather/3d?location=101280601&key=YOUR_KEY

例如我的KEY是 ABCasdsdgsdfgdsgdfgdf,则我的API是

https://devapi.qweather.com/v7/weather/3d?location=101280601&key=ABCasdsdgsdfgdsgdfgdf

填写你的KEY后,直接复制该API,将它作为网址跳转到对应页面,你就会看的返回的天气数据。

在这里插入图片描述
关于API返回的数据具体的意思是什么,参考该API的介绍页。

在这里插入图片描述
根据返回的参数说明,这里我关注的是4个数据:
在这里插入图片描述

图标代码的说明:返回的数据中关于天气的说明只有空落落的数字,这些数字在API说明中代表着各个天气情况。数字对应的天气情况链接。

在这里插入图片描述

到这里我们就已经是准备好了,接下来可以上工程代码了。请准备好你的完整APIKEY

3. 工程创建


在VSCode中打开PlatformIO扩展创建工程。

在这里插入图片描述
设置工程向导

在这里插入图片描述
在这里插入图片描述
等待创建完成。

在这里插入图片描述

4. 安装驱动库

创建完成之后,我们在VSCode中打开我们刚才创建的工程文件夹。

在这里插入图片描述
在VSCode中回到PlatformIO的主页,准备给工程安装JSON的驱动库。

在这里插入图片描述
在这里插入图片描述

搜索ArduinoJson,安装来自Benoit BlanchonArduinoJson库。

在这里插入图片描述

将库添加到我们的工程之中。

在这里插入图片描述

在这里插入图片描述

安装完成之后,打开platformio.ini文件,可以看到已经安装上了驱动库。

在这里插入图片描述

这里还有一个问题,和风天气API返回的JSON格式是带了Gzip压缩的。

为了能够在ESP32S3中进行Gzip的解压操作,引用了github上的一个开源项目,来自pfalcon的uzlib。感谢伟大的开源贡献者!

在这里插入图片描述

在我们的工程中,去lib文件夹下新建一个文件夹uzlib,将仓库中的 src 文件夹下的文件全部拉下来保存在我们在工程中新建的uzlib文件夹下。

在这里插入图片描述

5. 编辑代码


在工程中的src文件夹下的新建 weather.cpp 文件。

在这里插入图片描述
weather.cpp 中写入如下代码:

#include "weather.h"

Weather::Weather(String apiKey, String location)
{
    this->apiKey = apiKey;
    this->location = location;
}

bool Weather::update()
{
    HTTPClient http;   //用于访问网络
    WiFiClient *stream;
    int size;
    
    http.begin("https://devapi.qweather.com/v7/weather/3d?location="+ this->location + "&key=" + this->apiKey); //获取近三天天气信息
    int httpcode = http.GET();   //发送GET请求
    if(httpcode > 0)
    {
        if(httpcode == HTTP_CODE_OK)
        {
            stream = http.getStreamPtr();   //读取服务器返回的数据
            size = http.getSize();
        }
    }
    else
    {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpcode).c_str());
    }
    http.end();   //结束当前连接
    
    uint8_t inbuff[size];
    stream->readBytes(inbuff, size);
    uint8_t *outbuf = NULL;
    uint32_t out_size = 0;
    int result = ArduinoUZlib::decompress(inbuff,size, outbuf, out_size);
    deserializeJson(doc, outbuf);
    today = doc["daily"][0].as<JsonObject>();
    tomorrow = doc["daily"][1].as<JsonObject>();
    return true;
}

//获取天气数据中的当天最高气温数据
int Weather::getTempMax(bool is_today)
{
    if(is_today)
    {
        return today["tempMax"].as<int>();
    }
    else
    {
        return tomorrow["tempMax"].as<int>();
    }
}

//获取天气数据中的当天最低气温数据
int Weather::getTempMin(bool is_today)
{
    if(is_today)
    {
        return today["tempMin"].as<int>();
    }
    else
    {
        return tomorrow["tempMin"].as<int>();
    }
}

//获取天气数据中的天气标识代码
int Weather::getWeather(bool is_today, bool is_day)
{
    if(is_today)
    {
        if(is_day)
            return today["iconDay"].as<int>();
        else
            return today["iconNight"].as<int>();
    }
    else
    {
        if(is_day)
            return tomorrow["iconDay"].as<int>();
        else
            return tomorrow["iconNight"].as<int>();
    }
}

在工程中的include文件夹下的新建 weather.h 文件。

在这里插入图片描述
weather.h 中写入如下代码:

#ifndef _WEATHER_H
#define _WEATHER_H

#include "Arduino.h"
#include "ArduinoJson.h"
#include "ArduinoUZlib.h"
#include "HTTPClient.h"

//定义天气类
class Weather
{
    public:
        Weather(String apiKey, String location);
        bool update();  //发送一次请求信息,获取天气数据

        //只需要今明日的天气与温度,故仅设置了以下若干函数
        int getTempMax(bool is_today);
        int getTempMin(bool is_today);
        int getWeather(bool is_today, bool is_day);
    private:
        String apiKey;                  //天气API密钥
        String location;                //地点
        StaticJsonDocument<2048> doc;   //Json容器
        JsonObject today, tomorrow;     //可根据返回的json信息自行定义其他天气数据
};

#endif

打开工程下的src文件夹下的main.cpp,并且写入如下代码:

#include <Arduino.h>
#include <WiFi.h>
#include "weather.h"  //定义Weather类,用于解析Json数据并返回天气数据

//WIFI
#define WIFI_SSID "lckfb"         //要连接的WIFI名称
#define WIFI_PASSWORD "12345678"  //要连接的WIFI密码
#define WIFI_RETRY_COUNT  20      //WIFI连接重试数

//和风天气预报
#define USER_KEY      "d89d4706adcc4fb89d6f166cb420ee39" //密钥
#define LOCATION_ID   "101280601"  //地点标识:深圳

int weatherid;      //根据和风天气API返回的天气ID显示对应天气
bool is_day = 1;    //白天为1,夜晚为0
bool is_today = 1;  //今天为1,明天为0

//创建天气对象
Weather weather(USER_KEY, LOCATION_ID);

//根据和风天气API返回天气标识
void WeatherIcon(int weatherid)
{
    switch(weatherid)
    {
        case 100://白天晴
            Serial.println("白天晴\r\n");
            break;
        case 101://多云
        case 102://少云
        case 151://夜间多云
        case 152://夜间少云
        case 103://晴间多云
            Serial.println("多云\r\n");
            break;
        case 104://阴天
            Serial.println("阴天\r\n");
            break;
        case 150://夜间晴朗
            Serial.println("夜间晴朗\r\n");
            break;
        case 153://夜间晴间多云
            Serial.println("夜间多云\r\n");
            break;
        case 305://小雨
        case 309://毛毛雨/细雨
            Serial.println("小雨\r\n");
            break;
        case 300://阵雨
        case 350://夜间阵雨
        case 306://中雨
        case 399://雨
        case 313://冻雨
        case 314://小到中雨
            Serial.println("阵雨\r\n");
            break;
        case 301://强阵雨
        case 351://夜间强阵雨
        case 307://大雨
        case 308://极端降雨
        case 310://暴雨
        case 311://大暴雨
        case 312://特大暴雨
        case 315://中到大雨
        case 316://大到暴雨
        case 317://暴雨到大暴雨
        case 318://大暴雨到特大暴雨
            Serial.println("大雨\r\n");
            break;
        case 302://雷阵雨
            Serial.println("雷阵雨\r\n");
            break;
        case 303://强雷阵雨
            Serial.println("强雷阵雨\r\n");
            break;

        //雪天
        case 400://小雪
        case 401://中雪
        case 402://大雪
        case 403://暴雪
        case 404://雨夹雪
        case 405://雨雪天气
        case 406://阵雨夹雪
        case 407://阵雨夹雪
        case 408://小到中雪
        case 409://中到大雪
        case 410://雪
        case 456://阵雨夹雪
        case 457://阵雪
        case 499://雪
            Serial.println("雪天\r\n");
            break;

        //雾霾
        case 500://薄雾
        case 501://雾
        case 509://浓雾
        case 510://强浓雾
        case 514://大雾
        case 515://特强浓雾
            Serial.println("雾天\r\n");
            break;
        case 502://霾
        case 511://中度霾
        case 512://重度霾
        case 513://严重霾
            Serial.println("雾霾\r\n");
            break;
    }
}

void setup() 
{
  int count = 0;
  char disp_buf[50]={0};

  //串口初始化
  Serial.begin(9600);

  //尝试连接WIFI网络
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 
  //尝试连接直至超时
  while (WiFi.status() != WL_CONNECTED) 
  {
    count++;
    if (count > WIFI_RETRY_COUNT)
    {
      Serial.println("\r\nconnection failed.\r\n");
      break;
    }
    delay(500);
    Serial.print(".");
  }

  //获取天气数据
  weather.update();

  //WIFI断开连接
  WiFi.disconnect();

  //显示最低与最高温度
  sprintf(disp_buf, "TempMin = %d", weather.getTempMin(is_today));
  Serial.println(disp_buf);
  sprintf(disp_buf, "TempMax = %d", weather.getTempMax(is_today));
  Serial.println(disp_buf);

  //显示天气标识代码
  sprintf(disp_buf, "WeatherCode = %d", weather.getWeather(is_today, is_day));
  Serial.println(disp_buf);

  //根据天气标识代码确定天气
  WeatherIcon(weather.getWeather(is_today, is_day));
}

void loop() 
{
  delay(1000);
}

6. 代码验证

代码编写完成之后,将ESP32S3开发板接入电脑。我当前的开发板上是CH340K的驱动,故我这里选择COM3端口。

在这里插入图片描述
编译并下载到开发板中。

在这里插入图片描述

打开串口监视器。

在这里插入图片描述

实际获取天气数据的效果如下:
最低温度26,最高温度31,天气代码为307,对应的就是大雨。
在这里插入图片描述

查看和风天气的API中天气代码说明,确认数据是正确的。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1953771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Halcon 引擎方式调试

1.C# 端添加代码 启动调试模式 public HDevEngine MyEngine new HDevEngine(); // halcon引擎;// 启动调试服务 MyEngine.StartDebugServer();2.Halcon程序添加到进程 打开Halcon程序 【执行】>【附加到进程】 点击【确定】 3.C# 程序执行到相关位置 C# 程序执行调用…

大模型学习笔记十四:Agent模型微调

文章目录 一、大模型需要Agent技术的原因二、Prompt Engineering可以实现Agent吗&#xff1f;&#xff08;1&#xff09;ReAct原理展示和代码&#xff08;2&#xff09;ModelScope&#xff08;3&#xff09;AutoGPT&#xff08;4&#xff09;ToolLLaMA 三、既然AutoGPT可以满足…

Java SE 文件上传和文件下载的底层原理

1. Java SE 文件上传和文件下载的底层原理 文章目录 1. Java SE 文件上传和文件下载的底层原理2. 文件上传2.1 文件上传应用实例2.2 文件上传注意事项和细节 3. 文件下载3.1 文件下载应用实例3.2 文件下载注意事项和细节 4. 总结&#xff1a;5. 最后: 2. 文件上传 文件的上传和…

【C语言】指针基础知识理解

1. 内存和地址 1.1 内存 在讲内存和地址之前&#xff0c;我们想有个⽣活中的案例&#xff1a; 假设你在学校宿舍楼&#xff0c;但是宿舍的房间没有编号&#xff0c;你的⼀个朋友发微信来找你玩&#xff0c;如果想找到你&#xff0c;就得挨个房⼦去找&#xff0c;这样效率会很…

《算法笔记》总结No.11——数字处理(上)欧拉筛选

机试中存在部分涉及到较复杂数字的问题&#xff0c;这是编码的基本功&#xff0c;各位一定要得心应手。 目录 一.最大公约数和最小公倍数 1.最大公约数 2.最小公倍数 二.素数 1.判断指定数 2.输出所有素数 3.精进不休——埃拉托斯特尼筛法 4.达到更优&#xff01;——…

STL-string(使用和部分模拟实现)

1.string basic_string<char> 是 C 标准库中定义的一个模板类型,用于表示一个字符串。这个模板类接收一个字符类型作为模板参数。typedef basic_string<char> string&#xff1a;string类是basic_string类模板的实例化&#xff0c;它使用 char作为其字符类型。 2.…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第六十一章 Linux内核定时器

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

科普文:分布式数据一致性协议Paxos

1 什么是Paxos Paxos协议其实说的就是Paxos算法, Paxos算法是基于消息传递且具有高度容错特性的一致性算 法&#xff0c;是目前公认的解决分布式一致性问题最有效的算法之一。 Paxos由 莱斯利兰伯特(Leslie Lamport)于1998年在《The Part-Time Parliament》论文中首次公 开&…

KDP开源平台升级,推进大数据处理迈向轻量化、智能化

本文由 LeetTools 工具生成 编辑 | June 在当今数字化转型的浪潮中&#xff0c;企业面临着如何高效管理和利用大数据的挑战。智领云推出的Kubernetes Data Platform&#xff08;简称KDP&#xff09;正是为了解决这一问题而设计的。作为一款开源的云原生大数据平台&#xff0c;K…

【前端 08】简单学习js字符串

JavaScript中的String对象详解 在JavaScript中&#xff0c;字符串&#xff08;String&#xff09;是一种非常基础且常用的数据类型&#xff0c;用于表示文本数据。虽然JavaScript中的字符串是原始数据类型&#xff0c;但它们的行为类似于对象&#xff0c;因为JavaScript为字符…

[C#]调用本地摄像头录制视频并保存

AForge.NET是一个基于C#框架设计的开源计算机视觉和人工智能库&#xff0c;专为开发者和研究者设计。它提供了丰富的图像处理和视频处理算法、机器学习和神经网络模型&#xff0c;具有高效、易用、稳定等特点。AForge库由多个组件模块组成&#xff0c;包括AForge.Imaging&#…

算法日记day 19(找树左下角的值|路径总和)

一、找树左下角的值 题目&#xff1a; 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7 思路&#xff1a;…

【多线程】定时器

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 定时器是什么&#xff1f;2. 定时器的应用场景3. Timer类的使用3.1 Timer类创建定时器3.2 schedule()方法…

Unity横板动作游戏 -项目准备

项目准备 这是一篇 Unity 2022 最新稳定版本的教程同步笔记&#xff0c;本文将会讲解一些开始学习必须的条件。 安装环境 首先是安装 UnityHub&#xff0c;然后在 UnityHub 中安装 Unity 的版本(2022)。 只需要安装 开发者工具 和文档即可&#xff0c;导出到其他平台的工具等…

学习Vue2收藏这一篇就够了(如何创建Vue实例)

什么是Vue&#xff1f; Vue是什么&#xff1a;是一个用于构建用户界面的渐进式框架 什么是构建用户界面&#xff1a;基于数据动态渲染页面 什么是渐进式&#xff1a;循序渐进的学习 什么是框架&#xff1a;一整套完整的项目解决方案 创建Vue实例 核心步骤&#xff08;4步…

《javaEE篇》--单例模式详解

目录 单例模式 饿汉模式 懒汉模式 懒汉模式(优化) 指令重排序 总结 单例模式 单例模式属于一种设计模式&#xff0c;设计模式就好比是一种固定代码套路类似于棋谱&#xff0c;是由前人总结并且记录下来我们可以直接使用的代码设计思路。 单例模式就是&#xff0c;在有…

音视频入门基础:WAV专题(3)——FFmpeg源码中,判断某文件是否为WAV音频文件的实现

一、引言 通过FFmpeg命令&#xff1a; ./ffmpeg -i XXX.wav 可以判断出某个文件是否为WAV格式的音频文件&#xff1a; 所以FFmpeg是怎样判断出某个文件是否为WAV格式的音频文件呢&#xff1f;它内部其实是通过wav_probe函数来判断的。从文章《FFmpeg源码&#xff1a;av_prob…

02、爬虫数据解析-Re解析

数据解析的目的是不拿到页面的全部内容&#xff0c;只拿到部分我们想要的内容内容。 Re解析就是正则解析&#xff0c;效率高准确性高。学习本节内容前需要学会基础的正则表达式。 一、正则匹配规则 1、常用元字符 . 匹配除换行符以外的字符 \w 匹配字母或数字或下划…

软件测试---网络基础、HTTP

一、网络基础 &#xff08;1&#xff09;Web和网络知识 网络基础TCP/IP 使用HTTP协议访问Web WWW万维网的诞生 WWW万维网的构成 &#xff08;2&#xff09;IP协议 &#xff08;3&#xff09;可靠传输的TCP和三次握手策略 &#xff08;4&#xff09;域名解析服务DNS &#xff0…

一篇文章学完Python基础

1. 字符串 str1 "Hello" str2 " World" print(str1 str2) # 输出&#xff1a;HelloWorld 1.1 字符替换 text "Hello, World!" new_text text.replace("World", "Python") print(new_text) # 输出&#xff1a;…