รับ-ส่ง SMS ง่ายๆ ด้วย AirCard บน Raspberry Pi


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

อุปกรณ์ที่ต้องใช้

  1. Raspberry Pi (หรือคอมพิวเตอร์ที่ใช้ Linux และมี port USB ว่าง 1 พอร์ท)
  2. USB AirCard ที่เข้ากันได้กับระบบปฏิบัติการ Raspbian ของ Raspberry Pi (ดูรายชื่ออุปกรณ์ได้จากที่นี่) บทความนี้เลือกใช้ 3G AirCard ของ TrueMove-H ซึ่งภายในเป็นอุปกรณ์ของ Huawei รุ่น E303 ราคา 790 บาท (ซิมและโปรโมชันที่ใช้ต้องซื้อต่างหาก)
  3. โทรศัพท์มือถือเอาไว้ทดสอบการรับ-ส่งข้อความ

IMG_1921

การเตรียมระบบ

  • ติดตั้งโปรแกรม gammu และส่วนเสริมที่จำเป็น ให้เรียกใช้โปรแกรม Terminal แล้วพิมพ์คำสั่งต่อไปนี้ เครื่อง Raspberry Pi จะต้องเชื่อมต่อกับอินเทอร์เน็ต
sudo apt-get install gammu usb-modeswitch python-gammu
  • ลองเสียบ SIM ในโทรศัพท์มือถือทั่วไปและทดลองดูว่าสามารถรับส่งข้อความได้หรือไม่ เมื่อแน่ใจว่า SIM ใช้งานได้ ก็ให้ย้ายไปใส่ใน AirCard แล้วเสียบ AirCard เข้ากับช่อง USB ของ Raspberry Pi
  • ตรวจสอบว่า Raspberry Pi มองเห็น AirCard หรือไม่

ใช้คำสั่ง

lsusb

เนื่องจาก AirCard รุ่นที่ใช้ในตัวอย่างนี้จะทำตัวเป็น USB Drive ได้ด้วย ซึ่งบางครั้งจะทำให้ Raspberry Pi สับสน นึกว่าอุปกรณ์นี้ไม่ใช่ AirCard แต่เป็น USB Drive แทน ดังนั้นคำสั่ง lsusb จะให้ผลลัพท์ได้สองแบบ

เห็น AirCard (ถูกต้อง)

Bus 001 Device 010: ID 12d1:1506 Huawei Technologies Co., Ltd. E398 LTE/UMTS/GSM Modem/Networkcard

ไม่เห็น AirCard แต่เห็น USB Drive แทน (ผิด)

Bus 001 Device 010: ID 12d1:14d1 Huawei Technologies Co., Ltd.

แม้หากว่าลองแล้วได้ผลถูกต้อง แต่ก็เป็นไปได้ว่าบางครั้งเมื่อ reboot ระบบอาจกลับไปเห็นอุปกรณ์ที่ไม่ถูกต้องก็ได้ ดังนั้นถ้าให้แน่ใจจริงๆ ควรใช้โปรกรม usb-modeswitch เพื่อตั้งค่าอุปกรณ์ให้ถูกต้องตามขั้นตอนต่อไปนี้

  • ตั้งค่าโปรแกรม usb-modeswitch

โปรแกรมนี้ทำหน้าที่เปลี่ยนโหมดของอุปกรณ์ USB ที่มีหลากอุปกรณ์ในตัว และตั้งค่าเลือกอุปกรณ์ตัวที่เราต้องการใช้ การจะเลือกอุปกรณ์ จะต้องรู้รหัส Vendor ID กับ Product ID ซึ่งรหัสนี้จะต่างกันไปแล้วแต่ยี่ห้อและรุ่นของ AirCard ที่ใช้ ดังนั้นจะต้องไปค้นข้อมูลนี้จาก internet มาเองให้ตรงรุ่น แล้วนำค่านี้ไปเขียนต่อท้ายในไฟล์ /etc/usb_modeswitch.conf โดยใช้คำสั่งต่อไปนี้จาก Terminal

sudo nano /etc/usb_modeswitch.conf

เช่น AirCard Huawei E303 ที่ใช้ในบทความนี้จะมีค่ารหัสดังนี้ (หาพบจากการค้นหา “Huawei E303 USB vendor product Id” ใน Google)

DefaultVendor = 0x12d1
DefaultProduct = 0x1506

