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:

None

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

run()[source]

start the listener

Return type:None
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:
  • show_name (str) – name of the show to be started
  • parameters (dict) – these are passed to the show
Return type:

None

stop_controller(signum=None, frame=None)[source]

what happens if the controller exits

stop_running_show(timeout_sec=1)[source]

stops any running show

Parameters:timeout_sec (float) – time the show process has until it is terminated
Return type:None
stop_show(show_name)[source]

stops a show with a given name. If this show is not running, the function does nothing.

Parameters:show_name (str) – name of the show to be stopped
Return type:None

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 is 255

The constructor stores the given parameters and initializes the color and brightness buffers. Drivers can and should extend this method.

Parameters:
  • num_leds (int) – number of LEDs in the strip
  • max_clock_speed_hz (int) – maximum clock speed (Hz) of the bus
clear_buffer()[source]

Resets all pixels in the color buffer to (0,0,0).

Return type:None
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 integer
Return 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 (like FF001A)

Parameters:
  • red (float) – red component of the tuple (0.0 - 255.0)
  • green (float) – green component of the tuple (0.0 - 255.0)
  • blue (float) – blue component of the tuple (0.0 - 255.0)
Return type:

int

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() and on_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 get
Return 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 in lightshows.templates.base.sleep()

on_brightness_change(led_num)[source]

Reacts to a brightness change at led_num by modifying the message buffer

Parameters:led_num (int) – number of the LED whose brightness was modified
Return 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:
  • led_num – index of the pixel to be set
  • red (float) – red component of the pixel (0.0 - 255.0)
  • green (float) – green component of the pixel (0.0 - 255.0)
  • blue (float) – blue component of the pixel (0.0 - 255.0)
Return type:

None

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 rotate
Return type:None
set_brightness(led_num, brightness)[source]

Sets the brightness for a single LED in the strip. A global multiplier is applied.

Parameters:
  • led_num (int) – the target LED index
  • brightness (float) – the desired brightness (0.0 - 1.0)
Return type:

None

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 set
Return 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 set
Return type:None
set_pixel(led_num, red, green, blue)[source]

The buffer value of pixel led_num is set to (red, green, blue)

Parameters:
  • led_num (int) – index of the pixel to be set
  • red (float) – red component of the pixel (0.0 - 255.0)
  • green (float) – green component of the pixel (0.0 - 255.0)
  • blue (float) – blue component of the pixel (0.0 - 255.0)
Return type:

None

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, invoke show()

If you do not know, how the 3-byte rgb_color works, just use set_pixel() .

Parameters:
  • led_num (int) – index of the pixel to be set
  • rgb_color (int) – a 3-byte RGB color value represented as a base-10 integer
Return type:

None

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

unfreeze()[source]

Revokes all effects of freeze()

Return type:None

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:

The module also includes some functions that are just too generic to include them in the one place where they are used.

For example:

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 used
Return 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 for fade_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 power_blend(power, start_color, end_color, fade_progress)[source]

blend two colors using a power function, the exponent is set via param power

Return type:tuple
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

helpers.color.add_tuples(tuple1, tuple2)[source]

Add two tuples component-wise

Parameters:
  • tuple1 (tuple) – summand
  • tuple2 (tuple) – summand
Returns:

sum

helpers.color.blend_whole_strip_to_color(strip, color, fadetime_sec=2)[source]

this name is pretty self-explanatory ;-)

Parameters:
  • strip (LEDStrip) – LEDStrip object
  • color (tuple) – the color to blend two
  • fadetime_sec (float) – the time in seconds to blend in
Return type:

None

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:
  • lightness (float) – linear brightness value between 0 and max_in
  • max_in (float) – maximum value for lightness
  • max_out (int) – maximum output integer value (255 for 8-bit LED drivers)
Returns:

the correct PWM duty cycle for humans to see the desired lightness as integer

helpers.color.linear_dim(undimmed, factor)[source]

