Bluetooth is a radio technology that supports short-range communication between devices (generally within 10m). It enables wireless information exchange among various devices, including smartphones, wireless headsets, laptops, and IoT devices. With the Mijia extension program SDK, users can easily and quickly invoke Bluetooth functions and communicate with BLE/BLE Mesh devices for remote (gateway) and direct connections.
1. Gateway Connection and Control
1.1 BLE Devices
Due to the inability to send RPC commands through the gateway, BLE devices can only retrieve cached attribute values and historical records of attribute/event reports. The method for retrieving cached attribute values is identical to that of Wi-Fi devices.
1.2 BLE Mesh Devices
The extension program can send downlink commands through the gateway to remotely control BLE Mesh devices, and the usage is completely consistent with Wi-Fi devices. It can also retrieve cached attribute values and historical records of attribute/event reports.
1.3 Bluetooth Gateway Connection
After the device successfully connects to the gateway, the extension program can obtain the attribute values of the BLE Mesh device and execute methods, allowing BLE/BLE Mesh devices to actively report attribute values and events.
The termsuccessful connection here does not refer to a successful direct Bluetooth connection between the device and the gateway, but rather that the gateway has scanned the broadcast emitted by the device.
The following code can be used to determine if the device has been scanned by the Bluetooth gateway:
import React, { Component } from 'react';import { Device, DeviceEvent, Bluetooth } from 'miot';import { View } from 'react-native';import logger from '../../logger.js';class GatewayComponent extends Component { constructor(props) { super(props); this.state = { connected: false }; } async isGatewayConnected() { const { isOwner, isOnline, mac } = Device; if (!isOwner) { return Promise.resolve(isOnline); } try { const gatewayStatus = await Bluetooth.isBleOrMeshGatewayConnected( mac, true ); const gatewayConnected = gatewayStatus?.code === 0 && gatewayStatus?.data?.connected; return Promise.resolve(!!gatewayConnected); } catch (err) { logger.e('Update gateway connection status err: ', err); return Promise.resolve(false); } } updateStatus() { this.isGatewayConnected().then((connected) => { this.setState({ connected }); }); } componentDidMount() { this.updateStatus(); this.listener = DeviceEvent.deviceStatusChanged.addListener(() => { this.updateStatus(); }); } componentWillUnmount() { this.listener && this.listener.remove && this.listener.remove(); } render() { return <view></view>; }}
1.4 Signal Strength Scanned by the Gateway
export function getRssi() { Bluetooth.getBtGateWaySubDeviceRSSI(Device.mac).then((res) => { logger.i('RSSI : ', res?.data?.RSSI); }).catch((err) => { // Device offline or phone not connected to the network logger.e('getBtGateWaySubDeviceRSSI error: ', err); });}
2. Direct Control
Since communication between the gateway and the device is conducted through scanning broadcast packets, the extension program can simultaneously connect directly to the device while obtaining the status reported by the device through the gateway.
2.1 Authentication Type (Auth Type)
To ensure the security of Bluetooth communication, after a successful direct connection between the Mijia App and the device, the App will use a specific encryption method for secure authentication with the device. Different devices have different security authentication types. An incorrect authentication type will lead to authentication failure, resulting in a disconnection of the Bluetooth connection.
During the development of the Bluetooth device extension program, there will be many functions that require passing the authentication type parameter (<span>authType</span> or <span>bleAuthType</span>).
Developers can refer to the following table for all authentication types:
| type | description |
|---|---|
| 0 | Standard Xiaomi Bluetooth protocol device |
| 1 | Xiaomi Bluetooth device with security chip (e.g., lock products) |
| 2 | Shared security chip Xiaomi Bluetooth device |
| 3 | Standard BLE Bluetooth device (no mibeacon, no Xiaomi FE95 service) |
| 4 | Standard Auth standard Bluetooth authentication protocol |
| 5 | Mesh device |
| 6 | Shared lock device |
If you are still unable to determine the device’s authentication type, you can refer to the following process:
- The device is a BLE Mesh device
<span> authType = 5</span>
- The device is a lock product or another high-security device with a security chip
-
If the device is a lock device: when the user is the device owner,
<span>authType = 1</span>; when the user is not the device owner,<span>authType = 6</span> -
If the device is not a lock device:
<span>authType = 1</span>
- The device was created after October 1, 2019
<span> authType = 4</span>
- The device is a standard Bluetooth device
If the device does not have 0000FE95-0000-1000-8000-00805F9B34FB service in the Bluetooth broadcast scanned by third-party Bluetooth scanning software
<span>authType = 3</span>
- The device is a shared security chip Xiaomi Bluetooth device
<span> authType = 2</span>
- The device is a standard Xiaomi Bluetooth protocol device
<span> authType = 0, for old devices created before October 1, 2019</span>
2.2 Connecting to the Device
Before the extension program connects to the device, it can check whether the phone’s Bluetooth is enabled:
/** * Check if Bluetooth is enabled. If not, a prompt to enable it will be shown. * @return {Promise<boolean|undefined>} Whether Bluetooth is enabled. * If undefined is returned, it means the user has not granted Bluetooth permissions to the Mijia App. */async function isEnabled() { return Bluetooth.checkBluetoothIsEnabled() .then((enable) => { // If Bluetooth is not enabled, prompt to enable it if (!enable) { openGuide(); } return enable; }) .catch((error) => { logger.e(`Please grant Bluetooth-related permissions to the Mijia App: ${JSON.stringify(error)}`); return undefined; });}/** * Open Bluetooth prompt to guide the user to enable phone Bluetooth. */function openGuide() { if (Host.isAndroid) { Bluetooth.enableBluetoothForAndroid(true); } else { Host.ui.showBLESwitchGuide(); }}
Connecting the device with the extension program:
const ble = Device.getBluetoothLE();/** * Internal connection function. * * @param {0|1|2|3|4|5} authType Authentication type, refer to the above **Authentication Type** for filling in * * * @return {Promise<string|Object>} If connecting or already connected, returns a string prompt. * Otherwise, returns the original ble object. * @private */async function _connect(authType) { let message; if (ble.isConnected) { message = 'Bluetooth is already connected, stopping connection'; this._onConnectionChange(ConnectionState.connected); logger.w(message); return Promise.resolve(message); } else if (ble.isConnecting) { message = 'Bluetooth is connecting, stopping connection'; logger.w(message); this._onConnectionChange(ConnectionState.connecting); return Promise.resolve(message); } return this.origin.connect(authType, { timeout: 10000 });}
For the entire operation of the extension directly connecting to the BLE Spec, please refer to the following Demo. After downloading the Demo, unzip the document to the <span>projects</span> folder and modify the <span>config.js</span> file in the project root directory to run.
Name: com.miot.blespec.zip
Address: https://kpan.mioffice.cn/webfolder/ext/RYmWzTb0bXg%40
Password: Xhd4
3. Listening for Property/Event Changes
After successfully connecting directly to the device, the extension program can listen for changes in device properties/events through the Bluetooth GATT direct channel.
3.1 Subscribing to Properties/Events
const bt = Device.getBluetoothLE();const subs = ['prop.2.1','event.2.1'];if (bt.isConnected) { bt.subscribeMessages(...subs).then((res) => { logger.i(`Subscribes ${subs} success: `, res); }).catch((err) => { logger.e(`Subscribes ${subs} error: `, err); });}
3.2 Registering Callbacks
Using the following code to listen, when the device reports changes in properties/events through the Bluetooth GATT direct channel, the extension program will receive the relevant callback results.
this._bleSpecListener = DeviceEvent.BLESpecNotifyActionEvent.addListener((device, data) => { logger.d(`Spec notify: ${ JSON.stringify(data) }`); data?.forEach((key, value) => { logger.d(`receive prop(event) changed notification,prop:${ key }`, JSON.stringify(value)); });});
3.3 Unsubscribing
At an appropriate time (usually in the <span>componentWillUnmount</span> function), unsubscribe from the registered listeners and callbacks.
componentWillUnmount() { bt.unsubscribeMessages(); this._bleSpecListener && this._bleSpecListener.remove();}