跳至主要內容

得捷FollowMe第二期速通记录 - ESP32S3-Feather-TFT入门

A1exlindev大约 4 分钟计算机

成品图
成品图

任务 1 | 控制屏幕显示中文

要在板子上显示中文和其他自定义的字体,就需要往板子上上传对应的点阵字体,并利用相应的库来支持字体渲染。所幸Adafruit已经提供了现成的字体库,我们只需要安装相应的adafruit_bitmap_font库即可。

由于板子的存储空间受限,存储完整英文字体尚可,但存储完整中文字体则不太现实。我们需要先在电脑上制作字体的子集,随后转换成点阵字体上传到板子上。

制作用到了两个工具,分别是fonttools和otf2bdf。fonttools是一个Python库,可以用来处理字体文件,otf2bdf是一个命令行工具,可以将otf/ttf字体转换成bdf字体。

$ fonttools subset --text-file=subset.txt --output-file=target.otf font.otf

$ otf2bdf -p 32 -r 72 -o target.bdf target.otf    

即可根据输入的字库产生需要的中文字体子集。这次任务中,subset.txt中包含了天气API涉及的天气现象,和一些界面用到的字符。接下来是代码部分。

from adafruit_bitmap_font import bitmap_font

# 初始化并导入字体

f32 = bitmap_font.load_font("font/sf32.bdf")
f16 = bitmap_font.load_font("font/sf16.bdf")
fcn = bitmap_font.load_font("font/source.bdf")

# 显示中文
temp_label = label.Label(font=fcn, color = 0xaaaaaa, text="温度 ")

显示其他字体同理。笔者制作了苹果San Francisco字体的子集,用于显示界面上的英文字符。

任务 2 | 网络功能使用

使用网络同样只需要调用自带的WiFi库。

作为热点

作为热点在视频中没有演示,在这里另起一个项目展示这个功能。

连接Wifi

# network setup
print("connecting to wifi")
while not wifi.radio.connected:
    wifi.radio.connect(ssid="ssid", password="pwd")
    if wifi.radio.connected:
        break

    time.sleep(0.5)
    print("retrying...")
print("connected.")

pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())

连接wifi并创建requests对象后,便可以发起相应的网络请求。

任务 3 | 控制WS2812B

同样,调用board库和neopixel库即可方便的控制WS2812B。

首先,需要创建一个neopixel对象。

np = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)

然后,只需要利用fill方法,向对象传入一个(r,g,b)三元组,即可控制颜色。

if press is False:
    np.fill((0, 64, 0))

任务 4.1 | 日历&时钟

要显示日历和天气,需要寻找相应的开放API,查询相应的时间和天气信息,并将其显示在屏幕上。实现这些功能只需要用前面任务用到的知识。

查询信息

笔者用到了两个接口来查询。一个是worldtimeapi.org提供的时间查询,另一个是高德开放平台提供的天气查询。高德平台提供温度以及天气描述等信息,能够很方便地用于显示。当然,高德平台需要注册认证,有一定的调用限制,所以在编程时需要注意代码正确,避免意外滥用API.

首先,将板子连接到网络,初始化requests对象。然后根据API手册书写对应的查询函数。为了节约API调用次数,笔者创建了一个全局的dict对象,用于存储已经查询的相应字段。这样,在刷新屏幕的时候就不会发生过多的API调用。

调用API的查询代码如下

lut = "日一二三四五六"

def queryTime():
    r = json.loads(
        requests.get("http://worldtimeapi.org/api/timezone/Asia/Shanghai").text
    )

    s = r["datetime"].split("T")
    content["date"] = s[0]
    content["week"] = lut[r["day_of_week"]]
    time_tuple = s[1].split(":")
    content["time"] = time_tuple[0] + " : " + time_tuple[1]

def queryWeather(city : int):
    baseurl = "https://restapi.amap.com/v3/weather/weatherInfo"
    apikey = "secret!"

    url = baseurl + "?" + "city="+ str(city) + "&key=" + apikey + "&extensions=base"
    r = requests.get(url)
    response = json.loads(r.text)
    response = response["lives"][0]

    content["temp"] = response["temperature_float"]
    content["desc"] = response["weather"]

显示内容

将提前制作好的16px, 32px San Fransisco字体,以及16px思源黑体子集传送到板子上。为了让显示界面更美观,笔者还制作了一张背景图片。

利用display_text库和imageload库,可以很方便地在板子上显示文字和图片。

首先,要创建对象组,这是我们界面的画布。

text_group = displayio.Group()

然后,在最底层插入背景图

# back
image, palette = adafruit_imageload.load(
    "/img/background.bmp",
    bitmap = displayio.Bitmap,
    palette= displayio.Palette)
tile_grid = displayio.TileGrid(image, pixel_shader=palette)
text_group.append(tile_grid)

然后,逐个插入要显示的文字。标签较多,这里只展示一部分代码。

# tmp lable
temp_label = label.Label(font=fcn, color = 0xaaaaaa, text="温度 ")
temp_label.x = 10
temp_label.y = 20 + 32 + 10

tnum = label.Label(font=f16, color= 0xeeeeee, text=content["temp"] + "°")
tnum.y = temp_label.y
tnum.x = temp_label.x + temp_label.width + 10

text_group.append(temp_label)
text_group.append(tnum)

最后调用display.show(text_group)即可显示。

按钮控制

为节约API调用,笔者设置了每20秒刷新一次时间,每10分钟查询一次天气。在延迟较大时,笔者还设计了按按钮马上更新的功能。

# button
button = digitalio.DigitalInOut(board.BUTTON)
button.switch_to_input(pull=digitalio.Pull.UP)

def is_pressed():
    return button.value == False   

...
if is_pressed():
    ...

这些基本就是完成任务所需要的内容。

上次编辑于:
贡献者: Alexlin625