YFROBOT创客社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 39433|回复: 29
打印 上一主题 下一主题

ESP8266 wifi 获取天气数据情况 心知天气API 中国气象局开放平台 arduino

  [复制链接]

签到天数: 866 天

[LV.10]以坛为家III

跳转到指定楼层
楼主
发表于 2016-8-25 11:24:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
ESP8266连接到互联网并通过免费的API接口获取天气JSON数据并解析!

选择免费开放的信息平台:
上知乎看了一下:免费开放天气API接口 ,还是有很多的!
1、中国气象局开放平台网址:smartWeatherAPI(应该比较权威平台),但表示打开网址错误,大家可以看下这个:有道云笔记保存网页 (看这不舒服总比看不了强)。查看网页你会发现,需要填写申请表并发送至邮箱:smartweatherapi@weather.com.cn进行审核,审核通过会回复,我已经填写并发出了,没反应,不知道什么时候可以有回应!只能放弃(网上有人说现在不支持了)。
2、和风天气,注册账号即可免费使用部分数据(一天免费访问量3000,提供的数据也比较多)!最后测试国内城市天气数据中有中文,无法处理!放弃。
  api 文档说明:http://www.heweather.com/documents/api
  city id list:http://www.heweather.com/documents/cn-city-list
3、心知天气:支持多语言,免费账户可以使用:国内369个地级市+天气实况(温度、天气现象)+3天天气预报+生活指数(6项)+400次访问/小时!OK,就选这个了
4、OpenWeatherMapYaHoo天气 等等,不做介绍合适自己用的就行!

心知天气更改新IP - api.seniverse.com,原api - api.thinkpage.cn也可用(最好用新的),使用本文中的程序时,请保证你的ID是付费版 付费版 付费版(第一次注册会有免费试用)!

