How to make a datalogger with the ESP32 NodeMCU connected to a Django cloud on Raspberry

Introduction

In this article we will see how to use a Raspberry and REST APIs to receive and display, via a Django application, data detected by an ESP32 NodeMCU.

We have already seen in previous articles (Thermo-hygrometer with clock and LCD display on Arduino UNO, How to make a data logger with the ESP8266 NodeMCU connected to the Arduino Cloud, How to make a bluetooth datalogger for temperature and humidity using Arduino MEGA.) how to make data loggers to measure environmental temperature and humidity and display them in various ways (LCD display, Arduino Cloud, bluetooth). This time we will display them on a dashboard working on a Raspberry.

What are REST APIs?

The communication between the ESP32 and the Raspberry will take place through the “functions” exposed on the WiFi network by the Raspberry. The ESP32 will then periodically take measurements and send them to the Raspberry via a REST API. But what are these REST APIs?

REST APIs are interfaces that allow web applications to communicate with each other.

Through these interfaces (based on the classic client-server architecture), a client can send a certain request to a server which replies with the desired information or with a status information. The client can, for example, ask to read data, modify it, create it or delete it.
For this reason we have 4 types:

  • GET – to get specific information
  • POST – to enter a new information
  • PUT – to modify an existing information
  • DELETE – to delete an existing information

Our ESP32 will only use the POST type.

What will we do in this project?

This time, in addition to temperature and humidity, we will also measure atmospheric pressure and light intensity. These physical quantities are detected by an ESP32 NodeMCU with special sensors (in particular a DHT22 for temperature and humidity, a BMP180 for atmospheric pressure and a BH1750 for light intensity) and sent, via WiFi, at regular intervals to a Raspberry PI which receives them, as already mentioned, via a REST API. The data is sent from the ESP32 via this API to the Raspberry in Json format with the following format:

{
    "temperature": "56.48",
    "humidity": "19.82",
    "brightness": "93.82",
    "atmosphericPressure": "22.34"
}

The API, which is of type POST, looks like this:

http://IP_RASPBERRY:8000/api/measurement-items/

The API in question is part of a web application made in Django that runs on the Raspberry. This application takes care of receiving the data and writing them to a database created with Sqlite. A second Django application, also installed on the Raspberry, takes care of extracting data from the database and displaying them on a simple dashboard that can be queried via a browser at a URL like this:

http://IP_RASPBERRY:8000/view/showall

The two Django applications were tested on a Raspberry Pi 1 Model B and a Raspberry PI 3 Model B.

The dashboard will look like this (the data represented here is random):

Dashboard example shown by Raspberry
Dashboard example shown by Raspberry

In practice we will create an architecture like the one shown in the following image:

System architecture
System architecture

What components do we need?

The list of components is not particularly long:

  • a breadboard to connect the NodeMCU ESP32 to other components
  • some DuPont wires (male – male, male – female, female – female)
  • a DHT22 sensor
  • a 4.7kΩ resistor
  • a BMP180 sensor
  • a BH1750 sensor
  • an SD card with a size from 8GB to 32GB
  • an USB WiFi dongle for the Raspberry (if necessary)
  • and, of course, a Raspberry !

The SD card I used for the experiments is 16GB.

As already mentioned, the Django project has been tested on a Raspberry Pi 1 Model B and on a Raspberry PI 3 Model B but it is possible that it will also work on other Raspberry models.

Project realization

The wiring diagram

Before realizing the real circuit of the data logger let’s look at the pinout of the board:

ESP32 pinout
ESP32 pinout

We will use GPIO 14 to connect the DHT22 sensor.

The DHT22 sensor pinout is:

The DHT22 sensor and its pinout
The DHT22 sensor and its pinout

The pinout of the BMP180 is:

Pinout of the BMP180
Pinout of the BMP180

The pinout of the BH1750 is:

BH1750 pinout
BH1750 pinout

The BMP180 and BH1750 sensors are connected to GPIO 21 (SDA) and 22 (SCL) of the ESP32. These pins are part of a two-wire communication bus called I2C. This bus requires the presence of a master device (in our case the ESP32) which manages the communication and one or more slave devices (which in our case are the two sensors). The slave devices all have their own hexadecimal address in order to let the master understand which device a certain message is coming from or to make the master send a message to the right slave. In this way, conflicts between messages are avoided, since they travel on the same bus.

