|
| 1 | +/** |
| 2 | + * Demo: |
| 3 | + * 演示Http请求天气接口信息 |
| 4 | + * @author 单片机菜鸟 |
| 5 | + * @date 2019/09/09 |
| 6 | + */ |
| 7 | +#include <ESP8266WiFi.h> |
| 8 | +#include <ArduinoJson.h> |
| 9 | +#include <ESP8266HTTPClient.h> |
| 10 | + |
| 11 | +//以下三个定义为调试定义 |
| 12 | +#define DebugBegin(baud_rate) Serial.begin(baud_rate) |
| 13 | +#define DebugPrintln(message) Serial.println(message) |
| 14 | +#define DebugPrint(message) Serial.print(message) |
| 15 | + |
| 16 | +const char* AP_SSID = "TP-LINK_5344"; // XXXXXX -- 使用时请修改为当前你的 wifi ssid |
| 17 | +const char* AP_PSK = "6206908you11011010"; // XXXXXX -- 使用时请修改为当前你的 wifi 密码 |
| 18 | +const char* HOST = "http://api.seniverse.com"; |
| 19 | +const char* APIKEY = "wcmquevztdy1jpca"; //API KEY |
| 20 | +const char* CITY = "guangzhou"; |
| 21 | +const char* LANGUAGE = "zh-Hans";//zh-Hans 简体中文 会显示乱码 |
| 22 | + |
| 23 | +const unsigned long BAUD_RATE = 115200; // serial connection speed |
| 24 | +const unsigned long HTTP_TIMEOUT = 5000; // max respone time from server |
| 25 | + |
| 26 | +// 我们要从此网页中提取的数据的类型 |
| 27 | +struct WeatherData { |
| 28 | + char city[16];//城市名称 |
| 29 | + char weather[32];//天气介绍(多云...) |
| 30 | + char temp[16];//温度 |
| 31 | + char udate[32];//更新时间 |
| 32 | +}; |
| 33 | + |
| 34 | +HTTPClient http; |
| 35 | +String GetUrl; |
| 36 | +String response; |
| 37 | +WeatherData weatherData; |
| 38 | + |
| 39 | +void setup() { |
| 40 | + // put your setup code here, to run once: |
| 41 | + WiFi.mode(WIFI_STA); //设置esp8266 工作模式 |
| 42 | + DebugBegin(BAUD_RATE); |
| 43 | + DebugPrint("Connecting to ");//写几句提示,哈哈 |
| 44 | + DebugPrintln(AP_SSID); |
| 45 | + WiFi.begin(AP_SSID, AP_PSK); //连接wifi |
| 46 | + WiFi.setAutoConnect(true); |
| 47 | + while (WiFi.status() != WL_CONNECTED) { |
| 48 | + //这个函数是wifi连接状态,返回wifi链接状态 |
| 49 | + delay(500); |
| 50 | + DebugPrint("."); |
| 51 | + } |
| 52 | + DebugPrintln(""); |
| 53 | + DebugPrintln("WiFi connected"); |
| 54 | + DebugPrintln("IP address: " + WiFi.localIP()); |
| 55 | + |
| 56 | + //拼接get请求url 博哥后面考虑看看是否可以封装一个方法来用用 不需要自己一个个拼装这个url |
| 57 | + GetUrl = String(HOST) + "/v3/weather/now.json?key="; |
| 58 | + GetUrl += APIKEY; |
| 59 | + GetUrl += "&location="; |
| 60 | + GetUrl += CITY; |
| 61 | + GetUrl += "&language="; |
| 62 | + GetUrl += LANGUAGE; |
| 63 | + //设置超时 |
| 64 | + http.setTimeout(HTTP_TIMEOUT); |
| 65 | + //设置请求url |
| 66 | + http.begin(GetUrl); |
| 67 | + //以下为设置一些头 其实没什么用 最重要是后端服务器支持 |
| 68 | + http.setUserAgent("esp8266");//用户代理版本 |
| 69 | + http.setAuthorization("esp8266","boge");//用户校验信息 |
| 70 | +} |
| 71 | + |
| 72 | +void loop() { |
| 73 | + //心知天气 发送http get请求 |
| 74 | + int httpCode = http.GET(); |
| 75 | + if (httpCode > 0) { |
| 76 | + Serial.printf("[HTTP] GET... code: %d\n", httpCode); |
| 77 | + //判断请求是否成功 |
| 78 | + if (httpCode == HTTP_CODE_OK) { |
| 79 | + //读取响应内容 |
| 80 | + response = http.getString(); |
| 81 | + DebugPrintln("Get the data from Internet!"); |
| 82 | + DebugPrintln(response); |
| 83 | + //解析响应内容 |
| 84 | + if (parseUserData(response, &weatherData)) { |
| 85 | + //打印响应内容 |
| 86 | + printUserData(&weatherData); |
| 87 | + } |
| 88 | + } |
| 89 | + } else { |
| 90 | + Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); |
| 91 | + } |
| 92 | + http.end(); |
| 93 | + delay(1000);//每5s调用一次 |
| 94 | +} |
| 95 | + |
| 96 | +/** |
| 97 | + * @Desc 解析数据 Json解析 |
| 98 | + * 数据格式如下: |
| 99 | + * { |
| 100 | + * "results": [ |
| 101 | + * { |
| 102 | + * "location": { |
| 103 | + * "id": "WX4FBXXFKE4F", |
| 104 | + * "name": "北京", |
| 105 | + * "country": "CN", |
| 106 | + * "path": "北京,北京,中国", |
| 107 | + * "timezone": "Asia/Shanghai", |
| 108 | + * "timezone_offset": "+08:00" |
| 109 | + * }, |
| 110 | + * "now": { |
| 111 | + * "text": "多云", |
| 112 | + * "code": "4", |
| 113 | + * "temperature": "23" |
| 114 | + * }, |
| 115 | + * "last_update": "2017-09-13T09:51:00+08:00" |
| 116 | + * } |
| 117 | + * ] |
| 118 | + *} |
| 119 | + */ |
| 120 | +bool parseUserData(String content, struct WeatherData* weatherData) { |
| 121 | +// -- 根据我们需要解析的数据来计算JSON缓冲区最佳大小 |
| 122 | +// 如果你使用StaticJsonBuffer时才需要 |
| 123 | +// const size_t BUFFER_SIZE = 1024; |
| 124 | +// 在堆栈上分配一个临时内存池 |
| 125 | +// StaticJsonBuffer<BUFFER_SIZE> jsonBuffer; |
| 126 | +// -- 如果堆栈的内存池太大,使用 DynamicJsonBuffer jsonBuffer 代替 |
| 127 | + DynamicJsonBuffer jsonBuffer; |
| 128 | + |
| 129 | + JsonObject& root = jsonBuffer.parseObject(content); |
| 130 | + |
| 131 | + if (!root.success()) { |
| 132 | + DebugPrintln("JSON parsing failed!"); |
| 133 | + return false; |
| 134 | + } |
| 135 | + |
| 136 | + //复制我们感兴趣的字符串 |
| 137 | + strcpy(weatherData->city, root["results"][0]["location"]["name"]); |
| 138 | + strcpy(weatherData->weather, root["results"][0]["now"]["text"]); |
| 139 | + strcpy(weatherData->temp, root["results"][0]["now"]["temperature"]); |
| 140 | + strcpy(weatherData->udate, root["results"][0]["last_update"]); |
| 141 | + // -- 这不是强制复制,你可以使用指针,因为他们是指向“内容”缓冲区内,所以你需要确保 |
| 142 | + // 当你读取字符串时它仍在内存中 |
| 143 | + return true; |
| 144 | +} |
| 145 | + |
| 146 | +// 打印从JSON中提取的数据 |
| 147 | +void printUserData(const struct WeatherData* weatherData) { |
| 148 | + DebugPrintln("Print parsed data :"); |
| 149 | + DebugPrint("City : "); |
| 150 | + DebugPrint(weatherData->city); |
| 151 | + DebugPrint(", \t"); |
| 152 | + DebugPrint("Weather : "); |
| 153 | + DebugPrint(weatherData->weather); |
| 154 | + DebugPrint(",\t"); |
| 155 | + DebugPrint("Temp : "); |
| 156 | + DebugPrint(weatherData->temp); |
| 157 | + DebugPrint(" C"); |
| 158 | + DebugPrint(",\t"); |
| 159 | + DebugPrint("Last Updata : "); |
| 160 | + DebugPrint(weatherData->udate); |
| 161 | + DebugPrintln("\r\n"); |
| 162 | +} |
0 commit comments