4

I am trying to multi thread on a Raspberry Pi using python 3. I have one Pi acting as a server listening for multiple connections from other Pi clients and the server is also connected to relays and physical push buttons.

I can get the server to listen to and allow connections from the clients and allow the clients to send commands to throw the relays, but I can't get the server to throw the relays from the physical push buttons. If I take out the code for the socket server and just leave the code for the physical push buttons, then it works and the relays will throw.

I have moved code around, tried writing the threading for the push buttons different that I have read and just can't get the Pi to allow the switch of relays by both commands from the clients and the push buttons.

What changes do I need in the following code to allow both command approaches to work? Or is there some kind of setup that I am missing?

import socket
import threading
import serial
from time import sleep
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)

switch1 = 11
switch2 = 13

GPIO.setup(switch1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(switch2, GPIO.IN, pull_up_down=GPIO.PUD_UP)

ser = serial.Serial('/dev/ttyUSB0', 9600)

host = ''
port = 5560


class Button(threading.Thread):
    def __init__(self, channel):
        threading.Thread.__init__(self)
        self.channel = channel
        GPIO.setup(self.channel, GPIO.IN)
        self._pressed = False
        self.daemon = True
        #self.start()

    def pressed(self):
        if self._pressed:
            self._pressed = False
            return True
        else:
            return False

def run(self):
    previous = None
    while True:
        current = GPIO.input(self.channel)
        sleep(.01)
        if current == False and previous == True:
            self._pressed = True
            while self._pressed:
                sleep(.05)
        previous = current

def relay():
    while True:
        if GPIO.input(switch1) == 0:
            ser.write('a3'.encode('UTF-8'))
            sleep(2)
        elif GPIO.input(switch2) == 0:
            ser.write('a4'.encode('UTF-8'))
            sleep(2)

#thread1 = threading.Thread(target=relay)



class ThreadedServer(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind((self.host, self.port))



def listen(self):
    self.sock.listen(5)
    while True:
        client, address = self.sock.accept()
        #client.settimeout(90)
        threading.Thread(target=self.listenToClient, args=(client, address)).start()


def listenToClient(self, client, address):
    size = 1024
    while True:
        try:
            data = client.recv(size)
            if data:
                # Set the response to echo back the recieved data
                response = data
                client.send(response)
                data = data.decode('UTF-8')

                if data == 'a1':
                    ser.write('a1'.encode())
                    print("A1")
                elif data == 'a2':
                    ser.write('a2'.encode())
                    print("A2")
                elif data == 'a3':
                    ser.write('a3'.encode())
                    print("A3")
                elif data == 'a4':
                    ser.write('a4'.encode())
                    print("A4")
                elif data == 'quit':
                    break
                elif data == 'off':
                    command = "/usr/bin/sudo /sbin/shutdown -h now"
                    import subprocess
                    process = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
                    output = subprocess.communicate()[0]
                    print(output)
            #else:
             #   raise error = 'Client disconnected'
        except:
            client.close()
            return False

if __name__ == "__main__":
    while True:
        #port_num = input("Port? ")
        try:
            port_num = int(5560)
            button = Button(11)
            buttonthread = threading.Thread(target=button.run)
            buttonthread.start()
            if button.pressed():
                relay()
            #thread1.join()
            break
        except ValueError:
            pass

    ThreadedServer('',port_num).listen()
  • For the physical buttons use interrupts, not threads. See answers to this question: raspberrypi.stackexchange.com/questions/75511/… – Brick Nov 26 '17 at 4:06
  • Sounds like a XY problem Why not just use a separate process on the server to connect to the socket on localhost? – Milliways Nov 26 '17 at 7:28
  • Have a look at (my) pigpio which provides these features. By the way you do no error checking on the received data which may be both shorter or longer than you expect. – joan Nov 26 '17 at 9:35
4

Because of the GIL (Global Interpreter Lock), Python is notorious for not being very friendly to multi-threaded application design.

One possible solution is to use the Python MultiProcessing library instead. This library provides process-level execution to "emulate" much of the capabilities you normally get with multithreading.

Might be worth trying it out! Please check back in and let us know if this helped. Good luck!

  • Threading is a red herring here. Even in a single-threaded process that just checks for the button being pressed, the OP is likely to encounter the same problem. – Brick Nov 26 '17 at 17:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.