更新全局布尔值以启动或停止函数
Update a Global Boolean to Start or Stop a Function
我正在 python 中编写一个应用程序,它根据 GPIO 状态控制一些 LED。在硬件上,我监听 GPIO 更改状态并发布到 raspberry pi 上的 MQTT 服务器 运行 以控制 LED。其中一个 GPIO 应该使 LED 无限期闪烁,直到状态再次改变以将其关闭,这正是汽车转向信号灯的工作原理。
因此,当 GPIO 变高时,我将发布到一个具有有效负载 'on' 的主题。然后我设置一个全局变量
blinker_status = True
然后基本上说(伪代码)
while (blinker_status) { blink }
当我使用负载 'off' 发布到同一主题时,我设置了全局变量的值
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()
on_message
回调是 运行 在 MQTT 客户端的网络线程上,如果您阻止该线程,您将无法发送或接收任何更多消息。
您不应在此(或任何客户端回调)中执行任何阻塞或长时间 运行ning 操作,您应该在状态机中设置标志并使用这些更改来控制其他线程。
我正在 python 中编写一个应用程序,它根据 GPIO 状态控制一些 LED。在硬件上,我监听 GPIO 更改状态并发布到 raspberry pi 上的 MQTT 服务器 运行 以控制 LED。其中一个 GPIO 应该使 LED 无限期闪烁,直到状态再次改变以将其关闭,这正是汽车转向信号灯的工作原理。
因此,当 GPIO 变高时,我将发布到一个具有有效负载 'on' 的主题。然后我设置一个全局变量
blinker_status = True
然后基本上说(伪代码)
while (blinker_status) { blink }
当我使用负载 'off' 发布到同一主题时,我设置了全局变量的值
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()
on_message
回调是 运行 在 MQTT 客户端的网络线程上,如果您阻止该线程,您将无法发送或接收任何更多消息。
您不应在此(或任何客户端回调)中执行任何阻塞或长时间 运行ning 操作,您应该在状态机中设置标志并使用这些更改来控制其他线程。