# IP-PA System > network solution for smart enterprise ## Posts - [ใช้ SIP กับ IP Speaker - 20 มิถุนายน 2569](https://wenet.co.th/%e0%b9%83%e0%b8%8a%e0%b9%89-sip-%e0%b8%81%e0%b8%b1%e0%b8%9a-ip-speaker-20-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/) - [ทำระบบ Role & Permission - 20 มิถุนายน 2569](https://wenet.co.th/%e0%b8%97%e0%b8%b3%e0%b8%a3%e0%b8%b0%e0%b8%9a%e0%b8%9a-role-permission-20-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): // ตัวอย่างการเคลียร์ Cache เมื่อมีการเปลี่ยนสิทธิ์ผู้ใช้ const redis = require('./redis-client'); async function updateUserPermissions(userId, newPermissions) { // 1. - [Optimize Performance JS - 19 มิถุนายน 2569](https://wenet.co.th/optimize-performance-js-19-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/) - [Fetch API vs Axios - 19 มิถุนายน 2569](https://wenet.co.th/fetch-api-vs-axios-19-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/) - [ทำ CRUD API - 16 มิถุนายน 2569](https://wenet.co.th/%e0%b8%97%e0%b8%b3-crud-api-16-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): const express = require('express'); const mongoose = require('mongoose'); const app = express(); app.use(express.json()); // กำหนด Schema สำหรับข้อมูลสินค้า const productSchema = new mongoose.Schema({ name: { type: String, required: true }, price: { type: Number, required: true }, instock: { type: Boolean, default: true } }); const Product = mongoose.model('Product', productSchema); // 1. - [Monitor Call แบบ Real-time - 16 มิถุนายน 2569](https://wenet.co.th/monitor-call-%e0%b9%81%e0%b8%9a%e0%b8%9a-real-time-16-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): // ฟังก์ชันสำหรับดึงข้อมูลสถิติจาก Peer Connection async function monitorCallStats(peerConnection) { if (!peerConnection) { console.error("No active RTCPeerConnection found."); return; } const statsInterval = setInterval(async () => { try { const stats = await peerConnection.getStats(); stats.forEach(report => { // ตรวจสอบรายงานประเภท inbound-rtp (ข้อมูลที่รับเข้ามา) if (report.type === 'inbound-rtp' && (report.kind === 'audio' || report.kind === 'video')) { const jitter = report.jitter; const packetsLost = report.packetsLost; const packetsReceived = report.packetsReceived; // คำนวณอัตรา Packet Loss เป็นเปอร์เซ็นต์ const totalPackets = packetsLost + packetsReceived; const packetLossRate = totalPackets > 0 ? - [ตั้งเวลาเปิดเพลงอัตโนมัติ - 15 มิถุนายน 2569](https://wenet.co.th/%e0%b8%95%e0%b8%b1%e0%b9%89%e0%b8%87%e0%b9%80%e0%b8%a7%e0%b8%a5%e0%b8%b2%e0%b9%80%e0%b8%9b%e0%b8%b4%e0%b8%94%e0%b9%80%e0%b8%9e%e0%b8%a5%e0%b8%87%e0%b8%ad%e0%b8%b1%e0%b8%95%e0%b9%82%e0%b8%99%e0%b8%a1/): การทำงานของระบบนี้คือ ผมจะตั้งเวลา (Trigger) ไว้ที่ 07:30 น. - [การตั้งค่า Firewall ป้องกัน DDoS - 14 มิถุนายน 2569](https://wenet.co.th/%e0%b8%81%e0%b8%b2%e0%b8%a3%e0%b8%95%e0%b8%b1%e0%b9%89%e0%b8%87%e0%b8%84%e0%b9%88%e0%b8%b2-firewall-%e0%b8%9b%e0%b9%89%e0%b8%ad%e0%b8%87%e0%b8%81%e0%b8%b1%e0%b8%99-ddos-14-%e0%b8%a1%e0%b8%b4/) - [Snapshot และ Rollback VM - 14 มิถุนายน 2569](https://wenet.co.th/snapshot-%e0%b9%81%e0%b8%a5%e0%b8%b0-rollback-vm-14-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/) - [Performance Production - 13 มิถุนายน 2569](https://wenet.co.th/performance-production-13-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): ในโลกของการพัฒนาซอฟต์แวร์ยุคปัจจุบัน คำว่า "โค้ดทำงานได้" (It works!) - [Monitor Call แบบ Real-time - 13 มิถุนายน 2569](https://wenet.co.th/monitor-call-%e0%b9%81%e0%b8%9a%e0%b8%9a-real-time-13-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): const axios = require('axios'); const SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/T000/B000/XXXXXX'; const PACKET_LOSS_THRESHOLD = 5.0; // เปอร์เซ็นต์แพ็กเก็ตสูญหายที่ยอมรับได้ async function checkCallQuality(metrics) { const { callId, userId, packetsReceived, packetsLost, jitter } = metrics; // คำนวณเปอร์เซ็นต์ Packet Loss const totalPackets = packetsReceived + packetsLost; const packetLossPercent = totalPackets > 0 ? - [สร้างระบบ Login/Register - 11 มิถุนายน 2569](https://wenet.co.th/%e0%b8%aa%e0%b8%a3%e0%b9%89%e0%b8%b2%e0%b8%87%e0%b8%a3%e0%b8%b0%e0%b8%9a%e0%b8%9a-login-register-11-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): หลังจากที่ผู้ใช้ล็อกอินสำเร็จแล้ว คำถามสำคัญคือเราจะรักษาเซสชันการเข้าใช้งานของพวกเขาไว้อย่างไร? - [Optimize Performance Router - 10 มิถุนายน 2569](https://wenet.co.th/optimize-performance-router-10-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): Photo by Damir K . - [Integrate IP PA กับ CCTV - 9 มิถุนายน 2569](https://wenet.co.th/integrate-ip-pa-%e0%b8%81%e0%b8%b1%e0%b8%9a-cctv-9-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): import requests import json vms_event_data = { "camera_id": "CAM-ZONE-04", "event_type": "Intrusion_Detected", "timestamp": "2023-10-27T14:30:00Z" } speaker_ip = "192.168.2.50" api_url = f"http://{speaker_ip}/api/v1/stream/start" payload = { "stream_url": "rtsp://192.168.1.10/audio/alert.sdp", "priority": 1, "duration_seconds": 15 } headers = {'Content-Type': 'application/json'} if vms_event_data["event_type"] == "Intrusion_Detected": response = requests.post(api_url, data=json.dumps(payload), headers=headers, auth=('admin', 'password')) if response.status_code == 200: print("Alert broadcast initiated successfully.") else: print(f"Failed to trigger speaker. - [เชื่อม Asterisk กับ CRM - 8 มิถุนายน 2569](https://wenet.co.th/%e0%b9%80%e0%b8%8a%e0%b8%b7%e0%b9%88%e0%b8%ad%e0%b8%a1-asterisk-%e0%b8%81%e0%b8%b1%e0%b8%9a-crm-8-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/) - [Fetch API vs Axios - 7 มิถุนายน 2569](https://wenet.co.th/fetch-api-vs-axios-7-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): async function customFetch(endpoint, options = {}) { const BASE_URL = 'https://api.example.com/v1'; const defaultHeaders = { 'Content-Type': 'application/json', }; const config = { ...options, headers: { ...defaultHeaders, ...options.headers, }, }; try { const response = await fetch(`${BASE_URL}${endpoint}`, config); // สิ่งที่ควรทำ: ตรวจสอบสถานะ response.ok เสมอ if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.message || `HTTP error! - [ทำ Emergency Alert System - 7 มิถุนายน 2569](https://wenet.co.th/%e0%b8%97%e0%b8%b3-emergency-alert-system-7-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): // ตัวอย่างการทำ Rate Limiting และ Retry Mechanism ด้วยการใช้ Exponential Backoff ใน Python import time import random import requests from typing import Dict, Any class ResilientAlertSender: def __init__(self, api_url: str, max_retries: int = 5): self.api_url = api_url self.max_retries = max_retries def send_alert_with_retry(self, alert_data: Dict[str, Any]) -> bool: retries = 0 base_delay = 0.5 # เริ่มต้นที่ 500 มิลลิวินาที while retries < self.max_retries: try: # กำหนด Timeout เพื่อไม่ให้ระบบรอนานเกินไปหากเซิร์ฟเวอร์ปลายทางไม่ตอบสนอง response = requests.post(self.api_url, json=alert_data, timeout=2.0) if response.status_code == 200: return True # หากเจอ Rate Limit (HTTP 429) หรือ Server Error (HTTP 5xx) ให้เตรียม Retry if response.status_code in [429, 500, 502, 503, 504]: retries += 1 # คำนวณเวลาหน่วงแบบ Exponential Backoff พร้อมใส่ Jitter เพื่อกระจายโหลด delay = (base_delay * (2 ** retries)) + random.uniform(0, 0.5) print(f"[WARN] rate limited or server error ({response.status_code}). - [Performance Production - 6 มิถุนายน 2569](https://wenet.co.th/performance-production-6-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): แต่เมื่ออยู่บน Production ที่มีรายการสินค้าแสดงผลพร้อมกัน 100 รายการต่อหน้า และมีผู้ใช้กดเข้ามาดูพร้อมกัน 5,000 คนในวินาทีเดียว สิ่งที่เกิดขึ้นคือ ORM ทำการดึงข้อมูลสินค้ามา 1 ครั้ง (1 Query) จากนั้นก็วิ่งไปดึงข้อมูลร้านค้าของสินค้าแต่ละชิ้นทีละครั้ง (N Queries) รวมเป็น 101 Queries ต่อการโหลดหน้าเว็บ 1 ครั้ง! - [ออกแบบระบบเสียงตามสายองค์กร - 6 มิถุนายน 2569](https://wenet.co.th/%e0%b8%ad%e0%b8%ad%e0%b8%81%e0%b9%81%e0%b8%9a%e0%b8%9a%e0%b8%a3%e0%b8%b0%e0%b8%9a%e0%b8%9a%e0%b9%80%e0%b8%aa%e0%b8%b5%e0%b8%a2%e0%b8%87%e0%b8%95%e0%b8%b2%e0%b8%a1%e0%b8%aa%e0%b8%b2%e0%b8%a2%e0%b8%ad/) - [Monitor Resource CPU/RAM - 5 มิถุนายน 2569](https://wenet.co.th/monitor-resource-cpu-ram-5-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/): #!/bin/bash # กำหนดเกณฑ์ขั้นต่ำของการใช้งาน RAM (เป็นเปอร์เซ็นต์) THRESHOLD=85 DISCORD_WEBHOOK="https://discord.com/api/webhooks/your_webhook_url" # คำนวณเปอร์เซ็นต์การใช้งาน RAM ปัจจุบัน FREE_DATA=$(free -m) CURRENT_MEM=$(echo "$FREE_DATA" | grep Mem | awk '{print $3/$2 * 100.0}') CURRENT_MEM_INT=${CURRENT_MEM%.*} # ตรวจสอบว่าเกินเกณฑ์ที่กำหนดหรือไม่ if [ "$CURRENT_MEM_INT" -gt "$THRESHOLD" ]; then PAYLOAD="{\"content\": \"⚠️ WARNING: Server RAM usage is critical! - [Fetch API vs Axios - 5 มิถุนายน 2569](https://wenet.co.th/fetch-api-vs-axios-5-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/) - [เทคนิคใช้ Proxmox VE - 4 มิถุนายน 2569](https://wenet.co.th/%e0%b9%80%e0%b8%97%e0%b8%84%e0%b8%99%e0%b8%b4%e0%b8%84%e0%b9%83%e0%b8%8a%e0%b9%89-proxmox-ve-4-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8%e0%b8%99%e0%b8%b2%e0%b8%a2%e0%b8%99-2569/) - [ตั้งค่า Time Condition เวลาเปิดปิด - 4 มิถุนายน 2569](https://wenet.co.th/%e0%b8%95%e0%b8%b1%e0%b9%89%e0%b8%87%e0%b8%84%e0%b9%88%e0%b8%b2-time-condition-%e0%b9%80%e0%b8%a7%e0%b8%a5%e0%b8%b2%e0%b9%80%e0%b8%9b%e0%b8%b4%e0%b8%94%e0%b8%9b%e0%b8%b4%e0%b8%94-4-%e0%b8%a1/): อย่างไรก็ตาม นักพัฒนาและผู้ดูแลระบบมักจะเผชิญกับคำถามสำคัญที่ว่า "เราควรตั้งค่า Time Condition ด้วยวิธีใดจึงจะเหมาะสมที่สุด?" - [จำกัดความเร็ว Internet ราย User - 3 มิถุนายน 2569](https://wenet.co.th/%e0%b8%88%e0%b8%b3%e0%b8%81%e0%b8%b1%e0%b8%94%e0%b8%84%e0%b8%a7%e0%b8%b2%e0%b8%a1%e0%b9%80%e0%b8%a3%e0%b9%87%e0%b8%a7-internet-%e0%b8%a3%e0%b8%b2%e0%b8%a2-user-3-%e0%b8%a1%e0%b8%b4%e0%b8%96%e0%b8%b8/) - [npm vs yarn vs pnpm - 31 พฤษภาคม 2569](https://wenet.co.th/npm-vs-yarn-vs-pnpm-31-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/) - [ทำ CRUD API - 30 พฤษภาคม 2569](https://wenet.co.th/%e0%b8%97%e0%b8%b3-crud-api-30-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/): // ตัวอย่างการทำ Dynamic Update สำหรับ PATCH API ใน Node.js app.patch('/api/users/:id', async (req, res) => { const userId = req.params.id; const updates = req.body; // ป้องกันการอัปเดตฟิลด์ที่ไม่ได้รับอนุญาต (เช่น role หรือ id) const allowedUpdates = ['name', 'email', 'phoneNumber']; const isValidOperation = Object.keys(updates).every((update) => allowedUpdates.includes(update)); if (!isValidOperation) { return res.status(400).send({ error: 'Invalid updates!' - [ทำ Emergency Alert System - 30 พฤษภาคม 2569](https://wenet.co.th/%e0%b8%97%e0%b8%b3-emergency-alert-system-30-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/) - [WireGuard VPN บน MikroTik - 29 พฤษภาคม 2569](https://wenet.co.th/wireguard-vpn-%e0%b8%9a%e0%b8%99-mikrotik-29-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/): แม้ว่าในช่วงแรกอาจจะต้องปรับตัวกับระบบการจัดการคีย์ (Public/Private Key) แทนการใช้ Username/Password แบบเดิมๆ บ้าง แต่เมื่อระบบเข้าที่แล้ว มันเป็นระบบ VPN ที่แทบไม่ต้องเข้าไปดูแลรักษาอะไรเพิ่มเติมเลย (Configure and Forget) หากออฟฟิศของคุณยังใช้ IPsec หรือ L2TP ที่แสนจะปวดหัวอยู่ ผมแนะนำให้ลองหาเวลาอัปเกรด MikroTik เป็น v7 แล้วเริ่มทดลองใช้ WireGuard วันนี้ เชื่อผมเถอะครับว่าชีวิตไอทีของคุณจะง่ายขึ้นอีกเยอะ! - [เทคนิคใช้ Proxmox VE - 28 พฤษภาคม 2569](https://wenet.co.th/%e0%b9%80%e0%b8%97%e0%b8%84%e0%b8%99%e0%b8%b4%e0%b8%84%e0%b9%83%e0%b8%8a%e0%b9%89-proxmox-ve-28-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/) - [Performance Production - 28 พฤษภาคม 2569](https://wenet.co.th/performance-production-28-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/) - [Closure และ Scope - 27 พฤษภาคม 2569](https://wenet.co.th/closure-%e0%b9%81%e0%b8%a5%e0%b8%b0-scope-27-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/): คำถามแรกที่ผุดขึ้นมาในหัวของผมตอนนั้นคือ "ทำไมค่าของ i ถึงกลายเป็น 3 เสมอเมื่อเราคลิกปุ่ม?" - [Array Methods ที่ต้องรู้ - 26 พฤษภาคม 2569](https://wenet.co.th/array-methods-%e0%b8%97%e0%b8%b5%e0%b9%88%e0%b8%95%e0%b9%89%e0%b8%ad%e0%b8%87%e0%b8%a3%e0%b8%b9%e0%b9%89-26-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/): // ❌ สิ่งที่ไม่ควรทำ: มี Side Effect และแก้ไขข้อมูลต้นฉบับโดยตรง const products = [{ name: 'Book', price: 100 }, { name: 'Pen', price: 20 }]; const taxProductsBad = products.map(item => { item.price = item.price * 1.07; // แก้ไข Object ต้นฉบับโดยตรง! - [Clean Code JavaScript - 25 พฤษภาคม 2569](https://wenet.co.th/clean-code-javascript-25-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/) - [ตั้งค่า DNS Cache + Adblock - 25 พฤษภาคม 2569](https://wenet.co.th/%e0%b8%95%e0%b8%b1%e0%b9%89%e0%b8%87%e0%b8%84%e0%b9%88%e0%b8%b2-dns-cache-adblock-25-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/) - [สร้าง Captive Portal แบบมืออาชีพ - 13 พฤษภาคม 2569](https://wenet.co.th/%e0%b8%aa%e0%b8%a3%e0%b9%89%e0%b8%b2%e0%b8%87-captive-portal-%e0%b9%81%e0%b8%9a%e0%b8%9a%e0%b8%a1%e0%b8%b7%e0%b8%ad%e0%b8%ad%e0%b8%b2%e0%b8%8a%e0%b8%b5%e0%b8%9e-13-%e0%b8%9e%e0%b8%a4%e0%b8%a9/) - [Streaming เสียงผ่าน RTSP/HTTP - 12 พฤษภาคม 2569](https://wenet.co.th/streaming-%e0%b9%80%e0%b8%aa%e0%b8%b5%e0%b8%a2%e0%b8%87%e0%b8%9c%e0%b9%88%e0%b8%b2%e0%b8%99-rtsp-http-12-%e0%b8%9e%e0%b8%a4%e0%b8%a9%e0%b8%a0%e0%b8%b2%e0%b8%84%e0%b8%a1-2569/): Live Audio Stream