Skip to content

Instantly share code, notes, and snippets.

@Gadgetoid
Last active January 9, 2018 22:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Gadgetoid/35b2cc87f3d07823bb82cdd3e7f12e6d to your computer and use it in GitHub Desktop.
Save Gadgetoid/35b2cc87f3d07823bb82cdd3e7f12e6d to your computer and use it in GitHub Desktop.
import atexit
import colorsys
from rpi_ws281x import __version__ as __rpi_ws281x__, PixelStrip, Color
__version__ = '2.2.3'
# LED strip configuration:
LED_COUNT = 96 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal
LED_BRIGHTNESS = 128 # Set to 0 for darkest and 255 for brightest
LED_CHANNEL = 0 # PWM channel
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_GAMMA = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5,
6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11,
11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28,
29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40,
40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89,
90, 91, 93, 94, 95, 96, 98, 99,100,102,103,104,106,107,109,110,
111,113,114,116,117,119,120,121,123,124,126,128,129,131,132,134,
135,137,138,140,142,143,145,146,148,150,151,153,155,157,158,160,
162,163,165,167,169,170,172,174,176,178,179,181,183,185,187,189,
191,193,194,196,198,200,202,204,206,208,210,212,214,216,218,220,
222,224,227,229,231,233,235,237,239,241,244,246,248,250,252,255]
ws2812 = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, LED_GAMMA)
ws2812.begin()
"""
Store the rotation of UnicornHat, defaults to
0 which places 0,0 on the top left with the B+
HDMI port facing downwards
"""
_rotation = 0
_requested_rotation = 0
_wx = 8
_wy = 8
_map = []
_pixels = [(0,0,0) for x in range(64)]
"""
Store a map of pixel indexes for
translating x, y coordinates.
"""
MY_DISPLAY = [
[95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72],
[48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71],
[47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]
]
AUTO = None
def set_gamma(gamma):
ws2812.setGamma(gamma)
def disable_gamma():
set_gamma(list(range(256)))
def set_layout(pixel_map = AUTO):
"""Set the layout to Unicorn HAT or Unicorn pHAT
Note: auto detection relies upon the HAT EEPROM. Your Unicorn HAT
must be connected before boot to successfully auto detect.
:param pixel_map: Choose the layout to set, can be either HAT, PHAT, PHAT_VERTICAL or AUTO
"""
global _map
if pixel_map is None:
pixel_map = MY_DISPLAY
_map = pixel_map
def get_shape():
"""Returns the shape (width, height) of the display"""
global _map
return (len(_map), len(_map[0]))
def _clean_shutdown():
"""Registered at exit to ensure ws2812 cleans up after itself
and all pixels are turned off.
"""
off()
def rotation(r=0):
"""Set the display rotation
:param r: Specify the rotation in degrees: 0, 90, 180 or 270
"""
global _map
global _rotation
global _requested_rotation
if r in [0, 90, 180, 270]:
_requested_rotation=r
wx = len(_map)
wy = len(_map[0])
if wx == wy:
_rotation = r
else:
if r in [0, 180]:
_map = PHAT
_rotation = r
else:
_map = PHAT_VERTICAL
_rotation = r-90
return True
else:
raise ValueError('Rotation must be 0, 90, 180 or 270 degrees')
def get_rotation():
"""Get the display rotation value
Returns an integer, either 0, 90, 180 or 270
"""
return _requested_rotation
def brightness(b=0.2):
"""Set the display brightness between 0.0 and 1.0
0.2 is highly recommended, UnicornHat can get painfully bright!
:param b: Brightness from 0.0 to 1.0 (default 0.2)
"""
if b > 1 or b < 0:
raise ValueError('Brightness must be between 0.0 and 1.0')
"""Absolute max brightness has been capped to 50%, do not change
this unless you know what you're doing.
UnicornHAT draws too much current above 50%."""
brightness = int(b*128.0)
if brightness < 30:
print("Warning: Low brightness chosen, your UnicornHAT might not light up!")
ws2812.setBrightness(brightness)
def get_brightness():
"""Get the display brightness value
Returns a float between 0.0 and 1.0
"""
return round(ws2812.getBrightness()/128.0, 3)
def clear():
"""Clear the buffer"""
for x in range(64):
ws2812.setPixelColorRGB(x, 0, 0, 0)
_pixels[x] = (0, 0, 0)
def off():
"""Clear the buffer and immediately update UnicornHat
Turns off all pixels.
"""
clear()
show()
def get_index_from_xy(x, y):
"""Convert an x, y value to an index on the display
:param x: Horizontal position from 0 to 7
:param y: Vertical position from 0 to 7
"""
wy = len(_map) - 1
wx = len(_map[0]) - 1
y = (wy)-y
if _rotation == 180:
x, y = (wx)-x, (wy)-y
try:
index = _map[y][x]
except IndexError:
index = None
return index
def set_pixel_hsv(x, y, h, s=None, v=None):
"""Set a single pixel to a colour using HSV
:param x: Horizontal position from 0 to 7
:param y: Veritcal position from 0 to 7
:param h: Hue from 0.0 to 1.0 ( IE: degrees around hue wheel/360.0 )
:param s: Saturation from 0.0 to 1.0
:param v: Value (also known as brightness) from 0.0 to 1.0
"""
if type(h) is tuple:
h, s, v = h
r, g, b = [int(n*255) for n in colorsys.hsv_to_rgb(h, s, v)]
set_pixel(x, y, r, g, b)
def set_pixel(x, y, r, g=None, b=None):
"""Set a single pixel to RGB colour
:param x: Horizontal position from 0 to 7
:param y: Veritcal position from 0 to 7
:param r: Amount of red from 0 to 255
:param g: Amount of green from 0 to 255
:param b: Amount of blue from 0 to 255
"""
if type(r) is tuple:
r, g, b = r
index = get_index_from_xy(x, y)
if index is not None:
ws2812.setPixelColorRGB(index, r, g, b)
_pixels[index] = (r, g, b)
def get_pixel(x, y):
"""Get the RGB value of a single pixel
:param x: Horizontal position from 0 to 7
:param y: Veritcal position from 0 to 7
"""
index = get_index_from_xy(x, y)
if index is not None:
return _pixels[index]
def set_all(r, g=None, b=None):
"""Set all pixels to a specific colour"""
if type(r) is tuple:
r, g, b = r
shade_pixels(lambda x, y: (r, g, b))
def shade_pixels(shader):
"""Set all pixels using a pixel shader style function
:param pixels: A function which accepts the x and y positions of a pixel and returns values r, g and b
For example, this would be synonymous to clear::
set_pixels(lambda x, y: return 0,0,0)
Or perhaps we want to map red along the horizontal axis, and blue along the vertical::
set_pixels(lambda x, y: return (x/7.0) * 255, 0, (y/7.0) * 255)
"""
width, height = get_shape()
for x in range(width):
for y in range(height):
r, g, b = shader(x, y)
set_pixel(x, y, r, g, b)
def set_pixels(pixels):
"""Set all pixels using an array of `get_shape()`"""
shade_pixels(lambda x, y: pixels[y][x])
def get_pixels():
"""Get the RGB value of all pixels in a 7x7x3 2d array of tuples"""
width, height = get_shape()
return [[get_pixel(x, y) for x in range(width)] for y in range(height)]
def show():
"""Update UnicornHat with the contents of the display buffer"""
ws2812.show()
set_layout(MY_DISPLAY)
atexit.register(_clean_shutdown)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment