将秤,温度计和咖啡机连接到互联网后,终于应该使圣诞树变得更智能了。
硬件

6英尺圣诞树

可寻址的WS2811 LED灯带(3x50足以满足此树的大小)
Raspberry Pi零W

电压电平转换器(3.3V至5V)
电源

软件

将rpi_ws281x Python示例用作控制LED的基本库

在特定端口上提供的Flask应用程序,该应用程序转发到Internet(通过IFTTT控制) )

webcolors库可在颜色名称和RGB值之间进行映射/>
用特定颜色擦拭(以颜色名称命名)


“彩虹”图案


“疯狂”图案(在rpi_ws281x示例中也称为“剧院追逐”)


“停止”-熄灭-所有LED变黑


代码
烧瓶部分
from flask import Flask

from libs import LEDStrip


app = Flask(__name__)
led_strip = LEDStrip(count=150)


@app.route('/wipe/<color>')
def wipe_color(color):
    led_strip.color_wipe(color)

    return "Wipe with {color} - success!".format(color=color)


@app.route('/rainbow')
def rainbow():
    led_strip.rainbow()
    led_strip.rainbow_cycle()

    return "Rainbow animation executed successfully!"


@app.route('/crazy')
def crazy():
    led_strip.theater_chase_rainbow()

    return "Crazy christmas tree animation executed successfully!"


@app.route('/stop')
def stop():
    led_strip.clear()

    return "Christmas tree was turned off!"

libs.py
import time

from webcolors import name_to_rgb
from neopixel import *

from exceptions import ColorNotFoundException


def wheel(pos):
    """Generate rainbow colors across 0-255 positions."""
    if pos < 85:
        return Color(pos * 3, 255 - pos * 3, 0)
    elif pos < 170:
        pos -= 85
        return Color(255 - pos * 3, 0, pos * 3)
    else:
        pos -= 170
        return Color(0, pos * 3, 255 - pos * 3)


class LEDStrip:
    def __init__(self,  count,
                 pin=18, frequency=800000,
                 dma=5, brightness=255,
                 invert=False, channel=0,
                 strip_type=ws.WS2811_STRIP_RGB):
        """
        LED strip abstraction class.

        :param count: number of LED pixels
        :param pin: GPIO pin connected to the pixels (18 uses PWM!)
        :param frequency: LED signal frequency in hertz (usually 800khz)
        :param dma: DMA channel to use for generating signal
        :param brightness: set to 0 for darkest and 255 for brightest
        :param invert: True to invert the signal (when using NPN transistor level shift)
        :param channel: set to '1' for GPIOs 13, 19, 41, 45 or 53
        :param strip_type: strip type and colour ordering
        """

        self.led_count = count
        self.strip = Adafruit_NeoPixel(count, pin, frequency, dma, invert, brightness, channel, strip_type)
        self.strip.begin()

    def clear(self):
        self.color_wipe("black")

    def color_wipe(self, color, wait_ms=30):
        """Wipe color across display a pixel at a time."""
        try:
            color_value = Color(*name_to_rgb(color))
        except ValueError:
            raise ColorNotFoundException("Color {color} not found.".format(color=color))

        for led_number in range(self.led_count):
            self.strip.setPixelColor(led_number, color_value)
            self.strip.show()
            time.sleep(wait_ms / 1000.0)

    def theater_chase(self, color, wait_ms=50, iterations=10):
        """Movie theater light style chaser animation."""
        for j in range(iterations):
            for q in range(3):
                for i in range(0, self.led_count, 3):
                    self.strip.setPixelColor(i + q, color)

                self.strip.show()
                time.sleep(wait_ms / 1000.0)

                for led_number in range(0, self.led_count, 3):
                    self.strip.setPixelColor(led_number + q, 0)

    def rainbow(self, wait_ms=20, iterations=1):
        """Draw rainbow that fades across all pixels at once."""
        for j in range(256 * iterations):
            for led_number in range(self.led_count):
                self.strip.setPixelColor(led_number, wheel((led_number + j) & 255))

            self.strip.show()
            time.sleep(wait_ms / 1000.0)

    def rainbow_cycle(self, wait_ms=20, iterations=5):
        """Draw rainbow that uniformly distributes itself across all pixels."""
        for j in range(256 * iterations):
            for led_number in range(self.led_count):
                self.strip.setPixelColor(led_number, wheel((int(led_number * 256 / self.led_count) + j) & 255))

            self.strip.show()
            time.sleep(wait_ms / 1000.0)

    def theater_chase_rainbow(self, wait_ms=50):
        """Rainbow movie theater light style chaser animation."""
        for j in range(256):
            for q in range(3):
                for led_number in range(0, self.led_count, 3):
                    self.strip.setPixelColor(led_number + q, wheel((led_number + j) % 255))

                self.strip.show()
                time.sleep(wait_ms / 1000.0)

                for led_number in range(0, self.led_count, 3):
                    self.strip.setPixelColor(led_number + q, 0)

exceptions.py
class ChristmasError(BaseException):
    pass


class ColorNotFoundException(ChristmasError):
    pass

除了Google Home和Alexa语音控制功能外,例如“ Okay Google-Turn the Christmas “绿树成荫”和“好的Google-创造彩虹”,将其与运动传感器和其他智能设备连接起来非常有趣。
您对LEDStrip类和flask应用程序的总体设计有何看法?您认为我可以改善什么?我也很感激关于如何在圣诞节期间继续使它变得更有趣的任何想法。
请注意,已经有很多事情可以解决安全问题。

评论

我想知道为什么您的ColourNotFoundException需要调用Christmas Error。不能仅将其设置为ColourNotFoundException(BaseException)类:pass。 P.S对不起,如果这个问题很愚蠢,我什至不知道你能做到。

或者你可以做ColourNotFoundException = Exception(“”)

@ 13ros27我已经习惯了以这种方式定义自定义异常,以简化调试并在错误处理和模块化方面提供更好的可读性。就我而言,这只是一个自定义例外,除了基本例外,但我希望(双关语意)模块会增加并解决这一问题。.谢谢!

#1 楼


我建议将着色和动画处理分开。现在,特别是theater_chase_rainbow复制了其他方法中的代码。而是让theater_chase将颜色数组作为参数。如果再添加一些动画样式和配色方案,则可以尝试所有组合获得\ $ O(n ^ 2)\ $的乐趣。

在我看来,这段代码i + q可能溢出led_count如果不是3的倍数,那么我会使用

for i in range(0, self.led_count, 3):
    self.strip.setPixelColor(i + q, color)



/>