(For more resources related to this topic, see here.)
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.
The things required for this project are as follows:
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 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.
Because we will be using a phone to connect to the Netduino, there are two distinct parts which need to be coded.
using System.IO.Ports;
using System.Text;
using NPWM = SecretLabs.NETMF.Hardware.PWM;
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).
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.
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.
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.
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:
<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.
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.
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.
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.
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.
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.
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.
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.
Further resources on this subject: