MENU

利用GSM模块给NAS增加短信功能

July 30, 2021 • Read: 2747 • 技术杂谈

一、前序

大概在小学快上初中的时候吧,那时候喜欢泡各种“手机游戏软件分享”类似的论坛,基本都是柯林程序搭建的;当时这些程序源码对于用户注册、找回密码这些动作验证,都和一个叫做“短信云猫”的东西有关。

像现在,这些动作基本都是以“收取验证码”的形式作为验证,而“云猫”却恰恰相反,它是通过发送指定“口令”给指定号码的形式作为验证;他们之间的区别和优势这里就不做比较了,虽然“云猫”这种东西好像逐渐淡出了生活的视线,但这种曾经的过往记忆还是比较深刻。

回到现在,我们现在每个人有多张手机卡很正常,工作学习可能都有一张卡,像我初中时期办的一张移动卡至今还在用,虽然电话基本已经不打了,除了怀旧之外,还绑定了不知道多少个网站APP,所以换是不可能换的,这辈子都不可能换卡的!

刚好最近在慢慢学Go,也凑巧知道有个包能支持串口通信,于是这件事就提上了日常,前后折腾了一个礼拜左右(等快递...),能够顺利收取短信,后期可能慢慢加其它功能。

Ps:虽然随便买个二手机也能插卡,但想要享受折腾的乐趣,那就得折腾,嘿嘿!

二、硬件准备

1、NAS

其实这也谈不上是一个NAS,是我在闲鱼收的矿渣“我家云”套壳产品联想云,系统刷的是别人搞好的固件Armbian,结果我觉得不好用,把所有无关组件全删了;然后装了宝塔、V2、Zerotier和Samba,又塞进去一块1T的硬盘;放家里做家庭代理,内网穿透共享文件夹用用。

刚好机器后面还有空余的USB口,于是想着也可以刚好把它利用起来。

2、USB转TTL模块

我用的型号是CH340G,USB不能和通信模块直接通信,所以需要一个模块中转一下;而驱动方面支持的也比较好,Windows 直接驱动精灵扫描一下直接安装就行,Linux 好像直接是自带就有,反正我的Armbian没有额外安装,插上就能直接用,不过好像就是版本有点老。

3、GSM 通信模块

通信模块用的型号是SIM800C,支持移动联通卡,通信是基于GSM 的2G网络,所以购买的时候一定要查清楚自己地区2G有没取消;坐标上海已经全面取消了联通2G,我刚测试的时候差点帮我整懵了还以为是模块有问题。

4、闲置手机卡

我的目标是要托管一张我自用的中国移动的正常手机卡,但测试用的是一张香港手机卡,也是中国移动信号,所以不影响。


Ps:USB转串口和GSM模块都是淘宝同一个店铺买的,一共不到50块钱,价格一般般吧。

三、软件准备

刚拿到模块的时候需要对模块进行调试测试,确保工作正常,所以需要一些串口调试助手软件进行测试。

  • Windows 推荐 野火调试助手,这软件一般买模块的时候,最好直接问商家要,有问题也方便直接沟通。
  • Linux 推荐 minicom,这是一款命令行调试工具;使用之前先确保驱动正常,再插上模块,随后在/dev目录下面就会出现串口路径;我的是/dev/ttyUSB0,在自己敲代码写程序的时候,这个路径就是串口名。

然后其它软件,就靠自己写了,比如本篇文章,我只完成了基本的收信读取功能,反正只要你会写,功能总是可以搞定滴!

四、图片展示

联想云NAS

平常放在路由器旁边,还有一个小风扇,买了大概半年多了吧,取代了我之前的树莓派3B
联想云.jpg
联想云 (2).jpg
联想云 (3).jpg

模块

USB转TTL和GSM模块使用杜邦线连接好,注意接线,TX和RX互接,GND接地,VCC五伏供电
USB转TTL.jpg
SIM模块.jpg

QQ换绑测试

换绑自己玩游戏的QQ小号作为测试,成功发送了验证码
QQ换绑.png

短信收取

代码跑起来之后,成功收到了来自腾讯的短信验证码,看发信号码,也属于香港地区
短信收取.png

五、成品代码


package main

import (
    "fmt"
    "github.com/tarm/serial"
    "log"
    "strings"
)

func main() {
    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 115200}
    com, err := serial.OpenPort(c)
    if err != nil {

        log.Fatal(err)
    }

    n, err := com.Write([]byte("AT\r\n"))
    //com.Write([]byte("AT+CMGF=1\r\n"))
    //n, err := com.Write([]byte("ATE0\r\n")) //关闭回显
    //n, err := com.Write([]byte("AT+CMGR=14\r\n"))
    //n, err := com.Write([]byte("ATD008618209809694;\r\n"))
    if err != nil {

        log.Fatal(err)
    }

    data := ""
    buf := make([]byte, 128)
    for {
        n, err = com.Read(buf)
        if err != nil {

            log.Fatal(err)
        }

        data += string(buf[:n])
        if n < 32 {
            if strings.Contains(data, "CMTI") {
                header := strings.Split(data, ",")
                smsId := clearInvalidChar(header[1])
                log.Printf("收到一条新短信[%s]>>>\n", smsId)

                com.Write([]byte(fmt.Sprintf("AT+CMGR=%s\r\n", smsId)))
            } else if strings.Contains(data, "CMGR") {
                log.Println("短信读取内容如下>>>")

                arr := strings.Split(data, "\r\n")
                info := strings.Replace(arr[1], "\"", "", -1)
                header := strings.Split(info, ",")
                content := arr[2]

                log.Println("发信号码:" + header[1])
                log.Println("发信时间:" + header[3] + " " + header[4])
                log.Println("短信内容:" + content)
                log.Println("--------------------------- \n")
            } else {
                log.Println("未知数据:" + data)
            }

            // 清空数据
            data = ""
        }
    }
}

func clearInvalidChar(str string) string {
    str = strings.Replace(str, " ", "", -1)
    str = strings.Replace(str, "\r", "", -1)
    str = strings.Replace(str, "\n", "", -1)

    return str
}

六、最后

  • 这个GSM模块不仅仅只是收发短信,还可以打电话、GPRS通信,还是挺好玩的,可玩性比较高,推荐点赞!
  • 本篇的代码只是Demo测试,能够勉强跑起来;短信的解析只是文本模式简单的字符串切割,如果用PDU解析的话会更加标准。
  • 整个过程参考了各种资料,因为涉及的文档地址太多,最后我也不记得到底看了多少资料,所以就不一一列出来了;总之:感谢各位大佬前辈。
Last Modified: August 2, 2021