ต้องทำในบทเรียน · เปิดตามลำดับนี้ ทั้งชุดราว 29 นาที
| ลำดับ · เรื่อง · เวลา | ไฟล์ | ลงมือทำอะไร แล้วจะเข้าใจอะไร |
|---|---|---|
1 · scan() คืน tuple ไม่ใช่ dict · 6 นาที |
01_scan_tuples.py |
แกะสี่ช่องของแต่ละวงได้ถูกตั้งแต่บรรทัดแรก แทนที่จะเสียครึ่งบทเรียนกับ TypeError · จะเข้าใจว่าผลของ scan() เป็น tuple ไม่ใช่ dict จึงต้องอ่านด้วยลำดับช่อง ไม่ใช่ด้วยชื่อคีย์ |
| 2 · ป้ายสถานะขึ้นก่อนบรรทัดที่บล็อก · 8 นาที | 03_connect_says_first.py |
เขียนลำดับที่ทำให้จอไม่ดูเหมือนเครื่องค้าง ตอน connect() กินเวลาเป็นนาที · จะเข้าใจว่าป้ายสถานะต้องขึ้นก่อนบรรทัดที่บล็อกเสมอ ไม่ใช่หลังจากมันคืนค่า |
| 3 · หน้าจอสถานะลิงก์ที่วัดมาจริง · 15 นาที | 06_link_panel_hmi.py |
ประกอบ MVP ของชุดบทเรียนนี้ได้ครบ — SSID · IP · ping ms พร้อมสามสถานะที่แยกออกจากกัน · จะเห็นว่าหน้าจอสถานะลิงก์ที่เชื่อได้ ทุกตัวเลขบนนั้นต้องวัดมาจริง |
ไฟล์ที่ 3 ไม่มีแท่งความแรงสัญญาณ และนั่นตั้งใจ แท่งบนจอนั้นคือเวลา ping — ยาว = ช้า ตรงข้ามกับมาตรวัดความแรงในเฉลยที่มาจาก scan() ซึ่งเป็นคนละคำถามกัน เหตุผลอยู่ในหัวไฟล์ พร้อม path ของซอร์สที่ hardcode ค่าไว้
ติดตรงไหน เปิดอันนี้
| อาการที่เจอ | ไฟล์ที่ตอบอาการนั้น |
|---|---|
| ต่อติดแล้ว ได้ IP แล้ว แต่เปิดอะไรไม่ได้เลย | 04_ping_two_targets.py — วัดเกตเวย์กับ 8.8.8.8 พร้อมกัน แล้วบอกได้ว่าขาดตรงไหน |
เรียก status() หลายครั้งในรอบเดียว แล้วได้ภาพที่ไม่เคยเกิดจริง |
05_status_dict.py — อ่านครั้งเดียวต่อรอบ แล้วใช้ค่าชุดนั้นทั้งรอบ |
| ไม่รู้ว่าวงไหนอยู่ใกล้ที่สุด | 02_rank_by_rssi.py — เรียงจากแรงไปอ่อนด้วย dBm จริงจาก scan() |
อ่านเสริมนอกเวลา — เรื่องนี้อยู่นอกเกณฑ์ผ่านของบทเรียน 4.1–4.3 เพราะเช็กพอยต์ของชุดบทเรียนนี้วัดแค่ว่าหน้าจอสถานะอัปเดตสดได้ ยังไม่ได้วัดการฟื้นตัว: 03_reconnect_backoff.py ตอบคำถามถัดไปว่าลิงก์หลุดแล้วจะต่อใหม่อย่างไร ไม่ให้สามสิบบอร์ดถล่มเราเตอร์พร้อมกัน
| อาการ | สาเหตุที่แท้จริง | วิธีแก้ |
|---|---|---|
TypeError: tuple indices |
เขียน net['ssid'] หรือ net['rssi'] ตามตัวอย่างที่มากับเครื่อง |
ใช้ net[0] และ net[1] — scan() คืน tuple |
| ต่อไม่ติดทั้งที่ SSID ถูกและไม่มีรหัสผ่าน | connect() ล็อกโหมดเป็น WPA3/WPA2 ตายตัว ต่อวงแบบเปิดไม่ได้ |
ตั้งรหัสผ่านให้ Hotspot หรือเราเตอร์ (อย่างน้อย 8 ตัว) |
| จอนิ่งไปเป็นนาทีหลังกด Program | connect() บล็อกได้ถึง ~85 วินาทีเมื่อรหัสผิด |
รอจนขึ้นผล แล้วตรวจรหัสทีละตัวอักษร ไม่ต้องกดซ้ำ |
ValueError ตอนเรียก ping |
ใส่ชื่อโฮสต์ เช่น "google.com" |
wifi.ping() รับเฉพาะเลข IP |
| แถวเครือข่ายขึ้นแล้วหายไปใน 2 วิ | ลืม ui.poll() ในลูป หรือหน่วงยาวเป็นก้อนเดียว |
เรียก ui.poll() ทุกรอบ และให้ลูปเดินรอบละ 200 ms |
| ตารางสูงเกินจอ แถวสุดท้ายหาย | ข้อความในช่องยาวเกิน col_width แล้วถูกตัดบรรทัด แถวนั้นสูงเป็นสองเท่า |
ขยาย col_width ของคอลัมน์นั้น หรือย่อข้อความก่อนใส่ (เฉลยตัด SSID ที่ 12 ตัวอักษร) |
| กดสแกนใหม่แล้วแถวเก่ายังค้าง | ลืม tbl.clear_items() ก่อนเทแถวชุดใหม่ |
ล้างก่อนเสมอ แล้วใส่หัวตารางใหม่ทุกครั้ง เพราะการล้างลบหัวตารางไปด้วย |
| เปลี่ยนสีแท่งแล้วแท่งดูเต็มทั้งราง | .color() ของ ui.Bar ไปลงที่ราง ไม่ใช่แถบที่เต็ม |
อย่าเปลี่ยนสีแท่งตอนรัน ให้เปลี่ยนสีตัวเลขหรือใช้ ui.Led บอกสถานะแทน |
wifi.status() คืน ssid ว่าง rssi = 0 |
ทั้งสองช่องเป็นค่าตายตัวในเฟิร์มแวร์ | อ่านความแรงจาก wifi.scan() และเก็บ SSID ที่เราสั่งต่อไว้เอง |
| gateway timeout ทั้งที่ IP ขึ้นปกติ | เดาเลขเกตเวย์เป็น .1 แต่วงนี้ไม่ได้ใช้ .1 |
ดูเลข gateway จริงจากโน้ตบุ๊กที่ต่อวงเดียวกัน (ipconfig / ip route) แล้วแก้ค่าในโค้ด |
IndexError ตอนวาดแถวท้าย ๆ |
สแกนเจอน้อยกว่า TOP_N |
ใช้ min(TOP_N, len(nets)) เป็นขอบเขตลูป |
| ping เน็ต timeout ทุกครั้ง แต่ gateway ปกติ | ทางออกอินเทอร์เน็ตของวงมีปัญหา หรือถูกกรองไว้ | ไม่ใช่บั๊กของเรา — จดผลลงบันทึกการเรียนแล้วทำงานต่อได้ |
เจ็ดในสิบสองข้อนี้คือ ข้อจำกัดที่รู้ได้ล่วงหน้า ไม่ใช่ความผิดพลาดของโค้ด — สามข้อกลางตารางเป็นเรื่องของ
ui.Tableโดยเฉพาะ และทั้งสามข้อ ไม่มี error ให้จับ มีแต่จอที่ดูผิด
s09_network_status.py — ส่วนที่หนึ่งอ่านให้เข้าใจ แล้วพิมพ์เอง อย่าคัดลอกวาง
WIFI_SSID = "my-hotspot" # ชื่อ WiFi บ้านหรือ Hotspot มือถือของคุณ
WIFI_PASS = "changeme"
NET_TEST_IP = "8.8.8.8" # ปลายทางฝั่งอินเทอร์เน็ต
PING_TIMEOUT_MS = 1500
TOP_N = 3 # ตารางสูง 288 = หัวตารางบวกสามแถว แถวละ 72 พิกเซล
PING_EVERY_MS = 3000
RSSI_FLOOR, RSSI_CEIL = -90, -40 # พิสัยของมาตรวัด
def signal_of(rssi):
pct = (rssi - RSSI_FLOOR) * 100 // (RSSI_CEIL - RSSI_FLOOR)
pct = 0 if pct < 0 else (100 if pct > 100 else pct)
col = COL_RUN if rssi >= -60 else (COL_WARN if rssi >= -75 else COL_BAD)
return pct, col
เกณฑ์สี −60 / −75 หลวมกว่าเกณฑ์ห้าขีดของหน้าจอบอร์ด เพราะการ์ดของเรามีสามระดับ — เลือกเกณฑ์ให้เข้ากับสิ่งที่จะแสดง ไม่ใช่ลอกมาทั้งชุด · ระดับ "ปกติ" คืนสีฟ้า COL_RUN ไม่ใช่เขียว สถานะปกติต้องเงียบ สีจัดสงวนไว้ให้เรื่องผิดปกติ — จอที่ระบายเขียวทั้งจอฝึกให้ตามองข้ามสี แล้ววันที่มีเรื่องจริง สีแดงก็กลืนไปกับพื้นหลัง
ค่าที่ต้องแก้บ่อยอยู่บนสุด ตรรกะอยู่กลาง หน้าจออยู่ล่าง — โครงนี้ใช้ได้กับทุกสคริปต์ตั้งแต่บทเรียน 1.1–1.3
tbl = ui.Table(x=24, y=104, w=480, h=288, cols=4) # หัวตาราง + 3 แถว แถวละ 72 px
tbl.col_width(0, 144) # ช่องแคบกว่าข้อความ = ตัดบรรทัด = แถวสูงสองเท่า = แถวท้ายตกจอ
tbl.col_width(1, 96)
tbl.col_width(2, 80)
tbl.col_width(3, 128)
led_up = ui.Led(x=536, y=112, w=48, h=48, color=COL_OK, value=0) # ต่ออยู่
led_down = ui.Led(x=536, y=168, w=48, h=48, color=COL_BAD, value=1) # ยังไม่ต่อ
bar_rssi = ui.Bar(x=536, y=320, w=152, h=12, color=COL_RUN,
min=RSSI_FLOOR, max=RSSI_CEIL, value=RSSI_FLOOR)
sc_rssi = ui.Scale(x=536, y=340, w=152, h=44, color=COL_TEXT,
min=RSSI_FLOOR, max=RSSI_CEIL)
sc_rssi.ticks(11, 5) # 11 ขีด ป้ายเลขทุกขีดที่ 5 = เหลือสามป้าย ไม่ทับกัน
สามอย่างนี้แทนของเดิมทีละอย่าง และแต่ละอย่างมีเหตุผลที่วัดได้
| ของเดิม | ของใหม่ | เพราะ |
|---|---|---|
ui.Label เรียงกันห้าบรรทัด |
ui.Table สี่คอลัมน์ |
ตารางจัดคอลัมน์ให้เอง เราไม่ต้องนับพิกเซลทุกครั้งที่ข้อความเปลี่ยนความยาว |
| ตัวอักษรสีเขียว/แดงบอกว่าต่ออยู่ไหม | ui.Led สองดวง |
แปลงภาพหน้าจอเป็นขาวดำแล้วสีตัวอักษรหายหมด ส่วนไฟติดกับไฟหรี่ยังแยกออก |
| ตัวเลข dBm ลอย ๆ | ui.Bar ทับ ui.Scale |
ค่ากับพิสัยอยู่ด้วยกัน คนอ่านตอบได้ทันทีว่า −67 นี่ดีหรือแย่ |
ui.Scale ไม่รับ .value() มันคือไม้บรรทัด ตัวที่ขยับคือ ui.Bar ที่วางทับ (แบบวงกลมมีเข็มจริง — บทเรียน 3.1–3.3) · ui.Led สั่ง .value(0) แล้ว หรี่ ไม่ใช่หาย — ไฟที่หายไปตอนดับ ทำให้คนดูแยกไม่ออกว่าดับหรือจอเสีย
ทั้งสามตัวเป็นของใหม่ที่เพิ่มเข้าไลบรารีเมื่อ 15 ส.ค. 2026 —
09_scale_led_spinbox.pyสอนทั้งสามตัวแยกกันทีละตัว
def rescan(): # ปุ่ม "สแกนใหม่" เรียกซ้ำได้ทั้งชุด
nets = wifi.scan()
nets.sort(key=lambda net: net[1], reverse=True)
print("found", len(nets), "networks")
tbl.clear_items() # ล้างก่อน ไม่งั้นแถวเก่าค้างใต้แถวใหม่
tbl.add_row("SSID", "dBm", "ช่อง", "รหัส")
for i in range(min(TOP_N, len(nets))):
ssid, rssi, security, channel = nets[i]
tbl.add_row(ssid[:12], str(rssi), str(channel),
"เปิด" if security == 0 else "มีรหัส")
ui.poll()
security == 0 คือเครือข่ายแบบเปิด ค่าอื่นคือมีการเข้ารหัส — เขียนแค่ เปิด กับ มีรหัส เพราะโมดูลยังไม่มีค่าคงที่ให้เทียบ WPA2/WPA3 และเขียนเป็น คำ ไม่ใช่ระบายสี ภาพขาวดำก็ยังอ่านออก · ssid[:12] ตัดชื่อที่ยาวเกินคอลัมน์โดยตั้งใจ ราคาคือสองวงที่ขึ้นต้นเหมือนกันจะดูเหมือนกัน — ชื่อเต็มยังอยู่ที่ Console ทุกการตัดข้อมูลบนจอต้องรู้ตัวว่าตัดอะไร และต้องมีที่ให้ดูของเต็ม
reverse=Trueคือหนึ่งคำที่เปลี่ยนความหมายของทั้งหน้าจอ — ตรวจผลด้วยตาทุกครั้งหลังเรียงข้อมูล
nets = rescan() # ท่า 2 + 3 จบในบรรทัดเดียว และเรียกซ้ำได้
...
ok = wifi.connect(WIFI_SSID, WIFI_PASS)
...
ip = wifi.ip()
gw = gateway_of(ip) # เดาว่าเกตเวย์เป็น .1 ของวงเดียวกัน
led_up.value(1)
led_down.value(0)
...
while True:
now = time.ticks_ms()
events = ui.poll() # ท่า 5 — รับนิ้วทุก 200 ms
...
if wifi.is_connected():
...
ms_gw = wifi.ping(gw, PING_TIMEOUT_MS) # ยิงทุก 3 วิ ตามนาฬิกาของมันเอง
ms_net = wifi.ping(NET_TEST_IP, PING_TIMEOUT_MS)
ท่า 2 สแกน มาก่อนต่อ เพราะสแกนไม่ต้องใช้รหัสผ่าน — เจอวงแปลว่าวิทยุทำงาน · ท่า 3 แปลข้อมูล มาก่อนต่อเน็ต เพราะบั๊ก tuple/dict โผล่ตรงนี้ · ท่า 2 กับ 3 ถูกมัดเป็นฟังก์ชัน rescan() ตัวเดียว เพราะปุ่มบนจอต้องเรียกทั้งชุดซ้ำได้ — นั่นคือความต่างระหว่าง "สคริปต์ที่รันครั้งเดียว" กับ "หน้าจอที่คนใช้งานได้" · gateway_of() เดาเลขเกตเวย์เหมือนหน้าจอ C แต่เราไม่หยุดแค่เดา — ยิง ping เพื่อพิสูจน์
ไล่จากสิ่งที่พึ่งพาคนอื่นน้อยที่สุดไปหามากที่สุด — เป็นลำดับการดีบักมาตรฐานของงานฝังตัว
วันนี้เราได้: อ่าน RSSI เป็น dBm และเทียบกำลังได้ · แกะ tuple จาก wifi.scan() · ต่อเครือข่ายด้วย wifi.connect() โดยรู้ว่ามันบล็อก · วินิจฉัยลิงก์ด้วย ping สองปลายทาง · ประกอบทั้งหมดเป็นการ์ดสถานะบนหน้าจอเดิม
การบ้านของทีม: เลือกทำ 1 ข้อจากสี่ข้อในสไลด์ต่อยอด จดลงบันทึกการเรียน
ชุดบทเรียนถัดไป: บอร์ดจะเริ่ม ส่งข้อมูลออกไปจริง ๆ ด้วย MQTT — เปิดคอมพิวเตอร์อีกเครื่องแล้วเห็นค่าจากบอร์ดวิ่งขึ้นบนหน้าจอนั้น และสั่ง LED กลับมาที่บอร์ดได้
เก็บโค้ดวันนี้ไว้ให้ดี บทเรียน 4.4–4.6 เริ่มจากไฟล์นี้ต่อโดยตรง — เพิ่ม
mqttทับลงบนลิงก์ที่เราเพิ่งทำให้ทำงาน
ทั้งสี่มุมนี้ใช้ตัวเลขชุดเดียวกับที่ขึ้นบนจอบอร์ดวันนี้ ต่างกันแค่ว่าใครเป็นคนอ่านและตัดสินใจอะไรต่อ
สองคลิปนี้เป็นการบ้านแบบสมัครใจ เนื้อหาในบทเรียนเข้าใจได้ครบโดยไม่ต้องดู
อ่านต่อสำหรับคนอยากรู้ลึก — ทำไมเลข dBm ถึงติดลบ https://dongknows.com/wi-fi-signal-strength-dbm-explained/ · RSSI ต่างจาก dBm อย่างไร https://www.oscium.com/training/resources/understanding-rssi/ · 2.4 กับ 5 GHz ภาษาไทย https://www.asus.com/th/support/faq/1044838/
คลิปทั้งสองไม่อยู่ในเกณฑ์ผ่าน แต่คนที่ดูจะเข้าใจว่าทำไม
connect()ถึงใช้เวลาหลายวินาที
ข้อ 1 · แผนที่สัญญาณในบ้านหรือที่ทำงาน เดินถือบอร์ดไปห้าจุดที่ห่างจากเราเตอร์ต่างกัน จด RSSI ของ SSID เดียวกันพร้อมระยะโดยประมาณ วาดกราฟระยะเทียบ dBm แล้วอธิบายว่าทำไมของจริงแย่กว่าสูตร FSPL
ข้อ 2 · เครื่องวัดคุณภาพลิงก์ ยิง ping ไปที่เกตเวย์ 100 ครั้ง เก็บใน list แล้วหาค่าต่ำสุด เฉลี่ย สูงสุด และเปอร์เซ็นต์ที่ตอบไม่กลับ แสดงสี่ตัวเลขบนจอ · ทำไม "ค่าเฉลี่ยอย่างเดียว" ถึงหลอกเราได้
ข้อ 3 · ล่าเกตเวย์ตัวจริง ทดลอง ping .1, .254, .100 ของวงเดียวกันแล้วสรุปว่าอันไหนตอบ · เขียนสั้น ๆ ว่าถ้าเฟิร์มแวร์เปิด wifi.ifconfig() ให้ (ตอนนี้ยังไม่มี) โค้ดเราจะเปลี่ยนไปอย่างไร
ข้อ 4 · เฝ้าลิงก์สิบนาที ปล่อยโปรแกรมรันสิบนาทีโดยไม่แตะ นับครั้งที่ ping timeout และจดว่า RSSI เปลี่ยนไปกี่ dB แล้วสรุปว่าเครือข่ายนี้เชื่อถือได้แค่ไหน
เขียนคำตอบลงบันทึกการเรียน แล้วเอามาเล่าให้เพื่อนฟังต้นชุดบทเรียนถัดไป
แปดไฟล์ที่ผ่านมาดูแต่ตัวลิงก์ — สแกน ต่อ หลุด ต่อใหม่ 09_link_gates_a_real_reading.py เอาเซนเซอร์จริงมาต่อท้าย ให้เห็นว่าอะไรคือของที่รอส่ง และอะไรคือคนตัดสินว่าส่งได้หรือยัง
ค่าที่รอส่งคือ อุณหภูมิ อ่านผ่าน read_temp() ในไฟล์ — sensors.snapshot() ไม่มีช่องอุณหภูมิบนบอร์ดไหนเลย ไฟล์จึงถามก่อนว่าบอร์ดมี sensors.sht40 ไหม: บน Dev Kit ได้อุณหภูมิห้องจริง ส่วน บน Eva ไม่มีเซนเซอร์อุณหภูมิ ลูกบิดจึงเล่นบทแทน (0–100 % = 15–45 °C) และ console บอกไว้ตั้งแต่รอบแรกว่าค่ามาจากไหน — บทเรียนเรื่องคิวกับลิงก์เหมือนกันทั้งสองบอร์ด
กติกาข้อเดียวที่ต้องจำ — วัดกับส่งต้องแยกขาดจากกัน
| ทำอะไร | เมื่อไร | เพราะอะไร |
|---|---|---|
| วัด | ทุกรอบ ไม่ว่าเน็ตจะเป็นยังไง | เซนเซอร์ไม่ได้พังตอนเน็ตหลุด |
| เก็บใส่คิว | ทุกครั้งที่วัดได้ | ค่าที่วัดได้ตอนออฟไลน์ยังมีค่า |
| ส่ง | เมื่อลิงก์กลับมา และปล่อยทีละค่า | ปล่อยรวดเดียวคือการยิงรัวใส่ปลายทาง |
ถ้าเขียนว่า "วัดเมื่อเน็ตมา" ข้อมูลช่วงที่เน็ตหลุดจะหายไปตลอดกาล ทั้งที่เซนเซอร์ยังทำงานปกติ — และไม่มี error ให้จับสักตัว
09_link_gates_a_real_reading.py
แถบบนคือลิงก์ (ออนไลน์พร้อม IP หรือหลุด) · การ์ดซ้ายคืออุณหภูมิที่วัดได้รอบล่าสุด · การ์ดขวาคือ จำนวนค่าที่ค้างอยู่ในคิว — ตัวเลขที่เดินขึ้นตอนลิงก์หลุด และไหลออกทีละค่าเมื่อลิงก์กลับมา
ลองบนโต๊ะ: ปิด Hotspot หรือ WiFi ที่เราเตอร์สักครู่ แล้วดูเลขคิวเดินขึ้น เสียบกลับแล้วดูมันไหลออก
ui.Keyboard
10_keyboard_types_the_password.py สร้าง ชื่อวงในช่องซ้ายบนเครื่องโฮสต์เป็นค่าแทน บนบอร์ดจริงมันมาจาก wifi.scan()14 ส.ค. 2026 บอร์ดสแกนเจอ 18 วง และไม่มีวงที่ตัวอย่างใช้อยู่ในนั้นเลย (HARDWARE_CHECKLIST.md ข้อ 6 ของต้นฉบับ) บอร์ดทุกตัวค้างที่ป้าย "กำลังต่อ" พร้อมกัน เพราะ WIFI_SSID กับ WIFI_PASS เขียนตายอยู่ในไฟล์ทุกไฟล์ของบทเรียน 4.1–5.3 — ของจริงทุกตัวที่ต่อ WiFi ได้ ถามรหัสผ่านจากคน ไม่ได้ฝังมาจากโรงงาน
| ชิ้นส่วน | หน้าที่ |
|---|---|
ui.Textarea |
ช่องที่ตัวอักษรไปโผล่ |
ui.Keyboard |
แป้นพิมพ์เต็มบนจอ |
kb.bind(ta) |
บอกแป้นพิมพ์ว่าจะพิมพ์ลงช่องไหน — แป้นหนึ่งอันผูกได้ทีละช่องเดียว |
.prop(ui.PROP_PASSWORD, 1) |
โหมดดาว คนที่ยืนข้าง ๆ ไม่ควรอ่านรหัสออก |
สร้าง
Textareaก่อนKeyboardเสมอ —.bind()ไปยังแฮนเดิลที่ยังไม่ใช่ Textarea ถูก CM55 ปฏิเสธเงียบ ๆ
ui.Keyboard — เงียบจนกว่าจะขอ และอ่านกลับได้แล้วkb = ui.Keyboard(x=24, y=200, w=440, h=168, color=COL_TEXT)
kb.bind(ta_pass)
kb.listen("ready", "cancel")
...
pw = ta_pass.text()
| กติกา | สิ่งที่เกิดจริง |
|---|---|
| ไม่ขอ ไม่ส่ง | แป้นพิมพ์ไม่ส่ง event เองจนกว่าจะ kb.listen("ready", "cancel") — ปุ่มตกลงกับปุ่มปิดจึงรายงานกลับมา ค่าตั้งต้นคือเงียบ เพราะคิวเหตุการณ์มี 16 ช่อง |
| ตัวอักษรทีละตัวไม่ส่ง | และนั่นถูกแล้ว — สิ่งที่โปรแกรมต้องรู้คือข้อความทั้งช่อง ไม่ใช่ปุ่มทีละใบ |
อ่านกลับด้วย ta.text() ไม่ใส่อาร์กิวเมนต์ |
คืนสตริงที่อยู่ในช่องเดี๋ยวนั้น (GET_TEXT, opcode 0x6B ใน ipc_ui_protocol.h) — ไฟล์นี้จึงต่อด้วยรหัสที่พิมพ์จริง ไม่ใช่ค่าคงที่ |
จนถึง 15 ส.ค. 2026 ตาราง IPC_CMD_UI_* มี SET_TEXT (0x52) แต่ไม่มีคำสั่งอ่านกลับ หลักสูตรจึงเคยสอนว่า "สิ่งที่พิมพ์ คนอ่านได้ โปรแกรมอ่านไม่ได้" — ตอนนี้ไม่จริงแล้ว · ถ้าต้องประกอบสตริงจากปุ่มทีละใบด้วยเหตุผลอื่น ui.ButtonMatrix ยังทำได้ โดยส่ง value_changed พร้อมลำดับปุ่มกลับมา · อีกทางคือ SoftAP แล้วกรอกจากมือถือ ตาม 08_softap_fallback.py
เลขที่ทำให้ต้องคิดเรื่องนี้ตั้งแต่ออกแบบ — เป้าสัมผัสตามเกณฑ์คือ 88 พิกเซล แป้นพิมพ์มีสี่แถว 4 x 88 = 352 พิกเซล ซึ่งกินพื้นที่วาด 398 ไปเกือบหมด ปุ่มบนแป้นพิมพ์จึงเล็กกว่าเกณฑ์เสมอบนจอ 4.3 นิ้ว นี่เป็นข้อจำกัดของขนาดจอ ไม่ใช่ของ widget



