reactor:【IoT 物联网】重新梳理下行消息的逻辑(未测试,用于相互 review 作用)

This commit is contained in:
YunaiV
2025-06-11 09:56:59 +08:00
parent 4ea6e08f99
commit 66b42367cb
48 changed files with 734 additions and 1536 deletions

View File

@@ -1,45 +0,0 @@
package cn.iocoder.yudao.module.iot.core.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
// TODO @芋艿:需要添加对应的 DTO以及上下行的链路网关、网关服务、设备等
/**
* IoT 设备消息标识符枚举
*/
@Getter
@RequiredArgsConstructor
public enum IotDeviceMessageIdentifierEnum {
PROPERTY_GET("get"), // 下行 TODO 芋艿【讨论】貌似这个“上行”更合理device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置
PROPERTY_SET("set"), // 下行
PROPERTY_REPORT("report"), // 上行
STATE_ONLINE("online"), // 上行
STATE_OFFLINE("offline"), // 上行
CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景
CONFIG_SET("set"), // 下行
SERVICE_INVOKE("${identifier}"), // 下行
SERVICE_REPLY_SUFFIX("_reply"), // 芋艿TODO 芋艿:【讨论】上行 or 下行
OTA_UPGRADE("upgrade"), // 下行
OTA_PULL("pull"), // 上行
OTA_PROGRESS("progress"), // 上行
OTA_REPORT("report"), // 上行
REGISTER_REGISTER("register"), // 上行
REGISTER_REGISTER_SUB("register_sub"), // 上行
REGISTER_UNREGISTER_SUB("unregister_sub"), // 下行
TOPOLOGY_ADD("topology_add"), // 下行;
;
/**
* 标志符
*/
private final String identifier;
}

View File

@@ -1,8 +1,13 @@
package cn.iocoder.yudao.module.iot.core.enums;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.ArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Set;
/**
* IoT 设备消息的方法枚举
*
@@ -10,16 +15,47 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum IotDeviceMessageMethodEnum {
public enum IotDeviceMessageMethodEnum implements ArrayValuable<String> {
// ========== 设备状态 ==========
STATE_ONLINE("thing.state.online"),
STATE_OFFLINE("thing.state.offline"),
STATE_ONLINE("thing.state.online", true),
STATE_OFFLINE("thing.state.offline", true),
// ========== 设备属性 ==========
// 可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services
PROPERTY_REPORT("thing.property.report", true),
PROPERTY_SET("thing.property.set", false),
PROPERTY_GET("thing.property.get", false),
//
;
public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageMethodEnum::getMethod).toArray(String[]::new);
/**
* 不进行 reply 回复的方法集合
*/
public static final Set<String> REPLY_DISABLED = Set.of(STATE_ONLINE.getMethod(), STATE_OFFLINE.getMethod());
private final String method;
private final Boolean upstream;
@Override
public String[] array() {
return ARRAYS;
}
public static IotDeviceMessageMethodEnum of(String method) {
return ArrayUtil.firstMatch(item -> item.getMethod().equals(method),
IotDeviceMessageMethodEnum.values());
}
public static boolean isReplyDisabled(String method) {
return REPLY_DISABLED.contains(method);
}
}

View File

