树莓派 GSM 语音和短信报警

树莓派 GSM 语音短信报警

  1. 树莓派系统安装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1. 购买树莓派
    2. 购买无线网卡,读卡器,内存卡,HDMI转VGA线,USB转RS232串口连接转换线,相应的电源线
    3. 下载树莓派系统
    4. 将系统安装到内存卡中
    5. 接通电源,启动服务
    6. 通过无线网卡,连接WIFI
    7. 启动ssh服务
    root@raspberrypi:~# /etc/init.d/ssh start
    root@raspberrypi:~# update-rc.d ssh defaults
    root@raspberrypi:~# update-rc.d -f ssh remove
  2. 树莓派基本操作

    1
    2
    3
    4
    5
    6
    7
    pi@raspberrypi:~ $ sudo su -
    root@raspberrypi:~# apt-get update
    root@raspberrypi:~# apt-get upgrade
    root@raspberrypi:~# apt-get install vim ntpdate
    root@raspberrypi:~# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

    root@raspberrypi:~# raspi-config 初始化一些配置
  3. 树莓派工具 密码:yb3k


树莓派 调用 GSM模块 发送短信 和 语音

  1. 给单个用户发送短信

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    pi@raspberrypi:~/gsm $ cat send_sms.py
    #!/usr/bin/env python3
    #coding:utf8

    import RPi.GPIO as GPIO
    import serial
    import time, sys
    import datetime
    import binascii

    P_BUTTON = 24

    def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(P_BUTTON, GPIO.IN, GPIO.PUD_UP)

    def Unicode2HexStr(Unicde_Str):
    Hex_Str = ""
    for i in range(0,len(Unicde_Str)):
    Hex_Str += (hex(ord(Unicde_Str[i])).replace('0x','').zfill(4))
    return Hex_Str

    INFO = Unicode2HexStr('hi,刘朋')

    AA = binascii.a2b_hex('1A')

    SERIAL_PORT = "/dev/ttyUSB0"

    ser = serial.Serial(SERIAL_PORT, baudrate = 9600, timeout = 5)
    setup()

    ser.write('AT+CMGDA="DEL ALL"\r'.encode())
    print(ser.read(ser.inWaiting()))
    time.sleep(1)

    ser.write("AT+CMGF=1\r".encode())
    print(ser.read(ser.inWaiting()))
    time.sleep(1)

    ser.write('AT+CSMP=17,167,2,25\r'.encode())
    time.sleep(3)
    print(ser.read(ser.inWaiting()))

    ser.write('AT+CSCS="UCS2"\r'.encode())
    time.sleep(3)
    print(ser.read(ser.inWaiting()))

    ser.write('AT+CMGS="00310035003200300031003600380034003200320033"\r'.encode())
    time.sleep(2)
    ser.write(INFO.encode())
    time.sleep(1)
    ser.write(AA)
    print(ser.read(ser.inWaiting()))
    time.sleep(1)

    ser.close()
  2. 给单个用户打电话,语音报警

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    pi@raspberrypi:~/gsm $ cat send_gms.py
    #!/usr/bin/env python3
    #coding:utf8

    import serial
    import time, sys
    import datetime

    def Unicode2HexStr(Unicde_Str):
    Hex_Str = ""
    for i in range(0,len(Unicde_Str)):
    Hex_Str += (hex(ord(Unicde_Str[i])).replace('0x','').zfill(4))
    return Hex_Str

    INFO = Unicode2HexStr('你在干什么!!! 我一直在盯着你!!! 你给我小心点!!!')
    SEND_INFO = 'AT+CTTS=1,' + '"' + INFO + '"'
    PHONE_NUM = 'ATD' + '{手机号}' + ';'


    SERIAL_PORT = "/dev/ttyUSB0"

    ser = serial.Serial(SERIAL_PORT, baudrate = 115200, timeout = 5)
    time.sleep(1)

    ser.write("ATE1;\r".encode())
    time.sleep(1)
    print(ser.read(ser.inWaiting()))

    ser.write("AT+COLP=1\r".encode())
    time.sleep(1)
    print(ser.read(ser.inWaiting()))

    ser.write("AT+CTTSRING=0\r".encode())
    time.sleep(1)
    print(ser.read(ser.inWaiting()))

    ser.write("AT+CTTSPARAM=20,0,50,75,1\r".encode())
    time.sleep(1)
    print(ser.read(ser.inWaiting()))

    ser.write((PHONE_NUM + '\r').encode())
    time.sleep(1)

    ABC = 0
    CBA = 0
    while ABC != 1:
    AA = ser.read(ser.inWaiting())
    BB = AA.decode()
    if '+COLP' in BB and 'OK' in BB:
    ser.write((SEND_INFO + '\r').encode())
    time.sleep(10)
    ser.write("AT+CTTS=0\r".encode())
    time.sleep(1)
    ABC = 1
    CBA += 1
    print(CBA)
    if CBA == 50:
    ABC = 1
    time.sleep(1)

    ser.write("ATH\r".encode())
    ser.close()

树莓派 python 模块

  1. pyserial

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    Python中用于读串口的模块是"pySerial"
    读取串口时首先导入包"import serial",其次设置读取哪一个口,波特率,数据位,停止位

    例如:
    class serial.Serial
    __init__( port=None,
    baudrate=9600,
    bytesize=EIGHTBITS,
    parity=PARITY_NONE,
    stopbits=STOPBITS_ONE,
    timeout=None,
    xonxoff=False,
    rtscts=False,
    writeTimeout=None,
    dsrdtr=False,
    interCharTimeout=None )


    baudrate:设置波特率
    bytesize:数据位
    stopbits:停止位
    timeout:超时时间
    timeout = None: 长时间等待
    timeout = 0: 不阻塞形式 (读完之后就返回)
    timeout = x: x秒后超时 (float allowed)

    例2:
    import serial //导入模块
    ser = serial.Serial(0) //打开第一个串口
    print ser.portstr //能看到第一个串口的标识,windows下是COM1
    ser.write("hello") //往串口里面写数据
    ser.close() //关闭ser表示的串口
    ser.open() //打开这个串口
    ser = serial.Serial('COM1', 115200) //来设置波特率,当然还有专门的函数
    data = ser.read() //可以读1个字符
    data = ser.read(20) //可以读20个字符
    data = ser.readline() //是读一行,以/n结束,要是没有/n就一直读,阻塞
    data = ser.readlines()和ser.xreadlines() //都需要设置超时时间
    ser.baudrate = 9600 //设置波特率
    ser //来查看当前串口的状态
    ser.isOpen() //看看这个串口是否已经被打开
  2. RPi.GPIO

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    GPIO(General Purpose I/O Ports)意思为通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平
    用户可以通过GPIO口和硬件进行数据交互(如UART),控制硬件工作(如LED、蜂鸣器等),读取硬件的工作状态信号(如中断信号)等
    掌握了GPIO,差不多相当于掌握了操作硬件的能力

    例如:
    import RPi.GPIO as GPIO //导入RPi.GPIO模块
    或者:
    try:
    import RPi.GPIO as GPIO
    except RuntimeError:
    print("引入错误")

    在RPi.GPIO中,同时支持树莓派上的两种GPIO引脚编号:
    第一种编号是BOARD编号,这和树莓派电路板上的物理引脚编号相对应.使用这种编号的好处是,你的硬件将是一直可以使用的,不用担心树莓派的版本问题.因此,在电路板升级后,你不需要重写连接器或代码
    第二种编号是BCM规则,是更底层的工作方式,它和Broadcom的片上系统中信道编号相对应.在使用一个引脚时,你需要查找信道号和物理引脚编号之间的对应规则.对于不同的树莓派版本,编写的脚本文件也可能是无法通用的

    GPIO.setmode(GPIO.BOARD) //指定BOARD编号
    或者
    GPIO.setmode(GPIO.BCM) //指定BCM规则

    mode = GPIO.getmode() //返回设置的引脚编号

    GPIO.setwarnings(False) //禁用警告

    GPIO.setup(channel, GPIO.IN) //将引脚设置为输入模式
    GPIO.setup(channel, GPIO.OUT) //将引脚设置为输出模式
    GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH) //为输出的引脚设置默认值

    GPIO.cleanup() //释放脚本中的使用的引脚(注意,GPIO.cleanup()只会释放掉脚本中使用的GPIO引脚,并会清除设置的引脚编号规则)

    GPIO.output(channel, state) //设置引脚的输出状态(状态可以设置为0,GPIO.LOW,False,1,GPIO.HIGH,True.如果编码规则为"GPIO.BOARD",那么channel就是对应引脚的数字)

    一次性设置多个引脚:
    chan_list = [11,12]
    GPIO.output(chan_list, GPIO.LOW)
    GPIO.output(chan_list, (GPIO.HIGH, GPIO.LOW))

    你还可以使用Input()函数读取一个输出引脚的状态并将其作为输出值:
    GPIO.output(12, not GPIO.input(12))

    我们也常常需要读取引脚的输入状态,获取引脚输入状态如下代码:
    GPIO.input(channel)
    注意:低电平返回0,GPIO.LOW,False;高电平返回1,GPIO.HIGH.True

    如果输入引脚处于悬空状态,引脚的值将是漂动的.换句话说,读取到的值是未知的,因为它并没有被连接到任何的信号上,直到按下一个按钮或开关.由于干扰的影响,输入的值可能会反复的变化.解决方法:
    GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    注意: 上面的读取代码只是获取当前一瞬间的引脚输入信号

    如果需要实时监控引脚的状态变化,可以有两种办法:
    最简单原始的方式是每隔一段时间检查输入的信号值,这种方式被称为轮询.如果你的程序读取的时机错误,则很可能会丢失输入信号.轮询是在循环中执行的,这种方式比较占用处理器资源.
    另一种响应GPIO输入的方式是使用中断(边缘检测),这里的边缘是指信号从高到低的变换(下降沿)或从低到高的变换(上升沿)

    轮询方式:
    while GPIO.input(channel) == GPIO.LOW:
    time.sleep(0.01) # wait 10 ms to give CPU chance to do other things

    边缘检测:
    边缘是指信号状态的改变,从低到高(上升沿)或从高到低(下降沿).通常情况下,我们更关心于输入状态的该边而不是输入信号的值.这种状态的该边被称为事件
    先介绍两个函数:
    * wait_for_edge() 函数
    wait_for_edge()被用于阻止程序的继续执行,直到检测到一个边沿.也就是说,上文中等待按钮按下的实例可以改写为:
    channel = GPIO.wait_for_edge(channel, GPIO_RISING, timeout=5000)
    if channel is None:
    print('Timeout occurred')
    else:
    print('Edge detected on channel', channel)

    * add_event_detect() 函数
    该函数对一个引脚进行监听,一旦引脚输入状态发生了改变,调用event_detected()函数会返回true,如下代码:
    GPIO.add_event_detect(channel, GPIO.RISING) # add rising edge detection on a channel
    do_something()
    // 下面的代码放在一个线程循环执行。
    if GPIO.event_detected(channel):
    print('Button pressed')

    设置多个回调函数:
    def my_callback_one(channel):
    print('Callback one')
    def my_callback_two(channel):
    print('Callback two')
    GPIO.add_event_detect(channel, GPIO.RISING)
    GPIO.add_event_callback(channel, my_callback_one)
    GPIO.add_event_callback(channel, my_callback_two)
    注意:回调触发时,并不会同时执行回调函数,而是根据设置的顺序调用它们

    例如: 点亮LED灯
    import RPi.GPIO as GPIO //引入函数库
    import time

    RPi.GPIO.setmode(GPIO.BOARD) //设置引脚编号规则
    RPi.GPIO.setup(11, RPi.GPIO.OUT) //将11号引脚设置成输出模式

    while True
    GPIO.output(channel, 1) //将引脚的状态设置为高电平,此时LED亮了
    time.sleep(1) //程序休眠1秒钟,让LED亮1秒
    GPIO.output(channel, 0) //将引脚状态设置为低电平,此时LED灭了
    time.sleep(1) //程序休眠1秒钟,让LED灭1秒

    GPIO.cleanup() //程序的最后别忘记清除所有资源

00310035003200300031003600380034003200320033
00480065006C006C006F002C5218670B