Commit 45b8172a617a15f5a7b34347ed1da208097a2339

Authored by YunaiV
1 parent b4540698

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

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http
1   -### 请求 /iot/device/simulation-downstream 接口 => 成功
  1 +### 请求 /iot/device/simulation-downstream 接口(服务调用) => 成功
2 2 POST {{baseUrl}}/iot/device/simulation-downstream
3 3 Content-Type: application/json
4 4 tenant-id: {{adminTenentId}}
... ... @@ -11,4 +11,32 @@ Authorization: Bearer {{token}}
11 11 "data": {
12 12 "xx": "yy"
13 13 }
  14 +}
  15 +
  16 +### 请求 /iot/device/simulation-downstream 接口(属性设置) => 成功
  17 +POST {{baseUrl}}/iot/device/simulation-downstream
  18 +Content-Type: application/json
  19 +tenant-id: {{adminTenentId}}
  20 +Authorization: Bearer {{token}}
  21 +
  22 +{
  23 + "id": 25,
  24 + "type": "property",
  25 + "identifier": "set",
  26 + "data": {
  27 + "xx": "yy"
  28 + }
  29 +}
  30 +
  31 +### 请求 /iot/device/simulation-downstream 接口(属性获取) => 成功
  32 +POST {{baseUrl}}/iot/device/simulation-downstream
  33 +Content-Type: application/json
  34 +tenant-id: {{adminTenentId}}
  35 +Authorization: Bearer {{token}}
  36 +
  37 +{
  38 + "id": 25,
  39 + "type": "property",
  40 + "identifier": "get",
  41 + "data": ["xx", "yy"]
14 42 }
15 43 \ No newline at end of file
... ...
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;
6 6 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 7 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
8 8 import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceDownstreamAbstractReqDTO;
  9 +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO;
  10 +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO;
9 11 import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO;
10 12 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO;
11 13 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
... ... @@ -24,6 +26,7 @@ import org.springframework.validation.annotation.Validated;
24 26 import org.springframework.web.client.RestTemplate;
25 27  
26 28 import java.time.LocalDateTime;
  29 +import java.util.List;
27 30 import java.util.Map;
28 31 import java.util.Objects;
29 32  
... ... @@ -91,11 +94,12 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
91 94 */
92 95 @SuppressWarnings("unchecked")
93 96 private void invokeDeviceService(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
94   - IotDeviceDO device, IotDeviceDO parentDevice) {
  97 + IotDeviceDO device, IotDeviceDO parentDevice) {
95 98 // 1. 参数校验
96 99 if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) {
97 100 throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型");
98 101 }
  102 + // TODO @super:【可优化】过滤掉不合法的服务
99 103  
100 104 // 2. 发送请求
101 105 String url = String.format( "sys/%s/%s/thing/service/%s",
... ... @@ -125,16 +129,73 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
125 129 * @param device 设备
126 130 * @param parentDevice 父设备
127 131 */
  132 + @SuppressWarnings("unchecked")
128 133 private void setDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
129   - IotDeviceDO device, IotDeviceDO parentDevice) {
130   - // TODO 1. 请求
  134 + IotDeviceDO device, IotDeviceDO parentDevice) {
  135 + // 1. 参数校验
  136 + if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) {
  137 + throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型");
  138 + }
  139 + // TODO @super:【可优化】过滤掉不合法的属性
  140 +
  141 + // 2. 发送请求
  142 + String url = String.format( "sys/%s/%s/thing/service/property/set",
  143 + getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
  144 + IotDevicePropertySetReqDTO reqDTO = new IotDevicePropertySetReqDTO()
  145 + .setProperties((Map<String, Object>) downstreamReqVO.getData());
  146 + CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
  147 +
  148 + // 3. 发送设备消息
  149 + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
  150 + .setType(IotDeviceMessageTypeEnum.PROPERTY.getType())
  151 + .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())
  152 + .setData(reqDTO.getProperties());
  153 + sendDeviceMessage(message, device, result.getCode());
131 154  
132   - // TODO 2. 发送消息
  155 + // 4. 如果不成功,抛出异常,提示用户
  156 + if (result.isError()) {
  157 + log.error("[setDeviceProperty][设备({})属性设置失败,请求参数:({}),响应结果:({})]",
  158 + device.getDeviceKey(), reqDTO, result);
  159 + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg());
  160 + }
133 161 }
134 162  
  163 + /**
  164 + * 获取设备属性
  165 + *
  166 + * @param downstreamReqVO 下行请求
  167 + * @param device 设备
  168 + * @param parentDevice 父设备
  169 + */
  170 + @SuppressWarnings("unchecked")
135 171 private void getDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
136   - IotDeviceDO device, IotDeviceDO parentDevice) {
137   - // TODO 芋艿:这里需要获取设备属性
  172 + IotDeviceDO device, IotDeviceDO parentDevice) {
  173 + // 1. 参数校验
  174 + if (!(downstreamReqVO.getData() instanceof List<?>)) {
  175 + throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 List 类型");
  176 + }
  177 + // TODO @super:【可优化】过滤掉不合法的属性
  178 +
  179 + // 2. 发送请求
  180 + String url = String.format( "sys/%s/%s/thing/service/property/get",
  181 + getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
  182 + IotDevicePropertyGetReqDTO reqDTO = new IotDevicePropertyGetReqDTO()
  183 + .setIdentifiers((List<String>) downstreamReqVO.getData());
  184 + CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
  185 +
  186 + // 3. 发送设备消息
  187 + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
  188 + .setType(IotDeviceMessageTypeEnum.PROPERTY.getType())
  189 + .setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())
  190 + .setData(reqDTO.getIdentifiers());
  191 + sendDeviceMessage(message, device, result.getCode());
  192 +
  193 + // 4. 如果不成功,抛出异常,提示用户
  194 + if (result.isError()) {
  195 + log.error("[getDeviceProperty][设备({})属性获取失败,请求参数:({}),响应结果:({})]",
  196 + device.getDeviceKey(), reqDTO, result);
  197 + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg());
  198 + }
138 199 }
139 200  
140 201 /**
... ...
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 1 package cn.iocoder.yudao.module.iot.plugin.common.downstream;
2 2  
  3 +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertyGetVertxHandler;
  4 +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertySetVertxHandler;
3 5 import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler;
4 6 import io.vertx.core.Vertx;
5 7 import io.vertx.core.http.HttpServer;
... ... @@ -24,8 +26,12 @@ public class IotDeviceDownstreamServer {
24 26 // 创建 Router 实例
25 27 Router router = Router.router(vertx);
26 28 router.route().handler(BodyHandler.create()); // 处理 Body
27   - router.post(IotDeviceServiceInvokeVertxHandler.PATH).handler(
28   - new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler)); // 处理 Service Invoke
  29 + router.post(IotDeviceServiceInvokeVertxHandler.PATH)
  30 + .handler(new IotDeviceServiceInvokeVertxHandler(deviceDownstreamHandler));
  31 + router.post(IotDevicePropertySetVertxHandler.PATH)
  32 + .handler(new IotDevicePropertySetVertxHandler(deviceDownstreamHandler));
  33 + router.post(IotDevicePropertyGetVertxHandler.PATH)
  34 + .handler(new IotDevicePropertyGetVertxHandler(deviceDownstreamHandler));
29 35 // 创建 HttpServer 实例
30 36 this.server = vertx.createHttpServer().requestHandler(router);
31 37 }
... ...
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 → 100644
  1 +package cn.iocoder.yudao.module.iot.plugin.common.downstream.router;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO;
  5 +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler;
  6 +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils;
  7 +import io.vertx.core.Handler;
  8 +import io.vertx.core.json.JsonObject;
  9 +import io.vertx.ext.web.RoutingContext;
  10 +import lombok.RequiredArgsConstructor;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +
  13 +import java.util.List;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  16 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
  17 +
  18 +/**
  19 + * IOT 设备服务获取 Vertx Handler
  20 + *
  21 + * 芋道源码
  22 + */
  23 +@Slf4j
  24 +@RequiredArgsConstructor
  25 +public class IotDevicePropertyGetVertxHandler implements Handler<RoutingContext> {
  26 +
  27 + public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/get";
  28 +
  29 + private final IotDeviceDownstreamHandler deviceDownstreamHandler;
  30 +
  31 + @Override
  32 + @SuppressWarnings("unchecked")
  33 + public void handle(RoutingContext routingContext) {
  34 + // 1. 解析参数
  35 + IotDevicePropertyGetReqDTO reqDTO;
  36 + try {
  37 + String productKey = routingContext.pathParam("productKey");
  38 + String deviceName = routingContext.pathParam("deviceName");
  39 + JsonObject body = routingContext.body().asJsonObject();
  40 + String requestId = body.getString("requestId");
  41 + List<String> identifiers = (List<String>) body.getMap().get("identifiers");
  42 + reqDTO = ((IotDevicePropertyGetReqDTO) new IotDevicePropertyGetReqDTO()
  43 + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName))
  44 + .setIdentifiers(identifiers);
  45 + } catch (Exception e) {
  46 + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e);
  47 + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST));
  48 + return;
  49 + }
  50 +
  51 + // 2. 调用处理器
  52 + try {
  53 + CommonResult<Boolean> result = deviceDownstreamHandler.getDeviceProperty(reqDTO);
  54 + IotPluginCommonUtils.writeJson(routingContext, result);
  55 + } catch (Exception e) {
  56 + log.error("[handle][请求参数({}) 属性获取异常]", reqDTO, e);
  57 + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR));
  58 + }
  59 + }
  60 +
  61 +}
... ...
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 → 100644
  1 +package cn.iocoder.yudao.module.iot.plugin.common.downstream.router;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO;
  5 +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler;
  6 +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils;
  7 +import io.vertx.core.Handler;
  8 +import io.vertx.core.json.JsonObject;
  9 +import io.vertx.ext.web.RoutingContext;
  10 +import lombok.RequiredArgsConstructor;
  11 +import lombok.extern.slf4j.Slf4j;
  12 +
  13 +import java.util.Map;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  16 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
  17 +
  18 +/**
  19 + * IOT 设备服务设置 Vertx Handler
  20 + *
  21 + * 芋道源码
  22 + */
  23 +@Slf4j
  24 +@RequiredArgsConstructor
  25 +public class IotDevicePropertySetVertxHandler implements Handler<RoutingContext> {
  26 +
  27 + public static final String PATH = "/sys/:productKey/:deviceName/thing/service/property/set";
  28 +
  29 + private final IotDeviceDownstreamHandler deviceDownstreamHandler;
  30 +
  31 + @Override
  32 + @SuppressWarnings("unchecked")
  33 + public void handle(RoutingContext routingContext) {
  34 + // 1. 解析参数
  35 + IotDevicePropertySetReqDTO reqDTO;
  36 + try {
  37 + String productKey = routingContext.pathParam("productKey");
  38 + String deviceName = routingContext.pathParam("deviceName");
  39 + JsonObject body = routingContext.body().asJsonObject();
  40 + String requestId = body.getString("requestId");
  41 + Map<String, Object> properties = (Map<String, Object>) body.getMap().get("properties");
  42 + reqDTO = ((IotDevicePropertySetReqDTO) new IotDevicePropertySetReqDTO()
  43 + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName))
  44 + .setProperties(properties);
  45 + } catch (Exception e) {
  46 + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e);
  47 + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST));
  48 + return;
  49 + }
  50 +
  51 + // 2. 调用处理器
  52 + try {
  53 + CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceProperty(reqDTO);
  54 + IotPluginCommonUtils.writeJson(routingContext, result);
  55 + } catch (Exception e) {
  56 + log.error("[handle][请求参数({}) 属性设置异常]", reqDTO, e);
  57 + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR));
  58 + }
  59 + }
  60 +
  61 +}
... ...
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;
14 14 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
15 15 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
16 16  
  17 +/**
  18 + * IOT 设备服务调用 Vertx Handler
  19 + *
  20 + * 芋道源码
  21 + */
17 22 @Slf4j
18 23 @RequiredArgsConstructor
19 24 public class IotDeviceServiceInvokeVertxHandler implements Handler<RoutingContext> {
... ... @@ -26,7 +31,7 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler&lt;RoutingContex
26 31 @SuppressWarnings("unchecked")
27 32 public void handle(RoutingContext routingContext) {
28 33 // 1. 解析参数
29   - IotDeviceServiceInvokeReqDTO invokeReqDTO;
  34 + IotDeviceServiceInvokeReqDTO reqDTO;
30 35 try {
31 36 String productKey = routingContext.pathParam("productKey");
32 37 String deviceName = routingContext.pathParam("deviceName");
... ... @@ -34,21 +39,21 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler&lt;RoutingContex
34 39 JsonObject body = routingContext.body().asJsonObject();
35 40 String requestId = body.getString("requestId");
36 41 Map<String, Object> params = (Map<String, Object>) body.getMap().get("params");
37   - invokeReqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO()
  42 + reqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO()
38 43 .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName))
39 44 .setIdentifier(identifier).setParams(params);
40 45 } catch (Exception e) {
41   - log.error("[handle][解析参数失败]", e);
  46 + log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e);
42 47 IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST));
43 48 return;
44 49 }
45 50  
46   - // 2. 调用下游处理器
  51 + // 2. 调用处理器
47 52 try {
48   - CommonResult<Boolean> result = deviceDownstreamHandler.invokeDeviceService(invokeReqDTO);
  53 + CommonResult<Boolean> result = deviceDownstreamHandler.invokeDeviceService(reqDTO);
49 54 IotPluginCommonUtils.writeJson(routingContext, result);
50 55 } catch (Exception e) {
51   - log.error("[handle][请求参数({}) 服务调用异常]", invokeReqDTO, e);
  56 + log.error("[handle][请求参数({}) 服务调用异常]", reqDTO, e);
52 57 IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR));
53 58 }
54 59 }
... ...