12+ Years of App Development
Everything from a single source
50+ Successful App Projects

Blog

Controlling a BeeWi Car with Xamarin.Android

The BeeWi Car is a remote-controlled toy car made by BeeWi. During yesterday's workshop at Developer Open Space in Leipzig on the topic of Internet of Things, I had my first contact with this little gadget.

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.

Sebastian Seidel

Sebastian Seidel

As a mobile enthusiast and managing director of Cayas Software GmbH, it is very important to me to support my team and our customers in discovering new potential and growing together. Here I mainly write about the development of Android and iOS apps with Xamarin and .NET MAUI.

Related Articles

Voice input facilitates documentation - A hackathon topic
Voice input facilitates documentation - A hackathon topic

Voice input makes it possible to intuitively record food eaten and drunk without having to look at a device or tap. Instead of laboriously entering everything by hand, users can simply record their meals and snacks by voice command. This approach can lower the inhibition threshold and encourage users to continuously document their eating habits. This saves time and encourages regular documentation.

Animations in Jetpack Compose
Animations in Jetpack Compose

Modern applications are becoming more design-centric and therefore end-user-centric. For the user, the technical side of the program is not at all interesting, but rather taken for granted. Attractive design, animation and ease of use, on the contrary, all other things being equal, can make the application more popular among competitors.

7 steps to migrate from Xamarin.Forms to .NET MAUI
7 steps to migrate from Xamarin.Forms to .NET MAUI

With the end of support for Xamarin approaching in May 2024, developers are busy migrating existing Xamarin.Forms projects to .NET MAUI as its successor. So are we, of course. In this article, I'll show 7 steps we've always had to take during the transition to make your upgrade .NET MAUI easier.