mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-11-01 03:28:41 +08:00 
			
		
		
		
	【代码新增】IoT:增加 device 配置下发(设置)实现
This commit is contained in:
		| @ -0,0 +1,22 @@ | ||||
| package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream; | ||||
|  | ||||
| import jakarta.validation.constraints.NotNull; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * IoT 设备【配置】设置 Request DTO | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| @Data | ||||
| public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO { | ||||
|  | ||||
|     /** | ||||
|      * 配置 | ||||
|      */ | ||||
|     @NotNull(message = "配置不能为空") | ||||
|     private Map<String, Object> config; | ||||
|  | ||||
| } | ||||
| @ -10,15 +10,17 @@ import lombok.RequiredArgsConstructor; | ||||
| @RequiredArgsConstructor | ||||
| public enum IotDeviceMessageIdentifierEnum { | ||||
|  | ||||
|     PROPERTY_GET("get"), // 下行 | ||||
|     PROPERTY_GET("get"), // 下行 TODO 芋艿:【讨论】貌似这个“上行”更合理?device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置 | ||||
|     PROPERTY_SET("set"), // 下行 | ||||
|     PROPERTY_REPORT("report"), // 上行 | ||||
|  | ||||
|     STATE_ONLINE("online"), // 上行 | ||||
|     STATE_OFFLINE("offline"), // 上行 | ||||
|  | ||||
|     SERVICE_REPLY_SUFFIX("_reply"); // TODO 上行 or 下行 | ||||
|     CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景 | ||||
|     CONFIG_SET("set"), // 下行 | ||||
|  | ||||
|     SERVICE_REPLY_SUFFIX("_reply"); // 芋艿:TODO 芋艿:【讨论】上行 or 下行 | ||||
|  | ||||
|     /** | ||||
|      * 标志符 | ||||
|  | ||||
| @ -16,7 +16,8 @@ public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> { | ||||
|     STATE("state"), // 设备状态 | ||||
|     PROPERTY("property"), // 设备属性 | ||||
|     EVENT("event"), // 设备事件 | ||||
|     SERVICE("service"); // 设备服务 | ||||
|     SERVICE("service"), // 设备服务 | ||||
|     CONFIG("config"); // 设备配置 | ||||
|  | ||||
|     public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new); | ||||
|  | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| ### 请求 /iot/device/simulation-downstream 接口(服务调用) => 成功 | ||||
| POST {{baseUrl}}/iot/device/simulation-downstream | ||||
| ### 请求 /iot/device/downstream 接口(服务调用) => 成功 | ||||
| POST {{baseUrl}}/iot/device/downstream | ||||
| Content-Type: application/json | ||||
| tenant-id: {{adminTenentId}} | ||||
| Authorization: Bearer {{token}} | ||||
| @ -13,8 +13,8 @@ Authorization: Bearer {{token}} | ||||
|   } | ||||
| } | ||||
|  | ||||
| ### 请求 /iot/device/simulation-downstream 接口(属性设置) => 成功 | ||||
| POST {{baseUrl}}/iot/device/simulation-downstream | ||||
| ### 请求 /iot/device/downstream 接口(属性设置) => 成功 | ||||
| POST {{baseUrl}}/iot/device/downstream | ||||
| Content-Type: application/json | ||||
| tenant-id: {{adminTenentId}} | ||||
| Authorization: Bearer {{token}} | ||||
| @ -28,8 +28,8 @@ Authorization: Bearer {{token}} | ||||
|   } | ||||
| } | ||||
|  | ||||
| ### 请求 /iot/device/simulation-downstream 接口(属性获取) => 成功 | ||||
| POST {{baseUrl}}/iot/device/simulation-downstream | ||||
| ### 请求 /iot/device/downstream 接口(属性获取) => 成功 | ||||
| POST {{baseUrl}}/iot/device/downstream | ||||
| Content-Type: application/json | ||||
| tenant-id: {{adminTenentId}} | ||||
| Authorization: Bearer {{token}} | ||||
| @ -40,3 +40,15 @@ Authorization: Bearer {{token}} | ||||
|   "identifier": "get", | ||||
|   "data": ["xx", "yy"] | ||||
| } | ||||
|  | ||||
| ### 请求 /iot/device/downstream 接口(配置设置) => 成功 | ||||
| POST {{baseUrl}}/iot/device/downstream | ||||
| Content-Type: application/json | ||||
| tenant-id: {{adminTenentId}} | ||||
| Authorization: Bearer {{token}} | ||||
|  | ||||
| { | ||||
|   "id": 25, | ||||
|   "type": "config", | ||||
|   "identifier": "set" | ||||
| } | ||||
| @ -5,10 +5,8 @@ import cn.hutool.core.lang.Assert; | ||||
| 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.framework.common.util.json.JsonUtils; | ||||
| import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.*; | ||||
| import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO; | ||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; | ||||
| import cn.iocoder.yudao.module.iot.dal.dataobject.plugin.IotPluginInstanceDO; | ||||
| @ -68,21 +66,27 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic | ||||
|             return; | ||||
|         } | ||||
|         // 属性相关 | ||||
|         if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) | ||||
|         if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.PROPERTY.getType())) { | ||||
|             // 属性设置 | ||||
|             if (Objects.equals(downstreamReqVO.getIdentifier(), | ||||
|                     IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier())) { | ||||
|                 setDeviceProperty(downstreamReqVO, device, parentDevice); | ||||
|                 return; | ||||
|             } | ||||
|         // 属性设置 | ||||
|         if (Objects.equals(downstreamReqVO.getIdentifier(), | ||||
|                 IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { | ||||
|             getDeviceProperty(downstreamReqVO, device, parentDevice); | ||||
|             // 属性设置 | ||||
|             if (Objects.equals(downstreamReqVO.getIdentifier(), | ||||
|                     IotDeviceMessageIdentifierEnum.PROPERTY_GET.getIdentifier())) { | ||||
|                 getDeviceProperty(downstreamReqVO, device, parentDevice); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         // 配置下发 | ||||
|         if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType()) | ||||
|             && Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) { | ||||
|             setDeviceConfig(downstreamReqVO, device, parentDevice); | ||||
|             return; | ||||
|         } | ||||
|         // TODO 芋艿:ota 升级 | ||||
|         // TODO 芋艿:配置下发 | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @ -198,6 +202,41 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 设置设备配置 | ||||
|      * | ||||
|      * @param downstreamReqVO 下行请求 | ||||
|      * @param device          设备 | ||||
|      * @param parentDevice    父设备 | ||||
|      */ | ||||
|     @SuppressWarnings({"unchecked", "unused"}) | ||||
|     private void setDeviceConfig(IotDeviceDownstreamReqVO downstreamReqVO, | ||||
|                                  IotDeviceDO device, IotDeviceDO parentDevice) { | ||||
|         // 1. 参数转换,无需校验 | ||||
|         Map<String, Object> config = JsonUtils.parseObject(device.getConfig(), Map.class); | ||||
|  | ||||
|         // 2. 发送请求 | ||||
|         String url = String.format( "sys/%s/%s/thing/service/config/set", | ||||
|                 getProductKey(device, parentDevice), getDeviceName(device, parentDevice)); | ||||
|         IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO() | ||||
|                 .setConfig(config); | ||||
|         CommonResult<Boolean> result = requestPlugin(url, reqDTO, device); | ||||
|  | ||||
|         // 3. 发送设备消息 | ||||
|         IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId()) | ||||
|                 .setType(IotDeviceMessageTypeEnum.CONFIG.getType()) | ||||
|                 .setIdentifier(IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier()) | ||||
|                 .setData(reqDTO.getConfig()); | ||||
|         sendDeviceMessage(message, device, result.getCode()); | ||||
|  | ||||
|         // 4. 如果不成功,抛出异常,提示用户 | ||||
|         if (result.isError()) { | ||||
|             log.error("[setDeviceConfig][设备({})配置下发失败,请求参数:({}),响应结果:({})]", | ||||
|                     device.getDeviceKey(), reqDTO, result); | ||||
|             throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 请求插件 | ||||
|      * | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package cn.iocoder.yudao.module.iot.plugin.common.downstream; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||
| import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; | ||||
| 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; | ||||
| @ -38,4 +39,12 @@ public interface IotDeviceDownstreamHandler { | ||||
|      */ | ||||
|     CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO); | ||||
|  | ||||
|     /** | ||||
|      * 设置设备配置 | ||||
|      * | ||||
|      * @param setReqDTO 设置设备配置的请求 | ||||
|      * @return 是否成功 | ||||
|      */ | ||||
|     CommonResult<Boolean> setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO); | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package cn.iocoder.yudao.module.iot.plugin.common.downstream; | ||||
|  | ||||
| import cn.iocoder.yudao.module.iot.plugin.common.config.IotPluginCommonProperties; | ||||
| import cn.iocoder.yudao.module.iot.plugin.common.downstream.router.IotDeviceConfigSetVertxHandler; | ||||
| 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; | ||||
| @ -36,6 +37,8 @@ public class IotDeviceDownstreamServer { | ||||
|                 .handler(new IotDevicePropertySetVertxHandler(deviceDownstreamHandler)); | ||||
|         router.post(IotDevicePropertyGetVertxHandler.PATH) | ||||
|                 .handler(new IotDevicePropertyGetVertxHandler(deviceDownstreamHandler)); | ||||
|         router.post(IotDeviceConfigSetVertxHandler.PATH) | ||||
|                 .handler(new IotDeviceConfigSetVertxHandler(deviceDownstreamHandler)); | ||||
|         // 创建 HttpServer 实例 | ||||
|         this.server = vertx.createHttpServer().requestHandler(router); | ||||
|     } | ||||
|  | ||||
| @ -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.IotDeviceConfigSetReqDTO; | ||||
| 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 IotDeviceConfigSetVertxHandler implements Handler<RoutingContext> { | ||||
|  | ||||
|     public static final String PATH = "/sys/:productKey/:deviceName/thing/service/config/set"; | ||||
|  | ||||
|     private final IotDeviceDownstreamHandler deviceDownstreamHandler; | ||||
|  | ||||
|     @Override | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public void handle(RoutingContext routingContext) { | ||||
|         // 1. 解析参数 | ||||
|         IotDeviceConfigSetReqDTO 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> config = (Map<String, Object>) body.getMap().get("config"); | ||||
|             reqDTO = ((IotDeviceConfigSetReqDTO) new IotDeviceConfigSetReqDTO() | ||||
|                     .setRequestId(requestId).setProductKey(productKey).setDeviceName(deviceName)) | ||||
|                     .setConfig(config); | ||||
|         } catch (Exception e) { | ||||
|             log.error("[handle][路径参数({}) 解析参数失败]", routingContext.pathParams(), e); | ||||
|             IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(BAD_REQUEST)); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // 2. 调用处理器 | ||||
|         try { | ||||
|             CommonResult<Boolean> result = deviceDownstreamHandler.setDeviceConfig(reqDTO); | ||||
|             IotPluginCommonUtils.writeJson(routingContext, result); | ||||
|         } catch (Exception e) { | ||||
|             log.error("[handle][请求参数({}) 配置设置异常]", reqDTO, e); | ||||
|             IotPluginCommonUtils.writeJson(routingContext, CommonResult.error(INTERNAL_SERVER_ERROR)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -1,6 +1,7 @@ | ||||
| package cn.iocoder.yudao.module.iot.plugin.http.downstream; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||
| import cn.iocoder.yudao.module.iot.api.device.dto.control.downstream.IotDeviceConfigSetReqDTO; | ||||
| 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; | ||||
| @ -33,4 +34,9 @@ public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandle | ||||
|         return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public CommonResult<Boolean> setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO) { | ||||
|         return CommonResult.error(NOT_IMPLEMENTED.getCode(), "HTTP 不支持设置设备属性"); | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV