2025年ESP8266天气时钟

ESP8266天气时钟前言 从零开始打造 ESP8266 天气时钟 提示 不要用 5G 频段的 wifl 用 2 4G 的 一 材料准备 1 esp8266 2 SSD1306 四针 IIC 接口 3 杜邦线 母对母四根 心知天气 https www seniverse

大家好,我是讯享网,很高兴认识大家。

前言:从零开始打造ESP8266天气时钟,

提示:不要用5G频段的wifl,用2.4G的

一、材料准备

1、esp8266

                                          
讯享网

2、SSD1306(四针,IIC接口)

 3、杜邦线(母对母四根)、心知天气:https://www.seniverse.com

4、注意线的颜色、接线说明在代码里面有

 

二、软件及开发环境的配置

1、Arduino开发环境配置,先去访问Arduino官网,下载Arduino IDE

​

2、安装ESP8266 所需的库

https://arduino.esp8266.com/stable/package_esp8266com_index.json

​

(3)打开开发板管理选项,搜索esp8266并安装

 三、代码展示(代码参考:b站会飞的阿卡林)

/*设备引脚连接图 * ESP8266 --- OLED * 3.3V --- VCC * G (GND) --- GND * D1(GPIO5)--- SCL * D2(GPIO4)--- SDA */ //必要的头文件 #include <Arduino.h> #include <ArduinoJson.h> #include <ESP8266WiFi.h> #include <SPI.h> #include <U8g2lib.h> #include <WiFiUdp.h> #include <TimeLib.h> #include <DNSServer.h> #include <ESP8266WebServer.h> WiFiUDP Udp; unsigned int localPort = 8888; // 用于侦听UDP数据包的本地端口 //网络校时的相关配置 static const char ntpServerName[] = "ntp1.aliyun.com";//NTP服务器,使用阿里云 int timeZone = 8; //时区设置,采用东8区 //保存断网前的最新数据 int results_0_now_temperature_int_old; String results_0_now_text_str_old; int results_0_daily_1_high_int_old; int results_0_daily_1_low_int_old; String results_0_daily_1_text_day_str_old; //函数声明 void sendNTPpacket(IPAddress &address);//向给定地址的时间服务器发送NTP请求 void oledClockDisplay();//OLED的时钟显示器 void sendCommand(int command, int value);//发送命令 void OIED_Init();//OLED初始化 void connectWiFi();//连接WiFi void predict_the_weather(WiFiClient client,int i);//利用ArduinoJson库解析心知天气响应信息(预测天气) void real_time_weather(WiFiClient client,int i);//利用ArduinoJson库解析心知天气响应信息(实时天气) void http_Request_information(String reqRes,int stat);// 向心知天气服务器服务器请求信息并对信息进行解析 void display_1(int results_0_now_temperature_int,String results_0_now_text_str);//声明函数,用于显示温度、天气 void display_0(int results_0_now_temperature_int,String results_0_now_text_str);//输出实时天气 boolean isNTPConnected = false; const unsigned char xing[] U8X8_PROGMEM = { 0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x08, 0x08, 0xF8, 0x0F, 0x80, 0x00, 0x88, 0x00, 0xF8, 0x1F, 0x84, 0x00, 0x82, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x3F, 0x00, 0x00}; /*星*/ const unsigned char liu[] U8X8_PROGMEM = { 0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x20, 0x04, 0x10, 0x08, 0x10, 0x10, 0x08, 0x10, 0x04, 0x20, 0x02, 0x20, 0x00, 0x00}; /*六*/ typedef struct { //存储配置结构体 int tz; //时间戳 } config_type; config_type config; WiFiClient clientNULL; DNSServer dnsServer; ESP8266WebServer server(80); //WIFI连接配置 const char* ssid = "1";// 连接WiFi名 const char* password = "";// 连接WiFi密码 //天气API配置 const char* host = "api.seniverse.com";// 将要连接的服务器地址(心知天气) const int httpPort = 80;// 将要连接的服务器端口 // 心知天气请求所需信息 String reqUserKey = "SkcNuWgSONLPSNLH4";// 私钥 (请把你的心知天气的私钥复制到引号内) String reqLocation = "qingyang";// 城市 String reqUnit = "c";//摄氏 //设置屏幕(SSD1306,4针,IIC接口) U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE); int sta = 0; //初始化OLED void OIED_Init() { u8g2.begin(); u8g2.enableUTF8Print(); } //用于获取实时天气的函数 void TandW(){ String reqRes = "/v3/weather/now.json?key=" + reqUserKey + + "&location=" + reqLocation + "&language=en&unit=" +reqUnit; // 向心知天气服务器服务器请求信息并对信息进行解析 http_Request_information(reqRes,0); //延迟,需要低于20次/分钟 delay(5000); } //获取3天预报 void three_day(){ // 建立心知天气API当前天气请求资源地址 String reqRes = "/v3/weather/daily.json?key=" + reqUserKey + + "&location=" + reqLocation + "&language=en&unit=" + reqUnit + "&start=0&days=3"; // 向心知天气服务器服务器请求信息并对信息进行解析 http_Request_information(reqRes,1); delay(5000); } //时钟显示 void clock_display(time_t prevDisplay){ server.handleClient(); dnsServer.processNextRequest(); if (timeStatus() != timeNotSet) { if (now() != prevDisplay) { //时间改变时更新显示 prevDisplay = now(); oledClockDisplay(); } } } void setup(){ Serial.begin(9600); Serial.println(""); OIED_Init(); // 连接WiFi u8g2.clearBuffer(); u8g2.setFont(u8g2_font_unifont_t_chinese2); u8g2.setCursor(0, 14); u8g2.print("Waiting for WiFi"); u8g2.setCursor(0, 30); u8g2.print("connection..."); u8g2.sendBuffer(); connectWiFi(); Udp.begin(localPort); setSyncProvider(getNtpTime); setSyncInterval(300); //每300秒同步一次时间 } time_t prevDisplay = 0; //当时钟已经显示 void loop(){ if (sta>=0 && sta<=250){ clock_display(prevDisplay); }else if(sta == 251){ TandW(); }else{ three_day(); } ++sta; if(sta==253){ sta = 0; } } // 向心知天气服务器服务器请求信息并对信息进行解析 void http_Request_information(String reqRes,int stat){ WiFiClient client; // 建立http请求信息 String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"; Serial.println(""); Serial.print("Connecting to "); Serial.print(host); // 尝试连接服务器 if (client.connect(host, 80)){ Serial.println(" Success!"); // 向服务器发送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."); } if (stat == 0){ // 利用ArduinoJson库解析心知天气响应信息(实时数据) real_time_weather(client,1); }else if(stat == 1){ predict_the_weather(client,1); } }else{ Serial.println(" connection failed!"); if (stat == 0){ // 利用ArduinoJson库解析心知天气响应信息(实时数据) real_time_weather(clientNULL,0); }else if(stat == 1){ predict_the_weather(clientNULL,0); } } //断开客户端与服务器连接工作 client.stop(); } // 连接WiFi void connectWiFi(){ WiFi.begin(ssid, password); // 启动网络连接 Serial.print("Connecting to "); // 串口监视器输出网络连接信息 Serial.print(ssid); Serial.println(" ..."); // 告知用户NodeMCU正在尝试WiFi连接 int i = 0; // 这一段程序语句用于检查WiFi是否连接成功 while (WiFi.status() != WL_CONNECTED) { // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 delay(1000); // 如果WiFi连接成功则返回值为WL_CONNECTED Serial.print(i++); Serial.print(' '); // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值 } // 同时NodeMCU将通过串口监视器输出连接时长读秒。 // 这个读秒是通过变量i每隔一秒自加1来实现的。 Serial.println(""); // WiFi连接成功后 Serial.println("Connection established!"); // NodeMCU将通过串口监视器输出"连接成功"信息。 Serial.print("IP address: "); // 同时还将输出NodeMCU的IP地址。这一功能是通过调用 Serial.println(WiFi.localIP()); // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。 } //利用ArduinoJson库解析心知天气响应信息(实时天气) void real_time_weather(WiFiClient client,int i) { if(i==1) { 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); JsonObject results_0 = doc["results"][0]; JsonObject results_0_now = results_0["now"]; const char* results_0_now_text = results_0_now["text"]; // "Sunny" const char* results_0_now_code = results_0_now["code"]; // "0" const char* results_0_now_temperature = results_0_now["temperature"]; // "32" const char* results_0_last_update = results_0["last_update"]; // "2023-07-03T14:40:00+08:00" // 通过串口监视器显示以上信息 String results_0_now_text_str = results_0_now["text"].as<String>(); int results_0_now_code_int = results_0_now["code"].as<int>(); int results_0_now_temperature_int = results_0_now["temperature"].as<int>(); String results_0_last_update_str = results_0["last_update"].as<String>(); Serial.println(F("======Weahter Now=======")); Serial.print(F("Weather Now: ")); Serial.print(results_0_now_text_str); Serial.print(F(" ")); Serial.println(results_0_now_code_int); Serial.print(F("Temperature: ")); Serial.println(results_0_now_temperature_int); Serial.print(F("Last Update: ")); Serial.println(results_0_last_update_str); Serial.println(F("========================")); display_0(results_0_now_temperature_int,results_0_now_text_str); results_0_now_text_str_old = results_0_now_text_str; results_0_now_temperature_int_old = results_0_now_temperature_int; }else{ display_0(results_0_now_temperature_int_old,results_0_now_text_str_old); } } //输出实时天气 void display_0(int results_0_now_temperature_int,String results_0_now_text_str){ u8g2.clearBuffer(); u8g2.setFont(u8g2_font_wqy16_t_gb2312); u8g2.setCursor(15, 14); u8g2.print("庆阳实时天气"); u8g2.setFont(u8g2_font_logisoso24_tr); u8g2.setCursor(45, 44); u8g2.print(results_0_now_temperature_int); u8g2.setCursor(35, 61); u8g2.setFont(u8g2_font_unifont_t_chinese2); u8g2.print(results_0_now_text_str); u8g2.sendBuffer(); } // 利用ArduinoJson库解析心知天气响应信息(预测天气) void predict_the_weather(WiFiClient client,int i){ if(i==1){ 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) + 860; DynamicJsonDocument doc(capacity); deserializeJson(doc, client); JsonObject results_0 = doc["results"][0]; JsonArray results_0_daily = results_0["daily"]; JsonObject results_0_daily_0 = results_0_daily[0]; const char* results_0_daily_0_date = results_0_daily_0["date"]; const char* results_0_daily_0_text_day = results_0_daily_0["text_day"]; const char* results_0_daily_0_code_day = results_0_daily_0["code_day"]; const char* results_0_daily_0_text_night = results_0_daily_0["text_night"]; const char* results_0_daily_0_code_night = results_0_daily_0["code_night"]; const char* results_0_daily_0_high = results_0_daily_0["high"]; const char* results_0_daily_0_low = results_0_daily_0["low"]; const char* results_0_daily_0_rainfall = results_0_daily_0["rainfall"]; const char* results_0_daily_0_precip = results_0_daily_0["precip"]; const char* results_0_daily_0_wind_direction = results_0_daily_0["wind_direction"]; const char* results_0_daily_0_wind_direction_degree = results_0_daily_0["wind_direction_degree"]; const char* results_0_daily_0_wind_speed = results_0_daily_0["wind_speed"]; const char* results_0_daily_0_wind_scale = results_0_daily_0["wind_scale"]; const char* results_0_daily_0_humidity = results_0_daily_0["humidity"]; JsonObject results_0_daily_1 = results_0_daily[1]; const char* results_0_daily_1_date = results_0_daily_1["date"]; const char* results_0_daily_1_text_day = results_0_daily_1["text_day"]; const char* results_0_daily_1_code_day = results_0_daily_1["code_day"]; const char* results_0_daily_1_text_night = results_0_daily_1["text_night"]; const char* results_0_daily_1_code_night = results_0_daily_1["code_night"]; const char* results_0_daily_1_high = results_0_daily_1["high"]; const char* results_0_daily_1_low = results_0_daily_1["low"]; const char* results_0_daily_1_rainfall = results_0_daily_1["rainfall"]; const char* results_0_daily_1_precip = results_0_daily_1["precip"]; const char* results_0_daily_1_wind_direction = results_0_daily_1["wind_direction"]; const char* results_0_daily_1_wind_direction_degree = results_0_daily_1["wind_direction_degree"]; const char* results_0_daily_1_wind_speed = results_0_daily_1["wind_speed"]; const char* results_0_daily_1_wind_scale = results_0_daily_1["wind_scale"]; const char* results_0_daily_1_humidity = results_0_daily_1["humidity"]; JsonObject results_0_daily_2 = results_0_daily[2]; const char* results_0_daily_2_date = results_0_daily_2["date"]; const char* results_0_daily_2_text_day = results_0_daily_2["text_day"]; const char* results_0_daily_2_code_day = results_0_daily_2["code_day"]; const char* results_0_daily_2_text_night = results_0_daily_2["text_night"]; const char* results_0_daily_2_code_night = results_0_daily_2["code_night"]; const char* results_0_daily_2_high = results_0_daily_2["high"]; const char* results_0_daily_2_low = results_0_daily_2["low"]; const char* results_0_daily_2_rainfall = results_0_daily_2["rainfall"]; const char* results_0_daily_2_precip = results_0_daily_2["precip"]; const char* results_0_daily_2_wind_direction = results_0_daily_2["wind_direction"]; const char* results_0_daily_2_wind_direction_degree = results_0_daily_2["wind_direction_degree"]; const char* results_0_daily_2_wind_speed = results_0_daily_2["wind_speed"]; const char* results_0_daily_2_wind_scale = results_0_daily_2["wind_scale"]; const char* results_0_daily_2_humidity = results_0_daily_2["humidity"]; const char* results_0_last_update = results_0["last_update"]; String results_0_daily_0_date_str = results_0_daily_0["date"].as<String>(); String results_0_daily_0_text_day_str = results_0_daily_0["text_day"].as<String>(); int results_0_daily_0_code_day_int = results_0_daily_0["code_day"].as<int>(); String results_0_daily_0_text_night_str = results_0_daily_0["text_night"].as<String>(); int results_0_daily_0_code_night_int = results_0_daily_0["code_night"].as<int>(); int results_0_daily_0_high_int = results_0_daily_0["high"].as<int>(); int results_0_daily_0_low_int = results_0_daily_0["low"].as<int>(); String results_0_last_update_str = results_0["last_update"].as<String>(); int results_0_daily_1_high_int = results_0_daily_1["high"].as<int>(); int results_0_daily_1_low_int = results_0_daily_1["low"].as<int>(); String results_0_daily_1_text_day_str = results_0_daily_1["text_day"].as<String>(); Serial.println(F("======Today Weahter =======")); Serial.print(F("DATE: ")); Serial.println(results_0_daily_0_date_str); Serial.print(F("Day Weather: ")); Serial.print(results_0_daily_0_text_day_str); Serial.print(F(" ")); Serial.println(results_0_daily_0_code_day_int); Serial.print(F("Night Weather: ")); Serial.print(results_0_daily_0_text_night_str); Serial.print(F(" ")); Serial.println(results_0_daily_0_code_night_int); Serial.print(F("High: ")); Serial.println(results_0_daily_0_high_int); Serial.print(F("LOW: ")); Serial.println(results_0_daily_0_low_int); Serial.print(F("Last Update: ")); Serial.println(results_0_last_update_str); Serial.println(F("==============================")); display_1(results_0_daily_1_high_int,results_0_daily_1_low_int,results_0_daily_1_text_day_str); results_0_daily_1_high_int_old=results_0_daily_1_high_int; results_0_daily_1_low_int_old=results_0_daily_1_low_int; results_0_daily_1_text_day_str_old=results_0_daily_1_text_day_str; } else{ display_1(results_0_daily_1_high_int_old,results_0_daily_1_low_int_old,results_0_daily_1_text_day_str_old); } } //预测明天天气 void display_1(int results_0_daily_1_high_int,int results_0_daily_1_low_int,String results_0_daily_1_text_day_str){ u8g2.clearBuffer(); u8g2.setFont(u8g2_font_wqy16_t_gb2312); u8g2.setCursor(15, 14); u8g2.print("庆阳明天天气"); u8g2.setFont(u8g2_font_logisoso24_tr); u8g2.setCursor(20, 46); u8g2.print(results_0_daily_1_low_int); u8g2.setCursor(56, 46); u8g2.print("~"); u8g2.setCursor(75, 46); u8g2.print(results_0_daily_1_high_int); u8g2.setCursor(30, 62); u8g2.setFont(u8g2_font_unifont_t_chinese2); u8g2.print(results_0_daily_1_text_day_str); u8g2.sendBuffer(); } //NTP 代码 const int NTP_PACKET_SIZE = 48; // NTP时间在消息的前48个字节里 byte packetBuffer[NTP_PACKET_SIZE]; // 输入输出包的缓冲区 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; 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 - UL + timeZone * SECS_PER_HOUR); return secsSince1900 - UL + timeZone * SECS_PER_HOUR; } } Serial.println("No NTP Response :-("); //无NTP响应 isNTPConnected = false; return 0; //如果未得到时间则返回0 } // 向给定地址的时间服务器发送NTP请求 void sendNTPpacket(IPAddress &address) { memset(packetBuffer, 0, NTP_PACKET_SIZE); packetBuffer[0] = 0b; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; Udp.beginPacket(address, 123); //NTP需要使用的UDP端口号为123 Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket(); } //OLED的时钟显示器 void oledClockDisplay() { int years, months, days, hours, minutes, seconds, weekdays; years = year(); months = month(); days = day(); hours = hour(); minutes = minute(); seconds = second(); weekdays = weekday(); Serial.printf("%d/%d/%d %d:%d:%d Weekday:%d\n", years, months, days, hours, minutes, seconds, weekdays); u8g2.clearBuffer(); u8g2.setFont(u8g2_font_unifont_t_chinese2); u8g2.setCursor(0, 14); if (isNTPConnected) { if(timeZone>=0) { u8g2.print("当前时间(UTC+"); u8g2.print(timeZone); u8g2.print(")"); } else { u8g2.print("当前时间(UTC"); u8g2.print(timeZone); u8g2.print(")"); } } else u8g2.print("无网络!"); //如果上次对时失败,则会显示无网络 String currentTime = ""; if (hours < 10) currentTime += 0; currentTime += hours; currentTime += ":"; if (minutes < 10) currentTime += 0; currentTime += minutes; currentTime += ":"; if (seconds < 10) currentTime += 0; currentTime += seconds; String currentDay = ""; currentDay += years; currentDay += "/"; if (months < 10) currentDay += 0; currentDay += months; currentDay += "/"; if (days < 10) currentDay += 0; currentDay += days; u8g2.setFont(u8g2_font_logisoso24_tr); u8g2.setCursor(0, 44); u8g2.print(currentTime); u8g2.setCursor(0, 61); u8g2.setFont(u8g2_font_unifont_t_chinese2); u8g2.print(currentDay); u8g2.drawXBM(80, 48, 16, 16, xing); u8g2.setCursor(95, 62); u8g2.print("期"); if (weekdays == 1) u8g2.print("日"); else if (weekdays == 2) u8g2.print("一"); else if (weekdays == 3) u8g2.print("二"); else if (weekdays == 4) u8g2.print("三"); else if (weekdays == 5) u8g2.print("四"); else if (weekdays == 6) u8g2.print("五"); else if (weekdays == 7) u8g2.drawXBM(111, 49, 16, 16, liu); u8g2.sendBuffer(); }

讯享网

 四、成品展示

 

小讯
上一篇 2025-03-27 22:50
下一篇 2025-04-05 21:26

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/74856.html