# UDX710短信桌面提醒 **Repository Path**: zinface/udx710-sms-notification ## Basic Information - **Project Name**: UDX710短信桌面提醒 - **Description**: 轮询 UDX710 模块(接口固定地址 `http://192.168.66.1`)的短信接口,**新收到短信时在电脑上弹出桌面通知**。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-25 - **Last Updated**: 2026-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # udx710-sms · 短信桌面提醒 轮询 UDX710 模块(接口固定地址 `http://192.168.66.1`)的短信接口,**新收到短信时在电脑上弹出桌面通知**。 这是 Android 版的「逻辑试验田」:轮询节奏、id 去重、纳秒时间戳解析、只提醒 incoming、长短信截断等规则都在这里先跑通并验证,之后可原样移植到 Kotlin/Compose 工程。 ## 文件 | 文件 | 说明 | |---|---| | `udx710-sms-notify.py` | 主程序,仅依赖 Python 3 标准库,无需 pip install | | `poll-notify.sh` | 最小 bash 版(`curl` + `notify-send`),用于快速验证或对照 | | `test-notify.py` | 关键逻辑离线测试(时间戳解析、去重、方向过滤),不发通知、不碰设备 | | `state.json` | 运行时状态(已提醒到的 id 水位),自动生成,勿提交 | | `linux/install.sh` | 用户级安装脚本(装到 `~/.local`,可选 systemd 用户服务) | | `linux/udx710-sms-notify.service` | systemd 用户服务单元(含 `@EXEC@`/`@ENVFILE@` 占位符,install.sh 会替换) | | `linux/udx710-sms-notify.sh.in` | 免扩展名命令的启动器模板(读取 environment 后 exec 主程序) | | `linux/environment.example` | 配置示例(接口地址、状态文件位置),带注释供查阅 | ## 测试 ```bash python3 test-notify.py # 17 项断言,覆盖纳秒时间戳解析与去重规则 ``` ## 快速开始 ```bash cd udx710-sms ./udx710-sms-notify.py --once # 首轮:只播种基线,不弹历史短信 ./udx710-sms-notify.py # 常驻,默认 15 秒轮询 ./udx710-sms-notify.py -i 5 # 5 秒轮询 ./udx710-sms-notify.py --sound # 新短信时额外播放提示音 ./udx710-sms-notify.py --urgency normal --timeout 8000 # 气泡 8 秒自动消失 ``` ## 工作原理 ``` ┌─ 每 15s ─┐ GET /api/sms/stats (几十字节,便宜) │ 轮询 │──▶ total 与上次相同 ──▶ 直接跳过,不发列表请求 └──────────┘ │ └─ 变了 ──▶ GET /api/sms/list?limit=50 │ ├─ 过滤 direction == outgoing ├─ 过滤 id <= 水位(去重) └─ 逐条 notify-send -r 6000+id ``` * **两级轮询**:先用 `/api/sms/stats` 的 `total` 判断有没有变化,没变就不拉列表,省流量也省电。 * **去重靠 id 高水位**:水位存 `state.json`,进程重启不会重复提醒。接口没有 `since` 参数,所以一律「拉最近 N 条 + 本地过滤」。 * **首次运行只播种基线**:不会把模块里已有的历史短信全部弹一遍。 * **同会话聚合**:通知 id 用 `6000 + 短信id` 传给 `notify-send -r`,同一条会的更新复用同一条气泡,不会刷屏(已用 `dbus-monitor` 验证两次 `Notify` 调用的 `replaces_id` 一致)。 * **只提醒 incoming**:`direction == "outgoing"` 的发送记录不提醒。 * **长短信截断**:实测最长收到过 309 字,通知正文截到 300 字;接口报文本身是 UTF-8 无 BOM,中文正常。 ## 通知后端分层 | 层级 | 手段 | 触发条件 | |---|---|---| | 主 | `notify-send`(libnotify / `org.freedesktop.Notifications`) | 正常桌面会话 | | 降级 | 终端彩色输出 + 响铃 `\a` | 没有 D-Bus(SSH、无桌面)时自动切换 | | 可选 | `mpv` 合成提示音(回退 `paplay` + 系统音效) | `--sound` | | 可选 | Webhook 推送到手机 | `--webhook-url` | 跨平台预留:本机是 Linux/X11 + D-Bus,脚本按 Linux 实现;macOS 需换 `osascript`、Windows 需换 PowerShell toast,目前只留了分层结构未写死。 ## 推送到手机(人不在电脑前时) ```bash # Bark(iOS) ./udx710-sms-notify.py --webhook-url https://api.day.app/你的key --webhook-kind bark # 钉钉 / 企业微信机器人 ./udx710-sms-notify.py --webhook-url 'https://oapi.dingtalk.com/robot/send?access_token=xxx' --webhook-kind dingtalk # Server酱 ./udx710-sms-notify.py --webhook-url https://sctapi.ftqq.com/你的key.send --webhook-kind serverchan ``` ## 安装(推荐,用户级、免 root) 仓库的 `linux/` 目录提供安装脚本与可查看的 systemd 单元文件,默认装到 `~/.local`: ```bash git clone https://gitee.com/zinface/udx710-sms-notification.git cd udx710-sms-notification/linux ./install.sh ``` 安装脚本会: 1. 把主程序装到 `~/.local/bin/udx710-sms-notify.py`; 2. 生成 `~/.local/bin/udx710-sms-notify`(**启动器**,运行前会读取配置,保证与服务行为一致); 3. 在 `~/.local/state/udx710-sms/` 写入 `environment`(接口地址 + 状态文件位置)与 `environment.example`; 4. **询问**是否安装 systemd 用户服务(开机自启 + 崩溃自动重启),回答 `n` 就只装命令。 ```bash ./install.sh -y # 全部默认,不询问 ./install.sh --no-systemd # 只要命令,完全不碰 systemd ./install.sh --interval 30 --sound ./install.sh --dry-run # 只打印将要做什么 ./install.sh --uninstall [--purge] ``` 装好后: ```bash udx710-sms-notify # 前台运行 systemctl --user status udx710-sms-notify journalctl --user -u udx710-sms-notify -f ``` > 若提示 `~/.local/bin` 不在 PATH 中,把 `export PATH="$HOME/.local/bin:$PATH"` 加进 `~/.bashrc`。 > 另外,未开启 linger 时注销登录后服务会停止,需要时执行 `sudo loginctl enable-linger $USER`。 不想用安装脚本、或想手动配置 systemd 时,见下面的「手动运行方式」。 ## 手动运行方式 ```bash # 方式一:nohup nohup ./udx710-sms-notify.py -i 15 >> udx710-sms.log 2>&1 & # 方式二:直接使用仓库里可查看的单元文件模板 # linux/udx710-sms-notify.service 中 @EXEC@ / @ENVFILE@ 由 install.sh 替换; # 手动安装时自行改成实际路径即可。 mkdir -p ~/.config/systemd/user sed -e "s#@EXEC@#$PWD/udx710-sms-notify.py -i 15#" \ -e "s#@ENVFILE@#$HOME/.local/state/udx710-sms/environment#" \ linux/udx710-sms-notify.service > ~/.config/systemd/user/udx710-sms-notify.service systemctl --user daemon-reload systemctl --user enable --now udx710-sms-notify.service journalctl --user -u udx710-sms-notify -f ``` ```bash # 方式三:cron 每分钟(用 --once,无长驻进程) * * * * * /path/to/udx710-sms/udx710-sms-notify.py --once >> /tmp/udx710-sms.log 2>&1 ``` ## 状态文件位置 已提醒到的短信 id 水位存在 `state.json`,避免重启后重复提醒。查找顺序: 1. 命令行 `--state-file` 显式指定; 2. 环境变量 `UDX710_STATE_FILE`(安装后的 `environment` 会写入这一项); 3. 否则:脚本所在目录可写就用同目录的 `state.json`,不可写就用 `${XDG_STATE_HOME:-~/.local/state}/udx710-sms/state.json`。 也就是说:**在仓库里直接运行**用仓库内的 `state.json`;**装到 `~/.local` 后运行**用 `~/.local/state/udx710-sms/state.json`,不会污染安装目录。 ## 已知限制 * **电脑必须开机**。这是桌面提醒的固有限制;要「人不在电脑前也收到」,用上面的 Webhook 出口,或改做 Android 版。 * **轮询有延迟**:默认 15 秒,最大延迟即一个轮询周期。`-i` 可调,但别低于 2~3 秒。 * **接口无鉴权**:局域网内任何人可读写短信,甚至 `POST /api/system/reboot`。不要把该地址暴露到公网。 * `/api/sms/clear`、`/api/system/reboot` **无二次确认**,不要随手调用。 * 设备型号字段是假数据(`Fake Modem Manufacturer`),不要用于逻辑判断。 ## 移植到 Android 的对应关系 | 本脚本 | Android 方案 | |---|---| | `run_cycle()` 两级轮询 | `SmsRepository.tick()` | | `state.json` 的 id 水位 | DataStore / Room | | `notify-send -r` | `NotificationManagerCompat` + `tag`/`id` + channel 分组 | | `while True` + `sleep` | `ForegroundService`(准实时)或 `WorkManager`(15 分钟保底) | | `parse_time()` 纳秒归一化 | 同逻辑,但注意 `Instant.parse()` 会直接抛异常 | ## 致谢 本工具调用的短信 HTTP 接口(`/api/sms/list`、`/api/sms/stats`、`/api/sms/send` 等,即 `http://192.168.66.1` 上的 UDX710 模块后台)来自开源项目: **[1orz/project-cpe](https://github.com/1orz/project-cpe)** —— 5G 模组高级后台 感谢该项目作者提供并开源这套模块后台与 API。本仓库只做轮询与桌面通知的消费端实现,接口本身的设计与实现均归原作者所有;如接口有更新,请以该项目为准。