Tutorial 27 & 28 & 29: Socket Communication
The following video tutorials cover the topic of socket communication between two (or more) Raspberry Pis using Python 3. This tutorial is not particular to just the Raspberry Pi and the concepts learned here can be applied to any regular PC.
Socket communication allows our Raspberry Pi's to communicate via Ethernet (or wifi) to each other using your home's router. In the context of the Cookie Thief project, we will be using socket communication to transfer readings from sensors on one side of my apartment to yield an output on the other side of my apartment. Tutorials 27 & 28 cover basic text socket communication. However we're going to want to transfer real data from one pi to the other. Tutorial 29 involves the use of an analog sensor and temperature data being sent to another Raspberry Pi connected to a LED. In tutorial 30 I will show you how to transfer files (or backup files) via socket communication.
This tutorial is a little older (published in 2015!). The main principles are still relevant, so I haven't needed to update this lesson.
- 2x Raspberry Pi
- 2x 5VDC Micro USB Power Supply
- Home Router
- 2x Ethernet Cables or Wifi Modules
- LED
- MCP3008 or MCP3004
- TMP36 Analog Temperature Sensor
- Resistor (220 – 1,000 ohm)
- Breadboard
- Breadboard compatible wires
- 2x Pi Cobbler (Optional)
DIFFICULTY
COMPUTER FAMILIARITY
CIRCUITRY KNOWLEDGE UNDERSTANDING
PYTHON PROGRAMMING
- How socket communication works
- How to transfer data from one Raspberry Pi to another using Python 3 and TCP Networking
- How to automatically implement outputs on a distant Raspberry Pi from inputs on a local Raspberry Pi
You can copy / paste the code below if you’re having issues with typos or want a shortcut. However I recommend that you follow along in the tutorial to understand what is going on!
cookieServer.py
import socket
host = ''
port = 5560
storedValue = "Yo, what's up?"
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
except socket.error as msg:
print(msg)
print("Socket bind comlete.")
return s
def setupConnection():
s.listen(1) # Allows one connection at a time.
conn, address = s.accept()
print("Connected to: " + address[0] + ":" + str(address[1]))
return conn
def GET():
reply = storedValue
return reply
def REPEAT(dataMessage):
reply = dataMessage[1]
return reply
def dataTransfer(conn):
# A big loop that sends/receives data until told not to.
while True:
# Receive the data
data = conn.recv(1024) # receive the data
data = data.decode('utf-8')
# Split the data such that you separate the command
# from the rest of the data.
dataMessage = data.split(' ', 1)
command = dataMessage[0]
if command == 'GET':
reply = GET()
elif command == 'REPEAT':
reply = REPEAT(dataMessage)
elif command == 'EXIT':
print("Our client has left us :(")
break
elif command == 'KILL':
print("Our server is shutting down.")
s.close()
break
else:
reply = 'Unknown Command'
# Send the reply back to the client
conn.sendall(str.encode(reply))
print("Data has been sent!")
conn.close()
s = setupServer()
while True:
try:
conn = setupConnection()
dataTransfer(conn)
except:
break
cookieClient.py
import socket
host = '192.168.1.79'
port = 5560
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
while True:
command = input("Enter your command: ")
if command == 'EXIT':
# Send EXIT request to other end
s.send(str.encode(command))
break
elif command == 'KILL':
# Send KILL command
s.send(str.encode(command))
break
s.send(str.encode(command))
reply = s.recv(1024)
print(reply.decode('utf-8'))
s.close()
cookieClient2.py
import socket
from time import sleep
host = '192.168.1.79'
port = 5560
def setupSocket():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
return s
def sendReceive(s, message):
s.send(str.encode(message))
reply = s.recv(1024)
print("We have received a reply")
print("Send closing message.")
s.send(str.encode("EXIT"))
s.close()
reply = reply.decode('utf-8')
return reply
def transmit(message):
s = setupSocket()
response = sendReceive(s, message)
return response
cookieAnalog2.py
import spidev
# First open up SPI bus
spi = spidev.SpiDev()
spi.open(0,0)
# Initialize what sensor is where
tempChannel = 0
def getReading(channel):
# First pull the raw data from the chip
rawData = spi.xfer([1, (8 + channel) << 4, 0])
# Process the raw data into something we understand.
processedData = ((rawData[1]&3) << 8) + rawData[2]
return processedData
def convertVoltage(bitValue, decimalPlaces=2):
voltage = (bitValue * 3.3) / float(1023)
voltage = round(voltage, decimalPlaces)
return voltage
def convertTemp(bitValue, decimalPlaces=2):
# Converts to degrees Celsius
temperature = ((bitValue * 330)/float(1023) - 50)
temperature = round(temperature, decimalPlaces)
return temperature
def getTemp():
tempData = getReading(tempChannel)
temperature = convertTemp(tempData)
return temperature
#>
cookieMain2.py
import P3picam
import picamera
from datetime import datetime
from subprocess import call
from time import sleep
from cookieClient2 import transmit
from cookieAnalog2 import getTemp
motionState = False
picPath = "/home/pi/Desktop/cookie/images/"
sleepTime = 3
triggerTemp = 20
def captureImage(currentTime, picPath):
# Generate the picture's name
picName = currentTime.strftime("%Y.%m.%d-%H%M%S") + '.jpg'
with picamera.PiCamera() as camera:
camera.resolution = (1280, 720)
camera.capture(picPath + picName)
print("We have taken a picture.")
return picName
def getTime():
# Fetch the current time
currentTime = datetime.now()
return currentTime
def timeStamp(currentTime, picPath, picName):
# Variable for file path
filepath = picPath + picName
# Create message to stamp on picture
message = currentTime.strftime("%Y.%m.%d - %H:%M:%S")
# Create command to execute
timestampCommand = "/usr/bin/convert " + filepath + " -pointsize 36 \
-fill red -annotate +700+650 '" + message + "' " + filepath
# Execute the command
call([timestampCommand], shell=True)
print("We have timestamped our picture.")
def tempMonitor():
print("About to take a reading.")
temp = float(getTemp())
print("Out temp is: " + str(temp))
if temp > float(triggerTemp):
message = "LED_ON"
print("Transmitting data.")
response = transmit(message)
print(response)
while True:
#motionState = P3picam.motion()
tempMonitor()
sleep(sleepTime)
#print(motionState)
#if motionState:
# currentTime = getTime()
# picName = captureImage(currentTime, picPath)
# timeStamp(currentTime, picPath, picName)
cookieLED.py
import RPi.GPIO as GPIO
from time import sleep
sleepTime = 5
ledPin = 12
def ledSetup():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(ledPin, GPIO.OUT)
def ledON():
GPIO.output(ledPin, True)
sleep(sleepTime)
GPIO.cleanup()
def callLED():
ledSetup()
ledON()
cookieServer2.py
import socket
from cookieLED import callLED
host = ''
port = 5560
storedValue = "Yo, what's up?"
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
except socket.error as msg:
print(msg)
print("Socket bind comlete.")
return s
def setupConnection():
s.listen(1) # Allows one connection at a time.
conn, address = s.accept()
print("Connected to: " + address[0] + ":" + str(address[1]))
return conn
def GET():
reply = storedValue
return reply
def REPEAT(dataMessage):
reply = dataMessage[1]
return reply
def dataTransfer(conn):
# A big loop that sends/receives data until told not to.
while True:
# Receive the data
data = conn.recv(1024) # receive the data
data = data.decode('utf-8')
# Split the data such that you separate the command
# from the rest of the data.
dataMessage = data.split(' ', 1)
command = dataMessage[0]
if command == 'GET':
reply = GET()
elif command == 'REPEAT':
reply = REPEAT(dataMessage)
elif command == 'LED_ON':
callLED()
reply = 'LED was on'
elif command == 'EXIT':
print("Our client has left us :(")
break
elif command == 'KILL':
print("Our server is shutting down.")
s.close()
break
else:
reply = 'Unknown Command'
# Send the reply back to the client
conn.sendall(str.encode(reply))
print("Data has been sent!")
conn.close()
s = setupServer()
while True:
try:
conn = setupConnection()
dataTransfer(conn)
except:
break