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

2024-04-29 09:20:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用python编写一个应用程序,它根据GPIO状态控制一些LED。在硬件上,我监听GPIO改变状态并发布到运行在raspberry pi上的MQTT服务器以控制LED。其中一个GPIO应使LED无限期闪烁,直到状态再次改变以将其关闭,这正是汽车转向信号灯的工作方式

因此,当GPIO变高时,我会发布一个有效负载为“开”的主题。然后设置一个全局变量

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()

Tags: therightclientledsignalonstatusmsg
1条回答
网友
1楼 · 发布于 2024-04-29 09:20:27

on_message回调在MQTT客户机的网络线程上运行,如果阻止该线程,将无法发送或接收更多消息

您不应该在此(或任何客户端回调)中执行任何阻塞或长时间运行的操作,您应该在状态机中设置标志,并使用这些更改来控制其他线程

相关问题 更多 >