ภาพพื้นหลังปกบทเรียน

บทเรียน 4.2 — จอสถานะเครือข่าย: แกะโค้ดโมดูล wifi

WiFi และเครือข่ายพื้นฐาน · บอร์ดของเราออกจากโต๊ะทำงาน แล้วไปมีที่อยู่ในเครือข่าย

โมดูล 4 — เชื่อมต่อแพลตฟอร์ม IoT

ต่อจากบทเรียน 4.1 — WiFi และเครือข่าย: dBm DHCP IP และ DNS

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

เรื่องที่เราให้ 70% ผู้เรียนเขียน 30%

70% — เฟิร์มแวร์ + ไดรเวอร์ WiFi ทำให้แล้ว 30% — งานของเรา หกในแปดตัวของโมดูล wifi ที่โครงวันนี้เรียก wifi.scan() → list ของ tuple wifi.connect(ssid, pw) → bool wifi.is_connected() wifi.ip() wifi.status() wifi.ping(ip, timeout_ms) → ms หรือ -1 สิ่งที่เราต้องตัดสินใจเอง เลือกวงไหนจากที่สแกนเจอ · เรียงยังไง แปลง dBm เป็นภาพที่คนอ่านเข้าใจ ยิง ping ไปที่ไหน บ่อยแค่ไหน แปลผลเป็นข้อความที่ช่วยคนแก้ปัญหาได้

ไดรเวอร์ WiFi หนักกว่าโค้ดทั้งชุดบทเรียนนี้หลายพันบรรทัด — เราไม่ได้เขียนมัน เรา ใช้มันให้เป็น และนั่นคือทักษะที่ตรงกับงานจริงมากกว่า

โมดูล wifi มี แปดชื่อ ไม่ใช่หก — อีกสองตัวคือ wifi.disconnect() กับ wifi.softap() ซึ่งโครงหลักไม่ได้เรียก แต่เราจะลงมือทั้งคู่ในสไลด์ถัดไป เพราะตัวหนึ่งคือวิธีพิสูจน์ว่าลิงก์หลุดจริง และอีกตัวคือทางออกเมื่อในห้องไม่มีวงให้ต่อ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

สามข้อที่เฟิร์มแวร์ยังทำได้ไม่ครบ — ต้องรู้ก่อนเขียน

1 · wifi.status() มีช่อง ssid กับ rssi — แต่มันคืนค่าตายตัวเสมอ ssid คืนสตริงว่าง และ rssi คืน 0 ทุกครั้ง ไม่ว่าจะต่ออยู่กับวงไหน · ความแรงจริงต้องเอามาจาก wifi.scan() 2 · wifi.connect() ล็อกโหมดความปลอดภัยเป็น WPA3/WPA2 ตายตัว เครือข่ายเปิดไม่มีรหัสผ่าน ต่อจาก Python ไม่ได้ ทั้งที่เมนูบนจอต่อได้ · ถ้า AP ห้องเปิด ต้องขอวงที่มีรหัส 3 · หน้า Wi-Fi Setting ที่มากับเครื่อง แสดงค่าที่ "แต่งขึ้น" บางช่อง netmask ถูกฮาร์ดโค้ดเป็น 255.255.255.0 และ gateway/DNS ถูกเดาเป็น a.b.c.1 — ไม่ได้ถามระบบจริง ถ้าเฟิร์มแวร์เปิด wifi.ifconfig() ให้ โค้ดของผู้เรียนจะแม่นกว่าหน้าจอที่มากับเครื่อง

ข้อ 1 กับข้อ 2 เป็น กับดักที่ทำให้เสียเวลาทั้งบทเรียนถ้าไม่รู้ก่อน — จะนั่งแก้โค้ดที่ไม่ได้ผิด

ข้อ 3 เป็นเรื่องที่น่าสนใจกว่านั้น: หน้าจอที่ดูน่าเชื่อถือ อาจแสดงค่าที่ไม่ได้มาจากการวัดจริง การรู้ว่า ตัวเลขบนจอมาจากไหน คือส่วนหนึ่งของงานวิศวกรรม ไม่ใช่การจับผิด

ในโค้ดวันนี้เราก็เดาเกตเวย์เหมือนกัน — ต่างกันตรงที่เราจะ ping เพื่อพิสูจน์ ว่าเดาถูก แล้วแสดงผลตามความจริง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

โมดูล wifi ทั้งแปดชื่อ — ตารางที่เปิดค้างไว้ได้ทั้งบทเรียน

เรียกอย่างไร คืนอะไร สิ่งที่ต้องรู้ก่อนใช้
wifi.scan() list ของ tuple (ssid, rssi, security, channel) คืน ไม่เกิน 20 วง ต่อครั้ง วงที่ 21 หายไปเงียบ ๆ · บล็อก 3-10 วินาที · ถ้าบอร์ดกำลังสแกนของตัวเองอยู่ มันจะรอให้เสร็จก่อนแล้วค่อยถามใหม่ ไม่โยน error ใส่เรา
wifi.connect(ssid, password) True / False รับ สองอาร์กิวเมนต์แบบตำแหน่งเท่านั้น · บล็อกได้ถึงราว 85 วินาทีเมื่อรหัสผิด · ล็อกโหมดเป็น WPA3/WPA2 ตายตัว จึง ต่อวงเปิดที่ไม่มีรหัสผ่านจาก Python ไม่ได้
wifi.disconnect() None ตัดลิงก์แล้วบอกคอร์จอให้ลดไอคอนลง · เรียกตอนยังไม่เคยต่อก็ไม่ error เงียบ ๆ ผ่านไป
wifi.status() dict 5 คีย์ mode connected ip ssid rssi mode คืน "off" / "idle" / "sta" เป็นช่องเดียวที่บอกมากกว่า is_connected() · แต่ ssid คืนสตริงว่างและ rssi คืน 0 เสมอ ทั้งคู่เป็นค่าตายตัวในเฟิร์มแวร์
wifi.is_connected() True / False ถามสถานะจริงจากไดรเวอร์ทุกครั้ง ไม่ใช่ค่าที่จำไว้
wifi.ip() str ยังไม่ต่อจะได้ "0.0.0.0" ซึ่ง เป็นสตริงที่ไม่ว่าง จึงเป็นจริงใน if · ต้องเทียบค่าตรง ๆ ห้ามเขียน if wifi.ip():
wifi.ping(host, timeout=5000) int มิลลิวินาที หรือ -1 รับ เลข IP เท่านั้น ใส่ชื่อโฮสต์ได้ ValueError · ถ้ายังไม่ต่อเน็ตได้ OSError ไม่ใช่ -1
wifi.softap(ssid, password) True / False บอร์ดกลายเป็นตัวปล่อยสัญญาณเองที่ 192.168.4.1 · ไม่ใส่อาร์กิวเมนต์จะได้ชื่อ PSoC-Edge-MPY รหัส micropython · WPA2 ช่อง 1

หกแถวแรกคือของที่โครงหลักวันนี้เรียกจริง สองแถวล่างเราจะลองมือในสไลด์ถัดไป

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

สองตัวที่โครงหลักไม่ได้เรียก — และทำไมยังต้องรู้จัก

# --- disconnect(): วิธีพิสูจน์ว่า "หลุด" หน้าตาเป็นอย่างไรจริง ๆ ---
wifi.disconnect()                 # คืน None ไม่ใช่ True
print(wifi.is_connected())        # False
print(wifi.ip())                  # "0.0.0.0"  <- ไม่ว่าง จึงเป็นจริงใน if

# --- softap(): เมื่อหาวงที่ตั้งไว้ไม่เจอ บอร์ดปล่อยวงของตัวเองได้ ---
wifi.softap("bento-team01", "12345678")   # True แล้วบอร์ดอยู่ที่ 192.168.4.1
โหมด sta — ที่เราใช้กันทั้งบทเรียน บอร์ด AP ที่มีอยู่ บอร์ดไปขอเข้าร่วมวงที่มีอยู่แล้ว ได้เลข IP มาจาก DHCP ของ AP นั้น โหมด softap — บอร์ดเป็นเจ้าของวงเอง บอร์ด มือถือเรา บอร์ดอยู่ที่ 192.168.4.1 เสมอ ไม่ต้องเดา ไม่มีทางออกอินเทอร์เน็ต — คุยได้แค่ในวงนี้

