欢迎光临散文网 会员登陆 & 注册

esp8266制作简易气象站

2023-06-30 13:58 作者:pb-qd  | 我要投稿

温湿度检测

ESP8266 CH340

ESP8266-NodeMCU搭建Arduino IDE开发环境

参考链接"太极创客"

0.96 寸OLED 4针

从淘宝店铺得到的资料:

0.91寸OLED 4针 链接:https://pan.baidu.com/s/1oGT7Pg00rmYFhS0QzzEJcw?pwd=8889  提取码:8889

0.96寸OLED 链接:https://pan.baidu.com/s/1EHmikFHeFMRDAI_hr85tHQ?pwd=8xc1  提取码:8xc1

1.3寸OLED 链接:https://pan.baidu.com/s/1SA0RHKdYF8p2XCBKIt-JYA?pwd=i2l9  提取码:i2l9

1.54寸OLED 4针 链接:https://pan.baidu.com/s/1Da8EKFy0qM-NjZtNRNY41w?pwd=8889  提取码:8889

1.54寸OLED 7针 链接:https://pan.baidu.com/s/1INwNfoje1pqrMyh-tWMZYw?pwd=8889  提取码:8889

2.42寸OLED显示液晶屏模块 7针 链接:https://pan.baidu.com/s/1U0bzHRbcs30MQJjdikV-xQ?pwd=8889  提取码:8889    

DHT11温湿度传感器

https://pan.baidu.com/s/1aROzKaKxbXm2DzMy2OtICA 提取码: q6qb

ESP8266驱动0.96寸OLED屏幕

NTP展示网络时间

网络时间协议NTP(Network Time Protocol)是TCP/IP协议族里面的一个应用层协议,用来使客户端和服务器之间进行时钟同步,提供高精准度的时间校正。NTP服务器从权威时钟源(例如原子钟、GPS)接收精确的协调世界时UTC,客户端再从服务器请求和接收时间。NTP基于UDP报文进行传输。

1.接线方式

2.参考资料

https://randomnerdtutorials.com/esp8266-nodemcu-date-time-ntp-client-server-arduino/

https://blog.csdn.net/qq_45205470/article/details/126712272

3.修改后的代码


#include <stdio.h>
#include <stdlib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include <NTPClient.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
// Setup Wifi
const char *ssid     = "2023";      //wifiName
const char *password = "Internet";  //wifiPW

// Set date to day
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
WiFiUDP ntpUDP; // define ntp
NTPClient timeClient(ntpUDP, "ntp.aliyun.com");

Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup() {
 Serial.begin(115200); //打开串口通讯,设置传输速率为115200字节每秒

 WiFi.begin(ssid, password); // init wifi ssid and password
 while ( WiFi.status() != WL_CONNECTED ) {
   delay (500);
   Serial.print ( "." ); // while connecting will print this
 }
 
 timeClient.begin( );// wifi ready to use(这一步编译可能会出错,出错的话就下载最新的NTP库版本)
 timeClient.setTimeOffset(28800);//设置时区,同步当地时间
 // Set offset time in seconds to adjust for your timezone, for example:
 // GMT +1 = 3600
 // GMT +8 = 28800
 // GMT -1 = -3600
 // GMT 0 = 0


 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
   Serial.println(F("SSD1306 allocation failed"));
   for (;;);
 }
 delay(2000);
 display.clearDisplay();
 display.setTextColor(WHITE);
}

void loop() {
 timeClient.update();
 // 3秒刷新显示内容
 delay(1000);
 // 清空显示
 display.clearDisplay();
 // 使更改的显示生效
 display.display();
 // 判断应该显示的内容
  display.setTextSize(1);  // 设置字体大小(1~8)
  display.setCursor(0, 0); // 设置坐标
  display.print("Time:"); // 显示内容
  display.setTextSize(2);
  display.setCursor(15, 15);
  display.print(timeClient.getHours());
  display.print(":");
  display.print(timeClient.getMinutes()); // separate by minutes
  display.print(":");
  display.println(timeClient.getSeconds()); // separate by second
  display.setTextSize(2);
  display.setCursor(25, 40);
  display.println(daysOfTheWeek[timeClient.getDay()]);


 Serial.print(daysOfTheWeek[timeClient.getDay()]);
 Serial.print(timeClient.getHours()); // separate by hour
 Serial.print(":");
 Serial.print(timeClient.getMinutes()); // separate by minutes
 Serial.print(":");
 Serial.println(timeClient.getSeconds()); // separate by


 display.display();
}


