Commit f46a2fb011282f33b6e61224a1334e6bc04151e1
1 parent
47c281d9
【代码新增】IoT:增加 device 配置下发(设置)实现
Showing
9 changed files
with
175 additions
and
20 deletions
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream; | |
| 2 | + | |
| 3 | +import jakarta.validation.constraints.NotNull; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.util.Map; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * IoT 设备【配置】设置 Request DTO | |
| 10 | + * | |
| 11 | + * @author 芋道源码 | |
| 12 | + */ | |
| 13 | +@Data | |
| 14 | +public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 配置 | |
| 18 | + */ | |
| 19 | + @NotNull(message = "配置不能为空") | |
| 20 | + private Map<String, Object> config; | |
| 21 | + | |
| 22 | +} | ... | ... |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java
| ... | ... | @@ -10,19 +10,21 @@ import lombok.RequiredArgsConstructor; |
| 10 | 10 | @RequiredArgsConstructor |
| 11 | 11 | public enum IotDeviceMessageIdentifierEnum { |
| 12 | 12 | |
| 13 | - PROPERTY_GET("get"), // 下行 | |
| 13 | + PROPERTY_GET("get"), // 下行 TODO 芋艿:【讨论】貌似这个“上行”更合理?device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置 | |
| 14 | 14 | PROPERTY_SET("set"), // 下行 |
| 15 | 15 | PROPERTY_REPORT("report"), // 上行 |
| 16 | 16 | |
| 17 | 17 | STATE_ONLINE("online"), // 上行 |
| 18 | 18 | STATE_OFFLINE("offline"), // 上行 |
| 19 | 19 | |
| 20 | - SERVICE_REPLY_SUFFIX("_reply"); // TODO 上行 or 下行 | |
| 20 | + CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景 | |
| 21 | + CONFIG_SET("set"), // 下行 | |
| 21 | 22 | |
| 23 | + SERVICE_REPLY_SUFFIX("_reply"); // 芋艿:TODO 芋艿:【讨论】上行 or 下行 | |
| 22 | 24 | |
| 23 | 25 | /** |
| 24 | 26 | * 标志符 |
| 25 | 27 | */ |
| 26 | 28 | private final String identifier; |
| 27 | 29 | |
| 28 | 30 | -} |
| 31 | +} | |
| 29 | 32 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java
| ... | ... | @@ -16,7 +16,8 @@ public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> { |
| 16 | 16 | STATE("state"), // 设备状态 |
| 17 | 17 | PROPERTY("property"), // 设备属性 |
| 18 | 18 | EVENT("event"), // 设备事件 |
| 19 | - SERVICE("service"); // 设备服务 | |
| 19 | + SERVICE("service"), // 设备服务 | |
| 20 | + CONFIG("config"); // 设备配置 | |
| 20 | 21 | |
| 21 | 22 | public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); |
| 22 | 23 | ... | ... |
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 接口(服务调用) => 成功 | |
| 2 | -POST {{baseUrl}}/iot/device/simulation-downstream | |
| 1 | +### 请求 /iot/device/downstream 接口(服务调用) => 成功 | |
| 2 | +POST {{baseUrl}}/iot/device/downstream | |
| 3 | 3 | Content-Type: application/json |
| 4 | 4 | tenant-id: {{adminTenentId}} |
| 5 | 5 | Authorization: Bearer {{token}} |
| ... | ... | @@ -13,8 +13,8 @@ Authorization: Bearer {{token}} |
| 13 | 13 | } |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | -### 请求 /iot/device/simulation-downstream 接口(属性设置) => 成功 | |
| 17 | -POST {{baseUrl}}/iot/device/simulation-downstream | |
| 16 | +### 请求 /iot/device/downstream 接口(属性设置) => 成功 | |
| 17 | +POST {{baseUrl}}/iot/device/downstream | |
| 18 | 18 | Content-Type: application/json |
| 19 | 19 | tenant-id: {{adminTenentId}} |
| 20 | 20 | Authorization: Bearer {{token}} |
| ... | ... | @@ -28,8 +28,8 @@ Authorization: Bearer {{token}} |
| 28 | 28 | } |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | -### 请求 /iot/device/simulation-downstream 接口(属性获取) => 成功 | |
| 32 | -POST {{baseUrl}}/iot/device/simulation-downstream | |
| 31 | +### 请求 /iot/device/downstream 接口(属性获取) => 成功 | |
| 32 | +POST {{baseUrl}}/iot/device/downstream | |
| 33 | 33 | Content-Type: application/json |
| 34 | 34 | tenant-id: {{adminTenentId}} |
| 35 | 35 | Authorization: Bearer {{token}} |
| ... | ... | @@ -39,4 +39,16 @@ Authorization: Bearer {{token}} |
| 39 | 39 | "type": "property", |
| 40 | 40 | "identifier": "get", |
| 41 | 41 | "data": ["xx", "yy"] |
| 42 | +} | |
| 43 | + | |
| 44 | +### 请求 /iot/device/downstream 接口(配置设置) => 成功 | |
| 45 | +POST {{baseUrl}}/iot/device/downstream | |
| 46 | +Content-Type: application/json | |
| 47 | +tenant-id: {{adminTenentId}} | |
| 48 | +Authorization: Bearer {{token}} | |
| 49 | + | |
| 50 | +{ | |
| 51 | + "id": 25, | |
| 52 | + "type": "config", | |
| 53 | + "identifier": "set" | |
| 42 | 54 | } |
| 43 | 55 | \ 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
| ... | ... | @@ -5,10 +5,8 @@ import cn.hutool.core.lang.Assert; |
| 5 | 5 | 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 | -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; | |
| 11 | -import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 9 | +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; | |
| 12 | 10 | import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; |
| 13 | 11 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; |
| 14 | 12 | import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; |
| ... | ... | @@ -68,21 +66,27 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 68 | 66 | return; |
| 69 | 67 | } |
| 70 | 68 | // 属性相关 |
| 71 | - if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) | |
| 69 | + if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { | |
| 72 | 70 | // 属性设置 |
| 73 | 71 | if (Objects.equals(downstreamReqVO.getIdentifier(), |
| 74 | 72 | IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) { |
| 75 | 73 | setDeviceProperty(downstreamReqVO, device, parentDevice); |
| 76 | 74 | return; |
| 77 | 75 | } |
| 78 | - // 属性设置 | |
| 79 | - if (Objects.equals(downstreamReqVO.getIdentifier(), | |
| 80 | - IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { | |
| 81 | - getDeviceProperty(downstreamReqVO, device, parentDevice); | |
| 76 | + // 属性设置 | |
| 77 | + if (Objects.equals(downstreamReqVO.getIdentifier(), | |
| 78 | + IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { | |
| 79 | + getDeviceProperty(downstreamReqVO, device, parentDevice); | |
| 80 | + return; | |
| 81 | + } | |
| 82 | + } | |
| 83 | + // 配置下发 | |
| 84 | + if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType()) | |
| 85 | + && Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { | |
| 86 | + setDeviceConfig(downstreamReqVO, device, parentDevice); | |
| 82 | 87 | return; |
| 83 | 88 | } |
| 84 | 89 | // TODO 芋艿:ota 升级 |
| 85 | - // TODO 芋艿:配置下发 | |
| 86 | 90 | } |
| 87 | 91 | |
| 88 | 92 | /** |
| ... | ... | @@ -199,6 +203,41 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic |
| 199 | 203 | } |
| 200 | 204 | |
| 201 | 205 | /** |
| 206 | + * 设置设备配置 | |
| 207 | + * | |
| 208 | + * @param downstreamReqVO 下行请求 | |
| 209 | + * @param device 设备 | |
| 210 | + * @param parentDevice 父设备 | |
| 211 | + */ | |
| 212 | + @SuppressWarnings({"unchecked", "unused"}) | |
| 213 | + private void setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, | |
| 214 | + IotDeviceDO device, IotDeviceDO parentDevice) { | |
| 215 | + // 1. 参数转换,无需校验 | |
| 216 | + Map<String, Object> config = JsonUtils.parseObject(device.getConfig(), Map.class); | |
| 217 | + | |
| 218 | + // 2. 发送请求 | |
| 219 | + String url = String.format( "sys/%s/%s/thing/service/config/set", | |
| 220 | + getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); | |
| 221 | + IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO() | |
| 222 | + .setConfig(config); | |
| 223 | + CommonResult<Boolean> result = requestPlugin(url, reqDTO, device); | |
| 224 | + | |
| 225 | + // 3. 发送设备消息 | |
| 226 | + IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) | |
| 227 | + .setType(IotDeviceMessageTypeEnum.CONFIG.getType()) | |
| 228 | + .setIdentifier(IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier()) | |
| 229 | + .setData(reqDTO.getConfig()); | |
| 230 | + sendDeviceMessage(message, device, result.getCode()); | |
| 231 | + | |
| 232 | + // 4. 如果不成功,抛出异常,提示用户 | |
| 233 | + if (result.isError()) { | |
| 234 | + log.error("[setDeviceConfig][设备({})配置下发失败,请求参数:({}),响应结果:({})]", | |
| 235 | + device.getDeviceKey(), reqDTO, result); | |
| 236 | + throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); | |
| 237 | + } | |
| 238 | + } | |
| 239 | + | |
| 240 | + /** | |
| 202 | 241 | * 请求插件 |
| 203 | 242 | * |
| 204 | 243 | * @param url URL | ... | ... |
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
| 1 | 1 | package cn.iocoder.yudao.module.iot.plugin.common.downstream; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; |
| 5 | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; |
| 6 | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; |
| ... | ... | @@ -38,4 +39,12 @@ public interface IotDeviceDownstreamHandler { |
| 38 | 39 | */ |
| 39 | 40 | CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO); |
| 40 | 41 | |
| 42 | + /** | |
| 43 | + * 设置设备配置 | |
| 44 | + * | |
| 45 | + * @param setReqDTO 设置设备配置的请求 | |
| 46 | + * @return 是否成功 | |
| 47 | + */ | |
| 48 | + CommonResult<Boolean> setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO); | |
| 49 | + | |
| 41 | 50 | } | ... | ... |
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 | 3 | import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; |
| 4 | +import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceConfigSetVertxHandler; | |
| 4 | 5 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertyGetVertxHandler; |
| 5 | 6 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDevicePropertySetVertxHandler; |
| 6 | 7 | import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceServiceInvokeVertxHandler; |
| ... | ... | @@ -36,6 +37,8 @@ public class IotDeviceDownstreamServer { |
| 36 | 37 | .handler(new IotDevicePropertySetVertxHandler(deviceDownstreamHandler)); |
| 37 | 38 | router.post(IotDevicePropertyGetVertxHandler.PATH) |
| 38 | 39 | .handler(new IotDevicePropertyGetVertxHandler(deviceDownstreamHandler)); |
| 40 | + router.post(IotDeviceConfigSetVertxHandler.PATH) | |
| 41 | + .handler(new IotDeviceConfigSetVertxHandler(deviceDownstreamHandler)); | |
| 39 | 42 | // 创建 HttpServer 实例 |
| 40 | 43 | this.server = vertx.createHttpServer().requestHandler(router); |
| 41 | 44 | } | ... | ... |
yudao-module-iot/yudao-module-iot-plugins/yudao-module-iot-plugin-common/src/main/java/cn/iocoder/yudao/module/iot/plugin/common/downstream/router/IotDeviceConfigSetVertxHandler.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.IotDeviceConfigSetReqDTO; | |
| 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 IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { | |
| 26 | + | |
| 27 | + public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; | |
| 28 | + | |
| 29 | + private final IotDeviceDownstreamHandler deviceDownstreamHandler; | |
| 30 | + | |
| 31 | + @Override | |
| 32 | + @SuppressWarnings("unchecked") | |
| 33 | + public void handle(RoutingContext routingContext) { | |
| 34 | + // 1. 解析参数 | |
| 35 | + IotDeviceConfigSetReqDTO 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> config = (Map<String, Object>) body.getMap().get("config"); | |
| 42 | + reqDTO = ((IotDeviceConfigSetReqDTO) new IotDeviceConfigSetReqDTO() | |
| 43 | + .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) | |
| 44 | + .setConfig(config); | |
| 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.setDeviceConfig(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-http/src/main/java/cn/iocoder/yudao/module/iot/plugin/http/downstream/IotDeviceDownstreamHandlerImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.plugin.http.downstream; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | +import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; | |
| 4 | 5 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertyGetReqDTO; |
| 5 | 6 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDevicePropertySetReqDTO; |
| 6 | 7 | import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceServiceInvokeReqDTO; |
| ... | ... | @@ -33,4 +34,9 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle |
| 33 | 34 | return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); |
| 34 | 35 | } |
| 35 | 36 | |
| 37 | + @Override | |
| 38 | + public CommonResult<Boolean> setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO) { | |
| 39 | + return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); | |
| 40 | + } | |
| 41 | + | |
| 36 | 42 | } | ... | ... |