Skip to content

Commit 2cd2930

Browse files
authored
Improv bluetooth sample (#223)
1 parent db1e7e7 commit 2cd2930

File tree

8 files changed

+906
-0
lines changed

8 files changed

+906
-0
lines changed

samples/Bluetooth/ImprovWifi/Improv.cs

+552
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="Current" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup Label="Globals">
4+
<NanoFrameworkProjectSystemPath>$(MSBuildExtensionsPath)\nanoFramework\v1.0\</NanoFrameworkProjectSystemPath>
5+
</PropertyGroup>
6+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.Default.props')" />
7+
<PropertyGroup>
8+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
9+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
10+
<ProjectTypeGuids>{11A8DD76-328B-46DF-9F39-F559912D0360};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
11+
<ProjectGuid>05f3cc2c-5074-44f9-9437-40a9f0268a57</ProjectGuid>
12+
<OutputType>Exe</OutputType>
13+
<AppDesignerFolder>Properties</AppDesignerFolder>
14+
<FileAlignment>512</FileAlignment>
15+
<RootNamespace>ImprovWifi</RootNamespace>
16+
<AssemblyName>ImprovWifi</AssemblyName>
17+
<TargetFrameworkVersion>v1.0</TargetFrameworkVersion>
18+
</PropertyGroup>
19+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.props" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.props')" />
20+
<ItemGroup>
21+
<Compile Include="Improv.cs" />
22+
<Compile Include="Program.cs" />
23+
<Compile Include="Properties\AssemblyInfo.cs" />
24+
</ItemGroup>
25+
<ItemGroup>
26+
<Reference Include="mscorlib">
27+
<HintPath>packages\nanoFramework.CoreLibrary.1.12.0\lib\mscorlib.dll</HintPath>
28+
</Reference>
29+
<Reference Include="nanoFramework.Device.Bluetooth, Version=1.0.2.4, Culture=neutral, PublicKeyToken=c07d481e9758c731">
30+
<HintPath>packages\nanoFramework.Device.Bluetooth.1.0.2.4\lib\nanoFramework.Device.Bluetooth.dll</HintPath>
31+
<Private>True</Private>
32+
<SpecificVersion>True</SpecificVersion>
33+
</Reference>
34+
<Reference Include="nanoFramework.Runtime.Events, Version=1.10.0.3, Culture=neutral, PublicKeyToken=c07d481e9758c731">
35+
<HintPath>packages\nanoFramework.Runtime.Events.1.10.0\lib\nanoFramework.Runtime.Events.dll</HintPath>
36+
<Private>True</Private>
37+
<SpecificVersion>True</SpecificVersion>
38+
</Reference>
39+
<Reference Include="nanoFramework.Runtime.Native, Version=1.5.4.3, Culture=neutral, PublicKeyToken=c07d481e9758c731">
40+
<HintPath>packages\nanoFramework.Runtime.Native.1.5.4\lib\nanoFramework.Runtime.Native.dll</HintPath>
41+
<Private>True</Private>
42+
<SpecificVersion>True</SpecificVersion>
43+
</Reference>
44+
<Reference Include="nanoFramework.System.Collections, Version=1.4.0.3, Culture=neutral, PublicKeyToken=c07d481e9758c731">
45+
<HintPath>packages\nanoFramework.System.Collections.1.4.0\lib\nanoFramework.System.Collections.dll</HintPath>
46+
<Private>True</Private>
47+
<SpecificVersion>True</SpecificVersion>
48+
</Reference>
49+
<Reference Include="nanoFramework.System.Text, Version=1.1.3.3, Culture=neutral, PublicKeyToken=c07d481e9758c731">
50+
<HintPath>packages\nanoFramework.System.Text.1.1.3\lib\nanoFramework.System.Text.dll</HintPath>
51+
<Private>True</Private>
52+
<SpecificVersion>True</SpecificVersion>
53+
</Reference>
54+
<Reference Include="System.Device.Wifi, Version=1.4.0.16, Culture=neutral, PublicKeyToken=c07d481e9758c731">
55+
<HintPath>packages\nanoFramework.System.Device.Wifi.1.4.0.16\lib\System.Device.Wifi.dll</HintPath>
56+
<Private>True</Private>
57+
<SpecificVersion>True</SpecificVersion>
58+
</Reference>
59+
<Reference Include="System.IO.Streams, Version=1.0.0.2, Culture=neutral, PublicKeyToken=c07d481e9758c731">
60+
<HintPath>packages\nanoFramework.System.IO.Streams.1.0.0\lib\System.IO.Streams.dll</HintPath>
61+
<Private>True</Private>
62+
<SpecificVersion>True</SpecificVersion>
63+
</Reference>
64+
<Reference Include="System.Net, Version=1.9.0.1, Culture=neutral, PublicKeyToken=c07d481e9758c731">
65+
<HintPath>packages\nanoFramework.System.Net.1.9.0.1\lib\System.Net.dll</HintPath>
66+
<Private>True</Private>
67+
<SpecificVersion>True</SpecificVersion>
68+
</Reference>
69+
<Reference Include="System.Net.Http, Version=1.4.0.14, Culture=neutral, PublicKeyToken=c07d481e9758c731">
70+
<HintPath>packages\nanoFramework.System.Net.Http.1.4.0.14\lib\System.Net.Http.dll</HintPath>
71+
<Private>True</Private>
72+
<SpecificVersion>True</SpecificVersion>
73+
</Reference>
74+
<Reference Include="System.Threading, Version=1.0.4.3, Culture=neutral, PublicKeyToken=c07d481e9758c731">
75+
<HintPath>packages\nanoFramework.System.Threading.1.0.4\lib\System.Threading.dll</HintPath>
76+
<Private>True</Private>
77+
<SpecificVersion>True</SpecificVersion>
78+
</Reference>
79+
</ItemGroup>
80+
<ItemGroup>
81+
<None Include="packages.config" />
82+
<None Include="README.md" />
83+
</ItemGroup>
84+
<Import Project="$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets" Condition="Exists('$(NanoFrameworkProjectSystemPath)NFProjectSystem.CSharp.targets')" />
85+
<ProjectExtensions>
86+
<ProjectCapabilities>
87+
<ProjectConfigurationsDeclaredAsItems />
88+
</ProjectCapabilities>
89+
</ProjectExtensions>
90+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.1.32210.238
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{11A8DD76-328B-46DF-9F39-F559912D0360}") = "ImprovWifi", "ImprovWifi.nfproj", "{05F3CC2C-5074-44F9-9437-40A9F0268A57}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{05F3CC2C-5074-44F9-9437-40A9F0268A57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{05F3CC2C-5074-44F9-9437-40A9F0268A57}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{05F3CC2C-5074-44F9-9437-40A9F0268A57}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
17+
{05F3CC2C-5074-44F9-9437-40A9F0268A57}.Release|Any CPU.ActiveCfg = Release|Any CPU
18+
{05F3CC2C-5074-44F9-9437-40A9F0268A57}.Release|Any CPU.Build.0 = Release|Any CPU
19+
{05F3CC2C-5074-44F9-9437-40A9F0268A57}.Release|Any CPU.Deploy.0 = Release|Any CPU
20+
EndGlobalSection
21+
GlobalSection(SolutionProperties) = preSolution
22+
HideSolutionNode = FALSE
23+
EndGlobalSection
24+
GlobalSection(ExtensibilityGlobals) = postSolution
25+
SolutionGuid = {C61ACCD8-F5E9-43E8-B395-F743874A7359}
26+
EndGlobalSection
27+
EndGlobal
+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using System;
2+
using System.Threading;
3+
using System.Net;
4+
5+
/// <summary>
6+
/// Improv provisioning sample
7+
/// For details about Improv protocol and to try provisioning Wifi credentials from a web page
8+
/// See: https://www.improv-wifi.com/
9+
/// Also has instructions on how to embed into your web page.
10+
/// </summary>
11+
12+
namespace ImprovWifi
13+
{
14+
public class Program
15+
{
16+
static Improv _imp;
17+
18+
public static void Main()
19+
{
20+
Console.WriteLine("Example of using IMPROV bluetooth LE for Wifi provisioning");
21+
22+
// Construct Improv class
23+
_imp = new Improv();
24+
25+
// This optional event will be fired if asked to identify device
26+
// You can flash an LED or some other method.
27+
_imp.OnIdentify += Imp_OnIdentify;
28+
29+
// This optional event is called when the provisioning is completed and Wifi is connected but before
30+
// improv has informed Improv client of result. This allows user to set the provision URL redirect with correct IP address
31+
// See event handler
32+
_imp.OnProvisioningComplete += Imp_OnProvisioningComplete;
33+
34+
// This optional event will be called to do the Wifi provisioning in user program.
35+
// if not set then improv class will automatically try to connect to Wifi
36+
// For this sample we will let iprov do it, uncomment next line to try user event. See event handler
37+
// imp.OnProvisioned += Imp_OnProvisioned;
38+
39+
// Start IMPROV service to start advertising using provided device name.
40+
_imp.Start("Improv sample");
41+
42+
// You may need a physical button to be pressed to authorise the provisioning (security)
43+
// Wait for button press and call Authorise method
44+
// For out test we will just Authorise
45+
_imp.Authorise(true);
46+
47+
Console.WriteLine("Waiting for device to be provisioned");
48+
49+
// Now wait for Device to be Provisioned
50+
// we could also just use the OnProvisioningComplete event
51+
while (_imp.CurrentState != Improv.ImprovState.provisioned)
52+
{
53+
Thread.Sleep(500);
54+
}
55+
56+
Console.WriteLine("Device has been provisioned");
57+
58+
// We are now provisioned and connected to Wifi, so stop bluetooth service to release resources.
59+
_imp.Stop();
60+
_imp = null;
61+
;
62+
63+
// Start our very simple web page server to pick up the redirect we gave
64+
Console.WriteLine("Starting simple web server");
65+
SimpleWebListener();
66+
67+
Thread.Sleep(Timeout.Infinite);
68+
}
69+
70+
/// <summary>
71+
/// Event handler for OnProvisioningComplete event
72+
/// </summary>
73+
/// <param name="sender">Improv instance</param>
74+
/// <param name="e">Not used</param>
75+
private static void Imp_OnProvisioningComplete(object sender, EventArgs e)
76+
{
77+
SetProvisioningURL();
78+
}
79+
80+
/// <summary>
81+
/// Set URL with current IP address
82+
/// The Improv client will redirect to this URL if set.
83+
/// </summary>
84+
private static void SetProvisioningURL()
85+
{
86+
// All good, wifi connected, set up URL for access
87+
_imp.RedirectUrl = "http://" + _imp.GetCurrentIPAddress() + "/start.htm";
88+
}
89+
90+
private static void Imp_OnProvisioned(object sender, ProvisionedEventArgs e)
91+
{
92+
string ssid = e.Ssid;
93+
string password = e.Password;
94+
95+
Console.WriteLine("Provisioning device");
96+
97+
Console.WriteLine("Connecting to Wifi...");
98+
99+
// Try to connect to Wifi AP
100+
// use improv internal method
101+
if (_imp.ConnectWiFi(ssid, password))
102+
{
103+
Console.WriteLine("Connected to Wifi");
104+
105+
SetProvisioningURL();
106+
}
107+
else
108+
{
109+
Console.WriteLine("Failed to Connect to Wifi!");
110+
111+
// if not successful set error and return
112+
_imp.ErrorState = Improv.ImprovError.unableConnect;
113+
}
114+
}
115+
116+
private static void Imp_OnIdentify(object sender, EventArgs e)
117+
{
118+
// Flash LED to Identify device or do nothing
119+
Console.WriteLine("Flashing LED...");
120+
}
121+
122+
private static void SimpleWebListener()
123+
{
124+
// set-up our HTTP response
125+
string responseString =
126+
"<HTML><BODY>" +
127+
"<h2>Hello from nanoFramework</h2>" +
128+
"<p>We are a newly provisioned device using <b>Improv</b> over Bluetooth.</p>" +
129+
"<p>See <a href='https://www.improv-wifi.com'>Improv web site</a> for details" +
130+
"</BODY></HTML>";
131+
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
132+
133+
// Create a listener.
134+
HttpListener listener = new("http", 80);
135+
136+
listener.Start();
137+
138+
while (true)
139+
{
140+
try
141+
{
142+
// Now wait on context for a connection
143+
HttpListenerContext context = listener.GetContext();
144+
145+
Console.WriteLine("Web request received");
146+
147+
// Get the response stream
148+
HttpListenerResponse response = context.Response;
149+
150+
// Write reply
151+
response.ContentLength64 = buffer.Length;
152+
response.OutputStream.Write(buffer, 0, buffer.Length);
153+
154+
// output stream must be closed
155+
context.Response.Close();
156+
157+
Console.WriteLine("Web response sent");
158+
159+
// context must be closed
160+
context.Close();
161+
}
162+
catch (Exception ex)
163+
{
164+
Console.WriteLine("* Error getting context: " + ex.Message + "\r\nSack = " + ex.StackTrace);
165+
}
166+
}
167+
}
168+
}
169+
}
170+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("CSharp.BlankApplication")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("CSharp.BlankApplication")]
13+
[assembly: AssemblyCopyright("Copyright © ")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// Version information for an assembly consists of the following four values:
23+
//
24+
// Major Version
25+
// Minor Version
26+
// Build Number
27+
// Revision
28+
//
29+
// You can specify all the values or you can default the Build and Revision Numbers
30+
// by using the '*' as shown below:
31+
// [assembly: AssemblyVersion("1.0.*")]
32+
[assembly: AssemblyVersion("1.0.0.0")]
33+
[assembly: AssemblyFileVersion("1.0.0.0")]
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Improv Wifi provisioning
2+
3+
This sample shows the use of the *Improv class* to provision the Wifi credentials for an ESP32 device via Bluetooth LE.
4+
5+
The device will advertise with the name "Improv sample" and support the *Improv Service* allowing the Wifi Credentials to be setup directly from the Improv test page.
6+
or any other web page.
7+
8+
This is an initial working version of the *Improv* class showing what can be done.
9+
Probably later this class can be moved to a separate repo, so it has its own nuGet package to make it easy to consume by applications.
10+
11+
*Improv* is a free open standard which allows the device to be provisioned directly from a web page.
12+
This works for Chrome and Edge browsers.
13+
14+
For more information on the *Improv* standard and a test page, see: <https://www.improv-wifi.com/>
15+
See <https://www.improv-wifi.com/code/> for details on including it into other web pages.
16+
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="nanoFramework.CoreLibrary" version="1.12.0" targetFramework="netnanoframework10" />
4+
<package id="nanoFramework.Device.Bluetooth" version="1.0.2.4" targetFramework="netnanoframework10" />
5+
<package id="nanoFramework.Runtime.Events" version="1.10.0" targetFramework="netnanoframework10" />
6+
<package id="nanoFramework.Runtime.Native" version="1.5.4" targetFramework="netnanoframework10" />
7+
<package id="nanoFramework.System.Collections" version="1.4.0" targetFramework="netnanoframework10" />
8+
<package id="nanoFramework.System.Device.Wifi" version="1.4.0.16" targetFramework="netnanoframework10" />
9+
<package id="nanoFramework.System.IO.Streams" version="1.0.0" targetFramework="netnanoframework10" />
10+
<package id="nanoFramework.System.Net" version="1.9.0.1" targetFramework="netnanoframework10" />
11+
<package id="nanoFramework.System.Net.Http" version="1.4.0.14" targetFramework="netnanoframework10" />
12+
<package id="nanoFramework.System.Text" version="1.1.3" targetFramework="netnanoframework10" />
13+
<package id="nanoFramework.System.Threading" version="1.0.4" targetFramework="netnanoframework10" />
14+
</packages>

samples/Bluetooth/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Currently only support on ESP32 devices running either the ESP32_BLE_REV0, ESP32
88
On other firmware versions a not supported exception will be returned.
99

1010
## Samples
11+
* [Bluetooth Low energy Improv sample](ImprovWifi)
12+
Provision device directly from a web page using *Improv* standard.
13+
See sample readme for more information.
1114

1215
* [Bluetooth Low energy serial](BluetoothLESerial)
1316
Shows how to use the built-in SSP(Serial Service Profile) which simulates a serial link over Bluetooth. Use a phone app.

0 commit comments

Comments
 (0)