Nanoframework 操作单片机蓝牙配置WIFI的案例

nanoframework,操作,单片机,蓝牙,配置,wifi,案例 · 浏览次数 : 683

小编点评

首先先读取数据,然后接收读,在得到数据转换字符串,通过调用SetWifi方法去解析设置WIFI ``` public static void SetWifi(string value) { var wifiValue = value.Split(';'); if (wifiValue.Length > 1) { var name = wifiValue[0].Substring(2); var password = wifiValue[1].Substring(2); if (password.Length > 0) { ConfigHelper.SetWifi(value); try { CancellationTokenSource cs = new(60000); var success = WifiNetworkHelper.ConnectDhcp(name, password, requiresDateTime: true, token: cs.Token); Debug.WriteLine(\"链接WIFI成功\"); } catch (Exception) { Debug.WriteLine(\"尝试链接WiFi失败\"); } } } } } ``` 最后定义设置密码格式 n:wifi名称;p:WiFi密码,不使用json格式从而减少包的依赖。

正文

Nanoframework 操作单片机蓝牙配置WIFI的案例

通过Nanoframework的蓝牙配置Wifi的名称和密码

下面是基本需要的工具

  1. ESP32设备一个 需要支持蓝牙和wifi,一般情况的ESP32都支持wifi和蓝牙,当前教程使用的ESP32的接口是Type-C
    设备实物图片:

    1. 部署好的ESP32NanoFramework环境

      刷支持蓝牙的固件

      nanoff --update --target ESP32_BLE_REV0 --serialport COM5 --fwversion 1.8.1.292 --baud 1500000
      
    2. VS扩展安装好NanoFramework扩展

    3. 准备好手机下载蓝牙调试APP,我用的是这个

实现通过蓝牙配置单片机的WIFI

using nanoFramework.Device.Bluetooth;
using nanoFramework.Device.Bluetooth.GenericAttributeProfile;
using nanoFramework.Networking;
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using static Gotrays.Program;

namespace Gotrays
{
    public class Program
    {
        static GattLocalCharacteristic _readCharacteristic;
        static GattLocalCharacteristic _readWriteCharacteristic;

        // Read/Write Characteristic value
        static byte _redValue = 128;
        static byte _greenValue = 128;
        static byte _blueValue = 128;

        public static void Main()
        {
            var wifi = ConfigHelper.GetWifi();

            // 如果存在wifi配置尝试链接wifi
            if (wifi.Password != null)
            {
                try
                {
                    CancellationTokenSource cs = new(60000);
                    var success = WifiNetworkHelper.ConnectDhcp(wifi.Name, wifi.Password, requiresDateTime: true, token: cs.Token);
                }
                catch (Exception)
                {
                    Debug.WriteLine("尝试链接WiFi失败");
                }

            }
            // BluetoothLEServer是一个单例对象,因此获得它的实例。对象是在您第一次访问它时创建的
            // 可以释放内存。
            BluetoothLEServer server = BluetoothLEServer.Instance;

            // 给设备命名
            server.DeviceName = "TokenIOT";

            // 定义一些自定义uid
            Guid serviceUuid = new Guid("A7EEDF2C-DA87-4CB5-A9C5-5151C78B0057");
            Guid readCharUuid = new Guid("A7EEDF2C-DA88-4CB5-A9C5-5151C78B0057");
            Guid readStaticCharUuid = new Guid("A7EEDF2C-DA89-4CB5-A9C5-5151C78B0057");
            Guid readWriteCharUuid = new Guid("A7EEDF2C-DA8A-4CB5-A9C5-5151C78B0057");

            // GattServiceProvider用于创建和发布主服务定义。
            // 将自动创建一个额外的设备信息服务。
            GattServiceProviderResult result = GattServiceProvider.Create(serviceUuid);
            if (result.Error != BluetoothError.Success)
            {
                return;
            }

            GattServiceProvider serviceProvider = result.ServiceProvider;

            // 从提供者处创建主服务
            GattLocalService service = serviceProvider.Service;

            #region Static read characteristic
            // 现在我们给服务添加一个特性

            //如果读取值不会改变,那么你可以使用Static值
            DataWriter sw = new DataWriter();
            sw.WriteString("这是蓝牙示例1");

            GattLocalCharacteristicResult characteristicResult = service.CreateCharacteristic(readStaticCharUuid,
                 new GattLocalCharacteristicParameters()
                 {
                     CharacteristicProperties = GattCharacteristicProperties.Read,
                     UserDescription = "我的静态特性",
                     StaticValue = sw.DetachBuffer()
                 });

            if (characteristicResult.Error != BluetoothError.Success)
            {
                // An error occurred.
                return;
            }
            #endregion

            #region Create Characteristic for dynamic Reads 

            // 对于变更为业务的数据,增加“读特性”
            // 我们还希望连接的客户端在值改变时得到通知,所以我们添加了notify属性
            characteristicResult = service.CreateCharacteristic(readCharUuid,
                new GattLocalCharacteristicParameters()
                {
                    CharacteristicProperties = GattCharacteristicProperties.Read | GattCharacteristicProperties.Notify,
                    UserDescription = "我的阅读特点"
                });

            if (characteristicResult.Error != BluetoothError.Success)
            {
                // An error occurred.
                return;
            }

            // 查阅我们的read特性
            _readCharacteristic = characteristicResult.Characteristic;

            // 每次从客户端请求该值时,都会调用此事件
            _readCharacteristic.ReadRequested += ReadCharacteristic_ReadRequested;

            #endregion

            #region Create Characteristic for RGB read/write
            characteristicResult = service.CreateCharacteristic(readWriteCharUuid,
                new GattLocalCharacteristicParameters()
                {
                    CharacteristicProperties = GattCharacteristicProperties.Read | GattCharacteristicProperties.Write,
                    UserDescription = "My Read/Write Characteristic"
                });

            if (characteristicResult.Error != BluetoothError.Success)
            {
                // An error occurred.
                return;
            }

            // 查阅我们的read特性
            _readWriteCharacteristic = characteristicResult.Characteristic;

            //每次从客户端请求该值时,都会调用此事件
            _readWriteCharacteristic.WriteRequested += _readWriteCharacteristic_WriteRequested;
            _readWriteCharacteristic.ReadRequested += _readWriteCharacteristic_ReadRequested;

            #endregion

            #region Start Advertising

            // 一旦所有的特征已经创建,你需要广告的服务,所以
            // 其他设备可以看到它。这里我们也说设备也可以连接
            // 设备可以看到它。
            serviceProvider.StartAdvertising(new GattServiceProviderAdvertisingParameters()
            {
                IsConnectable = true,
                IsDiscoverable = true
            });

            #endregion 

            Thread.Sleep(Timeout.Infinite);
        }

        /// <summary>
        /// 读取特性的事件处理程序。
        /// </summary>
        /// <param name="sender">GattLocalCharacteristic object</param>
        /// <param name="ReadRequestEventArgs"></param>
        private static void ReadCharacteristic_ReadRequested(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs)
        {
            GattReadRequest request = ReadRequestEventArgs.GetRequest();

            // Get Buffer with hour/minute/second
            //request.RespondWithValue(GetTimeBuffer());
        }

        /// <summary>
        /// 读/写特性的读事件处理程序。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ReadRequestEventArgs"></param>
        private static void _readWriteCharacteristic_ReadRequested(GattLocalCharacteristic sender, GattReadRequestedEventArgs ReadRequestEventArgs)
        {
            GattReadRequest request = ReadRequestEventArgs.GetRequest();

            DataWriter dw = new DataWriter();
            dw.WriteByte((Byte)_redValue);
            dw.WriteByte((Byte)_greenValue);
            dw.WriteByte((Byte)_blueValue);

            request.RespondWithValue(dw.DetachBuffer());

            Debug.WriteLine($"RGB read");
        }

        /// <summary>
        /// 读写特性的写处理程序。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="WriteRequestEventArgs"></param>
        private static void _readWriteCharacteristic_WriteRequested(GattLocalCharacteristic sender, GattWriteRequestedEventArgs WriteRequestEventArgs)
        {
            GattWriteRequest request = WriteRequestEventArgs.GetRequest();
            var size = request.Value.Length;
            // 从缓冲区解包数据
            DataReader rdr = DataReader.FromBuffer(request.Value);
            var buffer = new byte[request.Value.Length];
            rdr.ReadBytes(buffer);

            // 如果Write需要响应,则响应
            if (request.Option == GattWriteOption.WriteWithResponse)
            {
                request.Respond();
            }

            // 定义设置密码格式 n:wifi名称;p:dd666666
            var value = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
            SetWifi(value);
        }

