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..0827c921 --- /dev/null +++ b/404.html @@ -0,0 +1,1806 @@ + + + +
+ + + + + + + + + + + + + + + + +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 perfomed.
+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 always performed, provided of course that the button instructed to write the value to the dataref pointed py 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.
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: longpress
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 Longpress 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 Longpress 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 Longpress 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 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.
+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 turned clockwise and pushed 4. Fourth command gets executed when encoder is turned counterclockwise and pushed |
+
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 as its default-label-color
. The button will then 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 attempts to provide a day and a night theme. The attribute cockpit
can be set to day
(or light
) or night
(or dark
).
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 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.
+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.
+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.
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.
+(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 parametrised 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 diectionary 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.
+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
.
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.
+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
+
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 or the 13 available encoder LEDs are accessible. It is not possible to access LED 0 and 13, only 1 to 12.
+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.)
+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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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 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
+
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, but this can be done.
+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.
+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 Metar currently in use at a location in the simulator.
+If the location is provided, 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 for the closest Metar location. (Closest to the current aircraft location.)
+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
+X-Plane Weather is currently heavily modified by Laminar. The following representation do not work reliably.
+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.
+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 LargeButtons (A LargeButton can have two or more buttons represented inside.). Each annunciator part or each button inside a LargeButton 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 LargeButtons.
+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.
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.
+A dataref is always 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 to update their appearance.
+To explore datarefs, 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.
+For simplicity, Cockpitdecks assumes all individual dataref values are floating point numbers or strings (in which case it actually is a list of floating point values representing the ASCII code number of each character in the string.)
+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
+
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 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 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, or slid is a button.
+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 parameters 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.
+Resulting button:
+The following Sections describe button definition attributes that are common to all buttons, what ever they do and represent.
+The button Activation page describes attributes specific to what a button will trigger or do when used.
+The button Representation page describes attributes specific to the feedback given by the button on the deck, be it an iconic image to display, a led to turn on or off, or a sound to emit.
+(In the picture 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. On a given Page, the Index of a button must be unique on that Page since it addresses a very precise key, knob or slider on the deck. Depending on the model of deck, buttons have Button Index. 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… until the number of knobs is reached. |
+
name |
+Optional. A button can be named. 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 a Command that is executed after the activation. | +
view-if |
+The view-if formula is evaluated before the view is executed. If present, the view will only be executed if view-if evaluates to True. | +
(In the picture above, this refer to the yellow part of the definition.)
+A Button has a value that is maintained and used mainly for representation.
+The following attributes are used to determine a button’s value:
+dataref
: A single dataref value.
formula
: An expression that contains variables and mathematical operations to combine and compute a value
multi-datarefs
: A list of two or more datarefs. The values of all datarefs in the list will be returned.
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.
+activation_count
(number of time button was «used»)current_value
previous_value
Internal state attributes varies depending on the button activation. Please refer to button activations, 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 a button's value computation.
+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 picture 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.
(In the picture 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.
+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.
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +The Cockpit is the Maestro 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.
+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 discover all decks connected to the system and available to it.
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.
+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 | +
secreat.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. |
+
config.yaml
FileThe file named config.yaml
in the deckconfig
folder contains declarations for each deck that will be used and global, aircraft-level attributes.
# Definition of decks for Toliss A321
+#
+aicraft: Toliss
+decks:
+ - name: XPLive
+ type: loupedeck
+ layout: live
+ brightness: 70
+# These attributes are default values at global level
+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 parameters 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. | +
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. | +
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
+
Resources are fonts, icons, other images, wallpapers, documentation, and texts used and related to that aircraft.
+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 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. | +
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 add 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 separately.
+ + + + + + + + + + + + + + + + + + + + + + + + +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. | +
default-homepage-name |
+Optional. Default page name in layout. Default to index . |
+
default-* |
+Optional. Default attributes to use for deck. | +
For a given aircraft, a deck has a Layout. The Layout of a deck is a collection of Pages that will be used and displayed on the deck device for that aircraft.
+A Layout is a folder in the deckconfig
folder.
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +To add a new activation to Cockpitdecks, the developer has to create a new Activation sub-class and declare it in the
+<cockpitdecks-source-code>/cockpitdecks/buttons/activation/__init__.py
file.
+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%.
+ + + + + + + + + + + + + + + + + + + + + + + + +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 he or she want to exercise to produce a result.
+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 have been identified and are available in Cockpitdecks: - push : ability to press a button, optionally pushing a long time,- encoder - press - longpress - touch - swipe |
+
view | +Similarly, decks defined the following view interactions: - image - led - colored-led - encoder-led |
+
name | +Name and repeat will determine the index name of the buttons. | +
repeat | ++ |
prefix | +Prefix is used to distinghish button capabilities. If a button has, for example, encoder and push capabilities, the push capabilties will use name 0 (name only), the corresponding encoder will be named e0 (prefix + name). |
+
image | +The image attribute sets the image size for the button, and offset if the image is a portion of a larger display. | +
vibrate | ++ |
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. Events will be decoded (which key was pressed, when, how, etc.) and presented to Cockpitdecks for handling.
+Depending on the device driver's hardware access, events will either be presented directly to Cockpitdecks, or through a FIFO queue: Driver enqueues events, Cockpitdecks dequeues events.
+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 view it requires. A representation that displays an image (icon, drawing, animation…) will require a lcd
view for instance.
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 declare it in the
+<cockpitdecks-source-code>/cockpitdecks/buttons/representation/__init__.py
file.
+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
+
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 Longpress 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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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.
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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 more probable, more 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.
+From time to time, new deck models may appear. Adding a new deck model highlights steps necessary to add a new deck model.
+In addition of defining a new deck model, it might me necessary to develop specialized, custom activation mechanism not foreseen by the current Cockpitdecks version.
+If the new deck model brings a new way of interacting with it, it might be necessary to add a new method of interaction, a new Action type.
+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.
+Cockpitdecks incudes a few developer specific activations that can be used to introspect Cockpitdecks while running.
+ + + + + + + + + + + + + + + + + + + + + + + + +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 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 | +
+ | + |
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)
+Deck Internals explains how Cockpitdecks discovers about miscellaneous deck hardware capabilities and how user interactions on a physical deck device enter Cockpitdecks.
+Work In Progress
+This important file is under DEEP re-writing.
+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 how bridged the physical deck hardware with the python language.
+By design and coïncidence, all three deck brands currently proceed with similar means.
+The python package that interfaces the physical deck to the python language request to supply and install a callback function, with a proper interface.
+The function, that we supply, is called each time an interaction occurs on the physical deck device.
+When Cockpitdecks is started, its scans for available devices, and check whether the interfacing software package is available. If it is, it installs its own 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, it creates an Event with all necessary data and enqueues it for later processing by Cockpitdecks.
+The Event contains information about the deck, of course, but also the precise button, knob, encoder, slider, screen… that was used and what type of interaction occurred (pushed, turned, swiped…) All that information is in the Event and the Event is sent to Cockpitdecks. That's how physical deck interaction enters Cockpitdecks.
+Cockpitdecks runs a specific routine that listen to events that enter through the queue. Cockpitdecks instruct the event to run. That's how and when actions are actually performed, like sending a command to X-Plane or changing the value of a dataref.
+In the overall software organisation of Cockpitdecks, everything related to decks is confined in a decks
folder.
The decks
folder is organized as follow: (between parenthesis, the content of the folder or file.)
deckconfig
+ ⊢ resources
+ ⊢ decks
+decks
+ ⊢ resources (accessory files)
+ ⊢ templates (Jinja2 templates)
+ ⊢ index.j2
+ ⊢ deck.j2
+ ⊢ assets (Web Deck assets)
+ ⊢ decks (Web Deck specific assets)
+ ⊢ images (Web Deck background images)
+ ⊢ images (Web Applicatioin images and icons)
+ ⊢ js (Interaction and display software in JavaScript)
+ decktype.py (Deck Type class)
+ ...
+ deckdefinition.yaml (Deck types, one file per type)
+ ...
+ webdeckdefinition.yaml (Deck types, one file per type)
+ ...
+ virtualdeck.py (Virtual Deck implementation class)
+ virtualdeckmanager.py (Virtual Deck Manager implementation class)
+ ...
+ loupedeck.py (main drivers for each type of deck)
+ ...
+ virtualdeck.py (main drivers for all virtual decks)
+ xtouchmini.py (main drivers for each type of deck)
+
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:
+On startup, Cockpitdecks will report which deck types are available:
+INFO: loaded 15 deck types (
+Virtual Streamdeck Mini, Virtual Streamdeck MK.2, Streamdeck +,
+Virtual LoupedeckLive, Stream Deck XL, Stream Deck Neo,
+Virtual Streamdeck XL, LoupedeckLive, Streamdeck, Virtual X-Touch Mini,
+Stream Deck Original, Stream Deck Mini, X-Touch Mini, Stream Deck +,
+Virtual XKeys 80), 6 are virtual deck types
+INFO: drivers installed for streamdeck 0.9.5, xtouchmini 1.3.6; scanning..
+INFO: found 0 streamdeck
+INFO: found 0 xtouchmini
+...
+INFO: found 1 web deck(s)
+INFO: added virtual deck LoupedeckLive, serial None)
+
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 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. | +
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 . |
+
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:
+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]
+
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
+
The second interface provided for decks is the software necessary to:
+This require the coding of a bridge between Cockpitdecks and the API that controls the device.
+Currently, this require the coding of a single python 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)
+
On startup, Cockpitdecks will report which drivers are installed:
+INFO: drivers installed for streamdeck 0.9.5, loupedeck 1.4.5, xtouchmini 1.3.6; scanning..
+INFO: found 3 streamdeck
+INFO: found 1 loupedeck
+INFO: found 1 xtouchmini
+
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.
Meta data is a python dictionary serialized into JSON (mostly name, value pairs).
+It can contain any arbitrary serialisable items.
+{
+ "code": code,
+ "deck": name,
+ "meta": {
+ "ts": datetime.now().timestamp()
+ }
+}
+
It can be a key image, or a «hardware» image.
+{
+ "code": code,
+ "deck": name,
+ "key": key,
+ "image": base64.encodebytes(content).decode("ascii"),
+ "meta": {
+ "ts": datetime.now().timestamp()
+ }
+}
+
{
+ "code": code,
+ "deck": name,
+}
+
{
+ "code": 0,
+ "deck": deck,
+ "key": key,
+ "event": value,
+ "data": data
+}
+
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 index | +
action | +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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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"
+
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?!
+ + + + + + + + + + + + + + + + + + + + + + + + +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
+
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).
+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
.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
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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.
+ + + + + + + + + + + + + + + + + + + + + + + + +The Simulator 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.)
+ + + + + + + + + + + + + + + + + + + + + + + + +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}
+
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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.
+If this schema is successful, it will be extended to other definitions that use a command attribute.
+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.
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +In addition to real physical decks, Cockpitdecks offers Web Decks rendered in a browser window.
+This is very handy to design layout for deck a developer does not necessary owns.
+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 decks are defined like any other deck. Their driver must be virtualdeck
. They contain a few 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.
+ + + + + + + + + + + + + + + + + + + + + + + + +The project started from the multiplication of accessory devices. Some are very dedicated and allow for little flexibility. miniCockpit devices fall into that category. Some other devices are very generic and allow for customisations. Streamdecks, 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 needs to rely on conventions or generalisation 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 generalise all particularities of devices. 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 input (what is called Activation) and output (what is called Representation).
+A second step was to isolate all interactions with X-Plane: Issuing commands and monitoring dataref values. This is done in a collection of Simulator, Dataref, and Command abstractions.
+A final 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).
+Other entities glue things together with concepts like the Cockpit with is a collection of one or more deck, 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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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 is a regular python application and will run with 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 versions as comments in the deckconfig
.
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 internal 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. Again, the Cockpitdecks Helper plugin is strictly not required to run Cockpitdecks but some features will not work.
+X-Plane 12 and UDP
+X-Plane 12 appears to disable UDP networking initially. 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 git+https://github.com/devleaks/cockpitdecks.git
+
If you would like to use Weather or METAR buttons, add the following packages:
+pip install avwx-engine scipy suntime timezonefinder metar tabulate
+
No Physical Deck?
+If you only use web decks and no physical deck, you can skip this step.
+To have Cockpitdecks manage Streamdeck devices, add
+pip install streamdeck
+
To have Cockpitdecks manage Loupedeck devices, add
+pip install git+https://github.com/devleaks/python-loupedeck-live.git
+
To have Cockpitdecks manage Touch Mini devices, add
+pip install git+https://github.com/devleaks/python-berhinger-xtouchmini.git
+
Cockpitdecks X-Plane Helper Plugin
+You can do this step later, but some functions will not work or be available inside Cockpitdecks.
+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.
+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.
+To collect string-typed datarefs, the Cockpitdecks Helper plugin needs to be installed in XPPython3 PythonPlugins folder.
+See String Datarefs for details about this.
+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 both services described above, copy the plugin file to:
+... /X-Plane 12/resources/plugins/PythonPlugins/PI_cockpitdecks.py
+
and ask XPPython3 plugin to reload the 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
+
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.
+config.py
Cockpitdecks uses a single configuration file to define a few elements that cannot easily be guessed.
+Variable | +Definiton | +
---|---|
XP_HOME |
+Home directory of X-Plane on the computer where Cockpitdecks runs. If X-Plane is installed on a remote host, XP_HOME must be None . |
+
XP_HOST |
+Hostname or IP address where X-Plane runs. | +
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) | +
API_PORT |
+X-Plane (12.1.1 and above) where REST API runs | +
API_PATH |
+X-Plane API root path | +
DEMO_HOME |
+Directory where demonstration deckconfig files are found. |
+
COCKPITDECKS_PATH |
+COCKPITDECKS_PATH is a colon-separated list of folder paths. Cockpitdecks will search for aircrafts in directories specified in this variable. First match is returned. |
+
Most of these variables gets their default value from operating system environment variables. If no environment variable is defined, the config.py
file supplies a value.
If always is a good idea to see what the client application offers:
+$ cockpitdecks-cli --help
+usage: cockpitdecks-cli [-h] [-d] [-f] [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
+ -f, --fixed does not automatically switch aircraft.
+
A second easy step is to start Cockpitdecks in demonstration mode. In this mode, it will offer a single demonstration deck. See Examples for details about the demonstration.
+cockpitdecks-cli --demo
+
In this mode, Cockpitdecks will start a single web deck.
+There are two main configuration mode to start Cockpitdecks.
+This is the simplest case. In this mode, everything is automatic.
+Make sure the configuration file is setup and issue:
+cockpitdecks-cli
+
Cockpitdecks will immediately start in demonstration mode and listen for X-Plane interaction. If Cockpitdecks finds that an aircraft is loaded and that Cockpitdecks deckconfig
folder exists in the folder of that aircraft, Cockpitdecks will load this 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, 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.
In this case, it is not possible for Cockpitdecks to locate aircraft configuration files. 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/deckcockpit
. 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. This is particularly handy when developing decks.
If --fixed
is not present, Cockpitdecks will attempt to find a suitable deckconfig folder 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 aircraft folder name 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 proper 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.
+If you cloned Cockpitdecks software in a folder, you can start Cockpitdecks with
+python start.py
+
from the top folder of the source code.
+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 your script 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 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.
+If necessary, pressing Ctrl+C several time in the main window will stop Cockpitdecks completely right away.
+ + + + + + + + + + + + + + + + + + + + + + + + +For a given deck, a Layout is a collection of Pages that will be displayed on that deck.
+A Layout is a folder, inside the deckconfig
main folder.
The Layout is named and addressed by the name of the folder.
+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. But you have to make two pages of buttons on a 16 key deck. Same button definitions, but two layouts.
+The Layout folder contains the following files:
+ ⊢ layout_name
+ ⊢ config.yaml
+ ⊢ page1.yaml
+ ⊢ page2.yaml
+
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: index
+
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 value of some attributes (like font, colors, and sizes) is 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.
+Other 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 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. |
+
default-* |
+Default values to be used at the Page-level for display. | +
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. |
+
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +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
+
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.
++[NOTE] 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.
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
+
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.
+ + + + + + + + + + + + + + + + + + + + + + + + +