Как бесконечный цикл внутри функции - PullRequest
0 голосов
/ 17 июня 2019

У меня проблема с созданием кода (я все еще учусь), который будет соединяться с сервером MQTT и проверять фактическое состояние вывода GPIO, которым я могу управлять с помощью локальной веб-страницы.

Моя проблема заключается в том, чтоЯ не знаю, как сделать бесконечный цикл внутри функции, которая будет проверять фактическое состояние вывода и сравнивать его с последним состоянием, отправленным 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()

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Правильный способ сделать это - изменить client.loop_forever() на client.start_loop() ( документы ).

Это запустит цикл клиента 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)

(ps. Вы действительно не должны спать в обратном вызове on_message, поскольку это происходит насетевой поток и замедляет обработку сообщений)

0 голосов
/ 17 июня 2019

Вы можете использовать цикл while .

Цикл 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

Попробуйте онлайн!

Вы можете тривиально изменить выражение while, чтобы ВСЕГДА перевести в True:

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

Попробуйте онлайн!

Это работает в функции.

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

print_natural_numbers()

Попробуйте онлайн!

Чтобы изменить вышеуказанное в соответствии с вашими потребностями:

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) и не продолжатьсяна другой код)

Похоже, для этого требуется многопроцессорная .

Демонстрация:

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()

Для вашего случая вам нужносделать две функции: функцию проверки и функцию, которая представляет все остальное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...