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

ค่าออกไป คำสั่งกลับมา: MQTT บน broker สาธารณะ

โมดูล 1 — แอปพลิเคชันบนจอที่มีอยู่แล้ว · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร

ส่งค่าลูกบิดและค่าเอียงจริงจากบอร์ดออกไปที่ broker สาธารณะด้วย MQTT ให้หน้าเว็บของทีมอ่าน แล้วรับคำสั่งจากหน้าเว็บกลับมาสั่งเสียงและหลอดไฟบนบอร์ด โดยไม่เชื่อคนส่งเลยสักบรรทัด

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

  1. รัน 05_value_leaves_the_board.py จนบันไดสามขั้น (WiFi ได้ IP · ต่อ broker · publish) เป็นเขียวครบ และเห็นค่า knob กับ az บนหน้าเว็บของทีมขยับตามมือ หรือถ้าไม่ผ่าน บอกได้จากจอว่าหยุดที่ขั้นไหนและเพราะอะไร
  2. อธิบายกติกาสี่ข้อของ broker สาธารณะ (หัวข้อไม่ซ้ำใคร · ห้าม subscribe ทุกหัวข้อด้วย # · ห้ามส่งความลับ · client_id ต้องไม่ชน) และผลที่เกิดเมื่อฝ่าฝืนแต่ละข้อ
  3. รัน 06_command_comes_back.py แล้วสั่ง beep และ led จากหน้าเว็บได้ พร้อมอธิบายว่าทำไมต้องถาม get_message() ถี่ ๆ และทำไมข้อความที่ไม่ใช่ JSON หรือเลขดวงไฟที่บอร์ดไม่มีต้องจบลงที่ข้อความบนจอ ไม่ใช่โปรแกรมตาย
  4. เติม is_usable() ใน 03_your_link_rule.py ให้ตรวจครบทั้งต่ออยู่และมีเลข IP ที่ใช้ได้ จนตัวเลข “กฎคุณรายงาน” เท่ากับ “ควรรายงาน” คือ 2 แล้วอธิบายได้ว่าเมื่อเปลี่ยน NEED เป็น 5 เราพลาดปัญหาช่วงไหนไป

ต้องผ่านไฟล์ 01 ของบทเรียน 1.4 มาแล้ว คือบอร์ดต่อ Hotspot ของทีมได้และมีเลข IP และตั้งรหัสสำหรับ TEAM ไว้ก่อน: ตัวอักษรอังกฤษตัวเล็กกับตัวเลข ยาว 4–16 ตัว ไม่ซ้ำใคร เช่นชื่อเล่นต่อด้วยเลขสุ่ม 4 หลัก (nok4821) เพราะผู้เรียนคนอื่นก็ใช้ broker สาธารณะและหัวข้อชุดเดียวกัน (ถ้าเรียนเป็นกลุ่ม ใช้เลขทีมที่ผู้จัดแจก) ในไฟล์ 05 และ 06 แก้สามบรรทัดบนสุด WIFI_SSID WIFI_PASS TEAM (ส่วน BROKER ตั้งไว้แล้ว) ถ้าลืมแก้ TEAM ไฟล์จะหยุดตั้งแต่ขั้นแรกพร้อมบอกบนจอ บนโน้ตบุ๊กหรือมือถือ เปิดหน้า my_first_reader.html แล้วต่อท้ายลิงก์ด้วย ?team= ตามด้วยรหัสเดียวกับ TEAM ไม่ต้องติดตั้งอะไร (หน้าที่เผยแพร่บนเว็บ AIC รับเฉพาะรูป teamNN ถ้าใช้รหัสของตัวเอง ให้ดาวน์โหลด shared/web/my_first_reader.html ของรีโพนี้ไปเปิดแทน) ความจริงที่ต้องรู้ก่อน: เวลาไปกลับของ broker วัดแล้วจาก Mac บนโต๊ะผู้สอน (188-191 ms) แต่ ยังไม่มีใครรันไฟล์ 05 กับ 06 บนบอร์ดกับ broker นี้ และยังไม่รู้ว่าเน็ตขององค์กรปล่อยพอร์ต 1883 กับ 8884 ออกไปหรือไม่

  • อุปกรณ์: บอร์ด Eva Kit หรือ TESAIoT Dev Kit ที่ลงเฟิร์มแวร์ MicroPython ของ BENTO แล้ว หรือ BENTO Emulator ใน BENTO IDE (Emulator ใน ide.tesaiot.dev ต่อ broker จริงผ่าน wss 8884 ได้แล้ว เติม -emu ท้าย client_id เองจึงไม่เตะบอร์ดจริงของทีม และถ้าต่อไม่ได้ภายใน 5 วินาทีจะถอยไปใช้ broker จำลองในตัวพร้อมบอกใน Console)
  • เรียนมาก่อน: บทเรียน 1.4 — บอร์ดออกจากโต๊ะ: ต่อ WiFi ครั้งแรก

รัน 05_value_leaves_the_board.py แล้วดูบันไดสามขั้นบนจอบอร์ดไล่จากเทาเป็นเขียว จากนั้นหันไปที่หน้าเว็บของทีม คนหนึ่งหมุนลูกบิด อีกคนเอียงบอร์ด แล้วดูเลข knob กับ az บนหน้าเว็บขยับตาม นี่คือค่าจริงที่เพิ่งออกจากโต๊ะนี้ไป ไม่ใช่ตัวเลขสุ่มที่ใครก็เถียงได้ จดว่าหน้าเว็บเห็นใบแรกที่ n เท่าไร ถ้าขั้นไหนเป็นแดง อ่านเหตุผลบนจอแล้วจดไว้ ผลแบบนั้นก็ยังเป็นผลที่ใช้ได้

ข้อความวันนี้เดินสองทางและใช้คนละพอร์ต บอร์ดพูด MQTT ธรรมดาที่พอร์ต 1883 ส่วนหน้าเว็บเปิดสาย TCP ดิบไม่ได้ จึงพูด MQTT ผ่าน WebSocket ที่ wss://broker.hivemq.com:8884/mqtt ทั้งสองทางลงหัวข้อชุดเดียวกัน broker ส่งต่อให้เองโดยไม่สนว่าแต่ละฝั่งมาทางไหน broker นี้เป็นของสาธารณะ ไม่มีรหัสผ่าน ใครรู้ชื่อหัวข้อก็อ่านและเขียนได้ทันที จึงมีกติกาสี่ข้อ: หัวข้อต้องไม่ซ้ำใคร (bento-aiot/<ทีม>/telemetry และ .../cmd) · ห้าม subscribe # เพราะเท่ากับขอรับข้อความทั้งโลก · ห้ามส่งความลับ เพราะทุกใบวิ่งแบบไม่เข้ารหัส · client_id ชนได้กับทุกคนบนอินเทอร์เน็ต และเมื่อชน broker จะเตะตัวเก่าออกโดยไม่มีข้อความเตือน ไฟล์จึงตั้ง DEVICE_ID = "bento-aiot-" + TEAM

05 คือบันไดสามขั้นที่ห้ามสลับ: WiFi ต้องได้ IP ก่อน แล้ว mqtt.connect(BROKER, port=1883, client_id=DEVICE_ID, keepalive=60) จึงแนะนำตัวกับ broker ได้ แล้ว mqtt.publish(TOPIC, body) จึงส่งของได้ ขั้นไหนไม่ผ่านจะเป็นแดงพร้อมเหตุผล แล้วโปรแกรมจบอย่างสุภาพ ไม่ค้างเงียบ นี่คือแบบที่โปรแกรมหน้างานต้องเขียน ค่าที่ส่งเป็นค่าจริงจาก sensors.snapshot() (ลูกบิด กับค่าเร่งแกน z จาก BMI270) ถามด้วย in ก่อนหยิบคีย์ และใช้ -1 กับ -99 บอกว่ารอบนั้นอ่านไม่ได้ json.dumps() แปลง dict ของเราเป็นข้อความที่ทุกภาษาอ่านออก กับดักมีสองข้อ: ชื่ออาร์กิวเมนต์คือ username= ไม่ใช่ user= (ผิดได้ TypeError ทันที) และ publish() ตอนสายหลุดไม่คืน False แต่โยน OSError ต้องดักทั้งสองทาง เฟิร์มแวร์ส่งแบบ retain ไม่ได้ หน้าเว็บที่เปิดช้าเห็นแค่ใบถัดไป ไฟล์จึงส่ง 60 ใบ ใบละ 2 วินาที ระวังเครือข่ายที่ต้อง login ผ่านหน้าเว็บ: wifi.connect() คืน True และได้เลข IP ตามปกติ แต่นาฬิกาบนแถบบนไม่ขึ้น และ mqtt.connect() ไปไม่ถึง broker ไอคอน WiFi บนแถบบนตอบว่า “ต่อเครือข่ายได้” ส่วนนาฬิกาที่โผล่ตามมาตอบว่า “ออกอินเทอร์เน็ตได้จริง”

06 เติมทางกลับให้ครบวง mqtt.subscribe(TOPIC_CMD) ต้องมาหลัง connect() เสมอ และต้องทำซ้ำถ้าสายหลุดแล้วต่อใหม่ mqtt.get_message() ไม่บล็อก คืน None ทันทีเมื่อยังไม่มีอะไรมา ลูปจึงต้องถามซ้ำถี่ ๆ (POLL_MS = 100) เพราะกล่องรับมีช่องเดียว ใบที่มาถึงก่อนเราหยิบใบเก่าจะทับใบเก่าทิ้งไป ไม่ได้ต่อคิว นี่คือคำตอบของเกมส่งข้อความพร้อมกันทั้งห้องในบทเรียน 1.4 ข้อความที่ได้เป็น (topic, payload) โดย payload เป็น bytes ต้อง .decode() ก่อน json.loads() บอร์ดรู้จักสามคำสั่ง beep led say ครึ่งหนึ่งของไฟล์คือ การไม่เชื่อคนส่ง: ข้อความที่ไม่ใช่ JSON, JSON ที่ไม่ใช่ object, เลขดวงไฟที่บอร์ดนี้ไม่มี และข้อความยาวเกินป้าย ทั้งหมดต้องจบที่ข้อความบนจอ ก่อนจบไฟล์ปิดไฟทุกดวงเสมอ 05 คู่กับ 06 คือวงจรที่ปิดครบ งานของเราไม่ใช่เรื่องคลื่นหรือโปรโตคอล เพราะเฟิร์มแวร์ทำให้หมดแล้ว งานของเราคือตัดสินใจว่าจะส่งอะไรออกไป และจะยอมรับคำสั่งอะไรกลับมา

03 เป็นคู่ฝึกของ 02 ในบทเรียน 1.4 แต่ไม่ต้องต่อเน็ตจริง มันเล่นเทปผลตรวจลิงก์ 24 รอบที่บันทึกจากบอร์ดจริง รันซ้ำกี่รอบก็ได้ผลเดิม กฎที่ทดสอบซ้ำไม่ได้คือกฎที่ยังไม่รู้ว่าถูก ลิงก์ที่ใช้ได้จริงต้องต่ออยู่ และ มีเลข IP ที่ใช้ได้ กับดัก "0.0.0.0" จากไฟล์ 01 กลับมาในรูปโจทย์ เพราะลิงก์ที่ไม่มี IP คือลิงก์ที่ publish() ไปไม่ถึงไหน โค้ดรายงานเมื่อ bad_streak == NEED (ใช้ == ไม่ใช่ >= เพื่อให้ได้บรรทัดเดียวตอนเริ่มเสีย) ส่วน 07 เป็นการอ่านนอกเวลา: คลังค่าตั้งของ tesaiot อยู่บนแฟลช ถอดไฟแล้วยังอยู่ แต่ tesaiot.connect() ต่อแบบ TLS ที่พอร์ต 8883 หรือ 8884 เสมอ ไม่อ่านคีย์ port และไม่บล็อก ค่าที่คืนแปลว่า “รับคำสั่งแล้ว” ไม่ใช่ “ต่อได้แล้ว” วันนี้จึงต่อ broker.hivemq.com ไม่ได้

สไลด์เรียงต่อจากบทเรียน 1.4 ดังนี้: 05_value_leaves_the_board.py (ราว 25 นาที) → 06_command_comes_back.py (ราว 25 นาที) → 03_your_link_rule.py (ราว 20 นาที) ส่วน 07_platform_in_one_call.py เป็นการอ่านนอกเวลา ความช่วยเหลือลดลงทีละขั้น: 05 กับ 06 คือของจริงเต็มวง ส่วน 03 กับ 07 คุณตัดสินใจเอง ก่อนรัน 06 ด้วย POLL_MS = 3000 ให้ ทำนายก่อน ว่ากดปุ่มสามครั้งรวดในวินาทีเดียวจะขึ้นกี่ใบ แล้วค่อยนับเทียบ ใน 03 จอบนบอร์ดคือเฉลย แก้แล้วรันใหม่จนเลขสองตัวตรงกัน ไม่ต้องรอผู้สอน ถ้าหน้าเว็บของทีมใช้ไม่ได้ ใช้หน้าทดลองของ HiveMQ แทนได้ ตั้ง host broker.hivemq.com port 8884 เปิด SSL แล้ว subscribe bento-aiot/<ทีมของคุณ>/# ส่วน broker สำรอง test.mosquitto.org ใช้เมื่อผู้สอนประกาศเท่านั้น

ไฟล์ ไฟล์นี้สอน
examples/03_your_link_rule.py ไฟล์นี้รันได้ แต่มันมองไม่เห็นปัญหาแบบที่สอง
examples/05_value_leaves_the_board.py ค่าที่วัดได้บนโต๊ะนี้ ไปโผล่บนเครื่องคนอื่น
examples/06_command_comes_back.py คนอื่นพิมพ์คำสั่งจากที่ไกล แล้วไฟบนโต๊ะเราติด
examples/07_platform_in_one_call.py บอร์ดจำได้เองว่าจะต่อไปที่ไหน แม้ถอดไฟแล้วเสียบใหม่

สไลด์ของบทเรียนนี้อ้างถึงไฟล์ที่อยู่ในบทเรียนอื่นด้วย:

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

จอของ examples/03_your_link_rule.py ขณะรันใน BENTO Emulator: ไฟล์นี้รันได้ แต่มันมองไม่เห็นปัญหาแบบที่สอง
03_your_link_rule.py ไฟล์นี้รันได้ แต่มันมองไม่เห็นปัญหาแบบที่สอง
จอของ examples/05_value_leaves_the_board.py ขณะรันใน BENTO Emulator: ค่าที่วัดได้บนโต๊ะนี้ ไปโผล่บนเครื่องคนอื่น
05_value_leaves_the_board.py ค่าที่วัดได้บนโต๊ะนี้ ไปโผล่บนเครื่องคนอื่น
จอของ examples/06_command_comes_back.py ขณะรันใน BENTO Emulator: คนอื่นพิมพ์คำสั่งจากที่ไกล แล้วไฟบนโต๊ะเราติด
06_command_comes_back.py คนอื่นพิมพ์คำสั่งจากที่ไกล แล้วไฟบนโต๊ะเราติด
จอของ examples/07_platform_in_one_call.py ขณะรันใน BENTO Emulator: บอร์ดจำได้เองว่าจะต่อไปที่ไหน แม้ถอดไฟแล้วเสียบใหม่
07_platform_in_one_call.py บอร์ดจำได้เองว่าจะต่อไปที่ไหน แม้ถอดไฟแล้วเสียบใหม่

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

  1. บอร์ดต่อ WiFi ขององค์กรที่ต้อง login ผ่านหน้าเว็บ ขั้นที่ 1 ของไฟล์ 05 เป็นเขียวพร้อมเลข IP แต่ขั้นที่ 2 เป็นแดงว่าต่อ broker ไม่ได้ สาเหตุที่น่าจะเป็นที่สุดคืออะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)

    • ก) บอร์ดได้เลข IP แต่ออกอินเทอร์เน็ตไม่ได้ เพราะไม่มีเบราว์เซอร์ให้กดยอมรับ จึงไปไม่ถึง broker
    • ข) เขียน user= แทน username= ใน mqtt.connect()
    • ค) ลืม subscribe หัวข้อก่อน connect
    • ง) ค่า knob อ่านไม่ได้ จึงเป็น -1
    เฉลย

    ก — เครือข่ายที่ต้อง login ให้ connect() คืน True และได้เลข IP ตามปกติ แต่นาฬิกาไม่ขึ้นและ mqtt.connect() ไปไม่ถึง broker คือกรณีติดข้อแรกแต่ไม่ผ่านข้อสอง วันนี้ทุกทีมจึงใช้ Hotspot มือถือ

  2. ข้อใดถูกต้องเกี่ยวกับการใช้ broker สาธารณะ broker.hivemq.com ในบทเรียนนี้ เลือกทุกข้อที่ถูก (เลือกได้หลายข้อ · เป้าหมายข้อ 2)

    • ก) หน้าเว็บของทีมควรฟัง bento-aiot/team03/# ไม่ใช่ # เปล่า ๆ ซึ่งเท่ากับขอรับข้อความทั้งโลก
    • ข) ใส่รหัส WiFi ของทีมใน payload ได้ เพราะหัวข้อของทีมไม่ซ้ำใคร
    • ค) ถ้า client_id ซ้ำกับใครก็ตามบน broker เดียวกัน broker จะเตะตัวเก่าออกโดยไม่มีข้อความเตือน
    • ง) broker เก็บใบล่าสุดไว้ให้ หน้าเว็บที่เปิดทีหลังจึงเห็นค่าทันที
    เฉลย

    ก, ค — ฟังเฉพาะหัวข้อของทีม และตั้ง client_id ที่ไม่ชนใครทั้งอินเทอร์เน็ต ทุกใบวิ่งแบบไม่เข้ารหัสและใครที่ subscribe หัวข้อเดียวกันก็เห็น จึงห้ามส่งความลับ ส่วนเฟิร์มแวร์ส่งแบบ retain ไม่ได้ หน้าเว็บที่เปิดช้าเห็นแค่ใบถัดไป

  3. คุณตั้ง POLL_MS = 3000 ในไฟล์ 06 แล้วกดปุ่มบนหน้าเว็บสามครั้งรวดภายในวินาทีเดียว ตัวนับบนจอบอร์ดน่าจะเป็นอย่างไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)

    • ก) ขึ้นครบสามใบ เพราะ broker ต่อคิวให้
    • ข) ขึ้นน้อยกว่าสามใบ เพราะกล่องรับมีช่องเดียว ใบที่มาถึงก่อนเราหยิบจะทับใบเก่าทิ้ง
    • ค) ไม่ขึ้นเลย เพราะ get_message() บล็อกจนหมดเวลา
    • ง) โปรแกรมตายด้วย OSError เพราะส่งถี่เกินไป
    เฉลย

    ข — get_message() ไม่บล็อกและคืน None เมื่อยังไม่มีอะไรมา กล่องรับมีช่องเดียว ใบใหม่ไม่ได้ต่อคิวแต่ทับของเดิม ลูปจึงต้องถามถี่ ๆ อย่างค่าตั้งต้น 100 ms

  4. ไฟล์ 06 ทำอะไรบ้างเพื่อไม่ให้ข้อความจากคนแปลกหน้าทำให้โปรแกรมตาย เลือกทุกข้อที่ถูก (เลือกได้หลายข้อ · เป้าหมายข้อ 3)

    • ก) เรียก .decode() กับ payload ที่เป็น bytes ก่อนส่งให้ json.loads()
    • ข) ดัก ValueError เมื่อข้อความไม่ใช่ JSON แล้วขึ้นบนจอว่า “ไม่ใช่ JSON”
    • ค) ตรวจว่าเลขดวง n เป็นจำนวนเต็มและอยู่ในช่วงดวงที่บอร์ดนี้มีจริงก่อนสั่ง gpio.led(n)
    • ง) ไม่ต้องตรวจอะไร เพราะมีแต่หน้าเว็บของทีมที่รู้ชื่อหัวข้อ cmd
    เฉลย

    ก, ข, ค — บน broker สาธารณะใครที่รู้ชื่อหัวข้อก็ส่งเข้ามาได้ คนส่งอาจพิมพ์ผิด ส่งของที่ไม่ใช่ JSON หรือสั่งดวงที่ไม่มี ทุกกรณีต้องจบที่ข้อความบนจอ ไม่ใช่โปรแกรมตาย

  5. is_usable(online, ip) แบบไหนทำให้ไฟล์ 03 รายงานครบ 2 ครั้งตามเทป (เลือกหนึ่งข้อ · เป้าหมายข้อ 4)

    • ก) return online and ip != “0.0.0.0”
    • ข) return online and ip
    • ค) return online
    • ง) return online or ip != “0.0.0.0”
    เฉลย

    ก — ลิงก์ที่ใช้ได้ต้องต่ออยู่และมีเลข IP ที่ใช้ได้พร้อมกัน “0.0.0.0” เป็นสตริงที่ไม่ว่าง Python จึงถือว่าจริง การเขียน and ip จึงผ่านหมด ต้องเทียบกับ “0.0.0.0” ตรง ๆ

ค่าออกไป คำสั่งกลับมา จดผลลงบันทึกการเรียนทุกข้อ

  • 05: บันไดสามขั้นเป็นเขียวครบ หมุนลูกบิดหรือเอียงบอร์ดแล้ว knob หรือ az บนหน้าเว็บของทีมขยับตาม จดว่าเห็นใบแรกที่ n เท่าไร (ถ้าขั้นไหนแดง จดขั้นและเหตุผลบนจอ)
  • 05 ตาคุณ: ตกลงกับทีมข้าง ๆ ตั้ง TEAM ชนกันชั่วคราว รันพร้อมกันสองบอร์ด แล้วจดว่าใครถูกเตะออกและฝั่งเราเห็นอะไร จากนั้นแก้กลับ
  • 06: กดส่งเสียงและเปิดปิดไฟ LED 0 จากหน้าเว็บ บอร์ดร้องและไฟติดดับตาม (ถ้ามองไม่เห็นดวง 0 ลองเลขดวงที่ชื่อขึ้นต้นด้วย RGB_ จากหน้ารวม mqtt_dashboard.html)
  • 06 ตาคุณ: ตั้ง POLL_MS = 3000 กดปุ่มสามครั้งรวดในวินาทีเดียว นับว่าตัวเลขบนจอขึ้นกี่ใบเทียบกับสามใบที่ส่งจริง
  • 03: เติม is_usable() จน “กฎคุณรายงาน” เป็น 2 เท่ากับ “ควรรายงาน” แล้วเปลี่ยน NEED เป็น 5 และเขียนคำตอบว่าช่วงไหนในเทปหายไป
  • (อ่านนอกเวลา) 07: รันโดยปล่อย PLATFORM_BROKER ว่าง จดค่า port กับ tls_mode ที่จอแสดง แล้วตอบว่าทำไม port นั้นอาจไม่ใช่พอร์ตที่ connect() ใช้จริง

บทเรียน 1.6 เป็นแล็บปิดโมดูล 1: พาค่าจริงออกจากบอร์ดด้วยไฟล์ฝึกของทีม แล้วสรุปสิ่งที่เรียนมาทั้งโมดูล หัวข้อ .../event เริ่มใช้ในบทเรียน 2.1–2.3 ส่วนเรื่องสิทธิ์และการเข้ารหัสที่ broker สาธารณะไม่มีให้ รออยู่ในบทเรียน 4.4–4.6 กับ 4.7–4.9

บทเรียนถัดไป: บทเรียน 1.6 — ลงมือทำ: พาค่าจริงออกจากบอร์ด และสรุปโมดูล 1

  • ในงานของคุณ ค่าอะไรที่ควรส่งออกไปให้คนอื่นเห็น และอะไรที่ห้ามออกจากบอร์ดเด็ดขาดตราบที่ยังไม่เข้ารหัส
  • ใครก็ส่งเข้าหัวข้อ cmd ได้ มีคำสั่งแบบไหนที่บอร์ดของคุณไม่ควรทำตามเลย แม้จะเป็น JSON ที่ถูกต้อง
  • “ต่ออยู่” กับ “ส่งข้อมูลออกได้” ต่างกันอย่างไรในระบบของคุณ และจอของคุณแยกสองเรื่องนี้ให้คนดูเห็นหรือยัง

คำถามทบทวน

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

  1. บอร์ดต่อ WiFi ขององค์กรที่ต้อง login ผ่านหน้าเว็บ ขั้นที่ 1 ของไฟล์ 05 เป็นเขียวพร้อมเลข IP แต่ขั้นที่ 2 เป็นแดงว่าต่อ broker ไม่ได้ สาเหตุที่น่าจะเป็นที่สุดคืออะไร (เป้าหมายข้อ 1)

    1. บอร์ดได้เลข IP แต่ออกอินเทอร์เน็ตไม่ได้ เพราะไม่มีเบราว์เซอร์ให้กดยอมรับ จึงไปไม่ถึง broker
    2. เขียน user= แทน username= ใน mqtt.connect()
    3. ลืม subscribe หัวข้อก่อน connect
    4. ค่า knob อ่านไม่ได้ จึงเป็น -1
    ดูเฉลย

    คำตอบ: A. บอร์ดได้เลข IP แต่ออกอินเทอร์เน็ตไม่ได้ เพราะไม่มีเบราว์เซอร์ให้กดยอมรับ จึงไปไม่ถึง broker

    เครือข่ายที่ต้อง login ให้ connect() คืน True และได้เลข IP ตามปกติ แต่นาฬิกาไม่ขึ้นและ mqtt.connect() ไปไม่ถึง broker คือกรณีติดข้อแรกแต่ไม่ผ่านข้อสอง วันนี้ทุกทีมจึงใช้ Hotspot มือถือ

  2. ข้อใดถูกต้องเกี่ยวกับการใช้ broker สาธารณะ broker.hivemq.com ในบทเรียนนี้ เลือกทุกข้อที่ถูก (เป้าหมายข้อ 2)

    1. หน้าเว็บของทีมควรฟัง bento-aiot/team03/# ไม่ใช่ # เปล่า ๆ ซึ่งเท่ากับขอรับข้อความทั้งโลก
    2. ใส่รหัส WiFi ของทีมใน payload ได้ เพราะหัวข้อของทีมไม่ซ้ำใคร
    3. ถ้า client_id ซ้ำกับใครก็ตามบน broker เดียวกัน broker จะเตะตัวเก่าออกโดยไม่มีข้อความเตือน
    4. broker เก็บใบล่าสุดไว้ให้ หน้าเว็บที่เปิดทีหลังจึงเห็นค่าทันที
    ดูเฉลย

    คำตอบ: A. หน้าเว็บของทีมควรฟัง bento-aiot/team03/# ไม่ใช่ # เปล่า ๆ ซึ่งเท่ากับขอรับข้อความทั้งโลก · C. ถ้า client_id ซ้ำกับใครก็ตามบน broker เดียวกัน broker จะเตะตัวเก่าออกโดยไม่มีข้อความเตือน

    ฟังเฉพาะหัวข้อของทีม และตั้ง client_id ที่ไม่ชนใครทั้งอินเทอร์เน็ต ทุกใบวิ่งแบบไม่เข้ารหัสและใครที่ subscribe หัวข้อเดียวกันก็เห็น จึงห้ามส่งความลับ ส่วนเฟิร์มแวร์ส่งแบบ retain ไม่ได้ หน้าเว็บที่เปิดช้าเห็นแค่ใบถัดไป

  3. คุณตั้ง POLL_MS = 3000 ในไฟล์ 06 แล้วกดปุ่มบนหน้าเว็บสามครั้งรวดภายในวินาทีเดียว ตัวนับบนจอบอร์ดน่าจะเป็นอย่างไร (เป้าหมายข้อ 3)

    1. ขึ้นครบสามใบ เพราะ broker ต่อคิวให้
    2. ขึ้นน้อยกว่าสามใบ เพราะกล่องรับมีช่องเดียว ใบที่มาถึงก่อนเราหยิบจะทับใบเก่าทิ้ง
    3. ไม่ขึ้นเลย เพราะ get_message() บล็อกจนหมดเวลา
    4. โปรแกรมตายด้วย OSError เพราะส่งถี่เกินไป
    ดูเฉลย

    คำตอบ: B. ขึ้นน้อยกว่าสามใบ เพราะกล่องรับมีช่องเดียว ใบที่มาถึงก่อนเราหยิบจะทับใบเก่าทิ้ง

    get_message() ไม่บล็อกและคืน None เมื่อยังไม่มีอะไรมา กล่องรับมีช่องเดียว ใบใหม่ไม่ได้ต่อคิวแต่ทับของเดิม ลูปจึงต้องถามถี่ ๆ อย่างค่าตั้งต้น 100 ms

  4. ไฟล์ 06 ทำอะไรบ้างเพื่อไม่ให้ข้อความจากคนแปลกหน้าทำให้โปรแกรมตาย เลือกทุกข้อที่ถูก (เป้าหมายข้อ 3)

    1. เรียก .decode() กับ payload ที่เป็น bytes ก่อนส่งให้ json.loads()
    2. ดัก ValueError เมื่อข้อความไม่ใช่ JSON แล้วขึ้นบนจอว่า "ไม่ใช่ JSON"
    3. ตรวจว่าเลขดวง n เป็นจำนวนเต็มและอยู่ในช่วงดวงที่บอร์ดนี้มีจริงก่อนสั่ง gpio.led(n)
    4. ไม่ต้องตรวจอะไร เพราะมีแต่หน้าเว็บของทีมที่รู้ชื่อหัวข้อ cmd
    ดูเฉลย

    คำตอบ: A. เรียก .decode() กับ payload ที่เป็น bytes ก่อนส่งให้ json.loads() · B. ดัก ValueError เมื่อข้อความไม่ใช่ JSON แล้วขึ้นบนจอว่า "ไม่ใช่ JSON" · C. ตรวจว่าเลขดวง n เป็นจำนวนเต็มและอยู่ในช่วงดวงที่บอร์ดนี้มีจริงก่อนสั่ง gpio.led(n)

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

  5. is_usable(online, ip) แบบไหนทำให้ไฟล์ 03 รายงานครบ 2 ครั้งตามเทป (เป้าหมายข้อ 4)

    1. return online and ip != "0.0.0.0"
    2. return online and ip
    3. return online
    4. return online or ip != "0.0.0.0"
    ดูเฉลย

    คำตอบ: A. return online and ip != "0.0.0.0"

    ลิงก์ที่ใช้ได้ต้องต่ออยู่และมีเลข IP ที่ใช้ได้พร้อมกัน "0.0.0.0" เป็นสตริงที่ไม่ว่าง Python จึงถือว่าจริง การเขียน and ip จึงผ่านหมด ต้องเทียบกับ "0.0.0.0" ตรง ๆ

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

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

"ค่าออกไป คำสั่งกลับมา: MQTT บน broker สาธารณะ" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ข้อความอ้างอิงภาษาอังกฤษ: "Values out, commands back: MQTT on a public broker" 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/m01-ui-application/l05-values-out-commands-back/

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

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

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

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