diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..d32cdbaa --- /dev/null +++ b/404.html @@ -0,0 +1,2780 @@ + + + +
+ + + + + + + + + + + + + + + + +In the definition of the button, the type
attribute determine what the button will do.
For a given button on a deck, the action that the button will be able to carry over is limited to a set of valid types. A push button is not capable of rotations of an encoder.
+When interaction occurs on a button on a deck, Cockpitdecks creates a typed Event, and passes it for activation.
+Each activation is designed to handle one or more Events types. For example a EncoderPush activation is capable of handling both PressEvent and EncoderEvent. What is does with those event is left to the activation.
+This file list all activations that are currently available in Cockpitdecks. For each activation, we present its name or keyword by which it must be referred to, the attributes it expects to work properly, the type of events it expects, and internal state values it produces and maintains.
+Each activation always goes through 3 steps.
+First, the event is handled completely. Most of the time, the root class of activations is activated first, for global handling and checks. Then the activation itself is performed. The activation returns a boolean flag to indicate that it completed successfully.
+Second, if the activation produces a value, it is written to the set-dataref
of the button, if any. This operation can be considered like an second instruction that is performed provided that the button instructed to write the value to the dataref pointed by set-dataref
.
Third, and finally, if the button activation contains a view
command, it is executed. The purpose of the view command if to alter the view in the cockpit, may be to focus on a particular area of the dashboard to control the effect of the activation.
When specifying attributes for an activation command
and commands
attributes can be requested. A command
is a single command, commands
is a list of individual commands, often, the number of commands in the list matters and match the Activation requirements.
A command
can be:
command: sim/map/show_current
+
A Command Block is a series of attributes that specify a command to execute and some optional behavior.
+ command:
+ - set-dataref: sim/value/to/set
+ condition: ${sim/position/altitude} 5000 >
+ delay: 5
+
The group of attributes set-dataref
, condition
, delay
is a command block. It is one instruction (set-dataref
), a condition to satisfy before executing the instruction, and a delay to wait after the condition is satisfied before executing the command.
The condition is evaluated each time one of its parameter changes.
+There are currently two attributes that can be used to specify a command to execute:
+command
set-dataref
Either one can be used but not both. (If both are specified, a warning is issued and the command is ignored.)
+A condition is a formula that specify, when evaluated, if the command can be executed. The condition is evaluated each time one of its constituting simulator value changes.
+The delay is a value in seconds that specifies how long after the command receives its instruction to execute it actually perform the task. This allows to pause between commands rather than submitting them all simultaneously to the target.
+ command:
+ - command: AirbusFBW/MCDU1Menu
+ - command: AirbusFBW/MCDU1LSK6L
+ delay: 1
+ - command: AirbusFBW/MCDU1LSK6R
+ delay: 1
+ - command: AirbusFBW/MCDU1LSK1R
+ delay: 1
+
In the above example, the single command consists of a series of 4 command blocks. In this case, the single command is called a Macro Instruction.
+type: none
Button with no activation are button used for display purpose only.
+Any event can be handed over to the No Activation, since it will not be used.
+State Variable | +Value | +
---|---|
activation_count |
+Number of time button was activated | +
last_activated |
+Time stamp of last activation | +
initial_value |
+Initial value in configuration (if any) | +
current_value |
+Button current value | +
previous_value |
+Button previous value before change | +
guarded |
+Whether button has a guard on top of it | +
managed |
+Whether button has managed mode (specific to some cockpits, which means there are alternate display values) | +
Among the above State Value that an Activation returns, there always is a special state value named the activation value. The activation value can be accessed by accessing the activation_value
attributes in the state values.
This value is just a value among the existing state values that gets highlighted because it is the most sensible value used by the activation.
+For exemple, the activation value for the On/Off activation is the current state of the activation, either On or Off.
+In the following descriptions, the activation value is highlighted for each activation.
+For No Activation activation, the activation value is equal to the activation count. This is also the "default" activation value, if nothing more precise is returned, the activation value is the number of activation of that button.
+The activation value comes to play when the button needs to determine its value. It first look for a formula, then a single dataref, and if there is no formula and no single dataref, the activation value is used.
+type: page
When the button is pressed, a deck will load a page of buttons.
+Attribute | +Definition | +
---|---|
page |
+Mandatory. Name of the page to load. The page must be in the Layout of the target deck. | +
remote_deck |
+Optional. If present, will load the page on the target deck. | +
PushEvent
and PressEvent
can trigger the Page activation.
Attribute | +Definition | +
---|---|
page |
+page that is currently displayed | +
type: theme
When the button is pressed, the main theme will be changed.
+Attribute | +Definition | +
---|---|
theme |
+Mandatory. Name of theme. | +
PushEvent
and PressEvent
can trigger the Page activation.
type: push
Push button.
+Attribute | +Definition | +
---|---|
command |
+Mandatory. X-Plane command that is executed each time the button is pressed. | +
Note
+Command is a mandatory parameter but if no command is necessary a command placeholder value can be used. Command placeholder value are any of the following string:
+none, noop, no-operation, no-command, do-nothing
+They all are ignored and do not trigger any activity in X-Plane.
PushEvent. Please note that PushEvent consists of 2 distinct events, a pressed event (PushEvent with pressed = True), and a release event (PushEvent with pressed = False), when the button is pressed or released respectively.
+Option | +Definition | +
---|---|
auto-repeat |
+Auto repeat command at specified pace while the button remains pressed.auto-repeat option accepts a couple of optional values:- delay : Time (in second) after which the auto-repeat starts, default to 1 second.- speed : Time (in second) between 2 executions of the command. |
+
options: auto-repeat=3/0.5,dot
+
Auto-repeat will start 3 second after the button was pressed, the command will auto-repeat every 0.5 seconds, twice per second. (dot
option also set for other purpose.)
type: begin-end-command
Push button that will carry the command as long as the button will remain pressed.
+Long press command should not be confused with auto-repeat commands. A BeginEndPress command in one command that is executed once as long as the button remain pressed. An auto-repeat command is the same command that is executed several times at regular interval (typically once every 0.2 seconds, 5 times per second) as long as the button is pressed.
+Note
+The BeginEndPress command requires installation of a XPPYthon3 plugin in X-Plane to circumvent a few X-Plane UDP limitations.
+PushEvent
+Only PushEvent can be used to trigger BeginEndPress Activation since both press and release events are necessary to estimate the timing between both events.
+Attribute | +Definition | +
---|---|
command |
+Mandatory. X-Plane command that is executed each time the button is pressed. | +
X-Plane will issue a beginCommand
when the button is pressed and a endCommand
when released.
Note
+Please note that the use of longpress command needs the addition of a little plugin to circumvent X-Plane UDP limitations when used through UDP.
+type: onoff
Push button.
+PushEvent, PressEvent, LongPressEvent
+Attribute | +Definition | +
---|---|
commands |
+Optional pair of X-Plane commands that are executed alternatively. Two commands must be supplied, but the same command can be provided twice. | +
set-dataref |
+Optional dataref to set On(=1) or Off (=0). Either attribute can be set or both. In the latter case, the command is first executed and then the dataref is set. |
+
Attribute | +Definition | +
---|---|
on |
+current state On or Off | +
The activation value for On/Off activation is the current status, either On or Off.
+type: updown
Cycle Up and Down button.
+Attribute | +Definition | +
---|---|
commands |
+X-Plane commands that are executed when pushes increase value, and when pushes descrease value. | +
stops=3 |
+Number of stop values. For example: Stops=3 will give 0-1-2-1-0 cycles, with 3 stops 0, 1, and 2. | +
initial-value |
+If an initial value is supplied, it's sign indicated how the value will evolve. For example, if the initial value is 1, the next value will be 2 (go up). If the initial value is -1, the initial value will be set to 1, but the next value will be zero (go down). |
+
set-dataref |
+Optional dataref to set the value of the current stop. Very much like On/Off activation either commands or set-dataref can be supplied or both. |
+
The number of supplied commands may vary.
+If no command is supplied, it is assumed that there is a set-dataref
instruction. In this case, the activation runs inside the [0, #stops[
interval and writes the current value to the dataref.
If two commands are supplied, they are assumed to be commands to go up and go down when cycling between the values.
+If the number of commands is equal to the number of stops, and if there are more than 3 stops, then the activation runs inside the [0, #stops[
interval and executes the command corresponding to the current value.
The activation value for UpDown activation is the current value.
+Attribute | +Definition | +
---|---|
stops |
+Number of stops | +
go_up |
+True will increase at next push; False will decrease | +
stop |
+Current value | +
Short or long press has two commands, one that is executed when the button is pressed for less than long-time
seconds, and one when it is pressed more than long-time
seconds.
type
: short-or-longpress
Attribute | +Definition | +
---|---|
commands |
+Two commands, the first one is called on short press. | +
long-time |
+Time to press the button to activate second command. Default to 2 seconds. | +
Type: encoder
An Encoder is a rotating knob or dial with steps. Steps are often materialised by a little sound or a slight resistance in the rotation.
+Attribute | +Definition | +
---|---|
commands |
+An Encoder has two commands, one that is executed for each step while turning clockwise, and one for each step when turning counter-clockwise. | +
State | +Definition | +
---|---|
rotation_clockwise |
+number of times/clicks the encoder was turned clockwise. | +
rotation_counterclockwise |
+same. | +
The activation value for Encoder activation is the current rotation value, i.e. number of rotation clockwise minus number of rotation counter-clockwise, negative values means there are more counter clockwise turns.
+type: encoder-push
An EncoderPush is the combination of an Encoder and a push button.
+Attribute | +Definition | +
---|---|
commands |
+An EncoderPush has 3 commands: 1. First command gets executed when it is pushed 2. Second command gets executed when encoder is turned clockwise 3. Third command gets executed when encoder is turned counterclockwise |
+
State | +Definition | +
---|---|
turns |
+Number of turns, positive is clockwise | +
cw |
+number of times/clicks the encoder was turned clockwise. | +
ccw |
+same, counter clockwise. | +
Same as Encoder activation.
+type: encoder-push
An EncoderOnOff is the combination of an Encoder and an OnOff button.
+Attribute | +Definition | +
---|---|
commands |
+An EncoderPush has 4 commands: 1. First command gets executed when it is OFF, to turn it ON 2. Second command gets executed when it is ON, to turn it OFF 3. Third command gets executed when encoder is turned clockwise 4. Fourth command gets executed when encoder is turned counterclockwise |
+
Attribute | +Definition | +
---|---|
dual |
+With option dual , the activation uses two more commands.1. First command gets executed when it is OFF, to turn it ON 2. Second command gets executed when it is ON, to turn it OFF 3. Third command gets executed when encoder is turned clockwise and ON 4. Fourth command gets executed when encoder is turned counterclockwise and ON 5. Third command gets executed when encoder is turned clockwise and OFF 6. Fourth command gets executed when encoder is turned counterclockwise and OFF. |
+
State | +Definition | +
---|---|
cw |
+number of times/clicks the encoder was turned clockwise. | +
ccw |
+same. | +
on |
+Is currently On or Off | +
Same as Encoder activation.
+A combination of pushing and turning.
+Attribute | +Definition | +
---|---|
commands |
+An EncoderLongPush has 4 commands: 1. First command gets executed when encoder is turned clockwise 2. Second command gets executed when encoder is turned counterclockwise 3. Third command gets executed when encoder is first pushed, then turned clockwise 4. Fourth command gets executed when encoder is first pushed, then turned counterclockwise |
+
+ | + |
State | +Definition | +
---|---|
cw |
+number of times/clicks the encoder was turned clockwise. | +
ccw |
+same. | +
Same as Encoder activation.
+type: encoder-push
An EncoderValue is an Encoder that increases or decrease an internal value each time it is rotated clockwise or counterclockwise. The value can be written to an X-Plane dataref or used for other pruposes.
+Attribute | +Definition | +
---|---|
initial-value |
+Initial value. Default to 0. | +
step |
+Amount of value increase or decrease. | +
stepxl |
+Alternate value for step increase or decrease. If the encoder is capable of push action, the push action will switch between the step and stepxl values. |
+
min |
+Minimal value. | +
max |
+Maximal value. | +
formula |
+Optional. Formula to transform the ${state:button-value} before it is sent to the dataref. |
+
set-dataref |
+Optional dataref to set to the value of the computed value. The value is sent right away, after each encoder activation. | +
State | +Definition | +
---|---|
cw |
+number of times/clicks the encoder was turned clockwise. | +
ccw |
+same. | +
value |
+Current raw value | +
The activation value of the EncoderValue activation is the computed value of the encoder.
+type: slider
A Slider is a one dimensional cursor that produces a continuous value within a range. The value can be written to an X-Plane dataref, directly, or after a computation.
+Attribute | +Definition | +
---|---|
set-dataref |
+Optional. Dataref to write the value to, if present. | +
formula |
+Optional. Formula to transform the ${state:button-value} (value produced by the slider) before it is sent to the dataref. |
+
State | +Definition | +
---|---|
value |
+Current raw value | +
The activation value of the Slider activation is the value of the slider.
+type: swipe
A Swipe is a 2 dimensional movement of a finger on a surface. The event produced consists of the start and end positions of the finger relative to the surface (x, y) and timing information (time stamp).
+(Currently not used.)
+The Swipe event has no attribute.
+The event of a swipe is complex. The entire event is available as last_event
.
The event has the following structure:
+ts_start: 123.456
+ts_end: 135.246
+pos_start: (23, 48)
+pos_end: (78, 42)
+
State | +Definition | +
---|---|
start_x |
+Start of swipe position laterally | +
start_y |
+Start of swipe position vertically | +
start_ts |
+Timestamp of start of swipe, in microseconds | +
end_x |
+End of swipe position laterally | +
end_y |
+End of swipe position vertically | +
end_ts |
+Timestamp of end of swipe, in microseconds | +
From the above values, with some tolerence, it is possible to determine whether the finger moved on the surface or not (swipe or touch), and to determine the duration of the contact with the surface.
+Reload, Stop, or Inspect are special activations for developer.
+These activations are normally not used during regular operations.
+It always is possible to create new activations by extending Cockpitdecks.
+ + + + + + + + + + + + + + + + + + + + + + +Buttons are defined by a list of attributes.
+Some attributes are unique to a button, very specific, and cannot have default values like, for exemple, the button index or a button label attribute.
+Some other attributes are used by numerous buttons, like for example the color of the label. These common attributes benefit from a sophisticated default value lookup.
+Before we can look up at the attribute evaluation method, we must notice that all objects we manipulate in Cockpitdecks are organized in a hierarchical way.
+This hierarchy is very important.
+As an example, let us find the value of the label-color
.
First, the button will perform a direct lookup in its attribute. If it finds a label-color
in its attribute, it will use it. If it does not find it, it will ask for its default-label-color
. The button will ask its parent entity for the default-label-color
.
So the Page will search for a default-label-color
in its attributes. If it finds it, it will use it. If it does not find it, it ask its parent entity.
The Deck will search for a default-label-color
in its attributes. If it finds it, it will use it. If it does not find it, it ask its parent entity.
Finally, the Cockpit will return a default-label-color
. If there is no value for the default-label-color
, Cockpitdecks will issue an error. It simply means that there is no default value for that attribute and that a value must be supplied by the user in the definition of the button.
Cockpitdecks introduced the concept of color schemes or Themes. A theme is an additional parameter (string) that is added to the attribute name being looked up. Let us see in a practical example.
+Cockpitdecks attempts to provide a day and a night theme. The attribute cockpit
can be set to day
(or light
) or night
(or dark
) to specify which theme to use.
cockpit-theme: dark
+
The effect is that in night
(or dark
) theme, default values prefixed with dark-
will be favored. If no default value prefixed with dark-
is found, the regular default value is fetched.
If the theme dark
is defined, the attribute dark-default-label-color
is first searched, and if not defined, the default-label-color
is retuned.
The word dark
is arbitrary. It can be any string. But the attribute named <any-string>-default-label-color
will be searched first, and if not found default-label-color
will be used.
Note
+Ultimately, this scheme can be extended to any theme name value, like airbus, or barbie. However, it is advisable to limit theme default values to global appearance parameters like colors, fonts, textures, and sizes.
+There is no automatic theme switch, but a special activation allows for theme setting.
+Cockpitdecks behavior and deck appearance are driven by a list of Yaml config action files always called config.yaml
.
Sometimes, configuration values can be specified at different level for a given entity.
+At the highest level, a Cockpit will start with a set of default values provided in its internal code.
+It will then loads additional parameters in a global resource configuration file. That file is the same for ALL aircrafts. The config.yaml file is located in the home directory of Cockpitdecks software, in the resources folder. It cannot be changed.
+Next, Cockpitdecks will look for an aircraft specific configuration file, in the deckconfig folder of that aircraft. It will load the config.yaml file of that aircraft, and default values loaded from there will apply to that aircraft only. That configuration file can be used for cockpit designer to specify their requirements and preferences.
+A Deck will start with the configuration attributes supplied by the Cockpit. The Cockpit uses the configuration passed in the the global, aircraft-level configuration file.
+A deck will load a Layout. When doing so, the deck may read an optional configuration file located in the folder of the Layout it will use. The attributes specified in the layout configuration file will take precedence over those at the deck level.
+In addition to button definitions, a Page contains other page-level attributes.
+When a page includes another page, their respective attributes get melted (combined). The attributes of the included page overwrite the attributes of the base page.
+Since a page can include more than one other page, the attributes of the included page are added (on top of) the attribute of the base page and other included pages. But since the order of page inclusion is not specified, attributes may be piled up in any order.
+In other words, it is advisable to not include any page-level attribute in a page that will be included in another page, it may lead to unexpected behavior or presentation. It is safer to limit inclusion to the buttons
attribute, where buttons of main page and included page are merged together.
Here is an example how attribute value is looked up for a button's bg-color
.
The index
attribute is a mandatory attribute of a Button. It designate a very precise button on the deck. Hence, it defines what the button is capable of performing and how it will be rendered.
Button Index is specified in the Deck Type definition of the deck.
+Streamdeck Mk.2, XL, Mini are composed of square icon keys. Image sizes vary with models.
+Streamdeck + (Plus) as 8 square keys, 4 knobs, and 1 larger LCD capable of touch interactions.
+Streamdeck Plus encoders are aligned at the bottom of the deck and have indices e0 to e3.
+Streamdeck Plus has a 800x100 pixel touchscreen between the keys and the encoders.
+LoupedeckLive has 6 knobs, 12 square keys (90x90), and 2 side LCD (60x270).
+There is an additional row of 8 push button labeled 0 (dotted-circle) to 7.
+Both LCD and all 12 keys form a larger (480x270) LCD capable of touch interaction.
+In an alternate presentation, side LCD can be considered as 3 individual buttons each.
+To simplify, we assume in this case that all 6 side buttons are square (60x60). Space between these button is filled with default color, image, or pattern.
+XTouchMini has 8 encoders with 8 "multi-led" displays, and 16 buttons with LED.
+There is a slider and two more buttons on the side. These two buttons were meant to be used as "page" switches between 2 pages labeled A and B. For simplicity, we chose to not change the use of these two buttons and they should be programmed as Page Loader activation. The currently loaded page can be highlighted, like on the above photograph, Page A is loaded.
+ + + + + + + + + + + + + + + + + + + + + + +The Representation of a button determine how it will be displayed on the deck device.
+The representation depends on the capabilities of the button on the deck. There is a list of valid representations or a given button on a deck. A image or icon cannot be displayed on a LED-only button.
+In the button definitions, the presence of a specific attribute with determine how the button gets represented on the deck. The name of that attribute is the key word of the representation. For example:
+icon
: To show a image imageled
: To turn a LED on or OFFannunciator
: To display a complex image as an iconThe first attribute mentioned in each section below determines the type of Representation (icon
, text
, multi-icons
, etc.) If more than one representation is found, or a representation that is not valid for the given button, a warning message is reported and the button does not render anything.
If no Representation is found, a warning message is reported and the button is assumed having no representation. For example, a X-Touch Mini slider has no representation. To suppress the warning message, the representation
attribute can be used and set to false
.
- index: slider
+ name: SLIDER
+ type: slider
+ representation: false
+
will not issue any warning message.
+A representation often has attributes that customise its behavior.
+All representation-specific attributes must be declared under the attribute that declares the representation: (See attributes in pink in picture below.)
+This is a requirement to differentiate attributes at the button activation level (not indented, in blue or green), and button representation (indented, in pink)
+Here is a list of currently available, general purpose representations.
+Please refer to the following pages for deck specific representtions.
+Deck specific means those representations on one deck will (probably) not work on another deck.
(To be used as model for alternate development.)
+dataref: dataref-path
Path to a dataref that is interpreted to determine whether the value is managed.
+If the value is managed, the value can be displayed as a text string in an alternative way depending on the text-alternate
value.
text-alternate: dash=4
: Represent managed value by a set of -
. Default is 3 dashes.
text-alternate: dot
: Represent managed value by a single dot •
.
- index: 0
+ type: none
+ name: FCU Airspeed display
+ label: SPD
+ text: ${sim/cockpit2/autopilot/airspeed_dial_kts_mach}
+ text-format: "{:3.2f}"
+ text-color: khaki
+ text-size: 24
+ text-font: Seven Segment.ttf
+ text-position: cm
+ text-bg-color: (40, 40, 40)
+ managed:
+ dataref: AirbusFBW/SPDmanaged
+ text-alternate: dash
+
In example above, speed managed mode, if AirbusFBW/SPDmanaged
dataref value is non zero, the text will display ---
. Otherwise, it will display the air speed.
dataref: dataref-path
Path to a dataref that is interpreted to determine whether the button or key is guarded (protected against unintentional use by a cap or lock). If guarded, it can be displayed in an alternative way depending on the options value.
+type
: Protects the button with a full red cover (type: full
) or a see-through grid (type: grid
)(cover is the default).
color
: Color of the guard. Default is red for cover, and translucent red for grid.
label: RAM AIR
+ guard:
+ type: grid
+ color: black
+ dataref: ckpt/ramair/cover
+ # 0=closed, 1=opened
+
Guarded buttons or keys need to be pressed twice to activate, the first activation lifts the guard, the second one acts normally. To replace the guard, a long press of more than 2 seconds is necessary to replace (close) the guard.
+Long Press
+Make sure long press lasts 2 seconds or more, otherwise the button will be activated!
+Typical buttons display an information in a static way, an icon or a LED that is updated when a status or a value has changed.
+Animation is a button representation option that consists of continuously sending representation updates to continuously change the button's appearance.
+For example, in its simplest form, a icon animation consist of sending a different images to a key at regular interval, cycling to a list of images (vey much like a GIF animation…).
+Another simple animation consists of making an icon «blink» on or off. A more complex animation can consist of a parametrized drawing, an image is drawn at each iteration and sent to a key.
+Animations are automatic. They should not be confused with button appearance updates that occur automagically when underlying button values change.
+Most of the time, the value button determine if the animation runs. When the value of the button is On, the animation runs. When Off, the animation does not run and may displays an alternate representation.
+An icon-based animation is a procedure that changes the icon to display at regular internal.
+The icon to display is specified through its index value in the list of icons available to the button (through the multi-icons
attribute).
icon-animation:
+ - ICON_FILE_1
+ - ICON_FILE_2
+
Multiple icon files are displayed in sequence automagically when the button is On.
+icon-off: ICON_FILE_NAME
The icon to display when the button is Off. If there is no icon-off, the first icon in the icon-animation list is used.
+speed
Time in second an icon is displayed before displaying the next one.
+A blinking animation is an procedure that forces some of all part of a Representation alternatively On and Off and provoque a rendering update after changes, leading to a blinking button effect.
+In this case, the animation controls and changes the value of the button, switching between On and Off states. The representation changes accordingly.
+A Drawing animation is a parametrized drawing that uses a single parameter value (for exemple the button's value). When the value changes, the procedure optionally uses a tweening algorithm to progressively change the value from the old one to the new one.
+As a proof of this concept, the FollowTheGreens Representation displays a portion of taxiway centerline with "flashing" lead light when it is activated.
+Animations do not need to be fast. As another proof of concept, the Weather representation pictures a Metar report on a icon. The representation is updated each time the Metar is updated (about every 30 minutes). It is another form or use of animation.
+ + + + + + + + + + + + + + + + + + + + + + +An Annunciator is a special image used for display on a deck key.
+An Annunciator image is build dynamically from its definition and from data coming from X-Plane. Airbus airliners extensively use annunciator buttons.
+Annunciator do not specify what they do, this is done by the button activation definition. Annunciator only address the representation of the button, the content of the image displayed on a deck key.
+On a deck, the representation of keys that accepts images can either be
+Annunciators exits in 3 sizes:
+Annunciator can display from 1 to 4 different data or information on a single key. Depending on the annunciator model, data is displayed on two rows, in two colums.
+Each portion of an annunciator that can be used to display information is called an (annunciator) part. In an annunciator of type A, there is only one part called A0. In an annunciator of type E, there are three parts, E0, E1, and E2, arranged like shown on the above illustration.
+Annunciator of type F can display 4 different informations. The button underlying such an annunciator has therefore 4 distinct values.
+Each annunciator part is defined independently of the other parts.
+In a part, displayed information is either
+ - index: 5
+ name: A/THR
+ type: annunciator-push
+ annunciator:
+ size: medium
+ model: B
+ parts:
+ B0:
+ color: lime
+ led: bars
+ dataref-rpn: ${AirbusFBW/ATHRmode}
+ B1:
+ text: A/THR
+ color: white
+ size: 60
+ dataref-rpn: "1"
+ command: AirbusFBW/ATHRbutton
+
The Annunciator defintion starts at the annunciator:
attribute.
Code letter from A to F to specify how annunciator parts are organised on the annunciator.
+Annunciator size: large, medium or small. Full size is a large size that occupies the whole square button. Size mini exists but is practically not used.
+The part attribute can be used to group all part definitions.
+Each part is addressed by the name of the part: A0, B0, B1, etc. The content is the part definition.
+ B0:
+ color: lime
+ led: bars
+ dataref-rpn: ${AirbusFBW/ATHRmode}
+
The part definition must contain either a text
attribute or a led
attribute.
Each part of a Annunciator has its own value. The value of a part is computed like the value of a Button, from datarefs and/or formula.
+A part is either lit or not, On or Off. Either status can be represented by supplying background and foreground colors.
+About Off Color
+When off, Vivisun style annunciators remain black what ever is asked for dimmed or off-color.
+When off, Korry style annunciator will exhibit either a dimmed representation of the text (or LED, or what ever is displayed) or a "off-color" representation of it.
Each part of a Annunciator has its own value. The value of a part is computed like the value of a Button, from datarefs and/or formula.
+Single dataref used for value.
+Formula used to determine the value of the part.
+There are two styles of annunciators. Both are named after major brands of annunciator manufacturer. Annunciators appears differently according to their style.
+The first style is Korry (annunciator-style: k
), where the annunciator appears like a translucent window with back light. When the annunciator is not lit, the text or drawing is slightly readable on the display. When lit, the text appears to glow.
The second style is Vivisun (annunciator-style: v
). When the annunciator is not lit, it has the color of the button (usually black) and no text is readable. When lit, displays on a Vivisun annunciator are sharp, very much like a "retina display" (high resolution display).
Both styles truthfully reproduce keys on decks. Combined with the adjustment of the intensity of the deck back light, they provide a real immersive experience.
+annnunciator-style
can be defined at the Cockpit, Deck, or Page level.
Annunciators can optionally be protected by plastic cover guards.
+dateref
Dataref path to value driving the guard status (open or protected).
+type
Cover or grid
+color
Color of guard. Defaults to red.
+Translucent color (with alpha, or transparency channel) can be supplied.
+color: (255, 0, 0, 100)
Is a translucent red color (r,g,b,a), a=0=transparent, a=255=full opaque.
+icon: ICON_FILE_NAME
An image file is loaded on the deck key if it is capable of displaying images.
+icon: isi
+frame:
+ frame: frame_image.png
+ frame-size: [256, 256]
+ content-size: [128, 128]
+ content-offset: [64, 64]
+
A frame
is a special "background" image that is first loaded, and the icon itself is laid over the background image. In the above example, icon isi
will be resized to 128x128px and placed (pasted, laid over) at position (64, 64) in the frame image.
The purpose of framed icon is to provide a uniform icon representation (the frame) with varying inner content (the icon itself).
+It is different from a textured background because it allows for icon placement and resizing before pasting over the underlying image frame.
+text: "SOME\nTEXT"
An image file is created with a uniform background color or texture and text laid over.
+The text laid over the button should not be confused with the label. The text laid over is additional to the label, and can be dynamic to display a changing value like the heading of the aircraft or the amount of fuel left in a tank.
+text-bg-color: lime
Background color of the image or icon where the text is displayed. Default background color is cockpit color.
+text-*: value
Values for font, font size, color, and position of the text on the image.
+It is possible to use subsitution of coded string in text values:
+${dataref-path}
is replaced by the scalar value of the dataref pointed by dataref-path
.${formula}
is replaced by the value computed in the formula
.${state:name}
is replaced by the scalar value of the button' state name
.Note: A Text string value is not a formula and is not evaluated. Above strings are simply substituted.
+text: ${formula}
+text-format: 4.2f
+formula: 3.14 2 ${dataref-path} * *
+
Will produce an icon with text value "3.14
" text in the middle.
multi-icons
multi-icons:
+ - ICON_FILE_1
+ - ICON_FILE_2
+
Multiple icon files are displayed according to the value of the button.
+For example, for an OnOff activation type there may be two icons for On and Off positions; for a UpDown activation type, there may be one icon for each stop position.
+No attribute.
+Multi
+Cockpitdecks offers representations like multi-icons, multi-texts, and even multi-buttons always on the same pattern. The multi- keyword means that there are several representations of the same type available in the button definition. The value of the button determine which one if chosen for representation. If the value of the button does not point at a valid index in the list, the representation is ignored.
+multi-texts
multi-texts:
+ - text: Option 1
+ text-color: green
+ - text: Option 2
+ text-color: amber
+ - text: ${aicraft/some_value}
+ text-format: "Limit reached {4.1f}"
+ text-color: red
+ text-font: DIN Bold
+ text-position: tr
+ formula: ${dataref_for_text_selection}
+
A Multitext attributes contains a list of IconText-like attributes (a list of text block) where each text block can contain attributes like in an IconText text block.
+A single text block is selected according to the value of the button.
+In the above example, the formula ${dataref_for_text_selection}
return 2, the second text block
text: ${aicraft/some_value}
+ text-format: "Limit reached {4.1f}"
+ text-color: red
+ text-font: DIN Bold
+ text-position: tr
+
will be selected and displayed as a IconText.
+None
+The selection of the text block must be performed by a formula and not a dataref.
+When a formula is present in the attributes of a button, it is always favored over a list of datarefs, even if the list contains only one dataref. (If there a button uses multiple datarefs and there is no formula, the value that is returned for that button is a dictionary of all dataref values.)
+led: led
Turns a single LED light On or Off depending on the button's value.
+led: colored
color: orange
Turns a single LED light On or Off depending on the button's value. The color of the LED is determined by the color attribute.
+The color
attribute can use a formula to determine the color (single hue value in 360° circle.)
Switches are drawings often used by OnOff activations that can be used in replacement of icons.
+Switches is a drawing of a simple two or three-way switch.
+Circular switches are multi-value rotation switches or selectors.
+Push switches are simpler two state push button.
Some decks have particular LCD displays. Cockpitdecks designed specific activations and representations for those. See here:
+ +Above switches are special instances of dynamically drawn representations.
+There are other dynamically drawn represetations for displaying data, or weather information.
+The sky is the limit.
+Each Representation has a is_valid()
method that checks whether all necessary attributes or parameters are available to it and valid. If the validity function fails, a warning is reported and the button is not rendered. The inspect keyword used to verify the validity of the representation is valid
.
Each Representation has an describe()
method that explains what it displays in plain English. The inspect keyword used to describe the representation is what
.
ColoredLed buttons are color capable led behind a transparent or mask button.
+They are either on or off, with a RGB color.
+colored-led: blue
+
icon-side: ICON_FILE_NAME
An IconSide is a special icon for LoupedeckLive devices, used on either side of the main panel. IconSide have particular display capabilities to cope with their specifics, sizes, and their positions that allow to display information regarding the nearby encoders.
+labels
Labels that are displayed on the icon.
+label-positions
Label anchor position expressed in percentage of the 100% height of the side image.
+Note: There might be similar icons to control the display of other, larger display like the Streamdeck Plus bottom LCD display.
+Some decks exhibit displays that are larger than a key with and iconic representation. Those displays often have touch and swipe capabilities. This led to design activations and representations specific to these larger displays to be used with your favourite flight simulation software.
+++Please note, for example, that the LoupedeckLive deck has a unique central display screen accepting touches and swipes. A plastic grid cover gives the illusion that there are two vertical side screens and 12 « keys » in the middle, but underlying is a unique 480 × 360 pixel screen. Each key is a 90 × 90 pixel portion of that screen.
+
Larger screens can be used in two different ways:
+In the later case, the specificity of the display is not apparent, and resulting buttons are treated as regular keys with iconic image display (with different sizes sometimes.) This is called a Mosaic.
+When considered as a single larger display, it is difficult to remain generic since each display will have special size, location, and behavior. Cockpitdecks buttons assigned to those specific display are therefore also very specific.
+Having no activation at all to use those display solely for displaying purposes is always an option. However simple activations can make the passive display a lot more enjoyable.
+For exemple, if the display is capable, touching or swiping the display can be used to change its content. On startup, display heading, swipe left, display speed, swipe right display heading, etc.
+Touch is similar to button press activation and can be used as such.
+Swipe returns movement start and end position and timing. These values can be interpreted to model a limited set of movements like swipe left, right or up, down. Raw values can also be used as an increasing or decreasing sliding cursor.
+Given the sizes of each display, representations fitting those displays will always remain very specific.
+The highly specific Airbus FCU representation reproduces the central display with all possible modes.
+The Airbus FMA displays the five annunciators on top of the Primary Flight Display (PFD).
+There are two modes of display. The first one make use of a larger, horizontal display and shows all five annunciators next to each other. The second one use five keys with iconic display and show one annunciator on one key. In both cases, data necessary for display is fetched only once, the first annunciator being the master one with all data, other annunciators are slave ones and fetch their data from the master annunciator.
+Airbus FMA display is a pure display with no activation associated with it.
+On LoupedeckLive decks, vertical displays exploit their proximity to the lateral encoder dials to present direct encoder feedback. For example, next to the QNH adjustment encoder, the current atmospheric pressure is displayed. Pushing the encode switches between Standard pressure and local ambiant pressure.
+Image or drawn icons (especially text messages) are also an alternative way to decorate those displays. One can imagine displaying ATC instructions on a tape display, with swipe actions to acknowledge messages.
+ + + + + + + + + + + + + + + + + + + + + + +ColoredLed buttons are color capable led behind a transparent or mask button.
+They are either on or off, with a RGB color.
+colored-led: blue
+
The Elgato Stream Deck Neo has two small colored led on each side of the LCD display.
+Some decks exhibit displays that are larger than a key with and iconic representation. Those displays often have touch and swipe capabilities. This led to design activations and representations specific to these larger displays to be used with your favourite flight simulation software.
+++Please note, for example, that the LoupedeckLive deck has a unique central display screen accepting touches and swipes. A plastic grid cover gives the illusion that there are two vertical side screens and 12 « keys » in the middle, but underlying is a unique 480 × 360 pixel screen. Each key is a 90 × 90 pixel portion of that screen.
+
Larger screens can be used in two different ways:
+In the later case, the specificity of the display is not apparent, and resulting buttons are treated as regular keys with iconic image display (with different sizes sometimes.) This is called a Mosaic.
+When considered as a single larger display, it is difficult to remain generic since each display will have special size, location, and behavior. Cockpitdecks buttons assigned to those specific display are therefore also very specific.
+Having no activation at all to use those display solely for displaying purposes is always an option. However simple activations can make the passive display a lot more enjoyable.
+For exemple, if the display is capable, touching or swiping the display can be used to change its content. On startup, display heading, swipe left, display speed, swipe right display heading, etc.
+Touch is similar to button press activation and can be used as such.
+Swipe returns movement start and end position and timing. These values can be interpreted to model a limited set of movements like swipe left, right or up, down. Raw values can also be used as an increasing or decreasing sliding cursor.
+Given the sizes of each display, representations fitting those displays will always remain very specific.
+The highly specific Airbus FCU representation reproduces the central display with all possible modes.
+The Airbus FMA displays the five annunciators on top of the Primary Flight Display (PFD).
+There are two modes of display. The first one make use of a larger, horizontal display and shows all five annunciators next to each other. The second one use five keys with iconic display and show one annunciator on one key. In both cases, data necessary for display is fetched only once, the first annunciator being the master one with all data, other annunciators are slave ones and fetch their data from the master annunciator.
+Airbus FMA display is a pure display with no activation associated with it.
+On LoupedeckLive decks, vertical displays exploit their proximity to the lateral encoder dials to present direct encoder feedback. For example, next to the QNH adjustment encoder, the current atmospheric pressure is displayed. Pushing the encode switches between Standard pressure and local ambiant pressure.
+Image or drawn icons (especially text messages) are also an alternative way to decorate those displays. One can imagine displaying ATC instructions on a tape display, with swipe actions to acknowledge messages.
+ + + + + + + + + + + + + + + + + + + + + + +led: encoder-leds
(Specific to the X-Touch Mini Encoders.)
+MultiLeds are LED-based display that use more than one LED for reporting information.
+X-Touch Mini encoders, for example, are surrounded by 11 LED that can be lit individually.
+led-mode: fan
or led-mode: 2
; name or number
Valid modes are:
+The value of the button determine how many leds will be displayed (0 to 11).
+X-Touch Mini MACKIE MODE
+To send feedback instruction to the deck, two modes of interactions are available: Direct mode, and Mackie Mode. Cockpitdecks uses Mackie Mode which makes deck interaction easier and standard through the MIDI protocol. However, in Mackie Mode, only 11 of the 13 available encoder LEDs are accessible. It is not possible to access LED 0 and 13, only 1 to 12.
+If nothing is specified, raw button value is used.
+If value_min
and value_max
are specified in the encoder attribute, the Encoder representation performs a linear mapping between (value_min
, value_max
) and the range of valid values (0, 10).
A Warning is issued if the value is out of the range 0-11.
+ + + + + + + + + + + + + + + + + + + + + + +Cockpitdecks allows to represent a dataref value on a simple chart, or rather, a simple Sparkline. Up to three Sparklines can be combined on a single chart icon.
+A Sparkline is a chart element that plot a single variable over time.
+A Sparkline keeps a number of points to be plotted.
+The maximum number of point that can be plotted is either directly supplied, or determined by the time width of the chart. (Points older that the oldest point on the chart are discarded.)
+The list of time-series data can be plotted as
+A Sparkline is based on a value like a button value.
+The value is either fetched at regular interval or updated each time it changes.
+Therefore, a chart will be updated either at regular interval, if at least one of the data is fetched at regular internal, or whenever the dataref value has changed.
+There is a maximum update/refresh rate fixed at 4 Hz (¼ of a second.)
+The horizontal axis of charts is always the time.
+The maximum time that is displayed on the total width of the chart can be determined either by directly supplying a maximum time width, or by supplying a number of points to keep, spaced at a regular interval.
+Charts a little icons that can involve a lot of CPU cycles, from dataref collection, change detection, graph data update and then graph update.
+We limit the update of graphs to 4 Hz maximum (that is 4 times per seconds).
+There is a limit on the number of Sparklines (graphs) in a single icon: 3.
+There is also a limit on the total number of Sparklines that can be use at one point in time: 10, all displayed decks combined.
+Cockpitdecks provides a few, drawing-based, icons and animations to complement your cockpit or dashboard.
+The following icons or animations provide each a limited set of customization attributes. Please recall that Cockpitdecks is not a drawing tool, but rather a template tool with custom icons ready to be used with a few customization attributes.
+In each case, we will detail its intended use and the limits of the icon provided.
+Also, these special icons exhibit particular design techniques that can be extended by Cockpitdecks Representation developers.
+Work In Progress
+These icons are currently basic but do provide their function.
+They have limited customization, but these can be added over time later if necessary or requested.
A Tape is a type of display that appears like a tape being slid under the screen. Here are famous display tapes on an Airbus Primary Flight Display:
+Tapes are often fitted With colorful marks that represent critical values for the indication being displayed.
+Display tapes should not be confused with duct tapes, often used to fix aircrafts.
+Duct tapes have one configuration attribute: duct-tape-color
with default value silver-grey
.
Cockpitdecks provides a small set of customizable gauge. Since gauges are rendered on small, often square, LCD screens, they are very limited in detail.
+One gauge displays one value, and it updated when the value change.
+A special gauge is the heading gauge (called rose
) which show the heading on a compass. Compass can be adjusted North, on autopilot value, or on actual aircraft value (compass or true).
Cockpitdecks provides a limited set of time-based display charts, also often called sparklines.
+ + + + + + + + + + + + + + + + + + + + + + +A few set of special buttons are dynamically drawn based on attributes.
+Attributes are numerous to allow for design flexibility, however default values will always provide a usable representation.
+The idea of drawn buttons came after the flexibility discovered when designing Annunciators. All annunciators are drawn buttons: Texts, frames, basic icons…
+A Switch is a drawing of a two or three-way switch on an image key.
+Switches are often used by On/Off activations.
+They can be used in replacement of an icon.
+Ticks are marks on the side of the switch to label corresponding positions. The tick underline is the visual line line that connect all ticks.
+ switch:
+ switch-style: 3dot
+ tick-underline: true
+ tick-label-size: 36
+ tick-label-font: DIN Bold
+ tick-labels:
+ - "ON"
+ - "MID"
+ - "OFF"
+ options: 3way,horizontal
+
Switches, Circular Switches, and Push Switches have numerous attributes in common to control their appearance. See Circular Switches for a list.
+options: 3way
Defines a switch with 3 positions, 2 extremities, and one middle position.
+options: horizontal
Draws and manipulates the switch horizontally rather than vertically.
+options: hexa
Draws an hexagonal base to mimic Airbus switch inserts and fixation instead of a round base (default).
+options: invert
Inverts On and Off positions.
+A Circular Switch is a rotating knob/switch used to represent a rotation switch. It is displayed on an image key. Circular switches are often used by Up/Down activation to cycle and bounce through the set of possible values.
+They can be used in replacement of multi-icons.
+ circular-switch:
+ switch-style: normal
+ down: 20
+ left: 20
+ tick-from: 135
+ tick-to: 315
+ tick-space: 20
+ tick-underline-width: 12
+ tick-color: red
+ tick-underline-color: red
+ needle-color: lime
+ needle-length: 130
+ tick-labels:
+ - "0"
+ - "1"
+ - "2"
+ - "3"
+ - "4"
+ - "5"
+
button-size
button-color
button-off-color
witness-fill-color
witness-stroke-color
witness-stroke-width
A PushButton is a simple button that can be used to trigger a command. It can be On or Off, and it's state can be reflected graphically by adjusting its color for instance.
+Later.
+Knobs are circular rotating buttons used to set values by rotating the button clockwise or counterclockwise. Although they can be drawn and « turn » according to dataref values, they cannot currently be used with activations to trigger their rotation. Real, physical rotation knobs must be used instead. (Mimicking a rotation knob with a push button is a difficult task that requires awkward manipulations such as long pushes. We may later offer a possibility to allow for rotation knows on icon button, because the surface of some icon button (LoupedeckLive) reacts to touch and swipes. It would therefore be possible to detect precisely where the button was touched (left, right, up, center…) and assign activations accordingly.)
+So we shall just say that Knob icons can be used as simple push button, with an alternative representation.
+A few set of special buttons are dynamically drawn based on attributes.
+Attributes are numerous to allow for design flexibility, however default values will always provide a usable representation.
+The idea of drawn buttons came after the flexibility discovered when designing Annunciators. All annunciators are drawn buttons: Texts, frames, basic icons…
+A DataButton is a particular case of a display only button.
+A DataButton displays four informations:
+ - index: 4
+ name: Fuel Level
+ type: none
+ label: Fuel
+ label-size: 10
+ label-position: ct
+ data:
+ icon-name: "gas-pump"
+ data: 75.4256
+ data-format: "{:02.0f}"
+ data-font: DIN Condensed Light
+ data-size: 24
+ data-unit: "%"
+ data-progress: 100
+ data-trend: 0
+ dataref-rpn: ${sim/aircraft/fuel_level} 10 *
+ bottomline: Go Faster
+
Data button representation aims at providing a dashboard-like single value highlighted in a deck key image, very much like common web dashboards.
+Decor representation displays simple connected lines to populate unused icons. They can be used to display visual helper lines that connect annunciators (bleed air, hydraulics, etc.) The idea behind Decor icons is to provide a quick alternative to blank icons when filling large decks with numerous keys.
+Decor icon are governed by two parameters type
and code
. The type is a category of drawings. The code determine which drawing will be made in that category.
type: line
Decor icons of type line
display a single horizontal or vertical line, and corner angles. The code
determine which line get drawn.
type: line
+code: H
+
type: segment
Decor icons of type segment
display segments that are present in the code
attribute.
For example:
+type: segment
+code: BGNSIL0123
+
will light (turn on) segments B, G, N… 3, which correspond will result in a drawing like the one proposed by the H
code in type line
above.
width: 10
Width of the line.
+color: red
Color of the line.
+The aircraft representation displays the name of the aircraft (ICAO type designator) located in the dataref: sim/aircraft/view/acf_ICAO
. All 4 (or more) characters are fetched and displayed in the icon. (We currently limit fetching the first four characters only, which should be sufficient for ICAO aircraft code designator.)
The representation attribute is
+ aircraft:
+ text-font: B612-Bold
+ text-size: 32
+
If a set-dataref
is present, the aircraft representation increases the value of that dataref by one each time the aircraft name changes in the sim/aircraft/view/acf_ICAO
. This can be used by other button or by Cockpitdecks itself to be notified of an aircraft or aircraft model change.
(Please refer to the dedicated Weather Representation page.)
+The WeatherButton is a special data button that displays METAR information of the station closest to the aircraft in a small, iconic representation.
+ - index: 8
+ name: METAR
+ type: weather
+ station: OTHH
+
(To do. Cycle through forecast each time button is pressed.)
+Multi-Buttons and Mosaic allow simultaneous representation of several buttons.
+Multi-buttons selects one button to represent from a list of buttons.
+Mosaic represent them all at once, simultaneously.
+A Mosaic is a trick used to split a large button into smaller ones.
+A Mosaic can, in some regards, be considered as a special case of a Page. Yes, a small page with its own set of individual buttons.
+Very much like a Page, a Mosaic contains buttons, with their own behavior (activation) and rendering (representation). However, at the end, all button rendering are sticked together, like tiles on a mosaic, to render on the larger button (the mosaic).
+Typical example of Mosaic are: LoupedeckLive side buttons: They are larger, 60x270 pixels, and can be "split" into smaller buttons, like a column of 4 60x60 buttons, with 10 pixels between each. A Streamdeck Plus touchscreen, which is 100x800 pixel in size, can either be split into 8 buttons of 100x100 each, or less buttons with more space between them.
+Mosaic representation has been designed so that it requires the minimal adjustment to Cockpitdecks. Here are some design constraints.
+When touching the Mosaic, we need to know where the contact occurred because we have to determine which tile was activated. Therefore, the only valid activation for a Mosaic is swipe event, because the swipe event reports the coordinates (x, y) where the contact occurred.
+Similarly, for tiles, for simplicity, we will only allow push and long-push events. We may, in future releases, allow for more events but cases will be requested before we make Mosaic too complicated.
+In a nutshell, the swipe activation of the Mosaic gets transformed into a push, or long-push representation of a tile.
+The Mosaic representation will be an image. As its name says, it will be composed of smaller tiles, that are also images.
+Therefore the representation of a button inside a Mosaic, a tile, must produce an image, like icon, all drawing representations (that indirectly create images), etc.
+In a nutshell, the representation of the Mosaic is built from the representations of all tiles that are put together at their proper offset position.
+Here is an example of Deck Type definition of a mosaic for the LoupedeckLive left screen.
+ - name: left
+ action:
+ - swipe
+ feedback: image
+ dimension:
+ - 60
+ - 270
+ layout:
+ offset:
+ - 120
+ - 59
+ options: corner_radius=4
+ # The left button is composed of 3 sub-buttons:
+ mosaic:
+ - name: 0
+ # prefix of mosaic buttons should match name of parent mosaic
+ # names will be left0, left1, left2
+ prefix: left
+ action:
+ - push
+ feedback: image
+ dimension:
+ - 60
+ - 60
+ repeat: [1, 3]
+ layout:
+ offset:
+ - 0
+ - 15
+ spacing:
+ - 0
+ - 30
+
In the above example, the left 60 × 270 pixel LCD screen will be split into 3 60 × 60 pixel icons with 30 pixels empty space between themselves.
+One Deck Type can define one or more mosaic for its large LCD displays. For example, a 800x100 pixel large LCD can propose a Mosaic of 4 x 200x100 pixels.
+If a user prefers an alternate Mosaic of 8 x 100x100 pixels, it is necessary to create another Deck Type, with another name, where the alternate mosaic is expressed.
+The same device, whether physical or "virtual" (through a Web Deck), can be declined in several Deck Types to offer a modular representation to Cockpitdecks.
+ - index: left
+ type: mosaic
+ label: MosaiK
+ mosaic:
+ tiles:
+ - index: m0
+ (...)
+
The activation (type
) must be mosaic
. This activation transforms the swipe event into push events.
The representation must be mosaic
. The representation collects the representation of each tile and compose the final image that is sent for display.
- index: left
+ type: mosaic
+ label: MosaiK
+ mosaic:
+ tiles:
+ - index: m0
+ name: RELOAD
+ type: reload
+ icon: RELOAD
+ label: RELOAD
+ label-position: ct
+(more clever and realist button later, this is a working placeholder)
+
(picture, later)
+The multi-button representation defines a list of buttons.
+The value of the main hosting button determine which button gets chosen from the list (index value).
+ + + + + + + + + + + + + + + + + + + + + + +Toliss Airbus Aircrafts A319, A320, A321, and A340 share numerous functions, with particularities or specialties. They share a common set of functions, displays, or dataref values. This has led to the development of very specific buttons representation.
+These buttons are highly specific and would probably not be usable in other aircrafts. However the very specific code used to produce these buttons is an example for alternative development.
+ToLiss FCU representation is actually a set of representations for Loupedeck LoupedeckLive side LCD display. As shown on the capture below, it vertically presents FCU data next to the encoders.
+There also is a horizontal version for the Stream Deck + horizontal display.
+The specific ToLiss FMA representation is made for long horizontal displays, like Stream Deck + (plus) LCD display.
+Page Switch
+It is easy to configure the LCD screen to change page between "FCU" and "FMA" allowing both screen to co-exist.
+In the FMA page:
+ - index: touchscreen
+ type: page
+ page: fcu
+
and in the FCU page:
+ - index: touchscreen
+ type: page
+ page: fma
+
The FMA display can also be used to display a single FMA on a smaller square icon. 5 small square icons can be used to display all 5 FMAs.
+It is also possible to display a single FMA (center), and loop through all FMAs by pressing on it.
+Examples of such configuration are provided for ToLiss aircraft and can be used to develop alternate display on smaller decks.
+ + + + + + + + + + + + + + + + + + + + + + +Cockpitdecks offers different types of Weather Representation, mainly on icons.
+These Representations have led to development of highly customized activations and representations to exhibit the potentials of Cockpitdecks.
+While some Representations remain highly generic, like graphical representation of METAR at the closest station, some others are highly specific like those that represent X-Plane simulated weather.
+There are two sources of information for weather:
+The WeatherMetarIcon provides the real life Metar currently in use at a location in the simulator.
+If the location is provided through an attribute, it is used and never updated. If no location is provided, the current aircraft location is used. If the aircraft is cruising, the location is updated approximatively every 5 minutes, or when the closest Metar source changes.
+If no aircraft location is available, a default location is used (currently EBBR, Brussels Airport, Belgium).
+weather-metar:
+ station: LFBO
+ update: 30 # minutes
+
Reports the current real life weather at LFBO. If the location is not changed, the Metar updates every update
minutes.
Metar is from external source
+The WeatherMetarIcon reflects the real Metar at the time of collection. It does not necessarily reflect the weather as simulated in X-Plane.
+X-Plane weather is flexible and proposed with several variant. We designed a few set of X-Plane specific button representation to present these data sets.
+In addition, X-Plane weather can be local or regional.
+X-Plane Weather
+X-Plane Weather is currently heavily modified by Laminar. The following representation may not work reliably and may need revisions.
+xp-weather-summary
+ mode: region
+
Provides the Real weather currently installed into X-Plane in a short, Metar-like summary.
+This is done by fetching a limited set of values from the weather-related datarefs (temperature, pressure, wind, weather conditions…:
+There are two modes: aircraft
and region
.
xp-real-weather
+ mode: region
+
Provides a detailed weather report from all weather-related datarefs.
+There are two modes: aircraft
and region
.
This representation fetches all weather-related datarefs from the simulator (wind layers, cloud layers, weather conditions, more than 100 datarefs) for a location or region and attempt to automagically generate a METAR from the collected data.
+To collect and monitor such an amount of datarefs, Cockpitdecks uses the X-Plane Web API, only available from release 12.1.1 onwards.
+ + + + + + + + + + + + + + + + + + + + + + +A button builds its representation from its value. The value of the button is computed from one or more dataref values returned by X-Plane and/or from some internal state variable values.
+A Button can have 0, 1, or more than one value in the special case of annunciators or Mosaic (A Mosaic can have two or more buttons represented inside.). Each annunciator part or each button inside a Mosaic has either 0, or 1 value.
+Each value of a button is either None (no value) or a numeric value (which is most of the time a floating point number). If a button has several values, its value is either a list of values or a dictionary of all individual values, each individual value being None or a number.
+Activations and Representations of the button knows how to manage the different values contained in the annunciator or Mosaic.
+A dataref is the name of a value used by the X-Plane simulator.
+The value can be a string, integer, or float value, either a single value or an array of (same type of) values. A dataref has a name to access it. Names are organized in a folder-like structure (namespace using /
separator). Some datarefs are read-only, some other can be written and modified. Names that start with sim/
are reserved for the simulator internal use.
Dataref name | +Value | +Description | +
---|---|---|
sim/cockpit/misc/barometer_setting | +Float | +Value of the atmospheric pressure at the aircraft location in inches of mercury | +
There are thousands of datarefs in a running instance of X-Plane. Datarefs drive almost everything in the simulator.
+When used by a button in Cockpitdecks, the value of a dataref is monitored. Its value is fetched from the simulator at regular interval (typically every second). When a dataref's value has changed, all buttons that depend on that dataref are notified of the change to, for example, update their appearance.
+To explore datarefs available in the simulator, there is a handy X-Plane plugin called DataRefTool. There are also a few web pages that collect, report, and present them so that they can be searched. The plugin allow not only for inspection of datarefs, but also for inspection and discovery of commands, strings that can be submitted to the simulator to perform some action.
+For simplicity, Cockpitdecks assumes all individual dataref values are floating point numbers or strings. The reason for this is that as today, X-Plane UDP only returns floating point numeric values for requested datarefs.
+Dataref values can change insignificantly very rapidly. To prevent dataref update and its consequences (update of the button value and its representation) with the value change insignificantly, dataref values can immediately be rounded before they are communicated to Cockpitdecks.
+Required rounding is expressed in the config.yaml
file.
The dataref-roundings
attribute is a list of (dataref-name, significant decimal digit after comma):
dataref-roundings:
+ sim/cockpit/autopilot/heading_mag: 2
+ sim/flightmodel/position/latitude: 8
+ sim/flightmodel/position/longitude: 8
+ sim/cockpit/misc/barometer_setting: 2
+
There is a global, application-level, dataref-roundings
located in the main Cockpitdecks resources folder. The file should never be changed or touched.
It is possible for the aircraft configuration developer to specify particular rounding needs in the main config.yaml
file in the aircraft deckconfig
folder in the same way. Aircraft roundings will take precedence on global roundings.
Dataref roundings only applies to datarefs fetched from X-Plane.
+Similarly to dataref roundings, it is possible to specify, on a dataref basis, the frequency at which Cockpitdecks will ask X-Plane to send values in UDP packets.
+The default values is between 1 and 4 times per seconds, 1 to 4 Hz.
+dataref-fetch-frequencies:
+ sim/cockpit/autopilot/heading: 10
+
The above configuration indicates that dataref named sim/cockpit/autopilot/heading
should be fetched 10 times per second (which is a lot, if not too much. Please recall that Cockpitdecks drives "deck" devices, not screen! Transfer of images to deck icons occurs on slow serial lines.)
Please refer to this Section for The special handling of string datarefs.
+Cockpitdecks manages its own set of internal datarefs.
+All datarefs that have a path or name that starts with a special key word are NOT forwarded to X-Plane but rather managed internally inside Cockpitdecks. Otherwise, they are not different from X-Plane datarefs. They can be set and used like any other datarefs.
+When a button produces an internal dataref, it's definition mention it clearly so that it can be used by other buttons.
+The current default prefix for internal datarefs is data:
.
set-dataref: data:my-local-variable
+
+# in the same or another button, it can be used like so:
+
+ formula: ${data:my-local-variable}
+
In the above example, the prefix data:
denotes internal datarefs. The name of the internal dataref is data:my-local-variable
.
Internal datarefs can be used as inter-button communication, to set a value in one button, and use or read it in another one.
+When a button cannot fetch its representation from X-Plane, it is possible to use some Cockpitdecks internal variables made available through the button state. Each button maintain its state, a few internal variables that can be accessed in formula.
+Some state variables are generic, and available for almost every buttons, like for instance the number of time a button was activated. Other state variables are activation specific and listed in the Button Activation page under the activation being used, like for example, the number of times a encoder was turned clockwise.
+Numeric internal values are accessible as ${state:variable-name}
in formula.
formula: {state:button_pressed_count} 2 mod
+
Most state attributes of a button come from the activation. Each activation has a specific set of state attributes. Among these state attributes, there is a more particular attribute, called the activation value, which is the most sensible value produced by the activation.
+For Cockpitdecks developers, all attributes used in the button, its activation, or its representation class instances are also available as state variables. In this case, the value of the attribute is returned with no type checking.
+class SpecialActivation:
+ ACTIVATION_NAME = "my-activation"
+ def __init__(self):
+ self.my_value = 8
+
When used:
+my-activation:
+ formula: ${state:my_value} 2 /
+
equals 4.
+From the above
+which may be called variables, a button provides a final value. This value is supplied to the representation that will provide the button feedback on the deck.
+The following sections details how the value gets computed from the above variables. The possibilities are:
+The value of the button is determined by a single dataref value.
+dataref: sim/weather/region/atmospheric_pressure
+
A Representation is driven by a single final value. However, it is possible to compute that final value form a list of dataref values, internal button attributes, and mathematical operations. This is done through a formula
attribute. The formula is written in Reverse Polish Notation, a method to write and execute operations on values. Since a formula allows for value transformation, a formula should always produce a value that is directly usable by a representation. The value of a button can be computed from data coming either from X-Plane (through dataref values) and/or from the button's internal state values.
Examples of formula
:
# Simple math (in reverse polish notation):
+formula: ${AirbusFBW/OHPLightsATA34[8]} 2 * floor
+
+# Constant 1; always 1; always True or On
+formula: 1
+
+# Insert 0 = true, 1 = false
+formula: ${sim/cockpit2/switches/avionics_power_on} 1 - abs
+
+# Boolean operation not
+formula: ${sim/cockpit2/switches/avionics_power_on} not
+
+# Boolean operation
+formula: ${AirbusFBW/OHPLightsATA34[8]} 4 eq
+
+# Formula used for display of a value
+formula: ${sim/cockpit/misc/barometer_setting} 33.8639 *
+text: ${formula}
+text-format: "{: 4.0f}"
+
+# The following two lines are equivalent; they both return the same value
+formula: ${sim/cockpit/autopilot/vertical_velocity}
+dataref: sim/cockpit/autopilot/vertical_velocity
+
Only one formula attribute can be used for a button or a annunciator part or a LargeButton button.
+The formula for computation is expressed in Reverse Polish Notation. The result of the formula is a numeric value (float value that can be rounded to an integer if necessary.) It is intimidating at first to write RPN formula, but once a user get use to it, it actually is equaly easy to write RPN formula and formula with parenthesis. In a nutshell, rather than writing:
+(8 / 2) + (4 × 5)
+
in RPN, we write:
+8 2 / 4 5 × +
+
We place the value we act upon first, then the operation we perform on those values.
+The following operator have been added:
+%
or mod
: Pushes reminder of division of last two elements, modulo.floor
: Round element to smaller integer value.ceil
: Round element to larger interger value.round
: Last element rounded to closest integer value.roundn
: Element rounded to last element of stack (forced to interger):1.2345 2 roundn => 1.23
abs
: Absolute value of last elementchs
: Change sign of last elementeq
: Test for equality of last two elements. Pushes 1 for True, 0 for False on the stack.not
: Boolean not operator, insert 1 if it was 0 or 0 otherwise.In formula:
+${dataref-path}
is replaced by the scalar value (converted to float) of the dataref pointed by dataref-path
. Example: ${sim/aircraft/fuel/tankleft}
.${state:name}
is replaced by the scalar value of the (current) button' state variable named name
. Names of available state variables depend on the activation; each activation lists internal state variables made available through the button' state. Example: ${state:activation_count}
.${button:cockpit-name:deck-name:page-name:button-name:button-variable-name}
: Substitute de given button name by its value. Example: ${button:Airbus A321:sd-xl:efis:apu:status:activation_count}
. If no button variable name is given, the current value of the button is returned.In all case, if the value is not found, it is replaced by None, which translate into 0 (zero) in formula (to prevent the formula from failing to compute). If the value is not found, a warning message is reported.
+The following formula determine the final status On(=1) or Off(=0) from the number of times a button was pressed:
+formula: ${state:activation_count} 2 %
+
If a button does not reference a dataref, and has no formula, the activation value can be used if it is available.
+In case a button has multiple values, each value comes from a part of the button. Each part of the button is independent of other parts of the same button. Each part maintains its single value.
+All part values are aggregated into either a dictionary or an array of values that is made available at the button level.
+For example, Annunciator, or LargeButton representation, have more than one individual values that are fetched and maintained to provide a single table (or array) of individual values.
+Another example is a button that has more than one dataref and no formula. In this case, the returned value is a dictionary of all dataref values of that button.
+A Button can force its first, initial value to set its startup or original state.
+ initial-value: 2
+
This value is assigned as the button's current value on startup.
+In case of a Button with multiple values, each value has a separate initial-value
attribute.
Some button may not maintain any state or use any value. Example of such button are simple push button with no feedback mean.
+The following depicts how a button's value is computed:
+The value of a button is updated at the following moment:
+An activation only modifies its internal state and does not "forward" its modification to the button. It is the button's responsibility to fetch the value it needs in the activation, through, for example, a state variable:
+formula: ${state:counter-clockwise-movement-count}
+
The following document explains the special set-dataref
attribute that can be used in numerous button definition.
Set-dataref
is an instruction that tells Cockpitdecks to set the value of the data pointed by the set-dataref
attribute value to the value of the button.
The set-dataref
attribute points at a writable dataref. After each activation of a button, the value of the button is computed and written to that dataref.
When a button uses or produces a single value, that value gets written to the set-dataref
.
When a button produces more than one value (for Annunciators, buttons without representation, etc.), the set-dataref needs additional information to know which value to write. In the latter case, a formula
is mandatory to select the appropriate value to send to X-Plane.
In some case, the button is using the same dataref for representation and set-dataref.
+Here is the simplest example of this case:
+- index: 0
+ type: push
+ text:
+ text: ${formula}
+ formula: ${data:activation_count}
+ set-dataref: data:internal_counter
+
The indent of the above button is to display a counter of how many times the button was pressed. In this example, it appears clearly that the order of operation must be:
+set-dataref
.So, in case the value of button is computed from one or more values that are very precisely modified by the activation of the button, the modification of the values is registered first, and the final value of the button computed afterwards, just before it is optionally written to the dataref pointed by the set-dataref
attribute.
A button view attribute is originally a X-Plane command that is submitted after the activation completed, as an additional command. The original intend is to propose a new view after some action to speed up information collection in the cockpit. For example, when the pilot selects APU on the ECAM display, the view
attribute specifies a command to change the view and focus on the ECAM display.
To achieve this, the view attribute value is a (single) X-Plane command to execute:
+view: x-camera/view/8
+
This document explains a new expression for the view attribute value to allow for the execution of one or more commands.
+This schema has been extended to other definitions that use a command attribute. It is an alternate way to specify a command. Rather that a single string expression:
+command: sim/view/map_display_toggle
+
it is now possible to express an entire block of pseudo code instruction:
+# Instruction to display the map if it is not visible.
+# The instruction will be hide the map, just show it if not visible.
+command:
+ command: sim/view/map_display_toggle
+ delay: 5
+ formula: ${sim/view/map_is_visible} not
+
view:
+ - command: command/to/execute
+ delay: 2
+ - set-dataref: dataref/to/set
+ formula: ${dataref/value} 2 +
+
The new view attribute value is a list of command blocks.
+Each command block is a command, an action that will be executed, and a few additional optional parameters.
+A command block contains a command which can be:
+In the latter case, the dataref being modified can either be a regular X-Plane dataref, or a Cockpitdecks internal dataref.
+command: command/to/execute
+
set-dateref: dataref/to/set
+
If the set dataref does not have any other attribute, the value will be set to the value of the button.
+However, it is possible to specify an alternate value to write:
+set-dateref: dataref/to/set
+formula: ${dataref/value} 2 +
+
To write another value than the button value, the set-dataref
attribute must be accompanied by a formula
attribute. The value resulting from the formula computation will be written to the dataref.
The following attributes can complement to above command.
+If specified, a delay is added after the execution of the last command and before the execution of this command.
+command: command/to/execute
+delay: 5
+
Command above will be executed 5 seconds after the execution of the activation or 5 seconds after the execution of the previous command.
+A condition
attribute is a formula that is executed before he command. If the result of the formula is evaluated to a non null (non zero) value, the command is executed. Otherwise, the command is not executed.
command: command/to/execute
+condition: ${some/dataref/to/check} 1 -
+
If the result of the computation of the formula is non zero, the command will be executed.
+Detection of the new parameter value is easy. Either it is a string representing a command to submit to X-Plane, or it is a list of one or more command blocks. There is no ambiguity.
+The view
attribute can be used as a test bed for execution of more than one command in a sequence, a kind of execution of « macro » command, with additional features like conditions and delay of execution.
Example of use:
+When executing a command to trigger a status view, you can imagine the following sequence:
+Other sequences can of course be imagined. Literally, the sky is the limit.
+This new view attribute value and its development paves the way of a new, more complex, more flexible action definition.
+ + + + + + + + + + + + + + + + + + + + + + +A button is the general term for a key, knob, rotary encoder, slider cursor, or even touch surface on a deck. On a given deck, each element that can be pressed, turned, swiped, or slid is a button.
+May be the term Interactor would have been better, more abstract, more generic, but he first deck we used only had keys to be pressed, so we sticked to the term Button, and extended the interactions a simple Button allow.
+For a given deck, all buttons that are available and/or displayed at a moment in time are on the same Page, the collection of buttons currently usable on that deck. Hence, in the definition of a page, there is a mandatory buttons
attributes that lists all buttons on that page.
In that list, each button is defined by a list of attributes that will determine what it does and how it appears on the deck. The list of attributes that define a button is called a Button Definition.
+The Button Definition is a list of attributes that describe what the button will do when it is manipulated and how it will be represented on the deck if the deck can some how represent the state of that button.
+Button definition can be very simple and straightforward, but definitions can also be complex and refined.
+Here is an example of a simple definition of a button to toggle the map display in X-Plane.
+index: 0
+type: push
+command: sim/map/toggle_map_display
+icon: map
+
The definition of a button can be organised into 4 distinct parts:
+Here is a complex definition of a button which exemplifies all above parts (in different colors):
+Resulting button:
+The following Sections describe the four button definition parts in detail.
+(In the Anatomy of a Button above, this refer to the blue part of the definition.)
+Attribute | +Definition | +
---|---|
index |
+Mandatory. There is no default value. Each «Button» on a deck is designated by its Button Index. So the index designate a very precise button on the deck. On a simple deck with a number of similar keys, the index of a button is its ordering number: 0, 1, 2… until the number of keys is reached. On a more complex deck, with button and knobs, knobs may be indexed with name like knob0, knob1, knob2… |
+
name |
+Optional. A button can be named to ease its identification. The name of a button on a page must be unique. If more than one button have the same name, an error is reported and the definition of the button is ignored. If no name is provided, a unique, long, technical name is created from deck name, page name, and index. |
+
type |
+Mandatory. The type of a button defines what the button will do and how it will be used. The Button Activation describe button-type specific attributes. In other words, depending on the value of the type attribute, other button defining attributes will be expected. For example, if the value of a button type is page to change a page on a deck, it is expected to find the attribute named page which contains the name of the page to switch to when pressed. |
+
label |
+The label of a button is a short reminder of what the button does. The text of the label is laid over the button image if any. The labelling of a button uses the following attributes: Note: The Button Label should not be confused with Button Text. The Label exist for all buttons, and is displayed according to its attributes if the underlying button is capable. The text of the label is defined as a button attribute and is static (cannot be changed dynamically). The Button Text is a text that is part of the Button representation. |
+
label-color |
+See Resources#Colors. | +
label-font |
+See Resources#Fonts. | +
label-size |
+In pixels. Internally, Cockpitdecks uses 256 × 256 pixel images. | +
label-position |
+The position of the label is a 2 letter code: 1. l, c, or r for left, center, or right-justified on the image (horizontal alignment), 2. t, m, or b, for top, middle, or bottom of the image (vertical alignment). |
+
options |
+Regularly, buttons have additional parameters. The button options parameter is a string of comma separated options. An option is either a simple string or word, or a name=value string. Options are, by nature, not indispensable to the button’s activation or rendering but rather add to it to alter behaviour or appearance. |
+
view |
+The view attribute is an additional optional instruction that is executed after the activation. The idea behind it is to first perform the action and then change the simulator view to focus on an area of interest and the activation has completed. | +
(In the Anatomy of a Button above, this refer to the yellow part of the definition.)
+A Button has a value that is maintained and used mainly for its representation.
+The value of a button can come from two sources:
+The following attributes are used to determine a button’s value:
+dataref
: A single dataref value.
formula
: An expression that contains variables, including datarefs, and mathematical operations to combine and compute a single final value.
multi-datarefs
: A list of two or more datarefs. The values of all datarefs in the list will be returned as the value of the button. In this case, the value will be a composite value. The representation that uses such a specific value will know how to use each part of the composite value.
When the value of a button is computed from one or more values coming from the simulator, Cockpitdecks will request the values from the simulator, and each time one of these values changes, Cockpitdecks will notify the button of the changes so that it can adjust its representation.
+Finally, in addition to the above attributes that can be used to specify the value of the button, a button has a set of internal attributes that can also be used to determine its value.
+Each button maintain an internal state: How many times it is pressed, released, turned clockwise or counter-clockwise, what is it current value, its previous, or last value, when it was last used or refreshed, etc.. State information can be accessed by Button designer to control the button behavior and its representation, or its value.
+Examples of internal state attributes are:
+activation_count
(number of time button was «used»)current_value
previous_value
Internal state attributes varies depending on the button activation. Each activation type returns its own set of particular state values.
+All these attributes can be used either individually or combined in a formula to determine the value of a button.
+Please head here for details about the computation of the value of a button.
+A Button can force its first, initial value to set its startup or original state.
+ initial-value: 2
+
This value is assigned as the button's current value on startup.
+In case of a Button with multiple values, each value has a separate initial-value
attribute in its own attribute list.
(In the Anatomy of a Button above, this refer to the green part of the definition.)
+The type
attribute of a button determine how the button will behave, what it will do when pressed, turned or slid.
A button definition can have a set-dataref
attribute that points at a Dataref name.
If present, Cockpitdecks will set the value of that dataref to the value of the button each time the value of the button changes.
+Here is example of use. If a button has a activation type of updown
with let us say 3 stops, the value of the button can be 0, 1, or 2. Each time the user presses the button the value of the button cycles between those three values.
type: updown
+stops: 3
+set-dataref: toliss/NDmodeFO
+
If there is a set-dataref
attribute, the current value of the dataref (toliss/NDmodeFO
) in the simulator will be set to the value of the button: 0, 1, or 2.
For some activations, the set-dataref
attribute is a mandatory attribute.
For some other activations that expects a command to be performed upon activation, the set-dataref
attribute (or instruction) can be an alternative to the command. In other words, the commands that gets executed is very precisely the set-dataref
instruction.
(In the Anatomy of a Button above, this refer to the pink part of the definition.)
+The representation of a Button determine what and how the button will display on the deck device. This depends on the capabilities of the button on the deck: LED, image, coloured led button, sound…
+The representation of a button is determined by the presence of a special attribute in the definition of the button. That attribute will determine how the button will be represented.
+For example, if a button definition contains an attribute named annunciator
, the button representation will be an Annunciator. A button can only define one representation in its definition. Otherwise, a warning is reported and the button is ignored.
Attributes related to the representation of the button are indented under the attributes that names the representation. This is done on purpose to clearly separate attributes dedicated to what the button does (activation), and how it provides feedback to the user (representation).
+A Page of 32 buttons 4 rows of 8 buttons) can quickly become quite large and difficult to read. Fortunately, recall that a Page can include other Pages to structure the creation of a layout. For example, it might be advisable to create a « main » page with global settings, and include four sub-pages, one for each row on the deck.
+ + + + + + + + + + + + + + + + + + + + + + +Cockpitdecks is an application that connect decks to the X-Plane flight simulator. On one side, the application scans for decks connected to the computer and prepare them for use with X-Plane. On the other side, Cockpitdecks connects to X-Plane through the network to issue instructions to the simulator and listen to changes to reflect those changes on the deck device if it allows it.
+To determine what to display on decks, which commands to issue to the simulator, etc. Cockpitdecks reads a set of configuration files on startup.
+Configuration files are specific to an aircraft. Commands are different on a Cessna and on an Airbus. Things to display on the deck are different as well. That’s why configuration files are located in the folder of the aircraft being used because they are specific to it. Numerous other software like X-Camera proceed in a similar way, locating their aircraft specific configuration there as well.
+The Cockpit is the Maestro component of the Cockpitdecks application.
+It starts up the entire Cockpitdecks application. It establishes connection to the simulator, scans for existing decks connected to the computer, and load the aircraft configuration files. It listen to interactions that occur on the decks and listen to simulator changes to reflect deck statuses. It also monitors which aircraft is currently loaded in the simulator, and if the user changes aircraft, it loads the new configuration if any.
+The following pages describe the necessary configuration files, their location and organisation, and their content. Configuration files are organized in structured folders, and this structure is explained as well.
+All configuration files for Cockpitdecks are Yaml-formatted files. Yaml file contains a structured list of (name, value) pairs. The name is referred to as an attribute. The value can be almost anything: A number, a string, a list of things, or a list of other attributes.
+Decks are particular to one aircraft. All files necessary to Cockpitdecks are located in a single folder named deckconfig
that is found in the folder of the X-Plane aircraft currently being used. In that folder, Cockpitdecks will find all its configuration files.
deckconfig
FolderThe overall structure of the files and sub-folders inside the deckconfig
folder is as follow:
<X-Plane Aircraft Folder>/
+ (.. aircraft files ..)
+ deckconfig/
+ config.yaml
+ secret.yaml
+ resources/
+ icons/
+ icon-off.png
+ fonts/
+ B612-Regular.otf
+ DIN.ttf
+ decks/
+ images
+ types
+ docs/
+ README.md
+ other-resource.py
+ layout1/
+ config.yaml
+ page1.yaml
+ page2.yaml
+ ...
+ ...
+ layoutN
+ page1.yaml
+ page2.yaml
+ ...
+
The deckconfig
folder contains the following files and sub-folders:
Name | +Description | +
---|---|
config.yaml |
+Main configuration file | +
secret.yaml |
+Serial numbers of decks used by Cockpitdecks | +
resources | +Resource files used by this configuration. Resources are icons, fonts, images, etc. | +
layout(s) | +A Layout is a folder that contains what is displayed on a deck. There can be as many Layout Folder as necessary for this aircraft. All remaining folders in the deckconfig folder are layout folders. There usually is one Layout folder per deck. |
+
config.yaml
FileThe file named config.yaml
in the deckconfig
folder it the main configuration file, It contains declarations for each deck that will be used, and global, aircraft-level attributes.
# Definition of decks for Toliss A321
+#
+aircraft: Toliss
+decks:
+ - name: XPLive
+ type: loupedeck
+ layout: live
+ brightness: 70
+# These attributes are default values at global level
+named-colors:
+ COCKPIT_BACKLIGHT: darkorange
+default-wallpaper-logo: Airbus-logo.png
+default-icon-color: (94, 111, 130)
+default-label-color: white
+default-label-font: DIN.ttf
+default-label-size: 14
+cockpit-color: lightblue
+
The following attributes apply to all decks for the given aircraft. Each individual deck will have the possibility to redefine these values if necessary.
+Attribute | +Definition | +
---|---|
aircraft |
+Optional information. The name of the aircraft for this set of deck. | +
named-colors |
+Allows to introduce your own named color. You can then use this name as a color. The value of the named color can either be a 3 or 4 value tuple (r, g, b, a), or the name of a Pillow color. (See Resources.) | +
cockpit-color |
+Color for the cockpit. This color is used as the default background color for icons. | +
cockpit-texture |
+Name of a image file (JPEG or PNG) that will be used as the (default) background of icons. The cockpit-texture file will be searched at different places depending on where it is specified.The cockpit-texture file can be specified at the Cockpit, Deck, Page, or Button level.Cockpit-level default textures will be seached in the following folders (in that order): - resources - resources/icons If the AIRCRAFT is specified, Cockpit-level textures and all other levels textures will be searched in the following folders: - AIRCRAFT/resource - AIRCRAFT/icons If no texture is found, a uniform cockpit-color icon is used. |
+
default-wallpaper-logo |
+Name of image file, located in the resource folder, to be loaded when the deck is not used. |
+
default-* |
+Name of default values of several parameters, defined at the aircraft-level. These values will be used for all missing values. They can be raffined at Layout and Page level if necessary. If no aircraft-level global parameter values are not provided, Cockpitdecks will use its own internal default values. |
+
decks | +A list of Deck structure, one per deck. | +
Yaml allow for other attributes in the file. They are ignored by Cockpitdecks. You may include other attributes like aircraft name, ICAO code, descriptions, notes, even change log of your file. Comments are also allowed in Yaml files.
+secret.yaml
FileThe secret.yaml
file contains the serial numbers of your connected decks.
If you have more than one deck of the same type (i.e. two Streamdecks, two X-TouchMini, etc.) this file is mandatory to distinguish between the two physical devices. Otherwise, it is optional.
+# My decks and their serial numbers.
+# Format:
+# DeckName: Serial number
+# DeckName must match name given in config.yaml.
+XPLive: AAA0000000000000000000A0000
+
Serial Numbers
+We experimentally noticed that serial numbers as displayed on the device and as reported by some software package do not always correspond. This also depends on the operating system. As a practical illustration, for HID devices, the request for its serial number throught HID specific protocol calls returns a value WA1234MHK0G, while the core operating system raw USB device probe returns A00WA1234MHK0G. Some device do not respond to serial number requests and in this case, an arbitrary software dependent value is returned, and not guaranteed to be unique(!).
+As a consequence, Cockpitdecks maintains a list of valid serial numbers for a given device.
Resources are fonts, icons, other images, wallpapers, documentation, and texts used and related to that aircraft. All these elements are organized into the resources
folder.
Usually, the resources folder contains the following sub-folders:
+Folder | +Content | +
---|---|
icons |
+Folder containing all icon images for that aircraft. Images should be in JPEG or PNG format. Typical icon size is 256 × 256 pixels, RGB(A). Icons are named after their file name without the extension. | +
fonts |
+Folder containing all fonts for that aircraft. Fonts can be Truetype or Opentype. Fonts are named after their file name with the extension. | +
docs |
+Docs folder may contain documentation files, like explanatory images, and descriptive texts. Simpler text or markdown files are preferred. | +
decks |
+Cockpitdecks allow experienced users to create their own Web Decks specific to an aircraft. | +
Next to the the above resources folder, there will be one folder per Layout for a deck.
+Layout folders are explained later.
+One of the most important attributes in the main configuration file is the decks
attribute which defnies all decks available to Cockpitdecks..
The following page describe the key components of Cockpitdecks and its vocabulary.
+Walking though Cockpitdecks main entities will get you familiar with Cockpitdecks vocabulary. Main objects have familiar names and do represent what their name designate.
+The core object of Cockpitdecks is the Deck. It can be a real, physical deck device like Stream Deck or LoupedeckLive, but it can also be the representation of a deck in a web page. In the later case, it is called a Web Deck. Web deck can either be a representation of an existing physical deck like Stream Deck or LoupedeckLive, and an imaginary one.
+A Deck usually has buttons that can be pressed, encoders that can be turned. They often also have either simple led that can be turned on or off, or small iconic LCD screens where some iconic image can be displayed.
+The goal of Cockpitdecks is to animate these devices to use them with a flight simulation software.
+A Page is a collection of buttons that are displayed on a deck and ready to be used.
+A Layout is nothing else than a group of related pages, displayed alternatively on a deck.
+A button is the general term for a key, knob, rotary encoder, slider cursor, or even touch surface on a deck. On a given deck, each element that can be pressed, turned, swiped, or slid is a button.
+The activation of a button determine what it will do when pressed, turned or slid.
+The representation of a Button determine what the button will display on the deck device. This depends on the capabilities of the button on the deck: LED, image, colored led, vibration, sound…
+The Cockpit is where everything occurs !
+The Cockpit is a container entity, the maestro that orchestrate the symphony.
+Cockpitdecks proceeds by numerous autonomous pieces of program that do some very precise task independently of each other, like listening to what happens on a deck or in the simulation software, and the Cockpit is responsible to orchestrate all these pieces of program so that they work in harmony to timely display information on decks or issue commands to simulation software.
+Cockpitdecks configuration is a folder (always named deckconfig
), organized into sub-folders, where the Cockpit will find all instructions to execute, both on the simulator side and on the deck side.
Internally, Cockpitdecks uses a few objects whose function are easy to understand.
+A data is a named entity ready to contain some data, a value.
+There are several types of data depending on where the data gets its value from.
+Cockpitdecks internal data is an internal value only used by Cockpitdecks, to maintain an internal state for example.
+Simulator data is a value coming from the simulation software. Each time it changes in the simulation software, its value is updated in Cockpitdecks.
+Each data has listeners associated with it. Each time the value of a Data changes, the listeners are notified of the updated value and can perform some tasks on their own to take into account the new value.
+An Instruction is a named entity that designate something to do, an action to perform.
+There are several types of instructions.
+Some are internal and specific to Cockpitdecks like loading a new page of button on a deck.
+Some other instructions are oriented towards the simulator software and designate an action to perform inside the simulation software.
+An Event is an object created each time somethings of interest to Cockpitdecks occurs. There mainly are two types of Events.
+Events that come from the decks: Each time a button is pressed, an encoder is turned, a slider is slid, or a touch screen touched, a Deck Event gets generated by the deck and is sent to Cockpitdecks. Cockpitdecks analyses the event and issue the necessary Instruction(s) (see above) to handle the event.
+Events that come from the simulation software: Each time a value changes in the simulation software, or some specific simulation event occurs, a Simulator Event is generated and sent to Cockpitdecks for handling.
+Please note that for the above objects, Data, Instruction, and Event, there always is a Cockpitdecks «internal» version of the object, and a simulator version of the object.
+The Cockpit.
+ + + + + + + + + + + + + + + + + + + + + + +A Deck represents a deck device connected to the computer, be it a
+a device that will be used to interact with the X-Plane flight simulator.
+A Deck uses and displays a collection of buttons called a Page of buttons. A Deck can display different pages of buttons at different times; a button on a page can be assigned to load another page of buttons.
+Each Page define the set of buttons on the deck device, what each button does when pressed or turned, and how it will appear on the deck device. The collection of pages that can be installed on a deck is called the Layout of the deck.
+In addition to the Layout and the Pages it contains, a Deck defines deck-level attributes, such as the overall brightness of the device, or how to fill unused or undefined buttons.
+Decks are declared in the config.yaml
file in the deckconfig
folder in the decks
attribute. The decks
attributes contains one or more decks as defined by the following attributes:
Attribute | +Definition | +
---|---|
name |
+Mandatory. Name of the deck. Must match the entry in secret.yaml file, it any. |
+
type |
+Mandatory. Type of deck. This points at a very precise deck brand and model. The value must match one of the deck types Cockpitdecks recognizes. The types of deck models Cockpitdecks recognizes is displayed upon startup of the Cockpitdecks application. | +
layout |
+Optional. Name of the layout for this deck. Default to name value default . See the next Section for more information. |
+
brightness |
+Optional. Overall brightness of deck. Default to 100%. It might be necessary to adjust brightness at night or in low light environment. | +
disabled |
+Boolean value to tell whether the deck should be enabled or not for this aircraft. Useful during development process. | +
default-homepage-name |
+Optional. Name of the page to load first in the layout. Default to index . That's why layout folder often contains a index.yaml page. |
+
default-* |
+Optional. Default attributes to use for deck. | +
Announce of available deck types on startup.
+cockpit.py: loaded 19 deck types (Virtual Deck for Development, X-Touch Mini, Virtual X-Touch Mini, LoupedeckLive, virtual loupedeck.ct, virtual loupedeck.live.s, Virtual LoupedeckLive with Mosaic, Virtual LoupedeckLive, Stream Deck Original, Stream Deck Mini, Stream Deck Neo, Stream Deck +, Stream Deck XL, Streamdeck, Virtual Streamdeck Mini, Virtual Streamdeck MK.2, Virtual Stream Deck Neo, Virtual Streamdeck +, Virtual Streamdeck XL), 11 are virtual deck types
+
For a given aircraft, a deck has a Layout. The Layout of a deck is the collection of Pages that will be used and displayed on the deck device for that aircraft. All these pages are grouped into a folder called a layout. A Layout is a folder in the deckconfig
folder that contains pages.
XPlaneAircraftFolder
+ (...)
+ ⊢ deckconfig
+ ⊢ resources
+ ⊢ fonts
+ ⊢ icons
+ ⊢ ...
+ ⊢ layout1
+ ⊢ config.yaml
+ ⊢ page1.yaml
+ ⊢ page2.yaml
+ ...
+ ...
+
The deck definition should contain a layout
attribute that indicates which layout will be used for that deck. The default layout name, if not indicated is default
. If no layout is found for the deck, a default, minimal layout is created.
No deck? We got you covered.
+If there is no physical deck device, Cockpitdecks can be used to replicate one of those on a web page.
+To use an emulation of a Stream Deck device for example, it is necessary to install the streamdeck component of Cockpitdecks. When done, it is possible to create virtual Stream Deck devices and display them in a web page.
+This is equally possible with other brands like Loupedeck or Behringer.
+ + + + + + + + + + + + + + + + + + + + + + +Adding a new deck model can be very simple or very difficult, depending on the deck's capabilities and software already available to access it (through the python language).
+Cockpitdecks does its best at isolating deck specifics into
+Decks, in general, have been defined as devices containing buttons that can be pressed, dials, or encoders that can be turned, cursors, or sliders that can be slid, or even touch screens that can be touched or swiped.
+These buttons can be illuminated by one or more monochrome or color LED(s), or can sometimes even display an image on a small LCD. Some can vibrate, or even produce sound.
+Each of these interaction has led to the definition of standardized behavior. On one side, the deck expresses what is is capable of, on the other side, the Cockpitdecks designer tells which capabilities she or he wants to produce a result.
+Please refer to the Deck Internals document to learn about how to express deck specifics in a Deck Type definition file.
+A small file defines the deck layout and capabilities, what is available through it:
+# This is the description of a deck's capabilities for a Elgato Streamdeck Plus device
+#
+---
+type: Streamdeck Plus
+brand: Streamdeck
+model: Plus
+driver: streamdeck
+buttons:
+ - name: 0
+ action: push
+ feedback: image
+ image: [96, 96, 0, 0]
+ repeat: 8
+ - name: 0
+ prefix: e
+ action: encoder-push
+ feedback: none
+ repeat: 4
+ # touchscreen in streamdeck package vocabulary
+ - name: touchscreen
+ action: swipe
+ feedback: image
+ image: [800, 100, 0, 0]
+
Through this file, Cockpitdecks is capable to determine that there are 8 (repeat) LCD buttons, named 0
.. 7
, capable of being pushed (action), and capable of displaying a 96x96 pixel image (feedback, image). Similarly, there are 4 encoders and a swipe screen.
Attribute | +Definition | +
---|---|
type | +Name the precise deck model. Referenced in config.yaml file to tell which deck is connected to the system. | +
driver | +Name of the driver software inside Cockpitdecks. See below. | +
buttons | +Button capabilities are modeled in two categories: 1. Actions, which specifies what a button is capable of, 2. View, which specifies what a button can show as a feedback to the user. |
+
Attribute | +Definition | +
---|---|
action | +The following actions (means of interaction with a deck) have been identified and are available in Cockpitdecks: - push : ability to press a button, optionally pushing a long time,- encoder - press : ability to press a button, no timing information- longpress - touch - swipe |
+
feedback | +Similarly, decks defined the following feedback interactions: - image - led : simple on-off light- colored-led : colored light (that can also be off)- encoder-led : ramp of led lights for X-Touch Mini |
+
name | +Name and repeat will determine the index name of the buttons. | +
repeat | +Number of time the same button needs repeating | +
prefix | +Prefix is used to distinguish button capabilities. If a button has, for example, encoder and push capabilities, the push capabilities will use name 0 (name only), the corresponding encoder will be named e0 (prefix + name). |
+
image | +In case of an image feedback, the image attribute sets the image size for this button, and its offset if the image is a portion of a larger display. |
+
vibrate | +If the device/button has a vibration capability | +
sound | +If the device/button has a sound emission capability | +
Depending on the button's action that is triggered, the deck will programmatically generate an Event. The type and content of the Event will depend on the action type.
+push
: produces an event with the identifier of the button that was pressed, and a flag indicating that the button was pressed or release.
encoder
: will produce an Event of type encoder, with the identifier of the encoder, and a flag telling whether the encoder was turned clockwise or counter-clockwise.
swipe
: will produce a complex swipe Event, with the position of the start of the swipe, the end of the swipe and some timing information (timestamps of start and end of swipe).
Technically speaking, the deck will start a thread to listen to incoming events. Interaction will be decoded (which key was pressed, when, how, etc.) and presented to Cockpitdecks as a typed Event.
+Depending on the device driver's hardware access, events will either be presented directly to Cockpitdecks, or through a FIFO queue: Driver just enqueues events, Cockpitdecks dequeues events and does the work.
+Depending on the deck's view capabilities, the computer will send the appropriate information to the deck to produce the feedback: Send an image, turn a LED on or off, with the appropriate color, emit a sound or vibrate.
+This is performed directly through the deck's device driver, by calling the appropriate function. Most of the time, this call is direct.
+When creating an Activation, the activation will specify which action it requires. For example, an activation that requires an encoder dial to work will require the encoder
or encoder-push
capability.
Similarly, a Representation will specify which feedback it requires. A representation that displays an image (icon, drawing, animation…) will require a image
feedback for instance.
To add a new activation to Cockpitdecks, the developer has to create a new Activation sub-class derived from cockpitdecks.buttons.activation.Activation
(or one of its subclass).
class SpecialAction(Activation):
+
+ ACTIVATION_NAME = "special-action"
+ REQUIRED_DECK_ACTIONS = [DECK_ACTIONS.PRESS, DECK_ACTIONS.LONGPRESS, DECK_ACTIONS.PUSH]
+
+ def __init__(self, config: dict, button: "Button"):
+
In the button definition:
+index: 42
+name: ULTIMATE
+type: special-action
+
The following python script adds a simple activation to adjust
+import logging
+from cockpitdecks import DECK_ACTIONS
+from .activation import UpDown
+
+logger = logging.getLogger(__name__)
+# logger.setLevel(logging.DEBUG)
+
+class LightDimmer(UpDown):
+ """Customized class to dim deck back lights according to up-down switch value"""
+
+ ACTIVATION_NAME = "dimmer"
+ REQUIRED_DECK_ACTIONS = [DECK_ACTIONS.PRESS, DECK_ACTIONS.LONGPRESS, DECK_ACTIONS.PUSH]
+
+ def __init__(self, config: dict, button: "Button"):
+ UpDown.__init__(self, config=config, button=button)
+ self.dimmer = config.get("dimmer", [10, 90])
+
+ def activate(self, event):
+ currval = self.stop_current_value
+ if currval is not None and 0 <= currval < len(self.dimmer):
+ self.button.deck.set_brightness(self.dimmer[currval])
+ super().activate(event)
+
Its accompanying button definition:
+ - index: 1
+ name: ANNUNCIATOR LIGHTS
+ label: ANN LT
+ type: dimmer
+ stops: 3
+ dimmer: [100, 80, 30]
+ switch:
+ switch-style: rect
+ button-fill-color: black
+ button-underline-width: 4
+ button-underline-color: coral
+ tick-labels:
+ - "TEST"
+ - "BRT"
+ - "DIM"
+ tick-space: 10
+ tick-label-size: 30
+ tick-label-font: DIN Bold
+ options: 3way,invert,hexa
+ dataref: AirbusFBW/AnnunMode
+ set-dataref: AirbusFBW/AnnunMode
+
When switch is moved to TEST, backlight is set to 100%, BTR sets it to 80%, and DIM to 30%.
+To add a new instruction to Cockpitdecks, the developer has to create a new ButtonInstruction sub-class derived from cockpitdecks.ButtonInstruction
(or one of its subclass).
from cockpitdecks.button import Button, ButtonInstruction
+
+
+class SpecialInstruction(ButtonInstruction):
+
+ INSTRUCTION_NAME = "button-special"
+
+ def __init__(self, button: Button, config: dict):
+ self._config = config
+
In the button definition:
+index: 42
+name: ULTIMATE
+type: push
+command: button-special
+
The following python script adds a simple instruction to print some information
+import logging
+from cockpitdecks.button import Button, ButtonInstruction
+
+logger = logging.getLogger(__name__)
+# logger.setLevel(logging.DEBUG)
+
+class PrintInstruction(ButtonInstruction):
+ """Custom instruction to print a message"""
+
+ INSTRUCTION_NAME = "button-print"
+
+ def __init__(self, name: str, button: Button, config: dict) -> None:
+ ButtonInstruction.__init__(self, name=name, button=button)
+ self._config = config
+ self.message = config.get("message", "Hello, world!")
+
+ def _execute(self):
+ logger.info(f"{self.message}")
+
Its accompanying button definition:
+ - index: 1
+ name: SAY HELLO
+ label: SAY HELLO
+ type: push
+ command: button-print
+ message: X-Plane rocks
+
When button is pressed, the message X-Plane rocks is printed on the console.
+The core Button class is designed to isolate deck key specifics in two attribute classes:
+In addition to these two attributes, the core Button class holds, keeps and maintains a set of other global, generic attributes made available to the two governing attributes.
+Last but not least, the button keeps a copy of its entire "definition", a dictionary of name, value pairs supplied through the configuration file of the Page. Again, some attributes are mandatory and/or imposed by Cockpitdecks, like
+type
index
options
set-dataref
Other attributes may already be defined by existing activations and representations, but any arbitrary name, value pair can be passed and stored in the button configuration dictionary and used by its activation and/or its representation.
+Creating a new representation, like sending some special information or custom image to a LCD key is more probable.
+To add a new representation to Cockpitdecks, the developer has to create a new Representation sub-class and derived it from cockpitdecks.buttons.representation.Representation
or one of its subclass.
class SpecialtyIcon(Representation):
+
+ REPRESENTATION_NAME = "specialty-icon"
+ REQUIRED_DECK_FEEDBACKS = DECK_FEEDBACK.IMAGE
+
+ def __init__(self, config: dict, button: "Button"):
+ Representation.__init__(self, config=config, button=button)
+
+ self.param1_value = config.get("param1")
+
In the button definition:
+index: 42
+name: SPECIAL_ICON
+type: push
+specialty-icon:
+ param1: value
+
To add a new simulator to Cockpitdecks, the developer has to create a new Simulator sub-class derived from cockpitdecks.Simulator
(or one of its subclass).
class SubLogicFlightSimulator(Simulator):
+
+ name = "A2FS1"
+
+ def __init__(self, cockpit, environ):
+
Cockpitdecks offers a few special activations that are normally not called in regular use.
+type: reload
No option. Provoke the reload of all decks from initialisation.
+The procedure first gracefull terminates the current setup, and then reloads the setup.
+If a page different than the home page was currently loaded, the process will try to reload the same page if available in the new setup.
+This activation is mainly used during development process to create buttons, alter their appearance and re-load the configuration to see the changes.
+(Please note that reloading decks is a complex process, since it involves the reset of all devices, reloading all configurations, and displaying pages as they used to be, if still present.)
+type: stop
No option. Gracefully stops all decks and terminates Cockpitdecks.
+type: inspect
Provoke the output of information for all buttons of all pages or all decks.
+Mainly for development purpose.
+Inspection always starts at the Cockpit level and may or may not crawl down into its constituting parts like decks, layouts, pages, and buttons. Some inspection terminates earlier in the drill down. For example, threads
inspection stops at the Deck level.
Button Inspect has one attribute
+what
The value of the what
attribute determine what is displayed when activated.
Value | +Description | +
---|---|
threads |
+list Cockpitdecks and deck threads that are currently running. | +
datarefs |
+list datarefs and values (the page containing the buttons need to be loaded first before it can display values). | +
datarefs-listener |
+List all datarefs and which buttons (listeners) are using the dataref. | +
status |
+list internal variables and statuses of each button. | +
valid |
+check button validity and report invalid status. | +
desc |
+print a description of what each button does in plain English, both for activation and representation. | +
image |
+produces an image of each deck, images are saved in the Cockpitdecks home directory and named after the deck. | +
longpress |
+list Button Activation#ShortOrLongpress command that should have a couple of additional commands added to X-Plane through the plugin. | +
index: 4
+type: inspect
+what: desc
+
When button index 4 is pressed, it will display what each button does (description) in plain English on the output or debugging screen or file.
+When a button is created, internal meta data are set first. Second, the Activation is installed and initialised. Third, the Representation is installed and initialized, as it may already use some activation information for rendering. Finally, the button is initialised. It will be rendered when the page that contains it is loaded on a deck.
+Each button has a validity function that ensures that all necessary attributes are provided in its definition. If the activation of the button is not valid, its activation function will never be triggered, because of missing or misconfigurated parameters. If its representation is not valid, it will not be rendered on the deck.
+If a button is not valid, a small red triangle appears in the lower right corner of the key icon if the button is capable of representing it. A small blue triangle appears in the lower right corner of the key icon if Cockpitdecks suspect the button is a placeholder.
+Each button has an describe()
method that prints in plain English what the button does and what it renders on the deck.
Each button has an inspect(what: str)
method that exposes internal values and state. The inspect method takes one parameter what
that determines what is displayed when invoked.
These methods can be invoked from the Inspect button activation.
+ + + + + + + + + + + + + + + + + + + + + + +Activation occurs when a Button is requested to handle an Event.
+A first step consists of the Activation preparation and initialization. This occurs when the deck is installed and each page created.
+Initialization of the Activation will result in the creation of one or more Instructions. In the process, the Performer entity responsible for executing the Instruction is clearly identified. For example, CockpitInstruction are performed by the Cockpit entity, while SimulatorInstructions are executed by the simulator software.
+The initialization of the Activation result in a global status is_valid() that returns True if the Activation contains all information necessary for handling events.
+When the Button receives the event, it calls the activate() function on its activation, supplying the event.
+ # In the Button class
+ def activate(self, event) -> bool:
+ result = self._activation.activate(event)
+ if result:
+ self.render()
+ else:
+ logger.warning("there was an issue handling the event")
+
Activate() functions return the status of the execution, True if all instructions were carried out without error.
+The Activation activate() function always proceeds in similar patterns:
+Here is a pseudo-code that handles button press events:
+ # In the Activation class
+ def activate(self, event: PushEvent) -> bool:
+ status = False
+ if not self.can_handle(event):
+ return False
+ if not super().activate(event):
+ return False
+ if event.pressed:
+ status = self.instruction.execute()
+ return status # Normal termination
+
From then on, the Button must decide what to do next, including if necessary regenerating its appearance.
+ + + + + + + + + + + + + + + + + + + + + + +As simple as it may appears when working, Cockpitdecks is a complex piece of software that relies on numerous technologies, systems, and interfaces to provide, ultimately, a confortable user experience.
+First of all, Cockpitdecks tries to provide a uniform representation of different deck models. Each deck model, from different manufacturers, has its own way of doing things. Different decks are accessed differently, some through basic serial (USB) interfaces, some through application programming interfaces, and some other through existing "protocols" made to talk to devices like HID or MIDI. Some device even allow several methods to be used.
+Cockpitdecks uses the appropriate method to hide the complexity of accessing the deck devices, to hide their particularities, at the expense of a complex and modular installation process. Some will use a single device, some other will use more than one, combining different models and brands to suit their needs.
+Cockpitdecks communicates with X-Plane through the network UDP protocol. This offers the advantage that Cockpitdecks and X-Plane do not necessarily need to run on the same computer, as long as both computer are on the same local network.
+Through UDP ports, X-Plane reports some internal parameter values (called datarefs), and accepts commands to execute.
+Never ever forget that in the UDP protocol, there is no guarantee of delivery, ordering, or duplicate protection. This is inherent to the UDP protocol. When something is sent, it is never guaranteed that it will be received or acknowledged.
+Cockpitdecks proceeds by starting autonomous threads of execution that monitor different aspects of the interaction of decks with X-Plane.
+Cockpitdecks threads are often created in start() procedures and terminated in terminate() procedures. Communication with the thread is performed through synchronous Queues.
+In addition, each deck has its own, internal, mechanism to capture user interactions.
+As today, things that occurs on a deck are captured by a lower level computer software module. In the case of Cockpitdecks and its Streamdeck, Loupedeck and Berhinger devices, each of those lower level software module is designed to use a user-provided callback function that is called each time something occurs on the deck. That's how event enters Cockpitdecks.
+During initialization of a deck, Cockpitdecks installs a small, minimalist callback function in the deck software module. This callback function processes data provided from the deck and immediately converts it into an Event (a Deck Event) that gets enqueued right away for later handling. This process is optimized to be as minimal and as fast as possible. The Queue where events are then enqueued is called the Event Queue.
+The Event Queue that receives all events from all decks connected to the system is unique for a Cockpit. It is the entry point for all interactions into Cockpitdecks. It behaves like a clean separator between lower level interaction handling at the device and Cockpitdecks. The callback function is responsible for decoding the information received from the device and crafting a typed Event that correspond to the interaction that occurred. The event also carries the necessary complementary information and data like, for instance, the precise button that was pressed or turned.
+Inside Cockpitdecks' Cockpit, a thread of execution receives the event from the Event Queue and immediately executes them to perform the action they carry.
+The action is executed in a separate thread of execution from those of the lower level physical interactions. Should execution of the action fail, the thread of execution of the capture is not affected.
+There is a similar mechanism for dataref values capture and processing.
+In the Simulator entity, a thread monitors datarefs by collecting them as they arrive on UDP port. It compare each value with the last one captured and enqueue a "value changed" event into the Event Queue if it was updated.
+Each dataref maintains a list of buttons that use/rely on it, and each of those buttons gets notified of the change to adjust. When a button receives the message that one of its dataref has changed, it can adjust its internal state, and if it is currently rendered on a deck, adjust its display.
+In the Simulator, a thread permanently monitors the connection of Cockpitdecks to X-Plane. When there is no connection, the thread attempt to initiate a new connection until it succeeds.
+When a new connection is created, it immediately request dataref updates and update all decks with all dataref values.
+If the connection breaks, it restarts its attempts to connect.
+When there is no connection to X-Plane, Cockpitdecks works as expected, however, no command get issued to X-Plane, and no dataref value gets collected, hence, no deck icon gets updated to reflect the state changes.
+Datarefs whose name starts with a prefix (currently data:
) behave like any other datarefs but are neither forwarded to X-Plane, nor read from it. They can be set, read, etc. like any other datarefs allowing for a kind of inter-button communication: one button sets it, another one adjust its appearance based on it, even buttons on another deck!
Truly, the sky is the limit. Enjoy.
+In addition to aircraft specific definitions, Cockpitdecks contains in its core, a default configuration used as a fall back if no value is found at the aircraft specific level. These global core configuration is found in a resources
folder inside Cockpitdecks software package. This folder should never be changed since it affects the entire Cockpitdecks application. It contains the following files and subfolders:
This is a global level configuration file. It always is loaded first and can be overwritten by aircraft, deck, or page-specific variants.
+Icons in this folder are available to all aircrafts.
+Fonts in this folder are available to all aircrafts.
+Cockpitdecks provides a few fonts found here and there together with their respective copyright files.
+A copy of Cockpitdecks documentation is included there. The documentation folder produced in the GitHub wiki of Cockpitdecks.
+The resource folder contains a few image files used as logos and wallpapers.
+There is also an image with color names that can be used in color
attributes.
This file defines icon fonts. Icon fonts are fonts that are used to display iconic characters often named intuitively. Cockpitdecks comes with a copy of Font Awesome icons, and Weather Icons.
+Defines a few constants that should never be changed. Change at your own risk.
+ + + + + + + + + + + + + + + + + + + + + + +Config files are kept in a Config structure which allows for easy access to attribute values.
+Attribute | +Content | +
---|---|
cockpit._config | +deckconfig/config.yaml file | +
cockpit._resources_config | +resources/config.yaml global file | +
deck._config | +portion of the deckconfig/config.yaml file for this deck | +
deck.deck_type | +Deck Type file for this deck | +
deck._layout_config | +layout/config.yaml file | +
decktype._config | +decktype.yalm file | +
page._config | +page.yaml file | +
button._config | +portion of the buttons attribute above for this button | +
button._def | +portion of the decktype buttons for this button | +
+ | + |
Cockpitdecks uses two types of value that can come from different sources:
+Values are used by buttons and observables. Values are used when there is a need to combine and modify raw values as provided by the simulator or by Cockpitdecks.
+Values are notified when one of its underlying Data has changed. This allows the Value to compute its new value. the Value in turn notifies the Button or the Observable that created it of its change. The Button or Observable can adjust as needed.
+Changes of Data value enter Cockpitdecks through Events. The SimulatorEvent (or one of its sub-class) is used to report the change of a value in the simulator software. The CockpitEvent (or one of its sub-class) to report change of value in the Cockpit.
+ + + + + + + + + + + + + + + + + + + + + + +Button definitions contains several attributes where datarefs can be used. Cockpitdecks needs to parse those attributes to create a list of datarefs to monitor.
+This page is an attempt to specify formally where datarefs are to be found.
+(Dataref list, or dictionary.)
+(List of values)
+(«Dictionary» of values)
+From the parameter supplied in the callback function, Cockpitdecks determine the type of interaction that occurred (pushed, turned, swiped…). For that interaction, an Event of a precise type is created, with all detailed parameters available to it. The callback function does not execute the activation but rather enqueues the event for later processing.
+In Cockpitdecks, another thread of execution reads events from the queue and perform the required action. This cleanly separate event collection and event "execution" in two separate process threads.
+The activation is the piece of code that will process the event.
+class Push(Activation):
+ """
+ Defines a Push activation.
+ The supplied command is executed each time a button is pressed.
+ """
+ ACTIVATION_NAME = "push"
+ REQUIRED_DECK_ACTIONS = DECK_ACTIONS.PUSH
+
Activation usually leads to either
+class Annunciator(DrawBase):
+ """
+ All annunciators are based on this class.
+ See docs for subtypes and models.
+ """
+ REPRESENTATION_NAME = "annunciator"
+ def __init__(self, config: dict, button: "Button"):
+ self.button = button
+
Similarly, when a Representation code is created, it must mention its identification keyword REPRESENTATION_NAME
that will be searched in the button definition attribute.
The REQUIRED_DECK_FEEDBACKS
determine which of the deck's definition feedback
type is requested to be able to use the Representation().
The ACTIVATION_NAME
is the string that the button definition must use to trigger that activation (type
attribute):
- index: 1
+ name: MASTER CAUTION
+ type: push
+ command: sim/annunciator/clear_master_caution
+ annunciator:
+ text: "MASTER\nCAUT"
+ text-color: darkorange
+ text-font: DIN Condensed Black.otf
+ text-size: 72
+ dataref: AirbusFBW/MasterCaut
+ vibrate: RUMBLE5
+
Deck Internals explains how Cockpitdecks discovers about miscellaneous deck hardware capabilities and how user interactions on a physical deck device enter Cockpitdecks.
+When a user want to use a deck with Cockpitdecks, it is necessary to have a python package available to interact with it. This python package is not provided by Cockpitdecks but by other developers who bridged the physical deck hardware with the python language.
+By design and coïncidence, all three deck brands currently used by Cockpitdecks (Elgato, Loupedeck, and Berhinger) proceed with a similar mechanism: The python package that interfaces the physical deck to the python language request to supply a callback function. That function is called each time an interaction occurs on the physical deck device.
+When Cockpitdecks is started, its scans for available devices, checks whether the interfacing software package is available, and if it is, installs its callback function into the python package for that deck.
+From that moment on, each time something occurs on the physical deck device, Cockpitdecks' callback function gets called. In that callback function, Cockpitdecks tries to spend a minimum time. From the data it receives from the interfacing python package, it creates an Event with all necessary data and enqueues it in Cockpitdecks for later processing. The Event the callback function creates is aptly called a Deck Event.
+The Deck Event contains information about the deck, of course, but also the precise button, knob, encoder, slider, screen… that was manipulated and the type of interaction that occurred (pushed, turned, swiped…) All that information is in the Deck Event and is sent to Cockpitdecks.
+That's how physical deck interaction enters Cockpitdecks.
+Cockpitdecks processes events that enter its queue. Cockpitdecks instruct the event to run. That's how and when actions are actually performed, like sending a command to the simulator or changing the value of a dataref.
+Cockpitdecks discovers about deck capabilities through a Deck Type structure.
+A deck is presented to Cockpitdecks through a deck definition file called a Deck Type. The deck definition file describes the deck capabilities:
+Here is for example, a deck configuration file for a Loupedeck LoupedeckLive device.
+# This is the description of a deck's capabilities for a Loupedeck LoupedeckLive device
+#
+---
+name: LoupedeckLive
+driver: loupedeck
+buttons:
+ - name: 0
+ action: push
+ feedback: image
+ image: [90, 90, 0, 0]
+ repeat: 12
+ - name: left
+ action: swipe
+ feedback: image
+ image: [60, 270, 0, 0]
+ - name: right
+ action: swipe
+ feedback: image
+ image: [60, 270, 420, 0]
+ - name: 0
+ prefix: e
+ action: [encoder, push]
+ feedback: none
+ repeat: 6
+ - name: 0
+ prefix: b
+ action: push
+ feedback: colored-led
+ repeat: 8
+ - name: buzzer
+ action: none
+ feedback: vibrate
+
Attribute | +Definition | +
---|---|
name | +Name used inside Cockpitdecks to identifying the deck model. | +
driver | +Keyword identifying the deck software driver class. (See main drivers class above.) | +
background | +The background attribute is an optional attribute only used by web decks. It specifies a background color and/or image to use for web deck representation. See explanation and exemple below. |
+
buttons | +The Buttons contains a list of Deck Button Type Block descriptions.This attribute is named Buttons, with Button having the same meaning as in Cockpitdecks. A Deck Type Button is a generic term for all possible means of interaction on the deck: 1. Keys to press, 2. Encoders to turn, 3. Touchscreens to tap or swipe 4. Cursors to slide A list of button types, each ButtonType leading to one or more individual buttons identified by their index, built from the prefix , repeat , and name attribute. See below. |
+
A Deck Type Button Block defines either a single button, or a group of identical buttons. For example, if a deck has a special, unique, «Escape» button, it can be defined alone in a Deck Type Button Block. Similarly, if a deck consist of a grid of regularly spaced 6 by 4 keys that are all the same, they can also be defined in a single Deck Type Button Block.
+Attribute | +Defintion | +
---|---|
name | +Name of the button type. The name of the button type is - either the final name of the button, like touchscreen , when there is a single button with that name on the deck,- or an integer value that will be used to build the button names, in the case the block defines a sets of identical buttons. |
+
actions | +Interaction with the button. Interaction can be: - none : There is no interaction with the button. It is only used for display purpose. (none interaction can be omitted.)- press : Simple press button that only reports when it is pressed (one event)- push : Press button that reports 2 events, when it is pushed, and when it is released. This allow for "long press" events.- swipe : A surface swipe event, with a starting touch and a raise events.- encoder : A rotating encoder, that can turn both clockwise and counter-clockwise- cursor : A linear cursor (straight or circular) delivering values in a finite range.Action can ba a single interaction or an array of interactions like [encoder, push] if a button combines both ways of interacting with it. |
+
feedbacks | +Feedback ability of the button. Feedback can be: - none : No feedback on device, or direct feedback provided by some marks on the deck device. (none feedback can be omitted.)- image : Small LCD iconic image.- led : Simple On/Off LED light.- colored-led : A single LED that can be colored.- multi-leds : Several, single color, LED on a ramp.- encoder-leds : Special encoder led ramp for X-Touch Mini (4 modes)- vibrate : emit a buzzer sound. |
+
repeat | +In case of a set if identical buttons, repeat if the number of time the same button is replicated along width (x) and height (y) axis.If only one value is supplied, it is supposed to be [value, 1] array. For vertical layout, specify [1, value] instead. |
+
In the case of a single button, the name of the button will be touchscreen
and that name needs to be unique for the deck type.
name: touchscreen
+
In the case of a set of identical buttons, the name of the button will be built from other attributes:
+name: 5
+prefix: k
+repeat: [4, 3]
+
Names of buttons will be: k5
, k6
, k7
, … k16
.
Trick
+If a deck has a vibrate capability, it is advisable to declare it as a separate button of interaction, and use that button like any other. Vibrate is a feedback mechanism.
+The above Deck Type Button Block attributes are necessary for all decks, both physical and web decks. Web Decks also contain an additional series of attributes that drive the drawing of the deck in a web navigator window.
+Web Deck Drawings
+For simplicity, Web Deck Drivers are drawn on an HTML Canvas, which is a pixel-driven drawing space. Web Decks are drawn with images and drawing instructions that use the pixel as a unit for display.
+Web decks can have the following types of interactive buttons:
+When rendered in a browser window, web deck interaction means are materialised through a changing pointer cursor (arrow, curved arrow (encode), single dot (push), double dot (pull), etc.)
+Background Deck Type Attribute
+Please read above in this page the background
Deck Type attribute used to specify a background image to use for web deck display.
Attribute | +Definition | +
---|---|
dimension | +The dimension attribute can be a single integer value or a list of two values. It determine the size of the button has drawn on the Web deck. If the feedback visualisation is an image , the image attribute specifies the characteristics of the image. X is horizontal and correspond to the width , Y is vertical and correspond to the height . |
+
layout | +Layout of the buttons on the web deck canvas. - Offset - Spacing Buttons will be arranged at regular interval, starting from Offset, with supplied spacing between the buttons. Button sizes are specified in the Dimension attribute. |
+
hardware | +Configuration information for a specific drawing representation of this hardware button. | +
empty-button | +Minimal Button definition to create an empty, dummy button. This dummy button will becreated and used to generate an "empty" hardware representation (completely off ). (In other words, if a button with hardware representation is not defined, this definition will be used to create a button.) See below. |
+
options | +Comma-separated list of options, a single option can either be a name=value, or just a name, in which case the value is assumed to be True.options: count=8,active sets options count to value 8, and active to True. active is equivalent to active=true . |
+
background
In addition to the above button definitions, a deck type may contain a background
attribute. This attribute is only used by web decks. The background attribute defines the background of the web page where the web deck will be rendered. The background can either be
Attribute | +Definition | +
---|---|
image |
+Name of a PNG image, with extension. No default. | +
color |
+Color of the background of the web page. No default. | +
size |
+Array of two values with width and height of the web canvas. Defaults to (200, 100) pixels. | +
overlay |
+Static text or image overlay. Not implemented yet. | +
Some deck buttons need a special representation or drawing to visually reproduce the physical deck equivalent button. Examples of such special representations are
+These highly specific « drawings » are performed on side representations called Hardware Representations.
+Technically speaking, they behave very much like LCD representations:
+Hardware Representations need to know how to represent themselves in case they are not used or defined on a page. To present nicely, Cockpitdecks needs to know how to draw an "undefined", unused Hardware Representation. To do this, Cockpitdecks uses a trick: It dynamically create an dummy placeholder button from the Empty Button Definition for its Hardware Representation. Basically, only two attributes need to be defined: A type (often set to none) and an attribute that tells its Hardware Representation. Optionally, a default, initial value can be supplied. Sometimes, some mandatory or optional Hardware Representation attributes need to be supplied as well. Here is an exemple of a simple LED representation.
+hardware:
+ type: virtual-xtm-led
+ empty-button:
+ type: none
+ led: single
+ initial-value: 1
+
name: Virtual Deck
+driver: virtualdeck
+buttons:
+ - name: left
+ action: [push, swipe]
+ feedback: image
+ dimension: [52, 270]
+ layout:
+ offset: [96, 78]
+ options: corner_radius=4
+
name: Virtual Deck
+driver: virtualdeck
+buttons:
+ - name: 0
+ prefix: e
+ repeat: [1, 3]
+ action: [encoder, push]
+ dimension: 27
+ layout:
+ offset: [45, 115]
+ spacing: [0, 41]
+ - name: 3
+ prefix: e
+ repeat: [1, 3]
+ action: [encoder, push]
+ dimension: 27
+ layout:
+ offset: [624, 115]
+ spacing: [0, 41]
+
On startup, Cockpitdecks reports which deck types are available:
+Cockpitdecks 12.7.2.20241209 © 2022-2024 Pierre M <pierre@devleaks.be>
+Elgato Stream Decks, Loupedeck decks, Berhinger X-Touch Mini, and web decks to X-Plane 12.1+
+
+INFO MainThread start.py:<module>:315: Initializing Cockpitdecks..
+INFO MainThread cockpit.py:add_extensions:610: loaded extensions cockpitdecks_xp, cockpitdecks_wm, cockpitdecks_ld, cockpitdecks_ext, s_sd, cockpitdecks_bx
+INFO MainThread cockpit.py:init:466: available simulators: X-Plane
+INFO MainThread cockpit.py:init:469: available deck drivers: virtualdeck, loupedeck, xtouchmini, streamdeck
+WARNING MainThread xplane.py:add_datarefs_to_monitor:1189: no connection
+INFO MainThread xplane.py:add_cockpit_datarefs:819: monitoring 1 cockpit datarefs
+WARNING MainThread xplane.py:add_datarefs_to_monitor:1189: no connection
+INFO MainThread xplane.py:add_simulator_datarefs:832: monitoring 7 simulator datarefs
+INFO MainThread cockpit.py:init_simulator:497: simulator driver XPlane 1.4.0 installed
+INFO MainThread cockpit.py:init_simulator:501: COCKPITDECKS_PATH=/Users/xplane/X-Plane 12/Aircraft/Laminar Research:/Users/xplane/X-Plane 12xtra Aircraft
+INFO MainThread cockpit.py:load_cd_fonts:1494: 18 fonts loaded, default font=D-DIN.otf, default label font=D-DIN.otf
+INFO MainThread cockpit.py:load_cd_icons:1369: 18 icons loaded from cache
+INFO MainThread cockpit.py:load_cd_sounds:1543: 8 sounds loaded
+DEBUG MainThread observable.py:init:130: observable Aircraft loaded: listening to {'sim/aircraft/view/acf_livery_path'}
+INFO MainThread cockpit.py:load_cd_observables:1284: loaded 1 observables
+INFO MainThread cockpit.py:load_deck_types:1336: loaded 19 deck types (Virtual Deck for Development, LoupedeckLive, virtual loupedeck.ct, pedeck.live.s, Virtual LoupedeckLive with Mosaic, Virtual LoupedeckLive, Stream Deck Original, Stream Deck Mini, Stream Deck Neo, Stream eam Deck XL, Streamdeck, Virtual Streamdeck Mini, Virtual Streamdeck MK.2, Virtual Stream Deck Neo, Virtual Streamdeck +, Virtual XL, X-Touch Mini, Virtual X-Touch Mini), 11 are virtual deck types
+INFO MainThread cockpit.py:scan_devices:800: device drivers installed for virtualdeck (included), loupedeck 1.4.5, xtouchmini 1.3.6, 0.9.6; scanning for decks and initializing them (this may take a few seconds)..
+INFO MainThread cockpit.py:scan_devices:825: found 1 loupedeck
+INFO MainThread cockpit.py:scan_devices:825: found 1 xtouchmini
+INFO MainThread cockpit.py:scan_devices:825: found 3 streamdeck
+INFO MainThread start.py:<module>:317: ..initialized
+
A particular deck will come with software that interfaces it with the python language. That piece of software is a deck device driver. It is necessary to
+Currently, this require the coding of a single python class derived from the cockpitdecks.deck
class, with the following functions:
General:
+Interaction control:
+In some drivers, there sometimes is a callback function per interaction type:
+Feedback:
+If the deck has image capabilities:
+See list below.
+If the deck has sound and/or vibrating capabilities:
+If the deck has lit button with color capabilities:
+If the deck has lit button without color capabilities:
+If the deck has lit button with several led capabilities (led ramps, etc.):
+The following functions are also necessary and can be overwritten if necessary.
+ def __init__(self, name: str, config: dict, cockpit: "Cockpit", device=None)
+ def set_deck_type(self)
+
+ def init(self)
+ def get_id(self) -> str:
+
+ def is_virtual_deck(self) -> bool:
+ def get_deck_button_definition(self, idx)
+ def get_deck_type(self) -> DeckType:
+ def get_attribute(self, attribute: str, silence: bool = False)
+ def load(self)
+
+ def change_page(self, page: str | None = None)
+ def reload_page(self)
+ def set_home_page(self)
+ def load_home_page(self)
+ def make_default_page(self, b: str | None = None)
+
+ def get_button_value(self, name)
+
+ def get_index_prefix(self, index)
+ def get_index_numeric(self, index)
+ def valid_indices(self, with_icon: bool = False)
+ def valid_activations(self, index=None)
+ def valid_representations(self, index=None)
+
+ def inspect(self, what: str | None = None)
+ def print_page(self, page: Page)
+
+ def vibrate(self, button)
+ def set_brightness(self, brightness: int)
+
+ def render(self, button: Button)
+ def fill_empty(self, key)
+ def clean_empty(self, key)
+
+ def start(self)
+ def terminate(self)
+
For deck with iconic display capabilities:
+ def get_image_size(self, index)
+ def create_empty_icon_for_key(self, index)
+ def get_icon_background(
+ self,
+ name: str,
+ width: int,
+ height: int,
+ texture_in,
+ color_in,
+ use_texture=True,
+ who: str = "Deck",
+ ):
+ def create_icon_for_key(self, index, colors, texture)
+ def scale_icon_for_key(self, index, image, name: str | None = None)
+ def fill_empty(self, key)
+ def clean_empty(self, key)
+ def set_key_icon(self, key, image)
+
Cockpitdecks comes with two designer tools.
+The Deck Designer is a tool that help positioning, sizing, and naming elements on a web deck background image.
+On the above designer, rectangular or circular buttons, encoder, or hardware image place holders can be positioned and sized.
+A layout can be saved and loaded later. When saving, two files are created, one for the graphical representation with the design, and one Yaml file in Deck Type format. The latter can be used as a skeleton to define a new virtual web deck.
+Layout and layout.
+In a very unfortunate choice of vocabulary, the word layout is used to designed two different things in Cockpitdecks.
+The web deck can then be used with the same background image, and each button, encoder, or hardware image will be laid over the background at the very precise defined position and size.
+Of course, manual tweaking of position and sizes is sometimes necessary, but the gross work of estimation is completed in fun time. For instance image size may need to be evenly rounded to the same value for all buttons for aesthetic layouts.
+See the A321 Overhead Panel example. Deck Designer is used to define the very precise position of each annunciator or switch.
+The Button Designer is a simple tools that help test and preview button design.
+A button can be defined, either through a form by filling a few intuitive fields, or by typing Yaml code directly in the code window. The design tool also can generate Yaml code from the form parameters values.
+Form is not completed from code area
+The opposite is not true, when entering or adjusting code in the coding window, form elements are not updated.
+By pressing the render button, Cockpitdecks will generate a button image and make it available for display in the Button Designer preview window. If the simulator is running, the button will show the simulated values like they would appear on the real deck.
+When "Saving…" the button, it is added to a file in the
+< current-aircraft | deck-name >/deckconfig/<layout-name>/<page-name>.yaml
+
file at the index position mentioned in the first part of the form. (If no layout or page name is supplied int he form, acceptable default values are provided.)
+So is it possible to design buttons one by one and add them after verification to the page file.
+Once the page is complete, it can be copied over to the deckconfig
folder of the aircraft.
Selecting a new deck name or a new button index resets the forms.
+To generate code, the code window must be empty. Pressing render while the code window is not empty has no effect.
+Representations are added one at a time, some are not currently working.
+What is working well, it the testing area: You can paste your button definition yaml code in the code text area and press render to get a preview of your button, data included if connected to a simulator.
+Events are entities created by decks to report which interaction occurred on the physical device.
+Events are created by callback functions to enter Cockpitdecks processing.
+Events have a type that identifies the interaction.
+Base class for events.
+Attribute | +Definition | ++ |
---|---|---|
deck | +Related Deck | +where interaction occured. | +
button | +Related button Button Index | ++ |
action | +Deck Internals | +Deck action name]] | +
timestamp | +Time of creation of event | ++ |
is_processed | +Whether event has run or not. | ++ |
Function | +Description | +
---|---|
run(just_do_it: bool = False) | +Run the event. If just_do_it is False, enqueue the Event. Otherwise, execute the activation. |
+
handling() | +Mark the start of processing. | +
handled() | +Mark the end of processing. | +
+ | + |
Attribute | +Description | +
---|---|
pressed | +True or False , if key is pressed (True ) or released (False ) |
+
pulled | +True if push/pull option is enabled and button was pulled rather than pushed. | +
+ | + |
PushEvents are in fact raised twice for an interaction. First when the button is pressed, and second when the button it released. It is a main differentiator of Press and LongPress Events.
+A Press event is a single event sent when a button is pressed. No event is sent when the button is released. It is therefore impossible to know how long the button was pressed.
+In the case of PressEvent, we only know that the button was pressed for a short time, without being able to set or determine how long it was pressed.
+A LongPress event is a single event sent when a button is pressed for a long time, but the time it remained pressed is not defined or settable. No event is sent when the button is released. It is therefore impossible to know how long the button was pressed.
+In the case of LongPressEvent, we only know that the button was pressed for a long time, without being able to set or determine how long it was pressed.
+The long time event occurs experimentally after roughly 600 milliseconds. It is therefore safe to assume that for a LongPress event, the button remained pressed for at least 1 second.
+Attribute | +Description | +
---|---|
clockwise | +True or False , if encoder is turned clockwise (True ) or counter-clockwise (False ) |
+
Attribute | +Description | +
---|---|
value | +Raw value of the slider (as produced by the driver) | +
Attribute | +Description | +
---|---|
x | +x-position of the event (horizontal) | +
y | +y-position of the event (vertical) | +
start | +Timestamp of touch event | +
A Swipe event is either an event on its own, or the combination of two Touch event.
+In the latter case, the first Touch event is the start of the swipe.
+The second one being the end of the swipe, and must be supplied the first event as an argument. In this case, the swipe() method will return a Swipe event that combine them both.
+Streamdeck Touch and Swipe Events
+Please note that some deck models do no report timing information. In this case, the timing information is either added by Cockpitdecks or not available at it.
+In particular, Streamdeck decks have a particular Swipe event that always last at most less that a second, without any timing information. Just a start position, and an end position taken at most one second after the start event.
Hardware Representations only exist for web decks.
+When a web deck tries to reproduce on screen hardware elements only available on physical decks, it uses hardware representation.
+Let us take a very simple hardware representation: A translucent button with a colored led. The button has sign on it (letter, number, icon…)
+For the physical deck, the deck device driver will handle the rendering of the feedback on that deck through a dedicated representation and its accompanying driver software.
+Cockpitdecks uses a hardware representation to draw the same button on a web deck. A hardware representation is nothing more than an image used to represent a button on a web deck.
+Very much like the physical representation, Cockpitdecks uses dedicated software to create the image, but once created, the image of the hardware button is sent to the web deck for drawing like any other image, supplying the image of course, but also its position and size.
+Since a hardware representation is an image, all hardware representations are in fact particular icons image and treated as such.
+In the case of our translucent button, all we need is a image of that button when it is not lit. When lit with a given color and/or intensity, the hardware representation software will overlay the button sign to give the illusion that it is lit as requested. The resulting image is sent to the web deck to give the illusion of the lit button.
+Hardware representations are often specific to a deck model. Therefore the device driver of the corresponding deck model need to be installed to make some feature parameters available to the hardware representation.
+Here is an example of the demo deck, with a X-Touch Mini hardware representation for the right most encoder (circular ramp of 13 monochrome leds). In the picture below; on the left side, the encoder is not represented because xtouchmini
driver software is not installed. On the right side, it is correctly represented.
An Instruction is some piece of code that needs to be carried out.
+A Cockpitdecks instruction is a internal Cockpitdecks instruction performed inside the Cockpit.
+The Instruction receives the current Cockpit as a parameter to execute its instruction.
+A SimulatorInstruction is sent to the Simulator for execution. Examples of SimulatorInstructions are executing of commands, or update of simulator data value.
+The Instruction receives the current Simulator as a parameter to execute its instruction.
+A ButtonInstruction is a hook to allow for custom, user defined instruction to be executed.
+The Instruction receives the current Button it is associated with as a parameter to execute its instruction. The Button has programmatic access to the Deck it belongs, to the Cockpit, and to the Simulator.
+ + + + + + + + + + + + + + + + + + + + + + +These datarefs are created and maintained for statistical purpose. They should not be used for simulation, only for development and Cockpitdecks health monitoring.
+class INTERNAL_DATAREF(Enum):
+ #
+ # C O C K P I T D E C K S
+ #
+
+ #
+ # C O C K P I T
+ #
+ # Number of cockpitdecks reloads
+ COCKPITDECK_RELOADS = "reload_pages"
+
+ #
+ # D E C K
+ #
+ # Number of page reloads
+ DECK_RELOADS = "reload_page" # /<deck-name>
+
+ # Number of page reloads
+ PAGE_CHANGES = "change_page" # /<deck-name>/<page-name>
+
+ RENDER_BG_TEXTURE = "bg-texture"
+ RENDER_BG_COLOR = "bg-color"
+ RENDER_CREATE_ICON = "create_icon"
+
+ #
+ # P A G E
+ #
+ DATAREF_REGISTERED = "registered_dataref"
+ PAGE_RENDER = "page_render"
+ PAGE_CLEAN = "page_clean"
+
+ #
+ # B U T T O N
+ #
+ BUTTON_ACTIVATIONS = "activation"
+ BUTTON_RENDERS = "render"
+ BUTTON_REPRESENTATIONS = "representation"
+ BUTTON_CLEAN = "clean"
+
+ #
+ # U D P
+ #
+ INTDREF_CONNECTION_STATUS = "_connection_status"
+ # Number of UDP packet received
+ UDP_BEACON_RCV = "udp_beacon_received"
+ UDP_BEACON_TIMEOUT = "udp_beacon_timeout"
+ STARTS = "starts"
+ STOPS = "stops"
+
+ UDP_READS = "udp_rcv"
+ LAST_READ = "last_read_time"
+ VALUES = "values_read"
+ UPDATE_ENQUEUED = "value_change_enqueued"
+
+ # Average number of reads per seconds (last 100 reads)
+ UDP_READS_PERSEC = "cockpitdecks/udp/persec"
+
+ # Time sice last read
+ UDP_CYCLE = "cockpitdecks/udp/cycle"
+
+ # Average number of dataref values recevied per seconds (last two minutes)
+ UDP_DATAREFS_PERSEC = "cockpitdecks/udp/datarefs_persec"
+
+ # Total number of dataref values recevied
+ UDP_DATAREF_COUNT = "cockpitdecks/udp/dataref-count"
+
+ #
+ # E V E N T
+ #
+ ENQUEUE_CYCLE = "cockpitdecks/udp/enqueue/cycle"
+
+ ENQUEUE_COUNT = "cockpitdecks/udp/enqueue/count"
+
+ ENQUEUE_PERSEC = "cockpitdecks/udp/enqueue/persec"
+
+ #
+ # X - P L A N E
+ #
+ # Zulu diff
+ # Time difference between zulu in sim and zulu on cockpitdecks host computer (in seconds and microseconds)
+ ZULU_DIFFERENCE = "xplane/timedelay"
+
It started with a standard Stream Deck device. I found it nice to be able to see result of interaction with the deck right away on the deck.
+I only fly Airbus, so I wanted to see annunciators switches on my deck. On panel at a time.
+So I started to cut icons from an overhead screen dump. I quickly noticed some repetitive annunciators. But also numerous wordings changes. Label above annunciators would also change of course. I did not want to end up with a thousand icons, named by some clever convention. So I gave up fairly quickly on image processing and static icons and headed for a mechanism to dynamically create images with words laid over. I elaborated a set of design conventions that resulted in image generation.
+Convention evolved quickly as I wanted to not only be able to generate annunciators but also switches, rotary knobs, and display some numbers like FCU data, fuel tank levels, etc.
+Then I discovered the Loupedeck device. More elaborate with encoders and touch screens. I wanted to be able to handle those devices as well.
+I am the happy owner of an inexpensive Behringer X-Touch Mini that I wanted to handle with my development too, even if it was not capable of showing images, it had other LED to communicate.
+This led, one button at a time to what Cockpitdecks is today.
+One, a gentleman approached me with questions about the configuration of a deck. I was first surprised to see that somebody else was successfully using my code. But above all, this gentleman who was designing cockpits for other aircrafts needed a way to speed up its development process and suggested rendering decks on screen. This led, in a first iteration in what we called « virtual decks », but as the screen rendering package used lacked features for interaction and brought in significant complexity, we decided to change for lightweight rendering in a browser window. Virtual decks became web decks (but in the code or wording, both terms still co-exist.) In a nutshell, rather than sending generated images to decks for display on their small LCD screens, we send them to a web page for display on a Canvas. Couldn’t be simpler!
+That, together with numerous code refactoring, abstractions, and conventions, lead to a flexible, configurable, autonomous application that now allow to use common deck models with X-Plane fight simulator. As an illustration of code refactoring, Cockpitdecks was first designed to work with X-Plane only, using X-Plane terminology of Datarefs, Commands, etc. Refactoring brought in a new abstractions for Simulator applications, with neutral generic terminology and allow now for different simulation software to be used with Cockpitdecks.
+Cockpitdecks underwent numerous refactoring processes. Some basic, like name changes, some easy, like abstractions (insertion of intermediate often abstract classes), and some heavy (computer value from data with formula). But, through all these changes, the syntax of config.yaml files for buttons rarely changed. Vocabulary get richer because of addition of activations or representations, but older existing definitions kept working with minimal changes. Pages developed a year ago still work surprisingly well after all these internal changes!
+Everything was created with fun and heart and is freely available to other to enjoy.
+Towards the end, we added very basic straightforward user interfaces to interactively create buttons on web pages without coding. While the core functions are working as expected, a web user interface specialist could build a friendlier application from the feasibility rough cut we laid over. My knowledge of web user interface disappeared over time as things were getting highly specialized and refined. I’m sure there is room for a little svelt or vue application if someone is tempted by collaborating. (Backend already exists.) This web-based user interface would allow any one to design buttons, button pages and deck layouts to use with any simulation software. Next to that, built in extension mechanism allow developers to bring their own creations to Cockpitdecks.
+Items here are more in a wish list rather than completed development
+Try: button meta (name, etc.) + global parameters + activation attributes + representation attribute name are all at minimal indent level.
+Representation is a next indentation.
+Checl: set-dataref copies the button VALUE to the dataref
+Only two possibility:
+Save stats on deck, page, buttons in internal datarefs
+Save stats on connection, speed of collection, speed of processing, etc.
+(Try something "à la Oracle": wait time on what?)
+number of plane change
+number of definition reloads (deck reloads, page reload)
+time since last start/reload/longest
+number of page load
+number of load
+number of button activations
+Number of activation
+Number of render
+number of update
+If redis? save in redis?!
+ + + + + + + + + + + + + + + + + + + + + + +Rendering occurs as follow.
+Request to render always starts from the Button. The Button solely calls the procedure render() on itself.
+To render a Page for example, the Page will call render() on each button in turn. It may then call a supplemental procedure to fill unused icons with images.
+The Button render() call is quickly transferred to the Deck for specific rendering handling. So the Button asks the Deck to render itself:
+ # In the Button class
+ def render(self) -> None:
+ self.deck.render(self)
+
From the button index, the Deck will deduce rendering possibilities. It will then ask the button to supply the data for the rendering.
+ # In the Deck class
+ def render(self, button: Button) -> None:
+ button_representation = button.get_representation()
+ render_data = button_representation.render()
+ # transform render_data if necessary
+ # send it to device driver for handling (display, sound, coloring...)
+ self.device.handle_data(render_data)
+
In other words, the representation of the button is responsible to generate and provide whatever is necessary for the deck device driver.
+Let us take a very practical example.
+The deck device driver has a function to display an iconic image on a key. That function expects the index of the key to designate it unambiguously, and an image in JPG format with the proper size 90 × 90 pixels.
+If we use a generic representation that produces an image, the resulting image will be a 256 × 256 pixel transparent PNG image. We need to convert and resize that image before we can send it to the device driver.
+ def render(self, button: Button) -> None:
+ brep = button.get_representation()
+ render_image = brep.render()
+ # transform render_data if necessary
+ keyicon = render_image.resize([90, 90]).convert("RGB")
+ # send it to device driver for handling (display, sound, coloring...)
+ self.device.set_key_image(key=button.inedx, image=keyicon)
+
This is a very simple example, but it shows the flow of information and the sequence of calls to get the work done.
+To emit a sound, the representation render() function would be responsible for generating, for example, a sound file in WAV format. The deck render function would then pass that sound to the device driver play_sound() function that expects a sound file to play.
+To color a LED, the representation render() function would be responsible for generating a color and a light intensity (in 0..1 value range). THe deck render function would then pass those data to the device driver turn_led_on(color, intensity) function to submit appropriate instruction to the device to turn the light on with the desired color and intensity.
+People familiar with internet web development knowledge can follow the process for (Virtual) Web Decks. The device driver of Web Deck (called VirtualDeck) is a relatively straightforward JSON message generator and ultimately sends the message to the browser for display. In the browser, JavaScript process decodes the message and interpret it to display an image, play a sound, or refresh an entire page. (Communication occurs in a WebSocket channel.)
+ + + + + + + + + + + + + + + + + + + + + + +Interactions with Cockpidecks enters the application through Events. Deck Events arrive from the user interaction with decks, Simulator Events arrive because of Simulator data modification. Both then follow the same execution path, performing actions and adjusting deck feedback.
+In the process, these events can be captured and saved for a later, for a replay of the same events for example.
+That's the purpose of the Replay feature in Cockpitdecks.
+Each interaction that occurred during the session has been recorded and can be replayed. It can be submitted to Cockpitdecks in a similar way it was submitted when interactions with the deck occurred. Simulator interactions are recorded as well but never replayed, as we expect the Simulator to respond to user interaction in a similar fashion each time.
+Replay optionally respect the original timing.
+ + + + + + + + + + + + + + + + + + + + + + +Improve cockpitdecks.
+ + + + + + + + + + + + + + + + + + + + + + +Cockpitdecks introduced the concept of a Value.
+A Value defines where it gets its value from, and make its value always available through the simple abstraction.
+Every entity that can have a value uses this abstraction.
+The value of a Button,
+The value of a chart or sparkline,
+The value of an Annunciator part.
It is a dynamic entity. It does not store any value. It just know where to gets its value from and gets it.
+It is up to the entity that uses the value to keep a copy, see if it has changed, keep the last ten values… The Value abstraction only knows where and how to find its value when asked to provide it.
+A Value can report information about its behavior, like for instance the list of datarefs that are necessary to compute its final value.
+The Value entity performs necessary variable substitution, computations if there is a formula, and can also take care of writing the value to an X-Plane dataref.
+Here is the list of attributes that are inspected by a Value to determine its value.
+Attribute | +Definition | +
---|---|
dataref |
+Single Dataref, monitored if coming from X-Plane | +
formula |
+Reverse Polish Notation expression with reference to Cockpitdecks variables such as datarefs, internal datarefs, and internal states. | +
multi-datarefs (or datarefs , plural form) |
+List of datarefs that are monitored | +
string-dataref (singular form) |
+String Datarefs | +
string-datarefs |
+List of String Datarefs fetched as string through a Cockpitdecks helper plugin. | +
set-dataref |
+Dataref where the value is written to | +
any-attribute |
+If an attribute is added, Cockpitdecks will look into this very particular attribute for variable substitution. See below. | +
Cockpitdecks will look into known additional attributes for variable substitution. Additionaly, a button designer can ask that its particular attribute be scanned as well.
+Here is a typical example of such variable scanning:
- index: 5
+ name: SQUAWK00XX
+ type: none
+ formula: ${sim/cockpit/radios/transponder_code} 100 / floor
+ text:
+ text: ${formula}
+ text-format: "{:02.0f}"
+ text-font: 7-segment-display-extended.otf
+ text-size: 50
+ text-position: rm
+ text-color: khaki
+ text-bg-color: (40, 40, 40)
+
In the above example, attribute text
will be scanned for more datarefs. The attribute that gets scanned always has the same name as the main attribute:
text:
+ text: "text to be scanned for ${datarefs}"
+
or
+any-attribute:
+ any-attribute: "additional attribute to be scanned for ${datarefs}"
+
A Value will always look into the following attributes:
+- Text
+- Formula
+- Annunciator parts
Web Decks are designed with simple standard web features, are rendered on an HTML Canvas, uses standard events to report interaction through basic JavaScript functions.
+The application that serves them is a very simple Flask application with Ninja2 templates. The Flask application also runs the WebSocket proxy.
{
+ "code": code,
+ "deck": name,
+ "meta": {
+ "ts": datetime.now().timestamp()
+ }
+}
+
Code is interpreted by the deck. Codes are:
+meta
data is a python dictionary serialized into JSON (mostly name, value pairs). It can contain any arbitrary serialisable items.
It can be a key image, or a «hardware» image.
+{
+ "code": 0,
+ "deck": name,
+ "key": key,
+ "image": base64.encodebytes(content).decode("ascii"),
+ "meta": {
+ "ts": datetime.now().timestamp()
+ }
+}
+
It can be a key image, or a «hardware» image.
+{
+ "code": 2,
+ "deck": name,
+ "sound": base64.encodebytes(content).decode("ascii"),
+ "type": "wav",
+ "meta": {
+ "ts": datetime.now().timestamp()
+ }
+}
+
{
+ "code": code,
+ "deck": name,
+}
+
Code values:
+{
+ "code": 0,
+ "deck": deck,
+ "key": key,
+ "event": value,
+ "data": data
+}
+
Technically speaking, web decks are very simple browser entities. The web representation is an HTML Canvas. The background image of the deck is laid out as the background image of the canvas. Deck icons are images laid over the background image at precise size and positions. Nothing less, nothing more.
+Another special kind of icon images can be generated by Cockpitdecks especially for web decks. They are called hardware representations. They behave exactly like other representations, but they only exists for web decks. They usually have particular sizes and positions, and their drawing is sometimes complex.
+Web decks communicate with Cockpitdecks through standard WebSocket.
+The connection is established or re-established on startup of Cockpitdecks. Cockpitdecks is aware of the web decks connected to it and only update web decks when necessary. There should never be a need to refresh a web page containing a web deck.
+ + + + + + + + + + + + + + + + + + + + + + +Here is a suggested workflow for web deck design.
+Ideally, X-Plane simulator should be running to get live response data.
+Get a background image. PNG
or JPEG
only.
Place it in
+<Aircraft>/deckconfig/resources/decks/images/<image-name>.png
+
Start cockpitdecks for that aircraft:
+$ cockpitdecks-cli <Aircraft>
+
Cockpitdecks will start the application server, notice the available background image and Deck Designer will be available.
+Head to the Deck Designer page at
+http://<hostname>:7777/designer
+
and select the above image.
+Add interactors like buttons, encoders, and hardware images. Resize interactors, position them over the background image, and name them.
+Double click inside the button to resize it.
+Click outside the button to deselect it.
+Press Delete key when selected to remove it.
+Double on the label to rename it. Press Enter to quit the edit text area.
+Save the layout. You can load it later if you wish and continue editing.
+We recommand creating a button named reload
and place it at a convenient location on the image.
Saving the layout will create a new Deck Type, and will add a new deck in the config.yaml file, like any other deck, and add it to the secret.yaml file as well.
+<Aircraft>/deckconfig/resources/decks/types/<image-name>.json
+<Aircraft>/deckconfig/resources/decks/types/<image-name>.yaml
+
Reload the decks, which will provoke the reload of virtual web decks as well.
+Web Deck Definitions
+Web deck definitions are located either in the Cockpitdecks code or in the aircraft deckconfig folder. On page reloads, web decks definitions located in the code are not reloaded. Web deck definitions in the aircraft folder are reloaded.
+Head to the web deck home page.
+http://<hostname>:7777/
+
Your new deck appears. In the web deck list, select the newly created deck it will open in a new window.
+Using the button designer create and test a new button for your new deck selectable at the top.
+Select the deck, give a name to a layout (default would be default if none provided), and to the page.
+If you followed our advise, there should be a button named reload
, the label we gave it in the Deck Designer.
Select reload as Activation.
+Select icon as Representation. Select icon named "reload.png".
+Press render to preview rendering.
+Press save to save the layout/page/button.
+Reload pages immediately preview the appearance on the new button.
+From now on, it is now possible to adjust any of the layout, or button definition, save them, reload and use the button.
+When happy with the final deck, I simply comment out the code of the reload button. You will need it later…
+index: reload
+type: reload
+icon: reload.png
+
Never ever forget that the goal of these designer tools is currently not to provide you with a final design ready to be used. One day may be. The above designer tools aim at providing you with skeleton files that contain data that is difficult to get or estimate, thereby removing numerous trial and errors attempts.
+The goal of the Deck Designer is to supply deck image positions and sizes for all items that need displaying on a web deck.
+The goal of the Button Designer is twofold:
+I hope both tools reach their goal and help you design buttons faster for your decks.
+One more thing…
+Never ever forget enjoy flying with your home made set up.
+If Cockpitdecks crashes or is not responding, just restart it. It will restart, reconnect, and reload necessary data. If failures are persistent, just drop us a mail with a description of the problem and Cockpitdecks.log
file.
Now just go and take off for new adventures.
+Using an external file watcher, it is possible to provoke a deck reload each time a file has been saved, using curl(1) to post a request for page reload to Cockpitdecks. There is a handy shell script that does exactly this using nodejs nodemon utility.
+$ nodemon -w aircrafts/*/deckconfig/resources/decks/types -e yaml --exec curl "http://127.0.0.1:7777/reload-decks"
+
From there one can:
+When the deck is completed, it is advisable to rename it.
+Change name and cross references to name in config, secret, and layout pages.
+ + + + + + + + + + + + + + + + + + + + + + +Cockpitdecks is «packaged» (in python's terminology) into a few packages to cleanly split dependencies and requirements.
+The main package contains Cockpitdecks core engine and virtual web decks.
+The following simulator packages are available:
+The following (physical) deck packages are availalble:
+The following extension packages are also available:
+A single extension can be installed as such:
+pip install 'cockpitdecks_ext @ git+https://github.com/devleaks/cockpitdecks_ext.git'
+
where cockpitdecks_ext is the extension package name
+or
+pip install 'cockpitdecks[demoext] @ git+https://github.com/devleaks/cockpitdecks.git'
+
where demoext is the extension name.
+Each extension lives its own evolution and maintenance part. Requirements are precisely set and monitored regularly to ensure smooth cooperation between all packages.
+X-Plane Simulator Extension
+Currently, X-Plane simulator is the only simulator option available. As such, it is included in the core Cockpitdecks installation. It is not necessary to install it separately.
+Deck-specific extensions contain both physical deck and virtual web decks. The reason is that some virtual web deck extensions extensively rely on deck device drivers.
+ + + + + + + + + + + + + + + + + + + + + + +Cockpitdecks discovers about deck capabilities through a Deck Type structure.
+A deck is presented to Cockpitdecks through a deck definition file called a Deck Type. The deck definition file describes the deck capabilities:
+Here is for example, a deck configuration file for a Loupedeck LoupedeckLive device.
+# This is the description of a deck's capabilities for a Loupedeck LoupedeckLive device
+#
+---
+name: LoupedeckLive
+driver: loupedeck
+buttons:
+ - name: 0
+ action: push
+ feedback: image
+ image: [90, 90, 0, 0]
+ repeat: 12
+ - name: left
+ action: swipe
+ feedback: image
+ image: [60, 270, 0, 0]
+ - name: right
+ action: swipe
+ feedback: image
+ image: [60, 270, 420, 0]
+ - name: 0
+ prefix: e
+ action: [encoder, push]
+ feedback: none
+ repeat: 6
+ - name: 0
+ prefix: b
+ action: push
+ feedback: colored-led
+ repeat: 8
+ - name: buzzer
+ action: none
+ feedback: vibrate
+
Attribute | +Definition | +
---|---|
name | +Name used inside Cockpitdecks to identifying the deck model. | +
driver | +Keyword identifying the deck software driver class. (See main drivers class above.) | +
background | +The background attribute is an optional attribute only used by web decks. It specifies a background color and/or image to use for web deck representation. See explanation and exemple below. |
+
buttons | +The Buttons contains a list of Deck Button Type Block descriptions.This attribute is named Buttons, with Button having the same meaning as in Cockpitdecks. A Deck Type Button is a generic term for all possible means of interaction on the deck: 1. Keys to press, 2. Encoders to turn, 3. Touchscreens to tap or swipe 4. Cursors to slide A list of button types, each ButtonType leading to one or more individual buttons identified by their index, built from the prefix , repeat , and name attribute. See below. |
+
A Deck Type Button Block defines either a single button, or a group of identical buttons. For example, if a deck has a special, unique, «Escape» button, it can be defined alone in a Deck Type Button Block. Similarly, if a deck consist of a grid of regularly spaced 6 by 4 keys that are all the same, they can also be defined in a single Deck Type Button Block.
+Attribute | +Defintion | +
---|---|
name | +Name of the button type. The name of the button type is - either the final name of the button, like touchscreen , when there is a single button with that name on the deck,- or an integer value that will be used to build the button names, in the case the block defines a sets of identical buttons. |
+
actions | +Interaction with the button. Interaction can be: - none : There is no interaction with the button. It is only used for display purpose. (none interaction can be omitted.)- press : Simple press button that only reports when it is pressed (one event)- push : Press button that reports 2 events, when it is pushed, and when it is released. This allow for "long press" events.- swipe : A surface swipe event, with a starting touch and a raise events.- encoder : A rotating encoder, that can turn both clockwise and counter-clockwise- cursor : A linear cursor (straight or circular) delivering values in a finite range.Action can ba a single interaction or an array of interactions like [encoder, push] if a button combines both ways of interacting with it. |
+
feedbacks | +Feedback ability of the button. Feedback can be: - none : No feedback on device, or direct feedback provided by some marks on the deck device. (none feedback can be omitted.)- image : Small LCD iconic image.- led : Simple On/Off LED light.- colored-led : A single LED that can be colored.- multi-leds : Several, single color, LED on a ramp.- encoder-leds : Special encoder led ramp for X-Touch Mini (4 modes)- vibrate : emit a buzzer sound. |
+
repeat | +In case of a set if identical buttons, repeat if the number of time the same button is replicated along width (x) and height (y) axis.If only one value is supplied, it is supposed to be [value, 1] array. For vertical layout, specify [1, value] instead. |
+
An Action is a keyword that represent a physical mean of interaction with a device:
+none
: There is no interaction with the button. It is only used for display purpose. (none
interaction can be omitted.)press
: Simple press button that only reports when it is pressed (one event)push
: Press button that reports 2 events, when it is pushed, and when it is released. This allow for "long press" events.swipe
: A surface swipe event, with a starting touch and a raise events.encoder
: A rotating encoder, that can turn both clockwise and counter-clockwisecursor
: A linear cursor (straight or circular) delivering values in a finite range.A Feedback is a keyword that represent a physical mean for a deck to communicate some information (i.e. provide some feedback):
+none
: No feedback on device, or direct feedback provided by some marks on the deck device. (none
feedback can be omitted.)image
: Small LCD iconic image.led
: Simple On/Off LED light.colored-led
: A single LED that can be colored.multi-leds
: Several, single color, LED on a ramp.encoder-leds
: Special encoder led ramp for X-Touch Mini (4 modes)vibrate
: emit a buzzerAction and Feedback keywords are used to express requirements in respectively Activation and Representation.
+For example, an Activation will tell, by listing Actions, which types of interaction it requires.
+class LightDimmer(Activation):
+ """Customized class to dim deck"""
+
+ ACTIVATION_NAME = "dimmer"
+ REQUIRED_DECK_ACTIONS = [DECK_ACTIONS.PRESS, DECK_ACTIONS.LONGPRESS, DECK_ACTIONS.PUSH]
+
+ def __init__(self, config: dict, button: "Button"):
+
A deck button that can be used for the LightDimmer activation must have one of the listed action:
+name: Virtual Deck
+driver: virtualdeck
+buttons:
+ - name: 0
+ prefix: e
+ repeat: [1, 3]
+ action: [encoder, push]
+ dimension: 27
+ layout:
+ offset: [45, 115]
+ spacing: [0, 41]
+
Same principle applies to Representation and Feedback.
+In the case of a single button, the name of the button will be touchscreen
and that name needs to be unique for the deck type.
name: touchscreen
+
In the case of a set of identical buttons, the name of the button will be built from other attributes:
+name: 5
+prefix: k
+repeat: [4, 3]
+
Names of buttons will be: k5
, k6
, k7
, … k16
.
Trick
+If a deck has a vibrate capability, it is advisable to declare it as a separate button of interaction, and use that button like any other. Vibrate is a feedback mechanism.
+The above Deck Type Button Block attributes are necessary for all decks, both physical and web decks. Web Decks also contain an additional series of attributes that drive the drawing of the deck in a web navigator window.
+Web Deck Drawings
+For simplicity, Web Deck Drivers are drawn on an HTML Canvas, which is a pixel-driven drawing space. Web Decks are drawn with images and drawing instructions that use the pixel as a unit for display.
+Web decks can have the following types of interactive buttons:
+When rendered in a browser window, web deck interaction means are materialised through a changing pointer cursor (arrow, curved arrow (encode), single dot (push), double dot (pull), etc.)
+Background Deck Type Attribute
+Please read above in this page the background
Deck Type attribute used to specify a background image to use for web deck display.
Attribute | +Definition | +
---|---|
dimension | +The dimension attribute can be a single integer value or a list of two values. It determine the size of the button has drawn on the Web deck. If the feedback visualisation is an image , the image attribute specifies the characteristics of the image. X is horizontal and correspond to the width , Y is vertical and correspond to the height . |
+
layout | +Layout of the buttons on the web deck canvas. - Offset - Spacing Buttons will be arranged at regular interval, starting from Offset, with supplied spacing between the buttons. Button sizes are specified in the Dimension attribute. |
+
hardware | +Configuration information for a specific drawing representation of this hardware button. | +
empty-button | +Minimal Button definition to create an empty, dummy button. This dummy button will becreated and used to generate an "empty" hardware representation (completely off ). (In other words, if a button with hardware representation is not defined, this definition will be used to create a button.) See below. |
+
options | +Comma-separated list of options, a single option can either be a name=value, or just a name, in which case the value is assumed to be True.options: count=8,active sets options count to value 8, and active to True. active is equivalent to active=true . |
+
background
In addition to the above button definitions, a deck type may contain a background
attribute. This attribute is only used by web decks. The background attribute defines the background of the web page where the web deck will be rendered. The background can either be
Attribute | +Definition | +
---|---|
image |
+Name of a PNG image, with extension. No default. | +
color |
+Color of the background of the web page. No default. | +
size |
+Array of two values with width and height of the web canvas. Defaults to (200, 100) pixels. | +
overlay |
+Static text or image overlay. Not implemented yet. | +
Some deck buttons need a special representation or drawing to visually reproduce the physical deck equivalent button. Examples of such special representations are
+These highly specific « drawings » are performed on side representations called Hardware Representations.
+Technically speaking, they behave very much like LCD representations:
+Hardware Representations need to know how to represent themselves in case they are not used or defined on a page. To present nicely, Cockpitdecks needs to know how to draw an "undefined", unused Hardware Representation. To do this, Cockpitdecks uses a trick: It dynamically create an dummy placeholder button from the Empty Button Definition for its Hardware Representation. Basically, only two attributes need to be defined: A type (often set to none) and an attribute that tells its Hardware Representation. Optionally, a default, initial value can be supplied. Sometimes, some mandatory or optional Hardware Representation attributes need to be supplied as well. Here is an exemple of a simple LED representation.
+hardware:
+ type: virtual-xtm-led
+ empty-button:
+ type: none
+ led: single
+ initial-value: 1
+
name: Virtual Deck
+driver: virtualdeck
+buttons:
+ - name: left
+ action: [push, swipe]
+ feedback: image
+ dimension: [52, 270]
+ layout:
+ offset: [96, 78]
+ options: corner_radius=4
+
name: Virtual Deck
+driver: virtualdeck
+buttons:
+ - name: 0
+ prefix: e
+ repeat: [1, 3]
+ action: [encoder, push]
+ dimension: 27
+ layout:
+ offset: [45, 115]
+ spacing: [0, 41]
+ - name: 3
+ prefix: e
+ repeat: [1, 3]
+ action: [encoder, push]
+ dimension: 27
+ layout:
+ offset: [624, 115]
+ spacing: [0, 41]
+
On startup, Cockpitdecks reports which deck types are available:
+Cockpitdecks 12.1.1.20241002 © 2022-2024 Pierre M
+Elgato Stream Decks, Loupedeck decks, Berhinger X-Touch Mini, and web decks to X-Plane 12.1+
+
+INFO start.py:<module>:248: Initializing Cockpitdecks..
+INFO xplane.py:init:745: aircraft dataref is sim/aircraft/view/acf_livery_path
+WARN xplane.py:add_datarefs_to_monitor:1171: no connection
+INFO xplane.py:add_datetime_datarefs:803: monitoring simulator date/time datarefs
+INFO cockpit.py:add_extension_paths:337: added extension path /Users/pierre/Developer/fs/cockpitdecks_ext to sys.path
+INFO cockpit.py:add_extension_paths:342: loaded package cockpitdecks_ext and all its subpackages/modules (recursively)
+INFO cockpit.py:init:234: available simulator: X-Plane
+INFO cockpit.py:init:237: available deck drivers: xtouchmini, virtualdeck, loupedeck, streamdeck
+INFO cockpit.py:load_deck_types:999: loaded 20 deck types (Virtual Deck for Development, LoupedeckLive...), 12 are virtual deck types
+INFO cockpit.py:scan_devices:507: device drivers installed for xtouchmini 1.3.6, virtualdeck (included), loupedeck 1.4.5, streamdeck 0.9.5; scanning for decks and initializing them (this may take a few seconds)..
+INFO cockpit.py:scan_devices:532: found 1 xtouchmini
+INFO cockpit.py:scan_devices:532: found 1 loupedeck
+INFO cockpit.py:scan_devices:532: found 3 streamdeck
+INFO start.py:<module>:250: ..initialized
+
Cockpitdecks discover about its computer host and its extensions through a global configuration file called its environment.
+The environment consists of a few attributes that tells Cockpitdecks about things it cannot discover on its own.
+Most of the above information can be communicated to Cockpitdecks either through operating system environment variables or in the global configuration file.
+Recall that Cockpitdecks can run either on the same host as the simulation software, or on a separate host connected through the local area network to the host running the simulator.
+If the simulation software is located on the same host, the XP_HOME
environment variable is the operating system folder path to the home directory of the software.
If the simulation solftware runs on another computer, XP_HOME does not need to be set or must be set to None.
+A button is a piece of a deck a user can use to provide some interaction.
+It can be a simple button to press, a small LCD button, an encoder to turn, or a touch screen that can be swiped with multiple fingers.
+A Deck is a piece of hardware connected to a computer to provide some input by means of buttons, encoders, cursors… A Deck also provide some feedback to the user through colored LED lights, small LCD icon screens, or by emitting sound and vibration.
+A Web Deck is an emulation of a deck in an internet browser window. Cockpitdecks provides a set of web decks that emulate existing decks.
+Originally, web decks where created to speed up deck page creation and arrangement. But web decks turned out to be so convenient that they are now part of Cockpitdecks. Some users actually only use web decks, without any physical ones.
+But it is possible to design as create any web deck one can imagine, built from basic components like buttons, encoders, led, and LCD displays. As a proof of this concept, there a entire overhead panel, fully reactive and responsive to the simulator changes.
+Cockpitdecks allow a designer to create and use any web deck, in the context of the Cockpitdecks application.
+A Layout is a collection of pages that can be displayed on a deck. On startup, a deck must tell Cockpitdecks which Layout it is going to use.
+A Page is a collection of buttons that are displayed on a deck at a moment.
+A deck can display different pages of buttons. A button on a page can be used to switch or change a page, leading to a literally infinite number of pages.
+All pages that can be displayed on a deck are grouped in a folder called the Layout of the deck.
+Cockpitdecks is the name of the application used to control decks connected to a computer.
+The Cockpit is the main entity of Cockpitdecks that controls most parts of the application, from the start to its termination.
+An Activation is an action that is executed when interaction occurs on a deck.
+A Representation is an abstraction of an instruction sent to a deck to change its appearance. It can be turning a LED light on or off, playing a sound, or dynamically generating an iconic image and sending it for display on a deck key.
+A Simulator Data is a variable value kept and modified in the simulator. Cockpitdecks expressed interest in receiving a notification when the value of the variable changes. The variable is accessed by its name.
+A Simulator Instruction is something the simulator software understand to perform an action. Cockpitdecks generate instructions and submit them to the simulation sofwtware for execution.
+See below.
+An Event is created to notify Cockpitdecks that something occurred.
+Simulator events are either sent by the simulator software or created by Cockpitdecks when something occurred in the simulator. There are two major types of Simulator Events:
+Deck Events are produced by deck driver software to notify Cockpitdecks that interaction occurred on the deck: A button was pressed, à encoder was turned, a cursor was slid…
+An Instruction is a request emitted by Cockpitdecks to perform an action.
+A Simulator Instruction is an order sent to the simulator to alter its behavior. There are two major types of instructions.
+A Command is an instruction to perform an action.
+This included instructions that simulate key press.
+The other type of Simulator Instruction is a request to update a value made accessible by the simulator.
+The Maestro of Cockpitdecks is the Cockpit entity. Internal components are interchangeably called Cockpitdecks items or Cockpit items (word is shorter !).
+Cockpit or Cockpitdecks or simply Internal Data is an internal Cockpitdecks value mainly kept for statistical or introspection purposes. Button internal state is maintained inside a few Cockpitdecks internal data. (CockpitData, CockpitdecksData, InternalData are synonyms.)
+End-users and Cockpitdecks developer can define and use internal cockpitdecks data. They all behave like simulator data, propagating changes to their listeners.
+Cockpit or Cockpitdecks Instructions are instructions triggered and used inside Cockpitdecks and are not forwarded to the simulator. Cockpitdecks instructions are:
+Cockpit or Cockpitdecks Events are generated internally by Cockpitdecks to notify interested parties that something occurred internally, like loading a new page, reloading the decks, or changing the decks because a change of aircraft was detected.
+A Dataref is a simulator data inside the X-Plane flight simulator.
+A SimVar is a simulator data from Microsoft Flight Simulator. There are several types of SimVar. Please refer to the Flight Simulator SDK for more information.
+Names are self explanatory 😉.
+angular_step
+base_fill_color
+base_size
+base_stroke_color
+base_stroke_width
+base_underline_color
+base_underline_width
+bgcolor
+button_dent_extension
+button_dent_size
+button_dents
+button_fill_color
+button_name
+button_size
+button_stroke_color
+button_stroke_width
+button_underline_color
+button_underline_width
+cockpit_color
+cockpit_texture
+code
+datarefs
+decor
+decor_color
+decor_width_horz
+decor_width_vert
+double_icon
+draw_labels
+draw_left
+draw_scale
+draw_ticks
+draw_up
+handle_base_fill_color
+handle_fill_color
+handle_off_fill_color
+handle_off_stroke_color
+handle_off_stroke_width
+handle_size
+handle_stroke_color
+handle_stroke_width
+handle_tip_fill_color
+hexabase
+icon_color
+icon_texture
+invert
+label_opposite
+mark_fill_color
+mark_off_fill_color
+mark_off_stroke_color
+mark_stroke_color
+mark_underline_color
+mark_underline_outer
+mark_underline_width
+mark_width
+move_and_send
+needle_color
+needle_length
+needle_start
+needle_tip
+needle_tip_size
+needle_underline_color
+needle_underline_width
+rotation
+screw_rot
+switch
+switch_length
+switch_style
+switch_width
+texture
+three_way
+tick_color
+tick_from
+tick_label_color
+tick_label_size
+tick_label_space
+tick_labels
+tick_length
+tick_space
+tick_steps
+tick_to
+tick_underline_color
+tick_underline_width
+tick_width
+top_fill_color
+top_stroke_color
+top_stroke_width
+type
+vertical
+
Cockpitdecks extensively uses X-Plane UDP for communicating with the simulator. X-Plane UDP suffers from shortcomings, one being its inability to collect several values of an array at once. Values need to be fetched one a a time, which can be not only tedious but also have an impact on performance by requesting numerous single values.
+UDP Dataref Emission and Performance
+We reasonably established a empiric limit around 50 to 80 individual datarefs values before it has a significant impact not only on X-Plane but also on Cockpitdecks.
+To circumvent this limitation, Cockpitdecks provides a simple mechanism to fetch entire arrays at once. However, this mechanism has voluntarily be limited to arrays of bytes, i.e. character strings. (But the mechanism could be used to fetch arrays of numeric values as well.)
+The mechanism relies on a small XPPython3 plugin that collects values of datarefs of type string (array of bytes) and broadcast the values on a UDP port, very much like X-Plane UDP does for float values.
+To use datarefs of type string, a button has to tell Cockpitdecks it want to use such a dataref.
+index: 1
+name: AIRCRAFT
+label: Aircraft
+type: none
+string-datarefs: ["sim/aircraft/view/acf_ICAO", "sim/aircraft/view/acf_tailnum"]
+text: "${sim/aircraft/view/acf_ICAO}\n${sim/aircraft/view/acf_tailnum}"
+text-font: B612-Bold
+text-size: 18
+
Given the particular nature and treatment of string datarefs, they have to be explicitely defined with a specific string-datarefs
attribute which expects a list of datarefs of type string as a value.
These datarefs will be collected by Cockpitdecks’ custom mechanism and can then be used like any other datarefs.
+A string dataref must be declared first with an explicit string-datarefs
attribute.
If Cockpitdecks first encounter a statement like this:
+text: ${some/dataref}
+
it will create a reference to a non string dataref some/dataref
.
It Cockpitdecks later finds a definition
+strings-daterefs: [ some/dataref ]
+
it will not create a string dataref, because an earlier definition of the same dataref declared it as a non string dataref. The solution is to never forget to explicitely declare string datarefs as they occur:
+strings-daterefs: [ some/dataref ]
+text: ${some/dateref}
+
To circumvent limitations of UDP dataref fetch, Cockpitdecks is bundled with a plugin that reads "string"-typed datarefs efficiently and post them on a UDP port, as a single decoded string value, very much like other dataref values sent by the simulator.
+The String Dataref Poster is a XPPython3 plugin that reads the string-datarefs
attribute in the main Cockpitdecks configuration file. The string-dataref
attributes is a list of datarefs that are supposed to be of type "array of bytes", each byte being assumed to be a character ASCII code.
string-datarefs:
+ - AirbusFBW/FMA1w
+...
+ - AirbusFBW/FMA3a
+use-default-string-datarefs: True
+
The String Dataref Poster will ask the plugin to post the value of each of those datarefs at regular intervals, typically every 5 seconds.
+String dataref collection is an expensive operation that requires numerous dataref reads. It should be scheduled to run periodically but not too often.
+The XPPython3 plugin proceeds as follow. For the aircraft currently being used by X-Plane, it reads the Cockpitdecks configuration in the deckconfig
folder, if any.
If it finds one, it inspect decks, their layouts, pages in these layouts, and ultimately buttons being used on each page, scan for string-datarefs
attributes in button definitions, and collects string datarefs that are used. It then collects the values of those datarefs and publish them on a dedicated UDP port, all at once at a regular interval. No more, no less.
Cockpitdecks treats string datarefs a little bit differently. When encountered in a button definition, they are created first with their particular type (string). Other datarefs are created after.
+Also, string dataref values are not collected throught X-Plane UDP but by another similar mechanism running on another UDP port, collecting values sent by the XPPython3 plugin.
+A part from those internal differences, string datarefs behave like any other datarefs, notifying the buttons that rely on them when their value is updated.
+ + + + + + + + + + + + + + + + + + + + + + +X-Plane UDP has some shortcomings that prevent some operations with decks.
+To circumvent this, Cockpitdecks provides a small python plugin called the Cockpitdecks Helper plugin, that need to be installed into X-Plane. The Cockpitdecks Helper plugin will execute some instructions on behalf of the Cockpitdecks application. Cockpitdecks Helper plugin just need to be installed and will provide its services to Cockpitdecks.
+If not installed, some of the commands inside Cockpitdecks will work properly.
+Cockpitdecks Helper plugin is an in-process plugin, running inside X-Plane, while Cockpitdecks is an out-of-process executable running independently of X-Plane.
+Here are the functions the Cockpitdecks Plugin offers to complement X-Plane UDP access.
+Some commands cannot be executed directly through UDP. For exemples, commands that have a start and an end cannot be started or ended though UDP. It is an X-Plane UDP limitation.
+To execute long press commands, the Cockpitdecks Helper plugin needs to be installed in XPPython3 PythonPlugins
folder.
X-Plane UDP only allows to fetch dataref values one by one. Retrieving a string is a tedious process because each character has to be fetched individually.
+To collect string-typed datarefs, the Cockpitdecks Helper plugin needs to be installed in XPPython3 PythonPlugins
folder. It collects the entire string and then broadcasts it as a whole string, not individual characters.
See String Datarefs for details about this.
+To circumvent limitations of UDP, a plugin is necessary to execute commands that require to be activated for a long time (like long push commands).
+For each long push command, the plugin will create a pair of commands that will be issued at the beginning of the command, and at the end.
+The plugin scans deckconfig folder for button definitions that contain longpress
activation. It then creates a pair of commands for the command specified in the command attribute.
- index: 27
+ type: long-press
+ label: "APU\nTEST"
+ push-switch:
+ button-size: 120
+ button-fill-color: black
+ button-stroke-width: 0
+ witness-size: 0
+ command: AirbusFBW/FireTestAPU
+ formula: 1
+
The above button definition will create the pair of commands
+AirbusFBW/FireTestAPU/begin
and
+AirbusFBW/FireTestAPU/end
AirbusFBW/FireTestAPU/begin
will be called when the button is pressed, AirbusFBW/FireTestAPU/end
when released.
The interaction with X-Plane is two folds.
+But let's first explain how Cockpitdecks connects to X-Plane.
+X-Plane connector through UDP uses the following threads of execution to permanently collect dataref values from X-Plane as requested by deck displays.
+The connect loop monitors the connection to X-Plane.
+If there is no connnection, if it cannot connect to X-Plane to submit a command, or if it does not receive any data periodically, the connect loop attempts to connect until it succeeds.
+When a new connection is established, the dataref collection loop is started and buttons get notified of dataref value changes.
+The connect loop is created and managed by the XPlaneBeacon
class.
When a button is activated, Cockpitdecks will either submit a command, or ask to change the value of a writable dataref, or both.
+It will also, optionally, execute another view
command. The purpose of the view command is to modify the focus proposed on the screen consecutively to the first command executed. For example, when the Status
ECAM button is pressed, the view
command changes to show the ECAM display.
Dataref value monitoring occurs in two steps.
+First, when a page is loaded in a deck, all dataref it uses are registered with the Dataref Monitor.
+Inside the dataref monitor, the dataref collection loop permanently collects data from X-Plane and notifies buttons of dataref value updates.
+If it cannot connect to X-Plane, or if the data collection otherwise fails, a time out occurs.
+When several times out have occurred, the collection process disconnects and terminates. (There is no need to monitor dataref values if we cannot collect them.) It will be restarted by the connect loop once a new connection is established.
+The dataref collection loop is created and managed by the XPlaneUDP
class.
The dataref collection loop immediately compare a dataref value with its previous value and enqueues a dataref change event into the dataref change queue.
+Decks sometimes have up to 30 buttons, and simulator pilots sometimes have several decks. During developments, Cockpitdecks controlled up to 6 decks. This led to the monitoring of an average of 80 different datarefs to change the appearance of 80 buttons or LED encoders.
+We only request dataref values to be sent at the lowest emission rate, that is once per second.
+A UDP packet of values contains at most 14 or 15 values. It takes a few packets to get all dataref values.
+We experimentally observed that there is a performance limit of about ~100 datarefs that can be requested from X-Plane. After that, UDP packets will be emitted, but with some noticeable delay (up to a few seconds). And since they will be emitted late, their value will no longer reflect the current X-Plane value.
+ + + + + + + + + + + + + + + + + + + + + + +X-Plane is the name of a flight simulation software edited by Laminar Research.
+For developers, X-Plane offers the following facilities:
+X-Plane maintains and exposes a large number of internal variables, called datarefs. X-Plane. For a running instance of X-Plane, there can be as much as 10,000 datarefs.
+X-plane also produces a limited number of internal messages to notify of occurence of special events like another plane has been loaded by the user, orr the VR mode has been enabled. X-Plane messages are related to the X-Plane environment and program. There is no message related to the simulation itself. There is no message to tell a plane has taken off, or brought its landing gear down. There are only messages related to the program: New scenery was loaded, new plane was loaded, new sound bank was loaded, X-Plane has crashed (!), etc.
+Cockpitdecks has three methods to get variable values from X-Plane.
+When started with no aircraft folder supplied, Cockpitdecks starts a demonstration web deck called Cockpitdecks. It is a 4x3 deck with encoders at the bottom. It demonstrate several of Cockpitdecks capabilities. The definition of the buttons can be used as a basis, as examples, to define yours.
+Cockpitdecks can be extended in several directions.
+The most common extension will be adding custom Representations.
+A Cockpitdecks developer may add a new type of feedback, very much like the Weather buttons. Those buttons do not exist in aircrafts, they were created to artificially enhance the simulation experience and ease other parts of the simulation. Similarly, there are endless opportunities to create other types of buttons and materialize them on a deck though Cockpitdecks. In Cockpitdecks, this is performed by mainly creating new Representations.
+New deck models may appear. Adding a new deck model highlights necessary steps.
+In addition of defining a new deck model, it might be necessary to add a new method of interaction that this deck may provide. In this case, it might me necessary to develop specialized, custom activation mechanism not foreseen by the current Cockpitdecks version.
+Core class Simulator can also be extended to connect Cockpitdecks to another simulation software. In this case, interaction models imposed by Cockpitdecks (datarefs, commands, UDP connection) inspired by the X-Plane flight simulator software may have to be adjusted as well.
+The above descriptions enumerates parts of Cockpitdecks that can be extended. To integrate those extensions into Cockpitdecks, there are two mechanisms.
+The first mechanism is limited to simpler extensions like providing new deck types or models. In this case, it is sufficient to create and provide a new Deck Type file. This also applies to defining new web decks.
+First, in normal operations, when an aircraft configuration is loaded, Cockpitdecks will search for deck types in the
+<Aircraft Folder>/deckconfig/resources/decks
+
folder. If new deck types are found, they are loaded and made available.
+Second, if a new deck type is available for all aircrafts, it is possible to create a similar folder organisation at another location and to point the cockpitdecks environment variable to it.
+COCKPITDECKS_EXTENSION_PATH:
+ - /Users/xplane/cockpitdecks/mydecktypes
+
On this case, Cockpitdecks will look for a folder named decks/resources/types
at the above location and load deck types defined there.
The second extension mechanism requires adding (python) code to Cockpitdecks.
+In this case, the extension mechanism proceeds by providing extension packages to Cockpitdecks, either by pointing at a folder that contains the package, or by mentioning its name if the package has been loaded by another method.
+Providing extension by location:
+COCKPITDECKS_EXTENSION_PATH: /Users/xplane/cockpitdekcs/myextension/mypackage
+
will loaded package named mypackage
from the above folder. (In this case, the above folder path will be added to python sys.path
and package will be discovered from there.)
Providing extension name:
+COCKPITDECKS_EXTENSION_NAME: customext
+
will load package customext
.
Cockpitdecks will recursively load the entire extension packages on startup, discover and add extensions provided by those packages.
+Depending on the extension provided, discovery is achieved as follow:
+cockpitdecks.buttons.activation.Activation
class.cockpitdecks.buttons.representation.Representation
class.cockpitdecks.deck
class.cockpitdecks.Simulator
class.Cockpitdecks will discover daughter classes of the above core classes and add them to its collections of available resources.
+In addition to the above code, new deck types can be added like described above, by providing the following structure inside an extension package:
+<extension-name>.decks.resources.types
+
Resources files located in that module will be loaded as Deck Types.
+Cockpitdecks incudes a few developer specific activations that can be used to introspect Cockpitdecks while running.
+ + + + + + + + + + + + + + + + + + + + + + +In addition to real physical decks, Cockpitdecks offers Web Decks rendered in a browser window.
+Web Decks were first developed as a tool to speed up deck page creation, but Web Decks turned out to be fast and available everywhere, in particular on tablets.
+A Web Deck behaves like their physical counterparts, with limitations inherent to presentation in a browser window. In a nutshell, a web deck has an optional background image (or a uniform background color), and buttons laid over it. Buttons can be of four main types:
+A web deck is added like any other deck.
+Like its physical counterpart, it first must be named and defined, that is Cockpitdecks must know how many buttons are available, of what type, how can users interact with those buttons, etc. While this information is sufficient for physical decks, web decks need a little more information to express how buttons, encoders, and touchscreens are positioned on the deck. That is also where we supply a background image.
+Second, the named web deck need to be added to the list of decks available to an aircraft, in the deckconfig/config.yaml
file.
If a Web Deck is detected in an aircraft configuration, Cockpitdecks will automagically start a basic web server to present the Web Deck to the user. The index (home) page of the web server will present all web decks available to the user for that aircraft. Selecting on web deck will start it in another browser window.
+Web decks are very handy to design layout for decks a developer does not necessary owns.
+Web decks can be (almost) any physical deck represented in Cockpitdecks (most popular brands and models are actually provided with Cockpitdecks), or any next deck model of your fantasy. As an example and proof of concept, Cockpitdecks comes with a fully operational overhead panel for Toliss A321 neo aircraft. Yes, you read it right, you can have Toliss A321 overhead panel on a touch screen or tablet.
+Web decks that reproduce existing physical decks like Stream Decks and Loupedeck LoupedeckLive are bundled together with their physical counterparts. To use virtual Stream Decks, you must install the streamdeck extension to Cockpitdecks.
+Virtual decks need to be declared at two places:
+deckconfig/config.yaml
file of an aircraft.Web Decks communicate with Cockpitdecks through Websockets. A WebSocket proxy server control Interactions between Web Decks and Cockpitdecks.
+Web decks can be defined at two locations. Cockpitdecks defined a few web decks to help development of physical decks. They are provided with Cockpitdecks and are not meant to be altered by users.
+However, a cockpit designer may want to add her or his own web deck. To do so, and to prevent adding files to Cockpitdecks source code, it is possible to define additional web deck types in the deckconfig
folder of an aircraft.
deckconfig
+ ⊢ resources
+ ⊢ decks
+ ⊢ types
+ ⊢ custom_deck_type.yaml
+ ⊢ images
+ ⊢ custom_background_image.png
+
Virtual web decks are defined like any other deck. Their driver must be virtualdeck
. They contain additional attributes to render them on a HTML web Canvas like background image or color.
name: Virtual Deck 3×2
+driver: virtualdeck
+buttons:
+ - index: 0
+ action: push
+ position: [55, 25]
+ feedback: image
+ image: [96, 96]
+ options: rounded=8
+ - ...
+
+background:
+ color: "#222"
+ image: loupedeck.live.png
+ size: [800, 600]
+ overlays:
+ - text: Hello, world
+ position: [840, 40]
+ font: anexistingwebfontalreadyloaded
+ size: 20
+ color: white
+ - image: logo-transparent.png
+ position: [840, 40]
+
Please refer to the Deck Internals for references on how to create and define web decks.
+To use a web deck for a given aircraft, it need to be declared in the list of decks available for that aircraft.
+deckconfig/config.yaml
# Definition of decks for Toliss A321
+#
+aicraft: Toliss
+decks:
+ - name: Vdeck1
+ type: Virtual Deck 3×2
+ layout: devlayout
+
The same web deck definition can be used more than once to create similar decks:
+decks:
+ - name: Vdeck2
+ type: Virtual Deck 3×2
+ layout: test version
+
Web decks include their name in the messages they send to Cockpitdecks. This allows Cockpitdecks to identify the deck that sent the message.
+deckconfig/secret.yaml
If several web decks are running, it is necessary, like other decks, to specify their serial numbers in the secret.yaml file.
+Serial Number of Web Decks
+The serial number of web decks must be specified in the secret.yaml file. It can be any number or string, but it must be different for each web deck.
+Vdeck1: deck1
+Vdeck2: deck2
+
The Web Deck application server is automagically started when Cockpitdecks starts if there are web decks to serve.
+When started, the web decks server offers a Welcome page with all web decks available to the user. Selecting a deck starts it in another web navigator window.
+Here is a web deck, carefully designed to represent an existing Elgato Stream Deck MK.2 deck. Cheaper.
+This example shows that there is no limit on background and deck type definition if you are patient and meticulous. Here is a fully working exemple of Toliss A321neo Overhead Panel virtualized with Cockpitdecks.
+name: Virtual A321neo Overhead
+driver: virtualdeck
+buttons:
+ - name: apumaster
+ action: push
+ feedback: image
+ dimension: [40, 40]
+ layout:
+ offset: [560, 855]
+ - name: apustart
+ action: push
+ feedback: image
+ dimension: [40, 40]
+ layout:
+ offset: [560, 918]
+background:
+ color: black
+ image: a321neo.overhead.png
+
decks:
+ - name: A321 Overhead
+ type: Virtual A321neo Overhead
+ layout: overhead
+
buttons:
+ - index: apumaster
+ name: APUMASTER
+ type: push
+ annunciator:
+ size: full
+ model: B
+ parts:
+ B1:
+ text: "ON"
+ color: deepskyblue
+ framed: true
+ size: 60
+ formula: ${AirbusFBW/APUMaster}
+ command: toliss_airbus/apucommands/MasterToggle
+ - index: apustart
+ name: APUSTART
+ type: push
+ annunciator:
+ size: full
+ model: B
+ parts:
+ B0:
+ text: AVAIL
+ color: lime
+ formula: ${AirbusFBW/APUAvail}
+ B1:
+ text: "ON"
+ color: deepskyblue
+ framed: true
+ size: 60
+ formula: ${AirbusFBW/APUStarter}
+ command: toliss_airbus/apucommands/StarterToggle
+
Pay attention to the center lower annunciator, lightly white-framed. They are produced by Cockpitdecks and reflect the status of Toliss' annunciators.
+If buttons have been created for other, physical decks, designing the entire overhead panel is a matter of:
+Nothing more. Nothing less.
+You can then hang a touchscreen over your head and display the above web page full screen.
+Cost: 1 touch screen, glue. Protection helmet optional, depending on your trust in the glue.
+You can consider web decks as live, interactive, responsive images. You can press buttons on the image, Cockpitdecks will adjust the image and its overlays to reflect X-Plane status.
+Taxi safely.
+As explained, Web Deck were originally created has a development tools to speed up button creation and testing. It was suggested by Duane.
+Once we settle on an architecture, and made critical web-oriented decision (use of HTML Canvas), it took no more that 2 days to get it working! Mainly because of the strict Cockpitdecks architecture and concepts. A few more days were necessary to open up the creation of web decks for Cockpitdecks creators, and imagine Hardware Representation.
+As today, Cockpitdecks can work with no physical decks, with just Web Decks, even those that replicate existing deck models like Stream Deck and Loupedeck.
+Please note that web deck lead to Instructions. Currently, Instructions are limited to flight simulation to issue commands, change values, etc. Nothing would prevent a developer from creating Instructions that execute command at the operating system level, like opening a file or starting an application.
+ + + + + + + + + + + + + + + + + + + + + + +The project started from the multiplication of accessory devices. Some are very dedicated and allow for little flexibility. mini•COCKPIT devices fall into that category. Some other devices are very generic and allow for customisations. Stream decks, Loupedeck devices or other MIDI-based devices fall into this category.
+I created a single software to allow for the second category of devices to be used with X-Plane. This software relies on conventions to cope with all options and particularities of those devices. That is what I tried to bring into this project.
+The history of this project explains decisions and processes that were taken to cope with the diversity of devices.
+A first step was clearly to abstract particularities of device. Pressing keys, rotating knobs or encoders, sliders, touch screens are all different means to interact with some devices. Little iconic display, colored buttons, or multi-led ramps are all different means to communicate feedback to the user. This leads to two abstractions for interaction input (what is called Activation) and feedback output (what is called Representation).
+A second step was to isolate this software from all device particularities and specificities. This leads to abstractions such as Deck (make, models, device drivers to interact with the device) and Buttons (things a user interact with on a device). A simple abstract model describe the device capabilities and physical organisation (the Deck).
+A final step was to isolate all interactions with flight simulation software: Issuing commands and monitoring data values coming from it. This is done in a collection of specialised Simulator, Dataref, and Command abstractions.
+Other entities glue things together with concepts like the Cockpit which is a collection of one or more decks, and a Page that is a grouping of buttons represented at once on a deck.
+I hope this piece of software will allow you to make a better desktop cockpit and make your flight simulation more enjoyable.
+A Layout is a collection of Pages that will be displayed on that deck.
+Layouts were created to cope with different deck models. If you have a set of 30 commands, you can display them all on a 32 key deck on the same page. But you have to spread 30 commands on two pages of buttons if your deck can only display 16 buttons at a time. Same commands, but two different layouts.
+A Layout is a folder, inside the deckconfig
main folder. The Layout is named and addressed by the name of that folder.
The Layout folder contains the following files:
+ ⊢ live
+ ⊢ config.yaml
+ ⊢ page1.yaml
+ ⊢ page2.yaml
+
The Layout name is live
, it contains 2 pages.
config.yaml
FileThe config.yaml
file inside a layout folder defines Layout-level attributes. The file is optional.
# This is at layout level
+default-icon-color: (94, 111, 130)
+default-label-color: blue
+default-label-font: DIN Bold.ttf
+default-label-size: 13
+default-page-name: page1
+
Attribute | +Definition | +
---|---|
default-icon-color: blue |
+Optional. Default color to use for icon background. | +
default-label-color: white |
+Optional. Default color to use for layout labels. | +
default-label-font: D-DIN.otf |
+Optional. Default font to use for layout labels. | +
default-label-size: 13 |
+Optional. Default label size. | +
default-homepage-name |
+Optional. Default page name in layout. | +
The default values of attributes (like font, colors, and sizes) are fetched at the Cockpit level if they are not specified at the Layout level.
+Layout attributes are used for all pages in the layout, unless a Page refines the definition of one of these attribute.
+All other Yaml files in the folder are considered to be Pages in the layout.
+If a deck has no layout specified, Cockpitdecks will generate one with one default page that will display a logo image on the deck (if it is capable of displaying images…) and use the first available push button to toggle X-Plane Map On or Off.
+ + + + + + + + + + + + + + + + + + + + + + +A Page is a Yaml file. It defines is a collection of button definitions that will be installed and used on the deck at a given moment.
+A deck displays one Page of buttons and allow end-users to press those buttons to trigger actions. Actions to be performed when a button is manipulated are defined in the button definition, together with the appearance of the button on the deck. Actions are constrained by the type of push button or encoder. A push button cannot be rotated. The appearance of the button is also constrained by the feedback ability of the deck: Image icon, LED, colored LED, or, sometimes, no display at all.
+A Page contains the following attributes:
+name: Index
+buttons:
+ - index: knobTL
+ name: FCU Airspeed
+ type: knob
+ commands:
+ - sim/autopilot/airspeed_down
+ - sim/autopilot/airspeed_up
+ options: dot, nostate
+includes: views
+fill-empty-keys: true
+
Attribute | +Definition | +
---|---|
name |
+Name of the Page. Superceedes the file name. Case sensitive. If no name is given, the name of the page is the page file name (without the .yaml extension.)For a given layout, all pages must have different names, otherwise an error is reported, and the page with the same name is ignored. |
+
buttons |
+Mandatory. A list of button definitions. Please refer to the Button Section for details about button definitions. If there is no buttons attribute, the page as no button to represent and is ignored. |
+
includes |
+Includes is a list of other pages to include in this page. Included pages are first merged inside the main page, and then submitted for display and use. |
+
fill-empty-keys |
+Optional, default to False, whether to fill unused keys with a default button definition as a placeholder. The default value of some attributes (like font, colors, and sizes) is fetched at the Layout level if they are not specified at the Page level. |
+
default-* |
+Default values to be used at the Page-level for display. | +
The buttons
attributes contains all button definitions.
If no Page is found in the Layout folder, Cockpit deck will create a default page which consists of a logo displayed on the deck (if the deck is capable of displaying images).
+The first available button will be programmed to toggle the X-Plane Map On or Off.
+ + + + + + + + + + + + + + + + + + + + + + +Observables are data that is constantly monitored. When the data matches a criteria, a list of actions or commands is executed.
+For people familiar with the concept, it can be considered a if-this-then-that instruction. For example: If the weather data from the simulator indicates rain is falling on the aircraft, we can set the windshield wipers automatically.
+Observables are defined at the aircraft level.
+The file observables.yaml
is located in the deckconfig/resources
folder of an aircraft. It is loaded on startup.
observables:
+ - name: example
+ trigger: onchange
+ dataref: some/dataref/to/check
+ actions:
+ - command: do/some/action
+ delay: 5
+
The observables
attribute is a list of individual observables.
The trigger
attribute of an observable is a single dataref or a formula that is evaluated each time a dataref mentioned in the formula changes. The result of a the formula is compared to 0, i.e. True (different from zero) or False (equal to zero).
If the result of the formula is True, commands listed into the actions
attributes are executed.
Another method to trigger the flow of action(s) is to select the value changed mode. Actions get executed as the value of the dataref or of the computation has changed.
+The observable is the data that is monitored. It can either be a single dataref or a formula.
+The actions
attribute is a list of individual actions that gets carried out in sequence if the trigger attribute is True.
An action as the same attribute as a command carried out by a button:
+Rendering themes is a experimental features that allows a Cockpitdecks developer to provide different sets of default values.
+cockpit-theme: night
+
Theme default value is an empty string (no theme).
+If a theme is used, its name is prepended to attribute name:
+ theme-default-label-color: purple
+
If no such attribute is found, the default-label-color
attribute name is looked up (without the theme-
prepended.)
When a theme is defined, its name is prepended to some default values.
+Default values affected by themes are:
+cockpit-color
and cockpit-texture
color
. Example default-color
.texture
. Example annunciator-bg-texture
.font
. Example label-font
.theme: light
+# Alternate theme is 'dark'
+default-label-color: white
+dark-default-label-color: coral
+
The following resources are common to all buttons.
+Color can either be expressed by their name, as defined in the Python PILLOW package, or by a tuple of 3 or 4 values, representing red, green, blue, and optionally the transparency.
+All values should be in the [0..255] range. For colors, 0 is black, 255 is pure color; for transparency, 0 is transparent, 255 is opaque.
+ icon-color: (100, 40, 40, 200)
+ label-color: darkorange
+ text-color: mediumaquamarine
+
Named colors are defined at the highest aircraft level. They behave like a placeholder for a color, an alternate name.
+In the main configuration file of the aircraft:
+named-colors:
+ COCKPIT_BACKGROUND: skyblue
+ COCKPIT_NIGHT: slateblue
+ HIGHLIGHT: coral
+
In a button definition attributes:
+label-color: HIGHLIGHT
+
Cockpitdecks uses the same convention as python number to text formatting.
+Font files available to all decks are in the deckconfig/resources/fonts
folder.
Font files must be either Truetype fonts (TTF) or Opentype fonts (OTF).
+The name of the file is used to designate the font.
+Fonts are loaded on start up.
+ text-font: DIN Condensed Black.otf
+
Cockpitdecks comes with a few fonts appropriate for aeronautical use: Standard formal fonts like DIN, fancier fonts like LED fonts, icon fonts like font-awesome and weather-icon.
+For Truetype font, it is not necessary to add the .ttf
extension. For Opentype fonts it is necessary to add the .otf
extension.
About font files.
+Fonts placed in the resources/fonts folder are available for images on decks. They are not necessarily available as « web fonts » available in web decks.
+To be available directly, not through Cockpitdecks generated images, web decks fonts have to be made available in the asset folder and referenced in proper CSS files.
Cockpitdecks provides the following licensed fonts in its distribution:
+- D-DIN (4 variants),
+- Overpass, especially Overpass Mono,
+- Segment7Standard,
+- Split flaps Skyfont and SplitFlap-TV,
+- Icon fonts Font Awesome and weathericons.
The following fonts are recommended:
+- B612
+- DSEG: Original 7-segment and 14-segment fonts
Any Truetype or OpenType font can be added to Cockpitdecks.
+Icon image files available to all decks need to be placed in the deckconfig/resources/icons
folder.
Image files must be either JPEG images (JPG, JPEG) or Portable Network Graphic (PNG).
+The name of the file is used to designate the icon.
+Icons are loaded on start up and optionally cached.
+Typical icon size should be (square) 128 to 256 pixels.
+Internally, Cockpitdecks use 256 pixel icons. Icons are resized to the deck requested size upon display.
+ icon: OFF_WHITE_FRAMED
+
Sounds files can be provided very much like icons. Valid sound file formats are wav
and mp3
. Other sound file format may be added in the future, provided they can be played in a browser.
Documentation of the aircraft decks can be placed in the folder deckconfig/docs
or in the folder deckconfig/resources
in a textual form (including markdown), or as PDF.
A particular aircraft allows for definition of particular decks. The deck definition is a special Yaml file that describes the deck capabilities and, optionally, for web decks, the layout of the buttons on the deck.
+Please refer to the particular section on Deck Types for details.
+All configuration files are Yaml formatted. Yaml is simple, structured, and readable.
+Yaml is loaded and interpreted by the python Yaml parser. Users must be aware that some keywords are sometimes interpreted by some parser. To prevent this interpretation, keywords should be placed between quotes.
+For example:
+variable: on
will be interpreted as boolean value true.
+variable: "on"
will be interpreted as string on
.
The following keywords have been noticeably discovered:
+on, off, true, false, yes, no (all mapped to Boolean values True or False).
+Cockpitdecks uses a Yaml 1.2 compliant parser (ruamel.yaml) that refuse those interpretation as describe in the Yaml 1.2 specifications.
+ + + + + + + + + + + + + + + + + + + + + + +This page is an attempt at providing all necessary step to create a new page of buttons to display on a deck.
+We assume you installed Cockpitdecks properly, together with the Cockpitdecks Helper Plugin which is necessary to work in fully automatic mode.
+First, make sure the deck model you own is a deck already available through Cockpitdecks. The following deck brands and models have been tested and used:
+In normal, simple, automatic mode, Cockpitdecks expects configuration to be found in the folder of the aircraft currently being used. (This may be adjusted by advanced configuration parameters if you do not want to store Cockpitdecks configuration files in the that folder.)
+In the aircraft folder, create a folder named deckconfig
.
config.yaml
FileInside the above folder, create the main configuration file with this content. Adjust the content to your deck.
+aircraft: Cessna 172
+decks:
+ - name: Aviator Loupdeck
+ type: loupedeck
+ layout: cockpit
+ brightness: 70
+
In the conifiguration file, you mention the name of the layout you are going to use for that deck: cockpit
. Inside the deckconfig folder, create a sub-folder and name it cockpit
.
Inside that cockpit
folder, create a file index.yaml
. Insert the following content in the file:
buttons:
+ - index: 0
+ label: Map
+ type: push
+ icon: map
+ command: sim/map/show_current
+
Start X-Plane, load the aircraft where you created your Cockpitdecks configuration folder.
+Disconnect all software that access your deck.
+If every runs on the same computer, you only need to supply X-Plane home directory. You can supply the folder either through a operating system environment variable SIMULATOR_HOME
, or through the Cockpitdecks environment file. A myenviron.yaml
file with the following content is sufficient:
SIMULATOR_NAME: X-Plane
+SIMULATOR_HOME: /Applications/X-Plane 12
+
$ cockpitdecks-cli --env myenviron.yaml
+
Cockpitdecks will start immediately in demonstration mode, and connect to the simulator. Once it is connected to the simulator, it will try to collect the information about the aircraft that is currently loaded. This may take a few seconds. Once Cockpitdecks has the information about the aircraft currently being used, it will search for the deckconfig folder in the folder of the aircraft, and if found, will load the configuration it finds there.
+If everything worked properly, you should now see the first, upper left button of your deck displaying the Map text. With no map icon.
+Cockpitdecks is a regular python application and will run under python 3.10, or newer.
+It is recommended to create a dedicated environment and run Cockpitdecks within that environment.
+Cockpitdecks is a modern software that takes benefit from all available possibilities. While being developed, it is constantly updated to use the latest packages and features.
+Therefore, Cockpitdecks will work better with the latest production release of X-Plane. It may not work properly, or some feature may not be available when using older versions of X-Plane. We do not have the engineering resources to maintain working versions of Cockpitdecks for all versions of X-Plane. While most features should still work in X-Plane 11, they were never tested, and we will not provide any support to make it work on older release.
+Same occurs with aircrafts. Aircrafts are pieces of software that are regularly updated. It is a good practice to include the X-Plane and aircraft version information as comments in the deckconfig
files, to precise which version of X-Plane or an aircraft is required to run properly.
As a practical example, X-Plane recently opened access to internal data through a new channel: A Web REST API access. This is offered in X-Plane release 12.1.1 or newer. Immediately, Cockpitdecks has taken benefit from this new, simplified mean to access simulator values.
+It is good practice to maintain the software you use to the latest, production version. Cockpitdecks is no exception to this advise.
+In particular, the X-Plane Cockpitdecks Helper plugin uses and requires the latest version of XPPython3 plugin to work. This plugin itself requires X-Plane 12 and recent version of X-Plane SDK. Cockpitdecks Helper plugin is strictly not required to run Cockpitdecks but some features will not work without it.
+X-Plane 12 and UDP
+X-Plane 12 appears to disable UDP networking on new installations. Check Settings -> Network page, and make sure “Accept incoming connections” is enabled.
+
(See X-Plane UDP manual. Will provide information here later.)
+Create a new python environment and activate it. In that environment, issue the pip install command:
+pip install 'cockpitdecks[xplane,weather,demoext,streamdeck] @ git+https://github.com/devleaks/cockpitdecks.git'
+
Valid installable extension packages (between the [
]
, comma separated, no space) are:
Extra | +Content | +
---|---|
xplane |
+Add X-Plane flight simulator. Mandatory if you want to use it with X-Plane flight simulator. | +
weather |
+Add special iconic representation for weather. These representations fetch information outside of simulation software. That's why it is not bundled with Cockpitdecks. Recommended. | +
streamdeck |
+For Elgato Stream Deck devices | +
loupedeck |
+For Loupedeck LoupedeckLive, LoupedeckLive.s and Loupedeck CT devices | +
xtouchmini |
+For Berhinger X-Touch Mini devices | +
demoext |
+Add a few Loupedeck and Stream Deck+ demo extensions. Recommended. | +
development |
+For Cockpitdecks developer only, adds testing packages and python types. Useless if you do not develop Cockpitdecks software. | +
Cockpitdecks X-Plane Helper Plugin
+You can do this step later, but some functions will not work or be available inside Cockpitdecks.
+Cockpitdecks Helper Plugin is written in the python language. So it needs the XPPython3 X-Plane plugin installed. XPPython3 plugin allow for execution of python code inside X-Plane.
+Cockpitdecks XPPython3 plugin is located in the
+< Cockpitdecks-installed-code > /cockpitdecks/resources/xppython3-plugins
+
folder in the source code. There is a single file.
+To install, copy the plugin file to:
+... /X-Plane 12/resources/plugins/PythonPlugins/PI_cockpitdecks.py
+
and ask XPPython3 plugin to reload its scripts.
+deckconfig
FoldersDuane, a Cockpitdecks aficionado has realized several configurations for several aircrafts.
+You can find them here, download them and install them in your aircraft folder.
+Cockpitdecks deckconfig
folder must be placed in the folder of the X-Plane aircraft to be found by Cockpitdecks or the Cockpitdecks Helper plugin.
<X-Plane 12 Folder>/Aircraft/Extra Airicraft/Toliss A321/deckconfig
+
Now you are ready to start Cockpitdecks.
+ + + + + + + + + + + + + + + + + + + + + + +First, you have to completely stop (quit completely) original manufacturer deck configuration applications. They take exclusive access to the device and that prevents Cockpitdecks from finding and using them.
+environment.yaml
Cockpitdecks uses a configuration file, called the Cockpitdecks environment file, to define a few elements that cannot easily be guessed. Cockpitdecks provides a environment file that is suitable for single computer installation. You must, however, adjust at least the simulator folder path.
+Variable | +Definiton | +
---|---|
SIMULATOR_NAME |
+Name of simulator to use. Currently, only X-Plane is a valid value. | +
SIMULATOR_HOME |
+Home directory of X-Plane on the computer where Cockpitdecks runs. If X-Plane is installed on a remote host, SIMULATOR_HOME must be None . |
+
SIMULATOR_HOST |
+Hostname or IP address where X-Plane runs. Defaults to local host. | +
APP_HOST |
+Tuple (Hostname or IP address, port) where Cockpitdecks application runs. If specified through operating system environment variables, use (APP_HOST and APP_PORT). Default to (localhost, 7777). | +
API_PORT |
+X-Plane (12.1.1 and above) where REST API runs. Default to 8086 . |
+
API_PATH |
+X-Plane (12.1.1 and above) where REST API: X-Plane API root path. Currently default to /api/v1 . |
+
COCKPITDECKS_EXTENSION_PATH |
+List of paths where to search for Cockpitdecks extensions | +
COCKPITDECKS_EXTENSION_NAME |
+List of python package names that contains Cockpitdecks extensions | +
In addition, there is a operating system environment variable COCKPITDECKS_PATH
that lists folder paths where Cockpitdecks will look for aircraft configurations.
If you do not want to modify the Cockpitdecks-provided environ.yaml
file, you always can supply one on the command line with the —-env
flag.
The set of global parameters provided in the environ.yaml
file is called the Cockpitdecks environment, since it provides all « external » information to Cockpitdecks (external, relative to Cockpitdecks).
Cockpitdecks provides two templates configuration files for local and remote use.
+The minimal environment file if everything runs locally is
+SIMILATOR_NAME: X-Plane
+SIMULATOR_HOME: <path to where X-Plane software is installed>
+
Currently, Cockpitdecks only offers a command-line interface to be executed in a shell window.
+Installation of the above package in a python environment adds a single command cockpitdecks-cli
that can be used to start Cockpitdecks and provide options.
If always is a good idea to see what the client application offers:
+$ cockpitdecks-cli --help
+usage: cockpitdecks-cli [-h] [-e environ_file] [-d] [-f] [-v] [aircraft_folder]
+
+Start Cockpitdecks
+
+positional arguments:
+ aircraft_folder aircraft folder for non automatic start
+
+options:
+ -h, --help show this help message and exit
+ -d, --demo start demo mode
+ -e environ_file, --env environ_file
+ alternate environment file
+ -f, --fixed does not automatically switch aircraft
+ -v, --verbose show startup information
+
A second easy step is to start Cockpitdecks in demonstration mode. In this mode, it will offer a single demonstration web deck. See Examples for details about the demonstration.
+cockpitdecks-cli --demo
+
In this mode, Cockpitdecks will start a single web deck. Head for the index web page as specified in the environ.yaml
environment file (APP_HOST
).
NoSimulator
+If no simulator package is loaded, Cockpitdecks will start a dummy, empty simulator connector for its internal use. The above demonstration will be fully functional. Please note that if no specific deck package has been loaded, "hardware" reprensentation may not appear correctly on the emulated web decks.
+There are two possible ways of working with Cockpitdecks:
+Note
+Cockpitdecks provides two templates global parameter/environment files to get you started.
+This is the simplest case. In this mode, everything is automatic.
+Make sure the configuration file is setup. When everything is run on the same computer, the only important parameter is the X-Plane home folder that should be supplied in SIMULATOR_HOME
configuration variable. Alternatively, for convenience, the operating system SIMULATOR_HOME
environment variable can be set, especially if it is the only configuration variable that has to be changed. Then issue:
cockpitdecks-cli
+
If you defined a personal environment file:
+cockpitdecks-cli --env myenv.yaml
+
Cockpitdecks will immediately start in demonstration mode and listen for X-Plane interaction. If Cockpitdecks detects that X-Plane is running, finds that an aircraft is loaded, and that a Cockpitdecks deckconfig
folder exists in the folder of that aircraft, Cockpitdecks will load that configuration.
If no configuration is found, Cockpitdecks will listen and interpret X-Plane data but will not load a new configuration.
+This mode is fully automatic. If X-Plane is stopped or later restarted, Cockpitdecks will notice it and either wait idle that X-Plane is started, and if X-Plane is running, Cockpitdecks will attempt to load the aircraft configuration, if any.
+Cockpitdecks always attempts to load the current aircraft deckconfig
configuration, if present. Similarly, the XPPython3 plugin, if installed, will load the corresponding new configuration as well.
May be thhe aircraft loaded in X-Plane has no Cockpitdecks configuration but still, a configuration need to be loaded. The command-line interface can help:
+cockpitdecks-cli --env myenv.yaml folder-where-there-is-a-config --fixed
+
The above command will look for a deckconfig
folder in the folder supplied on the command line. The --fixed
flag indicates that Cockpitdecks should not try to load another configuration in case the folder loaded (the one supplied on the command line) and the folder of the aircraft used in the simulator do not match.
In this case, it is not possible for Cockpitdecks to locate aircraft configuration files since they probably are on the remote computer. A set of configuration file will need to be supplied to Cockpitdecks on the command line to start with. (If no folder is supplied, Cockpitdecks will start in demonstration mode. See above.)
+cockpitdecks-cli aircrafts/A21N --fixed
+
Cockpitdecks will start and load the configuration in aircrafts/A21N/deckconfig
, then Cockpitdecks will attempt to connect to X-Plane.
The optional --fixed
flag ensure that Cockpitdecks will not reload a new aircraft if it detects the aircraft in X-Plane has changed or does not correspond to the aircraft currently being used.
If --fixed
is not present, Cockpitdecks will attempt to find a suitable configuration to load. To do this, Cockpitdecks will search for a folder named like the X-Plane aircraft folder. It will search in all folders listed in the COCKPITDECKS_PATH
python or environment variable.
Here is an example. Suppose you loaded Toliss A321 aircraft in X-Plane. The folder name for that aircraft is Toliss A321
.
If you defined the python variable as such:
+COCKPITDECKS_PATH="/XPDATA/CockpitdecksConfig:/Volume0/XPlane/Cockpitdecks/data
+
Cockpitdecks will search in each of the above folders (/XPDATA/CockpitdecksConfig
and /Volume0/XPlane/Cockpitdecks/data
) for a folder named Toliss A321
. It will then check whether that folder contains a deckconfig
subfolder. If it does, Cockpitdecks will load that configuration. If the folder /XPDATA/CockpitdecksConfig/Toliss A321/deckconfig
is found, Cockpitdecks will load it.
In all case, Cockpitdecks will repetitively try to connect to X-Plane. If it fails to connect, it infinitely tries again until it succeeds. If not connected, decks will load but no command will be issued to X-Plane and no data will come from X-Plane to update decks.
+When Cockpitdecks successfully connects to X-Plane, it refreshes all pages by reloading them to reflect the state of the aircraft on the decks.
+If Cockpitdecks fails to connect to X-Plane or notices it does no longer receive dataref values from X-Plane, it will again repetitively try to connect to it until it succeeds.
+To report an issue with Cockpitdecks, you should always include the XPPython3.log
file created in the X-Plane folder. Cockpitdecks also create a cockpitdecks.log
files with more information in the directory you started Cockpitdecks from.
The level of information produced in the file is controlled by the logging level parameter. (info=some information and warnings, debug=a lot of information for debugging purpose, your XPPython3.log file may grow quite large.) The parameter is available at the global plugin level (the entire plugin will report all messages), or can be set at a Cockpitdecks internal module level to pin point issues.
+Cockpitdecks is stateless. If we except its internal statistics, Cockpitdecks does not maintain any state variable of a situation. Therefore, at any time, it is possible to stop and restart it. Should a problem persists, please file an issue on github with necessary information to reproduce it.
+To terminate Cockpitdecks, press a single Ctrl+C to stop Cockpitdecks client application.
+Cockpitdecks is designed to terminates cleanly. All requested datarefs monitoring are cancelled, connections are closed, all threads are terminated and joined cleanly. However, it may sometimes take a few seconds before a thread terminates. For example, if a thread is meant to run every 30 seconds, it may be necessary to wait a full 30 seconds before the thread notices the termination request and quits. Longer threads (above 30 seconds or a minute) check periodically for termination request. Cockpitdecks should always terminate cleanly to release resources it controls from the simulator.
+If necessary, there is an activation that can be assigned to a button to stop Cockpitdecks.
+If necessary, or blocked, pressing Ctrl+C several time in the main window will stop Cockpitdecks completely right away.
+ + + + + + + + + + + + + + + + + + + + + + +The Simulator entity represent the simulator software and contains all procedures necessary for interaction with the flight simulation software.
+There currently is only one type of flight simulation software supported and it is Laminar Research X-Plane (release 12 onwards).
+It is possible to create a new Simulator implementation for another software, like for example Microsoft Flight Simulator.
+In addition to the core simulation software, the Simulator also proposes a few entities that represent interactions with it.
+The simulation software presents to Cockpitdecks all its reachable « values ». Any value that is accessible in the simulation software is made available to Cockpitdecks through the SimulationData. A sophisticated mechanism updates the data in Cockpitdecks every time the data is modified in the simulator.
+For example, Laminar X-Plane extensively uses « datarefs », while Microsoft Flight Simulator uses « simvars ». They both are values coming from the simulator, and they both can be used in Cockpitdecks.
+Cockpitdecks offers the Instruction, an action that must be carried out in the simulator software, provided that the simulation software allows for « external action » to be accepted.
+Again, as an example, Laminar X-Plane has « commands » (offered in two modes of operation), and Microsoft Flight Simulator has « idontknow ».
+The Simulator entity is responsible for maintaining a connection to the Simulator software to collect simulator data values and issue instructions.
+ + + + + + + + + + + + + + + + + + + + + + +