Raspberry Pi -MQTT经纪人接收消息多次 - [ERRNO 24]太多的开放文件
我需要帮助我的项目来毕业。
我已经将此程序设置为使用Node-red Node MQTT来控制Web的Raspberry。最初,通信工作正常,但是,在某个时候,程序开始从节点红色流中注入消息后多次接收消息,并且由于遇到错误,因此程序崩溃了:oserror:< strong> [errno 24]太多的打开文件。我分析了代码,只是找不到为什么MQTT经纪人每次收到多个消息,而我需要帮助,我真的很拼命。在图像中,我显示了来自节点红的流以及覆盆子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()
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()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
以下代码行:
只能在程序开始时运行一次。您将它们循环。
每次称呼这一点时,都会创建与MQTT代理的新连接,请订阅您的主题并创建一个新线程(
Client.loop_start()
)以接收订阅。很快,您将用光插座连接到MQTT经纪人,并获得太多的打开文件您看到的错误。您似乎还会看到多个消息,因为每个订阅都会收到相同的消息。
删除程序中使用的这些代码行(3次),然后在调用
MANUAL()
之前将它们移至代码的开始。---编辑---
遵循评论后,这里似乎还有更多问题。
on_message()
函数调用MANUAL()
或automatico()
运行循环。这会阻止MQTT客户端线程处理更多消息。因此,此功能应仅设置标志或状态以更改是否automatico()
或MANUAL()
在主应用程序线程中调用。这是对代码的建议(未经测试)更改以实现这一目标。
The following lines of code:
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 eithermanual()
orautomatico()
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 whetherautomatico()
ormanual()
are called in the main application thread.Here's a suggested (untested) change to the code to enable this.