Преглед на файлове

【代码新增】IoT:实现 device 下行属性获取、设置的下行消息

YunaiV преди 6 месеца
родител
ревизия
45b8172a61

+ 29 - 1
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http

@@ -1,4 +1,4 @@
-### 请求 /iot/device/simulation-downstream 接口 => 成功
+### 请求 /iot/device/simulation-downstream 接口(服务调用) => 成功
 POST {{baseUrl}}/iot/device/simulation-downstream
 Content-Type: application/json
 tenant-id: {{adminTenentId}}
@@ -11,4 +11,32 @@ Authorization: Bearer {{token}}
   "data": {
     "xx": "yy"
   }
+}
+
+### 请求 /iot/device/simulation-downstream 接口(属性设置) => 成功
+POST {{baseUrl}}/iot/device/simulation-downstream
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+  "id": 25,
+  "type": "property",
+  "identifier": "set",
+  "data": {
+    "xx": "yy"
+  }
+}
+
+### 请求 /iot/device/simulation-downstream 接口(属性获取) => 成功
+POST {{baseUrl}}/iot/device/simulation-downstream
+Content-Type: application/json
+tenant-id: {{adminTenentId}}
+Authorization: Bearer {{token}}
+
+{
+  "id": 25,
+  "type": "property",
+  "identifier": "get",
+  "data": ["xx", "yy"]
 }

+ 67 - 6
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java

@@ -6,6 +6,8 @@ import cn.hutool.core.util.IdUtil;
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceDownstreamAbstractReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO;
+import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO;
 import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
@@ -24,6 +26,7 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.client.RestTemplate;
 
 import java.time.LocalDateTime;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
@@ -91,11 +94,12 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
      */
     @SuppressWarnings("unchecked")
     private void invokeDeviceService(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
-            IotDeviceDO device, IotDeviceDO parentDevice) {
+                                     IotDeviceDO device, IotDeviceDO parentDevice) {
         // 1. 参数校验
         if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) {
             throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型");
         }
+        // TODO @super:【可优化】过滤掉不合法的服务
 
         // 2. 发送请求
         String url = String.format( "sys/%s/%s/thing/service/%s",
@@ -125,16 +129,73 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
      * @param device          设备
      * @param parentDevice    父设备
      */
+    @SuppressWarnings("unchecked")
     private void setDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
-            IotDeviceDO device, IotDeviceDO parentDevice) {
-        // TODO 1. 请求
+                                   IotDeviceDO device, IotDeviceDO parentDevice) {
+        // 1. 参数校验
+        if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) {
+            throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型");
+        }
+        // TODO @super:【可优化】过滤掉不合法的属性
+
+        // 2. 发送请求
+        String url = String.format( "sys/%s/%s/thing/service/property/set",
+                getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
+        IotDevicePropertySetReqDTO reqDTO = new IotDevicePropertySetReqDTO()
+                .setProperties((Map<String, Object>) downstreamReqVO.getData());
+        CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
+
+        // 3. 发送设备消息
+        IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
+                .setType(IotDeviceMessageTypeEnum.PROPERTY.getType())
+                .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())
+                .setData(reqDTO.getProperties());
+        sendDeviceMessage(message, device, result.getCode());
 
-        // TODO 2. 发送消息
+        // 4. 如果不成功,抛出异常,提示用户
+        if (result.isError()) {
+            log.error("[setDeviceProperty][设备({})属性设置失败,请求参数:({}),响应结果:({})]",
+                    device.getDeviceKey(), reqDTO, result);
+            throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg());
+        }
     }
 
+    /**
+     * 获取设备属性
+     *
+     * @param downstreamReqVO 下行请求
+     * @param device          设备
+     * @param parentDevice    父设备
+     */
+    @SuppressWarnings("unchecked")
     private void getDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
-            IotDeviceDO device, IotDeviceDO parentDevice) {
-        // TODO 芋艿:这里需要获取设备属性
+                                   IotDeviceDO device, IotDeviceDO parentDevice) {
+        // 1. 参数校验
+        if (!(downstreamReqVO.getData() instanceof List<?>)) {
+            throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 List 类型");
+        }
+        // TODO @super:【可优化】过滤掉不合法的属性
+
+        // 2. 发送请求
+        String url = String.format( "sys/%s/%s/thing/service/property/get",
+                getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
+        IotDevicePropertyGetReqDTO reqDTO = new IotDevicePropertyGetReqDTO()
+                .setIdentifiers((List<String>) downstreamReqVO.getData());
+        CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
+
+        // 3. 发送设备消息
+        IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
+                .setType(IotDeviceMessageTypeEnum.PROPERTY.getType())
+                .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())
+                .setData(reqDTO.getIdentifiers());
+        sendDeviceMessage(message, device, result.getCode());
+
+        // 4. 如果不成功,抛出异常,提示用户
+        if (result.isError()) {
+            log.error("[getDeviceProperty][设备({})属性获取失败,请求参数:({}),响应结果:({})]",
+                    device.getDeviceKey(), reqDTO, result);
+            throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg());
+        }
     }
 
     /**

+ 8 - 2
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamServer.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.iot.plugin.common.downstream;
 
+import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertyGetVertxHandler;
+import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertySetVertxHandler;
 import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler;
 import io.vertx.core.Vertx;
 import io.vertx.core.http.HttpServer;
@@ -24,8 +26,12 @@ public class IotDeviceDownstreamServer {
         // 创建 Router 实例
         Router router = Router.router(vertx);
         router.route().handler(BodyHandler.create()); // 处理 Body
-        router.post(IotDeviceServiceInvokeVertxHandler.PATH).handler(
-                new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler)); // 处理 Service Invoke
+        router.post(IotDeviceServiceInvokeVertxHandler.PATH)
+                .handler(new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler));
+        router.post(IotDevicePropertySetVertxHandler.PATH)
+                .handler(new IotDevicePropertySetVertxHandler(deviceDownstreamHandler));
+        router.post(IotDevicePropertyGetVertxHandler.PATH)
+                .handler(new IotDevicePropertyGetVertxHandler(deviceDownstreamHandler));
         // 创建 HttpServer 实例
         this.server = vertx.createHttpServer().requestHandler(router);
     }

+ 61 - 0
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertyGetVertxHandler.java

@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.iot.plugin.common.downstream.router;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO;
+import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler;
+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.util.List;
+
+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 设备服务获取 Vertx Handler
+ *
+ * 芋道源码
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class IotDevicePropertyGetVertxHandler implements Handler<RoutingContext> {
+
+    public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/get";
+
+    private final IotDeviceDownstreamHandler deviceDownstreamHandler;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void handle(RoutingContext routingContext) {
+        // 1. 解析参数
+        IotDevicePropertyGetReqDTO reqDTO;
+        try {
+            String productKey = routingContext.pathParam("productKey");
+            String deviceName = routingContext.pathParam("deviceName");
+            JsonObject body = routingContext.body().asJsonObject();
+            String requestId = body.getString("requestId");
+            List<String> identifiers = (List<String>) body.getMap().get("identifiers");
+            reqDTO = ((IotDevicePropertyGetReqDTO) new IotDevicePropertyGetReqDTO()
+                    .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName))
+                    .setIdentifiers(identifiers);
+        } catch (Exception e) {
+            log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e);
+            IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST));
+            return;
+        }
+
+        // 2. 调用处理器
+        try {
+            CommonResult<Boolean> result = deviceDownstreamHandler.getDeviceProperty(reqDTO);
+            IotPluginCommonUtils.writeJson(routingContext, result);
+        } catch (Exception e) {
+            log.error("[handle][请求参数({}) 属性获取异常]", reqDTO, e);
+            IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR));
+        }
+    }
+
+}

+ 61 - 0
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDevicePropertySetVertxHandler.java

@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.module.iot.plugin.common.downstream.router;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO;
+import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler;
+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.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 设备服务设置 Vertx Handler
+ *
+ * 芋道源码
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class IotDevicePropertySetVertxHandler implements Handler<RoutingContext> {
+
+    public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/set";
+
+    private final IotDeviceDownstreamHandler deviceDownstreamHandler;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void handle(RoutingContext routingContext) {
+        // 1. 解析参数
+        IotDevicePropertySetReqDTO reqDTO;
+        try {
+            String productKey = routingContext.pathParam("productKey");
+            String deviceName = routingContext.pathParam("deviceName");
+            JsonObject body = routingContext.body().asJsonObject();
+            String requestId = body.getString("requestId");
+            Map<String, Object> properties = (Map<String, Object>) body.getMap().get("properties");
+            reqDTO = ((IotDevicePropertySetReqDTO) new IotDevicePropertySetReqDTO()
+                    .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName))
+                    .setProperties(properties);
+        } catch (Exception e) {
+            log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e);
+            IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST));
+            return;
+        }
+
+        // 2. 调用处理器
+        try {
+            CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceProperty(reqDTO);
+            IotPluginCommonUtils.writeJson(routingContext, result);
+        } catch (Exception e) {
+            log.error("[handle][请求参数({}) 属性设置异常]", reqDTO, e);
+            IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR));
+        }
+    }
+
+}

+ 11 - 6
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceServiceInvokeVertxHandler.java

@@ -14,6 +14,11 @@ 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 设备服务调用 Vertx Handler
+ *
+ * 芋道源码
+ */
 @Slf4j
 @RequiredArgsConstructor
 public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContext> {
@@ -26,7 +31,7 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContex
     @SuppressWarnings("unchecked")
     public void handle(RoutingContext routingContext) {
         // 1. 解析参数
-        IotDeviceServiceInvokeReqDTO invokeReqDTO;
+        IotDeviceServiceInvokeReqDTO reqDTO;
         try {
             String productKey = routingContext.pathParam("productKey");
             String deviceName = routingContext.pathParam("deviceName");
@@ -34,21 +39,21 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContex
             JsonObject body = routingContext.body().asJsonObject();
             String requestId = body.getString("requestId");
             Map<String, Object> params = (Map<String, Object>) body.getMap().get("params");
-            invokeReqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO()
+            reqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO()
                     .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName))
                     .setIdentifier(identifier).setParams(params);
         } catch (Exception e) {
-            log.error("[handle][解析参数失败]", e);
+            log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e);
             IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST));
             return;
         }
 
-        // 2. 调用下游处理器
+        // 2. 调用处理器
         try {
-            CommonResult<Boolean> result = deviceDownstreamHandler.invokeDeviceService(invokeReqDTO);
+            CommonResult<Boolean> result = deviceDownstreamHandler.invokeDeviceService(reqDTO);
             IotPluginCommonUtils.writeJson(routingContext, result);
         } catch (Exception e) {
-            log.error("[handle][请求参数({}) 服务调用异常]", invokeReqDTO, e);
+            log.error("[handle][请求参数({}) 服务调用异常]", reqDTO, e);
             IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR));
         }
     }