4.8. Networking

We will be setting up networking to be able to remotely control your rover.

4.8.1. Why Remote Control?

Remote control enables us to control any device from another device. This is always done over the air using radio waves that are emitted from an antenna and received by another antenna.

In our case, we will not be reinventing the wheel as we will simply use the common 2.4GHz/5GHz wifi networks that we all know and use on a daily basis. These networks are ubiquitous as they are designed to connect computers together.

Well, our Raspberry Pi is a computer and so is our laptop (or phone!).

In the follow sections, we will install a web server on the Raspberry Pi and remotely connect to it from our laptop to send it commands.

4.8.2. Prerequisits

To connect computers together over a wifi network, they firstly need to be on the same network!!

There are two kinds of networks:

  • LAN: Local Area Networks

  • WAN: Wide Area Networks

The LAN is the small private network inside of your house. It is built around your wifi router which all your family connects to and which will then transfer packages between all the devices connected to it. This is how you can print things over wifi or play music on the family speaker in the center of the house.

But your router also has another job, it acts like an interface with the rest of the internet. The internet is the WAN (Wide Area Network). Your router redirects requests from devices inside your house to the right place outside of it. For instance, accessing: microver.ch over the https protocol is done by opening up your web browser and typing in the url bar:

https://microver.ch

This will ping the DNS (Domain Name System) which is a huge table of all the domain names in the world and the Internet Protocol addresses (IP addresses) associated with each domain name. In our case, it will return:

212.227.194.84

Which is the IP address of the computer which we are paying for each month to store and serve the documentation that you are currently reading. Depending on what address you append after the Top Level Domain (TLD), the server will give you a different page.

Your home router is letting our server return you this html page because you asked for it using the Hyper Text Transfer Protocol Safe (https) by typing in:

https://docs.microver.ch

Your router also has a firewall which only lets very specific things into your house such as https demands. It won’t let a hacker remotely connect to your laptop and ransom you all your data as this demand can’t be done over https. This kind of demand would be done over ssh which we will see just after.

For now, we need to make sure that all your devices are connected to the same LAN (Local Area Network). This can be :

  • your mobile phone 4G hotspot

  • the router inside your house

Warning

This LAN probably can’t be your school network or airport network as the system administrators (the people who setup the router) don’t like it if you hack into your neighbour’s laptop

Start by connecting both your laptop and your Raspberry Pi to the same wifi network to create the LAN in which they will communicate.

4.8.3. Finding IP Address

Just like our example above, you will need to know which Internet Protocol address your Raspberry Pi is using. The IP address was assigned to your Raspberry Pi by the wifi router when you connected the Raspberry Pi to the router. To do this, you can either:

  1. Ask the router (since he gave it out, he knows)
    • Hard to do as you need to have password access into the router

  2. Ask the Raspberry Pi (since it has it, it knows)
    • Best option

  3. Scan the network with another device
    • Not liked by your network administrator as you are spamming their router with millions of demands to check if there is a device at the end of each possible address

    • They may ban your device from their wifi network if you do this

    • We are not responsible

    • Great tools to do this are either:
      • nmap (shell program for linux computers)

      • Net Analyzer (play store app for android phones)

We will teach you Option 2
Simply open up a terminal on your Raspberry Pi and type:
hostname -I

It will return an address which should look something like this:

192.168.6.174

4.8.4. SSH (optional)

The easiest way to remotely control your Raspberry Pi over the LAN is to use the Secure Shell Host (SSH) utility already built into your Raspberry Pi.

Start by opening up a terminal from your laptop:

  • You are on Windows
    • Install WLS2 (Windows Subsystem for Linux) with the Ubuntu 24.04 distro from the Microsoft Store

    • Open it with: Windows Key, type “Ubuntu”, hit Enter

  • You are on Mac
    • Use the standard Mac Terminal

    • Open it with: Command + Space, type “Terminal,” and hit Enter

  • You are on Linux
    • Thank you

    • Simply open a terminal

Now type in your terminal:

ssh username@192.168.x.x

# username is what you set during the Raspi setup (Section 4.2)
# you can find it by opening a terminal on the Raspi
# it is the first word before the @

This will ask you to confirm that you know the person that you’re trying to connect into as your computer hasn’t connected to it before, type:

yes

Then you will be asked for a password, enter the password of your Raspberry Pi.

Congrats, you will now see that the text before the $ symbol on your terminal has changed to username@computername of your Raspberry Pi instead of your laptop. This means you are successfully connected into your Raspberry Pi.

You can now remotely work in your Raspberry Pi as you would if you were connected to it normally.

This is the simplest way to remotely control your Raspberry Pi, as long as you are in range of the wifi, you will be able to launch commands on the Raspberry Pi to control your rover.

