This repository contains a simple Toit application that shows temperature, relative humidity and barometric pressure on TFT display of ESP-WROVER-KIT. The following description provides a step by step instructions on how to develop the application. We will start by testing hardware and software that provides individual functionality, e.g. reading of barometric pressure sensor or showing some text on the display. Then we will put the individual pieces together to have a complete application.
- Required Hardware
- Hardware Connections
- Installation of Libraries
- How to Use Toit
- Compatibility
- Step by Step Guide
- Next Steps
- Conclusion
To run the application the following hardware is required.
- ESP-WROVER-KIT
- BME280 pressure sensor on a breakboard
- PIR motion sensor
- Some wires to make connections
- Optionally a prototype board and sockets to provide a more permanent connection between ESP-WROVER-KIT as well as BME280 and PIR.
The example code is configured for the connections described below.
ESP32 GPIO | BME280 Pin | Description of BME280 Pin Functionality |
---|---|---|
3.3V | VCC | Power Supply |
GND | GND | Ground |
GPIO13 | SCL | I2C Clock |
GPIO14 | SDA | I2C Data |
ESP32 GPIO | PIR Pin | Description of PIR Pin Functionality |
---|---|---|
3.3V | + | Power Supply |
GND | - | Ground |
GPIO34 | OUT | Motion Detected |
There are a couple of libraries required to compile and run this application. The libraries are not directly included in this repository. Instead, the name, url, version and hash of each library are saved in package.yaml and package.lock files. If you already have a copy of this repository and would like to install the libraries, then open a terminal, go to the climate-tft
folder and run the following command:
toit pkg update
This command will upload the libraries based on information contained in package
files.
If you like to install the libraries in a new project folder that does not contain any package
information, run the following commands:
toit pkg install github.com/toitware/bme280-driver
toit pkg install github.com/toitware/toit-color-tft
toit pkg install github.com/toitware/toit-pixel-display
toit pkg install github.com/toitware/toit-icons-pictogrammers
Check the readme file in the root folder for information on how to configure and use Toit.
This application has been run using the following software:
PS C:\Users\krzys\toit\climate-tft> toit version
+---------+------------+
| VERSION | DATE |
+---------+------------+
| v1.19.7 | 2022-03-07 |
PS C:\Users\krzys\toit\climate-tft> jag version
Version: v1.3.1
SDK version: v2.0.0-alpha.12
Build date: 2022-07-01T15:49:05Z
See package.yaml
The following guide presents the process to test individual components of the application and then running the complete application.
If not done already, please install Toit and check if it works following Quick start guide.
Then install Jaguar and check if it works following the instructions on GitHub. This guide is using Jaguar for application development. The reason is that climate-tft application does not need to use the cloud infrastructure of Toit and local development directly on your PC is faster.
Start by creating a new empty folder e.g., climate-tft
and then open this folder in VS Code.
In the folder, we are going to create some test files and check if they work with the hardware.
You can create a new file by right-clicking in VS Code EXPLORER pane on the left, selecting 'New File' from the context menu and entering the file name. Then you can just copy and paste to this file the code taken from https://github.com/krzychb/toit-samples/tree/main/climate-tft.
Before loading any test code you need to flash Jaguar application to your ESP-WROVER-KIT. Open a terminal window by clicking Terminal
> New Terminal
from the VS Code menu. In the terminal window enter:
jag flash --wifi-ssid [ssid-of-your-wifi] --wifi-password [password-to-your-wifi] --name climate-tft-name
Replace [ssid-of-your-wifi]
and [password-to-your-wifi]
with SSID and password to access the point of your wifi. Instead of climate-tft-name
put a specific name of your choice. You can skip --name climate-tft-name
if there no other Toit devices running on your network.
You will be asked to select a port name for your board. ESP-WROVER-KIT will be visible under two ports. Select the port with the higher number. The log of successful flashing will look similar to the below:
PS C:\Users\krzys\toit\climate-tft> jag flash --wifi-ssid my-ssid --wifi-password my-password --name climate-tft-krzysztof
v COM8
Flashing device over serial on port 'COM8' ...
esptool.py v3.0
Serial port COM8
Connecting....
Chip is ESP32-D0WD (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
Crystal is 40MHz
MAC: ac:67:b2:71:61:18
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 15840 bytes to 11108...
Wrote 15840 bytes (11108 compressed) at 0x00001000 in 0.1 seconds (effective 1002.8 kbit/s)...
Hash of data verified.
Compressed 3072 bytes to 147...
Wrote 3072 bytes (147 compressed) at 0x00008000 in 0.0 seconds (effective 1535.6 kbit/s)...
Hash of data verified.
Compressed 8192 bytes to 31...
Wrote 8192 bytes (31 compressed) at 0x0000d000 in 0.0 seconds (effective 4523.9 kbit/s)...
Hash of data verified.
Compressed 1205216 bytes to 782390...
Wrote 1205216 bytes (782390 compressed) at 0x00010000 in 12.7 seconds (effective 757.6 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
PS C:\Users\krzys\toit\climate-tft>
You can proceed to the next step only after successfully flashing Jaguar application.
It is a good idea to have access to the log reported by Jaguar. In the previously opened terminal window run:
jag monitor --port [port-to-monitor]
Instead of [port-to-monitor]
enter the port name used previously to flash Jaguar. The log of successfully executed commands will look like follows:
PS C:\Users\krzys\toit\climate-tft> jag monitor --port COM8
Starting serial monitor of port 'COM8' ...
ets Jun 8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x1e (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:188
ho 0 tail 12 room 4
load:0x40078000,len:12672
load:0x40080400,len:2892
entry 0x400805c0
[toit] Starting <v2.0.0-alpha.8>
[toit] clearing RTC memory: invalid checksum
[wifi] DEBUG: connecting
[wifi] DEBUG: connected
[wifi] INFO: dhcp assigned address {ip: 192.168.1.36}
[jaguar] INFO: running Jaguar device 'climate-tft-krzysztof' (id: '6f40f4bd-50c2-4994-9faf-90085c86f842') on 'http://192.168.1.36:9000'
Now you are ready to start testing the application code.
In this step, we are going to check if PIR sensor is operational. If the motion is detected then backlight of TFT screen of ESP-WROVER-KIT will turn on for one second. If there is no motion the screen will be off.
Connect PIR sensor to Main I/O Connector / JP1 of ESP-WROVER-KIT:
ESP32 GPIO | PIR Pin | Description of PIR Pin Functionality | Wire Color |
---|---|---|---|
3.3V | + | Power Supply | Red |
GND | - | Ground | Black |
GPIO34 | OUT | Motion Detected | White |
Backlight GPIO is already connected internally on ESP-WROVER-KIT and you do not need to do anything about it.
Before running the test application, you can check this internal connection by shortening GPIO5 to GND. The TFT should turn on if GPIO5 is at low level and turn off if it is at a high level or not connected.
After connecting the hardware you are ready to test the software. Create a new file detect_motion.toit and load it to ESP-WORVER-KIT.
To do so open a new terminal window by clicking Terminal
> New Terminal
from the VS Code menu. In the terminal enter:
jag watch detect_motion.toit --device climate-tft-krzysztof
The part --device climate-tft-krzysztof
is required to load the application to one specific device if there is more than one on your network. A successful log after executing the above command will look similar to the below:
PS C:\Users\krzys\toit\climate-tft> jag watch detect_motion.toit --device climate-tft-krzysztof
Scanning ...
Running 'detect_motion.toit' on 'climate-tft-krzysztof' ...
Success: Sent 24KB code to 'climate-tft-krzysztof'
Now check if the motion sensor is working. If you wave your hand in front to the PIR the TFT screen should turn on. The code to read the sensor and control the TFT is quite simple.
First, backlight GPIO is configured as output and PIR GPIO is configured as an input.
main:
backlight_off := BACKLIGHT_GPIO
backlight_off.config --output
pir_state := PIR_GPIO
pir_state.config --input
Then the PIR state is checked in an endless loop. If motion is detected the backlight is turned on for one second.
while true:
if pir_state.get == 1: // if motion is detected ...
backlight_off.set 0 // turn the backlight on
sleep --ms=DISPLAY_ON_DELAY // keep the backlight on for some time
else:
backlight_off.set 1 // turn the backlight off
sleep --ms=100
Please note that some PIR sensors have off delay and report motion for an extra couple of seconds after the movement already stopped. If this is the case then the backlight will be on for at least the the off delay of the PIR.
If the application is working properly, you can experiment by changing the value of DISPLAY_ON_DELAY
to e.g., 5_000
and checking if TFT screen will turn on for at least five seconds.
/*
For how long keep the display on if motion is detected
*/
DISPLAY_ON_DELAY ::= 01_000 // ms
Save the modification to detect_motion.toit
and since it is "watched" (remember running jag watch detect_motion.toit
), it should be automatically loaded to ESP-WROVER-KIT:
File modified 'C:\Users\krzys\toit\climate-tft\detect_motion.toit'
Running 'detect_motion.toit' on 'climate-tft-krzysztof' ...
Success: Sent 24KB code to 'climate-tft-krzysztof'
If you see any issue check the other terminal window where you run Jaguar monitoring. Each terminal is accessible by clicking one of "jag" lines at the bottom right of VS Code. To distinguish which terminal is witch it is a good idea to rename "jag" to something else. Right click on "jag" and rename the windows to "monitor" and "watch":
The next device to test is BME280 barometric pressure sensor. We would like to show readings from the sensor on monitor" terminal window.
Connect BME280 sensor to Main I/O Connector / JP1 of ESP-WROVER-KIT:
ESP32 GPIO | BME280 Pin | Description of BME280 Pin Functionality | Wire Color |
---|---|---|---|
3.3V | VCC | Power Supply | Red |
GND | GND | Ground | Black |
GPIO13 | SCL | I2C Clock | Yellow |
GPIO14 | SDA | I2C Data | Orange |
To operate the sensor we need to install BME280 driver library from Toit package registry. Open "watch" terminal window and terminate the jag watch
session by pressing Control-C. Then install the library by executing the following command:
jag pkg install bme280-driver
Log of successful installation of the package looks as follows:
PS C:\Users\krzys\toit\climate-tft> jag pkg install bme280-driver
Info: Package 'github.com/toitware/[email protected]' installed with name 'bme280'
PS C:\Users\krzys\toit\climate-tft>
Communication with BME280 sensor will not be possible if the library is not installed.
Having the driver package installed, you can now prepare and run the test application by adding read_bme.toit to the project folder and running it in "watch" terminal window:
jag watch read_bme.toit --device climate-tft-krzysztof
If the sensor is connected and if the application is compiled and loaded correctly you should be able to see a similar log in the "monitor" terminal window (change to "monitor" from "watch" window used in the previous step). A new reading will be printed out every 1 second:
Temperature: 29.0°C
Relative humidity: 51%
Barometric pressure: 1003 hPa
The code for reading BME280 consists of two parts. The first part is a function get_bme
to configure I2C bus, set I2C address and return an instance of the driver.
get_bme:
bus := i2c.Bus
--sda=BME280_SDA_GPIO
--scl=BME280_SCL_GPIO
device := bus.device bme280.I2C_ADDRESS
bme := bme280.Driver device
return bme
The second part is an endless loop to read measurements of the sensor using the driver and printing them on a terminal.
main:
bme := get_bme
while true:
print "Temperature: $(%.1f bme.read_temperature)°C"
print "Relative humidity: $(%d bme.read_humidity)%"
print "Barometric pressure: $(%d bme.read_pressure/100) hPa"
print // empty new line
sleep --ms=1000
If the above code is working for you, congratulations! Proceed to the next step to test the operation of the TFT display.
In case of "monitor" is returning I2C bus reading error (see below), verify the I2C address of the sensor.
Decoded by `jag monitor` <v2.0.0-alpha.8>
As check failed: an int (0) is not a ByteArray.
0: Bus.read_reg_ <sdk>\i2c.toit:115:5
1: Device.read_reg <sdk>\i2c.toit:240:17
2: Device.read_reg <sdk>\i2c.toit:233:12
3: Registers.read_bytes <sdk>\i2c.toit:289:20
4: Registers.read_u8 <sdk>\serial\registers.toit:41:14
5: Driver <pkg:bme280-driver>\driver.toit:79:17
6: get_bme read_bme.toit:32:16
7: main read_bme.toit:42:10
If SDO pin is connected to GND (instead of being left floating/unconnected) the address I2C should be changed to I2C_ADDRESS_ALT
.
The last component to test is TFT display of ESP-WROVER-KIT board. This time we do not need to connect anything since the display is an integral part of the board and is connected internally.
To drive the display we need to install and configure two libraries:
The installation process is identical to BME280 driver library. You can check the command to install the library by opening Toit package registry, searching for the package name and checking the package description.
See below the installation commands run in the terminal:
PS C:\Users\krzys\toit\climate-tft> toit pkg install github.com/toitware/toit-color-tft
Info: Package 'github.com/toitware/[email protected]' installed with name 'color_tft'
PS C:\Users\krzys\toit\climate-tft> toit pkg install github.com/toitware/toit-pixel-display
Info: Package 'github.com/toitware/[email protected]' installed with name 'pixel_display'
PS C:\Users\krzys\toit\climate-tft>
If the packages are installed successfully, you can now prepare and run the test application by adding update_display.toit to the project folder and running it in "watch" terminal window:
jag watch update_display.toit --device climate-tft-krzysztof
If there are no issues, the application should show on "Hello World" the display.
The major code blocks of the test application are described below.
Before using the display driver library we need to define GPIO pins controlling the display of the board. The pins are documented ESP-WROVER-KIT User Guide.
MOSI_GPIO := gpio.Pin 23
CLOCK_GPIO := gpio.Pin 19
CS_GPIO := gpio.Pin 22
DC_GPIO := gpio.Pin 21
RESET_GPIO := gpio.Pin 18
BACKLIGHT_GPIO := gpio.Pin 5
The display is driven using SPI bus of ESP32. The respective procedure to configure the bus and the driver is provided by the function get_display
:
get_display -> TrueColorPixelDisplay:
bus := spi.Bus
--mosi=MOSI_GPIO
--clock=CLOCK_GPIO
device := bus.device
--cs=CS_GPIO
--dc=DC_GPIO
--frequency=26_000_000 // Hz
driver := ColorTft device 320 240 // width x height (in pixels)
--x_offset=0 // pixels
--y_offset=0 // pixels
--flags=COLOR_TFT_16_BIT_MODE | COLOR_TFT_FLIP_XY
--invert_colors=false
--reset=RESET_GPIO
--backlight=null // backlight will be controlled separately
tft := TrueColorPixelDisplay driver
return tft
Note that besides configuring the pins of SPI bus and the display, the SPI bus frequency, we are also configuring the display driver by providing parameters like resolution (320 x 240 pixels) or color mode.
The final code block of the test application is contained in main
function. The code is using previously configured driver to show the "Hello World" on the screen. The main
function may be broken down into the following parts:
Configuration of backlight GPIO and turning the display backlight on:
backlight_off := BACKLIGHT_GPIO
backlight_off.config --output
backlight_off.set 0 // turn the backlight on
Configuration of so called "context" of the information displayed on the screen. The context describes the attributes of text (and graphics), e.g. font type and size, orientation, color, etc.:
tft := get_display
tft.background = BLACK
sans := Font.get "sans10"
sans_context := tft.context --landscape --color=WHITE --font=sans
hello_context := tft.text sans_context 130 120 "Hello World"
tft.draw
Note that the first line of the code is getting an instance of the display driver tft := get_display
, and the last is drawing previously configured information of the display tft.draw
.
The Location of the displayed text is provided in pixels in relation to the upper left corner of the screen.
Go ahead and change the text, the text attributes (e.g. color) and see what will be shown on the screen.
After having individual pieces of hardware and software checked, it is time to put all of them together into the final application. As stated at the beginning, the application would show temperature, relative humidity and barometric pressure on a TFT display.
If you like to check how the application works before reading the explanation below, connect PIR and BME280 sensors as done before, and load the file climate-tft.toit to ESP-WORVER-KIT. Please note that the application is using icons from https://materialdesignicons.com/ that are bundled in a pictogrammers_icons
package. To install the package run:
toit pkg install github.com/toitware/toit-icons-pictogrammers
Let's begin with the preparation of the layout of the information shown on the screen. To make the text visible from a distance we are going to use relatively big font and icon sizes:
- Font: SanSerif 24 pixels
- Icons: 48 pixels
The proposed layout is presented on the picture below. All measurements are shown in pixels in relation to the upper left corner of the screen.
Before being able to display information on the screen, we need some initial code to define the color of the display's background as well as to import fonts.
tft.background = BLACK
sans := Font [
sans_24.ASCII, // Regular characters
sans_24.LATIN_1_SUPPLEMENT, // Degree symbol
]
To add the text to the display we first need to define some initial parameters like the text orientation on the display, font color and font alignment. This information is assigned to the variable sans_context
in the first line of the code below. Please note the text is aligned right using --alignment=TEXT_TEXTURE_ALIGN_RIGHT
. Such alignment has been already reflected in the layout drawing above where the location of the text is measured from the end of the text. Using previously defined context we can then add a couple of lines of text formatted for showing measured parameters of temperature, relative humidity and atmospheric pressure. The last line is adding some static text to personalize the display.
sans_context := tft.context --landscape --color=WHITE --font=sans
--alignment=TEXT_TEXTURE_ALIGN_RIGHT
temp_context := tft.text sans_context 230 50 "??.?°C"
hum_context := tft.text sans_context 220 100 "??%"
prs_context := tft.text sans_context 255 150 "???? hPa"
name_context := tft.text sans_context 255 215 "Krzysztof"
Besides the text, we will also add a couple of icons to graphically represent displayed information. Again, we start with context definition (for that we provide a separate variable icon_context
) to set the orientation of the icons as well as color. Within the context we then add the icons.
icon_context := tft.context --landscape --color=(get_rgb 0xe0 0xe0 0xff)
icon_temperature := tft.icon context 50 55 icons.THERMOMETER
icon_humidity := tft.icon context 50 105 icons.WATER_OUTLINE
icon_pressure := tft.icon context 50 155 icons.ARROW_COLLAPSE_DOWN
icon_name := tft.icon context 50 220 icons.FACE
tft.draw
The last line of the above code is to draw all previously added information (text and icons) on the screen.
But we would like to see some live measurements instead of static text. To do so we only need to take measurements and display the values using the context defined previously for each measurement.
while true:
temp_context.text = "$(%.1f bme.read_temperature)°C"
hum_context.text = "$(%d bme.read_humidity)%"
prs_context.text = "$(%d bme.read_pressure/100) hPa"
tft.draw
sleep --ms=1000
The last item to describe is the main
function. It is used to call individual functions we have discussed one by one above.
main:
tft := get_display
bme := get_bme
task:: update_display tft bme
task:: detect_motion
Consider soldering a prototype board to install the sensor and connect the header of ESP-WROVER-KIT. Below is an example of two such boards.
First Prototype of Sensor Board | Second Prototype of Sensor Board |
The board on the left was the first prototype. It did not work as expected because BME230 sensor was showing a temperature higher than expected. The issue was due to the sensor being located above ESP-WROVER-KIT components and warming up the sensor.
To resolve the issue another prototype was built (shown on the right) with BME280 sensor located on the side of ESP-WROVER-KIT.
A closeout of both prototypes are shown below. For the location and labeling of sockets please check the layout document.
Prototypes of Sensor Board - Front | Prototype of Sensor Board - Back |
You may want to show the current time on the screen. Toit provides ntp package you can use to synchronize the clock of ESP to an external time server. Check sync_time.toit for an example on how to do it.
Writing this simple program we have demonstrated how to use Toit to take measurements and show them on a TFT screen of a commonly available ESP-WROVER-KIT development board from Espressif. We were able to complete the tasks using standard Toit libraries. The code looks quite compact and easy to read thanks to Toit programming language inspired by Python language.