เมื่อเพิ่มสองบรรทัดนี้เข้าไปในไฟล์แล้วก็ให้ save ไฟล์ (กด Ctrl-X และ Y) แล้วลอง reboot เครื่อง และเรียก lsusb อีกครั้ง ซึ่งคราวนี้น่าจะเห็นอุปกรณ์ที่ถูกต้อง

  • ตรวจสอบชื่ออุปกรณ์ของ AirCard โดยใช้คำสั่ง
dmesg | grep ttyUSB*

สังเกตุบรรทัดที่มีคำว่า GSM modem และดูว่าอุปกรณ์ชื่ออะไร เช่น ttyUSB0, ttyUSB1, ฯลฯ จำชื่อนี้ไว้

  • ตั้งค่าโปรแกรม gammu

โปรแกรม gammu จะทำหน้าที่รับส่ง SMS ซึ่งจะต้องตั้งค่าให้โปรแกรมรู้จัก AirCard ที่ใช้ก่อน โดยพิมพ์คำสั่งต่อไปนี้

sudo gammu-config

ซึ่งจะแสดงหน้าต่างการตั้งค่าขึ้นมา ให้เราตั้งค่าดังนี้

Port: /dev/ttyUSB0 << แล้วแต่เสียบ port ไหน
 Connection: at19200 
 Model: ปล่อยว่างๆ 
 Synchronize time: yes 
 Log file: ปล่อยว่างๆ 
 Log format: nothing 
 Use locking: ปล่อยว่างๆ 
 Gammu localisation: ปล่อยว่างๆ

เมื่อเสร็จก็ให้ save แล้วออกจากโปรแกรม

 การส่ง SMS

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

 sudo gammu sendsms TEXT +66819876543 -textutf8 "Hello from Raspberry Pi"

คำสั่งนี้จะส่งข้อความ “Hello from Raspberry Pi” ไปยังหมายเลขโทรศัพท์ 081-987-6543 ซึ่งรูปแบบการเขียนเบอร์โทรศัพท์ที่เป็น +66819876543 นี้เป็นมาตรฐานนานาชาติ คือขึ้นต้นด้วย “+” ตามด้วยรหัสประเทศ (66 = ประเทศไทย) และตามด้วยเบอร์โทร โดยตัด 0 ตัวแรกทิ้งไป ต่อไปนี้เป็นตัวอย่างการส่ง SMS ข้างต้นโดยใช้ภาษา Python

import commands

commandString = 'sudo gammu sendsms TEXT +66819876543 -textutf8 "Hello from Raspberry Pi" '

print commands.getoutput(commandString)

การใช้ภาษา Python มีความยืนหยุ่นสูงกว่าเพราะทำให้เราสามารถสร้างข้อความที่รับค่าจากผู้ใช้ได้เช่น

import commands

# Ask for your name
name = raw_input('What is your name? ')

# Ask for a phone number. Use the international format. +country-code phone-number,
# I.e. +66819876543
phoneNumber = raw_input('What is your phone number? ')
commandString = 'sudo gammu sendsms TEXT ' + phoneNumber + ' -textutf8 "Hello ' + name + '. This is Raspberry Pi"'

print 'Sending text "Hello ' + name + '. This is Raspberry Pi" to phone number ' + phoneNumber

# send the command to the AirCard
print commands.getoutput(commandString)

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

การรับ SMS

ปกติหาก AirCard ทำงานอยู่เมื่อมี SMS ส่งเข้ามามันจะเก็บข้อความเหล่านั้นไว้ในหน่วยความจำภายใน SIM Card โดยอัตโนมัติ ซึ่งเราสามารถใช้ API ชื่อ python-gammu การอ่านและจัดการข้อความเหล่านี้ได้ โปรแกรมตัวอย่างต่อไปนี้จะทำการพิมพ์ข้อความ SMS ทั้งหมดที่มีใน SIM Card ออกมาพร้อมกับ หมายเลขโทรศัพท์ผู้ส่ง, วันเวลาที่ได้รับ, และสถานะ (อ่าน หรือ ยังไม่ได้อ่าน)

import gammu

def readAllSMS():
    sm = gammu.StateMachine()
    sm.ReadConfig()
    sm.Init()

    status = sm.GetSMSStatus()

    smsCount = status['SIMUsed']

    print "SMS count = " + str(smsCount)

    for i in range(0,smsCount):
	     if i==0:
    		sms = sm.GetNextSMS(Folder=0, Start=True)
    	 else:
	        sms = sm.GetNextSMS(Folder=0, Location=i-1)
         print sms[0]['Number']     # Sender's phone number
         print sms[0]['DateTime']   # Receive date and time
         print sms[0]['State']      # message state (unread/read)
         print sms[0]['Text']	    # SMS content
         print "=================================="

    print "Done"

readAllSMS()

โปรแกรมตัวอย่างถัดไปจะคอยตรวจสอบว่ามี SMS ใหม่เข้ามาหรือไม่ และทำงานตามคำสั่งที่ได้รับในข้อความนั้นๆ ซึ่งในที่นี้คือทำการเปิดปิดมอเตอร์ที่ต่อกับบอร์ด PiTopping

import gammu
import time
from pibot import *

smsCount = 0

def executeCommand(command):
	if command=='on':
		talkTo('a')
		on()
	elif command == 'off':
		talkTo('a')
		off()

def checkSMS():

    global smsCount

    status = sm.GetSMSStatus()

    # check amount of SMS in the SIM card
    newSmsCount = status['SIMUsed']

    print "SMS count = " + str(newSmsCount)

    # if new SMS 
    if (newSmsCount > 0) and (newSmsCount != smsCount) :
   	smsCount = newSmsCount
	   # read the SMS
	   sms = sm.GetNextSMS(Folder=0, Location=smsCount-1)

	   # only use 'unread' SMS
	   if sms[0]['State'].lower() == 'unread':
		   # copy the SMS content
		   command = sms[0]['Text'].lower()
		   print "New command: " + command
		   # execute the SMS command
		   executeCommand(command)    

    print "Done"

sm = gammu.StateMachine()
sm.ReadConfig()
sm.Init()

while True:
	print "Checking SMS"
	checkSMS()
	time.sleep(4)

การทำงานของโปรแกรมข้างต้นเป็นดังนี้

  • โปรแกรมจะคอยเรียกฟังก์ชัน checkSMS() ทุกๆ 4 วินาที
  • ในฟังก์ชัน checkSMS() จะทำงานดังนี้
    • จะคอยอ่านจำนวน SMS ที่มีอยู่ใน SIM และเอาไปเทียบกับจำนวนที่เก็บไว้ในตัวแปร smsCount หากมีค่าไม่เท่ากันก็แสดงว่ามีข้อความใหม่เข้ามา
    • เมื่อมีข้อความใหม่โปรแกรมก็จะตรวจสอบเพื่อความแน่ใจว่าสถานะของข้อความนั้นคือยังไม่ได้อ่าน (UnRead)  ถ้าเป็นจริงก็จะส่งข้อความนั้นให้ฟังก์ชัน executeCommand() นำไปประมวลผลต่อไป (ว่าควรเปิด หรือปิดมอเตอร์)

วิดีโอสาธิตการทำงานของโปรแกรม

http://www.youtube.com/watch?v=KjORrEY8CYY

คำแนะนำ

  • ในการรับ SMS ควรทำการลบข้อความที่ไม่ได้ใช้เป็นพักๆ เพื่อป้องกันไม่ให้หน่วยความจำของ SIM Card เต็ม ซึ่งอาจทำให้ไม่สามารถรับข้อความใหม่ๆ ได้ โดยคำสั่งที่ใช้ลบข้อความทั้งหมดใน SIM คือ
gammu deleteallsms 1

โดยจะเรียกใช้จาก Command Prompt หรือในภาษา Python ผ่านทาง คำสั่ง commands.getoutput() ก็ได้

  • จากการทดลองใช้งาน พบว่าบริษัทผู้ให้บริการมักมีการส่งข้อความ SMS โฆษณาประชาสัมพันธ์ต่างๆ เข้ามาบ่อยๆ ดังนั้นหากจะใช้การรับ SMS เพื่อสั่งงาน ควรตรวจสอบเนื้อหาให้แน่ใจเสมอว่าใช่คำสั่งที่ส่งมาจริงๆ หรือไม่

อ้างอิง

รายละเอียดและคำสั่งเพิ่มเติมเกี่ยวกับการควบคุมระบบ SMS สามารถศึกษาได้จาก

 สรุป

การรับและส่ง SMS นั้นทำได้ง่ายขึ้นมากเมื่อใช้ Raspberry Pi คู่กับ USB AirCard เทียบกับวิธีการเดิมของระบบสมองกลฝังตัวทั่วไป บทความนี้ได้แนะนำวิธีการเบื้องต้นในการใช้งาน SMS ซึ่งน่าจะครอบคลุมความต้องการพื้นฐานของโครงงานทั่วไปที่ต้องการใช้ความสามารถนี้