-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path3-PUT-Requests.html
252 lines (184 loc) · 11.2 KB
/
3-PUT-Requests.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
<!-- Blackmagic REST API Tutorial -->
<!-- Episode 3: PUT Requests -->
<!-- (c) 2024 Dylan Speiser -->
<!-- Licensed under GNU GPL v3 -->
<!DOCTYPE html>
<html>
<head>
<!-- Page Title and Links -->
<title>3: PUT Requests - Blackmagic REST API Tutorials</title>
<!-- Link Stylesheets -->
<link rel="stylesheet" href="resources/prism.css">
<link rel="stylesheet" href="resources/stylesheet.css">
<!-- Page metadata-->
<meta charset="UTF-8">
<meta name="description" content="Tutorial series for Blackmagic Camera Control REST API">
<meta name="author" content="Dylan Speiser">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Favicons -->
<link rel="apple-touch-icon" sizes="180x180" href="resources/favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="resources/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="resources/favicon/favicon-16x16.png">
</head>
<body class="noto-sans-display">
<!-- Load Scripts -->
<script type="module" src="https://md-block.verou.me/md-block.js"></script>
<script src="resources/prism.js"></script>
<!-- Header Block, same for every page -->
<header>
<h1><a href="index.html">Blackmagic REST API Tutorials</a></h1>
<a href="https://github.com/DylanSpeiser/BM-API-Tutorial">GitHub</a>
</header>
<!-- Next/Previous Page Items -->
<div id="PrevNextBox">
<a href="2-JSON-Data.html">< Previous Page</a>
<a href="4-Conducting-an-Orchestra.html">Next Page ></a>
</div>
<!-- Parse page content from markdown -->
<md-block>
# 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!
</md-block>
<div><a href="4-Conducting-an-Orchestra.html" style="text-align: center;">Next Article</a></div>
<!-- Footer -->
<footer>
<div style="text-align: center;">
<br>
© 2024 Dylan Speiser
<br>
GNU GPL v3.0
<br>
All product images and trademarks are Copyright Blackmagic Design.
</div>
</footer>
</body>
</html>