In this article, I would like to show you how to write a small Bluetooth remote control for the BeeWi Car with Xamarin.Android and have some fun with it.
Internet of Things
The goal of the workshop was to connect to the car, an Arduino, or other sensor hardware with the platform of your choice and thereby take your first steps into the topic of IoT. In times of smart homes and home automation, there is no way around this exciting field anyway.
The user interface
To send the possible commands forward, backward, left, and right to the BeeWi Car, the app needs suitable input options.
The layout definition is intentionally simple. It consists of four buttons for the direction commands and a list of known devices. Before the user can control a car, they select one from the list. Then they are ready to go.
Based on that description, the following XML results for the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="@+id/btnForward"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Forward" />
<Button
android:id="@+id/btnLeft"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Left" />
<Button
android:id="@+id/btnRight"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Right" />
<Button
android:id="@+id/btnBackwards"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Backward" />
<TextView
android:text="Devices"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView1" />
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/listView1" />
</LinearLayout>
When the app starts, it makes sense to inform the user whether the device supports Bluetooth at all. If it does, the app can also immediately ask to enable Bluetooth if it is not already enabled. If not, there is nothing more to do.
The following code does exactly that:
var bluetoothDefaultAdapter = Android.Bluetooth.BluetoothAdapter.DefaultAdapter;
if (bluetoothDefaultAdapter == null)
{
Toast.MakeText(this, "Your device does not support Bluetooth", ToastLength.Long).Show();
return;
}
if (!bluetoothDefaultAdapter.IsEnabled)
StartActivityForResult(new Intent(Android.Bluetooth.BluetoothAdapter.ActionRequestEnable), 1);
Bluetooth is available and enabled, so it is time to display the Bluetooth devices already known to the device. To do that, iterate over the list of BondedDevices and output the device name and address.
var deviceList = new List<string>();
foreach (var device in bluetoothDefaultAdapter.BondedDevices)
deviceList.Add(String.Format("{0} ({1})", device.Name, device.Address));
var deviceAdapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItemMultipleChoice, deviceList.ToArray());
var listView = FindViewById<ListView>(Resource.Id.listView1);
listView.ChoiceMode = ChoiceMode.Single;
listView.Adapter = deviceAdapter;
Forward, backward, left, or right
The user selects the corresponding car by tapping one of the devices in the list. At that moment, the socket connection is created so that communication with the BeeWi Car can begin.
listView.ItemClick += async delegate(object sender, AdapterView.ItemClickEventArgs e)
{
if (currentDevice != null && currentDevice.Address != bluetoothDefaultAdapter.BondedDevices.ToList()[e.Position].Address)
socket.Close();
currentDevice = bluetoothDefaultAdapter.BondedDevices.ToList()[e.Position];
socket = currentDevice.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805f9b34fb"));
try
{
if (!socket.IsConnected)
await socket.ConnectAsync();
}
catch (Exception ex)
{
Toast.MakeText(this, "Could not connect to device", ToastLength.Short).Show();
currentDevice = null;
socket = null;
}
};
00001101-0000-1000-8000-00805f9b34fb is a standard ID for SSP Bluetooth.
The device is now connected and communication is established. To transmit the commands for the respective direction changes, the app still has to react to the user's input.
The example of moving forward shows how the button reacts when pressed by the user. When the button is pressed, the Forward_Go command is sent. As soon as the user releases the button, that command is canceled.
front.Touch += delegate(object sender, View.TouchEventArgs e)
{
if (e.Event.Action == MotionEventActions.Down || e.Event.Action == MotionEventActions.Move)
SendCommand(BeeWiCarCommands.Forward_Go);
else
SendCommand(BeeWiCarCommands.Forward_Stop);
};
All other buttons differ only in the type of command and are otherwise implemented the same way.
SendCommand is responsible for transmitting the selected commands to the BeeWi Car. It has to check whether a socket connection exists and whether it is connected to the current device. If so, the corresponding command can be written to the output stream.
void SendCommand(BeeWiCarCommands command)
{
try
{
if (socket == null)
{
Toast.MakeText(this, "No device selected", ToastLength.Short).Show();
return;
}
if (!socket.IsConnected)
{
Toast.MakeText(this, "Device not connected", ToastLength.Short).Show();
return;
}
if (socket.OutputStream.CanWrite)
{
socket.OutputStream.Write(new byte[]{ (byte)command }, 0, 1);
socket.OutputStream.Flush();
}
}
catch (Exception ex)
{
Toast.MakeText(this, ex.Message, ToastLength.Short).Show();
}
}
To use Bluetooth communication in the app, one permission is still missing from AndroidManifest:
<uses-permission android:name="android.permission.BLUETOOTH" />
What is missing?
Pairing the device with the BeeWi Car is done using the features provided by Android itself. Anyone interested is welcome to add that functionality to the app and describe their approach in the comments, or send a pull request for the repository.
Conclusion
With Xamarin.Android, it is easy to connect to Bluetooth devices, playfully explore the possibilities of the available hardware, and just have a bit of fun along the way.
I have been told that the same controls can also be used to fly the helicopters offered by BeeWi. So if you would rather be a pilot than a race driver, the same app could do that too.