【问题标题】:How to infinite loop inside function如何在函数内部无限循环
【发布时间】:2019-06-17 17:25:20
【问题描述】:

我在编写与 MQTT 服务器通信并检查我可以使用本地网页控制的 GPIO 引脚的实际状态的代码时遇到问题(我仍在学习)。

我的问题是我不知道如何在函数内部进行无限循环,该函数将检查 pin 的实际状态并将其与 MQTT 发送的最后状态进行比较,如果有变化,它将向 MQTT 发布新值。

#!/usr/bin/env python2

import paho.mqtt.client as mqtt
import urllib
from time import sleep
import RPi.GPIO as GPIO


#Conf GPIO Number for relays
out_1 = 6

#Conf MQTT broker
broker_ip = "192.168.1.34"
broker_port = 1883
broker_timeout = 60
topic_sub = "/printer/#"
topic_out1 = "/printer/onoff"

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(out_1, GPIO.OUT)
GPIO.output(out_1, GPIO.HIGH)

def main():
    # This is the issue part where I wanted to make looped check for actual value
    def check_state(astate):
            f= open("/sys/class/gpio/gpio6/value","r")
            if f.mode == "r":
                    state = f.read(1)
            if astate == state :
                    return
            else:
                    print("CHANGE")

    def on_connect(client, userdata, flags, rc):
            client.subscribe(topic_sub)

    def on_message(client, userdata, msg):
            if msg.topic == topic_out1 :
                    if msg.payload == "1" :
                            GPIO.output(out_1, GPIO.LOW)
                            state = "1"
                            sleep(.1)
                            print("OUT 1 ON")
                    if msg.payload == "0" :
                            GPIO.output(out_1, GPIO.HIGH)
                            state = "0"
                            sleep(.1)
                            print("OUT 1 OFF")

    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message

    client.connect(broker_ip, broker_port, broker_timeout)

    client.loop_forever()

if __name__ == "__main__":
    try:
            main()
    except KeyboardInterrupt:
            GPIO.cleanup()

编辑: 这就是我在 @MilkyWay90 的多处理帮助下实现的。

#!/usr/bin/env python2

import urllib
from multiprocessing import Process
from time import sleep
import RPi.GPIO as GPIO


#Conf GPIO Number for relays
out_1 = 6

#Conf MQTT broker
broker_ip = "192.168.1.34"
broker_port = 1883
broker_timeout = 60
topic_sub = "/printer/#"
topic_out1 = "/printer/onoff"

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(out_1, GPIO.OUT)
GPIO.output(out_1, GPIO.HIGH)

def check_state():
        import paho.mqtt.client as mqtt
        clientSEND = mqtt.Client()
        clientSEND.connect(broker_ip, broker_port, broker_timeout)
        while True:
                faf= open("/sys/class/gpio/gpio6/value","r")
                qf= open("/home/pi/.state","r")
                fastate = faf.read(1)
                #reverse logic for gpio value
                if fastate == "0" :
                        astate = "1"
                elif fastate == "1" :
                        astate = "0"
                qstate = qf.read(1)
                #print("GPIO state: ",astate,"MQTT state: ",qstate)
                if astate != qstate :
                        clientSEND.publish(topic_out1, astate)
                        #print("CHANGE")
                        sleep(3)
                else:
                        sleep(3)

def mqtt():
        import paho.mqtt.client as mqtt
        def on_connect(client, userdata, flags, rc):
                client.subscribe(topic_sub)

        def on_message(client, userdata, msg):
                if msg.topic == topic_out1 :
                        if msg.payload == "1" :
                                GPIO.output(out_1, GPIO.LOW)
                                state_write("1")
                                sleep(.1)
                                #print("OUT 1 ON")
                        if msg.payload == "0" :
                                GPIO.output(out_1, GPIO.HIGH)
                                state_write("0")
                                sleep(.1)
                                #print("OUT 1 OFF")

        def state_write(state):
                f= open("/home/pi/.state","w")
                f.write(state)
                f.close

        client = mqtt.Client()
        client.on_connect = on_connect
        client.on_message = on_message

        client.connect(broker_ip, broker_port, broker_timeout)

        client.loop_forever()

if __name__ == "__main__":
        try:
                bck_statuscheck = Process(target=check_state)
                mqtt_process = Process(target=mqtt)
                bck_statuscheck.start()
                mqtt_process.start()
                bck_statuscheck.join()
                mqtt_process.join()
        except KeyboardInterrupt:
                GPIO.cleanup()

【问题讨论】:

  • 你的问题是什么?
  • 不确定这是否有帮助,但while True 是一个无限循环。 :P

标签: python raspberry-pi mqtt


【解决方案1】:

您可以使用while loop

while 循环是 Python 中的一个循环,它在条件计算为 True 时运行指定的代码。

这是一个while循环的结构:

while <condition>:
    CODE

一个例子可以是:

counter = 1 # Declare a variable named "counter" and set it to the integer 1
while counter <= 10: # This is the while loop. As you can see, the condition checks whether the counter is less than or equal to the integer 10. If it is, execute the code that is indented. This will be checked every iteration
    print(counter) # Use the print function to print out the counter with a newline
    counter += 1 # Increment the counter. This is roughly equivalent to counter = counter + 1

这个输出:

1
2
3
4
5
6
7
8
9
10

Try it online!

您可以简单地将 while 语句修改为 ALWAYS evalulate 为 True:

counter = 1
while True:
   print(counter)
   counter += 1

Try it online!

这确实在函数中起作用。

def print_natural_numbers():
    counter = 1
    while True:
        print(counter)
        counter += 1

print_natural_numbers()

Try it online!

根据您的需要修改上述内容:

def check_state(astate):
        while True:
                f= open("/sys/class/gpio/gpio6/value","r")
                if f.mode == "r":
                        state = f.read(1)
                if astate == state :
                        return
                else:
                        print("CHANGE")

或者另一种选择:

while True:
    check_state(...)

编辑:

在这之后不会一直停留在一个功能中吗?所以它只会检查实际状态,而忽略其他一切(MQTT 部分)?

(改写:使用上面的代码,这将一直运行(因为 while 循环),而不是继续运行其他代码)

看起来这需要multiprocessing

演示:

from multiprocessing import Process

def print_natural_numbers():
    counter = 1
    while True:
        print(counter, flush = True)
        counter += 1

def print_square_numbers():
    counter = 1
    while True:
        print(counter ** 2, flush = True)
        counter += 1

if __name__ == '__main__':
    nat_numbers = Process(target=print_natural_numbers)
    sqrt_numbers = Process(target=print_square_numbers)
    sqrt_numbers.start()
    nat_numbers.start()
    sqrt_numbers.join()
    nat_numbers.join()

对于您的情况,您需要创建两个函数:检查函数和代表其他所有内容的函数。

【讨论】:

  • 不会一直卡在一个函数中吗?所以它只会检查实际状态,而忽略其他一切(MQTT 部分)?
  • @MartinRehak 我可以在多处理选项中进行编辑
  • @MartinRehak 好的,我编辑了它。如果这对您有帮助,请记住单击接受按钮,以便其他人知道此解决方案有效。
  • @MartinRehak 你也可以考虑在函数中加入sleep
【解决方案2】:

正确的做法是将client.loop_forever() 更改为client.start_loop() (docs)。

这将在后台在其自己的线程上启动 MQTT 客户端循环,然后您可以在启动循环后将自己的 while True: 循环添加到 main 函数,例如

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect(broker_ip, broker_port, broker_timeout)

client.start_loop()

while True:
   check_state()
   sleep(1)

(p.s. 你真的不应该在 on_message 回调中睡觉,因为这发生在网络线程上并减慢消息处理速度)

【讨论】:

    猜你喜欢
    • 2011-11-12
    • 2020-03-17
    • 1970-01-01
    • 2018-03-29
    • 2013-06-05
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 2019-09-27
    相关资源
    最近更新 更多