• 懒人的快递提醒小助手


    前言

    欢迎小伙伴们来到第二部分,在前文中 Latest Linux Distributions on LattePanda and Kernel Customization 我们费尽周折配置好了相关环境,本文开始进入第二部分:Core Code to Track the Packages | 包裹监视追踪项目的核心代码

    在这里我们会用到以下知识:

    1. Interaction between MPU and MCU on LattePanda with Firmata protocol | LattePanda上Linux和Arduino使用Firmata协议进行交互
    2. Python GUI Programming with remi | Python图形化编程(使用remi)
    3. Usage of TinyDB——a lightweight database | 介绍轻量级数据库TinyDB的使用
    4. Wechat notification via ServerChan | 使用Server酱实现微信通知功能
    5. Remote Development with Visual Studio Code | 使用VSC进行远程开发

    这一部分将实现如下功能:

    1. 网页前端添加待监视快递信息
    2. 查询的所有快递历史记录
    3. 自定义查询频率
    4. 快递信息变动时微信通知

    the Purpose of this Project | 为什么要做这个项目

    可能很多小伙伴要问了,我的淘宝、京东、菜鸟裹裹也可以帮我查快递,为啥还要弄这个哩?

    1. 隐私性。现在的信息泄露太严重了,不想使用第三方软件。
    2. 合并通知。希望有一个软件可以统一查询大多数的
    3. 减少冗杂的程序。不希望安装过多软件,特别国内的一些软件太流氓,捆绑过多无用功能
    4. 物流信息的订阅与实时追踪。一般的是服务端定时 push 物流信息到手机上,可能存在一定滞后性,而主动 pull 物流信息则可以更快获得相关信息。

    另外我不知道大家是怎样,我有时候买到心仪的东西,特别盼着早点到货,然后隔一会就去打开手机客户端刷新一下查看快递信息,时间久了浪费生命,所以想着用电脑帮我查,有变动主动告诉我。

    Project Architecture | 项目架构

    1. 通过网页前端或者命令行前端,录入待查询快递信息到数据库中,例如 TinyDB
    2. 读取数据库中的信息,利用 Requests 从互联网上的相关网站获取物流信息。
    3. 对获取的物流信息进行处理、如果有变动则录入数据库中,同时调用微信通知接口,使用 Firmata 协议与板载 Arduino Leonardo 交互。
    4. 使用计划任务 crontab 定期获取物流信息。
    5. 使用 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的网站

    1. kuaidi100、kuaidi、baidu—— express-plus 上述实行了严格的请求限制,不推荐使用

    2. 伙伴数据资源 | 推荐 加客服QQ即可以获得密钥,调用简单,但是支持的快递公司不全

    3. TrackingMore | 免费API申请,不推荐

    4. 快宝开放平台 | 可用,类似快递鸟,需要加密

    5. 快递鸟 | 推荐,支持快递公司较全,但是调用麻烦点?参考 kdniao_pythonPython3 调用快递鸟 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! Please 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。同时通过包管理器安装 ``

    image-20200524231047375

    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 也支持蓝牙嗅探,但是需要专门的蓝牙芯片,适用性不那么强,而且并不是所有人的手机蓝牙都是一直开着的,比如我。

    效果类似于这样:

    好,我们下期再见!

    版本更新历史

    1. 2020年5月26日
      • 增加核心代码中所查询单号尚未有物流信息的错误。
      • 更正 healthchecks.io 图片链接,该网站目前打开特别慢
  • 相关阅读:
    Maven 配置篇之 pom.xml
    Maven 配置篇之 pom.xml
    Building Seam 2.0 Application with NetBeans 6.1(Maven2)
    TestNG 使 Java 单元测试轻而易举
    文本加密和解密
    DLL/OCX中的MFC对话框不能处理Tab和回车键的问题 .
    如何在编辑框中使用IAutoComplete接口
    演练:创建和使用静态库 (C++)
    MFC Activex OCX Javascript 互相访问问题,线程回调javascript
    VC++学习方法及书籍推荐 .
  • 原文地址:https://www.cnblogs.com/sjqlwy/p/df51lazy_p2_packages.html
Copyright © 2020-2023  润新知