diff --git a/README.md b/README.md
index 2071047..faf73ce 100644
--- a/README.md
+++ b/README.md
@@ -6,15 +6,15 @@ The launch of the Cloud API mainly solves the problem of developers reinventing
## Docker
-If you don't want to install the development environment, you can try deploying with docker. [Click the link to download.](https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker_1.0.0.zip)
+If you don't want to install the development environment, you can try deploying with docker. [Click the link to download.](https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker.zip)
## Usage
-For more documentation, please visit the [DJI Developer Documentation](https://developer.dji.com/cn/document/209883f1-f2ad-406e-b99c-be7498df7f10).
+For more documentation, please visit the [DJI Developer Documentation](https://developer.dji.com/doc/cloud-api-tutorial/cn/).
## Latest Release
-Cloud API 1.0.0 was released on 21 March 2022. For more information, please visit the [Release Note](https://developer.dji.com/cn/document/87026f9b-e906-4809-9aba-870f569061b5).
+Cloud API 1.1.0 was released on 22 July 2022. For more information, please visit the [Release Note](https://developer.dji.com/doc/cloud-api-tutorial/cn/).
## License
diff --git a/api/Cloud API Demo.postman_collection.json b/api/Cloud API Demo.postman_collection.json
index 6c380a8..fc0fd32 100644
--- a/api/Cloud API Demo.postman_collection.json
+++ b/api/Cloud API Demo.postman_collection.json
@@ -18,7 +18,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\r\n \"username\": \"adminPC\",\r\n \"password\": \"adminPC\"\r\n}",
+ "raw": "{\r\n \"username\": \"adminPC\",\r\n \"password\": \"adminPC\",\r\n \"flag\": 1\r\n}",
"options": {
"raw": {
"language": "json"
@@ -100,12 +100,13 @@
"method": "GET",
"header": [],
"url": {
- "raw": "{{base_url}}{{manage_version}}/devices/devices",
+ "raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices",
"host": [
"{{base_url}}{{manage_version}}"
],
"path": [
"devices",
+ "{{workspace_id}}",
"devices"
]
}
@@ -132,12 +133,23 @@
},
{
"name": "Start Livestream",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript"
+ }
+ }
+ ],
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\r\n \"url_type\": 0,\r\n \"url\": \"\",\r\n \"video_id\": \"\",\r\n \"video_quality\": 0\r\n}",
+ "raw": "{\r\n \"url\": \"rtmp://192.168.1.1/live/1651053434895\",\r\n \"url_type\": 1,\r\n \"video_id\": \"1581F4BN/52-0-0/zoom-0\",\r\n \"video_quality\": 0\r\n}",
"options": {
"raw": {
"language": "json"
@@ -165,7 +177,7 @@
"header": [],
"body": {
"mode": "raw",
- "raw": "{\r\n \"video_id\": \"\"\r\n}",
+ "raw": "{\r\n \"video_id\": \"1581F4BNDQ/39-0-7/normal-0\"\r\n}",
"options": {
"raw": {
"language": "json"
@@ -213,19 +225,177 @@
}
},
"response": []
+ },
+ {
+ "name": "Get All Users Info",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{manage_version}}/users/{{workspace_id}}/users?page=1&page_size=10",
+ "host": [
+ "{{base_url}}{{manage_version}}"
+ ],
+ "path": [
+ "users",
+ "{{workspace_id}}",
+ "users"
+ ],
+ "query": [
+ {
+ "key": "page",
+ "value": "1"
+ },
+ {
+ "key": "page_size",
+ "value": "10"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Update User Info",
+ "request": {
+ "method": "PUT",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"mqtt_username\": \"admin\",\r\n \"mqtt_password\": \"admin\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{manage_version}}/users/{{workspace_id}}/users/a1559e7c-8dd8-4780-b952-100cc4797da2",
+ "host": [
+ "{{base_url}}{{manage_version}}"
+ ],
+ "path": [
+ "users",
+ "{{workspace_id}}",
+ "users",
+ "a1559e7c-8dd8-4780-b952-100cc4797da2"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Bind Device",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"user_id\": \"be7c6c3d-afe9-4be4-b9eb-c55066c0914e\",\r\n \"workspace_id\": \"e3dea0f5-37f2-4d79-ae58-490af3228069\",\r\n \"device_sn\": \"1ZMDG009\",\r\n \"child_device_sn\": \"\"\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{manage_version}}/devices/binding",
+ "host": [
+ "{{base_url}}{{manage_version}}"
+ ],
+ "path": [
+ "devices",
+ "binding"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get Binding Devices",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/bound?page=1&page_size=10&domain=sub-device",
+ "host": [
+ "{{base_url}}{{manage_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{workspace_id}}",
+ "devices",
+ "bound"
+ ],
+ "query": [
+ {
+ "key": "page",
+ "value": "1"
+ },
+ {
+ "key": "page_size",
+ "value": "10"
+ },
+ {
+ "key": "domain",
+ "value": "sub-device"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get Device",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{manage_version}}/devices/{{workspace_id}}/devices/{{device_sn}}",
+ "host": [
+ "{{base_url}}{{manage_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{workspace_id}}",
+ "devices",
+ "{{device_sn}}"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Unbind Device",
+ "request": {
+ "method": "DELETE",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{manage_version}}/devices/{{device_sn}}/unbinding",
+ "host": [
+ "{{base_url}}{{manage_version}}"
+ ],
+ "path": [
+ "devices",
+ "{{device_sn}}",
+ "unbinding"
+ ]
+ }
+ },
+ "response": []
}
],
"auth": {
"type": "apikey",
"apikey": [
{
- "key": "key",
- "value": "x-auth-token",
+ "key": "value",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTI2OTUxOTcsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTI3ODE1OTcsImlhdCI6MTY1MjY5NTE5NywidXNlcm5hbWUiOiJhZG1pblBDIn0.BHTwW8imw5ab0GUypRyJ2gkoz5av9q99NrxoFlL53dA",
"type": "string"
},
{
- "key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM",
+ "key": "key",
+ "value": "x-auth-token",
"type": "string"
}
]
@@ -390,7 +560,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTMzNzI3NDUsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTM0NTkxNDUsImlhdCI6MTY1MzM3Mjc0NSwidXNlcm5hbWUiOiJhZG1pblBDIn0.Zyb_f4umcGY2-WDaQKA1LHGOs9qYfJuPc3rQeIS-4hY",
"type": "string"
},
{
@@ -520,15 +690,12 @@
},
{
"name": "Check Tiny Fingerprints",
- "protocolProfileBehavior": {
- "disableBodyPruning": true
- },
"request": {
- "method": "GET",
+ "method": "POST",
"header": [],
"body": {
"mode": "raw",
- "raw": "{\r\n \"tiny_fingerprints\":[\r\n \r\n ]\r\n}",
+ "raw": "{\r\n \"tiny_fingerprints\":[\r\n \"4a3a67101ffb81d079338d4729315a8c_2022_3_3_11_38_58\",\r\n \"8e0fedb981be23dd034cf7927919da51_2022_3_3_11_45_26\"\r\n ]\r\n}",
"options": {
"raw": {
"language": "json"
@@ -536,7 +703,7 @@
}
},
"url": {
- "raw": "{{base_url}}{{media_version}}/workspaces/{{workspace_id}}/files/tiny-fingerprints?tiny_fingerprint=045040860fb014916c81082407e9ff8b_2021_12_2_16_17_8,922aca3dee753f2f9ee1ad0565967334_2021_12_8_22_13_12",
+ "raw": "{{base_url}}{{media_version}}/workspaces/{{workspace_id}}/files/tiny-fingerprints",
"host": [
"{{base_url}}{{media_version}}"
],
@@ -545,12 +712,6 @@
"{{workspace_id}}",
"files",
"tiny-fingerprints"
- ],
- "query": [
- {
- "key": "tiny_fingerprint",
- "value": "045040860fb014916c81082407e9ff8b_2021_12_2_16_17_8,922aca3dee753f2f9ee1ad0565967334_2021_12_8_22_13_12"
- }
]
}
},
@@ -562,7 +723,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTgzOTIyNzksImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTg0Nzg2NzksImlhdCI6MTY1ODM5MjI3OSwidXNlcm5hbWUiOiJhZG1pblBDIn0.ErClyQS1YzoQVBcLYxpFEiyFTb1L-eg2-vsudlL9WJU",
"type": "string"
},
{
@@ -622,7 +783,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTI2OTUxOTcsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTI3ODE1OTcsImlhdCI6MTY1MjY5NTE5NywidXNlcm5hbWUiOiJhZG1pblBDIn0.BHTwW8imw5ab0GUypRyJ2gkoz5av9q99NrxoFlL53dA",
"type": "string"
},
{
@@ -848,7 +1009,124 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NDg1MjI5ODAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NDg2MDkzODAsImlhdCI6MTY0ODUyMjk4MCwidXNlcm5hbWUiOiJhZG1pblBDIn0.QEDpB_60G4YLLXR_6rLZHWZNVbA1j162Xs1fZx8wEOM",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTU0NDk2MDIsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTU1MzYwMDIsImlhdCI6MTY1NTQ0OTYwMiwidXNlcm5hbWUiOiJhZG1pblBDIn0.YZWHJ65Pl_DT2Ampxk0WC01KD_fNTm_rYVUBIHAZD-4",
+ "type": "string"
+ },
+ {
+ "key": "key",
+ "value": "x-auth-token",
+ "type": "string"
+ }
+ ]
+ },
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "type": "text/javascript",
+ "exec": [
+ ""
+ ]
+ }
+ },
+ {
+ "listen": "test",
+ "script": {
+ "type": "text/javascript",
+ "exec": [
+ ""
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "name": "job",
+ "item": [
+ {
+ "name": "Create Flight Job",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "body": {
+ "mode": "raw",
+ "raw": "{\r\n \"name\": \"\",\r\n \"fild_id\": \"\",\r\n \"dock_sn\": \"\",\r\n \"type\": \"\",\r\n \"immediate\": false\r\n}",
+ "options": {
+ "raw": {
+ "language": "json"
+ }
+ }
+ },
+ "url": {
+ "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/flight-tasks",
+ "host": [
+ "{{base_url}}{{wayline_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "flight-tasks"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get Jobs",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/jobs?page=1&pageSize=10",
+ "host": [
+ "{{base_url}}{{wayline_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "jobs"
+ ],
+ "query": [
+ {
+ "key": "page",
+ "value": "1"
+ },
+ {
+ "key": "pageSize",
+ "value": "10"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Execute Job",
+ "request": {
+ "method": "POST",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}{{wayline_version}}/workspaces/{{workspace_id}}/jobs/{{plan_id}}",
+ "host": [
+ "{{base_url}}{{wayline_version}}"
+ ],
+ "path": [
+ "workspaces",
+ "{{workspace_id}}",
+ "jobs",
+ "{{plan_id}}"
+ ]
+ }
+ },
+ "response": []
+ }
+ ],
+ "auth": {
+ "type": "apikey",
+ "apikey": [
+ {
+ "key": "value",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTU4OTA5NTQsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTU5NzczNTQsImlhdCI6MTY1NTg5MDk1NCwidXNlcm5hbWUiOiJhZG1pblBDIn0.fd0iIzCd71LDUE6ixexUJvo-YqtnSCqRx-790snCyBI",
"type": "string"
},
{
@@ -885,7 +1163,7 @@
"apikey": [
{
"key": "value",
- "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2Mzg5MzY2OTEsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2MzkwMjMwOTEsImlhdCI6MTYzODkzNjY5MSwidXNlcm5hbWUiOiJhZG1pblBDIn0.W_v88rbhVKivl61MnJ0Cz_0Eq6Gw0RotiHCdLj0UPSQ",
+ "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3b3Jrc3BhY2VfaWQiOiJlM2RlYTBmNS0zN2YyLTRkNzktYWU1OC00OTBhZjMyMjgwNjkiLCJzdWIiOiJDbG91ZEFwaVNhbXBsZSIsInVzZXJfdHlwZSI6IjEiLCJuYmYiOjE2NTA0MjY3MzAsImxvZyI6IkxvZ2dlcltjb20uZGppLnNhbXBsZS5jb21tb24ubW9kZWwuQ3VzdG9tQ2xhaW1dIiwiaXNzIjoiREpJIiwiaWQiOiJhMTU1OWU3Yy04ZGQ4LTQ3ODAtYjk1Mi0xMDBjYzQ3OTdkYTIiLCJleHAiOjE2NTA1MTMxMzAsImlhdCI6MTY1MDQyNjczMCwidXNlcm5hbWUiOiJhZG1pblBDIn0.-FBpi0ktuZ68jV6-HQ7mwm8iC07YH-Hw2aRiREzJ8hs",
"type": "string"
},
{
diff --git a/api/Cloud API Demo.postman_environment.json b/api/Cloud API Demo.postman_environment.json
index f4faf3a..d2360f1 100644
--- a/api/Cloud API Demo.postman_environment.json
+++ b/api/Cloud API Demo.postman_environment.json
@@ -4,7 +4,7 @@
"values": [
{
"key": "ip",
- "value": "192.168.1.1",
+ "value": "localhost",
"type": "default",
"enabled": true
},
@@ -55,6 +55,6 @@
}
],
"_postman_variable_scope": "environment",
- "_postman_exported_at": "2022-03-29T03:52:14.600Z",
- "_postman_exported_using": "Postman/9.7.1"
+ "_postman_exported_at": "2022-07-21T08:35:48.441Z",
+ "_postman_exported_using": "Postman/9.19.0"
}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 5cbe4c6..b45b2f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
com.dji
cloud-api-sample
- 1.0.0
+ 1.1.0
cloud-api-sample
@@ -127,6 +127,35 @@
${glassfish-jaxb.version}
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+ com.amazonaws
+ aws-java-sdk-s3
+ 1.12.200
+
+
+ com.amazonaws
+ aws-java-sdk-sts
+ 1.12.200
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
diff --git a/sql/cloud_sample.sql b/sql/cloud_sample.sql
index 6f0e968..f644248 100644
--- a/sql/cloud_sample.sql
+++ b/sql/cloud_sample.sql
@@ -10,40 +10,8 @@ SET NAMES utf8mb4;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-# manage_camera_video
-# ------------------------------------------------------------
-
-DROP TABLE IF EXISTS `manage_camera_video`;
-
-CREATE TABLE `manage_camera_video` (
- `id` int unsigned NOT NULL AUTO_INCREMENT,
- `camera_id` int NOT NULL,
- `video_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `video_type` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
-
-
-# manage_capacity_camera
-# ------------------------------------------------------------
-
-DROP TABLE IF EXISTS `manage_capacity_camera`;
-
-CREATE TABLE `manage_capacity_camera` (
- `id` int unsigned NOT NULL AUTO_INCREMENT,
- `device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined',
- `description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
- `camera_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `coexist_video_number_max` int NOT NULL,
- `available_video_number` int NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
-
-
-
-# manage_device
+# manage_device
# ------------------------------------------------------------
DROP TABLE IF EXISTS `manage_device`;
@@ -52,25 +20,31 @@ CREATE TABLE `manage_device` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`device_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined',
- `workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `device_type` smallint NOT NULL,
- `sub_type` smallint NOT NULL,
- `domain` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `version` smallint NOT NULL,
- `device_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
- `child_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
+ `user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `nickname` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `device_type` smallint NOT NULL DEFAULT '-1',
+ `sub_type` smallint NOT NULL DEFAULT '-1',
+ `domain` smallint NOT NULL DEFAULT '-1',
+ `firmware_version` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `version` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `device_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `child_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
`create_time` bigint NOT NULL,
`update_time` bigint NOT NULL,
- `device_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
- `url_normal` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
- `url_select` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
+ `bound_time` bigint DEFAULT NULL,
+ `bound_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0:bund; 1:not bound',
+ `login_time` bigint DEFAULT NULL,
+ `device_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `url_normal` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
+ `url_select` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `product_sn_UNIQUE` (`device_sn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
-# manage_device_dictionary
+# manage_device_dictionary
# ------------------------------------------------------------
DROP TABLE IF EXISTS `manage_device_dictionary`;
@@ -106,15 +80,37 @@ VALUES
(14,1,165,0,'DJI Dock Camera',NULL),
(15,1,90742,0,'L1',NULL),
(16,2,56,0,'DJI Smart Controller','Remote control for M300'),
- (17,2,119,0,'Matrice 30 Smart Controller','Remote control for M30'),
- (18,3,1,0,'DJI Dock','DJI Airport');
-
+ (17,2,119,0,'DJI RC Plus','Remote control for M30'),
+ (18,3,1,0,'DJI Dock','');
/*!40000 ALTER TABLE `manage_device_dictionary` ENABLE KEYS */;
UNLOCK TABLES;
-# manage_device_payload
+# manage_device_hms
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `manage_device_hms`;
+
+CREATE TABLE `manage_device_hms` (
+ `id` int unsigned NOT NULL AUTO_INCREMENT,
+ `hms_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `tid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+ `bid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+ `sn` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+ `level` smallint NOT NULL,
+ `module` tinyint NOT NULL,
+ `hms_key` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `message_zh` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+ `message_en` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+ `create_time` bigint NOT NULL,
+ `update_time` bigint NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `UNIQUE_hms_id` (`hms_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
+
+
+# manage_device_payload
# ------------------------------------------------------------
DROP TABLE IF EXISTS `manage_device_payload`;
@@ -125,7 +121,7 @@ CREATE TABLE `manage_device_payload` (
`payload_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined',
`payload_type` smallint NOT NULL,
`sub_type` smallint NOT NULL,
- `version` smallint DEFAULT NULL,
+ `firmware_version` varchar(32) DEFAULT NULL,
`payload_index` smallint NOT NULL,
`device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`payload_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
@@ -137,7 +133,7 @@ CREATE TABLE `manage_device_payload` (
-# manage_user
+# manage_user
# ------------------------------------------------------------
DROP TABLE IF EXISTS `manage_user`;
@@ -147,7 +143,7 @@ CREATE TABLE `manage_user` (
`user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `workspace_id` int NOT NULL,
+ `workspace_id` varchar(64) NOT NULL DEFAULT '',
`user_type` smallint NOT NULL,
`mqtt_username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`mqtt_password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
@@ -162,14 +158,14 @@ LOCK TABLES `manage_user` WRITE;
INSERT INTO `manage_user` (`id`, `user_id`, `username`, `password`, `workspace_id`, `user_type`, `mqtt_username`, `mqtt_password`, `create_time`, `update_time`)
VALUES
- (1,'a1559e7c-8dd8-4780-b952-100cc4797da2','adminPC','adminPC',1,1,'admin','admin',1634898410751,1634898410751),
- (2,'be7c6c3d-afe9-4be4-b9eb-c55066c0914e','pilot','pilot123',1,2,'pilot','pilot123',1634898410751,1634898410751);
+ (1,'a1559e7c-8dd8-4780-b952-100cc4797da2','adminPC','adminPC','e3dea0f5-37f2-4d79-ae58-490af3228069',1,'admin','admin',1634898410751,1650880112310),
+ (2,'be7c6c3d-afe9-4be4-b9eb-c55066c0914e','pilot','pilot123','e3dea0f5-37f2-4d79-ae58-490af3228069',2,'pilot','pilot123',1634898410751,1634898410751);
/*!40000 ALTER TABLE `manage_user` ENABLE KEYS */;
UNLOCK TABLES;
-# manage_workspace
+# manage_workspace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `manage_workspace`;
@@ -182,22 +178,24 @@ CREATE TABLE `manage_workspace` (
`platform_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`create_time` bigint NOT NULL,
`update_time` bigint NOT NULL,
+ `bind_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
- UNIQUE KEY `workspace_id_UNIQUE` (`workspace_id`)
+ UNIQUE KEY `workspace_id_UNIQUE` (`workspace_id`),
+ UNIQUE KEY `bind_code_UNIQUE` (`bind_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
LOCK TABLES `manage_workspace` WRITE;
/*!40000 ALTER TABLE `manage_workspace` DISABLE KEYS */;
-INSERT INTO `manage_workspace` (`id`, `workspace_id`, `workspace_name`, `workspace_desc`, `platform_name`, `create_time`, `update_time`)
+INSERT INTO `manage_workspace` (`id`, `workspace_id`, `workspace_name`, `workspace_desc`, `platform_name`, `create_time`, `update_time`, `bind_code`)
VALUES
- (1,'e3dea0f5-37f2-4d79-ae58-490af3228069','Test Group One','Cloud Sample Test Platform','Cloud Api Platform',1634898410751,1634898410751);
+ (1,'e3dea0f5-37f2-4d79-ae58-490af3228069','Test Group One','Cloud Sample Test Platform','Cloud Api Platform',1634898410751,1634898410751,'qwe');
/*!40000 ALTER TABLE `manage_workspace` ENABLE KEYS */;
UNLOCK TABLES;
-# map_element_coordinate
+# map_element_coordinate
# ------------------------------------------------------------
DROP TABLE IF EXISTS `map_element_coordinate`;
@@ -213,7 +211,7 @@ CREATE TABLE `map_element_coordinate` (
-# map_group
+# map_group
# ------------------------------------------------------------
DROP TABLE IF EXISTS `map_group`;
@@ -244,7 +242,7 @@ VALUES
UNLOCK TABLES;
-# map_group_element
+# map_group_element
# ------------------------------------------------------------
DROP TABLE IF EXISTS `map_group_element`;
@@ -267,7 +265,7 @@ CREATE TABLE `map_group_element` (
-# media_file
+# media_file
# ------------------------------------------------------------
DROP TABLE IF EXISTS `media_file`;
@@ -277,22 +275,22 @@ CREATE TABLE `media_file` (
`file_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`file_path` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `fingerprint` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `fingerprint` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
`tinny_fingerprint` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `object_key` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
- `sub_file_type` int NOT NULL,
+ `object_key` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `sub_file_type` int DEFAULT NULL,
`is_original` tinyint(1) NOT NULL,
`drone` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined',
`payload` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined',
+ `job_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '',
`create_time` bigint NOT NULL,
`update_time` bigint NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `fingerprint_UNIQUE` (`fingerprint`)
+ PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
-# wayline_file
+# wayline_file
# ------------------------------------------------------------
DROP TABLE IF EXISTS `wayline_file`;
@@ -304,18 +302,41 @@ CREATE TABLE `wayline_file` (
`drone_model_key` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`payload_model_keys` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `sign` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'MD5',
`favorited` tinyint(1) NOT NULL DEFAULT '0',
`template_types` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`object_key` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`create_time` bigint NOT NULL,
- `update_time` bigint NOT NULL COMMENT 'required, can not modify.',
+ `update_time` bigint NOT NULL COMMENT 'required, can''t modify.',
PRIMARY KEY (`id`),
UNIQUE KEY `wayline_id_UNIQUE` (`wayline_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
+# wayline_job
+# ------------------------------------------------------------
+
+DROP TABLE IF EXISTS `wayline_job`;
+
+CREATE TABLE `wayline_job` (
+ `id` int unsigned NOT NULL AUTO_INCREMENT,
+ `job_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+ `name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `file_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `dock_sn` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `workspace_id` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `bid` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `type` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
+ `create_time` bigint NOT NULL,
+ `update_time` bigint NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `job_id_UNIQUE` (`job_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
+
+
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
diff --git a/src/main/java/com/dji/sample/CloudApiSampleApplication.java b/src/main/java/com/dji/sample/CloudApiSampleApplication.java
index 14cca32..a3619ab 100644
--- a/src/main/java/com/dji/sample/CloudApiSampleApplication.java
+++ b/src/main/java/com/dji/sample/CloudApiSampleApplication.java
@@ -8,6 +8,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@MapperScan("com.dji.sample.*.dao")
@SpringBootApplication
@EnableScheduling
+//@EnableConfigurationProperties(OssConfiguration.class)
public class CloudApiSampleApplication {
public static void main(String[] args) {
diff --git a/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java b/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java
index 1dab9d1..290cc42 100644
--- a/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java
+++ b/src/main/java/com/dji/sample/common/error/CommonErrorEnum.java
@@ -7,6 +7,16 @@ package com.dji.sample.common.error;
*/
public enum CommonErrorEnum implements IErrorInfo {
+ ILLEGAL_ARGUMENT(200001, "illegal argument"),
+
+ GET_ORGANIZATION_FAILED(210230, "Failed to get organization."),
+
+ DEVICE_BINDING_FAILED(210231, "Failed to bind device."),
+
+ NON_REPEATABLE_BINDING(210232, "The device has been bound to another organization and can't be bound repeatedly."),
+
+ GET_DEVICE_BINDING_STATUS_FAILED(210233, "Failed to get device binding status."),
+
SYSTEM_ERROR(600500, "system error"),
SECRET_INVALID(600100, "secret invalid"),
diff --git a/src/main/java/com/dji/sample/common/error/StorageErrorEnum.java b/src/main/java/com/dji/sample/common/error/StorageErrorEnum.java
new file mode 100644
index 0000000..16b5d2f
--- /dev/null
+++ b/src/main/java/com/dji/sample/common/error/StorageErrorEnum.java
@@ -0,0 +1,38 @@
+package com.dji.sample.common.error;
+
+/**
+ * @author sean
+ * @version 1.0
+ * @date 2022/5/25
+ */
+public enum StorageErrorEnum implements IErrorInfo {
+
+ GENERATE_CREDENTIALS_ERROR(217001, "Failed to generate temporary credentials."),
+
+ NO_BUCKET(217002, "The bucket does not exist."),
+
+ ILLEGAL_PATH_FORMAT(217006, "Illegal path format."),
+
+ FILE_CREATION_FAILED(217007, "File creation failed."),
+
+ DIR_CREATION_FAILED(217008, "Directory creation failed");
+
+ private String msg;
+
+ private int code;
+
+ StorageErrorEnum(int code, String msg) {
+ this.msg = msg;
+ this.code = code;
+ }
+
+ @Override
+ public String getErrorMsg() {
+ return msg;
+ }
+
+ @Override
+ public Integer getErrorCode() {
+ return code;
+ }
+}
diff --git a/src/main/java/com/dji/sample/common/util/JwtUtil.java b/src/main/java/com/dji/sample/common/util/JwtUtil.java
index 9c2cb9a..629cea1 100644
--- a/src/main/java/com/dji/sample/common/util/JwtUtil.java
+++ b/src/main/java/com/dji/sample/common/util/JwtUtil.java
@@ -54,6 +54,10 @@ public class JwtUtil {
JwtUtil.algorithm = Algorithm.HMAC256(secret);
}
+ private JwtUtil() {
+
+ }
+
/**
* Create a token based on custom information.
* @param claims custom information
diff --git a/src/main/java/com/dji/sample/component/ApplicationBootInitial.java b/src/main/java/com/dji/sample/component/ApplicationBootInitial.java
index 226fe1a..f35aa3c 100644
--- a/src/main/java/com/dji/sample/component/ApplicationBootInitial.java
+++ b/src/main/java/com/dji/sample/component/ApplicationBootInitial.java
@@ -1,15 +1,12 @@
package com.dji.sample.component;
-import com.dji.sample.manage.model.DeviceStatusManager;
-import com.dji.sample.manage.model.enums.DeviceDomainEnum;
-import com.dji.sample.manage.model.param.DeviceQueryParam;
+import com.dji.sample.component.redis.RedisConst;
+import com.dji.sample.component.redis.RedisOpsUtils;
import com.dji.sample.manage.service.IDeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
-import java.time.LocalDateTime;
-
/**
* @author sean.zhou
* @date 2021/11/24
@@ -21,20 +18,21 @@ public class ApplicationBootInitial implements CommandLineRunner {
@Autowired
private IDeviceService deviceService;
+ @Autowired
+ private RedisOpsUtils redisOps;
+
/**
- * Subscribe to the devices that exist in the database when the program starts,
+ * Subscribe to the devices that exist in the redis when the program starts,
* to prevent the data from being different from the pilot side due to program interruptions.
* @param args
* @throws Exception
*/
@Override
public void run(String... args) throws Exception {
- deviceService.getDevicesByParams(DeviceQueryParam.builder().build())
- .forEach(device -> {
- deviceService.subscribeTopicOnline(device.getDeviceSn());
- DeviceStatusManager.STATUS_MANAGER.put(
- DeviceDomainEnum.getVal(device.getDomain()) + "/"
- + device.getDeviceSn(), LocalDateTime.now());
- });
+ int start = RedisConst.DEVICE_ONLINE_PREFIX.length();
+
+ redisOps.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*")
+ .forEach(key -> deviceService.subscribeTopicOnline(key.substring(start)));
+
}
}
\ No newline at end of file
diff --git a/src/main/java/com/dji/sample/component/GlobalScheduleService.java b/src/main/java/com/dji/sample/component/GlobalScheduleService.java
index ea44a62..2813388 100644
--- a/src/main/java/com/dji/sample/component/GlobalScheduleService.java
+++ b/src/main/java/com/dji/sample/component/GlobalScheduleService.java
@@ -1,5 +1,9 @@
package com.dji.sample.component;
+import com.dji.sample.component.mqtt.service.IMqttTopicService;
+import com.dji.sample.component.redis.RedisConst;
+import com.dji.sample.component.redis.RedisOpsUtils;
+import com.dji.sample.manage.model.dto.DeviceDTO;
import com.dji.sample.manage.model.enums.DeviceDomainEnum;
import com.dji.sample.manage.service.IDeviceService;
import lombok.extern.slf4j.Slf4j;
@@ -7,13 +11,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
-import java.time.LocalDateTime;
-import java.util.Map;
+import java.util.Arrays;
import java.util.concurrent.TimeUnit;
-import static com.dji.sample.manage.model.DeviceStatusManager.DEFAULT_ALIVE_SECOND;
-import static com.dji.sample.manage.model.DeviceStatusManager.STATUS_MANAGER;
-
/**
* @author sean.zhou
* @date 2021/11/24
@@ -26,33 +26,34 @@ public class GlobalScheduleService {
@Autowired
private IDeviceService deviceService;
+ @Autowired
+ private RedisOpsUtils redisOps;
+
+ @Autowired
+ private IMqttTopicService topicService;
+
/**
* Check the status of the devices every 30 seconds. It is recommended to use cache.
*/
- @Scheduled(fixedRate = 30, timeUnit = TimeUnit.SECONDS)
+ @Scheduled(initialDelay = 30, fixedRate = 30, timeUnit = TimeUnit.SECONDS)
private void deviceStatusListen() {
- for (Map.Entry entry : STATUS_MANAGER.entrySet()) {
- if (entry.getValue().isAfter(
- LocalDateTime.now().minusSeconds(DEFAULT_ALIVE_SECOND))) {
- continue;
- }
-
- String device = entry.getKey();
- int index = device.indexOf("/");
-
- STATUS_MANAGER.remove(device);
-
- int type = Integer.parseInt(device.substring(0, index));
- String sn = device.substring(index + 1);
- // Determine whether it is a gateway device.
- if (DeviceDomainEnum.GATEWAY.getVal() == type) {
- deviceService.deviceOffline(sn);
- deviceService.unsubscribeTopicOffline(sn);
- continue;
+ int start = RedisConst.DEVICE_ONLINE_PREFIX.length();
+
+ redisOps.getAllKeys(RedisConst.DEVICE_ONLINE_PREFIX + "*").forEach(key -> {
+ long expire = redisOps.getExpire(key);
+ if (expire <= 30) {
+ DeviceDTO device = (DeviceDTO) redisOps.get(key);
+ if (device.getDomain().equals(DeviceDomainEnum.SUB_DEVICE.getDesc())) {
+ deviceService.subDeviceOffline(key.substring(start));
+ } else {
+ deviceService.unsubscribeTopicOffline(key.substring(start));
+ deviceService.pushDeviceOfflineTopo(device.getWorkspaceId(), device.getDeviceSn());
+ }
+ redisOps.del(key);
}
+ });
- deviceService.subDeviceOffline(sn);
- }
+ log.info("Subscriptions: {}", Arrays.toString(topicService.getSubscribedTopic()));
}
}
\ No newline at end of file
diff --git a/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java b/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java
index df6f04f..3964aaf 100644
--- a/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java
+++ b/src/main/java/com/dji/sample/component/mqtt/config/MqttInboundConfiguration.java
@@ -11,6 +11,7 @@ import org.springframework.integration.endpoint.MessageProducerSupport;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
+import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
@@ -62,7 +63,9 @@ public class MqttInboundConfiguration {
@ServiceActivator(inputChannel = ChannelName.DEFAULT)
public MessageHandler defaultInboundHandler() {
return message -> {
- log.info("The default channel does not handle messages.");
+ log.info("The default channel does not handle messages." +
+ "\nTopic: " + message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC) +
+ "\nPayload: " + message.getPayload());
};
}
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 2f06938..3d54599 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
@@ -74,7 +74,7 @@ public class MqttMessageChannel {
@Bean(name = ChannelName.INBOUND_OSD)
public MessageChannel osdChannel() {
- return new DirectChannel();
+ return new ExecutorChannel(threadPool);
}
@Bean(name = ChannelName.DEFAULT)
@@ -87,4 +87,54 @@ public class MqttMessageChannel {
return new DirectChannel();
}
+ @Bean(name = ChannelName.INBOUND_STATE_FIRMWARE_VERSION)
+ public MessageChannel stateFirmwareVersionChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_REQUESTS)
+ public MessageChannel requestsChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_REQUESTS_STORAGE_CONFIG_GET)
+ public MessageChannel requestsConfigGetChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS)
+ public MessageChannel eventsChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS)
+ public MessageChannel eventsFlightTaskProgressChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS_FILE_UPLOAD_CALLBACK)
+ public MessageChannel eventsFileUploadCallbackChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_REQUESTS_AIRPORT_BIND_STATUS)
+ public MessageChannel requestsAirportBindStatusChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_GET)
+ public MessageChannel requestsAirportOrganizationGetChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND)
+ public MessageChannel requestsAirportOrganizationBindChannel() {
+ return new DirectChannel();
+ }
+
+ @Bean(name = ChannelName.INBOUND_EVENTS_HMS)
+ public MessageChannel eventsHms() {
+ return new DirectChannel();
+ }
+
}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/AbstractStateTopicHandler.java b/src/main/java/com/dji/sample/component/mqtt/handler/AbstractStateTopicHandler.java
new file mode 100644
index 0000000..c3969f3
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/AbstractStateTopicHandler.java
@@ -0,0 +1,39 @@
+package com.dji.sample.component.mqtt.handler;
+
+import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
+import com.dji.sample.component.redis.RedisOpsUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.Map;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2022/2/21
+ */
+public abstract class AbstractStateTopicHandler {
+
+ protected AbstractStateTopicHandler handler;
+
+ @Autowired
+ protected ObjectMapper mapper;
+
+ @Autowired
+ protected RedisOpsUtils redisOps;
+
+ protected AbstractStateTopicHandler(AbstractStateTopicHandler handler) {
+ this.handler = handler;
+ }
+
+ /**
+ * Passing dataNode data, using different processing methods depending on the data selection.
+ * @param dataNode
+ * @param stateReceiver
+ * @param sn
+ * @return
+ * @throws JsonProcessingException
+ */
+ public abstract CommonTopicReceiver handleState(Map dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException;
+}
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
new file mode 100644
index 0000000..a2baabe
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/EventsRouter.java
@@ -0,0 +1,48 @@
+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.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.dsl.IntegrationFlow;
+import org.springframework.integration.dsl.IntegrationFlows;
+
+import java.io.IOException;
+
+/**
+ * @author sean
+ * @version 1.1
+ * @date 2022/6/1
+ */
+@Configuration
+public class EventsRouter {
+
+ @Autowired
+ private ObjectMapper mapper;
+
+ @Bean
+ public IntegrationFlow eventsMethodRouterFlow() {
+ return IntegrationFlows
+ .from(ChannelName.INBOUND_EVENTS)
+ .transform(payload -> {
+ try {
+ return mapper.readValue(payload, CommonTopicReceiver.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return new CommonTopicReceiver();
+ })
+ .route(
+ receiver -> EventsMethodEnum.find(receiver.getMethod()),
+ mapping -> {
+ mapping.channelMapping(EventsMethodEnum.FILE_UPLOAD_CALLBACK, ChannelName.INBOUND_EVENTS_FILE_UPLOAD_CALLBACK);
+ mapping.channelMapping(EventsMethodEnum.FLIGHT_TASK_PROGRESS, ChannelName.INBOUND_EVENTS_FLIGHT_TASK_PROGRESS);
+ mapping.channelMapping(EventsMethodEnum.HMS, ChannelName.INBOUND_EVENTS_HMS);
+ mapping.channelMapping(EventsMethodEnum.UNKNOWN, ChannelName.DEFAULT);
+ })
+ .get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/InboundMessageRouter.java b/src/main/java/com/dji/sample/component/mqtt/handler/InboundMessageRouter.java
new file mode 100644
index 0000000..3047ea5
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/InboundMessageRouter.java
@@ -0,0 +1,118 @@
+package com.dji.sample.component.mqtt.handler;
+
+import com.dji.sample.component.mqtt.model.ChannelName;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.integration.annotation.Router;
+import org.springframework.integration.mqtt.support.MqttHeaders;
+import org.springframework.integration.router.AbstractMessageRouter;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.regex.Pattern;
+
+import static com.dji.sample.component.mqtt.model.TopicConst.*;
+
+/**
+ *
+ * @author sean.zhou
+ * @date 2021/11/10
+ * @version 0.1
+ */
+@Component
+@Slf4j
+public class InboundMessageRouter extends AbstractMessageRouter {
+
+ @Resource(name = ChannelName.INBOUND)
+ private MessageChannel inboundChannel;
+
+ @Resource(name = ChannelName.INBOUND_STATUS)
+ private MessageChannel statusChannel;
+
+ @Resource(name = ChannelName.INBOUND_STATE)
+ private MessageChannel stateChannel;
+
+ @Resource(name = ChannelName.DEFAULT)
+ private MessageChannel defaultChannel;
+
+ @Resource(name = ChannelName.INBOUND_SERVICE_REPLY)
+ private MessageChannel serviceReplyChannel;
+
+ @Resource(name = ChannelName.INBOUND_OSD)
+ private MessageChannel osdChannel;
+
+ @Resource(name = ChannelName.INBOUND_REQUESTS)
+ private MessageChannel requestsChannel;
+
+ @Resource(name = ChannelName.INBOUND_EVENTS)
+ private MessageChannel eventsChannel;
+
+ private static final Pattern PATTERN_TOPIC_STATUS =
+ Pattern.compile("^" + BASIC_PRE + PRODUCT + REGEX_SN + STATUS_SUF + "$");
+
+ private static final Pattern PATTERN_TOPIC_STATE =
+ Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + STATE_SUF + "$");
+
+ private static final Pattern PATTERN_TOPIC_SERVICE_REPLY =
+ Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + SERVICES_SUF + _REPLY_SUF + "$");
+
+ private static final Pattern PATTERN_TOPIC_OSD =
+ Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + OSD_SUF + "$");
+
+ private static final Pattern PATTERN_TOPIC_REQUESTS =
+ Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + REQUESTS_SUF + "$");
+
+ private static final Pattern PATTERN_TOPIC_EVENTS =
+ Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + EVENTS_SUF + "$");
+
+ /**
+ * All mqtt broker messages will arrive here before distributing them to different channels.
+ * @param message message from mqtt broker
+ * @return channel
+ */
+ @Override
+ @Router(inputChannel = ChannelName.INBOUND)
+ protected Collection determineTargetChannels(Message> message) {
+ MessageHeaders headers = message.getHeaders();
+ String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString();
+ byte[] payload = (byte[])message.getPayload();
+
+ // osd
+ if (PATTERN_TOPIC_OSD.matcher(topic).matches()) {
+ return Collections.singleton(osdChannel);
+ }
+
+ log.debug("received topic :{} \t payload :{}", topic, new String(payload));
+
+ // status
+ if (PATTERN_TOPIC_STATUS.matcher(topic).matches()) {
+ return Collections.singleton(statusChannel);
+ }
+
+ // state
+ if (PATTERN_TOPIC_STATE.matcher(topic).matches()) {
+ return Collections.singleton(stateChannel);
+ }
+
+ // services_reply
+ if (PATTERN_TOPIC_SERVICE_REPLY.matcher(topic).matches()) {
+ return Collections.singleton(serviceReplyChannel);
+ }
+
+ // requests
+ if (PATTERN_TOPIC_REQUESTS.matcher(topic).matches()) {
+ return Collections.singleton(requestsChannel);
+ }
+
+ // events
+ if (PATTERN_TOPIC_EVENTS.matcher(topic).matches()) {
+ return Collections.singleton(eventsChannel);
+ }
+
+ return Collections.singleton(defaultChannel);
+ }
+}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/RequestsRouter.java b/src/main/java/com/dji/sample/component/mqtt/handler/RequestsRouter.java
new file mode 100644
index 0000000..753bad2
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/RequestsRouter.java
@@ -0,0 +1,49 @@
+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.RequestsMethodEnum;
+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.dsl.IntegrationFlow;
+import org.springframework.integration.dsl.IntegrationFlows;
+
+import java.io.IOException;
+
+/**
+ * @author sean
+ * @version 1.0
+ * @date 2022/5/25
+ */
+@Configuration
+public class RequestsRouter {
+
+ @Autowired
+ private ObjectMapper mapper;
+
+ @Bean
+ public IntegrationFlow requestsMethodRouterFlow() {
+ return IntegrationFlows
+ .from(ChannelName.INBOUND_REQUESTS)
+ .transform(payload -> {
+ try {
+ return mapper.readValue(payload, CommonTopicReceiver.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return new CommonTopicReceiver();
+ })
+ .route(
+ receiver -> RequestsMethodEnum.find(receiver.getMethod()),
+ mapping -> {
+ mapping.channelMapping(RequestsMethodEnum.STORAGE_CONFIG_GET, ChannelName.INBOUND_REQUESTS_STORAGE_CONFIG_GET);
+ mapping.channelMapping(RequestsMethodEnum.AIRPORT_BIND_STATUS, ChannelName.INBOUND_REQUESTS_AIRPORT_BIND_STATUS);
+ mapping.channelMapping(RequestsMethodEnum.AIRPORT_ORGANIZATION_GET, ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_GET);
+ mapping.channelMapping(RequestsMethodEnum.AIRPORT_ORGANIZATION_BIND, ChannelName.INBOUND_REQUESTS_AIRPORT_ORGANIZATION_BIND);
+ mapping.channelMapping(RequestsMethodEnum.UNKNOWN, ChannelName.DEFAULT);
+ })
+ .get();
+ }
+}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/StateDefaultHandler.java b/src/main/java/com/dji/sample/component/mqtt/handler/StateDefaultHandler.java
new file mode 100644
index 0000000..a1d2624
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/StateDefaultHandler.java
@@ -0,0 +1,26 @@
+package com.dji.sample.component.mqtt.handler;
+
+import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2022/3/21
+ */
+@Service
+public class StateDefaultHandler extends AbstractStateTopicHandler {
+
+ protected StateDefaultHandler() {
+ super(null);
+ }
+
+ @Override
+ public CommonTopicReceiver handleState(Map dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException {
+ // If no suitable handler is found for the data, it is not processed.
+ return stateReceiver;
+ }
+}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/StateDeviceBasicHandler.java b/src/main/java/com/dji/sample/component/mqtt/handler/StateDeviceBasicHandler.java
new file mode 100644
index 0000000..b85ebca
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/StateDeviceBasicHandler.java
@@ -0,0 +1,38 @@
+package com.dji.sample.component.mqtt.handler;
+
+import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
+import com.dji.sample.component.mqtt.model.StateDataEnum;
+import com.dji.sample.manage.model.receiver.DeviceBasicReceiver;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2022/2/21
+ */
+@Service
+public class StateDeviceBasicHandler extends AbstractStateTopicHandler {
+
+ public StateDeviceBasicHandler(@Autowired @Qualifier("stateLiveCapacityHandler") AbstractStateTopicHandler handler) {
+ super(handler);
+ }
+
+ @Override
+ public CommonTopicReceiver handleState(Map dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException {
+ // handle device basic data
+ if (dataNode.containsKey(StateDataEnum.PAYLOADS.getDesc())) {
+ DeviceBasicReceiver data = mapper.convertValue(stateReceiver.getData(), DeviceBasicReceiver.class);
+ data.setDeviceSn(sn);
+ data.getPayloads().forEach(payload -> payload.setDeviceSn(sn));
+
+ stateReceiver.setData(data);
+ return stateReceiver;
+ }
+ return handler.handleState(dataNode, stateReceiver, sn);
+ }
+}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/StateFirmwareVersionHandler.java b/src/main/java/com/dji/sample/component/mqtt/handler/StateFirmwareVersionHandler.java
new file mode 100644
index 0000000..aceeae4
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/StateFirmwareVersionHandler.java
@@ -0,0 +1,62 @@
+package com.dji.sample.component.mqtt.handler;
+
+import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
+import com.dji.sample.component.mqtt.model.StateDataEnum;
+import com.dji.sample.manage.model.enums.DeviceDomainEnum;
+import com.dji.sample.manage.model.enums.PayloadModelEnum;
+import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2022/2/21
+ */
+@Service
+public class StateFirmwareVersionHandler extends AbstractStateTopicHandler {
+
+ protected StateFirmwareVersionHandler(@Autowired @Qualifier("stateDefaultHandler") AbstractStateTopicHandler handler) {
+ super(handler);
+ }
+
+ @Override
+ public CommonTopicReceiver handleState(Map dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException {
+ // Parse the firmware version of the device.
+ if (dataNode.containsKey(StateDataEnum.FIRMWARE_VERSION.getDesc())) {
+ FirmwareVersionReceiver firmware = mapper.convertValue(dataNode, FirmwareVersionReceiver.class);
+ firmware.setSn(sn);
+ firmware.setDomain(DeviceDomainEnum.SUB_DEVICE);
+ stateReceiver.setData(firmware);
+ return stateReceiver;
+ }
+
+ // Parse the firmware version of the payload.
+ List payloads = PayloadModelEnum.getAllModel();
+ long count = dataNode.keySet()
+ .stream()
+ .map(key -> {
+ int end = key.indexOf("-");
+ return end == -1 ? key : key.substring(0, end);
+ })
+ .filter(payloads::contains)
+ .count();
+ if (count > 0) {
+ FirmwareVersionReceiver firmware = FirmwareVersionReceiver.builder()
+ .firmwareVersion(((Map)(dataNode.values().iterator().next()))
+ .get(StateDataEnum.FIRMWARE_VERSION.getDesc()))
+ .sn(sn)
+ .domain(DeviceDomainEnum.PAYLOAD)
+ .build();
+ stateReceiver.setData(firmware);
+ return stateReceiver;
+ }
+
+ return handler.handleState(dataNode, stateReceiver, sn);
+ }
+}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/StateLiveCapacityHandler.java b/src/main/java/com/dji/sample/component/mqtt/handler/StateLiveCapacityHandler.java
new file mode 100644
index 0000000..dc593ab
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/StateLiveCapacityHandler.java
@@ -0,0 +1,39 @@
+package com.dji.sample.component.mqtt.handler;
+
+import com.dji.sample.component.mqtt.model.CommonTopicReceiver;
+import com.dji.sample.component.mqtt.model.StateDataEnum;
+import com.dji.sample.manage.model.receiver.LiveCapacityReceiver;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2022/2/21
+ */
+@Service
+@Slf4j
+public class StateLiveCapacityHandler extends AbstractStateTopicHandler {
+
+ protected StateLiveCapacityHandler(@Autowired @Qualifier("stateFirmwareVersionHandler") AbstractStateTopicHandler handler) {
+ super(handler);
+ }
+
+ @Override
+ public CommonTopicReceiver handleState(Map dataNode, CommonTopicReceiver stateReceiver, String sn) throws JsonProcessingException {
+ // Determine if it is live capacity data based on name.
+ if (dataNode.containsKey(StateDataEnum.LIVE_CAPACITY.getDesc())) {
+ stateReceiver.setData(mapper.convertValue(
+ dataNode.get(StateDataEnum.LIVE_CAPACITY.getDesc()),
+ LiveCapacityReceiver.class));
+ log.info("Analyze live stream capabilities.");
+ return stateReceiver;
+ }
+ return handler.handleState(dataNode, stateReceiver, sn);
+ }
+}
diff --git a/src/main/java/com/dji/sample/component/mqtt/handler/StateRouter.java b/src/main/java/com/dji/sample/component/mqtt/handler/StateRouter.java
new file mode 100644
index 0000000..4f0e1e5
--- /dev/null
+++ b/src/main/java/com/dji/sample/component/mqtt/handler/StateRouter.java
@@ -0,0 +1,104 @@
+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.manage.model.receiver.DeviceBasicReceiver;
+import com.dji.sample.manage.model.receiver.FirmwareVersionReceiver;
+import com.dji.sample.manage.model.receiver.LiveCapacityReceiver;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.annotation.MessageEndpoint;
+import org.springframework.integration.annotation.Router;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.integration.annotation.Splitter;
+import org.springframework.integration.mqtt.support.MqttHeaders;
+import org.springframework.integration.router.MessageRouter;
+import org.springframework.integration.router.PayloadTypeRouter;
+import org.springframework.messaging.Message;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import static com.dji.sample.component.mqtt.model.TopicConst.*;
+
+/**
+ *
+ * @author sean.zhou
+ * @date 2021/11/17
+ * @version 0.1
+ */
+@MessageEndpoint
+@Slf4j
+@Configuration
+public class StateRouter {
+
+ @Resource(name = "stateDeviceBasicHandler")
+ private AbstractStateTopicHandler handler;
+
+ @Autowired
+ private ObjectMapper mapper;
+
+ /**
+ * Handles the routing of state topic messages. Depending on the data, it is assigned to different channels for handling.
+ * @param message
+ * @return
+ * @throws IOException
+ */
+ @ServiceActivator(inputChannel = ChannelName.INBOUND_STATE, outputChannel = ChannelName.INBOUND_STATE_SPLITTER)
+ public CommonTopicReceiver> resolveStateData(Message> message) throws IOException {
+ byte[] payload = (byte[])message.getPayload();
+ String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString();
+
+ CommonTopicReceiver stateReceiver = mapper.readValue(payload, CommonTopicReceiver.class);
+ // Get the sn of the topic source.
+ String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(),
+ topic.indexOf(STATE_SUF));
+
+ try {
+ Map data = (Map) (stateReceiver.getData());
+
+ return handler.handleState(data, stateReceiver, from);
+
+ } catch (UnrecognizedPropertyException e) {
+ log.info("The {} data is not processed.", e.getPropertyName());
+ }
+ return stateReceiver;
+ }
+
+ /**
+ * Split the state message data to different channels for handling according to their different types.
+ * @param receiver state message
+ * @return
+ */
+ @Splitter(inputChannel = ChannelName.INBOUND_STATE_SPLITTER, outputChannel = ChannelName.INBOUND_STATE_ROUTER)
+ public Collection