From a7aaeabc7873a0eafb4a7ecad7f65b018b7a9bc9 Mon Sep 17 00:00:00 2001
From: sean.zhou <sean.zhou@dji.com>
Date: Fri, 24 Feb 2023 19:31:23 +0800
Subject: [PATCH] What's new? 1. Add license for dock. 2. Modify the logic corresponding to the firmware file and device type. 3. Add multiple mqtt clients options. 4. Modify the structure of the interface for obtaining the device list. 5. Fixed some issues.
---
src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java | 927 +++++++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 726 insertions(+), 201 deletions(-)
diff --git a/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java b/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java
index 80e34df..6677ca8 100644
--- a/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java
+++ b/src/main/java/com/dji/sample/manage/service/impl/DeviceServiceImpl.java
@@ -1,44 +1,50 @@
package com.dji.sample.manage.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.dji.sample.component.mqtt.model.CommonTopicResponse;
-import com.dji.sample.component.mqtt.model.TopicStateReceiver;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dji.sample.common.error.CommonErrorEnum;
+import com.dji.sample.common.model.Pagination;
+import com.dji.sample.common.model.PaginationData;
+import com.dji.sample.common.model.ResponseResult;
+import com.dji.sample.component.mqtt.model.*;
import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.component.mqtt.service.IMqttTopicService;
+import com.dji.sample.component.redis.RedisConst;
+import com.dji.sample.component.redis.RedisOpsUtils;
import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession;
import com.dji.sample.component.websocket.model.BizCodeEnum;
import com.dji.sample.component.websocket.model.CustomWebSocketMessage;
-import com.dji.sample.component.websocket.model.WebSocketManager;
import com.dji.sample.component.websocket.service.ISendMessageService;
+import com.dji.sample.component.websocket.service.IWebSocketManageService;
import com.dji.sample.manage.dao.IDeviceMapper;
import com.dji.sample.manage.model.dto.*;
import com.dji.sample.manage.model.entity.DeviceEntity;
-import com.dji.sample.manage.model.enums.DeviceDomainEnum;
-import com.dji.sample.manage.model.enums.IconUrlEnum;
-import com.dji.sample.manage.model.enums.UserTypeEnum;
+import com.dji.sample.manage.model.enums.*;
+import com.dji.sample.manage.model.param.DeviceOtaCreateParam;
import com.dji.sample.manage.model.param.DeviceQueryParam;
-import com.dji.sample.manage.model.receiver.StatusGatewayReceiver;
-import com.dji.sample.manage.model.receiver.StatusSubDeviceReceiver;
-import com.dji.sample.manage.service.IDeviceDictionaryService;
-import com.dji.sample.manage.service.IDevicePayloadService;
-import com.dji.sample.manage.service.IDeviceService;
-import com.dji.sample.manage.service.IWorkspaceService;
-import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.dji.sample.manage.model.receiver.*;
+import com.dji.sample.manage.service.*;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.integration.mqtt.support.MqttHeaders;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -77,106 +83,146 @@
private ISendMessageService sendMessageService;
@Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private IWebSocketManageService webSocketManageService;
+
+ @Autowired
+ private IDeviceFirmwareService deviceFirmwareService;
+
+ @Autowired
@Qualifier("gatewayOSDServiceImpl")
- private AbstractTSAService tsaService;
+ private ITSAService tsaService;
+
+ private static final List<String> INIT_TOPICS_SUFFIX = List.of(
+ OSD_SUF, STATE_SUF, SERVICES_SUF + _REPLY_SUF, EVENTS_SUF, PROPERTY_SUF + SET_SUF + _REPLY_SUF);
@Override
- public Boolean deviceOffline(String gatewaySn) {
- List<DeviceDTO> gatewaysList = this.getDevicesByParams(
- DeviceQueryParam.builder()
- .deviceSn(gatewaySn)
- .build());
+ public Boolean deviceOffline(StatusGatewayReceiver gateway) {
+ String gatewaySn = gateway.getSn();
+ this.subscribeTopicOnline(gatewaySn);
- // If no information about this gateway device exists in the database, the drone is considered to be offline.
- if (gatewaysList.isEmpty()) {
- log.debug("The drone is already offline.");
+ // Only the remote controller is logged in and the aircraft is not connected.
+ String key = RedisConst.DEVICE_ONLINE_PREFIX + gatewaySn;
+
+ boolean exist = RedisOpsUtils.checkExist(key);
+ if (!exist) {
+ Optional<DeviceDTO> gatewayOpt = this.getDeviceBySn(gatewaySn);
+ if (gatewayOpt.isPresent()) {
+ DeviceDTO value = gatewayOpt.get();
+ RedisOpsUtils.setWithExpire(key, value, RedisConst.DEVICE_ALIVE_SECOND);
+ this.pushDeviceOnlineTopo(value.getWorkspaceId(), gatewaySn, gatewaySn);
+ return true;
+ }
+
+ // When connecting for the first time
+ DeviceEntity gatewayDevice = deviceGatewayConvertToDeviceEntity(gateway);
+ return onlineSaveDevice(gatewayDevice, null).isPresent();
+ }
+
+ DeviceDTO deviceDTO = (DeviceDTO) (RedisOpsUtils.get(key));
+ String deviceSn = deviceDTO.getChildDeviceSn();
+ if (!StringUtils.hasText(deviceSn)) {
return true;
}
- // Handle the drone connected to the gateway device offline.
- return this.subDeviceOffline(gatewaysList.get(0).getChildDeviceSn());
+
+ return subDeviceOffline(deviceSn);
}
@Override
public Boolean subDeviceOffline(String deviceSn) {
+
+ // If no information about this device exists in the cache, the drone is considered to be offline.
+ String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn;
+ if (!RedisOpsUtils.checkExist(key) || RedisOpsUtils.getExpire(key) <= 0) {
+ log.debug("The drone is already offline.");
+ return true;
+ }
+ DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(key);
// Cancel drone-related subscriptions.
this.unsubscribeTopicOffline(deviceSn);
- List<DeviceDTO> devicesList = this.getDevicesByParams(
- DeviceQueryParam.builder()
- .deviceSn(deviceSn)
- .build());
+ payloadService.deletePayloadsByDeviceSn(new ArrayList<>(List.of(deviceSn)));
+ // Publish the latest device topology information in the current workspace.
+ this.pushDeviceOfflineTopo(device.getWorkspaceId(), deviceSn);
- // If no information about this drone exists in the database, the drone is considered to be offline.
- if (devicesList.isEmpty()) {
- log.debug("{} is already offline.", deviceSn);
- return true;
- }
-
- List<String> ids = devicesList.stream()
- .map(DeviceDTO::getDeviceSn)
- .collect(Collectors.toList());
-
- // Delete all data related to the drone.
- boolean isDel = this.delDeviceByDeviceSns(ids);
- payloadService.deletePayloadsByDeviceSn(ids);
-
- log.debug("{} offline status: {}.", deviceSn, isDel);
- return isDel;
+ RedisOpsUtils.del(key);
+ RedisOpsUtils.del(RedisConst.OSD_PREFIX + device.getDeviceSn());
+ RedisOpsUtils.del(RedisConst.HMS_PREFIX + device.getDeviceSn());
+ log.debug("{} offline.", deviceSn);
+ return true;
}
@Override
public Boolean deviceOnline(StatusGatewayReceiver deviceGateway) {
String deviceSn = deviceGateway.getSubDevices().get(0).getSn();
+ String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn;
+ // change log: Use redis instead of
+ long time = RedisOpsUtils.getExpire(key);
+ long gatewayTime = RedisOpsUtils.getExpire(RedisConst.DEVICE_ONLINE_PREFIX + deviceGateway.getSn());
- List<DeviceDTO> devicesList = this.getDevicesByParams(
- DeviceQueryParam.builder()
- .deviceSn(deviceSn)
- .build());
- // If the information about this drone exists in the database, the drone is considered to be online.
- if (!devicesList.isEmpty()) {
+ if (time > 0 && gatewayTime > 0) {
+ RedisOpsUtils.expireKey(key, RedisConst.DEVICE_ALIVE_SECOND);
+ DeviceDTO device = DeviceDTO.builder().loginTime(LocalDateTime.now()).deviceSn(deviceSn).build();
+ DeviceDTO gateway = DeviceDTO.builder()
+ .loginTime(LocalDateTime.now())
+ .deviceSn(deviceGateway.getSn())
+ .childDeviceSn(deviceSn).build();
+ this.updateDevice(gateway);
+ this.updateDevice(device);
+ String workspaceId = ((DeviceDTO)(RedisOpsUtils.get(key))).getWorkspaceId();
+ if (StringUtils.hasText(workspaceId)) {
+ this.subscribeTopicOnline(deviceSn);
+ this.subscribeTopicOnline(deviceGateway.getSn());
+ }
log.warn("{} is already online.", deviceSn);
- // Subscribe to topic related to drone and gateway devices.
- this.subscribeTopicOnline(deviceGateway.getSn());
- this.subscribeTopicOnline(deviceSn);
return true;
}
- // Delete the gateway device information that was previously bound to the drone.
- this.delDeviceByDeviceSns(
- this.getDevicesByParams(
- DeviceQueryParam.builder()
- .childSn(deviceSn)
- .build())
- .stream()
- .map(DeviceDTO::getDeviceSn)
- .collect(Collectors.toList()));
+ List<DeviceDTO> gatewaysList = this.getDevicesByParams(
+ DeviceQueryParam.builder()
+ .childSn(deviceSn)
+ .build());
+ gatewaysList.stream()
+ .filter(gateway -> !gateway.getDeviceSn().equals(deviceGateway.getSn()))
+ .findAny()
+ .ifPresent(gateway -> {
+ gateway.setChildDeviceSn("");
+ this.updateDevice(gateway);
+ });
DeviceEntity gateway = deviceGatewayConvertToDeviceEntity(deviceGateway);
- gateway.setWorkspaceId(WorkspaceDTO.DEFAULT_WORKSPACE_ID);
- // Set the icon of the gateway device displayed in the pilot's map, required in the TSA module.
- gateway.setUrlNormal(IconUrlEnum.NORMAL_PERSON.getUrl());
- // Set the icon of the gateway device displayed in the pilot's map when it is selected, required in the TSA module.
- gateway.setUrlSelect(IconUrlEnum.SELECT_PERSON.getUrl());
+ Optional<DeviceEntity> gatewayEntityOpt = onlineSaveDevice(gateway, deviceSn);
+ if (gatewayEntityOpt.isEmpty()) {
+ log.error("Failed to go online, please check the status data or code logic.");
+ return false;
+ }
DeviceEntity subDevice = subDeviceConvertToDeviceEntity(deviceGateway.getSubDevices().get(0));
- subDevice.setWorkspaceId(WorkspaceDTO.DEFAULT_WORKSPACE_ID);
- // Set the icon of the drone device displayed in the pilot's map, required in the TSA module.
- subDevice.setUrlSelect(IconUrlEnum.SELECT_EQUIPMENT.getUrl());
- // Set the icon of the drone device displayed in the pilot's map when it is selected, required in the TSA module.
- subDevice.setUrlNormal(IconUrlEnum.NORMAL_EQUIPMENT.getUrl());
-
- gateway.setChildSn(subDevice.getDeviceSn());
-
- boolean isSave = this.saveDevice(gateway) > 0 && this.saveDevice(subDevice) > 0;
-
- log.debug(subDevice.getDeviceSn() + " online status: {}", isSave);
- if (isSave) {
- // Subscribe to topic related to drone and gateway devices.
- this.subscribeTopicOnline(subDevice.getDeviceSn());
- this.subscribeTopicOnline(gateway.getDeviceSn());
-
+ Optional<DeviceEntity> subDeviceEntityOpt = onlineSaveDevice(subDevice, null);
+ if (subDeviceEntityOpt.isEmpty()) {
+ log.error("Failed to go online, please check the status data or code logic.");
+ return false;
}
- return isSave;
+
+ subDevice = subDeviceEntityOpt.get();
+ gateway = gatewayEntityOpt.get();
+
+ // dock go online
+ if (DeviceDomainEnum.DOCK.getVal() == deviceGateway.getDomain() && !subDevice.getBoundStatus()) {
+ // Directly bind the drone of the dock to the same workspace as the dock.
+ bindDevice(DeviceDTO.builder().deviceSn(deviceSn).workspaceId(gateway.getWorkspaceId()).build());
+ subDevice.setWorkspaceId(gateway.getWorkspaceId());
+ }
+
+ // Subscribe to topic related to drone devices.
+ this.subscribeTopicOnline(deviceGateway.getSn());
+ this.subscribeTopicOnline(deviceSn);
+ this.pushDeviceOnlineTopo(subDevice.getWorkspaceId(), deviceGateway.getSn(), deviceSn);
+
+ log.debug("{} online.", subDevice.getDeviceSn());
+ return true;
}
@Override
@@ -188,16 +234,14 @@
return;
}
}
- topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + OSD_SUF);
- topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + STATE_SUF);
- topicService.subscribe(THING_MODEL_PRE + PRODUCT + sn + SERVICES_SUF + _REPLY_SUF);
+ String prefix = THING_MODEL_PRE + PRODUCT + sn;
+ INIT_TOPICS_SUFFIX.forEach(suffix -> topicService.subscribe(prefix + suffix));
}
@Override
public void unsubscribeTopicOffline(String sn) {
- topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + OSD_SUF);
- topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + STATE_SUF);
- topicService.unsubscribe(THING_MODEL_PRE + PRODUCT + sn + SERVICES_SUF + _REPLY_SUF);
+ String prefix = THING_MODEL_PRE + PRODUCT + sn;
+ INIT_TOPICS_SUFFIX.forEach(suffix -> topicService.unsubscribe(prefix + suffix));
}
@Override
@@ -232,17 +276,21 @@
return mapper.selectList(
new LambdaQueryWrapper<DeviceEntity>()
.eq(StringUtils.hasText(param.getDeviceSn()),
- DeviceEntity::getDeviceSn, param.getDeviceSn())
+ DeviceEntity::getDeviceSn, param.getDeviceSn())
.eq(param.getDeviceType() != null,
DeviceEntity::getDeviceType, param.getDeviceType())
.eq(param.getSubType() != null,
DeviceEntity::getSubType, param.getSubType())
.eq(StringUtils.hasText(param.getChildSn()),
DeviceEntity::getChildSn, param.getChildSn())
- .eq(param.getDomain() != null,
- DeviceEntity::getDomain, param.getDomain())
+ .and(!CollectionUtils.isEmpty(param.getDomains()), wrapper -> {
+ for (Integer domain : param.getDomains()) {
+ wrapper.eq(DeviceEntity::getDomain, domain).or();
+ }
+ })
.eq(StringUtils.hasText(param.getWorkspaceId()),
DeviceEntity::getWorkspaceId, param.getWorkspaceId())
+ .eq(param.getBoundStatus() != null, DeviceEntity::getBoundStatus, param.getBoundStatus())
.orderBy(param.isOrderBy(),
param.isAsc(), DeviceEntity::getId))
.stream()
@@ -255,38 +303,40 @@
List<DeviceDTO> devicesList = this.getDevicesByParams(
DeviceQueryParam.builder()
.workspaceId(workspaceId)
- .domain(DeviceDomainEnum.SUB_DEVICE.getVal())
+ .domains(List.of(DeviceDomainEnum.GATEWAY.getVal(), DeviceDomainEnum.DOCK.getVal()))
.build());
- devicesList.forEach(device -> {
- this.spliceDeviceTopo(device);
- device.setWorkspaceId(workspaceId);
+ devicesList.stream()
+ .filter(gateway -> DeviceDomainEnum.DOCK.getVal() == gateway.getDomain() ||
+ RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + gateway.getDeviceSn()))
+ .forEach(this::spliceDeviceTopo);
- });
return devicesList;
}
@Override
- public void spliceDeviceTopo(DeviceDTO device) {
+ public void spliceDeviceTopo(DeviceDTO gateway) {
- // remote controller
- List<DeviceDTO> gatewaysList = getDevicesByParams(
- DeviceQueryParam.builder()
- .childSn(device.getDeviceSn())
- .build());
+ gateway.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + gateway.getDeviceSn()));
+
+ // sub device
+ if (!StringUtils.hasText(gateway.getChildDeviceSn())) {
+ return;
+ }
+
+ DeviceDTO subDevice = getDevicesByParams(DeviceQueryParam.builder().deviceSn(gateway.getChildDeviceSn()).build()).get(0);
+ subDevice.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + subDevice.getDeviceSn()));
+ gateway.setChildren(subDevice);
// payloads
- List<DevicePayloadDTO> payloadsList = payloadService
- .getDevicePayloadEntitiesByDeviceSn(device.getDeviceSn());
-
-
- device.setGatewaysList(gatewaysList);
- device.setPayloadsList(payloadsList);
-
+ subDevice.setPayloadsList(payloadService.getDevicePayloadEntitiesByDeviceSn(gateway.getChildDeviceSn()));
}
@Override
public Optional<TopologyDeviceDTO> getDeviceTopoForPilot(String sn) {
+ if (sn.isBlank()) {
+ return Optional.empty();
+ }
List<TopologyDeviceDTO> topologyDeviceList = this.getDevicesByParams(
DeviceQueryParam.builder()
.deviceSn(sn)
@@ -301,7 +351,7 @@
}
@Override
- public void pushDeviceOnlineTopo(Collection<ConcurrentWebSocketSession> sessions, String sn) {
+ public void pushDeviceOnlineTopo(Collection<ConcurrentWebSocketSession> sessions, String sn, String gatewaySn) {
CustomWebSocketMessage<TopologyDeviceDTO> pilotMessage =
CustomWebSocketMessage.<TopologyDeviceDTO>builder()
@@ -312,6 +362,9 @@
this.getDeviceTopoForPilot(sn)
.ifPresent(pilotMessage::setData);
+ boolean exist = RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn);
+ pilotMessage.getData().setOnlineStatus(exist);
+ pilotMessage.getData().setGatewaySn(gatewaySn.equals(sn) ? "" : gatewaySn);
sendMessageService.sendBatch(sessions, pilotMessage);
}
@@ -321,91 +374,92 @@
TopologyDeviceDTO.TopologyDeviceDTOBuilder builder = TopologyDeviceDTO.builder();
if (device != null) {
- String domain = String.valueOf(DeviceDomainEnum.getVal(device.getDomain()));
- String subType = String.valueOf(device.getSubType());
- String type = String.valueOf(device.getType());
-
builder.sn(device.getDeviceSn())
- .deviceCallsign(device.getDeviceName())
+ .deviceCallsign(device.getNickname())
.deviceModel(DeviceModelDTO.builder()
- .domain(domain)
- .subType(subType)
- .type(type)
- .key(domain + "-" + type + "-" + subType)
+ .domain(String.valueOf(device.getDomain()))
+ .subType(String.valueOf(device.getSubType()))
+ .type(String.valueOf(device.getType()))
+ .key(device.getDomain() + "-" + device.getType() + "-" + device.getSubType())
.build())
.iconUrls(device.getIconUrl())
+ .onlineStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn()))
+ .boundStatus(device.getBoundStatus())
+ .model(device.getDeviceName())
+ .userId(device.getUserId())
+ .domain(device.getDomain())
.build();
}
return builder.build();
}
@Override
- public void pushDeviceOnlineTopo(String workspaceId, String deviceSn, String gatewaySn) {
+ public void pushDeviceOnlineTopo(String workspaceId, String gatewaySn, String deviceSn) {
- // All connected accounts on the pilot side of this workspace.
- Collection<ConcurrentWebSocketSession> pilotSessions = WebSocketManager
- .getValueWithWorkspaceAndUserType(
- workspaceId, UserTypeEnum.PILOT.getVal());
+ // All connected accounts in this workspace.
+ Collection<ConcurrentWebSocketSession> allSessions = webSocketManageService.getValueWithWorkspace(workspaceId);
- this.pushDeviceOnlineTopo(pilotSessions, deviceSn);
- this.pushDeviceOnlineTopo(pilotSessions, gatewaySn);
- this.pushDeviceUpdateTopo(pilotSessions, deviceSn);
- this.pushDeviceUpdateTopo(pilotSessions, gatewaySn);
- }
-
- @Override
- public void pushDeviceOfflineTopo(String workspaceId, String gatewaySn) {
- // All connected accounts on the pilot side of this workspace.
- Collection<ConcurrentWebSocketSession> pilotSessions = WebSocketManager
- .getValueWithWorkspaceAndUserType(
- workspaceId, UserTypeEnum.PILOT.getVal());
-
-
- List<DeviceDTO> gatewaysList = this.getDevicesByParams(
- DeviceQueryParam.builder()
- .deviceSn(gatewaySn)
- .build());
-
- if (!gatewaysList.isEmpty()) {
- String deviceSn = gatewaysList.get(0).getChildDeviceSn();
- this.pushDeviceOfflineTopo(pilotSessions, deviceSn);
- this.pushDeviceUpdateTopo(pilotSessions, deviceSn);
+ if (!gatewaySn.equals(deviceSn)) {
+ this.pushDeviceOnlineTopo(allSessions, deviceSn, gatewaySn);
+ this.pushDeviceUpdateTopo(allSessions, deviceSn);
}
-
- this.pushDeviceOfflineTopo(pilotSessions, gatewaySn);
- this.pushDeviceUpdateTopo(pilotSessions, gatewaySn);
+ this.pushDeviceOnlineTopo(allSessions, gatewaySn, gatewaySn);
+ this.pushDeviceUpdateTopo(allSessions, gatewaySn);
}
@Override
- public void handleOSD(String topic, byte[] payload) {
- TopicStateReceiver receiver;
+ public void pushDeviceOfflineTopo(String workspaceId, String sn) {
+ // All connected accounts of this workspace.
+ Collection<ConcurrentWebSocketSession> allSessions = webSocketManageService
+ .getValueWithWorkspace(workspaceId);
+
+ this.pushDeviceOfflineTopo(allSessions, sn);
+ this.pushDeviceUpdateTopo(allSessions, sn);
+ }
+
+ @Override
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_OSD)
+ public void handleOSD(Message<?> message) {
+ String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString();
+ byte[] payload = (byte[])message.getPayload();
+ CommonTopicReceiver receiver;
try {
String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(),
topic.indexOf(OSD_SUF));
- List<DeviceDTO> deviceList = this.getDevicesByParams(
- DeviceQueryParam.builder().deviceSn(from).build());
- if (deviceList.isEmpty()) {
- return;
+ // Real-time update of device status in memory
+ RedisOpsUtils.expireKey(RedisConst.DEVICE_ONLINE_PREFIX + from, RedisConst.DEVICE_ALIVE_SECOND);
+
+ DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + from);
+
+ if (device == null) {
+ Optional<DeviceDTO> deviceOpt = this.getDeviceBySn(from);
+ if (deviceOpt.isEmpty()) {
+ return;
+ }
+ device = deviceOpt.get();
+ if (!StringUtils.hasText(device.getWorkspaceId())) {
+ this.unsubscribeTopicOffline(from);
+ return;
+ }
+ RedisOpsUtils.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + from, device,
+ RedisConst.DEVICE_ALIVE_SECOND);
+ this.subscribeTopicOnline(from);
}
- ObjectMapper mapper = new ObjectMapper();
- mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ receiver = objectMapper.readValue(payload, CommonTopicReceiver.class);
- receiver = mapper.readValue(payload, TopicStateReceiver.class);
+ CustomWebSocketMessage<TelemetryDTO> wsMessage = CustomWebSocketMessage.<TelemetryDTO>builder()
+ .timestamp(System.currentTimeMillis())
+ .data(TelemetryDTO.builder().sn(from).build())
+ .build();
- CustomWebSocketMessage wsMessage = CustomWebSocketMessage.builder()
- .timestamp(System.currentTimeMillis()).build();
-
- JsonNode hostNode = mapper.readTree(payload).findPath("data");
-
- String workspaceId = deviceList.get(0).getWorkspaceId();
- Collection<ConcurrentWebSocketSession> webSessions = WebSocketManager
+ Collection<ConcurrentWebSocketSession> webSessions = webSocketManageService
.getValueWithWorkspaceAndUserType(
- workspaceId, UserTypeEnum.WEB.getVal());
+ device.getWorkspaceId(), UserTypeEnum.WEB.getVal());
- tsaService.handleOSD(receiver, from, workspaceId, hostNode, webSessions, wsMessage);
+ tsaService.handleOSD(receiver, device, webSessions, wsMessage);
} catch (IOException e) {
e.printStackTrace();
@@ -451,17 +505,20 @@
* @param entity
* @return
*/
- private Integer saveDevice(DeviceEntity entity) {
+ private Optional<DeviceEntity> saveDevice(DeviceEntity entity) {
DeviceEntity deviceEntity = mapper.selectOne(
new LambdaQueryWrapper<DeviceEntity>()
.eq(DeviceEntity::getDeviceSn, entity.getDeviceSn()));
// Update the information directly if the device already exists.
if (deviceEntity != null) {
+ if (deviceEntity.getDeviceName().equals(entity.getNickname())) {
+ entity.setNickname(null);
+ }
entity.setId(deviceEntity.getId());
mapper.updateById(entity);
- return deviceEntity.getId();
+ return Optional.of(deviceEntity);
}
- return mapper.insert(entity) > 0 ? entity.getId() : 0;
+ return mapper.insert(entity) > 0 ? Optional.of(entity) : Optional.empty();
}
/**
@@ -477,19 +534,22 @@
// Query the model information of this gateway device.
Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService
- .getOneDictionaryInfoByDomainTypeSubType(gateway.getDomain(),
+ .getOneDictionaryInfoByTypeSubType(Objects.nonNull(gateway.getDomain()) ?
+ gateway.getDomain() : DeviceDomainEnum.GATEWAY.getVal(),
gateway.getType(), gateway.getSubType());
dictionaryOpt.ifPresent(entity ->
builder.deviceName(entity.getDeviceName())
+ .nickname(entity.getDeviceName())
.deviceDesc(entity.getDeviceDesc()));
return builder
.deviceSn(gateway.getSn())
- .domain(gateway.getDomain())
.subType(gateway.getSubType())
.deviceType(gateway.getType())
.version(gateway.getVersion())
+ .domain(gateway.getDomain() != null ?
+ gateway.getDomain() : DeviceDomainEnum.GATEWAY.getVal())
.build();
}
@@ -506,48 +566,513 @@
// Query the model information of this drone device.
Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService
- .getOneDictionaryInfoByDomainTypeSubType(DeviceDomainEnum.SUB_DEVICE.getVal(),
- device.getType(), device.getSubType());
+ .getOneDictionaryInfoByTypeSubType(DeviceDomainEnum.SUB_DEVICE.getVal(), device.getType(), device.getSubType());
dictionaryOpt.ifPresent(dictionary ->
builder.deviceName(dictionary.getDeviceName())
+ .nickname(dictionary.getDeviceName())
.deviceDesc(dictionary.getDeviceDesc()));
return builder
.deviceSn(device.getSn())
.deviceType(device.getType())
.subType(device.getSubType())
- .domain(DeviceDomainEnum.SUB_DEVICE.getVal())
.version(device.getVersion())
.deviceIndex(device.getIndex())
+ .domain(DeviceDomainEnum.SUB_DEVICE.getVal())
.build();
}
/**
- * Convert database entity objects into device data transfer object.
+ * Convert database entity object into device data transfer object.
* @param entity
* @return
*/
private DeviceDTO deviceEntityConvertToDTO(DeviceEntity entity) {
- DeviceDTO.DeviceDTOBuilder builder = DeviceDTO.builder();
-
- if (entity != null) {
- builder.deviceSn(entity.getDeviceSn())
- .childDeviceSn(entity.getChildSn())
- .deviceName(entity.getDeviceName())
- .deviceDesc(entity.getDeviceDesc())
- .deviceIndex(entity.getDeviceIndex())
- .workspaceId(entity.getWorkspaceId())
- .type(entity.getDeviceType())
- .subType(entity.getSubType())
- .domain(DeviceDomainEnum.getDesc(entity.getDomain()))
- .iconUrl(IconUrlDTO.builder()
- .normalUrl(entity.getUrlNormal())
- .selectUrl(entity.getUrlSelect())
- .build())
- .build();
+ if (entity == null) {
+ return null;
}
- return builder.build();
+ DeviceDTO.DeviceDTOBuilder deviceDTOBuilder = DeviceDTO.builder()
+ .deviceSn(entity.getDeviceSn())
+ .childDeviceSn(entity.getChildSn())
+ .deviceName(entity.getDeviceName())
+ .deviceDesc(entity.getDeviceDesc())
+ .deviceIndex(entity.getDeviceIndex())
+ .workspaceId(entity.getWorkspaceId())
+ .type(entity.getDeviceType())
+ .subType(entity.getSubType())
+ .domain(entity.getDomain())
+ .iconUrl(IconUrlDTO.builder()
+ .normalUrl(entity.getUrlNormal())
+ .selectUrl(entity.getUrlSelect())
+ .build())
+ .boundStatus(entity.getBoundStatus())
+ .loginTime(entity.getLoginTime() != null ?
+ LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getLoginTime()), ZoneId.systemDefault())
+ : null)
+ .boundTime(entity.getBoundTime() != null ?
+ LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getBoundTime()), ZoneId.systemDefault())
+ : null)
+ .nickname(entity.getNickname())
+ .firmwareVersion(entity.getFirmwareVersion())
+ .workspaceName(entity.getWorkspaceId() != null ?
+ workspaceService.getWorkspaceByWorkspaceId(entity.getWorkspaceId())
+ .map(WorkspaceDTO::getWorkspaceName).orElse("") : "");
+
+ if (!StringUtils.hasText(entity.getFirmwareVersion())) {
+ return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.NOT_UPGRADE.getVal()).build();
+ }
+ // Query whether the device is updating firmware.
+ Object progress = RedisOpsUtils.get(RedisConst.FIRMWARE_UPGRADING_PREFIX + entity.getDeviceSn());
+ if (Objects.nonNull(progress)) {
+ return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.UPGRADING.getVal()).firmwareProgress((int)progress).build();
+ }
+
+ // First query the latest firmware version of the device model and compare it with the current firmware version
+ // to see if it needs to be upgraded.
+ Optional<DeviceFirmwareNoteDTO> firmwareReleaseNoteOpt = deviceFirmwareService.getLatestFirmwareReleaseNote(entity.getDeviceName());
+ if (firmwareReleaseNoteOpt.isPresent()) {
+ DeviceFirmwareNoteDTO firmwareNoteDTO = firmwareReleaseNoteOpt.get();
+ if (firmwareNoteDTO.getProductVersion().equals(entity.getFirmwareVersion())) {
+ return deviceDTOBuilder.firmwareStatus(entity.getCompatibleStatus() ?
+ DeviceFirmwareStatusEnum.NOT_UPGRADE.getVal() :
+ DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE.getVal()).build();
+ }
+
+ return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.NORMAL_UPGRADE.getVal()).build();
+ }
+ return deviceDTOBuilder.firmwareStatus(DeviceFirmwareStatusEnum.NOT_UPGRADE.getVal()).build();
}
+ @Override
+ public Boolean updateDevice(DeviceDTO deviceDTO) {
+ int update = mapper.update(this.deviceDTO2Entity(deviceDTO),
+ new LambdaUpdateWrapper<DeviceEntity>().eq(DeviceEntity::getDeviceSn, deviceDTO.getDeviceSn()));
+ return update > 0;
+ }
+
+ @Override
+ public Boolean bindDevice(DeviceDTO device) {
+ device.setBoundStatus(true);
+ device.setBoundTime(LocalDateTime.now());
+
+ boolean isUpd = this.saveDevice(this.deviceDTO2Entity(device)).isPresent();
+ if (!isUpd) {
+ return false;
+ }
+
+ String key = RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn();
+ if (!RedisOpsUtils.checkExist(key)) {
+ return false;
+ }
+
+ DeviceDTO redisDevice = (DeviceDTO)RedisOpsUtils.get(key);
+ redisDevice.setWorkspaceId(device.getWorkspaceId());
+ RedisOpsUtils.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND);
+
+ if (DeviceDomainEnum.GATEWAY.getVal() == redisDevice.getDomain()) {
+ this.pushDeviceOnlineTopo(webSocketManageService.getValueWithWorkspace(device.getWorkspaceId()),
+ device.getDeviceSn(), device.getDeviceSn());
+ }
+ if (DeviceDomainEnum.SUB_DEVICE.getVal() == redisDevice.getDomain()) {
+ DeviceDTO subDevice = this.getDevicesByParams(DeviceQueryParam.builder()
+ .childSn(device.getChildDeviceSn())
+ .build()).get(0);
+ this.pushDeviceOnlineTopo(webSocketManageService.getValueWithWorkspace(device.getWorkspaceId()),
+ device.getDeviceSn(), subDevice.getDeviceSn());
+ }
+ this.subscribeTopicOnline(device.getDeviceSn());
+
+ return true;
+ }
+
+ @Override
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_AIRPORT_BIND_STATUS, outputChannel = ChannelName.OUTBOUND)
+ public void bindStatus(CommonTopicReceiver receiver, MessageHeaders headers) {
+ List<Map<String, String>> data = ((Map<String, List<Map<String, String>>>) receiver.getData()).get(MapKeyConst.DEVICES);
+ String dockSn = data.get(0).get(MapKeyConst.SN);
+ String droneSn = data.size() > 1 ? data.get(1).get(MapKeyConst.SN) : "null";
+
+ Optional<DeviceDTO> dockOpt = this.getDeviceBySn(dockSn);
+ Optional<DeviceDTO> droneOpt = this.getDeviceBySn(droneSn);
+
+ List<BindStatusReceiver> bindStatusResult = new ArrayList<>();
+ bindStatusResult.add(dockOpt.isPresent() ? this.dto2BindStatus(dockOpt.get()) :
+ BindStatusReceiver.builder().sn(dockSn).isDeviceBindOrganization(false).build());
+ if (data.size() > 1) {
+ bindStatusResult.add(droneOpt.isPresent() ? this.dto2BindStatus(droneOpt.get()) :
+ BindStatusReceiver.builder().sn(droneSn).isDeviceBindOrganization(false).build());
+ }
+
+ messageSender.publish(headers.get(MqttHeaders.RECEIVED_TOPIC) + _REPLY_SUF,
+ CommonTopicResponse.builder()
+ .tid(receiver.getTid())
+ .bid(receiver.getBid())
+ .timestamp(System.currentTimeMillis())
+ .method(RequestsMethodEnum.AIRPORT_BIND_STATUS.getMethod())
+ .data(RequestsReply.success(Map.of(MapKeyConst.BIND_STATUS, bindStatusResult)))
+ .build());
+
+ }
+
+ @Override
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND)
+ public void bindDevice(CommonTopicReceiver receiver, MessageHeaders headers) {
+ Map<String, List<BindDeviceReceiver>> data = objectMapper.convertValue(receiver.getData(),
+ new TypeReference<Map<String, List<BindDeviceReceiver>>>() {});
+ List<BindDeviceReceiver> devices = data.get(MapKeyConst.BIND_DEVICES);
+ BindDeviceReceiver dock = null;
+ BindDeviceReceiver drone = null;
+ for (BindDeviceReceiver device : devices) {
+ int val = Integer.parseInt(device.getDeviceModelKey().split("-")[0]);
+ if (val == DeviceDomainEnum.DOCK.getVal()) {
+ dock = device;
+ }
+ if (val == DeviceDomainEnum.SUB_DEVICE.getVal()) {
+ drone = device;
+ }
+ }
+
+ assert dock != null;
+
+ Optional<DeviceEntity> dockEntityOpt = this.bindDevice2Entity(DeviceDomainEnum.DOCK.getVal(), dock);
+ Optional<DeviceEntity> droneEntityOpt = this.bindDevice2Entity(DeviceDomainEnum.SUB_DEVICE.getVal(), drone);
+
+ List<ErrorInfoReply> bindResult = new ArrayList<>();
+
+ droneEntityOpt.ifPresent(droneEntity -> {
+ dockEntityOpt.get().setChildSn(droneEntity.getDeviceSn());
+ Optional<DeviceEntity> deviceEntityOpt = this.saveDevice(droneEntity);
+ bindResult.add(
+ deviceEntityOpt.isPresent() ?
+ ErrorInfoReply.success(droneEntity.getDeviceSn()) :
+ new ErrorInfoReply(droneEntity.getDeviceSn(),
+ CommonErrorEnum.DEVICE_BINDING_FAILED.getErrorCode())
+ );
+ });
+ Optional<DeviceEntity> dockOpt = this.saveDevice(dockEntityOpt.get());
+
+ bindResult.add(dockOpt.isPresent() ?
+ ErrorInfoReply.success(dock.getSn()) :
+ new ErrorInfoReply(dock.getSn(),
+ CommonErrorEnum.DEVICE_BINDING_FAILED.getErrorCode()));
+
+ String topic = headers.get(MqttHeaders.RECEIVED_TOPIC) + _REPLY_SUF;
+ messageSender.publish(topic,
+ CommonTopicResponse.builder()
+ .tid(receiver.getTid())
+ .bid(receiver.getBid())
+ .method(RequestsMethodEnum.AIRPORT_ORGANIZATION_BIND.getMethod())
+ .timestamp(System.currentTimeMillis())
+ .data(RequestsReply.success(Map.of(MapKeyConst.ERR_INFOS, bindResult)))
+ .build());
+
+ }
+
+ @Override
+ public PaginationData<DeviceDTO> getBoundDevicesWithDomain(String workspaceId, Long page,
+ Long pageSize, Integer domain) {
+
+ Page<DeviceEntity> pagination = mapper.selectPage(new Page<>(page, pageSize),
+ new LambdaQueryWrapper<DeviceEntity>()
+ .eq(DeviceEntity::getDomain, domain)
+ .eq(DeviceEntity::getWorkspaceId, workspaceId)
+ .eq(DeviceEntity::getBoundStatus, true));
+ List<DeviceDTO> devicesList = pagination.getRecords().stream().map(this::deviceEntityConvertToDTO)
+ .peek(device -> {
+ device.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn()));
+ if (StringUtils.hasText(device.getChildDeviceSn())) {
+ Optional<DeviceDTO> childOpt = this.getDeviceBySn(device.getChildDeviceSn());
+ childOpt.ifPresent(child -> {
+ child.setStatus(
+ RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + child.getDeviceSn()));
+ child.setWorkspaceName(device.getWorkspaceName());
+ device.setChildren(child);
+ });
+ }
+ })
+ .collect(Collectors.toList());
+ return new PaginationData<DeviceDTO>(devicesList, new Pagination(pagination));
+ }
+
+ @Override
+ public void unbindDevice(String deviceSn) {
+ String key = RedisConst.DEVICE_ONLINE_PREFIX + deviceSn;
+ DeviceDTO redisDevice = (DeviceDTO) RedisOpsUtils.get(key);
+ redisDevice.setWorkspaceId("");
+ RedisOpsUtils.setWithExpire(key, redisDevice, RedisConst.DEVICE_ALIVE_SECOND);
+
+ DeviceDTO device = DeviceDTO.builder()
+ .deviceSn(deviceSn)
+ .workspaceId("")
+ .userId("")
+ .boundStatus(false)
+ .build();
+ this.updateDevice(device);
+ }
+
+ @Override
+ public Optional<DeviceDTO> getDeviceBySn(String sn) {
+ List<DeviceDTO> devicesList = this.getDevicesByParams(DeviceQueryParam.builder().deviceSn(sn).build());
+ if (devicesList.isEmpty()) {
+ return Optional.empty();
+ }
+ DeviceDTO device = devicesList.get(0);
+ device.setStatus(RedisOpsUtils.checkExist(RedisConst.DEVICE_ONLINE_PREFIX + sn));
+ return Optional.of(device);
+ }
+
+ @Override
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_FIRMWARE_VERSION)
+ public void updateFirmwareVersion(FirmwareVersionReceiver receiver) {
+ // If the reported version is empty, it will not be processed to prevent misleading page.
+ if (!StringUtils.hasText(receiver.getFirmwareVersion())) {
+ return;
+ }
+
+ if (receiver.getDomain() == DeviceDomainEnum.SUB_DEVICE) {
+ final DeviceDTO device = DeviceDTO.builder()
+ .deviceSn(receiver.getSn())
+ .firmwareVersion(receiver.getFirmwareVersion())
+ .firmwareStatus(receiver.getCompatibleStatus() == null ?
+ null : DeviceFirmwareStatusEnum.CompatibleStatusEnum.INCONSISTENT.getVal() != receiver.getCompatibleStatus() ?
+ DeviceFirmwareStatusEnum.UNKNOWN.getVal() : DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE.getVal())
+ .build();
+ this.updateDevice(device);
+ return;
+ }
+ payloadService.updateFirmwareVersion(receiver);
+ }
+
+ @Override
+ public ResponseResult createDeviceOtaJob(String workspaceId, List<DeviceFirmwareUpgradeDTO> upgradeDTOS) {
+ List<DeviceOtaCreateParam> deviceOtaFirmwares = deviceFirmwareService.getDeviceOtaFirmware(workspaceId, upgradeDTOS);
+ if (deviceOtaFirmwares.isEmpty()) {
+ return ResponseResult.error();
+ }
+
+ DeviceOtaCreateParam deviceOtaFirmware = deviceOtaFirmwares.get(0);
+ List<DeviceDTO> devices = getDevicesByParams(DeviceQueryParam.builder().childSn(deviceOtaFirmware.getSn()).build());
+ String gatewaySn = devices.isEmpty() ? deviceOtaFirmware.getSn() : devices.get(0).getDeviceSn();
+
+ String topic = THING_MODEL_PRE + PRODUCT + gatewaySn + SERVICES_SUF;
+
+ // The bids in the progress messages reported subsequently are the same.
+ String bid = UUID.randomUUID().toString();
+ ServiceReply serviceReply = messageSender.publishWithReply(
+ topic, CommonTopicResponse.<Map<String, List<DeviceOtaCreateParam>>>builder()
+ .tid(UUID.randomUUID().toString())
+ .bid(bid)
+ .timestamp(System.currentTimeMillis())
+ .method(FirmwareMethodEnum.OTA_CREATE.getMethod())
+ .data(Map.of(MapKeyConst.DEVICES, deviceOtaFirmwares))
+ .build());
+ if (serviceReply.getResult() != ResponseResult.CODE_SUCCESS) {
+ return ResponseResult.error(serviceReply.getResult(), "Firmware Error Code: " + serviceReply.getResult());
+ }
+
+ // Record the device state that needs to be updated.
+ deviceOtaFirmwares.forEach(deviceOta -> RedisOpsUtils.setWithExpire(
+ RedisConst.FIRMWARE_UPGRADING_PREFIX + deviceOta.getSn(),
+ bid,
+ RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND));
+ return ResponseResult.success();
+ }
+
+ @Override
+ public void devicePropertySet(String workspaceId, String dockSn, DeviceSetPropertyEnum propertyEnum, JsonNode param) {
+ boolean dockOnline = this.checkDeviceOnline(dockSn);
+ if (!dockOnline) {
+ throw new RuntimeException("Dock is offline.");
+ }
+ DeviceDTO deviceDTO = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + dockSn);
+ boolean deviceOnline = this.checkDeviceOnline(deviceDTO.getChildDeviceSn());
+ if (!deviceOnline) {
+ throw new RuntimeException("Device is offline.");
+ }
+
+ // Make sure the data is valid.
+ BasicDeviceProperty basicDeviceProperty = objectMapper.convertValue(param, propertyEnum.getClazz());
+ boolean valid = basicDeviceProperty.valid();
+ if (!valid) {
+ throw new IllegalArgumentException(CommonErrorEnum.ILLEGAL_ARGUMENT.getErrorMsg());
+ }
+
+ String topic = THING_MODEL_PRE + PRODUCT + dockSn + PROPERTY_SUF + SET_SUF;
+ OsdSubDeviceReceiver osd = (OsdSubDeviceReceiver) RedisOpsUtils.get(RedisConst.OSD_PREFIX + deviceDTO.getChildDeviceSn());
+ if (!param.isObject()) {
+ this.deviceOnePropertySet(topic, propertyEnum, Map.entry(propertyEnum.getProperty(), param));
+ return;
+ }
+ // If there are multiple parameters, set them separately.
+ for (Iterator<Map.Entry<String, JsonNode>> filed = param.fields(); filed.hasNext(); ) {
+ Map.Entry<String, JsonNode> node = filed.next();
+ boolean isPublish = basicDeviceProperty.canPublish(node.getKey(), osd);
+ if (!isPublish) {
+ continue;
+ }
+ this.deviceOnePropertySet(topic, propertyEnum, Map.entry(propertyEnum.getProperty(), node));
+ }
+
+ }
+
+ @Override
+ public void deviceOnePropertySet(String topic, DeviceSetPropertyEnum propertyEnum, Map.Entry<String, Object> value) {
+ if (Objects.isNull(value) || Objects.isNull(value.getValue())) {
+ throw new IllegalArgumentException(CommonErrorEnum.ILLEGAL_ARGUMENT.getErrorMsg());
+ }
+
+ Map reply = messageSender.publishWithReply(
+ Map.class, topic,
+ CommonTopicResponse.builder()
+ .bid(UUID.randomUUID().toString())
+ .tid(UUID.randomUUID().toString())
+ .timestamp(System.currentTimeMillis())
+ .data(value)
+ .build(),
+ 2);
+
+ while (true) {
+ reply = (Map<String, Object>) reply.get(value.getKey());
+ if (value.getValue() instanceof JsonNode) {
+ break;
+ }
+ value = (Map.Entry) value.getValue();
+ }
+
+ SetReply setReply = objectMapper.convertValue(reply, SetReply.class);
+ if (SetReplyStatusResultEnum.SUCCESS.getVal() != setReply.getResult()) {
+ throw new RuntimeException("Failed to set " + value.getKey() + "; Error Code: " + setReply.getResult());
+ }
+
+ }
+
+ public Boolean checkDeviceOnline(String sn) {
+ String key = RedisConst.DEVICE_ONLINE_PREFIX + sn;
+ return RedisOpsUtils.checkExist(key) && RedisOpsUtils.getExpire(key) > 0;
+ }
+
+ /**
+ * Convert device data transfer object into database entity object.
+ * @param dto
+ * @return
+ */
+ private DeviceEntity deviceDTO2Entity(DeviceDTO dto) {
+ DeviceEntity.DeviceEntityBuilder builder = DeviceEntity.builder();
+ if (dto == null) {
+ return builder.build();
+ }
+
+ return builder.deviceSn(dto.getDeviceSn())
+ .userId(dto.getUserId())
+ .nickname(dto.getNickname())
+ .workspaceId(dto.getWorkspaceId())
+ .boundStatus(dto.getBoundStatus())
+ .loginTime(dto.getLoginTime() != null ?
+ dto.getLoginTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null)
+ .boundTime(dto.getBoundTime() != null ?
+ dto.getBoundTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() : null)
+ .childSn(dto.getChildDeviceSn())
+ .domain(dto.getDomain())
+ .firmwareVersion(dto.getFirmwareVersion())
+ .compatibleStatus(dto.getFirmwareStatus() == null ? null :
+ DeviceFirmwareStatusEnum.CONSISTENT_UPGRADE != DeviceFirmwareStatusEnum.find(dto.getFirmwareStatus()))
+ .build();
+ }
+
+ /**
+ * Convert device binding data object into database entity object.
+ *
+ * @param domain
+ * @param receiver
+ * @return
+ */
+ private Optional<DeviceEntity> bindDevice2Entity(Integer domain, BindDeviceReceiver receiver) {
+ if (receiver == null) {
+ return Optional.empty();
+ }
+ int[] droneKey = Arrays.stream(receiver.getDeviceModelKey().split("-")).mapToInt(Integer::parseInt).toArray();
+ Optional<DeviceDictionaryDTO> dictionaryOpt = dictionaryService.getOneDictionaryInfoByTypeSubType(domain, droneKey[1], droneKey[2]);
+ DeviceEntity.DeviceEntityBuilder builder = DeviceEntity.builder();
+
+ dictionaryOpt.ifPresent(entity ->
+ builder.deviceName(entity.getDeviceName())
+ .nickname(entity.getDeviceName())
+ .deviceDesc(entity.getDeviceDesc()));
+
+ Optional<WorkspaceDTO> workspace = workspaceService.getWorkspaceNameByBindCode(receiver.getDeviceBindingCode());
+
+ DeviceEntity entity = builder
+ .workspaceId(workspace.isPresent() ? workspace.get().getWorkspaceId() : receiver.getOrganizationId())
+ .domain(droneKey[0])
+ .deviceType(droneKey[1])
+ .subType(droneKey[2])
+ .deviceSn(receiver.getSn())
+ .boundStatus(true)
+ .loginTime(System.currentTimeMillis())
+ .boundTime(System.currentTimeMillis())
+ .urlSelect(IconUrlEnum.SELECT_EQUIPMENT.getUrl())
+ .urlNormal(IconUrlEnum.NORMAL_EQUIPMENT.getUrl())
+ .build();
+ if (StringUtils.hasText(receiver.getDeviceCallsign())) {
+ entity.setNickname(receiver.getDeviceCallsign());
+ }
+ return Optional.of(entity);
+ }
+
+ /**
+ * Convert device data transfer object into device binding status data object.
+ * @param device
+ * @return
+ */
+ private BindStatusReceiver dto2BindStatus(DeviceDTO device) {
+ if (device == null) {
+ return null;
+ }
+ return BindStatusReceiver.builder()
+ .sn(device.getDeviceSn())
+ .deviceCallsign(device.getNickname())
+ .isDeviceBindOrganization(device.getBoundStatus())
+ .organizationId(device.getWorkspaceId())
+ .organizationName(device.getWorkspaceName())
+ .build();
+ }
+
+ private Optional<DeviceEntity> onlineSaveDevice(DeviceEntity device, String childSn) {
+
+ Optional<DeviceDTO> deviceOpt = this.getDeviceBySn(device.getDeviceSn());
+ if (deviceOpt.isEmpty()) {
+ // Set the icon of the gateway device displayed in the pilot's map, required in the TSA module.
+ device.setUrlNormal(IconUrlEnum.NORMAL_PERSON.getUrl());
+ // Set the icon of the gateway device displayed in the pilot's map when it is selected, required in the TSA module.
+ device.setUrlSelect(IconUrlEnum.SELECT_PERSON.getUrl());
+ device.setBoundStatus(false);
+ } else {
+ DeviceDTO oldDevice = deviceOpt.get();
+ device.setNickname(oldDevice.getNickname());
+ device.setBoundStatus(oldDevice.getBoundStatus());
+ }
+
+ device.setChildSn(childSn);
+ device.setLoginTime(System.currentTimeMillis());
+
+ Optional<DeviceEntity> saveDeviceOpt = this.saveDevice(device);
+ if (saveDeviceOpt.isEmpty()) {
+ return saveDeviceOpt;
+ }
+ device.setWorkspaceId(saveDeviceOpt.get().getWorkspaceId());
+
+ RedisOpsUtils.setWithExpire(RedisConst.DEVICE_ONLINE_PREFIX + device.getDeviceSn(),
+ DeviceDTO.builder()
+ .deviceSn(device.getDeviceSn())
+ .workspaceId(device.getWorkspaceId())
+ .childDeviceSn(childSn)
+ .domain(device.getDomain())
+ .type(device.getDeviceType())
+ .subType(device.getSubType())
+ .build(),
+ RedisConst.DEVICE_ALIVE_SECOND);
+
+ return saveDeviceOpt;
+ }
}
\ No newline at end of file
--
Gitblit v1.9.3