本次任务是结合123,在手机上通过网络控制板载Neopixel LED的显示和颜色切换,屏幕同步显示状态。
本来我原计划采用APP Inventor配合板子进行TCP通讯实现任务要求的功能,但是这个只适合安卓手机,普适性差。后来看见坛友大佬ttxiaotaoge的帖子《【得捷电子Follow me第2期】CircuitPython入门到完成任务1-5详细教程》后,感觉这个网页的方法非常棒,只需浏览器就能操作,不挑系统,索性可耻的抄作业了。大佬帖子链接:
https://bbs.eeworld.com.cn/thread-1253916-1-1.html
抄作业第一步,就是学习分析代码。由于大佬用的板子不是这次官方要求的Adafruit ESP32-S3 TFT Feather,需要适配硬件参数。
第一步修改屏幕,这个改起来很简单,原来的屏蔽掉,直接用系统原配即可。如下代码。
然后添加WiFi连接,我猜测大佬的板子是支持WiFi记忆的,所以上电不需要再做连接设置。
接下来修改按键和RGB灯的配置信息,其中按键不要忘了设置上拉哦,如下图红框所示。
最后就是调整显示文字的格式,不然会显示不全。
代码改好后直接运行就OK了,效果如下图所示。
然后用电脑浏览器打开网址:
http://192.168.31.110:1080/client
就可在网页中改变RGB灯颜色了,如下图。
当然也可以在手机浏览器中打开这个网页,如下图。
最后的最后,我对代码进行小幅修改,删掉了天气和时间显示,只显示RGB灯的状态,录了一段视频,放在下面了。
感谢得捷电子和EEWORLD提供的这次机会,也希望在接下来的活动中,提供更多好玩的板子和题目,让大家一起快乐搞机。
具体代码如下。
import board
import digitalio
import terminalio
import busio
import neopixel
import rtc
import time
#网络相关库
import wifi
import socketpool
import ssl
import adafruit_requests
from adafruit_httpserver import Server, Request, Response, Websocket, GET
#显示相关库
import displayio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.label import Label
display = board.DISPLAY
board.DISPLAY.brightness = 0.5
board.DISPLAY.rotation = 0
my_display_group = displayio.Group()
print("Display Init Success\n")
# displayDriver_End
wifi.radio.connect('xxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxx')
print(f"My IP address: {wifi.radio.ipv4_address}")
# WiFi状态查询,未连接WIFI则不联网更新数据,开启AP模式
wificonnect_State = wifi.radio.connected
print("wificonnect_State",wificonnect_State)
if(wificonnect_State == False):
wifi.radio.start_ap(ssid = 'Esp32', password = '')
Wifi_Mode = 'STA' if(wificonnect_State == True) else 'AP'
Wifi_ip = wifi.radio.ipv4_address if(wificonnect_State == True) else wifi.radio.ipv4_address_ap
#构造函数——按键控制RGB
i = 0
Enter_flag = False
def Button0_Work():
global i
global Enter_flag
global RGBr, RGBg, RGBb
if(Button0.value == False and Enter_flag == False):
time.sleep(0.05)#延时消抖
if(Button0.value == False and Enter_flag == False):
i+=1
RGBr, RGBg, RGBb = 8*i, 8*i, 8*i
pixels.fill((RGBr, RGBg, RGBb))
Enter_flag = True
print("pixels change\n",i)
if(i>20):
i = 0
elif(Button0.value == True and Enter_flag == True):
time.sleep(0.05)#延时消抖
if(Button0.value == True and Enter_flag == True):
Enter_flag = False
# RGBDriver_Begin
pixel_pin = board.NEOPIXEL
num_pixels = 1
pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.2, auto_write=True)
pixels.fill((8, 8, 8))
print("RGBDriver Init Success\n")
# RGBDriver_End
# ButtonDriver_Begin
Button0 = digitalio.DigitalInOut(board.BUTTON)
Button0.direction = digitalio.Direction.INPUT
Button0.pull = digitalio.Pull.UP
print("Button0 Init Success\n")
# ButtonDriver_End
# 添加中文字体
font_file = "opposans_m_12.pcf"
font_Chinese = bitmap_font.load_font(font_file)
print("fonts Init Success\n")
# 显示WiFi IP 和 Mode
text_Wifi = "WiFi状态:{}\n{}:1080/client".format(Wifi_Mode,Wifi_ip)#更新RGB状态
text_Wifi_title = Label(font_Chinese, text=text_Wifi, color = 0xffffff)
text_Wifi_title.x = 5
text_Wifi_title.y = 10
my_display_group.append(text_Wifi_title)
# 显示RGB状态,和按键状态,RGB文字同RGB灯颜色
RGBr, RGBg, RGBb = 255,255,255
text_RGB = "RGB灯颜色:{:03}:{:03}:{:03}\n按键次数:{:02}".format(RGBr, RGBg, RGBb, i)#更新RGB状态
text_RGB_title = Label(font_Chinese, text=text_RGB, color = (RGBr, RGBg, RGBb))
text_RGB_title.x = 5
text_RGB_title.y = 70
my_display_group.append(text_RGB_title)
# ShowChinese_End
# GetandSetHttp_Begin
pool = socketpool.SocketPool(wifi.radio) # 网络管理,触发http操作
server = Server(pool, debug=True)
websocket: Websocket = None
next_message_time = time.monotonic()#数据更新时钟,以秒为单位变化
HTML_TEMPLATE = """
<html lang="en">
<head>
<!--注释:强制html使用utf-8编码-->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Web控制中心</title>
</head>
<body>
<p>按键状态: <strong>-</strong></p>
<p>RGB 颜色: <input type="color"></p>
<script>
const Button_count = document.querySelector('strong');
const colorPicker = document.querySelector('input[type="color"]');
let ws = new WebSocket('ws://' + location.host + '/connect-websocket');
ws.onopen = () => console.log('WebSocket connection opened');
ws.onclose = () => console.log('WebSocket connection closed');
ws.onmessage = event => Button_count.textContent = event.data;
ws.onerror = error => Button_count.textContent = error;
colorPicker.oninput = debounce(() => ws.send(colorPicker.value), 200);
<!--注释:创建一个延时函数,消除RGB调整抖动-->
function debounce(callback, delay = 1000) {
let timeout
return (...args) => {
clearTimeout(timeout)
timeout = setTimeout(() => {
callback(...args)
}, delay)
}
}
</script>
</body>
</html>
"""
#创建Http服务器
@server.route("/client", GET)
def client(request: Request):
return Response(request, HTML_TEMPLATE, content_type="text/html")
#创建websocket服务
@server.route("/connect-websocket", GET)
def connect_client(request: Request):
global websocket # pylint: disable=global-statement
if websocket is not None:
print("websocket.close")
websocket.close() # Close any existing connection
websocket = Websocket(request)
return websocket
#UI show Begin
display.show(my_display_group)
print("display show Success\n")
#UI show End
#判断网络模式,设定location.host
if(wificonnect_State == True):
server.start(str(wifi.radio.ipv4_address), port = 1080)
else:
server.start(str(wifi.radio.ipv4_address_ap), port = 1080)
# GetandSetHttp_Begin
time.sleep(2)#等待2秒进入循环
while True:
#httpSeverLoop_Begin
server.poll()
# Check for incoming messages from client
if websocket is not None:
if (data := websocket.receive(True)) is not None:
RGBr, RGBg, RGBb = int(data[1:3], 16), int(data[3:5], 16), int(data[5:7], 16)
pixels.fill((RGBr, RGBg, RGBb))
# Send a message every second
if websocket is not None and next_message_time < time.monotonic():
time.sleep(0.2)
if websocket is not None:
Button_count = i
websocket.send_message(str(Button_count))
next_message_time = time.monotonic() + 1
#httpSeverLoop_End
#Other_Loop
text_RGB_title.color = (RGBr, RGBg, RGBb)
text_RGB_title.text = "RGB灯颜色:{:03}:{:03}:{:03}\n按键次数:{:02}".format(RGBr, RGBg, RGBb, i)#更新RGB状态
Button0_Work()
实际效果如下视频。
还有一个问题,我的板子每次启动都先花屏一下,如下图,然后再正常显示,不知道是不是被修过的原因,已经收到板子的同学们,你们的板子有这个情况吗?
进入系统后,先清一下屏,可能就不会出现花屏的现象了。