ESP32(Arduino)获取和风天气数据
和风天气API采用HTTPS方式获取相关天气数据,并且返回数据采用GZIP压缩方式,因此先要建立HTTPS链接,获取数据后,使用UZIP库里的 int result=ArduinoUZlib::decompress(inbuff, size, outbuf,outsize);库,用于解压和风天气返回的数据流。由于和风天气采用Gzip压缩方式返回数据流,返回的数据需要解压。以及与HTTPS、JSON
·
一、准备工作
1.在和风天气官网注册,获取账号的key。
2.Arduino安装ArduinoUZlib库,用于解压和风天气返回的数据流。由于和风天气采用Gzip压缩方式返回数据流,返回的数据需要解压。以及与HTTPS、JSON等相关库。
二、相关代码
为了方便理解代码功能,不同功能的代码,各采用1个.h和.cpp文件。
1.获取数据流。和风天气API采用HTTPS方式获取相关天气数据,并且返回数据采用GZIP压缩方式,因此先要建立HTTPS链接,获取数据后,使用UZlib库里的 int result=ArduinoUZlib::decompress(inbuff, size, outbuf,outsize);函数进行解压。相关代码如下:
HttpsGetUtils.h代码
#ifndef _HTTPS_GET_UTILS_H_
#define _HTTPS_GET_UTILS_H_
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
class HttpsGetUtils {
public:
HttpsGetUtils();
static bool getString(const char* url, uint8_t*& outbuf, size_t &len);
static const char *host; // 服务器地址
private:
static bool fetchBuffer(const char* url);
static uint8_t _buffer[2048]; //gzip流最大缓冲区
static size_t _bufferSize;
};
#endif
HttpsGetUtils.cpp代码
#include "HttpsGetUtils.h"
#include "ArduinoUZlib.h" // gzip库
uint8_t HttpsGetUtils::_buffer[2048];
const char* HttpsGetUtils::host = "https://devapi.qweather.com"; //服务器地址,这是免费用户的地址,如果非免费用户,改为:https://api.qweather.com
size_t HttpsGetUtils::_bufferSize=0;
HttpsGetUtils::HttpsGetUtils() {
}
bool HttpsGetUtils::getString(const char* url, uint8_t *& outbuf, size_t &outlen) {
fetchBuffer(url); //HTTPS获取数据流
if(_bufferSize) {
ArduinoUZlib::decompress(_buffer, _bufferSize,outbuf, outlen);//GZIP解压
_bufferSize=0;
return true;
}
return false;
}
bool HttpsGetUtils::fetchBuffer(const char *url) {
_bufferSize=0;
std::unique_ptr<WiFiClientSecure> client(new WiFiClientSecure);
client->setInsecure();
HTTPClient https;
if (https.begin(*client, url)) {
https.addHeader("Accept-Encoding", "gzip");
int httpCode = https.GET();
if (httpCode > 0) {
if (httpCode == HTTP_CODE_OK) {
int len = https.getSize(); // get length of document (is -1 when Server sends no Content-Length header)
static uint8_t buff[200] = { 0 }; // create buffer for read
int offset=0; // read all data from server
while (https.connected() && (len > 0 || len == -1)) {
size_t size = client->available(); // get available data size
if (size) {
int c = client->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
memcpy(_buffer+offset, buff, sizeof(uint8_t)*c);
offset+=c;
if (len > 0) {
len -= c;
}
}
delay(1);
}
_bufferSize=offset;
}
} else {
Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
}
https.end();
} else {
Serial.printf("Unable to connect\n");
}
return _bufferSize>0;;
}
2.获取实时天气数据
WeatherNow.h
#ifndef _WEATHERNOW_H_
#define _WEATHERNOW_H_
#include <Arduino.h>
#include <ArduinoJson.h>
class WeatherNow {
public:
WeatherNow();
void config(String userKey, String location);//获取城市的天气
void config_Grid(String userKey, String Grid_location);//获取经纬度地点的天气
bool get();
String getServerCode();
String getLastUpdate();
int getTemp();
int getFeelLike();
int getIcon();
String getWeatherText();
String getWindDir();
int getWindScale();
float getHumidity();
float getPrecip();
private:
void _parseNowJson(char* input, size_t inputLength); // 解析json信息
String _url;
String _response_code = ""; // API状态码
String _last_update_str = ""; // 当前API最近更新时间
int _now_temp_int = 999; // 实况温度
int _now_feelsLike_int = 999; // 实况体感温度
int _now_icon_int = 999; // 当前天气状况和图标的代码
String _now_text_str = "no_init"; // 实况天气状况的文字描述
String _now_windDir_str = "no_init"; // 实况风向
int _now_windScale_int = 999; // 实况风力等级
float _now_humidity_float = 999; // 实况相对湿度百分比数值
float _now_precip_float = 999; // 实况降水量,毫米
};
#endif
WeatherNow.cpp
#include "WeatherNow.h"
#include "HttpsGetUtils.h"
WeatherNow::WeatherNow() {
}
//例如 location="101010100",城市相关ID从https://github.com/qwd/LocationList下载。
void WeatherNow::config(String userKey, String location) {
_url = String(HttpsGetUtils::host) + "/v7/weather/now?location=" + location +
"&key=" + userKey + "&unit=m&lang=zh";
}
//以英文逗号分隔的经度,纬度坐标(十进制,支持小数点后两位)例如Grid_location="116.41,39.92"
void WeatherNow::config_Grid(String userKey, String Grid_location) {
_url = String(HttpsGetUtils::host) + "/v7/grid-weather/now?location=" + Grid_location +"&key=" + userKey + "&unit=m&lang=zh";
}
bool WeatherNow::get() {
uint8_t *outbuf=NULL;
size_t len=0;
Serial.println("Get WeatherNow...");
bool result = HttpsGetUtils::getString(_url.c_str(), outbuf, len);
if(outbuf && len){
_parseNowJson((char*)outbuf,len);
} else {
Serial.println("Get WeatherNow failed");
}
//一定要记得释放内存
if(outbuf!=NULL) {
free(outbuf);
outbuf=NULL;
}
return result;
}
// 解析Json信息
void WeatherNow::_parseNowJson(char* input, size_t inputLength) {
StaticJsonDocument<512> doc;
DeserializationError error = deserializeJson(doc, input, inputLength);
JsonObject now = doc["now"];
_response_code = doc["code"].as<String>(); // API状态码
_last_update_str = doc["updateTime"].as<String>(); // 当前API最近更新时间
_now_temp_int = now["temp"].as<int>(); // 实况温度
_now_feelsLike_int = now["feelsLike"].as<int>(); // 实况体感温度
_now_icon_int = now["icon"].as<int>(); // 当前天气状况和图标的代码
_now_text_str = now["text"].as<String>(); // 实况天气状况的文字描述
_now_windDir_str = now["windDir"].as<String>(); // 实况风向
_now_windScale_int = now["windScale"].as<int>(); // 实况风力等级
_now_humidity_float = now["humidity"].as<float>(); // 实况相对湿度百分比数值
_now_precip_float = now["precip"].as<float>(); // 实况降水量,毫米
}
// API状态码
String WeatherNow::getServerCode() {
return _response_code;
}
// 当前API最近更新时间
String WeatherNow::getLastUpdate() {
return _last_update_str;
}
// 实况温度
int WeatherNow::getTemp() {
return _now_temp_int;
}
// 实况体感温度
int WeatherNow::getFeelLike() {
return _now_feelsLike_int;
}
// 当前天气状况和图标的代码
int WeatherNow::getIcon() {
return _now_icon_int;
}
// 实况天气状况的文字描述
String WeatherNow::getWeatherText() {
return _now_text_str;
}
// 实况风向
String WeatherNow::getWindDir() {
return _now_windDir_str;
}
// 实况风力等级
int WeatherNow::getWindScale() {
return _now_windScale_int;
}
// 实况相对湿度百分比数值
float WeatherNow::getHumidity() {
return _now_humidity_float;
}
// 实况降水量,毫米
float WeatherNow::getPrecip() {
return _now_precip_float;
}
3.使用示例
.ino文件
#include "WeatherNow.h"
#include "HttpsGetUtils.h"
const char* ssid = "wifiname"; // WiFi名称
const char* password = "password"; // WiFi密码
String UserKey = "394809a78ca744fcb0fc020fxxxxxxxx"; //和风天气的key
String gridLocation ="113.25,23.14"; //经纬度取2位小数
String Location = "101280107";// 城市代码 https://github.com/heweather/LocationList,表中的 Location_ID
float ROUND = 5; // 更新间隔<分钟>实时天气API 1~20分钟更新一次
WeatherNow weatherNow;
void setup(){
Serial.begin(115200);
Serial.println("");
ConnectWiFi(); // 连接WiFi
//使用城市ID或者经纬度,选用以下2个函数中的一个
weatherNow.config(UserKey, Location); // 配置请求信息
//weatherNow.config_Grid(UserKey, gridLocation); // 配置请求信息
}
void loop(){
if(weatherNow.get()){ // 获取天气更新
Serial.println(F("======Weahter Now Info======"));
Serial.print(F("Last Update: "));
Serial.println(weatherNow.getLastUpdate()); // 获取服务器更新天气信息时间
Serial.print(F("Temperature: "));
Serial.print(weatherNow.getTemp()); // 获取实况温度
Serial.print(F(" FeelsLike: "));
Serial.println(weatherNow.getFeelLike()); // 获取实况体感温度
Serial.print(F("Weather Now: "));
Serial.println(weatherNow.getWeatherText()); // 获取实况天气状况的文字描述
Serial.print(F("windDir: "));
Serial.print(weatherNow.getWindDir()); // 获取实况风向
Serial.print(F(" WindScale: "));
Serial.println(weatherNow.getWindScale()); // 获取实况风力等级
Serial.print(F("Humidity: "));
Serial.print(weatherNow.getHumidity()); // 获取实况相对湿度百分比数值
Serial.print(F(" Precip: "));
Serial.println(weatherNow.getPrecip()); // 获取实况降水量,毫米
Serial.println(F("========================"));
}
else { // 更新失败
Serial.println("Update Failed...");
Serial.print("Server Response: ");
Serial.println(minutely5m.getServerCode());
}
delay(ROUND * 60000);
}
// 连接WiFi
void ConnectWiFi(){
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to ");
Serial.print(ssid);
int i = 0;
while (WiFi.status() != WL_CONNECTED && (i < 10)) {
delay(1000);
Serial.print('.');
i++;
}
if (i == 10) { // 10s失败
Serial.println("WiFi Connection Failed");
} else { // 成功
Serial.println("");
Serial.println("WiFi Connection Successful!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
}

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)