Blackmagic REST API Tutorials

GitHub
< Previous Page Next Page >
# 3. PUT Requests It's finally time to send some commands to the camera. A super simple one is `PUT /lens/focus/doAutoFocus`, but how do we send a `PUT` command? ## doAutoFocus ### JavaScript We can take our sendGETRequest function from before and modify it into a sendPUTRequest function. Let's see it: ```JS function sendPUTRequest(endpoint, data) { // Put the camera's API address in a constant const cameraAPIAddress = "http://studio-camera-6k-pro.local/control/api/v1"; // Remember to change this for YOUR camera's API address // Instantiate the XMLHttpRequest object let xhr = new XMLHttpRequest(); // Create an object to store and return the response var responseObject = {}; // Define the onload function xhr.onload = function() { if (this.status < 300) { // If the operation is successful if (this.responseText) responseObject = JSON.parse(this.responseText); // Give the data to the responseObject responseObject.status = this.status; // Also pass along the status code for error handling } else { // If there has been an error responseObject = this; // Give the XMLHttpRequest data to the responseObject console.error("Error ", this.status, ": ", this.statusText); // Log the error in the console } }; // Open the connection // The "false" here specifies that we want to wait for the response to come back before returning from xhr.send() xhr.open("PUT", cameraAPIAddress+endpoint, false); // Send the request with data xhr.send(data); // Return response data return responseObject; } ``` Notice the new parameter, `data`. We can pass a JSON string into this parameter that will get sent to the camera for commands that require data values. `PUT /lens/focus/doAutoFocus` doesn't have any data, though, so we can call the function and pass the string for an empty JSON Object in for the `data` argument, like so: ```JS sendPUTRequest("/lens/focus/doAutoFocus","{}"); ``` The camera usually responds to `PUT` requests with `204: No Content`, so there will be no JSON data to parse from the responseText. That is why we had to add the line `if (this.responseText)` to the code. Even though the function only returns `{"status": 204}`, if you look at the camera feed as you send the command, you can catch the camera auto-focusing! > **Note:** Any lens control commands will require a lens with electronic control pins that connect to the camera. Many lenses, especially ones > designed for cinema cameras, do not have these electronic connections, and so will not work with the API. ### Python Just like the JavaScript, we can modify our sendGETRequest function into a sendPUTRequest one. The Python version looks like: ```Python import requests def sendPUTRequest(endpoint, data): # Store the API Address cameraAPIAddress = "http://Studio-Camera-6K-Pro.local/control/api/v1" # Remember to change this for YOUR camera's API address # Send the request response = requests.put(cameraAPIAddress+endpoint, json=data) # Handle errors and return return response ``` Because the camera doesn't return any data on a successful `PUT`, we can just return the `response` object and leave the error handling for later. Let's run this now with the `doAutoFocus` endpoint and empty `dict` object in the data argument: ```python sendPUTRequest("/lens/focus/doAutoFocus", {}) ``` And we get a response object as a return value, that when running in interactive mode shows up as `<Response [204]>`. Hopefully, the camera did the auto focus too. ## ISO So we've gotten the camera to auto focus, but what about a PUT request that has some data, like changing the ISO? Consulting the documentation, we can see that a `PUT /video/iso` API call will have one integer parameter named `'iso'`. Here's how we can send a command to change the ISO in JS using our sendPUTRequest functions: ```JavaScript sendPUTRequest("/video/iso", "{\"iso\": 1600}"); // Set the ISO to 1600 sendPUTRequest("/video/iso", JSON.stringify({iso: 1600})); // Alternate way of passing JSON to data argument ``` > (XMLHttpRequest.send(data) takes the JSON data as a string, and the way we wrote our sendPUTRequest function does not convert the argument to a string automatically. That is why we must either use `\"` to add quotes within a string we pass to the function or call `JSON.stringify()`) And, in Python: ```Python sendPUTRequest("/video/iso", {'iso': 3200}) # Set the ISO to 3200 ``` Now that we know how to send JSON data to specific endpoints, let's try changing some other settings! ## White Balance White Balance is another easy setting to change, since it is just one value. We can do it like this: ```JavaScript sendPUTRequest("/video/whiteBalance", "{\"whiteBalance\": 3200}"); // Set WB to 3200K ``` ```Python sendPUTRequest("/video/whiteBalance", {'whiteBalance': 5600}) # Set WB to 5600K ``` ## Iris The iris data from the camera is more complex than just one number. Do we want to set a specific f-stop? Do we want to set it as a percentage of fully open/closed? The API allows us to send a `PUT` request with just one of these values, and it will interpret it for us. If we want to set the iris to exactly f/8, we can do that with our JavaScript function like this: ```JavaScript sendPUTRequest("/lens/iris", "{\"apertureStop\": 8}"); // Set iris to f/8 ``` If we want to open the iris as much as possible, wait one second, and then fully close it, we can do it (shown in Python) like this: ```Python sendPUTRequest("/lens/iris", {'normalised': 0}) # Fully open iris time.sleep(1) sendPUTRequest("/lens/iris", {'normalised': 1}) # Fully close iris ``` ## Record Now this is a setting that you'll find useful. The camera's current recording state can be `GET` and `PUT` at the endpoint `/transports/0/record`. Looking at the documentation, the `PUT /transports/0/record` command has an extra parameter: a name for the new clip. Let's write JavaScript and Python functions to toggle the recording state of the camera and set a custom file name: ```JS function toggleRecord(filename="") { // First, get whether or not the camera is recording right now var recordingState = sendGETRequest("/transports/0/record"); // Boolean invert the recording state recordingState.recording = !recordingState.recording; // If a file name was specified, add that to the state object as "clipName" if (filename) { recordingState.clipName = filename; } // PUT the data back on the camera sendPUTRequest("/transports/0/record",JSON.stringify(recordingState)); } ``` ```Python def toggleRecord(filename=""): # First, get whether or not the camera is recording right now recordingState = sendGETRequest("/transports/0/record") # Boolean invert the recording state recordingState["recording"] = not (recordingState["recording"]) # If a file name was specified, add that to the dict as "clipName" if (len(filename) > 0): recordingState["clipName"] = filename # PUT the data back on the camera sendPUTRequest("/transports/0/record",recordingState) ``` Try it out! Now that you know how to `GET` data, modify the `dict` and JSON data, and `PUT` it back on the camera, try writing your own functions and scripts to control the settings you want! The possibilities are literally endless. Some endpoints in the API specify that they use the `POST` method. If that's one of the settings you care about, write a sendPOSTRequest function. In the next article, we'll organize all of this data and these functions, allowing control of _multiple_ devices! Let's go!
Next Article