เอกสารและมาตรฐาน
scan() connect() เหมือน Eva ทุกประการ (โค้ด modwifi.c เป็นชุดเดียวกัน)วิดีโอ (ตรวจแล้วว่าเปิดได้)
youtube.com/watch?v=WoUKXm9iG7kyoutube.com/watch?v=oD5nC2NhHWQyoutube.com/watch?v=ywkJepIQNIUyoutube.com/watch?v=vHIRmG_BzQIภาพจาก Wikimedia Commons (ตามลำดับที่ปรากฏ) TaBaZzz · Sss41 · Kirlf (สเปกตรัม 2.4 GHz และ 5 GHz ที่วัดจริง, CC BY-SA 4.0) · Michael Gauthier, Wireless Networking in the Developing World · Superspritz · Gelmo96 · Michel Bakni · Aaron Filbert · Moeenrahi — CC BY-SA 3.0/4.0 ทั้งหมด วางทั้งภาพพร้อมเครดิต ไม่ได้ครอปหรือแก้ไข
ไดอะแกรมที่เหลือวาดขึ้นใหม่สำหรับหลักสูตรนี้ · ข้อเท็จจริงของโมดูล wifi ตรวจจากซอร์ส modwifi.c ใน BENTO-TESAIoT-libraries ซึ่งเป็นโค้ดร่วมของทั้ง Eva Kit และ TESAIoT Dev Kit — แปดชื่อ เพดาน 20 วง และกับดักทุกข้อในตารางจึงเหมือนกันสองบอร์ด · หน้า Wi-Fi Setting บนหน้า Home ก็เป็นหน้าเดียวกันทั้งคู่
ทุกตัวเลขบนสไลด์นี้สืบกลับไปที่เอกสารต้นทางหรือซอร์สโค้ดได้ ถ้าเจอที่ไม่ตรง แจ้ง erratum ได้เลย

