简体   繁体   中英

Raspberry Pi - MQTT broker receiving message more than one time - [errno 24] too many open files

i need help for my project for my graduation conclusion.

I've set this program to controll the raspberry from the web, using node-red node MQTT. At first, the communication worked just fine, however, in some point the program start to receive the message more than one time after I inject it from the node-red flow and it makes the program crash as it gets the error: oserror: [errno 24] too many open files . I analysed the code and just can't find out why the mqtt broker receives more than one message per time, and I need help, I'm really desperate. In the images I show the flow from node-red and the output from the terminal on raspberry pi.

 #! usr/bin/ env python

#Import librarys used#
import paho.mqtt.client as mqtt 
import RPi.GPIO as GPIO 
import sys 
import time 
import Adafruit_DHT 
import MFRC522 

#Definition of inputs#

GPIO.setwarnings(False) 
GPIO.setmode(GPIO.BOARD) 
pino_presenca = 11 #Set the input of the PIR sensor used in the project
GPIO.setup(pino_presenca, GPIO.IN)
pino_luminosidade = 15  #Set the input of the LDR module used in the project
GPIO.setup(pino_luminosidade, GPIO.IN)
pino_temperatura = 27 #Sets the input of the DHT11 sensor used in the project


#Set the LED used to demonstrate the mode select (Automatic or manual)#
GPIO.setup(12, GPIO.OUT) 
GPIO.output(12, GPIO.LOW) 
GPIO.setup(16, GPIO.OUT) 
GPIO.output(16, GPIO.LOW) 

#Set the outputs used in the project
GPIO.setup(36, GPIO.OUT) 
GPIO.output(36, GPIO.HIGH) 
GPIO.setup(38, GPIO.OUT) 
GPIO.output(38, GPIO.HIGH) 
GPIO.setup(40, GPIO.OUT) 
GPIO.output(40, GPIO.HIGH) 

#Set the cleared tags that will be read by RFID module

cartao = {"12:4F:90:34:F9":"Matheus Neri", "47:22:9D:60:98":"Matheus Neri"}
leitor = MFRC522.MFRC522() 
auto = False #Declare the variable auto for using in the loop of the automatic mode
modo_auto = False #Declare the variable auto for using in the loop of the automatic mode
estado_lampada = 0 #Declare the variable that will monitor the state of the lamp
estado_ventilador = #Declare the variable that will monitor the state of the fan

#Function that will make the program runs in automatic mode
def automatico():
    global estado_ventilador
    global estado_lampada
    global modo_auto
    global estado_luminosidade
    pino_luminosidade = 15
    GPIO.setup(pino_luminosidade, GPIO.IN)
    estado_luminosidade = GPIO.input(pino_luminosidade)
    print ("Automatic mode activated")
    GPIO.output(12, GPIO.HIGH)
    GPIO.output(16,GPIO.LOW)
    while auto == True:
        estado_presenca = GPIO.input(pino_presenca)
        if estado_presenca == 1:
            modo_auto = True
            while modo_auto == 1:
                estado_luminosidade = GPIO.input(pino_luminosidade)
                estado_presenca = GPIO.input(pino_presenca)
                if estado_luminosidade == 1:
                    print ("Ambiente escuro")
                    GPIO.output(40, GPIO.LOW)
                    time.sleep(2)
                if estado_luminosidade == 0:
                    print ("Luz acessa")
                    time.sleep(2)
                temp_atual = temperatura()
                if temp_atual > 21:
                    estado_ventilador = 1
                    ventilador_automatico()
                if temp_atual < 21 and estado_ventilador == 1:
                    GPIO.output(38, GPIO.HIGH)
                if estado_presenca == 0:
                    modo_auto = False
                client = mqtt.Client()
                client.on_connect = on_connect
                client.on_message = on_message
                client.connect("raspzerow.local", port = 1883, keepalive = 120)
                client.username_pw_set("root","neri2143")
                client.loop_start()
        if estado_luminosidade == 0 and estado_presenca == 0:
            GPIO.output(40, GPIO.HIGH)
        if estado_presenca ==0 and estado_ventilador == 1:
            GPIO.output(38, GPIO.HIGH)
        print ("Sem presença")
        time.sleep(3)
        client = mqtt.Client()
        client.on_connect = on_connect
        client.on_message = on_message
        client.connect("raspzerow.local", port = 1883, keepalive = 120)
        client.username_pw_set("root", "neri2143")
        client.loop_start()

