SlideShare a Scribd company logo
Jeff Prestes
Eddystone
New protocol for Beacons
Giving a URL to All Objects
“Operating System for Digital Commerce.”
Dan Schulman – USA Today - May 21th, 2015
@braintree_dev / @jeffprestesPre-presentation slide
About me…
@jeffprestes
github.com/jeffprestes
slideshare.net/jeffprestes
Developer Advocate
Java, PHP, JavaScript,
Mobile Developer
Football (Soccer?) fan,
father and IoT Researcher
Eddystone
New protocol for Beacons
Giving a URL to Physical Objects
Jeff Prestes
#eddystone @braintree_dev / @jeffprestes
What is it?
@braintree_dev / @jeffprestes
eddystone-tlm
eddystone-uid
eddystone-url
#eddystone
@braintree_dev / @jeffprestes
eddystone-tlm
eddystone-uid
eddystone-url
#eddystone
@braintree_dev / @jeffprestes
eddystone-tlm
eddystone-uid
eddystone-url
#eddystone
@braintree_dev / @jeffprestes
eddystone-tlm
eddystone-uid
eddystone-url
#eddystone
@braintree_dev / @jeffprestes
Why should
I use it?
#eddystone
@braintree_dev / @jeffprestes
eddystone-url
#eddystone
@braintree_dev / @jeffprestes#eddystone
https://github.com/google/eddystone/tree/master/eddystone-url
@braintree_dev / @jeffprestes
Physical Web
#eddystone
http://physical-web.org
@braintree_dev / @jeffprestes
PayPal.me
#eddystone
@braintree_dev / @jeffprestes
Braintree
Drop-In UI
#eddystone
@braintree_dev / @jeffprestes
Demo
#eddystone
@braintree_dev / @jeffprestes
Install
Physical Web App
#eddystone
https://play.google.com/store/apps/details?id=physical_web.org.physicalweb
https://itunes.apple.com/us/app/physical-web/id927653608?mt=8
@braintree_dev / @jeffprestes
Advertising
a URL
#eddystone
https://github.com/jeffprestes/node-eddystone-url
@braintree_dev / @jeffprestes#eddystone
var Beacon = require('./node_modules/eddystone-beacon/lib/beacon');
beacon = new Beacon();
var options = {
txPowerLevel: -22, //override TX Power Level, default value is -21
tlmCount: 2, // 2 TLM frames
tlmPeriod: 10 // every 10 advertisements
};
beacon.advertiseUrl('http://www.paypal.com', [options]);
@braintree_dev / @jeffprestes
Physical Web
#eddystone
How to detect a Beacon using Eddystone format
and how to parse his data
@braintree_dev / @jeffprestes#eddystone
MainActivity.java
protected void onResume() {
super.onResume();
BluetoothManager btManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
BluetoothAdapter btAdapter = btManager != null ? btManager.getAdapter() : null;
if (btAdapter == null) {
finish();
return;
}
if (checkIfUserHasOptedIn()) {
ensureBluetoothIsEnabled(btAdapter);
showNearbyBeaconsFragment();
} else {
// Show the oob activity
// Webview to: https://google.github.io/physical-web/mobile/android/getting-started.html
Intent intent = new Intent(this, OobActivity.class);
startActivity(intent);
}
}
@braintree_dev / @jeffprestes#eddystone
NearbyBeaconsFragment.java
public void onResume() {
super.onResume();
getActivity().getActionBar().setTitle(R.string.title_nearby_beacons);
getActivity().getActionBar().setDisplayHomeAsUpEnabled(false);
getListView().setVisibility(View.INVISIBLE);
mDiscoveryServiceConnection.connect(true);
}
public synchronized void connect(boolean requestCachedPwos) {
if (mDiscoveryService != null) {
return;
}
mRequestCachedPwos = requestCachedPwos;
Intent intent = new Intent(getActivity(), PwoDiscoveryService.class);
getActivity().startService(intent);
getActivity().bindService(intent, this, Context.BIND_AUTO_CREATE);
}
@braintree_dev / @jeffprestes#eddystone
PwoDiscoveryService.java
/**
* This is a service that scans for nearby Physical Web Objects.
* It is created by MainActivity.
* It finds nearby ble beacons, and stores a count of them.
* It also listens for screen on/off events
* and start/stops the scanning accordingly.
* It also silently issues a notification informing the user of nearby beacons.
* As beacons are found and lost, the notification is updated to reflect
* the current number of nearby beacons.
*/
public class PwoDiscoveryService extends Service
private void initialize() {
mNotificationManager = NotificationManagerCompat.from(this);
mPwoDiscoverers = new ArrayList<>();
mPwoDiscoverers.add(new BlePwoDiscoverer(this));
for (PwoDiscoverer pwoDiscoverer : mPwoDiscoverers) {
pwoDiscoverer.setCallback(this);
}
...
}
@braintree_dev / @jeffprestes#eddystone
BlePwoDiscoverer.java
public class BlePwoDiscoverer extends PwoDiscoverer
implements BluetoothAdapter.LeScanCallback {
mBluetoothAdapter.startLeScan(this);
@braintree_dev / @jeffprestes#eddystone
mScanFilterUuids = new ParcelUuid[]{URIBEACON_SERVICE_UUID, EDDYSTONE_URL_SERVICE_UUID};
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanBytes) {
if (!leScanMatches(ScanRecord.parseFromBytes(scanBytes))) {
return;
}
UriBeacon uriBeacon = UriBeacon.parseFromBytes(scanBytes);
if (uriBeacon == null) {
return;
}
String url = uriBeacon.getUriString();
if (!URLUtil.isNetworkUrl(url)) {
return;
}
PwoMetadata pwoMetadata = createPwoMetadata(url);
pwoMetadata.setBleMetadata(device.getAddress(), rssi, uriBeacon.getTxPowerLevel());
pwoMetadata.bleMetadata.updateRegionInfo();
reportPwo(pwoMetadata);
}
BlePwoDiscoverer.java
@braintree_dev / @jeffprestes#eddystone
/**
* Parse scan record bytes to Eddystone
* The format is defined in Eddystone specification.
*
* @param scanRecordBytes The scan record of Bluetooth LE advertisement and/or scan response.
*/
public static UriBeacon parseFromBytes(byte[] scanRecordBytes) {
byte[] serviceData = parseServiceDataFromBytes(scanRecordBytes);
...
if (serviceData != null && serviceData.length >= 2) {
int currentPos = 0;
byte txPowerLevel = serviceData[currentPos++];
byte flags = (byte) (serviceData[currentPos] >> 4);
serviceData[currentPos] = (byte) (serviceData[currentPos] & 0xFF);
String uri = decodeUri(serviceData, currentPos);
return new UriBeacon(flags, txPowerLevel, uri);
}
return null;
}
UriBeacon.java
@braintree_dev / @jeffprestes#eddystone
private static String decodeUri(byte[] serviceData, int offset) {
if (serviceData.length == offset) {
return NO_URI;
}
StringBuilder uriBuilder = new StringBuilder();
if (offset < serviceData.length) {
byte b = serviceData[offset++];
String scheme = URI_SCHEMES.get(b);
if (scheme != null) {
uriBuilder.append(scheme);
if (URLUtil.isNetworkUrl(scheme)) {
return decodeUrl(serviceData, offset, uriBuilder);
} else if ("urn:uuid:".equals(scheme)) {
return decodeUrnUuid(serviceData, offset, uriBuilder);
}
}
Log.w(TAG, "decodeUri unknown Uri scheme code=" + b);
}
return null;
}
UriBeacon.java
@braintree_dev / @jeffprestes#eddystone
private static String decodeUri(byte[] serviceData, int offset) {
if (serviceData.length == offset) {
return NO_URI;
}
StringBuilder uriBuilder = new StringBuilder();
if (offset < serviceData.length) {
byte b = serviceData[offset++];
String scheme = URI_SCHEMES.get(b);
if (scheme != null) {
uriBuilder.append(scheme);
if (URLUtil.isNetworkUrl(scheme)) {
return decodeUrl(serviceData, offset, uriBuilder);
} else if ("urn:uuid:".equals(scheme)) {
return decodeUrnUuid(serviceData, offset, uriBuilder);
}
}
Log.w(TAG, "decodeUri unknown Uri scheme code=" + b);
}
return null;
}
UriBeacon.java
@braintree_dev / @jeffprestes#eddystone
/**
* URI Scheme maps a byte code into the scheme and an optional scheme specific prefix.
*/
private static final SparseArray<String> URI_SCHEMES = new SparseArray<String>() {{
put((byte) 0, "http://www."); put((byte) 1, "https://www.");
put((byte) 2, "http://"); put((byte) 3, "https://");
put((byte) 4, "urn:uuid:"); // RFC 2141 and RFC 4122};
}};
/**
* Expansion strings for "http" and "https" schemes. These contain strings appearing anywhere in a
* URL. Restricted to Generic TLDs. <p/> Note: this is a scheme specific encoding.
*/
private static final SparseArray<String> URL_CODES = new SparseArray<String>() {{
put((byte) 0, ".com/"); put((byte) 1, ".org/");
put((byte) 2, ".edu/"); put((byte) 3, ".net/");
put((byte) 4, ".info/"); put((byte) 5, ".biz/");
put((byte) 6, ".gov/"); put((byte) 7, ".com");
put((byte) 8, ".org"); put((byte) 9, ".edu");
put((byte) 10, ".net"); put((byte) 11, ".info");
put((byte) 12, ".biz"); put((byte) 13, ".gov");
}};
UriBeacon.java
@braintree_dev / @jeffprestes
Physical Web
#eddystone
http://physical-web.org
I’d love to hear
your questions.
Thanks.
Jeff Prestes
@jeffprestes
Slideshare.com/jeffprestes
Github.com/jeffprestes
@paypaldev
@braintree_dev
developer.paypal.com
developers.braintreepayments.com

