GarminDB - ฐานข้อมูลที่ดึงและพาร์สข้อมูลจาก Garmin Connect/นาฬิกา
(github.com/tcgoetz)- GarminDB คือชุดสคริปต์ Python ที่ดาวน์โหลดข้อมูลสุขภาพและกิจกรรมจาก Garmin Connect แล้วพาร์สเป็น ฐานข้อมูล SQLite เพื่อให้วิเคราะห์และสร้างกราฟได้จาก command line หรือ Jupyter Notebook
- ข้อมูลที่ดึงได้อัตโนมัติ ได้แก่ ไฟล์การติดตามรายวัน, การนอนหลับ, น้ำหนัก, อัตราการเต้นหัวใจขณะพัก และไฟล์กิจกรรม โดยกิจกรรมบางประเภทจะบันทึกรายละเอียดเพิ่มถึง lap และ record entry
- ระบบจะเก็บรักษา ไฟล์ JSON และ FIT ที่ดาวน์โหลดไว้ จึงสามารถสร้าง DB ใหม่ได้โดยไม่ต้องเชื่อมต่อ Garmin Connect หรือดาวน์โหลดซ้ำ
- ติดตั้งได้เป็นแพ็กเกจ PyPI จากนั้นตั้งค่าบัญชี Garmin Connect และวันที่เริ่มต้นใน
GarminConnectConfig.jsonแล้วใช้garmindb_cli.py --all --download --import --analyzeเพื่อเริ่มรวบรวมและวิเคราะห์ข้อมูลทั้งหมด - สามารถขยายขอบเขตการประมวลผลของ แอป Connect IQ และ data field จากบุคคลที่สามผ่านปลั๊กอินได้ และหลังอัปเดตสคีมา DB อาจต้อง rebuild DB จากไฟล์ที่ดาวน์โหลดไว้เดิม
GarminDB ทำอะไร
- GarminDB คือชุดสคริปต์ Python สำหรับพาร์สและจัดการข้อมูลสุขภาพเป็นฐานข้อมูล SQLite
- SQLite ใช้เป็นฐานข้อมูลขนาดเบาที่ไม่ต้องมีเซิร์ฟเวอร์
- ฟีเจอร์ที่รองรับ:
- ดาวน์โหลดและนำเข้าไฟล์การติดตามรายวันจากหน้า “Daily Summary” ของ Garmin Connect โดยอัตโนมัติ
- อัตราการเต้นหัวใจตลอดทั้งวัน
- กิจกรรม
- การไต่ขึ้น/ลง
- ความเครียด
- เวลาความเข้มข้น
- ดึงข้อมูล การนอนหลับ, น้ำหนัก, อัตราการเต้นหัวใจขณะพัก จาก Garmin Connect แล้วบันทึกเป็นไฟล์ JSON และนำเข้า DB
- ดาวน์โหลดและนำเข้าไฟล์กิจกรรมจาก Garmin Connect
- สร้างตารางสรุปสำหรับกิจกรรมทั้งหมด
- เก็บข้อมูลละเอียดมากขึ้นสำหรับกิจกรรมบางประเภท
- รวม lap และ record entry แยกตามกิจกรรม
- สรุปข้อมูลเป็น DB ที่มีตารางสรุปรายวัน รายสัปดาห์ รายเดือน และรายปี
- แสดงข้อมูลเป็นกราฟผ่าน command line หรือ Jupyter Notebook
- เก็บรักษาไฟล์ JSON และ FIT ที่ดาวน์โหลดไว้ เพื่อสร้าง DB ใหม่ได้โดยไม่ต้องเชื่อมต่อ Garmin Connect หรือดาวน์โหลดซ้ำ
- ส่งออกกิจกรรมเป็น ไฟล์ TCX ได้
- ดาวน์โหลดและนำเข้าไฟล์การติดตามรายวันจากหน้า “Daily Summary” ของ Garmin Connect โดยอัตโนมัติ
การสำรวจและวิเคราะห์ข้อมูล
- หลังจากมีข้อมูลใน DB แล้ว สามารถใช้ Jupyter Notebook ที่ให้มา, Jupyter Notebook จากบุคคลที่สาม หรือ SQLite browser เพื่อสำรวจและทำงานกับข้อมูลได้
- ตัวอย่าง SQLite browser ที่ใช้ได้มีดังนี้
- สคริปต์จะสร้าง views พื้นฐานใน DB เพื่อให้สำรวจข้อมูลได้ง่ายขึ้น
การติดตั้งและ flow การใช้งานพื้นฐาน
- รีลีสของ GarminDb อยู่บน PyPI และต้องใช้ Python 3.x
- ติดตั้งรีลีสล่าสุด:
pip install garmindb
- การตั้งค่าเริ่มต้น:
- คัดลอก
GarminConnectConfig.json.exampleไปเป็น~/.GarminDb/GarminConnectConfig.json - แก้ไขไฟล์เพื่อเพิ่มชื่อผู้ใช้และรหัสผ่านของ Garmin Connect
- ปรับวันที่เริ่มต้นให้ตรงกับวันที่ของข้อมูลที่มีอยู่ใน Garmin Connect
- คัดลอก
- คำสั่งสำหรับดาวน์โหลดข้อมูลทั้งหมดและสร้าง DB เมื่อเริ่มต้นครั้งแรก:
garmindb_cli.py --all --download --import --analyze
- คำสั่งอัปเดตแบบเพิ่มเฉพาะข้อมูลล่าสุดเพื่อดาวน์โหลดและนำเข้าในภายหลัง:
garmindb_cli.py --all --download --import --analyze --latest
- ควรรันการสำรองข้อมูล DB เป็นครั้งคราวด้วยคำสั่งต่อไปนี้
garmindb_cli.py --backup
- อัปเดตเป็นรีลีสล่าสุด:
pip install --upgrade garmindb
การรันจากซอร์ส
- สคริปต์ใน source tree ถูกทำให้เป็นอัตโนมัติด้วย Make
- ขั้นตอนการใช้งานจากซอร์ส:
- โคลน repository ของ GarminDB ด้วยวิธี SSH clone
- ต้องใช้ SSH ไม่ใช่ HTTPS เนื่องจากมี submodule
- ใน tree ที่โคลนมา ให้รัน
make setupเพื่อเตรียมสคริปต์ให้พร้อมประมวลผลข้อมูล - คัดลอก
GarminConnectConfig.json.exampleไปเป็น~/.GarminDb/GarminConnectConfig.jsonแล้วตั้งค่าบัญชีและวันที่เริ่มต้น - สำหรับการดึงและประมวลผลข้อมูลครั้งแรก ให้รัน
make create_dbsหนึ่งครั้ง - หลังจากนั้น หากต้องการให้ข้อมูลในเครื่องเป็นปัจจุบัน ให้รันเพียง
makeเป็นระยะ
- วิธีใช้เพิ่มเติมอยู่ใน เอกสารการใช้งานใน wiki
Jupyter Notebook และปลั๊กอิน
- Jupyter Notebook สำหรับวิเคราะห์ข้อมูลในฐานข้อมูลอยู่ในไดเรกทอรี
Jupyterของ source tree - ลิงก์ Notebook ที่ผู้ใช้ส่งเข้ามาอยู่ใน หน้ารวมโปรเจกต์ที่เกี่ยวข้องของ wiki
- ปลั๊กอินช่วยให้ขยายประเภทข้อมูลที่ประมวลผลและบันทึกลง DB ได้
- GarminDb มีปลั๊กอินหลายตัวอยู่แล้วสำหรับประมวลผลข้อมูลจาก แอป Connect IQ และ data field ของบุคคลที่สาม
- รายละเอียดเพิ่มเติมเกี่ยวกับปลั๊กอินอยู่ที่ GarminDbPlugins
ข้อควรระวังในการใช้งาน
- หลังอัปเดตโค้ด อาจเกิดข้อยกเว้นเกี่ยวกับเวอร์ชัน DB ได้
- หมายความว่า DB schema ถูกอัปเดตแล้ว
- ต้อง rebuild DB ด้วย
garmindb_cli.py --rebuild_db - DB จะถูกสร้างใหม่จากไฟล์ข้อมูลที่ดาวน์โหลดไว้ก่อนหน้า และจะไม่ดาวน์โหลดข้อมูลทั้งหมดจาก Garmin ใหม่
- สคริปต์พัฒนาบน MacOS และรับข้อมูลการใช้งานหรือแพตช์สำหรับแพลตฟอร์มอื่น
- เมื่ออัปเดตฐานข้อมูลเสร็จแล้ว สรุปข้อมูลใน DB จะถูกบันทึกลง
stats.txt- รวมช่วงวันที่ของไฟล์การติดตามรายวันและกิจกรรมที่ดาวน์โหลดมา
- รวมจำนวนเรคอร์ดของการติดตามรายวัน, กิจกรรม, การนอนหลับ, อัตราการเต้นหัวใจขณะพัก, น้ำหนัก เป็นต้น
- ใช้ตรวจสอบได้ว่าดาวน์โหลดข้อมูลทั้งหมดจาก Garmin Connect แล้วหรือไม่
- หากมีข้อมูลขาดหาย ให้ปรับวันที่ใน
GarminConnectConfig.jsonแล้วรันการดาวน์โหลดอีกครั้ง
- ใน
GarminConnectConfig.jsonองค์ประกอบstepsของcourse_viewsคือรายการ course ID ที่จะใช้สร้าง DB view แยกตามคอร์ส- DB view ดังกล่าวช่วยเปรียบเทียบกิจกรรมทั้งหมดในคอร์สเดียวกันได้
รายงานบั๊กและการมีส่วนร่วม
- หากพบปัญหา ให้ลงทะเบียนบั๊กในแท็บ Issues ของโปรเจกต์
- รัน
make bugreportหรือgarmindb_bug_report.pyแล้วแนบbugreport.txtที่สร้างขึ้นในรายงานบั๊ก - หนึ่งในตำแหน่งแรก ๆ ที่ควรตรวจสอบข้อมูลเพิ่มเติมนอกเหนือจากข้อผิดพลาดที่แสดงบนหน้าจอคือ ไฟล์ล็อก
garmindb.log - หากปัญหาเกิดจากไฟล์ข้อมูลบางไฟล์ ให้พิจารณาแชร์ไฟล์นั้นเพื่อช่วยในการดีบักและเพิ่มการรองรับ
- การมีส่วนร่วมให้ส่ง Pull Request ไปยัง branch
develop - ก่อนส่ง ต้องรัน
make flake8ที่ไดเรกทอรีระดับบนสุดและแก้ไขข้อผิดพลาดทั้งหมด
2 ความคิดเห็น
ความคิดเห็นจาก Hacker News
คนที่คิดจะใช้สิ่งนี้ควรรู้ไว้ว่าใช้ Garth(https://github.com/matin/garth) สำหรับการยืนยันตัวตน
มันทำการยืนยันตัวตนแบบค่อนข้าง แฮ็ก ๆ โดยแสร้งว่าเป็นแอป Android และยังปลอมตัวเหมือนเป็นอินสแตนซ์เดียว เพื่อเลี่ยงการล็อกอินผ่านเว็บฟอร์ม
Garmin เป็นบริษัทที่เชื่อมต่อด้วยแล้วปวดหัวจริง ๆ และไม่รู้ว่าทำไมถึงล็อกไว้แน่นขนาดนี้ ต่อให้ได้สิทธิ์เข้าถึง API หรือ SDK อย่างเป็นทางการ คุณภาพก็มักจะแย่มาก
Garmin เคยถูกโจมตีด้วยแรนซัมแวร์ในปี 2020 และหลังจากบริการล่มไปหลายวันก็จ่ายเงิน 10 ล้านดอลลาร์ แต่ก็ไม่ได้จัดการปัญหานั้นอย่างจริงจัง
เหตุผลที่บริษัทต่าง ๆ ล็อกข้อมูลไว้ก็คล้ายกันหมด ผู้ใช้คือสินค้า และพวกเขาอยากผูกผู้ใช้ไว้ต่อไปเพื่อป้อนข้อมูลให้
เวลาคู่แข่งมีอุปกรณ์ที่ดีกว่าออกมา ผู้ใช้ต้องไม่สามารถหอบข้อมูลของตัวเองย้ายออกไปได้ เพราะถ้าเป็นแบบนั้น บริษัทก็ต้องแข่งขันให้หนักขึ้น
Garmin มีประวัติเฉื่อยชามากจนกว่าจะมีใครมาแข่งขันจริง ๆ พอตลาดสมาร์ตวอตช์เริ่มร้อนแรง ฟีเจอร์และรุ่นที่ดีกว่าก็ทะลักออกมาอย่างกะทันหัน ส่วนคอมพิวเตอร์จักรยานก็ไม่มีการอัปเดตกันเป็นปี ๆ จนกว่า Wahoo, Bryton, Coros, Hammerhead จะมาเคาะประตู
Strava ก็คล้ายกัน เมื่อก่อนการนำเข้า/ส่งออกข้อมูลค่อนข้างเสรี แต่หลังจากนั้นก็ล็อกลง ทำให้ การส่งออกข้อมูล แทบเป็นไปไม่ได้
ตอนนี้ดูเหมือนจะฟรี แต่ยังต้องได้รับการอนุมัติอยู่
https://developer.garmin.com/gc-developer-program/overview/
ถ้าจะใช้ข้อมูลส่วนตัวหรือส่งจากบริการหนึ่งไปอีกบริการหนึ่ง tapiriik เคยเป็นตัวเลือกที่ดี ไม่ได้ใช้มาหลายปีแล้ว เลยไม่รู้ว่าตอนนี้ยังเป็นแบบนั้นอยู่ไหม
https://tapiriik.com/
การออกแบบและความเสถียรก็ดีมาก ระบบรายงานอีเวนต์/พอยต์แบบ callback แข็งแรง ต่อให้โค้ดของผมพังหรือไม่เสถียร ฝั่ง Garmin ก็ retry ให้ และยังมีอินเทอร์เฟซดีบักที่ยอดเยี่ยมให้ดูว่าเกิดอะไรขึ้นเมื่อ webhook ล้มเหลว การซัพพอร์ตก็แม้จะไม่เร็ว แต่ก็อยู่ระดับยอดเยี่ยม
ช่วงแรกของการทำ implementation มีบั๊กแปลก ๆ ใน webhook คือทุกอีเวนต์เข้ามาสองครั้ง และหนึ่งในนั้นมี event timestamp ถูกตัดเหลือเป็นจำนวนเต็มระดับวินาที จาก user agent ก็เห็นได้ด้วยว่าฝั่งที่ถูกตัดนั้นเป็นซอฟต์แวร์เก่ากว่าอยู่หลายเวอร์ชัน
ผมส่งการวิเคราะห์นี้ทางอีเมลไป ประมาณ 12 ชั่วโมงต่อมาก็แก้ไขแล้ว และอีกราว 12 ชั่วโมงหลังจากนั้นวิศวกรตัวจริงก็ตอบกลับมา ขอบคุณสำหรับคำอธิบาย พร้อมบอกว่าเกิดขึ้นเพราะอะไร อย่างไร และแก้อะไรไปบ้าง
InReach โดยเฉพาะ InReach Professional API อาจใกล้เคียงผลิตภัณฑ์สำหรับมืออาชีพมากกว่าสินค้าผู้บริโภคล้วน ๆ แต่ Garmin เป็นบริษัทที่รู้วิธีทำเรื่องแบบนี้
เพื่อนแนะนำ Intervals(https://intervals.icu) ให้ใช้สำหรับขุดคุ้ยข้อมูลเกี่ยวกับ Garmin/Strava ซึ่งผมใช้แล้วค่อนข้างพอใจ
ในฐานะคนพายเรือ สิ่งที่ดีคือสามารถทำรายงานที่มีไม่ใช่แค่เมตริกจักรยาน/วิ่งที่พบทั่วไป แต่รวมถึง เมตริกเกี่ยวกับการพายเรือ ด้วย
แต่เมื่อเร็ว ๆ นี้ผมมีปัญหาอีกอย่างตอนพยายามติดตามการออกกำลังกาย Hyrox ถึงจะมี epix gen 2(800 ยูโร) ก็ยังติดตามให้ถูกต้องได้ยาก และแม้จะกำหนดการออกกำลังกายได้ แต่มันยุ่งยากเกินไปและก็ทำงานได้ไม่ดีนัก
สุดท้ายผมเลยสร้างแอปเอง ใช้ได้กับนาฬิกา Garmin ทุกเรือน สามารถกำหนดการออกกำลังกายแบบคงที่ แล้ววิเคราะห์ผลการทำแต่ละท่าได้
https://multisports.creatness.studio - ยังรอ Garmin อนุมัติการส่งขึ้นแอปสโตร์อยู่ แต่ตอนนี้ดาวน์โหลดแล้ว ไซด์โหลด เข้าไปในนาฬิกา Garmin ได้ และผมก็ใช้เองมาหลายสัปดาห์แล้ว
ตอนบันทึกกิจกรรมแบบอินเทอร์วัล เหมือนมันต้องการรูปแบบที่ไม่บันทึกช่วงพักระหว่างกลางรวมไปด้วย ซึ่งไม่สะดวก
แก้ไข: ผมจำผิด อันนี้ไม่ใช่ Intervals.icu แต่สับสนกับ runalyze
หากต้องการดึงข้อมูลดิบทั้งหมดจาก Garmin Connect ออกมาเป็น ไฟล์ FIT ก็ใช้การส่งออกข้อมูล(https://support.garmin.com/en-US/?faq=W1TvTPW8JZ6LfJSfK512Q8) ได้
ยังมีไลบรารีโอเพนซอร์สที่ดีสำหรับอ่านและตีความไฟล์เหล่านี้ด้วย เช่น https://github.com/polyvertex/fitdecode สำหรับ Python และ https://github.com/tormoder/fit สำหรับ Go
ถ้าอยากได้ข้อมูลปัจจุบัน ก็เชื่อมต่ออุปกรณ์ (นาฬิกา คอมพิวเตอร์จักรยาน ฯลฯ) เข้ากับคอมพิวเตอร์ เมานต์เป็นระบบไฟล์ แล้วดึงไฟล์ .FIT ปัจจุบันออกมาได้
เมื่อก่อนเคยเริ่มทำไซด์โปรเจกต์ที่ทำสิ่งนั้นเป๊ะ ๆ แต่เลิกไปกลางทาง
https://github.com/jo-m/garmin-disconnect
มีไฟล์ json 196 ไฟล์ รวม 228MB และทั้งหมดเป็นแค่สรุประดับสูง
ต้องใช้หนึ่งในไลบรารีส่งออกของบุคคลที่สามแบบแฮ็ก ๆ ถึงจะได้ไฟล์ fit จริง ๆ มา เป็น 5708 ไฟล์ ขนาด 373MB ถึงอย่างนั้นก็ยังมีไฟล์หาย ไฟล์ว่าง และไฟล์ซ้ำ ทำให้หงุดหงิดมาก
ได้บทเรียนว่าอย่าเชื่อว่าการส่งออกจากบริการออนไลน์จะครบถ้วนหรืออยู่ในรูปแบบที่คาดหวัง ถ้าเป็นบริการที่คุณพึ่งพาอยู่ ผมแนะนำอย่างยิ่งให้ลองส่งออกจริง ๆ แล้วตรวจดูว่ามีข้อมูลที่ต้องการอยู่หรือไม่
Garmin ควรยอมรับกระแสแบบนี้จริง ๆ ถ้าทางเลือกคือการพึ่งพาแอปสมาร์ตโฟน ในระยะยาว Garmin จะถูกเบียดตกไป
ข้อดีใหญ่ของการซื้อ ฮาร์ดแวร์เฉพาะทาง อย่างคอมพิวเตอร์จักรยาน Garmin คือการมีสิทธิ์ควบคุมข้อมูลมากกว่า
เอกสารแย่อย่างไม่น่าเชื่อ ครึ่งหนึ่งต้องค้นพบด้วยการลองผิดลองถูก และถึงอย่างนั้นก็ยังไม่รู้ว่าควรบิลด์และทดสอบบนรุ่นอื่นนอกจากนาฬิกาที่ผมมีได้อย่างไร
ผมยินดีจะขัดเกลาแอปแล้วนำขึ้นสโตร์ และคิดว่าน่าจะมีประโยชน์กับบางคน แต่ความพยายามที่ต้องลงดูจะมากกว่าคุณค่าที่ได้มาก
คาดหวังว่าจะมี ซินเนอร์จี อยู่บ้าง แต่กลับไม่มีอะไรเลย ถ้าบันทึกกิจกรรมเดียวกันพร้อมกันด้วยสองอุปกรณ์ ก็เกิดแค่รายการซ้ำ เช่น ระยะทางที่ได้กลายเป็นผลรวมของระยะที่สองอุปกรณ์วัด
แย่ยิ่งกว่าการใช้อุปกรณ์คนละแบรนด์สองเครื่องเสียอีก
มีอุปกรณ์ลักษณะคล้ายกันที่ไม่ขัดขวางผู้ใช้ที่ต้องการเข้าถึงข้อมูลของตัวเองไหม?
ผมประหลาดใจอยู่เสมอว่ามีข้อมูลถูกล็อกไว้ใน SDK เก่า ๆ ของ Garmin มากแค่ไหน
เช่น รูปแบบไฟล์ FIT ที่ใช้เขียนโปรแกรมการฝึกซ้อมบนคอมพิวเตอร์จักรยานทุกเครื่อง กลับมีแอปแค่หนึ่งหรือสองตัวที่รองรับ
สุดท้ายอาจเป็นความผิดของพวกเราเองก็ได้ และเราอาจต้องสร้างของเองบน SDK นั้น
ถ้าไม่ใช่เพื่อวางแผนการฝึกซ้อม แอปที่อ่านหรือเขียนไฟล์ FIT ได้มีมากกว่าสองตัวเยอะ ผมเองก็ทำหนึ่งในนั้น
ไม่ใช่แค่เข้าถึง API ยากเท่านั้น แต่ Garmin ไม่ฟังเสียงชุมชนเลย
เช่น ไม่สามารถกรองหา กิจกรรมที่ไม่มีอุปกรณ์ ได้ บางครั้งผมลืมเพิ่มจักรยานหรือรองเท้า ดังนั้นถ้ามีตัวกรองแบบนั้นจะช่วยได้มาก
การเพิ่มตัวกรองนั้นในแอปหรือเว็บไซต์ Connect น่าจะง่ายมาก แต่ไม่มี community manager จึงมีส่วนร่วมไม่ได้
ถ้ามีตัวติดตามสาธารณะให้ผู้คนขอฟีเจอร์ได้ Garmin ก็สามารถพิจารณาสิ่งเหล่านี้เพื่อทำผลิตภัณฑ์ให้ดีขึ้นและทำเงินได้มากขึ้น
สัปดาห์นี้ผมซื้อ Garmin Vivoactive5 เครื่องใหม่ เพราะ Vivoactive3 เครื่องเก่าพัง
ตอนนี้ค่อนข้างพอใจ แต่ซื้อมาโดยรู้ว่า API และความเป็นไปได้ของ Garmin นั้น ไม่ใช่สิ่งที่ดีที่สุดเลย
เคยพิจารณา Apple Watch Series 10 ด้วย แต่สุดท้ายก็ถอดใจ เพราะแบตเตอรี่ไม่อยู่เกิน 1.5 วัน แทบไม่ได้ใช้การส่งข้อความหรือแอปอัจฉริยะนอกเหนือจากฟีเจอร์สุขภาพ และราคาก็เป็นสองเท่าของ Vivoactive
อยากให้มี นาฬิกาแบบเปิด ที่แฮ็กได้ มี API ดี ๆ โฮสต์แดชบอร์ดเองได้ และมีแอปที่ใช้ได้ดี รู้สึกว่ามีตลาดสำหรับคนแบบผมอยู่ การกลับมาของ Pebble อาจเติมช่องว่างนี้ได้ก็ได้
ผมนึกว่าจะเป็นวิธีดึงข้อมูลจากอุปกรณ์โดยตรงเพื่อนำมาติดตาม แต่ดูแล้วเป็นการคุยกับ Connect API จึงยังผูกกับแอปทางการอยู่
รูปแบบไฟล์ก็เลือกได้ระหว่าง gpx, fit, tcx
ผมตั้งค่าสิ่งนี้ไว้เมื่อไม่กี่เดือนก่อน เก็บข้อมูลไว้ใน ฐานข้อมูล sqlite ในเครื่อง และรันสคริปต์วันละครั้งเพื่อดึงข้อมูลใหม่
ใช้เวลานานกว่าที่คิดพอสมควร ทั้งที่นาฬิกาซิงก์ข้อมูลเดียวกันกับโทรศัพท์ใช้แค่ประมาณ 1 วินาที จึงเหมือนว่าข้างในมีความไร้ประสิทธิภาพร้ายแรงอยู่ ยังไม่มีโอกาสดูข้างในอย่างละเอียด
ขอบคุณครับ/ค่ะ ด้วยความช่วยเหลือของคุณ ผมนำไปปรับใช้ได้เรียบร้อยแล้ว