蓝牙配网基本知识

1,411 阅读12分钟

基本概念

配网定义

无论Wi-Fi设备、蓝牙BLE设备、3/4G设备、Zigbee设备,实现设备联网智能化的前提在于硬件可以直接或间接(通过手机)连接到Internet网络,并添加到用户账号下。进而,设备才可以向云端上报数据、接收来自云端的指令

简易流程

名词解释

SSID: Service Set Identifier(服务集标识符)。它是一个用于识别无线局域网(WLAN)的名称,可以理解为无线网络的名称或标识

Wi-Fi 的两种工作模式:STA 模式与 AP 模式

  • STA模式:Station,即 Wi-FI 工作在无线终端模式,通过连接 AP 热点连接到网络
  • AP模式:Access Point,即 Wi-Fi 工作在热点模式,其它设备可以连接到此节点(AP热点)

BLE (Bluetooth Low Energy): 蓝牙低功耗也称蓝牙低能耗低功耗蓝牙

蓝牙和蓝牙低功耗(BLE)的区别:与传统蓝牙相比,BLE 旨在显著降低功耗。这样,应用就可以与功率要求更严格的 BLE 设备(例如近程传感器、心率监测器和健身设备)进行通信。

Linux篇 | CentOS6、CentOS7、Ubuntu1804修改主机名、网卡、网络:blog.51cto.com/niub/237495…

主流的配网方案

SmartConfig(广播配网)

SmartConfig 是手机通过广播发送上网信息( 目标路由器参数),设备通过监听方式获取信息,然后连接上网的方案。该方案只需要用户输入 WiFi 的名称及密码,点击开始配网即可完成配网操作

SoftAP(热点配网)

SoftAP方式配网时,设备处于 AP 模式,手机直连设备,传送目标路由器参数,不考虑终端兼容性(2.4G 或 5GWiFi)问题,配网成功率100%

WPS 方式( 路由器配网)

路由器支持的WPS协议可以一键配网。该方式要求路由器和设备同时支持WPS,目前部分路由已经取消WPS功能,但也有部分厂家推出智能路由器将其修改为私有协议进行设备配网(如阿里的灵配、米家路由器)

Combo 配网模式(蓝牙WiFi双模)

搭配 Wi-Fi 蓝牙双模模组的智能硬件,配网过程中APP通过蓝牙将路由器参数传给设备,供设备连接路由器。由于iPhone 手机可能会存在蓝牙使用限制,故该模式会自动附带AP配网模式作为备用方

蓝牙+Wifi 配网步骤(基于smartConfig)

  1. 手机APP通过蓝牙连接到待配网的设备
  2. 手机通过 BLE (低功耗蓝牙) 将Wi-Fi路由器的配网信息(SSID/password)发送给设备端
  3. 设备得到配网信息后,进入STA模式 (Station,即Wi-FI工作在无线终端模式,通过连接 AP 热点连接到网络) ,即可连接到Wi-Fi

将以上配网过程,画成时间序列图,则用户、APP、物联网设备、路由器这四者的交互关系为:

目前主流的智能家居APP如下

优点:该方案适合与本身既有蓝牙又有Wi-Fi的应用场景的设备,或者模组成本相对不是那么敏感的土豪设备。随着低成本BLE的推行,其占有率逐渐提升

缺点:需要设备自带无线网卡,需要额外增加蓝牙硬件成本

使用效果

  1. 紫灯闪烁,设备蓝牙打开
  2. 手机连接设备蓝牙
  3. 输入wifi密码;后面步骤会把 wifi 相关信息发送给设备,设备根据对应信息去连接家庭 Wifi
  4. 橙灯闪烁,设备已连上家庭 wifi;蓝灯慢闪,设备已连接上服务器,可正常使用

蓝牙配对开发

Go语言可以使用蓝牙,但需要第三方库的支持。有一些Go语言库可以帮助您操作蓝牙设备,例如:

  • gatt:这是一个Go语言的蓝牙低功耗(BLE)库,可以用于实现BLE设备的客户端和服务端

  • go-ble:这是一个Go语言的蓝牙低功耗库,提供了操作蓝牙设备的简单方法

  • bluez:这是一个Go语言的蓝牙库,可以使用BlueZ蓝牙栈的API实现蓝牙通信

简易流程

暂时无法在飞书文档外展示此内容

交互流程如下

暂时无法在飞书文档外展示此内容

Golang实现通过蓝牙配置Linux系统WI-FI 这篇文章教你用Go实现一个 BlueToothService

Android手机蓝牙互联,并传递数据。_android 两台手机蓝牙互联-CSDN博客 这篇文章教你怎么实现 client 到蓝牙BlueTooth Service 的通信

Server 端相当于是一个 http server,监听对应的 HTTP 请求,比如

var localAPIHost = "http://127.0.0.1:3002/"
var getLocalIPAddressURL = localAPIHost + "getLocalIPAddress"
var internetHealthyCheckURL = localAPIHost + "internetHealthyCheck"
var setupNewWifiURL = localAPIHost + "setupNewWifi"
var factoryResetURL = localAPIHost + "factoryResetForBle"

蓝牙交互流程开发

设定特征值通信的权限

参考:github.com/tinygo-org/…

// CharacteristicPermissions lists a number of basic permissions/capabilities
// that clients have regarding this characteristic. For example, if you want to
// allow clients to read the value of this characteristic (a common scenario),
// set the Read permission.
type CharacteristicPermissions uint8

// Characteristic permission bitfields.
const (
    广播权限,允许将特征值广播给周围的设备
    CharacteristicBroadcastPermission CharacteristicPermissions = 1 << iota
    
    读取权限,允许设备读取特征值。
    CharacteristicReadPermission
    
    无响应写权限,允许设备写入特征值,但不需要接收方返回响应
    CharacteristicWriteWithoutResponsePermission

    写入权限,允许设备写入特征值,并期望接收方返回响应
    CharacteristicWritePermission
    
    通知权限,允许设备在特征值发生变化时主动发送通知给其他设备
    CharacteristicNotifyPermission
    
    指示权限,与通知权限类似,但它是一种高优先级的通知,用于在需要时立即向其他设备发送特征值的变化。
    CharacteristicIndicatePermission
)

Server 端和 Client 端

  1. 盒子打开蓝牙并上电
package main

import (
        "time"

        "tinygo.org/x/bluetooth"
)

var adapter = bluetooth.DefaultAdapter

func main() {
        // 1.Enable BLE interface.
        must("enable BLE stack", adapter.Enable())

        // 2.Define the peripheral device info.
        adv := adapter.DefaultAdvertisement()
        must("config adv", adv.Configure(bluetooth.AdvertisementOptions{
LocalName: "Go Bluetooth" ,
          }))
  
        // 3.Start advertising
        must("start adv", adv.Start())

        // 4. 注册service
        must("add service", adapter.AddService(&bluetooth.Service{
            UUID: serviceUUID,
            Characteristics: []bluetooth.CharacteristicConfig{
                {
                    Handle: &refreshChar,
                    UUID:   refreshUUID,
Flags:  bluetooth.CharacteristicWritePermission | bluetooth.CharacteristicWriteWithoutResponsePermission,
                    // 设置write-Event
                    WriteEvent: func(client bluetooth.Connection, offset int, value []byte) {
                        statusChar.Write([]byte("online"))
                    },
                },
           .....
          )
    
        println("advertising...")
        for {
                // Sleep forever.
                time.Sleep(time.Hour)
        }
}

func must(action string, err error) {
        if err != nil {
                panic("failed to " + action + ": " + err.Error())
        }
}
  1. 电脑或手机等连接
package main

import (
        "tinygo.org/x/bluetooth"
)

var adapter = bluetooth.DefaultAdapter

func main() {
    // 1. Enable BLE interface.
    must("enable BLE stack", adapter.Enable())

    // 2.扫描并连接对应的设备
    // 这里目标deviceName需要和server端注册的deviceName相同
    println("scanning...")
    err := adapter.Scan(func(adapter *bluetooth.Adapter, device bluetooth.ScanResult) {
        if device.LocalName() == "" {
            return
        }

        fmt.Println("device name:", device.Address.String(), " device rssi:", device.RSSI, " device name:", device.LocalName(), " UUID:", device.Address.UUID)

        if device.LocalName() == definedDeviceName {
            address.UUID = device.Address.UUID

            err := adapter.StopScan()
            if err != nil {
                // Unlikely, but we can't recover from this.
                println("failed to stop the scan:", err.Error())
                panic(err)
            }

        }
    })
    must("start scan", err)

    // 3.开始连接
    fmt.Println("connect start")
    device, err := adapter.Connect(address, bluetooth.ConnectionParams{
        // ConnectionTimeout: bluetooth.NewDuration(10 * time.Second),
        // MinInterval:       bluetooth.NewDuration(100 * time.Millisecond),
        // MaxInterval:       bluetooth.NewDuration(1000 * time.Millisecond),
    })
    
    // 4.连接对应的device-service
}

func must(action string, err error) {
        if err != nil {
                panic("failed to " + action + ": " + err.Error())
        }
}

Ubuntu 蓝牙配对步骤

  1. 插入外接蓝牙适配器
  2. 输入 hciconfig 命令,确认你的蓝牙设备是否被系统识别,避免你插入多个蓝牙设备
root@hello-MBX-TGL3R100:~# hciconfig
hci0:        Type: Primary  Bus: USB            #蓝牙设备名
        BD Address: 00:1A:7D:DA:71:11  ACL MTU: 310:10  SCO MTU: 64:8    #蓝牙地址
        UP RUNNING PSCAN ISCAN
        RX bytes:1324 acl:0 sco:0 events:88 errors:0
        TX bytes:4136 acl:0 sco:0 commands:88 errors:0
  1. 为你的蓝牙设备上电,输入hciconfig hci0 up

相反关闭蓝牙使用:hciconfig hci0 down

root@hello-MBX-TGL3R100:~# hciconfig hci0 up

如果报错:Can't init device hci0: Operation not possible due to RF-kill (132)

请执行如下命令:rfkill unblock all

  1. 输入 bluetoothctl 命令并启动搜索模式,输入 scan on (用于主动连接其他蓝牙设备
root@hello-MBX-TGL3R100:~# bluetoothctl
Agent registered
scan on

简易Demo:通过蓝牙访问 heartrate

前提条件:两台设备需要能通过蓝牙互联

  1. 将一台设备作为蓝牙服务端,提供对应的心率服务

服务端代码参考:github.com/tinygo-org/…

  1. 另一个设备作为蓝牙客户端,通过蓝牙建立连接后访问蓝牙设备端对应的心率服务

客户端代码参考:github.com/tinygo-org/…

启动客户端后连接服务端需要对端的蓝牙地址,可通过 hciconfig 查看蓝牙设备地址

root@demo:~# hciconfig
hci0:        Type: Primary  Bus: USB
        BD Address: A0:9F:10:28:19:F9  ACL MTU: 820:8  SCO MTU: 255:16
        UP RUNNING PSCAN ISCAN INQUIRY
        RX bytes:25550 acl:67 sco:0 events:2150 errors:0
        TX bytes:47488 acl:534 sco:0 commands:1237 errors:0

启动客户端程序:获得蓝牙连接对端输入

Mac 连接盒子上自带的蓝牙

  1. 查看对端盒子的蓝牙名称,名称为demo

  1. 使用 mac 连接到对端盒子的蓝牙

  1. 查看mac的蓝牙设备地址
  ~ system_profiler SPBluetoothDataType
Bluetooth:
      Bluetooth Controller: 
          Address: 14:7D:DA:3E:48:6B    mac的蓝牙地址
          State: On
          Chipset: BCM_4364B3
          Discoverable: Off
          Firmware Version: v91 c4211
          Supported services: 0x392039 < HFP AVRCP A2DP HID Braille LEA AACP GATT SerialPort >
          Transport: UART
          Vendor ID: 0x004C (Apple)
      Connected:
          Bluetooth Mouse M336/M337/M535:
              Address: F4:73:35:1F:06:99
              Vendor ID: 0x046D
              Product ID: 0xB016
              Firmware Version: 18.0.3
              Minor Type: Mouse
              Services: 0x800020 < HID ACL >
          demo:
              Address: A0:9F:10:28:19:F9        连接的设备端的蓝牙地址
              Vendor ID: 0x1D6B
              Product ID: 0x0246
              Firmware Version: 5.3.5
              Minor Type: DesktopComputer
              RSSI: -71
              Services: 0x900018 < AVRCP A2DP GATT ACL >
  1. 盒子上启动server端,mac上启动client端读取数据

持久化修改机器的网络配置

Ubuntu 操作方法

在 Ubuntu 中,网络配置通常由 netplan 工具处理

root@demo: which netplan
/usr/sbin/netplan 

新建一个文件 {{.ethName}}-network-vei.yaml,里面写入配置的相关信息

每个网卡配置完之后都生成一个对应的文件在 /etc/netplan 目录下 ,比如网卡一eth1-network-vei.yaml

Ubuntu 使用的都是 NetworkManager 来管理

network:
  version: 2
renderer: NetworkManager    指定要使用的网络渲染器,例如 networkd  NetworkManager;TODO:判断指定的渲染器
  ethernets:
    enp4s0:
      dhcp4: false            指定是否使用 DHCPv4 自动获取 IP 地址
      addresses: [192.168.1.50/16]    指定静态 IPv4  IPv6 地址
      gateway4: 10.88.160.1           指定 IPv4 默认网关
      nameservers:
        addresses: [233.5.5.5, 114.114.114.114]  指定DNS-Server地址

生效配置:netplan apply --config=/etc/netplan/eth1-network-vei.yaml

Debian 操作方法

网络配置文件通常位于 /etc/network/interfaces 文件中,不管有多少网卡,只有这一个配置文件

root@linaro-alip:/etc/network# cat interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source /etc/network/interfaces.d/*

单网卡配置

auto eth1
iface eth1 inet static
address 30.38.128.222
netmask 255.255.248.0
gateway 30.38.224.1
dns-nameservers 114.114.114.114

每个配置文件配置完成之后写入到 /etc/network/interfaces.d这个目录下面,比如网卡一eth1-network.yaml

重启网卡服务,即可生效

debian8
systemctl restart network

debian9
service networking restart    
systemctl restart networking

踩坑

获取物理网卡信息

获取物理网卡参看这种方法

  physics_net=($(ls /sys/class/net | grep -v "$(ls /sys/devices/virtual/net/)"))

Linux 网关作用

网关的作用就是帮助两个不能直接互通的网络,进行数据转发的

所以只要是能够帮助在不能直接互通的网络中进行数据转发的东西就可以成为网关,比如路由器,三层交换机,甚至防火墙都可以;当然现在大部分还是路由器来充当

查看默认的网关

root@demo:~# ip route show default
default via 10.88.160.1 dev enp3s0 proto dhcp metric 100
default via 192.168.1.1 dev enp4s0 proto static metric 20101
root@demo:~#
root@demo:~# route -n
内核 IP 路由表
目标            网关            子网掩码        标志  跃点   引用  使用 接口
0.0.0.0         10.88.160.1    0.0.0.0         UG    100    0        0 enp3s0
0.0.0.0         192.168.1.1    0.0.0.0         UG    20101  0        0 enp4s0
10.88.160.0     0.0.0.0         255.255.240.0   U     100    0        0 enp3s0
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 enp3s0
192.168.0.0     0.0.0.0         255.255.0.0     U     101    0        0 enp4s0

这里显示的两个默认网关,但是只会有上面的默认的网关起作用

注意:Linux 路由可以配置多个,但是默认的网关是只能有一个的;默认网关是指当主机要发送数据包到目标网络时,如果没有更具体的路由表项匹配,就会使用默认网关来转发数据包

修改默认的网关
ip route replace default via 192.168.1.2

删除默认的网关
ip route delete default via 192.168.1.2

Linux 单网卡多IP设置

网卡设置多IP的作用是什么,参考:

多网卡网关设置

root@hello-MBX-TGL3R100:/etc/netplan# cat enp4s0-network-vei.yaml
network:
  version: 2
  renderer: NetworkManager
  ethernets:
    enp4s0:
      dhcp4: false
      addresses: [10.88.173.0/24]
      gateway4: 10.88.160.1

网络配置不生效

root@hello-MBX-TGL3R100:/etc/netplan# netplan apply -f config=enp4s0-network-vei.yaml

** (generate:136885): WARNING **: 20:48:58.930: Problem encountered while validating default route consistency.Please set up multiple routing tables and use `routing-policy` instead.
Error: Conflicting default route declarations for IPv4 (table: main, metric: default), first declared in enp2s0 but also in enp4s0

** (process:136883): WARNING **: 20:48:59.531: Problem encountered while validating default route consistency.Please set up multiple routing tables and use `routing-policy` instead.
Error: Conflicting default route declarations for IPv4 (table: main, metric: default), first declared in enp2s0 but also in enp4s0

问题原因

两个网卡不能设置同一个默认的网关,否则就会有上面的提示

解决办法

参考这篇文章 关于linux的默认网关_51CTO博客_默认网关

结论就是两个网卡不同的网段,无论网关设置到哪边都会影响到另外一个网段所连接的网段不能正常使用

这篇文章也有说明:双网卡同时使用配置网关的处理方法+VLAN_双网卡都接互联网,都配网关可以吗-CSDN博客

route add -p 192.168.1.0 mask 255.0.0.0 192.168.1.1
route:用于配置和显示网络路由表的命令。
add:指示要添加一条新的路由表项。
-p:表示将路由表项持久化,使其在系统重启后仍然有效。如果不使用 -p 参数,则此路由表项在系统重启后将被删除。
192.168.1.0:目标网络的 IP 地址。
mask 255.0.0.0:子网掩码,用于确定目标网络的范围。在此示例中,子网掩码为 255.0.0.0,表示目标网络的范围是 192.0.0.0 - 192.255.255.255192.168.1.1:下一跳网关的 IP 地址。当目标 IP 地址属于目标网络时,数据包将通过该网关进行转发。

说明:这样192.168.1.0网段就可以正常通过局域网访问了。(实际中如果是和内网地址同一个网段的计算机用户,即使不增加这条路由也是可以访问的)