Welcome to the 102shows documentation!¶
Note
This documentation is still not completely finished. If you are missing something, please open an issue.
Using 102shows¶
Installation¶
102shows consists of two parts:
- the lightshow server, which should run on a Raspberry Pi - it controls the LED strip via SPI - it listens for MQTT messages that tell it which show to start (and what the paramters for the show are)
- the UI - it delivers a nice web interface - it sends the MQTT messages to the server
For the two elements to be able to communicate (via MQTT) you need an MQTT broker, for example mosquitto
All of these can run on the same Raspberry Pi but only the server has to.
MQTT broker¶
If you already have an MQTT broker in your network, you can use it. Else, install mosquitto via sudo apt-get install mosquitto. In any case, you will need the host, port (and maybe access credentials) of your MQTT broker for later.
Server¶
For the latest stable release: In the folder you want to install 102shows in, run:
wget -q -O 102s-setup.sh https://git.io/vHydu; chmod u+x 102s-setup.sh; ./102s-setup.sh stable; rm 102s-setup.sh
This will launch an assistant that will lead you through the installation process.
Installing a development version
The setup script 102s-setup.sh
takes the GitHub branch to clone as an argument.
So, if you want to install the latest development version (which resides on the master
branch),
you should run:
wget -q -O 102s-setup.sh https://git.io/vHydu; chmod u+x 102s-setup.sh; ./102s-setup.sh master; rm 102s-setup.sh
Web UI¶
1. Prerequisites¶
The web UI depends on Node-RED with the dashboard add-on.
- Install Node-RED: Follow the Installation Instructions
Raspbian Tip
There is a special simple installation way for the Raspberry Pi:
bash <(curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)
Warning
If you have installed any version of node-red-contrib-ui, you have to uninstall it before installing node-red-dashboard.
- Install the Node-RED dashboard add-on:
cd ~/.node-red npm install node-red-dashboard
2. Start Node-RED¶
Execute node-red on a console. The Node-RED administration interface should now be available on yournoderedhost:1880
Raspbian Tip
If you want Node-RED to automatically start on boot, execute:
sudo systemctl enable nodered.service
3. Paste the 102shows UI in Node-RED¶
Copy the contents of ui/nodered.json into the clipboard. Go to the Node-RED admin interface and in the main menu (upper right corner) choose Import >> Clipboard and paste the code you copied earlier into the window that is opening. Confirm with Import
You should now see the flow LED control.
Installing a development version
The link to ui/nodered.json
above points to the latest stable
version.
4. Configure the 102shows UI¶
In the upper left LED control there is a node named global
settings. Double-click on it to open it and modify the preferences in
the code so that they match the settings in your server-side
config.py
.
Save with Done and hit the red Deploy button on the upper right.
5. Have fun 😄¶
The UI is now available on yournoderedhost:1880/ui and you should be able to control your LED strips from there 👍
Configuration¶
Todo
Give configuration advice
Running¶
Server¶
- Start the MQTT broker
- Execute /path/to/102shows/server/run.sh
Web UI¶
Just start Node-RED. The panel should appear on yournoderedhost:1880/ui
Supported LED chipsets¶
APA102 (aka Adafruit DotStar)¶
The APA102 is an RGB LED with an integrated driver chip that can be addressed via SPI. That makes it ideal for the Raspberry Pi as talking to an SPI device from Python is really easy. Another advantage of this chip is its support for high SPI data rates (for short strips of less than 200 LEDs you can easily do 8 MHz) which results in very high framerates and smooth-looking animations.
You can find cheap strips on AliExpress etc. or buy them at Adafruit - they sell them as DotStar.
This driver was originally written by tinue and can be found here.
-
class
drivers.apa102.
APA102
(num_leds: int, max_clock_speed_hz: int = 4000000, max_global_brightness: float = 1.0)[source]¶ Note
A very brief overview of the APA102
An APA102 LED is addressed with SPI. The bits are shifted in one by one, starting with the least significant bit.
An LED usually just forwards everything that is sent to its data-in to data-out. While doing this, it remembers its own color and keeps glowing with that color as long as there is power.
An LED can be switched to not forward the data, but instead use the data to change it’s own color. This is done by sending (at least) 32 bits of zeroes to data-in. The LED then accepts the next correct 32 bit LED frame (with color information) as its new color setting.
After having received the 32 bit color frame, the LED changes color, and then resumes to just copying data-in to data-out.
The really clever bit is this: While receiving the 32 bit LED frame, the LED sends zeroes on its data-out line. Because a color frame is 32 bits, the LED sends 32 bits of zeroes to the next LED. As we have seen above, this means that the next LED is now ready to accept a color frame and update its color.
So that’s really the entire protocol:
- Start by sending 32 bits of zeroes. This prepares LED 1 to update its color.
- Send color information one by one, starting with the color for LED 1, then LED 2 etc.
- Finish off by cycling the clock line a few times to get all data to the very last LED on the strip
The last step is necessary, because each LED delays forwarding the data a bit. Imagine ten people in a row. When you yell the last color information, i.e. the one for person ten, to the first person in the line, then you are not finished yet. Person one has to turn around and yell it to person 2, and so on. So it takes ten additional “dummy” cycles until person ten knows the color. When you look closer, you will see that not even person 9 knows the color yet. This information is still with person 2. Essentially the driver sends additional zeroes to LED 1 as long as it takes for the last color frame to make it down the line to the last LED.
- Restrictions of this driver:
- strips cannot have more than 1024 LEDs
The constructor initializes the strip connection via SPI
-
clear_strip
()¶ Clears the color buffer, then invokes a blackout on the strip by calling
show()
Return type: None
-
color_bytes_to_tuple
()¶ Converts a 3-byte color value (like
FF001A
) into an RGB color tuple (like(255, 0, 26)
).Parameters: rgb_color ( int
) – a 3-byte RGB color value represented as a base-10 integerReturn type: tuple
Returns: color tuple (red, green, blue)
-
color_tuple_to_bytes
(green, blue)¶ Converts an RGB color tuple (like
(255, 0, 26)
) into a 3-byte color value (likeFF001A
)Parameters: Return type: Returns: the tuple components joined into a 3-byte value with each byte representing a color component
-
freeze
()¶ Freezes the strip. All state-changing methods (
on_color_change()
andon_brightness_change()
) must not do anything anymore and leave the buffer unchanged.Return type: None
-
get_pixel
(led_num)¶ Returns the pixel at index
led_num
Parameters: led_num ( int
) – the index of the pixel you want to getReturn type: tuple
Returns: (red, green, blue)
as tuple
-
classmethod
led_prefix
(brightness)[source]¶ generates the first byte of a 4-byte SPI message to a single APA102 module
Parameters: brightness ( float
) – float from 0.0 (off) to 1.0 (full brightness)Return type: int
Returns: the brightness byte
-
max_refresh_time_sec
= 1¶ the maximum time the whole strip takes to refresh
-
on_brightness_change
(led_num)[source]¶ For the LED at
led_num
, regenerate the prefix and store the new prefix to the message bufferParameters: led_num ( int
) – The index of the LED whose prefix should be regeneratedReturn type: None
-
on_color_change
(led_num, red, green, blue)[source]¶ Changes the message buffer after a pixel was changed in the global color buffer. Also, a grayscale correction is performed. To send the message buffer to the strip and show the changes, you must invoke
show()
Parameters: Return type:
-
rotate
(positions=1)¶ Treating the internal leds array as a circular buffer, rotate it by the specified number of positions. The number can be negative, which means rotating in the opposite direction.
Parameters: positions ( int
) – the number of steps to rotateReturn type: None
-
set_brightness
(led_num, brightness)¶ Sets the brightness for a single LED in the strip. A global multiplier is applied.
Parameters: Return type:
-
set_global_brightness
(brightness)¶ Sets a global brightness multiplicator which applies to every single LED’s brightness.
Parameters: brightness ( float
) – the global brightness (0.0 - 1.0
) multiplicator to be setReturn type: None
-
set_global_brightness_percent
(brightness)¶ Just like
set_global_brightness()
, but with a 0-100 percent value.Parameters: brightness ( float
) – the global brightness (0.0 - 100.0
) multiplicator to be setReturn type: None
-
set_pixel
(led_num, red, green, blue)¶ The buffer value of pixel
led_num
is set to(red, green, blue)
Parameters: Return type:
-
set_pixel_bytes
(led_num, rgb_color)¶ Changes the pixel
led_num
to the given color in the buffer. To send the buffer to the strip and show the changes, invokeshow()
If you do not know, how the 3-byte
rgb_color
works, just useset_pixel()
.Parameters: Return type:
-
static
spi_end_frame
()[source]¶ As explained above, dummy data must be sent after the last real color information so that all of the data can reach its destination down the line. The delay is not as bad as with the human example above. It is only 1/2 bit per LED. This is because the SPI clock line needs to be inverted.
Say a bit is ready on the SPI data line. The sender communicates this by toggling the clock line. The bit is read by the LED, and immediately forwarded to the output data line. When the clock goes down again on the input side, the LED will toggle the clock up on the output to tell the next LED that the bit is ready.
After one LED the clock is inverted, and after two LEDs it is in sync again, but one cycle behind. Therefore, for every two LEDs, one bit of delay gets accumulated. For 300 LEDs, 150 additional bits must be fed to the input of LED one so that the data can reach the last LED. In this implementation we add a few more zero bytes at the end, just to be sure.
Ultimately, we need to send additional num_leds/2 arbitrary data bits, in order to trigger num_leds/2 additional clock changes. This driver sends zeroes, which has the benefit of getting LED one partially or fully ready for the next update to the strip. An optimized version of the driver could omit the
spi_start_frame()
method if enough zeroes have been sent as part ofspi_end_frame()
.Return type: list
Returns: The end frame to be sent at the end of each SPI transmission
-
static
spi_start_frame
()[source]¶ To start a transmission, one must send 32 empty bits
Return type: list
Returns: The 32-bit start frame to be sent at the beginning of a transmission
-
sync_down
()¶ Reads the shared color and brightness buffers and copies them to the local buffers
Return type: None
No LED Strip (Dummy Driver)¶
-
class
drivers.dummy.
DummyDriver
(num_leds: int, max_clock_speed_hz: int = 4000000, max_global_brightness: float = 1.0)[source]¶ A Dummy Driver that just shows the LED states on the logger. This can be useful for developing without having a real LED strip at hand.
-
clear_strip
()¶ Clears the color buffer, then invokes a blackout on the strip by calling
show()
Return type: None
-
color_bytes_to_tuple
()¶ Converts a 3-byte color value (like
FF001A
) into an RGB color tuple (like(255, 0, 26)
).Parameters: rgb_color ( int
) – a 3-byte RGB color value represented as a base-10 integerReturn type: tuple
Returns: color tuple (red, green, blue)
-
color_tuple_to_bytes
(green, blue)¶ Converts an RGB color tuple (like
(255, 0, 26)
) into a 3-byte color value (likeFF001A
)Parameters: Return type: Returns: the tuple components joined into a 3-byte value with each byte representing a color component
-
freeze
()¶ Freezes the strip. All state-changing methods (
on_color_change()
andon_brightness_change()
) must not do anything anymore and leave the buffer unchanged.Return type: None
-
get_pixel
(led_num)¶ Returns the pixel at index
led_num
Parameters: led_num ( int
) – the index of the pixel you want to getReturn type: tuple
Returns: (red, green, blue)
as tuple
-
rotate
(positions=1)¶ Treating the internal leds array as a circular buffer, rotate it by the specified number of positions. The number can be negative, which means rotating in the opposite direction.
Parameters: positions ( int
) – the number of steps to rotateReturn type: None
-
set_brightness
(led_num, brightness)¶ Sets the brightness for a single LED in the strip. A global multiplier is applied.
Parameters: Return type:
-
set_global_brightness
(brightness)¶ Sets a global brightness multiplicator which applies to every single LED’s brightness.
Parameters: brightness ( float
) – the global brightness (0.0 - 1.0
) multiplicator to be setReturn type: None
-
set_global_brightness_percent
(brightness)¶ Just like
set_global_brightness()
, but with a 0-100 percent value.Parameters: brightness ( float
) – the global brightness (0.0 - 100.0
) multiplicator to be setReturn type: None
-
set_pixel
(led_num, red, green, blue)¶ The buffer value of pixel
led_num
is set to(red, green, blue)
Parameters: Return type:
-
set_pixel_bytes
(led_num, rgb_color)¶ Changes the pixel
led_num
to the given color in the buffer. To send the buffer to the strip and show the changes, invokeshow()
If you do not know, how the 3-byte
rgb_color
works, just useset_pixel()
.Parameters: Return type:
-
sync_down
()¶ Reads the shared color and brightness buffers and copies them to the local buffers
Return type: None
-
Developing for 102shows¶
MQTT¶
The 102shows server can be controlled completely via MQTT. On this page, you see the commands it responds to.
Paths¶
The general scheme is {prefix}/{sys_name}/show/{show_name}/{command}
Switching a show¶
Starting a show¶
topic:
{prefix}/{sys_name}/show/start
payload: JSON Object, for example:
{ "name": "name_of_my_show", "parameters": { "some_time_sec": 3.5, "arbitrary_color": [255, 64, 8] } }The
parameters
block is optional.retained: no
Stopping a show¶
- topic:
{prefix}/{sys_name}/show/stop
- payload: none needed
- retained: no
Response of the system¶
- topic:
{prefix}/{sys_name}/show/current
- payload: show name as string
- retained: yes
The system is sending this message every time the current show is changed.
Global brightness¶
Setting the global brightness¶
- topic:
{prefix}/{sys_name}/global-brightness/set
- payload: string containing a floating-point number between 0.0 and 1.0
- retained: no
Response of the system¶
- topic:
{prefix}/{sys_name}/global-brightness/current
- payload: string containing a floating-point number between 0.0 and 1.0
- retained: yes
The system is sending this message every time the brightness is changed.
Show-specific parameters¶
Setting a parameter¶
- topic:
{prefix}/{sys_name}/show/{show-name}/parameters/set
- payload: JSON
- retained: no
Response of the system¶
topic:
{prefix}/{sys_name}/show/{show-name}/parameters/current
payload: JSON with all the parameters, for example:
{ "some_time_sec": 3.5, "arbitrary_color": [255, 64, 8] }retained: yes
The system is sending this message every time the parameter is changed.
General commands¶
The MQTT controller listens for the commands start
and stop
for all shows,
and all shows (should) respond to the brightness
command.
Any other commands (so all except for start
, stop
and brightness
)
are up to the individual lightshow.
start
¶
Todo
fix method links
The MQTT controller stops (see below) any running show.
Then it checks if the given parameters (the JSON payload of the MQTT start message)
are valid by invoking show.check_runnable()
.
If the show calls the parameters valid, the controller starts a new process
that runs the method show.run(strip, parameters)
.
stop
¶
The MQTT controller asks the lightshow process kindly to join by sending SIGINT to the show process. The Lightshow base template implements a handler for this signal and usually saves the current strip state and joins after a few milliseconds. However, if the process does not join after 1 second, it is terminated by the controller.
brightness
¶
This command is handled by lightshows (in earlier versions, the controller handled brightness changes - but two processes accessing the same strip at the same time causes a lot of trouble). They change the brightness of a strip. Payload is a float from 0 to 100.
Lightshow-specific commands¶
Each lightshow can implement its own commands, like foo-color
, velocity
(of an animation) etc.
The name of the parameter must not be start
or stop
Lightshows¶
Formal interface¶
- any show should reside in its own file (aka module) under
server/lightshows/
for example:
myshow.py
- any show should reside in its own file (aka module) under
- the module must be registered in the list
__all__
inlightshows
for example:
__all__ = ['foo', 'bar', 'myshow']
- the module must be registered in the list
- all lightshows should inherit the basic lightshow template under
lightshows.templates.base
for example:
from lightshows.templates.base import * def MyShow(Lightshow): def run(self): ... def check_runnable(self): ... def set_parameter(self): ...
- all lightshows should inherit the basic lightshow template under
- it must be registered under
shows
inconfig
file for example:
configuration.shows('MyShow') = myshow.MyShow
- it must be registered under
creating a lightshows
object¶
It is really simple:
my_show_object = lightshows.__active__.shows['commonnameofthelightshow'](strip, parameters)
You could access the lightshow class directly, but the 102shows convention is to access the class
by its common name in the shows
array under lightshows.active
There are two arguments that you have to pass to the constructor:
strip
: Adrivers.LEDStrip
object representing your stripparameters
: Adict
mapping parameter names (of the lightshow) to the parameter values, for example:parameters = {'example_rgb_color': (255,127,8), 'an_arbitrary_fade_time_sec': 1.5}
See also: The documentation of lightshows.templates.base.Lightshow
Example¶
a lightweight example is lightshows.solidcolor
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 | # SolidColor
# (c) 2016-2017 Simon Leiner
# licensed under the GNU Public License, version 2
from helpers.color import blend_whole_strip_to_color
from helpers.preprocessors import list_to_tuple
from lightshows.templates.base import *
class SolidColor(Lightshow):
"""\
The whole strip shines in the same color.
Parameters:
=====================================================================
|| || python || JSON representation ||
|| color: || 3x1 tuple || 3x1 array ||
=====================================================================
"""
def init_parameters(self):
self.register('color', None, verify.rgb_color_tuple, preprocessor=list_to_tuple)
def check_runnable(self):
if self.p.value['color'] is None:
raise InvalidParameters.missing('color')
def run(self):
blend_whole_strip_to_color(self.strip, self.p.value['color'])
|
Developer Reference¶
This will give you an overview of all the classes in 102shows.
mqttcontrol
¶
The MQTT controller is the essential idea of 102shows: Starting and controlling lightshows via MQTT without making lightshow development very hard.
The MQTT controller takes care of reading the configuration file and initializing the LED strip with the right driver, providing the MQTT interface for starting and stopping shows (of course) and it ensures that only one lightshow is running at the same time. You can think of it as the “main function” of 102shows that is starting and controlling all things that happen.
-
class
mqttcontrol.
MQTTControl
(config: orderedattrdict.AttrDict)[source]¶ This class provides function to start/stop the shows under lightshows/ according to the commands it receives via MQTT
-
notify_user
(message, qos=0)[source]¶ send to the MQTT notification channel: Node-RED will display a toast notification
Parameters: - message – the text to be displayed
- qos – MQTT parameter
Return type:
-
on_connect
(client, userdata, flags, rc)[source]¶ subscribe to all messages related to this LED installation
-
on_message
(client, userdata, msg)[source]¶ react to a received message and eventually starts/stops a show
-
start_show
(show_name, parameters)[source]¶ looks for a show, checks if it can run and if so, starts it in an own process
Parameters: Return type:
-
drivers
¶
Structure¶
102shows is designed to work with several types of LED strips. Currently, only APA102 (aka Adafruit DotStar) chips are supported but other chipsets will be included in the future.
There is also a Dummy driver included.
It does not control any LED strip. It merely manages similar internal
buffers as a “normal” driver and if drivers.dummy.DummyDriver.show()
is called, it will print the state of all LEDs in the hypothetical strip
to the debug output. This is particular useful for tests on a machine
with no actual LED strip attached.
To be able to effortlessly switch between drivers, there is a common
interface: All drivers should base on the class drivers.LEDStrip
and be located under /path/to/102shows/server/drivers
.
Note
For 102shows to find and use the driver, it must have an entry in both
drivers.__all__
and drivers.__active__.drivers
.
Interface¶
-
class
drivers.
LEDStrip
(num_leds: int, max_clock_speed_hz: int = 4000000, max_global_brightness: float = 1.0)[source]¶ This class provides the general interface for LED drivers that the lightshows use. All LED drivers for 102shows should inherit this class. Mind the following:
- Pixel order is
r,g,b
- Pixel resolution (number of dim-steps per color component) is 8-bit, so minimum brightness is
0
and maximum brightness is255
The constructor stores the given parameters and initializes the color and brightness buffers. Drivers can and should extend this method.
Parameters: -
clear_strip
()[source]¶ Clears the color buffer, then invokes a blackout on the strip by calling
show()
Return type: None
-
close
()[source]¶ An abstract method to be overwritten by the drivers.
It should close the bus connection and clean up any remains.
Return type: None
-
static
color_bytes_to_tuple
()[source]¶ Converts a 3-byte color value (like
FF001A
) into an RGB color tuple (like(255, 0, 26)
).Parameters: rgb_color ( int
) – a 3-byte RGB color value represented as a base-10 integerReturn type: tuple
Returns: color tuple (red, green, blue)
-
static
color_tuple_to_bytes
(green, blue)[source]¶ Converts an RGB color tuple (like
(255, 0, 26)
) into a 3-byte color value (likeFF001A
)Parameters: Return type: Returns: the tuple components joined into a 3-byte value with each byte representing a color component
-
freeze
()[source]¶ Freezes the strip. All state-changing methods (
on_color_change()
andon_brightness_change()
) must not do anything anymore and leave the buffer unchanged.Return type: None
-
get_pixel
(led_num)[source]¶ Returns the pixel at index
led_num
Parameters: led_num ( int
) – the index of the pixel you want to getReturn type: tuple
Returns: (red, green, blue)
as tuple
-
max_refresh_time_sec
= 1¶ The maximum time (in seconds) that a call of
show()
needs to execute. Currently only used inlightshows.templates.base.sleep()
-
on_brightness_change
(led_num)[source]¶ Reacts to a brightness change at
led_num
by modifying the message bufferParameters: led_num ( int
) – number of the LED whose brightness was modifiedReturn type: None
-
on_color_change
(led_num, red, green, blue)[source]¶ Changes the message buffer after a pixel was changed in the global color buffer. To send the buffer to the strip and show the changes, you must invoke
show()
Parameters: Return type:
-
rotate
(positions=1)[source]¶ Treating the internal leds array as a circular buffer, rotate it by the specified number of positions. The number can be negative, which means rotating in the opposite direction.
Parameters: positions ( int
) – the number of steps to rotateReturn type: None
-
set_brightness
(led_num, brightness)[source]¶ Sets the brightness for a single LED in the strip. A global multiplier is applied.
Parameters: Return type:
-
set_global_brightness
(brightness)[source]¶ Sets a global brightness multiplicator which applies to every single LED’s brightness.
Parameters: brightness ( float
) – the global brightness (0.0 - 1.0
) multiplicator to be setReturn type: None
-
set_global_brightness_percent
(brightness)[source]¶ Just like
set_global_brightness()
, but with a 0-100 percent value.Parameters: brightness ( float
) – the global brightness (0.0 - 100.0
) multiplicator to be setReturn type: None
-
set_pixel
(led_num, red, green, blue)[source]¶ The buffer value of pixel
led_num
is set to(red, green, blue)
Parameters: Return type:
-
set_pixel_bytes
(led_num, rgb_color)[source]¶ Changes the pixel
led_num
to the given color in the buffer. To send the buffer to the strip and show the changes, invokeshow()
If you do not know, how the 3-byte
rgb_color
works, just useset_pixel()
.Parameters: Return type:
-
show
()[source]¶ Subclasses should overwrite this method
This method should show the buffered pixels on the strip, e.g. write the message buffer to the port on which the strip is connected.
Return type: None
-
sync_down
()[source]¶ Reads the shared color and brightness buffers and copies them to the local buffers
Return type: None
-
sync_up
()[source]¶ Copies the local color and brightness buffers to the shared buffer so other processes can see the current strip state.
Return type: None
-
synced_red_buffer
= None¶ the individual dim factors for each LED (0-1), EXCLUDING the global dim factor
- Pixel order is
helpers
¶
Overview¶
This module includes several helpful functions for 102shows to use. Any functionality that could be used in multiple parts of the program should be defined here.
- For example:
- checking if color tuples are valid:
helpers.verify.rgb_color_tuple()
- add two color tuples:
helpers.color.add_tuples()
- interpreting an incoming MQTT message:
helpers.mqtt
- parsing the
config.yml
file:helpers.configparser
- checking if color tuples are valid:
The module also includes some functions that are just too generic to include them in the one place where they are used.
- For example:
- getting the 102shows version:
helpers.get_logo()
- getting the colored 102shows logo:
helpers.get_version()
- getting the 102shows version:
-
helpers.
get_logo
(filename='../logo')[source]¶ Returns the colored 102shows logo. It is read from
/path/to/102shows/logo
Parameters: filename ( str
) – You can specify another logo source file, if you want.Return type: str
Returns: The logo as a multiline string. The colors are included as escape characters.
-
helpers.
get_version
(filename='../version')[source]¶ Returns the current 102shows version as a string that is read from a special version file
Parameters: filename ( str
) – Name of the version file. If no name is supplied, the standard file/path/to/102shows/version
will be usedReturn type: str
Returns: version string (as in the file))
color¶
-
class
helpers.color.
SmoothBlend
(strip: drivers.LEDStrip)[source]¶ This class lets the user define a specific state of the strip (
target_colors
) and then smoothly blends the current state over to the set state.-
class
BlendFunctions
[source]¶ Todo
Include blend pictures directly in documentation
An internal class which provides functions to blend between two colors by a parameter fade_progress for
fade_progress == 0
the function should return the start_color forfade_progress == 1
the function should return the end_color-
classmethod
cubic_blend
(start_color, end_color, fade_progress)[source]¶ cubic blend => see https://goo.gl/wZWm07
Return type: tuple
-
classmethod
linear_blend
(start_color, end_color, fade_progress)[source]¶ linear blend => see https://goo.gl/lG8RIW
Return type: tuple
-
classmethod
parabolic_blend
(start_color, end_color, fade_progress)[source]¶ quadratic blend => see https://goo.gl/hzeFb6
Return type: tuple
-
classmethod
-
SmoothBlend.
blend
(time_sec=2, blend_function=<bound method SmoothBlend.BlendFunctions.linear_blend of <class 'helpers.color.SmoothBlend.BlendFunctions'>>)[source]¶ blend the current LED state to the desired state
-
SmoothBlend.
set_color_for_whole_strip
(red, green, blue)[source]¶ set the same color for all LEDs in the strip
-
SmoothBlend.
set_pixel
(led_num, red, green, blue)[source]¶ set the desired state of a given pixel after the blending is finished
-
SmoothBlend.
target_colors
= None¶ an array of float tuples
-
class
-
helpers.color.
add_tuples
(tuple1, tuple2)[source]¶ Add two tuples component-wise
Parameters: Returns: sum
-
helpers.color.
blend_whole_strip_to_color
(strip, color, fadetime_sec=2)[source]¶ this name is pretty self-explanatory ;-)
Parameters: Return type:
-
helpers.color.
grayscale_correction
(lightness, max_in=255.0, max_out=255)[source]¶ Corrects the non-linear human perception of the led brightness according to the CIE 1931 standard. This is commonly mistaken for gamma correction. [1]
CIE 1931 Lightness correction [2]
The human perception of brightness is not linear to the duty cycle of an LED. The relation between the (perceived) lightness \(Y\) and the (technical) lightness \(L^*\) was described by the CIE:
\begin{align} Y & = Y_{max} \cdot g( ( L^* + 16) / 116 ) \quad ,& \quad 0 \le L^* \le 100 \\ \text{with} \quad g(t) & = \begin{cases} 3 \cdot \delta^2 \cdot ( t - \frac{4}{29}) & t \le \delta \\ t^3 & t > \delta \end{cases} \quad ,& \quad \delta = \frac{6}{29} \end{align}For more efficient computation, these two formulas can be simplified to:
\[\begin{split}Y = \begin{cases} L^* / 902.33 & L^* \le 8 \\ ((L^* + 16) / 116)^3 & L^* > 8 \end{cases} \\ \\ 0 \le Y \le 1 \qquad 0 \le L^* \le 100\end{split}\][1] For more information, read here: https://goo.gl/9Ji129 [2] formula from Wikipedia Parameters: Returns: the correct PWM duty cycle for humans to see the desired lightness as integer
configparser¶
-
helpers.configparser.
get_configuration
(default_filename='defaults.yml', user_filename='config.yml')[source]¶ gets the current configuration, as specified by YAML files
Parameters: Return type: AttrDict
Returns: settings tree
-
helpers.configparser.
update_settings_tree
(base, update)[source]¶ For all attributes in
update
override the defaults set inbase
or add them to the tree, if they did not exist inbase
.Parameters: - base (
AttrDict
) – default config tree - update (
AttrDict
) – “patch” for the default config tree
Return type: AttrDict
Returns: the updated tree
- base (
exceptions¶
see Exceptions (#fixme: link)
mqtt¶
A couple of helper functions (big surprise!) for MQTTControl
-
class
helpers.mqtt.
TopicAspect
[source]¶ information you can get out of an MQTT topic (and on which path hierarchy they are)
preprocessors¶
verify¶
Functions that validate input parameters and exceptions, raising InvalidParameters exceptions if the input does not fit the requirements. #fixme: link to exception
-
helpers.verify.
boolean
(candidate, param_name=None)[source]¶ a boolean value: True or False
Parameters: - candidate – the object to be tested
- param_name (
Optional
[str
]) – name of the parameter (to be included in the error message)
-
helpers.verify.
not_negative_integer
(candidate, param_name=None)[source]¶ a not-negative integer => 0,1,2,3,...
Parameters: - candidate – the object to be tested
- param_name (
Optional
[str
]) – name of the parameter (to be included in the error message)
-
helpers.verify.
not_negative_numeric
(candidate, param_name=None)[source]¶ a not-negative number => 0 or above
Parameters: - candidate – the object to be tested
- param_name (
Optional
[str
]) – name of the parameter (to be included in the error message)
-
helpers.verify.
numeric
(candidate, param_name=None, minimum=None, maximum=None)[source]¶ number (between minimum and maximum)
Parameters:
-
helpers.verify.
positive_integer
(candidate, param_name=None)[source]¶ a positive integer => greater than 0 => 1 or above
Parameters: - candidate – the object to be tested
- param_name (
Optional
[str
]) – name of the parameter (to be included in the error message)
-
helpers.verify.
positive_numeric
(candidate, param_name=None)[source]¶ a positive number => greater than 0
Parameters: - candidate – the object to be tested
- param_name (
Optional
[str
]) – name of the parameter (to be included in the error message)
-
helpers.verify.
rgb_color_tuple
(candidate, param_name=None)[source]¶ An RGB color tuple. It must contain three integer components between 0 and 255.
Parameters: - candidate – the object to be tested
- param_name (
Optional
[str
]) – name of the parameter (to be included in the error message)
Tests¶
Todo
write docstring for this module
lightshows
¶
Overview¶
102shows offers a framework for writing and displaying lightshows.
lightshows
includes the code that actually relies on this
and displays animations on an LED strip.
Templates¶
Todo
include link to controller
To make writing lightshows easy and convenient we introduced templates. These provide the interfaces for the controller and generic functionalities.
Basically: The templates are there so that lightshow modules just have to worry about the LED animations, and not about the backgrounds of 102shows
The base template¶
As the name says, this is the most basic template. All lightshows (and all other templates) rely on this template. It offers quite a lot:
- The interface to the controller:
lightshows.base.Lightshow.name()
returns the name of the lightshow
lightshows.base.Lightshow.start()
initializes the show process,- starts the built-in MQTT client and then triggers the start of the animation
lightshows.base.Lightshow.stop()
can be called to gracefully end the showlightshows.base.Lightshow.name()
-
class
lightshows.templates.base.
Lightshow
(strip: drivers.LEDStrip, parameters: dict)[source]¶ This class defines the interfaces and a few helper functions for lightshows. It is highly recommended to use it as your base class when writing your own show.
Parameters: - strip (
LEDStrip
) – Adrivers.LEDStrip
object representing your strip - parameters (
dict
) –A
dict
mapping parameter names (of the lightshow) to the parameter values, for example:parameters = {'example_rgb_color': (255,127,8), 'an_arbitrary_fade_time_sec': 1.5}
-
class
MQTTListener
(lightshow)[source]¶ This class collects the functions that receive incoming MQTT messages and parse them as parameter changes.
-
parse_message
(client, userdata, msg)[source]¶ Function to be executed as
on_message
hook of the Paho MQTT client. If the message commands a brightness or parameter change the corresponding hook (set_brightness()
orset_parameter()
) is called.Todo
- include link to the paho mqtt lib
- explain currently unknown parameters
Parameters: - client – the calling client object
- userdata – no idea what this does. This is a necessary argument but is not handled in any way in the function.
- msg – The object representing the incoming MQTT message
Return type:
-
set_brightness
(brightness)[source]¶ Limits the brightness value to the maximum brightness that is set in the configuration file, then calls the strip driver’s
drivers.LEDStrip.set_global_brightness()
functionParameters: brightness ( float
) – float between 0.0 and 1.0Return type: None
-
start_listening
()[source]¶ If this method is called (e.g. by the show object), incoming MQTT messages will be parsed, given they have the path
$prefix/$sys_name/$show_name/$parameter
$parameter
and the$payload
will be given tolightshow.templates.base.Lightshow.set_parameter()
Return type: None
-
stop_listening
()[source]¶ Ends the connection to the MQTT broker. Messages from the subscribed topics are not parsed anymore.
Return type: None
-
subscribe
(client, userdata, flags, rc)[source]¶ Function to be executed as
on_connect
hook of the Paho MQTT client. It subscribes to the MQTT paths for brightness changes and parameter changes for the show.Todo
- include link to the paho mqtt lib
- explain currently unknown parameters
Parameters: - client – the calling client object
- userdata – no idea what this does. This is a necessary argument but is not handled in any way in the function.
- flags – no idea what this does. This is a necessary argument but is not handled in any way in the function.
- rc – no idea what this does. This is a necessary argument but is not handled in any way in the function.
Return type:
-
-
Lightshow.
apply_parameter_set
(parameters)[source]¶ Applies a set of parameters to the show.
Parameters: parameters ( dict
) – Parameter JSON Object, represented as a Pythondict
Return type: None Returns: True
if successful,False
if not
-
Lightshow.
check_runnable
()[source]¶ Todo
include official exception raise notice
Raise an exception (InvalidStrip, InvalidConf or InvalidParameters) if the show is not runnable
-
Lightshow.
cleanup
()[source]¶ This is called before the show gets terminated. Lightshows can use it to clean up resources before their process is killed.
Return type: None
-
Lightshow.
idle_forever
(delay_sec=-1)[source]¶ Just does nothing and invokes
drivers.LEDStrip.show()
until the end of time (or a call ofstop()
)Parameters: delay_sec ( float
) – Time between two calls ofdrivers.LEDStrip.show()
Return type: None
-
Lightshow.
init_parameters
()[source]¶ Lightshows can inherit this to set their default parameters. This function is called at initialization of a new show object.
Return type: None
-
Lightshow.
logger
= None¶ The logger object this show will use for debug output
-
Lightshow.
mqtt
= None¶ represents the MQTT connection for parsing parameter changes #FIXME: type annotation
-
Lightshow.
p
= None¶ The object that stores all show parameters
-
Lightshow.
register
(parameter_name, default_val, verifier, args=None, kwargs=None, preprocessor=None)[source]¶ MQTT-settable parameters are stored in
lightshows.templates.base.Lightshow.p.value
. Calling this function will register a new parameter and his verifier invalue
andverifier
, so the parameter can be set via MQTT and by the controller.Parameters: - parameter_name (
str
) – name of the parameter. You access the parameter via self.p.value[parameter_name]. - default_val – initializer value of the parameter. Note that this value will not be checked by the verifier function!
- verifier – a function that is called before the parameter is set via MQTT. If it raises an InvalidParameters exception, the new value will not be set. #FIXLINK
- args (
Optional
[list
]) – the verifier function will be called asverifier(new_value, param_name, *args, **kwargs)
- kwargs (
Optional
[dict
]) – the verifier function will be called viaverifier(new_value, param_name, *args, **kwargs)
- preprocessor – before the validation in set_parameter
value = preprocessor(value)
will be called
Return type: - parameter_name (
-
Lightshow.
run
()[source]¶ The “main” function of the show (obviously this must be re-implemented in child classes)
Return type: None
-
Lightshow.
set_parameter
(param_name, value, send_mqtt_update=True)[source]¶ Take a parameter by name and new value and store it to p.value.
Parameters: Return type:
-
Lightshow.
sleep
(time_sec)[source]¶ Does nothing (but refreshing the strip a few times) for
time_sec
secondsParameters: time_sec ( float
) – duration of the breakReturn type: None
-
Lightshow.
start
()[source]¶ invokes the
run()
method and after that synchronizes the shared bufferReturn type: None
-
Lightshow.
stop
(signum=None, frame=None)[source]¶ Todo
include link for SIGINT
This should be called to stop the show with a graceful ending. It guarantees that the last strip state is uploaded to the global inter-process buffer. This method is called when SIGINT is sent to the show process. The arguments have no influence on the function.
Parameters: - signum – The integer-code of the signal sent to the show process. This has no influence on how the function works.
- frame – #fixme
Return type:
-
Lightshow.
strip
= None¶ the object representing the LED strip (driver) #FIXME: type annotation
- strip (
-
class
lightshows.templates.base.
LightshowParameters
[source]¶ A collection of maps for the parameters which store their:
- current values
- preprocessor method references
- verifier method references
-
preprocessor
= None¶ maps the show parameter names to their preprocessor functions
-
value
= None¶ maps the show parameter names to their current values
-
verifier
= None¶ maps the show parameter names to their verifier functions
Exceptions¶
This module defines some exception classes specific to 102shows:
-
exception
helpers.exceptions.
DescriptiveException
(value)[source]¶ This type of exception must contain a value (usually a string) that is used as the string representation of the exception
-
exception
helpers.exceptions.
InvalidConf
(value)[source]¶ Use if something in the configuration will not work for what the user has chosen in the config file.
Thanks!¶
- To tinue for the APA102_Pi library. This was the code that 102shows was originally based on.
- The authors and contributors of the libraries that 102shows uses:
- The people of Sphinx, the great tool that is used for this documentation and the authors and contributors of the plugins for Sphinx that we use:
Indices and tables¶
Trouble?¶
Open an issue on GitHub or write an email to me: 102shows@leiner.me