Skip to main content

Project Overview

In this wiki, we will show how to use the Bluetooth 5.0 BLE capabilities of the Seeed Studio XIAO nRF52840 with the Seeed Studio Grove Temperature & Humidity Sensor (DHT20) to broadcast measurements of temperature and humidity to Home Assistant using the BTHome protocol.

We will be using CircuitPython for the code.

Getting Started

To follow this tutorial , you need the following hardware

Seeed Studio XIAO nRF52840-SenseSeeed Studio Grove Temperature&Humidity Sensor V2.0 (DHT20)

Hardware Preparation

The Grove DHT20 sensor uses I2C for communication. We need to connect it to the I2C pins of the XIAO nRF52840 Sense:

  • We can use a XIAO Grove Shield with a Universal 4 pin Unbuckled cable
  • Connect the DHT20 sensor directly to the XIAO nRF52840 Sense using a 4 pin Female Jumper to Grove 4 pin Conversion Cable

Here's the pinout for XIAO nRF52840 Sense and XIAO Grove Shield



Hardware setup

Wiring is straight forward. Either using the Shield or not, the following Fritzing Schematic show how to wire the components together.




Software Preparation

We're going to use Thonny IDE software (Linux) and some related libraries and files. These are the steps we're going to take:

  1. Install CircuitPython on the XIAO nRF52840 Sense
  2. Install the necessary libraries
  3. Code our sensor using the BTHome protocol
  4. Configure Home Assistant

Step 1 - Install CircuitPython

Let's install CircuitPython.

Go to CircuitPython and download a version for the XIAO nRF52840 Sense. Choose Downloads and in the search field start writing the XIAO nRF52840 until the results show the sensor.

CircuitPython Download

Next, press the download button to get the file for our device.

CircuitPython Download

You should have a .uf2 file. To install it we need to enter bootloader mode. Connect the XIAO nRF52840 Sense to your computer and press the reset button twice.

CircuitPython Download

A new drive should have appeared on your computer called XIAO-SENSE.

XIAO nRF52840 Sense drive

Next, copy the downloaded file to the drive.

XIAO nRF52840 Sense drive

After a while, a new drive appears named CIRCUITPY. We have CircuitPython installed on our microcontroller.

XIAO nRF52840 Sense drive

Step 2 - Install libraries

To use our Grove Temperature & Humidity sensor V2.0 (DHT20), we need the Adafruit's AHT20 library.

The previous website has instructions on how to install libraries.

After installed, we should have the following files (this are the required for our DHT20 sensor):

XIAO nRF52840 Sense drive

Step 3 - Upload Code

Before going for the code, we need to understand what BTHome is.

BTHome logo


BTHome is an open standard for broadcasting sensor data and button presses over Bluetooth Low Energy (BLE). It is designed to be energy efficient, flexible, and secure. BTHome is supported by popular home automation platforms, such as Home Assistant, out of the box.

Some benefits of BTHome:

  • Is an open standard, so devices from different manufacturers can work together.
  • Devices are designed to be energy efficient, so they can run for a long time on a single battery.
  • Data is encrypted, so it is secure from unauthorized access.
  • Is a flexible format, so it can be used to transmit a variety of sensor data and button presses.

BTHome is a versatile and powerful standard for broadcasting sensor data and button presses over BLE. It is a good option for anyone who wants to add sensor data and button presses to their smart home.

You can read more about it and learn about the data format on the official site.


Here's the CircuitPython code.

Click to copy the CircuitPython code
# BTHome with DHT20
# This code is based on the excelent code by Koen Vervloesem
# We don't use deep sleep because it just doesn't work
# on the XIAO nRF52840 Sense. It's a pitty.

from _bleio import adapter
from time import sleep
import board
# for the Grove sensor
import adafruit_ahtx0

# The size of the name is important.
DEVICE_NAME = "XIAO nRF52840 Sense"

# Because this is delaying just 0.1s - 100 milliseconds, we don't need to read the sensor
# values everytime. It's overkill - let's just read every 5 minutes.
# Let's create a timer that will add every INTERVAL
# when it reaches 30 - it will be 5 minutes passed
# then we read the sensor
# INTERVAL * 60 seconds * 5 minutes
# CONVERTING 0.1ms to seconds * 60s * minutes = 300
readTimer = INTERVAL * 10 * 60 * MINUTES_PER_READING

# convert the measurement value to the BTHome format
def value_to_little_endian (measurement):

# Calculate the integer value by dividing the temperature by the factor
integer_value = int(measurement / 0.01)

# Extract the lower and upper bytes for little-endian representation
lower_byte = integer_value & 0xFF
upper_byte = (integer_value >> 8) & 0xFF

# Reverse the order of the bytes
little_endian_bytes = bytes([upper_byte, lower_byte])
return little_endian_bytes

