package cn.iocoder.yudao.module.iot.job.device; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; import cn.iocoder.yudao.module.iot.core.enums.device.IotDeviceStateEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; import cn.iocoder.yudao.module.iot.framework.iot.config.YudaoIotProperties; import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; import cn.iocoder.yudao.module.iot.service.device.property.IotDevicePropertyService; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; import java.time.Duration; import java.time.LocalDateTime; import java.util.Collections; import java.util.List; import java.util.Set; /** * IoT 设备离线检查 Job * * 检测逻辑:设备最后一条 {@link IotDeviceMessage} 消息超过一定时间,则认为设备离线 * * @see 阿里云 IoT —— 设备离线分析 * @author 芋道源码 */ @Component public class IotDeviceOfflineCheckJob implements JobHandler { @Resource private YudaoIotProperties iotProperties; @Resource private IotDeviceService deviceService; @Resource private IotDevicePropertyService devicePropertyService; @Resource private IotDeviceMessageService deviceMessageService; @Override @TenantJob public String execute(String param) { // 1.1 获得在线设备列表 List devices = deviceService.getDeviceListByState(IotDeviceStateEnum.ONLINE.getState()); if (CollUtil.isEmpty(devices)) { return JsonUtils.toJsonString(Collections.emptyList()); } // 1.2 获取超时的设备集合 Set timeoutDeviceIds = devicePropertyService.getDeviceIdListByReportTime(getTimeoutTime()); // 2. 下线设备 List offlineDevices = CollUtil.newArrayList(); for (IotDeviceDO device : devices) { if (!timeoutDeviceIds.contains(device.getId())) { continue; } offlineDevices.add(new String[]{device.getProductKey(), device.getDeviceName()}); // 为什么不直接更新状态呢?因为通过 IotDeviceMessage 可以经过一系列的处理,例如说记录日志等等 deviceMessageService.sendDeviceMessage(IotDeviceMessage.buildStateOffline().setDeviceId(device.getId())); } return JsonUtils.toJsonString(offlineDevices); } private LocalDateTime getTimeoutTime() { return LocalDateTime.now().minus(Duration.ofNanos( (long) (iotProperties.getKeepAliveTime().toNanos() * iotProperties.getKeepAliveFactor()))); } }