Skip to content

Instantly share code, notes, and snippets.

@dglaude
Last active June 2, 2020 10:51
Show Gist options
  • Save dglaude/df8d5cbd5d58c9f835a4d8a7f6ab7808 to your computer and use it in GitHub Desktop.
Save dglaude/df8d5cbd5d58c9f835a4d8a7f6ab7808 to your computer and use it in GitHub Desktop.
Modifying Pimoroni Unicorn HAT library for use in microPython on ESP8266
### microPython ESP8266 documentation from http://docs.micropython.org/en/latest/esp8266/esp8266/quickref.html#neopixel-driver
###
###from machine import Pin
###from neopixel import NeoPixel
###
###pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels
###np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels
###np[0] = (255, 255, 255) # set the first pixel to white
###np.write() # write data to all pixels
###r, g, b = np[0] # get first pixel colour
## No atexit support in microPython
#import atexit
## Use the one from https://github.com/dglaude/blinkt-on-espiot-phat/blob/master/colorsys.py
import colorsys
##
#from neopixel import *
from neopixel import NeoPixel
# LED strip configuration:
LED_COUNT = 64 # Number of LED pixels.
LED_PIN = 12 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 5 # DMA channel to use for generating signal (try 5)
LED_BRIGHTNESS = 128 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
##ws2812 = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS)
##ws2812.begin()
from machine import Pin
from neopixel import NeoPixel
pin = Pin(LED_PIN, Pin.OUT) # set GPIO12 to output to drive NeoPixels
np = NeoPixel(pin, LED_COUNT) # create NeoPixel driver on GPIO12 for 32 pixels (Unicorn pHAT)
"""
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
_wx = 8
_wy = 8
_map = []
"""
Store a map of pixel indexes for
translating x, y coordinates.
"""
HAT = [
[7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ],
[8 , 9 , 10, 11, 12, 13, 14, 15],
[23, 22, 21, 20, 19, 18, 17, 16],
[24, 25, 26, 27, 28, 29, 30, 31],
[39, 38, 37, 36, 35, 34, 33, 32],
[40, 41, 42, 43, 44, 45, 46, 47],
[55, 54, 53, 52, 51, 50, 49, 48],
[56, 57, 58, 59, 60, 61, 62, 63]
]
PHAT_VERTICAL = [
[0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ],
[8 , 9 , 10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21, 22, 23],
[24, 25, 26, 27, 28, 29, 30, 31]
]
PHAT = [
[24, 16, 8, 0],
[25, 17, 9, 1],
[26, 18, 10, 2],
[27, 19, 11, 3],
[28, 20, 12, 4],
[29, 21, 13, 5],
[30, 22, 14, 6],
[31, 23, 15, 7]
]
AUTO = None
def set_layout(pixel_map = AUTO):
global _map
if pixel_map is None:
pixel_map = PHAT # Assume PHAT
## try:
## product = open("/proc/device-tree/hat/product","r").read().strip()
## if product[:11] == "Unicorn HAT":
## pixel_map = HAT
## except IOError:
## pass
_map = pixel_map
def get_shape():
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
Valid values:
0
90
180
270"""
global _map
global _rotation
if r in [0, 90, 180, 270]:
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 brightness(b=0.2):
"""Set the display brightness between 0.0 and 1.0
0.2 is highly recommended, UnicornHat can get painfully bright!"""
## 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)
return round(ws2812.getBrightness()/128.0, 3)
def clear():
"""Clear the buffer"""
for x in range(64):
ws2812.setPixelColorRGB(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"""
wx = len(_map) - 1
wy = len(_map[0]) - 1
#if x > wx or x < 0:
# raise ValueError('X position must be between 0 and {wx}'.format(wx=wx))
#if y > wy or y < 0:
# raise ValueError('Y position must be between 0 and {wy}'.format(wy=wy))
y = (wy)-y
if _rotation == 90 and wx == wy:
x, y = y, (wx)-x
elif _rotation == 180:
x, y = (wx)-x, (wy)-y
elif _rotation == 270 and wx == wy:
x, y = (wy)-y, x
try:
index = _map[x][y]
except IndexError:
index = None
return index
def set_pixel_hsv(x, y, h, s, v):
"""Set a single pixel to a colour using HSV"""
index = get_index_from_xy(x, y)
if index is not None:
r, g, b = [int(n*255) for n in colorsys.hsv_to_rgb(h, s, v)]
ws2812.setPixelColorRGB(index, r, g, b)
def set_pixel(x, y, r, g, b):
"""Set a single pixel to RGB colour"""
index = get_index_from_xy(x, y)
if index is not None:
ws2812.setPixelColorRGB(index, r, g, b)
def get_pixel(x, y):
"""Get the RGB value of a single pixel"""
index = get_index_from_xy(x, y)
if index is not None:
pixel = ws2812.getPixelColorRGB(index)
return int(pixel.r), int(pixel.g), int(pixel.b)
def set_pixels(pixels):
for x in range(8):
for y in range(8):
r, g, b = pixels[y][x]
set_pixel(x, y, r, g, b)
def get_pixels():
"""Get the RGB value of all pixels in a 7x7x3 2d array of tuples"""
return [[get_pixel(x, y) for x in range(8)] for y in range(8)]
def show():
"""Update UnicornHat with the contents of the display buffer"""
ws2812.show()
##set_layout(HAT)
set_layout(pHAT)
##atexit.register(_clean_shutdown)
@dglaude
Copy link
Author

dglaude commented Aug 11, 2016

Currently I am commenting out all the stuff likely to fail on microPython...
But seeing the code, it might be best to provide a ws2812 like library as all the hardware call go to there.
And replace that by the ESP8266 microPython specific fonction...

@dglaude
Copy link
Author

dglaude commented Aug 30, 2016

This is how to use neopixel library build in mycroPython for ESP8266.

from machine import Pin
from neopixel import NeoPixel

pin = Pin(0, Pin.OUT) # set GPIO0 to output to drive NeoPixels
np = NeoPixel(pin, 8) # create NeoPixel driver on GPIO0 for 8 pixels
np[0] = (255, 255, 255) # set the first pixel to white
np.write() # write data to all pixels

r, g, b = np[0] # get first pixel colour

This is alternate low level implementation.

import esp

esp.neopixel_write(pin, grb_buf, is800khz)

This is the usage of neopixel library from unicornhat library.

from neopixel import *

LED strip configuration:

LED_COUNT = 64 # Number of LED pixels.
LED_PIN = 12 # GPIO pin connected to the pixels (must support PWM!).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 5 # DMA channel to use for generating signal (try 5)
LED_BRIGHTNESS = 128 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)

ws2812 = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS)
ws2812.begin()
ws2812.setBrightness(brightness)
ws2812.getBrightness()
ws2812.setPixelColorRGB(x, 0, 0, 0)
ws2812.getPixelColorRGB(index)
ws2812.show()

So now I need to create a library Ada_neopixel that implement the object
Adafruit_NeoPixel(...) and all its function in use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment