本文最后更新于337 天前,其中的信息可能已经过时,如有错误请发送邮件到273925452@qq.com

这个项目是入门Arduino后做的项目,Arduino是跟着太极创客学的,强烈推荐😀
功能介绍
简易WiFi连接
用户可使用手机对本时钟设备设置WiFi连接。简单易用。
实时信息显示
– 可实时显示天气信息(当前天气情况和当前气温)
– 可实时显示天气预报(天气情况、最高气温、最低气温)
– 用户可根据自行需要显示五天天气预报(需要修改代码)
时钟背景可调
– 背景图片定时变化
– 可自行定制背景图片
配合然也物联应用
– 可通过然也物联手机应用对系统进行设置,如设置背景更换时间间隔,LED灯亮灭
– 可使用然也物联手机应用将聊天信息显示在屏幕上(目前只支持英文或拼音,尚无法显示中文)
硬件材料说明
电路模块
– ESP8266物联网开发板 – 1块
– ILI9341 TFT彩屏 – 1块
演示视频
Arduino程序
#include <TimeLib.h>
#include <ESP8266WiFi.h> // 调用ESP8266WiFi功能
#include <WiFiUdp.h>
#include <DNSServer.h>
#define FS_NO_GLOBALS // 调用ESP8266的SPIFFS FLASH
#include <FS.h>
#include <TFT_eSPI.h>
#include <TFT_eFEX.h>
#include <SPI.h>
#include <WiFiManager.h> //配网,物联网服务器
#include <ESP8266_BiliBili.h>
#include <ESP8266_Seniverse.h>
#include <PubSubClient.h>
#define USE_MQTT
//MQTT通讯相关
String controlTopic = WiFi.macAddress() + "-control"; // 设备控制主题
String chatTopic = WiFi.macAddress() + "-chat"; // 用户消息主题
String reportTopic = WiFi.macAddress() + "-report"; // 系统报告主题
String userControlString; // 用户通过MQTT协议发来的设置信息
String userChatString; // 用户通过MQTT协议发来的聊天信息
bool userChatFlag = false; // 告知系统是否有用户聊天信息需要显示
WiFiClient wifiClient; //建立MQTT协议所需对象
PubSubClient mqttClient(wifiClient);
//中文字库和设置库
#include "chinese.h"
#include "settings.h"
//图片解码
#include <TJpg_Decoder.h>
#include <ArduinoJson.h>
//TFT屏幕显示相关 对象 和 变量
TFT_eSPI tft = TFT_eSPI();
TFT_eFEX fex = TFT_eFEX(&tft);
TFT_eSprite clk = TFT_eSprite(&tft);
bool bgChangeFlag; // 背景更改显示标识
int bgId = START_BG_NUM; // 背景序号
// NTP服务
WiFiUDP Udp;
unsigned int localPort = 8888; // 端口
time_t prevDisplay = 0; // 上一次显示的时间,打点
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
//Ticker相关
//Ticker ticker;
int bgCounter;
//b站API相关
FansInfo fansInfo(biliUserId); // 建立对象用于获取 粉丝信息
VideoInfo videoInfo(biliBV); // 建立对象用于获取 视频信息
int biliCounter;
bool biliUpdateFlag;
long biliFans;
long biliViews;
// 建立对象和变量用于获取 心知天气信息
WeatherNow weatherNow;
Forecast forecast;
int weatherUpdateCounter;
bool weatherUpdateFlag;
byte weatherInfoDisplayCounter;
byte weatherInfoId = 1;
//设置图片大小 或者 文字颜色位置
#define BANNER_HEIGHT 20 // 横幅高
#define BANNER_WIDTH 320 // 横幅宽
#define HALF_BANNER_WIDTH 160 // 半横幅宽
#define BANNER_BG TFT_WHITE // 横幅背景色
#define BANNER_FG TFT_NAVY // 横幅文字色
//字库 动画或者图标
#include "font/ZdyLwFont_20.h"
#include "font/FxLED_32.h"
#include "img/watch_top.h"
#include "img/watch_bottom.h"
#include "img/temperature.h"
#include "img/humidity.h"//湿度
#include "img/pangzi/i0.h"
#include "img/pangzi/i1.h"
#include "img/pangzi/i2.h"
#include "img/pangzi/i3.h"
#include "img/pangzi/i4.h"
#include "img/pangzi/i5.h"
#include "img/pangzi/i6.h"
#include "img/pangzi/i7.h"
#include "img/pangzi/i8.h"
#include "img/pangzi/i9.h"
int led1 = D1;
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
if ( y >= tft.height() ) return 0;
tft.pushImage(x, y, w, h, bitmap);
// Return 1 to decode next block
return 1;
}
//开机加载动画
byte loadNum = 6; //加载开始位置
void loading(byte delayTime)
{
clk.setColorDepth(8); //颜色深度 4 8 16
clk.createSprite(250, 30); //创建精灵区域(int16_t width, int16_t height, uint8_t frames = 1)
clk.fillSprite(TFT_BLACK); //填充精灵区域的颜色
//开始在精灵区域画图
clk.drawRoundRect(0,0,250,16,8,TFT_WHITE);// 绘制圆角矩形(xy为0的时候,自动在区域基准开始)(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color)
clk.fillRoundRect(3,3,loadNum,10,5,TFT_ORANGE);//填充圆角矩形(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color);
clk.setTextDatum(CC_DATUM);//文字基准位置
clk.setTextColor(TFT_WHITE, TFT_BLACK); //文字颜色,背景颜色
clk.drawString("Connecting to WiFi",150,160,2);//(const char *string, int32_t x, int32_t y, uint8_t font(字体)),
clk.pushSprite(40,180);//(int32_t x, int32_t y);//将精灵的窗口区域推到tx,ty的TFT上
clk.deleteSprite();
loadNum += 1;
if(loadNum>=244){
loadNum = 244;
}
}
void setup()
{
Serial.begin(9600);
if (!SPIFFS.begin()) { // 检查SPIFFS是否可以正确启动
Serial.println("SPIFFS initialisation failed!"); // 如果SPIFFS无法启动则输出错误提示
while (1) yield(); // 然后程序停在此处
}
Serial.println("\r\nSPIFFS initialised."); // 如果SPIFFS正确启动则输出启动成功信息
pinMode(D1,OUTPUT);
// 初始化tft屏幕
tft.begin();
tft.setRotation(1); // 设置屏幕显示方向
tft.fillScreen(TFT_BLACK); // 将屏幕填充黑色
// ---WiFi准备工作---
// 建立WiFiManager对象
WiFiManager wifiManager;
//wifiManager.resetSettings();// 清除ESP8266所存储的WiFi连接信息
wifiManager.autoConnect("heiweilu"); //手动配网
//开机加载背景与动画
String bgName1 = "/bg" + String(61) + ".jpg";
fex.drawJpeg(bgName1, 2, 2); //(数组名字,x,y)
while (WiFi.status() != WL_CONNECTED) {
for(byte n=0;n<10;n++){ //每500毫秒检测一次状态
loading(50);
}
}
while(loadNum < 194){ //让动画走完
loading(1);
}
#ifdef USE_MQTT
// ---MQTT准备工作---
// 设置MQTT服务器和端口号
mqttClient.setServer(mqttServer, 1883);
// 设置MQTT订阅回调函数
mqttClient.setCallback(receiveCallback);
// 连接MQTT服务器
connectMQTTserver();
Serial.println("Report Topic:");
Serial.println(reportTopic);
#endif
//---bili信息初始化---
biliFans = getBiliFans();
biliViews = getBiliViews();
// 天气信息
weatherNow.config(reqUserKey, reqLocation, reqUnit);
forecast.config(reqUserKey, reqLocation, reqUnit);
updateWeatherInfo(); // 启动后获取天气信息
// ---NTP初始化---
ntpInit();
TJpgDec.setJpgScale(1);
TJpgDec.setSwapBytes(true);
TJpgDec.setCallback(tft_output);
//设置一个窗口和基准
tft.setViewport(2, 38, 316, 240);
tft.fillScreen(TFT_WHITE);
tft.resetViewport();//复位基准
//背景设置
String bgName = "/bg" + String(60) + ".jpg";
fex.drawJpeg(bgName, 2, 2); //(数组名字,x,y)
displayBg(bgId);
//绘制线框
tft.drawFastHLine(0,238,320,TFT_BLACK);//横线(int32_t x, int32_t y, int32_t w, uint32_t color)
tft.drawFastHLine(2,40,320,TFT_BLACK);
tft.drawFastHLine(2,2,320,TFT_BLACK);
tft.drawFastVLine(2,2,238,TFT_BLACK);//竖线(int32_t x, int32_t y, int32_t h, uint32_t color)
tft.drawFastVLine(2,2,40,TFT_BLACK);
tft.drawFastVLine(184,42,179,TFT_BLACK);
//显示星期二字
tft.drawBitmap(235,10,xing,20,20,TFT_BLACK); // 显示星字
tft.drawBitmap(256,10,qi1,20,20,TFT_BLACK); // 显示期字
tft.setTextColor(TFT_MAROON);
tft.drawString(reqLocation,128,10,4); //显示地区
//初始化时显示天气信息
displayWeatherInfo(1);
//TJpgDec.drawJpg(7,10,temperature, sizeof(temperature)); //温度图标
//TJpgDec.drawJpg(65,10,humidity, sizeof(humidity)); //湿度图标
}
void loop()
{
if (timeStatus() != timeNotSet)
{
if (now() != prevDisplay)
{ //仅当时间发生变化时才更新显示
prevDisplay = now();
displayTime();
//digitalClockDisplay();
#ifdef USE_MQTT
Serial.println("");
Serial.println("controlTopic:");
Serial.println(controlTopic);
Serial.println("chatTopic:");
Serial.println(chatTopic);
Serial.println("reportTopic:");
Serial.println(reportTopic);
Serial.println("");
#endif
tick(); // 计时函数
}
}
if (bgChangeFlag == true)
{
bgChangeFlag = false;
bgId++;
if (bgId > END_BG_NUM)
bgId = START_BG_NUM;
displayBg(bgId);
}
// 更新bili信息
if (biliUpdateFlag == true)
{
Serial.println("Update Bili Info");
biliUpdateFlag = false;
biliFans = getBiliFans();
biliViews = getBiliViews();
}
// 更新天气信息
if (weatherUpdateFlag == true)
{
Serial.println("Update Weather Info");
weatherUpdateFlag = false;
updateWeatherInfo();
displayWeatherInfo(weatherInfoId);
}
#ifdef USE_MQTT
if (mqttClient.connected()) // 如果开发板成功连接服务器
{
mqttClient.loop(); // 处理信息以及心跳
} else { // 如果开发板未能成功连接服务器
connectMQTTserver(); // 则尝试连接服务器
}
#endif
imgAnim();//启动太空人
}
//---------时间显示相关函数开始----------
//显示时间子函数
void displayTime()
{
String timeString;
String dateString;
String dateTimeString;
timeString = adjDigit(hour()) + ":" ;//+ adjDigit(minute())+ ":" + adjDigit(second());
dateString = adjDigit(month()) + "-" + adjDigit(day());
dateTimeString = dateString + " " + timeString;
/*// 设置时钟显示位置
tft.setViewport(0, 0, BANNER_WIDTH, BANNER_HEIGHT);
tft.setTextDatum(TL_DATUM);
tft.setTextColor(BANNER_FG, ); //设置文字颜色和背景色
tft.setTextPadding(10); //设置文字padding,覆盖旧字
tft.drawString(dateTimeString, 0, 0, 4); */
//显示星期几(右上角)
if (weekday() == 1)
{
tft.fillRect(280, 9, 20, 20, TFT_LIGHTGREY);
tft.drawBitmap(280,9,tian,20,20,TFT_BLACK); // 星期天显示天字 (中文用Bitmap)
}
else
{
tft.fillRect(300, 4, 20, 20, TFT_LIGHTGREY);
tft.setTextDatum(TR_DATUM);
tft.setTextColor(TFT_BLACK);
tft.drawString(String(weekday()-1), 300, 9, 4); //显示星期几数字
}
tft.resetViewport();
/***时间区***/
//时
clk.setColorDepth(8);
clk.createSprite(135, 48);//宽高
clk.fillSprite(TFT_LIGHTGREY);
// clk.loadFont(FxLED_32);
clk.setTextDatum(CC_DATUM);
clk.setTextColor(TFT_MAROON,TFT_LIGHTGREY);
clk.drawString(timeString,39,24,7); //绘制时
// clk.unloadFont();
clk.setTextColor(TFT_ORANGE,TFT_LIGHTGREY);
clk.drawString(adjDigit(minute()),105,24,7); //绘制分
//clk.unloadFont();
clk.pushSprite(185,42);//完美坐标
clk.deleteSprite();
//秒
clk.createSprite(40, 32);
clk.fillSprite(TFT_LIGHTGREY);
clk.loadFont(FxLED_32);
clk.setTextDatum(CC_DATUM);
clk.setTextColor(TFT_BLACK, TFT_LIGHTGREY);
clk.drawString(adjDigit(second()),20,16);
clk.unloadFont();
clk.pushSprite(278,89);
clk.deleteSprite();
//月日
clk.loadFont(ZdyLwFont_20);
clk.createSprite(90, 24);//动态变化必须创建精灵
clk.fillSprite(TFT_TRANSPARENT);//设置透明背景~~
clk.setTextDatum(CC_DATUM);
clk.setTextColor(TFT_BLACK, TFT_TRANSPARENT);
clk.drawString(monthDay(),45,16);
clk.pushSprite(13,8,TFT_TRANSPARENT);
clk.deleteSprite();
clk.unloadFont();
}
String adjDigit(int number)
{
if (number >= 10){
return String(number);
} else {
return String("0" + String(number));
}
}
String monthDay(){
String s = String(month());
s = s + "月" + day() + "日";
return s;
}
//*********************动画****************
//太空人
void imgAnim()
{
int x=230,y=125,dt=30;//瘦子版dt=10毫秒 胖子30较为合适
TJpgDec.drawJpg(x,y,i0, sizeof(i0));
delay(dt);
TJpgDec.drawJpg(x,y,i1, sizeof(i1));
delay(dt);
TJpgDec.drawJpg(x,y,i2, sizeof(i2));
delay(dt);
TJpgDec.drawJpg(x,y,i3, sizeof(i3));
delay(dt);
TJpgDec.drawJpg(x,y,i4, sizeof(i4));
delay(dt);
TJpgDec.drawJpg(x,y,i5, sizeof(i5));
delay(dt);
TJpgDec.drawJpg(x,y,i6, sizeof(i6));
delay(dt);
TJpgDec.drawJpg(x,y,i7, sizeof(i7));
delay(dt);
TJpgDec.drawJpg(x,y,i8, sizeof(i8));
delay(dt);
TJpgDec.drawJpg(x,y,i9, sizeof(i9));
delay(dt);
}
//*********************动画****************
//背景图片展示子函数
void displayBg(int bgId){
String bgName = "/bg" + String(bgId) + ".jpg";
fex.drawJpeg(bgName, 4, 42);
if (userChatFlag == true)
{
Serial.print("userChatFlag = ");Serial.println(userChatFlag);
showChatMessage(userChatString);
}
Serial.println(bgName);
}
//--- NTP(Network Time Protocol,网络时间协议)相关函数开始 ---
// ntp初始化
void ntpInit()
{
Serial.println("Starting UDP");
Udp.begin(localPort);
Serial.print("Local UDP port: ");
Serial.println(Udp.localPort());
Serial.println("-------------");
setSyncProvider(getNtpTime);// 设置对时函数
setSyncInterval(timeCheckInterval); // 每隔10秒钟对时一次
}
//获取NTP时间
time_t getNtpTime()
{
IPAddress ntpServerIP; // NTP server's ip address
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println("Transmit NTP Request");
WiFi.hostByName(ntpServerName, ntpServerIP);
Serial.print(ntpServerName);
Serial.print(": ");
Serial.println(ntpServerIP);
sendNTPpacket(ntpServerIP);
uint32_t beginWait = millis();
while (millis() - beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response :-(");
return 0; // return 0 if unable to get the time
}
// 向指定地址的时间服务器发送NTP请求子函数
void sendNTPpacket(IPAddress &address){
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
//--- NTP相关函数结束 ---
//--- 定时调用计时器函数 ---
void tick()
{
displayTime(); // 每秒更新时钟显示
bgCounter++;//背景更换
// 哔哩哔哩更新计时器
biliCounter++;
//天气更新计时器
weatherUpdateCounter++;
weatherInfoDisplayCounter++;
// 达到背景变换时间
if (bgCounter > bgChgInterval)
{
bgCounter = 0;
bgChangeFlag = true;//更换背景变换状态标志
}
// 达到bili信息更新时间
if (biliCounter > biliUpdateInterval){
biliCounter = 0;
biliUpdateFlag = true;
}
// 达到天气信息更新时间
if (weatherUpdateCounter > weatherUpdateInterval){
weatherUpdateCounter = 0;
weatherUpdateFlag = true;
}
// 达到天气信息变化时间
if (weatherInfoDisplayCounter > weatherDisplayInterval){
weatherInfoDisplayCounter = 1;
weatherInfoId++;
if(weatherInfoId > MAX_INFO_ID) {
weatherInfoId = 1;
}
displayWeatherInfo(weatherInfoId);
}
}
//--- 定时调用计时器函数结束 ---
//--- b站API相关函数 ---
long getBiliFans(){
if(fansInfo.update()){ // 更新信息成功
return fansInfo.getFansNumber();
} else { // 更新失败
Serial.println("Update Fail...");
return -1;
}
}
long getBiliViews(){
if(videoInfo.update()){ // 更新信息成功
return videoInfo.getPlay();
} else { // 更新失败
Serial.println("Update Fail...");
return -1;
}
}
//--- b站API相关函数结束 ---
//--- 心知天气相关函数 ---
void updateWeatherInfo(){
weatherUpdateCounter = 0;
if(weatherNow.update()){ // 更新天气信息
Serial.println("Weather Now Updated: ");
Serial.println(weatherNow.getLastUpdate()); // 获取服务器更新天气信息时间
} else { // 更新失败
Serial.println("Weather Now Update Fail.");
Serial.print("Server Response: "); // 输出服务器响应状态码供用户查找问题
Serial.println(weatherNow.getServerCode()); // 心知天气服务器错误代码说明可通过以下网址获取
}
if(forecast.update()){ // 更新天气信息
Serial.println("Weather Forecast Updated: ");
Serial.println(forecast.getLastUpdate());
} else { // 更新失败
Serial.println("Weather Forecast Update Fail.");
Serial.print("Server Response: "); // 输出服务器响应状态码供用户查找问题
Serial.println(weatherNow.getServerCode()); // 心知天气服务器错误代码说明可通过以下网址获取
}
}
// 显示天气的文字信息
void displayWeatherInfo(int infoId)
{
const uint8_t* chn1;
const uint8_t* chn2;
const uint8_t* chn3;
const uint8_t* chn4;
int weatherCode; // 天气或温度代码信息
bool chineseFlag; // 中文显示标识
if (infoId == 1){
chn1 = dang;
chn2 = qian;
chn3 = tian;
chn4 = qi;
weatherCode = weatherNow.getWeatherCode();
chineseFlag = true;
} else if (infoId == 2){
chn1 = dang;
chn2 = qian;
chn3 = qi;
chn4 = wen;
weatherCode = weatherNow.getDegree();
chineseFlag = false;
} else if (infoId == 3){
chn1 = jin;
chn2 = tian;
chn3 = zui;
chn4 = gao;
weatherCode = forecast.getHigh(0);
chineseFlag = false;
} else if (infoId == 4){
chn1 = jin;
chn2 = tian;
chn3 = zui;
chn4 = di;
weatherCode = forecast.getLow(0);
chineseFlag = false;
} else if (infoId == 5){
chn1 = ming;
chn2 = tian;
chn3 = tian;
chn4 = qi;
weatherCode = forecast.getDayCode(1);
chineseFlag = true;
} else if (infoId == 6){
chn1 = ming;
chn2 = wan;
chn3 = tian;
chn4 = qi;
weatherCode = forecast.getNightCode(1);
chineseFlag = true;
} else if (infoId == 7){
chn1 = ming;
chn2 = tian;
chn3 = zui;
chn4 = gao;
weatherCode = forecast.getHigh(1);
chineseFlag = false;
} else if (infoId == 8){
chn1 = ming;
chn2 = tian;
chn3 = zui;
chn4 = di;
weatherCode = forecast.getLow(1);
chineseFlag = false;
} else if (infoId == 9){
chn1 = bi;
chn2 = li;
chn3 = fen;
chn4 = si;
weatherCode = biliFans;
chineseFlag = false;
} else if (infoId == 10){
chn1 = bo;
chn2 = fang;
chn3 = shu;
chn4 = liang;
weatherCode = biliViews;
chineseFlag = false;
}
showWeatherDetail(weatherCode, chineseFlag);//天气代码,变换标志
showWeatherChnDesc(chn1, chn2, chn3, chn4);//显示天气文字的函数调用
}
//显示网络获取的具体天气信息
void showWeatherDetail(int weatherCode, bool chineseFlag){
tft.setViewport(160, 222, 160, BANNER_HEIGHT);//底端文字坐标
tft.fillScreen(TFT_LIGHTGREY);
// 设置信息显示位置
tft.setTextDatum(TL_DATUM);
tft.setTextColor(BANNER_FG, TFT_LIGHTGREY); //设置文字颜色和背景色
tft.setTextPadding(10); //设置文字padding,覆盖旧字
if (chineseFlag == false)
{ // 如果不是中文
tft.drawString(" : " + String(weatherCode) + " ", 0, 0, 4);
tft.drawBitmap(35, 0, du, 20, 20, BANNER_FG);
}
else
{ // 如果是中文
tft.drawString(" : ", 0, 0, 4);
if (weatherCode >= 0 && weatherCode <= 3)
{
tft.drawBitmap(15, 0, qing, 20, 20, BANNER_FG);
}
else if (weatherCode >= 4 && weatherCode <= 8)
{
tft.drawBitmap(15, 0, duo, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, yun, 20, 20, BANNER_FG);
}
else if (weatherCode == 9)
{
tft.drawBitmap(15, 0, yin, 20, 20, BANNER_FG);
}
else if (weatherCode >= 10 && weatherCode <= 12)
{
tft.drawBitmap(15, 0, zhen, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, yu, 20, 20, BANNER_FG);
}
else if (weatherCode == 13)
{
tft.drawBitmap(15, 0, xiao, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, yu, 20, 20, BANNER_FG);
} else if (weatherCode == 14) {
tft.drawBitmap(15, 0, zhong, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, yu, 20, 20, BANNER_FG);
}
else if (weatherCode >= 15 && weatherCode <= 18)
{
tft.drawBitmap(15, 0, da, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, yu, 20, 20, BANNER_FG);
}
else if (weatherCode == 19 || weatherCode == 20)
{
tft.drawBitmap(15, 0, dong, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, yu, 20, 20, BANNER_FG);
}
else if (weatherCode == 21)
{
tft.drawBitmap(15, 0, zhen, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, xue, 20, 20, BANNER_FG);
}
else if (weatherCode == 22)
{
tft.drawBitmap(15, 0, xiao, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, xue, 20, 20, BANNER_FG);
}
else if (weatherCode == 23)
{
tft.drawBitmap(15, 0, zhong, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, xue, 20, 20, BANNER_FG);
}
else if (weatherCode == 24 || weatherCode == 25 )
{
tft.drawBitmap(15, 0, da, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, xue, 20, 20, BANNER_FG);
}
else if (weatherCode >= 26 && weatherCode <= 29 )
{
tft.drawBitmap(15, 0, sha, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, chen, 20, 20, BANNER_FG);
}
else if (weatherCode == 30 || weatherCode == 31 )
{
tft.drawBitmap(15, 0, wu, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, mai, 20, 20, BANNER_FG);
}
else if (weatherCode >= 32 || weatherCode <= 36 )
{
tft.drawBitmap(15, 0, da, 20, 20, BANNER_FG);
tft.drawBitmap(35, 0, feng, 20, 20, BANNER_FG);
}
else {
tft.drawString(" : Unknown", 0, 0, 4);
}
}
tft.resetViewport();
}
void showWeatherChnDesc(const uint8_t chnChar1[], const uint8_t chnChar2[], const uint8_t chnChar3[], const uint8_t chnChar4[] ){
// 设置信息显示位置-底端
tft.setViewport(4, 222, HALF_BANNER_WIDTH, BANNER_HEIGHT);//设置横幅显示位置(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true)
tft.fillScreen(TFT_LIGHTGREY);//横幅填充颜色
tft.setTextColor(BANNER_FG, TFT_LIGHTGREY); //设置文字颜色和横幅背景色
//显示中文说明
tft.drawBitmap(80,0,chnChar1,20,20,BANNER_FG);//( int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t fgcolor)
tft.drawBitmap(100,0,chnChar2,20,20,BANNER_FG);
tft.drawBitmap(120,0,chnChar3,20,20,BANNER_FG);
tft.drawBitmap(140,0,chnChar4,20,20,BANNER_FG);
tft.resetViewport();
}
//--- b站API相关函数结束 ---
//--- MQTT相关函数开始 ---
// 连接MQTT服务器并订阅信息
void connectMQTTserver(){
// 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
String clientId = "esp8266-" + WiFi.macAddress();
// 连接MQTT服务器
if (mqttClient.connect(clientId.c_str())) {
Serial.println("MQTT Server Connected.");
Serial.println("Server Address:");
Serial.println(mqttServer);
Serial.println("ClientId: ");
Serial.println(clientId);
subscribeTopic(); // 订阅指定主题
} else {
Serial.print("MQTT Server Connect Failed. Client State:");
Serial.println(mqttClient.state());
delay(5000);
}
}
// 订阅指定主题
void subscribeTopic(){
String topicString = controlTopic;
char subTopic[topicString.length() + 1];
strcpy(subTopic, topicString.c_str());
// 建立订阅主题2
String topicString2 = chatTopic;
char subTopic2[topicString2.length() + 1];
strcpy(subTopic2, topicString2.c_str());
// 通过串口监视器输出是否成功订阅主题1以及订阅的主题1名称
if(mqttClient.subscribe(subTopic)){
Serial.println("Subscribe Control Topic");
Serial.println(subTopic);
Serial.println("OK");
} else {
Serial.print("Subscribe Fail...");
}
// 通过串口监视器输出是否成功订阅主题2以及订阅的主题2名称
if(mqttClient.subscribe(subTopic2)){
Serial.println("Subscribe Chat Topic ");
Serial.println(subTopic2);
Serial.println("OK");
} else {
Serial.print("Subscribe Fail...");
}
}
// 收到信息后的回调函数
void receiveCallback(char* topic, byte* payload, unsigned int length) {
int cmdId; // 系统控制指令id
char cmdInfo; // 系统控制信息具体内容
Serial.print("Message Received [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println("");
Serial.print("Message Length(Bytes) ");
Serial.println(length);
if(String(topic) == controlTopic){
userControlString = "";
for (int i = 0; i < length; i++) {
userControlString += (char)payload[i];
}
Serial.print("userControlString = ");Serial.println(userControlString);
if(payload[0] == 'b' && payload[1] == 'j' ){
cmdId = 1; // 修改背景显示间隔
cmdInfo = payload[2];
} else if(payload[0] == 's' && payload[1] == 'j' ){
cmdId = 2; // 修改时间更新间隔
cmdInfo = payload[2];
} else if(payload[0] == 'b' && payload[1] == 'l' ){
cmdId = 3; // 修改bili更新间隔
cmdInfo = payload[2];
} else if(payload[0] == 't' && payload[1] == 'q' ){
cmdId = 4; // 修改bili更新间隔
cmdInfo = payload[2];
} else if(payload[0] == 'x' && payload[1] == 's' )
{
cmdId = 5; // 修改信息显示时间间隔
cmdInfo = payload[2];
}
else if(payload[0] == 'h' && payload[1] == 'b'
){
cmdId = 6; // 修改信息显示时间间隔
cmdInfo = payload[2];
}
else if(payload[0] == 'K' && payload[1] == 'D'
)
{
cmdId = 7; // 改变led亮
cmdInfo = payload[2];
}
else if(payload[0] == 'G' && payload[1] == 'D'
)
{
cmdId = 8; // 改变led关
cmdInfo = payload[2];
}
else {
return;
}
changeSettings(cmdId, cmdInfo);
} else if(String(topic) == chatTopic){
userChatString = "";
for (int i = 0; i < length; i++) {
userChatString += (char)payload[i];
}
Serial.print("userChatString = ");Serial.println(userChatString);
showChatMessage(userChatString); // 屏幕上显示用户聊天消息
pubReportMsg(userChatString); // 通过系统报告主题发布用户聊天信息
}
}
// 发布信息
void pubReportMsg(String reportMsg){
String topicString = reportTopic;
char publishTopic[topicString.length() + 1];
strcpy(publishTopic, topicString.c_str());
char publishMsg[reportMsg.length() + 1];
strcpy(publishMsg, reportMsg.c_str());
// 实现ESP8266向主题发布信息
if(mqttClient.publish(publishTopic, publishMsg)){
Serial.println("Publish Report Topic:");Serial.println(publishTopic);
Serial.println("Publish Report Message:");Serial.println(publishMsg);
} else {
Serial.println("Report Message Publish Failed.");
}
}
//--- MQTT相关函数结束 ---
//--- 显示用户聊天信息相关函数开始 ---
void showChatMessage(String userChatString){
if (userChatString == NULL){
userChatFlag = false; // 告知系统目前没有用户聊天信息
displayBg(bgId);
} else {
userChatFlag = true; // 告知系统目前有用户聊天信息
if(userChatString.length() > 24){
userChatString = "[MESSAGE TOO LONG!]";
} else {
displayUserMessage(userChatString);
}
}
}
void displayUserMessage(String userString){
tft.setViewport(0, 220, BANNER_WIDTH, BANNER_HEIGHT);
tft.fillScreen(BANNER_BG);
// 设置信息显示位置
tft.setTextDatum(TC_DATUM);
tft.setTextColor(BANNER_FG, TFT_LIGHTGREY); //设置文字颜色和背景色
tft.setTextPadding(10); //设置文字padding,覆盖旧字
tft.drawString(userString, 160, 0, 4);
tft.resetViewport();
}
//--- 显示用户聊天信息相关函数结束 ---
//--- 设置系统相关函数开始 ---
void changeSettings(int cmdId, char cmdInfo){
String userSettingMessage;
Serial.print("cmdId = ");Serial.println(cmdId);
Serial.print("cmdInfo = ");Serial.println(cmdInfo);
if(cmdId == 1){ // 收到修改背景变化间隔调整的指令
if(cmdInfo == '1'){
bgChgInterval = 5;
} else if(cmdInfo == '2'){
bgChgInterval = 10;
} else if(cmdInfo == '3'){
bgChgInterval = 30;
} else if(cmdInfo == '4'){
bgChgInterval = 60;
} else if(cmdInfo == '5'){
bgChgInterval = 300;
} else {
return;
}
userSettingMessage = "bgChgInterval = " + String(bgChgInterval);
} else if(cmdId == 2){ // 收到修改更新间隔调整的指令
if(cmdInfo == '1'){
timeCheckInterval = 300;
} else if(cmdInfo == '2'){
timeCheckInterval = 600;
} else if(cmdInfo == '3'){
timeCheckInterval = 900;
} else if(cmdInfo == '4'){
timeCheckInterval = 1200;
} else if(cmdInfo == '5'){
timeCheckInterval = 1800;
} else {
return;
}
userSettingMessage = "timeCheckInterval = " + String(timeCheckInterval);
} else if(cmdId == 3){ // 收到修改哔哩哔哩信息更新时间设置
if(cmdInfo == '1'){
biliUpdateInterval = 350;
} else if(cmdInfo == '2'){
biliUpdateInterval = 650;
} else if(cmdInfo == '3'){
biliUpdateInterval = 950;
} else if(cmdInfo == '4'){
biliUpdateInterval = 1250;
} else if(cmdInfo == '5'){
biliUpdateInterval = 1850;
} else {
return;
}
userSettingMessage = "biliUpdateInterval = " + String(biliUpdateInterval);
} else if(cmdId == 4){ // 收到修改天气信息更新时间设置
if(cmdInfo == '1'){
weatherUpdateInterval = 300;
} else if(cmdInfo == '2'){
weatherUpdateInterval = 600;
} else if(cmdInfo == '3'){
weatherUpdateInterval = 900;
} else if(cmdInfo == '4'){
weatherUpdateInterval = 1200;
} else if(cmdInfo == '5'){
weatherUpdateInterval = 1800;
} else {
return;
}
userSettingMessage = "weatherUpdateInterval = " + String(weatherUpdateInterval);
}
else if(cmdId == 5)
{ // 收到修改天气信息显示时间设置
if(cmdInfo == '1'){
weatherDisplayInterval = 2;
} else if(cmdInfo == '2'){
weatherDisplayInterval = 5;
} else if(cmdInfo == '3'){
weatherDisplayInterval = 10;
} else if(cmdInfo == '4'){
weatherDisplayInterval = 15;
} else if(cmdInfo == '5'){
weatherDisplayInterval = 20;
} else if (cmdId == 6) {
} else {
return;
}
userSettingMessage = "weatherDisplayInterval = " + String(weatherDisplayInterval);
}
else if(cmdId == 7)
{
digitalWrite(D1,HIGH);
}
else if(cmdId == 8)
{
digitalWrite(D1,LOW);
}
else if (cmdId == 6){ // 收到要求系统汇报状态的指令
String systemReportString;
systemReportString = "bj:" + String(bgChgInterval) + ", ";
systemReportString = systemReportString + "sj:" + String(timeCheckInterval) + ", ";
systemReportString = systemReportString + "bl:" + String(biliUpdateInterval) + ", ";
systemReportString = systemReportString + "tq:" + String(weatherUpdateInterval) + ", ";
systemReportString = systemReportString + "xs:" + String(weatherDisplayInterval);
systemReportString = systemReportString + "led:" ;
pubReportMsg(systemReportString);
return;
} else {
return;
}
displayUserMessage(userSettingMessage);
pubReportMsg(userSettingMessage);
}
/*
MQTT控制指令说明
bj - 修改背景变换时间间隔
1 - 5秒 / 2 -10秒 / 3 - 30秒 / 4 - 60秒(默认) / 5 - 300秒
sj - 修改系统NTP对时时间间隔
1 - 300秒(默认) / 2 -600秒 / 3 - 900秒 / 4 - 1200秒 / 5 - 1800秒
bl - 修改哔哩哔哩信息更新时间间隔
1 - 350秒(默认) / 2 -650秒 / 3 - 950秒 / 4 - 1250秒 / 5 - 1850秒
tq - 修改天气信息更新时间间隔
1 - 300秒 / 2 -600秒 / 3 - 900秒(默认) / 4 - 1200秒 / 5 - 1800秒
xs - 修改屏幕下方信息显示变换时间间隔
1 - 2秒 / 2 -5秒 / 3 - 10秒 / 4 - 15秒 / 5 - 20秒(默认)
hb - 指示系统汇报运行状态
*/
下载链接
百度网盘 | 链接:https://pan.baidu.com/s/1YyaeFz9Ohmwjabt0inRWkw?pwd=vnnl 提取码:vnnl |
评论