使用 Python+AT 指令接收并解码中文短信

我手上的设备型号是「EC600N」, 使用「联通4G」卡, 查看短信流程如下:

1
2
3
4
5
6
7
8
9
> AT+CMGF=1
OK # 这一句用于设置读取短信时为文本模式, 由于未知原因, 在我的设备上PDU模式总是空的
> AT+CMGL="ALL"
+CMGL: 0,"REC UNREAD","180********",,"22/10/03,11:35:58+32"
4E2D658777ED4FE16D4B8BD5002000680065006C006C006F00200077006F0072006C0064

OK # 这一句用于查阅所有短信, 无论已读未读
> AT+CMGD=1,4
OK # 这一句用于删除储存1里的所有短信, 阅后即焚

收到的短信格式是这样的:

1
2
3
4
5
> AT+CMGL="ALL"
+CMGL: 0,"REC UNREAD","180********",,"22/10/03,11:35:58+32"
4E2D658777ED4FE16D4B8BD5002000680065006C006C006F00200077006F0072006C0064

OK

这串字符是「utf-16-be」编码的十六进制表示, 在Python里应当使用如下解读方式:

1
2
3
>>> line = '4E2D658777ED4FE16D4B8BD5002000680065006C006C006F00200077006F0072006C0064'
>>> bytes.fromhex(line).decode('utf-16-be')
中文短信测试 hello world

综合来讲, 我的代码是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
async def main():
ec600n = ES600N()
await ec600n.write('AT')
assert await ec600n.wait_ok()

await ec600n.write_wait_ok('AT+CMGF=1')
res = await ec600n.write_wait_ok('AT+CMGL="ALL"')
for line in res.splitlines(keepends=False):
if not re.match("^[0-9A-F]+$", line):
print(line)
else:
print(bytes.fromhex(line).decode('utf-16-be'))

inputs = input('删除所有短信吗? [yes/NO]\n')
if inputs.lower() == 'yes':
print(await ec600n.write_wait_ok('AT+CMGD=1,4'))

运行结果是这样的:

1
2
3
4
5
6
7
8
$ python 收短信.py
+CMGL: 0,"REC UNREAD","180********",,"22/10/03,11:35:58+32"
中文短信测试 hello world

OK
删除所有短信吗? [yes/NO]

$