Multiply all components of undimmed with factor

Parameters:
  • undimmed (tuple) – the vector
  • factor (float) – the factor to multiply the components of the vector byy
Return type:

tuple

Returns:

resulting RGB color vector

helpers.color.wheel(wheel_pos)[source]

Get a color from a color wheel: Green -> Red -> Blue -> Green

Parameters:wheel_pos (float) – numeric from 0 to 254
Returns:RGB color tuple

configparser

helpers.configparser.get_configuration(default_filename='defaults.yml', user_filename='config.yml')[source]

gets the current configuration, as specified by YAML files

Parameters:
  • default_filename (str) – name of the default settings file (relative to configparser.py)
  • user_filename (str) – name of the user settings file (relative to configparser.py)
Return type:

AttrDict

Returns:

settings tree

helpers.configparser.update_settings_tree(base, update)[source]

For all attributes in update override the defaults set in base or add them to the tree, if they did not exist in base.

Parameters:
  • base (AttrDict) – default config tree
  • update (AttrDict) – “patch” for the default config tree
Return type:

AttrDict

Returns:

the updated tree

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)

helpers.mqtt.get_from_topic(hierarchy_level, topic)[source]

get the string on a specified hierarchy level

Parameters:
  • hierarchy_level (int) – integer level
  • topic (str) – string to be analyzed
Return type:

str

Returns:

part-string of the wanted level

helpers.mqtt.parse_json_safely(payload)[source]

parse a string as JSON object logs failures as warnings

Parameters:payload (str) – string to be parsed
Return type:dict
Returns:parsed JSON object (as dict)

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.integer(candidate, param_name=None, minimum=None, maximum=None)[source]
Parameters:
  • candidate – the object to be tested
  • param_name (Optional[str]) – name of the parameter (to be included in the error message)
  • minimum (Optional[float]) – minimum
  • maximum (Optional[float]) – maximum
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:
  • candidate – the object to be tested
  • param_name (Optional[str]) – name of the parameter (to be included in the error message)
  • minimum (Optional[float]) – minimum (of a closed set)
  • maximum (Optional[float]) – maximum (of a closed set)
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 show
    • lightshows.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) – A drivers.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() or set_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:

None

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() function

Parameters:brightness (float) – float between 0.0 and 1.0
Return 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 to lightshow.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:

None

Lightshow.apply_parameter_set(parameters)[source]

Applies a set of parameters to the show.

Parameters:parameters (dict) – Parameter JSON Object, represented as a Python dict
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 of stop())

Parameters:delay_sec (float) – Time between two calls of drivers.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.name

The name of the lightshow in lower-cases

Return type:str
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 in value and verifier, 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 as verifier(new_value, param_name, *args, **kwargs)
  • kwargs (Optional[dict]) – the verifier function will be called via verifier(new_value, param_name, *args, **kwargs)
  • preprocessor – before the validation in set_parameter value = preprocessor(value) will be called
Return type:

None

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:
  • param_name (str) – name of the parameter to be stored
  • value – new value of the parameter to be stored
  • send_mqtt_update (bool) – Send the updated parameter array to the MQTT current parameter path after update
Return type:

None

Lightshow.sleep(time_sec)[source]

Does nothing (but refreshing the strip a few times) for time_sec seconds

Parameters:time_sec (float) – duration of the break
Return type:None
Lightshow.start()[source]

invokes the run() method and after that synchronizes the shared buffer

Return 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:

None

Lightshow.strip = None

the object representing the LED strip (driver) #FIXME: type annotation

Lightshow.suicide()[source]

terminates its own process

Return type:None
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.

exception helpers.exceptions.InvalidParameters(value)[source]

Use when given parameters (for a lightshow) are not valid

static missing()[source]

Todo

document!

static unknown()[source]

Todo

document!

exception helpers.exceptions.InvalidStrip(value)[source]

Use if something is wrong with the strip.

For example: not enough LEDs to run the selected lightshow