KIT_PSE84_EVAL_EPC2-MicroPython-BentoClaw/sim) ซึ่งรัน ipc_ui.c กับ ui_widget_mgr.c ตัวจริงเดียวกับบอร์ด บนพื้นที่วาด 792×398 (ขนาดเดียวกันบน Dev Kit) · แสดงหน้าจอที่ตัวอย่างสร้าง — หน้าจอของ 11_two_fields_one_keyboard.py · ค่าที่เห็นในภาพมาจากเซนเซอร์จำลองบนเครื่องโฮสต์ ไม่ใช่ผลการวัดของบอร์ดฟอร์มจริงมีมากกว่าหนึ่งช่อง แต่จอนี้ใส่แป้นพิมพ์ได้ใบเดียว — เหตุการณ์สองชนิดพอสำหรับทั้งฟอร์ม
| ชนิด | ใช้ทำอะไร |
|---|---|
focused |
รู้ว่าผู้ใช้แตะช่องไหน แล้วผูกแป้นพิมพ์ไปที่ช่องนั้น |
ready |
ผู้ใช้กดปุ่มตกลง — พิมพ์เสร็จแล้ว |
ta.text() ที่ไม่ใส่อาร์กิวเมนต์ อ่านสิ่งที่ผู้ใช้พิมพ์กลับมาได้ (GET_TEXT, opcode 0x6B) · ตัวอักษรแต่ละตัวที่แตะ ไม่ ส่งเหตุการณ์มาทีละตัว และนั่นถูกแล้ว — สิ่งที่โปรแกรมต้องรู้คือข้อความทั้งช่อง ไม่ใช่ปุ่มทีละใบ
แป้นพิมพ์ใบเดียวย้ายไปตามช่องที่ถูกแตะ —
focusedคือเหตุการณ์ที่บอกว่าต้องbind()ใหม่
อย่าเติมครบหกจุดแล้วค่อยรันทีเดียว — การสแกนกับการต่อเน็ตพังคนละแบบ แยกรันแล้วจะรู้ทันทีว่าใครพัง