Nontas' Blog

Raspberry Pi IP Reporting Service

automatic report of a raspberry pi's ip

In this post we are going to develop a simple reporting service for Raspberry Pis, which will allow them to report their IP address when they boot.

It’s no big surprise that nowadays you see more and more Raspberry Pis appearing in all kind of tech projects. In one of the projects I’ve worked on, we were using five Raspberry Pis to perform a specific task. These Pis, were connected to the TU/e’s WiFi network (see more about this), which has a (literally) huge pool of IP addresses, and we could not use static IPs for them. That being said, every time we powered on each Raspberry Pi, it could get a different IP address.

Finding this IP address could have been a much much easier task if we were working at our home, or at a place where we could have access to the network router. In the latter case, we could just connect to our router’s web interface and see the ip addresses given by the DHCP server, or we could scan our local network using nmap and check for devices whose MAC address starts with B8:27:EB (which is an identifier for Raspberry Pis), using the following command:

sudo nmap -sP 192.168.1.0/24 | awk '/^Nmap/{ip=$NF}/B8:27:EB/{print ip}'

This requires nmap installed on your computer. If you have a Mac, you can get nmap from homebrew. If you have Windows, try Wireshark.

Although the above-mentioned solutions seem neat, there are two major problems for our case. The first problem is that we don’t have access to the TU/e’s network routers or to the DHCP servers running there. The second problem is that scanning the whole WiFi subnet is not a very nice solution. Moreover, it is very possible that you will find more Raspberry Pis connected on this network and then you have to determine which ones are yours.

If we didn’t find an elegant solution to this problem, we would have to connect each Raspberry Pi to a screen and keyboard every time it was powered on. This possibility gave me extra motivation to start thinking of a possible solution. Long story short, the idea I started working on was based on the simple question: What if every time a Raspberry Pi boots, it reports its IP address to a server of our own?. We did have a linux machine sitting in the office, so I decided to use this machine to test my idea.

The concept we will example is rather simple:

  • On a server machine, we will have a MySQL database where we will store the IP address of each Raspberry Pi.
  • On this server we will also have a web server that will allow our Raspberry Pis to report their IPs and will also allow us to view the latest update on their IPs.
  • On each Raspberry Pi, we will create a script that, once the device is booted, will find its the IP address and will report it to the above-mentioned server.

On the server

Let’s start by thinking about the database we will need. We need to store there the hostname and the IP address of each Raspberry Pi. The simplest solution we can give, is a database of the following schema:

mysql> USE rpiobserver;
mysql> DESCRIBE raspberry_pi;

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| hostname   | varchar(50)  | NO   |     | NULL    |                |
| ip_address | varchar(100) | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

Nothing fancy here. A slightly different approach could be to set the hostname as the primary key of the database and use only the hostname to identify the entries of the table.

After setting up your database, you need to insert the hostnames of your Raspberry Pis in this table. As you can easily understand, each Raspberry must have a different and unique hostname. By default the Raspberry Pis are configured to use the hostname raspberrypi, but in our case, if you have 5 devices with the same hostname it would be very difficult to uniquely identify them. In order to change the hostname of your Raspberry Pi, you can follow either one of the following methods. First method: From the command line of your Raspberry Pi, run: sudo raspi-config. Select “Advanced Options” and then “Hostname.” Change the default hostname to the one you want to use. Second method: Edit the file: /etc/hostname with your favorite editor.

Now, let’s continue with the server’s script.

We are going to use Python’s Tornado web framework to develop our solution. As we saw earlier, on the server we want to do two things: to be able to see the IPs of our Raspberry Pis and to provide the opportunity to a Raspberry Pi to register its new IP address. The code that will allow us to provide this functionality is the following:

import torndb
import tornado.web
import tornado.ioloop

home_url = "127.0.0.1"
home_port = 4242
index_page = "index.html"
db_host = "localhost"

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        db = torndb.Connection(db_host, "db_name", user="db_user", password="db_pass")
        coll =  db.query("SELECT * FROM raspberry_pi")
        db.close()
        self.render(index_page, title = "Raspberry Pis", data = coll)

class RaspObserver(tornado.web.RequestHandler):
    # handle a get request
    def get(self):
        ip_add = self.request.arguments["ip"][0]
        host = self.request.arguments["hostname"][0]
        db = torndb.Connection(db_host, "db_name", user="db_user", password="db_pass")
        db.execute("UPDATE raspberry_pi SET ip_address=%s WHERE hostname=%s", str(ip_add), str(host))
        db.close()

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/", MainHandler),
            (r"/report", RaspObserver),
        ]
        tornado.web.Application.__init__(self, handlers)


if __name__ == "__main__":
    app = Application()
    app.listen(home_port)
    tornado.ioloop.IOLoop.instance().start()

Where you should define:

  • as home_url, the IP address of your server
  • as db_host, the IP address of your database server (in case it’s on a different machine)
  • as db_name, the name of your database
  • as db_user and db_pass, the credentials you use to connect to your database (you can also put these two in a separate python/config file and get them from there)

A brief explanation of the code:

  • the MainHandler function acts as our main endpoint. When the user requests this endpoint, we create a collection from our database that contains the current information we have about the IP addresses, and then we pass this collection to a template page, named index.html (we’ll discuss shortly about this page).
  • the RaspObserver function acts as the endpoint through which each Raspberry Pi will update its IP address. Each Raspberry Pi will make a request to this endpoint and will pass two parameters: its hostname and its IP address. The url of the request will look like: http://ip_of_server/report?hostname=”rpi-hostname”&ip=”XXX.XXX.XXX.XXX”. After this request is made, we get the values passed to the parameters of hostname and ip, and then we update the database accordingly.

Now let’s have a look at the index.html template page:


<html>
  <head>
    <title>{{ title }}</title>
  </head>
  <body>
    <table>
      <tr>
        <td>Hostname</td>
        <td>IP Address</td>
      </tr>
      {% for item in data %}
      <tr>
        <td>{{ item.hostname }}</td>
        <td>{{ item.ip_address }}</td>
      </tr>
      {% end %}
    </ul>
  </body>
</html>

This page is very similar to an HTML page, but you can also observe some differences (like the {% for %} loop). In fact, this file contains the skeleton of the HTML page that will be produced in the end. We iterate over the items of the collection we pass to this template in order to create a table that contains these information. Then, the finalized version of this HTML page is served to us.

Let’s see now what do we need on the side of our Raspberry Pis.

On the Raspberry Pi

As we discussed before, every time a Raspberry Pi boots, it needs to report its IP address to our server. For this reason we are going to create a Python script, which will make an HTTP request to our server and report the IP address and the hostname of each Raspberry Pi. This code of this script is:

import requests
import platform
import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

ip =get_ip_address('wlan0')
hostname = platform.node()

payload = {'hostname': hostname, 'ip': ip}

requests.get('http://server_ip:4242/report', params=payload)

You can save this script on your home directory and name it report.py.

The last thing that remains to do, is to execute this script every time your Raspberry Pi is booted. You can easily do this using a cron job. This can be done by executing crontab -e, in order to add your job there. In the end of this file, add a line that will execute your script every time your Raspberry Pi is booted:

@reboot   /usr/bin/python /home/pi/report.py


Warning: This solution was designed as a proof-of-concept. Security was not taken into account. If you are planning to put this on a publicly accessible server, then you should consider to sanitize the data you put into the SQL queries, in order to avoid SQL injections.