Any Adafruit device with the UART service can be sent 'AT' commands to configure the device, including setting the device up as an Apple iBeacon or a Google UriBeacon via the following commands:
If the device is detected as being UART enabled, should we add a new activity to configure iBeacon and UriBeacon information from the phone?
Talking to Google, this was the biggest complaint from customers ... "How do I configure the UriBeacon once it's deployed?".
By having an activity in the Android app for these two beacon options, we can generate the AT command ourselves and send it via the UART service: +++\r\nAT+BLEBEACON=xxx\r\n+++\r\n
, though we should test first if we have access to the AT Parser via AT\r\n
which should response with OK\r\n
.
UriBeacon is a bit more complicated since you can (and often should) use a URI shortener beyond a certain link size, but the advantage of an Activity for this is that we can do this automatically for user's once the length exceeds a certain size.
This code is pretty basic, but if it helps here is some simple JavaScript code in an HTML file I wrote to encode a UriBeacon payload from the supplied URI.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div>UriBeacon URI: <input id="uri" type="text" /> <input id="clickMe" type="button" value="Generate" onclick="jsGenerateUri();" /> </div>
<label>Advertising Data: </label><label id="advData">--</label>
<!-- See: https://github.com/google/uribeacon/tree/master/specification#uribeacon-advertising-data -->
<script>
function $(element) {
return document.getElementById(element);
}
function asc2hex(string) {
var temp = '';
var a;
for (a = 0; a < string.length; a++) {
temp += ('-' + string.charCodeAt(a).toString(16));
}
return temp.toUpperCase();
}
function jsGenerateUri() {
var input = $('uri').value;
var header1 = '03-03-D8-FE'; /* Complete 16-bit Service List Flag, UUID = 0xFED8 */
var header2 = '-16-D8-FE'; /* Service Data AD Type and UUID again */
var flags = '-00';
var txpower = '-00';
var prefix = '';
var len = 6; /* Payload len counter, minus header1 */
/* Make sure we have a valid string */
if (input.length < 1) {
alert("Invalid URI");
return -1;
}
/* See if we can chop off the Uri prefix */
if (input.indexOf('urn:uuid:') > -1) {
prefix = '-04';
input = input.substr(9, input.length - 9);
}
else if (input.indexOf('http://www.') > -1) {
prefix = '-00';
input = input.substr(11, input.length - 11);
}
else if (input.indexOf('https://www.') > -1) {
prefix = '-01';
input = input.substr(12, input.length - 12);
}
else if (input.indexOf('http://') > -1) {
prefix = '-02';
input = input.substr(7, input.length - 7);
}
else if (input.toLowerCase().indexOf('https://') > -1) {
prefix = '-03';
input = input.substr(8, input.length - 8);
}
else {
alert("Prefix must be one of the following values:\n\nhttp://www.\nhttps://www.\nhttp://\nhttps://\nurn:uuid:");
return -1;
}
/* Get the total payload length so far (minus the header and the len byte) */
len += input.length;
/* Generate the full URI payload (minus the header and len byte) */
var uri = flags + txpower + prefix + asc2hex(input);
/* See if we can chop off the suffix in the Uri */
if (input.indexOf('.com/') > -1) {
uri = uri.replace(asc2hex('.com/'), '-00');
len -= 4;
}
else if (input.indexOf('.org/') > -1) {
uri = uri.replace(asc2hex('.org/'), '-01');
len -= 4;
}
else if (input.indexOf('.edu/') > -1) {
uri = uri.replace(asc2hex('.edu/'), '-02');
len -= 4;
}
else if (input.indexOf('.net/') > -1) {
uri = uri.replace(asc2hex('.net/'), '-03');
len -= 4;
}
else if (input.indexOf('.info/') > -1) {
uri = uri.replace(asc2hex('.info/'), '-04');
len -= 5;
}
else if (input.indexOf('.biz/') > -1) {
uri = uri.replace(asc2hex('.biz/'), '-05');
len -= 4;
}
else if (input.indexOf('.gov/') > -1) {
uri = uri.replace(asc2hex('.gov/'), '-06');
len -= 4;
}
else if (input.indexOf('.com') > -1) {
uri = uri.replace(asc2hex('.com'), '-07');
len -= 3;
}
else if (input.indexOf('.org') > -1) {
uri = uri.replace(asc2hex('.org'), '-08');
len -= 3;
}
else if (input.indexOf('.edu') > -1) {
uri = uri.replace(asc2hex('.edu'), '-09');
len -= 3;
}
else if (input.indexOf('.net') > -1) {
uri = uri.replace(asc2hex('.net'), '-0A');
len -= 3;
}
else if (input.indexOf('.info') > -1) {
uri = uri.replace(asc2hex('.info'), '-0B');
len -= 4;
}
else if (input.indexOf('.biz') > -1) {
uri = uri.replace(asc2hex('.biz'), '-0C');
len -= 3;
}
else if (input.indexOf('.gov') > -1) {
uri = uri.replace(asc2hex('.gov'), '-0D');
len -= 3;
}
/* Generate the len string (zero-padding if necessary) */
var lenStr = '';
if (len < 16) {
lenStr = '-0' + len.toString(16).toUpperCase();
}
else {
lenStr = '-' + len.toString(16).toUpperCase();
}
/* Add header1 and the payload len byte to the len count */
len += 5;
/* Make sure we don't exceed the 27 byte advertising payload limit */
if (len > 27) {
alert('Invalid payload length. The encoded UriBeacon payload must be <= 27' +
'bytes (16 characters max for the custom URI segment).\n\n' +
'The current payload is ' + len.toString() + ' bytes long.');
$('advData').innerHTML = '--';
return -1;
}
/* Update the page with the fully encoded UriBeacon payload */
$('advData').innerHTML = header1 + lenStr + header2 + uri;
}
</script>
</body>
</html>