disconnect() ทำให้เรา สร้างสถานะ "หลุด" ขึ้นมาดูได้ตามสั่ง ไม่ต้องรอให้เน็ตล่มเอง — บทเรียน 5.1–5.3 ต้องเขียนโค้ดที่ทนการหลุด ถ้าไม่เคยเห็นว่าหลุดแล้วค่าไหนเปลี่ยน จะเขียนเงื่อนไขถูกได้ยาก

softap() เป็นทางออกจริงเมื่อไม่มีวงให้ต่อ — เครื่องมือช่างและกล้องติดรถจำนวนมากตั้งค่าครั้งแรกด้วยวิธีนี้ ข้อแลกเปลี่ยนคือ วิทยุมีชุดเดียว เป็น AP แล้วจะเป็นลูกข่ายพร้อมกันไม่ได้ ping() ออกเน็ตจึงใช้ไม่ได้ในโหมดนี้ · ลองไฟล์ 07_disconnect_rejoin.py กับ 08_softap_fallback.py

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แกะโค้ดจริง — ท่าที่ 1 วางสองแผงให้ครบก่อนเข้าลูป

ui.screen()
time.sleep_ms(200)
ui.Label("สถานะเครือข่ายของทีม", x=24, y=8, color=COL_TEXT, value=24)
l_ssid = ui.Label("SSID: -", x=336, y=12, color=COL_TEXT, value=20)
l_ip = ui.Label("IP: -", x=24, y=48, color=COL_TEXT, value=20)
l_tick = ui.Label("กำลังสแกน", x=336, y=48, color=COL_DIM, value=20)
btn_scan = ui.Button("สแกนใหม่", x=552, y=8, w=216, h=88, color=0x3A4150, value=20)

tbl = ui.Table(x=24, y=104, w=480, h=288, cols=4)   # แถวละ 72 px: หัว + 3 แถว = 288
tbl.col_width(0, 144)        # กว้างพอสำหรับชื่อ 12 ตัวอักษร ซึ่งเป็นเพดานที่เราตัดไว้
tbl.col_width(1, 96)
tbl.col_width(2, 80)
tbl.col_width(3, 128)        # "มีรหัส" คือข้อความที่ยาวที่สุดในคอลัมน์นี้
SSID dBm ช่อง รหัส my-hotspot -48 6 มีรหัส Office-2.4 -67 1 มีรหัส Guest-Zone-1 -74 11 เปิด สถานะลิงก์ ต่ออยู่ ยังไม่ต่อ SSID · IP · ping x2 -48 dBm (84%) -90 -40 16 widgets จากเพดาน 64

ทุก widget ถูกสร้าง ก่อน เข้าลูป ในลูปแค่เปลี่ยนข้อความกับค่า · ตารางเดียวแทน ui.Label สิบตัว — col_width คือสิ่งเดียวที่ต้องตั้งให้ถูก ช่องแคบกว่าข้อความ = ตัดบรรทัด = แถวสูงสองเท่า แถวสุดท้ายตกขอบเงียบ ๆ · ปุ่ม สแกนใหม่ อยู่บนแถบหัวเรื่อง เพราะ มุมขวาล่างเฟิร์มแวร์ถือไว้ให้ปุ่ม Console widget ที่ไปทับมันจะถูกบังจนกดไม่โดน

16 widgets จาก 64 — เหลือที่ให้ทีมเติมของตัวเองได้อีกมาก

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แกะโค้ดจริง — ท่าที่ 2 มันคือ tuple ไม่ใช่ dict

# --- ท่าที่ 2 + 3 อยู่ในฟังก์ชันเดียว เพราะปุ่ม "สแกนใหม่" ต้องเรียกซ้ำได้ทั้งชุด ---
def rescan():
    nets = wifi.scan()                              # บล็อกราว 3-10 วินาที
    nets.sort(key=lambda net: net[1], reverse=True) # net[1] คือ rssi
ของจริงที่ scan() คืนมา ("my-hotspot", -48, 4, 6) net[0] = ssid net[1] = rssi net[2] = security net[3] = channel เรียงด้วย net[1] มากไปน้อย = แรงไปอ่อน สิ่งที่ตัวอย่างที่มากับเครื่องเขียนผิด net['ssid'] net['rssi'] TypeError: tuple indices must be integers, not str ชุดตัวอย่างที่มากับเฟิร์มแวร์ ไฟล์ network/01_wifi_scan_connect.py บรรทัด 33

sort() แก้ลิสต์เดิมในที่ · key=lambda net: net[1] สั่งให้เรียงตามช่องที่สอง · reverse=True ทำให้ค่ามากมาก่อน — RSSI ค่ามากคือแรงกว่า เพราะ −48 มากกว่า −79

ทำไมสองบรรทัดนี้ต้องอยู่ในฟังก์ชัน: ปุ่ม สแกนใหม่ ต้องทำงานทั้งชุด — สแกน เรียง ล้างตาราง เทใหม่ ถ้าปล่อยสองบรรทัดนี้ไว้กลางไฟล์ ปุ่มจะเรียกได้แค่ครึ่งเดียวของงาน

ตัวอย่างที่มากับเฟิร์มแวร์เขียนผิดจริง — ไฟล์ network/01_wifi_scan_connect.py บรรทัด 33 ยังเขียน net['ssid'] อยู่จนวันนี้ บทเรียนคือ โค้ดตัวอย่างไม่ใช่เอกสารอ้างอิง อย่าลอกไปใช้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แกะโค้ดจริง — ท่าที่ 3 เทลงตาราง แล้ววัดวงของทีมด้วย dBm

    tbl.clear_items()                           # ท่าที่ 3 (ยังอยู่ใน rescan)
    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()
    for ssid, rssi, security, channel in nets:  # แล้วค่อยขยับมาตรวัดฝั่งขวา
        if ssid == WIFI_SSID:                   # มาตรวัดเล่าเรื่องวงของทีมเอง
            pct, col = signal_of(rssi)
            bar_rssi.value(rssi)                # Bar รับพิสัย -90..-40 ตรง ๆ ได้
            l_rssi.color(col)
            l_rssi.text("ความแรง " + str(rssi) + " dBm (" + str(pct) + "%)")

q=clamp⁡ ⁣(RSSI−(−90)(−40)−(−90)×100,  0,  100)q=\operatorname{clamp}\!\left(\frac{\text{RSSI}-(-90)}{(-40)-(-90)}\times100,\;0,\;100\right) — ยืดช่วง −90 ถึง −40 dBm ให้เป็น 0 ถึง 100 เพื่อบอก คุณภาพเป็นเปอร์เซ็นต์ ข้างตัวเลข dBm · ตัวเลขจริง: −67 dBm → (−67+90)×2=46(-67+90)\times 2 = 46

−90 dBm = แท่งว่าง · −40 dBm = แท่งเต็ม · เลขในวงเล็บข้างค่า dBm คือคุณภาพเป็น % -48 dBm 84 -67 dBm 46 -86 dBm 8 แท่งกระเพื่อมเล็กน้อยตลอดเวลา เพราะคลื่นจริงไม่เคยนิ่ง — คนเดินผ่าน ประตูเปิดปิด ก็ทำให้เลขขยับได้ 3-5 dB

ui.Bar ไม่ต้องแปลงอะไรเลย เพราะตั้ง min=-90, max=-40 ได้ตรง ๆ — ที่ต้องแปลงคือเลขที่ คน จะอ่าน ไม่ใช่เลขที่ widget จะรับ · min(TOP_N, len(nets)) กันพังตอนสแกนเจอน้อยกว่าสามวง

signal_of() คืนทั้งเปอร์เซ็นต์และสีพร้อมกัน เพราะมาจากตัวเลขเดียว — แยกกันคำนวณเมื่อไร วันหนึ่งมันจะไม่ตรงกัน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แกะโค้ดจริง — ท่าที่ 4 บรรทัดที่บล็อกได้ 85 วินาที

l_tick.text("กำลังต่อ 85 วิ")            # ท่าที่ 4: บอกก่อน แล้วค่อยเรียกของที่บล็อก
ui.poll()
ok = wifi.connect(WIFI_SSID, WIFI_PASS)   # สองอาร์กิวเมนต์ตามลำดับเท่านั้น