def manual():
    try:
        
        print ("Manual mode activated")
        GPIO.output(16,GPIO.HIGH)
        GPIO.output(12, GPIO.LOW)
        while modo_auto == False: 
            leitor = MFRC522.MFRC522()
            status,tag_type = leitor.MFRC522_Request(leitor.PICC_REQIDL) #F$
            if status == leitor.MI_OK:
                status, uid = leitor.MFRC522_Anticoll()
                if status == leitor.MI_OK:
                    uid = ':'.join(['%X'% x for x in uid])
                    print("UID do cartão: %s" %uid)
                if uid in cartao:
                    print ("Acesso liberado")
                    print ("Olá %s." % cartao[uid])
                    GPIO.output(36, GPIO.LOW)
                    time.sleep(5)
                    GPIO.output(36, GPIO.HIGH)
                else:
                    print ("Acesso negado")

            client = mqtt.Client()
            client.on_connect = on_connect
            client.on_message = on_message
            client.connect("raspzerow.local", port = 1883, keepalive =120)
            client.username_pw_set("root", "neri2143")
            client.loop_start()
    except KeyboardInterrupt:
        GPIO.cleanup()
        print ("Simulação finalizada")
        sys.exit(0)


def on_connect (client, userdata, flags, rc):
    client.subscribe("iluminação")
    client.subscribe("ventilação")
    client.subscribe("modo")

def on_message(client, userdata, msg):
    msg.payload = msg.payload.decode("utf-8")
    mensagem = msg.payload
    global estado_lampada
    global estado_ventilador
    global auto
    global modo_auto
    if mensagem == "ON":
        auto = True
        automatico()
    if mensagem == "OFF":
        auto = False
        modo_auto= False
        print (auto, modo_auto)
        manual()
    if mensagem == "ONL":
        if estado_lampada == 1:
            estado_lampada = 0
        lampada()
    if mensagem == "OFFL":
        if estado_lampada == 0:
            estado_lampada = 1
        lampada()
    if mensagem == "ONV":
        if estado_ventilador == 1:
            estado_ventilador = 0
        ventilador()
    if mensagem == "OFFV":
        if estado_ventilador == 0:
            estado_ventilador = 1
        ventilador()

#Define the function that will change the state of the fan in automatic mode
def ventilador_automatico():
        
        print("Ventilador ligado")
        GPIO.output(38, GPIO.LOW)
        estado_ventilador = 1
        time.sleep(2)

#Define the function that will change the state of the fan in manual mode
def ventilador():

    GPIO.setup (38, GPIO.OUT)   
    global estado_ventilador
    if estado_ventilador == 0:
        print ("Ventilador ligado")
        GPIO.output(38,GPIO.LOW)
        estado_ventilador = 1
        time.sleep(2)
    else:
        print ("Ventilador desligado")
        GPIO.output(38, GPIO.HIGH)
        estado_ventilador = 0

#Define the function that will change the state of the lamp in manual mode
def lampada():
    
    GPIO.setup(40, GPIO.OUT)
    global estado_lampada
    if estado_lampada == 0:
        GPIO.output(40, GPIO.LOW)
        print ("Lampada acessa")
        estado_lampada = 1
    else:
        GPIO.output(40,GPIO.HIGH)
        print ("Lampada apagada")
        estado_lampada = 0
    
#Define the function that will make the reading of the DHT11 sensor
def temperatura():
    
    sensor = Adafruit_DHT.DHT11 
    pino_sensor = 27
    umid, temp = Adafruit_DHT.read_retry(sensor, pino_sensor)
    if umid is not None and temp is not None:
        print ("Temperatura = {0:0.1f}".format(temp))
        #print ("Temperatura = {0:0.1f} Umidade = {1:0.1f}n".format(temp, umid))
    if umid is None and temp is None:
        print ("Falha ao ler dados do DHT11")   
    return temp
