更新全局布尔值以启动或停止函数

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 获取布尔值以进行插入

如何添加布尔值以形成内容 C#

Discord.py:如何提取布尔值以判断某人是不是静音

全局布尔值在 addListenerForSingleEventValue 函数内设置,但在以下 if 语句中无法识别 [重复]

C# 布尔评估未按预期进行评估