ต่อโทรศัพท์กลับบ้านด้วย Asterisk และ Raspbery Pi

by lew
10 March 2014 - 19:00

ปัญหาค่าโรมมิ่งแพงจนหลายคนช็อคเป็นปัญหาเรื้อรังของการสื่อสารไทย คำแนะนำโดยทั่วไปคือที่ใช้ได้ผลที่สุดคือ "อย่าเอาซิมไปใช้ต่างประเทศ" โดยแนะนำให้ซื้อซิมในประเทศนั้นๆ ใช้งาน แม้อาจจะถูกบ้างแพงบ้างแต่ส่วนมากก็อยู่ในระดับไม่เกินสองพันบาทต่อสองสัปดาห์เท่านั้น แต่ในหลายกรณีเราก็ยังต้องการใช้หมายเลขที่บ้านของเราอยู่เสมอ บางกรณีเช่นการรับ SMS เช่นข้อความ OTP ก็จำเป็นอย่างมากต่อการใช้งานจริง

Raspberry Pi (RPi) เป็นคอมพิวเตอร์ขนาดเล็กมากแต่ความสามารถค่อนข้างสูงเมื่อเทียบกับคอมพิวเตอร์ที่เราเปิดตลอดเวลาในบ้านเช่นเราท์เตอร์ทั่วไป อัตราการกินไฟของ RPi นั้นประมาณ 500mA หรือ 2.5 วัตต์เท่านั้น การเปิดทิ้งไว้ทั้งปีกินพลังงานเพียง 4-5 kWh คิดเป็นค่าไฟไม่กี่สิบบาทเท่านั้น แต่สามารถติดตั้งลินุกซ์เต็มรูปแบบไว้ใช้งานได้

ข้อดีของการมีลินุกซ์เต็มรูปแบบคือแอพพลิเคชั่นที่มีจำนวนมากมายมหาศาล ดิสก์โทรเป็นทางการของ RPi คือ Raspbian นั้นสร้างขึ้นมาจาก Debian และมีแอพพลิเคชั่นแทบทุกอย่างที่ Debian มี หนึ่งในนั้นคือ Asterisk

Asterisk ถูกออกแบบให้เป็นซอฟต์แวร์ตู้สาขา (private branch exchange - PBX) งานทั่วไปของมันจะคล้ายกับโทรศัพท์ตามสำนักงานที่เมื่อเราโทรเข้าไปแล้วจะมีเสียงแจ้งให้โทรต่อเลขหมายภายใน เครื่อง PBX รุ่นเก่านั้นการเชื่อมระหว่างสายภายนอกและภายในก็อาศัยการเชื่อมต่อสายโทรศัพท์ปกติทำให้สำนักงานต้องเดินคู่สายจำนวนมากเพื่อให้บริการ สำหรับ PBX รุ่นใหม่นั้นมักจะเป็น IP-PBX นั่นคือขาออกของเครื่องเหล่านี้ก็จะเป็นสายแลนหรือ Wi-Fi ที่เราใช้งานกับคอมพิวเตอร์ทุกวันนี้ ส่วนโทรศัพท์นั้นจะเป็นเครื่องเฉพาะที่มีราคาตั้งแต่ 1,500 บาทไปจนถึงหลายพันบาท หรือจะเป็นโทรศัพท์ Android ทุกวันนี้ล้วนรองรับการโทรผ่านไอพีทั้งสิ้น

ภาพการ์ด FXO 4 พอร์ต ราคาขายปลีก 65.70 ดอลลาร์

แม้ว่าจะสามารถเชื่อมต่อโทรศัพท์ในสำนักงานด้วยกันผ่านทางโทรศัพท์ไอพีได้ แต่ระบบโทรศัพท์ในสำนักงานก็จำเป็นต้องเชื่อมต่อกลับไปยังโลกภายนอก การเชื่อมต่อแบบนี้คอมพิวเตอร์ต้องติดตั้งการ์ดเชื่อมต่อกับสายโทรศัพท์ปกติ เรียกการ์ดเหล่านี้ว่าการ์ด FXO (Foreign eXchange Office) เราสามารถสมัครเบอร์โทรศัพท์หลายหมายเลขแล้วให้คนที่โทรเข้ามาเลือกโทรเข้าเบอร์ใดก็ได้ แต่ระบบจะมารวมที่เดียวกัน การ์ดเหล่านี้มีราคาถูกลงมากในช่วงหลัง เราสามารถหาซื้อการ์ดราคาสองถึงสามพันบาทที่สามารถเชื่อมต่อโทรศัพท์สี่เลขหมายได้ ที่แย่คือการ์ดเหล่านี้มักเชื่อมต่อผ่านสล็อต PCI ขณะที่ RPi มีเพียงพอร์ต USB เท่านั้น น่าเสียดายที่มีโมเด็มราคาถูกและใช้พอร์ต USB มากมายแต่ยังไม่มีใครเชื่อมต่อมันเข้ากับ Asterisk

ข่าวดีคือมีคนทำซอฟต์แวร์เชื่อมต่อ Asterisk สำหรับ 3G dongle ที่บ้านเราใช้งานกันอยู่ทั่วไป และมีขายกันในราคาไม่กี่ร้อยบาทเท่านั้น การ์ดเหล่านี้ภายในแทบจะเป็นโทรศัพท์มือถือโดยสมบูรณ์ ขาดเพียงไมโครโฟนและลำโพงสำหรับพูดคุยเท่านั้น โครงการนี้ชื่อว่า chan_dongle (มาจาก Channel Dongle) มันรองรับ dongle ของ Huawei หลายรุ่น (ดูรายการรุ่นที่รองรับ) ในบ้านเราเองแม้จะมีแบรนด์อื่นๆ แต่ส่วนมากมักเป็นการจ้าง Huawei ผลิต กรณีผมเองมีการ์ด E158 อยู่ที่บ้านอยู่แล้วก็นำมาใช้งานได้เลย

เมื่อเราติดตั้ง Asterisk ใน Raspbian ด้วยคำสั่ง sudo apt-get install asterisk แล้วก็จะสามารถเริ่มคอนฟิกได้ทันที แต่ Asterisk นั้นรองรับโปรโตคอลจำนวนมาก เรียกเป็นภาษาเฉพาะว่า channel เช่น ช่องทาง SCCP จะแยกออกจากช่องทาง Jabber ที่รองรับเฉพาะข้อความ ทำให้มีไฟล์คอนฟิกมากมาย แต่ตอนนี้เมื่อติดตั้งแล้วให้พักการคอนฟิก Asterisk เอาไว้ก่อน แล้วมาติดตั้งตัว dongle

ัตัว chan_dongle นั้นไม่มี package ใน Raspbian โดยตรงก็จำเป็นต้องคอมไพล์เอง สามารถดาวน์โหลดซอร์สโค้ดมาคอมไพล์ใน RPi ได้โดยใช้เวลาไม่นานนัก จากนั้นมีสองไฟล์คือ chan_dongle.so ต้องนำไปวางไว้ที่ /usr/lib/asterisk/modules/ ส่วนไฟล์ etc/dongle.conf ให้ไปวางไว้ใน /etc/asterisk หลังจากนั้นต้องติดตั้ง sudo apt-get install usb-modeswitch เพิ่มเพื่อให้ใช้งาน dongle ได้ (ใน Ubuntu จะติดตั้งมาแล้วเพื่อให้รองรับ 3G dongle ได้)

จากนั้นทดสอบการทำงานเบื้องต้น ด้วยการเริ่มการทำงาน Asterisk ใหม่อีกครั้ง แล้วสั่ง sudo asterisk -vvvr เพื่อเข้าคอนโซลของตัว Asterisk มาดูสถานะการทำงานของโมดูลต่างๆ สั่ง dongle show devices หากขึ้นข้อความแสดงรายการ dongle0 พร้อมหมายเลข IMEI, ชื่อเครือข่าย, และ IMSI ก็แสดงว่าใช้งานได้แล้ว

ตัว Asterisk นั้นมองตัวเองเป็นตัวกลางทำหน้าเชื่อมต่ออุปกรณ์ที่หลากหลายสารพัดเข้าด้วยกัน มันรองรับโทรศัพท์หลากหลายโปรโตคอล นับแต่ SIP ที่เป็นมาตรฐานเปิดที่ได้รับความนิยมสูง, IAX ที่ Asterisk พัฒนาขึ้นมาเอง, หรือ SCCP ของซิสโก้ก็ตามที แต่ละอุปกรณ์หากต้องการรับสายจะต้องมีหมายเลขภายใน (extension) เพื่อเรียกถึงกันได้ กรณีทั่วไปเช่นเรามีหมายเลข 6001 เป็นโทรศัพท์ SIP หมายเลข 6002 เป็นหมายเลขโทรศัพท์ IAX ที่ต่ออยู่ เมื่อ 6001 โทรหา 6002 ตัว Asterisk ก็จะเป็นตัวกลางให้ทั้งสองเครื่องเชื่อมต่อกันได้ แม้ว่าทั้งสองเครื่องอาจจะต่างกันมาก เช่น 6001 โทรหาหมายเลข 02-XXX-XXXX ซึ่งเป็นโทรศัพท์บ้านในเมืองไทยก็สามารถโทรได้หากเรากำหนดเส้นทางการโทรไว้ให้ Asterisk แล้ว

ในกรณีทั่วไป เราจะสนใจไฟล์เพียงไม่กี่ไฟล์เท่านั้น ในโครงการนี้ได้แก่ sip.conf โดยส่วนมากค่าเริ่มต้นมักใช้งานได้ทั้งหมด มียกเว้นบ้างเช่นค่า tcpenable ที่ค่าเริ่มต้นเป็น no แต่หากเครือข่ายใดไม่รองรับ UDP อาจจะต้องเปิดเป็น yes แทน

การเชื่อมต่อด้วย TCP หรือ UDP ก็ตาม ล้วนไม่มีการเข้ารหัสใดๆ บทความนี้เป็นเพียงการทดสอบการใช้งาน VoIP เท่านั้น ในการใช้งานจริงและมีการใช้งานภายนอกองค์กรสามารถตั้งค่า TLS เพื่อเข้ารหัสได้ แต่ไม่อยู่ในขอบเขตบทความนี้

ที่เราต้องทำจริงๆ ในไฟล์คอนฟิก SIP นี้คือการเพิ่มผู้ใช้ และการเพิ่มก็ตรงไปตรงมา

[demo-blognone]
type=friend
host=dynamic
secret=blognonewillcallyousometimes ; put a strong, unique password here instead
context=default

ในส่วนเริ่มต้น section ที่จริงคือหมายเลขที่จะใช้โทรไปหาผู้ใช้ type มีสามแบบใน Asterisk ได้แก่ user โทรเข้าได้อย่างเดียว, peer โทรออกไปหาได้อย่างเดียว, และ friend โทรเข้าและออกได้ สุดท้าย secret ก็คือรหัสผ่าน ในระบบ Asterisk นั้นผู้ใช้หนึ่งคนอาจจะสามารถรับสายจากหมายเลขได้หลายหมายเลข ในกรณีนี้หมายเลขกลับเป็นตัวอักษรที่โทรศัพท์บางรุ่นอาจจะโทรหาไม่ได้ ก็สามารถตั้งค่า alternateexts เพื่อตั้งหมายเลขเพิ่มเติมได้ ส่วน context เป็นการกำหนดขอบเขตของหมายเลขที่โทรได้ ในกรณีที่บริษัทแบ่งออกเป็นหลายๆ ส่วน ในกรณีทั่วไปองค์กรไม่ใหญ่นักมักมี context เดียว ก็ใช้ default ได้เลย

เมื่อคอนฟิกเสร็จแล้วให้ restart Asterisk (สั่ง sudo service asterisk restart) แล้วกลับมาดูคอนโซลของ Asterisk อีกครั้ง สั่ง sip show users เพื่อตรวจการตั้งค่า ถ้าเห็นผู้ใช้ที่กำหนดก็แสดงว่าใช้งานได้แล้ว

ถึงตอนนี้เราอาจจะสร้างผู้ใช้หลายคน และผู้ใช้แต่ละคนจะสามารถโทรหากันได้แล้ว โทรศัพท์หลายรุ่นรองรับ SIP ในตัว แต่หลายรุ่นก็ตัดความสามารถนี้ออกไป แต่ในแอนดรอยด์ไม่ว่าจะมีความสามารถนี้แต่แรกหรือไม่ก็สามารถติดตั้ง Sipdroid เพื่อใช้งานได้ ใส่ชื่อผู้ใช้ รหัสผ่าน แล้วเลือกชื่อเซิร์ฟเวอร์ ในกรณีที่เป็นไอพีในบ้านอาจจะใช้ทดสอบในบ้านไปก่อน ในส่วนของการเปิดให้บริการนอกบ้านต้องตรวจสอบการตั้งค่าเราท์เตอร์และการตั้งชื่อโดเมนของเราท์เตอร์ที่บ้านกันต่อไปตามแต่รุ่นที่ใช้งาน หากมีโทรศัพท์แอนดรอยด์หลายเครื่องก็สามารถสร้างผู้ใช้หลายคนแล้วโทรหากันได้ทันทีตามชื่อ username ที่ตั้งไว้

มาถึงส่วนสุดท้ายคือการชื่อให้โทรออกและรับสายจาก dongle ได้ ในระบบของ Asterisk นั้นแกนกลางของมันคือระบบที่เรียกว่า Dialplan มันเป็นเหมือนตารางหาเส้นทางของเราท์เตอร์ที่เราสามารถเลือกเส้นทางเฉพาะให้กับปลายทางบางแบบได้ หรือไฟร์วอลบางรุ่นอาจจะมีความสามารถบล็อกเว็บโดยเข้าไปดู URL ที่ผู้ใช้กำลังดูได้

Asterisk อาศัยการกดหมายเลขต่อภายในหรือ extension เพื่อเลือกเส้นทางว่าผู้ใช้แต่ละคนควรจะต้องต่อไปทางใดบ้าง เราอาจจะสร้างหมายเลขที่ไม่มีอยู่จริง เช่น กด "0000" แล้วตามด้วยหมายเลขภายในเพื่อส่งอีเมลเสียงแทนที่จะโทรหาโดยตรง หรือสร้างหมายเลขกด "*" เพื่อโทรออกนอกบริษัท

ในกรณีของโมดูล chan_dongle มีหมายเลขต่อภายในพิเศษ ที่เพิ่มขึ้นมาได้แก่ sms และ ussd นั่นคือเวลาที่ซิมการ์ดได้ข้อความสั้น (SMS) และข้อความจากเครือข่าย (USSD) ก็จะทำตัวเหมือนการโทรเข้าด้วยหมายเลขภายในแบบหนึ่ง ใน Asterisk จะกำหนดช่องทางการโทรที่ซับซ้อนหลากหลายไว้ตั้งแต่แรกเพื่อสาธิตความสามารถต่างๆ ของ Asterisk เช่นระบบตอบรับอัตโนมัติ หรือระบบฝากข้อความเสียง แต่ในกรณีของเราที่ต้องการโทรออกและรับสายผ่าน SIP เท่านั้นผมเตรียม extension ไว้สั้นๆ ดังนี้

[default]
exten => sms,1,Noop(Incoming SMS from ${CALLERID(num)} ${BASE64_DECODE(${SMS_BASE64})})
exten => sms,n,System(echo '${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M:%S)} - ${DONGLENAME} - ${CALLERID(num)}: ${BASE64_DECODE(${SMS_BASE64})}' >>
 /var/log/asterisk/sms.txt)
exten => sms,n,Hangup()

exten => s,1,Dial(SIP/demo-blognone)

exten => _0XXXXXXXXX,1,Dial(Dongle/dongle0/${EXTEN})

ไฟล์คอนฟิกนี้กำหนดสามอย่างด้วยกัน อย่างแรกคือในสามบรรทัดแรก จะกำหนดว่าหากมี SMS เข้ามา ให้เขียนล็อกลงไฟล์ /var/log/asterisk/sms.txt สังเกตว่าที่จริงแล้วการเขียนล็อกเป็นคำสั่ง system แสดงว่าเราสามารถสร้างคำสั่งอื่นๆ เช่นการส่งอีเมลไปได้เช่นกัน

คำสั่งชุดที่สองคือ exten => s,1,Dial(SIP/demo-wason) มีหมายเลขภายใน s ซึ่งเป็นหมายเลขพิเศษแปลว่าหากไม่เข้ากฎใดๆ เลยให้ทำตามนี้ กรณีนี้กำหนดให้โทรผ่าน SIP ไปยังผู้ใช้ demo-blognone

คำสั่งชุดสุดท้าย exten => _0XXXXXXXXX,1,Dial(Dongle/dongle0/${EXTEN}) เป็นการหา pattern ของหมายเลข โดย Asterisk จะรู้ว่าเส้นทางใดเป็น pattern จากการเริ่มต้นหมายเลขภายในด้วยเครื่องหมายขีดล่าง (_) คำสั่งนี้คือการระบุว่าหากมีการโทรด้วยหมายเลขยาว 10 ตัวที่ขึ้นต้นด้วย 0 ซึ่งตรงกับหมายเลขโทรศัพท์มือถือในไทย ให้โทรออกด้วยหมายเลขนั้นๆ ผ่านทาง dongle0

กฎทั้งสามนี้จะทำให้เมื่อมีเลขหมายใดๆ โทรเข้ามาทางซิมโทรศัพท์มือถือที่อยู่ใน dongle ตัว Asterisk จะโทรออกหาผู้ใช้ demo-blognone ทันที ขณะเดียวกันเมื่อผู้ใช้ใดๆ กดหมายเลขโทรศัพท์ Asterisk ก็จะโทรหมายเลขนั้นๆ ผ่านซิมโทรศัพท์มือถือเช่นกัน กระบวนการนี้ทำให้เราสามารถใช้งานซิมโทรศัพท์มือถือได้จากระยะไกล

Blognone Jobs Premium