目录

一、心知天气

1.1 注册账号

1.2 申请产品获取专属密钥

1.3 查看专属密钥

1.4 阅读数据产品手册,了解相关信息

1.5 获取"天气实况"API接口地址

1.5.1 “私钥” 直接请求方式

1.5.2 “公钥 + 私钥” 签名验证方式

1.6 “公钥 + 私钥” 签名验证方式复现

1.6.1 构造验证参数字符串

1.6.2 对上一步得到的字符串使用 HMAC-SHA1 的方式做哈希运算得到二进制结果,并用 Base64 的方式编码,得到一串哈希字符串

1.6.3 使用 URLEncode 上一步的结果进行编码,得到签名 sig

1.6.4 将sig作为第一步得到的参数字符串的最后一个参数

1.6.5 组合替换得出API接口地址

1.6.6 在线测试

二、使用ESP8266进行访问测试

2.1 串口配置

2.2 EPS8266 STA模式配置

2.3 主程序

三、 总结


一、心知天气

HyperData 是心知天气的高精度气象数据产品,通过标准的 Restful API 接口,提供标准化的数据访问。无论是 APP、智能硬件还是企业级系统都可以轻松接入心知的精细化天气数据。最重要的是一些基础功能免费。

1.1 注册账号 

传送门:心知天气

1.2 申请产品获取专属密钥

具体步骤:进入控制台--->产品管理--->添加产品(天气数据API)--->申请免费版

1.3 查看专属密钥

具体步骤:进入控制台--->产品管理--->找到你的产品--->基本信息--->API密钥(事关安全,请勿轻易向他人透露)

1.4 阅读数据产品手册,了解相关信息

传送门:HyperData 数据产品简介

1.5 获取"天气实况"API接口地址

传送门:天气实况使用说明

  • 接口地址格式:https://api.seniverse.com/v3/weather/now.json?key=your_api_key&location=beijing&language=zh-Hans&unit=c
  • 请求参数说明:(我们需要填充的是等号=后面的参数,例如:your_api_key

参数名称

类型

默认值

必填

备注

key

String

你的API密钥

location

Location

所查询的位置

language

Language

zh-Hans

语言

unit

Unit

c

单位

  • 返回结果示例:
{"results": [{"location": {"id": "C23NB62W20TF","name": "西雅图","country": "US","path": "西雅图,华盛顿州,美国","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" //数据更新时间(该城市的本地时间)}]
}

那么,我们的重点工作就在于获取API密钥;心知天气支持两种 API 安全验证方式:

我的公钥:Pnqrgerh6idkcIs6U              我的私钥:STNnlCcI3dgZn5NLW

1.5.1 “私钥” 直接请求方式

这种方式比较简单粗暴,只需要将 API 密钥中的“私钥”作为 API 请求中的 key 参数值:(说明此方式较为方便,但请注意不要泄漏你的“私钥”)

API接口地址格式:https://api.seniverse.com/v3/weather/now.json?key=your_private_key&location=beijing&language=zh-Hans&unit=c

        这里我们只需要将your_private_key替换为我们的私钥即可,替换后的API接口地址如下:

https://api.seniverse.com/v3/weather/now.json?key=STNnlCcI3dgZn5NLW&location=beijing&language=zh-Hans&unit=c

1.5.2 “公钥 + 私钥” 签名验证方式

“公钥 + 私钥” 验证方式更加安全。请求地址中只包含你的“公钥”以及用你的“私钥”制作的签名,因此不会在请求地址中泄露你的私钥。具体使用方式可以查看官方的详细介绍如何使用签名验证方式。

下面我将按照官方的步骤进行复现。

1.6 “公钥 + 私钥” 签名验证方式复现

1.6.1 构造验证参数字符串

数据格式要求:ts=UNIX时间戳&ttl=签名失效时间&uid=用户的公钥

①UNIX时间戳:

传送门:在线时间戳转换

②签名失效时间:签名失效时间参数 ttl 是可选参数。如果忽略这个参数,生成的签名有效期默认为 1800 秒(30 分钟)。较短的有效期可以使签名更难被盗用,提高安全性,但请务必保证请求到达心知服务器的时间在签名有效期内,否则会鉴权失败;在这里我以24小时为例(24*60*60)s。

构造的结果:ts=1655945206&ttl=86400&uid=Pnqrgerh6idkcIs6U

1.6.2 对上一步得到的字符串使用 HMAC-SHA1 的方式做哈希运算得到二进制结果,并用 Base64 的方式编码,得到一串哈希字符串

传送门:HMAC-SHA1计算

HMAC-SHA1计算+Base64编码后的结果:0nmfAICtezPCqE417SM0oiZTQ68=

1.6.3 使用 URLEncode 上一步的结果进行编码,得到签名 sig

传送门:URLEncode编码

URLEncode编码后的结果:0nmfAICtezPCqE417SM0oiZTQ68%3D

1.6.4 将sig作为第一步得到的参数字符串的最后一个参数

拼接格式:ts=1655945206&ttl=86400&uid=Pnqrgerh6idkcIs6U&sig=签名sig

拼接后的结果:ts=1655945206&ttl=86400&uid=Pnqrgerh6idkcIs6U&sig=0nmfAICtezPCqE417SM0oiZTQ68%3D

1.6.5 组合替换得出API接口地址

API接口格式:https://api.seniverse.com/v3/weather/now.json?your_api_key&location=Nanchang&language=en&unit=c

这里我们只需要将your_api_key替换为上一步(2.6.4节)得出的结果即可,下面是替换后的最终结果:

https://api.seniverse.com/v3/weather/now.json?ts=1655945206&ttl=86400&uid=Pnqrgerh6idkcIs6U&sig=0nmfAICtezPCqE417SM0oiZTQ68%3D&location=Nanchang&language=en&unit=c

1.6.6 在线测试

至此,整个签名验证方式全部执行完毕;在正式使用ESP8266进行访问之前,可以先对API接口地址进行在线Get测试,以免上述配置出现问题!传送门:在线GET请求测试

二、使用ESP8266进行访问测试

2.1 串口配置

/******************************************************************************\函数功能:串口3初始化配置硬件连接:USART3_TX - PB10 - 复用推挽输出USART3_RX - PB11 - 上下拉输入形参说明:返 回 值:
\******************************************************************************/
void USART3_Init(u32 baud)
{//1,打相应的外设时钟RCC->APB2ENR |= 1<<3; //IOPB外设时钟使能RCC->APB1ENR |= 1<<18;//USART3外设时钟使能//2,配置GPIO工作模式: 通用推挽-3 复用推挽-B 上下拉输入-8 模拟输入-0GPIOB->CRH &= 0xFFFF00FF;GPIOB->CRH |= 0x00008B00;//3,配置串口3的相应功能RCC->APB1RSTR |= 1<<18;    //开启USART3复位RCC->APB1RSTR &= ~(1<<18); //关闭USART3复位USART3->CR1 |= 1<<13;   //USART模块使能USART3->CR1 &= ~(1<<12);//字长:一个起始位,8个数据位,n个停止位USART3->CR2 &= ~(3<<12);//1个停止位//brr = clk / baud;USART3->BRR = (36*1000000) / baud;  //设置通信波特率#ifdef USART3_IRQ_ENUSART3->CR1 |= 1<<5;    //接收缓冲区非空中断使能CM3_NVIC_SetPriority(USART3_IRQn, 0, 2);  //设置中断优先级#endifUSART3->CR1 |= 1<<3;    //发送器使能USART3->CR1 |= 1<<2;    //接收器使能
}/******************************************************************************\函数功能:串口3发送字符串形参说明:返 回 值:
\******************************************************************************/
void USART3_Send_String(char *pstr)
{while(*pstr != '\0'){USART3->DR = *pstr++;   //1/72uswhile(!(USART3->SR & 1<<7)){}    //等待TDR发送数据缓冲器空}
}//串口3中断服务函数
u8 USART3_RX_BUFF[USART_RX_MAX];
u16 USART3_RX_CNT;
u8 USART3_RX_FLAG;
void USART3_IRQHandler(void)
{if(USART3->SR & 1<<5)  //判断是否是接收中断触发{TIM3->CNT = 0;TIM3->CR1 |= 1<<0;  //启动计数器u8 tmp = USART3->DR; //1,保存数据 2,清除标志位if(USART3_RX_CNT < USART_RX_MAX){USART3_RX_BUFF[USART3_RX_CNT] = tmp;USART3_RX_CNT++;}else USART3_RX_FLAG = 1; //缓冲区满了}
}

2.2 EPS8266 STA模式配置

char buff[50];/******************************************************************************\函数功能:核心函数-发送AT指令(自动判断是否成功,具备失败自动重发的能力)形参说明:返 回 值:0 - 成功 / 1 - 失败
\******************************************************************************/
u8 ESP8266_Send_AtCmd(char *cmd, char *ack)
{u8 i;u16 j;for(i=0; i<5; i++){USART3_Send_String(cmd); //1,把命令发出去for(j=0; j<10*1000; j++)  //60s{if(j%50==0) printf(">");if(USART3_RX_FLAG) //2,确认是否收到回复{USART3_RX_CNT = 0;USART3_RX_FLAG = 0;if(strstr((char *)USART3_RX_BUFF, ack))  //3,确认收到的回复是否正确{printf("\n");return 0;}}Delay_Ms(1);}}return 1;
}/******************************************************************************\函数功能:STA模式配置形参说明:ssid - 热点名称pwd - 热点密码ip - 服务器ipport 服务器端口号返 回 值:
\******************************************************************************/
u8 ESP8266_STA_TCPClientMode_Init(const char *ssid, const char *pwd, const char *ip, const u16 port)
{USART3_Send_String("AT+RST\r\n");Delay_Ms(1000);Delay_Ms(1000);//1,发送AT测试指令printf("1\n");if(ESP8266_Send_AtCmd("AT\r\n", "OK")) return 0xE1;//2,配置WIFI工作模式:STA模式printf("2\n");if(ESP8266_Send_AtCmd("AT+CWMODE=1\r\n", "OK")) return 0xE2;//3,连接热点printf("3\n");snprintf(buff, sizeof(buff), "AT+CWJAP_DEF=\"%s\",\"%s\"\r\n", ssid, pwd);if(ESP8266_Send_AtCmd(buff, "OK")) return 0xE3;//4,查询本机IPprintf("4\n");if(ESP8266_Send_AtCmd("AT+CIFSR\r\n", "OK")) return 0xE4;//5,开启单连接printf("5\n");if(ESP8266_Send_AtCmd("AT+CIPMUX=0\r\n", "OK")) return 0xE5;//6,连接服务器printf("6\n");snprintf(buff, sizeof(buff), "AT+CIPSTART=\"TCP\",\"%s\",%d\r\n", ip, port);if(ESP8266_Send_AtCmd(buff, "OK")) return 0xE6;printf("热点名称:%s\n", ssid);printf("热点密码:%s\n", pwd);printf("服务器IP:%s\n", ip);printf("服务器端口号:%d\n", port);return 0;
}/******************************************************************************\函数功能:客户端向服务器发送数据形参说明:txData - 要发送的数据返 回 值:0 - 成功 / 1 - 失败
\******************************************************************************/
u8 ESP8266_STA_TCPClient_SendData(char *txData)
{snprintf(buff, sizeof(buff), "AT+CIPSEND=%d\r\n", strlen(txData));if(ESP8266_Send_AtCmd(buff, ">")) return 1;if(ESP8266_Send_AtCmd(txData, "SEND OK")) return 2; return 0;
}

2.3 主程序

//连接服务器所需信息
const char *ssid       = "oooh";                //热点名称
const char *password   = "12345678";            //热点密码
const char *ServerHost = "api.seniverse.com";   //服务器域名/服务器IP
const int ServerPort   = 80;                    //服务器端口号//心知天气HTTP请求所需信息
#define SigMode 0
#if SigMode //签名验证方式
const char *reqUserAPIKey = "ts=1655945206&ttl=86400&uid=Pnqrgerh6idkcIs6U&sig=0nmfAICtezPCqE417SM0oiZTQ68%3D"; //你的API密钥(3.2.5步的结果)
#else
const char *reqUserAPIKey = "&key=STNnlCcI3dgZn5NLW";  //私钥直接请求
#endif
const char *reqLocation   = "NanChang";     //所查询的位置
const char *reqLanguage   = "en";           //语言
const char reqUnit        = 'c';            //单位   //用于存放最终组合出来的请求地址
char reqURL[512];
char keywords[3][20] = {"text", "code", "temperature"};
char result[3][20];   int main()
{LED_Init(); BEEP_Init();KEY_Init();USART1_Init(115200);     //串口1调试接口 - 串口调试助手TIM1_Init(72, 1000*10);  //辅助串口1接收数据USART3_Init(115200);     //串口3 - WIFITIM3_Init(72, 1000*10);  //辅助串口3接收数据//1,关键函数 - ESP8266 STA模式配置do{}while(ESP8266_STA_TCPClientMode_Init(ssid, password, ServerHost, ServerPort));//2,拼接请求地址sprintf(reqURL, "GET https://api.seniverse.com/v3/weather/now.json?%s&location=%s&language=%s&unit=%c\n", reqUserAPIKey, reqLocation, reqLanguage, reqUnit);BEEP = 1;Delay_Ms(30);BEEP = 0;while(1)     //轮询{if(KEY_Scan(0)){//3,在这里我选择通过按键的方式触发请求printf("reqURL:%s, %d\n", reqURL, strlen((char *)reqURL));ESP8266_STA_TCPClient_SendData(reqURL);}if(USART3_RX_FLAG){printf("USART3_RX_BUFF:%s, %d\n", USART3_RX_BUFF, strlen((char *)USART3_RX_BUFF));//解析天气ESP8266_ReqRes_DataParsing((char *)USART3_RX_BUFF, keywords[0], result[0]);ESP8266_ReqRes_DataParsing((char *)USART3_RX_BUFF, keywords[1], result[1]);ESP8266_ReqRes_DataParsing((char *)USART3_RX_BUFF, keywords[2], result[2]);printf("解析结果:\n");for(u8 i=0; i<3; i++){printf("%s : %s\n", keywords[i], result[i]);}USART3_RX_CNT = 0;USART3_RX_FLAG = 0;}if(USART1_RX_FLAG){printf("USART3_TX_BUFF:%s, %d\n", USART1_RX_BUFF, strlen((char *)USART1_RX_BUFF));USART3_Send_String((char *)USART1_RX_BUFF);USART1_RX_CNT = 0;USART1_RX_FLAG = 0;}}
}/******************************************************************************\函数功能:解析请求响应的数据形参说明:reqRes - 响应数据keywords - 要解析的信息result - 解析后的结果返 回 值:
\******************************************************************************/
u8 ESP8266_ReqRes_DataParsing(char *reqRes, char *keywords, char *result)
{char *p1 = NULL;char *p2 = NULL;if(strstr(reqRes, "last_update"))   //判断请求响应的数据是否正确{p1 = strstr(reqRes, keywords);  //查找关键词if(p1){p1 += strlen(keywords) + 3;p2 = strstr(p1, "\"");      //查找末端的 " strncpy(result, p1, p2 - p1); //拷贝数据return 0;}}return 1;
}

具体的测试结果如下:

注:大家如果也是使用ESP8266进行访问,那这里的访问链接是有细微的不一样的。具体如下:(主要是新加入了GET命令)

三、 总结

这篇文章前前后后写了很久,中间有很多次次因为手贱使用了"Ctrl+Z",导致码了很久的文字一夜回到解放前;本想摆烂,但是还是坚持了下来。毕竟做任何事情要有始有终。在此也非常感谢心知天气的技术人员提供的技术支持与帮助,万分感谢!

文章中出现的密钥,在大家看到这篇文章的时候,应该已经被我废除了;但是考虑到有些情况下只是想快速的访问一下天气,所以在此我也给大家留了一个做好的,有效期比较长(3年)的API接口地址,提供给能耐心看到这里的有缘人使用:

https://api.seniverse.com/v3/weather/now.json?ts=1656147796&ttl=94867200&uid=PepU6vrMa6uGoj-zf&sig=0iYKi3lf83bmQZSimvxd55OK23c%3D&location=Nanchang&language=en&unit=c

【STM32学习笔记-03】ESP8266 访问心知天气API获取实时天气信息相关推荐

  1. 小程序笔记(9)调用腾讯api获取周边饮食店信息

    调用腾讯api获取周边饮食店信息 实现功能 实现流程 基本逻辑实现 开始注册key 开始代码 先配置app.json中的权限获取 index.wxml index.wxss index.jssssss ...

  2. esp8266初级入门实用教程一之访问心知天气读取实时天气数据

    ESP8266作为一款功能强大的的物联网模块,已经被应用到了很多实用的物联网项目中.作为一个菜鸟,本人也捣鼓这个东西很长时间了,在捣鼓这个东西的同时我也总结了一些使用经验.在此借助CSDN平台出几个教 ...

  3. 点亮LED-STM32电控学习笔记03

    Robocon战队电控学习笔记03 day3:2022/9/21 [基本界面/结构] 在学习开始之前肯定要先了解我们开发的是个什么东西,每个部位是啥功能,这里我放几张官方(fuza)的图片 图一:C板 ...

  4. STM32学习笔记(13)——模数转换ADC

    这个月一直忙于准备考试,已经考完一半科目了,偷闲写了这篇文章.因为还没考完试,估计还得咕一段时间了. STM32学习笔记(13)--模数转换ADC 第一部分:ADC功能框图 一.输入电压 二.输入通道 ...

  5. ESP32 单片机学习笔记 - 03 - MCPWM脉冲输出/PCNT脉冲计数

    ESP32 单片机学习笔记 - 03 - MCPWM脉冲输出/PCNT脉冲计数 前言,继续上一篇的内容.因为上一篇刚好实验了iic和spi,形成一对.接下来讲pwm另起一篇. 目录 ESP32 单片机 ...

  6. Git 的安装与初次使用 —— Git 学习笔记 03

    Git 的安装与初次使用 -- Git 学习笔记 03 Git 的安装与初次使用 -- Git 学习笔记 03 安装 Git 在 Linux 上安装 在 Windows 上安装 初次运行 Git 前的 ...

  7. JavaWeb黑马旅游网-学习笔记03【登陆和退出功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

  8. HTML/CSS学习笔记03【CSS概述、CSS选择器、CSS属性、CSS案例-注册页面】

    w3cschool菜鸟教程.CHM(腾讯微云):https://share.weiyun.com/c1FaX6ZD HTML/CSS学习笔记01[概念介绍.基本标签.表单标签][day01] HTML ...

  9. JDBC学习笔记03【JDBC事务管理、数据库连接池、JDBCTemplate】

    黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...

  10. MySQL学习笔记03【数据库表的CRUD操作、数据库表中记录的基本操作、客户端图形化界面工具SQLyog】

    MySQL 文档-黑马程序员(腾讯微云):https://share.weiyun.com/RaCdIwas 1-MySQL基础.pdf.2-MySQL约束与设计.pdf.3-MySQL多表查询与事务 ...

最新文章

  1. 因为在企业软件中采用了React,我差点被公司开除
  2. inet_aton和inet_network和inet_addr三者比较-《别怕Linux编程》之五
  3. HashedWheelTimer时间轮定时任务原理分析
  4. Illegal mix of collations (utf8_unicode_ci,IMPLICIT) and (utf8_general_ci,IMPLICIT) for operation '=
  5. 音频开发中常见的四个错误
  6. Atitit 常见触发器功能总结 目录 1.1. mysql触发器实例 插入数据前更改数据值.mhtml 1 1.2. 数据修改后更改数据值 1 1.3. 不能为空检测约束。。 1 2. Ref 2
  7. DIP 电源跌落瞬时中断(Voltage dips)
  8. 从零开始学Java——基础篇
  9. 拿下我人生中第7个Offer,社招面试心得
  10. 【Python】在Anaconda中设置清华镜像站并解决“http error“问题
  11. 你真的了解“药品追溯码”吗?
  12. 饿了么table排序
  13. 卫星轨道和两行数据TLE
  14. 复现lio_sam激光slam算法创建点云地图
  15. Windows删除流氓软件方法记录
  16. 建立适当的索引(ZZ)
  17. java程序日志管理
  18. magnum devstack部署
  19. 简述机器指令与微指令之间的关系_机器指令与微指令之间的关系是(
  20. 股指期货交易系统简介架构

热门文章

  1. 中关村标协智能物联分技术委员会成立,小米张明当选第一届主任委员
  2. python获取键盘按键键值_python获取键值
  3. No matter what,just do not give up。
  4. 黄金矿工~java小游戏【内含源码】
  5. linux手动重启网卡驱动,手动添加linux无线网卡驱动
  6. educoder1-2Python 计算思维训练——公式计算
  7. 没有U盘怎么给电视盒子装软件?新手必看三种方法
  8. Borůvka (Sollin) 算法求 MST 最小生成树
  9. matplotlib用Times New Roman且不加粗
  10. STM32HAL----USB升级固件(DFU)