【功能新增】IoT:OTA 升级的下行消息的实现

This commit is contained in:
YunaiV
2025-02-07 21:18:57 +08:00
parent 795e06bc8f
commit 4919439b96
12 changed files with 311 additions and 31 deletions

View File

@@ -51,4 +51,25 @@ Authorization: Bearer {{token}}
"id": 25,
"type": "config",
"identifier": "set"
}
### 请求 /iot/device/downstream 接口OTA 升级) => 成功
POST {{baseUrl}}/iot/device/downstream
Content-Type: application/json
tenant-id: {{adminTenentId}}
Authorization: Bearer {{token}}
{
"id": 25,
"type": "ota",
"identifier": "upgrade",
"data": {
"firmwareId": 1,
"version": "1.0.0",
"signMethod": "MD5",
"fileSign": "d41d8cd98f00b204e9800998ecf8427e",
"fileSize": 1024,
"fileUrl": "http://example.com/firmware.bin",
"information": "{\"desc\":\"升级到最新版本\"}"
}
}

View File

@@ -80,11 +80,15 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
}
// 配置下发
if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.CONFIG.getType())
&& Objects.equals(downstreamReqVO.getIdentifier(), IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) {
&& Objects.equals(downstreamReqVO.getIdentifier(),
IotDeviceMessageIdentifierEnum.CONFIG_SET.getIdentifier())) {
return setDeviceConfig(downstreamReqVO, device, parentDevice);
}
// TODO 芋艿ota 升级
return null;
// OTA 升级
if (Objects.equals(downstreamReqVO.getType(), IotDeviceMessageTypeEnum.OTA.getType())) {
return otaUpgrade(downstreamReqVO, device, parentDevice);
}
throw new IllegalArgumentException("不支持的下行消息类型:" + downstreamReqVO);
}
/**
@@ -97,7 +101,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
*/
@SuppressWarnings("unchecked")
private IotDeviceMessage invokeDeviceService(IotDeviceDownstreamReqVO downstreamReqVO,
IotDeviceDO device, IotDeviceDO parentDevice) {
IotDeviceDO device, IotDeviceDO parentDevice) {
// 1. 参数校验
if (!(downstreamReqVO.getData() instanceof Map<?, ?>)) {
throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型");
@@ -105,9 +109,10 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
// TODO @super【可优化】过滤掉不合法的服务
// 2. 发送请求
String url = String.format( "sys/%s/%s/thing/service/%s",
getProductKey(device, parentDevice), getDeviceName(device, parentDevice), downstreamReqVO.getIdentifier());
IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO()
String url = String.format("sys/%s/%s/thing/service/%s",
getProductKey(device, parentDevice), getDeviceName(device, parentDevice),
downstreamReqVO.getIdentifier());
IotDeviceServiceInvokeReqDTO reqDTO = new IotDeviceServiceInvokeReqDTO()
.setParams((Map<String, Object>) downstreamReqVO.getData());
CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
@@ -144,7 +149,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
// TODO @super【可优化】过滤掉不合法的属性
// 2. 发送请求
String url = String.format( "sys/%s/%s/thing/service/property/set",
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());
@@ -184,7 +189,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
// TODO @super【可优化】过滤掉不合法的属性
// 2. 发送请求
String url = String.format( "sys/%s/%s/thing/service/property/get",
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());
@@ -214,14 +219,14 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
* @param parentDevice 父设备
* @return 下发消息
*/
@SuppressWarnings({"unchecked", "unused"})
@SuppressWarnings({ "unchecked", "unused" })
private IotDeviceMessage 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",
String url = String.format("sys/%s/%s/thing/service/config/set",
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
IotDeviceConfigSetReqDTO reqDTO = new IotDeviceConfigSetReqDTO()
.setConfig(config);
@@ -243,16 +248,54 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
return message;
}
/**
* 设备 OTA 升级
*
* @param downstreamReqVO 下行请求
* @param device 设备
* @param parentDevice 父设备
* @return 下发消息
*/
private IotDeviceMessage otaUpgrade(IotDeviceDownstreamReqVO downstreamReqVO,
IotDeviceDO device, IotDeviceDO parentDevice) {
// 1. 参数校验
if (!(downstreamReqVO.getData() instanceof Map<?, ?> data)) {
throw new ServiceException(BAD_REQUEST.getCode(), "data 不是 Map 类型");
}
// 2. 发送请求
String url = String.format("ota/%s/%s/upgrade",
getProductKey(device, parentDevice), getDeviceName(device, parentDevice));
IotDeviceOtaUpgradeReqDTO reqDTO = IotDeviceOtaUpgradeReqDTO.build(data);
CommonResult<Boolean> result = requestPlugin(url, reqDTO, device);
// 3. 发送设备消息
IotDeviceMessage message = new IotDeviceMessage().setRequestId(reqDTO.getRequestId())
.setType(IotDeviceMessageTypeEnum.OTA.getType())
.setIdentifier(IotDeviceMessageIdentifierEnum.OTA_UPGRADE.getIdentifier())
.setData(downstreamReqVO.getData());
sendDeviceMessage(message, device, result.getCode());
// 4. 如果不成功,抛出异常,提示用户
if (result.isError()) {
log.error("[otaUpgrade][设备({}) OTA 升级失败,请求参数:({}),响应结果:({})]",
device.getDeviceKey(), reqDTO, result);
throw exception(DEVICE_DOWNSTREAM_FAILED, result.getMsg());
}
return message;
}
/**
* 请求插件
*
* @param url URL
* @param reqDTO 请求参数,只需要设置子类的参数!
* @param device 设备
* @param url URL
* @param reqDTO 请求参数,只需要设置子类的参数!
* @param device 设备
* @return 响应结果
*/
@SuppressWarnings({"unchecked", "HttpUrlsUsage"})
private CommonResult<Boolean> requestPlugin(String url, IotDeviceDownstreamAbstractReqDTO reqDTO, IotDeviceDO device) {
@SuppressWarnings({ "unchecked", "HttpUrlsUsage" })
private CommonResult<Boolean> requestPlugin(String url, IotDeviceDownstreamAbstractReqDTO reqDTO,
IotDeviceDO device) {
// 获得设备对应的插件实例
IotPluginInstanceDO pluginInstance = pluginInstanceService.getPluginInstanceByDeviceKey(device.getDeviceKey());
if (pluginInstance == null) {
@@ -266,7 +309,8 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
ResponseEntity<CommonResult<Boolean>> responseEntity;
try {
responseEntity = restTemplate.postForEntity(
String.format("http://%s:%d/%s", pluginInstance.getHostIp(), pluginInstance.getDownstreamPort(), url),
String.format("http://%s:%d/%s", pluginInstance.getHostIp(), pluginInstance.getDownstreamPort(),
url),
reqDTO, (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class);
Assert.isTrue(responseEntity.getStatusCode().is2xxSuccessful(),
"HTTP 状态码不是 2xx而是" + responseEntity.getStatusCode());