ข้ามไปยังเนื้อหา

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

โมดูล 4 — เชื่อมต่อแพลตฟอร์ม IoT · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร

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

เมื่อจบบทเรียนนี้ คุณจะ:

  1. บอกค่าที่คืนและกับดักของโมดูล wifi ได้ถูกอย่างน้อยหกในแปดชื่อจากตารางของบทเรียน เช่น wifi.ip() ตอนยังไม่ต่อคืน "0.0.0.0" ซึ่งเป็นจริงใน if · wifi.status() คืน ssid ว่างกับ rssi เป็น 0 เสมอ · wifi.ping() รับเฉพาะเลข IP และโยน OSError เมื่อยังไม่ต่อ
  2. อธิบายบรรทัด nets.sort(key=lambda net: net[1], reverse=True) ได้ว่าเรียงผล wifi.scan() ที่เป็น tuple จากแรงไปอ่อน บอกได้ว่าทำไม net['ssid'] จึงได้ TypeError และแปลง RSSI เป็นเปอร์เซ็นต์คุณภาพในพิสัย −90 ถึง −40 dBm ได้ถูก (−67 dBm ได้ 46%)
  3. อธิบายได้ว่าทำไมต้องเขียนป้ายสถานะแล้ว ui.poll() ก่อนเรียก wifi.scan() หรือ wifi.connect() ซึ่งบล็อกได้ 3–10 วินาทีและราว 85 วินาทีตามลำดับ และทำไมลูปจึง ui.poll() ทุก 200 ms แต่ให้ ping เดินตามนาฬิกาของตัวเองทุก 3 วินาทีด้วย time.ticks_diff() แทน sleep_ms(3000) ก้อนเดียว
  4. รัน 07_disconnect_rejoin.py และ 08_softap_fallback.py บนบอร์ดจริง แล้วจดลงบันทึกการเรียนได้ว่าค่าไหนเปลี่ยนเมื่อสั่ง wifi.disconnect() และบอร์ดอยู่ที่เลขอะไรกับทำอะไรไม่ได้เมื่อเป็น softap

ทบทวนบทเรียน 4.1: ห้าขั้นจากคลื่นถึงเลข IP กฎ 10 dB = 10 เท่า และการอ่าน ping เกตเวย์คู่กับ 8.8.8.8 เปิดไฟล์เฉลย s09_network_status.py ของบทเรียน 4.3 ไว้ข้าง ๆ เพราะบทเรียนนี้แกะไฟล์นั้นทีละท่า ก่อนรันไฟล์ 07 และ 08 แก้สองบรรทัดบนสุด WIFI_SSID กับ WIFI_PASS เป็น WiFi บ้านหรือ Hotspot มือถือของคุณ และในไฟล์ 08 เปลี่ยน AP_SSID ให้ไม่ซ้ำกับวงอื่นรอบตัว เช่นเติมชื่อเล่นภาษาอังกฤษของคุณ

  • อุปกรณ์: บอร์ด Eva Kit หรือ TESAIoT Dev Kit ที่ลงเฟิร์มแวร์ MicroPython ของ BENTO แล้ว หรือ BENTO Emulator ใน BENTO IDE (Emulator วาดหน้าจอของทั้งสองไฟล์ได้ แต่ชื่อวง ความแรง และสถานะลิงก์บนเครื่องโฮสต์เป็นค่าแทน ไม่ใช่ผลการวัดของบอร์ด การดูสถานะหลุดจริงจาก disconnect() และการปล่อยวงด้วย softap() จึงต้องใช้บอร์ดจริง)
  • เรียนมาก่อน: บทเรียน 4.1 — WiFi และเครือข่าย: dBm DHCP IP และ DNS

เราไม่ได้เขียนไดรเวอร์ WiFi เราใช้มันให้เป็น ไดรเวอร์หนักกว่าโค้ดทั้งชุดบทเรียนนี้หลายพันบรรทัด เฟิร์มแวร์ทำ 70% ส่วน 30% ที่เหลือเป็นการตัดสินใจของเรา: เลือกวงไหนและเรียงอย่างไร แปลง dBm เป็นภาพที่คนอ่านเข้าใจ ยิง ping ไปที่ไหน บ่อยแค่ไหน และแปลผลเป็นข้อความที่ช่วยคนแก้ปัญหาได้ โมดูล wifi มีแปดชื่อ โครงหลักเรียกหก (scan connect status is_connected ip ping) อีกสองตัว disconnect กับ softap เราลองมือในไฟล์ 07 และ 08

กับดักเกินครึ่งอยู่ในคอลัมน์ขวาของตาราง ไม่ได้อยู่ในโค้ดที่เราเขียนผิด wifi.scan() คืน list ของ tuple (ssid, rssi, security, channel) ไม่เกิน 20 วงต่อครั้ง และบล็อก 3–10 วินาที · wifi.connect(ssid, password) รับสองอาร์กิวเมนต์แบบตำแหน่งเท่านั้น บล็อกได้ถึงราว 85 วินาทีเมื่อรหัสผิด และล็อกโหมดเป็น WPA3/WPA2 จึงต่อวงเปิดที่ไม่มีรหัสผ่านจาก Python ไม่ได้ · wifi.status() คืน dict ห้าคีย์ แต่ ssid เป็นสตริงว่างและ rssi เป็น 0 เสมอ ความแรงจริงต้องเอามาจาก scan() · wifi.ip() ตอนยังไม่ต่อได้ "0.0.0.0" ซึ่งไม่ว่าง จึงเป็นจริงใน if คำถาม “ต่ออยู่ไหม” ต้องถามด้วย wifi.is_connected() ซึ่งถามไดรเวอร์ทุกครั้ง · wifi.ping() รับเฉพาะเลข IP ใส่ชื่อโฮสต์ได้ ValueError และถ้ายังไม่ต่อจะได้ OSError ไม่ใช่ −1 ส่วนหน้า Wi-Fi Setting ที่มากับเครื่อง ฮาร์ดโค้ด netmask เป็น 255.255.255.0 และเดา gateway กับ DNS เป็น a.b.c.1 การรู้ว่าตัวเลขบนจอมาจากไหน คือส่วนหนึ่งของงานวิศวกรรม โค้ดของเราก็เดาเกตเวย์เหมือนกัน แต่เรา ping เพื่อพิสูจน์

ห้าท่าของโค้ดจริง ท่าที่ 1 สร้าง widget ให้ครบก่อนเข้าลูป ใช้ ui.Table ตารางเดียวแทน Label สิบตัว และตั้ง col_width ให้พอกับข้อความ ช่องแคบกว่าข้อความจะตัดบรรทัดจนแถวสุดท้ายตกขอบเงียบ ๆ ปุ่ม สแกนใหม่ อยู่บนแถบหัวเรื่องเพราะมุมขวาล่างเฟิร์มแวร์ถือไว้ให้ปุ่ม Console ทั้งหน้าใช้ 16 จาก 64 widget · ท่าที่ 2 ผลสแกนเป็น tuple จึงอ่านด้วยเลขดัชนี net[1] คือ rssi เรียงแบบ reverse=True เพราะ −48 มากกว่า −79 ตัวอย่างที่มากับเฟิร์มแวร์ (network/01_wifi_scan_connect.py บรรทัด 33) ยังเขียน net['ssid'] อยู่ โค้ดตัวอย่างจึงไม่ใช่เอกสารอ้างอิง · ท่าที่ 3 เทลงตารางด้วย min(TOP_N, len(nets)) กันพังตอนเจอน้อยกว่าสามวง ui.Bar รับพิสัย −90 ถึง −40 ได้ตรง ๆ ส่วนเลขที่คนอ่านแปลงเป็นเปอร์เซ็นต์ $q=\operatorname{clamp}\left(\frac{\text{RSSI}+90}{50}\times100,0,100\right)$ และ signal_of() คืนเปอร์เซ็นต์กับสีพร้อมกัน เพราะมาจากตัวเลขเดียว

ท่าที่ 4 และ 5 คือเรื่องของเวลา บรรทัดที่บล็อกนานกว่าครึ่งวินาทีต้องมีป้ายแจ้งผู้ใช้กำกับเสมอ จึงเขียน l_tick.text("กำลังต่อ 85 วิ") แล้ว ui.poll() ก่อน wifi.connect() ถ้าต่อไม่ติดก็ raise SystemExit ล้มเร็วดีกว่าปล่อยให้ลูปวนแสดง timeout และสถานะลิงก์แสดงเป็นไฟสองดวง ไม่ใช่ตัวอักษรเขียวแดง ซึ่งกลายเป็นเทาเหมือนกันเมื่อดูแบบขาวดำ ในลูปสถานะสด ui.poll() ทุก 200 ms (ลืมเมื่อไร widget หายในราวสองวินาที) แต่ ping เดินตามนาฬิกาของตัวเองทุก 3 วินาทีด้วย time.ticks_diff(now, t_ping) ถ้าใช้ sleep_ms(3000) ก้อนเดียว ปุ่มจะกดแล้วรอถึงสามวินาทีกว่าจะตอบ try/except OSError ครอบ ping เพราะความผิดพลาดชั่วคราวของเครือข่ายเป็นเรื่องปกติ ยิงเกตเวย์ก่อนอินเทอร์เน็ตเพื่ออ่านผลสองบรรทัดแล้วรู้ว่าขาดตรงไหน และตัวเลขนับถอยหลังเขียนใหม่เฉพาะเมื่อวินาทีเปลี่ยน

RSSI หนึ่งค่าเดินทางผ่านห้าจุดกว่าจะเป็นแท่งบนจอ: คลื่นในอากาศ · ชิปวิทยุ CYW55513 กับไดรเวอร์ · โค้ด Python บน CM33 · กล่องจดหมาย IPC · CM55 ที่วาดจอ WiFi ทั้งหมดอยู่ฝั่ง CM33 เวลาดีบักให้ถามว่าขาดที่ช่วงไหนของห้าช่วงนี้

07_disconnect_rejoin.py ก่อนกด Run ให้ทายลงบันทึกการเรียนว่าตอนสั่งตัดแล้ว is_connected() ip() และ if wifi.ip(): จะตอบอะไร แล้วรันดูสี่บรรทัดบนเปลี่ยนค่าพร้อมกันผ่านสี่จังหวะ (ก่อนต่อ · ต่อแล้ว · สั่งตัด · ต่อกลับ) สังเกตว่า disconnect() คืน None และบรรทัด if wifi.ip(): ยังขึ้น True ทั้งที่หลุดสนิท ตอนต่อกลับให้ดูว่าได้ IP เดิมหรือไม่ เพราะ DHCP ให้ยืมเป็นครั้ง ๆ ลองแก้ DOWN_SECONDS ให้หลุดนานขึ้นแล้วรันซ้ำ

08_softap_fallback.py ไฟล์นี้สแกนก่อนแล้วค่อยตัดสินใจ ถ้าเจอวงที่ตั้งไว้ก็ต่อแบบลูกข่าย (โหมด sta) ถ้าไม่เจอก็ปล่อยวงเองที่ 192.168.4.1 ลองเปลี่ยน WIFI_SSID เป็นชื่อที่ไม่มีอยู่จริงรอบตัวเพื่อบังคับให้เข้าทางสำรอง แล้วเอามือถือต่อวงของบอร์ด ข้อแลกเปลี่ยนคือวิทยุมีชุดเดียว เป็น AP แล้วเป็นลูกข่ายพร้อมกันไม่ได้ ping() ออกเน็ตจึงใช้ไม่ได้ และถ้าไม่ใส่อาร์กิวเมนต์ บอร์ดทุกตัวจะชื่อ PSoC-Edge-MPY ซ้ำกันหมด ไฟล์นี้คือแผนสำรองของทั้งหลักสูตร ถ้าวันไหนบอร์ดหาวงที่ตั้งไว้ไม่เจอ

ไฟล์ ไฟล์นี้สอน
examples/07_disconnect_rejoin.py สร้างสถานะ “เน็ตหลุด” ขึ้นมาดูเองตามสั่ง
examples/08_softap_fallback.py ถ้าหาวงที่ตั้งไว้ไม่เจอ บอร์ดปล่อยวงของตัวเองได้

ภาพจอจาก BENTO Emulator ของตัวอย่างในบทนี้ (คลิกชื่อไฟล์เพื่อเปิดโค้ด)

จอของ examples/07_disconnect_rejoin.py ขณะรันใน BENTO Emulator: สร้างสถานะ "เน็ตหลุด" ขึ้นมาดูเองตามสั่ง
07_disconnect_rejoin.py สร้างสถานะ "เน็ตหลุด" ขึ้นมาดูเองตามสั่ง
จอของ examples/08_softap_fallback.py ขณะรันใน BENTO Emulator: ถ้าหาวงที่ตั้งไว้ไม่เจอ บอร์ดปล่อยวงของตัวเองได้
08_softap_fallback.py ถ้าหาวงที่ตั้งไว้ไม่เจอ บอร์ดปล่อยวงของตัวเองได้

คำถามชุดเดียวกันอยู่ใน quiz.yaml สำหรับระบบที่ตรวจอัตโนมัติ

  1. หลังเรียก wifi.disconnect() แล้ว โค้ดเขียนว่า if wifi.ip(): print(“ต่ออยู่”) จะเกิดอะไรขึ้น (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)

    • ก) ไม่พิมพ์ เพราะ ip() คืนสตริงว่างเมื่อหลุด
    • ข) พิมพ์ “ต่ออยู่” เพราะ ip() คืน “0.0.0.0” ซึ่งไม่ว่าง Python จึงถือว่าเป็นจริง
    • ค) ได้ OSError เพราะยังไม่ได้ต่อเน็ต
    • ง) ไม่พิมพ์ เพราะ ip() คืน None เหมือน disconnect()
    เฉลย

    ข — ตอนหลุด wifi.ip() คืน “0.0.0.0” ซึ่งเป็นสตริงที่ไม่ว่าง if จึงเป็นจริงทั้งที่เน็ตหลุดสนิท คำถาม “ต่ออยู่ไหม” ต้องถามด้วย wifi.is_connected() หรือเทียบสตริงตรง ๆ

  2. ข้อใดถูกเกี่ยวกับโมดูล wifi บนบอร์ดนี้ เลือกทุกข้อที่ถูก (เลือกได้หลายข้อ · เป้าหมายข้อ 1)

    • ก) wifi.status()[“rssi”] คืน 0 เสมอ ความแรงจริงต้องเอามาจาก wifi.scan()
    • ข) wifi.ping() ตอนยังไม่ต่อเน็ตคืน -1
    • ค) wifi.connect() ต่อวงเปิดที่ไม่มีรหัสผ่านจาก Python ไม่ได้ เพราะล็อกโหมดเป็น WPA3/WPA2
    • ง) wifi.connect(ssid, password, timeout=10000) ใช้ตั้งเวลารอให้สั้นลงได้
    • จ) wifi.scan() คืนไม่เกิน 20 วงต่อครั้ง วงที่เกินหายไปเงียบ ๆ
    เฉลย

    ก, ค, จ — ssid กับ rssi ใน status() เป็นค่าตายตัวในเฟิร์มแวร์ ping ตอนยังไม่ต่อโยน OSError ไม่ใช่ -1 และ connect() รับสองอาร์กิวเมนต์แบบตำแหน่งเท่านั้น ไม่มี timeout= ให้ตั้ง

  3. บรรทัด nets.sort(key=lambda net: net[1], reverse=True) ทำอะไรกับผลของ wifi.scan() (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)

    • ก) เรียงตามชื่อวงจาก Z ไป A
    • ข) เรียงตาม rssi จากค่ามากไปน้อย คือจากแรงไปอ่อน และแก้ลิสต์เดิมในที่
    • ค) เรียงตาม rssi จากอ่อนไปแรง เพราะ −79 มากกว่า −48
    • ง) คืนลิสต์ใหม่ที่เรียงแล้ว ส่วนลิสต์เดิมไม่เปลี่ยน
    เฉลย

    ข — net[1] คือช่องที่สองของ tuple (ssid, rssi, security, channel) คือ rssi และ reverse=True ให้ค่ามากมาก่อน RSSI ค่ามากคือแรงกว่าเพราะ −48 มากกว่า −79 ส่วน sort() แก้ลิสต์เดิมในที่

  4. ลูปสถานะสดต้องยิง ping ทุก 3 วินาที ทำไมโค้ดจึงไม่เขียน time.sleep_ms(3000) ก้อนเดียวท้ายลูป (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)

    • ก) เพราะ sleep_ms() รับค่าได้ไม่เกิน 1000
    • ข) เพราะต้อง ui.poll() ทุก 200 ms ให้ปุ่มตอบทันทีและ widget ไม่หาย ping จึงถามนาฬิกาเองด้วย ticks_diff
    • ค) เพราะ ping จะคืน -1 ถ้าเว้นช่วงนานเกินสองวินาที
    • ง) เพราะ wifi.connect() ต้องถูกเรียกซ้ำทุก 200 ms
    เฉลย

    ข — ถ้า sleep ก้อนเดียวสามวินาที ปุ่มจะกดแล้วรอถึงสามวินาทีกว่าจะตอบ และลืม ui.poll() นานเกินราวสองวินาทีเฟิร์มแวร์จะซ่อน widget งานคนละจังหวะจึงอยู่ในลูปเดียวกันได้ถ้าแต่ละงานถามนาฬิกาเอง

  5. จากไฟล์ 07 และ 08 ข้อใดถูก เลือกทุกข้อที่ถูก (เลือกได้หลายข้อ · เป้าหมายข้อ 4)

    • ก) wifi.disconnect() คืน None จึงห้ามเขียน if wifi.disconnect():
    • ข) ในโหมด softap บอร์ดอยู่ที่ 192.168.4.1 เสมอ
    • ค) ในโหมด softap บอร์ดยัง ping 8.8.8.8 ออกเน็ตได้ตามปกติ
    • ง) ต่อกลับหลังหลุดอาจได้ IP คนละเลขกับรอบแรก เพราะ DHCP ให้ยืมเป็นครั้ง ๆ
    เฉลย

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

อ่านโค้ดคู่กับตาราง แล้วพิสูจน์บนบอร์ด (ราว 20 นาที) จดลงบันทึกการเรียน

  • เขียนตารางแปดแถวของโมดูล wifi จากความจำ: ชื่อ · คืนอะไร · กับดักหนึ่งข้อ แล้วเทียบกับตารางในสไลด์
  • ในไฟล์เฉลย s09_network_status.py วงเลขท่าที่ 1 ถึง 5 ให้ครบ และขีดเส้นใต้ทุกบรรทัดที่บล็อกพร้อมป้ายที่ขึ้นก่อนมัน
  • คำนวณเปอร์เซ็นต์คุณภาพของ −48 · −67 · −86 dBm ด้วยมือ แล้วเทียบกับ 84 · 46 · 8
  • รันไฟล์ 07 บนบอร์ดจริง จดค่าของ is_connected() ip() และ status()['mode'] ทั้งตอนต่อและตอนหลุด
  • รันไฟล์ 08 บนบอร์ดจริงในทางสำรอง แล้วจดชื่อวง เลข IP ของบอร์ด และสิ่งที่มือถือทำได้กับทำไม่ได้

บทเรียน 4.3 ลงมือเติมช่องว่างในไฟล์ s09_network_status.py จนได้หน้าสถานะเครือข่ายของทีมครบทั้งสองแผง

บทเรียนถัดไป: บทเรียน 4.3 — ลงมือทำ: หน้าสถานะเครือข่ายของทีม

  • บั๊ก if wifi.ip(): หาเจอยากเพราะโค้ดดูถูกทุกบรรทัด ในงานของคุณมีค่าอะไรอีกที่ “ไม่ว่าง แต่ไม่ได้แปลว่ามีข้อมูล”
  • ถ้าต้องอธิบายให้คนที่ไม่ใช่วิศวกรฟังว่าทำไมจอนิ่งไป 85 วินาที คุณจะเขียนป้ายบนจอว่าอะไร
  • ตัวเลขบนหน้าจอที่มากับเครื่องบางช่องไม่ได้มาจากการวัด ระบบที่คุณเคยใช้มีตัวเลขแบบนี้ไหม และรู้ได้อย่างไร

คำถามทบทวน

ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย

  1. หลังเรียก wifi.disconnect() แล้ว โค้ดเขียนว่า if wifi.ip(): print("ต่ออยู่") จะเกิดอะไรขึ้น (เป้าหมายข้อ 1)

    1. ไม่พิมพ์ เพราะ ip() คืนสตริงว่างเมื่อหลุด
    2. พิมพ์ "ต่ออยู่" เพราะ ip() คืน "0.0.0.0" ซึ่งไม่ว่าง Python จึงถือว่าเป็นจริง
    3. ได้ OSError เพราะยังไม่ได้ต่อเน็ต
    4. ไม่พิมพ์ เพราะ ip() คืน None เหมือน disconnect()
    ดูเฉลย

    คำตอบ: B. พิมพ์ "ต่ออยู่" เพราะ ip() คืน "0.0.0.0" ซึ่งไม่ว่าง Python จึงถือว่าเป็นจริง

    ตอนหลุด wifi.ip() คืน "0.0.0.0" ซึ่งเป็นสตริงที่ไม่ว่าง if จึงเป็นจริงทั้งที่เน็ตหลุดสนิท คำถาม "ต่ออยู่ไหม" ต้องถามด้วย wifi.is_connected() หรือเทียบสตริงตรง ๆ

  2. ข้อใดถูกเกี่ยวกับโมดูล wifi บนบอร์ดนี้ เลือกทุกข้อที่ถูก (เป้าหมายข้อ 1)

    1. wifi.status()["rssi"] คืน 0 เสมอ ความแรงจริงต้องเอามาจาก wifi.scan()
    2. wifi.ping() ตอนยังไม่ต่อเน็ตคืน -1
    3. wifi.connect() ต่อวงเปิดที่ไม่มีรหัสผ่านจาก Python ไม่ได้ เพราะล็อกโหมดเป็น WPA3/WPA2
    4. wifi.connect(ssid, password, timeout=10000) ใช้ตั้งเวลารอให้สั้นลงได้
    5. wifi.scan() คืนไม่เกิน 20 วงต่อครั้ง วงที่เกินหายไปเงียบ ๆ
    ดูเฉลย

    คำตอบ: A. wifi.status()["rssi"] คืน 0 เสมอ ความแรงจริงต้องเอามาจาก wifi.scan() · C. wifi.connect() ต่อวงเปิดที่ไม่มีรหัสผ่านจาก Python ไม่ได้ เพราะล็อกโหมดเป็น WPA3/WPA2 · E. wifi.scan() คืนไม่เกิน 20 วงต่อครั้ง วงที่เกินหายไปเงียบ ๆ

    ssid กับ rssi ใน status() เป็นค่าตายตัวในเฟิร์มแวร์ ping ตอนยังไม่ต่อโยน OSError ไม่ใช่ -1 และ connect() รับสองอาร์กิวเมนต์แบบตำแหน่งเท่านั้น ไม่มี timeout= ให้ตั้ง

  3. บรรทัด nets.sort(key=lambda net: net[1], reverse=True) ทำอะไรกับผลของ wifi.scan() (เป้าหมายข้อ 2)

    1. เรียงตามชื่อวงจาก Z ไป A
    2. เรียงตาม rssi จากค่ามากไปน้อย คือจากแรงไปอ่อน และแก้ลิสต์เดิมในที่
    3. เรียงตาม rssi จากอ่อนไปแรง เพราะ −79 มากกว่า −48
    4. คืนลิสต์ใหม่ที่เรียงแล้ว ส่วนลิสต์เดิมไม่เปลี่ยน
    ดูเฉลย

    คำตอบ: B. เรียงตาม rssi จากค่ามากไปน้อย คือจากแรงไปอ่อน และแก้ลิสต์เดิมในที่

    net[1] คือช่องที่สองของ tuple (ssid, rssi, security, channel) คือ rssi และ reverse=True ให้ค่ามากมาก่อน RSSI ค่ามากคือแรงกว่าเพราะ −48 มากกว่า −79 ส่วน sort() แก้ลิสต์เดิมในที่

  4. ลูปสถานะสดต้องยิง ping ทุก 3 วินาที ทำไมโค้ดจึงไม่เขียน time.sleep_ms(3000) ก้อนเดียวท้ายลูป (เป้าหมายข้อ 3)

    1. เพราะ sleep_ms() รับค่าได้ไม่เกิน 1000
    2. เพราะต้อง ui.poll() ทุก 200 ms ให้ปุ่มตอบทันทีและ widget ไม่หาย ping จึงถามนาฬิกาเองด้วย ticks_diff
    3. เพราะ ping จะคืน -1 ถ้าเว้นช่วงนานเกินสองวินาที
    4. เพราะ wifi.connect() ต้องถูกเรียกซ้ำทุก 200 ms
    ดูเฉลย

    คำตอบ: B. เพราะต้อง ui.poll() ทุก 200 ms ให้ปุ่มตอบทันทีและ widget ไม่หาย ping จึงถามนาฬิกาเองด้วย ticks_diff

    ถ้า sleep ก้อนเดียวสามวินาที ปุ่มจะกดแล้วรอถึงสามวินาทีกว่าจะตอบ และลืม ui.poll() นานเกินราวสองวินาทีเฟิร์มแวร์จะซ่อน widget งานคนละจังหวะจึงอยู่ในลูปเดียวกันได้ถ้าแต่ละงานถามนาฬิกาเอง

  5. จากไฟล์ 07 และ 08 ข้อใดถูก เลือกทุกข้อที่ถูก (เป้าหมายข้อ 4)

    1. wifi.disconnect() คืน None จึงห้ามเขียน if wifi.disconnect():
    2. ในโหมด softap บอร์ดอยู่ที่ 192.168.4.1 เสมอ
    3. ในโหมด softap บอร์ดยัง ping 8.8.8.8 ออกเน็ตได้ตามปกติ
    4. ต่อกลับหลังหลุดอาจได้ IP คนละเลขกับรอบแรก เพราะ DHCP ให้ยืมเป็นครั้ง ๆ
    ดูเฉลย

    คำตอบ: A. wifi.disconnect() คืน None จึงห้ามเขียน if wifi.disconnect(): · B. ในโหมด softap บอร์ดอยู่ที่ 192.168.4.1 เสมอ · D. ต่อกลับหลังหลุดอาจได้ IP คนละเลขกับรอบแรก เพราะ DHCP ให้ยืมเป็นครั้ง ๆ

    บอร์ดมีวิทยุชุดเดียว เป็น AP แล้วเป็นลูกข่ายพร้อมกันไม่ได้ โหมด softap จึงไม่มีทางออกอินเทอร์เน็ต คุยได้เฉพาะกับเครื่องที่มาต่อวงของเรา

อ้างอิงบทเรียนนี้

ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน

"จอสถานะเครือข่าย: แกะโค้ดโมดูล wifi" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ข้อความอ้างอิงภาษาอังกฤษ: "The network status screen: reading the wifi code" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0

ลิงก์บทเรียน: https://tesaiot.github.io/tesa-qualification-program/courses/aiot-micropython/m04-iot-connectivity/l02-network-status-code/

บทเรียนนี้ดัดแปลงจากต้นฉบับด้านล่าง เมื่ออ้างอิงให้คงเครดิตต้นฉบับไว้ด้วย
https://github.com/Advance-Innovation-Centre-AIC/embedded-systems-for-aiot-developer/blob/a80bbe88a34bcb9bb8d991f42f9252b77cdab079/session-09.html (slides 17–28)

วิธีอ้างอิง TESA ฉบับเต็ม

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA