dji_mqtt_connect 0.1.22.2 → 0.1.23.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,231 +4,11 @@ module DjiMqttConnect
4
4
  # Factories for building example messages
5
5
  # Do not include this in your production code
6
6
  module Factories
7
- # Events
7
+ autoload :EventsMessages, "dji_mqtt_connect/factories/events_messages"
8
+ autoload :StateMessages, "dji_mqtt_connect/factories/state_messages"
8
9
 
9
- def build_device_exit_homing_notify_events_message
10
- message_data = {
11
- action: 1,
12
- sn: "DOCK01",
13
- reason: "0"
14
- }
15
- Thing::Product::DeviceExitHomingNotifyEventsMessage.new(
16
- _method: "device_exit_homing_notify",
17
- bid: Message.generate_bid,
18
- tid: Message.generate_tid,
19
- need_reply: 1,
20
- gateway: "GATEWAY01",
21
- timestamp: Message.current_timestamp,
22
- data: message_data,
23
- _data: message_data
24
- )
25
- end
26
-
27
- def build_thing_product_device_reboot_events_message
28
- message_data = {
29
- result: 0,
30
- output: {
31
- status: "ok",
32
- progress: {
33
- percent: 100
34
- }
35
- }
36
- }
37
-
38
- Thing::Product::DeviceRebootEventsMessage.new(
39
- bid: Message.generate_bid,
40
- tid: Message.generate_tid,
41
- timestamp: Message.current_timestamp,
42
- _method: "device_reboot",
43
- need_reply: 1,
44
- data: message_data,
45
- _data: message_data
46
- )
47
- end
48
-
49
- def build_file_upload_callback_events_message
50
- message_data = {
51
- file: {
52
- object_key: "object_key",
53
- path: "xxx",
54
- name: "dog.jpeg",
55
- ext: {
56
- flight_id: "xxx",
57
- drone_model_key: "0-67-0",
58
- payload_model_key: "0-67-0",
59
- is_original: true
60
- },
61
- metadata: {
62
- shoot_position: {
63
- lat: 22.1,
64
- lng: 122.5
65
- },
66
- gimbal_yaw_degree: -91.4,
67
- absolute_altitude: 56.311,
68
- relative_altitude: 41.124,
69
- created_time: "2021-05-10 16:04:20"
70
- }
71
- },
72
- result: 0
73
- }
74
-
75
- Thing::Product::FileUploadCallbackEventsMessage.new(
76
- _method: "file_upload_callback",
77
- bid: Message.generate_bid,
78
- tid: Message.generate_tid,
79
- need_reply: 1,
80
- gateway: "xxx",
81
- timestamp: Message.current_timestamp,
82
- data: message_data,
83
- _data: message_data
84
- )
85
- end
86
-
87
- def build_fileupload_progress_events_message
88
- message_data = {
89
- output: {
90
- ext: {
91
- files: [
92
- {
93
- module: "0",
94
- size: 155232,
95
- device_sn: "drone_sn",
96
- key: "4bf0039f-6434-44a8-b891-8d7b6b7ff138/drone_sn/video_20220621_110830.log",
97
- fingerprint: "4f65b891f3bc09bdb6d4c36a996b532d",
98
- progress: {
99
- current_step: 19,
100
- progress: 100,
101
- finish_time: 1655781395926,
102
- upload_rate: 0,
103
- result: 0,
104
- status: "ok"
105
- }
106
- },
107
- {
108
- module: "3",
109
- size: 155232,
110
- device_sn: "dock_sn",
111
- key: "4bf0039f-6434-44a8-b891-8d7b6b7ff138/dock_sn/video_20220621_110830.log",
112
- fingerprint: "4f65b891f3bc09bdb6d4c36a996b532d",
113
- progress: {
114
- current_step: 19,
115
- total_step: 30,
116
- progress: 100,
117
- finish_time: 1655781395926,
118
- upload_rate: 0,
119
- result: 0,
120
- status: "ok"
121
- }
122
- }
123
- ]
124
- },
125
- status: "ok"
126
- }
127
- }
128
-
129
- Thing::Product::FileuploadProgressEventsMessage.new(
130
- _method: "fileupload_progress",
131
- need_reply: 0,
132
- bid: Message.generate_bid,
133
- tid: Message.generate_tid,
134
- timestamp: Message.current_timestamp,
135
- gateway: "dock_sn",
136
- _data: message_data,
137
- data: message_data
138
- )
139
- end
140
-
141
- def build_flighttask_progress_events_message
142
- message_data = {
143
- output: {
144
- ext: {
145
- current_waypoint_index: 3,
146
- media_count: 6,
147
- track_id: "track_id",
148
- flight_id: "flight_id",
149
- break_point: {
150
- index: 1,
151
- state: 0,
152
- progress: 0.34,
153
- wayline_id: 0,
154
- break_reason: 1,
155
- latitude: 23.4,
156
- longitude: 113.99,
157
- height: 100.23,
158
- attitude_head: 30
159
- }
160
- },
161
- progress: {
162
- current_step: 19,
163
- percent: 100
164
- },
165
- status: "ok"
166
- },
167
- result: 0
168
- }
169
-
170
- Thing::Product::FlighttaskProgressEventsMessage.new(
171
- bid: Message.generate_bid,
172
- tid: Message.generate_tid,
173
- data: message_data,
174
- _data: message_data,
175
- _method: "flighttask_progress",
176
- timestamp: Message.current_timestamp
177
- )
178
- end
179
-
180
- def build_flighttask_ready_events_message
181
- message_data = {
182
- flight_ids: [
183
- SecureRandom.uuid,
184
- SecureRandom.uuid
185
- ]
186
- }
187
-
188
- Thing::Product::FlighttaskReadyEventsMessage.new(
189
- bid: Message.generate_bid,
190
- tid: Message.generate_tid,
191
- data: message_data,
192
- _data: message_data,
193
- _method: "flighttask_ready",
194
- timestamp: Message.current_timestamp
195
- )
196
- end
197
-
198
- def build_highest_priority_upload_flighttask_media_events_message
199
- message_data = {
200
- flight_id: SecureRandom.uuid
201
- }
202
-
203
- Thing::Product::HighestPriorityUploadFlighttaskMediaEventsMessage.new(
204
- bid: Message.generate_bid,
205
- _data: message_data,
206
- data: message_data,
207
- _method: "highest_priority_upload_flighttask_media",
208
- need_reply: 1,
209
- tid: Message.generate_tid,
210
- timestamp: Message.current_timestamp,
211
- gateway: "DOCK01"
212
- )
213
- end
214
-
215
- def build_offline_map_sync_progress_events_message
216
- message_data = {
217
- status: "failed",
218
- reason: 0,
219
- file: "geofence_xxx.json"
220
- }
221
-
222
- Thing::Product::OfflineMapSyncProgressEventsMessage.new(
223
- bid: Message.generate_bid,
224
- tid: Message.generate_tid,
225
- timestamp: Message.current_timestamp,
226
- _method: "offline_map_sync_progress",
227
- need_reply: 1,
228
- data: message_data,
229
- _data: message_data
230
- )
231
- end
10
+ include EventsMessages
11
+ include StateMessages
232
12
 
