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. ES6中的解构赋值(数组,对象,嵌套,默认值)

    解构赋值 通过解构赋值,可以快速从对象或者数组中取出属性或者数值. 解构赋值 可以通过定位到数组或者对象的某一个位置,将值直接赋给一个或多个变量. const arr = ['dasha', 'ers ...

  2. Vue 路由导航守卫

    Vue 路由导航守卫 一:全局守卫 (1) router.beforeEach beforeEach((to, from, next) => {}) 接收三个参数,在路由切换成功之前调用 to ...

  3. kubernetes(k8s)安装BGP模式calico网络支持IPV4和IPV6

    kubernetes(k8s)安装BGP模式calico网络支持IPV4和IPV6 BGP是互联网上一个核心的去中心化自治路由协议,它通过维护IP路由表或"前缀"表来实现自治系统A ...

  4. sqlite3使用2

    一. 在cmd中打开SQLite 1.进入数据库 通过输入 d:cd D:\--\SQLitesqlite3 进入数据库 查看数据库的基本信息: .help 显示各种重要的SQLite点命令的列表.s ...

  5. python入门教程之二十三Python3 MySQL 数据库连接 - PyMySQL 驱动

    MySQL 是最流行的关系型数据库管理系统,如果你不熟悉 MySQL,可以阅读我们的 MySQL 教程. 本章节我们为大家介绍使用 mysql-connector 来连接使用 MySQL, mysql ...

  6. [网络]公共网络安全漏洞库: CVE / CNCVE

    本文博主的经历与该博文处理绿盟科技安全评估的系统漏洞 - 博客园的经历相同: 处理[第三方网络安全公司]给[公司产品]的[客户的服务器]扫描后生成的[安全漏洞报告]. 1 前言 以网络安全行业中最大的 ...

  7. [Web服务容器/Apache Tomcat]WINDOWS系统下:一台机器部署多个[解压版]Tomcat

    以windows为例. 1 思路 1.1 前置条件 已成功配置JDK (JAVA_HOME / Path) 控制面板>所有控制面板项>系统>高级系统设置>系统变量(S): JA ...

  8. day30:TCP&UDP:socket

    目录 1.TCP协议和UDP协议 2.什么是socket? 3.socket正文 1.TCP基本语法 2.TCP循环发消息 3.UDP基本语法 4.UDP循环发消息 4.黏包 5.解决黏包问题 1.解 ...

  9. 你真的懂synchronized锁?

    1. 前言 synchronized在我们的程序中非常的常见,主要是为了解决多个线程抢占同一个资源.那么我们知道synchronized有多种用法,以下从实践出发,题目由简入深,看你能答对几道题目? ...

  10. Java 的 SPI 机制

    什么是SPI机制? SPI机制( Service Provider Interface)是Java的一种服务发现机制,为了方便应用扩展.那什么是服务发现机制?简单来说,就是你定义了一个接口,但是不提供 ...