ESP8266实现天气预报

一、硬件准备

ESP8266 nodeMCU*1,0.96寸OLED屏幕,DHT11

GPIO功能状态限制
0引导模式选择3.3V无Hi-Z
1TX0-串口通讯过程中不能使用
2引导模式选择
TX1
3.3V启动时不能接地
启动时发送调试信息
3RX0-串口通讯过程中不能使用
4SDA (I²C)--
5SCL (I²C)--
6-11连接闪存-不可用
12MISO (SPI)--
13MOSI (SPI)--
14SCK (SPI)--
15SS (SPI)0V上拉电阻不可用

16

睡眠唤醒-无上拉电阻,仅有下拉电阻
连接 RST 引脚实现睡眠唤醒

二、代码实现

用到的一些库文件

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <ESP8266HTTPClient.h>
#include "WiFiClient.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <string.h>

1、连接WIFI

const char* ssid="xxxxx";         //WIFI名称
const char* password="xxxxx";     //WIFI密码

//连接WiFi
void connectWifi()
{
  WiFi.begin(ssid,password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);                                 // 如果WiFi连接成功则返回值为WL_CONNECTED                       
    Serial.print(".");
  }
  Serial.println("");                           // WiFi连接成功后
  Serial.println("Connection established!");
}

2、发送HTTP请求

String reqUserKey="xxxxxxxxxx";   //用户私钥
String reqLocation="Beijing";            //查询地点
String reqUnit="c";                      //温度单位为摄氏度
String reqRes = "/v3/weather/daily.json?key=" + reqUserKey +
                  + "&location=" + reqLocation + 
                  "&language=en&unit=" +reqUnit+"&start=0"+"&days=3";   //API的HTTP调用


void httpRequest(String reqRes){
  if(millis()-wifitick<10000) return;
  wifitick=millis();                               //实现定时调用(10s)

  WiFiClient client;
  // 建立http请求信息
  String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" + 
                              "Host: " + host + "\r\n" + 
                              "Connection: close\r\n\r\n";

  if (client.connect(host, 80)){          // 尝试连接服务器
    Serial.println(" Success!");
    client.print(httpRequest);    // 向服务器发送http请求信息
    String status_response = client.readStringUntil('\n');    // 获取并显示服务器响应状态行
    if (client.find("\r\n\r\n")) {            // 使用find跳过HTTP响应头
      Serial.println("Found Header End. Start Parsing.");
    }
    parseInfo(client);           // 自己编写JSON函数解析心知天气响应信息
  } 
  else {
    Serial.println(" connection failed!");
  }  
  client.stop();          //断开客户端与服务器连接工作
}

3、JSON解析

String results_0_daily_date_0;
String results_0_daily_date_1;
String results_0_daily_date_2;
int results_0_daily_highT_0;
int results_0_daily_highT_1;
int results_0_daily_highT_2;
int results_0_daily_humidity_0;
int results_0_daily_humidity_1;
int results_0_daily_humidity_2;
String results_0_daily_weather_0;
String results_0_daily_weather_1;
String results_0_daily_weather_2;
String results_0_location_name;

//对JOSN数据解析
void parseInfo(WiFiClient client){
  //开辟存储空间
  const size_t capacity = JSON_ARRAY_SIZE(1) +JSON_ARRAY_SIZE(3)+ JSON_OBJECT_SIZE(1)+
                          JSON_OBJECT_SIZE(3)+JSON_OBJECT_SIZE(6) + 3*JSON_OBJECT_SIZE(14)  + 700; 
  DynamicJsonDocument doc(capacity);
  deserializeJson(doc, client);
  
  JsonObject results_0 = doc["results"][0];                          //result为数组第一行
  JsonObject results_0_location = results_0["location"];
  JsonArray results_0_daily = results_0["daily"];                    //对返回的数组进行索引
  JsonObject results_0_daily_0=results_0_daily[0];
  JsonObject results_0_daily_1=results_0_daily[1];
  JsonObject results_0_daily_2=results_0_daily[2];
  
  results_0_location_name = results_0_location["name"].as<String>();     //地点 
  results_0_daily_date_0 = results_0_daily_0["date"].as<String>();       //日期
  results_0_daily_date_1 = results_0_daily_1["date"].as<String>();       //日期
  results_0_daily_date_2 = results_0_daily_2["date"].as<String>();       //日期
  results_0_daily_highT_0 = results_0_daily_0["high"].as<int>();         //今天最高温度
  results_0_daily_highT_1 = results_0_daily_1["high"].as<int>();         //明天最高温度
  results_0_daily_highT_2 = results_0_daily_2["high"].as<int>();         //后天最高温度
  results_0_daily_humidity_0=results_0_daily_0["humidity"].as<int>();    //今天湿度
  results_0_daily_humidity_1=results_0_daily_1["humidity"].as<int>();    //明天湿度
  results_0_daily_humidity_2=results_0_daily_2["humidity"].as<int>();    //后天湿度
  results_0_daily_weather_0 = results_0_daily_0["text_day"].as<String>();//今天天气
  results_0_daily_weather_1 = results_0_daily_1["text_day"].as<String>();//明天天气
  results_0_daily_weather_2 = results_0_daily_2["text_day"].as<String>();//后天天气 
}

