SpringCloud Alibaba无人售货柜实战(四):设备接入模块——设备注册、心跳上报、在线状态管理
SpringCloud Alibaba无人售货柜实战四设备接入模块——设备注册、心跳上报、在线状态管理一台售货柜上电后怎么让服务器知道我来了怎么判断它还活着怎么知道它掉线了这篇把设备接入的全流程讲透。一、设备接入流程总览无人售货柜不是普通的服务器它是一台跑在RK3588工控板上的Android设备通过MQTT和服务器通信。设备从上电到在线可用要经过四个阶段设备上电 → 连接MQTT Broker → 注册报到 → 心跳保活 → 在线服务详细步骤工控板上电启动Android App拉起读取本地存储的设备SN码连接EMQX MQTT Broker连接成功后向服务端发送注册请求携带SN码服务端校验SN合法性分配Token更新设备状态为在线设备每30秒发送一次心跳包服务端定时扫描90秒未收到心跳则标记离线二、MQTT Topic设计MQTT通信的核心是Topic设计。本项目采用{前缀}/{设备SN}/{动作}的层级结构Topic方向说明device/{sn}/register设备→服务端设备注册device/{sn}/heartbeat设备→服务端心跳上报device/{sn}/status设备→服务端状态上报开门/关门/故障device/{sn}/command服务端→设备下行指令开柜/重启等device/{sn}/callback设备→服务端指令执行回调每个设备订阅自己的device/{sn}/commandTopic服务端往这个Topic发消息设备就能收到。SN码天然就是路由Key。三、设备注册流程3.1 注册逻辑设备首次上电或Token过期后需要注册设备读取本地SN码出厂烧录不可篡改拼接SN 设备型号 固件版本发送到device/{sn}/registerTopic服务端收到消息查device表确认SN存在且未被禁用生成JWT Token存入Rediskeydevice:token:{sn}有效期7天更新设备状态为在线记录上线时间通过MQTT返回Token给设备3.2 注册Controller设备注册走MQTT消息不走HTTP。服务端用MQTT消息监听器处理Slf4jComponentpublicclassDeviceRegisterListener{AutowiredprivateDeviceServicedeviceService;AutowiredprivateRedisUtilsredisUtils;AutowiredprivateMqttGatewaymqttGateway;privatestaticfinalStringDEVICE_TOKEN_PREFIXdevice:token:;privatestaticfinallongTOKEN_EXPIRE_DAYS7L;/** * 监听设备注册Topic */MqttMessageListener(topicdevice//register)publicvoidonRegister(MqttMessagemessage){Stringtopicmessage.getTopic();Stringsntopic.split(/)[1];StringpayloadnewString(message.getPayload(),StandardCharsets.UTF_8);log.info(收到设备注册请求: sn{}, payload{},sn,payload);DeviceRegisterReqreqJSON.parseObject(payload,DeviceRegisterReq.class);req.setSn(sn);// 1. 校验设备合法性DevicedevicedeviceService.getBySn(sn);if(devicenull){log.error(设备未登记: sn{},sn);sendRegisterResult(sn,false,设备未登记,null);return;}if(device.getStatus()DeviceStatus.MAINTENANCE.getCode()){sendRegisterResult(sn,false,设备维护中,null);return;}// 2. 生成TokenStringtokenJwtUtils.generateDeviceToken(sn,device.getId());// 3. 缓存Token到RedisredisUtils.set(DEVICE_TOKEN_PREFIXsn,token,TOKEN_EXPIRE_DAYS,TimeUnit.DAYS);// 4. 更新设备状态device.setStatus(DeviceStatus.ONLINE.getCode());device.setLastOnlineTime(LocalDateTime.now());device.setLastHeartbeatTime(LocalDateTime.now());device.setFirmwareVersion(req.getFirmwareVersion());device.setIpAddress(req.getIpAddress());deviceService.updateById(device);// 5. 返回注册结果sendRegisterResult(sn,true,注册成功,token);log.info(设备注册成功: sn{},sn);}privatevoidsendRegisterResult(Stringsn,booleansuccess,Stringmsg,Stringtoken){JSONObjectresultnewJSONObject();result.put(success,success);result.put(message,msg);if(token!null){result.put(token,token);}mqttGateway.sendToMqtt(device/sn/register/resp,result.toJSONString());}}四、心跳上报机制4.1 心跳协议设备每30秒上报一次心跳内容非常精简{sn:VM202601001,timestamp:1753766400000,cpuTemp:52.3,memoryUsage:68,diskUsage:45,signalStrength:-67}心跳不只是我还活着顺便带上设备健康指标。cpuTemp超过80度就该告警了。4.2 心跳处理ServiceSlf4jServicepublicclassDeviceHeartbeatService{AutowiredprivateDeviceServicedeviceService;AutowiredprivateRedisUtilsredisUtils;privatestaticfinalStringDEVICE_ONLINE_PREFIXdevice:online:;privatestaticfinallongONLINE_EXPIRE_SECONDS90L;/** * 处理心跳消息 */MqttMessageListener(topicdevice//heartbeat)publicvoidonHeartbeat(MqttMessagemessage){Stringtopicmessage.getTopic();Stringsntopic.split(/)[1];StringpayloadnewString(message.getPayload(),StandardCharsets.UTF_8);HeartbeatReqreqJSON.parseObject(payload,HeartbeatReq.class);// 1. 更新Redis在线状态90秒过期StringonlineKeyDEVICE_ONLINE_PREFIXsn;redisUtils.set(onlineKey,1,ONLINE_EXPIRE_SECONDS,TimeUnit.SECONDS);// 2. 更新数据库最后心跳时间异步不阻塞MQTT回调DevicedevicenewDevice();device.setSn(sn);device.setLastHeartbeatTime(LocalDateTime.now());deviceService.updateHeartbeatBySn(sn,LocalDateTime.now());// 3. 异常告警检查if(req.getCpuTemp()!nullreq.getCpuTemp()80){log.warn(设备CPU温度过高: sn{}, temp{}℃,sn,req.getCpuTemp());// 发送告警通知...}log.debug(心跳处理完成: sn{},sn);}}心跳处理一定要快。MQTT消息回调是串行的如果心跳处理慢了后面的消息全部排队。所以DB更新用异步核心逻辑只做Redis更新。五、在线状态判定5.1 双重判定机制设备在线状态用Redis 定时扫描双重保障Redis快速判定device:online:{sn}这个Key存在就算在线过期时间90秒。心跳每30秒续期一旦心跳停止Key自动过期。DB定时扫描兜底机制防止Redis故障导致状态不一致。5.2 定时状态扫描Slf4jComponentpublicclassDeviceStatusScanner{AutowiredprivateDeviceServicedeviceService;AutowiredprivateRedisUtilsredisUtils;privatestaticfinalStringDEVICE_ONLINE_PREFIXdevice:online:;privatestaticfinallongOFFLINE_THRESHOLD_SECONDS90L;/** * 每60秒扫描一次将超时设备标记为离线 */Scheduled(fixedRate60000)publicvoidscanOfflineDevices(){log.info(开始扫描离线设备...);// 查询所有状态为在线的设备ListDeviceonlineDevicesdeviceService.listByStatus(DeviceStatus.ONLINE.getCode());intofflineCount0;LocalDateTimethresholdLocalDateTime.now().minusSeconds(OFFLINE_THRESHOLD_SECONDS);for(Devicedevice:onlineDevices){// 优先检查RedisBooleanisOnlineredisUtils.hasKey(DEVICE_ONLINE_PREFIXdevice.getSn());if(BooleanUtil.isFalse(isOnline)){// Redis已过期再检查DB最后心跳时间兜底if(device.getLastHeartbeatTime()null||device.getLastHeartbeatTime().isBefore(threshold)){// 标记离线device.setStatus(DeviceStatus.OFFLINE.getCode());deviceService.updateById(device);offlineCount;log.warn(设备离线: sn{}, lastHeartbeat{},device.getSn(),device.getLastHeartbeatTime());}}}log.info(离线扫描完成: 在线{}, 新增离线{},onlineDevices.size(),offlineCount);}}5.3 设备状态机注册成功 心跳超时/异常 OFFLINE ────────→ ONLINE ──────────→ OFFLINE │ │ 故障上报 重新注册 ↓ │ FAULT ←──────────────┘ │ 维修开始 ↓ MAINTENANCE │ 维修完成 ↓ OFFLINE → 重新注册 → ONLINE六、设备信息缓存策略设备信息是高频读取数据每次下单都要查设备状态直接查DB扛不住。缓存策略数据缓存KeyTTL说明在线状态device:online:{sn}90秒心跳续期设备信息device:info:{sn}30分钟DB变更时主动刷新认证Tokendevice:token:{sn}7天注册时写入设备锁device:lock:{sn}10秒防止并发操作同一设备publicDevicegetDeviceBySn(Stringsn){Stringkeydevice:info:sn;DevicedeviceredisUtils.get(key,Device.class);if(device!null){returndevice;}devicethis.getBySn(sn);if(device!null){redisUtils.set(key,device,30,TimeUnit.MINUTES);}returndevice;}七、常见问题7.1 设备频繁上下线网络抖动设备网络不稳定一会儿上线一会儿掉线状态频繁切换产生大量日志。解决方案引入离线延迟确认机制。心跳超时后不立即标记离线先进入疑似离线状态再等一个心跳周期30秒如果还没心跳才正式标记离线。// 疑似离线缓存30秒后过期redisUtils.set(device:pending_offline:sn,1,30,TimeUnit.SECONDS);7.2 心跳丢失MQTT QoS设置为1至少一次但极端情况下仍可能丢消息。解决设备端本地记录心跳序号连续3次未收到服务端ACK就重连服务端用Scheduled补偿扫描以DB时间戳为最终判据八、设备管理表补充在第一篇的device表基础上补充设备扩展信息表CREATETABLEdevice_config(idbigintNOTNULL,device_snvarchar(64)NOTNULLCOMMENT设备SN,heartbeat_intervalintNOTNULLDEFAULT30COMMENT心跳间隔(秒),offline_thresholdintNOTNULLDEFAULT90COMMENT离线判定阈值(秒),door_timeoutintNOTNULLDEFAULT120COMMENT开门超时(秒),max_open_durationintNOTNULLDEFAULT300COMMENT最大开门时长(秒),auto_close_enabledtinyintNOTNULLDEFAULT1COMMENT是否自动关门,volumeintNOTNULLDEFAULT50COMMENT音量(0-100),create_timedatetimeNOTNULLDEFAULTCURRENT_TIMESTAMP,update_timedatetimeNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,PRIMARYKEY(id),UNIQUEKEYuk_device_sn(device_sn))ENGINEInnoDBDEFAULTCHARSETutf8mb4COMMENT设备配置表;九、小结设备接入是IoT项目的第一道关卡。核心就三件事注册让设备拿到身份、心跳让服务端知道设备活着、状态扫描兜底处理异常掉线。MQTT Topic设计要提前规划好层级结构后期改Topic成本极高。Redis做在线状态缓存是标配——DB扛不住每30秒一次的心跳写入。

相关新闻

Windows系统PyTorch稳定安装指南:Conda环境配置与CUDA版本匹配详解

Windows系统PyTorch稳定安装指南:Conda环境配置与CUDA版本匹配详解

1. 项目概述:为什么你的PyTorch安装总是不稳定? 在Windows上安装PyTorch,尤其是想用上GPU加速,这事儿听起来简单,做起来却是个技术活。我见过太多新手,甚至是有些经验的朋友,照着官方文档或者一…

2026/8/24 6:15:13 阅读更多 →
从Uzi回应看技术评估:解构“第一”标签,构建健康工程思维

从Uzi回应看技术评估:解构“第一”标签,构建健康工程思维

在电子竞技领域,选手的自我认知与外界评价之间往往存在巨大鸿沟。当一位选手被粉丝或媒体冠以“世界第一”的头衔时,这种标签既是一种荣誉,也是一种沉重的负担。近期,知名《英雄联盟》职业选手Uzi在赛后采访中,面对“世…

2026/8/20 3:41:59 阅读更多 →
10分钟快速入门Magic动画库:让你的网页瞬间动起来的终极指南

10分钟快速入门Magic动画库:让你的网页瞬间动起来的终极指南

10分钟快速入门Magic动画库:让你的网页瞬间动起来的终极指南 【免费下载链接】magic CSS3 Animations with special effects 项目地址: https://gitcode.com/gh_mirrors/ma/magic 想要为你的网站添加令人惊艳的动画效果,但又不想学习复杂的JavaSc…

2026/8/11 7:34:13 阅读更多 →

最新新闻

从智慧高速到数字化转型:交通行业价值回归与实战路径

从智慧高速到数字化转型:交通行业价值回归与实战路径

1. 项目概述:一场关于“智慧高速”的行业思辨最近在行业交流群里,一个话题引发了激烈的讨论,甚至有点“火药味”。话题的源头,正是“智慧高速”的建设热潮似乎正在转向一个更宽泛、更基础的概念——“数字化转型”。不少一线从业者…

2026/8/25 10:46:51 阅读更多 →
从AI辅助到AI优先:构建智能研发流水线实现高频部署

从AI辅助到AI优先:构建智能研发流水线实现高频部署

1. 项目概述:从“用AI”到“AI优先”的研发效能革命“怎么把6周一次版本更新提升到1天8次部署?” 这个标题,第一次看到时,我以为是哪个技术团队在吹牛。但当我真正深入去拆解和实践后,发现这背后代表的,远不…

2026/8/25 10:46:51 阅读更多 →
从月更到日更:AI优先驱动研发效能革命与持续交付实践

从月更到日更:AI优先驱动研发效能革命与持续交付实践

1. 从“月更”到“日更”:一个研发团队的效率革命“6周一次版本更新”,这个节奏对很多传统研发团队来说,可能并不陌生,甚至觉得“还能接受”。毕竟,从需求评审、开发、测试到上线,一个完整的迭代周期&#…

2026/8/25 10:46:51 阅读更多 →
基于腾讯云轻量服务器部署Moltbot AI助手:全链路安全防护实践

基于腾讯云轻量服务器部署Moltbot AI助手:全链路安全防护实践

1. 项目概述:一个能真正跑起来的AI助手最近在折腾一个挺有意思的东西:把一个叫Moltbot的AI助手,部署到腾讯云轻量应用服务器上,并且给它套上了一整套从网络到应用的安全防护。这听起来可能有点技术,但说白了&#xff0…

2026/8/25 10:46:51 阅读更多 →
AI智能体开发:从框架依赖到自主可控的架构演进与实践

AI智能体开发:从框架依赖到自主可控的架构演进与实践

1. 项目概述:一场由封杀引发的AI智能体生态重构今天早上,我的开发群和几个技术社区直接炸了锅。Anthropic官方发布了一则简短但措辞严厉的公告,宣布其Claude API将全面封杀一个名为“OpenClaw”的第三方智能体框架。公告里没有太多细节&#…

2026/8/25 10:46:50 阅读更多 →
C/C++跨平台获取可执行文件路径:原理、实现与工程实践

C/C++跨平台获取可执行文件路径:原理、实现与工程实践

1. 项目概述:为什么获取当前路径是个“老大难”问题?在C/C开发中,获取当前可执行文件或源代码的运行路径,听起来是个再基础不过的需求,但实际动手时,很多开发者都会愣一下。这不像Python里一个简单的__file…

2026/8/25 10:45:49 阅读更多 →

日新闻

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

洛谷 P7912:[CSP-J 2021 T4] 小熊的果篮 ← 双向链表

【题目来源】 https://www.luogu.com.cn/problem/P7912 【题目描述】 小熊的水果店里摆放着一排 n 个水果。每个水果只可能是苹果或桔子,从左到右依次用正整数 1,2,…,n 编号。连续排在一起的同一种水果称为一个“块”。小熊要把这一排水果挑到若干个果篮里&#x…

2026/8/25 0:00:34 阅读更多 →
Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG

Transformers.js 网页端图像抠图实战:零后端 3 行代码返回透明 PNG 【免费下载链接】transformers.js State-of-the-art Machine Learning for the web. Run 🤗 Transformers directly in your browser, with no need for a server! 项目地址: https:/…

2026/8/25 0:00:34 阅读更多 →
数学建模竞赛论文写作指南:从模型构建到学术表达的核心技能

数学建模竞赛论文写作指南:从模型构建到学术表达的核心技能

1. 项目概述:从“会做”到“会写”的竞赛核心跃迁“全国大学生数学建模竞赛”,这个名字对理工科学生来说,分量极重。每年,无数团队在三天三夜的时间里,为一个开放性问题绞尽脑汁,从建立模型、求解算法到编程…

2026/8/25 0:00:34 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 3:38:12 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 3:38:18 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/25 3:38:23 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/24 20:22:44 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/25 10:31:12 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/24 11:20:22 阅读更多 →