result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO);
-
- // 3.2 返回结果 - 使用IotStandardResponse实体类
- IotStandardResponse response;
- if (result.isSuccess()) {
- response = IotStandardResponse.success(reportReqDTO.getRequestId(), METHOD, result.getData());
- } else {
- response = IotStandardResponse.error(
- reportReqDTO.getRequestId(), METHOD, result.getCode(), result.getMsg());
- }
- IotPluginCommonUtils.writeJsonResponse(routingContext, response);
- } catch (Exception e) {
- log.error("[handle][请求参数({}) 属性上报异常]", reportReqDTO, e);
-
- // 构建错误响应 - 使用IotStandardResponse实体类
- IotStandardResponse errorResponse = IotStandardResponse.error(
- reportReqDTO.getRequestId(), METHOD,
- INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
- IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse);
- }
- }
-}
diff --git a/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java
new file mode 100644
index 0000000000..ce250f41e1
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/upstream/router/IotDeviceUpstreamVertxHandler.java
@@ -0,0 +1,185 @@
+package cn.iocoder.yudao.module.iot.plugin.http.upstream.router;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
+import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDevicePropertyReportReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceStateUpdateReqDTO;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
+import cn.iocoder.yudao.module.iot.plugin.common.pojo.IotStandardResponse;
+import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils;
+import io.vertx.core.Handler;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.web.RoutingContext;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
+import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
+
+/**
+ * IoT 设备上行统一处理的 Vert.x Handler
+ *
+ * 统一处理设备属性上报和事件上报的请求
+ *
+ * @author haohao
+ */
+@RequiredArgsConstructor
+@Slf4j
+public class IotDeviceUpstreamVertxHandler implements Handler {
+
+ // 属性上报路径
+ public static final String PROPERTY_PATH = "/sys/:productKey/:deviceName/thing/event/property/post";
+ // 事件上报路径
+ public static final String EVENT_PATH = "/sys/:productKey/:deviceName/thing/event/:identifier/post";
+
+ private static final String PROPERTY_METHOD = "thing.event.property.post";
+ private static final String EVENT_METHOD_PREFIX = "thing.event.";
+ private static final String EVENT_METHOD_SUFFIX = ".post";
+
+ private final IotDeviceUpstreamApi deviceUpstreamApi;
+
+ @Override
+ public void handle(RoutingContext routingContext) {
+ String path = routingContext.request().path();
+ String requestId = IdUtil.fastSimpleUUID();
+
+ try {
+ // 1. 解析通用参数
+ String productKey = routingContext.pathParam("productKey");
+ String deviceName = routingContext.pathParam("deviceName");
+ JsonObject body = routingContext.body().asJsonObject();
+ requestId = ObjUtil.defaultIfBlank(body.getString("id"), requestId);
+
+ // 2. 根据路径模式处理不同类型的请求
+ CommonResult result;
+ String method;
+
+ if (path.matches(".*/thing/event/property/post")) {
+ // 处理属性上报
+ IotDevicePropertyReportReqDTO reportReqDTO = parsePropertyReportRequest(productKey, deviceName, requestId, body);
+
+ // 设备上线
+ updateDeviceState(reportReqDTO.getProductKey(), reportReqDTO.getDeviceName());
+
+ // 属性上报
+ result = deviceUpstreamApi.reportDeviceProperty(reportReqDTO);
+ method = PROPERTY_METHOD;
+ } else if (path.matches(".*/thing/event/.+/post")) {
+ // 处理事件上报
+ String identifier = routingContext.pathParam("identifier");
+ IotDeviceEventReportReqDTO reportReqDTO = parseEventReportRequest(productKey, deviceName, identifier, requestId, body);
+
+ // 设备上线
+ updateDeviceState(reportReqDTO.getProductKey(), reportReqDTO.getDeviceName());
+
+ // 事件上报
+ result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO);
+ method = EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX;
+ } else {
+ // 不支持的请求路径
+ IotStandardResponse errorResponse = IotStandardResponse.error(requestId, "unknown", BAD_REQUEST.getCode(), "不支持的请求路径");
+ IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse);
+ return;
+ }
+
+ // 3. 返回标准响应
+ IotStandardResponse response;
+ if (result.isSuccess()) {
+ response = IotStandardResponse.success(requestId, method, result.getData());
+ } else {
+ response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg());
+ }
+ IotPluginCommonUtils.writeJsonResponse(routingContext, response);
+
+ } catch (Exception e) {
+ log.error("[handle][处理上行请求异常] path={}", path, e);
+
+ // 构建错误响应
+ String method = path.contains("/property/") ? PROPERTY_METHOD : EVENT_METHOD_PREFIX + (routingContext.pathParams().containsKey("identifier") ? routingContext.pathParam("identifier") : "unknown") + EVENT_METHOD_SUFFIX;
+
+ IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
+ IotPluginCommonUtils.writeJsonResponse(routingContext, errorResponse);
+ }
+ }
+
+ /**
+ * 更新设备状态
+ *
+ * @param productKey 产品Key
+ * @param deviceName 设备名称
+ */
+ private void updateDeviceState(String productKey, String deviceName) {
+ deviceUpstreamApi.updateDeviceState(((IotDeviceStateUpdateReqDTO) new IotDeviceStateUpdateReqDTO().setRequestId(IdUtil.fastSimpleUUID()).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setState(IotDeviceStateEnum.ONLINE.getState()));
+ }
+
+ /**
+ * 解析属性上报请求
+ *
+ * @param productKey 产品Key
+ * @param deviceName 设备名称
+ * @param requestId 请求ID
+ * @param body 请求体
+ * @return 属性上报请求DTO
+ */
+ @SuppressWarnings("unchecked")
+ private IotDevicePropertyReportReqDTO parsePropertyReportRequest(String productKey, String deviceName, String requestId, JsonObject body) {
+
+ // 按照标准JSON格式处理属性数据
+ Map properties = new HashMap<>();
+
+ // 优先使用params字段,符合标准
+ Map params = body.getJsonObject("params") != null ? body.getJsonObject("params").getMap() : null;
+
+ if (params != null) {
+ // 将标准格式的params转换为平台需要的properties格式
+ for (Map.Entry entry : params.entrySet()) {
+ String key = entry.getKey();
+ Object valueObj = entry.getValue();
+
+ // 如果是复杂结构(包含value和time)
+ if (valueObj instanceof Map) {
+ Map valueMap = (Map) valueObj;
+ properties.put(key, valueMap.getOrDefault("value", valueObj));
+ } else {
+ properties.put(key, valueObj);
+ }
+ }
+ }
+
+ return ((IotDevicePropertyReportReqDTO) new IotDevicePropertyReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setProperties(properties);
+ }
+
+ /**
+ * 解析事件上报请求
+ *
+ * @param productKey 产品Key
+ * @param deviceName 设备名称
+ * @param identifier 事件标识符
+ * @param requestId 请求ID
+ * @param body 请求体
+ * @return 事件上报请求DTO
+ */
+ @SuppressWarnings("unchecked")
+ private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier, String requestId, JsonObject body) {
+
+ // 按照标准JSON格式处理事件参数
+ Map params;
+
+ // 优先使用params字段,符合标准
+ if (body.getJsonObject("params") != null) {
+ params = body.getJsonObject("params").getMap();
+ } else {
+ // 兼容旧格式
+ params = new HashMap<>();
+ }
+
+ return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO().setRequestId(requestId).setProcessId(IotPluginCommonUtils.getProcessId()).setReportTime(LocalDateTime.now()).setProductKey(productKey).setDeviceName(deviceName)).setIdentifier(identifier).setParams(params);
+ }
+}
\ No newline at end of file