Forget the past and surpass yourself
- Blog homepage Microcontroller rookie brother, a wild non-professional hardware IOT enthusiast
- Creation record of this article 2023-10-21
- Update record of this article 2023-10-21
- Welcome to follow Like Collection Leave a message
- This blog is written by the blogger alone and is not operated by any commercial team. If you find any errors, please leave a message! Correct in time! Thanks for the support!
- The Arduino ESP8266 tutorial has helped more than 10,000 students get started learning hardware network programming. They have been selected for elective courses and have been published in radio magazines. From getting started to being familiar with the Arduino platform, developing ESP8266 will also involve network programming knowledge. There are more than 60 column articles in total, divided into basic articles, network articles, application articles, and advanced articles, covering most of the ESP8266 development techniques.
Quick Navigation
Microcontroller novice’s blog quick index (quickly find what you want)
If you find it useful, please like and save it. Your support is the motivation for the blogger’s creation.
Article directory
-
- 1 Introduction
- 2. Software code
-
- 2.1 Main project code
- 2.2 Gentle weather
- 2.3 Font pictures (too large)
1. Preface
Use esp8266 to drive oled 1306 to achieve:
- date time
- City temperature information
- Forecast information for the next three days
2. Software code
2.1 Main project code
Esp8266_Clock_Weather.ino
#include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <time.h> #include <sys/time.h> #include <coredecls.h> #include "SSD1306Wire.h" //Use this for 0.96 inches #include "OLEDDisplayUi.h" #include "HeFeng.h" #include "WeatherStationFonts.h" #include "WeatherStationImages.h" /**************************** Begin Settings ******************************/ const char* WIFI_SSID = "CMCC-pm3h"; //Fill in your WIFI name and password const char* WIFI_PWD = "hw2htwv4"; //Because too many people use my secret key, the number of times I can obtain it exceeds the limit, so I will not provide the secret key. You can go to https://dev.heweather.com/ to get a free one. const char* HEFENG_KEY = "f78a1c10fe5c490b8f3dc3946fe00975";//Fill in your Hefeng weather key const char* HEFENG_LOCATION = "101280107";//Fill in your city ID, you can check it at https://where.heweather.com/index.html #define TZ 8 // China time zone is 8 #define DST_MN 0 //Default is 0 const int UPDATE_INTERVAL_SECS = 30 * 60; // Update weather every 30 minutes const int I2C_DISPLAY_ADDRESS = 0x3c; //I2c address default const String WDAY_NAMES[] = {<!-- -->"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; //week const String MONTH_NAMES[] = {<!-- -->"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; //Month /**************************** End Settings ******************************/ SSD1306Wire display(I2C_DISPLAY_ADDRESS, SDA, SCL); // Use this for 0.96 inches OLEDDisplayUi ui( & amp;display ); HeFengCurrentData currentWeather; //instantiate object HeFengForeData foreWeather[3]; HeFeng HeFengClient; #define TZ_MN ((TZ)*60) //Time conversion #define TZ_SEC ((TZ)*3600) #define DST_SEC ((DST_MN)*60) time_t now; //instantiation time bool readyForWeatherUpdate = false; // Weather update flag bool first = true; //First update flag long timeSinceLastWUpdate = 0; //Time since last update long timeSinceLastCurrUpdate = 0; //Time since the last weather update void drawProgress(OLEDDisplay *display, int percentage, String label); //Declare the function in advance void updateData(OLEDDisplay *display); void updateDatas(OLEDDisplay *display); void drawDateTime(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(); //Add frame //This array holds function pointers to all frames //The frame is a single view that slides from right to left FrameCallback frames[] = {<!-- --> drawDateTime, drawCurrentWeather, drawForecast }; //Number of pages int numberOfFrames = 3; OverlayCallback overlays[] = {<!-- --> drawHeaderOverlay }; //Overlay callback function int numberOfOverlays = 1; //Number of overlays void setup() {<!-- --> Serial.begin(115200); Serial.println(); Serial.println(); //Screen initialization display.init(); display.clear(); display.display(); display.flipScreenVertically(); //Screen flip display.setContrast(120); //Screen brightness wifiConnect(); ui.setTargetFPS(30); //Refresh frequency ui.setActiveSymbol(activeSymbole); //Set active symbol ui.setInactiveSymbol(inactiveSymbole); //Set the inactive symbol // symbol position // You can change this to TOP, LEFT, BOTTOM, RIGHT ui.setIndicatorPosition(BOTTOM); // Define the position of the first frame in the column ui.setIndicatorDirection(LEFT_RIGHT); //Screen switching direction // You can change the screen switching direction used SLIDE_LEFT, SLIDE_RIGHT, SLIDE_TOP, SLIDE_DOWN ui.setFrameAnimation(SLIDE_LEFT); ui.setFrames(frames, numberOfFrames); // Set frames ui.setTimePerFrame(5000); //Set switching time ui.setOverlays(overlays, numberOfOverlays); //Set overlays // UI is responsible for initializing the display ui.init(); display.flipScreenVertically(); //Screen flipped configTime(TZ_SEC, DST_SEC, "ntp.ntsc.ac.cn", "ntp1.aliyun.com"); //ntp gets the time, you can also use other "pool.ntp.org",\ "0.cn.pool.ntp.org","1.cn.pool.ntp.org","ntp1.aliyun.com" delay(200); } void loop() {<!-- --> if (first) {<!-- --> //First load updateDatas( & amp;display); first = false; } if (millis() - timeSinceLastWUpdate > (1000L * UPDATE_INTERVAL_SECS)) {<!-- --> //Screen refresh setReadyForWeatherUpdate(); timeSinceLastWUpdate = millis(); } if (readyForWeatherUpdate & amp; & amp; ui.getUiState()->frameState == FIXED) {<!-- --> //Weather update updateData(); } int remainingTimeBudget = ui.update(); //Remaining time budget if (remainingTimeBudget > 0) {<!-- --> //You can work here if you are below your time budget. delay(remainingTimeBudget); } } void wifiConnect() {<!-- --> //WIFI password connection, please comment on Web configuration WiFi.begin(WIFI_SSID, WIFI_PWD); while (WiFi.status() != WL_CONNECTED) {<!-- --> Serial.print('.'); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_5); display.display(); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_6); display.display(); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_7); display.display(); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_8); display.display(); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_1); display.display(); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_2); display.display(); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_3); display.display(); delay(80); display.clear(); display.drawXbm(34, 0, bili_Logo_width, bili_Logo_height, bili_Logo_4); display.display(); } Serial.println(""); delay(500); } void drawProgress(OLEDDisplay *display, int percentage, String label) {<!-- --> //Drawing progress 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(void) {<!-- --> //Weather update HeFengClient.doUpdateCurr( & currentWeather, HEFENG_KEY, HEFENG_LOCATION); HeFengClient.doUpdateFore(foreWeather, HEFENG_KEY, HEFENG_LOCATION); readyForWeatherUpdate = false; } void updateDatas(OLEDDisplay *display) {<!-- --> //First weather update drawProgress(display, 33, "Updating weather..."); HeFengClient.doUpdateCurr( & currentWeather, HEFENG_KEY, HEFENG_LOCATION); drawProgress(display, 66, "Updating forecasts..."); HeFengClient.doUpdateFore(foreWeather, HEFENG_KEY, HEFENG_LOCATION); readyForWeatherUpdate = false; drawProgress(display, 100, "Done..."); delay(200); } void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {<!-- --> //Display time now = time(nullptr); struct tm* timeInfo; timeInfo = localtime( & amp;now); char buff[16]; display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(ArialMT_Plain_16); String date = WDAY_NAMES[timeInfo->tm_wday]; sprintf_P(buff, PSTR(" d- d- d %s"), timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, timeInfo->tm_mday, WDAY_NAMES[timeInfo->tm_wday].c_str ()); display->drawString(64 + x, 5 + y, String(buff)); display->setFont(ArialMT_Plain_24); sprintf_P(buff, PSTR(" d: d: d"), timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec); display->drawString(64 + x, 22 + y, String(buff)); display->setTextAlignment(TEXT_ALIGN_LEFT); } void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {<!-- --> //Display weather display->setFont(ArialMT_Plain_10); display->setTextAlignment(TEXT_ALIGN_CENTER); display->drawString(64 + x, 38 + y, currentWeather.cond_txt + " | Wind: " + currentWeather.wind_sc + " "); display->setFont(ArialMT_Plain_24); display->setTextAlignment(TEXT_ALIGN_LEFT); String temp = currentWeather.tmp + "°C" ; display->drawString(60 + x, 3 + y, temp); display->setFont(ArialMT_Plain_10); display->drawString(62 + x, 26 + y, currentWeather.fl + "°C | " + currentWeather.hum + "%"); display->setFont(Meteocons_Plain_36); display->setTextAlignment(TEXT_ALIGN_CENTER); display->drawString(32 + x, 0 + y, currentWeather.iconMeteCon); } void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {<!-- --> //Weather forecast 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) {<!-- --> //Weather forecast display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(ArialMT_Plain_10); display->drawString(x + 20, y, foreWeather[dayIndex].dateStr); display->setFont(Meteocons_Plain_21); display->drawString(x + 20, y + 12, foreWeather[dayIndex].iconMeteCon); String temp = foreWeather[dayIndex].tmp_min + " | " + foreWeather[dayIndex].tmp_max; display->setFont(ArialMT_Plain_10); display->drawString(x + 20, y + 34, temp); display->setTextAlignment(TEXT_ALIGN_LEFT); } void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state) {<!-- --> //Drawing header overlay now = time(nullptr); struct tm* timeInfo; timeInfo = localtime( & amp;now); char buff[14]; sprintf_P(buff, PSTR(" d: d"), timeInfo->tm_hour, timeInfo->tm_min); display->setColor(WHITE); display->setFont(ArialMT_Plain_10); display->setTextAlignment(TEXT_ALIGN_LEFT); display->drawString(6, 54, String(buff)); display->setTextAlignment(TEXT_ALIGN_RIGHT); display->drawHorizontalLine(0, 52, 128); } void setReadyForWeatherUpdate() {<!-- --> //Get ready for weather updates Serial.println("Setting readyForUpdate to true"); readyForWeatherUpdate = true; } </code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack. png" alt="" title="">
2.2 Japanese weather
- HeFeng.h
#pragma once #include <ArduinoJson.h> typedef struct HeFengCurrentData {<!-- --> String cond_txt; String fl; String tmp; String hum; String wind_sc; String iconMeteCon; } HeFengCurrentData; typedef struct HeFengForeData {<!-- --> String dateStr; String tmp_min; String tmp_max; String iconMeteCon; } HeFengForeData; class HeFeng {<!-- --> private: String getMeteConIcon(String cond_code); bool fetchBuffer(const char* url); static uint8_t _buffer[1024 * 3]; //gzip stream maximum buffer static size_t _bufferSize; public: HeFeng(); void doUpdateCurr(HeFengCurrentData *data, String key, String location); void doUpdateFore(HeFengForeData *data, String key, String location); }; </code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack. png" alt="" title="">
- HeFeng.cpp
#include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiClientSecureBearSSL.h> #include "ArduinoUZlib.h" // gzip library #include "HeFeng.h" uint8_t HeFeng::_buffer[1024 * 3]; size_t HeFeng::_bufferSize = 0; HeFeng::HeFeng() {<!-- --> } bool HeFeng::fetchBuffer(const char *url) {<!-- --> _bufferSize = 0; std::unique_ptr<WiFiClientSecure> client(new WiFiClientSecure); client->setInsecure(); HTTPClient https; Serial.print("[HTTPS] begin...now\\ "); if (https.begin(*client, url)) {<!-- --> https.addHeader("Accept-Encoding", "gzip"); https.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0"); int httpCode = https.GET(); if (httpCode > 0) {<!-- --> if (httpCode == HTTP_CODE_OK) {<!-- --> int len = https.getSize(); // get length of document (is -1 when Server sends no Content-Length header) static uint8_t buff[128 * 1] = {<!-- -->0}; // create buffer for read int offset = 0; // read all data from server while (https.connected() & amp; & amp; (len > 0 || len == -1)) {<!-- --> size_t size = client->available(); // get available data size if(size) {<!-- --> int c = client->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size)); memcpy(_buffer + offset, buff, sizeof(uint8_t) * c); offset + = c; if (len > 0) {<!-- --> len -= c; } } delay(1); } _bufferSize = offset; } } else {<!-- --> Serial.printf("[HTTPS] GET... failed, error: %s\\ ", https.errorToString(httpCode).c_str()); } https.end(); }else{<!-- --> Serial.printf("Unable to connect\\ "); } Serial.print("[HTTPS] end...now\\ "); return _bufferSize > 0; } void HeFeng::doUpdateCurr(HeFengCurrentData *data, String key, String location) {<!-- --> //Get the weather String url = "https://devapi.qweather.com/v7/weather/now?lang=en & amp;gzip=n & amp;location=" + location + " & amp;key=" + key; Serial.print("[HTTPS] begin...now\\ "); fetchBuffer(url.c_str()); // HTTPS gets the data stream if (_bufferSize){<!-- --> Serial.print("bufferSize:"); Serial.println(_bufferSize, DEC); uint8_t *outBuf=NULL; size_t outLen = 0; ArduinoUZlib::decompress(_buffer, _bufferSize, outBuf, outLen); // GZIP decompression // Output the decrypted data to the console. Serial.write(outBuf,outLen); if(outBuf & amp; & amp; outLen){<!-- --> DynamicJsonDocument jsonBuffer(2048); deserializeJson(jsonBuffer, (char*)outBuf,outLen); JsonObject root = jsonBuffer.as<JsonObject>(); String tmp = root["now"]["temp"];//Temperature data->tmp = tmp; String fl = root["now"]["feelsLike"];//Feeling temperature data->fl = fl; String hum = root["now"]["humidity"];//Humidity data->hum = hum; String wind_sc = root["now"]["windScale"];//wind power data->wind_sc = wind_sc; String cond_code = root["now"]["icon"];//Weather icon String meteConIcon = getMeteConIcon(cond_code); String cond_txt = root["now"]["text"];//Weather data->cond_txt = cond_txt; data->iconMeteCon = meteConIcon; jsonBuffer.clear(); } else {<!-- --> Serial.println("doUpdateCurr failed"); data->tmp = "-1"; data->fl = "-1"; data->hum = "-1"; data->wind_sc = "-1"; data->cond_txt = "no network"; data->iconMeteCon = ")"; } //Be sure to remember to release memory if(outBuf != NULL) {<!-- --> free(outBuf); outBuf=NULL; } _bufferSize = 0; } } void HeFeng::doUpdateFore(HeFengForeData *data, String key, String location) {<!-- --> //Get the forecast String url = "https://devapi.qweather.com/v7/weather/3d?lang=en & amp;gzip=n & amp;location=" + location + " & amp;key=" + key; Serial.print("[HTTPS] begin...forecast\\ "); fetchBuffer(url.c_str()); // HTTPS gets the data stream if (_bufferSize){<!-- --> Serial.print("bufferSize:"); Serial.println(_bufferSize, DEC); uint8_t *outBuf=NULL; size_t outLen = 0; ArduinoUZlib::decompress(_buffer, _bufferSize, outBuf, outLen); // GZIP decompression // Output the decrypted data to the console. Serial.write(outBuf,outLen); if(outBuf & amp; & amp; outLen){<!-- --> DynamicJsonDocument jsonBuffer(2048); deserializeJson(jsonBuffer, (char*)outBuf,outLen); JsonObject root = jsonBuffer.as<JsonObject>(); int i; for (i = 0; i < 3; i + + ) {<!-- --> String dateStr = root["daily"][i]["fxDate"]; data[i].dateStr = dateStr.substring(5, dateStr.length()); String tmp_min = root["daily"][i]["tempMin"]; data[i].tmp_min = tmp_min; String tmp_max = root["daily"][i]["tempMax"]; data[i].tmp_max = tmp_max; String cond_code = root["daily"][i]["iconDay"]; String meteConIcon = getMeteConIcon(cond_code); data[i].iconMeteCon = meteConIcon; } jsonBuffer.clear(); } else {<!-- --> int i; for (i = 0; i < 3; i + + ) {<!-- --> data[i].tmp_min = "-1"; data[i].tmp_max = "-1"; data[i].dateStr = "N/A"; data[i].iconMeteCon = ")"; } } //Be sure to remember to release memory if(outBuf != NULL) {<!-- --> free(outBuf); outBuf=NULL; } _bufferSize = 0; } } String HeFeng::getMeteConIcon(String cond_code) {<!-- --> //Get the weather icon. See https://dev.qweather.com/docs/start/icons/ if (cond_code == "100" || cond_code == "150" || cond_code == "9006") {<!-- -->//clear Sunny/Clear return "B"; } if (cond_code == "101") {<!-- -->//Cloudy Cloudy return "Y"; } if (cond_code == "102") {<!-- -->//Shaoyun Few Clouds return "N"; } if (cond_code == "103" || cond_code == "153") {<!-- -->//Partly Cloudy/ return "H"; } if (cond_code == "104" || cond_code == "154") {<!-- -->//Yin Overcast return "D"; } if (cond_code == "300" || cond_code == "301") {<!-- -->//Shower Rain 301-Heavy Shower Rain return "T"; } if (cond_code == "302" || cond_code == "303") {<!-- -->//302-Thundershower Thundershower / 303-Strong Thundershower return "P"; } if (cond_code == "304" || cond_code == "313" || cond_code == "404" || cond_code == "405" || cond_code == "406" ) {<!-- --> //304-Thundershowers with hail Freezing Rain //313-Freezing Rain Freezing Rain //404-Sleet Sleet //405-Rain And Snow Rain And Snow //406- Shower Snow return "X"; } if (cond_code == "305" || cond_code == "308" || cond_code == "309" || cond_code == "314" || cond_code == "399" ) {<!-- --> //305-小雨Light Rain //308-Extreme Rain Extreme Rain //309-Drizzle/Drizzle Drizzle Rain //314-Light to moderate rain Light to moderate rain //399-Rain Light to moderate rain return "Q"; } if (cond_code == "306" || cond_code == "307" || cond_code == "310" || cond_code == "311" || cond_code == "312" || cond_code == "315" || cond_code == "316" || cond_code == "317" || cond_code == "318") {<!-- --> //306-Moderate Rain Moderate Rain //307-Heavy Rain Heavy Rain //310-Heavy rainstorm //311-Heavy Storm Heavy Storm //312-Severe Storm //315-Moderate to heavy rain Moderate to heavy rain //316-Heavy rain to storm //317-Storm to heavy storm Storm to heavy storm //318-Heavy to severe storm Heavy to severe storm return "R"; } if (cond_code == "400" || cond_code == "408") {<!-- --> //400-Light Snow //408-Light to moderate snow Light to moderate snow return "U"; } if (cond_code == "401" || cond_code == "402" || cond_code == "403" || cond_code == "409" || cond_code == "410" ) {<!-- --> //401-Moderate Snow //402-Heavy Snow Heavy Snow //403-Blizzard Snowstorm //409-Moderate to heavy snow Moderate to heavy snow //410-Heavy snow to snowstorm return "W"; } if (cond_code == "407") {<!-- --> //407-Snow Flurry return "V"; } if (cond_code == "499" || cond_code == "901") {<!-- --> //499-Snow Snow //901-Cold Cold return "G"; } if (cond_code == "500") {<!-- --> //500-Mist Mist return "E"; } if (cond_code == "501" || cond_code == "509" || cond_code == "510" || cond_code == "514" || cond_code == "515" ) {<!-- --> //501-Foggy return "M"; } if (cond_code == "502" || cond_code == "511" || cond_code == "512" || cond_code == "513") {<!-- --> //502-Haze Haze return "L"; } if (cond_code == "503" || cond_code == "504" || cond_code == "507" || cond_code == "508") {<!-- --> //503-Sand return "F"; } if (cond_code == "999") {<!-- -->//Unknown return ")"; } if (cond_code == "213") {<!-- --> return "O"; } if (cond_code == "200" || cond_code == "201" || cond_code == "202" || cond_code == "203" || cond_code == "204" || cond_code == "205" || cond_code == "206" || cond_code == "207" || cond_code == "208" || cond_code == "209" || cond_code == "210" || cond_code == "211" || cond_code == "212") {<!-- --> return "S"; } return ")"; } </code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack. png" alt="" title="">
2.3 Font image (too large)
- WeatherStationFonts.h
- WeatherStationImages.h