ESP32 (28) – MQTT and SSL

Security is a very important aspect for MQTT brokers. In a previous article you’ve already learned how to implement authentication and authorization. The weakness in that configuration was that credentials were transmitted in cleartext; it was therefore possible, for an attacker who can sniff the network traffic, to read and use them to impersonate a legitimate client.

Today I’ll show you how to encrypt the communication channel between client and broker using SSL certificates. I’ll also explain how to write a program for the esp32 chip to send data to the broker using the secure channel…

SSL certificate

To be able to encrypt the communication, mosquitto requires a server certificate.

First generate the private key (RSA with a length at least 2048 bits):

openssl genrsa -out mosquitto.key 2048

Then create the CSR file:

openssl req -new -out mosquitto.csr -key mosquitto.key

type the required information; the most important of which is the common name that will identify the server:

mq-ssl-001

Now sign the CSR file with your Certificate Authority (or send it to a public / corporate CA) to generate the certificate:

openssl ca -config openssl.cnf -extensions server_cert 
 -notext -in mosquitto.csr -out mosquitto.cer

mq-ssl-002

Create the ssl subfolder in the folder where you installed mosquitto and copy into that folder the certificate, its private key and the certificate of the CA:

mq-ssl-003

Configuration

Open the mosquitto.conf file and add the following lines:

mq-ssl-004

The first line changes the TCP port mosquitto is normally listening to (1883) to the default port for SSL connection, 8883.

The following 3 lines set the path for server and CA certificates and for the private key that corresponds to the server certificate. The last one, which is not compulsory, forces the use of the TLS v1.2 protocol, the most secure one at the moment of writing.

Once the server has been configured, you can start it (-v is to enable the verbose output):

mosquitto.exe -c mosquitto.conf -v

To be able to use the mosquitto_pub and mosquitto_sub tools, you now have to add new parameters:

mosquitto_sub.exe -p 8883 -t test --cafile .\ssl\ca.cer --insecure
mosquitto_pub.exe -p 8883 -m 20 -t test --cafile .\ssl\ca.cer --insecure

With -p you specify the TCP port of the server, with –cafile the path of the CA certificate which signed the server certificate mosquitto uses and finally with –insecure you configure the two clients not to verify that the certificate’s common name (in my example mymosquitto.local) corresponds to the server name.

You can avoid using the –insecure switch if you generate a certificate with a common name the exact name of the server/PC which runs mosquitto or – alternatively – if you add a DNS alias which resolves the common name of your certificate with the IP address of the server and run the clients with -h commonName

esp32

Tuan PM developed a library (espmqtt) for the esp-idf framework that implements a complete MQTT client. Moreover, the library does support secure connections, you can therefore use it to connect to an MQTT broker with TLS enabled.

mq-ssl-005

Copy the content of the Github repository in the components folder of your project and include the library’s header file in your source code:

#include "mqtt.h"

The MQTT client is configured using the mqtt_settings struct:

mqtt-001

The most important parameters are:

  • the server (host) that runs the MQTT broker (you can use the IP address or the DNS name)
  • the TCP port (port) the server is listening to (default is 1883 or 8883 if SSL is enabled)
  • username and password if the server requires authentication
  • one or more callback functions the espmqtt library will call when the corresponding event occurs
the espmqtt library does not copy the parameters in an internal struct. It’s therefore very important that the mqtt_settings variable has a global scope and it’s defined outside a specific function.

Your program can interact with the MQTT client implementing its callback functions.

For example the connection or disconnection from the MQTT server occurs as follows:

mqtt-002

The connect_cb and disconnect_cb functions perform the “real” connection and disconnection, while connected_cb and disconnected_cb functions are executed after the corresponding activity is completed (= the client successfully connected to the server). Your program usually doesn’t need to re-implement the main functions, but will implement the ones related to events, to execute actions (for example subscribe a topic) when a specific event occurs.

After having configured the client, you can run it with:

mqtt_start(&settings);

Once connected to the server (connected_cb callback function) you can subscribe or unsubscribe a topic with:

void mqtt_subscribe(mqtt_client *client, const char *topic, uint8_t qos);
void mqtt_unsubscribe(mqtt_client *client, const char *topic);

and publish data to a topic with:

void mqtt_publish(mqtt_client* client, const char *topic, 
  const char *data, int len, int qos, int retain);

Demo

I prepared an example to show my esp32 devboard sending data to a mosquitto server, with SSL enabled.

I connected to the devboard an HTU21D sensor as explained in a previous article and my program reads, every 5 seconds, the temperature and humidity values and sends them to the broker. I used a very handy opensource program, HelloIoT, to create a dashboard and display the received data.

The source code of the program and the configuration of the HelloIoT dashboard are available in my Github repository; here’s a short video of the demo:

DCC, led accessory decoder

After having designed a shield to interface Arduino with a DCC bus, today I’ll show you how to realize a simple accessory decoder to control a couple of leds.

dccled-101 dccled-100

Accessory decoder

The DCC standard (specifically the document S-9.2.1 DCC Extended Packet Formats) defines different types of decoders, which are devices – connected to the DCC bus – that perform actions based on the command they receive.

An accessory decoder is “intended for control of a number of simple functions such as switch machine control or turning on and off lights“.

dcc2servo2relay

a DIY decoder by Paco

Addressing

Each decoder is assigned one or more addresses. The document S-9.2.1 linked above explains in details the format of a DCC packet sent to an accessory decoder (basic accessory decoder packet format):

dcc-001

9 bits of the packet (AAAAAAAAA) defines the address of the decoder. The address’ most significative bits (MSB) are the ones in the second bytes, while the least significative bits (LSB) are the ones in the first byte. To make things more complicated, the bits in the second byte are in ones’ complement representation.

Let’s understand it with an example:

dcc-003a

Most significative bits are 011. If you ones’ complement them, they become 100.

Least significative bits are 0010011. When you concatenate the two parts, you get 1000010011, therefore the decoder’s address is 267.

2 bit (PP) represents the address of a single port of the decoder. Conventionally, an accessory decoder has 4 ports, each one with a couple of outputs.

Bit O chooses, for the port represented by the PP bits, the output the command is related to. Finally, bit C is the action and defines if that output must be activated (1) or disactivated (0).

dcc-002

Some manufacturers prefert to use a “flat” addressing (not distinguishing between decoder address, port number and output). A good explaination about the different addressing methods (MADAPADA…) is available on the Rocrail wiki.

Arduino

Before developing the sketch for your accessory decoder, you have to install – using the Library Manager – the NmraDcc library in your Arduino IDE:

dcc-acc-001

Then include it in your sketch and create an instance of the NmraDcc object:

#include "NmraDcc.h"
NmraDcc Dcc;

In the setup() you have to configure and initialize the library. First, call the pin() method to tell the library which Arduino pin the DCC signal is connected to (ExtIntPinNum) and the corresponding interrupt number (ExtIntNum). In addition, you can enable or not the internal pullup resistor:

void pin(uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup);

The list of suitable pins for each Arduino board is available in the wiki and you can use the digitalPinToInterrupt() method to get the interrupt number that correspond to each pin.

If you’re using the shield I designed with an Arduino Uno, you can choose pin 2 with the pullup resistor enabled:

#define DCC_PIN 2
[...]
Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1);

Let’s now configure the library, with the method:

void init(uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, 
  uint8_t OpsModeAddressBaseCV);

The first two parameters are the manufacturer code and the decoder version; the DCC command station can get those values reading the corresponding CVs (configuration variables). For self-made decoders, the ManufacturedId is set to MAN_ID_DIY.

With the third parameter you can set, in OR, some flags:

dcc-acc-002

For accessory decoder, you have to specify at least the third flag (DCC_ACCESSORY_DECODER).

FLAG_MY_ADDRESS_ONLY

The first flag tells the library to filter the DCC messages it receives and to process only the ones sent to the decoder address. I usually do not set that flag, because I want my sketch to be able to “see” each incoming message. In my code I then decide which messages to process and which not.

When the library is correctly configured, in the loop() you have to call as frequently as possible the process() method to let the library handle the incoming messages:

void loop() {
  Dcc.process();
}

When the library receives a message for an accessory decoder, it can execute different callback functions, depending on what you defined in your sketch:

  • notifyDccAccState()
  • notifyDccAccTurnoutBoard()
  • notifyDccAccTurnoutOutput()
  • notifyDccSigState()

The first 3 methods are called for basic accessory decoder packets, while the last for extended accessory decoder control packets.

For my led decoder, I decided to implement the notifyDccAccState() method:

void notifyDccAccState(uint16_t Addr, uint16_t BoardAddr, 
  uint8_t OutputAddr, uint8_t State)

The method provides some variables. Let’s see their meaning (remember what you learned in the first part of this article about addressing):

  • BoardAddr is the decoder address (9 bits)
  • OutputAddr contains the 3 bits PP and O, that are the address for the port and the output
  • State is the action (1 = activate, 0 = deactivate)
  • Addr is the direct port address (PADA mode)

You can divide the port address (2 bits) from the output address (1 bit) with:

int portAddress = (OutputAddr >> 1) + 1;
int outAddress = OutputAddr & 0x01;

In the code I added 1 to the port address to be able to number the ports from 1 to 4 instead of from 0 to 3.

To keep it simple, the decoder developed for this article has hardcoded in the sketch both the board address and the port address (in a future article I’ll explain how to have the address configurable at runtime):

#define BOARD_ADDRESS   5
#define PORT_ADDRESS    1

In the sketch you can verify that the command received is for your decoder with:

if((BoardAddr == BOARD_ADDRESS) && (portAddress == PORT_ADDRESS)) {

and change the output status of two digital pins (to which I connected the leds) based on the output number and the command:

if(outAddress == 0) {
  digitalWrite(RED_LED_PIN, HIGH);
  digitalWrite(GREEN_LED_PIN, LOW);
   Serial.println("! RED led activated");
} else {
  digitalWrite(RED_LED_PIN, LOW);
  digitalWrite(GREEN_LED_PIN, HIGH);
  Serial.println("! GREEN led activated");      
    }

The source code of the decoder is available in my Github repository, here’s a video that shows how it works:

ESP32 (27) – GPS

In today’s post I’ll show you how to interface the esp32 chip to a GPS receiver to receive the actual position, speed and more…

GPS receiver

On the Internet and in electronic stores you can find different GPS receivers… thanks to the spread of navigators, smartphones and multicopters you can now buy one for few euros. For this tutorial, I used a GPS receiver sold by Banggood and based on the u-blox NEO-M8 chip:

gps-010 gps-011

Almost all the GPS receivers offer a serial interface, you can therefore connect them to an esp32 chip using one of its UART controllers, as I explained in a previous article. Sometimes it’s not easy to identify the various pins and it may be necessary – as in my case – to open the plastic case that contains the chip to read the PCB silk screen:

gps-001 gps-002

From the photos above you can understand the pinout of my receiver:

  • GND (ground) -> black cable
  • VCC (power supply) -> red cable
  • TXD (transmit) -> green  cable
  • RXD (receive) -> yellow cable

I decided to use the UART1 controller of my esp32 chip, with pins 4 (TX) and 16 (RX). I therefore connected all the cables, paying attention to connect the TX pin of the receiver to the RX pin of the chip and viceversa:

gps-003

NMEA

GPS receivers send data following the NMEA 0183 standard (often called just NMEA).

NMEA is based on strings (sentences) composed by a maximum of 80 characters with an ending CRLF. Each string has the following format:

$PREFIX,data1,data2 ... dataN-1,datoN*CHECKSUM

The prefix (5 chars) defines the type of device (for GPS receiver is GP) and the type of sentence (the following 3 chars). Each sentence includes a checksum (XOR) that allows the receiver to validate the data received.

The NMEA standard defines many types of sentences and each manufacturer can add proprietary types to communicate specific data. A complete list of NMEA sentences is available at this website. Let’s analyze one GGA (Global Positioning System Fix Data) sentence:

$GPGGA,183619,3877.038,N,07702.110,W,1,08,0.9,545.4,M,46.9,M,,*47

The receiver is sending the actual position (latitude 38°77.038′ NORTH and longitude 77°02.110′ WEST), obtained at 18:36:19 thanks to 8 satellites. The fix (position) quality is GPS Fix (1).

To be able to get data from the GPS receiver your program must therefore “understand” the NMEA sentences it receives. I found a very good library, minmea, developed in C and able to parse the most important NMEA sentences.

You only need to copy the two source files (minmea.c e minmea.h) in a subfolder of the components folder of your project and to create a component.mk file as it follows:

gps-001

I had to add the highlighted flag because of the esp framework does not include the timegm() function and therefore, as explained also in the README of the library, you need to tell the compiler to use the more common mktime() instead.

Program

In my Github repository you can find the program I developed for this tutorial. Let’s analyse the most important pieces of code:

To use the minmea library, include its header file:

#include "minmea.h"

Read a line from the UART1 controller and pass it to the library to be parsed:

char *line = read_line(UART_NUM_1);
switch (minmea_sentence_id(line, false)) {
  case MINMEA_SENTENCE_RMC:
  [...]
  case MINMEA_SENTENCE_GGA:
  [...]
}

Finally verify if the new parameters are different from the ones already saved and, if so, print them on the screen:

float new_latitude = minmea_tocoord(&frame.latitude);
if((new_latitude != NAN) && (abs(new_latitude - latitude) > 0.001)) {
  latitude = new_latitude;
  printf("New latitude: %f\n", latitude);
}

I added a threshold value (0.001) to avoid printing a lot of small updates, due to disturbances or oscillations on received data.

Here’s the program running on my laptop:

gps-010

How to configure I2C sensors with Arduino

sensorpan-600

Edward Mallon writes:

I’ve spent the last year in the ‘uncanny valley’ of the Arduino. That’s the point where you understand the tutorials at Arduino.cc, but still don’t get much from the material on gitHub because trained programmers would never stoop to using the wire.h library when they could just roll their own in native C++ using the avr-g++ compiler.  The problem with establishing sensor communication at the level of the TWI peripheral inside the AVR is that there are so many fiddling details to keep track of that it quickly overruns the 7±2 things this average human can hold in his head at one time: Computers aren’t the only things that crash after a buffer overflow!  So this post is meant to be a chunking exercise for beginner-intermediate level people like myself who want to get a new sensor working using the standard IDE.  I’ve tried to distill it all down to things that I run into frequently, but there’s still a lot of material here:  So pour yourself a cuppa before diving in…

More details at Arduino based underwater sensors blog.

ESP32 (26) – UART

UART (Universal Asynchronous Receiver-Transmitter) is an hardware peripheral which allows serial, asynchronous communication with configurable data format and speed. The UART interface usually works at logic level: the electric signals are generated by an external circuit, following the standards of the communication bus you chose.

For example the classical “serial port” of many personal computers is based on the EIA RS-232 standard, which defines how – at the physical layer – signals are generated on the communication medium. There are dedicated chips (the most famous of which is surely the MAX232 by Maxim Integrated) to convert the logic levels of a UART peripheral to the physical signals of the EIA RS232 standard:

uart-001

The esp32 chip offers 3 UART controllers. These controllers are connected to the GPIO matrix; this allows to assign them most of the digital pins of the chip:

uart-002

The esp-idf framework includes a driver (uart.c) to simplify the configuration and the use of the controllers; to use it, include its header file in your program:

#include "driver/uart.h"

For the driver, the 3 controllers are named as follows:

uart-003

In this first post, I’ll explain the basic use of a controller; events and interrupts will be covered in a future article.

The first thing to do is to configure the controller using the uart_config_t struct:

uart_config_t uart_config = {
  .baud_rate = 115200,
  .data_bits = UART_DATA_8_BITS,
  .parity = UART_PARITY_DISABLE,
  .stop_bits = UART_STOP_BITS_1,
  .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
  • baud_rate is the transmission speed
  • data_bits, and stop_bits are the number of bits for each “word” and the number of stop bits
  • parity defines if the controller must send the parity bit or not
  • flow_ctrl is the type of flow control (hardwaresoftware or disabled)

There are two additional parameters (rx_flow_ctrl_thresh and use_ref_tick) you can use to set the threshold for the RTS signal if hardware flow control is selected and to enable the REF_TICK signal as clock for the UART controller.

The constant values for data_bitsstop_bits… are declared in the uart.h file.

Often the parameters required to communicate with a serial device are expressed in a “condensed” format, for example if you read 9600,8N1 it means:

  • speed 9600 baud
  • “word” of 8 bits
  • No parity
  • 1 stop bit

Configure the controller with the method:

uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);

passing as parameters the number of the controller (uart_num) and the struct with the configuration previously defined (uart_config).

Conclude the configuration setting the pins the controller have to use for the different signals:

uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, 
  int rts_io_num, int cts_io_num);

