11. Embedded Networking and Communications
Here you can find a recording of the lecture from the 2th of april.
This week's assignments and learning outcomes, see here:
Group assignment:
- Send a message between two projects.
- Document your work on the group work page and reflect on your individual page what you learned.
You can find the documentation for our group assignments here.
Individual assignment:
- design, build and connect wired or wireless node(s) with network or bus addresses and a local input and/or output devices.
Questions to be answered/from Nueval:
Have you answered these questions?
- Linked to the group assignment page
- Documented your project and what you have learned from implementing networking and/or communication protocols.
- Explained the programming processes you used.
- Ensured and documented that your addressing for boards works.
- Outlined problems and how you fixed them.
- Included design files (or linked to where they are located if you are using a board you have designed and fabricated earlier) and original source code.
- Included a ‘hero shot’ of your network and/or communications setup.
Link to group page
Here you can find the documentation of our group assignment.
Hero shot
Hero shot from group project
MQTT
Video showing how we used a MQTT broker, two microcontrollers as clients, a temperature reader and an OLED screen to send the response to a heat change of the sensor in Ísafjörður live on the OLED screen in Neskaupstaður. The distance between these two places is 445km by air see here.
Host and client communicating
Hero shot from individual project
Two Raspberry Pi Pico W's communicating through wifi, using Neopixels as output
In this video you can see how the two Raspberry Pi Pico W's are connected to different laptops. One of the microcontrollers is soldered on a board that I designed in week 08. There are Neopixels soldered onto the board and they are used as output. The microcontroller with the Neopixels is used as client and the other microcontroller is a wifi host. They are programmed with MicroPython in Thonny. The wifi host sends random numbers and the host prints them and lets the Neopixels blink in different colours.
Server and client communicating with Neopixels as output
Summary
This week, as a group, we sent messages between two projects using a MQTT broker, reading temperature on one end and displaying the readings on the other end. We documented the results on our group page and you can find it here.
As an individual assignment I connected two Raspberry Pi Pico W's and used wifi for communication. I used Doppler radar as input and Neopixels as output.
Work process detail
The group project
Me and Jóhannes Andrésson began working on this project in Fab Lab Ísafjörður during the Machine week.The idea was to use a temperature sensor that a microcontroller would read and then send the reading to another microcontroller which would display the temperature reading on a LCD screen.
Jóhannes set up a Wifi host with a XIAO ESP32-C3 and provide a wireless access point to connect to. The sensor is a One-Wire digital Temperature sensor. Then I set up a XIAO ESP32-C3 as Wifi client and connect to the access point and receive data from it. Then the readings should have been displayed on an I2C LCD display. This did not work out as it should have. We created an access point (Soft AP) with one device (which served as host). Then the other microcontroller served as a client and connected to it.
We used this page as a reference.
When Jóhannes had set up his host, I used Arduino IDE and ran this code on my microcontroller, which was the client:
#include <WiFi.h>
const char* ssid = "ESP32C3_Johannes";
const char* password = "****";
void setup() {
Serial.begin(115200);
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {}
As you can see, my client was trying to connect to the host. It did seem to be able to establish a connection.
No communication between host and client
Then the host was supposed to send the temperature reading to the client, but the temperature did not appear on the LCD screen as it should have.
MQTT Communication
I travelled from Ísafjörður and home to Neskaupstaður. Since we could not finish our group assignment, we had to figure out a way to do that. Because of the long distances between the microcontrollers we couldn't use the same wireless network, so Jóhannes did some research and suggested we tried MQTT. He looked into the directions and explained all steps to me. We followed this tutorial, which used the arduino-mqtt library. We used public.cloud.shiftr.io and it worked in this project.
In the middle of all this planning I suddenly realized that the XIAO ESP32C3 microcomputer I had been using had been left behind in Ísafjörður so I had to find another XIAO ESP32C3 and solder pins to it. This did not take a long time because I am getting more used to soldering. That's good.
MQTT
Both ESP32-C3 work as client and there is no host, but a MQTT broker. The broker receives messages Every client can send messages to the broker, but it has to be under a certain topic. Client can then subscribes to a certain topic. In our case one client is publishing and the other is subscribing. The topic we created was called /fabisa
.
First we tested this example called ESP32DevelopmentBoard from the MQTT library and added our networking information and text into it:
// This example uses an ESP32 Development Board
// to connect to shiftr.io.
//
// You can check on your device after a successful
// connection here: https://www.shiftr.io/try.
//
// by Joël Gähwiler
// https://github.com/256dpi/arduino-mqtt
#include <WiFi.h>
#include <MQTT.h>
const char ssid[] = "fablab";
const char pass[] = "******";
WiFiClient net;
MQTTClient client;
unsigned long lastMillis = 0;
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!client.connect("arduino", "public", "public")) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/fabisa");
// client.unsubscribe("/hello");
}
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
// Note: Do not use the client in the callback to publish, subscribe or
// unsubscribe as it may cause deadlocks when other things arrive while
// sending and receiving acknowledgments. Instead, change a global variable,
// or push to a queue and handle it in the loop after calling `client.loop()`.
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported
// by Arduino. You need to set the IP address directly.
client.begin("public.cloud.shiftr.io", net);
client.onMessage(messageReceived);
connect();
}
void loop() {
client.loop();
delay(10); // <- fixes some issues with WiFi stability
if (!client.connected()) {
connect();
}
// publish a message roughly every second.
if (millis() - lastMillis > 1000) {
lastMillis = millis();
client.publish("/fabisa", "Fab Lab Austurland");
}
}
Then Ólöf opened the serial monitor and there this text was displayed:
The next step was to change this code and add to it what we needed. Together we figured out, how to display the message from the topic on the screen. These are the codes after changes:
Code for Temperature Client
// Code based on example
// by Joël Gähwiler. Changes added by Jóhannes and Ólöf
// https://github.com/256dpi/arduino-mqtt
#include <WiFi.h>
#include <MQTT.h>
#include <DS18B20.h>
String temp;
DS18B20 ds(D1);
const char ssid[] = "ssid";
const char pass[] = "****";
WiFiClient net;
MQTTClient client;
unsigned long lastMillis = 0;
String readTemp() {
ds.selectNext();
temp = ds.getTempC();
return temp;
}
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!client.connect("ESP32-C3-IFJ", "public", "public")) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/fabisa");
// client.unsubscribe("/hello");
}
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
// Note: Do not use the client in the callback to publish, subscribe or
// unsubscribe as it may cause deadlocks when other things arrive while
// sending and receiving acknowledgments. Instead, change a global variable,
// or push to a queue and handle it in the loop after calling `client.loop()`.
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported
// by Arduino. You need to set the IP address directly.
client.begin("public.cloud.shiftr.io", net);
client.onMessage(messageReceived);
connect();
}
void loop() {
client.loop();
delay(10); // <- fixes some issues with WiFi stability
if (!client.connected()) {
connect();
}
// publish a message roughly every second.
if (millis() - lastMillis > 1000) {
lastMillis = millis();
temp = readTemp();
client.publish("/fabisa", temp);
}
}
Jóhannes measured the temperature with the one-wire sensor and I connected the OLED screen and ran the code.
This video shows the response to a heat change of the sensor in Ísafjörður live on the OLED screen in Neskaupstaður.
Host and client communicating
Individual assignment
Overview
This week's goals
This week I wanted to learn the following, if possible:
-
Learn how to make two Raspberry Pi Pico W communicate through wifi by making one of them serve as a host and the other one serve as a client.
-
Learn how to use Neopixels as output with the two RPP.
-
Learn how to use a Doppler radar as input, first as a single project and then maybe, if possible, include it in the communication process between the two RPP.
-
Learn how to do this using MicroPython in Thonny.
The board I designed and produced
I produced a board in week 08. In previous projects I had been using a Raspberry Pi Pico without wifi, but now I needed a microcontroller with a wifi connection in the networking and communication assignment, so I soldered a Raspberry Pi Pico W on it. I used this microcontroller as the client.
Then I used another Raspberry Pi Pico W as a server in the assignment and I also used it with the Doppler radar. I did not want to solder it to a board because maybe I want to use it on another board in the final project, so I decided to solder pins to it and only use three small points to do that. Then I should be able to add it to another board later on.
Pinout and information for Raspberry Pi Pico W
Pinout and information on the Raspberry Pi Pico W
According to the information here, the Raspberry Pi Pico W has a single-band 2.4GHz wireless interface (802.11n). It's main features are:
-
Single-band 2.4GHz, wireless interface (802.11n)
-
WPA3
-
It has a soft access point for up to four clients
-
Bluetooth 5.2
You can find the pinout for the Raspberry Pi Pico W here.
Pinout (image from here):
Doppler radar
RCWL- 0516 Doppler radar
I began by learning how to use a Doppler radar (or RCWL motion detector) because I want to use it in my final project and time is running out. Here you can find information on it. It is a microwave radar sensor and has a high sensitivity and can detect movement with the range of 7m. It can detect movement in 360°.
Directions for Doppler radar
I followed these directions when connecting the Dopple radar to the Raspberry Pi Pico W. I only used three of the pins on the Doppler radar. I connected them this way:
Doppler radar | Raspberry Pi Pico W |
---|---|
OUT | GPIO 26 |
VIN | VBUS (5V) |
GND | GND |
Code for Doppler radar
Code used to control the Doppler radar
I used the code from these directions. I did not include the Led that was in the original code and I changed the number of the sensor pin. Here below is the adjusted code that I used.
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-rcwl-0516-micropython/
from machine import Pin
import time
# Pin numbers for LED and sensor
led_pin = 21
sensor_pin = 26
# Set the LED pin as an output and the sensor pin as an input
led = Pin(led_pin, Pin.OUT)
sensor = Pin(sensor_pin, Pin.IN)
# Initialize state variables
state = 0
val = 0
while True:
val = sensor.value() # read sensor value
if val == 1: # check if the sensor is HIGH
led.on() # turn LED ON
if state == 0:
print("Motion detected!")
state = 1 # update variable state to HIGH
else:
led.off() # turn LED OFF
if state == 1:
print("Motion stopped!")
state = 0 # update variable state to LOW
# Add a small delay to avoid constant checking of the sensor
time.sleep(0.1)
Video showing Doppler radar working
Server and client communicating
Two Raspberry Pi Pico W communicating
Directions
I followed the directions in this video. I also found these directions written on the Instructables page here.
Allow more that one instance
In the directions it is mentioned that in Thonny, the pre-set settings are most likely only allowing one instance of Thonny, so I began by clicking on Tools and then Options. There, under General, I unchecked the box by Allow only single Thonny instance. After changing these settings it is necessary to restart Thonny.
Not accepting two microcontrollers
For some reason, Thonny did not accept multiple instances in my computer, so I decided to connect the microcontrollers to two laptops.
The constants not working
In the directions they use constants command and the information about internet connections that the constants command is supposed to use is saved in a constants.py file on the microcontrollers. There are however no directions on how to setup this constants.py file, so I decided to search for other ways to program the internet connection part.
Defining ssid and password
I found these directions. There they added more to import and defined ssid and password for the internet connection. I did the same and deleted the constant command. This worked!!! Note that the server printed it's IP address in the shell and I wrote it in the code for the client.
The code for the server
The code for the server
This is the code I used for the microcontroller used as the server. I wrote stars to hide information about the internet connection.
from machine import Pin, ADC
import network
import random
import socket
import time
from time import sleep
import machine
import rp2
import sys
ssid = '****'
password = '****'
# making an internet connection
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
# Wait for connect or fail
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print("waiting for connection...")
time.sleep(1)
# Handle connection error
if wlan.status() != 3:
raise RunTimeError("network connection failed")
else:
print("connected")
status = wlan.ifconfig()
print("ip = "+ status [0])
# Open socket
addr = socket.getaddrinfo('0.0.0.0', 80) [0] [-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print("listening on", addr)
# Listen for connections
while True:
try:
cl, addr = s.accept()
request = cl.recv(1024)
print(request)
# No need to unpack request in this example
ran_num = str(random.randint(0, 100))
cl.send(ran_num)
print("Sent: " + ran_num)
cl.close()
except OSError as e:
cl.close()
print("connection closed")
The code for the client
The code for the client
This is the code I used for the microcontroller used as the client. I wrote stars to hide information about the internet connection.
from machine import Pin, ADC
import network
import random
import socket
import time
from time import sleep
import machine
import rp2
import sys
ssid = '****'
password = '****'
# Just making our internet connection
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
# Wait for connect or fail
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('waiting for connection...')
time.sleep(1)
# Handle connection error
if wlan.status() != 3:
raise RuntimeError('network connection failed')
else:
print('connected')
status = wlan.ifconfig()
#print('ip = ' + status[0])
while True:
ai = socket.getaddrinfo("******", 80) # Address of Web Server
addr = ai[0][-1]
# Create a socket and make a HTTP request
s = socket.socket() # Open socket
s.connect(addr)
s.send(b"Anything") # Send request
ss=str(s.recv(512)) # Store reply
# Print what we received
print(ss)
# Set RGB LED here
s.close() # Close socket
time.sleep(0.2) # wait
Video of communications
Server and client communicating
Adding an output
Neopixels as output
I wanted to add the Neopixels that were soldered to my board as an output. Here you can see an overview of the setup.
Code for Neopixels as output
I used the client code and mixed it with a code that I used in week 08. You can see that code from week 08 here below:
import neopixel
from machine import Pin
import time
pixPin = 0 # Numper of pin
pixSize = 2 # How many LEDs
pix = neopixel.NeoPixel(Pin(pixPin), pixSize) # Initialization
yellow = (255,255,0)
red = (255,0,0)
while True:
pix[0] = yellow
pix[1] = red
pix.write() # Tells the LED to perform the command
time.sleep(1)
pix[0] = red
pix[1] = yellow
pix.write() # Tells the LED to perform the command
time.sleep(1)
Code for client printing numbers and blinking Neopixels
This is the code after I mixed these two codes together. I used it to tell the client to print random numbers sent from server and also to use Neopixel as output and blink them in two colours. I added definitions on Neopixels under all import commands. Then I added the commands for controlling the Neopixels after the client establishes an internet connection and before the client shuts down the internet connection.
from machine import Pin, ADC
import network
import random
import socket
import time
from time import sleep
import machine
import rp2
import sys
import neopixel
pixPin = 0 # Numper of pin
pixSize = 2 # How many LEDs
pix = neopixel.NeoPixel(Pin(pixPin), pixSize) # Initialization
yellow = (255,255,0)
red = (255,0,0)
ssid = 'fablab'
password = 'fabvalab'
# Just making our internet connection
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
# Wait for connect or fail
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('waiting for connection...')
time.sleep(1)
# Handle connection error
if wlan.status() != 3:
raise RuntimeError('network connection failed')
else:
print('connected')
status = wlan.ifconfig()
#print('ip = ' + status[0])
while True:
ai = socket.getaddrinfo("192.168.3.211", 80) # Address of Web Server
addr = ai[0][-1]
# Create a socket and make a HTTP request
s = socket.socket() # Open socket
s.connect(addr)
s.send(b"Anything") # Send request
ss=str(s.recv(512)) # Store reply
# Print what we received
print(ss)
# Set RGB LED here
pix[0] = yellow
pix[1] = red
pix.write() # Tells the LED to perform the command
time.sleep(1)
pix[0] = red
pix[1] = yellow
pix.write() # Tells the LED to perform the command
time.sleep(1)
s.close() # Close socket
time.sleep(0.2) # wait
Video of two Raspberry Pi Pico W's communicating and using Neopixels as output
Server and client communicating with Neopixels as output
Learning outcome
Learning outcome from group assignment
I learned how a microcontroller can serve as a wifi host and another microcontroller can serve as a client that connects to the host's wifi. I also learned that with the MQtt protocol you can use two microcontrollers as clients where one of them publishes data under a certain topic and the other one subscribes to this topic.
Learning outcome from individual assignment
I learned how to use two Raspberry Pi Pico W's to communicate through wifi, using one of them as wifi host and the other one as client, using MicroPython in Thonny. I also learned how to add Neopixels as output in the project.
I learned how to use a Doppler radar and I plan on using it in the Final project. It would have been fun to learn how to add the Doppler radar as input in the individual project with the two Raspberry Pi Pico's and the Neopixels, but that did not happen. Maybe I will learn how later on.