nanoFramework.Device.Bluetooth 1.1.75

前缀已保留
dotnet add package nanoFramework.Device.Bluetooth --version 1.1.75                
NuGet\Install-Package nanoFramework.Device.Bluetooth -Version 1.1.75                
该命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用了 NuGet 模块的 Install-Package 版本。
<PackageReference Include="nanoFramework.Device.Bluetooth" Version="1.1.75" />                
对于支持 PackageReference 的项目,将此 XML 节点复制到项目文件中以引用包。
paket add nanoFramework.Device.Bluetooth --version 1.1.75                
#r "nuget: nanoFramework.Device.Bluetooth, 1.1.75"                
#r 指令可用于 F# Interactive 和多语言笔记本。将此复制到交互式工具或脚本的源代码中以引用包。
// Install nanoFramework.Device.Bluetooth as a Cake Addin
#addin nuget:?package=nanoFramework.Device.Bluetooth&version=1.1.75

// Install nanoFramework.Device.Bluetooth as a Cake Tool
#tool nuget:?package=nanoFramework.Device.Bluetooth&version=1.1.75                

Quality Gate Status Reliability Rating License NuGet #yourfirstpr Discord

nanoFramework logo


文档语言: 英文 | 简体中文

欢迎使用 .NET nanoFramework nanoFramework.Device.Bluetooth 库仓库

构建状态

组件 构建状态 NuGet 包
nanoFramework.Device.Bluetooth Build Status NuGet

nanoFramework.Device.Bluetooth 类库

低功耗蓝牙库。

此库基于 Windows.Devices.Bluetooth UWP 类库,但进行了简化,并将相关异步调用变为同步。原始 .Net 程序集依赖于 Windows.Storage.Streams 的 DataReader & DataWriter;此库简化了内置版本。因此,在 .Net UWP 示例中引用 IBuffer 时现在应使用 Buffer。

固件版本

目前蓝牙仅在具有以下固件的 ESP32 设备上得到支持。

  • ESP32_BLE_REV0
  • ESP32_BLE_REV3
  • ESP32_PSRAM_BLE_GenericGraphic_REV3
  • ESP32_S3_BLE
  • M5Core2
  • LilygoTWatch2021
  • ESP32_ETHERNET_KIT_1.2

由于固件映像中IRAM内存空间的限制,蓝牙并非在所有固件中都可用。对于早期修订版的1 ESP32设备,PSRAM实现需要大量PSRAM库修正,这大大减少了IRAM区域的可用空间,因此PSRAM目前对ESP32_BLE_REV0已被禁用。在修订3的设备中,蓝牙和PSRAM都可用。

样本

nanoFramework样本仓库中有许多蓝牙低功耗样本。

用法

概述

此实现支持简化的Gatt服务器和Gatt客户端实现。

设备可以作为服务器或客户端运行,但不能同时运行。

更多信息请见相关部分:

此集合的一部分还包括NordicSPP类,它基于Nordic规范实现串行协议配置文件。这使得客户端可以很容易地通过蓝牙低功耗连接到蓝牙串行终端应用程序发送和接收消息。一个常见的用例是为设备提供配置。有关使用方法,请参阅后面的SPP部分。

属性和UUIDs

每个服务、特性和描述符都由它自己独特的128位UUID定义。在.Net中它们被称为GUID,在蓝牙规范中称为UUID。

如果该属性是由蓝牙SIG定义的标准UUID,它也将有一个相应的16位短ID(例如,特性“电池级别”的UUID为00002A19-0000-1000-8000-00805F9B34FB,短ID为0x2A19)。通用标准UUID可以在GattServiceUuids和GattCharacteristicUuids类中找到。

如果短ID不在GattServiceUuids或GattCharacteristicUuids中,请通过调用实用函数CreateUuidFromShortCode创建自己的短GUID。

Guid uuid1 = Utility.CreateUuidFromShortCode(0x2A19);

安全和配对

此集合支持使用加密和身份验证进行配对。

如果您的代码中没有进行任何操作,它将使用“即插即用”的配对方法,这将启用连接上的加密。

要启用“身份验证”,您需要处理代码中的配对事件。

更多信息请见配对部分。

Gatt服务器

