I am trying to trigger an action via the HTTP API, but the bridge is serving an HTML response instead of triggering the action. Am I doing something wrong?
curl -v -H "BOND-Token: <redacted>" -H "Content-Type: application/json" -X PUT http://192.168.1.22/devices/4f0a116f/actions/TurnOff --data "{}"
* Trying 192.168.1.22...
* TCP_NODELAY set
* Connected to 192.168.1.22 (192.168.1.22) port 80 (#0)
> PUT /devices/4f0a116f/actions/TurnOff HTTP/1.1
> Host: 192.168.1.22
> User-Agent: curl/7.54.0
> Accept: */*
> BOND-Token: <redacted>
> Content-Type: application/json
> Content-Length: 2
>
* upload completely sent off: 2 out of 2 bytes
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 13618
<
<html>
<head>
<style>
* {
margin: 0 auto;
width: 100%;
display: block;
text-align: center;
font-family: sans-serif;
transition: all .75s
}
body {
max-width: 25em;
width: 90%;
margin: 15 auto
}
label>* {
display: inline;
width: auto
}
style,
script {
display: none
}
br,
hr {
margin: 5 auto;
max-width: 26em
}
button,
select,
input {
margin: 10 auto;
padding: 15 32;
text-decoration: none;
font-size: 16px
}
button {
background-color: #018FBE;
color: white;
}
</style>
<meta charset="UTF-8">
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' />
</head>
<body><svg enable-background="new 0 0 620 171.359" viewBox="0 0 620 171.359">
<g fill="#018FBE"><path d="m0 167v-163h25.7c14.9 0 25.8.961 32.6 2.88 9.77 2.59 17.5 7.4 23.3 14.4 5.78 7.02 8.66 15.3 8.66 24.8 0 6.21-1.31 11.9-3.94 16.9-2.62 5.06-6.9 9.82-12.8 14.3 9.91 4.66 17.2 10.5 21.7 17.5 4.58 6.99 6.88 15.2 6.88 24.8 0 9.17-2.37 17.5-7.11 25.1-4.74 7.54-10.8 13.2-18.3 16.9-7.48 3.73-17.8 5.6-31 5.6h-45.6zm31.1-133v34.4h6.79c7.57 0 13.2-1.59 16.9-4.77 3.67-3.18 5.51-7.5 5.51-13 0-5.1-1.75-9.15-5.23-12.1-3.49-3-8.8-4.49-15.9-4.49h-8.1zm0 62.1v41.8h7.78c12.9 0 21.6-1.63 26.1-4.88 4.48-3.25 6.73-7.99 6.73-14.2 0-7.02-2.63-12.6-7.9-16.6-5.26-4.06-14-6.1-26.2-6.1h-6.5z"/><path d="m323 4.1h29.8l69.8 107v-107h31.1v163h-29.9l-69.7-107v107h-31.1v-163z"/><path d="m491 4.1h36.8c23.7 0 41.3 2.94 52.9 8.82 11.5 5.88 21 15.4 28.5 28.7 6 13.2 10 28.7 10 46.4 0 12.6-2.09 24.1-6.26 34.7-4.18 10.5-9.94 19.3-17.3 26.2-7.35 6.95-15.3 11.8-23.9 14.4-8.57 2.66-23.4 3.99-44.5 3.99h-37.3v-163zm31 29.9v103h14.4c14.2 0 24.5-1.63 30.9-4.89s11.6-8.73 15.7-16.4c4.07-7.7 6.1-17.2 6.1-28.4 0-17.3-4.84-30.8-14.5-40.3-8.73-8.58-22.7-12.9-42-12.9h-10z"/></g><circle r="69.7" style="stroke:#018fbe;stroke-miterlimit:0;stroke-width:31.6;fill:none" cx="208" cy="85.7"/></svg>
<br>Everything Smart...
<br>
<hr><br>
<div id="splash">Connecting to BOND product...</div>
<div id="token"><div id="div_pin">Because this device has been powered on for more than 10 minutes, a 4-digit PIN number from the product label is required:
<input type="text" id="pin" autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="4-digit PIN" spellcheck="false">
<small>If you cannot find the PIN, try power cycling the product. On a Powered By BOND product, you may also hold down the Learn button on the remote control for 5 seconds to unlock.</small>
<br>
</div>
To connect to the correct BOND account, please enter the Account Code from the Account Settings in the BOND App:
<input type="text" id="account_code" autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="16-digit account code" spellcheck="false">
<font color="red"><div id="token_err"></div></font>
<small>If you cannot find the account code in the BOND app, please contact BOND Customer Support.</small>
<br>
<button id='submit_token' onclick="patch_token()">Add BOND to Account</button>
</div>
<hr><br>
<p><h3><div id="wifi_msg"></div></h3><br></p>
<div id="m">Select Wifi Network to connect the BOND to<button id='r' onclick="get_sys_wifi_scan()">Refresh Wi-Fi List</button>
<select onchange="hide(this)" id='o'><option>Loading...</option></select>
<input type="text" id="p" autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="Password" spellcheck="false" onclick="ch ? 0 : this.setSelectionRange(0, this.value.length); ch=1; hide(this)" onkeypress="hide(this);ch=1;">
<label><input type="checkbox" checked id="x" onchange="hide(this)"> Show Password</label>
<br>
<div id='a' onclick="advanced();">Advanced</div>
<br>
<div id='b'>
<label><input id='st' onclick="static_ip();" type="checkbox" > Static IP</label>
<div id='s'>
<div>The following three fields are mandatory</div>
<input type="text" placeholder="IP" onchange="this.style.color= ValidateIPaddress(this.value) ? 'black':'red';" id="ip" />
<input type="text" placeholder="Netmask" onchange="this.style.color= ValidateIPaddress(this.value) ? 'black':'red';" id="netmask" />
<input type="text" placeholder="Gateway" onchange="this.style.color= ValidateIPaddress(this.value) ? 'black':'red';" id="gw" />
<div>The following two fields are optional</div>
<input type="text" placeholder="DNS" onchange="this.style.color= ValidateIPaddress(this.value) ? 'black':'red';" id="dns" />
<input type="text" placeholder="Fallback DNS" onchange="this.style.color= ValidateIPaddress(this.value) ? 'black':'red';" id="dns_alt" />
</div>
</div>
<button id='s' onclick="put_sys_wifi_sta()">Connect to WiFi</button></div>
<hr><br>
<div id="status">loading BOND status...</div>
</body>
<script type="text/javascript">
var adv = 1;
var ch = 0;
d = document;
de = d.getElementById.bind(d);
var p = de("p");
var s = de("s");
var o = de('o');
var pin = de('pin');
var account_code = de('account_code');
var token = '';
var token_locked = 1;
var tried_patch = false;
var scaned_once = false;
var success_put_sta = false;
function get_token() {
var x = new XMLHttpRequest();
x.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
w = JSON.parse(this.response);
token_locked = w.locked
de("token").style.display = "block";
if (token_locked === 1) {
de("splash").style.display = "none";
de("div_pin").style.display = "block";
if (w.pin_attempts_left === 0) {
de("token_err").innerHTML = "PIN entered incorrectly too many times.<br>Please power cycle BOND.";
}
}
if ("token" in w) {
token = w.token
de("splash").style.display = "none";
if ("account_code" in w && w.account_code.length > 0 && tried_patch) {
de("token").style.display = "none";
}
if (!success_put_sta) de("m").style.display = "block";
/* hide the pin number once we have the token */
de("div_pin").style.display = "none";
if (!scaned_once) {
get_sys_wifi_scan();
scaned_once = true;
}
}
}
}
x.open("GET", "/v2/token", true);
x.send();
};
function patch_token() {
tried_patch = true;
if (token_locked === 1) {
if (!/^([0-9?]{4})$/.test(de("pin").value)) {
de("token_err").innerHTML = "PIN must be 4 digits";
return;
}
}
ac = de("account_code").value.replace(/\s/g, '');
if (!/^([a-fA-F0-9]{16})$/.test(ac)) {
de("token_err").innerHTML = "account_code must be 16 digits without spaces (letters A-F and numbers 0-9)";
return;
}
var sum = 0;
for (i in ac.slice(0,14)) { sum += parseInt(ac[i], 16); }
sum = sum % (16*16);
var checksum = parseInt(ac.slice(14,16), 16);
if (checksum !== sum) {
de("token_err").innerHTML = "the account_code you entered is invalid";
return;
}
ac = ac.slice(0,14)
de("token_err").innerHTML = "";
var x = new XMLHttpRequest();
x.onreadystatechange = function() {
if (this.readyState == 4 && this.status >= 200 && this.status < 300) {
de("splash").style.display = "block";
get_token();
}
if (this.readyState == 4 && this.status == 401) {
de("token_err").innerHTML = "the PIN you entered is incorrect";
get_token();
}
};
x.open("PATCH", "/v2/token", true);
x.setRequestHeader("Content-type", "application/json; charset=UTF-8");
if (token_locked === 1) {
x.send(JSON.stringify({
locked: 0,
pin: pin.value,
account_code: ac
}));
} else {
/* dont provide pin when not neeeded and possibly incorrect */
x.send(JSON.stringify({
locked: 0,
account_code: ac
}));
}
}
function put_sys_wifi_sta() {
base64_ssid = de(o.value).attributes.b.value;
if (base64_ssid === "NONE") return;
var x = new XMLHttpRequest();
x.onreadystatechange = function() {
if (this.readyState == 4 && this.status >= 200 && this.status < 300) {
de("m").style.display = "none";
success_put_sta = true;
setTimeout(function() {
de("wifi_msg").innerHTML = "Your BOND is now connecting to WiFi...";
}, 750)
}
};
let body = {password: btoa(p.value), ssid: base64_ssid}
if (de('st').checked) {
for (let key of ['ip', 'gw', 'netmask', 'dns', 'dns_alt']) {
let value = de(key).value;
if (value != null && value != "") {
body[key] = value;
}
}
}
x.open("PUT", "/v2/sys/wifi/sta");
x.setRequestHeader("BOND-Token", token);
x.setRequestHeader("Content-type", "application/json; charset=UTF-8");
x.send(JSON.stringify(body));
}
function get_sys_wifi_sta() {
var x = new XMLHttpRequest();
x.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 204) {
de("status").innerHTML = "WiFi not configured"
}
if (this.readyState == 4 && this.status == 200) {
w = JSON.parse(this.response);
de("status").innerHTML = ""
de("status").innerHTML += "SSID: '" + atob(w.ssid) + "'<br>"
de("status").innerHTML += "Status: "
if (w.status === -2) {
de("status").innerHTML += "authentication failure<br>"
}
if (w.status === -1) {
de("status").innerHTML += "network not found<br>"
}
if (w.status === 0) {
de("status").innerHTML += "connecting...<br>"
}
if (w.status === 1) {
de("status").innerHTML += "acquiring ip...<br>"
}
if (w.status === 2) {
de("status").innerHTML += "connected to WiFi<br>"
de("status").innerHTML += "ip: " + w.ip + "<br>"
de("status").innerHTML += "netmask: " + w.netmask + "<br>"
de("status").innerHTML += "gateway: " + w.gw + "<br>"
de("status").innerHTML += "dns: " + w.dns + "<br>"
de("status").innerHTML += "mac: " + w.mac + "<br>"
de("wifi_msg").innerHTML = "Your BOND is connected to WiFi!";
}
}
if (this.readyState == 4 && this.status == 401) {
de("status").innerHTML = "will load status after PIN provided...";
}
};
x.open("GET", "/v2/sys/wifi/sta", true);
x.setRequestHeader("BOND-Token", token);
x.send();
}
function get_sys_wifi_scan() {
var x = new XMLHttpRequest();
x.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
w = JSON.parse(this.response);
o.innerHTML = "<option id=\"Select your Access Point...\" b=\"NONE\" selected>Select your Access Point...</option>";
for (i in w.results) {
i = w.results[i];
id = atob(i[0]); /* base64 decode */
if (!id) continue;
o.innerHTML += "<option id=\"" + id + "\" b=\"" + i[0] + "\">" + id + "</option>";
}
}
if (this.readyState == 4 && this.status == 204) {
setTimeout(function(){ get_sys_wifi_scan(); }, 1000);
}
};
x.open("GET", "/v2/sys/wifi/scan", true);
x.setRequestHeader("BOND-Token", token);
x.send();
}
function hide(that) {
p.type = de("x").checked ? 'text' : 'password';
that.nodeName == 'SELECT' ? p.disabled = de(that.value).attributes.b.value == "NONE" ? 1 : 0 : 0
}
function advanced() {
adv = adv ? 0 : 1;
de('b').style.display = adv ? 'block' : 'none';
de('a').textContent = (adv ? "▴" : "▾") + ' Advanced'
}
function static_ip() {
de('s').style.display = de('st').checked ? 'block' : 'none';
}
function ValidateIPaddress(ipaddress) {
return (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress))
}
de("token").style.display = "none";
de("m").style.display = "none";
get_token();
advanced();
static_ip();
setInterval(function() {
get_token();
get_sys_wifi_sta();
}, 2000)
</script>
</html>
* Connection #0 to host 192.168.1.22 left intact