(For more resources related to this topic, see here.)
Why Bluetooth?
There are other forms of wireless communication that we could use, like infrared and Wi-Fi, but Bluetooth is perfect for many household projects. It is cheap, very easy to set up, will typically use less power than Wi-Fi because of the shorter range, and it’s very responsive.
It’s important to keep in mind that there isn’t a single “best” form of communication. Each type will suit each project (or perhaps budget) in different ways.
In terms of performance, I have found that a short message will be transmitted in under 20 milliseconds from one device to another, and the signal will work for just less than 10 meters (30 feet). These numbers, however, will vary based on your environment.
Things you need
The things required for this project are as follows:
- Netduino
- Breadboard
- Bluetooth module
- Windows Phone 8
Lots of different Bluetooth modules exist, but I have found that the JY-MCU is very cheap (around $10) and reliable. Any Windows Phone 8 device can be used, as they all have Bluetooth.
The project setup
The setup for this project is extremely basic because we are just connecting the Bluetooth module and nothing else. Once our phone is connected we will use it to control the onboard LED, however, you can expand this to control anything else too. The Bluetooth module you buy may look slightly different to the diagram, but not to worry, just make sure you match up the labels on the Bluetooth module (GND, 3-3V or VCC, TX, and RX) to the diagram.
If you encounter a situation where everything is hooked up right but no data is flowing, examine the minimum baud rate in your Bluetooth module’s manual or specifications sheet. It has been reported that some Bluetooth modules do not work well communicating at 9600 baud. This can be easily remedied by setting the baud rate in your SerialPort’s constructor to 115200. For example, SerialPort(new SerialPort(SerialPorts.COM1, 115200, Parity.None, 8, StopBits.One).
Once it is wired up, we can get onto the coding. First we will do the Netduino part. The Netduino will listen for messages over Bluetooth, and will set the brightness of the onboard LED based on the percentage it receives. The Netduino will also listen for “ping”, and if it receives this then it will send the same text back to the other device. We do this as an initial message to make sure that it gets from the phone to the Netduino, and then back to the phone successfully.
After that we will code the phone application. The phone will connect, send a “ping”, and then wait until it receives the “ping” back. When the phone receives the “ping” back then it can start sending messages.
In this article only Windows Phone 8 will be covered, however, the same concepts apply, and it won’t be too hard to code the equivalent app for another platform. The Netduino code will remain the same no matter what device you connect to.
Coding
Because we will be using a phone to connect to the Netduino, there are two distinct parts which need to be coded.
The Netduino code
- Open up Visual Studio and create a new Netduino Plus 2 Application.
- Add a reference to SecretLabs.NETMF.Hardware.PWM.
- Open Program.cs from the Solution Explorer. You need to add the following using statements at the top:
using System.IO.Ports;
using System.Text;
using NPWM = SecretLabs.NETMF.Hardware.PWM; - You need to get the phone paired with the Bluetooth module on the Netduino. So in Program.cs, replace the Main method with this:
private static SerialPort _bt;
public static void Main()
{
_bt = new SerialPort(SerialPorts.COM1, 9600,
Parity.None, 8, StopBits.One);
_bt.Open();
while (true)
{
Thread.Sleep(Timeout.Infinite);
}
}This code creates a new instance of a SerialPort (the Bluetooth module), then opens it, and finally has a loop (which will just pause forever).
- Plug in your Netduino and run the code. Give it a few seconds until the blue light goes off—at this point the Bluetooth module should have a flashing red LED. On your Windows Phone, go to Settings | Bluetooth and make sure that it is turned on. In the list of devices there should be one which is the Bluetooth module (mine is called “linvor”) so tap it to connect. If it asks for a pin try the default of “1234”, or check the data sheet. As it connects, the red LED on the Bluetooth module will go solid, meaning that it is connected. It will automatically disconnect in 10 seconds; that’s fine.
- Now that you’ve checked that it connects correctly, start adding in the real code:
private static SerialPort _bt;
private static NPWM _led;
private static string _buffer;
public static void Main()
{
_led = new NPWM(Pins.ONBOARD_LED);
_bt = new SerialPort(SerialPorts.COM1, 9600,
Parity.None, 8, StopBits.One);
_bt.DataReceived += new SerialDataReceivedEventHandler
(rec_DataReceived);
_bt.Open();
while (true)
{
Thread.Sleep(Timeout.Infinite);
}
}This is close to the code you replaced but also creates an instance of the onboard LED, and declares a string to use as a buffer for the received data.
- Next you need to create the event handler that will be fired when data is received. Something that can easily trip you up is thinking that each message will come through as a whole. That’s incorrect. So if you send a “ping” from your phone, it will usually come through in two separate messages of “p” and “ing”. The simplest way to work around that is to just have a delimiter that marks the end of a message (in the same way as military personnel end radio communications by saying “10-4”). So send the message as “ping|” with a pipe at the end. This code for the DataReceived event handler builds up a buffer until it finds a pipe (|), then processes the message, then resets the buffer (or sets it to whatever is after the pipe, which will be the first part of the next message):
private static void rec_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
byte[] bytes = new byte[_bt.BytesToRead];
_bt.Read(bytes, 0, bytes.Length);
char[] converted = new char[bytes.Length];
for (int b = 0; b < bytes.Length; b++)
{
converted[b] = (char)bytes[b];
}
string str = new String(converted);
if (str != null && str.Length > 0)
{
if (str.IndexOf("|") > -1)
{
_buffer += str.Substring(0, str.IndexOf("|"));
ProcessReceivedString(_buffer);
_buffer = str.Substring(str.LastIndexOf("|") +
1);
}
else
{
_buffer += str;
}
}
}At the start of the event handler, you create a byte array to hold the received data, then loop through that array and convert each byte to a char and put those chars into a char array. Once you have a char array, create a new string using the char array as a parameter, which will give the string representation of the array. After checking that it is not null or empty you check whether it has a pipe (meaning it contains the end of a message). If so, add all the characters up to the pipe onto the buffer and then process the buffer. If there is no pipe then just add to the buffer.
- The only thing that remains is the method to process the received string (the buffer) and a method to send messages back to the phone. So put these methods below the event handler that you just added:
private static void ProcessReceivedString(string _buffer)
{
if (_buffer == "ping")
{
Write(_buffer);
}
else
{
uint val = UInt32.Parse(_buffer);
_led.SetDutyCycle(val);
}
}
private static void Write(string message)
{
byte[] bytes = Encoding.UTF8.GetBytes(message + "|");
_bt.Write(bytes, 0, bytes.Length);
}As mentioned before, if you receive a “ping” then just send it back, or alternatively convert the string into an unsigned integer and set the brightness of the onboard LED.
The last method simply adds a pipe to the end of the string, converts it to a byte array, then writes it to the Bluetooth SerialPort to send to the phone.
At this point, you should run the code on the Netduino, but keep in mind that the same thing as before will happen because we are not sending it any data yet.
So next up, we need to make the phone application that helps us send messages to the Netduino.
The phone code
As mentioned, we will be using a Windows Phone 8 device to connect to the Netduino. The same principles demonstrated in this section will apply to any platform, and it all revolves around just knowing how to read and write the Bluetooth data. You may notice that much of the phone code resembles the Netduino code—this is because both are merely sending and receiving messages.
Before moving on, you will need the Windows Phone 8 SDK installed. Download and install it from here: http://developer.windowsphone.com
You may need to close any copies of Visual Studio that are open. Once it is installed you can go ahead and open the Netduino project (from the previous section) again, then follow these steps:
- We could create the phone project in the same solution as the Netduino project, but in terms of debugging, it’s easier to have them in separate instances of Visual Studio. So open up another copy of Visual Studio and click on File | New | Project. Find the Windows Phone App template by navigating to Installed | Templates | Visual C# | Windows Phone. Name the project and then click on OK to create it. A dialog may appear asking you to choose which version of the OS you would like to target. Make sure that Windows Phone OS 8.0 is selected (Windows Phone 7.1 does not have the required APIs for third party developers).
- When creating a new Windows Phone application, MainPage.xaml will automatically be displayed. This is the first page of the app that the user will see when they run your app. XAML is the layout language used on Windows Phone, and if you’ve ever used HTML then you will be quite at home. In the XAML window, scroll down until you find the grid named ContentPanel. Replace it with:
<Grid x_Name="ContentPanel" Grid.Row="1"
Margin="12,0,12,0">
<Slider IsEnabled="False" Minimum="0" Maximum="100"
x:Name="slider" ValueChanged="slider_ValueChanged"/>
</Grid>This will add a Slider control to the page with the value at the far left being 0 and the far right being 100—essentially a percent. Whenever the user drags the slider, it will fire the ValueChanged event handler, which you will add soon.
- That is the only UI change you need to make. So in the Solution Explorer, right-click on MainPage.xaml | View Code. Add these Using statements to the top:
using Windows.Storage.Streams;
using System.Text;
using Windows.Networking.Sockets;
using Windows.Networking.Proximity;
using System.Runtime.InteropServices.WindowsRuntime;We need to declare some variables, so replace the MainPage constructor with this:
StreamSocket _socket;
string _receivedBuffer = "";
bool _isConnected = false;
public MainPage()
{
InitializeComponent();
TryConnect();
}
private void slider_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
if (_isConnected)
{
Write(((int)slider.Value).ToString());
}
}
async private void Write(string str)
{
var dataBuffer = GetBufferFromByteArray(Encoding.UTF8.
GetBytes(str + "|"));
await _socket.OutputStream.WriteAsync(dataBuffer);
}
private IBuffer GetBufferFromByteArray(byte[] package)
{
using (DataWriter dw = new DataWriter())
{
dw.WriteBytes(package);
return dw.DetachBuffer();
}
}The StreamSocket is essentially a way to interact with the phone’s Bluetooth chip, which will be used in multiple methods in the app. When the slider’s value changes, we check that the phone is connected to the Netduino, and then use the Write method to send the value. The Write method is similar to the one we made on the Netduino, except it requires a few lines extra to convert the byte array into an IBuffer.
- In the previous step, you might have noticed that we ran a method called TryConnect in the MainPage constructor. As you may have guessed, in this method we will try to connect to the Netduino. Add this method below the ones you added previously:
private async void TryConnect()
{
PeerFinder.AlternateIdentities["Bluetooth:Paired"] =
"";
var pairedDevices = await PeerFinder.
FindAllPeersAsync();
if (pairedDevices.Count == 0)
{
MessageBox.Show("Make sure you pair the device
first.");
}
else
{
SystemTray.SetProgressIndicator(this,
new ProgressIndicator { IsIndeterminate = true,
Text = "Connecting", IsVisible = true });
PeerInformation selectedDevice = pairedDevices[0];
_socket = new StreamSocket();
await _socket.ConnectAsync(selectedDevice.
HostName, "1");
WaitForData(_socket);
Write("ping");
}
}We first get a list of all devices that have been paired with the phone (even if they are not currently connected), and display an error message if there are no devices. If it does find one or more devices, then we display a progress bar at the top of the screen (in the SystemTray) and proceed to connect to the first Bluetooth device in the list. It is important to note that in the example code we are connecting to the first device in the list—in a real-world app, you would display the list to the user and let them decide which is the right device. After connecting, we call a method to wait for data to be received (this will happen in the background and will not block the rest of the code), and then write the initial ping message.
- Don’t worry, we are almost there! The second last method you need to add is the one that will wait for the data to be received. It is an asynchronous method, which means that it can have a line within it that blocks execution (for instance, in the following code the line that waits for data will block the thread), but the rest of the app will carry on fine. Add in this method:
async private void WaitForData(StreamSocket socket)
{
try
{
byte[] bytes = new byte[5];
await socket.InputStream.ReadAsync(bytes.
AsBuffer(), 5, InputStreamOptions.Partial);
bytes = bytes.TakeWhile((v, index) =>
bytes.Skip(index).Any(w => w != 0x00)).ToArray();
string str = Encoding.UTF8.GetString(bytes, 0,
bytes.Length);
if (str.Contains("|"))
{
_receivedBuffer += str.Substring(0,
str.IndexOf("|"));
DoSomethingWithReceivedString(_
receivedBuffer);
_receivedBuffer = str.Substring(str.
LastIndexOf("|") + 1);
}
else
{
_receivedBuffer += str;
}
}
catch
{
MessageBox.Show("There was a problem");
}
finally
{
WaitForData(socket);
}
}Yes, this code looks complicated, but it is simple enough to understand. First we create a new byte array (the size of the array isn’t too important, and you can change it to suit your application), then wait for data to come from the Netduino. Once it does, we copy all non-null bytes to our array, then convert the array to a string. From here, it is exactly like the Netduino code.
- The final code left to write is the part that handles the received messages. In this simple app, we don’t need to check for anything except the return of the “ping”. Once we receive that ping, we know it has connected successfully and we enable the slider control to let the user start using it:
private void DoSomethingWithReceivedString(string buffer)
{
if (buffer == "ping")
{
_isConnected = true;
slider.IsEnabled = true;
SystemTray.SetProgressIndicator(this, null);
}
}We also set the progress bar to null to hide it.
- Windows Phone (and other platforms) needs to explicitly define what capabilities they require for security reasons. Using Bluetooth is one such capability, so to define that we are using it, in the Solution Explorer find the Properties item below the project name. Left-click on the little arrow on the left of it to expand its children. Now double-click on WMAppManifest.xml to open it up then click the Capabilities tab near the top. The list on the left defines each specific capability. Ensure that both ID_CAP_PROXIMITY and ID_CAP_NETWORKING are checked.
And that’s it! Make sure your Netduino is plugged in (and running the program you made in this article), then plug your Windows Phone 8 in, and run the code. The run button may say Emulator X, you will need to change it to Device by clicking on the little down arrow on the right of the button.
Once the two devices are connected, slide the slider on the phone forwards and backwards to see the onboard LED on the Netduino go brighter and dimmer.
Not working?
If the phone does not connect after a few seconds then something has probably gone wrong. After double-checking your wiring, the best thing to try is to unplug both the Netduino and phone, then plug them back in. If you are using a different Bluetooth board, you may have to pair it again to the phone. Repeat step 5 of the The Netduino Code section of this article. With both plugged back in, run the Netduino code (and give it a few seconds to boot up), then run the phone code. If that still doesn’t work, unplug both again, and only plug back in the Netduino. When it is powered up, it will run the last application deployed to it. Then with your phone unplugged, go to the app list and find the phone app you made, and tap on it to run it.
Summary
You’ve managed to control your Netduino from afar!
This article had a lot more code than most of the rest will because of needing to code both the Netduino and phone. However, the knowledge you’ve gained here will help you in many other projects, and we will be using this article as a base for some of the others.
Resources for Article:
Further resources on this subject:
- Automating the Audio Parameters – How it Works [Article]
- Ease the Chaos with Automated Patching [Article]
- Skype automation [Article]