更新全局布尔值以启动或停止函数
Posted
技术标签:
【中文标题】更新全局布尔值以启动或停止函数【英文标题】:Update a Global Boolean to Start or Stop a Function 【发布时间】:2020-06-09 14:57:58 【问题描述】:我正在用 python 编写一个基于 GPIO 状态控制一些 LED 的应用程序。在硬件上,我监听 GPIO 以更改状态并发布到运行在树莓派上的 MQTT 服务器以控制 LED。其中一个 GPIO 应导致 LED 无限闪烁,直到状态再次更改以将其关闭,这正是汽车转向信号的工作原理。
所以当 GPIO 变高时,我会发布到有效负载“开启”的主题。然后我设置了一个全局变量
blinker_status = True
然后基本上说(伪代码)
while (blinker_status) blink
当我使用“关闭”有效负载发布到同一个主题时,我设置了全局变量的值
blinker_status = False
我希望 LED 停止闪烁,但事实并非如此。我不确定问题是否在于 MQTT 阻塞?
一旦我启动 LED 闪烁,它可能会阻止 on_message()
回调并且它无法处理其他消息?我是否应该将所有订阅者客户端隔离到他们自己的线程中,以便发布到每个主题都由其自己的on_message()
回调处理?
如有必要,我可以提供代码,但此时我一直在试图理解为什么我的逻辑有缺陷。
下面是我的代码
import time
from neopixel import *
from threading import Thread
import paho.mqtt.client as mqtt
mqtt_client = None
# LED strip configuration:
LED_COUNT_LEFT = 150 # Number of LED pixels on the left strip.
LED_COUNT_RIGHT = 1 # Number of LED pixels on the right strip.
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL_LEFT = 0 # set to '1' for GPios 13, 19, 41, 45 or 53
LED_CHANNEL_RIGHT = 1
# NOTE: The WS2812B strip has red and green inverted, so red is actually (0, 255, 0) and green is (255, 0, 0)
left_blinker_status = False
right_blinker_status = False
blinker_status = False
# Create NeoPixel object with appropriate configuration.
# GPIO 18 is pin 12
left_strip = Adafruit_NeoPixel(LED_COUNT_LEFT, 18, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL_LEFT)
# GPIO 13 is pin 33
right_strip = Adafruit_NeoPixel(LED_COUNT_RIGHT, 13, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS,
LED_CHANNEL_RIGHT)
# Intialize the library (must be called once before other functions).
left_strip.begin()
right_strip.begin()
# MQTT functions
def start_mqtt():
global mqtt_client
try:
system_id = 'Kawasaki Ninja'
mqtt_client = mqtt.Client(client_id=system_id)
mqtt_client.disable_logger()
# Assign callback functions
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.connect(host='192.168.1.23')
# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
mqtt_client.loop_forever()
except Exception as ex:
print('Exception in start_mqtt()! exception: '.format(ex))
raise
# THe callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
print('Connected with result code ' + str(rc))
# Subscribing in on_connect() - if we lose connection and
# reconnect then subscriptions will be renewed.
client.subscribe('ninja/#') # The hash sign is wild-card
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
global blinker_status
global left_blinker_status
global right_blinker_status
print(' '.format(msg.topic, str(msg.payload)))
# Handle the brake topic
if msg.topic == 'ninja/brake':
if msg.payload == 'on':
# BRAKE ON
if not left_blinker_status:
solidColor(left_strip, Color(0, 255, 0))
if not right_blinker_status:
solidColor(right_strip, Color(0, 255, 0))
elif msg.payload == 'off':
# BRAKE OFF
if not left_blinker_status:
solidColor(left_strip, Color(255, 255, 255))
if not right_blinker_status:
solidColor(right_strip, Color(255, 255, 255))
# Handle the left turn signal topic
elif msg.topic == 'ninja/left_turn_signal':
# Left turn signal on
if msg.payload == 'on':
blinker_status = True
left_blinker_status = True
while left_blinker_status:
blinker(blinker_status, left_strip)
# Left turn signal off
elif msg.payload == 'off':
blinker_status = False
left_blinker_status = False
solidColor(left_strip, Color(255, 255, 255))
# Handle the right turn signal topic
elif msg.topic == 'ninja/right_turn_signal':
# Right turn signal on
if msg.payload == 'on':
blinker_status = True
right_blinker_status = True
while right_blinker_status:
blinker(blinker_status, right_strip)
# Right turn signal off
elif msg.payload == "off":
blinker_status = False
right_blinker_status = False
solidColor(right_strip, Color(255, 255, 255))
# Handle the party time topic
elif msg.topic == 'ninja/party_time':
# Party on
if msg.payload == 'on':
colorWipe(left_strip, Color(0, 255, 0)) # Red
elif msg.payload == 'white':
solidColor(left_strip, Color(255, 255, 255))
elif msg.payload == 'wipe':
colorWipe(left_strip, Color(0, 255, 0)) # Red
elif msg.payload == 'off':
solidColor(left_strip, Color(0, 0, 0))
# Neopixel functions
# Define functions which animate LEDs in various ways.
def colorWipe(strip, color, wait_ms=50):
"""Wipe color across display a pixel at a time."""
for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
time.sleep(wait_ms / 1000.0)
def solidColor(strip, color):
for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
def blinker(blinker_status, strip):
while blinker_status:
solidColor(strip, Color(65, 100, 0))
time.sleep(0.5)
solidColor(strip, Color(0, 0, 0))
time.sleep(0.5)
try:
while True:
mqtt_thread = Thread(target=start_mqtt, args=())
mqtt_thread.isDaemon()
mqtt_thread.start()
except KeyboardInterrupt:
exit()
【问题讨论】:
您介意整理一下您的帖子,以便于阅读吗?将所有内容都放在一个没有代码块的长段落中会让人难以阅读。 @DanielWalker 根据您的建议,我已经更新了格式。如果您希望我发布代码,我也可以这样做。但我不知道代码一定是我在这一点上卡住的地方,而是我对 MQTT 如何工作以及on_message()
回调处理程序的阻塞/非阻塞性质的理解。
没有看到你的代码我们只能猜测,至少你应该包含你的on_message()
函数。
你应该在一个线程中运行你闪烁的代码并尽快释放你的 on_message。您可以在闪烁时发布其他任何内容吗?
@DamienLEFEVRE 我认为这是问题所在 - 如果我调用 while (True)
循环,它会阻止 on_message()
处理程序并停止处理其他消息吗?我可以发布额外的消息,老实说,不记得这些额外的消息是否出现在 on_message()
处理程序打印语句中。距离我测试已经一个多星期了。我想说“是”,否则我不应该在这里发帖大声笑(还)。
【参考方案1】:
on_message
回调在 MQTT 客户端的网络线程上运行,如果您阻止该线程,您将无法再发送或接收任何消息。
您不应在此(或任何客户端回调)中执行任何阻塞或长时间运行的操作,您应该在状态机中设置标志并使用这些更改来控制其他线程。
【讨论】:
以上是关于更新全局布尔值以启动或停止函数的主要内容,如果未能解决你的问题,请参考以下文章
Knex.js 和 MySQL:将整数转换为布尔值以进行批量选择
无法使用 spring boot 和 postgresql 获取布尔值以进行插入
全局布尔值在 addListenerForSingleEventValue 函数内设置,但在以下 if 语句中无法识别 [重复]