The BMP180 sensor has an address of 0xEF for reading and 0xEE for writing while the address of the BH1750 sensor can be set via the ADDR pin. In particular, we will have that:

  • the address is 0x23 if the voltage at the ADDR pin is less than 0.7 Vdc
  • the address is 0x5C if the voltage at the ADDR pin is greater than 0.7V

Fortunately, the addresses of the two devices do not coincide so we will not have message collisions.

In general, if two or more devices have the same address (not modifiable) it will not be possible to connect them to the same I2C bus.

At this point you can proceed to the creation of the circuit. Unfortunately, the ESP32 NodeMCU is too large to fit on the breadboard, which is why it will be connected with flying wires to the rest of the circuit.

Below is the wiring diagram created using Fritzing:

Wiring diagram
Wiring diagram

As you can see, the power for the three sensors is taken from the 3.3V output of the NodeMCU (pin 3V3). It is necessary to power the sensors with 3.3V so that their output is also 3.3V as the digital pins of the NodeMCU do not accept voltages higher than 3.3V.

WARNING: in the ESP32 NodeMCU the maximum voltage tolerated by the digital inputs is equal to 3.3V. Any higher voltage would damage it irreparably!!

The sketch

Let’s create the PlatformIO project

We have already seen the procedure for creating a PlatformIO project in the article How to create a project for NodeMCU ESP8266 with PlatformIO.

Although it refers to the ESP8266 board, the procedure is similar.
Simply, when choosing the platform, you will have to choose the AZ-Delivery ESP-32 Dev Kit C V4.

Of the libraries indicated, install, following the procedure, the DHT sensor library for ESPx by Bernd Giesecke (which is used to read the data transmitted by the DHT22 temperature and humidity sensor) and leave the other two alone (WiFiManager and UniversalTelegramBot).

We will install the WiFiManager library in another way later.

Install the library HttpClient by Adrian McEwen:

Install the HttpClient library on the PlatformIO project
Install the HttpClient library on the PlatformIO project

Install the library ArduinoJson by Benoit Blanchon:

Install the ArduinoJson library on the PlatformIO project
Install the ArduinoJson library on the PlatformIO project

Install the library Adafruit BMP085 Library by Adafruit:

Install the BMP085 library on the PlatformIO project
Install the BMP085 library on the PlatformIO project

Install the library BH1750 by claws:

Install the BH1750 library on the PlatformIO project
Install the BH1750 library on the PlatformIO project

We still have to install the WiFiManager library that we left pending. We will install it by editing the platformio.ini file and adding the entry https://github.com/tzapu/WiFiManager.git to the lib_deps section. The file will then look like this:

[env:az-delivery-devkit-v4]
platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps = 
	beegee-tokyo/DHT sensor library for ESPx@^1.18
	amcewen/HttpClient@^2.2.0
	bblanchon/ArduinoJson@^6.20.1
	https://github.com/tzapu/WiFiManager.git
	adafruit/Adafruit BMP085 Library@^1.2.2
	claws/BH1750@^1.3.0

Note the WiFiManager library added directly to this file.

Of course you can download the project from the following link:

Replace the main.cpp file of the project you created with the one present in the zip file.

Now let’s see how the sketch works.

The sketch begins with including the necessary libraries:

#include <Arduino.h>
#include "DHTesp.h"
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <WiFiManager.h>
#include <WiFiClientSecure.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <SPI.h>
#include <BH1750.h>
#include <math.h>

Then it continues with the creation of the objects related to the pressure, brightness, temperature and humidity sensors. GPIO14 is also defined as the data link for DHT22:

Adafruit_BMP085 bmp;  
BH1750 brightnessMeasure;


DHTesp dht;
#define  DHT22_PIN 14   

Then the internal variables are defined:

double temperature;
double humidity;
double brightness;
double atmosphericPressure;

unsigned long measureDelay = 600000;                //    NOT LESS THAN 2000!!!!!    BETTER 600000  (10 MINUTES)
unsigned long lastTimeRan;

