รีพอร์ท Keyakizaka46 6th Single Handshake

เขียนไว้ในเฟสแล้ว แต่พบว่า formatting แย่มาก เลยเอามา remaster ลงบล็อคอีกทีละกัน


งานจับมือเคยากิเป็นอะไรที่อยากไปมาตั้งแต่เข้ามาตามวงนี้แล้ว แต่เป็นงานที่คิดว่าคนไม่รู้ภาษาญี่ปุ่นแบบเราคงจะมายากเหมือนกัน

ถึงแบบนั้นก็บอกว่าเป็น New Year Resolution แล้วต้องไปสิ

จองบัตร

ตอนจองบัตรแปะไว้ในเฟสว่ามีใครจองให้ได้มั้ย อ้นบอกว่าเพื่อนรับจอง ก็ไม่คิดว่าเพื่อนอ้นคือนุ่มที่เคยเจอกันแล้ว.. แล้วก็ไม่คิดว่าจะให้มารับที่งานด้วย ดีเลยไม่งั้นเราตายในงานแน่นอน

เตรียม!

คืนก่อนงานยังไม่รู้ว่าจะพูดอะไรกับน้องเลย (คราว BNK ก็แบบนี้แหละ) เลยปรึกษามิจจี้ เค้าเลยเขียน script ให้เราแบบนี้

ที่กลัวมากคือในหัวมันมีเสียงไอดอลอยู่ มันจะกลายเป็น

  • ouen kudasai (กรุณาเชียร์ด้วยนะ)
  • kore kara mo yoroshiku onegaishimasu (จากนี้ต่อไปฝากเนื้อฝากตัวด้วยนะ)

ทีนี้ล่ะอายจนมุดรูหนีแน่นอน

เพื่อไม่ให้พลาดเลยเซฟใส่ Telegram ไว้ จะได้เปิดง่ายๆ

วันงาน

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

  • เข้าไปช็อคกับ Market คือมาร์เก็ตในหัวมันไม่ใช่ภาพแบบเปิดท้ายขายของขนาดนี้ แถมมีธงเชียร์อีกต่างหาก
  • เหมือนไม่มีธงยุยปง? เห็นมีคนถือป้ายเล็กๆ เดินตรงทางเข้า
Market
  • ข้างในมีแถวขาย official goods คนอย่างเยอะ
    • ตอนแรกคิดว่าอาจจะสอย penlight แต่เยอะขนาดนี้ขอผ่าน (แต่ก็ไม่คิดว่าจะได้ซื้ออยู่แล้วนะเพราะรู้ดีว่า goods แถวยาว)
  • นุ่มบอกว่าต่อแถว goods อยู่ เราเลยไปนั่งรอซึ่งพื้นที่นั่งก็กว้างขวาง
  • พอฮอลล์มันใหญ่แล้วอะไรๆ มันก็ดีอ่ะนะ

ไปจับมือกันเถอะ

ตอนแรกคิดว่าบัตรบุ 3 เราเป็นบัตรเนรุ ปรากฏว่าไม่ใช่เป็นบัตรโอเซกิ ก็ดีจะได้ซ้อมมือ

  • เดินหาทางเข้าไม่เจอ คนทำป้ายก็น่ารัก ทั้งงานมีภาษาอังกฤษอยู่แค่ 2 ประโยค “Official Goods Store” “Exit” สนุกล่ะ
  • แต่ฮอลล์มันกว้างเลยคิดว่าต้องสำรวจดู ปรากฏว่าทางเข้าอยู่อีกฮอลล์นึงเลย ไม่คิดว่าใช้ถึง 2 ฮอลล์ รวยจริงๆ
  • เข้าไปถึงตรวจบัตรจับมือก่อน สบายๆ
  • ถัดมาตรวจกระเป๋า เค้าถาม ライター? โอเค lighter no no ไม่มี
  • คนถัดมาตรวจโลหะ ให้กางแขนออก แล้วเค้าบอกอะไรไม่รู้เลยบอกว่า I don’t know japanese เค้าบอกแบ๊กๆ เลยหยิบกระเป๋ามาเค้าบอกว่า “no no back” แล้วทำมือด้วย
  • เค้าถาม Are you an American? พี่เอาความมั่นใจมาจากไหนเนี่ย…

โอเซกิ

  • เข้าไปเจอคนชูป้ายเขียนอะไรยาวๆ ไม่รู้มีเลข 3 เราก็เดาไว้ก่อนว่าบุ 3 เลยเดินไปต่อแถว
  • แถวมีประมาณ 8 แถวหน้ากระดาน แล้วขด 4 รอบ คุณพระ ตอนต่อ ตม. ยังไม่ยาวขนาดนี้
  • คำถามถัดไปคือโอเซกิอยู่เลนไหน ก็ส่องๆ เลนไว้ตอนแถววนผ่าน ซึ่งเคยเห็นภาพงาน AKB มันจะมีภาษาอังกฤษ แต่ของเคยากิไม่มี แล้วคันจิชื่อน้องก็อ่านยาก ก็ยังดีว่าเห็น りか ซึ่ง か นี่อ่านออก り ก็พอเดาออก ก็เลยเทียบคันจิกับในบัตรดู (ไม่ดูนี่เป็นเบริกะยุ่งเลย)
    • ขอบคุณญี่ปุ่น 1 ที่ได้ U เรียนมาได้ใช้แล้ว T_T
  • สักบ่าย 2 25 ได้เข้า เลนยังไม่มีคนเยอะเลยได้ตรวจบัตร ยื่น passport ไปคนตรวจก็งงนิดหน่อยแต่นั่งแกะชื่อแล้วถามอะไรไม่รู้ เสร็จแล้ววง 1 ให้ที่บัตร (เดาได้ว่าถามว่ามีกี่ใบ)

  • แถวข้างในมีอีก 3 ขด เลนโอเซกิปล่อยเข้าช้าประมาณ 5 นาที

ในห้องจับมือ

*ยื่นบัตรให้สตาฟ*
&$#)(@#$)(&ketai&$#)(@#$)(&
“ketai? phone?”
*สตาฟแบมือ*

// อ๋อใช่ ต้องแบมือให้ดู

*แบมือแล้วเดินไปหาน้อง*
“มาจากไทยครับ”
*เงี่ยหูมาทำหน้างงๆ*
“มาจากไทยครับ”
“อ๊ะ ขอบคุณนะ”

// หมดเวลาครับ

“แล้วเจอกันใหม่น๊า” *โบกมือ*

เห้ย… นี่จับมือทั่วประเทศหรือไงเนี่ย 5 วิได้มั้ง 😭


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

บุ 4

ออกจากบุมาก็เห็นมีป้ายบุ 4 รอตั้งแต่เปิดบุ 3 แล้ว ก็เลยเข้าไปต่อแถวเลย นั่งๆ นอนๆ ไปจน 4 โมงสตาฟประกาศจบรอบทีละเลน เห็นน้องเลน 24 (หรือเปล่านะ) ใส่คอสตูมมาโบกตุ๊กตาขอบคุณแล้วโค้งให้หน้าเลนด้วย น่ารักมากแต่อยู่ฮิรางานะอ่ะ

ระหว่างรอถามนุ่มว่าเค้ามีบอกมั้ยว่าใครอยู่เลนไหน นุ่มส่งรูปจากเว็บมาให้ ค่อยง่ายหน่อยเพราะจะอ่านทีละตัวได้

หลังจากนั้นก็นั่งๆ นอนๆ ไปเป็นชั่วโมงกว่าจะเรียกแถว ฟังเพลงวนไปจนเบื่อโซโล่เทะไปแล้ว ยังดีว่ามี Garasu wo ware กับ Zenmai Shikake no Yume ให้ฮัม​ (น่าจะเปิดเพลงเก่าผสมไปบ้างนะ ซิงเกิลมันมีไม่กี่เพลงแล้ววนทั้งวัน)

พอเรียกแถวเข้าไปรอบนี้ก็คิดว่าไหนๆ เราได้เข้าก่อนมากๆ ไปเลนเนรุเลยละกันน่าจะนาน เดินเข้าไปต่อแถวแล้วรู้สึกเหมือนต่ออยู่เลน 3 คนข้างหลังบัตรจับมือก็น่าจะไม่ใช่เนรุ เลยหันไปถาม “Excuse me” *ชี้ที่บัตร* “This one?” “No, that” รู้สึกเหลือเชื่อที่คนหลังตอบเราได้ 🙏

พอเดินออกไปหาแถวไม่เจอ ตรงป้ายเลน 2 ไม่มีคน ยื่นถามสตาฟสตาฟชี้ให้ออกไป ก็งงๆ เลยลองภาษาอังกฤษดู

“exit?”
“yes again please sorry”

โอ้ก๊อด 😱 แต่พอเข้าใจเพราะเห็นแถวเลนนึงจากบุก่อนยังไม่หมดด้วยซ้ำ นึกได้ว่ามียุยปงอีกใบ ก็เลยวิ่งกลับไปต่อเลนยุยปง ได้คิวประมาณโอเซกิเมื่อกี้

ยุยปง

Impression แรกของยุยปงคือไม่เห็นเหมือนในรูปเลย (ใครเนี่ย มาต่อแถวฮิรางานะอยู่ป่าวหว่า…) ที่สำคัญคือสูงกว่าเราอีก (ไม่ได้สังเกตว่าใส่ส้นสูงหรือเปล่า)

ต้องเรียกว่าเหมือนคนธรรมดาอ่ะ ถ้าเทียบกับ BNK แล้วตัวท็อปๆ จะสวยแบบนางฟ้าชนิดที่ว่าหาจับไม่ได้ แต่ปงนี่โคตรธรรมดา (ทำไมในรายการน่ารักเหมือนนางฟ้า…)

“คนนิจิวะ”
“มาจากไทยนะครับ”
“ล้อเล่นน่า!”
“เชียร์อยู่นะครับ”

// หมดเวลาครับบ

“Thank you~”

รอบนี้รู้สึกว่าคุ้มค่า อยากได้เวลาเพิ่มอีกสัก 3 วิแต่ถ้านานกว่านั้นก็ไม่รู้จะคุยอะไรแล้ว

ที่แปลกใจคือฟังน้องพูดรู้เรื่องด้วย

เนรุ

หลังจากจับมือคามิโอชิเราแล้วก็ไปต่อแถวเนรุบ้าง

จริงๆ ที่จองบัตรเนรุมาเนี่ยคือจองใบเดียวขำๆ ดันได้ ทีจองริสะ 3 ใบไม่เห็นได้ แต่ก็ดีจะได้ลองสมมุติฐาน

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


มาถึงเลนเอ๊ะ… ทำไมคนไม่ล้น??? พอเข้าไปต่อพบว่า

  • แถวเลน 2 มี 3 ขดข้างนอก เข้าไปตรวจบัตรแล้วข้างในมีอีก 3 ขดเหมือนเลนอื่น
  • มันก็เท่าเลนอื่น… แค่มาช้าเอง
  • เพื่อไม่ให้ผิด แอบมองคนข้างหน้าเห็นบัตรเขียนเนรุก็เป็นอันใช้ได้ ชื่อเนรุพิเศษตรงเป็นฮิรางานะ ねる เห็นแล้วไม่ต้องอ่านก็เดาได้ว่าใคร

