esp8266oled做时钟python_【零知ESP8266】教程:OLED天气时钟

本帖最后由 lz-esp-link 于 2019-6-19 11:00 编辑

本文演示通过OLED显示一个时钟和天气情况的例子,主要利用的是openweathermap的免费天气API。

1、硬件准备

(1)零知ESP8266开发板

(2)OLED SSD1306模块

2、电路连接

接线很简单,I2C接口对应连接即可:

接线图.jpg (140.48 KB, 下载次数: 13)

2019-6-18 09:43 上传

接好后实物图如下:

实物图.jpg (49.76 KB, 下载次数: 12)

2019-6-18 09:44 上传

2、软件

本次使用了OLED和WeatherStation相关的软件库,因此需要安装对应的库:

2019-6-18 10:29 上传

点击文件名下载附件

安装完成后,我们新建工程或打开附件的工程代码:

[mw_shl_code=arduino,true]/*

2019年6月13日13:47:26

by 零知实验室

*/

#include

#include

#include

// time

#include                        // time() ctime()

#include                    // struct timeval

#include                   // 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;

}[/mw_shl_code]

注意代码里面填写自己的APIkey和要查询的城市名称,这里填写的是深圳-shenzhen。

3、验证测试

将代码验证并上传到零知-ESP8266上面,打开串口调试工具,可以看到如下结果:

调试窗口.jpg (107.42 KB, 下载次数: 14)

2019-6-18 10:33 上传

获取返回结果代码为200即表示成功了;如果是错误码,可以把地址粘贴到浏览器里看看是什么原因。

成功后OLED就会显示天气情况:

结果.jpg (58.67 KB, 下载次数: 6)

2019-6-18 10:34 上传

更多详细资料可到零知实验室官网免费获取。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值