4、获取当前时间

String Year;
String Month;
String Day;
String Hour;
String Minute;
String payload;

const String url="http://quan.suning.com/getSysTime.do";
void GetTime()
{
  if(millis()-timtick<5000) return;
  timtick=millis();

  WiFiClient tcpClient;
  HTTPClient http;
  http.begin(tcpClient,url);
  http.addHeader("Content-Type","text/plain");
  http.POST("Message from ESP8266");
  payload=http.getString();
  http.end();
  TimeHandle();
}

void TimeHandle()
{
  Year=payload.substring(13,17);
  Month=payload.substring(18,20);
  Day=payload.substring(21,23);
  Hour=payload.substring(24,26);
  Minute=payload.substring(27,29);
}

5、获取室内温湿度

#include <DHT.h>
#define DHTPIN 12
#define DHTTYPE DHT11
DHT dht(DHTPIN,DHTTYPE);

unsigned int dhttick=0;
float h;
float t;

void DHT_Init()
{
  dht.begin();
}

void DHT_Begin()
{
  if(millis()-dhttick<1000) return;   //1s调用一次
  dhttick=millis();

  h=dht.readHumidity();
  t=dht.readTemperature();
  if(isnan(h)||isnan(t)){
    return;
  }
}

6、OLED屏幕显示

(1)初始化

Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);

void OLED_Init()
{
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);      // 设置OLED的I2C地址
  display.clearDisplay();                         // 清空屏幕
  display.setTextSize(1);                         // 设置字体大小
  display.setTextColor(SSD1306_WHITE);            // 设置字体颜色
  // display.display();                              // 使更改的显示生效
}

(2)屏幕显示

void OLED_Display()
{
  display.clearDisplay();
  if(page==0||page==1||page==2)
  {
    display.setCursor(88,0);
    sprintf(LineString,"%s:%s",Hour,Minute);               //时间
    display.print(LineString);
    display.drawBitmap(48,16, tian_zn, 16, 16,1);          //天气
    display.drawBitmap(64,16, qi_zn, 16, 16,1);
    display.drawBitmap(80,16, maohao, 8, 16,1);
    display.drawBitmap(48,32, wen_zn, 16, 16,1);           //温度
    display.drawBitmap(64,32, du_zn, 16, 16,1);
    display.drawBitmap(80,32, maohao, 8, 16,1);
    display.drawBitmap(104,32, du_flag, 8, 16,1);
    display.drawBitmap(112,32, C_zn, 8, 16,1);
    display.drawBitmap(48,48, shi_zn, 16, 16,1);           //湿度
    display.drawBitmap(64,48, du_zn, 16, 16,1);
    display.drawBitmap(80,48, maohao, 8, 16,1);
    display.drawBitmap(104,48, baifenhao, 8, 16,1);
  }
  if(page==0)
  {
    Number_Handle(results_0_daily_highT_0,16,0);
    Number_Handle(results_0_daily_humidity_0,32,0);
    Weather_Judge(results_0_daily_weather_0);
    sprintf(LineString,"%s",results_0_daily_date_0);
    display.setCursor(0,0);
    display.print(LineString);
  }
  else if(page==1)
  {
    Number_Handle(results_0_daily_highT_1,16,0);
    Number_Handle(results_0_daily_humidity_1,32,0);
    Weather_Judge(results_0_daily_weather_1);
    sprintf(LineString,"%s",results_0_daily_date_1);
    display.setCursor(0,0);
    display.print(LineString);
  }
  else if(page==2)
  {
    Number_Handle(results_0_daily_highT_2,16,0);
    Number_Handle(results_0_daily_humidity_2,32,0);
    Weather_Judge(results_0_daily_weather_2);
    sprintf(LineString,"%s",results_0_daily_date_2);
    display.setCursor(0,0);
    display.print(LineString);
  }
  else if(page==3)
  {
    display.drawBitmap(0,16, temper, 48, 48,1);
    Number_Handle_1(t,0,0);
    display.drawBitmap(96,24, du_1, 16, 32,1);
  }
  else if(page==4)
  {
    display.drawBitmap(0,16, humidi, 48, 48,1);
    Number_Handle_1(h,0,0);
    display.drawBitmap(96,24, baifenhao_1, 16, 32,1);
  }
  display.display();
}

(3)界面切换

void Page_change()
{
  if(millis()-pagetick<5000) return;  //每5s切换一次界面
  pagetick=millis();

  page=(page+1)%5;
}

(4)一些子函数

//天气温度和湿度使用
void Number_Handle(int number,int offset,int offset1)
{
  static unsigned char high,low;
  high=number/10;
  low=number%10;
  switch(high)
  {
    case 0:display.drawBitmap(88+offset1,16+offset, ling_zn, 8, 16,1);break;
    case 1:display.drawBitmap(88+offset1,16+offset, yi_zn, 8, 16,1);break;
    case 2:display.drawBitmap(88+offset1,16+offset, er_zn, 8, 16,1);break;
    case 3:display.drawBitmap(88+offset1,16+offset, san_zn, 8, 16,1);break;
    case 4:display.drawBitmap(88+offset1,16+offset, si_zn, 8, 16,1);break;
    case 5:display.drawBitmap(88+offset1,16+offset, wu1_zn, 8, 16,1);break;
    case 6:display.drawBitmap(88+offset1,16+offset, liu_zn, 8, 16,1);break;
    case 7:display.drawBitmap(88+offset1,16+offset, qi1_zn, 8, 16,1);break;
    case 8:display.drawBitmap(88+offset1,16+offset, ba_zn, 8, 16,1);break;
    case 9:display.drawBitmap(88+offset1,16+offset, jiu_zn, 8, 16,1);break;
  }
  switch(low)
  {
    case 0:display.drawBitmap(96+offset1,16+offset, ling_zn, 8, 16,1);break;
    case 1:display.drawBitmap(96+offset1,16+offset, yi_zn, 8, 16,1);break;
    case 2:display.drawBitmap(96+offset1,16+offset, er_zn, 8, 16,1);break;
    case 3:display.drawBitmap(96+offset1,16+offset, san_zn, 8, 16,1);break;
    case 4:display.drawBitmap(96+offset1,16+offset, si_zn, 8, 16,1);break;
    case 5:display.drawBitmap(96+offset1,16+offset, wu1_zn, 8, 16,1);break;
    case 6:display.drawBitmap(96+offset1,16+offset, liu_zn, 8, 16,1);break;
    case 7:display.drawBitmap(96+offset1,16+offset, qi1_zn, 8, 16,1);break;
    case 8:display.drawBitmap(96+offset1,16+offset, ba_zn, 8, 16,1);break;
    case 9:display.drawBitmap(96+offset1,16+offset, jiu_zn, 8, 16,1);break;
  }
}
//室内温度和湿度使用
void Number_Handle_1(int number,int offset,int offset1)
{
  static unsigned char high,low;
  high=number/10;
  low=number%10;
  switch(high)
  {
    case 0:display.drawBitmap(64+offset1,24+offset, ling_zn_1, 16, 32,1);break;
    case 1:display.drawBitmap(64+offset1,24+offset, yi_zn_1, 16, 32,1);break;
    case 2:display.drawBitmap(64+offset1,24+offset, er_zn_1, 16, 32,1);break;
    case 3:display.drawBitmap(64+offset1,24+offset, san_zn_1, 16, 32,1);break;
    case 4:display.drawBitmap(64+offset1,24+offset, si_zn_1, 16, 32,1);break;
    case 5:display.drawBitmap(64+offset1,24+offset, wu1_zn_1, 16, 32,1);break;
    case 6:display.drawBitmap(64+offset1,24+offset, liu_zn_1, 16, 32,1);break;
    case 7:display.drawBitmap(64+offset1,24+offset, qi1_zn_1, 16, 32,1);break;
    case 8:display.drawBitmap(64+offset1,24+offset, ba_zn_1, 16, 32,1);break;
    case 9:display.drawBitmap(64+offset1,24+offset, jiu_zn_1, 16, 32,1);break;
  }
  switch(low)
  {
    case 0:display.drawBitmap(80+offset1,24+offset, ling_zn_1, 16, 32,1);break;
    case 1:display.drawBitmap(80+offset1,24+offset, yi_zn_1, 16, 32,1);break;
    case 2:display.drawBitmap(80+offset1,24+offset, er_zn_1, 16, 32,1);break;
    case 3:display.drawBitmap(80+offset1,24+offset, san_zn_1, 16, 32,1);break;
    case 4:display.drawBitmap(80+offset1,24+offset, si_zn_1, 16, 32,1);break;
    case 5:display.drawBitmap(80+offset1,24+offset, wu1_zn_1, 16, 32,1);break;
    case 6:display.drawBitmap(80+offset1,24+offset, liu_zn_1, 16, 32,1);break;
    case 7:display.drawBitmap(80+offset1,24+offset, qi1_zn_1, 16, 32,1);break;
    case 8:display.drawBitmap(80+offset1,24+offset, ba_zn_1, 16, 32,1);break;
    case 9:display.drawBitmap(80+offset1,24+offset, jiu_zn_1, 16, 32,1);break;
  }
}
void Weather_Judge(String Weather)
{
  sprintf(LineString,"%s",Weather);
  if(strcmp(LineString,"Overcast")==0)
  {
    display.drawBitmap(0,16, yin, 48, 48,1);
    display.drawBitmap(88,16, yin_zn, 16, 16,1);
  }
  else if(strcmp(LineString,"Cloudy")==0)
  {
    display.drawBitmap(0,16, duoyun, 48, 48,1);
    display.drawBitmap(88,16, duo_zn, 16, 16,1);
    display.drawBitmap(104,16, yun_zn, 16, 16,1);
  }
  else if(strcmp(LineString,"Sunny")==0)
  {
    display.drawBitmap(0,16, qing, 48, 48,1);
    display.drawBitmap(88,16, qing_zn, 16, 16,1);
  }
  else if(strcmp(LineString,"Light rain")==0)
  {
    display.drawBitmap(0,16, light_rain, 48, 48,1);
    display.drawBitmap(88,16, xiao_zn, 16, 16,1);
    display.drawBitmap(104,16, yu_zn, 16, 16,1);
  }
  else if(strcmp(LineString,"Moderate rain")==0)
  {
    display.drawBitmap(0,16, middle_rain, 48, 48,1);
    display.drawBitmap(88,16, zhong_zn, 16, 16,1);
    display.drawBitmap(104,16, yu_zn, 16, 16,1);
  }
  else if(strcmp(LineString,"Heavy rain")==0)
  {
    display.drawBitmap(0,16, heavy_rain, 48, 48,1);
    display.drawBitmap(88,16, da_zn, 16, 16,1);
    display.drawBitmap(104,16, yu_zn, 16, 16,1);
  }
  else if(strcmp(LineString,"Thundershower")==0)              //Thundershower写入LineString会乱码,未解决
  {
    display.drawBitmap(0,16, thunder_rain, 48, 48,1);
    display.drawBitmap(88,16, bao_zn, 16, 16,1);
    display.drawBitmap(104,16, yu_zn, 16, 16,1);
  }
}
//可以去心知开发文档里查看并继续添加

PS:

        对图标和字符取模后的数组在源代码的tubiao.h和hanzi.h文件中 

7、主函数

void setup() {
  DHT_Init();                                     //DHT初始化
  connectWifi();                                  //连接WIFI
  OLED_Init();                                    //OLED初始化                        
  Serial.begin(115200);
}

void loop() {
  httpRequest(reqRes);
  DHT_Begin();
  GetTime();
  OLED_Display();
  Page_change();
}

三、最终现象

VID_20240612_141708

四、源代码

https://wwl.lanzoue.com/iiDli21nzyab

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值