if not ok:
    l_ssid.color(COL_BAD)
    l_ssid.text("ต่อไม่ติด")
    l_tick.text("ตรวจ SSID/รหัสผ่าน")
    ui.poll()
    raise SystemExit
...
led_up.value(1)                           # ต่อติดแล้วไฟดวงบนติด ดวงล่างหรี่
led_down.value(0)
เส้นเวลาของ wifi.connect() หนึ่งครั้ง 3-8 วิ รหัสถูก นานถึง 85 วินาที แล้วคืน False รหัสผิด · SSID พิมพ์ผิด · วงเป็นแบบเปิด ระหว่างนี้จอไม่อัปเดตเลย เพราะโค้ดของเราหยุดรอที่บรรทัดนี้ — จึงต้องเขียนข้อความบอกไว้ก่อนเรียก ยอมแพ้

wifi.connect() รับ สองอาร์กิวเมนต์แบบตำแหน่งเท่านั้น — ไม่มี timeout= ไม่มี security= · raise SystemExit เมื่อต่อไม่ติดคือการตัดสินใจที่ตั้งใจ เพราะท่าที่ 5 ไม่มีความหมายถ้าไม่มีลิงก์ — ล้มเร็วดีกว่าปล่อยให้ลูปวนแสดง timeout จนคนดูสับสน · สองบรรทัดสุดท้ายคือ สถานะลิงก์เป็นไฟ ไม่ใช่ตัวอักษรสี — แปลงภาพเป็นขาวดำแล้วตัวอักษรเขียว/แดงกลายเป็นเทาเหมือนกัน ส่วนไฟติดกับไฟหรี่ยังแยกออกด้วยความสว่างและตำแหน่ง

ในระบบฝังตัว ทุกบรรทัดที่บล็อกนานกว่าครึ่งวินาที ต้องมีการแจ้งผู้ใช้กำกับเสมอ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แกะโค้ดจริง — ท่าที่ 5 ลูปสถานะสด ยิงสองปลายทาง

while True:                                     # ท่าที่ 5 — ลูปเดินทุก 200 ms
    now = time.ticks_ms()
    events = ui.poll()                          # ลืมบรรทัดนี้ = widget หายใน 2 วิ
    for ev in events:                           # นิ้วมาถึงเมื่อไรก็รับได้ทันที
        if ev["type"] == "clicked" and ev["handle"] == btn_scan.id():
            l_tick.text("กำลังสแกน")            # บอกก่อน แล้วค่อยเรียกของที่บล็อก
            ui.poll()
            nets = rescan()
    if wifi.is_connected():
        if time.ticks_diff(now, t_ping) >= PING_EVERY_MS:   # ping เดินนาฬิกาตัวเอง
            t_ping = now
            try:
                ms_gw = wifi.ping(gw, PING_TIMEOUT_MS)
                ms_net = wifi.ping(NET_TEST_IP, PING_TIMEOUT_MS)
            except OSError:
                ms_gw, ms_net = -1, -1
            l_gw.text(ms_text("เกตเวย์", ms_gw))
    time.sleep_ms(200)

ลูปเดินทุก 200 ms แต่ ping เดินตามนาฬิกาของตัวเองทุก 3 วินาที — งานคนละจังหวะอยู่ในลูปเดียวกันได้ ถ้าแต่ละงานถามนาฬิกาเอง แทนที่จะใช้ sleep ยาว ๆ ขวางทาง · ถ้าเขียน sleep_ms(3000) ก้อนเดียว ปุ่มบนจอจะกดแล้วรอถึงสามวินาทีกว่าจะตอบ ซึ่งคนกดจะสรุปว่าปุ่มเสีย

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

แกะโค้ดจริง — ท่าที่ 5 (ต่อ) สองนาฬิกาในลูปเดียว

สถานะลิงก์ SSID: my-hotspot IP: 192.168.1.42 เกตเวย์ 3 ms อินเทอร์เน็ต 24 ms หรือ timeout ทุก 3 วินาที แต่ ui.poll() ทุก 200 ms ห้าม sleep_ms(3000) ก้อนเดียว ไม่งั้น widget หายภายใน 2 วินาที

