iBeacon and mechanism of action
iBeacon?
iBeacon is a protocol developed by Apple and introduced from iOS 7. iBeacon allows handheld electronic devices to use Bluetooth Low Energy ( BLE ) to interact and receive data from wireless sensors ( often called the beacons). Imagine going to a supermarket where Beacons are located. Immediately your iPhone will identify and communicate with the beacons, thereby retrieving information on promotions, discounts … and displayed on the iPhone. In addition, employees can easily manage each customer who is present in the supermarket. The maximum data transmission distance of the beacons will depend on the location and obstacles in the environment. The standard beacons have a range of approximately 70m, some beacons can range up to 450m. This makes iBeacon an excellent way to build tracking applications on a narrow scale, requiring greater accuracy than GPS.
Mechanism of action
iBeacon uses BLE’s advertising mode (sending only one-way information) to send a universally unique identifier ( UUID ) with data bytes to compatible devices. A transmitted packet must follow the specified standards and be 47 bytes in length. The beacons can signal in cycles from 20ms to 10s, the longer the cycle, the longer the battery life.
Compatible devices
- iOS devices with Bluetooth 4.0+ (iPhone 4S and later, iPad (3rd generation) and later, iPad Mini (1st generation) and later, and iPod Touch (5th generation) and later).
- Macintosh computers with OS X Mavericks (10.9) or later and Bluetooth 4.0.
- Android Devices with Bluetooth 4.0+ and Android OS 4.3+ (eg Samsung Galaxy S7 / J1 mini Prime, Samsung Galaxy Note 2/3, HTC One, Google / LG Nexus 7 2013 / Nexus 4 / Nexus 5, OnePlus One, LG G3) .
- Windows Phone devices with Bluetooth 4.0+ and the Lumia Cyan update or above (reports suggest support is not included with Windows Phone 8.1).
What is iBeacon used for?
With a well-established beacons network, shops, buildings, zoos … can know exactly where users are. This allows users to receive useful information related to shops, items, discounts, etc. The iBeacon technology provides a solution that firms can communicate with each customer individually. more accurate way existing technologies. Currently, manufacturers have created many different types of beacons to apply iBeacon technology, in this article, Zeacon will be used.
Communicate with Zeacon
1 2 | Trong bài viết này sử dụng Xcode 11 & iOS 13 để đọc và ghi dữ liệu vào Zeacon |
The concept
Central is the device that receives data from beacons (here is iPhone). Peripheral are Blutooth devices that will emit signals – the Zeacon itself. Advertising Packets are packets that a peripheral emits. Each packet is usually very small and cannot contain a lot of information, so to share more data, a central will need to connect to the peripheral to read data from it. The data of a peripheral is organized into services and characteristics . Service is a collection of data and related behaviors that describe a specific function of peripheral. A Peripheral can have more than one service. Characteristic provides more details about the service. For example: A smart watch device will have services: measuring heart rate, monitoring sleep, tracking sport activities … In the activity tracking service, there will be features: counting steps, calories consume…
Scan Zeacon
1 2 | Note: iOS Simulator không hỗ trợ Blutooth, bạn sẽ cần build và run trên một thiết bị thật |
Import Core Bluetooth framework in MainViewController.swift . You will need to create a CBCentralManager that communicates with the peripheral
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">import</span> <span class="token builtin">CoreBluetooth</span> <span class="token keyword">class</span> <span class="token class-name">MainViewController</span> <span class="token punctuation">:</span> <span class="token builtin">UIViewController</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> centralManager <span class="token punctuation">:</span> <span class="token builtin">CBCentralManager</span> <span class="token operator">!</span> <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function">viewDidLoad</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> centralManager <span class="token operator">=</span> <span class="token function">CBCentralManager</span> <span class="token punctuation">(</span> delegate <span class="token punctuation">:</span> <span class="token keyword">self</span> <span class="token punctuation">,</span> queue <span class="token punctuation">:</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Most of the work in the Core Bluetooth framework is done through delegates. With central is CBCentralManagerDelegate and peripheral is CBPeripheralDelegate .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">extension</span> <span class="token builtin">MainViewController</span> <span class="token punctuation">:</span> <span class="token builtin">CBCentralManagerDelegate</span> <span class="token punctuation">,</span> <span class="token builtin">CBPeripheralDelegate</span> <span class="token punctuation">{</span> <span class="token keyword">func</span> <span class="token function">centralManagerDidUpdateState</span> <span class="token punctuation">(</span> <span class="token number">_</span> central <span class="token punctuation">:</span> <span class="token builtin">CBCentralManager</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span> central <span class="token punctuation">.</span> state <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> unknown <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"unknown"</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> resetting <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"resetting"</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> unsupported <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"unsupported"</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> unauthorized <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"unauthorized"</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> poweredOff <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"poweredOff"</span> <span class="token punctuation">)</span> <span class="token keyword">case</span> <span class="token punctuation">.</span> poweredOn <span class="token punctuation">:</span> <span class="token function">print</span> <span class="token punctuation">(</span> <span class="token string">"poweredOn"</span> <span class="token punctuation">)</span> centralManager <span class="token punctuation">.</span> <span class="token function">scanForPeripherals</span> <span class="token punctuation">(</span> withServices <span class="token punctuation">:</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token keyword">default</span> <span class="token punctuation">:</span> <span class="token keyword">break</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Function centralManagerDidUpdateState (_:) will check the bluetooth status before scanning starts. If bluetooth is off, turn it back on to make sure the status is .poweredOn . The scan results will be returned in the didDiscover function
1 2 3 4 | <span class="token keyword">func</span> <span class="token function">centralManager</span> <span class="token punctuation">(</span> <span class="token number">_</span> central <span class="token punctuation">:</span> <span class="token builtin">CBCentralManager</span> <span class="token punctuation">,</span> didDiscover peripheral <span class="token punctuation">:</span> <span class="token builtin">CBPeripheral</span> <span class="token punctuation">,</span> advertisementData <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token builtin">String</span> <span class="token punctuation">:</span> <span class="token builtin">Any</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> rssi <span class="token constant">RSSI</span> <span class="token punctuation">:</span> <span class="token builtin">NSNumber</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">print</span> <span class="token punctuation">(</span> peripheral <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
1 2 3 4 | <span class="token operator"><</span> <span class="token builtin">CBPeripheral</span> <span class="token punctuation">:</span> <span class="token number">0x28151c460</span> <span class="token punctuation">,</span> identifier <span class="token operator">=</span> 2C645D6A <span class="token operator">-</span> 35F4 <span class="token operator">-</span> <span class="token builtin">EFA1</span> <span class="token operator">-</span> 584C <span class="token operator">-</span> 1C5750FA5F2C <span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token constant">VR</span> <span class="token operator">-</span> <span class="token number">3200</span> <span class="token operator">-</span> 4C1DB4 <span class="token punctuation">,</span> state <span class="token operator">=</span> disconnected <span class="token operator">></span> <span class="token operator"><</span> <span class="token builtin">CBPeripheral</span> <span class="token punctuation">:</span> <span class="token number">0x2815001e0</span> <span class="token punctuation">,</span> identifier <span class="token operator">=</span> 7BF9C418 <span class="token operator">-</span> <span class="token builtin">C912</span> <span class="token operator">-</span> <span class="token builtin">A95A</span> <span class="token operator">-</span> 9C4D <span class="token operator">-</span> <span class="token builtin">F3A5DDA9D74D</span> <span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token constant">VR</span> <span class="token operator">-</span> <span class="token number">3200</span> <span class="token operator">-</span> 4C2A39 <span class="token punctuation">,</span> state <span class="token operator">=</span> disconnected <span class="token operator">></span> <span class="token operator"><</span> <span class="token builtin">CBPeripheral</span> <span class="token punctuation">:</span> <span class="token number">0x2815001e0</span> <span class="token punctuation">,</span> identifier <span class="token operator">=</span> <span class="token builtin">C1A1A8C2</span> <span class="token operator">-</span> <span class="token number">1226</span> <span class="token operator">-</span> 7AC0 <span class="token operator">-</span> <span class="token builtin">BF0C</span> <span class="token operator">-</span> <span class="token builtin">F78898D44150</span> <span class="token punctuation">,</span> name <span class="token operator">=</span> <span class="token punctuation">(</span> null <span class="token punctuation">)</span> <span class="token punctuation">,</span> state <span class="token operator">=</span> disconnected <span class="token operator">></span> |
A lot of peripheral are found, one of them with format name = VR-320 * – ****** are Zeacon.
1 2 3 4 5 6 7 8 9 | <span class="token keyword">func</span> <span class="token function">centralManager</span> <span class="token punctuation">(</span> <span class="token number">_</span> central <span class="token punctuation">:</span> <span class="token builtin">CBCentralManager</span> <span class="token punctuation">,</span> didDiscover peripheral <span class="token punctuation">:</span> <span class="token builtin">CBPeripheral</span> <span class="token punctuation">,</span> advertisementData <span class="token punctuation">:</span> <span class="token punctuation">[</span> <span class="token builtin">String</span> <span class="token punctuation">:</span> <span class="token builtin">Any</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> rssi <span class="token constant">RSSI</span> <span class="token punctuation">:</span> <span class="token builtin">NSNumber</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">guard</span> <span class="token keyword">let</span> name <span class="token operator">=</span> peripheral <span class="token punctuation">.</span> name <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> name <span class="token punctuation">.</span> <span class="token function">match</span> <span class="token punctuation">(</span> regex <span class="token punctuation">:</span> <span class="token string">"^VR-320.+"</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> arrPeripheral <span class="token punctuation">.</span> <span class="token function">append</span> <span class="token punctuation">(</span> peripheral <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Bind the values in arrPeripheral into a UITableView and display them on the screen. Make connect when tap on any cell.
1 2 3 | peripheral <span class="token punctuation">.</span> delegate <span class="token operator">=</span> <span class="token keyword">self</span> centralManager <span class="token punctuation">.</span> <span class="token function">connect</span> <span class="token punctuation">(</span> peripheral <span class="token punctuation">,</span> options <span class="token punctuation">:</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> |
The result after making connect will be returned in the didConnect function. Here perform discoverServices to find services that peripheral has
1 2 3 4 | <span class="token keyword">func</span> <span class="token function">centralManager</span> <span class="token punctuation">(</span> <span class="token number">_</span> central <span class="token punctuation">:</span> <span class="token builtin">CBCentralManager</span> <span class="token punctuation">,</span> didConnect peripheral <span class="token punctuation">:</span> <span class="token builtin">CBPeripheral</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> peripheral <span class="token punctuation">.</span> <span class="token function">discoverServices</span> <span class="token punctuation">(</span> <span class="token constant">nil</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
The service found will be returned in the didDiscoverServices function. Here discover discoverCharacteristics to find the characteristics corresponding to each service
1 2 3 4 5 6 7 | <span class="token keyword">func</span> <span class="token function">peripheral</span> <span class="token punctuation">(</span> <span class="token number">_</span> peripheral <span class="token punctuation">:</span> <span class="token builtin">CBPeripheral</span> <span class="token punctuation">,</span> didDiscoverServices error <span class="token punctuation">:</span> <span class="token builtin">Error</span> <span class="token operator">?</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> peripheral <span class="token punctuation">.</span> services <span class="token operator">?</span> <span class="token punctuation">.</span> <span class="token function">forEach</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span> service <span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token function">print</span> <span class="token punctuation">(</span> service <span class="token punctuation">)</span> peripheral <span class="token punctuation">.</span> <span class="token function">discoverCharacteristics</span> <span class="token punctuation">(</span> <span class="token constant">nil</span> <span class="token punctuation">,</span> <span class="token keyword">for</span> <span class="token punctuation">:</span> service <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 | <CBService: 0x2839a6640, isPrimary = YES, UUID = 1803> <CBService: 0x2839a65c0, isPrimary = YES, UUID = 1802> <CBService: 0x2839a66c0, isPrimary = YES, UUID = Battery> <CBService: 0x2839a6740, isPrimary = YES, UUID = Device Information> <CBService: 0x2839a6780, isPrimary = YES, UUID = 5405DB60-38BA-11E4-8928-0002A5D5C51B> <CBService: 0x2839a6700, isPrimary = YES, UUID = 00001016-D102-11E1-9B23-00025B00A5A5> |
The characteristic found will be returned in the fuction didDiscoverCharacteristicsFor . Here the analysis will begin to retrieve the information sent by the peripheral. The characteristic will contain a CBCharacteristicProperties (.read or .notify) property that specifies the corresponding data fetch:
1 2 3 | <span class="token comment">// .read</span> peripheral <span class="token punctuation">.</span> <span class="token function">readValue</span> <span class="token punctuation">(</span> <span class="token keyword">for</span> <span class="token punctuation">:</span> characteristic <span class="token punctuation">)</span> |
1 2 3 | <span class="token comment">// .notify</span> peripheral <span class="token punctuation">.</span> <span class="token function">setNotifyValue</span> <span class="token punctuation">(</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token keyword">for</span> <span class="token punctuation">:</span> characteristic <span class="token punctuation">)</span> |
The values obtained from peripheral will return in the didUpdateValueFor function. Here, save the values and display them in the UI
1 2 3 4 | func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) { // update UI } |
Above is a brief introduction about iBeacon. In the future, there will probably be many applications using iBeacon especially in the field of IoT.