Raspberry - Basic wifi setup and IP address discovery

Subscribe Send me a message home page tags


#raspberry-pi  #python  #wifi 

In this post, we will talk about the basic setup for raspbery pi. This post assumes the Ubuntu server version is installed.

Our objective is to

  1. Connect raspbery pi to wifi.
  2. Make raspbery pi connect to wifi automatically on start up
  3. Discover the IP address of the raspberry pi.

Connect to wifi

We will set up the wifi with old fashion and follow the insturction in the post Connecting to personal wifi on Ubuntu Server 20.04.

The first step is to set up the interface. Usually we will need wlan0.

# Check which interfaces you are working with
sudo ip link

# Example: Set up wlan0
#sudo link set wlan up  <--- This may not work.
sudo ip link set wlan0 up

The second set step is to configure the wifi connection. We will need wifi network name and wifi password. We will execute the following command, which saves the encrypted confiruation to a wpa_supplicant.conf file.

wpa_passphrase "<Wifi Name>" "<Password>" > /etc/wpa_supplicant/wpa_supplicant.conf

Note that we need sudo access for the above command but the IO redirection is not always compatible with sudo. One solution is to execute the command in an interactive shell with sudo access. We can enter the interactive shell using

sudo -s

and then execute the wpa_passphrase command. After the wifi configuration is saved, we can exit the interactive shell by entering Ctrl+D.

An alternative is to first redirect the output to a temporary file and then use sudo mv to copy the file to the wpa_supplicant.conf.

The third step is to enable DHCP by executing

wpa_supplicant -Bc /etc/wpa_supplicant/wpa_supplicant.conf -i <interface>
dhclient <interface>

To verify we are connecting to the wifi, we can ping google:

ping -c 5 www.google.com

Connect to wifi automatically on start up

In old Ubuntu version, we can achieve this by adding the commands in the previous section to /etc/rc.local file. However, Ubuntu 20.04 does not have the rc.local file by default thus we need to create one ourselves.

This section is a copy of the post How to Enable /etc/rc.local with Systemd.

1. Create /etc/systemd/system/rc-local.service file with the following content
[Unit]
 Description=/etc/rc.local Compatibility
 ConditionPathExists=/etc/rc.local

[Service]
 Type=forking
 ExecStart=/etc/rc.local start
 TimeoutSec=0
 StandardOutput=tty
 RemainAfterExit=yes
 SysVStartPriority=99

[Install]
 WantedBy=multi-user.target
2. Create /etc/rc.local file and make it executable by using the following command
sudo chmod +x /etc/rc.local

The /etc/rc.local file should contain the following code. (Here the interface is wlan0).

#!/bin/bash
ip link set wlan0 up
wpa_supplicant -Bc /etc/wpa_supplicant/wpa_supplicant.conf -i wlan0
dhclient wlan0
3. Enable and start the rc-local service.
sudo systemctl enable rc-local
sudo systemctl start rc-local.service
sudo systemctl status rc-local.service

Discover the raspberry pi host

An ideal solution would be making raspberry pi send out an email with ip information on start up. However, due to the two-factor verification of gmail, it becomes a little bit tricky to set up an email server on ubuntu server. There are many online posts descriping different solutions to set up a send-only email server. I tried a bunch of them but I'm still not able to set up an email server on my raspberry pi.

Fortunately there is a plan B. The real objective is to get the IP address. We need the IP address mostly because we want to ssh to the raspberry pi from a remote PC. One way to achieve this is to send a broadcast message to the local network and get the hostname. There are a few difficulties with this solution. First, not all machines response to a broadcast message. Second, we need a sort of DNS for local network.

The first problem is not a big deal. We can manully ping a range of IP address. For the second problem, I don't really know how to implement a DNS for a local network but once again our ultimate objective is to discover the IP address assocaited with our raspberry pi and it can be done without knowing/getting the hostname.

One observation is when we ping an IP address and if the host is reachable we will have the MAC address in the output. Therefore, we should be able to identify the raspberry pi from the output of ping command. To find out the MAC address of raspberry pi, we could execute the ifconfig command.

Now putting all pieces together, in order to discover the raspberry pi host, we can do the following

  1. Get the MAC address of the raspberry pi by executin ifconfig command.
  2. Ping a range of local IP address and get the results.
  3. Find the line with the MAC address of the raspberry pi in the ping result and it will contain the IP address of the raspberry pi.
Tip: We could use fping command, which is designed to be used in a script

Here is the sample python code(discover-host.py):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import subprocess
from collections import namedtuple

HostInfo = namedtuple("HostInfo", ["hostname", "mac"])

TARGET_HOST_INFO = [
    HostInfo(hostname="robot-ubuntu", mac="<MAC address of Raspberry PI>")
]

if __name__ == "__main__":
    macToHostnameMap = {info.mac : info.hostname for info in TARGET_HOST_INFO}
    subprocess.run(['fping', '--timeout=200', '-g', '10.0.0.1', '10.0.0.254'])
    completedProcess = subprocess.run(['arp', '-a'], capture_output=True)
    listOfResult = completedProcess.stdout.decode('UTF-8').split('\n')

    isAnyTargetFound = False

    for result in listOfResult:
        for mac in macToHostnameMap.keys():
            if mac in result:
                isAnyTargetFound = True
                print("[{}] {}".format(macToHostnameMap[mac], result))

    if not isAnyTargetFound:
        print("Did not find any target result.")

We could remove error message from the outputs as well

alias discoverhost="python3 discover-host.py | grep -v \"is unreachable\" | grep -v\"error\""

----- END -----