0.96“OLED+ESP8266天气时钟+古诗农历显示

Posted perseverance52

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了0.96“OLED+ESP8266天气时钟+古诗农历显示相关的知识,希望对你有一定的参考价值。

0.96"OLED+ESP8266天气时钟+古诗农历显示


谢鸣:感谢原创作者:小夸克


开源!ESP8266天气时钟,古诗农历显示!


  • 原创资源链接:百度云盘
链接:https://pan.baidu.com/s/10Fw_ArzupIAGaTFss-N2Dw 
提取码:1ooc

本文在第一作者的代码上进行了优化,(源码我是没有获取到农历和古诗词句子到,)

修改处
  • 古诗词和农历类的共有成员String parseInfo(String& line);去除掉了
  • 对接收JSON数据代码进行了修改。
  • 心知天气数据获取库:github
  • 主程序代码
/**********获取B站粉丝数库*************/
#include <ESP8266_BiliBili.h>
#include <FansInfo.h>
#include <UpInfo.h>
#include <VideoInfo.h>

/**********获取心知天气(当天以及未来三天)库*************/
#include <ESP8266_Seniverse.h>
#include <Forecast.h>
#include <LifeInfo.h>
#include <WeatherNow.h>
/**********访问网络数据库*************/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

#include <ArduinoJson.h>
#include <String>

/**********图像显示库*************/
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
/**********配网库*************/
#include <DNSServer.h>//密码直连将其三个库注释
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
/**********获取NTP时间库*************/
#include <time.h>
#include <sys/time.h>
#include <coredecls.h>
/**********获取网络数据库*************/
#include "WeatherIcon.h"
#include "nongli.h"//农历获取相关给库
#include "gushi.h"//获取古诗相关的库



//时间显示相关定义
#define TZ              8      // 中国时区为8
#define DST_MN          0      // 默认为0
#define TZ_MN           ((TZ)*60)   //时间换算
#define TZ_SEC          ((TZ)*3600)
#define DST_SEC         ((DST_MN)*60)
#define SDA   (4)   //nodemcu引脚连接,使用的是硬件IIC
#define SCL   (5)   //

time_t now; //实例化时间


//刷新更新,使用mills函数实现,如果用delay会造成显示秒的时候卡住不动
const int UPDATE_INTERVAL_SECS = 6 * 60; // 5分钟更新一次天气
const int UPDATE_NONGLI_SECS = 60 * 60 * 2; //农历一天更新一次
const int UPDATE_GUSHI_SECS = 20 * 60; //古诗20分钟更新一次
const int UPDATE_UI_SECS = 5; //UI5秒钟更新一次
const int UPDATE_Fans_SECS = 2 * 60; //粉丝两分钟更新一次


int count = 0; //计数变量
bool first = true;  //首次更新标志
long timeSinceLastWeatherUpdate = 0;    //上次更新后的时间
long timeSinceLastNongliUpdate = 0;   //上次天气更新后的时间
long timeSinceLastGushiUpdate = 0;   //上次天气更新后的时间
long timeSinceLastUiUpdate = 0;   //上次UI更新后的时间
long timeSinceLastFansUpdate = 0; //上次粉丝更新后的时间

const String WDAY_NAMES[] = {"星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};  //星期
const String MONTH_NAMES[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};  //月份

uint8_t* my_oled_buf1;
uint8_t* my_oled_buf2;
uint8_t* my_oled_buf3;
uint8_t* my_oled_buf4;//定义4个显示缓存空间

uint8_t my_oled_buf1_arry[1024];
uint8_t my_oled_buf2_arry[1024];
uint8_t my_oled_buf3_arry[1024];
uint8_t my_oled_buf4_arry[1024];//定义4个数组用来存放过度动画的画面


U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ SCL, /* data=*/ SDA);  //配置构造函数,使用硬件IIC

const char* ssid     = "MERCURY_D268G";       // 连接WiFi名
// 请将您需要连接的WiFi名填入引号中
const char* password = "pba5ayzk";          // 连接WiFi密码
// 请将您需要连接的WiFi密码填入引号中

//心知3天天气
//http://api.seniverse.com/v3/weather/daily.json?key=S4hKw5y47tk2ExyTZ&location=zhuzhou&language=en&unit=c&start=0&days=3
//http://api.seniverse.com/v3/weather/now.json?key=S4hKw5y47tk2ExyTZ&location=zhuzhou&language=en&unit=c
               
String reqUserKey = "S4hKw5y47tk2ExyTZ";   // 私钥
String reqLocation = "zhuzhou";            // 城市
String reqUnit = "c";                      // 摄氏/华氏
//天行数据密匙,我找了半天发现这个网站的API接口比较全,但是返回的json数据有点奇怪,需要处理一下,不过我已经处理好了,网址https://www.tianapi.com/
String tianxingkey = "9432083d616f22e2255a81dbbdd3f63c";
//B站账号
FansInfo fansInfo("201277333");

//对象的建立
WeatherNow weatherNow;  // 建立WeatherNow对象用于获取心知当前天气信息
Forecast forecast; // 建立Forecast对象用于获取心知天气预报信息
Nongli nongli;//建立一个nongli对象
Gushi gushi;//建立一个gushi对象


//函数的声明
void webconnect();//web配网
void connectWiFi();//直连wifi
void runProgress();//几个界面的运行切换
void updateForTime();//从网络获取各种信息的更新
void drawPogress(int16_t degree, int16_t x, int16_t y, const char* lable);//绘制进度条
void drawDateTime(); //显示时间
void drawGushi();//显示古诗
void drawForcastWeather();//显示未来三天的天气预报
void drawCurrentWeather(); //显示当前天气
void StartClock();//开机更新
void littleWeatherIconShow( int16_t day, int16_t x, int16_t y); //显示小的天气图标
void littleWeatherTempShow(int16_t day, int16_t x, int16_t y); //显示天气预报温度
void drawPagePoint(int16_t x, int16_t y, const char* icon); //绘制底栏的小圆点
void drawEyebow(int16_t x, int16_t y, int page, const char*someData); //绘制底栏
void Move_aPage(uint8_t  page_1[1024], uint8_t page_2[1024]);//动画过渡效果
void my_oled_clear(uint8_t* oled_gram);//清空缓存区(清空数组)



void setup(void)
{
  Serial.begin(115200);
  Serial.println("");
  u8g2.begin();
  u8g2.enableUTF8Print();//开启UTF-8字符显示,即开启中文的显示

  //WiFiManager wifiManager; //第一次web配网的时候如果ESP8266还保存着上次的wifi信息可能需要先格式化,如果直接编译下载后不能发现你的热点就需要把你原来的信息清楚一下
  //wifiManager.resetSettings();//格式化wifi信息

 // webconnect();//配网

  connectWiFi();//密码手动联网
  
  // 配置心知天气请求信息
  weatherNow.config(reqUserKey, reqLocation, reqUnit);//初始化天气
  forecast.config(reqUserKey, reqLocation, reqUnit);//初始化天气
  //天行数据的请求
  nongli.config(tianxingkey);//初始化农历
  gushi.config(tianxingkey);//初始化古诗
  //时间服务器的请求
  configTime(TZ_SEC, DST_SEC, "ntp.ntsc.ac.cn", "ntp1.aliyun.com");//获取当前时间
  delay(200);
}

void loop(void)
{
  updateForTime();//开机初始化和更新时间
  runProgress();//运行代码
  delay(200);
}



//Web配网,如果采用wifi写入,直接注释掉
void webconnect() {
  u8g2.clearBuffer();//清空缓存
  u8g2.drawXBMP(32, 0, 64, 64, tiaopi);//绘制连接网络的动画
  u8g2.sendBuffer();//显示
  //delay(1000);
  WiFiManager wifiManager;  //实例化WiFiManager
  if (!wifiManager.autoConnect("========")) {  //AP模式,用手机或者电脑web配网时你的esp8266的热点
    u8g2.setCursor(34, 60);
    u8g2.println("连接失败");
    //重新设置并再试一次,或者让它进入深度睡眠状态,这样断网之后它也会再有网的时候再次连接
    ESP.restart();
    delay(1000);
  }

  yield();
}

// 密码连接WiFi,由于我使用的是web配网,所以这部分的UI没设计
void connectWiFi() {
  WiFi.begin(ssid, password);                  // 启动网络连接
  Serial.print("Connecting to ");              // 串口监视器输出网络连接信息
  Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接

  int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功
  while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。
    delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED
    Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
  }                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。
  // 这个读秒是通过变量i每隔一秒自加1来实现的。
  Serial.println("");                          // WiFi连接成功后
  Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。
  Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
  Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。
}



