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/2 1:28:19 阅读更多 →
从Uzi回应看技术评估:解构“第一”标签,构建健康工程思维

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

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

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

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

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

2026/8/2 1:27:19 阅读更多 →

最新新闻

APK Installer:在Windows上无缝安装安卓应用的智能解决方案

APK Installer:在Windows上无缝安装安卓应用的智能解决方案

APK Installer:在Windows上无缝安装安卓应用的智能解决方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾经希望在Windows电脑上直接安装安卓应用…

2026/8/3 5:06:28 阅读更多 →
深度学习损失函数全解析:从MSE到Focal Loss的原理与应用实战

深度学习损失函数全解析:从MSE到Focal Loss的原理与应用实战

1. 损失函数:深度学习的“导航仪”与“裁判”在深度学习的项目实战里,无论是训练一个识别猫狗的模型,还是让机器狗学会协调步伐,我们总会遇到一个核心问题:怎么告诉模型它做得好不好?模型在训练时&#xff…

2026/8/3 5:06:28 阅读更多 →
Steam游戏自动破解工具:3步完成DRM移除的终极指南

Steam游戏自动破解工具:3步完成DRM移除的终极指南

Steam游戏自动破解工具:3步完成DRM移除的终极指南 【免费下载链接】Steam-auto-crack Steam Game Automatic Cracker 项目地址: https://gitcode.com/gh_mirrors/st/Steam-auto-crack Steam游戏自动破解工具是一款专业的开源解决方案,专门为合法购…

2026/8/3 5:06:28 阅读更多 →
Python接单实战指南:从数据分析到Web开发的技术变现路径

Python接单实战指南:从数据分析到Web开发的技术变现路径

这次我们来看一个关于“在家用Python接单”的话题。标题里提到的“昨天488,一台电脑,方法简单”非常吸引人,它指向了一个很多技术爱好者关心的问题:如何利用自己的编程技能,在业余时间创造收入。这篇文章不会给你画饼&…

2026/8/3 5:06:28 阅读更多 →
如何快速解决电脑自动锁屏问题:Mouse Jiggler 完整使用指南

如何快速解决电脑自动锁屏问题:Mouse Jiggler 完整使用指南

如何快速解决电脑自动锁屏问题:Mouse Jiggler 完整使用指南 【免费下载链接】mousejiggler Mouse Jiggler is a very simple piece of software whose sole function is to "fake" mouse input to Windows, and jiggle the mouse pointer back and forth.…

2026/8/3 5:06:28 阅读更多 →
离线环境PyTorch CPU到GPU迁移:版本匹配、依赖下载与安装验证全指南

离线环境PyTorch CPU到GPU迁移:版本匹配、依赖下载与安装验证全指南

1. 从CPU到GPU:一次彻底的PyTorch环境迁移最近在帮一个朋友处理他的深度学习项目,他之前一直用CPU版本的PyTorch跑模型,训练一个简单的图像分类任务都要等上大半天。项目临近交付,时间紧迫,他终于下定决心要把环境切换…

2026/8/3 5:05:28 阅读更多 →

日新闻

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

PC服务器具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构一、前言:具身智能需要“混合算力闭环系统”传统人工智能依赖云端静态数据集训练,不具备物理交互能力,无法适应真实世界的不确定性。具身智能(Embodied…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

前言构建机器人、具身智能这类分布式实时系统,通信底座直接决定整套系统的实时性、容错性、组网能力。分布式领域长期存在 4 类经典通信架构:点对点模式、Broker 中间代理模式、广播模式、以数据为中心(DDS)模式。很多开发者疑惑&…

2026/8/3 0:00:47 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/3 4:58:13 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/3 1:53:31 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/3 4:36:35 阅读更多 →

月新闻

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

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

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

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

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

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

2026/8/2 2:47:48 阅读更多 →
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/2 0:23:22 阅读更多 →