try/except ครอบไว้เพราะ ความผิดพลาดชั่วคราวของเครือข่ายเป็นเรื่องปกติ ไม่ใช่ข้อยกเว้น · ส่วนตัวเลขนับถอยหลัง "วัดใหม่ใน N วิ" เขียนใหม่เมื่อ วินาทีเปลี่ยน เท่านั้น ไม่ใช่ทุกรอบลูป — ตัวเลขที่กระพริบห้าครั้งต่อวินาที คนอ่านไม่ทันและไม่มีใครได้ประโยชน์

ยิงเกตเวย์ก่อนแล้วค่อยยิงอินเทอร์เน็ต — ลำดับนี้ทำให้อ่านผลสองบรรทัดแล้วรู้ทันทีว่าขาดตรงไหน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

ข้อมูลไหลไปทางไหน — ตั้งแต่คลื่นถึงตัวเลขบนจอ

คลื่นในอากาศ 2.4 / 5 GHz CYW55513 ชิปวิทยุ + ไดรเวอร์ CM33 โค้ด Python ของเรา IPC กล่องจดหมาย CM55 → จอ Label + Bar ที่คนอ่าน RSSI หนึ่งค่า เดินทางผ่านห้าจุดกว่าจะเป็นแท่งสีบนจอ WiFi ทั้งหมดอยู่ฝั่ง CM33 เท่านั้น — CM55 แตะวงจรเครือข่ายไม่ได้เลย จอไม่ขึ้นเลข ไม่ได้แปลว่าเน็ตพัง ให้ไล่ดูว่าขาดตอนที่จุดไหน

เวลาดีบัก ให้ถามว่า "ขาดที่ช่วงไหนของห้าช่วงนี้" แล้วปัญหาจะเหลือแค่หนึ่งในห้า ไม่ใช่ทั้งระบบ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

วิธีรันบนบอร์ด

1 · เปิด Playground ค้างหน้านี้ไว้ตลอดบทเรียน 2 · แก้ SSID + รหัส สองบรรทัดบนสุดของไฟล์ 3 · เติม 6 ช่องว่าง ทีละจุด แล้วรันทุกครั้ง 4 · Program to Device แล้วมองจอบอร์ด สิ่งที่จะเห็นตามลำดับ — และห้ามตกใจ ตารางว่าง → นิ่ง 3-10 วิ (สแกน) → สามแถวขึ้นพร้อมกัน → นิ่งอีกครั้ง (ต่อ) → ไฟเขียวติด แล้ว ping เดิน

โครงหน้าจอถูกวางให้ต่อยอดจากแดชบอร์ดบทเรียน 3.7–3.9 ได้ทันที — ถ้าทีมอยากเอาการ์ด IMU กลับมาวางคู่กัน ให้ลด TOP_N จาก 3 เหลือ 2 แล้วตั้ง h ของตารางเป็น 216 (หัวตารางบวกสองแถว แถวละ 72) พื้นที่ที่ว่างขึ้นมาพอวางการ์ดเดิมได้

ถ้าจอค้างอยู่ที่ กำลังต่อ 85 วิ นานเกินหนึ่งนาทีครึ่ง ให้กด RESTART แล้วตรวจ SSID กับรหัสผ่านทีละตัวอักษร — อย่ารอต่อ

ระหว่างพิมพ์ตามทีละท่า จับเวลาและจดตัวเลขที่เห็นบนจอไว้ด้วย (ถ้าเรียนเป็นกลุ่ม สลับกันพิมพ์กับจด)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก AIoT in Action (AIC มหาวิทยาลัยบูรพา) · CC BY-NC 4.0

อ่านตารางนี้ให้ครบก่อนเริ่มเขียน แล้วผู้เรียนจะประหยัดเวลาไปได้มาก — กับดักเกินครึ่งของชุดบทเรียนนี้อยู่ในคอลัมน์ขวา ไม่ได้อยู่ในโค้ดที่เราเขียนผิด

ไฟล์ตัวหลัง (08_softap_fallback) คือแผนสำรองของทั้งคอร์ส ถ้าวันไหนบอร์ดหาวงที่ตั้งไว้ไม่เจอ

เจอ TypeError: tuple indices เมื่อไร ให้นึกถึงบรรทัดนี้ทันที — เกือบทุกครั้งคือเรื่องเดียวกัน