数码之家

 找回密码
 立即注册
搜索
查看: 2514|回复: 1

【零知ESP8266】OLED天气时钟

[复制链接]
发表于 2019-6-19 11:41:24 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本文演示通过OLED显示时钟和天气情况,主要利用的是openweathermap的免费天气API。
1、硬件准备
(1)零知ESP8266开发板

(2)OLED SSD1306模块(3)若干杜邦线
2、电路连接
接线很简单,I2C接口对应连接即可:
接线图.jpg
接好后实物图如下:
实物图.jpg
2、软件代码
使用零知开发工具,使用了OLED和WeatherStation相关的软件库,因此需要安装对应的库:
esp8266-weather-station-1.6.6.rar (885.92 KB, 下载次数: 11)
安装完成后,我们新建工程:
  1. /*
  2. 2019年6月13日13:47:26
  3. by 零知实验室
  4. */

  5. #include <ESPWiFi.h>
  6. #include <ESPHTTPClient.h>
  7. #include <JsonListener.h>

  8. // time
  9. #include <time.h>                       // time() ctime()
  10. #include <sys/time.h>                   // struct timeval
  11. #include <coredecls.h>                  // settimeofday_cb()

  12. #include "SSD1306Wire.h"
  13. #include "OLEDDisplayUi.h"
  14. #include "Wire.h"
  15. #include "OpenWeatherMapCurrent.h"
  16. #include "OpenWeatherMapForecast.h"
  17. #include "WeatherStationFonts.h"
  18. #include "WeatherStationImages.h"


  19. /***************************
  20. * Begin Settings
  21. **************************/

  22. // WIFI
  23. const char* WIFI_SSID = "xx";
  24. const char* WIFI_PWD = "xx";

  25. #define TZ              8       // (utc+) TZ in hours
  26. #define DST_MN          60      // use 60mn for summer time in some countries

  27. // Setup
  28. const int UPDATE_INTERVAL_SECS = 20 * 60; // Update every 20 minutes

  29. // Display Settings
  30. const int I2C_DISPLAY_ADDRESS = 0x3c;

  31. const int SDA_PIN = D3;
  32. const int SDC_PIN = D4;

  33. // OpenWeatherMap Settings
  34. // Sign up here to get an API key:
  35. // [url=https://docs.thingpulse.com/how-tos/openweathermap-key/]https://docs.thingpulse.com/how-tos/openweathermap-key/[/url]
  36. String OPEN_WEATHER_MAP_APP_ID = "xxx"; //你的API KEY
  37. /*
  38. Go to [url=https://openweathermap.org/find?q=]https://openweathermap.org/find?q=[/url] and search for a location. Go through the
  39. result set and select the entry closest to the actual location you want to display
  40. data for. It'll be a URL like [url=https://openweathermap.org/city/2657896.]https://openweathermap.org/city/2657896.[/url] The number
  41. at the end is what you assign to the constant below.
  42. */
  43. String OPEN_WEATHER_MAP_LOCATION_ID = "1795565"; //city:深圳

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

  54. const boolean IS_METRIC = true;

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

  58. /***************************
  59. * End Settings
  60. **************************/
  61. // Initialize the oled display for address 0x3c
  62. // sda-pin=14 and sdc-pin=12
  63. SSD1306Wire     display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);
  64. OLEDDisplayUi   ui( &display );

  65. OpenWeatherMapCurrentData currentWeather;
  66. OpenWeatherMapCurrent currentWeatherClient;

  67. OpenWeatherMapForecastData forecasts[MAX_FORECASTS];
  68. OpenWeatherMapForecast forecastClient;

  69. #define TZ_MN           ((TZ)*60)
  70. #define TZ_SEC          ((TZ)*3600)
  71. #define DST_SEC         ((DST_MN)*60)
  72. time_t now;

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

  75. String lastUpdate = "--";

  76. long timeSinceLastWUpdate = 0;

  77. //declaring prototypes
  78. void drawProgress(OLEDDisplay *display, int percentage, String label);
  79. void updateData(OLEDDisplay *display);
  80. void drawDateTime(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
  81. void drawCurrentWeather(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
  82. void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y);
  83. void drawForecastDetails(OLEDDisplay *display, int x, int y, int dayIndex);
  84. void drawHeaderOverlay(OLEDDisplay *display, OLEDDisplayUiState* state);
  85. void setReadyForWeatherUpdate();


  86. // Add frames
  87. // this array keeps function pointers to all frames
  88. // frames are the single views that slide from right to left
  89. FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecast };
  90. int numberOfFrames = 3;

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

  93. void setup() {
  94.   Serial.begin(115200);
  95.   Serial.println();
  96.   Serial.println();

  97.   // initialize dispaly
  98.   display.init();
  99.   display.clear();
  100.   display.display();

  101.   //display.flipScreenVertically();
  102.   display.setFont(ArialMT_Plain_10);
  103.   display.setTextAlignment(TEXT_ALIGN_CENTER);
  104.   display.setContrast(255);

  105.   WiFi.begin(WIFI_SSID, WIFI_PWD);

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

  116.     counter++;
  117.   }
  118.   // Get time from network time service
  119.   configTime(TZ_SEC, DST_SEC, "pool.ntp.org");

  120.   ui.setTargetFPS(30);

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

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

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

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

  131.   ui.setFrames(frames, numberOfFrames);

  132.   ui.setOverlays(overlays, numberOfOverlays);

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

  135.   Serial.println("");

  136.   updateData(&display);

  137. }

  138. void loop() {

  139.   if (millis() - timeSinceLastWUpdate > (1000L*UPDATE_INTERVAL_SECS)) {
  140.     setReadyForWeatherUpdate();
  141.     timeSinceLastWUpdate = millis();
  142.   }

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

  146.   int remainingTimeBudget = ui.update();

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


  153. }

  154. void drawProgress(OLEDDisplay *display, int percentage, String label) {
  155.   display->clear();
  156.   display->setTextAlignment(TEXT_ALIGN_CENTER);
  157.   display->setFont(ArialMT_Plain_10);
  158.   display->drawString(64, 10, label);
  159.   display->drawProgressBar(2, 28, 124, 10, percentage);
  160.   display->display();
  161. }

  162. void updateData(OLEDDisplay *display) {
  163.   drawProgress(display, 10, "Updating time...");
  164.   drawProgress(display, 30, "Updating weather...");
  165.   currentWeatherClient.setMetric(IS_METRIC);
  166.   currentWeatherClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
  167.   currentWeatherClient.updateCurrentById(¤tWeather, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID);
  168.   drawProgress(display, 50, "Updating forecasts...");
  169.   forecastClient.setMetric(IS_METRIC);
  170.   forecastClient.setLanguage(OPEN_WEATHER_MAP_LANGUAGE);
  171.   uint8_t allowedHours[] = {12};
  172.   forecastClient.setAllowedHours(allowedHours, sizeof(allowedHours));
  173.   forecastClient.updateForecastsById(forecasts, OPEN_WEATHER_MAP_APP_ID, OPEN_WEATHER_MAP_LOCATION_ID, MAX_FORECASTS);

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



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


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

  186.   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);
  187.   display->drawString(64 + x, 5 + y, String(buff));
  188.   display->setFont(ArialMT_Plain_24);

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

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

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

  201.   display->setFont(Meteocons_Plain_36);
  202.   display->setTextAlignment(TEXT_ALIGN_CENTER);
  203.   display->drawString(32 + x, 0 + y, currentWeather.iconMeteoCon);
  204. }


  205. void drawForecast(OLEDDisplay *display, OLEDDisplayUiState* state, int16_t x, int16_t y) {
  206.   drawForecastDetails(display, x, y, 0);
  207.   drawForecastDetails(display, x + 44, y, 1);
  208.   drawForecastDetails(display, x + 88, y, 2);
  209. }

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

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

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

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

  239. void setReadyForWeatherUpdate() {
  240.   Serial.println("Setting readyForUpdate to true");
  241.   readyForWeatherUpdate = true;
  242. }
复制代码
注意代码里面填写自己的APIkey和要查询的城市名称,这里填写的是深圳-shenzhen。
3、验证测试
将代码验证并上传到零知-ESP8266上面,打开串口调试工具,可以看到如下结果:
调试窗口.jpg
获取返回结果代码为:200,即表示成功了;如果是错误码,可以把地址粘贴到浏览器里看看是什么原因。
成功后OLED就会显示时钟和天气情况:
结果.jpg
更多详细资料可到零知实验室官网免费获取。



发表于 2019-6-19 14:08:35 | 显示全部楼层
不错,都是面向对象的编程。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-3-29 21:45 , Processed in 0.296400 second(s), 20 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

快速回复 返回顶部 返回列表