Controlling GPIO Using UDP Packets!
There are many ways to control and get sensor data through GPIO through the network. Some require you to setup a web server and some require you to pass your data out of your network. In this post, we will be using none of those, instead we will be using UDP broadcasting.
Before we start off, what is UDP? UDP stands for User Datagram Protocol. It is similar to Transmission Control Protocol(TCP) except that UDP it is connectionless and provides no guarantee that your message will be received on the other end.(Downloading files over the internet is TCP since you don’t want your files to be corrupted.) This is useful for transmitting small amounts of data. Numerous protocols are using UDP such as Domain Name Services(DNS), Dynamic Host Control Protocol(DHCP), etc.
Ok, so what’s UDP Broadcasting? To simplify, it means to send a UDP packet to the broadcast address. A 192.168.1.0/24 network has a broadcast address of 192.168.1.255, if you were to send a message to 192.168.1.255, only hosts inside the subnet are able to receive the message.
However, if you were to send a message to 255.255.255.255(also known as 0.0.0.0), every hosts in the network are able to receive the message, be it a 10.10.10.10 or a 192.168.1.5 or a 126.96.36.199 address.
Make sure you are doing this on a network that you trust since none of this packets are encrypted and anyone on the network are able to sniff and manipulate your data. A simple way is to setup a Virtual Local Area Network(VLAN) for devices that will be communicating with each other and set the broadcast address accordingly. For this post, we will be using a 255.255.255.255, therefore, ANYONE will be able to read the data passing through the network.
I have written a helper class so that the code can be reused easily later on. The following is for sending UDP packets.
UDP_IP = "255.255.255.255" def SendUdp( UDP_PORT, sent_data ): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.sendto(sent_data, (UDP_IP, UDP_PORT))
The code takes in 2 parameters; UDP_PORT and sent_data. UDP_Port specifies which port the program will bind to between the range of 0-65535. In case the program doesn’t run as expected, you may want to check your iptables / UFW / firewalld rules or any other processes maybe using the port.
UDP_IP = "255.255.255.255" def RecvUdp( UDP_PORT ): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((UDP_IP, UDP_PORT)) recv_data , addr = sock.recvfrom(1024) return recv_data
The above is the receiving code. Combining them together and we have
import socket UDP_IP = "255.255.255.255" sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) def SendUdp( UDP_PORT, sent_data ): sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.sendto(sent_data, (UDP_IP, UDP_PORT)) def RecvUdp( UDP_PORT ): sock.bind((UDP_IP, UDP_PORT)) recv_data , addr = sock.recvfrom(1024) return recv_data
The code is taken from python’s wiki and modified for my needs.
Let’s get the temperature reading from a DHT22 sensor. This is how it will work. Firstly, set the Raspberry Pi on “listening mode”.
Then on our PC we will send a message to the Raspberry Pi.
from gpio_udp import SendUdp SendUdp(5005,"Please give me temperature data.")
The Raspberry Pi will respond accordingly. So you will have to program the message yourself. For this case, the message is “Please give me temperature data”. You could simplify it by using “temp data” instead. The content of the message is really up to you.
After receiving the message, the Pi will ping back with a broadcast using the following code.
humidity, temperature = Adafruit_DHT.read_retry(22, 14) if humidity is not None and temperature is not None: string_temp = str(round(temperature,2)) SendUdp(5005,string_temp) else: print 'Failed to get reading. Try again!'
Ensure your computer is also listening. That’s really it.
You could use this to control LEDs, motor relay, Wake on Lan and anything you like. A huge advantage of this project is that there is no reliance on external servers. But what if you will like to receive this outside your network? You could use a host proxy to relay data.
Simply send a message to the proxy server(make sure you have port forwarding enabled) and have the proxy server relay the message to your Raspberry Pi. The Raspberry Pi will then relay the data back to the proxy server before sending the data to your smartphone.
Another advantage of this project is that it’s written in python, therefore, it should work on any platform that has a python interpreter.
As usual, source code is available. The helper class is at the root directory named gpio_udp.py. Simply include it in your project. There are samples in the samples directory for initial setup. This is my first time writing python code so it’s really rough, any contributions are welcome.