CSDN垃圾了,保存了草稿还被吞了好几次
目录
HttpTool::updateBilibiliFlag()
System::uint8t_to_long(uint8_t *data, int length)
DateTimes::setDateTimes(long timestamp)
Udps::getNtpTimestamp()获取当前时间戳
HttpTool::bilibiliFans()刷新bilibili粉丝
HttpTool::loadBuid()从EEPROM中加载bilibili的UID
EEPROMTool.loadData()定义在EEPROMTool.h中
项目来源:ES8266多功能点阵时钟 - 立创EDA开源硬件平台
今天就从setup()函数中的udps.initudp()开始吧
udps.initudp()定义在Udps.cpp中。
Udps::initudp()
//Udps.cpp
//WiFiUDP udp;
void Udps::initudp()
{
// todo 这里需要判断网络状态
WiFi.hostByName(ntpServerName, timeServerIP); //将域名转换成IP地址//从网站名获取IP地址
udp.begin(localPort); // 启动监听本地端口
}
httptoolticker.attach()
//(时间, 回调函数)
httptoolticker.attach(5 * 6 * 1000, httptool.updateBilibiliFlag); // 每五分分钟更新一次更新bilibili粉丝flag
updateBilibiliFlag()定义在HttpTool.cpp文件中。
HttpTool::updateBilibiliFlag()
//置更新flag为TRUE
void HttpTool::updateBilibiliFlag()
{
is_need_update_bilibili = true;// 判断是否需要更新bilibili粉丝数flag
}
timestampticker.attach()
timestampticker.attach(1, DateTimes::timestampAdd); // 每一秒叠加一次秒数
DateTimes::timestampAdd
//系统时间戳++
void DateTimes::timestampAdd() { currtimestamp++; }
if (!wifis.isApMode())判断,在wifis.cpp定义
resetTime(NULL)
resetTime(NULL); // 每次初始化的时候都校准一下时间,这里是随便传的一个参数,不想重新声明参数
resetTime(NULL) 定义在Main.h中
// 重置时间: 重置时间这里有两种方式,一种就是用NTP校准时间,还有一种就是设备没有连接wifi,直接用手机发来的时间戳进行校准时间
void resetTime(uint8_t *data)
{
if (data != NULL) // 函数中参数如果不为空则使用参数值来作为时间来历
{
long timestamp = System::uint8t_to_long(data, 5); // 先将uint_8转成 long
datetimes.setDateTimes(timestamp + 8 * 60 * 60); // 将时间戳同步到系统时间中去
}
else
{
udps.updateTime(); // 校准时间
}
functions.reset(); // 重置功能
initStatus(); // 重置状态
}
uint8t_to_long(data, 5)定义在System.h中
System::uint8t_to_long(uint8_t *data, int length)
// * @brief uint8_t数组转long
long System::uint8t_to_long(uint8_t *data, int length)
{
long temp = 0;
for (int i = 0; i < length; i++)
{
temp += data[i] << (i * 8);
}
return temp;
}
datetimes.setDateTimes(timestamp + 8 * 60 * 60)定义在DateTimes.cpp中
DateTimes::setDateTimes(long timestamp)
//@brief 给时钟芯片和系统时间设置时间信息
void DateTimes::setDateTimes(long timestamp)
{
currtimestamp = timestamp; //每秒++
datetime = DateTime(timestamp); //这个没找到
}
//======后期要更新
udps.updateTime()定义在Udps.cpp中
Udps::updateTime()更新系统时间
/**
* @brief 更新系统时间
*
*/
void Udps::updateTime()
{
int count = 5; // 一共尝试五次
sendNTPpacket(); // 向NTP服务器发请求,先发送更新时间的操作
int lastSendTime = millis(); // 记录上一次发送更新时间的时间戳
while (true) // 这里用一个死循环来搞定,先发送更新时间的操作
{
long timeStamp = getNtpTimestamp(); // 获取当前时间戳
if (timeStamp != 0) // 说明已经获取到了时间信息,这里直接做更新操作
{
datetimes->setDateTimes(timeStamp); // 给时钟设置时间
break; // 跳出死循环
}
else
{
if (millis() - lastSendTime >= 1000) // 如果说发送时间超出上次发送时间1秒钟,则重新发送NTP请求
{
sendNTPpacket(); // 向NTP服务器发请求,先发送更新时间的操作
lastSendTime = millis();
count--;
}
}
lattice->showLongIcon(2); // 这里延迟两秒是因为过程太快了,交互体验不好//???这不是显示函数嘛
pilotLight->flashing(); // 校准时间LED闪烁
delay(100); // 等待100ms
if (count < 0) // 如果说所有机会都用完了
{
break; // 跳出死循环
}
}
}
sendNTPpacket()定义在Udps.cpp中
sendNTPpacket()发送NTP请求
/**
* @brief 发送NTP请求
*
*/
void Udps::sendNTPpacket()
{
memset(packetBuffer, 0, NTP_PACKET_SIZE); // 将字节数组的数据全部设置为0
packetBuffer[0] = 0b11100011; // 请求部分其实是有很多数据的,具体的请看参考请求报文说明,这里我们就只设置一个请求头部分即可
udp.beginPacket(timeServerIP, remoteNtpPort); // 配置远端ip地址和端口
udp.write(packetBuffer, NTP_PACKET_SIZE); // 把数据写入发送缓冲区
udp.endPacket(); // 发送数据
Serial.println("send ntp data"); //
}
memset(地址, 替换值, 字节数)
//将地址的字节数的值替换为替换值,替换值0~255
//UDP数据发送准备
udp.beginPacket(timeServerIP, remoteNtpPort); // 配置远端ip地址和端口
//UDP数据接收设备的IP地址(IPAddress类型)、UDP数据接收设备的IP地址监听端口号(uint16_t类型)
//将即将通过UDP协议发送的数据写入发送缓冲区。此函数必须置于beginPacket和endPacket之间。
udp.write(packetBuffer, NTP_PACKET_SIZE); // 把数据写入发送缓冲区
//此函数仅仅将数据写入发送缓冲区,但是数据不会发送。实施数据发送的函数是endPacket函数。
long timeStamp = getNtpTimestamp()定义在Udps.cpp,获取当前时间戳
Udps::getNtpTimestamp()获取当前时间戳
// 获取当前时间戳
long Udps::getNtpTimestamp()
{
int packetSize = udp.parsePacket(); //解析Udp数据包
if (!packetSize) //解析包为空
{
return 0;
}
else //解析包不为空
{
udp.read(packetBuffer, NTP_PACKET_SIZE); // 解析UDP数据包中的数据
// todo这里获取到的时间其实不是真实的时间,实际上还包含了网络延时的,但是为了方便,这里我们忽略这个因素的存在
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); // 取出t2时间的高位和低位数据拼凑成以秒为单位的时间戳
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord; // 拼凑成以秒为单位的时间戳(时间戳的记录以秒的形式从 1900-01-01 00:00:00算起)
const unsigned long seventyYears = 2208988800UL;
unsigned long timestamp = secsSince1900 - seventyYears; // 前面的32bit是时间戳的秒数(是用1900-01-01 00:00:00开始的秒数,但是我们的是1970年,所以需要减掉2208988800秒)
timestamp = timestamp + 8 * 60 * 60; // 这里加8 是因为时区的问题,如果不加8,得到的结果就会是其他时区的时间
return timestamp;
}
}
udp.parsePacket(); //解析Udp数据包
//用于检查是否有UDP数据包传入,返回值为数据包大小
udp.read(packetBuffer, NTP_PACKET_SIZE); // 解析UDP数据包中的数据
// (传入数据包的内存指针, 数据包大小)
//本函数可用于从设备接收到数据中读取数据。函数将会返回等待读取的数据字节数。
//请注意,使用本函数以前需要先调用parsePacket函数。
httptool.bilibiliFans()定义在HttpTool.cpp中
HttpTool::bilibiliFans()刷新bilibili粉丝
//刷新bilibili粉丝
void HttpTool::bilibiliFans()
{
if (!is_need_update_bilibili)
{
return;
}
fans = 0; // 每次都先重置粉丝数量,避免出现问题
biliUid = loadBuid(); // 每次都重新加载bilibili用户ID
Serial.println(biliUid);
if (WiFi.status() != WL_CONNECTED) // 确保wifi网络是可用的,不可用则忽略
{
Serial.println("no wifi");
is_need_update_bilibili = false;
return;
}
espClient.begin(wifiClient, bilibiliFansApi + biliUid); // 这里做法欠妥,我用自己服务器做了一层代理,直接解析了UP的粉丝数
int httpCode = espClient.GET();
Serial.println(httpCode);
if (httpCode > 0)
{
if (httpCode == HTTP_CODE_OK)
{
String nums = espClient.getString();
fans = strtol(nums.c_str(), NULL, 10);
Serial.println(fans);
is_need_update_bilibili = false;
}
}
espClient.end();
}
biliUid = loadBuid() // 每次都重新加载bilibili用户ID,定义在HttpTool.cpp中
HttpTool::loadBuid()从EEPROM中加载bilibili的UID
// @brief 从EEPROM中加载bilibili的UID
long HttpTool::loadBuid()
{
long uid = 0;
uint8_t *temp = EEPROMTool.loadData(BILIBILI_UID, 5); // 这里的97处理的不得当,后续优化,但是不影响实际功能
for (int i = 0; i < 5; i++)
{
uid += temp[i] << (i * 8);
}
// 用完以后删除内存
free(temp);
return uid;
}
EEPROMTool.loadData(BILIBILI_UID, 5)
人家UID都是5位的,我八位!
EEPROMTool.loadData()定义在EEPROMTool.h中
// * @brief EEPROM获取数据
uint8_t *loadData(int offset, int length)
{
unsigned char *arr = new uint8_t[length];
for (int i = 0; i < length; i++)
{
arr[i] = EEPROM.read(offset + i);
}
return arr;
}
WiFi.status()语句来获取联网状态
返回值类型为uint8_t。以下是返回值数值以及对应的信息:
255: WL_NO_SHIELD – 返回值为255说明无扩展板。8266本来带有网络功能,不需要额外的扩展板(sheld),因此一般不会出现这个报错
0: WL_IDLE_STATUS – 返回值为0说明正在尝试连接
1: WL_NO_SSID_AVAIL – 返回值为1说明没有找到设定的SSID的网络
2: WL_SCAN_COMPLETED – 返回值为2说明网络扫描完毕
3: WL_CONNECTED – 返回值为3说明连接成功成功
4: WL_CONNECT_FAILED – 返回值为4说明连接失败
5: WL_CONNECTION_LOST – 返回值为5说明连接丢失
6: WL_DISCONNECTED – 返回值为6说明未连接
获取粉丝数部分代码
参考:
espClient.begin(wifiClient, bilibiliFansApi + biliUid); // 这里做法欠妥,我用自己服务器做了一层代理,直接解析了UP的粉丝数
int httpCode = espClient.GET();
Serial.println(httpCode);
if (httpCode > 0)
{
if (httpCode == HTTP_CODE_OK)
{
String nums = espClient.getString();
fans = strtol(nums.c_str(), NULL, 10);
Serial.println(fans);
is_need_update_bilibili = false;
}
}
espClient.end();
//本函数用于设置ESP8266发送HTTP请求的目标URL
espClient.begin(wifiClient, bilibiliFansApi + biliUid);
//(请求网址, 请求的网络服务器端口)
int httpCode = espClient.GET();
//从指定的资源请求数据。返回值:服务器状态码
//此函数可用于获取服务器响应中的响应体信息。响应体信息将以字符串的形式进行返回。
String nums = espClient.getString();
//返回服务器HTTP响应中的响应体数据。(返回值类型:String)
espClient.end();
//当ESP8266发送HTTP请求结束后,我们应该调用此函数来清除ESP8266的接收缓存以便设备再次接收服务器发来的响应信息。
initSleepTime(); // 初始化休眠时间
定义在Main.h中
void initSleepTime()
{
// 先从内存中加载
uint8_t *t = EEPROMTool.loadData(SLEEP_TIME, 5);
for (int i = 0; i < 5; i++)
{
sleepTime[i] = t[i];
}
free(t);
}
初始化的东西看完了
初始化的东西看完了