ich habe eine kleine Webanwendung mit hug geschrieben, mit der man die Blinkt LED Leiste von Pimoroni ansteuern kann. Blinkt wird direkt auf den GPIO Pins des Raspberry Pi gesteckt. Die Leiste hat 8 LEDs (bei Blinkt "Pixel" genannt), die man direkt über ein von Pimoroni zur Verfügung gestelltes Python-Modul ansteuern kann.
Das Programm hat keinen tieferen Sinn, ich wollte nur mal was mit hug machen - die Gelegenheit bot sich hier.
Was bei hug IMHO ganz praktisch ist, ist der Type-Checker mit Konverter `hug.types` für die übergebenen GET-Parameter. Was bei hug ein bisschen komisch ist, ist das die Doku auf mehrere verschiedene Webeiten verteilt ist... Es ist auch alles dokumentiert, aber irgendwie komisch verteilt und strukturiert.
Kommentare zum Code sind willkommen, auch für die Benennung bzw. die URLs der Routen.
Code: Alles auswählen
import random
import hug
import blinkt
COLORS = {'red': (255, 0 , 0),
'green': (0, 255, 0),
'blue': (0, 0, 255),
'yellow': (255, 255, 0),
'orange': (255, 165, 0),
'magenta': (255, 0, 255),
'white': (255, 255, 255),
}
#define short name for each color, which is the first letter of the color
#as defined in COLORS
#needs to be modified / removed once two colors with the same starting letter
#are defined in COLORS, e.g. if ever purple and pink would be added.
COLORS_SHORT = {key[0]:value for (key, value) in COLORS.items()}
ALL_COLORS = COLORS | COLORS_SHORT
@hug.get('/color/{color}')
@hug.get('/color', examples='color=red')
def set_all_pixels(color: str):
'''Sets all pixels to the the given color. The color is specified by name,
e.g. red or green. Color can also be given by shortname, e.g. y for yellow
or m for magenta.'''
if not color in ALL_COLORS.keys():
return {'error': f'{color} is not a valid color. Please choose one of \
{list(ALL_COLORS.keys())}'}
else:
rgb_value = ALL_COLORS[color]
blinkt.set_all(rgb_value[0], rgb_value[1], rgb_value[2])
blinkt.show()
return {'success': f'set Pixels to color {color} (RBG: {rgb_value})'}
@hug.get('/color_for_pixel/{pixel}/{color}')
@hug.get('/color_for_pixel', examples='pixel=2&color=magenta')
def set_pixel_to(pixel: hug.types.in_range(1, 9), color: str):
'''Sets the given Pixel to the given color. Pixels are numbered 1 to 8 from
left to right. The color is specified by name, e.g. green or blue. Color can
also be given by shortname, e.g. y for yellow or m for magenta.'''
if not color in ALL_COLORS.keys():
return {'error': f'{color} is not a valid color. Please choose one of \
{list(ALL_COLORS.keys())}'}
else:
pixel-=1
rgb_value = ALL_COLORS[color]
blinkt.set_pixel(pixel, rgb_value[0], rgb_value[1], rgb_value[2])
blinkt.show()
return {'success': f'set Pixel {pixel} to color {color} (RBG: {rgb_value})'}
@hug.get('/colors_for_pixels/{colors}')
@hug.get('/colors_for_pixels', examples='colors=green,red,yellow,magenta,white,blue,y,g')
def set_pixels_to(colors: hug.types.delimited_list(',')):
'''Set each pixel to the given color specified for each Pixel. The colors
are specified by name, e.g. blue or yellow. In total eight colors needs
to be given, one for each Pixel. Colors must be separated by a comma , .'''
if len(colors) != 8:
return {'error': 'wrong length - exactly eight (8) colors separated by \
a comma have to be provided'}
if not all([True if (color.strip() in ALL_COLORS.keys()) else False for color in colors]):
return {'error': f'There is at least one invalid value in {colors}. \
Please ensure all values are one of {ALL_COLORS.keys()}'}
_set_color_for_each_pixel(colors)
return {'success': f'set Pixels 1 to 8 to colors {colors}'}
@hug.get('/brightness/{value}')
@hug.get('/brightness')
def set_brightness(value: hug.types.in_range(1, 100),
examples='value=50'):
'''Sets the brightness of all Pixels to the given value. Value must be an
integer between 1 and 99'''
value = round(value/100, 2)
blinkt.set_brightness(value)
blinkt.show()
return {'success': f'set brightness to: {value}'}
@hug.get('/randomize')
def randomize_colors():
'''Sets all eight pixels to a randomly chosen color from the color dict.'''
colors = random.choices(list(COLORS.keys()), k=8)
_set_color_for_each_pixel(colors)
return {'success': 'set pixels to randomly chosen colors.'}
@hug.get('/show_state')
def show_state():
'''Shows the current state of each pixel - current RGB value and brightness.'''
state = {}
for pixel in range(blinkt.NUM_PIXELS):
value = blinkt.get_pixel(pixel)
state[f'Pixel {pixel}'] = f'color: {value[0:3]}, brightness: {value[3]}'
return state
@hug.get('/off')
def leds_off():
'''Turns off all pixels.'''
blinkt.clear()
blinkt.show()
return {'success': 'turned off all Pixels'}
def _set_color_for_each_pixel(colors):
'''Helper function to set each pixel to a given color.
Expects one argument, which has to be an iterable holding the names of exactly
eight colors.'''
assert len(colors)==8
rgb_values = [ALL_COLORS[color] for color in colors]
for position, rgb_value in enumerate(rgb_values):
blinkt.set_pixel(position, rgb_value[0], rgb_value[1], rgb_value[2])
blinkt.show()
Code: Alles auswählen
#Dummy Modul zum Testen
NUM_PIXELS = 8
def show():
pass
def clear():
pass
def set_pixel(x, r, g, b, brightness=None):
pass
def set_all(r, g, b, brightness=None):
pass
def set_brightness(x):
pass
def get_pixel(x):
return (128, 128, 128, 0.5)
Code: Alles auswählen
[Unit]
Description=Blinkt Server
After=network-online.target
[Service]
User=noisefloor
WorkingDirectory=/home/noisefloor/code/hug_venv
ExecStart=/home/noisefloor/code/hug_venv/bin/waitress-serve --listen=192.168.178.117:8001 --threads=2 blinkt_api:__hug_wsgi__
Restart=Always
[Install]
WantedBy=multi-user.target

Gruß, noisefloor