ระหว่างรอมองเลนข้างๆ

  • เลน 1 เป็นแถวตรงยาวไป ตรงตรวจบัตรมีขดอยู่ แล้วยาวต่อไปจนสุดอีกฝั่งของฮอลล์แล้ววนกลับมา แถมรั้วกั้นนี่ตั้งรอไว้ยาวกว่าแถวอีก
  • แสดงว่าแถวที่ไม่หมดบุก่อนคือเลน 1 มากกว่า
  • มีป้ายกระดาษติดตามทางด้วย เทคแคร์คนจับมากกก
  • แอบมองในเลนเห็นรูปคุ้นๆ เลยลองอ่านชื่อ ゆい รู้สึกคุ้นๆ ก็อ๋ออีกยุยยอดนักตกนี่เอง
  • มองเข้าไปเลนเห็นยุยส่งหลายคนขนาดว่าเดินมาตรงทางออก (ปกติเมมจะยืนตรงกลางอย่างเดียว) เห็นแล้วอยากลองจับเลย
    • นี่สินะเรียกว่าโดนตก

เลนเนรุมีฝรั่งอยู่หน้าเราคนนึง เราก็ว่ารอดละ แพลนคือจะเข้าไปซัดภาษาอังกฤษใส่เนรุ อยากรู้ว่าเป็นไง

คนนิจิวะ

// เนรุยกสองมือให้เลย เราเลยจับสองข้างเลย

I come from Thailand

// สตาฟทักอะไรไม่รู้ เราก็งงๆ ละจะหมดเวลามั้ย

ที่เหลือจำไม่ได้ว่าพูดอะไรไปอีกประโยค คือสดแล้วตอนนั้น (แพลนไว้ว่า “Keep up the good work”)

// หมดเวลาครับ


โอ๊ยสตาฟอย่าทำผมเขวสิ…

เดาว่าอาจจะไม่ให้จับท่านั้นหรือเปล่านะถึงทัก


สำหรับเนรุก็ตามในทีวีอ่ะ คือไม่รู้สึกว่าเนรุน่ารักจนละลายเท่าปงอยู่แล้วเลยเฉยๆ นะ

ส่วนภาษาอังกฤษคิดว่าเฟล รอบหน้าเอาธรรมดาๆ เถอะ น้องอาจจะสลับภาษาไม่ทัน อันนี้เข้าใจ

Bye-bye~

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

จะรอวันที่ได้พบกันอีกนะคะ💕
พรุ่งนี้ก็สู้ๆน้า ✨

(สนับสนุนคำแปลโดยมิจจี้อีกแล้ว)

สรุป

สรุปแล้วรู้สึกว่าจับมือเคยากิไม่เหมือนจับมือ BNK เท่าไรนะ คืออันนั้นรู้สึกว่าเวลาเยอะจน dead air แต่รอบนี้เหมือนน้องยังไม่ทันปริปากอะไรเท่าไรก็หมดเวลาแล้ว แต่ที่เหมือนกันคือเข้าไปแล้วงงๆ เขินๆ (น่าจะงงมากกว่าด้วย)

คิดว่าถ้าจะมาอีกแล้วมาหลายๆ ใบ อาจจะต้องลองซ้อมจับกับน้อง BNK สักคนวนจนกว่าจะหายเขินอ่ะถึงจะคุ้มให้มาใหม่ แต่ก็ไม่แน่ใจถ้าเตรียมเรื่องมาคุยกับน้องเราอาจจะรู้สึกเวลาไม่พอแบบนี้หรือเปล่า

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

สุดท้ายสำหรับคนไม่รู้ญี่ปุ่นเลยก็มาได้แหละ แต่ถ้ามาเยอะๆ คงจะเหนื่อยเพราะคุยกับน้องเยอะไม่ได้

ทำไมเน็ตช้า! หาคำตอบด้วย M5Stack และ Raspberry Pi

หลายสัปดาห์ก่อนเพิ่ง Download Dota 2 กลับมาครับ แล้วก็พบว่าเวลามัน patch เน็ตมันช้ามาก แถมรันเป็น background ไม่รู้อีกว่าเน็ตโดนสูบอยู่ นึกว่าคอมมีปัญหาเพราะไม่มีใครใช้เน็ตแล้วมันจะช้าได้ยังไง

