用上网卡转发短信

在 V 站上上了个 SIM 卡的车。但长时间带着俩手机不方便。于是就想办法将短信和电话从备用手机实时转到主力机上。试了 IFTTT,不稳定。然后就想用树莓+SMS 开发版来做这个事儿。偶然间发现其实上网卡里面也藏着短信功能,就买了个上网卡开始鼓捣。

25 块钱,深水鱼二手,包邮到家。

物理

我买来的是华为 E303s。一个 12 年左右的 3G 上网卡,可以插一个大 SIM 卡和一个 MicroSD 卡。

插上 Win 电脑,会识别出来一个 USB 光盘。自动安装驱动,弹出 192.168.1.1 的控制页面。赶快取消自动拨号、断线重连、漫游。反正是把能关的都关了。信号选自动。

插上 Linux 电脑,毛事情都没发生?

  • lsusb 看一下,发现一个 Bus 001 Device 011: ID 12d1:14db Huawei Technologies Co., Ltd.。注意这里的 12d1:14db。后面会用到。
  • dmesg 可以看到,识别了一个 USB Mass Storage,还有一个网卡设备。
  • ip a 可以看到,多了一个网卡。
  • ls /dev | grep ttyUSB,什么都没有。

查资料(都是些 13 年左右的帖子……好老了……毕竟买的是 3G 上网卡,也都是 12、13 年的东西了)发现,它有好多工作模式:一种是 U 盘模式,一种是 HiLink 模式,一种是 Debug 模式,最后还有个序列设备模式。下面我们用两种方法来用它。

方法一 使用内置 WebAPI

这个 3G 上网卡里面有一套 WebUI 给用户使用的。由于是前后端分离的写法,API 可以比较容易地找到,一个 Chrome F12 就可以找出来大多数 API。我们可以用找到的这些 API 来做一些事情,比如状态监测、短信收发。

说简单也简单,说难也难,毕竟是第一次在完全没有文档和说明的情况下扒 API 来用。另外是测试比较费钱……

说一下几个坑的点:

  • 最最关键的,会多出一块网卡。后果是访问某些网站的时候会被带到上网卡的 WebUI 上,而不是从树莓派的有线网链接到 Internet。虽然代码很方便,但不太推荐。
  • 首先是,它是通过 XML 交互的,但也不完全。
  • 其次是,所有参数都是有顺序的,只能用 OrderedDict 进行序列化。
  • 最后是,不需要找着网上的教程去拿 Header、拿 Token、登录。直接暴力 request 解决问题即可。

大体思路是这样的:

  1. 看一下统计信息,如果有未读信息,就处理
  2. 从收件箱里面取出短信
  3. 对于每一条短信,该转发就转发,该 Push 就 Push
  4. 删除这条消息
  5. 收尾,清空发件箱

在用函数调试通过之后,封装成了类,便于使用。整个文件见这里。除了没写注释之外,代码风格还算过得去吧?

加入 crontab 豪华套餐,给手机卡充好值,开始享受「双卡」吧。

方法二 使用 AT 指令

这种方式,我们可以用比较低层的命令直接操控。好处是不会因为多一个网卡而出现很多奇奇怪怪的事情。缺点嘛……比较麻烦。

将上网卡转到 ttyUSB 模式

上面做了那么多测试,说明这个上网卡工作在 HiLink 模式。对于一般使用者来说,免驱动即插即用,是极好的;但对于我来说……我要通过 tty 和 AT 指令来读短信啊。所以就需要把模式切换到 ttyUSB 模式。

IDlsusb namemode
12d1:1f01Huawei Technologies Co., Ltd.USB Mass Storage
12d1:14dbHuawei Technologies Co., Ltd.HiLink
12d1:14dcHuawei Technologies Co., Ltd.HiLink
12d1:1001Huawei Technologies Co., Ltd. E169/E620/E800 HSDPA ModemModem
12d1:1c05Huawei Technologies Co., Ltd. Broadband stick (modem on) 

这个过程比较波折一些。资料中提到很多种方法,下面是我觉得成功率最高、最简单的。

方法一(确认成功)

新建文件/etc/usb_modeswitch.d/12d1:1f01,输入内容

# Huawei E303s - switch to other mode instead of HiLink CDC-Ether mode
#DefaultVendor=  0x12d1
#DefaultProduct= 0x14db
TargetVendor=0x12d1
TargetProduct=0x1f01

# switch to E169/E620/E800 HSDPA Modem
MessageContent="55534243000000000000000000000011060000000000000000000000000000"

# switch to USB Mass Storage mode
#MessageContent="55534243123456780000000000000011062000000100000000000000000000"

# Unknown
#MessageContent="55534243123456780000000000000a11062000000000000100000000000000"

# Unknown
#MessageContent="55534243123456780000000000000011062000000101000100000000000000"

然后重启。lsusb 可以按到已经工作在了 Modem 模式下。再用 ls /dev | grep ttyUSB 就可以看到三个 ttyUSB 设备了。

按说此时就能直接用了。不过为了避免以后麻烦,我们再多做一点东西。

我们可以使用 screen /dev/ttyUSB2 来进行控制。如果 screen 之后发现怎么敲键盘都没反应就说明不是 ttyUSB2,就换其他的。

输入

AT^U2DIAG?

查看当前模式,最好能记录下来。然后再输入

AT^U2DIAG=0

就可以让网卡以后都工作在这个序列设备模式上。当然,如果想切换回来,也很简单,输入

AT^U2DIAG=375

就好了。其中最后的 375 是第一步记录下来的数字。

之后删除前面创建的/etc/usb_modeswitch.d/12d1:1f01 文件。

拔下上网卡,插到其他 Linux 电脑上——是不是发现出现了 ttyUSB 设备了呢?这时候再用 lsusb 看设备,会发已经变成了最后一个模式——能用就行了呗。

方法二(没有继续试下去)

工作在 HiLink 模式下,看 ip a,会多出来个 eth1 网卡。然后就有人找到了方法开启调试(debug)模式:

curl -X POST -d '<?xml version="1.0" encoding="UTF-8"?><request><mode>0</mode></request>' http://192.168.1.1/api/device/mode

会出现两个 ttyUSB 设备。想办法连接上去,然后用前面的 AT 指令弄成个永久的 ttyUSB 模式——我没有做继续尝试。tty 一直都是黑屏,可能是波特率设置不太对的原因吧。

测试发短信

我们就不亲自用 AT 指令来发短信了,找现成工具代劳吧。

sudo apt-get install gammu

然后进行一下配置

gammu-config

Port 选我们能用的那个 ttyUSB 设备。 Connection 可以在这里找到。我选择了 at19200。其他保持默认。

最后,确认一下信息

$ gammu --identify
Device               : /dev/ttyUSB2
Manufacturer         : Huawei
Model                : E303 (E303)
Firmware             : 22.157.39.00.112
IMEI                 : XXXXXXXXXXXXXXX
SIM IMSI             : XXXXXXXXXXXXXXX

发个短信试试

$ echo "HelloWorld" | gammu sendsms TEXT 18XXXXXXXXX
If you want break, press Ctrl+C...
Sending SMS 1/1....waiting for network answer..OK, message reference=67

获取和转发短信

在收到短信后,上网卡会通过内部私有指令第一时间将短信读出来、给网络发 ACK 消息、存储到内部 Inbox 里。所以直接用 AT 指令是获取不到短信的!这里我暂时没搞定。


没搞定的话……就又在深水鱼上 20 元包邮了个华为 E220。这个东西插上去就直接有两个 ttyUSB,而且 ttyUSB1 是我们需要的接口。省事很多。

方案一: 使用 gammu-systemd

我们的逻辑是这样的: 使用 gammu-smsd 服务获取短信,存储在 sqlite 里面。写一个 Python,定时查看 sqlite 内容,找到没处理的短信,进行转发。这样的好处是有完整的记录,万一转漏了,之后也能再把短信找到。

所以第一步是安装一些东西:

sudo apt install libgammu-dev python3-gammu gammu-smsd libdbd-sqlite3 libsqlite3-dev sqlite3

这里安装了 gamu-smsd 和 python 的接口,并且还有 sqlite 及其接口。

如果使用 Conda 来安装的话,可以这样玩:

sudo apt install gammu-smsd libgammu-dev
conda create --name pisms python=3 sqlite 
source activate pisms
pip install python-gammu

安装后,编辑/etc/gammu-smsdrc 文件:

[gammu]
port = /dev/ttyUSB1
connection = at19200
[smsd]
service = sql 
logfile = syslog 
debuglevel = 0 
driver = sqlite3 
dbdir = /home/pi 
database = smsd.db 

最后是创建一个 smsd.db 的 sqlite 数据库。我们找到/usr/share/doc/gammu/examples/sql,这里面有例子。

OK,准备工作做完了,这样新来短信会直接被存储到这个 sqlite 数据库中。

我们使用 Python 代码来完成短信转发这件事儿。代码见这里

同样,加入 Crontab 豪华套餐,开始享受短信转发。

方案二: 直接使用 gammu

这个不想写了。大致思路是,只使用 gammu,不使用 gammu-smsd。每次直接从 sim 卡中手动获取短信,然后进行转发,并删除已经转发过的短信。应该和上面的代码差不多。

总结

不难,就是 Debug 比较费钱。Debug 过程总共浪费了 30 多条短信

我们还可以再转发之前加一层过滤,避免转发垃圾短信——嗯,搞个 SVM 分类器?反正文本都已经拿到了,怎么玩就随意了吧?

同样的,我们还可以将短信推送到 Telegram 上、Wechat 上、邮件上,甚至微博和 Twitter 上。甚至可以搞一个自动展示短信的网站——随意啦。

参考资料

留下评论