Commit b45406989702c20f5221b007646ea5b0dadf1038

Authored by YunaiV
1 parent 7670ac19

【代码新增】IoT:实现 device 下行服务调用的逻辑

Showing 17 changed files with 289 additions and 36 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceServiceInvokeReqDTO.java
1 1 package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
2 2  
  3 +import jakarta.validation.constraints.NotEmpty;
3 4 import lombok.Data;
4 5  
  6 +import java.util.Map;
  7 +
5 8 /**
6 9 * IoT 设备【服务】调用 Request DTO
7 10 *
... ... @@ -9,4 +12,15 @@ import lombok.Data;
9 12 */
10 13 @Data
11 14 public class IotDeviceServiceInvokeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 服务标识
  18 + */
  19 + @NotEmpty(message = "服务标识不能为空")
  20 + private String identifier;
  21 + /**
  22 + * 调用参数
  23 + */
  24 + private Map<String, Object> params;
  25 +
12 26 }
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java
... ... @@ -19,7 +19,6 @@ public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO
19 19 /**
20 20 * 事件参数
21 21 */
22   - @NotEmpty(message = "事件参数不能为空")
23 22 private Map<String, Object> params;
24 23  
25 24 }
... ...
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
... ... @@ -30,6 +30,7 @@ public interface ErrorCodeConstants {
30 30 ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在");
31 31 ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备");
32 32 ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!");
  33 + ErrorCode DEVICE_DOWNSTREAM_FAILED = new ErrorCode(1_050_003_007, "执行失败,原因:{}");
33 34  
34 35 // ========== 产品分类 1-050-004-000 ==========
35 36 ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
... ... @@ -46,6 +47,6 @@ public interface ErrorCodeConstants {
46 47 ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效");
47 48  
48 49 // ========== 插件实例 1-050-007-000 ==========
49   - ErrorCode PLUGIN_INSTANCE_NOT_EXISTS = new ErrorCode(1_050_007_000, "插件实例不存在");
  50 +
50 51  
51 52 }
52 53 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http 0 → 100644
  1 +### 请求 /iot/device/simulation-downstream 接口 => 成功
  2 +POST {{baseUrl}}/iot/device/simulation-downstream
  3 +Content-Type: application/json
  4 +tenant-id: {{adminTenentId}}
  5 +Authorization: Bearer {{token}}
  6 +
  7 +{
  8 + "id": 25,
  9 + "type": "service",
  10 + "identifier": "temperature",
  11 + "data": {
  12 + "xx": "yy"
  13 + }
  14 +}
0 15 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8 8 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO;
9 10 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
10 11 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationUpstreamReqVO;
11 12 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
... ... @@ -171,7 +172,7 @@ public class IotDeviceController {
171 172 @Operation(summary = "模拟设备下行")
172 173 @PreAuthorize("@ss.hasPermission('iot:device:simulation')")
173 174 public CommonResult<Boolean> simulationDownstreamDevice(
174   - @Valid @RequestBody IotDeviceSimulationUpstreamReqVO downstreamReqVO) {
  175 + @Valid @RequestBody IotDeviceSimulationDownstreamReqVO downstreamReqVO) {
175 176 deviceDownstreamService.simulationDeviceDownstream(downstreamReqVO);
176 177 return success(true);
177 178 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceLogDO.java
... ... @@ -75,6 +75,12 @@ public class IotDeviceLogDO {
75 75 * 存储具体的消息数据内容,通常是 JSON 格式
76 76 */
77 77 private String content;
  78 + /**
  79 + * 响应码
  80 + *
  81 + * 目前只有 server 下行消息给 device 设备时,才会有响应码
  82 + */
  83 + private Integer code;
78 84  
79 85 /**
80 86 * 上报时间戳
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/message/IotDeviceMessage.java
... ... @@ -55,12 +55,16 @@ public class IotDeviceMessage {
55 55 * 例如说:属性上报的 properties、事件上报的 params
56 56 */
57 57 private Object data;
  58 + /**
  59 + * 响应码
  60 + *
  61 + * 目前只有 server 下行消息给 device 设备时,才会有响应码
  62 + */
  63 + private Integer code;
58 64  
59 65 /**
60 66 * 上报时间
61 67 */
62 68 private LocalDateTime reportTime;
63 69  
64   - // TODO @芋艿 code;
65   -
66 70 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamService.java
1 1 package cn.iocoder.yudao.module.iot.service.device.control;
2 2  
3   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationUpstreamReqVO;
  3 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO;
4 4 import jakarta.validation.Valid;
5 5  
6 6 /**
... ... @@ -17,6 +17,6 @@ public interface IotDeviceDownstreamService {
17 17 *
18 18 * @param downstreamReqVO 设备下行请求 VO
19 19 */
20   - void simulationDeviceDownstream(@Valid IotDeviceSimulationUpstreamReqVO downstreamReqVO);
  20 + void simulationDeviceDownstream(@Valid IotDeviceSimulationDownstreamReqVO downstreamReqVO);
21 21  
22 22 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java
1 1 package cn.iocoder.yudao.module.iot.service.device.control;
2 2  
3   -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationUpstreamReqVO;
  3 +import cn.hutool.core.exceptions.ExceptionUtil;
  4 +import cn.hutool.core.lang.Assert;
  5 +import cn.hutool.core.util.IdUtil;
  6 +import cn.iocoder.yudao.framework.common.exception.ServiceException;
  7 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  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.IotDeviceServiceInvokeReqDTO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceSimulationDownstreamReqVO;
4 11 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  12 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
5 13 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageIdentifierEnum;
6 14 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  15 +import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
  16 +import cn.iocoder.yudao.module.iot.mq.producer.device.IotDeviceProducer;
7 17 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  18 +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
8 19 import jakarta.annotation.Resource;
9 20 import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.http.ResponseEntity;
10 22 import org.springframework.stereotype.Service;
11 23 import org.springframework.validation.annotation.Validated;
  24 +import org.springframework.web.client.RestTemplate;
12 25  
  26 +import java.time.LocalDateTime;
  27 +import java.util.Map;
13 28 import java.util.Objects;
14 29  
  30 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  31 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  32 +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_DOWNSTREAM_FAILED;
  33 +
15 34 /**
16 35 * 设备下行 Service 实现类
17 36 *
... ... @@ -24,9 +43,17 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
24 43  
25 44 @Resource
26 45 private IotDeviceService deviceService;
  46 + @Resource
  47 + private IotPluginInstanceService pluginInstanceService;
  48 +
  49 + @Resource
  50 + private RestTemplate restTemplate;
  51 +
  52 + @Resource
  53 + private IotDeviceProducer deviceProducer;
27 54  
28 55 @Override
29   - public void simulationDeviceDownstream(IotDeviceSimulationUpstreamReqVO downstreamReqVO) {
  56 + public void simulationDeviceDownstream(IotDeviceSimulationDownstreamReqVO downstreamReqVO) {
30 57 // 校验设备是否存在
31 58 IotDeviceDO device = deviceService.validateDeviceExists(downstreamReqVO.getId());
32 59 // TODO 芋艿:父设备的处理
... ... @@ -40,12 +67,14 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
40 67 // 属性相关
41 68 if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType()))
42 69 // 属性设置
43   - if (Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) {
  70 + if (Objects.equals(downstreamReqVO.getIdentifier(),
  71 + IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) {
44 72 setDeviceProperty(downstreamReqVO, device, parentDevice);
45 73 return;
46 74 }
47 75 // 属性设置
48   - if (Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) {
  76 + if (Objects.equals(downstreamReqVO.getIdentifier(),
  77 + IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) {
49 78 getDeviceProperty(downstreamReqVO, device, parentDevice);
50 79 return;
51 80 }
... ... @@ -53,22 +82,121 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
53 82 // TODO 芋艿:配置下发
54 83 }
55 84  
56   - private void invokeDeviceService(IotDeviceSimulationUpstreamReqVO downstreamReqVO,
57   - IotDeviceDO device, IotDeviceDO parentDevice) {
58   - // 校验服务是否存在
59   - // TODO 芋艿:这里需要校验服务是否存在
60   - // 调用服务
61   - // TODO 芋艿:这里需要调用服务
  85 + /**
  86 + * 调用设备服务
  87 + *
  88 + * @param downstreamReqVO 下行请求
  89 + * @param device 设备
  90 + * @param parentDevice 父设备
  91 + */
  92 + @SuppressWarnings("unchecked")
  93 + private void invokeDeviceService(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
  94 + IotDeviceDO device, IotDeviceDO parentDevice) {
  95 + // 1. 参数校验
  96 + if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) {
  97 + throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型");
  98 + }
  99 +
  100 + // 2. 发送请求
  101 + String url = String.format( "sys/%s/%s/thing/service/%s",
  102 + getProductKey(device, parentDevice), getDeviceName(device, parentDevice), downstreamReqVO.getIdentifier());
  103 + IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO()
  104 + .setParams((Map<String, Object>) downstreamReqVO.getData());
  105 + CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
  106 +
  107 + // 3. 发送设备消息
  108 + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
  109 + .setType(IotDeviceMessageTypeEnum.SERVICE.getType()).setIdentifier(reqDTO.getIdentifier())
  110 + .setData(reqDTO.getParams());
  111 + sendDeviceMessage(message, device, result.getCode());
  112 +
  113 + // 4. 如果不成功,抛出异常,提示用户
  114 + if (result.isError()) {
  115 + log.error("[invokeDeviceService][设备({})服务调用失败,请求参数:({}),响应结果:({})]",
  116 + device.getDeviceKey(), reqDTO, result);
  117 + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg());
  118 + }
62 119 }
63 120  
64   - private void setDeviceProperty(IotDeviceSimulationUpstreamReqVO downstreamReqVO,
65   - IotDeviceDO device, IotDeviceDO parentDevice) {
66   - // TODO 芋艿:这里需要设置设备属性
  121 + /**
  122 + * 设置设备属性
  123 + *
  124 + * @param downstreamReqVO 下行请求
  125 + * @param device 设备
  126 + * @param parentDevice 父设备
  127 + */
  128 + private void setDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
  129 + IotDeviceDO device, IotDeviceDO parentDevice) {
  130 + // TODO 1. 请求
  131 +
  132 + // TODO 2. 发送消息
67 133 }
68 134  
69   - private void getDeviceProperty(IotDeviceSimulationUpstreamReqVO downstreamReqVO,
70   - IotDeviceDO device, IotDeviceDO parentDevice) {
  135 + private void getDeviceProperty(IotDeviceSimulationDownstreamReqVO downstreamReqVO,
  136 + IotDeviceDO device, IotDeviceDO parentDevice) {
71 137 // TODO 芋艿:这里需要获取设备属性
72 138 }
73 139  
  140 + /**
  141 + * 请求插件
  142 + *
  143 + * @param url URL
  144 + * @param reqDTO 请求参数,只需要设置子类的参数!
  145 + * @param device 设备
  146 + * @return 响应结果
  147 + */
  148 + @SuppressWarnings({"unchecked", "HttpUrlsUsage"})
  149 + private CommonResult<Boolean> requestPlugin(String url, IotDeviceDownstreamAbstractReqDTO reqDTO, IotDeviceDO device) {
  150 + // 获得设备对应的插件实例
  151 + IotPluginInstanceDO pluginInstance = pluginInstanceService.getPluginInstanceByDeviceKey(device.getDeviceKey());
  152 + if (pluginInstance == null) {
  153 + throw exception(DEVICE_DOWNSTREAM_FAILED, "设备找不到对应的插件实例");
  154 + }
  155 +
  156 + // 补充通用参数
  157 + reqDTO.setRequestId(IdUtil.fastSimpleUUID());
  158 +
  159 + // 执行请求
  160 + ResponseEntity<CommonResult<Boolean>> responseEntity;
  161 + try {
  162 + responseEntity = restTemplate.postForEntity(
  163 + String.format("http://%s:%d/%s", pluginInstance.getHostIp(), pluginInstance.getDownstreamPort(), url),
  164 + reqDTO, (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class);
  165 + Assert.isTrue(responseEntity.getStatusCode().is2xxSuccessful(),
  166 + "HTTP 状态码不是 2xx,而是" + responseEntity.getStatusCode());
  167 + Assert.notNull(responseEntity.getBody(), "响应结果不能为空");
  168 + } catch (Exception ex) {
  169 + log.error("[requestPlugin][设备({}) url({}) 下行消息失败,请求参数({})]", device.getDeviceKey(), url, reqDTO, ex);
  170 + throw exception(DEVICE_DOWNSTREAM_FAILED, ExceptionUtil.getMessage(ex));
  171 + }
  172 + return responseEntity.getBody();
  173 + }
  174 +
  175 + private void sendDeviceMessage(IotDeviceMessage message, IotDeviceDO device, Integer code) {
  176 + // 1. 完善消息
  177 + message.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName())
  178 + .setDeviceKey(device.getDeviceKey());
  179 + Assert.notNull(message.getRequestId(), "requestId 不能为空");
  180 + if (message.getReportTime() == null) {
  181 + message.setReportTime(LocalDateTime.now());
  182 + }
  183 + message.setCode(code);
  184 +
  185 + // 2. 发送消息
  186 + try {
  187 + deviceProducer.sendDeviceMessage(message);
  188 + log.info("[sendDeviceMessage][message({}) 发送消息成功]", message);
  189 + } catch (Exception e) {
  190 + log.error("[sendDeviceMessage][message({}) 发送消息失败]", message, e);
  191 + }
  192 + }
  193 +
  194 + private String getDeviceName(IotDeviceDO device, IotDeviceDO parentDevice) {
  195 + return parentDevice != null ? parentDevice.getDeviceName() : device.getDeviceName();
  196 + }
  197 +
  198 + private String getProductKey(IotDeviceDO device, IotDeviceDO parentDevice) {
  199 + return parentDevice != null ? parentDevice.getProductKey() : device.getProductKey();
  200 + }
  201 +
74 202 }
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceService.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.plugin;
2 2  
3 3 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO;
4 4 import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
  5 +import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
5 6 import org.springframework.web.multipart.MultipartFile;
6 7  
7 8 import java.time.LocalDateTime;
... ... @@ -67,4 +68,12 @@ public interface IotPluginInstanceService {
67 68 */
68 69 void updateDevicePluginInstanceProcessIdAsync(String deviceKey, String processId);
69 70  
  71 + /**
  72 + * 获得设备对应的插件实例
  73 + *
  74 + * @param deviceKey 设备 Key
  75 + * @return 插件实例
  76 + */
  77 + IotPluginInstanceDO getPluginInstanceByDeviceKey(String deviceKey);
  78 +
70 79 }
71 80 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugin/IotPluginInstanceServiceImpl.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.plugin;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.io.FileUtil;
  5 +import cn.hutool.core.util.StrUtil;
5 6 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotPluginInstanceHeartbeatReqDTO;
6 7 import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInfoDO;
7 8 import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO;
... ... @@ -203,4 +204,13 @@ public class IotPluginInstanceServiceImpl implements IotPluginInstanceService {
203 204 devicePluginProcessIdRedisDAO.put(deviceKey, processId);
204 205 }
205 206  
  207 + @Override
  208 + public IotPluginInstanceDO getPluginInstanceByDeviceKey(String deviceKey) {
  209 + String processId = devicePluginProcessIdRedisDAO.get(deviceKey);
  210 + if (StrUtil.isEmpty(processId)) {
  211 + return null;
  212 + }
  213 + return pluginInstanceMapper.selectByProcessId(processId);
  214 + }
  215 +
206 216 }
207 217 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDeviceLogMapper.xml
... ... @@ -13,6 +13,7 @@
13 13 type NCHAR(50),
14 14 identifier NCHAR(255),
15 15 content NCHAR(1024),
  16 + code INT,
16 17 report_time TIMESTAMP
17 18 ) TAGS (
18 19 device_key NCHAR(50)
... ... @@ -24,7 +25,7 @@
24 25 </select>
25 26  
26 27 <insert id="insert">
27   - INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, report_time)
  28 + INSERT INTO device_log_${deviceKey} (ts, id, product_key, device_name, type, identifier, content, code, report_time)
28 29 USING device_log
29 30 TAGS ('${deviceKey}')
30 31 VALUES (
... ... @@ -35,6 +36,7 @@
35 36 #{type},
36 37 #{identifier},
37 38 #{content},
  39 + #{code},
38 40 #{reportTime}
39 41 )
40 42 </insert>
... ...
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/IotDeviceDownstreamHandler.java
... ... @@ -14,10 +14,28 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceSe
14 14 */
15 15 public interface IotDeviceDownstreamHandler {
16 16  
  17 + /**
  18 + * 调用设备服务
  19 + *
  20 + * @param invokeReqDTO 调用设备服务的请求
  21 + * @return 是否成功
  22 + */
17 23 CommonResult<Boolean> invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO);
18 24  
  25 + /**
  26 + * 获取设备属性
  27 + *
  28 + * @param getReqDTO 获取设备属性的请求
  29 + * @return 是否成功
  30 + */
19 31 CommonResult<Boolean> getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO);
20 32  
  33 + /**
  34 + * 设置设备属性
  35 + *
  36 + * @param setReqDTO 设置设备属性的请求
  37 + * @return 是否成功
  38 + */
21 39 CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO);
22 40  
23 41 }
... ...
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
1 1 package cn.iocoder.yudao.module.iot.plugin.common.downstream.router;
2 2  
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO;
3 5 import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler;
  6 +import cn.iocoder.yudao.module.iot.plugin.common.util.IotPluginCommonUtils;
4 7 import io.vertx.core.Handler;
5 8 import io.vertx.ext.web.RoutingContext;
6 9 import lombok.RequiredArgsConstructor;
7 10 import lombok.extern.slf4j.Slf4j;
  11 +import io.vertx.core.json.JsonObject;
  12 +import java.util.Map;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  15 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
8 16  
9 17 @Slf4j
10 18 @RequiredArgsConstructor
... ... @@ -15,9 +23,34 @@ public class IotDeviceServiceInvokeVertxHandler implements Handler&lt;RoutingContex
15 23 private final IotDeviceDownstreamHandler deviceDownstreamHandler;
16 24  
17 25 @Override
  26 + @SuppressWarnings("unchecked")
18 27 public void handle(RoutingContext routingContext) {
19   - // TODO 芋艿:这里没实现
20   - deviceDownstreamHandler.invokeDeviceService(null);
  28 + // 1. 解析参数
  29 + IotDeviceServiceInvokeReqDTO invokeReqDTO;
  30 + try {
  31 + String productKey = routingContext.pathParam("productKey");
  32 + String deviceName = routingContext.pathParam("deviceName");
  33 + String identifier = routingContext.pathParam("identifier");
  34 + JsonObject body = routingContext.body().asJsonObject();
  35 + String requestId = body.getString("requestId");
  36 + Map<String, Object> params = (Map<String, Object>) body.getMap().get("params");
  37 + invokeReqDTO = ((IotDeviceServiceInvokeReqDTO) new IotDeviceServiceInvokeReqDTO()
  38 + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName))
  39 + .setIdentifier(identifier).setParams(params);
  40 + } catch (Exception e) {
  41 + log.error("[handle][解析参数失败]", e);
  42 + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST));
  43 + return;
  44 + }
  45 +
  46 + // 2. 调用下游处理器
  47 + try {
  48 + CommonResult<Boolean> result = deviceDownstreamHandler.invokeDeviceService(invokeReqDTO);
  49 + IotPluginCommonUtils.writeJson(routingContext, result);
  50 + } catch (Exception e) {
  51 + log.error("[handle][请求参数({}) 服务调用异常]", invokeReqDTO, e);
  52 + IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR));
  53 + }
