Eddystone beacons demo
-
Upload
angelo-rueggeberg -
Category
Engineering
-
view
873 -
download
4
Transcript of Eddystone beacons demo
Eddystone Beacons DemoLecture on Eddystone, an open Bluetooth Smart Beacon format from Google
+Angelo Rüggeberg@s3xy4ngyc
agenda- Introductions to Beacons
- Introduction to Eddystone
- Coding Session
Introduction to Beacons
Image: Google
Context orexact Location
Location, Accuracy, Range, and alike
Image: Google…
Use Cases
Image: Estimote
Opportunities
Presence (e.g. sights)
Image: Google
Opportunities
Tracking and Securing
Image: Google
Opportunities
• Contextual fencing(aka Geo-fence)
• Contextual content(e.g. reader circle)
• …
Image: Bundesarchiv
Landscape
• AltBeacon• Apple‘s property: iBeacon™• Estimote• Gimbal™ • PayPal™ Beacon• yoints• …
• Bluetooth® SIG(Special Interest Group)
• Bluetooth® Smart Beacon • Eddystone™
• https://github.com/google/eddystone/tree/master/branding
Introduction to Eddystone
Eddystone™, what’s so special?Openness
• It is an open Bluetooth 4.0 protocol• While iBeacon™ is officially
supported by iOS devices only, Eddystone™ has official support for both iOS and Android
Packet types / frames
• Eddystone-UID (identifier)• Namespace as UUID• Instance (6 bytes), much like Major
and Minor
• Eddystone-URL• Eddystone-TLM (telemetry)
• battery voltage• temperature• number of packets since last reboot• beacon uptime since last reboot
HardwarePhones can become Smart Beacons themselves• TxEddystone-UID (Android Lollipop 5.0)
Almost all devices with BLE can become Smart Beacons themselves• BlueGiga BLED112 Dongle• Cambridge Silicon Radio CSR1010 (Beacon
Development Board)• Rfduino
• Linux (bluez)
• ARM mbed (Nordic nRF51-dongle, nRF51-DK)
• Node.js (node-eddystone-beacon using bleno)
• Arduino (BLEPeripheral), using Nordic Semiconductor's nRF8001 or nR51822
https://github.com/google/eddystone/tree/master/eddystone-uid/tools/txeddystone-uid
Some Bluetooth® Facts
• Bluetooth / BLEis a wireless protocol
• Bluetooth uses UHF radio waves in the ISM band from 2.4 to 2.485 GHz divided into channels with frequency hopping
• Signal strength is an indicator for proximity (RSSI, received signal strength indicator)
• BLE has reduced power consumption
• Bluetooth SIG predicts more than 90% of Bluetooth-enabled smartphones will support the low energy standard by 2018.
Coding a Simple BLE Scanner
Prerequisites
• Real device with BLE (emulator has no Bluetooth™ support)
• Alternative emulator http://stackoverflow.com/questions/20348743/bluetooth-low-energy-on-android- emulator/27712017
• Android 4.3 (Jelly Bean, API Level 18)
• Android 4.4.4 (KitKat, API Level 19) fixes some issues (e.g. https://code.google.com/p/android/issues/detail?id=67272)
• Android 5.0 (Lollipop, API Level 21) recommended due to some API changes (e.g. Advertisement and LE Scanner)
BLE Permissions for an App
•
<!– Allow any Bluetooth communication --><uses-permission android:name="android.permission.BLUETOOTH"/>
<!– Allow device discovery --><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
•
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true“
/>
•••
••
•
public class MainActivity extends AppCompatActivity {
// Declare Bluetooth adapter private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter;
public class MainActivity extends AppCompatActivity {
// Declare Bluetooth adapter private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter;
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// Initialize Bluetooth adapter bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter(); …
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// Initialize Bluetooth adapter bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter(); …
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// Initialize Bluetooth adapter bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); bluetoothAdapter = bluetoothManager.getAdapter(); …
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { Log.d(TAG, "Device-Adress: " + device.getAddress()); Log.d(TAG, "RSSI: " + rssi); }});
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { Log.d(TAG, "Device-Adress: " + device.getAddress()); Log.d(TAG, "RSSI: " + rssi); }});
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { Log.d(TAG, "Device-Adress: " + device.getAddress()); Log.d(TAG, "RSSI: " + rssi); }});
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { Log.d(TAG, "Device-Adress: " + device.getAddress()); Log.d(TAG, "RSSI: " + rssi); }});
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { if(device.getAddress().equals("C1:4F:F1:FF:9B:90")) { Log.d(TAG, "Device-Adress: " + device.getAddress()); Log.d(TAG, "RSSI: " + rssi); } }});
bluetoothAdapter.startLeScan(new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { if(device.getAddress().equals("C1:4F:F1:FF:9B:90")) { Log.d(TAG, "Device-Adress: " + device.getAddress()); Log.d(TAG, "RSSI: " + rssi); } }});
Move away from deprecated Methods
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); }
@Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); }});
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); }
@Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); }});
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); }
@Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); }});
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
bluetoothLeScanner.startScan(new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); }
@Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); }});
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); }});
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); }});
ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build();
List<ScanFilter> filters = new ArrayList<>();
ScanFilter filter = new ScanFilter.Builder() .setDeviceAddress("C1:4F:F1:FF:9B:90") .build();
filters.add(filter);
ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build();
List<ScanFilter> filters = new ArrayList<>();
ScanFilter filter = new ScanFilter.Builder() .setDeviceAddress("C1:4F:F1:FF:9B:90") .build();
filters.add(filter);
ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build();
List<ScanFilter> filters = new ArrayList<>();
ScanFilter filter = new ScanFilter.Builder() .setDeviceAddress("C1:4F:F1:FF:9B:90") .build();
filters.add(filter);
ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build();
List<ScanFilter> filters = new ArrayList<>();
ScanFilter filter = new ScanFilter.Builder() .setDeviceAddress("C1:4F:F1:FF:9B:90") .build();
filters.add(filter);
ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build();
List<ScanFilter> filters = new ArrayList<>();
ScanFilter filter = new ScanFilter.Builder() .setDeviceAddress("C1:4F:F1:FF:9B:90") .build();
filters.add(filter);
Coding Proximity and Presence
There is only one packet format for BLE which
Payload consists of 2 Bytes Header, 6 Bytes Mac Address and up to 31 Bytes data.
Image: Google
Fixed: 02 01 06 03 03 aa fe
Length: 15
Fixed: 16 aa fe
Frame Type: 00
TX Power: ed
Namespace: ed d1 eb ea c0 4e 5d ef a0 17
Instance: c5 61 2a 8c c2 53
... 04 09
... 45 53 54 03 03
Bat. Service: 0f 18 0e
... 16 0a 18
Mac: 53 c2 8c 2a 61 c5
... 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Fixed: 02 01 06 03 03 aa fe
Length: 11
Fixed: 16 aa fe
Frame Type: 20
Version: 00
Volt: 0c 06
Temo: 13 00
Adv. Count: 00 0f 70 77
Sec. Count: 00 14 4e 70
... 04 09
... 45 53 54 03 03
Bat. Service: 0f 18 0e
... 16 0a 18
Mac: 53 c2 8c 2a 61 c5
... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// The Eddystone Service UUID, 0xFEAA. private static final ParcelUuid EDDYSTONE_SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
// Eddystone frame types private static final byte TYPE_UID = 0x00; private static final byte TYPE_URL = 0x10; private static final byte TYPE_TLM = 0x20;
// The Eddystone Service UUID, 0xFEAA. private static final ParcelUuid EDDYSTONE_SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
// Eddystone frame types private static final byte TYPE_UID = 0x00; private static final byte TYPE_URL = 0x10; private static final byte TYPE_TLM = 0x20;
// The Eddystone Service UUID, 0xFEAA. private static final ParcelUuid EDDYSTONE_SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
// Eddystone frame types private static final byte TYPE_UID = 0x00; private static final byte TYPE_URL = 0x10; private static final byte TYPE_TLM = 0x20;
// The Eddystone Service UUID, 0xFEAA. private static final ParcelUuid EDDYSTONE_SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
// Eddystone frame types private static final byte TYPE_UID = 0x00; private static final byte TYPE_URL = 0x10; private static final byte TYPE_TLM = 0x20;
// The Eddystone Service UUID, 0xFEAA. private static final ParcelUuid EDDYSTONE_SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
// Eddystone frame types private static final byte TYPE_UID = 0x00; private static final byte TYPE_URL = 0x10; private static final byte TYPE_TLM = 0x20;
••
Image: Estimote
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); byte[] data = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);
byte frameType = data[0]; if (frameType != TYPE_TLM) { return; } // Beacon temperature
double temp = new BigInteger(Arrays.copyOfRange(data, 4, 6)).intValue() / 256.0;
Log.d(TAG, String.format("%.2f°C", temp)); }});
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); byte[] data = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);
byte frameType = data[0]; if (frameType != TYPE_TLM) { return; } // Beacon temperature
double temp = new BigInteger(Arrays.copyOfRange(data, 4, 6)).intValue() / 256.0;
Log.d(TAG, String.format("%.2f°C", temp)); }});
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); byte[] data = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);
byte frameType = data[0]; if (frameType != TYPE_TLM) { return; } // Beacon temperature
double temp = new BigInteger(Arrays.copyOfRange(data, 4, 6)).intValue() / 256.0;
Log.d(TAG, String.format("%.2f°C", temp)); }});
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); byte[] data = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);
byte frameType = data[0]; if (frameType != TYPE_TLM) { return; } // Beacon temperature
double temp = new BigInteger(Arrays.copyOfRange(data, 4, 6)).intValue() / 256.0;
Log.d(TAG, String.format("%.2f°C", temp)); }});
Fixed: 02 01 06 03 03 aa fe
Length: 11
Fixed: 16 aa fe
Frame Type: 20
Version: 00
Volt: 0c 06
Temo: 13 00
Adv. Count: 00 0f 70 77
Sec. Count: 00 14 4e 70
... 04 09
... 45 53 54 03 03
Bat. Service: 0f 18 0e
... 16 0a 18
Mac: 53 c2 8c 2a 61 c5
... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); byte[] data = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);
byte frameType = data[0]; if (frameType != TYPE_TLM) { return; } // Beacon temperature
double temp = new BigInteger(Arrays.copyOfRange(data, 4, 6)).intValue() / 256.0;
Log.d(TAG, String.format("%.2f°C", temp)); }});
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); byte[] data = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);
byte frameType = data[0]; if (frameType != TYPE_TLM) { return; } // Beacon temperature
double temp = new BigInteger(Arrays.copyOfRange(data, 4, 6)).intValue() / 256.0;
Log.d(TAG, String.format("%.2f°C", temp)); }});
bluetoothLeScanner.startScan(filters, settings, new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); byte[] data = result.getScanRecord().getServiceData(EDDYSTONE_SERVICE_UUID);
byte frameType = data[0]; if (frameType != TYPE_TLM) { return; } // Beacon temperature
double temp = new BigInteger(Arrays.copyOfRange(data, 4, 6)).intValue() / 256.0;
Log.d(TAG, String.format("%.2f°C", temp)); }});
Outlook and helpers
, etc.http://on.google.com/hub/
•
•
• …
••
•
•
• …
Image: https://commons.wikimedia.org/wiki/File:Zinkh%C3%BCtter_Hof_Messing_Werkzeuge.jpg