233
13
  # OSD
234
14
 
@@ -1166,85 +946,5 @@ module DjiMqttConnect
1166
946
  data: message_data
1167
947
  )
1168
948
  end
1169
-
1170
- ### State Messages ###
1171
-
1172
- def build_thing_product_live_capacity_state_message
1173
- message_data = {
1174
- live_capacity: {
1175
- available_video_number: 3,
1176
- coexist_video_number_max: 2,
1177
- device_list: [
1178
- {
1179
- sn: "DOCK01",
1180
- available_video_number: 1,
1181
- coexist_video_number_max: 1,
1182
- camera_list: [
1183
- {
1184
- camera_index: "165-0-7",
1185
- available_video_number: 1,
1186
- coexist_video_number_max: 1,
1187
- video_list: [
1188
- {
1189
- video_index: "normal-0",
1190
- video_type: "normal",
1191
- switchable_video_types: [
1192
- "normal"
1193
- ]
1194
- }
1195
- ]
1196
- }
1197
- ]
1198
- },
1199
- {
1200
- sn: "DRONE01",
1201
- available_video_number: 2,
1202
- coexist_video_number_max: 2,
1203
- camera_list: [
1204
- {
1205
- camera_index: "39-0-7",
1206
- available_video_number: 1,
1207
- coexist_video_number_max: 1,
1208
- video_list: [
1209
- {
1210
- video_index: "normal-0",
1211
- video_type: "normal",
1212
- switchable_video_types: [
1213
- "normal"
1214
- ]
1215
- }
1216
- ]
1217
- },
1218
- {
1219
- camera_index: "52-0-0",
1220
- available_video_number: 1,
1221
- coexist_video_number_max: 1,
1222
- video_list: [
1223
- {
1224
- video_index: "normal-0",
1225
- video_type: "wide",
1226
- switchable_video_types: [
1227
- "wide",
1228
- "zoom",
1229
- "ir"
1230
- ]
1231
- }
1232
- ]
1233
- }
1234
- ]
1235
- }
1236
- ]
1237
- }
1238
- }
1239
-
1240
- Thing::Product::StateMessage.new(
1241
- bid: Message.generate_bid,
1242
- tid: Message.generate_tid,
1243
- timestamp: Message.current_timestamp,
1244
- gateway: "GATEWAY01",
1245
- _data: message_data,
1246
- data: message_data
1247
- )
1248
- end
1249
949
  end
1250
950
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-transformer"
4
+ require "json"
5
+
6
+ module DjiMqttConnect
7
+ module Thing::Product
8
+ class StateReplyMarshal < MessageMarshal
9
+ # Renames the method attribute
10
+ class HashTransformer < Dry::Transformer::Pipe
11
+ import Dry::Transformer::HashTransformations
12
+
13
+ define! do
14
+ rename_keys _method: :method
15
+ end
16
+ end
17
+
18
+ # Converts a message for transmission via MQTT
19
+ def dump(message)
20
+ # Fix up the hash representation
21
+ transformed_message = hash_transformer.call(message)
22
+
23
+ # Convert the transformed message into JSON
24
+ JSON.generate(transformed_message)
25
+ end
26
+
27
+ private
28
+
29
+ def hash_transformer
30
+ @hash_transformer ||= HashTransformer.new
31
+ end
32
+ end
33
+ end
34
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module DjiMqttConnect
4
4
  module Thing::Product
5
- class DeviceLogEventsMessage < ServicesReplyMessage
5
+ class DeviceLogEventsMessage < EventsMessage
6
6
  # BID is not always included in message
7
7
  attribute? :bid, Types::UUID
8
8
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DjiMqttConnect
4
+ module Thing::Product
5
+ class TakeoffToPointProgressEventsMessage < EventsMessage
6
+ attribute :_method, Types::String.enum("takeoff_to_point_progress")
7
+
8
+ attribute :data do
9
+ attribute :flight_id, Types::String
10
+ attribute :remaining_distance, Types::Integer
11
+ attribute :remaining_time, Types::Integer
12
+ attribute :result, Types::Integer
13
+ attribute :status, Types::String
14
+ attribute :track_id, Types::String | Types::Nil
15
+ attribute :way_point_index, Types::Integer
16
+ end
17
+ end
18
+ end
19
+ end
@@ -21,19 +21,7 @@ module DjiMqttConnect
21
21
  attribute :tid, Types::UUID
22
22
  attribute :timestamp, Types::Timestamp
23
23
 
24
- attribute :_method, Types::String.enum(
25
- "airsense_warning",
26
- "device_exit_homing_notify",
27
- "device_reboot",
28
- "file_upload_callback",
29
- "fileupload_progress",
30
- "flight_areas_drone_location",
31
- "flight_areas_sync_progress",
32
- "flighttask_progress",
33
- "flighttask_ready",
34
- "highest_priority_upload_flighttask_media",
35
- "offline_map_sync_progress"
36
- )
24
+ attribute :_method, Types::String
37
25
 
38
26
  attribute :data do
39
27
  include Mixins::ResultMessage
@@ -82,7 +82,18 @@ module DjiMqttConnect
82
82
 
83
83
  attribute :_data, Types::Hash
84
84
 
85
+ # NOTE: Included in some state messages, requires a reply on the state_reply topic if true
86
+ attribute? :need_reply, Types::Integer.enum(0, 1)
87
+
88
+ def need_reply?
89
+ need_reply == 1
90
+ end
91
+
85
92
  attribute :data do
93
+ attribute? :geo_caging_status do
94
+ attribute :state, Types::Integer
95
+ end
96
+
86
97
  # Not all messages will have a live_capacity attribute
87
98
  attribute? :live_capacity do
88
99
  attribute :available_video_number, Types::Integer
@@ -103,6 +114,65 @@ module DjiMqttConnect
103
114
  end
104
115
  end
105
116
  end
117
+
118
+ attribute? :live_status, Types::Array do
119
+ attribute :video_id, Types::String
120
+ attribute :video_type, Types::String
121
+ attribute :video_quality, Types::Integer
122
+ attribute :status, Types::Integer
123
+ attribute :error_status, Types::Integer
124
+ end
125
+
126
+ attribute? :payloads, Types::Array do
127
+ attribute :control_source, Types::String
128
+ attribute? :firmware_version, Types::String
129
+ attribute :payload_index, Types::String
130
+ attribute? :sn, Types::String
131
+ end
132
+
133
+ attribute? :rtcm_info do
134
+ attribute :host, Types::String
135
+ attribute :mount_point, Types::String
136
+ attribute :port, Types::String
137
+ attribute :rtcm_device_type, Types::Integer
138
+ attribute :source_type, Types::Integer
139
+ end
140
+
141
+ attribute? :wireless_link_topo do
142
+ attribute :center_node do
143
+ attribute :sdr_id, Types::Integer
144
+ attribute :sn, Types::String
145
+ end
146
+
147
+ attribute :leaf_nodes, Types::Array do
148
+ attribute :control_source_index, Types::Integer
149
+ attribute :sdr_id, Types::Integer
150
+ attribute :sn, Types::String
151
+ attribute :valid, Types::Bool
152
+ end
153
+
154
+ attribute :secret_code, Types::Array.of(Types::Integer)
155
+ end
156
+
157
+ attribute? :ar_info_switch, Types::Integer
158
+ attribute? :commander_flight_height, Types::Integer
159
+ attribute? :commander_flight_mode, Types::Integer
160
+ attribute? :commander_mode_lost_action, Types::Integer
161
+ attribute? :control_source, Types::String
162
+ attribute? :current_commander_flight_mode, Types::Integer
163
+ attribute? :current_rth_mode, Types::Integer
164
+ attribute? :flysafe_database_version, Types::String
165
+ attribute? :home_latitude, Types::Latitude
166
+ attribute? :home_longitude, Types::Longitude
167
+ attribute? :locked, Types::Bool
168
+ attribute? :mode_code_reason, Types::Integer
169
+ attribute? :offline_map_enable, Types::Bool
170
+ attribute? :rth_mode, Types::Integer
171
+ attribute? :uom_real_name_state, Types::Integer
172
+ attribute? :wpmz_version, Types::String
173
+
174
+ attribute? :low_battery_warning_threshold, Types::Integer
175
+ attribute? :serious_low_battery_warning_threshold, Types::Integer
106
176
  end
107
177
  end
108
178
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DjiMqttConnect
4
+ module Thing::Product
5
+ class StateReplyMessage < Message
6
+ # a result of 0 means we approve of this action
7
+ def self.build_for(events_message, result: 0)
8
+ new(
9
+ tid: events_message.tid,
10
+ bid: events_message.bid,
11
+ timestamp: current_timestamp,
12
+ data: {
13
+ result: result
14
+ }
15
+ )
16
+ end
17
+
18
+ attribute :bid, Types::UUID
19
+ attribute :tid, Types::UUID
20
+ attribute :timestamp, Types::Timestamp
21
+
22
+ attribute :data do
23
+ include Mixins::ResultMessage
24
+
25
+ attribute :result, Types::ResultCode
26
+ end
27
+ end
28
+ end
29
+ end
@@ -25,6 +25,9 @@ module DjiMqttConnect
25
25
  event_name = message.class.name.demodulize.sub(/sMessage\z/, "").underscore.to_sym
26
26
  broadcast(event_name, device_sn, message)
27
27
  end
28
+
29
+ # Broadcast a generic received events message event
30
+ broadcast(:received_events_message, device_sn, message)
28
31
  rescue ParseError => error
29
32
  broadcast(:parse_error, error, topic, raw_message)
30
33
  end
@@ -3,7 +3,7 @@
3
3
  module DjiMqttConnect
4
4
  module Thing::Product
5
5
  class OsdTopicRepository < TopicRepository
6
- OSD_TOPIC_REGEX = /\Athing\/product\/(?<device_identifier>.+)\/osd\z/
6
+ OSD_TOPIC_REGEX = /\Athing\/product\/(?<device_sn>.+)\/osd\z/
7
7
 
8
8
  def listen!
9
9
  listen_to_topic("thing/product/+/osd") do |topic, raw_message|
@@ -12,10 +12,10 @@ module DjiMqttConnect
12
12
  matched_topic = OSD_TOPIC_REGEX.match(topic)
13
13
  raise Error, "Unknown topic: #{topic}" unless matched_topic
14
14
 
15
- device_identifier = matched_topic[:device_identifier]
15
+ device_sn = matched_topic[:device_sn]
16
16
  message = OsdMarshal.load(raw_message)
17
17
 
18
- logger.info("Received #{message} from #{device_identifier}")
18
+ logger.info("Received #{message} from #{device_sn}")
19
19
 
20
20
  if message.instance_of?(OsdMessage)
21
21
  # Broadcast an unsupported message event
@@ -23,8 +23,11 @@ module DjiMqttConnect
23
23
  else
24
24
  # Build event name and broadcast (i.e. ::RemoteOsdMessage => remote_osd_update)
25
25
  event_name = message.class.name.demodulize.sub(/Message\z/, "Update").underscore.to_sym
26
- broadcast(event_name, device_identifier, message)
26
+ broadcast(event_name, device_sn, message)
27
27
  end
28
+
29
+ # Broadcast a generic received osd message event
30
+ broadcast(:received_osd_message, device_sn, message)
28
31
  rescue ParseError => error
29
32
  broadcast(:parse_error, error, topic, raw_message)
30
33
  end
@@ -24,6 +24,9 @@ module DjiMqttConnect
24
24
  # Build event name and broadcast (i.e. ::ConfigRequestsMessage => config)
25
25
  broadcast(message._method.to_sym, gateway_sn, message)
26
26
  end
27
+
28
+ # Broadcast a generic received requests message event
29
+ broadcast(:received_requests_message, gateway_sn, message)
27
30
  rescue ParseError => error
28
31
  broadcast(:parse_error, error, topic, raw_message)
29
32
  end
@@ -25,6 +25,9 @@ module DjiMqttConnect
25
25
  event_name = "#{message._method.to_sym}_reply"
26
26
  broadcast(event_name, gateway_sn, message)
27
27
  end
28
+
29
+ # Broadcast a generic received services reply message event
30
+ broadcast(:received_services_reply_message, gateway_sn, message)
28
31
  rescue ParseError => error
29
32
  broadcast(:parse_error, error, topic, raw_message)
30
33
  end
@@ -3,7 +3,7 @@
3
3
  module DjiMqttConnect
4
4
  module Thing::Product
5
5
  class StateTopicRepository < TopicRepository
6
- STATE_TOPIC_REGEX = /\Athing\/product\/(?<gateway_sn>.+)\/state\z/
6
+ STATE_TOPIC_REGEX = /\Athing\/product\/(?<device_sn>.+)\/state\z/
7
7
 
8
8
  def listen!
9
9
  listen_to_topic("thing/product/+/state") do |topic, raw_message|