ถ้าใช้ router แพงๆ มันมักจะมีจอมาด้วยซึ่งจะแสดง network speed อยู่ ก็เลยคิดว่าจะลองเขียนอะไรแบบนั้นดู

แผนการ

สำหรับแผนการในรอบนี้คือผมจะเอา M5Stack อ่าน SNMP จาก router ผม แล้วมาแสดงบนหน้าจอ

M5Stack

espressif.com

พอดีไปเดินงาน Maker Faire Bangkok ก็เลยยุให้พ่อซื้อ M5Stack ให้ตัวหนึ่ง (บังเอิญเจอพี่ลิ่ว Blognone ด้วย เลยให้พี่ลิ่วช่วยยุ) ซึ่งผมว่ามันเจ๋งมากเพราะมันมีจอ ปุ่มกด และ battery ในตัว (แบตเท่าที่ลองอยู่ได้ประมาณ 10 นาที อย่าคาดหวังอะไรมันมาก และมันจะ reset ตอนเสียบไฟ)

สำหรับการเขียนโปรแกรมนั้น M5Stack ใช้ CPU ESP32 (ตัวพี่ของ ESP8266 ยอดนิยม) สามารถใช้ Arduino IDE เขียนได้ ซึ่งปรากฏว่า Arduino ไม่มี SNMP client library ครั้นจะเขียนเองก็ยุ่งยากไป เลยคิดว่าจะเอา Raspberry Pi มาอ่านแล้วส่งข้อมูลให้ M5Stack อีกที

Router configuration

ก่อนจะไปถึง Raspberry Pi มาตั้งค่า router ให้มีข้อมูลพร้อมอ่านกันก่อน สำหรับ Router Mikrotik ทำได้ดังนี้

  1. เปิด WebFig/WinBox ขึ้นมาแล้ว login ให้เรียบร้อย
  2. ไปที่เมนู IP > SNMP
  3. เลือก Enabled
  4. คลิกที่ Communities ด้านบน กด Add New
  5. ระบุข้อมูลดังนี้
    • Name: อะไรก็ได้
    • Addresses: ไม่ใส่ก็ได้ หรือถ้าต้องการให้ปลอดภัยระบุเป็น IP ของ Raspberry Pi หรือ CIDR ก็ได้
    • Read Access: ติ๊กไว้
    • ผมยังไม่เปิดใช้ security เนื่องจากเป็น read only และ allow เฉพาะ LAN IP ไว้เลยคิดว่าความเสี่ยงต่ำพอแล้ว
  6. ตอนนี้น่าจะพร้อมใช้งาน SNMP แล้ว

ถัดมาเราจะหา OID ของ interface ที่ออกเน็ต ขั้นตอนนี้จะต้องใช้เมนู Terminal แล้วใช้คำสั่ง /interface print oid จะได้ผลดังนี้

 0  R  name=.1.3.6.1.2.1.2.2.1.2.1 actual-mtu=.1.3.6.1.2.1.2.2.1.4.1 mac-address=.1.3.6.1.2.1.2.2.1.6.1 admin-status=.1.3.6.1.2.1.2.2.1.7.1 oper-status=.1.3.6.1.2.1.2.2.1.8.1 bytes-in=.1.3.6.1.2.1.31.1.1.1.6.1 packets-in=.1.3.6.1.2.1.31.1.1.1.7.1 discards-in=.1.3.6.1.2.1.2.2.1.13.1 
       errors-in=.1.3.6.1.2.1.2.2.1.14.1 bytes-out=.1.3.6.1.2.1.31.1.1.1.10.1 packets-out=.1.3.6.1.2.1.31.1.1.1.11.1 discards-out=.1.3.6.1.2.1.2.2.1.19.1 errors-out=.1.3.6.1.2.1.2.2.1.20.1 

 1  RS name=.1.3.6.1.2.1.2.2.1.2.2 actual-mtu=.1.3.6.1.2.1.2.2.1.4.2 mac-address=.1.3.6.1.2.1.2.2.1.6.2 admin-status=.1.3.6.1.2.1.2.2.1.7.2 oper-status=.1.3.6.1.2.1.2.2.1.8.2 bytes-in=.1.3.6.1.2.1.31.1.1.1.6.2 packets-in=.1.3.6.1.2.1.31.1.1.1.7.2 discards-in=.1.3.6.1.2.1.2.2.1.13.2 
       errors-in=.1.3.6.1.2.1.2.2.1.14.2 bytes-out=.1.3.6.1.2.1.31.1.1.1.10.2 packets-out=.1.3.6.1.2.1.31.1.1.1.11.2 discards-out=.1.3.6.1.2.1.2.2.1.19.2 errors-out=.1.3.6.1.2.1.2.2.1.20.2 

 2  RS name=.1.3.6.1.2.1.2.2.1.2.3 actual-mtu=.1.3.6.1.2.1.2.2.1.4.3 mac-address=.1.3.6.1.2.1.2.2.1.6.3 admin-status=.1.3.6.1.2.1.2.2.1.7.3 oper-status=.1.3.6.1.2.1.2.2.1.8.3 bytes-in=.1.3.6.1.2.1.31.1.1.1.6.3 packets-in=.1.3.6.1.2.1.31.1.1.1.7.3 discards-in=.1.3.6.1.2.1.2.2.1.13.3 
       errors-in=.1.3.6.1.2.1.2.2.1.14.3 bytes-out=.1.3.6.1.2.1.31.1.1.1.10.3 packets-out=.1.3.6.1.2.1.31.1.1.1.11.3 discards-out=.1.3.6.1.2.1.2.2.1.19.3 errors-out=.1.3.6.1.2.1.2.2.1.20.3 

แล้วดูเทียบกับเมนู /interface print

 #     NAME                                TYPE       ACTUAL-MTU L2MTU  MAX-L2MTU MAC-ADDRESS      
 0  R  ether1-internet                     ether            1500  1596       2026
 1  RS ether2-celty                        ether            1500  1596       2026
 2  RS ether3-switch                       ether            1500  1596       2026

ซึ่งของผม ether1-internet เป็นตัวที่ต่อกับ router ภายนอก ก็เลยจะต้องดูว่าเบอร์ 0 นั้น oid ที่แสดงข้อมูล internet คืออะไร ก็จะเห็นว่า

  • Bytes in: .1.3.6.1.2.1.31.1.1.1.6.1 (Download)
  • Bytes out: .1.3.6.1.2.1.31.1.1.1.10.1 (Upload)

ซึ่งเราจะจดไว้ใช้ในโค้ดเราต่อไป

Raspberry Pi

สำหรับบน Raspberry Pi นั้นของที่ผมมีอยู่จะเป็น Model B+ ค่อนข้างเก่าแต่ก็ไม่ได้จำเป็นต้องใช้อะไรแรงอยู่แล้ว (งานแค่นี้ Arduino ก็คงทำได้ถ้ามันมี library) โดยใช้ดิสโตรโปรดของผมคือ Arch Linux ARM

โดยโค้ดจะประมาณนี้


import time import socket import struct from easysnmp import Session SLEEP_DURATION = 2 session = Session(hostname='192.168.2.1', community='local', version=2) client = socket.socket(type=socket.SOCK_DGRAM) last_download = 0 last_upload = 0 while True: download = int(int(session.get('.1.3.6.1.2.1.31.1.1.1.6.1').value)/SLEEP_DURATION) upload = int(int(session.get('.1.3.6.1.2.1.31.1.1.1.10.1').value)/SLEEP_DURATION) if last_download != 0: print(download - last_download, upload - last_upload) client.sendto(struct.pack('<2I', download - last_download, upload - last_upload), ('192.168.3.7', 1)) last_download = download last_upload = upload time.sleep(SLEEP_DURATION)

คร่าวๆ ก็คือโปรแกรมจะอ่่านค่า OID ทั้ง 2 ตัวจาก 192.168.2.1 แล้วส่งไปให้ 192.168.3.7 UDP port 1

การนำไปติดตั้งบน Raspberry Pi ก็จะต้องติดตั้ง Python และ easysnmp เพิ่มเติม ดังนี้

# pacman -S python gcc net-snmp python-pip
# pip install easysnmp

M5Stack

ถัดมาเราจะเขียนโปรแกรมสำหรับรับข้อมูลมาแสดงกัน ก็จะประมาณนี้

#include <M5Stack.h>
#include <WiFi.h>
#include <WiFiUdp.h>

const char *WIFI_SSID = "WHS-IoT";
const char *WIFI_PASSWORD = "";
const int SERVICE_PORT = 1;
const int MAX_DOWNLOAD = 35 * 1000000 / 8;
const int MAX_UPLOAD = 6 * 1000000 / 8;
const int GRAPH_WIDTH = 1;

typedef struct netPacket {
  unsigned int download;
  unsigned int upload;
} netPacket;

WiFiUDP udp;
netPacket data;
int graphPos = 0;
int graphOriginY, downloadHeight, uploadHeight;

#define LCD_WIDTH M5.Lcd.width()
#define LCD_HEIGHT M5.Lcd.height()
#define FONT_BASE 31

void wifiConnect(){
  int wifiStatus = WL_IDLE_STATUS;
  bool firstTry = true;

  while(wifiStatus != WL_CONNECTED){
    if(!firstTry){
      switch(wifiStatus){
        case WL_NO_SHIELD:
          M5.Lcd.println("E: No module");
          break;
         case WL_CONNECT_FAILED:
          M5.Lcd.println("E: Connection fail");
          break;
         case WL_CONNECTION_LOST:
          M5.Lcd.println("E: Connection lost");
          break;
         case WL_DISCONNECTED:
          M5.Lcd.print(".");
          break;
         default:
          M5.Lcd.printf("E: %d\n", wifiStatus);
      }
    }else{
      M5.Lcd.printf("Connecting to %s\n", WIFI_SSID);      
    }

    wifiStatus = WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    delay(5000);
    firstTry = false;
  }
  M5.Lcd.println();
  M5.Lcd.println(WiFi.localIP());

  graphPos = 0;
}

void checkWifiConnected(){
  if(WiFi.status() != WL_CONNECTED){
    M5.Lcd.clearDisplay();
    M5.Lcd.setCursor(0, FONT_BASE);
    M5.Lcd.println("Wifi disconnected!");
    wifiConnect();
  }
}

void setup() {
  M5.begin();
  M5.Speaker.mute();
  M5.Lcd.setFont(&FreeSans12pt7b);
  M5.Lcd.setCursor(0, FONT_BASE);
  M5.Lcd.setTextColor(WHITE, BLACK);
  M5.Lcd.setRotation(1);
  M5.Lcd.setTextWrap(false);

  int titleSize = FONT_BASE * 2;
  graphOriginY = titleSize + ((LCD_HEIGHT - titleSize) * 3 / 4);
  downloadHeight = graphOriginY;
  uploadHeight = LCD_HEIGHT - graphOriginY;

  Serial.printf("Graph origin %d\nDownload height %d\nUpload height %d\n", graphOriginY, downloadHeight, uploadHeight);

  wifiConnect();
  udp.begin(SERVICE_PORT);
}

void loop() {
  checkWifiConnected();

  bool drawText = false;
  if(udp.parsePacket()){
    udp.read((char *) &data, sizeof(netPacket));

    Serial.printf("DL %d UL %d\n", data.download, data.upload);
    drawText = true;
  }
  M5.Lcd.fillRect(graphPos, FONT_BASE * 2, GRAPH_WIDTH, LCD_HEIGHT, BLACK);

  int downloadPercent = min(max(1, data.download * downloadHeight / MAX_DOWNLOAD), graphOriginY - (FONT_BASE * 2));
  M5.Lcd.fillRect(graphPos, graphOriginY - downloadPercent, GRAPH_WIDTH, downloadPercent, RED);

  int uploadPercent = max(1, data.upload * uploadHeight / MAX_UPLOAD);
  M5.Lcd.fillRect(graphPos, graphOriginY, GRAPH_WIDTH, uploadPercent, YELLOW);

  if(drawText) {
    M5.Lcd.fillRect(0, 0, LCD_WIDTH, FONT_BASE * 2, BLACK);
     M5.Lcd.setCursor(0, FONT_BASE);
     M5.Lcd.printf("DL %.2f kb/s\nUL %.2f kb/s", (float) data.download/1000.0, (float) data.upload/1000.0);
  }

  graphPos = graphPos + GRAPH_WIDTH;
  if(graphPos > LCD_WIDTH){
    graphPos = 0;
  }

  delay(100);
}

Testing

ทีนี้เราก็จะต้องเทสว่ากราฟของเราขยับได้จริง โดยทำให้เน็ตมันโหลดขึ้นมา วิธีง่ายสุดคงเป็น speedtest

ถ้ากราฟขึ้นมาแบบนี้ก็เป็นอันใช้ได้

(Note: ความเร็วที่แสดงเป็น Kilobytes/s หรือจะตรงกับความเร็วที่แสดงในโปรแกรมดาวน์โหลด แต่โปรแกรม speedtest ส่วนมากจะแสดงผลเป็น Kilobits/s ฉะนั้นจะต้องคูณ 8 จากเลขที่แสดงบนจอด้วย)

สุดท้ายก็ไปแปะหน้า Switch ตามภาพ (M5Stack มีแม่เหล็กในตัว ส่วน power ดึงมาจาก Raspberry Pi เลย) คราวนี้ก็รู้สึกหรูขึ้นมา 10 เท่าเลย 555

Real world use

ติดเจ้าอุปกรณ์นี้มาสักพักแล้วครับ ประสบการณ์ที่เจอมาก็คือ

  • เวลากลับบ้านมาจะเห็น data use ขึ้นสูงเลยเพราะมือถือจะชอบ sync เมื่อชาร์จ + ต่อไวไฟ
  • config VPN failover อยู่ พอจะไปนอนเหลือบไปเห็นกราฟว่า upload วิ่งเต็มตลอด เลยรู้ตัวว่า BGP loop อยู่
  • ชอบดูตอนดู Streaming ถ้าเป็นพวก YouTube จะเห็นว่ามันโหลดหนักแป๊บเดียวแล้วเงียบเลย แต่ถ้าเป็น Twitch มันจะเบาๆ แต่ขึ้นตลอด
  • เมื่อวานเจอ Dota 2 โหลดแพทช์อีกแล้ว คราวนี้ก็รู้แล้วว่าเน็ตใช้อยู่จริงๆ

Future Improvements

ที่คิดว่าอยากทำคือ

  • ตอนนี้โปรแกรมอ่านค่ามีบั๊ก ถ้าค่าที่อ่านได้เกิน uint max (2^32) มันจะ serialize แล้วส่งไปไม่ได้ อาจจะต้องปรับ data size หรือทำท่าอื่นๆ
  • อาจจะมีค่าอื่นๆ ที่น่าเอามาแสดงผลอีก ก็ใช้ปุ่มบนตัว M5Stack เลื่อนเปลี่ยนโปรแกรมได้
  • การวาดกราฟทับดูยาก น่าจะมีวิธีที่ดีกว่านี้ (ตอนแรกในหัวนึกว่ามันจะเท่เหมือนเครื่องพล็อตกราฟชีพจร แต่อันนั้นหัวมันจะสว่างกว่าปกติ)

ปรากฏว่าพ่อเดินมาบอกว่า Raspberry Pi ก็ซื้อจอไว้นะ เอา Model B ไปใช้แทน B+ แล้วถอด M5Stack ไปทำอย่างอื่นเถอะ T_T ลดสเปคทุกอย่างไม่พอแถมต้อง rewrite อีกด้วย