14. Networking and communications¶
This week assignment we should design, build, and connect wired or wireless node(s) that communicate with each other via network or bus (addresses). The purpose is to know how integrate components in a network and how to make them interact with each other via the network.
Wireless communication - version 1¶
Previously I have designed a board that reads the value from a distance sensor and shows it in a OLED screen. This week I decided to add these components in a wireless node and exchange the information via WiFi. The sensor will send the distance read and the OLED will show it in a way that they can be located in different locations and still communicate with each other.
Wemos¶
Up to now, I was using ATtiny in the assignments, however this week this was not possible. ATtiny does not have enough memory available to load all the code necessary to enable the node to communicate with each other. So, I decided to use Wemos that is a WiFi development board base on ESP8266 (standard board for WiFi communication). The functioning of this board is similar to a NodeMCU, except that the hardware resembling Arduino UNO. It is a powerful board and I will fit perfectly to design the solution of the assignment of this week. For more info, visit their website WEMOS Home
Wemos Sensor¶
I have designed a very simple circuit for this assignment. I have used the sensor VL53L0X (also used in the 11. Input devices assignment) with Wemos. Wemos will be configurated to read the sensor value and send via MQTT using the ESP8266 board (WiFi) to another node that will be listening for the sensor value. The pins SCL and SDA from VL53L0X were connected to D1 and D2 from Wemos. VCC from the sensor were connected to 3.3V Wemos pin.
As I have made a couple of boards in previous assignments, I decided this week to focus in the communication between the nodes I designed. 11. Input devices assignment provides the detailed steps on how to design, mill, and sold customized PCBs. Bellow there is the gerber files generated from the designed PCB which you can mill the board using the mentioned steps in previous assignment.
Download the ZIP file containing Gerber files to mill the mentioned board.
Wemos OLED¶
Again, I have designed a very simple circuit. I have used the OLED 128x32 I2C (also used in the 13. Output devices assignment) with Wemos. Wemos will be configurated to get data from the sensor via MQTT using the ESP8266 board (WiFi) and update the distance value in the OLED screen. The pins SCL and SDA from OLED were connected to D1 and D2 from Wemos. VCC from the sensor were connected to 3.3V Wemos pin.
I follow the strategy explained in the previous section, and I provide the gerber file to mill the board.
Download the ZIP file containing Gerber files to mill the mentioned board.
MQTT¶
The Message Queuing Telemetry Transport (MQTT) is a standard messaging protocol for Internet of Things (IoT). It is designed as an extremely lightweight publish/subscribe messaging transport that is ideal for connecting remote devices with a small code footprint and minimal network bandwidth. Using MQTT, one node A can subcribe one topic X and another node B can publish messages to this topic that will be received by the node A. Many nodes can subscribe the same topic as well as many nodes can publish messages to the same topic. This easily create a N to N communication between different devices, not just IoT. Bellow the esquematic of how the communication happens between the devices when using MQTT (more info).
The communication requires a server and I decided to use a Raspberry Pi to create the WiFi network and also to host the MQTT Broker. The configuration will be present bellow.
Setup¶
The setup for the assignment requires the following steps:
- Prepare Raspberry Pi
- Configurate Raspberry Pi as AP
- Install MQTT
- Install libraries in the ArduinoIDE
Raspberry Pi¶
I followed up the steps described at Raspberry Pi setting up to install the Operation System Raspberry Pi. It also gives some details about the device and its capability. First I installed the Raspberry Pi Imager. Then I wrote the operation system RASPBERRY PI OS (32-BIT) files in a SDHC CARD. The device was ready to be configurated.
Access Point (AP)¶
In order to have a dedicate network, I have setup the Raspberry Pi as Access Point (AP) following the steps in Access point routed. I did not execute the step Enable routing and IP masquerading because it was not necessary for the purpose of this assignment.
Here are the steps taken to prepare the environment to setup the AP.
-
Install hostapd.
sudo apt install hostapd
-
Enable wireless access point service and set it to start during boot
sudo systemctl unmask hostapd sudo systemctl enable hostapd
-
Install dnsmasq.
sudo apt install dnsmasq
-
Finally, install netfilter-persistent and its plugin iptables-persistent. This utilty helps by saving firewall rules and restoring them when the Raspberry Pi boots
sudo DEBIAN_FRONTEND=noninteractive apt install -y netfilter-persistent iptables-persistent
Here are the steps taken to setup the network router.
-
Change the IP address for DHCP server in the raspberry pi (file /etc/dhcpcd.conf). It is important to have an static IP address to avoid the need of updating the nodes every time the raspberry pi reboot and change the IP address. Initially I used the interface name wlan1 to avoid name problem current configuration of raspberry pi that has wlan0. I learned that the interface name is associated to the network board in the raspberry pi and should match it. So I used the name wlan0. The IP address can have different numbers as long it uses the same format (10.20.30.40 would be a valid value as well). I followed the standard numbers for IP address, just changing the last two digits.
interface wlan0 static ip_address=192.168.4.1/24 nohook wpa_supplicant
-
Configure the DHCP and DNS services for the wireless network
-
Save previous file to have a backup if I needed undo some configuration.
sudo mv /etc/dnsmasq.conf /etc/dnsmasq.conf.orig
-
Create a new one with the same name in the same location
sudo nano /etc/dnsmasq.conf
-
Add the following content:
interface=wlan0 # Listening interface dhcp-range=192.168.4.2,192.168.4.20,255.255.255.0,24h # Pool of IP addresses served via DHCP domain=wlan # Local wireless DNS domain address=/gw.wlan/192.168.4.1 # Alias for this router #raspberry pi can be reached by gw.wlan from wireless client.
-
-
Ensure wireless operation. To ensure WiFi radio is not blocked on your Raspberry Pi, execute the following command:
sudo rfkill unblock wlan
-
Configure the access point software. Create the file sudo nano /etc/hostapd/hostapd.conf and add the following content. You can choose the ssid of your interest and a better password (wpa_passphrase).
country_code=GB interface=wlan0 ssid=FabAcademy hw_mode=g channel=7 macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_passphrase=fabacademy wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP rsn_pairwise=CCMP
-
Run your new wireless Access Point.
sudo systemctl reboot
-
Devices able to connect to WiFi can now see a new connection called FabAcademy (if you choose the same name above). Check which devices are connected in your AP.
arp -a -n
Install MQTT¶
Continuing the installation still in the raspberry pi, install mosquitto and mosquitto-clients softwares. They will serve as MQTT Broker to enable the communication between the devices.
sudo apt-get install mosquitto
sudo apt-get install mosquitto-clients
Check if the MQTT broker is running (after reboot). Open two terminals and execute:
-
Terminal One
mosquitto_sub -h localhost -t intellettoTest
-
Terminal Two
mosquitto_pub -h localhost -t intellettoTest -m "Testing1" mosquitto_pub -h 192.168.4.1 -t intellettoTest -m "Testing2"
The messages Testing1 and Testing2 should be printed in the Terminal One.
You can install mosquitto for windows here and exchange messages with the MQTT Broker. Do not forget to connect in the same network FabAcademy. Executing the following command, it should appear in the Terminal One the message Testing3.
mosquitto_pub -h 192.168.4.1 -t intellettoTest -m "Testing3"
Install libraries in the ArduinoIDE¶
In my work PC, it was necessary to install the board Esp8266 to enable configurate the WiFi board (includes also the library ESP8266Wifi) and PubSubClient to enable exchange message via MQTT Broker. Previously I have installed VL53L0X to be able to read the distance sensor and Tiny4OLED to show content in the OLED. I was able to reuse the library to read the distance sensor, but I needed to install the library U8g2 to show the content in the OLED. The libraries can be installed in the menu Sketch > Include Library > Manage Libraries….
To install the board and library Esp8266, follow the steps (also here):
- Add the link http://arduino.esp8266.com/stable/package_esp8266com_index.json in the Additional Boards Manager URL (menu: File > Preferences)
- Install board Esp8266 (menu: Tools > Board > Board Manager)
- Select the correct board type for the Wemos.
Initially I have installed the most recent version of the board Esp8266. However this version re-implements some standard libraries from ArduinoIDE and I had difficulties to work with these libraries, since it changed or did not implement the methods I needed to use. I have decided to install the version 2.3.0 which a specialist told me to be a stable version that provides the methods I need to use. The environment is ready to move to the implementation.
Programming¶
I studied the project Intel.letto to understand how I could implement the solution in my assignment. I will need two programs: (i) for the distance sensor and (ii) for the OLED screen. Trying to centrilize the common code that both programs would have, I create a module week14functions declaring the variables and functions in the header file (.h) and implementing them in the definition file (.c). ArduinoIDE was not able to compile the .c file, so I copied the definitions inside the header file (similar to what was done in the Intel.letto project). The code was working fine, until I face some errors and needed to change the version of the board Esp8266. Then the wemos could not connect in the WiFi anymore.
The library PubSubClient provides some code example, I checked if the wemos was working by adapting the example file mqtt_esp8266 to connect in the WiFi i have configurated for this assignment (mqtt_esp8266_example). Then, Wemos was able to connect in the WiFi again. I tried to check what was the problem of the previous code, comparing line by line with the code example, but I could not find the reason. So, to implement the solution for the assignment, I used the code example integrating the necessary code to read the distance sensor and to show it in the OLED (using the MQTT communication).
WemosESP8266 Sensor¶
I have extended the example mqtt_esp8266 to work with the distance sensor VL53L0X. I have created the file mqtt_esp8266_sensor.ino including the library VL53L0X that enables to get the sensor measurement. I also added the library Wire.h to setup the I2C communication between the Wemos and the sensor. I used the pins D1 and D2 from wemos to work with the SDA and SCL, respectively, of the distance sensor. Following the code of the sensor.
-
Include libraries and declare variables that will be used in the program.
-
Function that connects to the Wifi configurated in the Raspberry Pi. The variables ssid and password should match the ones configurated in the raspberry pi.
-
These are the functions that perform MQTT operations. The function mqttMessageCallback is called when the node receives a message via a topic that previously subscribed. The second one, setupMqttClient, initialize a client for the MQTT. mqttSubscribeTopic executes the library call to subscribe a topic in the MQTT Broker and mqttPublishMessage sends a message for a topic registered in the MQTT Broker. The function mqttReconnect reconnect the node in the MQTT Broker. And the last one handleMQTTClient check if the node has received any message, which triggers the function mqttMessageCallback.
-
The setup function stablishes the connection with the WiFi and the MQTT Broker, but also setup the sensor to work with the wemos in the defined pins mentioned before. The loop function will simply checks if the node received message (only for test purpose since this node is not configurated to process received messages) and reads and sends the sensor measurement to the topic mqttOLEDListener that is registered to the wemos OLED (explained bellow).
Download the INO file from the microcontroller code that manage the sensor.
WemosESP8266 OLED¶
I have also create an extension of the code example, named mqtt_esp8266_OLED. I have included the library u8g2lib that shows messages in the OLED screen. I have also added the library Wire.h to setup the I2C communication between the Wemos and the OLED. I also used the pins D1 and D2 from wemos to work as the SDA and SCL, respectivelly, of the OLED. Following the code of the OLED.
-
The list of libraries and variables are similar, differing in the library u8g2lib for the OLED and the variables used to manage the OLED.
-
Here it was used the same function to connect in the WiFi (showed before).
-
The functions to perform MQTT operations are very similar to the ones showed before, except for the function mqttMessageCallback, that update the OLED screen with the message received.
-
These two functions are to support updating content in the OLED screen. initial_display only shows an initial message to confirm the OLED is setup correctly. update_oled print the message received via MQTT Broker in the OLED.
-
The setup function is very similar, except that setup the OLED screen in the last step. The function loop only check if the node received message via MQTT Broker, triggering the callback function that update the OLED screen.
Download the INO file from the microcontroller code that manage the OLED screen.
Wire communication - version 2¶
In order to use a board designed by me, I have extended the Version 1 to use two microcontrollers (MC) that will (i) read the value from the sensor and (ii) show the information in the OLED. The idea was to reuse the existing structure and add the microcontroller. In this case, the MC would communicate via I2C with the Wemos ESP8266. I have chosen as MC the ATtiny85 because I have used in other assignments. Its datasheet can be seen in this link.
Bellow the schematic of my idea. Wemos would continue communicating between them via MQTT, however it was introduced one MC to read the sensor and one to show the information in the OLED.
- MC that reads the distance sensor and send the value to the WemosESP8266 via I2C (P1)
- WemosESP8266 send the value via wifi connection to WemosESP8266 (the first part of the assignment done already tested the communication via Wifi between two Wemos board. So I assumed there will not be surprises as the code is the same used in that part of the assignment)
- WemosESP8266 send the received value to MC with a display (P2)
- MC displays in the LED the received value
I have searched examples of I2C communication over the internet and I found two sources:
The first example, provided by Nicholas Zambetti http://www.zambetti.com -> ATTinyCore, looked simple as we do not need a complex code for this communication. I decided to use this example to test the I2C communication in both parts of the schematic.
Testing I2C Communication¶
Using WemosESP8266¶
I have made a few adaptations in the code to test the I2C communication. I also followed a bit the explanation of this forum topic How to connect D1 mini and ATTINY85 over data wire
Tested the I2C communication between the MC and WemosESP8266 (P1) using, respectivelly, master_write_mc and slave_receiver_wemos. However the result was not good. The communication was not being stablished, despite no errors in the code. I removed any delay in the code to avoid problems with the clock, but still did not stablish the communication.
I even used the code to scan I2C connections (code).
It worked well for the MC, but not for Wemos. After some research, it was concluded that that “Wemos D1 R1 & mini” cannot be used as slave for I2C communication (references Arduino Forum and Git Forum).
The alternative solution - WemosESP32¶
As suggested in one of the forums, Wemos D1 Mini ESP32 could be used as an alternative solution. Pinout reference for WemosESP32 (page). As this board als have WiFi board, it would be a perfect replacement for the WemosESP8266. I could still use the setup done in the first part and gain some time.
Testing I2C communication - WemosESP32¶
After uploading the same code tested before in the new board, the communication started to work as charm.
- Tested the I2C communication between the MC and WemosESP32 (P1) using, respectivelly, master_writer_mc and slave_receiver_wemos and it worked.
-
As I thought that WemosESP8266 would work as master in the I2C communication, I kept using it in the P2 of the schematic. However, it did not work the I2C communication between the WemosESP8266 and MC (P2). code: master_writer_wemos for WemosESP8266 code: slave_receiver_mc for MC
-
MC controller was not receiving the data from master. After reading some blogs about possible errors, it was concluded that the slave for MC could not have delays due to problems with timing to get the data via I2C. But even after removing all delays, method that handle the received data via I2C in the MC was not being triggered.
-
One of the blogs suggested to use a different library to create the Wire connection from the MC as slave. I have tried to modify the code “slave_receiver_mc” to use this library according to examples found. I tried the library from nadvmatalon but the example found was using a different version. Then I used the library from rambo. Loaded library into ArduinoIDE (used to change the code sent to MC). But again, the I2C communication was still not working.
-
I have found another example “attiny85_i2c_slave” and adapted to communicate the MC with WemosESP8266, however it did not work either.
-
I then realized that would not be the best idea keep using WemosESP8266 for I2C communication. It was when I decided to replace the P2 also for the WemosESP32. But also, instead of using WemosESP32 as master, I decided to use it as slave (similarly to what I did for P1). This way, MC would request information from slave and WemosESP32 would provide it. After doing that, the MC and WemosESP32 could stablish the communication and MC received the information. MC requested data from WemosESP32 and received the data as expected
- code for WemosESP32: slave_sender_wemos
- code for MC: master_reader_mc
Download¶
Programming boards¶
Most of the code of the Version Two was reused from the one created in Version One. Those codes were adapted in order to be used by the MC and the WemosESP32.
Common code - MC¶
I have defined in both codes the constants for the SDA and SCL pins in the ATtiny85. Even if these constants were not used, it is good to document in code the correct pins that need to be used in the I2C communication. I also defined one constant that represents the connection to a simple LED that was used to make sure the MC was initialized correct or it had an error. I have defined two functions to blink the simple LED, one to blink once and another to blink N times.
I have defined as well a constant to hold the I2C address used in the communication, names I2C_DEV_ADDR. However the value of this constant is different for each MC.
P2 - OLED - MC¶
In the prototype board, I have connected the OLED device in the MC keeping the same code used during the test phase. Rename the file to led_m_reader_mc. The address used to connect via I2C was 9.
#define I2C_DEV_ADDR 0x09
Differently from the previous version, I had to use the library Tiny4kOLED.h, because the ATtiny85 cannot store a big library. Otherwise you might get the error “region ‘text’ overflowed by X bytes”.
Functions initial_display and update_oled were updated to use the correct library. The first function displays an initial message to guarantee the OLED is functional. The second one receives as parameter the distance that need to be shown in the OLED. Once the MC receives the information via I2C from WemosESP32, it update the OLED.
P1 - Sensor - MC¶
I have connected the distance sensor in the MC keeping the same code used during the test phase. Rename the file to sensor_m_writer_mc. The address used to connect via I2C was 8.
#define I2C_DEV_ADDR 0x08
In this version, I reused the same VL53L0X.h library. The only change was that instead of sending the distance via MQTT, now the MC send it via I2C to WemosESP32.
In this part of the development, I faced some issues.
-
I had a couple of problems about verification error during upload of the code to the MC. It was fixed by moving a bit the wires and flashing the bootload configuration in the MC.
-
I thought I had problems sending the data via I2C. Tried to send long, but long has two bites and it would require to convert it in the WemosESP32. Checked how to use the structure union and also how to use uint16_t, but apparently was not working. I fixed by sending a simple integer in the I2C communication.
-
Checked if the function readRangeSingleMilimeters from VL53L0X was correct to get the value from the sensor. VL53L0X library. Checked a example code here. And realized I was using the wrong function. I should be using readRangeContinuousMillimeters().
-
I had errors with the wires to test the prototype of the board. ESP32 was not connected correctly. Once it was connected, it started to receive the data from MC.
-
I thought the data received was not entirely correct, so I decided to program the logic of the calculation of the MC in the ESP32 (where I could use the Serial easily to see the value read from the sensor) and then transfer the code to the MC. Relized that it was not a problem. This test showed the wires were in front of the sensor and the value read was not entirely accurate because of that. Test also helped to clean unnecessary code (which uses less memory from MC)
-
After re-editing the previous test code, I have flashed in the MC, and it worked as expected.
Common code - WemosESP32¶
I have tried before to create modules for WiFi and MQTT operations but I failed. I have done some research about the reasons that was not working and found the reason. Variables declared in the header was being declared twice, message multiple definition of variables. I discovered that there is a difference between declare and define a variable (here). Reading some forums I have found the solution (forum01 and forum02): variables were defined in the header (using the key word extern) and declared [initialized] in the .CPP file.
This enabled to create the following two modules for the WiFi and MQTT operations and make them reused by each WemosESP32 boards without repeting code or having different implementations for the same operation.
WiFiFabAcademy module¶
WemosESP32 uses the library WiFi.h – WiFi library for ESP32
mqttFabAcademy module¶
The only functions that was changed from the Version One of this assignment, were mqttMessageCallback and mqttPublishMessage. Obviously the first one needed to be changed as the information being sent also changed and the value needed to be stored in a variable to be sent via I2C. The second one changed only to add more information to the Serial output.
I have tried to use String as parameter in the function ‘mqttPublishMessage’, but somehow I got the error ‘Guru Meditation Error: Core 1 panic’ed (LoadProhibited). Exception was unhandled‘ I have read in a forum (here) that might be an memory position that is not possible to be accessed. I was trying to use String object in the mentioned function, but to send the value over WiFi I needed to convert to a pointer to char. To fix this issue I changed the signature of the function to already receive a pointer to const char, and the error was gone.
P1 - Sensor - WemosESP32¶
The code look very similar to Version One. Only difference is that WemosESP32 connects to I2C via the address 8
#define I2C_DEV_ADDR 0x08
And function to receive the value from I2C now send the received value via MQTT to OLED-WemosESP32. The distance value is converted to a array of char and sent via MQTT.
I had the error “brownout detector was triggered esp32 wifi” when WemosESP32 starts the setup function. Apparently this happens in the first call to setup function because of variation of voltage in the WemosESP32 board. This forum here suggested to add a capacitor of about 10µF in the WemosESP32. However, I did not do that because the board was able to initialize correctly in the second time the function setup was called.
I also got an error in the function ‘mqttPublishMessage’ that I have declared before to return a boolean but the function was not returning anything. I have just changed the function definition to void (not returning anything)
P1 - OLED - WemosESP32¶
The code is pretty similar to the Version One. Only difference is in the function that handle the I2C communication. It verify if the board received the value via the MQTT, and send it. Otherwise it sends the value -1 to the MC.
Download¶
Prototype V2¶
This was the prototype of both boards.
Sensor
OLED
PCB Designs¶
I have decided to not mill these boards, to avoid waste of material for something that will not be reused after the course ends. But I provides the schematic, the view of the board, and all the files that can be used to mill the board.
Sensor¶
Circuit
Lines of the PCB
3D view of the PCB
Download the ZIP file containing all the necessary files to mill the sensor board.
OLED¶
Circuit
Lines of the PCB
3D view of the PCB
Download the ZIP file containing all the necessary files to mill the OLED board.
Group Assignment¶
Ingegno - Networking and communications