2778 views|0 replies

85

Posts

0

Resources
The OP
 

【Zero Knowledge ESP8266 Project】1 OLED Weather Clock [Copy link]

Quote:
We have been learning the ESP8266 tutorial for so long, isn't it time to test ourselves? In the previous sharing, a friend left a message: It's too simple! Then I will take advantage of it and make a small project - a weather clock.

So far, as a basic developer, we have already had the most basic understanding of ESP8266. Maybe you can't wait to do a project! Let's do a small project today. Continue to add a dot to the outline of our electronic world.

1. Hardware preparation
Computer, Windows system
Zero-knowledge ESP8266 development board
OLED SSD1306 module
micro-usb cable

2. Connection

3. Software Library①Open
the latest version of Zero Knowledge Development Tool and select the development board, as shown in the figure:

②Click Library, and then install the following two libraries, as shown in the figure:

After the installation is complete, you can.

4. Open Zero-knowledge Development Software, create a new project, name it weather-station. Then burn the following code (Chinese comments have been made, just copy and paste):

/*
2019年6月13日13:47:26
by 零知实验室
*/

#include <ESPWiFi.h>
#include <ESPHTTPClient.h>
#include <JsonListener.h>

// time
#include <time.h>                       
#include <sys/time.h>                   
#include <coredecls.h>                 

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


/***************************
 * 开始设置
 **************************/

// 这里填写WiFi凭证信息
const char* WIFI_SSID = "WiFi名";
const char* WIFI_PWD = "WiFi密码";

#define TZ              8       // 通用协调时  东八区  北京时间为准
#define DST_MN          60      // 在一些国家依然用夏令时

// Setup
const int UPDATE_INTERVAL_SECS = 20 * 60; // 更新20分钟

// 展示设置
const int I2C_DISPLAY_ADDRESS = 0x3c;

const int SDA_PIN = D3;
const int SDC_PIN = D4;

// OpenWeatherMap设置
// 在此处注册以获取API密钥
// https://docs.thingpulse.com/how-tos/openweathermap-key/
//也可以在零知实验室查看原帖获取,或者留言给我呦,免费分享给你
String OPEN_WEATHER_MAP_APP_ID = "3213ac05f30cc2f7d8d8da6d2b03f2e8";  //得到密匙  下面会有教程
/*
转到https://openweathermap.org/find?q=并搜索位置。 
通过结果设置并选择最接近要显示的实际位置的条目数据 
它将是一个类似于https://openweathermap.org/city/2657896.的链接最后的数字是你分配给下面常量的数字。
 */
String OPEN_WEATHER_MAP_LOCATION_ID = "1795565"; //city:深圳   数字指的是openweathermap的分配的ID   同样也有教程

//从此列表中选择语言代码:
//阿拉伯文-ar,保加利亚语-bg,加泰罗尼亚语-ca,捷克语-cz,德语-de,希腊语-el,
//英语-en,波斯语(波斯语)-fa,芬兰语-fi,法语-fr,加利西亚语-gl,
//克罗地亚语-hr,匈牙利语-hu,意大利语-it,日语-ja,韩语-kr,
//拉脱维亚-la,立陶宛语-lt,马其顿语-mk,荷兰语-nl,波兰语-pl,
//葡萄牙语-pt,罗马尼亚语-ro,俄语-ru,瑞典语-se,斯洛伐克语-sk,
//斯洛文尼亚文-sl,西班牙文-es,土耳其文-tr,乌克兰文-ua,越南文-vi,
//简体中文-zh_cn,繁体中文-zh_tw。
String OPEN_WEATHER_MAP_LANGUAGE = "zh_cn";    //这里选择中文简体。
const uint8_t MAX_FORECASTS = 4;

const boolean IS_METRIC = true;

// 根据你的需要调整语言
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"}; //12个月

/***************************
 * 结束设置
 **************************/
 // 初始化OLED地址
 //  I2C接口:SDA引脚14 SCL引脚12
 SSD1306Wire     display(I2C_DISPLAY_ADDRESS, SDA_PIN, SDC_PIN);  //为OLED创建一个实例display
 OLEDDisplayUi   ui( &display );   //创建一个ui实例 

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;

// 标记每10分钟更改一次。
bool readyForWeatherUpdate = false;

String lastUpdate = "--";

long timeSinceLastWUpdate = 0;

//申明原型
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();

//添加框架
//此数组保留指向所有帧的函数指针
//框架是从右向左滑动的单个视图
FrameCallback frames[] = { drawDateTime, drawCurrentWeather, drawForecast };
int numberOfFrames = 3;

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

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

  // 初始化显示
  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++;
  }
  // 从网络时间服务得到时间
  configTime(TZ_SEC, DST_SEC, "pool.ntp.org");

  ui.setTargetFPS(30);

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

  // 你可以改变它,
  // 向上(TOP), 向左(LEFT), 向下(BOTTOM), 向右(RIGHT)
  ui.setIndicatorPosition(BOTTOM);

  // 定义第一个帧位于中间的位置
  ui.setIndicatorDirection(LEFT_RIGHT);

  // 你可以更改幻灯片通过
  // 向左滑动(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) {
    //你可以在这里添加一些代码,当然要在下面的remainingTimeBudget(停留时间预算内)
	//否则会出现闪频状态
    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;
}

After verification, click "Upload".

How to get data in the code: click here

Complete project: weather_station1.7z (If you have any questions, please leave a comment)

5. Results

Get the return result code: 200 means success

If there is an error code, you can paste the address into the browser to see what the reason is.

Effect video: Click my whisk

This post is from stm32/stm8
 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list