คู่มือการสอนฉบับสมบูรณ์: ติดตั้ง n8n, ออกแบบบอททุกประเภท & เจาะลึกการเขียนสคริปต์
รวบรวมครบจบในที่เดียว: ติดตั้ง Local ➔ นำเข้า Docker ➔ สถาปัตยกรรม 7 โหนด ➔ กฎ 4 เลเยอร์สร้างบอท ➔ แคตตาล็อกโหนด ➔ ชำแหละสคริปต์แจ้งเตือนบรรทัดต่อบรรทัด
บทที่ 1: ขั้นตอนการติดตั้ง n8n บนเครื่อง Local (Windows) ตั้งแต่ 0
สำหรับผู้เริ่มต้นที่ยังไม่มีโปรแกรมอะไรในเครื่องเลย ทดลองต่อโหนดบนเครื่องตัวเองก่อนนำขึ้นระบบจริง
ติดตั้ง Node.js (เครื่องยนต์รันโปรแกรม)
n8n พัฒนาด้วย JavaScript บน Node.js ผู้เรียนต้องติดตั้งเวอร์ชัน LTS (แนะนำ v20.x ขึ้นไป)
node -v
npm -v
คำสั่งรัน n8n บนเครื่อง Local (2 ทางเลือก)
npx n8n
npm install n8n -g
n8n start
เข้าใช้งาน Web UI ครั้งแรก
เมื่อขึ้นข้อความว่า "Editor is now accessible via:" ให้เปิดเบราว์เซอร์ไปที่:
การ Export Workflow ออกเป็นไฟล์ JSON
เมื่อต่อโหนดบน Local เสร็จ ให้ดึงไฟล์ออกมาเพื่อเตรียมเอาเข้า Docker:
- ผ่านหน้าเว็บ: กดเมนูจุด 3 จุดมุมบนขวาใน Workflow ➔ เลือก Download
- ผ่าน Terminal:
n8n export:workflow --all --output=backup.json
บทที่ 2: ขั้นตอนนำ n8n เข้าสู่ Docker ในโปรเจกต์ (Production 24/7)
เปลี่ยนจากการเปิด Terminal ค้างไว้ มาเป็นบริการในเบื้องหลังที่รันอัตโนมัติและเชื่อมคุยกับ Frigate
📌 ทำไมต้องย้ายเข้า Docker ในโปรเจกต์?
- ทำงาน 24 ชั่วโมงอัตโนมัติ: รีบูตเครื่องคอมพิวเตอร์ Container ก็ยังคงสตาร์ทขึ้นมาเองอัตโนมัติ
- เชื่อมต่อ Frigate/กล้องโดยตรง: สามารถยิง API หา Frigate ที่
http://frigate:5000ผ่านเครือข่าย Docker ภายในได้เลย ไม่ต้องผ่านอินเทอร์เน็ต - Named Volume (
n8n-data): โหนดและการตั้งค่าทั้งหมดถูกเซฟลงฮาร์ดดิสก์ถาวร ปิดคอนเทนเนอร์ข้อมูลก็ไม่หาย
💻 คำสั่ง Terminal ที่ใช้สอน:
# เข้าโฟลเดอร์ Frigate NVR
cd D:\BPP-VMS\frigate-nvr
# สตาร์ท n8n service บน Docker
docker compose up -d n8n
# นำไฟล์ workflow จาก Local import เข้าสู่ Container
docker exec n8n-service n8n import:workflow --input=/n8n-init/workflows/bpp_vms_master_bot_workflow.json
# สั่ง restart n8n container 1 ครั้งเพื่อโหลดค่าใหม่
docker restart n8n-service
บทที่ 3: สถาปัตยกรรม 7 โหนดของ BPP-VMS & การสกัดข้อมูล (Data Extraction)
ทำความเข้าใจบทบาทของแต่ละโหนดในระบบจริง พร้อมการสกัดข้อความ (AI) และภาพถ่าย (EXIF)
AI Intelligence Agent (การสกัดข้อมูลข้อความภาษาไทย)
@n8n/n8n-nodes-langchain.agentบทที่ 4: กฎเหล็กสากล 4 เลเยอร์ (IPO Model) & 4 ตระกูลบอทยอดนิยม
หลักคิดการออกแบบบอททุกตัวในโลก ก่อนเริ่มต่อโหนดบนกระดาน Canvas
คนทักแชท LINE, กล้องจับป้ายทะเบียนได้, หรือถึงเวลา 08:00 น.
แยกประเภทข้อความ (Switch), ไปดึงประวัติเก่าจาก Database มาประกอบ
ใช้ AI LLM ตีความภาษา สกัด Entity หรือใช้ Code คำนวณตรรกะ/GPS
ตอบกลับแชท, ยิง Alert เข้า Telegram, บันทึกลงตาราง หรือสั่งเปิดไม้กั้น
💬 1. Conversational & Extraction Bot
ตอบแชทเจ้าหน้าที่ รับรายงานเหตุการณ์ แล้วสกัดชื่อ, ของกลาง, ทะเบียน, พิกัด
🚨 2. Event-Driven Alert Bot
เฝ้าระวังสัญญาณจากกล้อง LPR เมื่อเจอป้ายเฝ้าระวัง ให้ยิงรูปพร้อมพิกัดแจ้งชุดจับกุมทันที
⏰ 3. Scheduled Report Bot
ทำงานตามเวลา เช่น ทุก 07:00 น. สรุปสถิติรถผ่านด่านรอบ 24 ชม. ส่งผู้บังคับบัญชา
🔄 4. Data Sync & ETL Bot
รับรูปภาพ สกัด EXIF GPS บันทึกลงฐานข้อมูล และส่งต่อไปแสดงผลบน Heatmap / i2
บทที่ 5: สารานุกรมประเภทโหนดใน n8n (5 หมวดหมู่หลัก)
คลิกเลือกหมวดหมู่โหนดด้านล่างเพื่อดูหน้าที่ การใช้งานจริง และตัวอย่างโหนด
บทที่ 6: ชำแหละสคริปต์ Code Node บอทแจ้งเตือนทุกรูปแบบ ละเอียดทุกบรรทัด ทุกคำศัพท์
คู่มือสอนเขียนสคริปต์การแจ้งเตือนทั้งหมด 4 รูปแบบจริงของระบบ BPP-VMS (ตชด.215) ฉบับคนเพิ่งเริ่มเขียนโปรแกรม พร้อมตาราง 4 มิติ และพรีวิว Telegram & LINE
ภาคปูพื้นฐาน: "คู่มือภาษา JavaScript ฉบับคนเพิ่งเริ่มเขียนโปรแกรม" (Beginner Foundation)
คือภาษา JavaScript (Node.js ES6+) ซึ่งเป็นภาษายอดนิยมอันดับ 1 ของโลก และเป็นภาษาดั้งเดิม (Native) ที่ n8n ใช้งานเป็นเครื่องยนต์หลัก
เพราะ JavaScript เกิดมาเพื่อจัดการข้อมูลแบบ JSON ได้เร็วที่สุดระดับมิลลิวินาที ไม่ต้องคอมไพล์ รันคำสั่งได้ทันทีที่เหตุการณ์กล้องส่งข้อมูลเข้ามา!
const= กล่องเก็บของห้ามเปลี่ยนค่า (ปลอดภัยที่สุด)let= กล่องเก็บของที่ยอมให้เปลี่ยนค่าใหม่ได้Dot Notation (.)= เช่นbody.plateคือเปิดกล่อง body แล้วหยิบของชื่อ plate|| (OR Fallback)= ถ้าซ้ายมือเป็นค่าว่าง ให้ใช้ค่าสำรองฝั่งขวา (กันระบบพัง)`...` (Backticks)= ข้อความที่แทรกตัวแปรตรงๆ ด้วย${ตัวแปร}
$input.item.json เพื่ออ่านก้อนข้อมูลจากโหนดก่อนหน้า
return { json: { ... } }; เสมอ หากส่งข้อความเปล่า โหนดถัดไปจะอ่านไม่เจอ!
|| {} หรือ || 'ไม่ระบุ' เสมอ ป้องกันระบบ Crash
ทำงานเมื่อกล้องตรวจจับป้ายทะเบียน (LPR) อ่านแผ่นป้ายแล้วตรวจพบว่าตรงกับบัญชีเฝ้าระวัง หมายจับ หรือรถต้องสงสัยในฐานข้อมูล BPP-VMS สคริปต์นี้จะสกัดข้อมูลรถ เจ้าของ ระดับอันตราย และสร้างลิงก์คลิปวิดีโอ VMS พร้อมส่งแจ้งเตือนทันที
// =========================================================================
// สคริปต์ที่ 1: จัดการแจ้งเตือนป้ายทะเบียนรถต้องสงสัย (LPR Watchlist Alert)
// ภาษา: JavaScript (Node.js ES6+) บน n8n Code Node
// =========================================================================
// 1. ดึงข้อมูล JSON ที่ได้รับจากโหนดก่อนหน้า พร้อมใส่ || {} ดักค่าว่างป้องกัน Error
const body = $input.item.json.body || {};
// 2. สกัดฟิลด์ข้อมูลสำคัญ (ตรวจจับชื่อกล้องอัตโนมัติ ถ้าไม่มีให้ใส่ชื่อกลุ่มกล้องแทน)
const plate = body.plate || '1กข 4567';
const province = body.province || 'สุรินทร์';
// ดึงชื่อกล้องก่อน (camera_name หรือ camera) หากไม่มีให้สลับไปดึงชื่อกลุ่มกล้อง (camera_group หรือ group) แทน
const camera = body.camera_name || body.camera || body.camera_group || body.group || 'cam-checkpoint-01 (ด่านตรวจหนองกวาง)';
const timestamp = body.timestamp || new Date().toLocaleString('th-TH', { timeZone: 'Asia/Bangkok' });
const dangerLevel = body.danger_level || '🔴 อันตรายสูง (หมายจับคดียาเสพติด)';
const ownerName = body.owner_name || 'นายสมพร ใจกล้า';
const eventId = body.event_id || 'ev-lpr-992140';
// 3. สร้างลิงก์คลิปวิดีโอเหตุการณ์ย้อนหลัง (VMS Clip URL) สำหรับให้เจ้าหน้าที่กดดูบนมือถือ
const serverHost = 'vms.bpp215.police.go.th';
const clipUrl = `https://${serverHost}/clip.html?id=${eventId}&cam=${encodeURIComponent(camera)}&type=lpr`;
// 4. จัดรูปแบบข้อความแจ้งเตือนสำหรับ Telegram Bot (รองรับ HTML แท็ก <b>, <a>, <code>)
const telegramMessage = `🚨 [แจ้งเตือนด่วน BPP-VMS: พบรถต้องสงสัย!]
━━━━━━━━━━━━━━━━━━
🚗 ทะเบียน: ${plate}
📍 จังหวัด: ${province}
⚠️ ระดับอันตราย: ${dangerLevel}
👤 ผู้ครอบครอง/เฝ้าระวัง: ${ownerName}
🎥 กล้องตรวจจับ: ${camera}
🕒 เวลา: ${timestamp}
🎬 ดูคลิปย้อนหลัง: <a href="${clipUrl}">▶️ คลิกเพื่อเปิดดูวิดีโอ (MP4)</a>
🆔 Event ID: <code>${eventId}</code>
━━━━━━━━━━━━━━━━━━`;
// 5. จัดรูปแบบข้อความแจ้งเตือนสำหรับ LINE (จัดแบบข้อความธรรมดาพร้อมสัญลักษณ์ชัดเจน)
const lineMessage = `🚨 [แจ้งเตือนด่วน BPP-VMS: พบรถต้องสงสัย!]
----------------------------------
🚗 ทะเบียน: ${plate}
📍 จังหวัด: ${province}
⚠️ ระดับอันตราย: ${dangerLevel}
👤 ผู้เฝ้าระวัง: ${ownerName}
🎥 กล้อง: ${camera}
🕒 เวลา: ${timestamp}
🎬 ดูคลิป: ${clipUrl}
🆔 Event: ${eventId}`;
// 6. ส่งผลลัพธ์ออกตามโครงสร้างบังคับของ n8n: ครอบด้วย { json: { ... } } เสมอ!
return {
json: {
alert_type: 'LPR_WATCHLIST',
plate: plate,
province: province,
camera: camera,
timestamp: timestamp,
danger_level: dangerLevel,
owner_name: ownerName,
clip_url: clipUrl,
event_id: eventId,
telegram_text: telegramMessage,
telegram_parse_mode: 'HTML',
line_text: lineMessage,
broadcast_ready: true
}
};
คู่มือชำแหละโค้ด 6 หมวดหมู่แบบจับมือทำ: ทำไมต้องเขียนแบบนี้ & เพราะอะไร (Line-by-Line & Keyword Deep Dive)
อธิบายละเอียดยิบทุกบรรทัด ทุกคำศัพท์ ทุกตัวแปร และผลกระทบเชิงระบบหากไม่เขียนตามนี้
- const: คำสั่งสร้างกล่องเก็บข้อมูลแบบ "ค่าคงที่" ห้ามโค้ดบรรทัดอื่นมาเขียนทับ ปลอดภัยสูงสุด
- $input.item.json: วัตถุ Built-in ของ n8n เพื่อเข้าถึงก้อนข้อมูล JSON แถวปัจจุบันที่ส่งมาจากโหนดก่อนหน้า
- .body: เปิดเข้าไปในคีย์ย่อยชื่อ
bodyซึ่งบรรจุเนื้อหาที่ Webhook ของกล้องส่งมา - || {} (เสื้อชูชีพกันระบบล่ม): ทำไมต้องเขียน? หาก Webhook ส่งข้อมูลว่างเปล่ามา การใส่
|| {}จะเปลี่ยนค่าundefinedให้เป็นออบเจกต์ว่างเปล่า{}ทันที หากไม่ใส่ โค้ดบรรทัดต่อไปที่เรียกbody.plateจะเกิดข้อผิดพลาดรุนแรงTypeError: Cannot read properties of undefinedทำให้บอทหยุดทำงานทันที!
ทำไมต้องแยกเป็น 7 บรรทัดและมี || 'ค่าเริ่มต้น' ทุกบรรทัด?
const plate = body.plate || '1กข 4567';const province = body.province || 'สุรินทร์';undefined บนหน้าจอเจ้าหน้าที่const camera = body.camera_name || body.camera || body.camera_group || body.group || '...';camera_name หรือ camera) ก่อนเป็นอันดับแรก หากไม่มี ให้สลับไปดึงชื่อกลุ่มกล้อง (camera_group หรือ group) แทน เพื่อให้ศูนย์สั่งการทราบโซนเกิดเหตุเสมอ ป้องกันค่าว่างconst timestamp = body.timestamp || new Date().toLocaleString(...);new Date().toLocaleString('th-TH', { timeZone: 'Asia/Bangkok' }) บังคับเวลาไทย UTC+7 ป้องกันเวลาบอทช้ากว่าเวลาจริง 7 ชม. จาก Docker Serverconst dangerLevel = body.danger_level || '🔴 อันตรายสูง...';const eventId = body.event_id || 'ev-lpr-992140';const clipUrl = `https://${serverHost}/clip.html?id=${eventId}&cam=${encodeURIComponent(camera)}&type=lpr`;
- serverHost: แยกโดเมนแม่ข่ายออกมา เพื่อให้แก้ไขง่ายในจุดเดียวเมื่อเปลี่ยน IP/Domain
- เครื่องหมาย Backtick `...` & ${...}: แม่พิมพ์ข้อความเชื่อมตัวแปรโดยไม่ต้องใช้เครื่องหมายบวก
+ให้ตาลาย - encodeURIComponent(camera): ทำไมต้องมี? ตัวแปร
cameraมีภาษาไทยและช่องว่าง หากใส่เข้าไปใน URL ตรงๆ ลิงก์จะขาดและกดเปิดวิดีโอบนสมาร์ตโฟนไม่ติด ฟังก์ชันนี้จะแปลงภาษาไทยเป็นรหัส URL สากล (เช่น%E0%B8...) ทำให้เปิดคลิปได้ 100%
• ใช้แท็ก <b>...</b> ทำตัวหนาเน้นหัวข้อ
• ใช้แท็ก <a href="...">...</a> แปลงลิงก์ยาวยืดเป็นปุ่มคลิกดูคลิปสั้นๆ
• ใช้แท็ก <code>${eventId}</code> ฟีเจอร์พิเศษของ Telegram: แตะที่ Event ID 1 ครั้งจะคัดลอกลงคลิปบอร์ดทันที!
• ทำไมต้องแยกตัวแปรกับ Telegram? เพราะ LINE ไม่รองรับแท็ก HTML หากส่ง <b> ไป LINE จะโชว์แท็กดิบๆ บนจออย่างน่าเกลียด
• LINE จึงต้องใช้ข้อความธรรมดา (Plain Text) และวางลิงก์ ${clipUrl} ตรงๆ เพื่อให้แอป LINE แปลงเป็นลิงก์กดได้อัตโนมัติ
- กฎเหล็กสูงสุดของ n8n: ข้อมูลที่จะส่งให้โหนดถัดไป (เช่น โหนด Telegram Bot หรือโหนด HTTP Request ของ LINE) ต้องครอบด้วยออบเจกต์ที่มีคีย์ชื่อว่า
jsonเสมอ หาก return ข้อความเปล่าๆ โหนดถัดไปจะอ่านไม่เจอ (No data returned) - telegram_parse_mode: 'HTML': สั่งให้โหนด Telegram Bot เรนเดอร์แท็กตัวหนาและลิงก์คลิป
- broadcast_ready: true: ตัวแปรยืนยันความสมบูรณ์เพื่อให้โหนด Switch หรือ Filter ถัดไปตรวจสอบก่อนยิงแจ้งเตือน
| ท่อนโค้ด / คำสั่งสคริปต์ | คืออะไร & หมายความว่ายังไง? | ทำทำไม? (เหตุผล & ตรรกะ) | ทำแล้วได้อะไร? (ผลลัพธ์) |
|---|---|---|---|
|
const body = $input.item.json.body || {};
🔴 กฎเหล็ก
|
ประกาศตัวแปรคงที่ const เพื่อรับข้อมูลจากโหนดก่อนหน้าผ่าน $input.item.json และใส่ || {} ป้องกันกรณีไม่มีฟิลด์ body
|
ป้องกัน Runtime Crash ข้อผิดพลาด Cannot read property of undefined หาก Webhook ส่งข้อมูลมาไม่ครบ
|
ได้ออบเจกต์ body ที่ปลอดภัย 100% ต่อให้ไม่มีข้อมูลก็ไม่ทำให้สคริปต์พังกลางคัน
|
|
const plate = body.plate || '1กข 4567';
🟡 ค่าสำรอง
|
อ่านค่าหมายเลขทะเบียนรถจาก body.plate ถ้าไม่มีค่าให้ใช้ค่าสตริงตัวอย่าง '1กข 4567'
|
ในการทดสอบรันบน n8n ผู้เรียนอาจยิง JSON ว่างเข้ามา การมี Fallback ช่วยให้เห็นหน้าตาผลลัพธ์โดยไม่ต้องกรอกข้อมูลครบทุกฟิลด์ |
ข้อความแจ้งเตือนจะมีเลขทะเบียนรถปรากฏเสมอ ไม่กลายเป็นคำว่า undefined บนหน้าจอเจ้าหน้าที่
|
|
const province = body.province || 'สุรินทร์';
|
อ่านค่าจังหวัดจาก body.province พร้อมสำรองค่าจังหวัดที่ตั้งศูนย์
|
กล้อง LPR บางมุมอาจจับภาพจังหวัดไม่ชัด การมี Fallback ช่วยรักษาฟอร์แมตข้อความให้สมบูรณ์ | ข้อความแจ้งเตือนมีชื่อจังหวัดแสดงเสมอ ป้องกันเจ้าหน้าที่สับสน |
|
const camera = body.camera_name || body.camera || body.camera_group || body.group || '...';
⚡ Auto Camera / Group Detect
|
ตรวจจับชื่อกล้องอัตโนมัติ (camera_name หรือ camera) หากไม่มีให้สลับไปดึงชื่อกลุ่มกล้อง (camera_group หรือ group) แทนแบบ Cascading Fallback | กรณีกล้องบางจุดยังไม่ได้ตั้งชื่อเฉพาะ หรือเป็นกล้องที่ดึงผ่านสตรีมแบบกลุ่ม การดึงชื่อกลุ่มกล้องแทนจะช่วยให้ศูนย์สั่งการยังรู้ว่าเกิดเหตุในโซน/สายทางใด | ได้ตำแหน่งกล้องหรือโซนกลุ่มกล้องเสมอ 100% ไม่ว่างเปล่าและไม่ขึ้นคำว่า undefined |
|
new Date().toLocaleString('th-TH', { timeZone: 'Asia/Bangkok' })
⚡ เวลาไทย
|
ฟังก์ชันแปลงเวลาปัจจุบันของระบบเป็นรูปแบบภาษาไทยและล็อกเขตเวลาเป็นเวลาประเทศไทย (UTC+7) | Server n8n มักตั้งค่าเวลาเครื่องเป็น UTC หากไม่กำหนดเขตเวลา เวลาในข้อความจะช้ากว่าเวลาจริง 7 ชั่วโมง | วันเวลาเกิดเหตุตรงกับเวลาจริงในประเทศไทย 100% ใช้เป็นหลักฐานทางคดีได้ทันที |
|
encodeURIComponent(camera)
🔴 สำคัญมาก
|
ฟังก์ชันแปลงอักขระพิเศษและภาษาไทย เช่น เว้นวรรค วงเล็บ หรือสระ ให้เป็นรหัส URL เปอร์เซ็นต์ (เช่น %20)
|
ชื่อกล้องภาษาไทยถ้าต่อเข้าไปใน URL โดยตรง ลิงก์จะขาด หรือเบราว์เซอร์จะไม่สามารถเปิดวิดีโอคลิปได้ | ได้ลิงก์เปิดคลิปวิดีโอที่คลิกแล้วทำงานได้บนสมาร์ตโฟนและคอมพิวเตอร์ทุกเครื่อง 100% |
|
<b>...</b>, <a href="...">, <code>
|
แท็กภาษา HTML ที่ Telegram Bot API รองรับสำหรับการจัดรูปแบบข้อความ |
สร้างตัวหนา แปลง URL ยาวยืดให้เป็นปุ่มคลิก และแท็ก <code> ช่วยให้แตะเพื่อคัดลอก Event ID ได้ทันที
|
ข้อความอ่านง่าย เป็นระเบียบ สะดวกต่อการใช้งานบนหน้าจอมือถือสายตรวจ |
|
const lineMessage = `...`;
|
ตัวแปรเก็บข้อความสำหรับส่งเข้า LINE โดยใช้ Plain Text ปราศจากแท็ก HTML | LINE ไม่รองรับแท็ก HTML หากนำข้อความของ Telegram มาส่งจะเห็นแท็กหลุดออกมาบนหน้าจอ | ข้อความบน LINE สวยงาม สะอาดตา และลิงก์คลิปวิดีโอคลิกได้ปกติ |
|
return { json: { ... } };
🔴 กฎเหล็ก
|
ส่งผลลัพธ์กลับสู่ Workflow โดยต้องครอบด้วยออบเจกต์ที่มีคีย์ชื่อว่า json
|
n8n ถูกออกแบบให้ประมวลผลข้อมูลผ่านคีย์ json หาก return สตริงเปล่าๆ โหนดถัดไปจะแจ้งว่า "No data returned"
|
ข้อมูลทั้งหมดถูกส่งต่อไปยังโหนด Telegram, LINE หรือ Respond to Webhook ได้อย่างราบรื่น |
{
"type": "alert",
"body": {
"plate": "2ขง 8899",
"province": "สุรินทร์",
"camera_name": "กล้องด่านตรวจหนองกวาง 01",
"camera": "cam-checkpoint-01",
"camera_group": "กลุ่มจุดตรวจหลักสาย 333",
"danger_level": "🔴 อันตรายสูงสุด (หมายจับคดียาเสพติดร้ายแรง)",
"owner_name": "นายวันชัย ดวงแก้ว",
"event_id": "ev-lpr-20260910-01"
}
}
💡 วิธีทดสอบ: คัดลอก JSON ด้านบนนี้ไปวางในคำสั่ง cURL หรือยิงเข้า Webhook URL โหนดแรกของท่านเพื่อทดสอบการฟอร์แมต
คู่มือการติดตั้งและตั้งค่า Telegram Bot เมื่อนำระบบ BPP-VMS ไปลงเครื่องใหม่
ขั้นตอนการสร้างบอตกับ @BotFather, การหา Chat ID (แชทเดี่ยว & กลุ่มสายตรวจ), การกรอกค่าใน .env และ n8n Credential พร้อมคำสั่งทดสอบ 1-Click Verification
เปิดแอป Telegram บนมือถือหรือ PC แล้วค้นหาผู้ใช้ชื่อ @BotFather (ต้องมีเครื่องหมายติ๊กถูกสีฟ้า Verified เท่านั้น ป้องกันบอตปลอม)
BPP-VMS Alert Botbpp215_surin_alert_bot (ห้ามซ้ำกับผู้อื่น)7182938475:AAFl9xK... (เก็บเป็นความลับ ห้ามเผยแพร่)- พิมพ์คำสั่ง
/setprivacy➔ เลือกบอต ➔ กดเลือก Disable (เพื่อให้บอตอ่านข้อความคำสั่งและรูปภาพในกลุ่มสายตรวจได้) - พิมพ์คำสั่ง
/setjoingroups➔ เลือกบอต ➔ กดเลือก Enable (อนุญาตให้ดึงเข้ากลุ่มได้)
1. ทักบอตที่เราเพิ่งสร้าง แล้วกดปุ่ม Start (หรือพิมพ์ /start) 1 ครั้ง เพื่อเปิดสิทธิ์ให้บอตส่งข้อความหาเราได้
2. ไปที่บอต @userinfobot หรือ @RawDataBot แล้วกด Start จะได้ตัวเลข Id: 123456789 (เป็นเลขบวก)
- ดึงบอตที่เราสร้างเข้ากลุ่มสายตรวจ
- ตั้งค่าบอตให้เป็น "Admin" ของกลุ่ม: เปิดสิทธิ์ Send Messages, Send Photos, Embed Links
- ดึงบอต
@RawDataBotเข้ากลุ่มชั่วคราว แล้วมองหาบรรทัด"chat": { "id": -100xxxxxxxxxx } - เมื่อได้เลขแล้ว ให้เตะ @RawDataBot ออกจากกลุ่มได้ทันที
Chat ID ของกลุ่ม Telegram ต้องมีเครื่องหมายลบ - หรือ -100 นำหน้าเสมอ! เช่น -1002148921456
หากเผลอตัดเครื่องหมายลบออก บอตจะส่งไม่ไปและเกิดข้อผิดพลาด 400 Bad Request: chat not found ทันที!
เปิดไฟล์ frigate-nvr/.env บนเครื่องเซิร์ฟเวอร์ใหม่ แล้วกรอกค่าทั้ง 3 บรรทัด:
# 1. แจ้งเตือนป้ายทะเบียน LPR และ AI ตรวจจับวัตถุประจำกล้อง
LPR_TELEGRAM_BOT_TOKEN=7182938475:AAFl9xKxxxxxxxxxxxxxxxxxxxxx
LPR_TELEGRAM_CHAT_ID=-1002148921456
# 2. บอตสืบสวนแฟ้มคดี NAS และสกัดพิกัด GPS ภาพถ่าย (nas-bot-service)
TELEGRAM_BOT_TOKEN=7182938475:AAFl9xKxxxxxxxxxxxxxxxxxxxxx
docker compose up -d lpr-service nas-bot-service
- เข้าหน้าเว็บ n8n:
http://<IP_เครื่องใหม่>:5678 - ไปที่เมนู Credentials (ไอคอนรูปกุญแจ) ➔ คลิก Add Credential
- พิมพ์ค้นหา Telegram API ➔ วางค่า Access Token ที่ได้จาก @BotFather ➔ คลิก Save
- ใน Workflow ของ Chapter 3 ให้เลือก Credential นี้ แล้วใส่
Chat IDที่ช่องปลายทาง
ก่อนเปิดใช้งานระบบจริง ให้ทดสอบยิงข้อความผ่านคำสั่ง Terminal บนเครื่องใหม่ เพื่อยืนยันว่า Token และ Chat ID ใช้งานได้ 100%:
curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" -d "chat_id=<CHAT_ID>" -d "text=🚨 [ทดสอบระบบ BPP-VMS] บอตเชื่อมต่อเครื่องใหม่สำเร็จเรียบร้อยแล้วครับ! 🟢" -d "parse_mode=HTML"
docker exec -it lpr-service python -c "from app import send_telegram_alert; send_telegram_alert('🚨 ทดสอบส่งแจ้งเตือนจากเครื่องใหม่สำเร็จ 100%', None)"
| รหัสข้อผิดพลาด / อาการ | สาเหตุที่แท้จริง | วิธีแก้ไขหน้างาน | วิธีป้องกันในระยะยาว |
|---|---|---|---|
| 401 Unauthorized | Token ไม่ถูกต้อง, มีช่องว่างเกิน หรือคัดลอกมาไม่ครบทุกตัวอักษร |
กลับไปที่ @BotFather พิมพ์ /token แล้วคัดลอก Token ทั้งชุดมาวางใหม่ใน .env
|
ห้ามแก้ไข Token ด้วยมือ ให้ใช้การคลิกคัดลอกโดยตรงจาก Telegram |
| 400 Bad Request: chat not found |
1. แชทส่วนตัว: ผู้รับยังไม่เคยกด /start กับบอต2. แชทกลุ่ม: ลืมใส่เครื่องหมายลบ -100
|
- แชทส่วนตัว: ทักบอตแล้วกดปุ่ม Start 1 ครั้ง - แชทกลุ่ม: ตรวจสอบ Chat ID ให้ขึ้นต้นด้วย -100 เช่น -1002148921456
|
ดึงบอต @RawDataBot เข้ากลุ่มเพื่อตรวจสอบ ID ที่มีเครื่องหมายลบติดมาให้แน่นอน |
| 400 Bad Request: can't parse entities |
ข้อความมีแท็ก HTML ผิดรูปแบบ เช่น มี <b> แต่ไม่มี </b> ปิด
|
ตรวจเช็กใน Code Node ให้ปิดแท็ก HTML ให้ครบ หรือส่งข้อความสำรองแบบ Plain Text |
ใช้ Helper Function ปิดแท็กอัตโนมัติ หรือใช้ Fallback plain_text ในสคริปต์
|
| 403 Forbidden: not enough rights to send photos | บอตในกลุ่มสายตรวจไม่ได้สิทธิ์ส่งภาพ หรือกลุ่มล็อกสิทธิ์ไม่ให้สมาชิกส่งมีเดีย | เข้าไปที่ Group Settings ➔ Administrators ➔ ตั้งบอตเป็น Admin และเปิดสิทธิ์ Post Photos & Links | ตั้งบอตเป็น Admin เสมอเมื่อใช้งานในกลุ่มภารกิจความมั่นคง |