Gatt服务器的主体对象是BluetoothLEServer类。这是一个单例类,因此只能有一个BluetoothLEServer对象的存在。可以通过使用静态属性BluetoothLEServer.Instance访问BluetoothLEServer对象。对此的第一次调用将创建对象。调用dispose将对象从内存中移除。

此对象是新的,在常规Windows实现中不存在,并且是为了允许从管理代码中更好地处理配对和连接而添加的。

设置设备和外观

设备名称和外观是通用接入服务的一部分,自动包含在每个 Gatt 服务器定义中。名称应该是当前设备的名称,而可选的外观是表示设备使用的 16 位代码。默认值为 0,代表“未知设备”。有关代码的详细信息,请参阅蓝牙Sig分配的数字文档;章节2.6.3 外观子类别值。使用值列中的代码。例如,代码 0x0481 是用于自行车计算机。

    BluetoothLEServer server = BluetoothLEServer.Instance;
    server.DeviceName = "Esp32_01";
    server.Appearance = 0x0481;

定义服务和关联特性

使用 GattServiceProvider 创建和宣传主要服务定义。第一次创建服务时,将自动创建额外的设备信息服务。

GattServiceProviderResult result = GattServiceProvider.Create(uuid);
if (result.Error != BluetoothError.Success)
{
    return result.Error;
}

serviceProvider = result.ServiceProvider;

要为 Gatt 服务器创建更多服务,请通过调用 GattServiceProvider.Create(UUID) 为每个新服务进行调用。

通过 BluetoothLEServer 实例访问所有创建的服务。

BluetoothLEServer server = BluetoothLEServer.instance;
GattServiceProvider[] services = server.Services()

或使用其 UUID 查找特定服务。

BluetoothLEServer server = BluetoothLEServer.instance;
GattServiceProvider service = server.GetServiceByUUID(uuid)

使用 GattServiceProvider 的 Service 属性可以添加所有必要的特性。目前支持只有读、写、无响应写、通知和指示特性。

添加读特性

如果向 GattLocalCharacteristicParameters 中添加了 userDescription,则将自动将用户描述符添加到特性。对于读特性,您需要一个相关的事件处理程序来提供读取数据。

GattLocalCharacteristicParameters ReadParameters = new GattLocalCharacteristicParameters
{
    CharacteristicProperties = (GattCharacteristicProperties.Read),
    UserDescription = "My Read Characteristic"
};

GattLocalCharacteristicResult characteristicResult = serviceProvider.Service.CreateCharacteristic(uuid1, ReadParameters);
if (characteristicResult.Error != BluetoothError.Success)
{
    // An error occurred.
    return characteristicResult.Error;
}

_readCharacteristic = characteristicResult.Characteristic;
_readCharacteristic.ReadRequested += _readCharacteristic_ReadRequested;

您可以通过设置 StaticValue 属性来设置具有常量值的读特性。

// Setting a Int 16 constant value to the characteristic. 
DataWriter dr = new DataWriter();
dr.WriteInt16(123);

GattLocalCharacteristicParameters ReadParameters = new GattLocalCharacteristicParameters
{
    CharacteristicProperties = (GattCharacteristicProperties.Read),
    UserDescription = "My Read Characteristic",
    StaticValue = dr.DetachBuffer()
};

如果设置了 StaticValue,则不会调用读事件,并且不需要定义。

添加写或无响应写特性

写特性用于接收来自客户端的数据。

GattLocalCharacteristicParameters WriteParameters = new GattLocalCharacteristicParameters
{
    CharacteristicProperties = GattCharacteristicProperties.Write,
    UserDescription = "My Write Characteristic"
};


characteristicResult = serviceProvider.Service.CreateCharacteristic(uuid2, WriteParameters);
if (characteristicResult.Error != BluetoothError.Success)
{
    // An error occurred.
    return characteristicResult.Error;
}
_writeCharacteristic = characteristicResult.Characteristic;
_writeCharacteristic.WriteRequested += _writeCharacteristic_WriteRequested;

添加通知特性

通知特性用于在值更改时自动通知已订阅的客户端。

GattLocalCharacteristicParameters NotifyParameters = new GattLocalCharacteristicParameters
{
    CharacteristicProperties = GattCharacteristicProperties.Notify,
    UserDescription = "My Notify Characteristic"
};

characteristicResult = serviceProvider.Service.CreateCharacteristic(uuid3, NotifyParameters);
if (characteristicResult.Error != BluetoothError.Success)
{
    // An error occurred.
    return characteristicResult.Error;
}

_notifyCharacteristic = characteristicResult.Characteristic;
_notifyCharacteristic.SubscribedClientsChanged += _notifyCharacteristic_SubscribedClientsChanged;

向通知特性发送数据

您可以通过在通知特性上调用 NotifyValue 方法将数据发送到已订阅的客户端。可以添加额外检查以确保仅在存在已订阅的客户端或自上次通知以来值已更改时发送值。

private static void UpdateNotifyValue(double newValue)
{
    DataWriter dw = new DataWriter();
    dw.WriteDouble(newValue);

    _notifyCharacteristic.NotifyValue(dw.DetachBuffer());
}

事件

读取请求事件

当客户端请求读取一个特性时,如果未设置静态值,则会调用管理事件。如果没有设置事件处理程序或没有及时响应,则向客户端返回一个不太可能的蓝牙错误。
如果从外围设备读取值需要花费时间,那么最好将此放置在事件处理程序之外。

此示例显示了向客户端请求返回 2 个值。

private static void _readCharacteristic_ReadRequested(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs)
{
    GattReadRequest request = ReadRequestEventArgs.GetRequest();

    // Create DataWriter and write the data into buffer
    DataWriter dw = new DataWriter();
    dw.WriteInt16(1);
    dw.WriteInt32(2);

    request.RespondWithValue(dw.DetachBuffer());

    // If there is some sort of error then response with an error 
    //request.RespondWithProtocolError((byte)BluetoothError.DeviceNotConnected);
}

写入请求事件

当向写特性发送数据时,会调用管理事件。如果没有设置事件处理程序或没有及时响应,则向客户端返回一个不太可能的蓝牙错误。

接收到的数据是字节数组,并按特性要求的格式进行格式化。这可能是一个值,如 Int16、Int32、字符串等,或者可能是一系列不同的值。

此示例显示了从缓冲区中读取单个 Int32 值,并在提供的字节数不正确时返回错误。

private static void _writeCharacteristic_WriteRequested(GattLocalCharacteristic sender, GattWriteRequestedEventArgs WriteRequestEventArgs)
{
    GattWriteRequest request = WriteRequestEventArgs.GetRequest();

    // Check expected data length
    if (request.Value.Length != 4)
    {
        request.RespondWithProtocolError((byte)BluetoothError.NotSupported);
        return;
    }

    // Read data from buffer of required format
    DataReader rdr = DataReader.FromBuffer(request.Value);
    Int32 data = rdr.ReadInt32();

    // Do something with received data
    Debug.WriteLine($"Rx data::{data}");

    // Respond if Write requires response
    if (request.Option == GattWriteOption.WriteWithResponse)
    {
        request.Respond();
    }
}

订阅客户端更改事件

对于可通知特性,客户端可以订阅以接收通知值。当客户端订阅时,会调用管理事件。特性的 SubscribedClients 数组包含已连接的客户端。

private static void _notifyCharacteristic_SubscribedClientsChanged(GattLocalCharacteristic sender, object args)
{
    if ( sender.SubscribedClients.Length > 0)
    {
         Debug.WriteLine($"Client connected ");
    }
}

宣传您的服务

一旦创建了所有特性,您需要宣传服务,这样其他设备就可以看到它并/或连接到它。

作为 ServiceProvider 的一部分,我们自动将以下数据部分添加到广告负载中。

  • 标志
  • 完整的本地名称
  • 在提供商上定义的服务 UUID。
  • 服务数据(可选)

nanoFramework 的一个扩展允许通过向 GattServiceProviderAdvertisingParameters 对象的 Advertisement 属性添加数据段来添加广播。此外,通过设置 GattServiceProviderAdvertisingParameters.CustomAdvertisement 标志,所有数据段都可以由用户设置。

开始广播。

serviceProvider.StartAdvertising(new GattServiceProviderAdvertisingParameters()
{
    IsConnectable = true,
    IsDiscoverable = true
});

Gatt客户端/中心

蓝牙低能耗(BLE)客户端用于查找来自设备(服务器)的广告,并连接到这些设备以及对特性进行读取和/或写入值。可以设置通知,以便在值更改时自动触发事件。

我们提供了 2 个示例。

  • Central1 - 这是一个简单的示例,仅用于监视广告并打印出结果。
  • Central2 - 这是一个更完整的示例,展示了如何收集具有环境传感器服务的多个设备的值,例如温度。这些设备是 Sample 设备示例的更新版本。

监视广告。

要监视广告,请使用 BluetoothLEAdvertisementWatcher 类。

    BluetoothLEAdvertisementWatcher watcher = new();
    watcher.Received += Watcher_Received;
    watcher.Start();

当接收到广告时,将引发一个事件,调用 Watcher_Received 事件处理程序。在事件处理程序中,您可以使用事件提供的信息选择设备。这可以是设备的 LocalName 或广告数据中提供的其他数据。

如果您启动一个 Watcher 来查找来自服务器设备的广告,则在停止 Watcher 之前无法连接到这些设备,但您可以在 Watcher 扫描时接收已连接设备的消息。因此,需要在连接服务器时停止 Watcher。

请参阅示例以获取更多信息。

可以向 BluetoothLEAdvertisementWatcher 添加过滤器。有以下 2 个过滤器可用:-

  • RSSI 过滤器 - 只接收来自一定信号强度范围内的设备的广告。
  • 广告过滤器 - 根据广告内容进行过滤。

RSSI 过滤器。

    watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
    watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -77;
    watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(10000);

广告过滤器。

只接收与过滤器中包含的数据段或数据段一部分匹配的设备广告。

更新广告对象以使用数据段与过滤器进行匹配。对象上有些属性对于常见数据段来说是通用的。对于其他数据段,请将所需匹配的数据段加载到 "dataSections" arrayList 属性中。

使用属性匹配设备本地名称。只有本地名称为 "Sample" 的设备的广告才会被接收。

    watcher.AdvertisementFilter.Advertisement.LocalName = "Sample";

此过滤器使用数据段的局部匹配。选择第二个位置为 "a" 的所有广告。

如果您想根据数据段的一部分进行过滤,请使用 BytePatterns arrayList。

   BluetoothLEAdvertisementBytePattern pattern = new BluetoothLEAdvertisementBytePattern()
   {
      DataType = (byte)BluetoothLEAdvertisementDataSectionType.CompleteLocalName,
      Data = new Buffer(new Byte[] { (Byte)'a' }),
      Offset = 1
   };

   watcher.AdvertisementFilter.BytePatterns.Add(pattern2;

可以过滤广告中的任何数据。可以同时使用广告和字节模式。

有关广告过滤器的更多示例,请参阅 Watcher 过滤器示例。

创建设备和连接到设备。

要与设备通信,请使用 BluetoothLEDevice 类创建设备,指定设备的蓝牙地址和类型。这可以是来自 BluetoothLEAdvertisementWatcher 事件的蓝牙地址,也可以是硬编码的地址。

在这种情况下,来自 Watcher 广告接收事件的 BluetoothAddress 参数。

BluetoothLEDevice device = BluetoothLEDevice.FromBluetoothAddress(args.BluetoothAddress)

没有特定的连接方法,当查询设备服务或启动配对操作时将自动建立连接。可以使用 ConnectionStatusChanged 事件来检测连接状态的变化,并可以通过再次查询设备的服务来实现重连。避免在事件中这样做,因为这可能会阻塞在连接期间触发其他事件。

连接设备后,返回到“监视广告”选项,但请注意,在停止监视之前,您不能连接到新发现的设备。当监视器运行时,您仍然可以与连接的设备进行通信。最佳做法是,在停止监视器之前,将所有找到的设备收集到一个表格中,然后连接到所有找到的设备。请参见中央 2 示例

在桌面版本中没有公开 Close() 方法,但在这个版本中已实现,以提供对连接的更好控制。

获取连接设备的信息

连接到设备后,通用访问设备名称和外观代码将作为 BluetoothLEDevice 对象的属性可用。

查询设备服务

查询设备提供的所有服务。如果 GattDeviceServicesResult 状态是 GattCommunicationStatus.Success,则在 GattDeviceServicesResult 的 Services 属性中将可用数组 GattDeviceService 对象。

    GattDeviceServicesResult sr = device.GetGattServices();
    if (sr.Status == GattCommunicationStatus.Success)
    {
        GattDeviceService[] services = sr.Services;

    }

查询设备提供的特定服务。

    GattDeviceServicesResult sr = device.GetGattServicesForUuid(GattServiceUuids.EnvironmentalSensing);
    if (sr.Status == GattCommunicationStatus.Success)
    {
        
    }

上述两种获取服务的方法都将尝试连接到设备。

注意:服务被缓存,因此第一次查询时将从设备检索它们。对服务的后续调用将返回缓存的结果。要清除缓存,必须处置设备。

查询服务特征

使用 GattDeviceService 对象可以查询所需特征。与方法查询服务的方式相同,有一种方法可以查询所有特征或仅特定特征。

查询所有特征

    GattCharacteristicsResult cr = service.GetCharacteristics();
    if (cr.Status == GattCommunicationStatus.Success)
    {
        GattCharacteristic[] chars = cr.Characteristics;
    }    

查询具有标准温度 UUID 的所有特征的服务。

    GattCharacteristicsResult cr = service.GetCharacteristicsForUuid(GattCharacteristicUuids.Temperature);
    if (cr.Status == GattCommunicationStatus.Success)
    {
        GattCharacteristic[] gcs = cr.Characteristics;
    }    

注意:特征被缓存,因此第一次请求它时将从设备检索它们。对同一服务的后续调用将返回缓存的结果。

查询特征描述符

可以使用 GetDescriptors 和 GetDescriptorsForUuid 方法以与服务和特征相同的方式进行描述符检索。

在这些示例中,gc 是 GattCharacteristic 对象。

获取所有描述符。

    GattDescriptorsResult dr = gc.GetDescriptors();
    if (dr.Status == GattCommunicationStatus.Success)
    {

    }   

获取具有特定 UUID 的所有描述符。

    GattDescriptorsResult dr = gc.GetDescriptorsForUuid(uuid);
    if (dr.Status == GattCommunicationStatus.Success)
    {

    }   

用户描述表示格式属性将自动从设备检索描述符。对描述符的任何进一步调用将来自本地缓存。

读取和写入属性值

要从一个特征或描述符中读取值,请使用 ReadValue() 方法。如果成功,将可用 Buffer 对象,可以使用 DataReader 从该对象中读取数据。

缓冲区中的数据格式取决于正在读取的特征/描述符。

此示例从特征/描述符读取值并将 3 个字节加载到字节和无符号短整型中。

    GattReadResult rr = gc.ReadValue();
    if (rr.Status == GattCommunicationStatus.Success)
    {
        DataReader rdr = DataReader.FromBuffer(rr.Value);
        Byte data1 = rdr.ReadByte();
        ushort data2 = rdr.ReadInt16();

    }

要写入特征或描述符,创建包含所需数据的 Buffer 并调用 WriteValueWithResult() 方法。这可以用于有或无响应的写入。

    DataWriter dw = new();
    dw.WriteBytes(new byte[] { 1, 2, 3, 4 });
    dw.WriteUInt32(23);

    GattWriteResult wr = gc.WriteValueWithResult(dw.DetachBuffer(), , GattWriteOption.WriteWithResponse);
    if (wr.Status == GattCommunicationStatus.Success)
    {

    }

启用值更改通知

这可以使用设置事件然后设置如下 CCCD 描述符的值启用接收当服务器上特征值更改时的事件。

gc 是要启用的 GattCharacteristic 的示例。

    // Set up a notify value changed event
    gc.ValueChanged += ValueChanged;

    // and configure CCCD for Notify
    gc.WriteClientCharacteristicConfigurationDescriptorWithResult(GattClientCharacteristicConfigurationDescriptorValue.Notify);

要关闭通知,写入无值到 CCCD 描述符。

通知事件的处理器。

发送者是特征更改来源的 GattCharacteristic,valueChangedEventArgs.CharacteristicValue 是带有新值的 Buffer 值。

    private static void ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs valueChangedEventArgs)
    {
        DataReader rdr = DataReader.FromBuffer(valueChangedEventArgs.CharacteristicValue);

        // Read value from DataReader
    }

处理设备错误

通过监视 BluetoothLEDevice 对象上的 ConnectionStatusChanged 事件来处理连接错误。
如果连接丢失,通过再次请求服务来重新连接。

参见 Central2 示例。

请确保检查所有请求的返回状态,以确保它们成功。

配对

配对由 DevicePairing 类处理,该类是 BluetoothLEServerBluetoothLEDevice 类的一个属性。属性 ProtectionLevelIOCapabilities 控制了配对的方式。

有关 Bluetooth 配对和 IO 能力如何影响配对类型的好信息,请参阅这个非常有用的 博客,网址为 www.bluetooth.com

ProtectionLevel

默认情况下,ProtectionLevelNoneIOCapabilitiesNoInputNoOutput,因此如果两端都是 nanoFramework,配对将使用 Just Works 方法。

根据添加的特性要求,ProtectionLevel 将自动更新。可以手动设置以强制不同级别的保护。

ProtectionLevel
None 连接不使用安全,使用传统配对
加密 使用安全连接。自动生成连接密钥。
EncryptionAndAuthentication 由于使用安全连接并且需要身份验证,因此必须正确设置 IoCapabilities

IOCapabilities

IO 能力是设备上可用的输入和输出外围设备,用于配对。根据每个设备具有的 IO 能力将决定如何进行配对。

IOCapabilities
DisplayOnly 仅提供显示。可用来显示其他设备的 PassKey 以供输入。
DisplayYesNo 提供显示和“是/否”输入方式,例如 2 个按钮。
NoInputNoOutput 没有输入或输出可用。
KeyboardDisplay 提供显示和键盘。

配对矩阵

引发者是启动配对操作的设备。通常这是客户端。应答者是响应配对请求的设备。

Just Works:表示不需要输入,仅设置连接。如果有特性的保护级别为身份验证,则将给出访问错误。

应答者 IO 能力 Initiator IOCapabilities
DisplayOnly DisplayYesNo KeyboardOnly NoInputNoOutput KeyboardDisplay
DisplayOnly Just Works Just Works PassKey R->I Just Works PassKey R->I
DisplayYesNo Just Works Just Works 或 Compare(sec) PassKey R->I Just Works PassKey R->I 或 Compare(sec)
KeyboardOnly PassKey I->R PassKey I->R Passkey R&gum;I Just Works PassKey I->R
NoInputNoOutput Just Works Just Works Just Works Just Works Just Works
KeyboardDisplay PassKey I->R PassKey I->R 或 Compare(sec) PassKey R->I Just Works PassKey I->R 或 Compare(sec)

其中:-

  • Passkey R->I:Passkey 在应答者上显示,在引发者上进行输入。
  • Passkey I->R:Passkey 在引发者上显示,在应答者上进行输入。
  • Passkey R&gum;I:Passkey 在引发者和应答者上输入。
  • Compare(sec):使用安全连接时的数字比较。两端输入和显示 Passkey。

IO 能力的常见用例。

应答者(客户端) 配对 引发者(服务器)
NoInputNoOutput Just Works NoInputNoOutput
KeyboardOnly 从客户端接收并发送 PassKey,服务器进行检查 DisplayOnly

代码示例

有关完整示例,请参阅示例 BluetoothLESample2Central3

服务器
设置服务器配对。

客户端必须提供正确的 PassKey。

    BluetoothLEServer server = BluetoothLEServer.Instance;
    server.DeviceName = "MyTestEsp32";

    // Set up an event handler for handling pairing requests
    server.Pairing.PairingRequested += Pairing_PairingRequested;
    server.Pairing.PairingComplete += Pairing_PairingComplete;

    // Say we have a display
    server.Pairing.IOCapabilities = DevicePairingIOCapabilities.DisplayOnly;

    // Set ProtectionLevel
    server.Pairing.ProtectionLevel = DevicePairingProtectionLevel.EncryptionAndAuthentication;

    // Start the Bluetooth server. 
    server.Start();

    // Add services and advertise

处理配对请求事件的处理器。

配对类型表示应用程序需要做什么。在这种情况下,它是 DevicePairingKinds.DisplayPin,只需比较客户端的 PassKey。

对于具有显示的一般用途设备,应将 PassKey 显示出来,以便客户端知道要输入什么。

private static void Pairing_PairingRequested(object sender, DevicePairingRequestedEventArgs args)
{
    switch (args.PairingKind)
    {
        // Passkey displayed on current device or just a know secret passkey
        // Tell BLE what passkey is, so it can be checked against what has been entered on other device.
        case DevicePairingKinds.DisplayPin:
            args.Accept(654321);
            break;
    }
}
处理配对完成事件的事件处理器。

这将通知程序配对是否成功。检查 args.Status 是否为成功,并且 IsPaired 属性为 true。

private static void Pairing_PairingComplete(object sender, DevicePairingEventArgs args)
{
    DevicePairing dp = sender as DevicePairing;
         
    Console.WriteLine($"PairingComplete:{args.Status} IOCaps:{dp.IOCapabilities} IsPaired:{dp.IsPaired} IsAuthenticated:{dp.IsAuthenticated}");
}
客户端
为配对身份验证设置 BluetoothLEDevice。
static void SetupDevice(BluetoothLEDevice device)
{
    // Event handlers pairing
    device.Pairing.PairingRequested += Pairing_PairingRequested;
    device.Pairing.PairingComplete += Pairing_PairingComplete;

    // Set up IOCapabilities & ProtectionLevel
    device.Pairing.IOCapabilities = DevicePairingIOCapabilities.KeyboardOnly;
    device.Pairing.ProtectionLevel = DevicePairingProtectionLevel.EncryptionAndAuthentication;

    // Pair with device
    DevicePairingResult pairResult = device.Pairing.Pair();

处理输入 PassKey 的事件处理器。
private static void Pairing_PairingRequested(object sender, DevicePairingRequestedEventArgs args)
{
    Console.WriteLine($"Pairing_PairingRequested:{args.PairingKind}");

    switch (args.PairingKind)
    {
        case DevicePairingKinds.ProvidePin:
            // Provide valid passkey
            args.Accept(654321);
            break;
    }
}

处理配对完成事件的事件处理器。
private static void Pairing_PairingComplete(object sender, DevicePairingEventArgs args)
{
    // Pick up DevicePairing from sender or just use it directly
    DevicePairing pairing = (DevicePairing)sender;

    if (args.Status == DevicePairingResultStatus.Paired)
    {
        Console.WriteLine($"PairingComplete:{args.Status} IOCaps:{pairing.IOCapabilities} IsPaired:{pairing.IsPaired} IsAuthenticated:{pairing.IsAuthenticated}");
    }
    else
    {
        Console.WriteLine($"PairingComplete failed - status = {args.Status}");
    }
}

BluetoothLEAdvertisementPublisher 类允许配置和广播 Bluetooth LE 广告数据包。广告数据包的有效负载在构造 BluetoothLEAdvertisement 类时进行配置。

BluetoothLEAdvertisement 类用于控制广告包具体包含的内容,主要用于创建信标。

通过将 BluetoothLEAdvertisementDataSection 添加到 BluetoothLEAdvertisement 类中来构建广告。对于一些常见的数据部分,BluetoothLEAdvertisement 类上有属性可以自动添加正确的数据部分到广告中。例如:LocalName,Flags。

构建 BluetoothLEAdvertisementPublisher 类后,可以使用 Start() 和 Stop() 方法启动或停止广告。

创建广告包

对于遗留的广告,包长度为 31 字节,包括所有数据部分。每个数据部分长度为 1 字节,部分类型为 1 字节,数据字节。任何不适合广告的数据部分将被移动到扫描响应或留在其中。

当前不支持扩展广告。这将在未来的版本中提供。

BluetoothLEAdvertisementPublisher publisher = new BluetoothLEAdvertisementPublisher();

// Add Flags using property
publisher.Advertisement.Flags = BluetoothLEAdvertisementFlags.GeneralDiscoverableMode |
                                BluetoothLEAdvertisementFlags.DualModeControllerCapable |
                                BluetoothLEAdvertisementFlags.DualModeHostCapable;

// Adding flags using Data Sections
publisher.Advertisement.

启动和停止发布者

广告 1 分钟。

publisher.Start();

Thread.Sleep(60000);

publisher.Stop();

蓝牙串行端口配置文件(SPP)

此组件实现了 Nordic SPP,可以轻松地在蓝牙客户端与运行 SPP 的设备之间发送消息。这是给设备添加任何额外信息(如 WiFi 详细信息)的简单方法。

有一些 Android 和 IOS 应用支持 Nordic SPP,可以用来发送/接收消息。

创建 SPP 实例

创建一个 SPP 实例,并为读取消息和客户端连接活动提供事件处理程序。以设备名称启动广告。

使用命名空间 nanoFramework.Device.Bluetooth.Spp

NordicSpp spp = new NordicSpp();
spp.ReceivedData += Spp_ReceivedData;
spp.ConnectedEvent += Spp_ConnectedEvent;

spp.Start("MySpp");

完成后,调用 Stop 方法停止 SPP。

处理读取数据事件

数据可以以字节数组或字符串的形式读取。

private void Spp_ReceivedData(IBluetoothSpp sender, SppReceivedDataEventArgs ReadDataEventArgs)
{
    string message = ReadDataEventArgs.DataString;

    // Do something with incoming message
    Debug.WriteLine($"Message:{message}");

    // For this example lets respond with "OK"
    NordicSpp spp = sender as NordicSpp;
    spp.SendString("OK");
}

处理连接事件

当客户端连接到或从 SPP 服务器断开连接时,会抛出一个连接事件。在这里,当客户端连接时,我们发送一条消息。

private void Spp_ConnectedEvent(IBluetoothSpp sender, EventArgs e)
{
    NordicSpp spp = sender as NordicSpp;

    if (spp.IsConnected)
    {
        spp.SendString("Welcome to nanoFramework");
    }
}

反馈和文档

有关文档、提供反馈、问题和了解如何贡献,请参阅主页仓库

加入我们的 Discord 社区 在此

贡献者

此项目的贡献者列表可在贡献者中找到。

许可协议

nanoFramework 类库的使用受MIT 许可协议的约束。

行为准则

本项目已采用贡献者协议规定的准则,以阐明我们社区中预期的行为。有关更多信息,请参阅.NET 基金会行为准则

.NET 基金会

本项目得到.NET 基金会的支持。

产品 兼容和额外的目标框架版本。
.NET 框架 net 兼容。
兼容目标框架(s)
包含的目标框架(s)(在包中)
了解更多关于目标框架.NET 标准的信息。

NuGet包 (1)

显示依赖nanoFramework.Device.Bluetooth的前1个NuGet包

包名 下载
nanoFramework.Bluetooth.Hid

这个包包含用于.NET nanoFramework C#项目的nanoFramework.Bluetooth.Hid程序集。这允许设备通过蓝牙以HID设备的形式被发现。

GitHub仓库 (1)

显示依赖nanoFramework.Device.Bluetooth的前1个流行的GitHub仓库

仓库 星标
nanoframework/Samples
🍬 ninjaFramework团队用于测试、概念验证和其他探索性工作的代码示例
版本 下载 最后更新
1.1.75 365 6/16/2024
1.1.73 90 6/15/2024
1.1.65 285 5/9/2024
1.1.60 900 11/9/2023
1.1.58 92 11/9/2023
1.1.56 408 8/9/2023
1.1.54 228 8/2/2023
1.1.47 382 4/25/2023
1.1.45 208 4/16/2023
1.1.43 177 4/13/2023
1.1.40 278 3/16/2023
1.1.37 270 3/10/2023
1.1.35 204 3/9/2023
1.1.32 428 12/28/2022
1.1.30 272 12/27/2022
1.1.21 602 10/26/2022
1.1.16 449 9/27/2022
1.1.13 485 9/16/2022
1.1.10 405 9/6/2022
1.1.8 371 9/6/2022
1.1.4 450 8/20/2022
1.1.2 435 8/4/2022
1.0.2.6 537 6/9/2022
1.0.2.4 406 6/8/2022
1.0.2.1 381 6/6/2022
1.0.1 308 3/30/2022
1.0.0-preview.31 119 3/28/2022
1.0.0-preview.29 115 3/28/2022
1.0.0-preview.26 126 3/17/2022
1.0.0-preview.24 140 3/17/2022
1.0.0-preview.23 117 3/14/2022
1.0.0-preview.21 116 3/14/2022
1.0.0-preview.18 166 2/17/2022
1.0.0-preview.17 128 2/8/2022
1.0.0-preview.16 125 2/4/2022
1.0.0-preview.15 132 1/28/2022
1.0.0-preview.14 125 1/28/2022
1.0.0-preview.13 126 1/21/2022
1.0.0-preview.12 126 1/21/2022
1.0.0-preview.11 122 1/20/2022
1.0.0-preview.9 150 1/4/2022
1.0.0-preview.8 139 12/28/2021
1.0.0-preview.6 273 12/3/2021
1.0.0-preview.4 146 12/3/2021