You can use the UART_PIN_NO_CHANGE constant if that specific signal is not used or if you want to keep the default pin.

For example to map the controller to pins 4 and 5 without using the RTS and CTS signals:

uart_set_pin(UART_NUM_0, 4, 5, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

Now you can install the driver with:

uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, 
  int queue_size, QueueHandle_t* uart_queue, int intr_alloc_flags);

In addition to the controller number, you have to pass the size for the receive and transmit buffers. The parameters about queue and interrupts will be discussed in a future article.

The two buffers must have a size bigger than the corresponding hardware buffers (128). Only for the transmit buffer you can specify size = 0; in this case, the driver will be blocking, that is the execution of the task will be halted until the transmission ends.

Let’s now learn how to send data. To better understand the differences between the available commands, you have to understand that there are two buffers: one hardware, included in the UART controller, and one software, implemented in the driver:

uart-004

The first command to send data – to be used only if the software trasmit buffer is disabled – is uart_tx_chars():

int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);

This command sends len bytes from buffer. As you’re not using a software buffer, it may happens that the command cannot send all the bytes because the hardware buffer is full; the uart_tx_chars method therefore returns the number of bytes actually sent.

To use the software buffer, the uart_write_bytes() is available:

int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);

This command copies size bytes from the src array to the driver’s buffer: the driver will take care of filling the hardware buffer of the controller until all the data is transmitted. The uart_write_bytes() also retuns the number of bytes actually copied in the tx buffer.

When receiving, you can use the uart_read_bytes() command:

int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, 
  TickType_t ticks_to_wait);

The command reads a maximum of length bytes from the receive buffer and copies them in the buf array. The command waits for data the number of specified ticks, then returns the number of bytes actually read.

You can know the number of bytes at each moment available in the receive buffer with:

uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);

UART and stdio

The framework allows to use a UART controller as a peripheral for standard I/O. Unix streams stdin, stdout and stderr are indeed linked to RX and TX operations on that controller: you can therefore use standard C functions like printf()scanf()… to write and read from the UART controller.

Via menuconfig you can specify which controller to use, the parameters for the controller and you can also disable this feature at all:

uart-005

Demo

In the following video I’ll show how to work with UART controllers connecting one of them to a USB->serial converter. Both the converter and the esp32 devboard are connected to my laptop: in this way I can send data from the laptop to UART1 via the converter, read it and send it back to my laptop using the UART0 controller.

ESP8266 Deep Sleep with Arduino IDE

Deep-sleep-blog-1280-600

Rui Santos has written a great guide shows us what’s Deep Sleep and how to use it with the ESP8266 in the Arduino IDE.

With most of the ESP8266 modules, you can’t change the hardware to save power, but you can write software to do it. If you use the sleep functions with the ESP8266, it will draw less power and your batteries will last longer. In this guide, we’re going to talk about Deep Sleep with the ESP8266.

See the full post on his blog, Random Nerd Tutorials.

Check out the video after the break.

ESP32 (25) – Oled display with U8G2

If you read my post ESP32, Wemos or not to Wemos you know that I brought a development board, that happened to be a D-duino-32 clone, with an ESP-WROOM-32 module and a 0.96″ oled display.

This display, available also as a standalone module on several websites (for example on Banggood), has the following features:

  • size: 0.96 inches
  • resolution: 128×64 pixels
  • controller: SSD1306 with I2C interface
  • power supply: 3.3V – 6V

u8g2-00a u8g2-00b

It’s very easy to interface it with the esp32 chip thanks to the work of olikraus and Neil Kolban. The first wrote the u8g2 library, while the second implemented the specific functions of the u8g2’s hardware abstraction layer (HAL) for the esp32.

u8g2, installation

u8g2 is a fantastic library for monochrome displays: it supports several types of displays and controllers, it’s easy to port to new platforms and offers many methods to draw geometric figures, display images and write strings using different fonts.

Let’s learn how to use it in your project. First download the archive with the content of the library’s Github repository:

u8g2-01

If it doesn’t exist, create the components folder in the main folder of your project. Unzip the archive into that folder and rename the subfolder u8g2-master in u8g2:

u8g2-02

In the u8g2 folder create a file named component.mk with the following content:

u8g2-03

Now download the files u8g2_esp32_hal.c and u8g2_esp32_hal.h from nkolban’s repository:

u8g2-04

You can copy the two files in the main folder of your project:

u8g2-05

u8g2, configuration

To use the u8g2 library in your program, first include the header file:

#include "u8g2_esp32_hal.h"

The HAL configuration is stored in the u8g2_esp32_hal_t struct:

typedef struct {
  gpio_num_t clk;
  gpio_num_t mosi;
  gpio_num_t sda;
  gpio_num_t scl;
  gpio_num_t cs;
  gpio_num_t reset;
  gpio_num_t dc;
} u8g2_esp32_hal_t;

The library supports both I2C and SPI displays: this is the reason why you see in the struct fields related to the two buses.

You can define and initialize the struct with default values with:

u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT;

The oled display of the D-duino-32 board has an I2C interface connected to esp32’s pin 4 (SCL) and 5 (SDA):

u8g2_esp32_hal.sda = 5;
u8g2_esp32_hal.scl = 4;

When the configuration of the struct is complete, you can use the u8g2_esp32_hal_init() method:

u8g2_esp32_hal_init(u8g2_esp32_hal);

Now move to the configuration of the u8g2 library. Define an u8g2_t variable:

u8g2_t u8g2;

Based on the display you’re using, you have to choose the correct setup function. The parameters for the function are:

  • the pointer to the u8g2_t variable you defined before
  • a constant value that specifies the display rotation
  • two HAL functions to send data on the bus and to delay

The constants for the display roation are:

u8g2-06

and the two HAL functions developed by Kolban are:

  • u8g2_esp32_msg_i2c_cb
  • u8g2_esp32_msg_i2c_and_delay_cb

Here I’m using the setup function for the ssd1306 “noname” controller with the _f prefix that means full framebuffer:

u8g2_Setup_ssd1306_128x64_noname_f(
  &u8g2, U8G2_R0,
  u8g2_esp32_msg_i2c_cb,
  u8g2_esp32_msg_i2c_and_delay_cb);

framebuffer

full framebuffer means that all the data to send to the display are stored in the RAM memory of the microcontroller. This makes easier and faster to work with the display but consumes more RAM. The u8g2 library also supports a page buffer mode to save some memory. A comparison between the different modes, with pros and cons, is available on the library’s wiki.

Finally – if you’re using an I2C display – you have to specify its address (here 0x78):

u8x8_SetI2CAddress(&u8g2.u8x8,0x78);

u8g2, use

After the setup, initialize the display with:

u8g2_InitDisplay(&u8g2);

The display is now in power save mode, to “turn it on” you have to disable this mode with:

u8g2_SetPowerSave(&u8g2, 0);

Now you can call the different methods available to display text, images, shapes. If you’re using the full framebuffer mode, first prepare the buffer in memory and then send it to the display.

Prepare an empty buffer with ClearBuffer():

u8g2_ClearBuffer(&u8g2);

Now for example use the SetFont() and DrawStr() methods to write a string into the buffer with a specific font:

u8g2_SetFont(&u8g2, u8g2_font_timR14_tf);
u8g2_DrawStr(&u8g2, 2,17,"Hello World!");

and finally display the buffer’s content on the display with:

u8g2_SendBuffer(&u8g2);

u8g2-00c

Demo

In the following video I quickly explain how to install the library, how to prepare an image to be displayed and in the end you can see the execution, on my D-duino-32, of the example program available on Github.

A Certificate Authority with OpenSSL

The security of several protocols is implemented using SSL certificates. Usually, those certificates are created by public certificate authorities. If we’re connecting to a website (HTTPS protocol), the browser we’re using must recognize the identity of the CA that signed the server certificate, otherwise an error message is shown:

ca-002

A CA “creates” a new certificate signing it with its own certificate… you can find more than one level, for example the Google certificate (in blu) has been signed by an intermediate CA (green), whose certificate is signed by a root CA (red):

ca-001

To consider the certificate valid, the browser or the operating system must have the certificates of the CAs that signed it in their trusted repository:

ca-003

Today I’ll explain you how to create a CA using an opensource tool, OpenSSL. This CA will be very useful everytime you’ll need an SSL certificate for internal use.

After having installed the OpenSSL tool, create a new folder dedicated to the CA (in my example, MyCA).

Within the new folder, create some empty folders and files:

ca-004

Open the “serial” file and type the value 1000 (this will be the serial number of our first certificate).

Now download from my Github repository the openssl.cnf file and copy it in the MyCA folder. This file contains the whole configuration of the Certificate Authority.

Open the file and change the dir parameter with the path of your CA’s main folder:

ca-005

Now generate the private key of your CA. All the following commands must be issued in the MyCA folder:

openssl genrsa -aes256 -out private/ca.key.pem 4096

You’ll be prompted for a password; it’s very important to note it down because you’ll need it everytime you’ll use the CA.

Now generate the self-signed certificate for the CA:

openssl req -config openssl.cnf -key private/ca.key.pem -new -x509 -days 3650 
 -sha256 -extensions v3_ca -out certs/ca.cert.pem

OpenSSL will ask some information; the most important of which is the Common Name, that is the name which identifies your CA:

ca-006

Let’s now generate client or server certificates using your new CA.

Generating a new certificate starts from a private key, that will be safely stored on the system which will use the certificate (for example on the webserver that will publish the site in HTTPS). Then you have to generate a CSR (certificate signing request) from the key. The CSR is the file that will be signed by the CA to produce the final certificate.

As CA administrator, you can receive the CSR file from the end user; alternatively you can generate it using OpenSSL:

1. generate the private key (RSA algorithm) for your new certificate:

openssl.exe genrsa -out server.key

2. generate the CSR file:

openssl.exe req -new -config openssl.cnf -key server.key -out server.csr

Again you are prompted for some information, including the name (common name) of your server.

Now generate the certificate signing the request:

openssl.exe ca -config openssl.cnf -extensions server_cert 
 -notext -in server.csr -out server.cer

Confirm with two Y (yes) and your new certificate is ready:

ca-007

Pulse Oximeter functionality for a medical device

Pulse Oximeter on my finger-600

Alexander Lang writes:

The gentlemen for whom I’m developing this hardware for has requested some additional functionality. The additional functionality requested is a Pulse Oximetry measurement.  Pulse Oximetry is the measurement of a person’s pulse along with how much oxygen is present within their blood.  It is a common measurement made by medical practitioners to ensure their patients are in good health.  I suspect for the medical device, this information will be correlated with a person’s breathing to assess how well a person’s lungs are working and how much oxygen from the air is getting into their blood.

See the full post on his blog here.

ESP32 (24) – I2C a pratical example with HTU21D sensor

In my previous tutorial I explained how to use the I2C driver included in the esp-idf framework to communicate with I2C devices. Today I’ll show you a pratical example: the use of a temperature/humidity sensor.

The sensor

For this tutorial I chose the HTU21D sensor by Te Connectivity. This sensor offers a good level of accuracy and it’s available, already soldered on a breakboard, for few euros:

htu21d-00a htu21d-00b

htu21d-00c

Sparkfun was the first manufacturer to sell a board based on this sensor… even if now this board is retired, other websites (for example Banggood) sell similar products.

To connect the sensor to your esp32 development board, first you have to choose which pins will be used for SDA and SCL signals. Besides these, you have also to connect VDD (3.3V) and GND:

htu21d-00d htu21d-00e

htu21d-00f htu21d-00g

Datasheet and commands

After having completed the physical connection between the devboard and the sensor, you have to understand how to write a program that communicates with it. The first thing to do is certainly to read the datasheet of the sensor (here in PDF format). Do not be scared if you realize that it contains 21 pages of technical details, in the following paragraphs I’ll explain what are the information you absolutely have to know!

On page 10, it starts the chapter about the communication protocol (COMMUNICATION PROTOCOL WITH HTU21D(F) SENSOR). Immediately you read that the sensor offers an I2C slave interface with address 0x40; just below you can also find the table with the supported commands:

htu21d-001

The sensor offers two different modes when measuring temperature and humidity:

  • hold master
  • no hold master

In the first mode, the sensor blocks the clock signal (SCK) during measurement process: this means that the master can send the read command only when the measure is completed. In the second mode instead the master can operate on the bus (for example send commands to other devices) during the measurement process.

In no hold mode the master, after having sent the “trigger maesurement” command, must wait for the sensor to complete the measurement before reading the value. You can verify if the measuring process is complete sending to the sensor a read command and wait for the ACK: if you receive it, it means that the value is ready.

The sensor returns a raw value of 16bits (= 2 bytes). In addition to the value, it also returns a checksum byte; this byte allows the master to verify that no errors occurred when data was transmitted on the bus.

In the previous post you’ve already learned how to query a slave device; therefore the instructions to read the temperature value from a HTU21D sensor in no hold mode are:

// constants
#define HTU21D_ADDR			0x40
#define TRIGGER_TEMP_MEASURE_NOHOLD  	0xF3
 
// send the command
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, TRIGGER_TEMP_MEASURE_NOHOLD, true);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
 
// wait for the sensor (50ms)
vTaskDelay(50 / portTICK_RATE_MS);
 
// receive the answer
uint8_t msb, lsb, crc;
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (HTU21D_ADDR << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, &msb, 0x00);
i2c_master_read_byte(cmd, &lsb, 0x00);
i2c_master_read_byte(cmd, &crc, 0x01);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);

The code above waits 50ms before fetching the data; from the datasheet you can indeed read that the maximum measuring time is exactly 50ms for the temperature value at the maximum resolution:

htu21d-002

To convert the raw value into the “real” temperature (in °C) or humidity (in %) you can use the formulas in the datasheet:

uint16_t raw_value = ((uint16_t) msb << 8) | (uint16_t) lsb;
float temperature = (raw_value * 175.72 / 65536.0) - 46.85;
float humidity = (raw_value * 125.0 / 65536.0) - 6.0;

Resolution

The sensor offers 4 different resolution combinations for temperature and humidity:

  • humidity 12bit, temperature 14bit
  • humidity 8bit, temperature 12bit
  • humidity 10bit, temperature 13bit
  • humidity 11bit, temperature 11bit

You can select the resolution changing the value of a configuration register with the command write user register. Specifically, the registry bits to be modified are bit 0 and bit 7:

htu21d-003

CRC

The algorithm for verifying the CRC value is explained in the datasheet.

The polynomial used is x^8 + x^5 + x^4 + 1, in binary:

htu21d-004

First add to the polynomial as many zeroes as the bit length of the CRC:

htu21d-005

The resulting value, in hexadecimal, is 0x98800.

Add, at the right of the value you want to verify, the CRC value received from the sensor as third byte:

uint32_t row = (uint32_t)value << 8;
row |= crc;

Then check the input bit above the leftmost divisor bit: if the bit is 1, the input value is XORed to the divisor. Finally, the divisor is shifted one bit right:

for (int i = 0 ; i < 16 ; i++) {
 if (row & (uint32_t)1 << (23 - i)) row ^= divisor;  divisor >>= 1;
}

If, at the end of the process, the row value equals zero, the CRC is verified.

Component

I developed a component for the esp-idf framework that implements what explained in this post. The component is available on Github and the documentation about its use is published in a dedicated page.

Here’s a video about it: