前言
欢迎小伙伴们来到第二部分,在前文中 Latest Linux Distributions on LattePanda and Kernel Customization 我们费尽周折配置好了相关环境,本文开始进入第二部分:Core Code to Track the Packages | 包裹监视追踪项目的核心代码。
在这里我们会用到以下知识:
- Interaction between MPU and MCU on LattePanda with Firmata protocol | LattePanda上Linux和Arduino使用Firmata协议进行交互
- Python GUI Programming with remi | Python图形化编程(使用remi)
- Usage of TinyDB——a lightweight database | 介绍轻量级数据库TinyDB的使用
- Wechat notification via ServerChan | 使用Server酱实现微信通知功能
- Remote Development with Visual Studio Code | 使用VSC进行远程开发
这一部分将实现如下功能:
- 网页前端添加待监视快递信息
- 查询的所有快递历史记录
- 自定义查询频率
- 快递信息变动时微信通知
the Purpose of this Project | 为什么要做这个项目
可能很多小伙伴要问了,我的淘宝、京东、菜鸟裹裹也可以帮我查快递,为啥还要弄这个哩?
- 隐私性。现在的信息泄露太严重了,不想使用第三方软件。
- 合并通知。希望有一个软件可以统一查询大多数的
- 减少冗杂的程序。不希望安装过多软件,特别国内的一些软件太流氓,捆绑过多无用功能
- 物流信息的订阅与实时追踪。一般的是服务端定时 push 物流信息到手机上,可能存在一定滞后性,而主动 pull 物流信息则可以更快获得相关信息。
另外我不知道大家是怎样,我有时候买到心仪的东西,特别盼着早点到货,然后隔一会就去打开手机客户端刷新一下查看快递信息,时间久了浪费生命,所以想着用电脑帮我查,有变动主动告诉我。
Project Architecture | 项目架构
- 通过网页前端或者命令行前端,录入待查询快递信息到数据库中,例如
TinyDB
。
- 读取数据库中的信息,利用
Requests
从互联网上的相关网站获取物流信息。
- 对获取的物流信息进行处理、如果有变动则录入数据库中,同时调用微信通知接口,使用 Firmata 协议与板载 Arduino Leonardo 交互。
- 使用计划任务
crontab
定期获取物流信息。
- 使用 Kismet 进行网络嗅探,判断目标设备是否在附近,是的话就启用额外的通知手段。否则只微信通知和在网页面板上显示。
注意: Kismet 网络嗅探将在第三部分中详述。
配置VSC远程开发环境
参考 Visual Studio Code remote_ssh 即可。官方提供的工具,非常简单方便。
- 注意一些拓展需要在 Server 上重新安装一遍,
- 支持密钥和账号密码登陆,连接远程服务器时每次都要输入密码,不会保存。建议使用密钥登陆
- Windows 需要ssh-client,我的 Windows_10_1909 默认安装了,没有的在应用-可选里面安装 OpenSSH-Client ,使用 ssh 登陆后会自动配置 server 。
安装常用库
- TinyDB 简单轻量的数据库,除了官方文档,也可以看看 王大桃zzZ 的系列分享
- Requests | 优雅好用的 Python HTTP 库,an elegant and simple HTTP library for Python, built for human beings.
提供物流信息查询服务API的网站
-
kuaidi100、kuaidi、baidu—— express-plus 上述实行了严格的请求限制,不推荐使用
-
伙伴数据资源 | 推荐 加客服QQ即可以获得密钥,调用简单,但是支持的快递公司不全
-
TrackingMore | 免费API申请,不推荐
-
快宝开放平台 | 可用,类似快递鸟,需要加密
-
快递鸟 | 推荐,支持快递公司较全,但是调用麻烦点?参考 kdniao_python 及 Python3 调用快递鸟 Api 查快递
这里我使用的是伙伴数据资源提供的API,首页可以看到支持的快递公司列表。
核心代码(后端)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
__author__ = 'Code_Paintium'
import requests, time, sys
from tinydb import TinyDB, Query
db = TinyDB("/home/sjqlwy/Projects/kd/db.json")
parcel = Query()
# 填入自己的授权密钥,http://www.kdpt.net/express_api.html
# 支持快递公司列表 http://www.kdpt.net/index.html#companies
id = 'YOURIDKEY'
# 增加数据记录
def AddItem(name, com, postid):
if db.search(parcel.postid == postid) == []:
db.insert({'name': str(name), 'com': str(com), 'postid': str(postid), 'Fstatus': {}, 'Cstatus': {}, 'state': ''})
# 微信提醒
def fqtt(desp):
payload_ftqq = {'text': name, 'desp': str(desp)}
requests.get('https://sc.ftqq.com/YOURKEY.send', params=payload_ftqq)
# 检查快递状态
def check_status(com, postid, name, Cstatus):
payload_status = {'id': id, 'com': com, 'nu': postid}
r = requests.get('http://q.kdpt.net/api', params=payload_status).json()
if Cstatus != r['data'][0]:
Cstatus = r['data'][0]
desp = Cstatus['time'], Cstatus['context']
fqtt(desp)
db.update({'Cstatus': Cstatus, 'Fstatus': r['data'], 'state': r['state']}, parcel.postid == postid)
# Main,当没有输入参数时检查已有数据;正确输入参数时创建条目;错误输入时提示
if len(sys.argv) == 4:
AddItem(sys.argv[1], sys.argv[2], sys.argv[3])
elif len(sys.argv) == 1:
pass
else:
print("INVAIND INPUT! pls input name, companny, postid and try again.")
print("e.g., python3 kd.py Gaoda zhongtong zt1124991")
exit
# 仅检查未签收的项目,注意调用时间不小于1s
for item in db.search(parcel.state != '3'):
com = item['com']
postid = item['postid']
name = item['name']
Cstatus = item['Cstatus']
# print(Cstatus)
try:
check_status(com, postid, name, Cstatus)
except IndexError:
print("Delivery infomation not found yet! Please try again later.")
else:
time.sleep(2)
代码逻辑:
因为整体代码比较简单,所以就不用面向对象代码了。
AddItem()
向表中写入数据,该表中包括以下内容:
- 物品名称 name
- 快递公司 com
- 快递单号 str
- 物流全程信息 Fstatus
- 最新物流信息 Cstatus
- 是否已签收 state
fqtt()
用来实现微信提醒功能,借助简单好用的 Server酱 的服务
check_status()
获取快递的最新物流信息,通过 伙伴数据资源 提供的API,可以联系QQ获取KEY
- 首先分析获取的数据,将最新的物流状态与已保存对比
- 有变化的话更新数据库内容
- 运行程序时如果没有参数,则循环查询各个快递状态,有完整参数时添加新的快递以便追踪,参数不对时报错
- 循环查询时,采用
db.search(parcel.state != '3')
来排除已经签收的* 发现仅有单号但未有物流信息时,r['data'] 为 [] ,此时会 r['data'][0] 报错 IndexError: list index out of range
。
如何使用
- 你需要去 Server酱 注册登录账号,获取自己的 SCKEY ,然后绑定微信即可
- 去伙伴数据联系客服 QQ 免费获取自己的 IDKEY
- 设置数据库存储路径,建议使用绝对路径,我的是
/home/sjqlwy/Projects/kd/db.json
效果展示:
# 首次需要输入参数以向数据库中添加相关信息,为物品名称(自定义)、快递公司(可以选auto来自动识别,如果获取信息错误可以移步伙伴数据获取名称,如shentong)、快递单号。
python3 kd.py FS-T6 auto 773037873703622
# 录入信息后,后续查询不带参数运行则会遍历数据库中所有未签收的快递
python3 kd.py
定期执行
这里想到最省资源最方便的就是系统自带的计划任务,定时每 1h 无参数运行 kd.py
即可。
crontab -l
crontab -e
0 */1 * * * /usr/bin/python3 /home/sjqlwy/Projects/kd/kd.py
2 */1 * * * /usr/bin/curl -l https://hc-ping.com/6ebdfd32-1fd5-4ecf-******* # use your own
同时添加计划任务提醒,这里借助 healthchecks 。填写任务名称,备注等,然后设置时间和之前的差不多,执行的命令为向下述网址发送一个 http 请求,建议用 curl -l URL
, 最省事。
关于 crontab 的使用参考 之前的文章 ,直接 crontab -e 编辑即可,不需要重启服务,现在都是 systemd 接管。记得设置好时区,参考 System time 。
网页前端 [TBD]
相信了解我的小伙伴知道我之前在 LattePanda 项目之 P2.2 起飞条件检测系统(CLI & GUI) 一文中介绍过 remi, Remi is a GUI library for Python applications that gets rendered in web browsers。
该前端实现的功能就是增加欲追踪包裹数据,发给后端。remi带了一个图形化编辑器,支持拖拽。[TBD]
使用 Firmata协议 交互
之前写过一部分,由于相关库更新,这里写一下。
之前主要介绍三个两款:
如果你需要的功能不多,用起来越简单越好,就选pyFirmata。如果你有一些高级功能的应用需求,就选上面的两个,同时提供了增强版的FirmataExpress sketch, 相比Arduino IDE 自带的 StandardFirmata 它提供了如下特性:
- HC-SR04 Ultrasonic Distance Sensors using a single pin.
- DHT Humidity/Temperature Sensors.
- Stepper Motors.
- Piezo Tone Generation.
- Baud rate of 115200
更新Arduino IDE
之前用的 sudo apt install arduino
进行安装的,打开感觉不太对,一股子历史感。一看还是超级老的版本,怀疑根本没人维护源里面的这个软件包,果断官网下载最新的 arduino ide 1.8.12
。同时通过包管理器安装 ``
from pyfirmata import Arduino, util
board = Arduino('/dev/ttyACM0')
board.digital[13].write(1)
剩下的就简单了,创建一个函数 ArduCom()
, 想干啥干啥了。
Additional Functions | 额外功能
热敏打印机
今天看了葛老师的帖子,想着也可以用那个标签打印机打印出来,后续会更新。
网页面板
类似 Home Assistant 那种
下期预告
想要实现一个功能,就是如果探测到人在旁边,就激活额外的提醒功能,例如语音播报等。难点就是如何知道人在旁边,[发现的一个思路]()就是使用 Kismet 这个软件进行无线嗅探。
一般情况下,我们的设备是如何连接到已经保存的无线网的呢?原理大致是设备一直向空中发送数据包,询问名为 XXX0 的无线网络在吗,如果无应答,就继续询问 XXX1 在吗?而如果相应的无线网络存在,就会回复我在,可以连接。
题外话: 这也就是网络欺骗的原理之一,设备询问有没有 XXX0 的时候,按规矩如果你不是 XXX0 的话,就不要吱声,而诱骗设备则会告诉设备我就是 XXX0 ,然后接收设备提供的密码进行连接,继而实现 mitm 中间人攻击。
那我们实现无线追踪的方法就是记录设备的 mac 地址,听到该设备在吆喝,就知道人在旁边。因为需要一个支持 monitor 模式的无线网卡,所以我们要额外通过有线网或者第二块无线网卡以供连接。因为板载的无线网卡虽然支持 monitor/station/client 模式的,但是 iw list
不支持同时运行2个以上模式。当然 Kismet 也支持蓝牙嗅探,但是需要专门的蓝牙芯片,适用性不那么强,而且并不是所有人的手机蓝牙都是一直开着的,比如我。
效果类似于这样:
好,我们下期再见! ## 版本更新历史
- 2020年5月26日
- 增加核心代码中所查询单号尚未有物流信息的错误。
- 更正 healthchecks.io 图片链接,该网站目前打开特别慢