Search code examples
pythonpython-3.xconcurrencypython-multithreading

Threading with Python


complete python newbie... I'm working with the Arduino pyfirmata package and Im trying to do something quite simple.

Depending on a user input to python, I want an LED to flash or not.

My problem is that the python program only asks for the user input once but I would like it to always ask for the input so the user can change function at any time.

I have tried using the threading package but no success... Perhaps there is a simpler way, but I am totally new to coding so I do not know of any other. Open to suggestions!!

Here is my code,

import pyfirmata
import threading
import time

board = pyfirmata.Arduino('/dev/cu.usbmodem14101')

def flash():
    for i in range(1000):
        board.digital[13].write(1)
        time.sleep(1)
        board.digital[13].write(0)
        time.sleep(1)

def stop():
    board.digital[13].write(0)


while True:
    runMode = input("Run or Stop? ")

    if runMode == "Run":
        x = threading.Thread(target=flash(), args=(1,))
        x.start()
        # x.join()

    elif runMode == "Stop":
        x = threading.Thread(target=stop(), args=(1,))
        x.start()
        #x.join()

Solution

  • You can do it in an object-oriented way by creating your own Thread subclass something like the Flasher class below.

    One of the advantages to this approach is that it would be relatively easy to extend the Flasher class and make it control LEDs connected to different outputs, or to allow the delay between flashes to be specified at creation time. Doing the former would allow multiple instances to be running at the same time.

    import pyfirmata
    import threading
    import time
    
    OFF, ON = False, True
    
    class Flasher(threading.Thread):
        DELAY = 1
    
        def __init__(self):
            super().__init__()
            self.daemon = True
            self.board = pyfirmata.Arduino('/dev/cu.usbmodem14101')
            self.flashing = False
            self.LED_state = OFF
    
        def turn_LED_on(self):
            self.board.digital[13].write(1)
            self.LED_state = ON
    
        def turn_LED_off(self):
            self.board.digital[13].write(0)
            self.LED_state = OFF
    
        def run(self):
            while True:
                if self.flashing:
                    if self.LED_state == ON:
                        self.turn_LED_off()
                    else:
                        self.turn_LED_on()
                time.sleep(self.DELAY)
    
        def start_flashing(self):
            if self.LED_state == OFF:
                self.turn_LED_on()
            self.flashing = True
    
        def stop_flashing(self):
            if self.LED_state == ON:
                self.turn_LED_off()
            self.flashing = False
    
    
    flasher = Flasher()
    flasher.start()
    
    while True:
        runMode = input("Run or Stop? ").strip().lower()
    
        if runMode == "run":
            flasher.start_flashing()
        elif runMode == "stop":
            flasher.stop_flashing()
        else:
            print('Unknown response ignored')