固件升级功能只在机场上支持
执行步骤
- 前端上传固件离线升级包
- 机场上报设备固件属性
- 前端点击固件升级,发送请求后,后端下发升级任务,机场进行对应固件升级
- 固件升级是一个job,会通过mqtt通报进度,调用websocket通知前端
代码实现
- 机场的固件版本信息通过thing/product/{device_sn}/state主题向云端上报固件版本号firmware_version。判断是否需要升级
// ChannelName.INBOUND_STATE_DOCK_FIRMWARE_VERSION处理
@Bean
public IntegrationFlow stateDataRouterFlow() {
return IntegrationFlows
.from(ChannelName.INBOUND_STATE)
.transform(Message.class, source -> {
try {
// 将上报的state消息根据消息内容转换
TopicStateRequest response = Common.getObjectMapper().readValue((byte[]) source.getPayload(), new TypeReference<TopicStateRequest>() {});
String topic = String.valueOf(source.getHeaders().get(MqttHeaders.RECEIVED_TOPIC));
String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(), topic.indexOf(STATE_SUF));
return response.setFrom(from)
// 根据消息内容转换
.setData(Common.getObjectMapper().convertValue(response.getData(), getTypeReference(response.getGateway(), response.getData())));
} catch (IOException e) {
throw new CloudSDKException(e);
}
}, null)
// 根据消息内容序列化后将消息提交给不同的channel进行处理
.<TopicStateRequest, StateDataKeyEnum>route(response -> StateDataKeyEnum.find(response.getData().getClass()),
mapping -> Arrays.stream(StateDataKeyEnum.values()).forEach(key -> mapping.channelMapping(key, key.getChannelName())))
.get();
}
// mqtt消息处理
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_DOCK_FIRMWARE_VERSION)
public void dockFirmwareVersionUpdate(TopicStateRequest<DockFirmwareVersion> request, MessageHeaders headers) {
throw new UnsupportedOperationException("dockFirmwareVersionUpdate not implemented");
}
// service 处理
@Override
public void dockFirmwareVersionUpdate(TopicStateRequest<DockFirmwareVersion> request, MessageHeaders headers) {
// 版本号为空直接返回
if (!StringUtils.hasText(request.getData().getFirmwareVersion())) {
return;
}
DeviceDTO device = DeviceDTO.builder()
.deviceSn(request.getFrom())
.firmwareVersion(request.getData().getFirmwareVersion())
.firmwareStatus(request.getData().getNeedCompatibleStatus() ?
DeviceFirmwareStatusEnum.UNKNOWN : DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE)
.build();
// 更新数据库 设备版本和版本状态
boolean isUpd = deviceService.updateDevice(device);
if (!isUpd) {
log.error("Data update of firmware version failed. SN: {}", request.getFrom());
}
}
- 前端通过Post:/devices/{workspace_id}/devices/ota创建固件升级任务
@Override
public HttpResultResponse createDeviceOtaJob(String workspaceId, List<DeviceFirmwareUpgradeDTO> upgradeDTOS) {
// 获取设备版本是否存在
List<OtaCreateDevice> deviceOtaFirmwares = deviceFirmwareService.getDeviceOtaFirmware(workspaceId, upgradeDTOS);
if (deviceOtaFirmwares.isEmpty()) {
return HttpResultResponse.error();
}
// 查询redis设备是否在线
Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(deviceOtaFirmwares.get(0).getSn());
if (deviceOpt.isEmpty()) {
throw new RuntimeException("Device is offline.");
}
DeviceDTO device = deviceOpt.get();
// 网关sn
String gatewaySn = DeviceDomainEnum.DOCK == device.getDomain() ? device.getDeviceSn() : device.getParentSn();
// 检查ota升级条件 机场当前模式是否是IDLE
checkOtaConditions(gatewaySn);
// 创建ota升级任务
TopicServicesResponse<ServicesReplyData<OtaCreateResponse>> response = abstractFirmwareService.otaCreate(
SDKManager.getDeviceSDK(gatewaySn), new OtaCreateRequest().setDevices(deviceOtaFirmwares));
ServicesReplyData<OtaCreateResponse> serviceReply = response.getData();
String bid = response.getBid();
if (!serviceReply.getResult().isSuccess()) {
return HttpResultResponse.error(serviceReply.getResult());
}
// 更新redis中的设备升级状态
deviceOtaFirmwares.forEach(deviceOta -> deviceRedisService.setFirmwareUpgrading(deviceOta.getSn(),
EventsReceiver.<OtaProgress>builder().bid(bid).sn(deviceOta.getSn()).build()));
return HttpResultResponse.success();
}
- 设备上报固件升级进度。机场会通过thing/product/{gateway_sn}/events主题持续上报云端固件升级进度。
// 经过EventsRouter 处理后消息进入ChannelName.INBOUND_EVENTS_OTA_PROGRESS处理
@Override
public TopicEventsResponse<MqttReply> otaProgress(TopicEventsRequest<EventsDataRequest<OtaProgress>> request, MessageHeaders headers) {
String sn = request.getGateway();
EventsReceiver<OtaProgress> eventsReceiver = new EventsReceiver<OtaProgress>()
.setBid(request.getBid())
.setOutput(request.getData().getOutput())
.setResult(request.getData().getResult());
log.info("SN: {}, {} ===> Upgrading progress: {}",
sn, request.getMethod(), eventsReceiver.getOutput().getProgress());
if (!eventsReceiver.getResult().isSuccess()) {
log.error("SN: {}, {} ===> Error: {}", sn, request.getMethod(), eventsReceiver.getResult());
}
// 获取设备
Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(sn);
if (deviceOpt.isEmpty()) {
return null;
}
// 获取当前状态
OtaProgressStatusEnum statusEnum = eventsReceiver.getOutput().getStatus();
DeviceDTO device = deviceOpt.get();
// 网关进度
handleProgress(device.getWorkspaceId(), sn, eventsReceiver, statusEnum.isEnd());
// 飞行器进度
handleProgress(device.getWorkspaceId(), device.getChildDeviceSn(), eventsReceiver, statusEnum.isEnd());
return new TopicEventsResponse<MqttReply>().setData(MqttReply.success());
}
private void handleProgress(String workspaceId, String sn, EventsReceiver<OtaProgress> events, boolean isEnd) {
boolean upgrade = deviceRedisService.getFirmwareUpgradingProgress(sn).isPresent();
if (!upgrade) {
return;
}
if (isEnd) {
// 更新结束 删除缓存
deviceRedisService.delFirmwareUpgrading(sn);
} else {
//更新redis的任务进度
deviceRedisService.setFirmwareUpgrading(sn, events);
}
events.setSn(sn);
// websocket通知进度信息
webSocketMessageService.sendBatch(workspaceId, UserTypeEnum.WEB.getVal(), BizCodeEnum.OTA_PROGRESS.getCode(), events);
}