@@ -12,13 +12,13 @@ module DjiMqttConnect
12
12
  matched_topic = STATE_TOPIC_REGEX.match(topic)
13
13
  raise Error, "Unknown topic: #{topic}" unless matched_topic
14
14
 
15
- gateway_sn = matched_topic[:gateway_sn]
15
+ device_sn = matched_topic[:device_sn]
16
16
  message = state_marshal.load(raw_message)
17
17
 
18
- logger.info("Received #{message} from #{gateway_sn}")
18
+ logger.info("Received #{message} from #{device_sn}")
19
19
 
20
- # Broadcast the state update
21
- broadcast(:state_update, gateway_sn, message)
20
+ # Broadcast a generic received state message event
21
+ broadcast(:received_state_message, device_sn, message)
22
22
  rescue ParseError => error
23
23
  broadcast(:parse_error, error, topic, raw_message)
24
24
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DjiMqttConnect
4
+ module Thing::Product
5
+ class StateReplyTopicRepository < TopicRepository
6
+ # Publishes a message to gateway_sn on the "thing/product/+/state_reply" topic.
7
+ def publish_to_device(gateway_sn, state_reply_message)
8
+ publish_to_topic(
9
+ "thing/product/#{gateway_sn}/state_reply",
10
+ state_reply_message,
11
+ marshal: StateReplyMarshal
12
+ )
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DjiMqttConnect
4
- VERSION = "0.1.22.2"
4
+ VERSION = "0.1.23.1"
5
5
  end
@@ -51,6 +51,7 @@ module DjiMqttConnect
51
51
  autoload :OfflineMapSyncProgressEventsMessage, "dji_mqtt_connect/messages/thing/product/events/offline_map_sync_progress"
52
52
  autoload :ReturnHomeInfoEventsMessage, "dji_mqtt_connect/messages/thing/product/events/return_home_info"
53
53
  autoload :StatusCodeEventsMessage, "dji_mqtt_connect/messages/thing/product/events/status_code"
54
+ autoload :TakeoffToPointProgressEventsMessage, "dji_mqtt_connect/messages/thing/product/events/takeoff_to_point_progress"
54
55
  autoload :TrackEventsMessage, "dji_mqtt_connect/messages/thing/product/events/track"
55
56
  autoload :EventsMessage, "dji_mqtt_connect/messages/thing/product/events_message"
56
57
 
@@ -119,6 +120,7 @@ module DjiMqttConnect
119
120
  autoload :ReturnHomeCancelServicesReplyMessage, "dji_mqtt_connect/messages/thing/product/services_reply/return_home_cancel"
120
121
 
121
122
  autoload :StateMessage, "dji_mqtt_connect/messages/thing/product/state_message"
123
+ autoload :StateReplyMessage, "dji_mqtt_connect/messages/thing/product/state_reply_message"
122
124
 
123
125
  # Topics
124
126
  autoload :EventsTopicRepository, "dji_mqtt_connect/topics/thing/product/events"
@@ -129,6 +131,7 @@ module DjiMqttConnect
129
131
  autoload :ServicesTopicRepository, "dji_mqtt_connect/topics/thing/product/services"
130
132
  autoload :ServicesReplyTopicRepository, "dji_mqtt_connect/topics/thing/product/services_reply"
131
133
  autoload :StateTopicRepository, "dji_mqtt_connect/topics/thing/product/state"
134
+ autoload :StateReplyTopicRepository, "dji_mqtt_connect/topics/thing/product/state_reply"
132
135
 
133
136
  # Marshals
134
137
  autoload :EventsMarshal, "dji_mqtt_connect/marshals/thing/product/events_marshal"
@@ -143,6 +146,7 @@ module DjiMqttConnect
143
146
  autoload :ServicesReplyMarshal, "dji_mqtt_connect/marshals/thing/product/services_reply_marshal"
144
147
 
145
148
  autoload :StateMarshal, "dji_mqtt_connect/marshals/thing/product/state_marshal"
149
+ autoload :StateReplyMarshal, "dji_mqtt_connect/marshals/thing/product/state_reply_marshal"
146
150
  end
147
151
  end
148
152