Location>code7788 >text

WeChat applet BLE basic business interface encapsulation

Popularity:825 ℃/2024-08-28 10:57:05

Write in advance: the description in this article may not be in line with the current latest situation (including the development of Bluetooth technology, WeChat small program interface iteration, etc.).

WeChat small program provides a lot of interfaces for Bluetooth operation, but in the actual development process, it will be found to hide a lot of pits. Currently the mainstream Bluetooth applications are based onBluetooth Low Energy (BLE)of this paper introduces the relevant several basic interfaces and their encapsulation, easy to call the business layer.

Bluetooth development

Before developing a Bluetooth application, it is necessary to have a general understanding of Bluetooth as a technology.

Classic Bluetooth

A short-range wireless communication standard that operates in the 2.4GHz band and is primarily used for data transmission between two devices.

Versions of Bluetooth prior to 4.0 are generally referred to asClassic BluetoothThe transmission rate is between 1-3Mbps. Although it has a good transmission rate, it is difficult to meet the needs of mobile terminals and IoT due to its high power consumption, and is gradually being replaced by more advanced versions.

Bluetooth Low Energy (BLE)

Bluetooth 4.0 introducesBluetooth Low Energy (BLE)The technology has a maximum data throughput of only 1Mbps, but compared to classic Bluetooth, BLE has ultra-low operating and standby power consumption.

How is the low power consumption of BLE achieved? It is mainly by reducing the number of broadcast channels (from 16-32 in classic Bluetooth to 3), shortening the broadcast RF turn-on time (from 22.5ms in classic Bluetooth to 0.6-1.2ms), deep sleep mode, and optimizing the protocol stack for low-power scenarios, etc., which we will not repeat here.

Current version

The current major version is Bluetooth 5.0, with a transmission speed of 24Mbps, twice that of version 4.2, and an effective working distance of up to 300 meters, four times that of version 4.2. Transmission speeds in low-power mode are capped at 2Mbps, making it suitable for audio-visual grade applications such as high-definition audio decoding protocols.

Bluetooth eigenvalue

GATT (Generic Attribute Profile) Protocoldefines how Bluetooth devices communicate with each other, where a singleServiceIt is possible to include more than oneCharacteristicEach service and feature value is uniquely identified by a specific UUID. A feature value is the basic unit used to store and transmit data in a Bluetooth device, and each feature value has its own specificAttributes and Values

Attribute Agreement (ATT)Defining the retrieval of data allows a device to expose data to other devices, which are calledAttribute

The type of feature value operation can be set through attributes such asRead, Write, Notifyetc., the operation object is the feature value of theValue. A feature value can have multiple operation types at the same time.

In order to enable the transfer of data, the service needs to expose two main feature values:writecap (a poem)notify or indicationThe write eigenvalue is used to receive data and the notify eigenvalue is used to send data. These feature values are of type bytes, and the length of data transferred at one time can vary depending on the type of feature value.

Applet Interface Packaging

It is important to know that although Bluetooth is an open protocol, Apple devices are currently unable to connect to Android and other platforms via Bluetooth due to the closed design of Apple's IOS system.

The descriptions in this article are all based on the Android platform.

key interfaces

Transferring data using Bluetooth involves the following steps and interfaces:

  1. Activate device Bluetooth (e.g., tap the Bluetooth icon on your phone);
  2. : Initialize the applet Bluetooth module;
  3. Search Peripherals
    1. : Listen for events when a new device is searched for;
    2. : Start searching for nearby devices;
    3. : The search stops when the adversary device to be connected is found;
  4. : Connect the BLE device;
  5. receive data
    1. : Set the stage for the next step (note: notify or indicate must be supported by the feature of the adversary device for the call to succeed);
    2. : Listening to the adversary's feature value change event, you can get the changed feature value, so the data will be passed from the adversary device;
  6. : Write binary data to an adversary's feature value (note: the adversary's feature must support write for the call to succeed);
  7. : Disconnect;
  8. : Turn off the applet Bluetooth module;
  9. Turn off device Bluetooth.

Pit and attention (limited to the author based on the development process to use to the model observation records, may not be universal):

  • This method can only find new Bluetooth devices, the previously searched on some Android models, do not count as a new Bluetooth device, so re-search can not be. In this case, either restart the applet Bluetooth module or restart the applet, or use theGet all searched Bluetooth devices while the Bluetooth module is in effect.
  • The connection may not work all at once and will require more than one connection.
  • It is a good idea to restart the BluetoothAdapter each time it connects, otherwise it is prone to report a 10005 - Specified feature not found error on subsequent connections.
  • If the applet has searched for a Bluetooth device before and successfully established a connection, it can directly pass in the deviceId obtained from the previous search and try to connect to the device without searching again.
  • The system and the Bluetooth device will limit the data size of Bluetooth 4.0 to be transferred at one time, and a write error will occur if the maximum number of bytes is exceeded, and it is recommended that no more than 20 bytes be written at one time.
  • Once any exception occurs during the process, you must disconnect and reconnect, otherwise it will keep reporting notifyblecharacteristicValuechange:fail: no characteristic errors.

Primary Code

Note: This article code block for the author temporary blind knock, only for reference.

Define a tool object

const ble = {}

Because of the kinds of problems we might encounter, we'll start by globally defining the runtime exception enumeration and the throw/handle methods, so that we don't have to write our own exception handling later on.

const ble = {
  errors: {
    OPEN_ADAPTER: 'Enabling Bluetooth module exception',
    
    CONNECT: 'Bluetooth Connection Exception',
    
    
    
    //...
  },

  _throwError(title, err) {
    //... Consider calling

    if (err) {
       = title
      throw err
    }
    throw new Error(title)
  },

Bluetooth connection. Notice that this is a finite recursive method and that the BluetoothAdapter is restarted first for each connection, for reasons explained in the previous section.

/**
   * @param {string} deviceId device number
   * @param {int} tryCount Attempts made
   */
  async connectBLE(deviceId, tryCount = 5) {
    await ().catch(err => { ble._throwError(.CLOSE_ADAPTER, err) })
    await ().catch(err => { ble._throwError(.OPEN_ADAPTER, err) })
    await ({
      deviceId: deviceId,
      timeout: 5000
    })
      .catch(async err => {
        if ( === -1) { //Bluetooth is connected.
          // continue work
        } else {
          (`(prefix indicating ordinal number, e.g. first, number two etc)${6 - tryCount}Sub-Bluetooth connection error`, , )
          tryCount--
          if (tryCount === 0) {
            ble._throwError(, err)
          } else {
            await (deviceId, tryCount)
          }
        }
      })
      //Bluetooth connection successful
  },

After a successful connection, it may be necessary to listen to the adversary device for receiving data from it.

  async onDataReceive(deviceId, serviceId, characteristicId, callback) {
    await ({
      deviceId: deviceId,
      serviceId: serviceId,
      characteristicId: characteristicId,
      state: true
    }).catch(err => { ble._throwError(.NOTIFY_CHARACTERISTIC_VALUE_CHANGE, err) })

    (res => {
      let data = new Uint8Array()
      callback(data)
    })
  },

Send data, sliced, no more than 20 bytes at a time. This adds a retry mechanism within a fixed time period.

  /**
   * @param {Uint8ClampedArray} data pending data
   * @param {boolean} holdConnWhenDone Whether to keep the connection after sending
   */
  async send(deviceId, serviceId, characteristicId, data, holdConnWhenDone = false) {
    let idx = 0 //Number of bytes transferred
    let startTime = (),
      duration = 800 //Send Failure Retry Duration
    while (idx < ) {
      await ({
        deviceId: deviceId,
        serviceId: serviceId,
        characteristicId: characteristicId,
        value: (idx, idx += 20).buffer
      })
        .then(_ => startTime = ()) //success storynowreprovision
        .catch(err => {
          if (() - startTime >= duration) {
            ble._throwError(, err)
          } else {
            //retry
            idx -= 20
          }
        })
    }
    if (!holdConnWhenDone)
      await ({ deviceId: deviceId }).catch(err => { ble._throwError(, err) })
  }

In real projects, you may need to get a response from the adversary device after each data slice is sent, and then decide whether to retransmit the data slice based on the response (checksum error or response timeout, etc.), abort (device is busy), or continue to send the next data slice. In this case, you need to work with the onDataReceive method and pass it the appropriate callback parameters, which are not discussed here.