Commit d626ae03642493549b65e84eea898fca9234b64e

Authored by Andrii Shvaika
1 parent 38a3ca68

Device API Controller

@@ -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));