测试API接口(在浏览器中打开测试网址即可):
上文提到使用心知天气,我们看下心知天气API接口说明:心知天气API;支持城市列表:下载地址(包含收费城市)。当然首先你需要注册,对于我们来说免费即可,学习用途,不做商业用途!如果你需要商用,也可以付费。
我注册了免费账号(也可以自行注册): API密钥:24qbvr1mjsnukavo(仅供学习,每小时400次访问)
● 示例1:获取指定城市的实况天气 -- GET    /weather/now.json
请求地址 - https://api.thinkpage.cn/v3/weather/now.json?key=24qbvr1mjsnukavo&location=beijing&language=zh-Hans&unit=c
具体参数:key - API密钥 location - 位置  language - 语言(可选,默认zh-Hans简体中文)unit - 单位(可选,默认c)
返回结果:
{  "results":[{
  "location": {
      "id": "C23NB62W20TF",
      "name": "西雅图",
      "country": "US",
      "timezone": "America/Los_Angeles",
      "timezone_offset": "-07:00"  },
  "now": {
      "text": "多云", //天气现象文字
      "code": "4", //天气现象代码
      "temperature": "14", //温度,单位为c摄氏度或f华氏度
      "feels_like": "14", //体感温度,单位为c摄氏度或f华氏度
      "pressure": "1018", //气压,单位为mb百帕或in英寸
      "humidity": "76", //相对湿度,0~100,单位为百分比
      "visibility": "16.09", //能见度,单位为km公里或mi英里
      "wind_direction": "西北", //风向文字
      "wind_direction_degree": "340", //风向角度,范围0~360,0为正北,90为正东,180为正南,270为正西
      "wind_speed": "8.05", //风速,单位为km/h公里每小时或mph英里每小时
      "wind_scale": "2", //风力等级,请参考:http://baike.baidu.com/view/465076.htm
      "clouds": "90", //云量,范围0~100,天空被云覆盖的百分比 #目前不支持中国城市#
      "dew_point": "-12" //露点温度,请参考:http://baike.baidu.com/view/118348.htm #目前不支持中国城市#  },
  "last_update": "2015-09-25T22:45:00-07:00" //数据更新时间(该城市的本地时间)
    }]
}

● 示例2:逐日预报和你是 -- GET    /weather/daily.json
请求地址示例 -
北京今天和未来4天的预报
https://api.thinkpage.cn/v3/weather/daily.json?key=24qbvr1mjsnukavo&location=beijing&language=zh-Hans&unit=c&start=0&days=5
北京昨天天气、今天和未来3天的预报(仅旗舰会员和大客户支持昨天天气)
https://api.thinkpage.cn/v3/weather/daily.json?key=24qbvr1mjsnukavo&location=beijing&language=zh-Hans&unit=c&start=-1&days=5
具体参数:key - API密钥 location - 位置  language - 语言(可选,默认zh-Hans简体中文)unit - 单位(可选,默认c) start - 起始时间(可选,默认0) days - 天数(可选)
返回结果:
{  "results": [{
    "location": {
      "id": "WX4FBXXFKE4F",
      "name": "北京",
      "country": "CN",
      "path": "北京,北京,中国",
      "timezone": "Asia/Shanghai",
      "timezone_offset": "+08:00"    },
    "daily": [{                         //返回指定days天数的结果
      "date": "2015-09-20",             //日期
      "text_day": "多云",               //白天天气现象文字
      "code_day": "4",                  //白天天气现象代码
      "text_night": "晴",               //晚间天气现象文字
      "code_night": "0",                //晚间天气现象代码
      "high": "26",                     //当天最高温度
      "low": "17",                      //当天最低温度
      "precip": "0",                    //降水概率,范围0~100,单位百分比
      "wind_direction": "",             //风向文字
      "wind_direction_degree": "255",   //风向角度,范围0~360
      "wind_speed": "9.66",             //风速,单位km/h(当unit=c时)、mph(当unit=f时)
      "wind_scale": ""                  //风力等级
    }, {
      "date": "2015-09-21",
      "text_day": "晴",
      "code_day": "0",
      "text_night": "晴",
      "code_night": "0",
      "high": "27",
      "low": "17",
      "precip": "0",
      "wind_direction": "",
      "wind_direction_degree": "157",
      "wind_speed": "17.7",
      "wind_scale": "3"
    }, {
      ...                               //更多返回结果
    }],
    "last_update": "2015-09-20T18:00:00+08:00" //数据更新时间(该城市的本地时间)
    }]
}
更多这里不介绍,直接访问天气数据API文档

ESP8266 获取天气数据(使用nodemcu测试,无需电路,需要网络)
需要使用的库:JSON库
实时天气情况,测试网址:
https://api.thinkpage.cn/v3/weather/now.json?key=24qbvr1mjsnukavo&location=huaian&language=en

在浏览器中打开网址,分析数据:

分析得到的哪些数据是你需要的,然后在程序中打印出来......
nodemcu通过USB数据线连接到电脑,下载例程:
[C] 纯文本查看 复制代码
/**
    Get the Weather from intenet with esp8266

    get data from 心知天气:[url=http://www.thinkpage.cn/]http://www.thinkpage.cn/[/url]
    api 文档说明:[url=http://www.thinkpage.cn/doc]http://www.thinkpage.cn/doc[/url]
    city id list download :[url=http://www.thinkpage.cn/data/thinkpage_cities.zip]http://www.thinkpage.cn/data/thinkpage_cities.zip[/url]

    Created by yfrobot, 2016.8.23
    This example is in public domain.
*/

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

WiFiClient client;

const char* ssid     = "YFROBOT";         // XXXXXX -- 使用时请修改为当前你的 wifi ssid
const char* password = "yfrobot2016";         // XXXXXX -- 使用时请修改为当前你的 wifi 密码


const char* host = "api.thinkpage.cn";
const char* APIKEY = "24qbvr1mjsnukavo";        //API KEY
const char* city = "huaian";
const char* language = "en";
//心知天气获取连接:[url=https://api.thinkpage.cn/v3/weather/daily.json?key=KEY&location=]https://api.thinkpage.cn/v3/weather/daily.json?key=KEY&location=[/url]城市&language=zh-Hans&unit=c&start=-1&days=5

const unsigned long BAUD_RATE = 115200;                   // serial connection speed
const unsigned long HTTP_TIMEOUT = 2100;               // max respone time from server
const size_t MAX_CONTENT_SIZE = 2048;                   // max size of the HTTP response

// Skip HTTP headers so that we are at the beginning of the response's body
//  -- 跳过 HTTP 头,使我们在响应正文的开头
bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  char endOfHeaders[] = "\r\n\r\n";

  client.setTimeout(HTTP_TIMEOUT);
  bool ok = client.find(endOfHeaders);

  if (!ok) {
    Serial.println("No response or invalid response!");
  }

  return ok;
}

// 发送请求指令
bool sendRequest(const char* host, const char* cityid, const char* apiKey) {
  // We now create a URI for the request
  //心知天气
  String GetUrl = "/v3/weather/now.json?key=";
  GetUrl += apiKey;
  GetUrl += "&location=";
  GetUrl += city;
  GetUrl += "&language=";
  GetUrl += language;

  // This will send the request to the server
  client.print(String("GET ") + GetUrl + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  return true;
}

// Read the body of the response from the HTTP server -- 从HTTP服务器响应中读取正文
void readReponseContent(char* content, size_t maxSize) {
  size_t length = client.peekBytes(content, maxSize);
  delay(100);
  Serial.println("Get the data from Internet!");
  content[length] = 0;
  Serial.println(content);
  Serial.println("Read Over!");
}

// The type of data that we want to extract from the page -- 我们要从此网页中提取的数据的类型
struct UserData {
  char city[16];
  char cnty[16];
  char weather[32];
  char temp[16];
  char feel[16];
  char hum[16];
  char visi[16];
  char udate[32];
};

// 解析数据
bool parseUserData(char* content, struct UserData* userData) {
  // Compute optimal size of the JSON buffer according to what we need to parse.
  //  -- 根据我们需要解析的数据来计算JSON缓冲区最佳大小
  // This is only required if you use StaticJsonBuffer. -- 如果你使用StaticJsonBuffer时才需要
  //  const size_t BUFFER_SIZE = 1024;

  // Allocate a temporary memory pool on the stack -- 在堆栈上分配一个临时内存池
  //  StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
  //  -- 如果堆栈的内存池太大,使用 DynamicJsonBuffer jsonBuffer 代替
  // If the memory pool is too big for the stack, use this instead:
  DynamicJsonBuffer jsonBuffer;

  JsonObject& root = jsonBuffer.parseObject(content);

  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }
  //  const char* x = root["results"][0]["location"]["name"];//
  //  Serial.println(x);
  // Here were copy the strings we're interested in -- 复制我们感兴趣的字符串
  strcpy(userData->city, root["results"][0]["location"]["name"]);
  strcpy(userData->cnty, root["results"][0]["location"]["country"]);
  strcpy(userData->weather, root["results"][0]["now"]["text"]);
  strcpy(userData->temp, root["results"][0]["now"]["temperature"]);
  strcpy(userData->feel, root["results"][0]["now"]["feels_like"]);
  strcpy(userData->hum, root["results"][0]["now"]["humidity"]);
  strcpy(userData->visi, root["results"][0]["now"]["visibility"]);
  strcpy(userData->udate, root["results"][0]["last_update"]);
  // It's not mandatory to make a copy, you could just use the pointers
  // Since, they are pointing inside the "content" buffer, so you need to make
  // sure it's still in memory when you read the string
  //  -- 这不是强制复制,你可以使用指针,因为他们是指向“内容”缓冲区内,所以你需要确保
  //   当你读取字符串时它仍在内存中

  return true;
}

// Print the data extracted from the JSON -- 打印从JSON中提取的数据
void printUserData(const struct UserData* userData) {
  Serial.println("Print parsed data :");
  Serial.print("City : ");
  Serial.print(userData->city);
  Serial.print(", \t");
  Serial.print("Country : ");
  Serial.println(userData->cnty);
  
  Serial.print("Weather : ");
  Serial.print(userData->weather);
  Serial.print(",\t");
  Serial.print("Temp : ");
  Serial.print(userData->temp);
  Serial.print(" C");
  Serial.print(",\t");
  Serial.print("Feel : ");
  Serial.print(userData->feel);
  Serial.print(" C");
  Serial.print(",\t");
  Serial.print("Humidity : ");
  Serial.print(userData->hum);
  Serial.print(" %");
  Serial.print(",\t");
  Serial.print("visibility : ");
  Serial.print(userData->visi);
  Serial.println(" km");
  
  Serial.print("Last Updata : ");
  Serial.print(userData->udate);
  Serial.println("");
}

// Close the connection with the HTTP server -- 关闭与HTTP服务器连接
void stopConnect() {
  Serial.println("Disconnect");
  client.stop();
}

void setup(){
  WiFi.mode(WIFI_STA);     //设置esp8266 工作模式

  Serial.begin(BAUD_RATE );      //设置波特率
  Serial.println();
  Serial.print("connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);   //连接wifi
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  delay(500);
  // Check if a client has connected
  if (!client.connect(host, 80)) {
    Serial.println("connection failed");
    return;
  }

  if (sendRequest(host, city, APIKEY) && skipResponseHeaders()) {
    char response[MAX_CONTENT_SIZE];
    readReponseContent(response, sizeof(response));
    UserData userData;
    if (parseUserData(response, &userData)) {
      printUserData(&userData);
    }
  }
  stopConnect();
}
void loop(){
  delay(3000);
}

直接下载:
下载完成后,打开串口(波特率 - 115200):


提示:解析过程非常重要(一定要先在浏览器中打开并分析),代码稍有误差,会导致eap8266重启。如果遇到问题记得回帖!
现在就差个显示部分,就可以充当天气提示器了!

OLED 0.96显示天气:http://www.yfrobot.com.cn/thread-11880-1-1.html (有视频)



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 支持支持 反对反对

签到天数: 3 天

[LV.2]偶尔看看I

推荐
发表于 2017-5-2 23:43:29 | 只看该作者
楼主你好。解析是什么意思?为什么我下载我ESP8266下载进去了,串口没有输出
回复 支持 1 反对 0

使用道具 举报

签到天数: 866 天

[LV.10]以坛为家III

推荐
 楼主| 发表于 2018-4-5 18:15:23 | 只看该作者
bg8cg 发表于 2018-4-4 22:53
就改了个wifi和密码输出了一大串,什么意思

WiFi connected

应该是解析错误
回复 支持 1 反对 0

使用道具 举报

签到天数: 1 天

[LV.1]初来乍到

推荐
发表于 2020-3-11 20:47:28 | 只看该作者
HeyPandaJun 发表于 2020-3-11 17:53
我把楼主给的代码content[length]=0注释了,结果显示conttext内容的确不完整。
代码部分:
// Read the ...

目前我找不到原因,但是问题解决了,我按照链接下载了2.3版本的,之前版本较高,可能readReponseContent()这个函数不一样,更换了ESP8266的包之后,就可以正常获取json数据了。
链接:http://www.yfrobot.com.cn/thread-11797-1-1.html
回复 支持 1 反对 0

使用道具 举报

签到天数: 3 天

[LV.2]偶尔看看I

推荐
发表于 2018-11-9 18:05:02 | 只看该作者
本帖最后由 GeekPower 于 2018-11-10 11:43 编辑

你好,楼主,我的环境是arduino1.6.13,烧写例程代码出错,出错位置第98行, DynamicJsonBuffer jsonBuffer,请问一下怎么回事呢,谢谢解答

[C] 纯文本查看 复制代码
D:\Graduation Project\WeatherESP8266\WeatherESP8266.ino: In function 'bool parseUserData(char*, UserData*)':

WeatherESP8266:98: error: 'DynamicJsonBuffer' was not declared in this scope

WeatherESP8266:98: error: expected ';' before 'jsonBuffer'

WeatherESP8266:100: error: 'JsonObject' was not declared in this scope

WeatherESP8266:100: error: 'root' was not declared in this scope

WeatherESP8266:100: error: 'jsonBuffer' was not declared in this scope

exit status 1
'DynamicJsonBuffer' was not declared in this scope

2018.11.10 问题已解决,解决方案:
https://arduinojson.org/v5/faq/error-jsonbuffer-was-not-declared-in-this-scope/
回复 支持 1 反对 0

使用道具 举报

该用户从未签到

沙发
发表于 2016-10-16 11:56:16 | 只看该作者
不错不错  试试看   顶
回复 支持 反对

使用道具 举报

该用户从未签到

板凳
发表于 2016-10-16 11:56:34 | 只看该作者
还差个金币啊
回复 支持 反对

使用道具 举报

该用户从未签到

地板
发表于 2016-12-14 15:36:42 | 只看该作者
多少基于arduino的啊
回复 支持 反对

使用道具 举报

该用户从未签到

5#
发表于 2016-12-14 15:44:21 | 只看该作者
ArduinoJson.h怎么提示缺少这个啊
回复 支持 反对

使用道具 举报

签到天数: 866 天

[LV.10]以坛为家III

6#
 楼主| 发表于 2016-12-15 08:18:23 | 只看该作者
1754916380 发表于 2016-12-14 15:44
ArduinoJson.h怎么提示缺少这个啊

下载安装库文件,就好了;地址文中有的
回复 支持 反对

使用道具 举报

该用户从未签到

7#
发表于 2017-2-1 00:22:22 | 只看该作者
ESP8266WiFi.h在哪里下载啊?
回复 支持 反对

使用道具 举报

签到天数: 866 天

[LV.10]以坛为家III

8#
 楼主| 发表于 2017-2-1 10:28:47 | 只看该作者
polang2007 发表于 2017-2-1 00:22
ESP8266WiFi.h在哪里下载啊?

这个是需要安装ESP8266编译环境的,安装好后就可以了!
教程地址:http://www.yfrobot.com/thread-11797-1-1.html
回复 支持 反对

使用道具 举报

签到天数: 1 天

[LV.1]初来乍到

9#
发表于 2017-3-27 13:52:30 | 只看该作者
多谢楼主分享。考虑用其他的天气。因为现在的心知天气,免费api里提供的东西好像太少了,湿度都没有
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|联系我们|YFROBOT ( 苏ICP备20009901号-2  

GMT+8, 2024-4-26 11:15 , Processed in 0.055434 second(s), 25 queries .

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表