MENU

【ESP32/MicroPython】基于ESP32的博客状态监控器

2026 年 01 月 22 日 •

引子

单纯觉得我的ESP32吃灰太浪费了。纯纯伪需求。

那么,问题就来到了我的树莓派,What can I do with it?

功能

本次的小项目实现了这么几个功能:

  1. 通过ESP32连接Wi-Fi。
  2. 通过爬虫,检测博客是否宕机。
  3. 通过计时功能,每隔一个小时检测。
  4. 能够计算每天的宕机次数,并显示在一个八段数码管上。

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和若干杜邦线。

  1. 连接LED:随便找两个引脚,分别引出两根线,分别接到红绿LED的正极引脚,两个LED的负极引脚分别接到电阻上,然后接地。
  2. 连接数码管:我所使用的是5011AS共阴八段数码管,通过查询引脚图,则将3号和8号引脚接地,其余引脚连接到适当引脚即可。在ESP32中,大于34的引脚为纯输入引脚,所以需要选择34以内的引脚连接。
  3. 连接按键:我所使用的是四脚按键,这种按键长边的两个引脚是默认导通的,短边的两个引脚是不导通的,所以,可以在一个引脚上接一个电阻,随后接到ESP32的引脚上,另一个短边引脚则接地。

LED是为了显示「网络连接错误」和「正在验证博客状态」的,数码管是为了显示一天之内的宕机次数,而按键则是为了开启数码管,只有按下才开启数码管显示。

代码逻辑

代码逻辑其实很简单,可以分为以下几个部分:

  1. 初始化引脚。
  2. 连接Wi-Fi网络。
  3. 第一次检测网站是否宕机。
  4. 主循环:

    1. 检测按钮是否被按下。
    2. 检测时间是否满足要求。

初始化引脚

这里的操作很简单:

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)