More Related Content

Eddystone Beacons - Physical Web - Giving a URL to All Objects

  • 1. Jeff Prestes Eddystone New protocol for Beacons Giving a URL to All Objects
  • 2. “Operating System for Digital Commerce.” Dan Schulman – USA Today - May 21th, 2015 @braintree_dev / @jeffprestesPre-presentation slide
  • 3. About me… @jeffprestes github.com/jeffprestes slideshare.net/jeffprestes Developer Advocate Java, PHP, JavaScript, Mobile Developer Football (Soccer?) fan, father and IoT Researcher
  • 4. Eddystone New protocol for Beacons Giving a URL to Physical Objects Jeff Prestes
  • 5. #eddystone @braintree_dev / @jeffprestes What is it?
  • 10. @braintree_dev / @jeffprestes Why should I use it? #eddystone
  • 13. @braintree_dev / @jeffprestes Physical Web #eddystone http://physical-web.org
  • 17. @braintree_dev / @jeffprestes Install Physical Web App #eddystone https://play.google.com/store/apps/details?id=physical_web.org.physicalweb https://itunes.apple.com/us/app/physical-web/id927653608?mt=8
  • 18. @braintree_dev / @jeffprestes Advertising a URL #eddystone https://github.com/jeffprestes/node-eddystone-url
  • 19. @braintree_dev / @jeffprestes#eddystone var Beacon = require('./node_modules/eddystone-beacon/lib/beacon'); beacon = new Beacon(); var options = { txPowerLevel: -22, //override TX Power Level, default value is -21 tlmCount: 2, // 2 TLM frames tlmPeriod: 10 // every 10 advertisements }; beacon.advertiseUrl('http://www.paypal.com', [options]);
  • 20. @braintree_dev / @jeffprestes Physical Web #eddystone How to detect a Beacon using Eddystone format and how to parse his data
  • 21. @braintree_dev / @jeffprestes#eddystone MainActivity.java protected void onResume() { super.onResume(); BluetoothManager btManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); BluetoothAdapter btAdapter = btManager != null ? btManager.getAdapter() : null; if (btAdapter == null) { finish(); return; } if (checkIfUserHasOptedIn()) { ensureBluetoothIsEnabled(btAdapter); showNearbyBeaconsFragment(); } else { // Show the oob activity // Webview to: https://google.github.io/physical-web/mobile/android/getting-started.html Intent intent = new Intent(this, OobActivity.class); startActivity(intent); } }
  • 22. @braintree_dev / @jeffprestes#eddystone NearbyBeaconsFragment.java public void onResume() { super.onResume(); getActivity().getActionBar().setTitle(R.string.title_nearby_beacons); getActivity().getActionBar().setDisplayHomeAsUpEnabled(false); getListView().setVisibility(View.INVISIBLE); mDiscoveryServiceConnection.connect(true); } public synchronized void connect(boolean requestCachedPwos) { if (mDiscoveryService != null) { return; } mRequestCachedPwos = requestCachedPwos; Intent intent = new Intent(getActivity(), PwoDiscoveryService.class); getActivity().startService(intent); getActivity().bindService(intent, this, Context.BIND_AUTO_CREATE); }
  • 23. @braintree_dev / @jeffprestes#eddystone PwoDiscoveryService.java /** * This is a service that scans for nearby Physical Web Objects. * It is created by MainActivity. * It finds nearby ble beacons, and stores a count of them. * It also listens for screen on/off events * and start/stops the scanning accordingly. * It also silently issues a notification informing the user of nearby beacons. * As beacons are found and lost, the notification is updated to reflect * the current number of nearby beacons. */ public class PwoDiscoveryService extends Service private void initialize() { mNotificationManager = NotificationManagerCompat.from(this); mPwoDiscoverers = new ArrayList<>(); mPwoDiscoverers.add(new BlePwoDiscoverer(this)); for (PwoDiscoverer pwoDiscoverer : mPwoDiscoverers) { pwoDiscoverer.setCallback(this); } ... }
  • 24. @braintree_dev / @jeffprestes#eddystone BlePwoDiscoverer.java public class BlePwoDiscoverer extends PwoDiscoverer implements BluetoothAdapter.LeScanCallback { mBluetoothAdapter.startLeScan(this);
  • 25. @braintree_dev / @jeffprestes#eddystone mScanFilterUuids = new ParcelUuid[]{URIBEACON_SERVICE_UUID, EDDYSTONE_URL_SERVICE_UUID}; @Override public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanBytes) { if (!leScanMatches(ScanRecord.parseFromBytes(scanBytes))) { return; } UriBeacon uriBeacon = UriBeacon.parseFromBytes(scanBytes); if (uriBeacon == null) { return; } String url = uriBeacon.getUriString(); if (!URLUtil.isNetworkUrl(url)) { return; } PwoMetadata pwoMetadata = createPwoMetadata(url); pwoMetadata.setBleMetadata(device.getAddress(), rssi, uriBeacon.getTxPowerLevel()); pwoMetadata.bleMetadata.updateRegionInfo(); reportPwo(pwoMetadata); } BlePwoDiscoverer.java
  • 26. @braintree_dev / @jeffprestes#eddystone /** * Parse scan record bytes to Eddystone * The format is defined in Eddystone specification. * * @param scanRecordBytes The scan record of Bluetooth LE advertisement and/or scan response. */ public static UriBeacon parseFromBytes(byte[] scanRecordBytes) { byte[] serviceData = parseServiceDataFromBytes(scanRecordBytes); ... if (serviceData != null && serviceData.length >= 2) { int currentPos = 0; byte txPowerLevel = serviceData[currentPos++]; byte flags = (byte) (serviceData[currentPos] >> 4); serviceData[currentPos] = (byte) (serviceData[currentPos] & 0xFF); String uri = decodeUri(serviceData, currentPos); return new UriBeacon(flags, txPowerLevel, uri); } return null; } UriBeacon.java
  • 27. @braintree_dev / @jeffprestes#eddystone private static String decodeUri(byte[] serviceData, int offset) { if (serviceData.length == offset) { return NO_URI; } StringBuilder uriBuilder = new StringBuilder(); if (offset < serviceData.length) { byte b = serviceData[offset++]; String scheme = URI_SCHEMES.get(b); if (scheme != null) { uriBuilder.append(scheme); if (URLUtil.isNetworkUrl(scheme)) { return decodeUrl(serviceData, offset, uriBuilder); } else if ("urn:uuid:".equals(scheme)) { return decodeUrnUuid(serviceData, offset, uriBuilder); } } Log.w(TAG, "decodeUri unknown Uri scheme code=" + b); } return null; } UriBeacon.java
  • 28. @braintree_dev / @jeffprestes#eddystone private static String decodeUri(byte[] serviceData, int offset) { if (serviceData.length == offset) { return NO_URI; } StringBuilder uriBuilder = new StringBuilder(); if (offset < serviceData.length) { byte b = serviceData[offset++]; String scheme = URI_SCHEMES.get(b); if (scheme != null) { uriBuilder.append(scheme); if (URLUtil.isNetworkUrl(scheme)) { return decodeUrl(serviceData, offset, uriBuilder); } else if ("urn:uuid:".equals(scheme)) { return decodeUrnUuid(serviceData, offset, uriBuilder); } } Log.w(TAG, "decodeUri unknown Uri scheme code=" + b); } return null; } UriBeacon.java
  • 29. @braintree_dev / @jeffprestes#eddystone /** * URI Scheme maps a byte code into the scheme and an optional scheme specific prefix. */ private static final SparseArray<String> URI_SCHEMES = new SparseArray<String>() {{ put((byte) 0, "http://www."); put((byte) 1, "https://www."); put((byte) 2, "http://"); put((byte) 3, "https://"); put((byte) 4, "urn:uuid:"); // RFC 2141 and RFC 4122}; }}; /** * Expansion strings for "http" and "https" schemes. These contain strings appearing anywhere in a * URL. Restricted to Generic TLDs. <p/> Note: this is a scheme specific encoding. */ private static final SparseArray<String> URL_CODES = new SparseArray<String>() {{ put((byte) 0, ".com/"); put((byte) 1, ".org/"); put((byte) 2, ".edu/"); put((byte) 3, ".net/"); put((byte) 4, ".info/"); put((byte) 5, ".biz/"); put((byte) 6, ".gov/"); put((byte) 7, ".com"); put((byte) 8, ".org"); put((byte) 9, ".edu"); put((byte) 10, ".net"); put((byte) 11, ".info"); put((byte) 12, ".biz"); put((byte) 13, ".gov"); }}; UriBeacon.java
  • 30. @braintree_dev / @jeffprestes Physical Web #eddystone http://physical-web.org
  • 31. I’d love to hear your questions. Thanks. Jeff Prestes @jeffprestes Slideshare.com/jeffprestes Github.com/jeffprestes @paypaldev @braintree_dev developer.paypal.com developers.braintreepayments.com

Editor's Notes

  1. Open Protocol Designed by Google You can have a specific device like Estimote Beacons, or you can use a Rfduino, or BLE module for Arduino, or a Bluetooth 4.0 dongle on a Raspberry Pi, or use a computer that has Bluetooth 4.0 module to advertise data. You can create your own implementation in Node, Python, Java, etc… What data should I advertise?
  2. It has 3 data format specification. Like the Eddystone-UID and Eddystone-URL frame types, Eddystone-TLM is broadcast in the clear, without message integrity validation. You should design your application to be tolerant of the open nature of such a broadcast.
  3. Eddystone beacons may transmit data about their own operation to clients. This data is called telemetry and is useful for monitoring the health and operation of a fleet of beacons.
  4. Most known format: give an ID to your device to your mobile application be able to have a context inside of buildings where GPS signal isn’t available.
  5. You can advertise an URL that contains data about related to something (a device, a place, or a person) Max 17 caracters
  6. It’s open! It’s easy and very straightforward
  7. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  8. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  9. An effort to enable frictionless discovery of web content relating to one’s surroundings.
  10. https://ppd.io/jb https://ppd.io/jy
  11. https://ppd.io/jb https://ppd.io/jy https://github.com/don/node-eddystone-beacon https://github.com/sandeepmistry/bleno#running-on-linux It supports inform his temperature It supports inform a counter that informs the number of time it has emitted data frames. Useful to control performance.
  12. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  13. An effort to enable frictionless discovery of web content relating to one’s surroundings.
  14. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  15. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  16. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  17. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  18. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  19. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  20. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  21. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  22. The main reason Old UriBeacon Secure: the important information is in your website not into the device It’s a backbone for Physical Web
  23. An effort to enable frictionless discovery of web content relating to one’s surroundings.