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的案例的更多相关文章

  1. 树莓派3启动wifi并且配置wifi

    概述 树莓派3内置了wifi和蓝牙模块,我们不用像以前的版本那样,再去购买一个外接的模块练到raspberry上. 当我们第一次启动了树莓派的时候,必然使用了网线,但是之后的每一次使用,我们当然更希望 ...

  2. ESP32那些事儿(六):功能开发之蓝牙及WiFi功能

    蓝牙和WIFI是ESP32的核心功能,蓝牙和wifi的共存也是esp32的独门武功,但时候后续也会发现共存的时候会有很多问题.不管怎样,蓝牙和wifi在esp-idf中有很多的例子,大家都可以参考.本 ...

  3. 移植wpa_supplicant2.5及界面配置wifi(原创)

    JP5G开发机上需要图形界面配置 wifi网络,为此移植了wpa_supplicant2.5. 1.参考wpa_supplicant-2.5移植与使用l http://blog.csdn.net/hk ...

  4. vim常用操作技巧与配置

    vi是linux与unix下的常用文本编辑器,其运行稳定,使用方便,本文将分两部分对其常用操作技巧和配置进行阐述,其中参考了网上的一些文章,对作者表示感谢 PART1 操作技巧 说明: 以下的例子中  ...

  5. linux配置wifi连接并通过ssh代理开启socks代理

    1, 命令行配置连接wifi具体我是用的cubieboard2上Debian主机,其中配置wifi的命令行有wpa_cli,具体用法步骤如下.wpa_cli 命令行执行需要root权限,详细用法请见 ...

  6. LVS+Keepalived实现MySQL从库读操作负载均衡配置

    转载于osyunwei 说明: 操作系统:CentOS 5.X 64位 MySQL主服务器:192.168.21.126 MySQL从服务器:192.168.21.127,192.168.21.128 ...

  7. 用rfkill命令管理蓝牙和wifi

    rfkill是一个内核级别的管理工具,可以打开和关闭设备的蓝牙和wifi. #列出所有可用设备rfkill list 输出如下:0: phy0: Wireless LAN    Soft blocke ...

  8. #51单片机#蓝牙模块(ATK-SPP-HC06从机串口)的使用方法

    #include <AT89X51.H> #include <intrins.h> // 函数原形定义 #define uchar unsigned char #define ...

  9. Arduino 基于 ESP8266 配置WIFI模块

    Arduino 基于 ESP8266 配置WIFI模块 使用ESP8266作为服务器,使用浏览器访问该服务器,从而控制LED灯 选择 [文件]->[示例]->[ESP8266WIFI]-& ...

  10. linux 配置网卡、远程拷贝文件、建立软硬链接、打包/解包、压缩/解压缩、包操作、yum配置使用、root密码忘记

    目录 一.配置网卡 二.xshell连接 三.远程拷贝文件 四.建立软硬连接 五.打包/解包和压缩/解压缩 六.包操作 七.配置yum源 配置yum源 配置阿里云源 常用命令 yum其他命令 八.重置 ...

随机推荐

  1. 机器学习基础05DAY

    分类算法之k-近邻 k-近邻算法采用测量不同特征值之间的距离来进行分类 优点:精度高.对异常值不敏感.无数据输入假定 缺点:计算复杂度高.空间复杂度高 使用数据范围:数值型和标称型 一个例子弄懂k-近 ...

  2. mixins使用混入引入组件,并可以使用公共函数。组件类同名函数可以替代公共函数。使用$ref获得子元素数据和元素dom节点。使用$parents获得父元素数据。slot插槽的使用

    父组件: <template> <div class="box"> <Header > <div slot="left" ...

  3. go微服务框架kratos学习笔记三(构建单独的http或者grpc demo项目)

    go微服务框架kratos学习笔记三(构建单独的http或者grpc demo项目) 前面两篇跑通了demo项目,和大概了解了kratos demo整体结构,本篇分别构建一个http和一个grpc微服 ...

  4. 基于SqlSugar的开发框架循序渐进介绍(25)-- 基于SignalR实现多端的消息通讯

    基于ASP.NET Core SignalR 可以实现客户端和服务器之间进行即时通信.本篇随笔介绍一些SignalR的基础知识,以及结合对SqlSugar的开发框架的支持,实现SignalR的多端处理 ...

  5. Redis 数据类型 Zset

    Redis 数据类型 Zset(有序集合) Redis 常用命令,思维导图 >>> zset是Redis提供的一个非常特别的数据结构,常用作排行榜等功能,以用户id为value,关注 ...

  6. TS(一)环境搭建与基本类型

    1 TypeScript 环境搭建 1 准备NodeJs环境 2 npm全局安装typeScript npm i -g typescript 3 编写一个ts文件 4 使用tsc命令编译ts文件为js ...

  7. 基于sanic和爬虫创建的代理ip池

    搭建免费的代理ip池 需要解决的问题: 使用什么方式存储ip 文件存储 缺点: 打开文件修改文件操作较麻烦 mysql 缺点: 查询速度较慢 mongodb 缺点: 查询速度较慢. 没有查重功能 re ...

  8. PYTHON数据分析——python基础

    利用命令行创建python文件 C:\Users\Your Name>python myfile.py Python 变量命名规则: 变量名必须以字母或下划线字符开头 变量名称不能以数字开头 变 ...

  9. Linux云计算运维工程师day29软件安装

    1.  diff(文本比较) [root@guosaike ~]# cp /etc/passwd{,.ori}备份 [root@guosaike ~]# diff /etc/passwd{,.ori} ...

  10. Python-tomorrow应用于UI自动化的简单使用

    一.简介 tomorrow属于第三方的一个模块,使用threads方法作为装饰器去修饰一个普通的函数,使其可以达到并发效果.使用起来非常简单. 二.安装 pip install tomorrow 使用 ...