如何运行其功能可以称为线程的对象

时间:2019-02-14 00:23:10

标签: python multithreading multiprocessing mqtt iot

我正在用Python为Raspberry Pi编写脚本,其目的是侦听服务器/消息代理的命令并使用某些硬件执行所述命令。有时,这些命令必须持续指定的持续时间(例如,我需要打开一些东西,保持打开状态t秒钟,然后关闭),这可以通过使代码在打开和关闭命令之间的这段时间内处于睡眠状态来实现(这发生在内部函数调用-hardware1.on(dur = t))。我希望能够用另一个命令来中断该序列(例如在t秒上升之前关闭硬件)。我已经尝试通过多处理来完成此任务,但是无法获得所需的行为。

此硬件(不同颜色的灯杆)通过LiteStalk类进行控制。该类由Lite对象(茎中的每个灯)组成,它们也具有自己的类。这两个类都继承multiprocessing.process。在创建特定LiteStalk然后侦听消息代理(基于MQTT)的命令的主代码中,我评估发布到代理的命令(这是在将消息发布到代理时运行的on_message回调中)

import time
import LiteCntrlModule as LiteStalkMod
import multiprocessing
import paho.mqtt.client as mqtt

print('Starting...\n')

# Set gpio designatin mode to BCM
gpio.setmode(gpio.BCM)

# Initialize light stalk
stalkdict = {'red':1, 'yel':2, 'grn':3, 'bzr':4}
stalk = LiteStalkMod.LiteStalk(stalkdict)
msgRec = ""

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    if(rc == 0):
        print('Code "0" indicates successful connection.  Waiting for messages...')
    # Subscribing in on_connect() means that if we lose the connection and
    # reconnect then subscriptions will be renewed.
    client.subscribe("asset/andon1/state")

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.payload))
    msgRec = msg.payload
    eval(msg.payload)
    if msg.payload == "stalk.off()":
        print("If this executes while another command is running, it works!")

client = mqtt.Client(client_id="")
client.username_pw_set("mytopic", password="mypassword")
client.on_connect = on_connect
client.on_message = on_message

client.connect("mymessagebrokeraddress", 1883, 60)
client.subscribe("mytopic")

# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
# Other loop*() functions are available that give a threaded interface and a
# manual interface.

try:
    client.loop_start() # start listening in a thread and proceed

except KeyboardInterrupt: # so that aborting with Ctrl+C works cleanly
stalk.off()

finally:
stalk.shutDown()

LiteCtnrlModule(Lite和LiteStalk类)如下:

import time
import multiprocessing
from relay_lib_seeed import *

Lite类(multiprocessing.Process):

# A Lite object has an associated relay and functions
# Ex: red
    # A lite can be controlled
    # Ex: red.blink()       

def __init__(self, relayIn):
    # Ex: red = Lite.Lite(1)
    multiprocessing.Process.__init__(self) # allows you to create multiple objects that can be run as threads
    self.daemon = True # creates a daemon thread that will exit when the main code terminates
    self.start() # allows multiproc. to begin
    self.relay = relayIn

def shutDown(self):
    # terminates the threaded object
    relay_off(self.relay)
    self.join()

def off(self, dur = 0):
            # turns light off

def on(self, dur = 0):
            # turns light on, optional duration to stay on for

# blink
def blink(self, dur = 0, timeOn = .5, timeOff = .5):
            # blinks light

LiteStalk(multiprocessing.Process)类:

# A LiteStalk object can have any number of "lite" onjects in it. Ex:
    # Object: stalk1
        # A lite object in stalk1 respresents one segment/color of the light stalk
        # stalk1.red
            # Any lite can be turned on/off in various patterns for amounts of time, etc.
            # stalk1.red.blink()
        # An entire stalk can be controlled all at once
        # stalk1.cycle()

liteList = {}

def __init__(self, liteListIn):

    # liteListIn = {'clr1':relay1, 'clr2":relay2, 'clr3':relay3]...}
    self.liteList = liteListIn;
    multiprocessing.Process.__init__(self) # allows you to create multiple objects that can be run as threads
    self.daemon = True # creates a daemon thread that will exit when the main code terminates
    self.start() # allows multiproc. to begin
    for lite in self.liteList: # for each lite color string in the lites dict
        setattr(self, lite, Lite(self.liteList[lite])) # creates a lite obj attr in the LiteStalk obj
    print(self.liteList)

def shutDown(self):

    # each light is turned off and that gpio pin is cleaned-up
    relay_all_off()
    self.join() # joins thread

def off(self, dur = 0):
            # turns all hardware off

def on(self): 
            # turns all hardware on, optional duration to stay on for
def blink(self, timeOn, timeOff):
            # blinks all hardware

def cntDn(self, dur = 20, yelDur = 2, redDur = 10): #in min
    # enters a count down sequence

在执行发布到服务器的任何其他命令之前,该命令始终会运行到完成状态,即,秸秆在指定的持续时间内保持打开状态,并且无法在持续时间结束之前被命令关闭(或执行其他任何操作)。我认为这可能是因为我没有将可多处理对象的所有功能都包含在run()函数中,但是我还是碰运气了。

2 个答案:

答案 0 :(得分:0)

Paho MQTT客户端是单线程的(您从client.loop_start()函数开始的线程),它一次只能为一条消息调用on_message()

这意味着它将阻塞对eval()的调用,直到传递给它的内容完成为止,即使这是代码正在创建新的线程来执行操作。

答案 1 :(得分:0)

我会建议用在threading.Event或等效事件上等待超时来替换睡眠,然后检查睡眠是由于设置了事件还是超时而结束的。如果已设置事件,请停止。

但是似乎还有其他问题,而不仅仅是可中断的睡眠。