This way has downsides as you can only work in a terminal so we will not spend too much time on it in this microver.ch basics section. Instead we will teach you how to make a Web application to control your rover in a more visually appealing and portable manner.

4.8.5. Web Server

The Client-Server software architecture is one which we all use on a daily basis as we (the client) use our devices to connect to remote servers and they send us informations in return.

Exactly like the microver.ch server at the 212.227.194.84 IP address which has sent you this html webpage when you (the client) asked it with:

https://docs.microver.ch

We will implement the same thing on our rovers. The Raspberry Pi will act as the server, always serving a webpage, and your laptop (the client) will access those ressources by entering the IP address of the Raspberry Pi into a browser’s URL search bar.

But we will go further than simply sending static html pages like the server behind docs.microver.ch does (this is called a static website). We will have a dynamic Web Application (webapp) which will send commands to our Arduinos when we click on buttons on the web page.

4.8.6. Installing Nginx

Nginx will be our webserver.

Note

The Raspberry Pi is not actually a server, it is a computer which runs many programs, one of them is the server (Nginx) as it is transfers the bytes stored on the Raspberry Pi’s SD card over the Wifi network.

# Regularly update your packages
sudo apt update && sudo apt upgrade -y

# Install Nginx using apt
sudo apt install nginx

This will install the Nginx daemon on your system. A daemon is a program (like Firefox or Minecraft) but it is always running in the background. We need this as you never know when somebody will connect to your Raspberry Pi so it is always looking out of incoming connections.

You can check the status of your various daemons on a Linux system by running:

systemctl status nginx

We will now setup a basic landing page for Nginx to serve.

# Create a new directory in /srv/
sudo mkdir /srv/microver

# Give yourself permissions to edit this directory
sudo chown $USER:$USER /srv/microver/

# Make an empty index.html document
touch /srv/microver/index.html

You can now copy paste this standard html webpage into your new file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Welcome to microver.ch</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            font-family: Arial, sans-serif;
            text-align: center;
            background-color: #f4f4f4;
        }
        .container {
            padding: 20px;
            background: white;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            border-radius: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Welcome to microver.ch</h1>
        <p>This is your very first web page, congrats!!</p>
    </div>
</body>
</html>

Open your new file with your favorite terminal text editor,

  1. With nano

# Open the empty file
nano /srv/microver/index.html

# Paste the above html code
CTRL-SHIFT-V

# Save file
CTRL-O
ENTER

# Close file
CTRL-X
  1. With vim

# Open the empty file
vim /srv/microver/index.html

# Enter insert mode
i

# Paste the above html code
CTRL-SHIFT-V

# Exit insert mode
ESC

# Save file and quit
:wq
ENTER

Make a new nginx configuration file with:

sudo nano /etc/nginx/sites-available/microver

Copy in there the following Nginx config and make sure to change your IP:

server {
    listen 80;
    server_name 192.168.6.174;  # Change this to your IP

    root /srv/microver;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Activate the website with:

# Symlink the site into the enabled directory
sudo ln -s /etc/nginx/sites-available/microver /etc/nginx/sites-enabled/

# Remove default site
sudo rm /etc/nginx/sites-enabled/default

# Check for errors
sudo nginx -t

# Restart the nginx daemon
sudo systemctl restart nginx

Connect to the website for the very first time by opening up a new browser tab on your laptop and entering:

# Put your own IP
http://192.168.6.174/

If your phone is also connected to the network (or you are on a 4G hotspot), enter the same url on your phone’s browser.

Congratulations, you have just built and hosted your very first website!

4.8.7. Dynamic Website

Now you will want to interact with your rover by clicking on things present in the webpage. For this you need another program called a backend. The backend works with the server (nginx) to run programs on the interactions of the user.

There are dozens of backends, see what is the best backend.

We will be using Flask as it is one of the lightest and easiest ones to use, it is also fully in python so you don’t need to learn a new programming language.

Installing Flask:

sudo apt install python3-flask

We will now do 3 separate things:

  1. Update the html website to add a buttom to it

  2. Update our nginx config to call our backend code

  3. Write our backend code & run our backend server

1. Update the webpage to have a button at the bottom:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Welcome to microver.ch</title>
    <style>
        body {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            font-family: Arial, sans-serif;
            text-align: center;
            background-color: #f4f4f4;
        }
        .container {
            padding: 20px;
            background: white;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            border-radius: 10px;
        }
        .button {
            margin-top: 20px;
            padding: 10px 20px;
            font-size: 16px;
            background-color: #007bff;
            color: white;
            border: none;
            cursor: pointer;
            border-radius: 5px;
        }
        .button:hover {
            background-color: #0056b3;
        }
    </style>
    <script>
        function runShellScript() {
            fetch('/run-script', {
                method: 'POST'
            }).then(response => response.text())
              .then(data => alert(data))
              .catch(error => console.error('Error:', error));
        }
    </script>
</head>
<body>
    <div class="container">
        <h1>Welcome to microver.ch</h1>
        <p>This is your very first web page, congrats!!</p>
        <button class="button" onclick="runShellScript()">Run Server Script</button>
    </div>
</body>
</html>

2. Update our nginx config

# Open nginx config file
sudo nano /etc/nginx/microver/sites-available/microver
# Paste this inside of it and make sure to change you IP
server {
    listen 80;
    server_name 192.168.6.174;  # Change this to your IP

    root /srv/microver;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location /run-script {
        proxy_pass http://127.0.0.1:5000/run-script;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Restart nginx

sudo systemctl restart nginx

3. Write our backend code

Make a new python file which will be your backend code:

nano /srv/microver/server.py

Inside of it, paste the following standard code:

from flask import Flask
import subprocess

app = Flask(__name__)

@app.route('/run-script', methods=['POST'])
def run_script():
    subprocess.run(["/srv/microver/script.sh"])  # Add script
    return "Script executed successfully!", 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Save the file and run the server

python3 /srv/microver/server.py

4. Test out webpage You can now hard reload your webpage by going to it and doing:

CTRL-SHFT-R

Click on the buttom and you should see a successful prompt.

Congratulations, you can now control your Raspberry Pi over a webpage!

4.8.8. Reverse-Proxied Backend

As you have seen in the previous section, the python backend server always needs to be running to be listening to the button clicks from the webpage.

This is not scalable as you don’t want to always be launching:

python3 /srv/microver/server.py

Everytime you turn on your rover.

Instead we need to setup a second daemon (see Section 4.5.6) which will always be quietly running in the background and which will turn on automatically everytime our Raspberry Pi boots up.

But this daemon will be hosting a WSGI server (Web Server Gateway Interface) and it will run our backend Flask python code. We will connect this WSGI daemon to nginx’s daemon (http server) in a process called reverse proxying.

This basically means that our clients (your laptop and smartphone) will always be sending http commands to your Raspberry Pi (as this is all a web browser can do). All of those http requests will be caught by nginx’s http daemon and only some of them will be reverse proxied (or forwarded) to the WSGI daemon for it to run your python code.

Whether they are simply handled by nginx’s http daemon or reverse-proxied to Gunicorn’s WSGI daemon will depend on which url they point to.

In our previous chapter, we wrote the following html code:

<!-- index.html -->

<script>
   function runShellScript() {
       fetch('/run-script', {
           method: 'POST'
       }).then(response => response.text())
         .then(data => alert(data))
         .catch(error => console.error('Error:', error));
   }
</script>

Which means that when the client click on the button, the above javascript script is executed. This script automatically sends a POST request (POST is a type of HTTP request) from the client’s browser to the /run-script endpoint, here is how it looks like:

HTTP POST /192.168.6.174/run-script

The nginx http server intercepts this http post request on the Raspberry Pi and in the nginx configuration file, we wrote:

# /etc/nginx/sites-available/microver

location /run-script {
        proxy_pass http://127.0.0.1:5000/run-script;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
}

The important line here is:

proxy_pass http://127.0.0.1:5000/run-script;

Nginx passes the POST request made to the nginx server to the python server hosted on port 5000 of the current machine 127.0.0.1.

So our python server receives this POST request and thankfully, we wrote some python code to catch it and run something when it comes through.

# server.py

@app.route('/run-script', methods=['POST'])
def run_script():
    subprocess.run(["/srv/microver/script.sh"])  # Add script
    return "Script executed successfully!", 200

In this case it runs a generic script.sh bit of code that creates a new file on our Raspberry Pi to make sure it all works.

To make this permanent and reliable, we will now install a separate program which will run as a system daemon and which will execute this python code everytime a request is passed by nginx.

4.8.9. Installing Gunicorn

# Install it using apt
sudo apt install gunicorn -y

# Try it out from inside /srv/microver/ directory
gunicorn --bind 127.0.0.1:5000 server:app

You can now kill it with CTRL-C and we will configure it as a daemon.

Make a Gunicorn service file

sudo nano /etc/systemd/system/microver.service

Paste the following config inside of it:

[Unit]
Description=Gunicorn instance to serve microver
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/srv/microver
ExecStart=/usr/bin/gunicorn --workers 3 --bind 127.0.0.1:5000 server:app
Restart=always

[Install]
WantedBy=multi-user.target

Enable the daemon:

sudo systemctl start microver
sudo systemctl enable microver

# Make sure it's running
sudo systemctl status microver

Arduino IDE Logo
Arduino IDE Logo
If you run into any issue, apply the workflow described in the debugging cookbook and if you still can't figure it out, send a message on the microver.ch Discord Forum

Please signal any mistake to: errata@microver.ch