-
Notifications
You must be signed in to change notification settings - Fork 5
03.1 The Chandler Visual Programming Model
This page is more of an essay or intro to the general concepts than a tutorial.
Note: Before 0.85.0, chandler Groups were called Scenes. This was confusing as a "scene" is too similar to a "cue".
Chandler started as a lighting control module but has grown some visual programming features that I thought might be interesting enough to write up on their own.
The first thing to know is that this is meant for absolutely trivial programming, to a degree that can hardly even be called programming at all.
Any "Real" programming was never intended to be possible, and plenty of Python hooks exist if it is needed.
Even things as basic as reusable functions don't exist. An explicit goal is that the system shouldn't let you make stuff that an average end user(Imagine someone with Excel experience and no trouble setting up a WiFi router) can't learn in minutes.
The model is essentially a set of very extended finite-state machines that can be edited visually.
State machines are called "Groups" here, and states are called "Cues". An active group is always "on" a particular cue.
There is always one cue called "default" that groups begin in.
Every Cue has a duration, if nonzero it goes to the next cue after that many seconds(Actually beats, but the default bpm is 60).
Cues are an ordered list, and the default "next cue" is usually just the next cue in sequence, however, the "next cue" can be set on a per-cue basis.
The duration can also be randomized, and the next cue can be random as well by setting it to __random__. Every cue also has a probability setting that affects how likely it is to be chosen.
Since it is still a full lighting control system, cues can have lighting control values attached(Lighting control interfaces are configured globally).
Every cue has an "alpha" value, which affects its opacity when blending(Blending works like a photo editor layer stack) and the volume of any sounds it might play.
There are different "Blend Modes", and some can be dynamic, like applying flicker to all affected values.
In addition to adding lighting channel values to a group, you can also add Tag Point values(in 0.80.0+). All the blend modes work the same, but instead of writing to a DMX adapter, it sets the values to the tag point.
It will only set the values when something changes in Chandler, meaning you can still control the tag point elsewhere, too. This allows for things like timers and manual switches to work together in the way you expect.
Cues can have a sound associated, or even a video, image, or HTML slide(Every group has a player URL that plays the active slide in a web browser, meaning they can be used for digital signage).
The sound will play out the server's normal sound output. You can also set a specific output per-group and override it if needed per-cue for use with multiple soundcards.
Kaithem is meant to run on modern Linux, and PipeWire takes care of giving cards persistent names.
The built-in features are enough to cover almost all intended use cases, but for the remaining bit of functionality, cues can have logic.
Logic is in the form of ITTT-style rules attached to specific cues, inspired by DRAKON and Ladder Logic but greatly stripped down.
A rule is a statement saying "When this event happens, do these actions in sequence".
When a global event happens, all currently active cues respond by firing the actions. Events can also be sent directly to a specific group. "events" can be named events something else sends, or spreadsheet-inspired =expressions that fire when the expression is true.
They can also be time expressions like @every five minutes or @january 1 at 10pm. There are several events the system fires by itself, like cue.enter and cue.exit which will trigger when entering and exiting a cue.
Some actions are tests that terminate that rule if the condition fails. They can set variables, and new actions can be defined in Python code. Actions can also trigger groups to go to other cues. If the action causes a cue to exit, any remaining rules in that cue are canceled.
New actions can be defined in Module Events, separate from Chandler, in raw Python code, and code can easily trigger Chandler events. Simply add a function to the kaithem.chandler.commands dict, it will be passed parameters as strings, after processing =expressions. To trigger an event, just call kaithem.chandler.event(name).
Within expressions, you have access to the value of Tag Points, which are essentially variables with extra features. Tags live in a global list shared between everything on the Kaithem server, and most features make use of them.
If you have this cue in your group, all other cues will inherit any rules in it. Their own rules will also be in effect, in addition to the global inherited rules.
Groups are not just state machines with actions, they are also user-visible objects with configurable UI in the runtime mode.
In both the edit and runtime pages, there is a listing of groups, and each one has a configurable UI box.
Groups may have tag points set as displays or inputs. These are shown in the group overview as boxes, switches, or meters, and can used similarly to inputs and outputs in a spreadsheet.
Groups may have action buttons that fire an event within that group. They can even have a URL that displays in an iframe in the group overview(Which can be hidden in "compact mode") allowing the groups overview to effectively serve as a full dashboard.
These functions are available in any =expression.
Return a float unix timestamp.
Random value from 0 to 1
Random integer from a to b inclusive
Common math functions
Requires location set on server. Returns boolean depending on civil twilight or dawn/dusk.
Return the value of a numeric tagpoint
Return the value of a string tagpoint
(v0.80.0+ only)
Returns a config value. Values may be set in any module or in the config file.