Note that the measureDelay variable (which defines how often measurements must be taken and data sent) must not be less than 2000ms (corresponding to 2s) because the DHT22 takes about 2 seconds to make a measurement.

Now let’s create the WiFi client and define the API structure:

WiFiClientSecure client;

//Your Domain name with URL path or IP address with path
const char* serverName = "http://192.168.1.190:8000/api/measurement-items/";

Note that the API contains the IP address (192.168.1.190) which will later be defined for the Raspberry (ie this is the IP address of our Raspberry within the network). We will see later how to set this fixed IP on the Raspberry so that the router always assigns it the same. Obviously, nothing prevents you from choosing another IP (if this is already occupied by another device).

Then the round2 function is defined which is used to truncate the values ​​coming from the sensors to the second decimal place:

double round2(double value) {
   return (int)(value * 100 + 0.5) / 100.0;
}

At this point the setup function starts:

The serial port is activated:

Serial.begin(115200);
  // This delay gives the chance to wait for a Serial Monitor     without blocking if none is found
delay(1500); 

The I2C bus and the brightness sensor are activated:

Wire.begin();           

brightnessMeasure.begin();

Then a check is made on the presence of the pressure sensor:

if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP085/BMP180 sensor, check wiring!");      
    while (1) {}
  }

If the sensor is not present, an error message is printed and the board stops in an infinite loop given by the while (1). If, on the other hand, the sensor is present and functioning correctly, it is initialised.

Next is the part that manages the WiFi connection:

  //WiFiManager, Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wm;

  // reset settings - wipe stored credentials for testing
  // these are stored by the esp library
  // wm.resetSettings();

  // Automatically connect using saved credentials,
  // if connection fails, it starts an access point with the specified name ( "AutoConnectAP"),
  // if empty will auto generate SSID, if password is blank it will be anonymous AP (wm.autoConnect())
  // then goes into a blocking loop awaiting configuration and will return success result

  bool res;
  // res = wm.autoConnect(); // auto generated AP name from chipid
  // res = wm.autoConnect("AutoConnectAP"); // anonymous ap
  res = wm.autoConnect("AutoConnectAP","password"); // password protected ap

  if(!res) {
      Serial.println("Failed to connect");
      ESP.restart();
  } 
  else {
      //if you get here you have connected to the WiFi    
      Serial.println("Connected...yeey :)");
  }

Finally, the connection of the DHT22 to the ESP32 via the GPIO14 is defined:

dht.setup(DHT22_PIN, DHTesp::DHT22); // Connect DHT sensor to GPIO 14 

Immediately after that, the loop function starts.

Initially the HTTP client is defined and initialized, which we will need to send the data:

  HTTPClient http;

  http.begin(serverName);

Then begins an if block that contains several functions within it.

The condition inside the if determines the time interval with which the measurements are made and the data sent:

if (millis() > lastTimeRan + measureDelay)  {

So the described events happen every measureDelay ms thanks to this condition.

Continuing with the if, we see that the measurements of the physical quantities of our interest are made and the lastTimeRan variable is updated with the current value in ms:

humidity = dht.getHumidity();
temperature = dht.getTemperature();
brightness = brightnessMeasure.readLightLevel();
atmosphericPressure = bmp.readPressure() / 100.0;             

lastTimeRan = millis();

Immediately afterwards, the Json document containing the data to be sent to the Raspberry is created:

http.addHeader("Content-Type", "application/json");

DynamicJsonDocument jsonToSend(1024);
jsonToSend["temperature"] = round2(temperature);            
jsonToSend["humidity"] = round2(humidity);
jsonToSend["brightness"] = round2(brightness);
jsonToSend["atmosphericPressure"] = round2(atmosphericPressure);

String jsonToSendStr;
serializeJson(jsonToSend, jsonToSendStr);

The Json document just created is then sent to the API with the POST method and the HTTP code received from the Raspberry is printed on the Serial Monitor (if the transmission was successful, the code is 200):

int httpResponseCode = http.POST(jsonToSendStr);

Serial.println("\nHTTP response code: " + String(httpResponseCode));

Finally the client is terminated:

http.end();

At this point you just have to upload the sketch to the board and connect it to the WiFi network.

How to connect the board to the Internet

After uploading the sketch to the board, open the Serial Monitor to see the messages coming from the device.

First the board goes into Access Point mode and will give us an IP address which we will use shortly. This operation is used to connect the board to the Internet without having to enter the WiFi network parameters (SSID and password) in the code.

The board provides us with its IP address
The board provides us with its IP address

In this case the IP address is 192.168.4.1.

At this point the ESP32 is in Access Point mode (with SSID AutoConnectAP) and we need to connect our computer to the AutoConnectAP network. If we go to the networks menu of our computer, we should also see the AutoConnectAP network in the list of wireless networks.

List of available WiFi networks
List of available WiFi networks

Connect the computer to the AutoConnectAP network. Then go to your browser and enter the IP previously provided by the ESP32 (which in this example is 192.168.4.1)

You will see a screen like this:

The browser screen for choosing the network
The browser screen for choosing the network

Click the ConfigureWiFi button. It will show you the available networks:

List of available networks
List of available networks

Choose the SSID of your network:

Choose your network
Choose your network

Enter your network password and click the save button:

Enter the password
Enter the password

The response of the board
The response of the board

The ESP32 module keeps the access parameters memorized even if you turn it off, it will remember them on restart and it will reconnect automatically without having to repeat this procedure. Only if you reset it by uncommenting this line

// wm.resetSettings();

it will lose the connection parameters.

Please note: the device can memorize only one network. If you later connect it to another network, it will forget the previous network settings.

Raspberry setting up

In order to install the Django application, whose task is to collect and save the data transmitted by the ESP32 in the database and show them on the dashboard, on the Raspberry it is necessary to take some preliminary steps and install some software.

Let’s start right away with installing the operating system.

The chosen operating system is a distribution made to work on all types of Raspberry, even the most dated ones. As already specified elsewhere, the tests were done on a Raspberry Pi 1 Model B and on a Raspberry PI 3 Model B.

If the Raspberry doesn’t have a native wireless connection, you can use a WiFi dongle to plug into one of its USB sockets.

Let’s download and install the operating system on the SD card

You can download the image I used from the link below:

Otherwise, if you want the latest version, go to https://www.raspberrypi.com/software/operating-systems/

and navigate to the Raspberry Pi OS (Legacy) section. You will download a version that has no graphical environment so that it is as light as possible:

The chosen distribution
The chosen distribution

The downloaded file will be compressed in xz format. To unpack it on Linux you will first need to install the tool:

sudo dnf install xz           on CentOS/RHEL/Fedora Linux.
sudo apt install xz-utils     on Ubuntu/Debian

and then give the command:

xz -d -v filename.xz

where filename.xz is the name of the file you just downloaded containing the operating system.

On Windows it will be sufficient to use one of these tools: 7-Zip, winRAR, WinZip.

The result will be a file with the img extension which is the image to be flashed on the Raspberry SD card.

To flash the image to the SD card you will use the tool Balena Etcher that works on both Linux and Windows as well as MACOS.

Its use is very simple: just select the image to be flashed, the destination SD card and press the Flash button.

Here’s what its interface looks like:

The interface of the Balena Etcher tool
The interface of the Balena Etcher tool

The image to be flashed is set on the left, the SD card to be flashed in the centre, the button to start the flashing operation on the right.

At the end of the operation the SD card will contain two partitions: boot and rootfs. In the device manager on Linux, a menu like this appears:

Devices menu on Linux
Devices menu on Linux

Windows will also show a menu like this: from your file explorer, under This computer you will see the 2 partitions.

Now, with a text editor, create a file on your computer that you will call wpa_supplicant.conf and that you will edit like this:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=«your_ISO-3166-1_two-letter_country_code»
network={
     ssid="«your_SSID»"
     psk="«your_PSK»"
     key_mgmt=WPA-PSK
}

You will need to replace the following items:

  • «your_ISO-3166-1_two-letter_country_code» with the identifier of your country (for example for Italy it is IT)
  • «your_SSID» with the SSID name of your WiFi network
  • «your_PSK» with the password of your WiFi network

At this point, you will need to create an empty file that you will call ssh (with no extension).

The new distributions do not have the classic pi user with raspberry as password so, to be able to enter SSH, we must provide another way.

With a working Raspberry we need to create a file called userconf which will contain the user we want to create with an encrypted version of the password we want to assign to him. The format will therefore be username:password-hash.

Suppose we want to keep the user pi, we need to create the password-hash. Suppose we want to create the hash of raspberry as password, again on the Raspberry where we created the userconf file. We must issue the following command from the shell:

echo "raspberry" | openssl passwd -6 -stdin

This command will return the raspberry password hash. For example it could be a string like this:

$6$ROOQWZkD7gkLyZRg$GsKVikua2e1Eiz3UNlxy1jsUFec4j9wF.CQt12mta/6ODxYJEB6xuAZzVerM3FU2XQ27.1tp9qJsqqXtXalLY.

This is the raspberry password hash that I calculated on my Raspberry.

Our userconf file will then contain the following string:

pi:$6$ROOQWZkD7gkLyZRg$GsKVikua2e1Eiz3UNlxy1jsUFec4j9wF.CQt12mta/6ODxYJEB6xuAZzVerM3FU2XQ27.1tp9qJsqqXtXalLY.

PLEASE NOTE: it is necessary to calculate the hash with a Raspberry because the hash calculated with the computer uses another algorithm which would not allow the Raspberry we are preparing to recognize the password.

Alternatively you can download from the link below the userconf file that I created to have a pi user with raspberry as password.

Now open the boot partition on the SD card and copy the three files wpa_supplicant.conf, ssh and userconf into it. Safely remove the SD card from the computer and insert it into the Raspberry.

Turn on the Raspberry, wait a few minutes. In order to ssh into the Raspberry, you will need to find out what its IP is (the one that the router has assigned to it via DHCP).

To do this, simply issue the command from a PC shell:

ping raspberrypi.local 

valid on both Linux and Windows (after installing Putty on Windows).

In my PC the Raspberry responds like this:

Raspberry response to ping
Raspberry response to ping

This makes me realize that the assigned IP is 192.168.43.27.

Alternatively you can use the tool Angry IP Scanner or you can access your router settings to see the devices connected via WiFi and find out which IP the Raspberry has.

To be able to log into the Raspberry in ssh, give the shell command:

with password raspberry. On Windows you need Putty.

Once inside the Raspberry run the following commands to update the software:

sudo apt update
sudo apt upgrade

The password is always raspberry.

Let’s configure the timezone

To configure the timezone run the command:

sudo raspi-config

to the Raspberry shell. Suppose we want to set the time zone of Rome.

A screen like this will appear:

Initial screen of sudo raspi-config command
Initial screen of sudo raspi-config command

Select the localization option and click Ok:

Localization option selected
Localization option selected

Then select the option of the timezone and give Ok:

Selected the timezone option
Selected the timezone option

Now select the geographical area and give Ok:

Selected the geographical area
Selected the geographical area

Finally select the city and give Ok:

City selected
City selected

Done!

Restart the Raspberry by giving the command:

sudo reboot

and, after a few minutes, enter using ssh as you did before.

Give the command

date

The Raspberry should now show the correct date and time.

Let’s set the static IP

In order for the Raspberry to always have the same IP address, we need to set it to be static. In my tests I set it to 192.168.1.190. If we didn’t do this, the router would assign it a different IP at each reboot which would force us to change the IP address of the API in the ESP32 sketch and the URL we have to use on the browser to see the dashboard.

We will proceed in two steps:

  • we will set the fixed IP in the Raspberry
  • we’ll set up the router to reserve that address for our Raspberry

For the first point, give the command:

nano /etc/dhcpcd.conf

to open the dhcpcd.conf file and edit it.

At the end of the file you will need to add a block like this:

interface [INTERFACE]
static_routers=[ROUTER IP]
static domain_name_servers=[DNS IP]
static ip_address=[STATIC IP ADDRESS YOU WANT]/24

where:

  • [INTERFACE] is the name of the WiFi interface (in our case it will be wlan0)
  • [ROUTER IP] is the address of our router (usually something like 192.168.0.1 or 192.168.1.1). You can find it by logging into the administration interface of your modem/router
  • [DNS IP] it is the address of the DNS server, which generally coincides with the [ROUTER IP] parameter of the modem/router
  • [STATIC IP ADDRESS YOU WANT] is the IP address that we want to assign as a fixed IP to the Raspberry

So, assuming that [ROUTER IP] = [DNS IP] = 192.168.1.1 and that [STATIC IP ADDRESS YOU WANT] = 192.168.1.190, the block will look like this:

interface wlan0
static_routers=192.168.1.1
static domain_name_servers=192.168.1.1
static ip_address=192.168.1.190/24

Restart the Raspberry with the command

sudo reboot

and then log into ssh again, this time with IP 192.168.1.190.

As a second step we will set the router to reserve the address 192.168.1.190 for our Raspberry. Each modem/router is different from the others but more or less they look alike. I will show here what mine looks like.

To log in, I type the address 192.168.1.1 (because my modem has this IP) on the browser and, after entering the administrator password, I can see at the main screen. From here I have to look for the screen related to access control.

Adding a static IP to the Raspberry
Adding a static IP to the Raspberry

There will be a button to add a static IP: add the chosen IP combined with the MAC address of the Raspberry WiFi interface. However, I advise you to consult the instruction manual of your modem / router for this operation.

Now check that the Raspberry connects to the network by issuing the command:

ping www.google.com

If you get the response to the ping the network is connected. If you get a message like “Network is unreachable” issue the command

sudo route add default gw [ROUTER IP]  

where [ROUTER IP] is the gateway which in our case is the IP of the router, i.e192.168.1.1

Let’s install some indispensable tools and the virtual environment

Let’s proceed now by installing some indispensable tools.

First you will install the sqlite database manager by typing the command:

sudo apt install sqlite3

We will need this program later when we use the getdata.sh script.

Then we need to install the pip3 command which allows us to install additional packages and libraries for Python (since Django is built with this language).

On the Raspberry shell, issue the command:

sudo apt install python3-pip

which will install pip3.

At this point you have to install the command that creates the virtual environment by giving the following command:

sudo pip3 install virtualenv

Virtualenv it is a virtual environment that remains isolated from the rest of the operating system. Once created, it allows us to install packages and libraries of the version we need inside it without conflicting with the system ones. In this way we can create an environment in which each project can have its own libraries and requirements (with different versions) without risking that they conflict with each other and with the system ones.

Now create a folder named testDjango (or whatever you prefer) and enter it with the commands:

mkdir testDjango
cd testDjango

Once inside the testDjango folder you can create the virtual environment that you will call myenv by giving the command:

virtualenv myenv

Inside the testDjango folder the myenv folder will be created with, inside, all the files necessary for our virtual environment.

Now all that remains is to activate it by issuing the command:

source myenv/bin/activate

You will notice that the command prompt will change to look like this:

(myenv) pi@raspberrypi:~/testDjango $ 

The label (myenv) means that the myenv virtual environment is active.

PLEASE NOTE: to deactivate the virtual environment it is sufficient to give the command

deactivate

At this point you will have to upload the folder with the Django application inside the testDjango folder. To do this, turn off the Raspberry, remove the SD card and insert it into the PC.

Download the project from the link below:

Open the rootfs partition of the SD card and enter the /home/pi folder. Then enter the testDjango folder, copy the project in there and unzip it. You should end up with a restMeasurements folder with the project files inside. Extract the SD card from the PC, insert it into the Raspberry, start the board and log in again with ssh.

Enter the testDjango folder:

cd testDjango

Activate the virtual environment:

source myenv/bin/activate

Now enter the project folder with the command:

cd restMeasurements

This folder, in addition to the project files, contains the requirements.txt file which contains the list of packages (with the right versions) to be installed to make the application work.

The file looks like this:

asgiref==3.4.1
Django==3.2.6
djangorestframework==3.12.4
pytz==2021.1
sqlparse==0.4.1

You will now install these packages with the indicated versions inside the virtual environment by issuing the command:

pip3 install -r requirements.txt

Since here pip3 is a command of the virtual environment (and not of the system), the packages will be installed in it, without interfering with those of other virtual environments or with those of the system.

Giving the command

pip3 list

you will get the list of packages installed in this virtual environment:

Package             Version
------------------- -------
asgiref             3.4.1
Django              3.2.6
djangorestframework 3.12.4
pip                 23.0.1
pytz                2021.1
setuptools          67.4.0
sqlparse            0.4.1
typing_extensions   4.5.0
wheel               0.38.4

Still with the virtual environment activated, clean up the database like this:

enter the restMeasurements folder

cd ~/testDjango/restMeasurements/

delete the file containing the database

rm -f db.sqlite3

recreate the database

python manage.py migrate

At this point there is another small change: we have to set the Django application so that it recognizes the IP assigned to the Raspberry (in this case 192.168.1.190) and we have to set the timezone.

Go into the measurement_cart folder

cd measurement_cart/

to edit the settings.py file by issuing the command

nano settings.py

look for the label

ALLOWED_HOSTS

and add the IP of the Raspberry to the list.

So if that line at the beginning looks like this:

ALLOWED_HOSTS = ['127.0.0.1', 'localhost']

it should become like this:

ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '192.168.1.190']

Then go to the TIME_ZONE section and set the appropriate timezone. For example, the timezone for Italy is Europe/Rome. So this section, in the case of Italy, would look like this:

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'Europe/Rome'

USE_I18N = True

USE_L10N = True

USE_TZ = True

You are now ready to start the server. Go back to the restMeasurements folder with the command:

cd ~/testDjango/restMeasurements/

and start the server:

python manage.py runserver 0.0.0.0:8000

If all went well, the following messages will appear:

(myenv) pi@raspberrypi:~/testDjango/restMeasurements $ python manage.py runserver 0.0.0.0:8000
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
March 03, 2023 - 09:11:53
Django version 3.2.6, using settings 'measurement_cart.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

This means the server is listening on port 8000.

Now go to your browser and type in the URL

http://192.168.1.190:8000/view/showall

This screen will appear:

Dashboard home screen
Dashboard home screen

If you press the Refresh button, the data will appear (at the moment the database is empty so only the graph legends will appear):

The dashboard without data
The dashboard without data

At this point turn on the data logger with ESP32 that you should have already connected to WiFi. Hopefully the Raspberry should start collecting data and saving it to the database and displaying it every time you hit the Refresh button.

PLEASE NOTE: the ESP32 board will send the first data after a time equal to that set in the measureDelay variable. If, for example, this time is equal to 10 minutes, the first measurement will be made 10 minutes after the ESP32 is turned on.

This is my dashboard after one day of logging data measured every 10 minutes:

The dashboard with data for one day
The dashboard with data for one day

To stop the server (which therefore will no longer receive data from the ESP32 nor will it show them on the dashboard) just press the CTRL key followed by the letter C.

A slightly annoying problem due to the way we started the server so far is that if, with the server active, we close the shell, the server will be closed and the application will no longer work. But there is a way to make it continue to work even if you close the shell by modifying the startup command slightly like this:

nohup python manage.py runserver 0.0.0.0:8000 &

How to extract saved data from the database for subsequent processing

Sometimes we may need to extract data from the database in order to put them, for example, on a spreadsheet to further process them with some ad hoc tool.

A small script that can be found in the restMeasurements folder and which is called getdata.sh comes in handy.

So, finding ourselves in that folder and giving the command like this:

./getdata.sh

this will generate a file, called data.csv, in CSV format containing all the database records stored up to that moment.

So here’s an example of what the contents of this file look like:

pi@raspberrypi:~/testDjango/restMeasurements $ cat data.csv 
id,temperature,humidity,timestamp,atmosphericPressure,brightness
1,16.9,53.8,"2023-02-25 06:04:25.741774",989.31,0
2,17.1,53.5,"2023-02-25 06:14:25.710678",989.17,0
3,17.1,53.9,"2023-02-25 06:24:25.862770",989.17,33.33
4,16.9,53.7,"2023-02-25 06:34:25.756406",989.13,0
5,17,54.7,"2023-02-25 06:44:27.664863",988.78,0
6,16.9,55,"2023-02-25 06:54:25.939375",988.77,0
7,16.9,55.1,"2023-02-25 07:04:25.719414",988.74,0.83
8,16.9,54.8,"2023-02-25 07:14:25.713820",988.46,3.33
9,16.9,54.6,"2023-02-25 07:24:25.861219",988.52,2.5
10,16.9,55.8,"2023-02-25 07:34:25.808413",988.43,2.5
11,16.8,55.6,"2023-02-25 07:44:25.712195",988.4,3.33
12,16.8,55.5,"2023-02-25 07:54:25.650290",988.37,0.83
13,16.8,55.4,"2023-02-25 08:04:25.828069",988.35,0.83
14,16.6,53.3,"2023-02-25 08:14:25.697565",988.35,0.83
15,16.7,55,"2023-02-25 08:24:25.713511",988.33,0.83
16,16.7,54.3,"2023-02-25 08:34:25.848961",988.59,0.83
17,16.8,54.6,"2023-02-25 08:44:25.628505",988.64,0.83
18,16.8,55.4,"2023-02-25 08:54:25.718198",988.64,1.67
19,16.8,55.2,"2023-02-25 09:04:25.823875",988.35,1.67
20,16.9,56.4,"2023-02-25 09:14:25.850034",988.05,2.5
21,16.9,55.1,"2023-02-25 09:24:25.649983",987.93,1.67
.....
.....

This file was viewed by giving the command:

cat data.csv

You can then remove the SD card from the Raspberry (obviously switched off) and put it in your PC to extract the file and copy it to a folder to then open it with a spreadsheet, process it, calculate statistics and so on.

PLEASE NOTE: Django stores data in the database using UTC time zone which corresponds to Greenwich Mean Time. Therefore the timestamps extracted with the script and present in the data.csv file reflect this time and do not take into account the timezone.

The times present in the graphs are fixed on the fly with the right timezone (previously set in the settings.py file) before being displayed.

The image for the Raspberry already ready

The previous procedure for setting up the Raspberry with the installation and setting of the necessary programs is not particularly complex but I realize that for a beginner it could represent an obstacle and prevent him from completing the project.

In this regard I have prepared an image created with the same procedure described above and freely downloadable from the link below:

In this way you will have the operating environment already functioning without having to follow the previous procedure.

You just have to download the image, decompress it and flash it on the SD card using the Balena Etcher tool (although Balena Etcher is still able to decompress gz compressed files by itself).

Once the image is flashed to the SD card, open the rootfs partition and navigate to the /etc/wpa_supplicant/ folder. Open the wpa_supplicant.conf file which looks like this:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=«your_ISO-3166-1_two-letter_country_code»
network={
     ssid="«your_SSID»"
     psk="«your_PSK»"
     key_mgmt=WPA-PSK
}

With a text editor you will need to replace the following entries:

  • «your_ISO-3166-1_two-letter_country_code» with the identifier of your country (for example for Italy it is IT)
  • «your_SSID» with the SSID name of your WiFi network
  • «your_PSK» with the password of your WiFi network

and then save the file.

You may need administrator privileges to edit and save the file.

Alternatively, you can insert the SD card into the Raspberry, power it up and connect the Raspberry to the router with a LAN cable, find the IP assigned by the router with one of the methods explained above and log into ssh. At this point issue the command:

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

and you can edit the file as explained before. The password is raspberry.

Unplug the LAN cable, turn the Raspberry off and on again. Hopefully it should automatically reconnect to WiFi.

In this image the IP is set to 192.168.1.190 so you will have to set your router/modem accordingly so that it can reserve the IP for the Raspberry.

Consider that even if at first you may find it difficult to connect via WiFi, you can always connect it to the router with a LAN cable and ssh with the IP provided by the router and make any necessary corrections in the WiFi setting.

Newsletter

If you want to be informed about the release of new articles, subscribe to the newsletter. Before subscribing to the newsletter read the page Privacy Policy (UE)

If you want to unsubscribe from the newsletter, click on the link that you will find in the newsletter email.

Enter your name
Enter your email
Scroll to Top