草庐IT

ESP8266简易WIFI天气时钟

码农爱学习 2023-04-09 原文

本篇介绍了如何使用ESP8266,通过WIFI连网获取网络天气和网络时间,然后借助U8g2库,在OLED上显示当前时间和天气信息。

1 HTTP获取网络天气

连网获取网络天气,一般需要通过http的方式,从天气信息提供商的网络地址获取天气信息。

1.1 注册开发者key

这里以心知天气为例,需要先注册一个开发者账号,然后获取自己的私钥,也就是等下要用到的key。

然后可以先在浏览器中输入如下链接,注意要将自己的key替换进去,然后就可以测试一下天气信息的获取情况。

https://api.seniverse.com/v3/weather/now.json?key=替换为你的私钥&location=HangZhou&language=en&unit=c

如下即为获取的天气信息,是json格式的:

1.2 http请求基本原理

上面先通过浏览器的方式获取到了天气信息,而ESP8266没有浏览器功能,需要编写代码实现http数据请求。

在编写代码之前,需要先了解一下基础的http请求原理。

url全称是资源描述符,一个url地址,用于描述一个网络上的资源,而http中的get、post、put、delete就对于着这个资源的查、改、增、删4个操作,get一般用于获取/查询资源信息。

url的格式:
【协议】://【主机名(或者叫域名)】【:端口号(可选)】/【文件路径】/【文件名】

例如:https://api.seniverse.com/v3/weather/now.json?key=替换为你的私钥&location=HangZhou&language=en&unit=c

  • 协议:https
  • 域名:api.seniverse.com

客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。

服务器HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

根据http协议,可以编写ESP8266进行http请求的代码:

const char* host = "api.seniverse.com";     // 将要连接的服务器地址  
const int httpPort = 80;                    // 将要连接的服务器端口      
 
// 心知天气HTTP请求所需信息
String reqUserKey = "xxxxxxxxxxxxxxxxx";   // 私钥
String reqLocation = "HangZhou";           // 城市
String reqUnit = "c";                      // 摄氏/华氏
 
// 建立心知天气API当前天气请求资源地址
String reqRes = "/v3/weather/now.json?key=" + reqUserKey +
    + "&location=" + reqLocation + 
    "&language=en&unit=" +reqUnit;

// 建立http请求信息
// 请求方法(GET)+空格+URL+空格+协议(HTTP/1.1)+回车+换行+
// 头部字段(Host)+冒号+值(服务器地址)+回车+换行+
// 头部字段(Connection)+冒号+值(close)+回车+换行+回车+换行
String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" + 
    "Host: " + host + "\r\n" + 
    "Connection: close\r\n\r\n";

WiFiClient client;
// 尝试连接服务器
if (client.connect(host, 80))
{
    // 向服务器发送http请求信息
    client.print(httpRequest);
    Serial.println("Sending request: ");
    Serial.println(httpRequest);  

    // 获取并显示服务器响应状态行 
    String status_response = client.readStringUntil('\n');
    Serial.print("status_response: ");
    Serial.println(status_response);

    // 使用find跳过HTTP响应头
    if (client.find("\r\n\r\n")) 
    {
        Serial.println("Found Header End. Start Parsing.");
    }

    // 利用ArduinoJson库解析心知天气响应信息
    parseInfo(client); 
} 

1.3 json数据解析

http请求获取到的天气数据是json格式的(关于json的介绍可参考:https://blog.csdn.net/hbsyaaa/article/details/115561257),需要对数据进行解析,获取到具体的天气和温度等数据。

可以将获取的json原始数据打印出来,方便确认程序是否获取到的天气数据。

具体代码如下:

void parseInfo(WiFiClient client)
{
  const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2 * JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 230;
  DynamicJsonDocument doc(capacity);
  deserializeJson(doc, client);
  Serial.println(doc.as<String>());

  JsonObject result0 = doc["results"][0];
  JsonObject result0_now = result0["now"];

  // 通过串口监视器显示以上信息
  g_strWeather = result0_now["text"].as<String>();// "Sunny"
  g_iCode = result0_now["code"].as<int>();// "0"
  g_iTemperature = result0_now["temperature"].as<int>();// "32"
  g_strUpdateTime = result0["last_update"].as<String>();// "2020-06-02T14:40:00+08:00"

  Serial.println(F("======Weahter Now======="));
  Serial.print(F("Weather Now: "));
  Serial.print(g_strWeather);
  Serial.print(F(" -> "));
  Serial.println(g_iCode);
  Serial.print(F("Temperature: "));
  Serial.println(g_iTemperature);
  Serial.print(F("Last Update: "));
  Serial.println(g_strUpdateTime);
  Serial.println(F("========================"));
}

原始json格式的天气数据和解析后的天气和温度数据如下:

天气现象代码对照表

解析到的天气数据,除了英文形式的天气信息(text),还有一个对应的天气码(code),如上图的Cloudy对应的天气码是4。通过天气码,也可以转换为天气。天气码的对照表可参考心知天气文档:https://docs.seniverse.com/api/start/code.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ny9efaMH-1653319704707)(https://xxpcb-1259761082.cos.ap-shanghai.myqcloud.com/pic2/esp8266/3/6.png)]

简化起见,这里只使用常用的4种天气。

代码中文英文
0晴(国内城市白天晴)Sunny
4多云Cloudy
9Overcast
13小雨Light Rain0

2 NTP网络时间

NTP(Network Time Protocol) 是网络时间协议,它是用来同步网络中各个计算机时间的协议。

ESP8266可以连网,那就也可以通过获取网络时间来得到当前的时间:

time_t getNtpTime()
{
    IPAddress ntpServerIP; // NTP服务器的地址
 
    while(Udp.parsePacket() > 0); // 丢弃以前接收的任何数据包
    Serial.println("Transmit NTP Request");
    // 从池中获取随机服务器
    WiFi.hostByName(ntpServerName, ntpServerIP);
    Serial.print(ntpServerName);
    Serial.print(": ");
    Serial.println(ntpServerIP);
    sendNTPpacket(ntpServerIP);
    uint32_t beginWait = millis();
    while (millis() - beginWait < 1500)
    {
        int size = Udp.parsePacket();
        if (size >= NTP_PACKET_SIZE)
        {
            Serial.println("Receive NTP Response");
            isNTPConnected = true;
            Udp.read(packetBuffer, NTP_PACKET_SIZE); // 将数据包读取到缓冲区
            unsigned long secsSince1900;
            // 将从位置40开始的四个字节转换为长整型,只取前32位整数部分
            secsSince1900 = (unsigned long)packetBuffer[40] << 24;
            secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
            secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
            secsSince1900 |= (unsigned long)packetBuffer[43];
            Serial.println(secsSince1900);
            Serial.println(secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR);
            return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
        }
    }
    Serial.println("No NTP Response :-("); //无NTP响应
    isNTPConnected = false;
    return 0; //如果未得到时间则返回0
}

3 OLED显示页面设计

获取到天气信息和时间后,需要将这些信息显示出来。

这里使用0.96寸OLED显示屏来显示,借助U8g2库,显示文字与天气图标(U8g2库的使用,可参考:https://blog.csdn.net/hbsyaaa/article/details/123966095)。

具体的显示代码如下:

void testShowTimeAndWeather(rtc_time_t &now_time, weather_info_t &weather_info)
{
  u8g2.clearBuffer();
  int tm_year = now_time.tm_year;
  int tm_month = now_time.tm_mon;
  int tm_day = now_time.tm_mday;
  int tm_hour = now_time.tm_hour;
  int tm_minute = now_time.tm_min;
  int tm_sec = now_time.tm_sec;
  int tm_week = now_time.tm_week;
  
  //时分
  char str_big_time[] = "";
  my_strcat(str_big_time, tm_hour);
  strcat(str_big_time,":");
  my_strcat(str_big_time, tm_minute);
  u8g2.setFont(u8g2_font_logisoso24_tf); 
  u8g2.drawStr(0, 30, str_big_time);

  //秒
  char str_small_sec[] = "";
  my_strcat(str_small_sec, tm_sec);
  u8g2.setFont(u8g2_font_wqy14_t_gb2312);
  u8g2.drawStr(73, 30, str_small_sec);

  //日期
  char str_date[] = "";
  char str_temp[6];
  itoa(tm_year,str_temp,10);
  strcat(str_date,str_temp);
  strcat(str_date,"-");
  my_strcat(str_date, tm_month);
  strcat(str_date,"-");
  my_strcat(str_date, tm_day);
  u8g2.drawStr(0, 47, str_date);
  
  u8g2.setCursor(0, 63);
  u8g2.print("星期");
  switch (tm_week)
  {
    case 1: u8g2.print("日"); break;
    case 2: u8g2.print("一"); break;
    case 3: u8g2.print("二"); break;
    case 4: u8g2.print("三"); break;
    case 5: u8g2.print("四"); break;
    case 6: u8g2.print("五"); break;
    case 7: u8g2.print("六"); break;
    default: break;
  }
  u8g2.setCursor(60, 63);
  u8g2.print("杭州");

  //分割线
  u8g2.drawLine(90, 0, 90, 63);
  
  //天气
  if (weather_info.iconIdx<0 || weather_info.iconIdx>3) //没有对应的天气图标
  {
    Serial.print("no icon for weather: ");
    Serial.println(weather_info.weather);
  }
  else
  {
    u8g2.setFont(u8g2_font_open_iconic_weather_4x_t );
    u8g2.drawStr(96, 34, icon_index[weather_info.iconIdx]);
  }
  char temperature_tmp[25];
  itoa(weather_info.temp, temperature_tmp, 10);
  strcat(temperature_tmp,"℃");
  u8g2.setFont(u8g2_font_wqy16_t_gb2312);
  u8g2.setCursor(96, 55);
  u8g2.print(temperature_tmp);
  
  u8g2.sendBuffer();
}

4 最终效果

5 总结

本篇介绍了http获取网络天气的基本原理,并通过实践,使用ESP8266连网获取网络天气和网络时间,借助U8g2库,在OLED上显示当前时间和天气信息。

有关ESP8266简易WIFI天气时钟的更多相关文章

  1. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  2. FPGA 之 时钟,时钟域, 以及复位系统的设计 - 2

    FPGA时钟和时钟域时钟树所谓时钟树为FPGA内部资源,分:全局时钟树,区域时钟树,IO时钟树原则上优先使用全局时钟树,在GT接口上使用IO时钟树,一般工具也会对GT时钟加以限制;时钟树使用方式正确的物理连接FPGA会由物理管脚专门用于全局时钟设置,通过查询数据手册可以在PCB设计阶段进行确认,当外部时钟接入此管脚时,工具会自动占有全局时钟树资源,当接入普通信号时不会分配时钟树资源;恰当的代码描述原语的使用,即BUFG的使用,可以将PLL的输出等内部时钟进行全局时钟资源的分配;IO时钟资源需要参考相应接口手册,以ultrascale的GTH为例,其JESD204的时钟方案针对不同的子类会由不同

  3. ESP32学习入门:WiFi连接网络 - 2

    目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方

  4. 基于51单片机、DS1302时钟模块的电子闹钟设计 - 2

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录一、设计原理1.DS1302介绍2.闹钟音乐播放原理二、程序设计1.DS1302.h2.ds1302.c3.music.h4.main.c三、电路图四、运行结果1.proteus仿真2.开发板实验五、总结六、附件提示:以下是本篇文章正文内容,下面案例可供参考一、设计原理1.DS1302介绍DS1302是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.0V~5.5V。该芯片采用普通32.768kHz晶振,DS1302工作时功耗很

  5. STM32+ESP8266接入云(3) - 2

    解析数据     进入阿里云的IOTStdio,点击新建项目。         新建项目后点击新建Web应用。名称     应用名称随便填写              创建完成后我们进入应用。    在左侧组件处拖入一个指示灯和一个开关。     点击指示灯组件,点击配置数据源     选择我们的产品、数据、和属性。     我们还可以配置开和关的显示颜色。    点击按钮,配置交互动作。     选择设备和属性,设置值位置点击数据来源,选择组件值     配置完成后进入预览,点击按钮,在esp8266就会收到来自平台的json格式的数据,MCU端需要做的就是解析来自平台的数据,进而达到控制下

  6. ESP32学习笔记(七) 复位和时钟 - 2

    ESP32学习笔记(七)复位和时钟目录:ESP32学习笔记(一)芯片型号介绍ESP32学习笔记(二)开发环境搭建VSCode+platformioESP32学习笔记(三)硬件资源介绍ESP32学习笔记(四)串口通信ESP32学习笔记(五)外部中断ESP32学习笔记(六)定时器ESP32学习笔记(七)复位和时钟1.复位2.系统时钟2.1时钟树2.2时钟源从时钟树可以看出时钟源共七种ESP32的时钟源分别来自外部晶振、内部PLL或振荡电路具体地说,这些时钟源为:2.2.1快速时钟PLL_CLK320MHz或480MHz内部PLL时钟XTL_CLK2~40MHz外部晶振时钟,模组板载的是40MHz晶

  7. APP连接ESP8266——采用AT指令 - 2

    1.主要实验设备及器材1.1一块ESP8266(如图1)图1 ESP8266模块1.2一个USB转TTL模块(如图2)图2 USB转TTL模块2.测试ESP8266模块 2.1连接设备        WIFI模块与USB转TTL模块进行连接,连接实物图如图3所示,硬件连线框图如图4所示。图3 连接实物图图4 硬件连接框图2.2打开串口调试助手        本次实验使用的软件是XCOMV2.3,默认波特率为115200,停止位为1,数据位为8,校验位为None(如图5)。图5 XCOMV2.32.3输入测试指令AT        测试AT启动,返回OK(如图6)图6 AT测试2.4复位指令AT

  8. ruby-on-rails - 在不更改系统时钟的情况下在 rspec 测试中设置系统时间 - 2

    我正在努力让Rails3应用程序准备好使用时区。我的开发机器在美国东部时间,我托管的服务器在UTC。在我的rspec测试中有没有一种方法可以更改ruby​​使用的系统时区,这样我就可以使用相同的系统时区运行测试,而不必更改我计算机上的系统时钟?我研究过Delorean和Timecop,它们不是我要找的。我正在寻找类似的东西Time.system_time_zone="UTC"...然后Time.now将返回UTC时间,而不是我的系统时区设置的时间。 最佳答案 before{Time.stub(:now){Time.now.utc}}

  9. 【JavaScript】手撕前端面试题:对象参数浅拷贝 | 简易深拷贝 | 完整深拷贝 - 2

    🖥️NodeJS专栏:Node.js从入门到精通🖥️博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述)🖥️TypeScript知识总结:TypeScript从入门到精通(十万字超详细知识点总结)🧑‍💼个人简介:大三学生,一个不甘平庸的平凡人🍬👉你的一键三连是我更新的最大动力❤️!文章目录1、浅拷贝要求思路代码2、简易深拷贝要求思路代码3、完整深拷贝要求思路代码1、浅拷贝要求补全JavaScript代码,要求实现一个对象参数的浅拷贝并返回拷贝之后的新对象。注意:参数可能包含函数、正则、日期、ES6新对象是对对象的参数进行浅拷贝,并不是直接对整个对象进行浅拷贝(整个

  10. 微机课设 | 基于STC15单片机的简易数字密码锁设计 - 2

    在日常的生活和工作中,住宅与部门的安全防范、单位的文件档案、财务报表以及一些个人资料的保存多以加锁的办法来解决。若使用传统的机械式钥匙开锁,人们常需携带多把钥匙, 使用极不方便, 且钥匙丢失后安全性即大打折扣。在安全技术防范领域,具有防盗报警功能的电子密码锁逐渐代替了传统的机械式密码锁,电子密码锁具有安全性高、成本低、功耗低、易操作等优点。本文主要介绍运用51单片机设计数字密码锁的方法。本设计采用自上而下的数字系统设计方法,将数字密码锁系统分解为若干子系统,并且进一步细划为若干模块,然后用C语言来设计这些模块,通过KEIL软件编译,并且进行实机调试。调试结果表明:该数字密码锁能够效验4位十进制

随机推荐