Skip to main content
shopping_basket Basket 0

Building a Virtual User-Interface with Bluetooth Low Energy


In a previous article, we explored the idea of upcycling an old maker project into a greenhouse irrigation system and the feasibility of building simple home automation projects alongside the Pycom development environment. This article also demonstrated the simplicity of the micropython scripting language when building complex control systems and IoT enabled projects. In this article, we will dive deeper into the IoT context of this project by enabling Bluetooth Low Energy advertisements in an attempt to create a virtual user-interface.

The code for this project can be found on GitHub.

Parts List

The parts list for this project can be found in the original write-up but are not required to establish the functionality documented in this article. The key components for this step are listed below:

  • SiPy or other Pycom board
  • Pycom expansion board
  • Android phone or tablet

Bluetooth Background

Bluetooth Low Energy was developed by the Bluetooth SIG (Special Interest Group) to augment the functionality of classic Bluetooth to accommodate the growing popularity of decentralised IoT applications. The beauty of Bluetooth 4.1 Low Energy is its lack of dependence on peer-to-peer pairing in favour of a simple framework for interacting with many IoT devices quickly and efficiently.


GATT profile data structure.

This framework is called the Generic Attribute or GATT profile which defines the standard data structure for all BLE devices to use. This standard profile is the keystone in modern Bluetooth architecture which allows a higher degree of flexibility in low-level wireless networking.

This flexibility comes in the form of Bluetooth advertisements which accommodate simplistic data flow without the need for pairing. This functionality makes it easy for IoT hardware to interact with smart devices, servers, or as a network as of the latest Bluetooth 5 Mesh standard. This article will focus on the use of a smartphone to demonstrate the simplicity of using Bluetooth Low Energy as a flexible user-interface.

The Build

As the hardware for this project is embedded into the development board, no additional components are necessary to start experimenting with Bluetooth Low Energy functions. The software was developed using the Pymakr plugin for Visual Studio Code and uploaded to the SiPy using the Pycom expansion board.

The Pycom Bluetooth API documentation can be found here.

The first step in setting up our wireless user-interface is to initialise the Bluetooth hardware as a BLE GATT server and start advertising its availability. Once this is complete, we can start defining the service characteristics that enable the user to interact with system settings.

Fortunately, the Pycom Bluetooth API makes this very easy and only needs three lines of code to initialise the Bluetooth radio and start advertising. Once a name and unique identifier have been chosen, we can start advertising immediately. As this project is part of the greenhouse irrigation system, it has been simply named Greenhouse.

BLE_Obj = Bluetooth()
BLE_Obj.set_advertisement(name='Greenhouse', service_uuid=b'1234567890123456')

The BLE scanner app for Android was selected to check the visibility of the advertisement once the code had been uploaded to the device. The name of the advertisement should be easily visible on the list of services as seen below.


Scanning for Bluetooth advertisements.

Once this has been verified, we can start adding custom elements to our advertisement using the GATT data structure. The first thing that needs to be defined as part of the GATT hierarchy are services, which can be used to contextualise and group discrete data values called characteristics.Greenhouse_GATT_Structure_-_Highlight_4549d69a075f275979009f9a1b05004bb082fcb8.jpg

GATT data structure with custom services defined.

Developer note: Unfortunately, the current Pycom API is limited in its ability to define more than one characteristic per service or any meta-data, which currently makes its implementation of the Bluetooth SIG specification largely incomplete. This is difficult omission to overlook from an IoT hardware company and especially disappointing as a standard feature across the Pycom range.

For this example, two characteristics are required to hold the discrete timing values for the irrigation system. Ordinarily, we would define a single service to group the two related characteristics but as this is not possible with the current Pycom API, we will assign two separate services in our GATT profile. Fortunately, it only takes two lines of code to define each service and its respective characteristic.

srv1 = BLE_Obj.service(uuid= 0x100, isprimary=True)
srv2 = BLE_Obj.service(uuid= 0x200, isprimary=True)
chr1 = srv1.characteristic(uuid= 0x101, value= Irrigation_Delay_Sec_On)
chr2 = srv2.characteristic(uuid= 0x201, value= Irrigation_Delay_Sec_Off)

The service declaration requires a unique identifier and a primary service flag to be set for it to be visible, however, as the API currently only recognises primary services this must always be set to true. The service object can then be used to declare a single characteristic with a starting value. We can easily check if this is working by opening the Bluetooth app, connecting to our advertisement and checking for our custom services and characteristics.


GATT data structure with custom characteristics defined.

The GATT data structure should now be visible and able to interact with using the Bluetooth app. As no security features have been defined, the user is free to read, write and receive notifications from these BLE advertisements. The next step is to tell the system how to handle these remote changes to the GATT profile from the smartphone app through the use of event callbacks. Callback functions can be assigned easily using the characteristic object and a single line of code as seen below.

chr1.callback(trigger=Bluetooth.CHAR_WRITE_EVENT, handler=Delay_On_BLE_Callback)
chr2.callback(trigger=Bluetooth.CHAR_WRITE_EVENT, handler=Delay_Off_BLE_Callback)

When the user updates the GATT profile using the write function on the app, the irrigation system will now be prompted to read the new characteristic value and update the system settings accordingly.


Writing new characteristic values.


New characteristic values written to GATT profile.


By using the GATT profile framework, it is possible to negate the need for bulky tactile interfaces in favour of highly configurable virtual interfaces over Bluetooth Low Energy. The availability of Bluetooth on modern smart devices makes software-based interfacing solutions extremely accessible and perfect for the design of low-cost IoT applications.

A keen electronic engineer with a passion for sustainability, IoT and transport. Follower of the digital nomad movement and founder of Kickstart Kamper, the sustainable campervan conversion project on DesignSpark. Compulsive tea-drinker. BrightSpark 2017. BEng.

Recommended Articles

DesignSpark Electrical Logolinkedin