21 54 }
22 55  
23 56 }
... ...
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/util/IotPluginCommonUtils.java
... ... @@ -3,6 +3,11 @@ package cn.iocoder.yudao.module.iot.plugin.common.util;
3 3 import cn.hutool.core.util.IdUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.hutool.system.SystemUtil;
  6 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  7 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  8 +import io.vertx.core.http.HttpHeaders;
  9 +import io.vertx.ext.web.RoutingContext;
  10 +import org.springframework.http.MediaType;
6 11  
7 12 /**
8 13 * IoT 插件的通用工具类
... ... @@ -28,4 +33,12 @@ public class IotPluginCommonUtils {
28 33 SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID(), IdUtil.fastSimpleUUID());
29 34 }
30 35  
  36 + @SuppressWarnings("deprecation")
  37 + public static void writeJson(RoutingContext routingContext, CommonResult<?> result) {
  38 + routingContext.response()
  39 + .setStatusCode(200)
  40 + .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
  41 + .end(JsonUtils.toJsonString(result));
  42 + }
  43 +
31 44 }
... ...
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/config/IotPluginHttpAutoConfiguration.java
1 1 package cn.iocoder.yudao.module.iot.plugin.http.config;
2 2  
3 3 import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
  4 +import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler;
  5 +import cn.iocoder.yudao.module.iot.plugin.http.downstream.IotDeviceDownstreamHandlerImpl;
4 6 import cn.iocoder.yudao.module.iot.plugin.http.upstream.IotDeviceUpstreamServer;
5 7 import org.springframework.beans.factory.annotation.Value;
6 8 import org.springframework.context.annotation.Bean;
... ... @@ -26,4 +28,9 @@ public class IotPluginHttpAutoConfiguration {
26 28 return new IotDeviceUpstreamServer(port, deviceUpstreamApi);
27 29 }
28 30  
  31 + @Bean
  32 + public IotDeviceDownstreamHandler deviceDownstreamHandler() {
  33 + return new IotDeviceDownstreamHandlerImpl();
  34 + }
  35 +
29 36 }
... ...
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java
... ... @@ -5,7 +5,8 @@ import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePr
5 5 import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO;
6 6 import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO;
7 7 import cn.iocoder.yudao.module.iot.plugin.common.downstream.IotDeviceDownstreamHandler;
8   -import org.springframework.stereotype.Component;
  8 +
  9 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.NOT_IMPLEMENTED;
9 10  
10 11 /**
11 12 * HTTP 插件的 {@link IotDeviceDownstreamHandler} 实现类
... ... @@ -15,28 +16,21 @@ import org.springframework.stereotype.Component;
15 16 *
16 17 * @author 芋道源码
17 18 */
18   -@Component // TODO @芋艿:后续统一处理
19 19 public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler {
20 20  
21 21 @Override
22 22 public CommonResult<Boolean> invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) {
23   - // TODO @芋艿:待实现
24   - System.out.println();
25   - return null;
  23 + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持调用设备服务");
26 24 }
27 25  
28 26 @Override
29 27 public CommonResult<Boolean> getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO) {
30   - // TODO @芋艿:待实现
31   - System.out.println();
32   - return null;
  28 + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持获取设备属性");
33 29 }
34 30  
35 31 @Override
36 32 public CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) {
37   - // TODO @芋艿:待实现
38   - System.out.println();
39   - return null;
  33 + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性");
40 34 }
41 35  
42 36 }
... ...