Commit eb74f753a8e514c04581f3ca259bc59c60acdbb9
1 parent
7fe4dd23
【功能新增】IoT:增加 IotDeviceOnlineMessageConsumer,处理设备自动上线
Showing
5 changed files
with
118 additions
and
2 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java
| @@ -15,7 +15,9 @@ public enum IotDeviceMessageIdentifierEnum { | @@ -15,7 +15,9 @@ public enum IotDeviceMessageIdentifierEnum { | ||
| 15 | PROPERTY_REPORT("report"), | 15 | PROPERTY_REPORT("report"), |
| 16 | 16 | ||
| 17 | STATE_ONLINE("online"), | 17 | STATE_ONLINE("online"), |
| 18 | - STATE_OFFLINE("offline"); | 18 | + STATE_OFFLINE("offline"), |
| 19 | + | ||
| 20 | + SERVICE_REPLY_SUFFIX("_reply"); | ||
| 19 | 21 | ||
| 20 | 22 | ||
| 21 | /** | 23 | /** |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java
| @@ -15,7 +15,8 @@ public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> { | @@ -15,7 +15,8 @@ public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> { | ||
| 15 | 15 | ||
| 16 | STATE("state"), // 设备状态 | 16 | STATE("state"), // 设备状态 |
| 17 | PROPERTY("property"), // 设备属性 | 17 | PROPERTY("property"), // 设备属性 |
| 18 | - EVENT("event"); // 设备事件 | 18 | + EVENT("event"), // 设备事件 |
| 19 | + SERVICE("service"); // 设备服务 | ||
| 19 | 20 | ||
| 20 | public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); | 21 | public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); |
| 21 | 22 |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStateEnum.java
| @@ -35,4 +35,8 @@ public enum IotDeviceStateEnum implements ArrayValuable<Integer> { | @@ -35,4 +35,8 @@ public enum IotDeviceStateEnum implements ArrayValuable<Integer> { | ||
| 35 | return ARRAYS; | 35 | return ARRAYS; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | + public static boolean isOnline(Integer state) { | ||
| 39 | + return ONLINE.getState().equals(state); | ||
| 40 | + } | ||
| 41 | + | ||
| 38 | } | 42 | } |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.job.device; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler; | ||
| 4 | +import cn.iocoder.yudao.framework.tenant.core.job.TenantJob; | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | + | ||
| 7 | +// TODO @芋艿:待实现 | ||
| 8 | +/** | ||
| 9 | + * IoT 设备离线检查 Job | ||
| 10 | + * | ||
| 11 | + * 检测逻辑:设备最后一条 {@link cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage} 消息超过一定时间,则认为设备离线 | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Component | ||
| 16 | +public class IotDeviceOfflineCheckJob implements JobHandler { | ||
| 17 | + | ||
| 18 | + @Override | ||
| 19 | + @TenantJob | ||
| 20 | + public String execute(String param) { | ||
| 21 | + return ""; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceOnlineMessageConsumer.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.mq.consumer.device; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.IdUtil; | ||
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 5 | +import cn.iocoder.yudao.module.iot.api.device.dto.IotDeviceStateUpdateReqDTO; | ||
| 6 | +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||
| 7 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum; | ||
| 8 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum; | ||
| 9 | +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum; | ||
| 10 | +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; | ||
| 11 | +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; | ||
| 12 | +import cn.iocoder.yudao.module.iot.service.device.upstream.IotDeviceUpstreamService; | ||
| 13 | +import jakarta.annotation.Resource; | ||
| 14 | +import lombok.extern.slf4j.Slf4j; | ||
| 15 | +import org.springframework.context.event.EventListener; | ||
| 16 | +import org.springframework.scheduling.annotation.Async; | ||
| 17 | +import org.springframework.stereotype.Component; | ||
| 18 | + | ||
| 19 | +import java.time.LocalDateTime; | ||
| 20 | +import java.util.Objects; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 针对 {@link IotDeviceMessage} 的消费者,将离线的设备,自动标记为上线 | ||
| 24 | + * | ||
| 25 | + * 注意:只有设备上行消息,才会触发该逻辑 | ||
| 26 | + * | ||
| 27 | + * @author 芋道源码 | ||
| 28 | + */ | ||
| 29 | +@Component | ||
| 30 | +@Slf4j | ||
| 31 | +public class IotDeviceOnlineMessageConsumer { | ||
| 32 | + | ||
| 33 | + @Resource | ||
| 34 | + private IotDeviceService deviceService; | ||
| 35 | + | ||
| 36 | + @Resource | ||
| 37 | + private IotDeviceUpstreamService deviceUpstreamService; | ||
| 38 | + | ||
| 39 | + @EventListener | ||
| 40 | + @Async | ||
| 41 | + public void onMessage(IotDeviceMessage message) { | ||
| 42 | + // 1.1 只处理上行消息。因为,只有设备上行的消息,才会触发设备上线的逻辑 | ||
| 43 | + if (!isUpstreamMessage(message)) { | ||
| 44 | + return; | ||
| 45 | + } | ||
| 46 | + // 1.2 如果设备已在线,则不做处理 | ||
| 47 | + log.info("[onMessage][消息内容({})]", message); | ||
| 48 | + IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache( | ||
| 49 | + message.getProductKey(), message.getDeviceName()); | ||
| 50 | + if (device == null) { | ||
| 51 | + log.error("[onMessage][消息({}) 对应的设备部存在]", message); | ||
| 52 | + return; | ||
| 53 | + } | ||
| 54 | + if (IotDeviceStateEnum.isOnline(device.getState())) { | ||
| 55 | + return; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + // 2. 标记设备为在线 | ||
| 59 | + // 为什么不直接更新状态呢?因为通过 IotDeviceMessage 可以经过一系列的处理,例如说记录日志等等 | ||
| 60 | + deviceUpstreamService.updateDeviceState(((IotDeviceStateUpdateReqDTO) | ||
| 61 | + new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setReportTime(LocalDateTime.now()) | ||
| 62 | + .setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())) | ||
| 63 | + .setState((IotDeviceStateEnum.ONLINE.getState()))); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + private boolean isUpstreamMessage(IotDeviceMessage message) { | ||
| 67 | + // 设备属性 | ||
| 68 | + if (Objects.equals(message.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType()) | ||
| 69 | + && Objects.equals(message.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier())) { | ||
| 70 | + return true; | ||
| 71 | + } | ||
| 72 | + // 设备事件 | ||
| 73 | + if (Objects.equals(message.getType(), IotDeviceMessageTypeEnum.EVENT.getType())) { | ||
| 74 | + return true; | ||
| 75 | + } | ||
| 76 | + // 设备服务 | ||
| 77 | + // noinspection RedundantIfStatement | ||
| 78 | + if (Objects.equals(message.getType(), IotDeviceMessageTypeEnum.SERVICE.getType()) | ||
| 79 | + && !StrUtil.endWith(message.getIdentifier(), IotDeviceMessageIdentifierEnum.SERVICE_REPLY_SUFFIX.getIdentifier())) { | ||
| 80 | + return true; | ||
| 81 | + } | ||
| 82 | + return false; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | +} | ||
| 0 | \ No newline at end of file | 86 | \ No newline at end of file |