uniapp bluetooth multi-device connection

It's been a year since the blog garden was broken. I finally remembered that I still have a blog, mainly because there is nothing I want to record about my recent work, but I have recently started an interesting functional project.

 

Please note: This article is prohibited from reprinting, plagiarism, this is disrespect for my personal intellectual property

 

Project introduction: The original MCU application was transplanted to make a mobile APP without back-end participation

Function introduction: The single-chip microcomputer is the command sending device of the slave computer. When it is turned on, the single-chip microcomputer is used to connect the Bluetooth device of the slave computer, and then the command is sent to the slave computer for execution.

Requirement introduction: It is necessary to transplant all the functions of the original single-chip microcomputer into the new APP, and it is required to connect multiple Bluetooth devices. It is best to achieve unlimited device connection (in fact, due to the performance difference of each mobile phone, it is basically impossible to connect unlimited Bluetooth devices. , but requires a minimum of four connections)

 

First, let’s briefly introduce the precautions for connecting Bluetooth devices. The overall process of connecting to Bluetooth is as follows:

1. Turn on the scanner and scan for Bluetooth, during which the deviceId of the device will be obtained. This ID needs to be used for the connection between the mobile phone and the Bluetooth device

2. Use deviceId for initial connection with a Bluetooth device, and you can get many service items. These service items all have a serviceId , and you need to use this serviceId to get feature items later.

3. Use serviceId to get the feature items in the service. The feature items need to distinguish whether they support read/write monitoring and other functions, as shown in the figure below

Different uuid s in the figure support different functions. For example, write: true supports writing data to Bluetooth devices, notify: true supports monitoring data sent by Bluetooth devices, and read: true supports reading data.

At this point, it should be noted that if you need to monitor and send information, you need to use two different uuid to achieve,

The Bluetooth notify function only needs to be run once to receive the data sent by the device during the Bluetooth connection, and the transmission needs to be run every time

Use these three ID s to connect to Bluetooth for corresponding operations

 

The complete code is placed in the attached file, remember to replace the UUID to connect to the corresponding device

First make a button that requires the user to manually turn on scanning, then get the scanned list, throw it into the array and display it on the page (before turning it on, you need to check whether the Bluetooth of the mobile phone is turned on, otherwise it will not be able to connect normally)

After adding some bluetooth devices, start to call the official api of uniapp to realize the connection

 

Precautions:

1. The notify monitoring function should be called first when connecting, and it can be called only once globally to prevent loss of information

2. When you know the uuid of the service item and the uuid of the feature item, you can save the function of obtaining the service item and the feature item, and use the known uuid to connect directly, which can save a lot of time for multi-device connection (specifically Please see the complete code inside the nowLinkLis method)

3. Among the devices I have tested, the best situation is to connect 7 Bluetooth devices. If you find that only 6 or 7 devices can be connected during the test, it is normal. At present, only Android and small devices are tested. Program device, for iOS, it was not tested because the company did not provide me with a device

 

 

Complete code, .vue file in uniapp,

I have used a fixed uuid. If I need to paste it directly, I will get the uuid of the service and feature first, and then test it after replacing it.

<template>
  <view class="content">
    <button type="default" v-show="!shows" @click="initBle">
      Initialize the bluetooth module
    </button>
    <scroll-view scroll-y="true" show-scrollbar="true">
      <radio-group>
        <view
          v-for="(item, index) in bleDevs"
          :key="index"
          v-show="item.name.length > 0 && !shows"
          style="padding: 10rpx 20rpx; border-bottom: 1rpx solid #ececec"
          v-if="Math.max(100 + item.RSSI, 0) >= 30"
        >
          <view style="font-size: 32rpx; color: #333">
            <checkbox-group
              @change="checkboxChange"
              :data-name="item.name"
              :data-deviceId="item.deviceId"
            >
              <label>
                <checkbox :value="item.deviceId">
                  {{ item.name }}
                </checkbox>
              </label>
            </checkbox-group>
          </view>
          <view style="font-size: 20rpx; padding: 10rpx 0">
            deviceId: {{ item.deviceId }} signal strength: {{ item.RSSI }}dBm ({{
              Math.max(100 + item.RSSI, 0)
            }}%)
          </view>
        </view>
        <view class="dis">
          <view @tap="connectBle" v-if="!shows" class="pl"> connect </view>
          <view @tap="close" v-if="shows" class="pl"> disconnect </view>
        </view>
      </radio-group>
    </scroll-view>

    <view class="barItems" v-if="shows">
      <view class="barItem" v-for="(item, index) in testItems" :key="index">
        <view class="name">{{ item.name }}</view>
        <!-- <sliderBar
          class="bar"
          :min="item.min"
          :max="item.max"
          @change="changeBar($event, item)"
        ></sliderBar> -->
        <view class="bar">
          <view class="reduce" @click="changNums(1, item)">-</view>
          <input type="tel" v-model="item.typeNums" @input="changeBar(item)" />
          <view class="add" @click="changNums(2, item)">+</view>
        </view>
      </view>
    </view>

    <view class="timers" v-if="shows">
      <view class="time">
        {{ titleTime }}
      </view>
      <view class="btns">
        <view @click="begin">start up</view>
        <view @click="pause">pause</view>
        <view @click="stop">stop</view>
      </view>
    </view>

    <view v-if="shows">
      <view class="input3">
        <input type="text" v-model="input1" />
        <input type="text" v-model="input2" />
      </view>
      <button type="default" class="send" @click="send(1)">send</button>
    </view>

    <view class="appItems">
      <viwe
        :class="[item.status ? 'item bakBlue' : 'item']"
        v-for="(item, index) in totalList"
        :key="index"
      >
        <view class="txt">{{ item.text }}</view>
        <view class="name p_hide">{{ item.name }}</view>
      </viwe>
    </view>

    <view class="items" v-if="shows">
      <view class="item" v-for="(item, index) in getData" :key="index">
        {{ item.name }}: {{ item.txt }}
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      config: {
        color: "#333",
        backgroundColor: [1, "#fff"],
        title: "Multi-device Bluetooth connection",
        back: false,
      },
      title: "Hello",
      bleDevs: [],
      status: -2, //-2 not connected -1 connected 0 connected successfully
      deviceId: "",
      serviceId: "",
      characteristicId: "",

      sendData: "",
      getData: [],

      deviceIds: [],
      totalList: [], // All connected devices

      timeIndex: 0, // Default is the first in the list

      timeout: null,
      shows: false,

      testItems: [
        {
          index: 1,
          typeNums: 1,
          min: 0,
          max: 150,
          name: "set frequency",
          value: "F",
        },
        {
          index: 2,
          typeNums: 250,
          min: 50,
          max: 250,
          name: "Set pulse width",
          value: "W",
        },
        { index: 3, typeNums: 3, min: 0, max: 3, name: "set type", value: "C" },
        {
          index: 4,
          typeNums: 0,
          min: 0,
          max: 120,
          name: "set current",
          value: "I",
        },
        {
          index: 5,
          typeNums: 0,
          min: 1,
          max: 100,
          name: "set plan",
          value: "M",
        },
      ],

      titleTime: "00:00:00",
      timer: "",

      hour: 0,
      minutes: 0,
      seconds: 0,

      input1: "B",
      input2: "",
    };
  },
  destroyed() {
    clearInterval(this.timer);
  },
  onLoad() {},
  mounted() {
    this.onBLEConnectionStateChange();
  },
  methods: {
    // start the timer
    begin() {
      if (this.start) {
        return;
      }
      this.sendData = "BS1\r";
      this.start = true;
      this.timer = setInterval(this.startTimer, 1000);
      this.send();
    },
    startTimer() {
      this.seconds += 1;
      if (this.seconds >= 60) {
        this.seconds = 0;
        this.minute = this.minute + 1;
      }

      if (this.minute >= 60) {
        this.minute = 0;
        this.hour = this.hour + 1;
      }
      this.titleTime =
        (this.hour < 10 ? "0" + this.hour : this.hour) +
        ":" +
        (this.minutes < 10 ? "0" + this.minutes : this.minutes) +
        ":" +
        (this.seconds < 10 ? "0" + this.seconds : this.seconds);
    },
    // Pause the countdown
    pause() {
      if (this.timer) {
        clearInterval(this.timer);
        this.start = false;
        this.sendData = "BS2\r";
        this.send();
        // this.timer = null
      }
    },
    stop() {
      if (this.timer) {
        clearInterval(this.timer);
        // this.timer = null
        this.sendData = "BS3\r";
        this.send();
        this.titleTime = "00:00:00";
        this.timer = "";
        this.hour = 0;
        this.minutes = 0;
        this.seconds = 0;
        this.start = false;
      }
    },
    changNums(index, item) {
      // 1 to decrease, 2 to increase
      if (index == 1) {
        if (item.typeNums <= item.min) {
          uni.showToast({
            title: "can no longer be reduced",
            icon: "none",
          });
          return;
        }
        item.typeNums--;
      } else if (index == 2) {
        if (item.typeNums >= item.max) {
          uni.showToast({
            title: "can no longer be added",
            icon: "none",
          });
          return;
        }
        item.typeNums++;
      }
      this.changeBar(item);
    },
    changeBar(item) {
      // handle stabilization
      if (this.timeout) {
        clearTimeout(this.timeout);
      }
      this.timeout = setTimeout(() => {
        if (item.typeNums < item.min) {
          uni.showToast({
            title: "Below the minimum value, changed to the minimum value to send",
            icon: "none",
          });
          item.typeNums = item.min;
        } else if (item.typeNums > item.max) {
          uni.showToast({
            title: "Exceeded the maximum value, changed to the maximum value and sent",
            icon: "none",
          });
          item.typeNums = item.max;
        }
        this.sendData = "B" + item.value + item.typeNums + "\r";
        for (let i = 0; i < this.deviceIds.length; i++) {
          this.getBLEDeviceServices(1, this.deviceIds[i]);
        }
      }, 500);
    },
    checkboxChange(e) {
      if (e.target.value[0] && e.target.dataset.name) {
        let item = {
          deviceId: e.target.value[0],
          name: e.target.dataset.name,
        };
        this.deviceIds.push(item);
      } else {
        for (let index = 0; index < this.deviceIds.length; index++) {
          let item = this.deviceIds[index];
          if (item.deviceId == e.target.dataset.deviceid) {
            this.deviceIds.splice(index, 1);
          }
        }
      }
    },
    hextoString(hex) {
      var arr = hex.split("");
      var out = "";
      for (var i = 0; i < arr.length / 2; i++) {
        var tmp = "0x" + arr[i * 2] + arr[i * 2 + 1];
        var charValue = String.fromCharCode(tmp);
        out += charValue;
      }
      return out;
    },
    send(index) {
      let that = this;
      if (index == 1) {
        that.sendData = that.input1 + that.input2 + "\r";
      }
      if (!that.sendData) {
        return uni.showToast({
          title: "Send data cannot be null",
          icon: "none",
        });
      }
      uni.showLoading({
        title: "Sending, please wait",
        mask: true,
      });
      for (let i = 0; i < that.deviceIds.length; i++) {
        that.getBLEDeviceServices(1, that.deviceIds[i]);
      }
    },
    // ArrayBuffer to 16 progress string example
    ab2hex(buffer) {
      const hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function (bit) {
          return ("00" + bit.toString(16)).slice(-2);
        }
      );
      return hexArr.join("");
    },

    onBLEConnectionStateChange() {
      uni.onBLEConnectionStateChange((res) => {
        // This method callback can be used to handle abnormal situations such as unexpected disconnection of the connection
        if (res.connected == false) {
          uni.hideLoading();
          for (let i = 0; i < this.deviceIds.length; i++) {
            if (res.deviceId == this.deviceIds[i].deviceId) {
              uni.showToast({
                title: this.deviceIds[i].name + " Bluetooth device disconnected",
                icon: "none",
              });
            }
          }
        }
      });
    },
    //Initialize bluetooth
    initBle() {
      // console.log("Initialize Bluetooth >>>");
      this.bleDevs = [];
      this.deviceIds = [];
      uni.openBluetoothAdapter({
        success: (res) => {
          //opened
          uni.getBluetoothAdapterState({
            //Bluetooth matching status
            success: (res1) => {
              // console.log(res1, ""Bluetooth on this device is turned on"");
              // Start searching for bluetooth devices
              this.startBluetoothDeviceDiscovery();
            },
            fail(error) {
              uni.showToast({ icon: "none", title: "Check if your phone's bluetooth is turned on" });
            },
          });
        },
        fail: (err) => {
          //not open
          uni.showToast({ icon: "none", title: "Check if your phone's bluetooth is turned on" });
        },
      });
    },
    // Start searching for bluetooth devices
    startBluetoothDeviceDiscovery() {
      uni.startBluetoothDevicesDiscovery({
        success: (res) => {
          // console.log("Successful startup", res);
          // Discover peripherals
          this.onBluetoothDeviceFound();
        },
        fail: (err) => {
          // console.log(err, "Error message");
        },
      });
    },
    // Discover peripherals
    onBluetoothDeviceFound() {
      // console.log("execute to this -- discover peripheral devices")
      uni.onBluetoothDeviceFound((res) => {
        // Store the searched devices so that we can display them on the page
        if (this.bleDevs.indexOf(res.devices[0]) == -1) {
          this.bleDevs.push(res.devices[0]);
        }
        // console.log("Bluetooth list", res);
      });
    },

    // multi-select and connect
    connectBle() {
      if (this.deviceIds.length == 0) {
        uni.showToast({ title: "Please select a connected device", icon: "none" });
        return;
      }
      this.getData = [];
      // for (let i = 0; i < this.deviceIds.length; i++) {
      //   this.createBLEConnection(this.deviceIds[i]);
      //   // this.nowLinkLis(this.deviceIds[i]);
      // }
      this.deviceIds.forEach((item) => {
        // this.createBLEConnection(item);
        this.nowLinkLis(item);
      });
    },

    //Select the device to connect and pass in the deviceId
    createBLEConnection(item) {
      uni.showLoading({
        title: "Connecting, please wait",
        mask: true,
      });
      let that = this;
      //connect bluetooth
      uni.createBLEConnection({
        deviceId: item.deviceId,
        success(res) {
          that.shows = true;
          that.stopBluetoothDevicesDiscovery();
          that.getBLEDeviceServices(2, item);
        },
        fail(res) {
          console.log("Bluetooth connection failed", res);
          uni.showToast({
            title: items.name + "Bluetooth connection failed",
            icon: "none",
          });
        },
      });
    },
    // Stop searching for bluetooth devices
    stopBluetoothDevicesDiscovery() {
      uni.stopBluetoothDevicesDiscovery({
        success: (e) => {
          this.loading = false;
          // console.log("Stop searching for bluetooth devices:" + e.errMsg);
        },
        fail: (e) => {
          console.log("Failed to stop searching for bluetooth devices, error code:" + e.errCode);
        },
      });
    },

    //Get all services of bluetooth
    getBLEDeviceServices(index, items) {
      setTimeout(() => {
        uni.getBLEDeviceServices({
          // The deviceId here needs to have established a link with the corresponding device through createBLEConnection
          deviceId: items.deviceId,
          success: (res) => {
            // console.log("success", res)
            // console.log("device services:", res);
            //We will get a lot of services uuid here. We only need to store what we need to use. This uuid will generally be provided by hardware manufacturers.
            console.log("services", res.services);
            res.services.forEach((item) => {
              if (
                item.uuid.indexOf("0000FFE0-0000-1000-8000-00805F9B34FB") != -1
              ) {
                items["serviceId"] = item.uuid;
                //entry feature
                this.getBLEDeviceCharacteristics(index, items);
              }
            });
          },
        });
      }, 1000);
    },
    //Get bluetooth characteristics
    getBLEDeviceCharacteristics(index, items) {
      // console.log("Enter feature");
      setTimeout(() => {
        uni.getBLEDeviceCharacteristics({
          // The deviceId here needs to have established a link with the corresponding device through createBLEConnection
          deviceId: items.deviceId,
          // The serviceId here needs to be obtained in the getBLEDeviceServices interface
          serviceId: items.serviceId,
          success: (res) => {
            console.log("characteristics", res);
            res.characteristics.forEach((item) => {
              if (
                // 2 support listening 1 support writing
                item.uuid.indexOf(
                  index == 1
                    ? "0000FFE1-0000-1000-8000-00805F9B34FB"
                    : "0000FFE2-0000-1000-8000-00805F9B34FB"
                ) != -1
              ) {
                items["characteristicId"] = item.uuid;
                if (index == 2) {
                  this.notifyBLECharacteristicValueChange(items);
                }
              }
            });
            if (index == 1) {
              this.writeString(this

Posted by jc94062 on Mon, 19 Sep 2022 21:53:29 +0530