Python 調用 GSM A6

【環境準備】html

一、操做系統:python

Windows 7 x64 SP1

二、Python 版本:
linux

python-3.6.3-amd64

三、第三方組件:git

(1)、github

pip3 install pyserial

(2)、下載smspdubash

python3 setup.py build install


【列出全部串口】app

#encoding: utf-8
#author: walker
#date: 2017-10-06 
#summary: Python 用 pyserial 列出全部串口

import serial.tools.list_ports

# 打印全部串口名
def ListPorts():
	serailPortList = list(serial.tools.list_ports.comports())
	print('serail port number: %d' % len(serailPortList))
	if len(serailPortList) < 1:
		print("Not found serail port!")
		return 
		
	for serailPort in serailPortList:
		se = serial.Serial(list(serailPort)[0], 9600, timeout=9)
		print('serail port name:%s' % se.portstr)
		se.close()
	
if __name__ == '__main__':
	ListPorts()


【發送純英文(ASCII)短信】ide

#encoding: utf-8
#author: walker
#date: 2017-10-06 
#summary: Python 調用 GSM A6,發送英文短信

import time
import serial.tools.list_ports
		
class MessagerEn(object):
	# 構造函數,打開端口
	def __init__(self):        
		self.sePort = serial.Serial(port='COM3', baudrate=19200, bytesize=8, stopbits=1, timeout=3)
		time.sleep(3)
	
	# 析構函數,關閉端口
	def __del__(self): 
		self.sePort.close()
	
	# 從新打開端口
	def reopen(self):
		print('reopen ...')
		self.sePort.close()
		self.sePort = serial.Serial(port='COM3', baudrate=19200, bytesize=8, stopbits=1, timeout=3)
		time.sleep(3)

	# 執行指令
	# 返回從串口讀取的返回值
	def execCmd(self, cmd, end='\r'):
		cmd = cmd + end
		bCmd = cmd.encode('ascii')
		print('write:%s' % bCmd)
		self.sePort.write(bCmd)
		response = self.sePort.readall()
		print('read :%s' % response)
		print()
		
		return response
	
	# 發送英文短信
	# 正確返回 True;錯誤返回 False
	def __sendMessageEn(self, phoneNumber, message):
		if not self.execCmd('AT+CMGF=1').endswith(b'\r\nOK\r\n'):		#設置TEXT MODE
			return False
			
		if not self.execCmd('AT+CSCS="GSM"').endswith(b'\r\nOK\r\n'):		
			return False
			
		if not self.execCmd('AT+CMGS="%s"' % phoneNumber).endswith(b'\r\n> '):		
			return False
		
		if not self.execCmd(message + '\x1A', end='').endswith(b'\r\nOK\r\n'):		# 十六進制的1A爲結束符
			return False
			
		return True
	
	# 調用私有方法 __sendMessageEn
	# 在失敗時從新打開串口
	def sendMessage(self, phoneNumber, message):
		for _ in range(0, 3):
			if self.__sendMessageEn(phoneNumber, message):
				break
			self.reopen()
	
if __name__ == '__main__':
	messagerEn = MessagerEn()
	messagerEn.sendMessage('18688754379', 'xxx')
	messagerEn.sendMessage('18688754379', 'zzz')


【發送中文(Unicode)短信】函數

#encoding: utf-8
#author: walker
#date: 2017-10-06 
#summary: Python 調用 GSM A6,發送中文(Unicode)短信
 
import time
import serial.tools.list_ports
         
class Messager(object):
    # 構造函數,打開端口
    def __init__(self):        
        self.sePort = serial.Serial(port='COM3', baudrate=19200, bytesize=8, stopbits=1, timeout=3)
        time.sleep(3)
     
    # 析構函數,關閉端口
    def __del__(self): 
        self.sePort.close()
         
    # 從新打開端口
    def reopen(self):
        print('reopen ...')
        self.sePort.close()
        self.sePort = serial.Serial(port='COM3', baudrate=19200, bytesize=8, stopbits=1, timeout=3)
        time.sleep(3)
 
    # 執行指令
    # 返回從串口讀取的返回值
    def execCmd(self, cmd, end='\r'):
        cmd = cmd + end
        bCmd = cmd.encode('ascii')
        print('write:%s' % bCmd)
        self.sePort.write(bCmd)
        response = self.sePort.readall()
        print('read :%s' % response)
        print()
         
        return response
     
    # 發送英文短信
    # 正確返回 True;錯誤返回 False
    def __sendMessage(self, phoneNumber, message):
        if not self.execCmd('AT+CMGF=0').endswith(b'\r\nOK\r\n'):     #設置PDU格式
            return False
             
        if not self.execCmd('AT+CSCS="GSM"').endswith(b'\r\nOK\r\n'):    
            return False
         
        pdu_content = self.encodeMessage(phoneNumber, message)
        cmd = 'AT+CMGS=%d' % ((len(pdu_content)-2)/2)
        if not self.execCmd(cmd).endswith(b'\r\n> '):    
            return False
         
        # 十六進制的1A爲結束符
        if not self.execCmd(pdu_content + '\x1A', end='').endswith(b'\r\nOK\r\n'):    
            return False
             
        return True
     
    # 調用私有方法 __sendMessage
    # 在失敗時從新打開串口
    def sendMessage(self, phoneNumber, message):
        for _ in range(0, 3):
            if self.__sendMessage(phoneNumber, message):
                break
            self.reopen()
     
    # 將中文信息編碼爲PDU格式(ucs2)
    def encodeMessage(self, phoneNumber, message):
        tpdu = []
        if phoneNumber and message:             
            tpdu.append('001100')
            
            formatAddress = self.encodePhoneNumber(phoneNumber)
            tpdu.append(formatAddress)
 
            tpdu.append('0008AA')
             
            tpdu.append('%02X' % (len(message)*2))
            content = ''.join(['%02X' % c for c in message.encode('utf_16_be')])
            tpdu.append(content)
         
        print(''.join(tpdu))
        return ''.join(tpdu)
    
    # 將手機號編碼爲pdu所需格式
    def encodePhoneNumber(self, phoneNumber):
        #號碼爲11位數字
        if not re.match(r'\d{11}', phoneNumber):
            print('Error phoneNumber: %s' % phoneNumber)
        
        addr = '0D'  #號碼長度13
        addr += '91'      #Type-of-Address,目標地址格式(TON/NPI) 
        #加8六、F補成偶數個(14位),分7組翻轉
        phoneNumber = '86' + phoneNumber + 'F'
        for i in range(0, 7):       
            addr += phoneNumber[2*i+1] + phoneNumber[2*i]
            
        return addr
     
if __name__ == '__main__':
    messager = Messager()
    messager.sendMessage('18688754379', '你好')
    messager.sendMessage('18688754379', '你們好')


相關閱讀:ui

一、PDU編碼(很是經典)

二、在線PDU格式編碼/解碼

三、使用python實現短信PDU編碼


*** walker ***

相關文章
相關標籤/搜索