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.


DIFFICULTY
DIFFICULT
COMPUTER FAMILIARITY
LITTLE
CIRCUITRY KNOWLEDGE UNDERSTANDING
LITTLE
PYTHON PROGRAMMING
CONSIDERABLE
ABOUT
0
MINUTES
  • 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&#93;)
    # Process the raw data into something we understand.
    processedData = ((rawData&#91;1&#93;&3) << 8) + rawData&#91;2&#93;
    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

You shouldn’t need any additional supporting content to complete this tutorial!

Tutorial 27

Tutorial 28

Tutorial 29