引子
单纯觉得我的ESP32吃灰太浪费了。纯纯伪需求。
那么,问题就来到了我的树莓派,What can I do with it?
功能
本次的小项目实现了这么几个功能:
- 通过ESP32连接Wi-Fi。
- 通过爬虫,检测博客是否宕机。
- 通过计时功能,每隔一个小时检测。
- 能够计算每天的宕机次数,并显示在一个八段数码管上。
ESP32
首先我们来简单介绍一下ESP32究竟是什么,通俗来讲,ESP32就是一个「带有Wi-Fi、蓝牙功能的微型电脑」,可以通过「一些管脚控制其它的电子外设工作」。长这个样子:

如您所见,在电路板的两侧有两排引脚,可以输出数字信号,接收信号,并对信号进行处理。在下面,是一个Micro USB接口,可以连接电脑下载程序,也可以连接充电器作为供电接口。
MicroPython
嵌入式通常使用C语言进行开发,但是最近几年也出现了能够用Python语言进行开发的方法——MicroPython。MicroPython就是为嵌入式设备专门设计的一种Python语言,是常用Python语言的精简版,也增加了一些嵌入式设备独有的库。利用MicroPython开发,相比于C语言效率非常高,牺牲的是一部分性能和存储空间。
环境配置
安装Thonny,随后右下角-「配置解释器」,选择MicroPython(ESP32),选择好端口,然后点击「安装或更新MicroPython(esptool)」,然后根据自己板子的实际情况,填好相关内容,下载即可。
当写好Python文件时,只需要在Thonny中点击「视图-文件」,然后在写好的文件上右键,点选「上传到/」即可。在ESP32中,只有main.py才会在上电后直接运行。
接线
这边本来想用FritZing画一个面包板连线图的,但是没有找到板子的资料,姑且口述吧,这里也不是特别重要。
面包板上有这么几个东西:一个红色LED、一个绿色LED、一个八段数码管、三个适当阻值的电阻、一个按钮、一块ESP32和若干杜邦线。
- 连接LED:随便找两个引脚,分别引出两根线,分别接到红绿LED的正极引脚,两个LED的负极引脚分别接到电阻上,然后接地。
- 连接数码管:我所使用的是5011AS共阴八段数码管,通过查询引脚图,则将3号和8号引脚接地,其余引脚连接到适当引脚即可。在ESP32中,大于34的引脚为纯输入引脚,所以需要选择34以内的引脚连接。
- 连接按键:我所使用的是四脚按键,这种按键长边的两个引脚是默认导通的,短边的两个引脚是不导通的,所以,可以在一个引脚上接一个电阻,随后接到ESP32的引脚上,另一个短边引脚则接地。
LED是为了显示「网络连接错误」和「正在验证博客状态」的,数码管是为了显示一天之内的宕机次数,而按键则是为了开启数码管,只有按下才开启数码管显示。
代码逻辑
代码逻辑其实很简单,可以分为以下几个部分:
- 初始化引脚。
- 连接Wi-Fi网络。
- 第一次检测网站是否宕机。
主循环:
- 检测按钮是否被按下。
- 检测时间是否满足要求。
初始化引脚
这里的操作很简单:
if __name__ == "__main__":
# Init GPIOs
error_light_pin = 23
working_light_pin = 22
eight_a = 25
eight_b = 26
eight_c = 19
eight_d = 18
eight_e = 17
eight_f = 32
eight_g = 33
eight_dot = 16
button_monitor = 13
eight_a_led = Pin(eight_a, Pin.OUT)
eight_b_led = Pin(eight_b, Pin.OUT)
eight_c_led = Pin(eight_c, Pin.OUT)
eight_d_led = Pin(eight_d, Pin.OUT)
eight_e_led = Pin(eight_e, Pin.OUT)
eight_f_led = Pin(eight_f, Pin.OUT)
eight_g_led = Pin(eight_g, Pin.OUT)
eight_dot_led = Pin(eight_dot, Pin.OUT)
error_led = Pin(error_light_pin, Pin.OUT)
working_led = Pin(working_light_pin, Pin.OUT)
button = Pin(button_monitor, Pin.IN, Pin.PULL_UP)连接Wi-Fi
# Init Networks
SSID = "<YOUR WIFI SSID>"
PSWD = "<YOUR WIFI PSWD>"
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connection
print("Connecting to {SSID}")
wlan.connect(SSID, PSWD)
while not wlan.isconnected():
error_led.value(1)
time.sleep(1)
error_led.value(0)
print("Done.")WIFI通常有AP和STA模式,AP相当于热点,STA相当于客户端。
检测网站是否宕机
这里就使用HTTP状态码进行检测,逻辑如下:
def get_status_code():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36',
...
}
url = "https://www.coderlock.site"
rqg = requests.get(url, headers=headers)
return int(rqg.status_code)
def work(working_led):
fail_time = 0
working_led.value(1)
status_code = get_status_code()
if status_code != 200:
fail_time = 1
working_led.value(0)
return fail_time在主函数中:
fail_time = 0
print("Start Working!")
fail_time += work(working_led)检测按键是否被按下
我们的按键接地,所以在引脚内部要使用上拉输入,检测逻辑如下:
while True:
if button.value() == 0:
print("Button Pressed!")
num_list = show_num_list(fail_time % 10)
num_list.append(1 if fail_time > 10 else 0)
show_num(num_list, eight_a_led, eight_b_led, eight_c_led, eight_d_led, eight_e_led, eight_f_led, eight_g_led, eight_dot_led)
time.sleep(3)
show_num([0,0,0,0,0,0,0,0], eight_a_led, eight_b_led, eight_c_led, eight_d_led, eight_e_led, eight_f_led, eight_g_led, eight_dot_led)这里其实最好加一个防抖处理。我将dot位用作十位。
显示数字
显示数字没什么好说的,就是根据想要的数字,分别控制不同引脚的高电平,我们的是共阴数码管,所以给高电平是亮:
def show_num_list(num: int):
res = [0 for i in range(7)]
if num == 0:
res = [1,1,1,1,1,1,0]
elif num == 1:
res = [0,1,1,0,0,0,0]
elif num == 2:
res = [1,1,0,1,1,0,1]
elif num == 3:
res = [1,1,1,1,0,0,1]
elif num == 4:
res = [0,1,1,0,0,1,1]
elif num == 5:
res = [1,0,1,1,0,1,1]
elif num == 6:
res = [1,0,1,1,1,1,1]
elif num == 7:
res = [1,1,1,0,0,0,0]
elif num == 8:
res = [1,1,1,1,1,1,1]
elif num == 9:
res = [1,1,1,1,0,1,1]
else:
pass
return res
def show_num(num_list, eight_a_led, eight_b_led, eight_c_led, eight_d_led, eight_e_led, eight_f_led, eight_g_led, eight_dot_led):
eight_a_led.value(num_list[0])
eight_b_led.value(num_list[1])
eight_c_led.value(num_list[2])
eight_d_led.value(num_list[3])
eight_e_led.value(num_list[4])
eight_f_led.value(num_list[5])
eight_g_led.value(num_list[6])
eight_dot_led.value(num_list[7])检测时间
我设定的是一个小时检测一次:
curr_hour, curr_min, curr_sec = time.localtime()[3:6]
if curr_hour == 23:
fail_time = 0
if curr_min == 0 and curr_sec == 0:
print("Scanning...")
fail_time += work(working_led)完整代码
import network
from machine import Pin
import time
import requests
error_light_pin = 23
def led_on(led):
while True:
led.value(1)
time.sleep(1)
def show_num_list(num: int):
res = [0 for i in range(7)]
if num == 0:
res = [1,1,1,1,1,1,0]
elif num == 1:
res = [0,1,1,0,0,0,0]
elif num == 2:
res = [1,1,0,1,1,0,1]
elif num == 3:
res = [1,1,1,1,0,0,1]
elif num == 4:
res = [0,1,1,0,0,1,1]
elif num == 5:
res = [1,0,1,1,0,1,1]
elif num == 6:
res = [1,0,1,1,1,1,1]
elif num == 7:
res = [1,1,1,0,0,0,0]
elif num == 8:
res = [1,1,1,1,1,1,1]
elif num == 9:
res = [1,1,1,1,0,1,1]
else:
pass
return res
def show_num(num_list, eight_a_led, eight_b_led, eight_c_led, eight_d_led, eight_e_led, eight_f_led, eight_g_led, eight_dot_led):
eight_a_led.value(num_list[0])
eight_b_led.value(num_list[1])
eight_c_led.value(num_list[2])
eight_d_led.value(num_list[3])
eight_e_led.value(num_list[4])
eight_f_led.value(num_list[5])
eight_g_led.value(num_list[6])
eight_dot_led.value(num_list[7])
def get_status_code():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36',
...
}
url = "https://www.coderlock.site"
rqg = requests.get(url, headers=headers)
return int(rqg.status_code)
def work(working_led):
fail_time = 0
working_led.value(1)
status_code = get_status_code()
if status_code != 200:
fail_time = 1
working_led.value(0)
return fail_time
if __name__ == "__main__":
# Init LEDs
error_light_pin = 23
working_light_pin = 22
eight_a = 25
eight_b = 26
eight_c = 19
eight_d = 18
eight_e = 17
eight_f = 32
eight_g = 33
eight_dot = 16
button_monitor = 13
eight_a_led = Pin(eight_a, Pin.OUT)
eight_b_led = Pin(eight_b, Pin.OUT)
eight_c_led = Pin(eight_c, Pin.OUT)
eight_d_led = Pin(eight_d, Pin.OUT)
eight_e_led = Pin(eight_e, Pin.OUT)
eight_f_led = Pin(eight_f, Pin.OUT)
eight_g_led = Pin(eight_g, Pin.OUT)
eight_dot_led = Pin(eight_dot, Pin.OUT)
error_led = Pin(error_light_pin, Pin.OUT)
working_led = Pin(working_light_pin, Pin.OUT)
button = Pin(button_monitor, Pin.IN, Pin.PULL_UP)
# Init Networks
SSID = "<YOUR SSID HERE>"
PSWD = "<YOUR PSWD HERE>"
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connection
print("Connecting to {SSID}")
wlan.connect(SSID, PSWD)
while not wlan.isconnected():
error_led.value(1)
time.sleep(1)
error_led.value(0)
print("Done.")
# Init Time
fail_time = 0
print("Start Working!")
fail_time += work(working_led)
# Main Function
print("Looping!")
while True:
if button.value() == 0:
print("Button Pressed!")
num_list = show_num_list(fail_time % 10)
num_list.append(1 if fail_time > 10 else 0)
show_num(num_list, eight_a_led, eight_b_led, eight_c_led, eight_d_led, eight_e_led, eight_f_led, eight_g_led, eight_dot_led)
time.sleep(3)
show_num([0,0,0,0,0,0,0,0], eight_a_led, eight_b_led, eight_c_led, eight_d_led, eight_e_led, eight_f_led, eight_g_led, eight_dot_led)
curr_hour, curr_min, curr_sec = time.localtime()[3:6]
if curr_hour == 23:
fail_time = 0
if curr_min == 0 and curr_sec == 0:
print("Scanning...")
fail_time += work(working_led)