Showing
1 changed file
with
220 additions
and
32 deletions
@@ -17,6 +17,8 @@ package org.thingsboard.server.transport.http; | @@ -17,6 +17,8 @@ package org.thingsboard.server.transport.http; | ||
17 | 17 | ||
18 | import com.google.gson.JsonObject; | 18 | import com.google.gson.JsonObject; |
19 | import com.google.gson.JsonParser; | 19 | import com.google.gson.JsonParser; |
20 | +import io.swagger.annotations.ApiOperation; | ||
21 | +import io.swagger.annotations.ApiParam; | ||
20 | import lombok.RequiredArgsConstructor; | 22 | import lombok.RequiredArgsConstructor; |
21 | import lombok.extern.slf4j.Slf4j; | 23 | import lombok.extern.slf4j.Slf4j; |
22 | import org.springframework.beans.factory.annotation.Autowired; | 24 | import org.springframework.beans.factory.annotation.Autowired; |
@@ -68,6 +70,7 @@ import java.util.List; | @@ -68,6 +70,7 @@ import java.util.List; | ||
68 | import java.util.UUID; | 70 | import java.util.UUID; |
69 | import java.util.function.Consumer; | 71 | import java.util.function.Consumer; |
70 | 72 | ||
73 | + | ||
71 | /** | 74 | /** |
72 | * @author Andrew Shvayka | 75 | * @author Andrew Shvayka |
73 | */ | 76 | */ |
@@ -77,14 +80,70 @@ import java.util.function.Consumer; | @@ -77,14 +80,70 @@ import java.util.function.Consumer; | ||
77 | @Slf4j | 80 | @Slf4j |
78 | public class DeviceApiController implements TbTransportService { | 81 | public class DeviceApiController implements TbTransportService { |
79 | 82 | ||
83 | + private static final String MARKDOWN_CODE_BLOCK_START = "\n\n```json\n"; | ||
84 | + private static final String MARKDOWN_CODE_BLOCK_END = "\n```\n\n"; | ||
85 | + | ||
86 | + private static final String REQUIRE_ACCESS_TOKEN = "The API call is designed to be used by device firmware and requires device access token ('deviceToken'). " + | ||
87 | + "It is not recommended to use this API call by third-party scripts, rule-engine or platform widgets (use 'Telemetry Controller' instead).\n"; | ||
88 | + | ||
89 | + private static final String ATTRIBUTE_PAYLOAD_EXAMPLE = "{\n" + | ||
90 | + " \"stringKey\":\"value1\", \n" + | ||
91 | + " \"booleanKey\":true, \n" + | ||
92 | + " \"doubleKey\":42.0, \n" + | ||
93 | + " \"longKey\":73, \n" + | ||
94 | + " \"jsonKey\": {\n" + | ||
95 | + " \"someNumber\": 42,\n" + | ||
96 | + " \"someArray\": [1,2,3],\n" + | ||
97 | + " \"someNestedObject\": {\"key\": \"value\"}\n" + | ||
98 | + " }\n" + | ||
99 | + "}"; | ||
100 | + | ||
101 | + protected static final String TS_PAYLOAD = "The request payload is a JSON document with three possible formats:\n\n" + | ||
102 | + "Simple format without timestamp. In such a case, current server time will be used: \n\n" + | ||
103 | + MARKDOWN_CODE_BLOCK_START + | ||
104 | + "{\n" + | ||
105 | + " \"stringKey\":\"value1\", \n" + | ||
106 | + " \"booleanKey\":true, \n" + | ||
107 | + " \"doubleKey\":42.0, \n" + | ||
108 | + " \"longKey\":73, \n" + | ||
109 | + " \"jsonKey\": {\n" + | ||
110 | + " \"someNumber\": 42,\n" + | ||
111 | + " \"someArray\": [1,2,3],\n" + | ||
112 | + " \"someNestedObject\": {\"key\": \"value\"}\n" + | ||
113 | + " }\n" + | ||
114 | + "}" + | ||
115 | + MARKDOWN_CODE_BLOCK_END + | ||
116 | + "\n\n Single JSON object with timestamp: \n\n" + | ||
117 | + MARKDOWN_CODE_BLOCK_START + | ||
118 | + "{\"ts\":1634712287000,\"values\":{\"temperature\":26, \"humidity\":87}}" + | ||
119 | + MARKDOWN_CODE_BLOCK_END + | ||
120 | + "\n\n JSON array with timestamps: \n\n" + | ||
121 | + MARKDOWN_CODE_BLOCK_START + | ||
122 | + "[\n{\"ts\":1634712287000,\"values\":{\"temperature\":26, \"humidity\":87}}, \n{\"ts\":1634712588000,\"values\":{\"temperature\":25, \"humidity\":88}}\n]" + | ||
123 | + MARKDOWN_CODE_BLOCK_END; | ||
124 | + | ||
125 | + private static final String ACCESS_TOKEN_PARAM_DESCRIPTION = "Your device access token."; | ||
126 | + | ||
80 | @Autowired | 127 | @Autowired |
81 | private HttpTransportContext transportContext; | 128 | private HttpTransportContext transportContext; |
82 | 129 | ||
130 | + @ApiOperation(value = "Get attributes (getDeviceAttributes)", | ||
131 | + notes = "Returns all attributes that belong to device. " | ||
132 | + + "Use optional 'clientKeys' and/or 'sharedKeys' parameter to return specific attributes. " | ||
133 | + + "\n Example of the result: " | ||
134 | + + MARKDOWN_CODE_BLOCK_START | ||
135 | + + ATTRIBUTE_PAYLOAD_EXAMPLE | ||
136 | + + MARKDOWN_CODE_BLOCK_END | ||
137 | + + REQUIRE_ACCESS_TOKEN, | ||
138 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
83 | @RequestMapping(value = "/{deviceToken}/attributes", method = RequestMethod.GET, produces = "application/json") | 139 | @RequestMapping(value = "/{deviceToken}/attributes", method = RequestMethod.GET, produces = "application/json") |
84 | - public DeferredResult<ResponseEntity> getDeviceAttributes(@PathVariable("deviceToken") String deviceToken, | ||
85 | - @RequestParam(value = "clientKeys", required = false, defaultValue = "") String clientKeys, | ||
86 | - @RequestParam(value = "sharedKeys", required = false, defaultValue = "") String sharedKeys, | ||
87 | - HttpServletRequest httpRequest) { | 140 | + public DeferredResult<ResponseEntity> getDeviceAttributes( |
141 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
142 | + @PathVariable("deviceToken") String deviceToken, | ||
143 | + @ApiParam(value = "Comma separated key names for attribute with client scope", required = true, defaultValue = "state") | ||
144 | + @RequestParam(value = "clientKeys", required = false, defaultValue = "") String clientKeys, | ||
145 | + @ApiParam(value = "Comma separated key names for attribute with shared scope", required = true, defaultValue = "configuration") | ||
146 | + @RequestParam(value = "sharedKeys", required = false, defaultValue = "") String sharedKeys) { | ||
88 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | 147 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); |
89 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 148 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
90 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 149 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -106,9 +165,20 @@ public class DeviceApiController implements TbTransportService { | @@ -106,9 +165,20 @@ public class DeviceApiController implements TbTransportService { | ||
106 | return responseWriter; | 165 | return responseWriter; |
107 | } | 166 | } |
108 | 167 | ||
168 | + @ApiOperation(value = "Post attributes (postDeviceAttributes)", | ||
169 | + notes = "Post client attribute updates on behalf of device. " | ||
170 | + + "\n Example of the request: " | ||
171 | + + MARKDOWN_CODE_BLOCK_START | ||
172 | + + ATTRIBUTE_PAYLOAD_EXAMPLE | ||
173 | + + MARKDOWN_CODE_BLOCK_END | ||
174 | + + REQUIRE_ACCESS_TOKEN, | ||
175 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
109 | @RequestMapping(value = "/{deviceToken}/attributes", method = RequestMethod.POST) | 176 | @RequestMapping(value = "/{deviceToken}/attributes", method = RequestMethod.POST) |
110 | - public DeferredResult<ResponseEntity> postDeviceAttributes(@PathVariable("deviceToken") String deviceToken, | ||
111 | - @RequestBody String json, HttpServletRequest request) { | 177 | + public DeferredResult<ResponseEntity> postDeviceAttributes( |
178 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
179 | + @PathVariable("deviceToken") String deviceToken, | ||
180 | + @ApiParam(value = "JSON with attribute key-value pairs. See API call description for example.") | ||
181 | + @RequestBody String json) { | ||
112 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | 182 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); |
113 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 183 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
114 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 184 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -119,9 +189,17 @@ public class DeviceApiController implements TbTransportService { | @@ -119,9 +189,17 @@ public class DeviceApiController implements TbTransportService { | ||
119 | return responseWriter; | 189 | return responseWriter; |
120 | } | 190 | } |
121 | 191 | ||
192 | + @ApiOperation(value = "Post time-series data (postTelemetry)", | ||
193 | + notes = "Post time-series data on behalf of device. " | ||
194 | + + "\n Example of the request: " | ||
195 | + + TS_PAYLOAD | ||
196 | + + REQUIRE_ACCESS_TOKEN, | ||
197 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
122 | @RequestMapping(value = "/{deviceToken}/telemetry", method = RequestMethod.POST) | 198 | @RequestMapping(value = "/{deviceToken}/telemetry", method = RequestMethod.POST) |
123 | - public DeferredResult<ResponseEntity> postTelemetry(@PathVariable("deviceToken") String deviceToken, | ||
124 | - @RequestBody String json, HttpServletRequest request) { | 199 | + public DeferredResult<ResponseEntity> postTelemetry( |
200 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
201 | + @PathVariable("deviceToken") String deviceToken, | ||
202 | + @RequestBody String json, HttpServletRequest request) { | ||
125 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>(); | 203 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>(); |
126 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 204 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
127 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 205 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -132,9 +210,22 @@ public class DeviceApiController implements TbTransportService { | @@ -132,9 +210,22 @@ public class DeviceApiController implements TbTransportService { | ||
132 | return responseWriter; | 210 | return responseWriter; |
133 | } | 211 | } |
134 | 212 | ||
213 | + @ApiOperation(value = "Save claiming information (claimDevice)", | ||
214 | + notes = "Saves the information required for user to claim the device. " + | ||
215 | + "See more info about claiming in the corresponding 'Claiming devices' platform documentation." | ||
216 | + + "\n Example of the request payload: " | ||
217 | + + MARKDOWN_CODE_BLOCK_START | ||
218 | + + "{\"secretKey\":\"value\", \"durationMs\":60000}" | ||
219 | + + MARKDOWN_CODE_BLOCK_END | ||
220 | + + "Note: both 'secretKey' and 'durationMs' is optional parameters. " + | ||
221 | + "In case the secretKey is not specified, the empty string as a default value is used. In case the durationMs is not specified, the system parameter device.claim.duration is used.\n\n" | ||
222 | + + REQUIRE_ACCESS_TOKEN, | ||
223 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
135 | @RequestMapping(value = "/{deviceToken}/claim", method = RequestMethod.POST) | 224 | @RequestMapping(value = "/{deviceToken}/claim", method = RequestMethod.POST) |
136 | - public DeferredResult<ResponseEntity> claimDevice(@PathVariable("deviceToken") String deviceToken, | ||
137 | - @RequestBody(required = false) String json, HttpServletRequest request) { | 225 | + public DeferredResult<ResponseEntity> claimDevice( |
226 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
227 | + @PathVariable("deviceToken") String deviceToken, | ||
228 | + @RequestBody(required = false) String json) { | ||
138 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | 229 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); |
139 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 230 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
140 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 231 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -146,10 +237,18 @@ public class DeviceApiController implements TbTransportService { | @@ -146,10 +237,18 @@ public class DeviceApiController implements TbTransportService { | ||
146 | return responseWriter; | 237 | return responseWriter; |
147 | } | 238 | } |
148 | 239 | ||
240 | + @ApiOperation(value = "Subscribe to RPC commands (subscribeToCommands) (Deprecated)", | ||
241 | + notes = "Subscribes to RPC commands using http long polling. " + | ||
242 | + "Deprecated, since long polling is resource and network consuming. " + | ||
243 | + "Consider using MQTT or CoAP protocol for light-weight real-time updates. \n\n" + | ||
244 | + REQUIRE_ACCESS_TOKEN, | ||
245 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
149 | @RequestMapping(value = "/{deviceToken}/rpc", method = RequestMethod.GET, produces = "application/json") | 246 | @RequestMapping(value = "/{deviceToken}/rpc", method = RequestMethod.GET, produces = "application/json") |
150 | - public DeferredResult<ResponseEntity> subscribeToCommands(@PathVariable("deviceToken") String deviceToken, | ||
151 | - @RequestParam(value = "timeout", required = false, defaultValue = "0") long timeout, | ||
152 | - HttpServletRequest httpRequest) { | 247 | + public DeferredResult<ResponseEntity> subscribeToCommands( |
248 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
249 | + @PathVariable("deviceToken") String deviceToken, | ||
250 | + @ApiParam(value = "Optional timeout of the long poll. Typically less then 60 seconds, since limited on the server side.") | ||
251 | + @RequestParam(value = "timeout", required = false, defaultValue = "0") long timeout) { | ||
153 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | 252 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); |
154 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 253 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
155 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 254 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -164,10 +263,18 @@ public class DeviceApiController implements TbTransportService { | @@ -164,10 +263,18 @@ public class DeviceApiController implements TbTransportService { | ||
164 | return responseWriter; | 263 | return responseWriter; |
165 | } | 264 | } |
166 | 265 | ||
266 | + @ApiOperation(value = "Reply to RPC commands (replyToCommand)", | ||
267 | + notes = "Replies to server originated RPC command identified by 'requestId' parameter. The response is arbitrary JSON.\n\n" + | ||
268 | + REQUIRE_ACCESS_TOKEN, | ||
269 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
167 | @RequestMapping(value = "/{deviceToken}/rpc/{requestId}", method = RequestMethod.POST) | 270 | @RequestMapping(value = "/{deviceToken}/rpc/{requestId}", method = RequestMethod.POST) |
168 | - public DeferredResult<ResponseEntity> replyToCommand(@PathVariable("deviceToken") String deviceToken, | ||
169 | - @PathVariable("requestId") Integer requestId, | ||
170 | - @RequestBody String json, HttpServletRequest request) { | 271 | + public DeferredResult<ResponseEntity> replyToCommand( |
272 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
273 | + @PathVariable("deviceToken") String deviceToken, | ||
274 | + @ApiParam(value = "RPC request id from the incoming RPC request", required = true, defaultValue = "123") | ||
275 | + @PathVariable("requestId") Integer requestId, | ||
276 | + @ApiParam(value = "Reply to the RPC request, JSON. For example: {\"status\":\"success\"}", required = true) | ||
277 | + @RequestBody String json) { | ||
171 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>(); | 278 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>(); |
172 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 279 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
173 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 280 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -177,9 +284,23 @@ public class DeviceApiController implements TbTransportService { | @@ -177,9 +284,23 @@ public class DeviceApiController implements TbTransportService { | ||
177 | return responseWriter; | 284 | return responseWriter; |
178 | } | 285 | } |
179 | 286 | ||
287 | + @ApiOperation(value = "Send the RPC command (postRpcRequest)", | ||
288 | + notes = "Send the RPC request to server. The request payload is a JSON document that contains 'method' and 'params'. For example:" + | ||
289 | + MARKDOWN_CODE_BLOCK_START + | ||
290 | + "{\"method\": \"sumOnServer\", \"params\":{\"a\":2, \"b\":2}}" + | ||
291 | + MARKDOWN_CODE_BLOCK_END + | ||
292 | + "The response contains arbitrary JSON with the RPC reply. For example: " + | ||
293 | + MARKDOWN_CODE_BLOCK_START + | ||
294 | + "{\"result\": 4}" + | ||
295 | + MARKDOWN_CODE_BLOCK_END + | ||
296 | + REQUIRE_ACCESS_TOKEN, | ||
297 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
180 | @RequestMapping(value = "/{deviceToken}/rpc", method = RequestMethod.POST) | 298 | @RequestMapping(value = "/{deviceToken}/rpc", method = RequestMethod.POST) |
181 | - public DeferredResult<ResponseEntity> postRpcRequest(@PathVariable("deviceToken") String deviceToken, | ||
182 | - @RequestBody String json, HttpServletRequest httpRequest) { | 299 | + public DeferredResult<ResponseEntity> postRpcRequest( |
300 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
301 | + @PathVariable("deviceToken") String deviceToken, | ||
302 | + @ApiParam(value = "The RPC request JSON", required = true) | ||
303 | + @RequestBody String json) { | ||
183 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>(); | 304 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<ResponseEntity>(); |
184 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 305 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
185 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 306 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -196,10 +317,18 @@ public class DeviceApiController implements TbTransportService { | @@ -196,10 +317,18 @@ public class DeviceApiController implements TbTransportService { | ||
196 | return responseWriter; | 317 | return responseWriter; |
197 | } | 318 | } |
198 | 319 | ||
320 | + @ApiOperation(value = "Subscribe to attribute updates (subscribeToAttributes) (Deprecated)", | ||
321 | + notes = "Subscribes to client and shared scope attribute updates using http long polling. " + | ||
322 | + "Deprecated, since long polling is resource and network consuming. " + | ||
323 | + "Consider using MQTT or CoAP protocol for light-weight real-time updates. \n\n" + | ||
324 | + REQUIRE_ACCESS_TOKEN, | ||
325 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
199 | @RequestMapping(value = "/{deviceToken}/attributes/updates", method = RequestMethod.GET, produces = "application/json") | 326 | @RequestMapping(value = "/{deviceToken}/attributes/updates", method = RequestMethod.GET, produces = "application/json") |
200 | - public DeferredResult<ResponseEntity> subscribeToAttributes(@PathVariable("deviceToken") String deviceToken, | ||
201 | - @RequestParam(value = "timeout", required = false, defaultValue = "0") long timeout, | ||
202 | - HttpServletRequest httpRequest) { | 327 | + public DeferredResult<ResponseEntity> subscribeToAttributes( |
328 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
329 | + @PathVariable("deviceToken") String deviceToken, | ||
330 | + @ApiParam(value = "Optional timeout of the long poll. Typically less then 60 seconds, since limited on the server side.") | ||
331 | + @RequestParam(value = "timeout", required = false, defaultValue = "0") long timeout) { | ||
203 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | 332 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); |
204 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), | 333 | transportContext.getTransportService().process(DeviceTransportType.DEFAULT, ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceToken).build(), |
205 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { | 334 | new DeviceAuthCallback(transportContext, responseWriter, sessionInfo -> { |
@@ -214,26 +343,85 @@ public class DeviceApiController implements TbTransportService { | @@ -214,26 +343,85 @@ public class DeviceApiController implements TbTransportService { | ||
214 | return responseWriter; | 343 | return responseWriter; |
215 | } | 344 | } |
216 | 345 | ||
346 | + @ApiOperation(value = "Get Device Firmware (getFirmware)", | ||
347 | + notes = "Downloads the current firmware package." + | ||
348 | + "When the platform initiates firmware update, " + | ||
349 | + "it informs the device by updating the 'fw_title', 'fw_version', 'fw_checksum' and 'fw_checksum_algorithm' shared attributes." + | ||
350 | + "The 'fw_title' and 'fw_version' parameters must be supplied in this request to double-check " + | ||
351 | + "that the firmware that device is downloading matches the firmware it expects to download. " + | ||
352 | + "This is important, since the administrator may change the firmware assignment while device is downloading the firmware. \n\n" + | ||
353 | + "Optional 'chunk' and 'size' parameters may be used to download the firmware in chunks. " + | ||
354 | + "For example, device may request first 16 KB of firmware using 'chunk'=0 and 'size'=16384. " + | ||
355 | + "Next 16KB using 'chunk'=1 and 'size'=16384. The last chunk should have less bytes then requested using 'size' parameter. \n\n" + | ||
356 | + REQUIRE_ACCESS_TOKEN, | ||
357 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
217 | @RequestMapping(value = "/{deviceToken}/firmware", method = RequestMethod.GET) | 358 | @RequestMapping(value = "/{deviceToken}/firmware", method = RequestMethod.GET) |
218 | - public DeferredResult<ResponseEntity> getFirmware(@PathVariable("deviceToken") String deviceToken, | ||
219 | - @RequestParam(value = "title") String title, | ||
220 | - @RequestParam(value = "version") String version, | ||
221 | - @RequestParam(value = "size", required = false, defaultValue = "0") int size, | ||
222 | - @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) { | 359 | + public DeferredResult<ResponseEntity> getFirmware( |
360 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
361 | + @PathVariable("deviceToken") String deviceToken, | ||
362 | + @ApiParam(value = "Title of the firmware, corresponds to the value of 'fw_title' attribute.", required = true) | ||
363 | + @RequestParam(value = "title") String title, | ||
364 | + @ApiParam(value = "Version of the firmware, corresponds to the value of 'fw_version' attribute.", required = true) | ||
365 | + @RequestParam(value = "version") String version, | ||
366 | + @ApiParam(value = "Size of the chunk. Optional. Omit to download the entire file without chunks.") | ||
367 | + @RequestParam(value = "size", required = false, defaultValue = "0") int size, | ||
368 | + @ApiParam(value = "Index of the chunk. Optional. Omit to download the entire file without chunks.") | ||
369 | + @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) { | ||
223 | return getOtaPackageCallback(deviceToken, title, version, size, chunk, OtaPackageType.FIRMWARE); | 370 | return getOtaPackageCallback(deviceToken, title, version, size, chunk, OtaPackageType.FIRMWARE); |
224 | } | 371 | } |
225 | 372 | ||
373 | + @ApiOperation(value = "Get Device Software (getSoftware)", | ||
374 | + notes = "Downloads the current software package." + | ||
375 | + "When the platform initiates software update, " + | ||
376 | + "it informs the device by updating the 'sw_title', 'sw_version', 'sw_checksum' and 'sw_checksum_algorithm' shared attributes." + | ||
377 | + "The 'sw_title' and 'sw_version' parameters must be supplied in this request to double-check " + | ||
378 | + "that the software that device is downloading matches the software it expects to download. " + | ||
379 | + "This is important, since the administrator may change the software assignment while device is downloading the software. \n\n" + | ||
380 | + "Optional 'chunk' and 'size' parameters may be used to download the software in chunks. " + | ||
381 | + "For example, device may request first 16 KB of software using 'chunk'=0 and 'size'=16384. " + | ||
382 | + "Next 16KB using 'chunk'=1 and 'size'=16384. The last chunk should have less bytes then requested using 'size' parameter. \n\n" + | ||
383 | + REQUIRE_ACCESS_TOKEN, | ||
384 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
226 | @RequestMapping(value = "/{deviceToken}/software", method = RequestMethod.GET) | 385 | @RequestMapping(value = "/{deviceToken}/software", method = RequestMethod.GET) |
227 | - public DeferredResult<ResponseEntity> getSoftware(@PathVariable("deviceToken") String deviceToken, | ||
228 | - @RequestParam(value = "title") String title, | ||
229 | - @RequestParam(value = "version") String version, | ||
230 | - @RequestParam(value = "size", required = false, defaultValue = "0") int size, | ||
231 | - @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) { | 386 | + public DeferredResult<ResponseEntity> getSoftware( |
387 | + @ApiParam(value = ACCESS_TOKEN_PARAM_DESCRIPTION, required = true, defaultValue = "YOUR_DEVICE_ACCESS_TOKEN") | ||
388 | + @PathVariable("deviceToken") String deviceToken, | ||
389 | + @ApiParam(value = "Title of the software, corresponds to the value of 'sw_title' attribute.", required = true) | ||
390 | + @RequestParam(value = "title") String title, | ||
391 | + @ApiParam(value = "Version of the software, corresponds to the value of 'sw_version' attribute.", required = true) | ||
392 | + @RequestParam(value = "version") String version, | ||
393 | + @ApiParam(value = "Size of the chunk. Optional. Omit to download the entire file without using chunks.") | ||
394 | + @RequestParam(value = "size", required = false, defaultValue = "0") int size, | ||
395 | + @ApiParam(value = "Index of the chunk. Optional. Omit to download the entire file without using chunks.") | ||
396 | + @RequestParam(value = "chunk", required = false, defaultValue = "0") int chunk) { | ||
232 | return getOtaPackageCallback(deviceToken, title, version, size, chunk, OtaPackageType.SOFTWARE); | 397 | return getOtaPackageCallback(deviceToken, title, version, size, chunk, OtaPackageType.SOFTWARE); |
233 | } | 398 | } |
234 | 399 | ||
400 | + @ApiOperation(value = "Provision new device (provisionDevice)", | ||
401 | + notes = "Exchange the provision request to the device credentials. " + | ||
402 | + "See more info about provisioning in the corresponding 'Device provisioning' platform documentation." + | ||
403 | + "Requires valid JSON request with the following format: " + | ||
404 | + MARKDOWN_CODE_BLOCK_START + | ||
405 | + "{\n" + | ||
406 | + " \"deviceName\": \"NEW_DEVICE_NAME\",\n" + | ||
407 | + " \"provisionDeviceKey\": \"u7piawkboq8v32dmcmpp\",\n" + | ||
408 | + " \"provisionDeviceSecret\": \"jpmwdn8ptlswmf4m29bw\"\n" + | ||
409 | + "}" + | ||
410 | + MARKDOWN_CODE_BLOCK_END + | ||
411 | + "Where 'deviceName' is the name of enw or existing device which depends on the provisioning strategy. " + | ||
412 | + "The 'provisionDeviceKey' and 'provisionDeviceSecret' matches info configured in one of the existing device profiles. " + | ||
413 | + "The result of the successful call is the JSON object that contains new credentials:" + | ||
414 | + MARKDOWN_CODE_BLOCK_START + "{\n" + | ||
415 | + " \"credentialsType\":\"ACCESS_TOKEN\",\n" + | ||
416 | + " \"credentialsValue\":\"DEVICE_ACCESS_TOKEN\",\n" + | ||
417 | + " \"status\":\"SUCCESS\"\n" + | ||
418 | + "}" + MARKDOWN_CODE_BLOCK_END | ||
419 | + , | ||
420 | + produces = MediaType.APPLICATION_JSON_VALUE) | ||
235 | @RequestMapping(value = "/provision", method = RequestMethod.POST) | 421 | @RequestMapping(value = "/provision", method = RequestMethod.POST) |
236 | - public DeferredResult<ResponseEntity> provisionDevice(@RequestBody String json, HttpServletRequest httpRequest) { | 422 | + public DeferredResult<ResponseEntity> provisionDevice( |
423 | + @ApiParam(value = "JSON with provision request. See API call description for example.") | ||
424 | + @RequestBody String json) { | ||
237 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); | 425 | DeferredResult<ResponseEntity> responseWriter = new DeferredResult<>(); |
238 | transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json), | 426 | transportContext.getTransportService().process(JsonConverter.convertToProvisionRequestMsg(json), |
239 | new DeviceProvisionCallback(responseWriter)); | 427 | new DeviceProvisionCallback(responseWriter)); |