void runProgress()//让几个界面运行起来
{

  bool changeflag = false; //页面切换标志
  if (millis() - timeSinceLastUiUpdate > (1000L * UPDATE_UI_SECS)) //如果到了计时的时间
  {
    changeflag = true; //切换界面标志位取反
    count++;//以此作为计数值
    if (count == 4)
      count = 0;
    timeSinceLastUiUpdate = millis();

  }
  if (count == 1)
  {
    if (changeflag == true)//不要更改这两个语句的位置,不然要出bug
    {
      Move_aPage(my_oled_buf4_arry, my_oled_buf1_arry);
      changeflag = false; //只让其执行一次
    }
    drawDateTime();
  }
  if (count == 2)
  {
    if (changeflag == true)
    {

      Move_aPage(my_oled_buf1_arry, my_oled_buf2_arry);
      changeflag = false; //只让其执行一次
    }
    drawCurrentWeather();

  }
  if (count == 3)
  {
    if (changeflag == true)
    {

      Move_aPage(my_oled_buf2_arry, my_oled_buf3_arry);
      changeflag = false; //只让其执行一次
    }
    drawForcastWeather();

  }
  if (count == 0)
  {
    if (changeflag == true)
    {

      Move_aPage(my_oled_buf3_arry, my_oled_buf4_arry);
      changeflag = false; //只让其执行一次
    }
    drawGushi();

  }
}


void updateForTime()//根据设定的时间更新
{
  if (first) {  //首次加载
    StartClock();//开机动画
    first = false;
  }//mills返回开始运行当前程序的毫秒数,1000L * UPDATE_INTERVAL_SECS被视为long,它可以容纳更大的值
  if (millis() - timeSinceLastWeatherUpdate > (1000L * UPDATE_INTERVAL_SECS))//不要将判断时间设置为==,不然根本不能判断出,因为不会这么巧合刚刚等于
  { //如果现在运行的时间大于设定的时间,说明该更新了
    weatherNow.update();
    forecast.update();
    timeSinceLastWeatherUpdate = millis();//重置更新时间计时
  }
  if (millis() - timeSinceLastNongliUpdate > (1000L * UPDATE_NONGLI_SECS))
  { //农历更新
    nongli.upDate();
    timeSinceLastNongliUpdate = millis();
  }
  if (millis() - timeSinceLastGushiUpdate > (1000L * UPDATE_GUSHI_SECS))
  { //古诗更新
    gushi.upDate();
    timeSinceLastGushiUpdate = millis();
  }
  if (millis() - timeSinceLastFansUpdate > (1000L * UPDATE_Fans_SECS))
  { //粉丝更新
    fansInfo.update();
    timeSinceLastFansUpdate = millis();
  }

}

void drawPogress(int16_t degree, int16_t x, int16_t y, const char* lable) //绘制进度条
{
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_6x12_tf);//设置字体
  //u8g2.setCursor(35, 45 ); //年份居中显示
  switch (degree)
  {
    case 1: u8g2.drawBox(16, 24, 20, 5); u8g2.drawStr(35 + x, 54 + y, lable); break;
    case 2: u8g2.drawBox(16, 24, 20, 5); u8g2.drawBox(42, 24, 20, 5); u8g2.drawStr(35 + x, 54 + y, lable); break;
    case 3: u8g2.drawBox(16, 24, 20, 5); u8g2.drawBox(42, 24, 20, 5); u8g2.drawBox(68, 24, 20, 5); u8g2.drawStr(35 + x, 54 + y, lable); break;
    case 4: u8g2.drawBox(16, 24, 20, 5); u8g2.drawBox(42, 24, 20, 5); u8g2.drawBox(68, 24, 20, 5); u8g2.drawBox(94, 24, 20, 5); u8g2.drawStr(35 + x, 54 + y, lable); break;
  }
  //u8g2.drawFrame(18, 22, 92, 24);
  u8g2.sendBuffer();
}
void drawDateTime() //显示时间
{
  now = time(nullptr);//time库
  struct tm* timeInfo;//声明一个结构体
  timeInfo = localtime(&now);
  char buff[16];
  char tem[以上是关于0.96“OLED+ESP8266天气时钟+古诗农历显示的主要内容,如果未能解决你的问题,请参考以下文章

0.96 和 1.0 的 Django 模板继承的区别?

ESP8266/ESP32 +1.3“ or 0.96“ IIC OLED指针式时钟

MicroPython esp32读取DHT11温湿度传感器数据+ 0.96“I2C oled显示

GAE/Django 模板 (0.96) 过滤器以获取 GqlQuery 的长度并对其进行过滤

MicroPython ESP32ssd1306 0.96“OLED+网络时钟

0.96“OLED+ESP8266天气时钟+古诗农历显示