- /*
 
- 2019年6月13日13:47:26
 
- by 零知实验室
 
- */
 
 
- #include <ESPWiFi.h>
 
- #include <ESPHTTPClient.h>
 
- #include <JsonListener.h>
 
 
- // time
 
- #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"
 
 
 
- /***************************
 
- * Begin Settings
 
- **************************/
 
 
- // WIFI
 
- const char* WIFI_SSID = "xx";
 
- const char* WIFI_PWD = "xx";
 
 
- #define TZ              8       // (utc+) TZ in hours
 
- #define DST_MN          60      // use 60mn for summer time in some countries
 
 
- // Setup
 
- const int UPDATE_INTERVAL_SECS = 20 * 60; // Update every 20 minutes
 
 
- // Display Settings
 
- const int I2C_DISPLAY_ADDRESS = 0x3c;
 
 
- const int SDA_PIN = D3;
 
- const int SDC_PIN = D4;
 
 
- // OpenWeatherMap Settings
 
- // Sign up here to get an API key:
 
- // https://docs.thingpulse.com/how-tos/openweathermap-key/
 
- String OPEN_WEATHER_MAP_APP_ID = "xxx"; //你的API KEY
 
- /*
 
- Go to https://openweathermap.org/find?q= and search for a location. Go through the
 
- result set and select the entry closest to the actual location you want to display 
 
- data for. It'll be a URL like https://openweathermap.org/city/2657896. The number
 
- at the end is what you assign to the constant below.
 
- */
 
- String OPEN_WEATHER_MAP_LOCATION_ID = "1795565"; //city:深圳
 
 
- // 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
 
- **************************/
 
- // Initialize the oled display for address 0x3c
 
- // sda-pin=14 and sdc-pin=12
 
- 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 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 frames
 
- // this array keeps function pointers to all frames
 
- // frames are the single views that slide from right to left
 
- FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecast };
 
- int numberOfFrames = 3;
 
 
- OverlayCallback overlays[] = { drawHeaderOverlay };
 
- int numberOfOverlays = 1;
 
 
- void setup() {
 
-   Serial.begin(115200);
 
-   Serial.println();
 
-   Serial.println();
 
 
-   // initialize dispaly
 
-   display.init();
 
-   display.clear();
 
-   display.display();
 
 
-   //display.flipScreenVertically();
 
-   display.setFont(ArialMT_Plain_10);
 
-   display.setTextAlignment(TEXT_ALIGN_CENTER);
 
-   display.setContrast(255);
 
 
-   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);
 
 
- }
 
 
- 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(¤tWeather, 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 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(60 + x, 5 + y, temp);
 
 
-   display->setFont(Meteocons_Plain_36);
 
-   display->setTextAlignment(TEXT_ALIGN_CENTER);
 
-   display->drawString(32 + 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;
 
- }
注意代码里面填写自己的APIkey和要查询的城市名称,这里填写的是深圳-shenzhen。
3、验证测试
将代码验证并上传到零知-ESP8266上面,打开串口调试工具,可以看到如下结果:
获取返回结果代码为:200,即表示成功了;如果是错误码,可以把地址粘贴到浏览器里看看是什么原因。
成功后OLED就会显示时钟和天气情况:
更多详细资料可到零知实验室免费获取。