        /// <summary>
        /// 设置Wifi持久化
        /// </summary>
        /// <param name="value"></param>
        public static void SetWifi(string value)
        {
            var wifiValue = value.Split(';');
            if (wifiValue.Length > 1)
            {
                // 如果不是wifi配置则跳过
                if (wifiValue[0].StartsWith("n:"))
                {
                    var name = wifiValue[0].Substring(2);
                    var password = wifiValue[1].Substring(2);
                    if (password.Length > 0)
                    {
                        ConfigHelper.SetWifi(value);

                        try
                        {
                            CancellationTokenSource cs = new(60000);
                            var success = WifiNetworkHelper.ConnectDhcp(name, password, requiresDateTime: true, token: cs.Token);

                            Debug.WriteLine("链接WIFI成功");
                        }
                        catch (Exception)
                        {
                            Debug.WriteLine("尝试链接WiFi失败");
                        }
                    }
                }


            }

        }


        public struct WifiModule
        {
            public string Name { get; set; }

            public string Password { get; set; }
        }
    }

    public class ConfigHelper
    {
        private const string WifiName = "I:\\Wifi.ini";

        public static void SetWifi(string value)
        {
            var buffer = Encoding.UTF8.GetBytes(value);
            var file = File.Exists(WifiName) ? new FileStream(WifiName, FileMode.Open, FileAccess.Write) : File.Create(WifiName);
            file.Write(buffer, 0, buffer.Length);
            file.Close();
        }

        public static WifiModule GetWifi()
        {
            if (File.Exists(WifiName))
            {
                var file = new FileStream(WifiName, FileMode.Open, FileAccess.Read);
                if (file.Length > 0)
                {

                    var bytes = new byte[file.Length];
                    file.Read(bytes, 0, bytes.Length);
                    file.Close();
                    var value = Encoding.UTF8.GetString(bytes, 0, bytes.Length);

                    var wifiValue = value.Split(';');
                    if (wifiValue.Length > 1)
                    {
                        var name = wifiValue[0].Substring(2);
                        var password = wifiValue[1].Substring(2);
                        return new WifiModule
                        {
                            Name = name,
                            Password = password,
                        };
                    }
                }
                file.Close();
            }

            return new WifiModule { Name = null, Password = null };
        }
    }
}

上面是所有的代码,下面将一步一步的讲解

当我们接收到信息的时候会触发_readWriteCharacteristic_WriteRequested的事件_readWriteCharacteristic_WriteRequested的代码如下,第一步先读取数据,然后接收读,在得到数据转换字符串,通过调用SetWifi方法去解析设置WIFI

            GattWriteRequest request = WriteRequestEventArgs.GetRequest();
            var size = request.Value.Length;
            // 从缓冲区解包数据
            DataReader rdr = DataReader.FromBuffer(request.Value);
            var buffer = new byte[request.Value.Length];
            rdr.ReadBytes(buffer);

            // 如果Write需要响应,则响应
            if (request.Option == GattWriteOption.WriteWithResponse)
            {
                request.Respond();
            }

            // 定义设置密码格式 n:wifi名称;p:dd666666
            var value = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
            SetWifi(value);

SetWifi,这里是用于解析数据格式并且处理持久化和链接WIFI,wifi的格式也是规范好的n:wifi名称;p:WiFi密码,不使用json格式从而减少包的依赖。

        /// <summary>
        /// 设置Wifi持久化
        /// </summary>
        /// <param name="value"></param>
        public static void SetWifi(string value)
        {
            var wifiValue = value.Split(';');
            if (wifiValue.Length > 1)
            {
                // 如果不是wifi配置则跳过
                if (wifiValue[0].StartsWith("n:"))
                {
                    var name = wifiValue[0].Substring(2);
                    var password = wifiValue[1].Substring(2);
                    if (password.Length > 0)
                    {
                        ConfigHelper.SetWifi(value);

                        try
                        {
                            CancellationTokenSource cs = new(60000);
                            var success = WifiNetworkHelper.ConnectDhcp(name, password, requiresDateTime: true, token: cs.Token);

                            Debug.WriteLine("链接WIFI成功");
                        }
                        catch (Exception)
                        {
                            Debug.WriteLine("尝试链接WiFi失败");
                        }
                    }
                }


            }

        }

ConfigHelper则是操作文件将wifi的配置持久化,nanoframework的文件系统默认是I,文件路径则是I:\\Wifi.ini这样就可以将数据持久化了。

    public class ConfigHelper
    {
        private const string WifiName = "I:\\Wifi.ini";

        public static void SetWifi(string value)
        {
            var buffer = Encoding.UTF8.GetBytes(value);
            var file = File.Exists(WifiName) ? new FileStream(WifiName, FileMode.Open, FileAccess.Write) : File.Create(WifiName);
            file.Write(buffer, 0, buffer.Length);
            file.Close();
        }

        public static WifiModule GetWifi()
        {
            if (File.Exists(WifiName))
            {
                var file = new FileStream(WifiName, FileMode.Open, FileAccess.Read);
                if (file.Length > 0)
                {

                    var bytes = new byte[file.Length];
                    file.Read(bytes, 0, bytes.Length);
                    file.Close();
                    var value = Encoding.UTF8.GetString(bytes, 0, bytes.Length);

                    var wifiValue = value.Split(';');
                    if (wifiValue.Length > 1)
                    {
                        var name = wifiValue[0].Substring(2);
                        var password = wifiValue[1].Substring(2);
                        return new WifiModule
                        {
                            Name = name,
                            Password = password,
                        };
                    }
                }
                file.Close();
            }

            return new WifiModule { Name = null, Password = null };
        }
    }

下面是程序运行的效果

效果

这样就可以动态配置WIFI了,也可以用蓝牙做设备的初始化。

介绍Nanoframework

.NET nanoFramework是一个免费且开源的平台,可以用于编写针对受限嵌入式设备的托管代码应用程序。它适用于多种类型的项目,包括物联网传感器、可穿戴设备、学术概念验证、机器人技术、爱好者/创客创作甚至复杂的工业设备。它通过为嵌入式开发人员提供桌面应用程序开发人员使用的现代技术和工具,使这些平台的开发更加简单、快速和成本更低。

开发人员可以利用强大且熟悉的Microsoft Visual Studio集成开发环境和他们对.NET C#的了解,快速编写代码,无需担心微控制器的底层硬件细节。桌面.NET开发人员将感到“如在家中”,并能够在嵌入式系统开发中运用他们的技能,扩大合格的嵌入式开发人员的队伍。

它包括了.NET通用语言运行时(CLR)的精简版本,并配备了.NET基类库的子集,以及包含在.NET IoT中的最常用API,允许从.NET IoT应用程序中重用代码、数以千计的代码示例和开源项目。使用Microsoft Visual Studio,开发人员可以直接在真实硬件上部署和调试代码。

.NET nanoFramework平台在.NET Micro Framework的基础上进行了扩展,并使用了其中的一些构建模块。许多原始组件被完全重写,其他组件得到改进,还有一些组件被简单地重用。进行了大量的代码清理和改进,使.NET nanoFramework适应未来发展!

技术交流

如果你也对Nanoframework感兴趣的话可以联系wx:wk28u9123456789并且备注Nanoframework就可以加入Nanoframework中文社区交流群,由于群人数过多不能使用二维码加入敬请谅解!

来自token的分享

与Nanoframework 操作单片机蓝牙配置WIFI的案例相似的内容:

Nanoframework 操作单片机蓝牙配置WIFI的案例

# Nanoframework 操作单片机蓝牙配置WIFI的案例 通过`Nanoframework`的蓝牙配置Wifi的名称和密码 下面是基本需要的工具 1. ESP32设备一个 需要支持蓝牙和wifi,一般情况的ESP32都支持wifi和蓝牙,当前教程使用的ESP32的接口是`Type-C` 设备

.NET周报 【6月第1期 2023-06-04】

## 专题 - NanoFramework项目案例 如果有时间,我会在周报中加入一些专题和项目案例的分享,本周就是讨论.NET NanoFramework项目案例的专题,在讨论 NanoFramework 的典型案例之前,让我们先回顾一下 .NET 在嵌入式领域的历史。 2007年,.NET Mic

【Nano Framework ESP32篇】使用 LCD 屏幕

在开始主题之前,先介绍一个刷固件工具。这个工具在 idf 中是集成的,不过,乐鑫也单独发布了这个工具—— esptool。下载链接:Releases · espressif/esptool · GitHub。这货是用 Python 写的,只是封装成了 exe,方便直接运行罢了。 在使用时,需要 -p

【Nano Framework ESP32篇】WS2812 彩色灯带实验

地球人皆知,许多物联网教程作者的心中都深爱着一灯大师,所以第一个例程总喜欢点灯,高级一点的会来个“一闪一闪亮晶晶”。老周今天要扯的也是和灯有关的,但不单纯地点个灯,那样实在不好玩,缺乏乐趣。老周打算舞个龙灯,哦不,是用 LED 彩色灯带给伙伴们整点炫酷乐子。 说到这LED彩灯,咱们常见到的有两类: