diff --git a/api/Cloud API Demo.postman_collection.json b/api/Cloud API Demo.postman_collection.json
index a1535ea..6bfd878 100644
--- a/api/Cloud API Demo.postman_collection.json
+++ b/api/Cloud API Demo.postman_collection.json
@@ -887,7 +887,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NzAzMTU2MDEsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NzA0MDIwMDEsImlhdCI6MTY3MDMxNTYwMSwidXNlcm5hbWUiOiJhZG1pblBDIn0.yh8SkHZVsoIXo_vtlTGNB-ZX92XayalGe_q7mNRVcdI",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2ODIyMzI5MDYsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE3Njg2MzI5MDYsImlhdCI6MTY4MjIzMjkwNiwidXNlcm5hbWUiOiJhZG1pblBDIn0.ilO-3PcvWAX9r8z3AR4VAw3kVhavYjiTx_187ACBc1M",
"type": "string"
},
{
@@ -1537,7 +1537,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njg2NTk4MjYsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njg3NDYyMjYsImlhdCI6MTY2ODY1OTgyNiwidXNlcm5hbWUiOiJhZG1pblBDIn0.ykCpfJcReeb3etUzmNMQk1n0vaoDT6dl47J_aHRoTbU",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2ODAyNjAxNTYsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE3NjY2NjAxNTYsImlhdCI6MTY4MDI2MDE1NiwidXNlcm5hbWUiOiJhZG1pblBDIn0._QhvfhBxxfQN7xpFqZma1rCYbBtouo2pErtm8737L_8",
"type": "string"
},
{
@@ -1578,7 +1578,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\r\n \"name\": \"\",\r\n \"file_id\": \"\",\r\n \"dock_sn\": \"\",\r\n \"wayline_type\": 0,\r\n \"task_type\": 0,\r\n \"execute_time\": 123456789123,\r\n \"rth_altitude\": 20,\r\n \"out_of_control_action\": 1\r\n}",
+ "raw": "{\r\n \"name\": \"\",\r\n \"file_id\": \"\",\r\n \"dock_sn\": \"\",\r\n \"wayline_type\": 0,\r\n \"task_type\": 0,\r\n \"task_days\": [1676029468],\r\n \"task_periods\": [[1676029468]],\r\n \"rth_altitude\": 20,\r\n \"out_of_control_action\": 1\r\n}",
"options": {
"raw": {
"language": "json"
@@ -1679,6 +1679,64 @@
}
},
"response": []
+ },
+ {
+ "name": "Pause Job",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"status\": 0\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/jobs/{{job_id}}",
+ "host": [
+ "{{base_url}}{{wayline_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "jobs",
+ "{{job_id}}"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Resume Job",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"status\": 1\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/jobs/{{job_id}}",
+ "host": [
+ "{{base_url}}{{wayline_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "jobs",
+ "{{job_id}}"
+ ]
+ }
+ },
+ "response": []
}
],
"auth": {
@@ -1686,7 +1744,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njg2NTk4MjYsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njg3NDYyMjYsImlhdCI6MTY2ODY1OTgyNiwidXNlcm5hbWUiOiJhZG1pblBDIn0.ykCpfJcReeb3etUzmNMQk1n0vaoDT6dl47J_aHRoTbU",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Nzg4NjM0NzMsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE3NjUyNjM0NzMsImlhdCI6MTY3ODg2MzQ3MywidXNlcm5hbWUiOiJhZG1pblBDIn0.r3ODgJtAHxrBCzDnCwTDCdUq8hLyfIUiDYzasYAIUII",
"type": "string"
},
{
@@ -1727,7 +1785,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\r\n \"action\": 0\r\n}",
+ "raw": "",
"options": {
"raw": {
"language": "json"
@@ -1735,7 +1793,7 @@
}
},
"url": {
- "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/jobs/alarm_state_switch",
+ "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/jobs/return_home",
"host": [
"{{base_url}}{{control_version}}"
],
@@ -1743,7 +1801,250 @@
"devices",
"{{device_sn}}",
"jobs",
- "alarm_state_switch"
+ "return_home"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Web Drc Connect",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"client_id\": \"xxx\",\r\n \"expire_sec\": 1800\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/workspaces/{{workspace_id}}/drc/connect",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "drc",
+ "connect"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Enter Drc Mode",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"client_id\": \"\",\r\n \"dock_sn\": \"\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/workspaces/{{workspace_id}}/drc/enter",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "drc",
+ "enter"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Drc Mode Exit",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"client_id\": \"\",\r\n \"dock_sn\": \"\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/workspaces/{{workspace_id}}/drc/exit",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "drc",
+ "exit"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Fly to Point",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"max_speed\": 15,\r\n \"points\":[\r\n {\r\n \"latitude\": 22.5818,\r\n \"longitude\": 113.9394,\r\n \"height\": 20\r\n }\r\n ]\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/jobs/fly-to-point",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{device_sn}}",
+ "jobs",
+ "fly-to-point"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Stop Flying to Point",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/jobs/fly-to-point",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{device_sn}}",
+ "jobs",
+ "fly-to-point"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Take off to Point",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"target_latitude\": 22.579,\r\n \"target_longitude\": 113.9392,\r\n \"target_height\": 20,\r\n \"security_takeoff_height\": 20,\r\n \"rth_altitude\": 20,\r\n \"rc_lost_action\": 0,\r\n \"exit_wayline_when_rc_lost\": 0,\r\n \"max_speed\": 12\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/jobs/takeoff-to-point",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{device_sn}}",
+ "jobs",
+ "takeoff-to-point"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Payload Commands",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"cmd\":\"camera_mode_switch\",\r\n \"data\":{\r\n \"payload_index\":\"53-0-0\",\r\n \"camera_mode\": 1\r\n }\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/payload/commands",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{device_sn}}",
+ "payload",
+ "commands"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Flight Authority Grab",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/authority/flight",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{device_sn}}",
+ "authority",
+ "flight"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Payload Authority Grab",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"payload_index\":\"53-0-0\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{control_version}}/devices/{{device_sn}}/authority/payload",
+ "host": [
+ "{{base_url}}{{control_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{device_sn}}",
+ "authority",
+ "payload"
]
}
},
@@ -1755,7 +2056,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Njk2MzMzMzQsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2Njk3MTk3MzQsImlhdCI6MTY2OTYzMzMzNCwidXNlcm5hbWUiOiJhZG1pblBDIn0.OoIfdpyI5eL6bFm8akq8_stzClQU41YpIJkx6_kxVHU",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2ODIyMzI5MDYsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE3Njg2MzI5MDYsImlhdCI6MTY4MjIzMjkwNiwidXNlcm5hbWUiOiJhZG1pblBDIn0.ilO-3PcvWAX9r8z3AR4VAw3kVhavYjiTx_187ACBc1M",
"type": "string"
},
{
diff --git a/pom.xml b/pom.xml
index 66e3efa..4f0fea6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
com.dji
cloud-api-sample
- 1.3.1
+ 1.4.0
cloud-api-sample
diff --git a/sql/cloud_sample.sql b/sql/cloud_sample.sql
index 3ff45db..74fe68c 100644
--- a/sql/cloud_sample.sql
+++ b/sql/cloud_sample.sql
@@ -66,7 +66,7 @@ CREATE TABLE `manage_device` (
`device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'dock, drone, remote control',
`device_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined' COMMENT 'model of the device. This parameter corresponds to the device name in the device dictionary table.',
`user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT 'The account used when the device was bound.',
- `nickname` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT 'custom name of the device',
+ `nickname` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'custom name of the device',
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT 'The workspace to which the current device belongs.',
`device_type` int NOT NULL DEFAULT '-1' COMMENT 'This parameter corresponds to the device type in the device dictionary table.',
`sub_type` int NOT NULL DEFAULT '-1' COMMENT 'This parameter corresponds to the sub type in the device dictionary table.',
@@ -226,6 +226,7 @@ CREATE TABLE `manage_device_payload` (
`payload_index` smallint NOT NULL COMMENT 'The location of the payload on the device.',
`device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'Which device the current payload belongs to.',
`payload_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
+ `control_source` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`create_time` bigint NOT NULL,
`update_time` bigint NOT NULL,
PRIMARY KEY (`id`),
@@ -452,7 +453,7 @@ CREATE TABLE `wayline_job` (
`completed_time` bigint DEFAULT NULL COMMENT 'actual end time',
`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The name of the creator.',
`begin_time` bigint NOT NULL COMMENT 'planned begin time',
- `end_time` bigint NOT NULL COMMENT 'planned end time',
+ `end_time` bigint DEFAULT NULL COMMENT 'planned end time',
`error_code` int DEFAULT NULL,
`status` int NOT NULL COMMENT '1: pending; 2: in progress; 3: success; 4: cancel; 5: failed',
`rth_altitude` int NOT NULL COMMENT 'return to home altitude. min: 20m; max: 500m',
diff --git a/src/main/java/com/dji/sample/component/GlobalExceptionHandler.java b/src/main/java/com/dji/sample/component/GlobalExceptionHandler.java
index 953fd2d..0b6b6b0 100644
--- a/src/main/java/com/dji/sample/component/GlobalExceptionHandler.java
+++ b/src/main/java/com/dji/sample/component/GlobalExceptionHandler.java
@@ -36,7 +36,7 @@ public class GlobalExceptionHandler {
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
public ResponseResult methodArgumentNotValidExceptionHandler(BindException e) {
e.printStackTrace();
- return ResponseResult.error(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
+ return ResponseResult.error(e.getFieldError().getField() + e.getFieldError().getDefaultMessage());
}
}
diff --git a/src/main/java/com/dji/sample/component/GlobalScheduleService.java b/src/main/java/com/dji/sample/component/GlobalScheduleService.java
index e092ad4..7e77a34 100644
--- a/src/main/java/com/dji/sample/component/GlobalScheduleService.java
+++ b/src/main/java/com/dji/sample/component/GlobalScheduleService.java
@@ -7,6 +7,7 @@ import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.model.enums.DeviceDomainEnum;
import com.dji.sample.manage.service.IDeviceService;
import com.dji.sample.wayline.service.IWaylineJobService;
+import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
@@ -32,11 +33,12 @@ public class GlobalScheduleService {
@Autowired
private IWaylineJobService waylineJobService;
-
+ @Autowired
+ private ObjectMapper mapper;
/**
* Check the status of the devices every 30 seconds. It is recommended to use cache.
*/
- @Scheduled(initialDelay = 30, fixedRate = 30, timeUnit = TimeUnit.SECONDS)
+ @Scheduled(initialDelay = 10, fixedRate = 30, timeUnit = TimeUnit.SECONDS)
private void deviceStatusListen() {
int start = RedisConst.DEVICE_ONLINE_PREFIX.length();
@@ -49,8 +51,9 @@ public class GlobalScheduleService {
} else {
deviceService.unsubscribeTopicOffline(key.substring(start));
deviceService.pushDeviceOfflineTopo(device.getWorkspaceId(), device.getDeviceSn());
- RedisOpsUtils.hashDel(RedisConst.LIVE_CAPACITY, new String[]{key});
- RedisOpsUtils.del(RedisConst.HMS_PREFIX + key);
+ RedisOpsUtils.hashDel(RedisConst.LIVE_CAPACITY, new String[]{device.getDeviceSn()});
+ RedisOpsUtils.del(RedisConst.HMS_PREFIX + device.getDeviceSn());
+ RedisOpsUtils.del(RedisConst.OSD_PREFIX + device.getDeviceSn());
}
RedisOpsUtils.del(key);
}
diff --git a/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java b/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java
index 69c6398..ba8d939 100644
--- a/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java
+++ b/src/main/java/com/dji/sample/component/mqtt/config/MqttConfiguration.java
@@ -5,6 +5,7 @@ import com.dji.sample.common.util.JwtUtil;
import com.dji.sample.component.mqtt.model.MqttClientOptions;
import com.dji.sample.component.mqtt.model.MqttProtocolEnum;
import com.dji.sample.component.mqtt.model.MqttUseEnum;
+import com.dji.sample.control.model.dto.MqttBrokerDTO;
import lombok.Data;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -70,6 +71,32 @@ public class MqttConfiguration {
return addr.toString();
}
+ /**
+ * Get the connection parameters of the mqtt client of the drc link.
+ * @param clientId
+ * @param username
+ * @param age The validity period of the token. unit: s
+ * @param map Custom data added in token.
+ * @return
+ */
+ public static MqttBrokerDTO getMqttBrokerWithDrc(String clientId, String username, Long age, Map map) {
+ if (!mqtt.containsKey(MqttUseEnum.DRC)) {
+ throw new RuntimeException("Please configure the drc link parameters of mqtt in the backend configuration file first.");
+ }
+ Algorithm algorithm = JwtUtil.algorithm;
+
+ String token = JwtUtil.createToken(map, age, algorithm, null, null);
+
+ return MqttBrokerDTO.builder()
+ .address(getMqttAddress(mqtt.get(MqttUseEnum.DRC)))
+ .username(username)
+ .clientId(clientId)
+ .expireTime(System.currentTimeMillis() / 1000 + age)
+ .password(token)
+ .build();
+ }
+
+
@Bean
public MqttConnectOptions mqttConnectOptions() {
MqttClientOptions customizeOptions = getBasicClientOptions();
diff --git a/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java b/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java
index 8e168e8..8ff8629 100644
--- a/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java
+++ b/src/main/java/com/dji/sample/component/mqtt/config/MqttMessageChannel.java
@@ -107,6 +107,11 @@ public class MqttMessageChannel {
return new DirectChannel();
}
+ @Bean(name = ChannelName.OUTBOUND_EVENTS)
+ public MessageChannel eventsOutboundChannel() {
+ return new DirectChannel();
+ }
+
@Bean(name = ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS)
public MessageChannel eventsFlightTaskProgressChannel() {
return new DirectChannel();
@@ -172,4 +177,28 @@ public class MqttMessageChannel {
return new DirectChannel();
}
+ @Bean(name = ChannelName.INBOUND_EVENTS_FLIGHT_TASK_READY)
+ public MessageChannel eventsEventsFlightTaskReady() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS_FLY_TO_POINT_PROGRESS)
+ public MessageChannel eventsFlyToPointProgress() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS_TAKE_OFF_TO_POINT_PROGRESS)
+ public MessageChannel eventsTakeoffToPointProgress() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS_DRC_STATUS_NOTIFY)
+ public MessageChannel eventsDrcStatusNotify() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS_DRC_MODE_EXIT_NOTIFY)
+ public MessageChannel eventsDrcModeExitNotify() {
+ return new DirectChannel();
+ }
}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/EventsRouter.java b/src/main/java/com/dji/sample/component/mqtt/handler/EventsRouter.java
index 49034b3..152ae81 100644
--- a/src/main/java/com/dji/sample/component/mqtt/handler/EventsRouter.java
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/EventsRouter.java
@@ -1,17 +1,20 @@
package com.dji.sample.component.mqtt.handler;
-import com.dji.sample.component.mqtt.model.ChannelName;
-import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
-import com.dji.sample.component.mqtt.model.EventsMethodEnum;
+import com.dji.sample.component.mqtt.model.*;
+import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
+import org.springframework.integration.mqtt.support.MqttHeaders;
+import org.springframework.messaging.MessageHeaders;
import java.io.IOException;
import java.util.Arrays;
+import java.util.Optional;
/**
* @author sean
@@ -24,6 +27,9 @@ public class EventsRouter {
@Autowired
private ObjectMapper mapper;
+ @Autowired
+ private IMessageSenderService messageSenderService;
+
@Bean
public IntegrationFlow eventsMethodRouterFlow() {
return IntegrationFlows
@@ -42,4 +48,21 @@ public class EventsRouter {
methodEnum -> mapping.channelMapping(methodEnum, methodEnum.getChannelName())))
.get();
}
+
+ @ServiceActivator(inputChannel = ChannelName.OUTBOUND_EVENTS, outputChannel = ChannelName.OUTBOUND)
+ public void replyEventsOutbound(CommonTopicReceiver receiver, MessageHeaders headers) {
+ if (Optional.ofNullable(receiver).map(CommonTopicReceiver::getNeedReply).flatMap(val -> Optional.of(1 != val)).orElse(true)) {
+ return;
+ }
+ messageSenderService.publish(headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF,
+ CommonTopicResponse.builder()
+ .tid(receiver.getTid())
+ .bid(receiver.getBid())
+ .method(receiver.getMethod())
+ .timestamp(System.currentTimeMillis())
+ .data(RequestsReply.success())
+ .build());
+
+ }
+
}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/ServicesReplyHandler.java b/src/main/java/com/dji/sample/component/mqtt/handler/ServicesReplyHandler.java
index c0115ab..8d8030d 100644
--- a/src/main/java/com/dji/sample/component/mqtt/handler/ServicesReplyHandler.java
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/ServicesReplyHandler.java
@@ -36,13 +36,16 @@ public class ServicesReplyHandler {
byte[] payload = (byte[])message.getPayload();
CommonTopicReceiver receiver = mapper.readValue(payload, new TypeReference() {});
+ ServiceReply reply;
if (LogsFileMethodEnum.FILE_UPLOAD_LIST.getMethod().equals(receiver.getMethod())) {
LogsFileUploadList list = mapper.convertValue(receiver.getData(), new TypeReference() {});
- receiver.setData(list);
+ reply = new ServiceReply();
+ reply.setResult(list.getResult());
+ reply.setOutput(list.getFiles());
} else {
- ServiceReply reply = mapper.convertValue(receiver.getData(), new TypeReference() {});
- receiver.setData(reply);
+ reply = mapper.convertValue(receiver.getData(), new TypeReference() {});
}
+ receiver.setData(reply);
Chan> chan = Chan.getInstance();
// Put the message to the chan object.
chan.put(receiver);
diff --git a/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java b/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java
index aeee108..cf0ef71 100644
--- a/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java
+++ b/src/main/java/com/dji/sample/component/mqtt/model/ChannelName.java
@@ -51,6 +51,8 @@ public class ChannelName {
public static final String INBOUND_EVENTS = "inboundEvents";
+ public static final String OUTBOUND_EVENTS = "outboundEvents";
+
public static final String INBOUND_EVENTS_FLIGHT_TASK_PROGRESS = "inboundEventsFlightTaskProgress";
public static final String INBOUND_EVENTS_FILE_UPLOAD_CALLBACK = "inboundEventsFileUploadCallback";
@@ -76,4 +78,14 @@ public class ChannelName {
public static final String INBOUND_REQUESTS_CONFIG = "inboundRequestsConfig";
public static final String INBOUND_EVENTS_HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA = "inboundEventsHighestPriorityUploadFlightTaskMedia";
+
+ public static final String INBOUND_EVENTS_FLIGHT_TASK_READY = "inboundEventsFlightTaskReady";
+
+ public static final String INBOUND_EVENTS_FLY_TO_POINT_PROGRESS = "inboundFlyToPointProgress";
+
+ public static final String INBOUND_EVENTS_TAKE_OFF_TO_POINT_PROGRESS = "inboundTakeoffToPointProgress";
+
+ public static final String INBOUND_EVENTS_DRC_STATUS_NOTIFY = "inboundDrcStatusNotify";
+
+ public static final String INBOUND_EVENTS_DRC_MODE_EXIT_NOTIFY = "inboundDrcModeExitNotify";
}
diff --git a/src/main/java/com/dji/sample/component/mqtt/model/EventsMethodEnum.java b/src/main/java/com/dji/sample/component/mqtt/model/EventsMethodEnum.java
index d0782e0..37205bc 100644
--- a/src/main/java/com/dji/sample/component/mqtt/model/EventsMethodEnum.java
+++ b/src/main/java/com/dji/sample/component/mqtt/model/EventsMethodEnum.java
@@ -45,6 +45,16 @@ public enum EventsMethodEnum {
HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA("highest_priority_upload_flighttask_media", ChannelName.INBOUND_EVENTS_HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA),
+ FLIGHT_TASK_READY("flighttask_ready", ChannelName.INBOUND_EVENTS_FLIGHT_TASK_READY),
+
+ FLY_TO_POINT_PROGRESS("fly_to_point_progress", ChannelName.INBOUND_EVENTS_FLY_TO_POINT_PROGRESS),
+
+ TAKE_OFF_TO_POINT_PROGRESS("takeoff_to_point_progress", ChannelName.INBOUND_EVENTS_TAKE_OFF_TO_POINT_PROGRESS),
+
+ DRC_STATUS_NOTIFY("drc_status_notify", ChannelName.INBOUND_EVENTS_DRC_STATUS_NOTIFY),
+
+ JOYSTICK_INVALID_NOTIFY("joystick_invalid_notify", ChannelName.INBOUND_EVENTS_DRC_MODE_EXIT_NOTIFY),
+
UNKNOWN("Unknown", ChannelName.DEFAULT);
private String method;
diff --git a/src/main/java/com/dji/sample/component/mqtt/model/EventsOutputReceiver.java b/src/main/java/com/dji/sample/component/mqtt/model/EventsOutputProgressReceiver.java
similarity index 75%
rename from src/main/java/com/dji/sample/component/mqtt/model/EventsOutputReceiver.java
rename to src/main/java/com/dji/sample/component/mqtt/model/EventsOutputProgressReceiver.java
index 87667e8..499d85a 100644
--- a/src/main/java/com/dji/sample/component/mqtt/model/EventsOutputReceiver.java
+++ b/src/main/java/com/dji/sample/component/mqtt/model/EventsOutputProgressReceiver.java
@@ -8,9 +8,11 @@ import lombok.Data;
* @date 2022/7/29
*/
@Data
-public class EventsOutputReceiver {
+public class EventsOutputProgressReceiver {
private String status;
private OutputProgressReceiver progress;
+
+ private T ext;
}
diff --git a/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java b/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java
index 215995a..9ee3f9a 100644
--- a/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java
+++ b/src/main/java/com/dji/sample/component/mqtt/model/TopicConst.java
@@ -34,4 +34,9 @@ public class TopicConst {
public static final String REGEX_SN = "[A-Za-z0-9]+";
+ public static final String DRC = "/drc";
+
+ public static final String UP = "/up";
+
+ public static final String DOWN = "/down";
}
\ No newline at end of file
diff --git a/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java b/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java
index 40f7f18..e21816c 100644
--- a/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java
+++ b/src/main/java/com/dji/sample/component/mqtt/service/IMessageSenderService.java
@@ -2,6 +2,7 @@ package com.dji.sample.component.mqtt.service;
import com.dji.sample.component.mqtt.model.CommonTopicResponse;
import com.dji.sample.component.mqtt.model.ServiceReply;
+import com.fasterxml.jackson.core.type.TypeReference;
/**
* @author sean.zhou
@@ -26,15 +27,16 @@ public interface IMessageSenderService {
void publish(String topic, int qos, CommonTopicResponse response);
/**
- * Send live streaming start message and receive a response at the same time.
+ * Send message and receive a response at the same time.
+ * @param clazz
* @param topic
* @param response notification of whether the start is successful.
* @return
*/
- ServiceReply publishWithReply(String topic, CommonTopicResponse response);
+ T publishWithReply(Class clazz, String topic, CommonTopicResponse response);
/**
- * Send live streaming start message and receive a response at the same time.
+ * Send message and receive a response at the same time.
* @param clazz
* @param topic
* @param response
@@ -43,4 +45,46 @@ public interface IMessageSenderService {
* @return
*/
T publishWithReply(Class clazz, String topic, CommonTopicResponse response, int retryTime);
+
+ /**
+ * Used exclusively for sending messages for services.
+ * @param clazz The generic class for ServiceReply.
+ * @param sn
+ * @param method
+ * @param data
+ * @param bid
+ * @param
+ * @return
+ */
+ ServiceReply publishServicesTopic(TypeReference clazz, String sn, String method, Object data, String bid);
+
+ /**
+ * Used exclusively for sending messages for services, and does not set the received subtype.
+ * @param sn
+ * @param method
+ * @param data
+ * @param bid
+ * @return
+ */
+ ServiceReply publishServicesTopic(String sn, String method, Object data, String bid);
+
+ /**
+ * Used exclusively for sending messages for services.
+ * @param clazz The generic class for ServiceReply.
+ * @param sn
+ * @param method
+ * @param data
+ * @param
+ * @return
+ */
+ ServiceReply publishServicesTopic(TypeReference clazz, String sn, String method, Object data);
+
+ /**
+ * Used exclusively for sending messages for services, and does not set the received subtype.
+ * @param sn
+ * @param method
+ * @param data
+ * @return
+ */
+ ServiceReply publishServicesTopic(String sn, String method, Object data);
}
diff --git a/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java b/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java
index 2a76cf5..fdaf62c 100644
--- a/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java
+++ b/src/main/java/com/dji/sample/component/mqtt/service/impl/MessageSenderServiceImpl.java
@@ -1,17 +1,19 @@
package com.dji.sample.component.mqtt.service.impl;
-import com.dji.sample.component.mqtt.model.Chan;
-import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
-import com.dji.sample.component.mqtt.model.CommonTopicResponse;
-import com.dji.sample.component.mqtt.model.ServiceReply;
+import com.dji.sample.component.mqtt.model.*;
import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.component.mqtt.service.IMqttMessageGateway;
import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import java.util.Objects;
+import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -30,17 +32,12 @@ public class MessageSenderServiceImpl implements IMessageSenderService {
private ObjectMapper mapper;
public void publish(String topic, CommonTopicResponse response) {
- try {
- log.info("send topic: {}, payload: {}", topic, response.toString());
- messageGateway.publish(topic, mapper.writeValueAsBytes(response));
- } catch (JsonProcessingException e) {
- log.info("Failed to publish the message. {}", response.toString());
- e.printStackTrace();
- }
+ this.publish(topic, 1, response);
}
public void publish(String topic, int qos, CommonTopicResponse response) {
try {
+ log.info("send topic: {}, payload: {}", topic, response.toString());
messageGateway.publish(topic, mapper.writeValueAsBytes(response), qos);
} catch (JsonProcessingException e) {
log.info("Failed to publish the message. {}", response.toString());
@@ -48,12 +45,11 @@ public class MessageSenderServiceImpl implements IMessageSenderService {
}
}
- public ServiceReply publishWithReply(String topic, CommonTopicResponse response) {
- return this.publishWithReply(ServiceReply.class, topic, response, 2);
+ public T publishWithReply(Class clazz, String topic, CommonTopicResponse response) {
+ return this.publishWithReply(clazz, topic, response, 2);
}
public T publishWithReply(Class clazz, String topic, CommonTopicResponse response, int retryTime) {
- log.info("send topic: {}, payload: {}", topic, response.toString());
AtomicInteger time = new AtomicInteger(0);
// Retry three times
while (time.getAndIncrement() <= retryTime) {
@@ -62,15 +58,59 @@ public class MessageSenderServiceImpl implements IMessageSenderService {
Chan> chan = Chan.getInstance();
// If the message is not received in 0.5 seconds then resend it again.
CommonTopicReceiver receiver = chan.get(response.getTid());
- if (receiver == null) {
- continue;
- }
+
// Need to match tid and bid.
- if (receiver.getTid().equals(response.getTid()) &&
+ if (Objects.nonNull(receiver) && receiver.getTid().equals(response.getTid()) &&
receiver.getBid().equals(response.getBid())) {
- return receiver.getData();
+ if (clazz.isAssignableFrom(receiver.getData().getClass())) {
+ return receiver.getData();
+ }
+ throw new TypeMismatchException(receiver.getData(), clazz);
}
+ // It must be guaranteed that the tid and bid of each message are different.
+ response.setBid(UUID.randomUUID().toString());
+ response.setTid(UUID.randomUUID().toString());
}
throw new RuntimeException("No message reply received.");
}
+
+ @Override
+ public ServiceReply publishServicesTopic(TypeReference clazz, String sn, String method, Object data, String bid) {
+ String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + sn + TopicConst.SERVICES_SUF;
+ ServiceReply reply = this.publishWithReply(ServiceReply.class, topic,
+ CommonTopicResponse.builder()
+ .tid(UUID.randomUUID().toString())
+ .bid(StringUtils.hasText(bid) ? bid : UUID.randomUUID().toString())
+ .timestamp(System.currentTimeMillis())
+ .method(method)
+ .data(Objects.requireNonNullElse(data, ""))
+ .build());
+ if (Objects.isNull(clazz)) {
+ return reply;
+ }
+ // put together in "output"
+ if (Objects.nonNull(reply.getInfo())) {
+ reply.setOutput(mapper.convertValue(reply.getInfo(), clazz));
+ }
+ if (Objects.nonNull(reply.getOutput())) {
+ reply.setOutput(mapper.convertValue(reply.getOutput(), clazz));
+ }
+ return reply;
+ }
+
+ @Override
+ public ServiceReply publishServicesTopic(String sn, String method, Object data, String bid) {
+ return this.publishServicesTopic(null, sn, method, data, bid);
+ }
+
+ @Override
+ public ServiceReply publishServicesTopic(TypeReference clazz, String sn, String method, Object data) {
+ return this.publishServicesTopic(clazz, sn, method, data, null);
+ }
+
+ @Override
+ public ServiceReply publishServicesTopic(String sn, String method, Object data) {
+ return this.publishServicesTopic(null, sn, method, data, null);
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/dji/sample/component/redis/RedisConst.java b/src/main/java/com/dji/sample/component/redis/RedisConst.java
index 7ae29db..cb0ca7a 100644
--- a/src/main/java/com/dji/sample/component/redis/RedisConst.java
+++ b/src/main/java/com/dji/sample/component/redis/RedisConst.java
@@ -39,6 +39,10 @@ public final class RedisConst {
public static final String WAYLINE_JOB_TIMED_EXECUTE = "wayline_job_timed_execute";
+ public static final String WAYLINE_JOB_CONDITION_PREPARE = "wayline_job_condition_prepare";
+
+ public static final String WAYLINE_JOB_CONDITION_PREFIX = WAYLINE_JOB_CONDITION_PREPARE + DELIMITER;
+
public static final String WAYLINE_JOB_BLOCK_PREFIX = "wayline_job_block" + DELIMITER;
public static final String WAYLINE_JOB_RUNNING_PREFIX = "wayline_job_running" + DELIMITER;
@@ -53,7 +57,13 @@ public final class RedisConst {
public static final String LIVE_CAPACITY = "live_capacity";
+ public static final String DRC_PREFIX = "drc" + DELIMITER;
+
+ public static final Integer DRC_MODE_ALIVE_SECOND = 3600;
+
public static final String MQTT_ACL_PREFIX = "mqtt_acl" + DELIMITER;
public static final String FILE_UPLOADING_PREFIX = "file_uploading" + DELIMITER;
-}
+
+ public static final String DRONE_CONTROL_PREFiX = "control_source" + DELIMITER;
+}
\ No newline at end of file
diff --git a/src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java b/src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java
index 76727ca..2094d48 100644
--- a/src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java
+++ b/src/main/java/com/dji/sample/component/websocket/model/BizCodeEnum.java
@@ -57,7 +57,22 @@ public enum BizCodeEnum {
FILE_UPLOAD_CALLBACK("file_upload_callback"),
- HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA("HIGHEST_PRIORITY_UPLOAD_FLIGHTTASK_MEDIA");
+ FILE_UPLOAD_PROGRESS("fileupload_progress"),
+
+ OTA_PROGRESS("ota_progress"),
+
+ HIGHEST_PRIORITY_UPLOAD_FLIGHT_TASK_MEDIA("highest_priority_upload_flighttask_media"),
+
+ CONTROL_SOURCE_CHANGE("control_source_change"),
+
+ FLY_TO_POINT_PROGRESS("fly_to_point_progress"),
+
+ TAKE_OFF_TO_POINT_PROGRESS("takeoff_to_point_progress"),
+
+ DRC_STATUS_NOTIFY("drc_status_notify"),
+
+ JOYSTICK_INVALID_NOTIFY("joystick_invalid_notify")
+ ;
private String code;
diff --git a/src/main/java/com/dji/sample/component/websocket/service/ISendMessageService.java b/src/main/java/com/dji/sample/component/websocket/service/ISendMessageService.java
index e1d67e7..a9b3d8f 100644
--- a/src/main/java/com/dji/sample/component/websocket/service/ISendMessageService.java
+++ b/src/main/java/com/dji/sample/component/websocket/service/ISendMessageService.java
@@ -25,4 +25,8 @@ public interface ISendMessageService {
* @param message message
*/
void sendBatch(Collection sessions, CustomWebSocketMessage message);
+
+ void sendBatch(String workspaceId, Integer userType, String bizCode, Object data);
+
+ void sendBatch(String workspaceId, String bizCode, Object data);
}
diff --git a/src/main/java/com/dji/sample/component/websocket/service/impl/SendMessageServiceImpl.java b/src/main/java/com/dji/sample/component/websocket/service/impl/SendMessageServiceImpl.java
index 0546728..b605cf9 100644
--- a/src/main/java/com/dji/sample/component/websocket/service/impl/SendMessageServiceImpl.java
+++ b/src/main/java/com/dji/sample/component/websocket/service/impl/SendMessageServiceImpl.java
@@ -3,14 +3,17 @@ package com.dji.sample.component.websocket.service.impl;
import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession;
import com.dji.sample.component.websocket.model.CustomWebSocketMessage;
import com.dji.sample.component.websocket.service.ISendMessageService;
+import com.dji.sample.component.websocket.service.IWebSocketManageService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
import org.springframework.web.socket.TextMessage;
import java.io.IOException;
import java.util.Collection;
+import java.util.Objects;
/**
* @author sean.zhou
@@ -24,6 +27,9 @@ public class SendMessageServiceImpl implements ISendMessageService {
@Autowired
private ObjectMapper mapper;
+ @Autowired
+ private IWebSocketManageService webSocketManageService;
+
@Override
public void sendMessage(ConcurrentWebSocketSession session, CustomWebSocketMessage message) {
if (session == null) {
@@ -70,4 +76,25 @@ public class SendMessageServiceImpl implements ISendMessageService {
e.printStackTrace();
}
}
+
+ @Override
+ public void sendBatch(String workspaceId, Integer userType, String bizCode, Object data) {
+ if (!StringUtils.hasText(workspaceId)) {
+ throw new RuntimeException("Workspace ID does not exist.");
+ }
+ Collection sessions = Objects.isNull(userType) ?
+ webSocketManageService.getValueWithWorkspace(workspaceId) :
+ webSocketManageService.getValueWithWorkspaceAndUserType(workspaceId, userType);
+
+ this.sendBatch(sessions, CustomWebSocketMessage.builder()
+ .data(data)
+ .timestamp(System.currentTimeMillis())
+ .bizCode(bizCode)
+ .build());
+ }
+
+ @Override
+ public void sendBatch(String workspaceId, String bizCode, Object data) {
+ this.sendBatch(workspaceId, null, bizCode, data);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/dji/sample/control/controller/DockController.java b/src/main/java/com/dji/sample/control/controller/DockController.java
index 7836e5f..53d07f5 100644
--- a/src/main/java/com/dji/sample/control/controller/DockController.java
+++ b/src/main/java/com/dji/sample/control/controller/DockController.java
@@ -1,12 +1,15 @@
package com.dji.sample.control.controller;
import com.dji.sample.common.model.ResponseResult;
-import com.dji.sample.control.model.param.RemoteDebugParam;
+import com.dji.sample.control.model.enums.DroneAuthorityEnum;
+import com.dji.sample.control.model.param.*;
import com.dji.sample.control.service.IControlService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
+import javax.validation.Valid;
+
/**
* @author sean
* @version 1.2
@@ -24,6 +27,39 @@ public class DockController {
public ResponseResult createControlJob(@PathVariable String sn,
@PathVariable("service_identifier") String serviceIdentifier,
@RequestBody(required = false) RemoteDebugParam param) {
- return controlService.controlDock(sn, serviceIdentifier, param);
+ return controlService.controlDockDebug(sn, serviceIdentifier, param);
+ }
+
+ @PostMapping("/{sn}/jobs/fly-to-point")
+ public ResponseResult flyToPoint(@PathVariable String sn, @Valid @RequestBody FlyToPointParam param) {
+ return controlService.flyToPoint(sn, param);
+ }
+
+ @DeleteMapping("/{sn}/jobs/fly-to-point")
+ public ResponseResult flyToPointStop(@PathVariable String sn) {
+ return controlService.flyToPointStop(sn);
+ }
+
+ @PostMapping("/{sn}/jobs/takeoff-to-point")
+ public ResponseResult takeoffToPoint(@PathVariable String sn, @Valid @RequestBody TakeoffToPointParam param) {
+ return controlService.takeoffToPoint(sn, param);
}
+
+ @PostMapping("/{sn}/authority/flight")
+ public ResponseResult seizeFlightAuthority(@PathVariable String sn) {
+ return controlService.seizeAuthority(sn, DroneAuthorityEnum.FLIGHT, null);
+ }
+
+ @PostMapping("/{sn}/authority/payload")
+ public ResponseResult seizePayloadAuthority(@PathVariable String sn, @Valid @RequestBody DronePayloadParam param) {
+ return controlService.seizeAuthority(sn, DroneAuthorityEnum.PAYLOAD, param);
+ }
+
+ @PostMapping("/{sn}/payload/commands")
+ public ResponseResult payloadCommands(@PathVariable String sn, @Valid @RequestBody PayloadCommandsParam param) throws Exception {
+ param.setSn(sn);
+ return controlService.payloadCommands(param);
+ }
+
+
}
diff --git a/src/main/java/com/dji/sample/control/controller/DrcController.java b/src/main/java/com/dji/sample/control/controller/DrcController.java
new file mode 100644
index 0000000..6b66089
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/controller/DrcController.java
@@ -0,0 +1,55 @@
+package com.dji.sample.control.controller;
+
+import com.dji.sample.common.model.CustomClaim;
+import com.dji.sample.common.model.ResponseResult;
+import com.dji.sample.control.model.dto.JwtAclDTO;
+import com.dji.sample.control.model.dto.MqttBrokerDTO;
+import com.dji.sample.control.model.param.DrcConnectParam;
+import com.dji.sample.control.model.param.DrcModeParam;
+import com.dji.sample.control.service.IDrcService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+
+import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/11
+ */
+@RestController
+@Slf4j
+@RequestMapping("${url.control.prefix}${url.control.version}")
+public class DrcController {
+
+ @Autowired
+ private IDrcService drcService;
+
+ @PostMapping("/workspaces/{workspace_id}/drc/connect")
+ public ResponseResult drcConnect(@PathVariable("workspace_id") String workspaceId, HttpServletRequest request, @Valid @RequestBody DrcConnectParam param) {
+ CustomClaim claims = (CustomClaim) request.getAttribute(TOKEN_CLAIM);
+
+ MqttBrokerDTO brokerDTO = drcService.userDrcAuth(workspaceId, claims.getId(), claims.getUsername(), param);
+ return ResponseResult.success(brokerDTO);
+ }
+
+ @PostMapping("/workspaces/{workspace_id}/drc/enter")
+ public ResponseResult drcEnter(@PathVariable("workspace_id") String workspaceId, @Valid @RequestBody DrcModeParam param) {
+ JwtAclDTO acl = drcService.deviceDrcEnter(workspaceId, param);
+
+ return ResponseResult.success(acl);
+ }
+
+ @PostMapping("/workspaces/{workspace_id}/drc/exit")
+ public ResponseResult drcExit(@PathVariable("workspace_id") String workspaceId, @Valid @RequestBody DrcModeParam param) {
+ drcService.deviceDrcExit(workspaceId, param);
+
+ return ResponseResult.success();
+ }
+
+
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/AlarmState.java b/src/main/java/com/dji/sample/control/model/dto/AlarmState.java
index f670415..1fb590b 100644
--- a/src/main/java/com/dji/sample/control/model/dto/AlarmState.java
+++ b/src/main/java/com/dji/sample/control/model/dto/AlarmState.java
@@ -1,7 +1,7 @@
package com.dji.sample.control.model.dto;
+import com.dji.sample.control.service.impl.RemoteDebugHandler;
import com.dji.sample.manage.model.enums.StateSwitchEnum;
-import com.dji.sample.manage.model.receiver.BasicDeviceProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -18,7 +18,7 @@ import java.util.Objects;
@Data
@AllArgsConstructor
@NoArgsConstructor
-public class AlarmState extends BasicDeviceProperty {
+public class AlarmState extends RemoteDebugHandler {
private Integer action;
diff --git a/src/main/java/com/dji/sample/control/model/dto/BatteryStoreMode.java b/src/main/java/com/dji/sample/control/model/dto/BatteryStoreMode.java
index fa76703..9656a9e 100644
--- a/src/main/java/com/dji/sample/control/model/dto/BatteryStoreMode.java
+++ b/src/main/java/com/dji/sample/control/model/dto/BatteryStoreMode.java
@@ -1,7 +1,7 @@
package com.dji.sample.control.model.dto;
import com.dji.sample.control.model.enums.BatteryStoreModeEnum;
-import com.dji.sample.manage.model.receiver.BasicDeviceProperty;
+import com.dji.sample.control.service.impl.RemoteDebugHandler;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -18,7 +18,7 @@ import java.util.Objects;
@Data
@AllArgsConstructor
@NoArgsConstructor
-public class BatteryStoreMode extends BasicDeviceProperty {
+public class BatteryStoreMode extends RemoteDebugHandler {
private Integer action;
diff --git a/src/main/java/com/dji/sample/control/model/dto/DrcModeDTO.java b/src/main/java/com/dji/sample/control/model/dto/DrcModeDTO.java
new file mode 100644
index 0000000..771e85a
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/DrcModeDTO.java
@@ -0,0 +1,32 @@
+package com.dji.sample.control.model.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/12
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class DrcModeDTO {
+
+ private MqttBrokerDTO mqttBroker;
+
+ /**
+ * range: 1 - 30
+ */
+ @Builder.Default
+ private Integer osdFrequency = 10;
+
+ /**
+ * range: 1 - 30
+ */
+ @Builder.Default
+ private Integer hsiFrequency = 1;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/DrcModeReasonReceiver.java b/src/main/java/com/dji/sample/control/model/dto/DrcModeReasonReceiver.java
new file mode 100644
index 0000000..26429a9
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/DrcModeReasonReceiver.java
@@ -0,0 +1,15 @@
+package com.dji.sample.control.model.dto;
+
+import com.dji.sample.control.model.enums.DrcModeReasonEnum;
+import lombok.Data;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/14
+ */
+@Data
+public class DrcModeReasonReceiver {
+
+ private DrcModeReasonEnum reason;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/DrcStatusNotifyReceiver.java b/src/main/java/com/dji/sample/control/model/dto/DrcStatusNotifyReceiver.java
new file mode 100644
index 0000000..1ef8c04
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/DrcStatusNotifyReceiver.java
@@ -0,0 +1,18 @@
+package com.dji.sample.control.model.dto;
+
+import com.dji.sample.control.model.enums.DrcStatusErrorEnum;
+import com.dji.sample.manage.model.enums.DockDrcStateEnum;
+import lombok.Data;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/17
+ */
+@Data
+public class DrcStatusNotifyReceiver {
+
+ private DrcStatusErrorEnum result;
+
+ private DockDrcStateEnum drcState;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/FlyToProgressReceiver.java b/src/main/java/com/dji/sample/control/model/dto/FlyToProgressReceiver.java
new file mode 100644
index 0000000..f51fbf6
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/FlyToProgressReceiver.java
@@ -0,0 +1,22 @@
+package com.dji.sample.control.model.dto;
+
+import com.dji.sample.control.model.enums.FlyToStatusEnum;
+import com.dji.sample.wayline.model.enums.WaylineErrorCodeEnum;
+import lombok.Data;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/14
+ */
+@Data
+public class FlyToProgressReceiver {
+
+ private WaylineErrorCodeEnum result;
+
+ private FlyToStatusEnum status;
+
+ private String flyToId;
+
+ private Integer wayPointIndex;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/JwtAclDTO.java b/src/main/java/com/dji/sample/control/model/dto/JwtAclDTO.java
new file mode 100644
index 0000000..9bc6959
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/JwtAclDTO.java
@@ -0,0 +1,26 @@
+package com.dji.sample.control.model.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/12
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class JwtAclDTO {
+
+ private List sub;
+
+ private List pub;
+
+ private List all;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/LinkWorkMode.java b/src/main/java/com/dji/sample/control/model/dto/LinkWorkMode.java
index 00cb354..884330d 100644
--- a/src/main/java/com/dji/sample/control/model/dto/LinkWorkMode.java
+++ b/src/main/java/com/dji/sample/control/model/dto/LinkWorkMode.java
@@ -1,7 +1,7 @@
package com.dji.sample.control.model.dto;
import com.dji.sample.control.model.enums.LinkWorkModeEnum;
-import com.dji.sample.manage.model.receiver.BasicDeviceProperty;
+import com.dji.sample.control.service.impl.RemoteDebugHandler;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -19,7 +19,7 @@ import java.util.Objects;
@Data
@AllArgsConstructor
@NoArgsConstructor
-public class LinkWorkMode extends BasicDeviceProperty {
+public class LinkWorkMode extends RemoteDebugHandler {
@JsonProperty("link_workmode")
private Integer linkWorkMode;
diff --git a/src/main/java/com/dji/sample/control/model/dto/MqttBrokerDTO.java b/src/main/java/com/dji/sample/control/model/dto/MqttBrokerDTO.java
new file mode 100644
index 0000000..af19dba
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/MqttBrokerDTO.java
@@ -0,0 +1,31 @@
+package com.dji.sample.control.model.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/11
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class MqttBrokerDTO {
+
+ private String address;
+
+ private String username;
+
+ private String password;
+
+ private String clientId;
+
+ private Long expireTime;
+
+ @Builder.Default
+ private Boolean enableTls = false;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/PointDTO.java b/src/main/java/com/dji/sample/control/model/dto/PointDTO.java
new file mode 100644
index 0000000..8c6acaf
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/PointDTO.java
@@ -0,0 +1,31 @@
+package com.dji.sample.control.model.dto;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/2/14
+ */
+@Data
+public class PointDTO {
+
+ @Range(min = -90, max = 90)
+ @NotNull
+ private Double latitude;
+
+ @NotNull
+ @Range(min = -180, max = 180)
+ private Double longitude;
+
+ /**
+ * WGS84
+ * The M30 series are ellipsoidal heights.
+ */
+ @NotNull
+ @Range(min = 2, max = 1500)
+ private Double height;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/RemoteDebugOpenState.java b/src/main/java/com/dji/sample/control/model/dto/RemoteDebugOpenState.java
new file mode 100644
index 0000000..069307d
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/RemoteDebugOpenState.java
@@ -0,0 +1,25 @@
+package com.dji.sample.control.model.dto;
+
+import com.dji.sample.common.util.SpringBeanUtils;
+import com.dji.sample.control.service.impl.RemoteDebugHandler;
+import com.dji.sample.manage.model.enums.DockModeCodeEnum;
+import com.dji.sample.manage.service.IDeviceService;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/14
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class RemoteDebugOpenState extends RemoteDebugHandler {
+
+ @Override
+ public boolean canPublish(String sn) {
+ IDeviceService deviceService = SpringBeanUtils.getBean(IDeviceService.class);
+ DockModeCodeEnum dockMode = deviceService.getDockMode(sn);
+ return DockModeCodeEnum.IDLE == dockMode;
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/ResultNotifyDTO.java b/src/main/java/com/dji/sample/control/model/dto/ResultNotifyDTO.java
new file mode 100644
index 0000000..0de9461
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/ResultNotifyDTO.java
@@ -0,0 +1,24 @@
+package com.dji.sample.control.model.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/1
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ResultNotifyDTO {
+
+ private Integer result;
+
+ private String message;
+
+ private String sn;
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/ReturnHomeState.java b/src/main/java/com/dji/sample/control/model/dto/ReturnHomeState.java
new file mode 100644
index 0000000..66957ab
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/ReturnHomeState.java
@@ -0,0 +1,27 @@
+package com.dji.sample.control.model.dto;
+
+import com.dji.sample.common.util.SpringBeanUtils;
+import com.dji.sample.control.service.impl.RemoteDebugHandler;
+import com.dji.sample.manage.model.dto.DeviceDTO;
+import com.dji.sample.manage.model.receiver.OsdSubDeviceReceiver;
+import com.dji.sample.manage.service.IDeviceRedisService;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/19
+ */
+
+public class ReturnHomeState extends RemoteDebugHandler {
+
+ @Override
+ public boolean canPublish(String sn) {
+ IDeviceRedisService deviceRedisService = SpringBeanUtils.getBean(IDeviceRedisService.class);
+ return deviceRedisService.getDeviceOnline(sn)
+ .map(DeviceDTO::getChildDeviceSn)
+ .flatMap(deviceSn -> deviceRedisService.getDeviceOsd(deviceSn, OsdSubDeviceReceiver.class))
+ .map(OsdSubDeviceReceiver::getElevation)
+ .map(elevation -> elevation > 0)
+ .orElse(false);
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/dto/TakeoffProgressReceiver.java b/src/main/java/com/dji/sample/control/model/dto/TakeoffProgressReceiver.java
new file mode 100644
index 0000000..e4f5a83
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/dto/TakeoffProgressReceiver.java
@@ -0,0 +1,25 @@
+package com.dji.sample.control.model.dto;
+
+import com.dji.sample.control.model.enums.TakeoffStatusEnum;
+import com.dji.sample.wayline.model.enums.WaylineErrorCodeEnum;
+import lombok.Data;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/14
+ */
+@Data
+public class TakeoffProgressReceiver {
+
+ private WaylineErrorCodeEnum result;
+
+ private TakeoffStatusEnum status;
+
+ private String flightId;
+
+ private String trackId;
+
+ private Integer wayPointIndex;
+
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/CameraModeEnum.java b/src/main/java/com/dji/sample/control/model/enums/CameraModeEnum.java
new file mode 100644
index 0000000..a6dfe3c
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/CameraModeEnum.java
@@ -0,0 +1,26 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/3
+ */
+public enum CameraModeEnum {
+
+ PHOTO, VIDEO;
+
+ @JsonValue
+ public int getVal() {
+ return ordinal();
+ }
+
+ @JsonCreator
+ public static CameraModeEnum find(int val) {
+ return Arrays.stream(values()).filter(modeEnum -> modeEnum.ordinal() == val).findAny().get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/CameraStateEnum.java b/src/main/java/com/dji/sample/control/model/enums/CameraStateEnum.java
new file mode 100644
index 0000000..fbe9f1a
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/CameraStateEnum.java
@@ -0,0 +1,26 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/23
+ */
+public enum CameraStateEnum {
+
+ IDLE, WORKING;
+
+ @JsonValue
+ public int getVal() {
+ return ordinal();
+ }
+
+ @JsonCreator
+ public static CameraStateEnum find(int val) {
+ return Arrays.stream(values()).filter(stateEnum -> stateEnum.ordinal() == val).findAny().get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/CameraTypeEnum.java b/src/main/java/com/dji/sample/control/model/enums/CameraTypeEnum.java
new file mode 100644
index 0000000..cda43e1
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/CameraTypeEnum.java
@@ -0,0 +1,38 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/3
+ */
+@Getter
+public enum CameraTypeEnum {
+
+ ZOOM("zoom"),
+
+ WIDE("wide"),
+
+ IR("ir");
+
+ String type;
+
+ CameraTypeEnum(String type) {
+ this.type = type;
+ }
+
+ @JsonValue
+ public String getType() {
+ return type;
+ }
+
+ @JsonCreator
+ public static CameraTypeEnum find(String cameraType) {
+ return Arrays.stream(CameraTypeEnum.values()).filter(typeEnum -> typeEnum.type.equals(cameraType)).findAny().get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/DrcMethodEnum.java b/src/main/java/com/dji/sample/control/model/enums/DrcMethodEnum.java
new file mode 100644
index 0000000..93697d7
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/DrcMethodEnum.java
@@ -0,0 +1,22 @@
+package com.dji.sample.control.model.enums;
+
+import lombok.Getter;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/11
+ */
+@Getter
+public enum DrcMethodEnum {
+
+ DRC_MODE_ENTER("drc_mode_enter"),
+
+ DRC_MODE_EXIT("drc_mode_exit");
+
+ String method;
+
+ DrcMethodEnum(String method) {
+ this.method = method;
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/DrcModeReasonEnum.java b/src/main/java/com/dji/sample/control/model/enums/DrcModeReasonEnum.java
new file mode 100644
index 0000000..ceb20ac
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/DrcModeReasonEnum.java
@@ -0,0 +1,47 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/14
+ */
+public enum DrcModeReasonEnum {
+
+ UNKNOWN(-1, "unknown"),
+
+ RC_LOST(0, "The remote controller is lost."),
+
+ BATTERY_LOW_GO_HOME(1, "Due to low battery, the drone automatically returned home."),
+
+ BATTERY_SUPER_LOW_LANDING(2, "Due to the serious low battery, the drone landed automatically."),
+
+ NEAR_BOUNDARY(3, "The drone is near a not-fly zone."),
+
+ RC_AUTHORITY(4, "The remote controller grabs control authority.");
+
+ int val;
+
+ String message;
+
+ DrcModeReasonEnum(int val, String message) {
+ this.val = val;
+ this.message = message;
+ }
+
+ public int getVal() {
+ return val;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
+ public static DrcModeReasonEnum find(int val) {
+ return Arrays.stream(values()).filter(reasonEnum -> reasonEnum.val == val).findAny().orElse(UNKNOWN);
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/DrcStatusErrorEnum.java b/src/main/java/com/dji/sample/control/model/enums/DrcStatusErrorEnum.java
new file mode 100644
index 0000000..1cee634
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/DrcStatusErrorEnum.java
@@ -0,0 +1,52 @@
+package com.dji.sample.control.model.enums;
+
+import com.dji.sample.common.error.IErrorInfo;
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/17
+ */
+public enum DrcStatusErrorEnum implements IErrorInfo {
+
+ SUCCESS(0, "success"),
+
+ MQTT_ERR(514300, "The mqtt connection error."),
+
+ HEARTBEAT_TIMEOUT(514301, "The heartbeat times out and the dock disconnects."),
+
+ MQTT_CERTIFICATE_ERR(514302, "The mqtt certificate is abnormal and the connection fails."),
+
+ MQTT_LOST(514303, "The dock network is abnormal and the mqtt connection is lost."),
+
+ MQTT_REFUSE(514304, "The dock connection to mqtt server was refused."),
+
+ UNKNOWN(-1, "Unknown");
+
+ String msg;
+
+ int code;
+
+ DrcStatusErrorEnum(int code, String msg) {
+ this.code = code;
+ this.msg = msg;
+ }
+
+ @Override
+ public String getErrorMsg() {
+ return msg;
+ }
+
+ @Override
+ public Integer getErrorCode() {
+ return code;
+ }
+
+ @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
+ public static DrcStatusErrorEnum find(int code) {
+ return Arrays.stream(values()).filter(error -> error.code == code).findAny().orElse(UNKNOWN);
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/DroneAuthorityEnum.java b/src/main/java/com/dji/sample/control/model/enums/DroneAuthorityEnum.java
new file mode 100644
index 0000000..e751f7e
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/DroneAuthorityEnum.java
@@ -0,0 +1,25 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/1
+ */
+public enum DroneAuthorityEnum {
+
+ FLIGHT(1), PAYLOAD(2);
+
+ int val;
+
+ DroneAuthorityEnum(int val) {
+ this.val = val;
+ }
+
+ @JsonValue
+ public int getVal() {
+ return val;
+ }
+
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/DroneControlMethodEnum.java b/src/main/java/com/dji/sample/control/model/enums/DroneControlMethodEnum.java
new file mode 100644
index 0000000..dcb6a21
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/DroneControlMethodEnum.java
@@ -0,0 +1,28 @@
+package com.dji.sample.control.model.enums;
+
+import lombok.Getter;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/2/21
+ */
+@Getter
+public enum DroneControlMethodEnum {
+
+ FLIGHT_AUTHORITY_GRAB("flight_authority_grab"),
+
+ PAYLOAD_AUTHORITY_GRAB("payload_authority_grab"),
+
+ FLY_TO_POINT("fly_to_point"),
+
+ FLY_TO_POINT_STOP("fly_to_point_stop"),
+
+ TAKE_OFF_TO_POINT("takeoff_to_point");
+
+ String method;
+
+ DroneControlMethodEnum(String method) {
+ this.method = method;
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/FlyToStatusEnum.java b/src/main/java/com/dji/sample/control/model/enums/FlyToStatusEnum.java
new file mode 100644
index 0000000..4291769
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/FlyToStatusEnum.java
@@ -0,0 +1,39 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/14
+ */
+public enum FlyToStatusEnum {
+
+ WAYLINE_PROGRESS("wayline_progress", "The FlyTo job is in progress."),
+
+ WAYLINE_FAILED("wayline_failed", "The Fly To task execution failed."),
+
+ WAYLINE_OK("wayline_ok", "The FlyTo job executed successfully."),
+
+ WAYLINE_CANCEL("wayline_cancel", "The FlyTo job is closed.");
+
+ String status;
+
+ String message;
+
+ FlyToStatusEnum(String status, String message) {
+ this.status = status;
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
+ public static FlyToStatusEnum find(String status) {
+ return Arrays.stream(values()).filter(statusEnum -> statusEnum.status.equals(status)).findAny().get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/GimbalResetModeEnum.java b/src/main/java/com/dji/sample/control/model/enums/GimbalResetModeEnum.java
new file mode 100644
index 0000000..2c7e9dd
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/GimbalResetModeEnum.java
@@ -0,0 +1,26 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/13
+ */
+public enum GimbalResetModeEnum {
+
+ RECENTER, DOWN, RECENTER_PAN, PITCH_DOWN;
+
+ @JsonValue
+ public int getVal() {
+ return ordinal();
+ }
+
+ @JsonCreator
+ public static GimbalResetModeEnum find(int value) {
+ return Arrays.stream(values()).filter(resetModeEnum -> resetModeEnum.ordinal() == value).findAny().get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/MqttAclAccessEnum.java b/src/main/java/com/dji/sample/control/model/enums/MqttAclAccessEnum.java
new file mode 100644
index 0000000..771e4dc
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/MqttAclAccessEnum.java
@@ -0,0 +1,24 @@
+package com.dji.sample.control.model.enums;
+
+import lombok.Getter;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/13
+ */
+@Getter
+public enum MqttAclAccessEnum {
+
+ SUB(1),
+
+ PUB(2),
+
+ ALL(3);
+
+ int value;
+
+ MqttAclAccessEnum(int value) {
+ this.value = value;
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/PayloadCommandsEnum.java b/src/main/java/com/dji/sample/control/model/enums/PayloadCommandsEnum.java
new file mode 100644
index 0000000..1f1241f
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/PayloadCommandsEnum.java
@@ -0,0 +1,52 @@
+package com.dji.sample.control.model.enums;
+
+import com.dji.sample.control.service.impl.*;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/2
+ */
+public enum PayloadCommandsEnum {
+
+ CAMERA_MODE_SWitCH("camera_mode_switch", CameraModeSwitchImpl.class),
+
+ CAMERA_PHOTO_TAKE("camera_photo_take", CameraPhotoTakeImpl.class),
+
+ CAMERA_RECORDING_START("camera_recording_start", CameraRecordingStartImpl.class),
+
+ CAMERA_RECORDING_STOP("camera_recording_stop", CameraRecordingStopImpl.class),
+
+ CAMERA_AIM("camera_aim", CameraAimImpl.class),
+
+ CAMERA_FOCAL_LENGTH_SET("camera_focal_length_set", CameraFocalLengthSetImpl.class),
+
+ GIMBAL_RESET("gimbal_reset", GimbalResetImpl.class);
+
+ String cmd;
+
+ Class extends PayloadCommandsHandler> clazz;
+
+ PayloadCommandsEnum(String cmd, Class extends PayloadCommandsHandler> clazz) {
+ this.cmd = cmd;
+ this.clazz = clazz;
+ }
+
+ @JsonValue
+ public String getCmd() {
+ return cmd;
+ }
+
+ public Class extends PayloadCommandsHandler> getClazz() {
+ return clazz;
+ }
+
+ @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
+ public static PayloadCommandsEnum find(String cmd) {
+ return Arrays.stream(values()).filter(cmdEnum -> cmdEnum.cmd.equals(cmd)).findAny().get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/enums/RemoteControlMethodEnum.java b/src/main/java/com/dji/sample/control/model/enums/RemoteDebugMethodEnum.java
similarity index 70%
rename from src/main/java/com/dji/sample/control/model/enums/RemoteControlMethodEnum.java
rename to src/main/java/com/dji/sample/control/model/enums/RemoteDebugMethodEnum.java
index 130239c..3bfed6e 100644
--- a/src/main/java/com/dji/sample/control/model/enums/RemoteControlMethodEnum.java
+++ b/src/main/java/com/dji/sample/control/model/enums/RemoteDebugMethodEnum.java
@@ -1,9 +1,7 @@
package com.dji.sample.control.model.enums;
-import com.dji.sample.control.model.dto.AlarmState;
-import com.dji.sample.control.model.dto.BatteryStoreMode;
-import com.dji.sample.control.model.dto.LinkWorkMode;
-import com.dji.sample.manage.model.receiver.BasicDeviceProperty;
+import com.dji.sample.control.model.dto.*;
+import com.dji.sample.control.service.impl.RemoteDebugHandler;
import lombok.Getter;
import java.util.Arrays;
@@ -14,9 +12,9 @@ import java.util.Arrays;
* @date 2022/11/14
*/
@Getter
-public enum RemoteControlMethodEnum {
+public enum RemoteDebugMethodEnum {
- DEBUG_MODE_OPEN("debug_mode_open", false, null),
+ DEBUG_MODE_OPEN("debug_mode_open", false, RemoteDebugOpenState.class),
DEBUG_MODE_CLOSE("debug_mode_close", false, null),
@@ -24,7 +22,7 @@ public enum RemoteControlMethodEnum {
SUPPLEMENT_LIGHT_CLOSE("supplement_light_close", false, null),
- RETURN_HOME("return_home", false, null),
+ RETURN_HOME("return_home", false, ReturnHomeState.class),
DEVICE_REBOOT("device_reboot", true, null),
@@ -64,16 +62,16 @@ public enum RemoteControlMethodEnum {
private Boolean progress;
- private Class extends BasicDeviceProperty> clazz;
+ private Class extends RemoteDebugHandler> clazz;
- RemoteControlMethodEnum(String method, Boolean progress, Class extends BasicDeviceProperty> clazz) {
+ RemoteDebugMethodEnum(String method, Boolean progress, Class extends RemoteDebugHandler> clazz) {
this.method = method;
this.progress = progress;
this.clazz = clazz;
}
- public static RemoteControlMethodEnum find(String method) {
- return Arrays.stream(RemoteControlMethodEnum.values())
+ public static RemoteDebugMethodEnum find(String method) {
+ return Arrays.stream(RemoteDebugMethodEnum.values())
.filter(methodEnum -> methodEnum.method.equals(method))
.findAny()
.orElse(UNKNOWN);
diff --git a/src/main/java/com/dji/sample/control/model/enums/TakeoffStatusEnum.java b/src/main/java/com/dji/sample/control/model/enums/TakeoffStatusEnum.java
new file mode 100644
index 0000000..94ae3de
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/enums/TakeoffStatusEnum.java
@@ -0,0 +1,47 @@
+package com.dji.sample.control.model.enums;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+
+import java.util.Arrays;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/17
+ */
+public enum TakeoffStatusEnum {
+
+ TASK_READY("task_ready", "The drone is preparing to take off."),
+
+ WAYLINE_PROGRESS("wayline_progress", "The drone is taking off."),
+
+ WAYLINE_FAILED("wayline_failed", "The drone failed to take off."),
+
+ WAYLINE_OK("wayline_ok", "The drone took off successfully."),
+
+ WAYLINE_CANCEL("wayline_cancel", "The drone takeoff job has been cancelled."),
+
+ TASK_FINISH("task_finish", "The drone takeoff job is completed.");
+
+ String status;
+
+ String message;
+
+ TakeoffStatusEnum(String status, String message) {
+ this.status = status;
+ this.message = message;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
+ public static TakeoffStatusEnum find(String status) {
+ return Arrays.stream(values()).filter(statusEnum -> statusEnum.status.equals(status)).findAny().get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/model/param/DeviceDrcInfoParam.java b/src/main/java/com/dji/sample/control/model/param/DeviceDrcInfoParam.java
new file mode 100644
index 0000000..05930f0
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/param/DeviceDrcInfoParam.java
@@ -0,0 +1,19 @@
+package com.dji.sample.control.model.param;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/2/2
+ */
+@Data
+public class DeviceDrcInfoParam {
+
+ @Range(min = 1, max = 30)
+ private Integer osdFrequency = 10;
+
+ @Range(min = 1, max = 30)
+ private Integer hsiFrequency = 1;
+}
diff --git a/src/main/java/com/dji/sample/control/model/param/DrcConnectParam.java b/src/main/java/com/dji/sample/control/model/param/DrcConnectParam.java
new file mode 100644
index 0000000..3aa7926
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/param/DrcConnectParam.java
@@ -0,0 +1,19 @@
+package com.dji.sample.control.model.param;
+
+import com.dji.sample.component.redis.RedisConst;
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/11
+ */
+@Data
+public class DrcConnectParam {
+
+ private String clientId;
+
+ @Range(min = 1800, max = 86400)
+ private long expireSec = RedisConst.DRC_MODE_ALIVE_SECOND;
+}
diff --git a/src/main/java/com/dji/sample/control/model/param/DrcModeParam.java b/src/main/java/com/dji/sample/control/model/param/DrcModeParam.java
new file mode 100644
index 0000000..a750dc5
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/param/DrcModeParam.java
@@ -0,0 +1,35 @@
+package com.dji.sample.control.model.param;
+
+import com.dji.sample.component.redis.RedisConst;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/11
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DrcModeParam {
+
+ @NotBlank
+ private String clientId;
+
+ @NotBlank
+ private String dockSn;
+
+ @Range(min = 1800, max = 86400)
+ private long expireSec = RedisConst.DRC_MODE_ALIVE_SECOND;
+
+ @Valid
+ private DeviceDrcInfoParam deviceInfo = new DeviceDrcInfoParam();
+}
diff --git a/src/main/java/com/dji/sample/control/model/param/DronePayloadParam.java b/src/main/java/com/dji/sample/control/model/param/DronePayloadParam.java
new file mode 100644
index 0000000..97d156e
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/param/DronePayloadParam.java
@@ -0,0 +1,54 @@
+package com.dji.sample.control.model.param;
+
+import com.dji.sample.control.model.enums.CameraModeEnum;
+import com.dji.sample.control.model.enums.CameraTypeEnum;
+import com.dji.sample.control.model.enums.GimbalResetModeEnum;
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/1
+ */
+@Data
+public class DronePayloadParam {
+
+ @Pattern(regexp = "\\d+-\\d+-\\d+")
+ @NotNull
+ private String payloadIndex;
+
+ private CameraTypeEnum cameraType;
+
+ @Range(min = 2, max = 200)
+ private Float zoomFactor;
+
+ private CameraModeEnum cameraMode;
+
+ /**
+ * true: Lock the gimbal, the gimbal and the drone rotate together.
+ * false: Only the gimbal rotates, but the drone does not.
+ */
+ private Boolean locked;
+
+ private Double pitchSpeed;
+
+ /**
+ * Only valid when locked is false.
+ */
+ private Double yawSpeed;
+
+ /**
+ * upper left corner as center point
+ */
+ @Range(min = 0, max = 1)
+ private Double x;
+
+ @Range(min = 0, max = 1)
+ private Double y;
+
+ private GimbalResetModeEnum resetMode;
+}
diff --git a/src/main/java/com/dji/sample/control/model/param/FlyToPointParam.java b/src/main/java/com/dji/sample/control/model/param/FlyToPointParam.java
new file mode 100644
index 0000000..98b03e1
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/param/FlyToPointParam.java
@@ -0,0 +1,37 @@
+package com.dji.sample.control.model.param;
+
+import com.dji.sample.control.model.dto.PointDTO;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.List;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/2/14
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class FlyToPointParam {
+
+ private String flyToId;
+
+ @Range(min = 1, max = 15)
+ @NotNull
+ private Integer maxSpeed;
+
+ /**
+ * The M30 series only support one point.
+ */
+ @Size(min = 1)
+ @Valid
+ @NotNull
+ private List points;
+}
diff --git a/src/main/java/com/dji/sample/control/model/param/PayloadCommandsParam.java b/src/main/java/com/dji/sample/control/model/param/PayloadCommandsParam.java
new file mode 100644
index 0000000..f5c4a6e
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/param/PayloadCommandsParam.java
@@ -0,0 +1,27 @@
+package com.dji.sample.control.model.param;
+
+import com.dji.sample.control.model.enums.PayloadCommandsEnum;
+import lombok.Data;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/2
+ */
+@Data
+public class PayloadCommandsParam {
+
+ private String sn;
+
+ @NotNull
+ @Valid
+ private PayloadCommandsEnum cmd;
+
+ @Valid
+ @NotNull
+ private DronePayloadParam data;
+
+}
diff --git a/src/main/java/com/dji/sample/control/model/param/TakeoffToPointParam.java b/src/main/java/com/dji/sample/control/model/param/TakeoffToPointParam.java
new file mode 100644
index 0000000..4de1273
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/model/param/TakeoffToPointParam.java
@@ -0,0 +1,49 @@
+package com.dji.sample.control.model.param;
+
+import com.dji.sample.manage.model.enums.DroneRcLostActionEnum;
+import com.dji.sample.manage.model.enums.WaylineRcLostActionEnum;
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/3/1
+ */
+@Data
+public class TakeoffToPointParam {
+
+ private String flightId;
+
+ @Range(min = -180, max = 180)
+ @NotNull
+ private Double targetLongitude;
+
+ @Range(min = -90, max = 90)
+ @NotNull
+ private Double targetLatitude;
+
+ @Range(min = 2, max = 1500)
+ @NotNull
+ private Double targetHeight;
+
+ @Range(min = 2, max = 1500)
+ @NotNull
+ private Double securityTakeoffHeight;
+
+ @Range(min = 2, max = 1500)
+ @NotNull
+ private Double rthAltitude;
+
+ @NotNull
+ private DroneRcLostActionEnum rcLostAction;
+
+ @NotNull
+ private WaylineRcLostActionEnum exitWaylineWhenRcLost;
+
+ @Range(min = 1, max = 15)
+ @NotNull
+ private Double maxSpeed;
+}
diff --git a/src/main/java/com/dji/sample/control/service/IControlService.java b/src/main/java/com/dji/sample/control/service/IControlService.java
index f04c138..f9e122b 100644
--- a/src/main/java/com/dji/sample/control/service/IControlService.java
+++ b/src/main/java/com/dji/sample/control/service/IControlService.java
@@ -2,7 +2,8 @@ package com.dji.sample.control.service;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
-import com.dji.sample.control.model.param.RemoteDebugParam;
+import com.dji.sample.control.model.enums.DroneAuthorityEnum;
+import com.dji.sample.control.model.param.*;
import org.springframework.messaging.MessageHeaders;
/**
@@ -19,13 +20,60 @@ public interface IControlService {
* @param param
* @return
*/
- ResponseResult controlDock(String sn, String serviceIdentifier, RemoteDebugParam param);
+ ResponseResult controlDockDebug(String sn, String serviceIdentifier, RemoteDebugParam param);
/**
- * Handles multi-state command progress information.
+ * Make the drone fly to the target point.
+ * @param sn
+ * @param param
+ * @return
+ */
+ ResponseResult flyToPoint(String sn, FlyToPointParam param);
+
+ /**
+ * End the mission of flying the drone to the target point.
+ * @param sn
+ * @return
+ */
+ ResponseResult flyToPointStop(String sn);
+
+ /**
+ * Handle progress result notifications for fly to target point.
+ * @param receiver
+ * @param headers
+ * @return
+ */
+ CommonTopicReceiver handleFlyToPointProgress(CommonTopicReceiver receiver, MessageHeaders headers);
+
+ /**
+ * Control the drone to take off.
+ * @param sn
+ * @param param
+ * @return
+ */
+ ResponseResult takeoffToPoint(String sn, TakeoffToPointParam param);
+
+ /**
+ * Handle progress result notifications for takeoff to target point.
* @param receiver
* @param headers
+ * @return
*/
- void handleControlProgress(CommonTopicReceiver receiver, MessageHeaders headers);
+ CommonTopicReceiver handleTakeoffToPointProgress(CommonTopicReceiver receiver, MessageHeaders headers);
+ /**
+ * Seize the control authority of the drone or the payload control authority.
+ * @param sn
+ * @param authority
+ * @param param
+ * @return
+ */
+ ResponseResult seizeAuthority(String sn, DroneAuthorityEnum authority, DronePayloadParam param);
+
+ /**
+ * Control the payload of the drone.
+ * @param param
+ * @return
+ */
+ ResponseResult payloadCommands(PayloadCommandsParam param) throws Exception;
}
diff --git a/src/main/java/com/dji/sample/control/service/IDrcService.java b/src/main/java/com/dji/sample/control/service/IDrcService.java
new file mode 100644
index 0000000..505f526
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/IDrcService.java
@@ -0,0 +1,60 @@
+package com.dji.sample.control.service;
+
+import com.dji.sample.control.model.dto.JwtAclDTO;
+import com.dji.sample.control.model.dto.MqttBrokerDTO;
+import com.dji.sample.control.model.param.DrcConnectParam;
+import com.dji.sample.control.model.param.DrcModeParam;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/11
+ */
+public interface IDrcService {
+
+ /**
+ * Save the drc mode of dock in redis.
+ * @param dockSn
+ * @param clientId
+ */
+ void setDrcModeInRedis(String dockSn, String clientId);
+
+ /**
+ * Query the client that is controlling the dock.
+ * @param dockSn
+ * @return clientId
+ */
+ String getDrcModeInRedis(String dockSn);
+
+ /**
+ * Delete the drc mode of dock in redis.
+ * @param dockSn
+ * @return
+ */
+ Boolean delDrcModeInRedis(String dockSn);
+
+ /**
+ * Provide mqtt options for the control terminal.
+ * @param workspaceId
+ * @param userId
+ * @param username
+ * @param param
+ * @return
+ */
+ MqttBrokerDTO userDrcAuth(String workspaceId, String userId, String username, DrcConnectParam param);
+
+ /**
+ * Make the dock enter drc mode. And grant relevant permissions.
+ * @param workspaceId
+ * @param param
+ * @return
+ */
+ JwtAclDTO deviceDrcEnter(String workspaceId, DrcModeParam param);
+
+ /**
+ * Make the dock exit drc mode.
+ * @param workspaceId
+ * @param param
+ */
+ void deviceDrcExit(String workspaceId, DrcModeParam param);
+}
diff --git a/src/main/java/com/dji/sample/control/service/impl/CameraAimImpl.java b/src/main/java/com/dji/sample/control/service/impl/CameraAimImpl.java
new file mode 100644
index 0000000..4afb448
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/impl/CameraAimImpl.java
@@ -0,0 +1,24 @@
+package com.dji.sample.control.service.impl;
+
+import com.dji.sample.control.model.param.DronePayloadParam;
+
+import java.util.Objects;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/23
+ */
+public class CameraAimImpl extends PayloadCommandsHandler {
+
+ public CameraAimImpl(DronePayloadParam param) {
+ super(param);
+ }
+
+ @Override
+ public boolean valid() {
+ return Objects.nonNull(param.getX()) && Objects.nonNull(param.getY())
+ && Objects.nonNull(param.getLocked()) && Objects.nonNull(param.getCameraType());
+ }
+
+}
diff --git a/src/main/java/com/dji/sample/control/service/impl/CameraFocalLengthSetImpl.java b/src/main/java/com/dji/sample/control/service/impl/CameraFocalLengthSetImpl.java
new file mode 100644
index 0000000..d8b1450
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/impl/CameraFocalLengthSetImpl.java
@@ -0,0 +1,41 @@
+package com.dji.sample.control.service.impl;
+
+import com.dji.sample.control.model.enums.CameraStateEnum;
+import com.dji.sample.control.model.enums.CameraTypeEnum;
+import com.dji.sample.control.model.param.DronePayloadParam;
+
+import java.util.Objects;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/23
+ */
+public class CameraFocalLengthSetImpl extends PayloadCommandsHandler {
+
+ public CameraFocalLengthSetImpl(DronePayloadParam param) {
+ super(param);
+ }
+
+ @Override
+ public boolean valid() {
+ return Objects.nonNull(param.getCameraType()) && Objects.nonNull(param.getZoomFactor())
+ && (CameraTypeEnum.ZOOM == param.getCameraType()
+ || CameraTypeEnum.IR == param.getCameraType());
+ }
+
+ @Override
+ public boolean canPublish(String deviceSn) {
+ super.canPublish(deviceSn);
+ if (CameraStateEnum.WORKING == osdCamera.getPhotoState()) {
+ return false;
+ }
+ switch (param.getCameraType()) {
+ case IR:
+ return param.getZoomFactor().intValue() != osdCamera.getIrZoomFactor();
+ case ZOOM:
+ return param.getZoomFactor().intValue() != osdCamera.getZoomFactor();
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/service/impl/CameraModeSwitchImpl.java b/src/main/java/com/dji/sample/control/service/impl/CameraModeSwitchImpl.java
new file mode 100644
index 0000000..b20dbf0
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/impl/CameraModeSwitchImpl.java
@@ -0,0 +1,31 @@
+package com.dji.sample.control.service.impl;
+
+import com.dji.sample.control.model.enums.CameraStateEnum;
+import com.dji.sample.control.model.param.DronePayloadParam;
+
+import java.util.Objects;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/23
+ */
+public class CameraModeSwitchImpl extends PayloadCommandsHandler {
+
+ public CameraModeSwitchImpl(DronePayloadParam param) {
+ super(param);
+ }
+
+ @Override
+ public boolean valid() {
+ return Objects.nonNull(param.getCameraMode());
+ }
+
+ @Override
+ public boolean canPublish(String deviceSn) {
+ super.canPublish(deviceSn);
+ return param.getCameraMode() != osdCamera.getCameraMode()
+ && CameraStateEnum.IDLE == osdCamera.getPhotoState()
+ && CameraStateEnum.IDLE == osdCamera.getRecordingState();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/service/impl/CameraPhotoTakeImpl.java b/src/main/java/com/dji/sample/control/service/impl/CameraPhotoTakeImpl.java
new file mode 100644
index 0000000..79034b3
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/impl/CameraPhotoTakeImpl.java
@@ -0,0 +1,22 @@
+package com.dji.sample.control.service.impl;
+
+import com.dji.sample.control.model.enums.CameraStateEnum;
+import com.dji.sample.control.model.param.DronePayloadParam;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/23
+ */
+public class CameraPhotoTakeImpl extends PayloadCommandsHandler {
+
+ public CameraPhotoTakeImpl(DronePayloadParam param) {
+ super(param);
+ }
+
+ @Override
+ public boolean canPublish(String deviceSn) {
+ super.canPublish(deviceSn);
+ return CameraStateEnum.WORKING != osdCamera.getPhotoState() && osdCamera.getRemainPhotoNum() > 0;
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/service/impl/CameraRecordingStartImpl.java b/src/main/java/com/dji/sample/control/service/impl/CameraRecordingStartImpl.java
new file mode 100644
index 0000000..afe7f79
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/impl/CameraRecordingStartImpl.java
@@ -0,0 +1,25 @@
+package com.dji.sample.control.service.impl;
+
+import com.dji.sample.control.model.enums.CameraModeEnum;
+import com.dji.sample.control.model.enums.CameraStateEnum;
+import com.dji.sample.control.model.param.DronePayloadParam;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/23
+ */
+public class CameraRecordingStartImpl extends PayloadCommandsHandler {
+
+ public CameraRecordingStartImpl(DronePayloadParam param) {
+ super(param);
+ }
+
+ @Override
+ public boolean canPublish(String deviceSn) {
+ super.canPublish(deviceSn);
+ return CameraModeEnum.VIDEO == osdCamera.getCameraMode()
+ && CameraStateEnum.IDLE == osdCamera.getRecordingState()
+ && osdCamera.getRemainRecordDuration() > 0;
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/service/impl/CameraRecordingStopImpl.java b/src/main/java/com/dji/sample/control/service/impl/CameraRecordingStopImpl.java
new file mode 100644
index 0000000..929816b
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/impl/CameraRecordingStopImpl.java
@@ -0,0 +1,22 @@
+package com.dji.sample.control.service.impl;
+
+import com.dji.sample.control.model.enums.CameraStateEnum;
+import com.dji.sample.control.model.param.DronePayloadParam;
+
+/**
+ * @author sean
+ * @version 1.4
+ * @date 2023/4/23
+ */
+public class CameraRecordingStopImpl extends PayloadCommandsHandler {
+
+ public CameraRecordingStopImpl(DronePayloadParam param) {
+ super(param);
+ }
+
+ @Override
+ public boolean canPublish(String deviceSn) {
+ super.canPublish(deviceSn);
+ return CameraStateEnum.WORKING == osdCamera.getRecordingState();
+ }
+}
diff --git a/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java b/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java
index beb1e29..d9d43a7 100644
--- a/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java
+++ b/src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java
@@ -6,26 +6,34 @@ import com.dji.sample.component.mqtt.model.*;
import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.component.redis.RedisConst;
import com.dji.sample.component.redis.RedisOpsUtils;
-import com.dji.sample.component.websocket.model.CustomWebSocketMessage;
+import com.dji.sample.component.websocket.model.BizCodeEnum;
import com.dji.sample.component.websocket.service.ISendMessageService;
-import com.dji.sample.component.websocket.service.IWebSocketManageService;
-import com.dji.sample.control.model.enums.RemoteControlMethodEnum;
-import com.dji.sample.control.model.param.RemoteDebugParam;
+import com.dji.sample.control.model.dto.FlyToProgressReceiver;
+import com.dji.sample.control.model.dto.ResultNotifyDTO;
+import com.dji.sample.control.model.dto.TakeoffProgressReceiver;
+import com.dji.sample.control.model.enums.DroneAuthorityEnum;
+import com.dji.sample.control.model.enums.DroneControlMethodEnum;
+import com.dji.sample.control.model.enums.RemoteDebugMethodEnum;
+import com.dji.sample.control.model.param.*;
import com.dji.sample.control.service.IControlService;
import com.dji.sample.manage.model.dto.DeviceDTO;
+import com.dji.sample.manage.model.enums.DeviceModeCodeEnum;
+import com.dji.sample.manage.model.enums.DockModeCodeEnum;
import com.dji.sample.manage.model.enums.UserTypeEnum;
-import com.dji.sample.manage.model.receiver.BasicDeviceProperty;
+import com.dji.sample.manage.service.IDevicePayloadService;
+import com.dji.sample.manage.service.IDeviceRedisService;
import com.dji.sample.manage.service.IDeviceService;
+import com.dji.sample.wayline.model.enums.WaylineErrorCodeEnum;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.annotation.ServiceActivator;
-import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import java.util.Objects;
+import java.util.Optional;
import java.util.UUID;
/**
@@ -44,55 +52,49 @@ public class ControlServiceImpl implements IControlService {
private ISendMessageService webSocketMessageService;
@Autowired
- private IWebSocketManageService webSocketManageService;
+ private IDeviceService deviceService;
@Autowired
- private IDeviceService deviceService;
+ private IDeviceRedisService deviceRedisService;
@Autowired
private ObjectMapper mapper;
+ @Autowired
+ private IDevicePayloadService devicePayloadService;
+
+ private RemoteDebugHandler checkDebugCondition(String sn, RemoteDebugParam param, RemoteDebugMethodEnum controlMethodEnum) {
+ RemoteDebugHandler handler = Objects.nonNull(controlMethodEnum.getClazz()) ?
+ mapper.convertValue(Objects.nonNull(param) ? param : new Object(), controlMethodEnum.getClazz())
+ : new RemoteDebugHandler();
+ if (!handler.canPublish(sn)) {
+ throw new RuntimeException("The current state of the dock does not support this function.");
+ }
+ if (Objects.nonNull(param) && !handler.valid()) {
+ throw new RuntimeException(CommonErrorEnum.ILLEGAL_ARGUMENT.getErrorMsg());
+ }
+ return handler;
+ }
+
@Override
- public ResponseResult controlDock(String sn, String serviceIdentifier, RemoteDebugParam param) {
- RemoteControlMethodEnum controlMethodEnum = RemoteControlMethodEnum.find(serviceIdentifier);
- if (RemoteControlMethodEnum.UNKNOWN == controlMethodEnum) {
+ public ResponseResult controlDockDebug(String sn, String serviceIdentifier, RemoteDebugParam param) {
+ RemoteDebugMethodEnum controlMethodEnum = RemoteDebugMethodEnum.find(serviceIdentifier);
+ if (RemoteDebugMethodEnum.UNKNOWN == controlMethodEnum) {
return ResponseResult.error("The " + serviceIdentifier + " method does not exist.");
}
- Object data = "";
- // Add parameter validation.
- if (Objects.nonNull(controlMethodEnum.getClazz())) {
- if (Objects.isNull(param)) {
- return ResponseResult.error(CommonErrorEnum.ILLEGAL_ARGUMENT);
- }
- BasicDeviceProperty basicDeviceProperty = mapper.convertValue(param.getAction(), controlMethodEnum.getClazz());
- if (!basicDeviceProperty.valid()) {
- return ResponseResult.error(CommonErrorEnum.ILLEGAL_ARGUMENT);
- }
- data = basicDeviceProperty;
- }
+ RemoteDebugHandler data = checkDebugCondition(sn, param, controlMethodEnum);
- boolean isExist = deviceService.checkDeviceOnline(sn);
+ boolean isExist = deviceRedisService.checkDeviceOnline(sn);
if (!isExist) {
return ResponseResult.error("The dock is offline.");
}
- String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + sn + TopicConst.SERVICES_SUF;
String bid = UUID.randomUUID().toString();
- ServiceReply serviceReplyOpt = messageSenderService.publishWithReply(
- topic, CommonTopicResponse.builder()
- .tid(UUID.randomUUID().toString())
- .bid(bid)
- .method(serviceIdentifier)
- .timestamp(System.currentTimeMillis())
- .data(data)
- .build());
+ ServiceReply serviceReply = messageSenderService.publishServicesTopic(sn, serviceIdentifier, data, bid);
- ServiceReply serviceReply = mapper.convertValue(
- serviceReplyOpt, new TypeReference>() {});
if (ResponseResult.CODE_SUCCESS != serviceReply.getResult()) {
return ResponseResult.error(serviceReply.getResult(),
- Objects.nonNull(serviceReply.getOutput()) ? serviceReply.getOutput().getStatus()
- : "error: " + serviceIdentifier + serviceReply.getResult());
+ "error: " + serviceIdentifier + serviceReply.getResult());
}
if (controlMethodEnum.getProgress()) {
RedisOpsUtils.setWithExpire(serviceIdentifier + RedisConst.DELIMITER + bid, sn,
@@ -101,17 +103,22 @@ public class ControlServiceImpl implements IControlService {
return ResponseResult.success();
}
- @Override
- @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS, outputChannel = ChannelName.OUTBOUND)
- public void handleControlProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
+ /**
+ * Handles multi-state command progress information.
+ * @param receiver
+ * @param headers
+ * @return
+ */
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_CONTROL_PROGRESS, outputChannel = ChannelName.OUTBOUND_EVENTS)
+ public CommonTopicReceiver handleControlProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
String key = receiver.getMethod() + RedisConst.DELIMITER + receiver.getBid();
if (RedisOpsUtils.getExpire(key) <= 0) {
- return;
+ return receiver;
}
String sn = RedisOpsUtils.get(key).toString();
- EventsReceiver eventsReceiver = mapper.convertValue(receiver.getData(),
- new TypeReference>(){});
+ EventsReceiver eventsReceiver = mapper.convertValue(receiver.getData(),
+ new TypeReference>(){});
eventsReceiver.setBid(receiver.getBid());
eventsReceiver.setSn(sn);
@@ -127,26 +134,168 @@ public class ControlServiceImpl implements IControlService {
RedisOpsUtils.del(key);
}
- DeviceDTO device = (DeviceDTO) RedisOpsUtils.get(RedisConst.DEVICE_ONLINE_PREFIX + sn);
- webSocketMessageService.sendBatch(
- webSocketManageService.getValueWithWorkspaceAndUserType(
- device.getWorkspaceId(), UserTypeEnum.WEB.getVal()),
- CustomWebSocketMessage.builder()
- .data(eventsReceiver)
- .timestamp(System.currentTimeMillis())
- .bizCode(receiver.getMethod())
+ Optional deviceOpt = deviceRedisService.getDeviceOnline(sn);
+
+ if (deviceOpt.isEmpty()) {
+ throw new RuntimeException("The device is offline.");
+ }
+
+ DeviceDTO device = deviceOpt.get();
+ webSocketMessageService.sendBatch(device.getWorkspaceId(), UserTypeEnum.WEB.getVal(),
+ receiver.getMethod(), eventsReceiver);
+
+ return receiver;
+ }
+
+ private void checkFlyToCondition(String dockSn) {
+ // TODO 设备固件版本不兼容情况
+ Optional dockOpt = deviceRedisService.getDeviceOnline(dockSn);
+ if (dockOpt.isEmpty()) {
+ throw new RuntimeException("The dock is offline, please restart the dock.");
+ }
+
+ DeviceModeCodeEnum deviceMode = deviceService.getDeviceMode(dockOpt.get().getChildDeviceSn());
+ if (DeviceModeCodeEnum.MANUAL != deviceMode) {
+ throw new RuntimeException("The current state of the drone does not support this function, please try again later.");
+ }
+
+ ResponseResult result = seizeAuthority(dockSn, DroneAuthorityEnum.FLIGHT, null);
+ if (ResponseResult.CODE_SUCCESS != result.getCode()) {
+ throw new IllegalArgumentException(result.getMessage());
+ }
+ }
+
+ @Override
+ public ResponseResult flyToPoint(String sn, FlyToPointParam param) {
+ checkFlyToCondition(sn);
+
+ param.setFlyToId(UUID.randomUUID().toString());
+ ServiceReply reply = messageSenderService.publishServicesTopic(sn, DroneControlMethodEnum.FLY_TO_POINT.getMethod(), param, param.getFlyToId());
+ return ResponseResult.CODE_SUCCESS != reply.getResult() ?
+ ResponseResult.error("Flying to the target point failed." + reply.getResult())
+ : ResponseResult.success();
+ }
+
+ @Override
+ public ResponseResult flyToPointStop(String sn) {
+ ServiceReply reply = messageSenderService.publishServicesTopic(sn, DroneControlMethodEnum.FLY_TO_POINT_STOP.getMethod(), null);
+ return ResponseResult.CODE_SUCCESS != reply.getResult() ?
+ ResponseResult.error("The drone flying to the target point failed to stop. " + reply.getResult())
+ : ResponseResult.success();
+ }
+
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_FLY_TO_POINT_PROGRESS, outputChannel = ChannelName.OUTBOUND_EVENTS)
+ public CommonTopicReceiver handleFlyToPointProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
+ String dockSn = receiver.getGateway();
+
+ Optional deviceOpt = deviceRedisService.getDeviceOnline(dockSn);
+ if (deviceOpt.isEmpty()) {
+ log.error("The dock is offline.");
+ return null;
+ }
+
+ FlyToProgressReceiver eventsReceiver = mapper.convertValue(receiver.getData(), new TypeReference(){});
+ webSocketMessageService.sendBatch(deviceOpt.get().getWorkspaceId(), UserTypeEnum.WEB.getVal(),
+ BizCodeEnum.FLY_TO_POINT_PROGRESS.getCode(),
+ ResultNotifyDTO.builder().sn(dockSn)
+ .message(WaylineErrorCodeEnum.SUCCESS == eventsReceiver.getResult() ?
+ eventsReceiver.getStatus().getMessage() : eventsReceiver.getResult().getErrorMsg())
+ .result(eventsReceiver.getResult().getErrorCode())
+ .build());
+ return receiver;
+ }
+
+ private void checkTakeoffCondition(String dockSn) {
+ Optional dockOpt = deviceRedisService.getDeviceOnline(dockSn);
+ if (dockOpt.isEmpty() || DockModeCodeEnum.IDLE != deviceService.getDockMode(dockSn)) {
+ throw new RuntimeException("The current state does not support takeoff.");
+ }
+
+ ResponseResult result = seizeAuthority(dockSn, DroneAuthorityEnum.FLIGHT, null);
+ if (ResponseResult.CODE_SUCCESS != result.getCode()) {
+ throw new IllegalArgumentException(result.getMessage());
+ }
+
+ }
+
+ @Override
+ public ResponseResult takeoffToPoint(String sn, TakeoffToPointParam param) {
+ checkTakeoffCondition(sn);
+
+ param.setFlightId(UUID.randomUUID().toString());
+ ServiceReply reply = messageSenderService.publishServicesTopic(sn, DroneControlMethodEnum.TAKE_OFF_TO_POINT.getMethod(), param, param.getFlightId());
+ return ResponseResult.CODE_SUCCESS != reply.getResult() ?
+ ResponseResult.error("The drone failed to take off. " + reply.getResult())
+ : ResponseResult.success();
+ }
+
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_TAKE_OFF_TO_POINT_PROGRESS, outputChannel = ChannelName.OUTBOUND_EVENTS)
+ public CommonTopicReceiver handleTakeoffToPointProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
+ String dockSn = receiver.getGateway();
+
+ Optional deviceOpt = deviceRedisService.getDeviceOnline(dockSn);
+ if (deviceOpt.isEmpty()) {
+ log.error("The dock is offline.");
+ return null;
+ }
+ TakeoffProgressReceiver eventsReceiver = mapper.convertValue(receiver.getData(), new TypeReference(){});
+
+ webSocketMessageService.sendBatch(deviceOpt.get().getWorkspaceId(), UserTypeEnum.WEB.getVal(),
+ BizCodeEnum.TAKE_OFF_TO_POINT_PROGRESS.getCode(),
+ ResultNotifyDTO.builder().sn(dockSn)
+ .message(WaylineErrorCodeEnum.SUCCESS == eventsReceiver.getResult() ?
+ eventsReceiver.getStatus().getMessage() : eventsReceiver.getResult().getErrorMsg())
+ .result(eventsReceiver.getResult().getErrorCode())
.build());
- if (receiver.getNeedReply() != null && receiver.getNeedReply() == 1) {
- String topic = headers.get(MqttHeaders.RECEIVED_TOPIC) + TopicConst._REPLY_SUF;
- messageSenderService.publish(topic,
- CommonTopicResponse.builder()
- .tid(receiver.getTid())
- .bid(receiver.getBid())
- .method(receiver.getMethod())
- .timestamp(System.currentTimeMillis())
- .data(RequestsReply.success())
- .build());
+ return receiver;
+ }
+
+ @Override
+ public ResponseResult seizeAuthority(String sn, DroneAuthorityEnum authority, DronePayloadParam param) {
+ String method;
+ switch (authority) {
+ case FLIGHT:
+ if (deviceService.checkAuthorityFlight(sn)) {
+ return ResponseResult.success();
+ }
+ method = DroneControlMethodEnum.FLIGHT_AUTHORITY_GRAB.getMethod();
+ break;
+ case PAYLOAD:
+ if (checkPayloadAuthority(sn, param.getPayloadIndex())) {
+ return ResponseResult.success();
+ }
+ method = DroneControlMethodEnum.PAYLOAD_AUTHORITY_GRAB.getMethod();
+ break;
+ default:
+ return ResponseResult.error(CommonErrorEnum.ILLEGAL_ARGUMENT);
+ }
+ ServiceReply serviceReply = messageSenderService.publishServicesTopic(sn, method, param);
+ return ResponseResult.CODE_SUCCESS != serviceReply.getResult() ?
+ ResponseResult.error(serviceReply.getResult(), "Method: " + method + " Error Code:" + serviceReply.getResult())
+ : ResponseResult.success();
+ }
+
+ private Boolean checkPayloadAuthority(String sn, String payloadIndex) {
+ Optional dockOpt = deviceRedisService.getDeviceOnline(sn);
+ if (dockOpt.isEmpty()) {
+ throw new RuntimeException("The dock is offline, please restart the dock.");
}
+ return devicePayloadService.checkAuthorityPayload(dockOpt.get().getChildDeviceSn(), payloadIndex);
+ }
+
+
+ @Override
+ public ResponseResult payloadCommands(PayloadCommandsParam param) throws Exception {
+ param.getCmd().getClazz()
+ .getDeclaredConstructor(DronePayloadParam.class)
+ .newInstance(param.getData())
+ .checkCondition(param.getSn());
+
+ ServiceReply serviceReply = messageSenderService.publishServicesTopic(param.getSn(), param.getCmd().getCmd(), param.getData());
+ return ResponseResult.CODE_SUCCESS != serviceReply.getResult() ?
+ ResponseResult.error(serviceReply.getResult(), " Error Code:" + serviceReply.getResult())
+ : ResponseResult.success();
}
+
}
diff --git a/src/main/java/com/dji/sample/control/service/impl/DrcServiceImpl.java b/src/main/java/com/dji/sample/control/service/impl/DrcServiceImpl.java
new file mode 100644
index 0000000..7e089cc
--- /dev/null
+++ b/src/main/java/com/dji/sample/control/service/impl/DrcServiceImpl.java
@@ -0,0 +1,249 @@
+package com.dji.sample.control.service.impl;
+
+import com.dji.sample.common.model.ResponseResult;
+import com.dji.sample.component.mqtt.config.MqttConfiguration;
+import com.dji.sample.component.mqtt.model.*;
+import com.dji.sample.component.mqtt.service.IMessageSenderService;
+import com.dji.sample.component.redis.RedisConst;
+import com.dji.sample.component.redis.RedisOpsUtils;
+import com.dji.sample.component.websocket.model.BizCodeEnum;
+import com.dji.sample.component.websocket.service.ISendMessageService;
+import com.dji.sample.control.model.dto.*;
+import com.dji.sample.control.model.enums.DrcMethodEnum;
+import com.dji.sample.control.model.enums.DrcStatusErrorEnum;
+import com.dji.sample.control.model.enums.DroneAuthorityEnum;
+import com.dji.sample.control.model.enums.MqttAclAccessEnum;
+import com.dji.sample.control.model.param.DrcConnectParam;
+import com.dji.sample.control.model.param.DrcModeParam;
+import com.dji.sample.control.service.IControlService;
+import com.dji.sample.control.service.IDrcService;
+import com.dji.sample.manage.model.dto.DeviceDTO;
+import com.dji.sample.manage.model.enums.DockModeCodeEnum;
+import com.dji.sample.manage.model.enums.UserTypeEnum;
+import com.dji.sample.manage.model.receiver.OsdSubDeviceReceiver;
+import com.dji.sample.manage.service.IDeviceRedisService;
+import com.dji.sample.manage.service.IDeviceService;
+import com.dji.sample.wayline.model.dto.WaylineTaskProgressReceiver;
+import com.dji.sample.wayline.model.enums.WaylineJobStatusEnum;
+import com.dji.sample.wayline.model.enums.WaylineTaskStatusEnum;
+import com.dji.sample.wayline.model.param.UpdateJobParam;
+import com.dji.sample.wayline.service.IWaylineJobService;
+import com.dji.sample.wayline.service.IWaylineRedisService;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author sean
+ * @version 1.3
+ * @date 2023/1/11
+ */
+@Service
+@Slf4j
+public class DrcServiceImpl implements IDrcService {
+
+ @Autowired
+ private IMessageSenderService messageSenderService;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private IWaylineJobService waylineJobService;
+
+ @Autowired
+ private IDeviceService deviceService;
+
+ @Autowired
+ private ObjectMapper mapper;
+
+ @Autowired
+ private ISendMessageService webSocketMessageService;
+
+ @Autowired
+ private IControlService controlService;
+
+ @Autowired
+ private IDeviceRedisService deviceRedisService;
+
+ @Autowired
+ private IWaylineRedisService waylineRedisService;
+
+ @Override
+ public void setDrcModeInRedis(String dockSn, String clientId) {
+ RedisOpsUtils.setWithExpire(RedisConst.DRC_PREFIX + dockSn, clientId, RedisConst.DRC_MODE_ALIVE_SECOND);
+ }
+
+ @Override
+ public String getDrcModeInRedis(String dockSn) {
+ return (String) RedisOpsUtils.get(RedisConst.DRC_PREFIX + dockSn);
+ }
+
+ @Override
+ public Boolean delDrcModeInRedis(String dockSn) {
+ return RedisOpsUtils.del(RedisConst.DRC_PREFIX + dockSn);
+ }
+
+ @Override
+ public MqttBrokerDTO userDrcAuth(String workspaceId, String userId, String username, DrcConnectParam param) {
+
+ // refresh token
+ String clientId = param.getClientId();
+ // first time
+ if (!StringUtils.hasText(clientId) || !RedisOpsUtils.checkExist(RedisConst.MQTT_ACL_PREFIX + clientId)) {
+ clientId = userId + "-" + System.currentTimeMillis();
+ RedisOpsUtils.hashSet(RedisConst.MQTT_ACL_PREFIX + clientId, "", MqttAclAccessEnum.ALL.getValue());
+ }
+
+ String key = RedisConst.MQTT_ACL_PREFIX + clientId;
+
+ try {
+ RedisOpsUtils.expireKey(key, RedisConst.DRC_MODE_ALIVE_SECOND);
+
+ return MqttConfiguration.getMqttBrokerWithDrc(
+ clientId, username, param.getExpireSec(), Collections.emptyMap());
+ } catch (RuntimeException e) {
+ RedisOpsUtils.del(key);
+ throw e;
+ }
+ }
+
+ private void checkDrcModeCondition(String workspaceId, String dockSn) {
+ Optional> runningOpt = waylineRedisService.getRunningWaylineJob(dockSn);
+ if (runningOpt.isPresent() && WaylineJobStatusEnum.IN_PROGRESS == waylineJobService.getWaylineState(dockSn)) {
+ waylineJobService.updateJobStatus(workspaceId, runningOpt.get().getBid(),
+ UpdateJobParam.builder().status(WaylineTaskStatusEnum.PAUSE).build());
+ }
+
+ DockModeCodeEnum dockMode = deviceService.getDockMode(dockSn);
+ Optional dockOpt = deviceRedisService.getDeviceOnline(dockSn);
+ if (dockOpt.isPresent() && (DockModeCodeEnum.IDLE == dockMode || DockModeCodeEnum.WORKING == dockMode)) {
+ Optional deviceOsd = deviceRedisService.getDeviceOsd(dockOpt.get().getChildDeviceSn(), OsdSubDeviceReceiver.class);
+ if (deviceOsd.isEmpty() || deviceOsd.get().getElevation() <= 0) {
+ throw new RuntimeException("The drone is not in the sky and cannot enter command flight mode.");
+ }
+ } else {
+ throw new RuntimeException("The current state of the dock does not support entering command flight mode.");
+ }
+
+ ResponseResult result = controlService.seizeAuthority(dockSn, DroneAuthorityEnum.FLIGHT, null);
+ if (ResponseResult.CODE_SUCCESS != result.getCode()) {
+ throw new IllegalArgumentException(result.getMessage());
+ }
+
+ }
+
+ @Override
+ public JwtAclDTO deviceDrcEnter(String workspaceId, DrcModeParam param) {
+ String topic = TopicConst.THING_MODEL_PRE + TopicConst.PRODUCT + param.getDockSn() + TopicConst.DRC;
+ String pubTopic = topic + TopicConst.DOWN;
+ String subTopic = topic + TopicConst.UP;
+
+ // If the dock is in drc mode, refresh the permissions directly.
+ if (deviceService.checkDockDrcMode(param.getDockSn())
+ && param.getClientId().equals(this.getDrcModeInRedis(param.getDockSn()))) {
+ refreshAcl(param.getDockSn(), param.getClientId(), topic, subTopic);
+ return JwtAclDTO.builder().sub(List.of(subTopic)).pub(List.of(pubTopic)).build();
+ }
+
+ checkDrcModeCondition(workspaceId, param.getDockSn());
+
+ ServiceReply reply = messageSenderService.publishServicesTopic(
+ param.getDockSn(), DrcMethodEnum.DRC_MODE_ENTER.getMethod(),
+ DrcModeDTO.builder()
+ .mqttBroker(MqttConfiguration.getMqttBrokerWithDrc(param.getDockSn() + "-" + System.currentTimeMillis(), param.getDockSn(),
+ RedisConst.DRC_MODE_ALIVE_SECOND.longValue(),
+ Map.of(MapKeyConst.ACL, objectMapper.convertValue(JwtAclDTO.builder()
+ .pub(List.of(subTopic))
+ .sub(List.of(pubTopic))
+ .build(), new TypeReference