print ("Simulation start") 
manual()

节点红流 终端输出 ,

The following lines of code:

        client = mqtt.Client()
        client.on_connect = on_connect
        client.on_message = on_message
        client.connect("raspzerow.local", port = 1883, keepalive =120)
        client.username_pw_set("root", "neri2143")
        client.loop_start()

Should only be run once at the start of the program. You have them in a loop.

Each time this is called it will create a new connection to the MQTT broker, subscribe to your topics and create a new thread ( client.loop_start() ) to receive the subscriptions.

Very soon you'll run out of sockets to connect to the MQTT broker and get the too many open files error that you're seeing. You'll also appear to see multiple messages since each subscription will receive the same message.

Delete these lines of code everywhere they're used in the program (3 times) and move them to the start of the code before you call manual() .

--- EDIT ---

Following the comments it appears there are more issues here. on_message() function calls either manual() or automatico() which run a loop. This blocks the MQTT client thread from processing any more messages. Therefore this function should just set a flag or status to change whether automatico() or manual() are called in the main application thread.

Here's a suggested (untested) change to the code to enable this.

#! usr/bin/ env python

#Import librarys used#
import paho.mqtt.client as mqtt 
import RPi.GPIO as GPIO 
import sys 
import time 
import Adafruit_DHT 
import MFRC522 

#Definition of inputs#

GPIO.setwarnings(False) 
GPIO.setmode(GPIO.BOARD) 
pino_presenca = 11 #Set the input of the PIR sensor used in the project
GPIO.setup(pino_presenca, GPIO.IN)
pino_luminosidade = 15  #Set the input of the LDR module used in the project
GPIO.setup(pino_luminosidade, GPIO.IN)
pino_temperatura = 27 #Sets the input of the DHT11 sensor used in the project


#Set the LED used to demonstrate the mode select (Automatic or manual)#
GPIO.setup(12, GPIO.OUT) 
GPIO.output(12, GPIO.LOW) 
GPIO.setup(16, GPIO.OUT) 
GPIO.output(16, GPIO.LOW) 

#Set the outputs used in the project
GPIO.setup(36, GPIO.OUT) 
GPIO.output(36, GPIO.HIGH) 
GPIO.setup(38, GPIO.OUT) 
GPIO.output(38, GPIO.HIGH) 
GPIO.setup(40, GPIO.OUT) 
GPIO.output(40, GPIO.HIGH) 

#Set the cleared tags that will be read by RFID module

cartao = {"12:4F:90:34:F9":"Matheus Neri", "47:22:9D:60:98":"Matheus Neri"}
leitor = MFRC522.MFRC522() 
modo_auto = False #Declare the variable modo_auto for using in the loop of the automatic mode
estado_lampada = 0 #Declare the variable that will monitor the state of the lamp
estado_ventilador = #Declare the variable that will monitor the state of the fan

#Function that will make the program runs in automatic mode
def automatico():
    global estado_ventilador
    global estado_lampada
    global modo_auto
    global estado_luminosidade
    pino_luminosidade = 15
    GPIO.setup(pino_luminosidade, GPIO.IN)
    estado_luminosidade = GPIO.input(pino_luminosidade)
    print ("Automatic mode activated")
    GPIO.output(12, GPIO.HIGH)
    GPIO.output(16,GPIO.LOW)
    while modo_auto == True:
        estado_presenca = GPIO.input(pino_presenca)
        if estado_presenca == 1:
            modo_auto = True
            while modo_auto == 1:
                estado_luminosidade = GPIO.input(pino_luminosidade)
                estado_presenca = GPIO.input(pino_presenca)
                if estado_luminosidade == 1:
                    print ("Ambiente escuro")
                    GPIO.output(40, GPIO.LOW)
                    time.sleep(2)
                if estado_luminosidade == 0:
                    print ("Luz acessa")
                    time.sleep(2)
                temp_atual = temperatura()
                if temp_atual > 21:
                    estado_ventilador = 1
                    ventilador_automatico()
                if temp_atual < 21 and estado_ventilador == 1:
                    GPIO.output(38, GPIO.HIGH)
                if estado_presenca == 0:
                    modo_auto = False
        if estado_luminosidade == 0 and estado_presenca == 0:
            GPIO.output(40, GPIO.HIGH)
        if estado_presenca ==0 and estado_ventilador == 1:
            GPIO.output(38, GPIO.HIGH)
        print ("Sem presença")
        time.sleep(3)

def manual():
    global modo_auto 
    try:
        
        print ("Manual mode activated")
        GPIO.output(16,GPIO.HIGH)
        GPIO.output(12, GPIO.LOW)
        while modo_auto == False: 
            leitor = MFRC522.MFRC522()
            status,tag_type = leitor.MFRC522_Request(leitor.PICC_REQIDL) #F$
            if status == leitor.MI_OK:
                status, uid = leitor.MFRC522_Anticoll()
                if status == leitor.MI_OK:
                    uid = ':'.join(['%X'% x for x in uid])
                    print("UID do cartão: %s" %uid)
                if uid in cartao:
                    print ("Acesso liberado")
                    print ("Olá %s." % cartao[uid])
                    GPIO.output(36, GPIO.LOW)
                    time.sleep(5)
                    GPIO.output(36, GPIO.HIGH)
                else:
                    print ("Acesso negado")

    except KeyboardInterrupt:
        GPIO.cleanup()
        print ("Simulação finalizada")
        sys.exit(0)


def on_connect (client, userdata, flags, rc):
    client.subscribe("iluminação")
    client.subscribe("ventilação")
    client.subscribe("modo")

def on_message(client, userdata, msg):
    msg.payload = msg.payload.decode("utf-8")
    mensagem = msg.payload
    global estado_lampada
    global estado_ventilador
    global modo_auto

    if mensagem == "ON":
        modo_auto = True
    if mensagem == "OFF":
        modo_auto= False
        print (modo_auto)
    if mensagem == "ONL":
        if estado_lampada == 1:
            estado_lampada = 0
        lampada()
    if mensagem == "OFFL":
        if estado_lampada == 0:
            estado_lampada = 1
        lampada()
    if mensagem == "ONV":
        if estado_ventilador == 1:
            estado_ventilador = 0
        ventilador()
    if mensagem == "OFFV":
        if estado_ventilador == 0:
            estado_ventilador = 1
        ventilador()

#Define the function that will change the state of the fan in automatic mode
def ventilador_automatico():
        
        print("Ventilador ligado")
        GPIO.output(38, GPIO.LOW)
        estado_ventilador = 1
        time.sleep(2)

#Define the function that will change the state of the fan in manual mode
def ventilador():

    GPIO.setup (38, GPIO.OUT)   
    global estado_ventilador
    if estado_ventilador == 0:
        print ("Ventilador ligado")
        GPIO.output(38,GPIO.LOW)
        estado_ventilador = 1
        time.sleep(2)
    else:
        print ("Ventilador desligado")
        GPIO.output(38, GPIO.HIGH)
        estado_ventilador = 0

#Define the function that will change the state of the lamp in manual mode
def lampada():
    
    GPIO.setup(40, GPIO.OUT)
    global estado_lampada
    if estado_lampada == 0:
        GPIO.output(40, GPIO.LOW)
        print ("Lampada acessa")
        estado_lampada = 1
    else:
        GPIO.output(40,GPIO.HIGH)
        print ("Lampada apagada")
        estado_lampada = 0
    
#Define the function that will make the reading of the DHT11 sensor
def temperatura():
    
    sensor = Adafruit_DHT.DHT11 
    pino_sensor = 27
    umid, temp = Adafruit_DHT.read_retry(sensor, pino_sensor)
    if umid is not None and temp is not None:
        print ("Temperatura = {0:0.1f}".format(temp))
        #print ("Temperatura = {0:0.1f} Umidade = {1:0.1f}n".format(temp, umid))
    if umid is None and temp is None:
        print ("Falha ao ler dados do DHT11")   
    return temp

print ("Simulation start") 

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("raspzerow.local", port = 1883, keepalive = 120)
client.username_pw_set("root", "neri2143")
client.loop_start()

while True: 
    if modo_auto :
        automatico() 
    else:
        manual()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM