发布时间:2026/8/2 1:27:48
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秒一次的心跳写入。

相关新闻

2026/8/2 1:17:24

FT232 USB转串口芯片:硬件开发的稳定之选与实战应用

1. 从“串口消失”到“万能钥匙”:为什么FT232至今仍是硬件开发的硬通货?最近在整理工作室的“古董”开发板,翻出来一块落满灰尘的蓝色小板子,上面印着“FT232 USB UART Board”。我顺手把它插上电脑,Windows 10系统几…

2026/8/2 2:43:19

vsftp 2.3.4 后门漏洞

1)首先通过靶机的IP地址对端口进行扫描,发现靶机开放端口有ftp文件传输服务使用netcat命令,进行登录,此时我们并不知道账号和密码,但是这个版本有一个致命漏洞就是用户名最后加上":)"笑脸,密码随便填&#x…

2026/8/2 2:43:19

如何用Python实现95%成功率的大麦自动抢票终极指南

如何用Python实现95%成功率的大麦自动抢票终极指南 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 还在为热门演唱会门票秒光而烦恼吗?每…

2026/8/2 2:43:19

哈夫曼树与编码:数据结构中的贪心算法与文件压缩核心

1. 项目概述:从“最省”的树到“最省”的码如果你学过数据结构,大概率听过“哈夫曼树”这个名字,它常常和“最优二叉树”、“带权路径长度最短”这些听起来有点学术的词绑在一起。我第一次接触它的时候,也觉得这玩意儿是不是只在考…

2026/8/2 2:43:19

防火墙策略路由

需求分析一、整体组网架构内网分为两大业务网段:财务部、研发部防火墙双线互联网出口:电信链路 联通链路内网区域:Trust 安全区域;互联网:Untrust 安全区域配套能力:链路冗余检测、策略路由流量分流、源 N…

2026/8/2 2:32:54

单片机毕设选题推荐:基于嵌入式外设的多功能小车人机交互系统实现 基于 STM32 的实时数据可视化小车监测系统设计(017401)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/8/2 0:02:18

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/2 0:02:18

如何用免费工具突破游戏窗口限制:SRWE完整使用指南

如何用免费工具突破游戏窗口限制:SRWE完整使用指南 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否遇到过这样的困扰?想为心爱的游戏截图,却发现游戏不支持自定义分辨率…

2026/8/2 1:52:02

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/1 0:03:49

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/1 0:03:49

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…