@@ -14,7 +14,7 @@ import java.util.Arrays;
public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> {
STATE("state"), // 设备状态
PROPERTY("property"), // 设备属性:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
// PROPERTY("property"), // 设备属性:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
EVENT("event"), // 设备事件:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
SERVICE("service"), // 设备服务:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
CONFIG("config"), // 设备配置:可参考 https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1 远程配置

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.iot.core.mq.message;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
import lombok.AllArgsConstructor;
@@ -43,6 +44,20 @@ public class IotDeviceMessage {
*/
private LocalDateTime reportTime;
/**
* 设备编号
*/
private Long deviceId;
/**
* 租户编号
*/
private Long tenantId;
/**
* 服务编号,该消息由哪个 server 发送
*/
private String serverId;
// ========== codec编解码字段 ==========
/**
@@ -72,84 +87,53 @@ public class IotDeviceMessage {
* 响应错误码
*/
private Integer code;
// ========== 后端字段 ==========
/**
* 设备编号
* 返回结果信息
*/
private Long deviceId;
/**
* 租户编号
*/
private Long tenantId;
private String msg;
/**
* 服务编号,该消息由哪个 server 服务进行消费
*/
private String serverId;
// ========== 基础方法只传递“codec编解码字段” ==========
// public IotDeviceMessage ofPropertyReport(Map<String, Object> properties) {
// this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
// this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier());
// this.setData(properties);
// return this;
// }
//
// public IotDeviceMessage ofPropertySet(Map<String, Object> properties) {
// this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
// this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
// this.setData(properties);
// return this;
// }
//
// public IotDeviceMessage ofStateOnline() {
// this.setType(IotDeviceMessageTypeEnum.STATE.getType());
// this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier());
// return this;
// }
//
// public IotDeviceMessage ofStateOffline() {
// this.setType(IotDeviceMessageTypeEnum.STATE.getType());
// this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier());
// return this;
// }
//
// public static IotDeviceMessage of(String productKey, String deviceName) {
// return of(productKey, deviceName,
// null, null);
// }
//
// public static IotDeviceMessage of(String productKey, String deviceName,
// String serverId) {
// return of(productKey, deviceName,
// null, serverId);
// }
//
// public static IotDeviceMessage of(String productKey, String deviceName,
// LocalDateTime reportTime, String serverId) {
// if (reportTime == null) {
// reportTime = LocalDateTime.now();
// }
// String messageId = IotDeviceMessageUtils.generateMessageId();
// return IotDeviceMessage.builder()
// .messageId(messageId).reportTime(reportTime)
// .productKey(productKey).deviceName(deviceName)
// .serverId(serverId).build();
// }
public static IotDeviceMessage requestOf(String method) {
return requestOf(null, method, null);
}
public static IotDeviceMessage of(String requestId, String method, Object params) {
return of(requestId, method, params, null, null);
public static IotDeviceMessage requestOf(String method, Object params) {
return requestOf(null, method, params);
}
public static IotDeviceMessage requestOf(String requestId, String method, Object params) {
return of(requestId, method, params, null, null, null);
}
public static IotDeviceMessage replyOf(String requestId, String method,
Object data, Integer code, String msg) {
if (code == null) {
code = GlobalErrorCodeConstants.SUCCESS.getCode();
msg = GlobalErrorCodeConstants.SUCCESS.getMsg();
}
return of(requestId, method, null, data, code, msg);
}
public static IotDeviceMessage of(String requestId, String method,
Object params, Object data, Integer code) {
Object params, Object data, Integer code, String msg) {
// 通用参数
IotDeviceMessage message = new IotDeviceMessage()
.setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now());
// 当前参数
message.setRequestId(requestId).setMethod(method).setParams(params).setData(data).setCode(code);
message.setRequestId(requestId).setMethod(method).setParams(params)
.setData(data).setCode(code).setMsg(msg);
return message;
}
// ========== 核心方法:在 of 基础方法之上,添加对应 method ==========
public static IotDeviceMessage buildStateOnline() {
return requestOf(IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod());
}
public static IotDeviceMessage buildStateOffline() {
return requestOf(IotDeviceMessageMethodEnum.STATE_OFFLINE.getMethod());
}
}

View File

@@ -1,8 +1,9 @@
package cn.iocoder.yudao.module.iot.core.util;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.system.SystemUtil;
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
/**
@@ -18,15 +19,28 @@ public class IotDeviceMessageUtils {
return IdUtil.fastSimpleUUID();
}
// TODO @芋艿:需要优化下;
/**
* 是否是上行消息:由设备发送
*
* @param message 消息
* @return 是否
*/
@SuppressWarnings("SimplifiableConditionalExpression")
public static boolean isUpstreamMessage(IotDeviceMessage message) {
return StrUtil.isNotEmpty(message.getServerId());
IotDeviceMessageMethodEnum methodEnum = IotDeviceMessageMethodEnum.of(message.getMethod());
Assert.notNull(methodEnum, "无法识别的消息方法:" + message.getMethod());
// 注意:回复消息时,需要取反
return !isReplyMessage(message) ? methodEnum.getUpstream() : !methodEnum.getUpstream();
}
/**
* 是否是回复消息,通过 {@link IotDeviceMessage#getCode()} 非空进行识别
*
* @param message 消息
* @return 是否
*/
public static boolean isReplyMessage(IotDeviceMessage message) {
return message.getCode() != null;
}
// ========== Topic 相关 ==========