253 lines
12 KiB
Markdown
253 lines
12 KiB
Markdown
# 💧 水厂智能货柜(IoT)分布式终端接入与自动化交付技术白皮书
|
||
|
||
## 一、 业务愿景与战略定位
|
||
本方案旨在通过 **IoT(物联网)** 硬件矩阵,实现水厂饮用水交付的全面自动化与去人工化。针对**无屏幕、定位提货、套餐保值**等核心需求,构建“线上订水、LBS 匹配、无感交付”的智慧物流体系。
|
||
|
||
---
|
||
|
||
## 二、 核心应用场景与业务需求模型
|
||
|
||
### 1. 定位提货与套餐保值逻辑
|
||
* **需求:** 用户购买桶水套餐,不受后续调价影响;定位用户小区并呈现所有单元楼提水点,实现远程库存预览,防止用户“跑空”。
|
||
* **小程序实现:**
|
||
* **权益钱包**:引入“虚拟储水池”概念,用户购买套餐后,账户记录为“待取桶数”,而非金额,实现锁价保值。
|
||
* **LBS 智能网格**:首页通过 `uni.getLocation` 获取坐标,服务器根据经纬度反向检索关联小区,并在地图上以“桩位”形式展示该小区内所有单元楼下对应的提柜状态(空闲/库存数)。
|
||
* ****【新增机制:空柜自动调导 (Self-Correction)】****:当某单元楼货柜库存为 0 时,地图图标转为置灰状态并显示“补货中”,同时系统自动计算并推荐该小区内距离最近的“有货柜机”。
|
||
|
||
### 2. 无屏幕式“无感核销”模式(蓝牙/云端直控)
|
||
* **需求:** 货柜感应 + 云端瞬时指令”**模式。
|
||
* **操作流**:用户靠近货柜 $\rightarrow$ 手机蓝牙自动识别设备号(Beacon 广播)或 LBS 确认经纬度重合 $\rightarrow$ 小程序自动弹出“当前已到达XX单元提水点” $\rightarrow$ 用户在手机点击“开门” $\rightarrow$ 云端通过 MQTT 指令开锁。
|
||
* **价值**:降低硬件成本(无屏、防暴力),提升交互流畅度。
|
||
|
||
### 3. 故障闭环与客服联动系统
|
||
* **需求:** 下单不开门、没电、库存不足等异常,自动切入客服协助。
|
||
* **业务逻辑:**
|
||
1. **主动监测**:系统 15 秒内未收到门磁反馈,自动触发“开启失败弹窗”。
|
||
2. **一键路由**:弹窗直接集成“在线客服”与“紧急开锁申请”。对于电池电量低于 10% 或库存为 0 的柜体,小程序端自动置灰并置顶显示“联系客服维修/补货”。
|
||
|
||
### 4. 商家端(水厂)实时监控看板
|
||
* **需求:** 实时获取补货、电量、库存等全量信息。
|
||
* **技术看板:**
|
||
* **IoT 设备画像**:每个柜子都有实时“血条”(电量指示)和“胃容积”(库存比例)。
|
||
* **热力算法**:根据库存消耗频率,自动标注哪些柜子属于“急需补货”级别。
|
||
|
||
### 5. 补货员/检修员管理系统(工单派发制)
|
||
* **需求:** 考核规定时间内补货及检修。
|
||
* **小程序程序设定:**
|
||
* **强时效工单**:系统检测到库存不足或电池耗尽,自动生成“4小时响应工单”指派给最近的运维员。
|
||
* **到岗打卡**:运维员必须到达柜体 5 米范围内(经纬度校验),才能开启“运维门”进行操作。
|
||
* **闭环报告**:补货完成后,自动上报最新重量数据,系统同步更新前台库存。
|
||
|
||
---
|
||
|
||
## 三、 全链路技术架构与数据流向
|
||
|
||
### 1. 四层架构模型
|
||
* **物理执行层(Edge)**:基于 ESP32/工业级 4G 模组的主控板,集成继电器、重力传感器、温湿度计。
|
||
* **网络传输层(Network)**:采用 **MQTT 协议**,基于 TLS/SSL 加密,确保指令在复杂小区环境下的秒级送达。
|
||
* **业务逻辑层(Service)**:负责权益校验、库存动态调拨、支付分账逻辑判断。
|
||
* **应用展示层(Application)**:用户小程序(取水/充值)、商家管理后台(核销)、补货员 App(工单管理)。
|
||
|
||
### 2. 高级交互序列图 (Sequence Diagram)
|
||
|
||
`mermaid
|
||
sequenceDiagram
|
||
participant U as 消费者小程序
|
||
participant S as 业务中台 (PHP/Node.js)
|
||
participant M as MQTT 消息总线 (EMQX)
|
||
participant C as 智能货柜终端
|
||
participant P as 微信支付分/代金券接口
|
||
|
||
U->>S: 1. 扫码查阅柜体 (LBS+设备ID)
|
||
S-->>U: 2. 返回可用库存 & 专属优惠券
|
||
U->>S: 3. 点击“确认取水” (权益预扣)
|
||
S->>P: 4. 冻结余额/校验代金券状态
|
||
P-->>S: 5. 状态确认
|
||
S->>M: 6. 下发指令 (QoS 1: 至少送达一次)
|
||
M->>C: 7. 物理开门指令 (带加密Nonce)
|
||
C->>C: 8. 传感器检测门启
|
||
C->>M: 9. 实时反馈:门已开
|
||
M-->>U: 10. 小程序提示:请取水
|
||
Note over C: 用户提取桶装水...
|
||
C->>C: 11. 传感器检测门闭 & 重量减扣
|
||
C->>M: 12. 最终交易报文 (补货建议点)
|
||
M->>S: 13. 结算请求
|
||
S->>S: 14. 正式扣减权益 & 生成财务报表
|
||
`
|
||
|
||
---
|
||
|
||
## 四、 通信协议与数据字典规范
|
||
|
||
### 1. 指令安全加固
|
||
采用 **HMAC-SHA256** 对指令进行签名,防止中间人攻击或恶意开门。
|
||
Payload 样本:
|
||
`json
|
||
{
|
||
"header": {
|
||
"sn": "WH-CAB-2024-001",
|
||
"ver": "1.2.0",
|
||
"nonce": "8h7g2k1l"
|
||
},
|
||
"body": {
|
||
"action": "REMOTE_OPEN",
|
||
"params": {
|
||
"slot": 1,
|
||
"timeout": 30
|
||
},
|
||
"sign": "5e8f...f2a1"
|
||
}
|
||
}
|
||
`
|
||
|
||
### 2. 状态机定义 (State Machine)
|
||
* IDLE: 空闲状态,等待指令。
|
||
* LOCKED: 权益校验通过,正在下发脉冲。
|
||
* BUSY: 用户正在交互(取水进行中)。
|
||
* MAINTENANCE: 故障或补货模式,小程序下线该节点。
|
||
|
||
---
|
||
|
||
## 五、 核心功能模块代码深度实现
|
||
|
||
### 1. 智能防刷与补偿逻辑 (小程序/后端)
|
||
**问题场景**:用户点了开门但信号不好,或者门坏了没开,如何保证不误扣费?
|
||
|
||
`javascript
|
||
// 后端:具备“事务性”的开门逻辑
|
||
async function secureOpenProcess(userId, cabinetId) {
|
||
const transaction = await db.startTransaction();
|
||
try {
|
||
// 1. 锁券:先将福利券/水票设为“占用中”
|
||
await transaction.collection('vouchers').update(query, { status: 'PENDING' });
|
||
|
||
// 2. 下发异步指令,设置 15 秒确认窗口
|
||
const result = await mqttService.publishWithAck(cabinetId, 'open', 15000);
|
||
|
||
if (result.ack === 'SUCCESS') {
|
||
await transaction.commit(); // 指令送达,提交事务
|
||
return { success: true };
|
||
} else {
|
||
throw new Error('DEVICE_OFFLINE');
|
||
}
|
||
} catch (e) {
|
||
await transaction.rollback(); // 失败回滚,水票自动返还
|
||
return { success: false, reason: e.message };
|
||
}
|
||
}
|
||
`
|
||
|
||
### 2. 补货员端:基于路径优化的库存盘点
|
||
`python
|
||
# 逻辑伪代码:根据告警级别生成最优补货路径
|
||
def generate_refill_route(warn_cabinets):
|
||
# 排列优先级:告警等级(0-100) > 距离
|
||
priority_list = sorted(warn_cabinets, key=lambda x: (x.alert_level, x.distance))
|
||
return priority_list # 返回给补货员 App 的任务流
|
||
`
|
||
|
||
---
|
||
|
||
## 六、 智能货柜接入小程序的标准化流程 (Access Standard)
|
||
|
||
### 1. 核心逻辑:如何核验并完成取水(从下单到核销)
|
||
|
||
针对你疑惑的“下单后如何核验取水”,本项目采用 **“虚拟权益池 + 动态指令核销”** 机制。以下是详细的核验方案:
|
||
|
||
#### A. 权益发放(下单阶段)
|
||
1. **资产化**:用户下单购买后,系统不只是生成一个订单,而是在数据库中为用户 `OpenID` 增加“电子水票/桶数”资产(如:可用余额 +10 桶)。
|
||
2. **权益凭证**:系统生成一组不记名的电子权益 ID,状态标记为 `UNUSED`(未使用)。
|
||
|
||
#### B. 身份与位置核验(扫码阶段)
|
||
1. **设备匹配**:用户扫码,小程序获取 `cabinet_id`。系统即刻下发 **MQTT PING** 指令确认柜机通讯链路活跃。
|
||
2. **位置强校验 **(针对无蓝牙环境增强)****:
|
||
* 小程序调用 `uni.getLocation` 获取手机经纬度。
|
||
* **后端比对**:将手机位置与柜子的注册坐标进行计算(Haversine 公式)。
|
||
* **判定**:距离 < 50 米时,判定为“到店”,激活“开门按钮”;否则提示“请到达柜机旁操作”。
|
||
3. **在线预警**:若 MQTT 链路超时未响应,按钮置灰并提示“柜机离线中,请稍后再试”,防止用户重复扣款。
|
||
|
||
#### C. 权益核销(开门阶段)
|
||
1. **预锁定**:用户点击“确认开门”,后端立即执行 `Transaction`(事务):
|
||
* 查询用户是否有可用余额。
|
||
* 将 1 份权益设为 `LOCKING`(锁定中),防止并发重复开启。
|
||
2. **指令下发**:通过 MQTT 向货柜发送 `UNLOCK_CABINET` 指令。
|
||
3. **状态反馈**:
|
||
* **成功**:货柜反馈“门已开启”,权益标记为 `USED`(已使用),生成核销流水。
|
||
* **失败**:若 15 秒内未收到开门反馈,直接接入客服系统,让客服处理这笔订单。
|
||
|
||
### 2. 身份识别与设备绑定(参数二维码体系)
|
||
* **二维码本质**:机身二维码并非静态图片,而是携带设备 ID 的“动态索引链接”(例如:https://domain.com/q?id=10001)。
|
||
* **批量生产规范**:
|
||
* **映射逻辑**:后端建立 设备SN - 设备ID - 二维码URL 的 1:1 映射表。
|
||
* **自动化生成**:通过 Node.js/Python 脚本调用 qrcode 库,根据数据库 ID 批量生成 100+ 物理贴纸。
|
||
* **施工校验**:印刷贴纸需附带明文编号,安装时由运维端扫码并上传 LBS 坐标,完成“人-机-地”三位一体绑定。
|
||
|
||
### 2. “扫码即看”的信息同步机制
|
||
* **跳转逻辑**:利用微信“普通链接二维码跳转小程序”协议,所有货柜二维码均指向同一个小程序页面。
|
||
* **动态解析流程**:
|
||
1. **取参**:小程序在 onLoad(options) 中解析 options.q 获取 cabinet_id。
|
||
2. **溯源**:小程序以该 ID 为 Key,实时请求云端接口 /api/cabinet/info。
|
||
3. **渲染**:后端实时查询该柜体的 IoT 状态(库存剩几桶、电池余量、是否维修),前端实现“千柜千面”的精准显示。
|
||
|
||
### 3. 前端交互与权限校验逻辑
|
||
`javascript
|
||
// 基于 UniApp 的扫码取水核心逻辑
|
||
async function startWithdrawWater(cabinetId) {
|
||
// A. 获取用户地理位置,确保在柜机旁
|
||
const location = await uni.getLocation({ type: 'gcj02' });
|
||
|
||
// B. 调用后端校验接口:余额充值情况 + 设备在线状态
|
||
const checkRes = await request('/api/cabinet/check', {
|
||
cabinetId,
|
||
userId: global.userId,
|
||
lat: location.latitude,
|
||
lng: location.longitude
|
||
});
|
||
|
||
if (checkRes.status === 'READY') {
|
||
// C. 唤起蓝牙或网络指令下发确认框
|
||
uni.showModal({
|
||
title: '发现提水点',
|
||
content: '确认开启 1 号柜门取水?',
|
||
success: async (res) => {
|
||
if (res.confirm) {
|
||
// D. 下发开门指令
|
||
const openRes = await request('/api/cabinet/open', { cabinetId });
|
||
if(openRes.code === 0) {
|
||
// E. 进入倒计时监听,等待设备反馈开门信号
|
||
monitorDoorStatus(cabinetId);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
}
|
||
`
|
||
|
||
### 4. 数据通信闭环(双向反馈)
|
||
* **云端指令控制**:小程序点击后,通过 HTTPS POST 请求后端,后端转发 MQTT 指令至货柜。
|
||
* **WebSocket 状态同步**:小程序前端通过 Socket 实时监听后端推送。当货柜感应器检测到“物理门已开启”或“门已关闭”,小程序界面同步切换:**[待取水] -> [取心中] -> [成功扣费/取水完成]**。
|
||
|
||
---
|
||
|
||
## 七、 企业级安全与高可用保障
|
||
|
||
1. **容灾机制(断网续传)**:货柜具备离线存储功能。若断网期间发生本地开门(手动/钥匙),恢复后第一时间同步日志。
|
||
2. **【调整】续航与能源管理**:考虑到实际布放环境,设备采用**“大容量工业锂电池 + 定期换电/充电”**模式。系统集成低电量预警:
|
||
* **电量梯级预警**:低于 20% 时推送后台补货员工单;低于 10% 时小程序端自动置灰并停止接单,防止物理开锁力矩不足。
|
||
3. **异常处理机制**:提供“远程强制开锁”与“一键报漏及退费回滚”功能,确保用户权益不受损。 **【新增:离线开门补偿逻辑】**
|
||
|
||
---
|
||
|
||
## 八、 实施路线图 (Roadmap)
|
||
* **Q1-调研期**:完成 4G 模组与主控板的底层通信打通。
|
||
* **Q2-内测期**:完成试点投放,验证传感器精度。
|
||
* **Q3-商业化**:全面对接货柜节点,开启自动化交付。
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|