weather station(气象站)

材料清单:

  • ESP8266 (ESP-12F)

  • 0.96寸OLED屏幕

  • DHT11温湿度检测模块


参考资料

  • youtube博主“HACKOPAULIS”  ( https://www.youtube.com/watch?v=6-oLPSTG4GM )

  • csdn ( https://blog.csdn.net/qq_30135687/article/details/125365771 )

  • openWeatherApi (https://openweathermap.org/)

  • 其他 ( https://www.google.com/ )

效果展示



相关代码

#include <Arduino.h>
#include <ESPWiFi.h>
#include <ESPHTTPClient.h>
#include <JsonListener.h>
#include <time.h>                       // time() ctime()
#include <sys/time.h>                   // struct timeval
#include <coredecls.h>                  // settimeofday_cb()

#include "SSD1306Wire.h"
#include "OLEDDisplayUi.h"
#include "Wire.h"
#include "OpenWeatherMapCurrent.h"
#include "OpenWeatherMapForecast.h"
#include "WeatherStationFonts.h"
#include "WeatherStationImages.h"
#include "DHT.h"

const char* WIFI_SSID = "2023";    //wifiName
const char* WIFI_PWD = "Internet"; //wifiPassword

#define TZ              8       // (utc+) TZ in hours(这个时区可以自己谷歌查询)
#define DST_MN          0      // use 60mn for summer time in some countries

// Setup
const int UPDATE_INTERVAL_SECS = 10 * 60; // Update every 30 minutes

// Display Settings
const int I2C_DISPLAY_ADDRESS = 0x3C;
#if defined(ESP8266)
const int SDA_PIN = D2;
const int SDC_PIN = D1;
#else
const int SDA_PIN = 19; //D3;
const int SDC_PIN = 20; //D4;
#endif

String OPEN_WEATHER_MAP_APP_ID = "aa7f46b96a471b23c4e0c5dc069fcebb"; //keyApi获取途径(https://openweathermap.org/)
String OPEN_WEATHER_MAP_LOCATION_ID = "1814991"; //城市坐标

// Pick a language code from this list:
// Arabic - ar, Bulgarian - bg, Catalan - ca, Czech - cz, German - de, Greek - el,
// English - en, Persian (Farsi) - fa, Finnish - fi, French - fr, Galician - gl,
// Croatian - hr, Hungarian - hu, Italian - it, Japanese - ja, Korean - kr,
// Latvian - la, Lithuanian - lt, Macedonian - mk, Dutch - nl, Polish - pl,
// Portuguese - pt, Romanian - ro, Russian - ru, Swedish - se, Slovak - sk,
// Slovenian - sl, Spanish - es, Turkish - tr, Ukrainian - ua, Vietnamese - vi,
// Chinese Simplified - zh_cn, Chinese Traditional - zh_tw.
String OPEN_WEATHER_MAP_LANGUAGE = "zh_cn";
const uint8_t MAX_FORECASTS = 4;

const boolean IS_METRIC = true;

// Adjust according to your language
const String WDAY_NAMES[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
const String MONTH_NAMES[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};

/***************************
* End Settings
**************************/
SSD1306Wire     display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
OLEDDisplayUi   ui( &display );

OpenWeatherMapCurrentData currentWeather;
OpenWeatherMapCurrent currentWeatherClient;

OpenWeatherMapForecastData forecasts[MAX_FORECASTS];
OpenWeatherMapForecast forecastClient;

#define TZ_MN           ((TZ)*60)
#define TZ_SEC          ((TZ)*3600)
#define DST_SEC         ((DST_MN)*60)
time_t now;

// flag changed in the ticker function every 10 minutes
bool readyForWeatherUpdate = false;

String lastUpdate = "--";

long timeSinceLastWUpdate = 0;

//declaring prototypes
void drawProgress(OLEDDisplay *display, int percentage, String label);
void updateData(OLEDDisplay *display);
void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawTemp(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawHum(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex);
void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
void setReadyForWeatherUpdate();

FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecast, drawTemp, drawHum };
int numberOfFrames = 5;

OverlayCallback overlays[] = { drawHeaderOverlay };
int numberOfOverlays = 1;

DHT dht = DHT(D3, DHT11, 6);

void setup() {
 Serial.begin(115200);
 Serial.println();
 Serial.println();

 // initialize dispaly
 display.init();
 display.clear();
 display.display();

 display.setFont(ArialMT_Plain_10);
 display.setTextAlignment(TEXT_ALIGN_CENTER);
 display.setContrast(255);

 dht.begin();
 WiFi.begin(WIFI_SSID, WIFI_PWD);

 int counter = 0;
 while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   Serial.print(".");
   display.clear();
   display.drawString(64, 10, "Connecting to WiFi");
   display.drawXbm(46, 30, 8, 8, counter % 3 == 0 ? activeSymbole : inactiveSymbole);
   display.drawXbm(60, 30, 8, 8, counter % 3 == 1 ? activeSymbole : inactiveSymbole);
   display.drawXbm(74, 30, 8, 8, counter % 3 == 2 ? activeSymbole : inactiveSymbole);
   display.display();

   counter++;
 }

 // Get time from network time service
 configTime(TZ_SEC, DST_SEC, "pool.ntp.org");

 ui.setTargetFPS(30);

 ui.setActiveSymbol(activeSymbole);
 ui.setInactiveSymbol(inactiveSymbole);

 // You can change this to
 // TOP, LEFT, BOTTOM, RIGHT
 ui.setIndicatorPosition(BOTTOM);

 // Defines where the first frame is located in the bar.
 ui.setIndicatorDirection(LEFT_RIGHT);

 // You can change the transition that is used
 // SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN
 ui.setFrameAnimation(SLIDE_LEFT);

 ui.setFrames(frames, numberOfFrames);

 ui.setOverlays(overlays, numberOfOverlays);

 // Inital UI takes care of initalising the display too.
 ui.init();

 Serial.println("");

 updateData(&display);
 
 display.clear();
 display.drawXbm(26,0,logo1_width,logo1_height,logo1_bits);
 display.display();
 delay(5000);
 
 display.clear();
 display.setTextAlignment(TEXT_ALIGN_LEFT);
 display.setFont(ArialMT_Plain_10);
 display.drawString(0,0,"LOADING");
 display.display();  
 delay(4000);
 display.drawString(0,10,"TIME AND DATE");
 display.display();  
 delay(4000);
 display.drawString(0,20,"TEMPERATURE");
 display.display();  
 delay(4000);
 display.drawString(0,30,"HUMIDITY");
 display.display();  
 delay(4000);
 display.drawString(0,40,"FORECAST");
 display.display();  
 delay(4000);
 display.drawString(0,50,"INITIALIZING GUI");
 display.display();  
 delay(3000);
}

void loop() {
 
 
 if (millis() - timeSinceLastWUpdate > (1000L*UPDATE_INTERVAL_SECS)) {
   setReadyForWeatherUpdate();
   timeSinceLastWUpdate = millis();
 }

 if (readyForWeatherUpdate && ui.getUiState()->frameState == FIXED) {
   updateData(&display);
 }

 int remainingTimeBudget = ui.update();

 if (remainingTimeBudget > 0) {
   // You can do some work here
   // Don't do stuff if you are below your
   // time budget.
   delay(remainingTimeBudget);
 }


}

void drawProgress(OLEDDisplay *display, int percentage, String label) {
 display->clear();
 display->setTextAlignment(TEXT_ALIGN_CENTER);
 display->setFont(ArialMT_Plain_10);
 display->drawString(64, 10, label);
 display->drawProgressBar(2, 28, 124, 10, percentage);
 display->display();
}

void updateData(OLEDDisplay *display) {
 drawProgress(display, 10, "Updating time...");
 drawProgress(display, 30, "Updating weather...");
 currentWeatherClient.setMetric(IS_METRIC);
 currentWeatherClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
 currentWeatherClient.updateCurrentById(&currentWeather, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID);
 drawProgress(display, 50, "Updating forecasts...");
 forecastClient.setMetric(IS_METRIC);
 forecastClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
 uint8_t allowedHours[] = {12};
 forecastClient.setAllowedHours(allowedHours, sizeof(allowedHours));
 forecastClient.updateForecastsById(forecasts, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID, MAX_FORECASTS);

 readyForWeatherUpdate = false;
 drawProgress(display, 100, "Done...");
 delay(1000);
}



void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
 now = time(nullptr);
 struct tm* timeInfo;
 timeInfo = localtime(&now);
 char buff[16];


 display->setTextAlignment(TEXT_ALIGN_CENTER);
 display->setFont(ArialMT_Plain_10);
 String date = WDAY_NAMES[timeInfo->tm_wday];

 sprintf_P(buff, PSTR("%s, %02d/%02d/%04d"), WDAY_NAMES[timeInfo->tm_wday].c_str(), timeInfo->tm_mday, timeInfo->tm_mon+1, timeInfo->tm_year + 1900);
 display->drawString(64 + x, 5 + y, String(buff));
 display->setFont(ArialMT_Plain_24);

 sprintf_P(buff, PSTR("%02d:%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec);
 display->drawString(64 + x, 15 + y, String(buff));
 display->setTextAlignment(TEXT_ALIGN_LEFT);
}

void drawTemp(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {

 float temperature = dht.readTemperature();
 
 display->setTextAlignment(TEXT_ALIGN_CENTER);
 display->setFont(ArialMT_Plain_10);
 
 display->drawString(64 + x, 5 + y, "Room Temperature");
 display->setFont(ArialMT_Plain_24);

 display->drawString(64 + x, 15 + y, String(temperature,1)+("°C"));
 display->setTextAlignment(TEXT_ALIGN_LEFT);
}

void drawHum(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {

 int humidity = dht.readHumidity();
 
 display->setTextAlignment(TEXT_ALIGN_CENTER);
 display->setFont(ArialMT_Plain_10);
 
 display->drawString(64 + x, 5 + y, "Humidity");
 display->setFont(ArialMT_Plain_24);

 display->drawString(64 + x, 15 + y, String(humidity)+(" %"));
 display->setTextAlignment(TEXT_ALIGN_LEFT);
}

void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
 display->setFont(ArialMT_Plain_10);
 display->setTextAlignment(TEXT_ALIGN_CENTER);
 display->drawString(64 + x, 38 + y, currentWeather.description);

 display->setFont(ArialMT_Plain_24);
 display->setTextAlignment(TEXT_ALIGN_LEFT);
 String temp = String(currentWeather.temp, 1) + (IS_METRIC ? "°C" : "°F");
 display->drawString(51 + x, 5 + y, temp);

 display->setFont(Meteocons_Plain_36);
 display->setTextAlignment(TEXT_ALIGN_CENTER);
 display->drawString(23  + x, 0 + y, currentWeather.iconMeteoCon);
}


void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
 drawForecastDetails(display, x, y, 0);
 drawForecastDetails(display, x + 44, y, 1);
 drawForecastDetails(display, x + 88, y, 2);
}

void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex) {
 time_t observationTimestamp = forecasts[dayIndex].observationTime;
 struct tm* timeInfo;
 timeInfo = localtime(&observationTimestamp);
 display->setTextAlignment(TEXT_ALIGN_CENTER);
 display->setFont(ArialMT_Plain_10);
 display->drawString(x + 20, y, WDAY_NAMES[timeInfo->tm_wday]);

 display->setFont(Meteocons_Plain_21);
 display->drawString(x + 20, y + 12, forecasts[dayIndex].iconMeteoCon);
 String temp = String(forecasts[dayIndex].temp, 0) + (IS_METRIC ? "°C" : "°F");
 display->setFont(ArialMT_Plain_10);
 display->drawString(x + 20, y + 34, temp);
 display->setTextAlignment(TEXT_ALIGN_LEFT);
}

void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {
 now = time(nullptr);
 struct tm* timeInfo;
 timeInfo = localtime(&now);
 char buff[14];
 sprintf_P(buff, PSTR("%02d:%02d"), timeInfo->tm_hour, timeInfo->tm_min);

 display->setColor(WHITE);
 display->setFont(ArialMT_Plain_10);
 display->setTextAlignment(TEXT_ALIGN_LEFT);
 display->drawString(0, 54, String(buff));
 display->setTextAlignment(TEXT_ALIGN_RIGHT);
 String temp = String(currentWeather.temp, 1) + (IS_METRIC ? "°C" : "°F");
 display->drawString(128, 54, temp);
 display->drawHorizontalLine(0, 52, 128);
}

void setReadyForWeatherUpdate() {
 Serial.println("Setting readyForUpdate to true");
 readyForWeatherUpdate = true;
}


后续计划

  • 学习代码中的知识点,可以自己独立进行开发。

  • 用solidworks设计一个外壳,3D打印出来。

  • 开发个网页端,方便修改。

  • 上班摸鱼的时候搞更多的玩意。


esp8266制作简易气象站的评论 (共 条)

分享到微博请遵守国家法律