先上效果图:
看到标题很多人会疑惑,ESP32不是直接可以http获取网络时间和B站粉丝数吗?为什么要多加一层跟树莓派通过MQTT通信。
这是因为刚了解了MQTT的相关知识,想实践一下,所以就一起用上了。
整体的软件框架图如下:
接下来分树莓派端和ESP32端来讲解各个细节。
一:树莓派
首先,在树莓派上使用mosquito工具建立MQTT服务器,将树莓派作MQTT模型中的服务器,此外树莓派也同时作为MQTT通信中的发布者(publisher)。发布者实现的方法是通过python脚本,而服务器的建立直接通过命令行。此外通过python请求http拉取网络时间和b站粉丝数,具体实现步骤如下:
在python脚本中,使用Requests模块请求http连接,(1)首先是获取网络时间,这里用到的url是http://time1909.beijing-time.org/time.asp,获取到字符串后进行字符串分割,最后得到时间数据,具体代码如下,注意要import requests:
def getNetTime():
head = {'User-Agent' : 'Mozilla/5.0'}
url = r'http://time1909.beijing-time.org/time.asp'
r = requests.get(url=url,headers=head)
if r.status_code ==200 :
result = r.text
print('r.text:',r.text) #拉下来的字符串
data = result.split(";")
year = data[1].split('=')[1] #获得year数据
month = data[2].split('=')[1] #获得month数据
day = data[3].split('=')[1] #获得day数据
hrs = data[5].split('=')[1] #获得hour数据
minute = data[6].split('=')[1] #获得minute数据
sec = data[7].split('=')[1] #获得second数据
timestr = "%s/%s/%s %s:%s:%s" % (year, month, day, hrs, minute, sec)
print(timestr)
return (timestr)
(2)获取完时间后,紧接着就是获取bilibili的粉丝数,道理一样,requests.get返回后的text元素是json格式,应该使用json.loads()转成字典,代码如下(注意要import json):
Bilibili_UID 改成你自己b站的uid
Bilibili_UID = 13675014 #改成你自己b站的uid
def getBilibliFan():
url = 'https://api.bilibili.com/x/web-interface/card?mid=%d'%(Bilibili_UID)
r = requests.get(url)
temp = json.loads(r.text)
follower = temp['data']['follower']
print(follower)
return (follower)
(3)时间和粉丝数获取之后,最后就是将树莓派作为MQTT服务器同时作为发布者,使用的python模块是paho.mqtt.client,可以通过以下命令安装
pip3 install paho.mqtt
具体代码如下:
HOST="192.168.xxx.xxx" #您树莓派的IP地址
PORT=1883 #MQTT端口,默认就行
USER="admin" #修改成您MQTT服务器登入的用户名
PASSWD="1234" #修改成您MQTT服务器登入的密码
TOPIC="esp32" #修改成您想发布的话题名
if __name__ =="__main__":
mqttc = mqtt.Client("Raspi") #以Raspi昵称登入MQTT服务器
mqttc.username_pw_set(USER,PASSWD) #设置登入的用户和密码
mqttc.connect(HOST,PORT,60) #建立MQTT连接
mqttc.publish(TOPIC,"HELLO WORLD",0) #向TOPIC话题发布一条消息
mqttc.loop() #保持连接mqttc.connect()中的第三个参数是60,所以60s内要loop一下或者发布一条消息
(4)最后将时间和粉丝数量发送给ESP32就行了,总代码如下:
import json
import time
import requests
import paho.mqtt.client as mqtt
HOST="192.168.xxx.xxx" #改成你的树莓派ip
PORT=1883
USER="admin" #改成你MQTT服务器的用户名
PASSWD="1234" #改成你MQTT服务器的密码
TOPIC="esp32" #改成你MQTT想发布的话题
Bilibili_UID = 13675014 #改成你自己b站的uid
def getBilibliFan():
url = 'https://api.bilibili.com/x/web-interface/card?mid=%d'%(Bilibili_UID)
r = requests.get(url)
temp = json.loads(r.text)
follower = temp['data']['follower']
print(follower)
return (follower)
def getNetTime():
head = {'User-Agent' : 'Mozilla/5.0'}
url = r'http://time1909.beijing-time.org/time.asp'
r = requests.get(url=url,headers=head)
if r.status_code ==200 :
result = r.text
print('r.text:',r.text) #拉下来的字符串
data = result.split(";")
year = data[1].split('=')[1] #获得year数据
month = data[2].split('=')[1] #获得month数据
day = data[3].split('=')[1] #获得day数据
hrs = data[5].split('=')[1] #获得hour数据
minute = data[6].split('=')[1] #获得minute数据
sec = data[7].split('=')[1] #获得second数据
timestr = "%s/%s/%s %s:%s:%s" % (year, month, day, hrs, minute, sec)
print(timestr)
return (timestr)
if __name__ =="__main__":
mqttc = mqtt.Client("Raspi")
mqttc.username_pw_set(USER,PASSWD)
mqttc.connect(HOST,PORT,60)
mqttc.publish(TOPIC,"HEELO WORLD",0)
mqttc.loop()
print('now timer:',getNetTime())
while 1:
mqttc.publish(TOPIC,getNetTime()+'|'+str(getBilibliFan()),0)
time.sleep(1)
二:ESP32
首先,先将ESP32连接网络,注意要和你的树莓派在同一网段中。用到的MQTT库是这个:
用到的显示屏驱动库是:
然后由于我的显示器驱动芯片是ST7789,所以还需要安装Adafruit的ST7789库:
此外,如果你需要一些额外的字体,中文,图形库的话我这里使用了U8g2,U8g2有专门争对Adafruit系类的接口,所以使用起来十分方便。
至此,所有需要用到的arduino库安装完成,下面只剩ESP32的软件部分。直接上代码,总体思路就是连接树莓派的MQTT服务器,同时订阅树莓派发布的话题(注意ESP32订阅的和树莓派发布的话题要完全一样),然后在订阅的回调函数里处理数据然后显示出来。
/*
* ESP32 <---> 树莓派 MQTT
*/
//定义屏幕的宽、高
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 240
//定义颜色
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <U8g2_for_Adafruit_GFX.h>
#include <SPI.h>
#include "MyBitMap.h" //这里面定义了几张B站的logo bitmap数组
/*
* 选择软件SPI或者硬件SPI,硬件SPI会更快
*
*/
#define SCLK_PIN 18 //选择硬件SPI的话可以不定义,默认是18,选择软件SPI的话可随意定义
#define MOSI_PIN 23 //选择硬件SPI的话可以不定义,默认是23,选择软件SPI的话可随意定义
#define DC_PIN 27 //一定要定义
#define CS_PIN 5 //一定要定义
#define RST_PIN 15 //一定要定义
Adafruit_ST7789 mqtt_display = Adafruit_ST7789(CS_PIN, DC_PIN, RST_PIN); //选择硬件SPI
//Adafruit_ST7789 mqtt_display = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); //选择软件SPI
U8G2_FOR_ADAFRUIT_GFX my_u8g2;
const char* ssid = "xxx"; //你的WIFI名
const char* password = "xxxxxxxxx"; //你的WIFI密码
const char* mqtt_server = "192.168.xxx.xxx"; //树莓派的IP地址
const char *mqttUser="admin"; //登录MQTT服务器所需的用户名
const char *mqttPsw="1234"; //密码
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String BilibiliFan;
String str_year;
String str_time;
String temp;
int flag=1;
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
temp+=(char)payload[i];
}
int num_2 = temp.indexOf('|');
BilibiliFan = temp.substring(num_2+1);
int num = temp.indexOf(' ');
str_year = temp.substring(0,num);
str_time = temp.substring(num+1,num_2);
//Serial.printf("\r\nstr_time:%s",str_time);
Serial.println(str_year);
Serial.println(str_time);
Serial.println(BilibiliFan);
//u8g2_font_profont17_tf 这个字体可以画空格
my_u8g2.setFont(u8g2_font_profont29_mf); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
my_u8g2.setForegroundColor(BLUE); // apply Adafruit GFX color
my_u8g2.setCursor(45,20); // start writing at this position
my_u8g2.print(str_year);
my_u8g2.setFont(u8g2_font_profont22_mf); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
my_u8g2.setForegroundColor(WHITE); // apply Adafruit GFX color
my_u8g2.setCursor(70,50); // start writing at this position
my_u8g2.print(str_time+' '+' ');
my_u8g2.setForegroundColor(MAGENTA);
my_u8g2.setCursor(45,145);
my_u8g2.print("BiliBili:"+BilibiliFan+' '+' ');
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect("MYESP32",mqttUser,mqttPsw)) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe("esp32");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
mqtt_display.init(240, 240); //初始化屏幕
mqtt_display.setSPISpeed(80000000); //这里设置SPI速度,不过好像没什么用
my_u8g2.begin(mqtt_display);
Serial.println("ST7789-LCD Init!");
mqtt_display.fillScreen(BLACK);
//u8g2_font_helvR18_tf
my_u8g2.setFont(u8g2_font_helvR24_tf);
my_u8g2.setFontMode(1); // use u8g2 transparent mode (this is default)
my_u8g2.setFontDirection(0); // left to right (this is default)
my_u8g2.setForegroundColor(WHITE); // apply Adafruit GFX color
my_u8g2.setCursor(80,80); // start writing at this position
my_u8g2.print("MQTT");
my_u8g2.setFont(u8g2_font_helvR24_tf); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
my_u8g2.setForegroundColor(YELLOW); // apply Adafruit GFX color
my_u8g2.setCursor(50,120); // start writing at this position
my_u8g2.print("Raspiberry");
my_u8g2.setCursor(50,157);
my_u8g2.print("--> Esp32");
mqtt_display.drawBitmap(0,0,(uint8_t *)bilibili_bitmap_leftup,60,60,BLUE);
mqtt_display.drawBitmap(180,180,(uint8_t *)bilibili_bitmap_rightdown,60,60,MAGENTA);
mqtt_display.drawBitmap(171,0,(uint8_t *)bilibili_bitmap_rightup,69,60,CYAN);
mqtt_display.drawBitmap(0,180,(uint8_t *)bilibili_bitmap_leftdown,68,60,RED);
delay(2000);
mqtt_display.fillScreen(BLACK);
//时钟页面
mediabuttons();
mqtt_display.drawRoundRect(30,10,175,50,8,YELLOW);
mqtt_display.drawBitmap(85,68,(uint8_t *)BiliBili_1,60,60,MAGENTA);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
void mediabuttons() {
// play
mqtt_display.fillScreen(ST77XX_BLACK);
mqtt_display.fillRoundRect(30, 160, 78, 60, 8, ST77XX_WHITE);
mqtt_display.fillTriangle(47, 170, 47, 210, 95, 190, ST77XX_BLUE);
// delay(500);
// pause
mqtt_display.fillRoundRect(130, 160, 78, 60, 8, ST77XX_WHITE);
mqtt_display.fillRoundRect(144, 168, 20, 45, 5, ST77XX_GREEN);
mqtt_display.fillRoundRect(174, 168, 20, 45, 5, ST77XX_GREEN);
// delay(500);
}
没了,有什么问题可以留言
记录几个好用的网站:
各种类型的图像转化: https://www.online-utility.org/image_converter.jsp
图像(可有颜色)转bitmap数组 :http://javl.github.io/image2cpp/