class BTHomeAdvertisement:
_ADV_FLAGS = [0x02, 0x01, 0x06]
_ADV_SVC_DATA = [0x0a, 0x16, 0xd2, 0xfc, 0x40, 0x02, 0x00, 0x00, 0x03, 0xbf, 0x13]

def _name2adv(self, local_name):
adv_element = bytearray([len(local_name) + 1, 0x09])
adv_element.extend(bytes(local_name, "utf-8"))
return adv_element

def __init__(self, local_name=None):
if local_name:
self.adv_local_name = self._name2adv(local_name)
self.adv_local_name = self._name2adv(

def adv_data(self, temperature, humidity):
adv_data = bytearray(self._ADV_FLAGS)
adv_svc_data = bytearray(self._ADV_SVC_DATA)
# temperature
# change values according -
temp = value_to_little_endian (temperature)
# returned value is list
adv_svc_data[6] = temp[1]
adv_svc_data[7]= temp[0]
# humidity
# change values according -
hum = value_to_little_endian (humidity)
# returned value is list
adv_svc_data[9] = hum[1]
adv_svc_data[10]= hum[0]
return adv_data

# BTHome
bthome = BTHomeAdvertisement(DEVICE_NAME)

# Create sensor object
sensor = adafruit_ahtx0.AHTx0(board.I2C())

# because we want a initial reading
# let's initialize with the readTimer variable
# so we force the script to read the values
currentTimer = 0
# inital reading
temp = sensor.temperature
hum = sensor.relative_humidity

#print("\nTemperature: %0.1f C" % temp)
#print("Humidity: %0.1f %%" % hum)

while True:
adv_data = bthome.adv_data(temp,hum)
adv_data, scan_response=None, connectable=False, interval=INTERVAL * 2
# increase currentTimer
currentTimer += INTERVAL
#print (f"Current timer: {currentTimer}")
if (currentTimer >= readTimer):
#print (f'Read new values')
# Read new values
temp = sensor.temperature
hum = sensor.relative_humidity
#reset counter
currentTimer = 0

Remember to save it as so it gets executed on boot.

BTHome logo

A bit of code explaining

  • The code is full of comments to explain it a bit.
  • Basically, every 0.2s it is broadcasting the temperature and humidity coming from the DHT20 sensor.
  • Because we don't want to overload the sensor and read values every 0.2s, we've placed a timer. It will only read the values every 5 minutes. This time is controlled by the MINUTES_PER_READING variable.

Step 4 - Display data on Home Assistant

Step 4.1 - Add XIAO nRF52840 Sense on Home Assistant

Home Assistant Logo

Home Assistant is a free and open-source software for home automation. It is designed to be a central control system for smart home devices with a focus on local control and privacy.

Home Assistant acts as a central smart home controller hub by combining different devices and services in a single place and integrating them as entities. The provided rule-based system for automation allows creating custom routines based on a trigger event, conditions and actions, including scripts. These enable building automation, alarm management of security alarms and video surveillance for home security system as well as monitoring of energy measuring devices.

You can read more about it on the official site.


One crucial requirement is that HA (Home Assistant) has Bluetooth. If you're running HA on a Raspberry PI, chances are you have. All is dependent on the RPi version.


On "Step 3 - Upload Code", we coded the XIAO nRF52840 and for the next step, it must be running, so HA can detect it.

Open your HA installation. Go to Settings -> Devices and Services

Home Assistant

Now, your Integrations page shows up. Select Bluetooth

Home Assistant

And the Integration should appear.

Home Assistant

NOTE: If something is not working, check if Passive scanning is not selected

Home Assistant

When entering the Integrations page, if you have the XIAO nRF52840 Sense connected, it should already have been detected and will appear on the page.

Home Assistant

Press "Configure" to configure this new Integration. Press Submit.

Home Assistant

Now you just need to select the area where to put this new sensor and were done.

Home Assistant

Next, go again to Settings -> Integrations and select the new BTHome integration

Home Assistant

We then are taken to the integration page. We can see that we have 1 device and 3 entities. The entities are the temperature, humidity and signal strength

Home Assistant

If we click on the entities, we get a new page where we can have a view of them all.

Home Assistant

If instead, we pressed on device, we get the device page with all the options as well the current values. Using this page, we can add it to the dashboard.

Home Assistant

By pressing "ADD to DASHBOARD", we get to choose the view where to put it.

Home Assistant

After that, we get a view of the card. Just press "ADD TO DASHBOARD" to add it to the dashboard.

Home Assistant

If we go to the dashboard, our newly added card with the temperature and humidity broadcasted by the XIAO nRF52840 Sense.

Home Assistant

What's More - Deep Sleep Function

I couldn't make it work. If someone has a solution, please leave a comment. You can share your thoughts at GitHub

✨ Contributor Project

Tech Support & Product Discussion

Thank you for choosing our products! We are here to provide you with different support to ensure that your experience with our products is as smooth as possible. We offer several communication channels to cater to different preferences and needs.

Loading Comments...