一、硬件准备
ESP8266 nodeMCU*1,0.96寸OLED屏幕,DHT11
GPIO | 功能 | 状态 | 限制 |
0 | 引导模式选择 | 3.3V | 无Hi-Z |
1 | TX0 | - | 串口通讯过程中不能使用 |
2 | 引导模式选择 TX1 | 3.3V | 启动时不能接地 启动时发送调试信息 |
3 | RX0 | - | 串口通讯过程中不能使用 |
4 | SDA (I²C) | - | - |
5 | SCL (I²C) | - | - |
6-11 | 连接闪存 | - | 不可用 |
12 | MISO (SPI) | - | - |
13 | MOSI (SPI) | - | - |
14 | SCK (SPI) | - | - |
15 | SS (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