Merry Christmas 2020
Merry Christmas to you and yours, wishing you a much better 2021, how has your day been?
Today I’m sharing a small Raspberry Pi project I’ve been tinkering around with today, and will work with any Raspberry Pi with a soldered header.
I purchased the Raspberry Pi 3D RGB Christmas Tree as a small desktop accessory, and also because I love anything with pretty lights that glow. If you’re interested, they’re available from most Pi stockist, though mine was from https://thepihut.com/products/3d-rgb-xmas-tree-for-raspberry-pi for about £18. I went for the pre-assembled version, you can purchase a cheaper version if you’re adept with a soldering iron and have some time on your hands. I preferred the SMD (Surface Mounted Diode) as it looks marginally better.
Simply pop the parts off the frame (you may need snips) and slot the parts of the Christmas Tree together, and attach to the Raspberry Pi. Note the right angled pins are to face the HDMI port as you can see below. There’s no need to solder these parts since friction will work. That said, there’s nothing stopping you making it a permanent and solid connection.
Next you will need to install the software for which full instructions are here: https://github.com/ThePiHut/rgbxmastree#rgbxmastree
If you’re in a rush, type the following at the raspberry pi terminal command line: –
wget https://bit.ly/2Lr9CT3 -O tree.py python3 tree.py
You should see all the lights on the tree glow white, and possibly a bit too bright (They’re at half strength believe it or not).
No doubt you’ll be keen to get your tree changing colours fairly quickly, where you can find the official scripts here: https://github.com/ThePiHut/rgbxmastree/tree/master/examples
Or within a Python3 prompt you could just enter the following: –
from tree import RGBXmasTree
import random
tree = RGBXmasTree()
def random_color():
r = random.random()
g = random.random()
b = random.random()
return (r, g, b)
try:
while True:
pixel = random.choice(tree)
pixel.color = random_color()
except KeyboardInterrupt:
tree.close()
I took a look at the official offerings and example scripts written in Python which demonstrate how to set the lights on the tree, change the brightness etc, although they work and are pretty, I couldn’t help think about the smooth colour transition in Pimorini’s Plasma Buttons colour change in the Pimorini PiCade Kit, so I set about combining the two.
You can use your favourite Raspberry Pi IDE, though for this project I’m using Thonny since it’s preinstalled on the Desktop and meets my basic needs.
First things first. I needed to read a PNG file which contains the array of colours to cycle through the Christmas Tree. The Pimorini script contained simple re-usable code I could easily adapt…
def load_pattern(pattern_name):
pattern_file = os.path.join(PATTERNS, "{}.png".format(pattern_name))
if os.path.isfile(pattern_file):
r = png.Reader(file=open(pattern_file, 'rb'))
pattern_w, pattern_h, pattern, pattern_meta = r.read()
pattern = list(pattern)
log("Loaded pattern file: {}".format(pattern_file))
return pattern, pattern_w, pattern_h, pattern_meta
else:
log("Invalid pattern file: {}".format(pattern_file))
return None, 0, 0, None
Simply put, it will attempt to load the filename passed in pattern_name and return the Pattern, Width, Height (In pixels) and its metadata (Important as we need to know if the PNG file has an Alpha Channel). If the file failed to load, then it will return None.
I then adapted part of the Pimorini Script which changed the Plasma button colours, to change the pixels of the Tree… it looked something like this :-
def main():
r, g, b = 0, 0, 0
pattern, pattern_w, pattern_h, pattern_meta = load_pattern("rainbow-cycle")while not stopped.wait(1.0 / FPS):
delta = time.time() * 60
if pattern is not None:
alpha = pattern_meta['alpha']
channels = 4 if alpha else 3
offset_y = int(delta % pattern_h)
row = pattern[offset_y]
x = 0
for pixel in tree:
offset_x = (x * channels) % (pattern_w * channels)
r, g, b = row[offset_x:offset_x + 3]
pixel.color = r/255.0, g/255.0, b/255.0
x+=1
else:
for pixel in tree:
pixel.color = r/255.0, g/255.0, b/255.0
Basically, we’re reading the colour information in each pixel of the PNG and setting the Tree pixel accordingly using pixel.color
This script worked well, however I noticed that the colour change wasn’t smooth because we’re writing to the SPI (Serial Peripheral Interface) 25 times per iteration of the loop. Some investigation revealed that the original tree.py script was writing all the pixel data each time a change occurred (625 changes for each loop), which is inefficient.
I amended the Official Script (tree.py) to add an update() function ensuring the LEDs are only updated when we’re ready. This resulted in a much smoother and better experience of the Xmas Tree, with the added advantage that you can create your own PNG files of coloured pixels for your tree to display.
@value.setter
def value(self, value):
self._value = value
# Update all lights in one SPI Transfer
def update(self):
start_of_frame = [0]*4
end_of_frame = [0]*5
# SSSBBBBB (start, brightness)
brightness = 0b11100000 | self._brightness_bits
pixels = [[int(255*v) for v in p] for p in self._value]
pixels = [[brightness, b, g, r] for r, g, b in pixels]
pixels = [i for p in pixels for i in p]
data = start_of_frame + pixels + end_of_frame
self._spi.transfer(data)
The full project code is available on my GitHub https://github.com/muckypaws/Raspberry-Pi/tree/main/RGBXmasTree Please feel free to amend the code to suit your project needs.
I changed the brightness down to 0.1 because it was too bright sat on my desk, even with that set, it remains too bright for my camera to pick up the subtle colours being displayed, hence why it looks blown out in the video above.
Please feel free to experiment with the code, and also PNG files your create for different effects.
Once again, Merry Christmas and Happy New Year x
1 Comment »