Raspberry Pi Network Chat in Python

Myself and @ryanteck (Mr Rastrack) ran some Raspberry Pi workshops this week. I put together a simple network chat application between two Pi’s to demonstrate how easy it can be to build a network aware application.

We ran some workshops this week at a College, to train up students to be facilitators at an event we will soon be running for school children. One of the workshops we want to run is a “networking” workshop, to give kids the building blocks to connect bits of hardware over the network (and potentially the internet). With the present buzz about “The Internet of Things”, we’re hoping that our new generation of engineers can hit the ground running!

It’s relatively simple to use network sockets from a program if you know how. However, the sockets module is quite big and it’s not completely obvious how to take this general purpose module and do something real with it. Python has a number of very nice socket abstraction classes (e.g. StreamSocket), one of which I used for my 13 line python web server example.

However, I wanted something non object based (as we don’t specifically teach python classes and inheritance to kids at an early age) and something that could be used as a simple building block for all sorts of programs.

Network Chat

My use-case for a simple networking module, was to enable kids with limited python knowledge to write a chat application. The chat application would have a client mode and a server mode, and allow messages to be typed in both directions. Oh, and I wanted a single program to work as both the client and the server, with the main “messaging” loop being identical between both of them.

The server is started first, and listens on a known TCP/IP port number. The client is then started on another computer and the IP address of the server computer used as a parameter. Both computers can then be used to accept messages from the keyboard and route those messages to the other computer.

My hope for this program is that it will prove a useful networking building block for class teachers and people running school clubs to build upon to build bigger and better projects out of. Ryan is already talking about controlling his robots with it, and I have some “Internet of Things” conceptual demos I want to put together using it for an up and coming Raspberry Jam.

Network Configuration (Dynamic)

Before you can connect two computers together, the networking needs to be correctly configured so that it is possible to make a connection between them both. This is all about making sure that both machines have an IP address that you know.

If you plug both Raspberry Pi’s into a shared network and use DHCP (Dynamic Host Configuration Protocol) to allocate each an IP address, they will automatically get a unique IP address on that network. If they are both on the same network without any firewalls in the way, the network equipment (switches) will make sure that network traffic can flow between the two.

You can use this setup, for example, by plugging both Pi into a school wired network, or by using a spare internet router and plugging both Pi into the same router (with DHCP enabled on the router, it’s on by default on most routers).

Then, on each Pi, type at a command prompt:

ifconfig

and against the “eth0″ adaptor you will see the IP address that has been allocated to that Pi.

Network Configuration (Static)

If all you have is two Raspberry Pi and a bit of network cable (no router or no school network access), you can still make this work with static IP addressing.

Edit the file /etc/network/interfaces as below (you can use sudo nano /etc/network/interfaces as a way to edit this file)

iface eth0 inet static
address 192.168.0.2
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.1

i.e. change the line that says “iface eth0 inet dhcp” to use static, and add the lines that follow.

It is usual to reserve the .1 address for a router, so number your first pi with a .2 at the end, and your second pi with a .3 at the end.

Once you have made these changes, save the file (in nano CTRL-X then say “y” to save the changes”.

Finally, the most reliable way to make sure these changes take effect is to reboot with:

sudo reboot

When you have rebooted and logged back in again, type ifconfig at the command prompt to verify that your chosen IP address has been allocated to the eth0 adaptor.

Ping

Before you try to run any applications that rely on this network setup, you should check that the low level communications are working – always build networks from the “bottom up”. First plug in the ethernet cable to both Pi’s, then use the ping command to ping the IP address of the other machine:

ping 192.168.0.2

Network Chat

The final step is to copy both the network.py and chat.py programs into the same folder on your pi. Both programs are provided in the zip file for download in the resources links at the end.

On the first Pi, set it up as a server by typing at a command prompt:

python chat.py

On the second Pi, set it up as a client (calling your server) by typing this at the command prompt (note you use the IP address of the Pi you are connecting to).

python chat.py 192.168.0.3

You should now be able to type messages on either Pi and they will appear on the other screen when you press the enter key.

The Program

The full program is linked below in the resources, but shown here also so we can talk about some of the details a bit further. It’s only a 14 line program, so not too much to expect kids to type in!

import network
import sys

def heard(phrase):
  print "them:" + phrase

print "Chat Program"

if (len(sys.argv) >= 2):
  network.call(sys.argv[1], whenHearCall=heard)
else:  
  network.wait(whenHearCall=heard)

print "Chat away!"  
while network.isConnected():
  phrase = raw_input()
  print "me:" + phrase
  network.say(phrase)

The clever code is inside the network.py file, so we import that at the top. We also import sys as we want to get at the command line arguments to check if the user provided an IP address or not.

One of the challenges with this program is we need to accept messages from the network at any time, while we are waiting reading characters from the keyboard from our local user. There is a bit of magic inside the network.py module that does this for us, but at this point in the program all you have to do is to provide your own function that is called when an incoming message arrives. The magic bit (there is a “thread” inside network.py) is all handled cleanly for you. So, the “heard” function is where you put any code that you want to run when the network module “hears” something from the other end.

sys.argv tells us the arguments (argv is the “argument vector”) that are provided on the command line. The first argument is always the name of the running program. So, if there are 2 or more arguments, the user has provided an IP address and we want to start in client mode.

It’s like making a telephone call – one person stays sitting by the telephone waiting for it to ring, the other picks up their phone and dials the number.

network.call() makes the phone call – it connects to the desired IP address (just think of this a bit like a telephone number). The “whenHearCall=heard” tells the network module which of your functions it should call when it hears a message from the other end

If there is only 1 argument (the program name), it means no IP address was provided, so we want to start in server mode. “network.wait()” basically tells the network module to wait for an incoming call – a bit like sitting by the phone waiting for it to ring.

So, at this point, you have either made the call and it has been answered (network.call) or you were waiting for a call and it came in and you answered it (network.wait)

Finally, we have a little loop, all the while the network is connected, we ask our local user to enter a message, then “say” that over the network line for the other end to hear. If at any time while we are waiting here a message is heard from the other end, our “heard” function is automatically called.

Handling the network sockets, error conditions, and the threading associated with this setup is slightly too complex for kids to work out and code on their own, but we have found by example that the above chat program is simple enough to understand and modify further without getting too entangled in all the required threading and network sockets code.

Ideas for further development

I would hope that the code and the attached resources here could be used in many ways as a building block for something bigger, so please use these resources as a basis for your own lessons or workshops.

One of the nice things to try is instead of using it as a chat program, connect some hardware to each Pi and get it to send hardware related messages – e.g. at the Stevenage Raspberry Jam I demonstrate a switch on Pi number 1, and when the switch is changed it sends a network message to Pi number 2 which turns a light on and off. This could be the basis of a simple “Internet of Things” product (the switch could be a door sensor, and the light could be an alarm).

If you can send a message over a piece of ethernet cable like this, you can send a message over the whole internet. Most children these days know how to configure your home broadband router, and it is possible to put a “port forward” on your internet router so that all traffic coming from the outside world on our port 8888 is redirected to your raspberry pi at home. A second raspberry pi out in the wild could then connect-in and send messages to it. (Tip, you can usually get the public IP address of your router either from your router’s admin page, or there are sites on the internet you can visit that tell you your public IP address).

If you do make some interesting workshops or internet connected gadgets using these building blocks, please let me know, you can find me as @whaleygeek on twitter.

Update September 2014

I first wrote this chat program to support the North Herts College Raspberry Pi Bake-off competition in December 2013. Since then, I’ve run a number of workshops at the Cambridge Raspberry Jam, and a lot of schools have shown interest in using this material to teach networking. I’m really pleased to say that the Raspberry Pi Foundation have kindly turned this and related projects into a 4-lesson scheme of work that supports the new National Curriculum.

Clive Beale at the Foundation has done a fantastic job of packaging this up into a complete networking scheme, which includes configuring your Pi for networking, writing and extending the Internet Chat application, and making your own Internet connected “Thing”. Please do take a look, and try those advanced exercises too! See link [5] below.

Resources

Note, the code and examples in this blog post use python 2. If you use python 3 you will have to use brackets round print() and use input() instead of raw_input(). Typing “python” at the command prompt as in the examples provided, should normally access python 2, so hopefully all these examples should work out of the box for you. I have written the network.py specifically to adjust automatically to both Python 2 and Python 3 environments.

[1] network-chat.zip

[2] NetworkingCribsheet.pdf (by @ryantek)

[3] NetworkMessaging-Cribsheet.pdf (by @whaleygeek)

p.s. there is the odd spelling error in the worksheets and code, we were under pressure to get this all typed up in time for a workshop. I will revisit in a few days and fix typos (but the programs are tested and do work)

[4] Newer network code on github supports python2 and python3 (by @whaleygeek)

[5] Raspberry Pi Foundation – Networking Lessons, September 2014

 

This entry was posted in Raspberry Pi. Bookmark the permalink.

Comments are closed.