Skip to content

Using Custom States and Simulator Variables

Max Paperno edited this page Nov 8, 2023 · 13 revisions
Table of Contents

Background - or "Why?"

MSFS has thousands of points of data (variables) which can be accessed via various means. Most common are the "Simulation Variables" or Sim Vars, but there are many other variable types available also (such as the ubiquitous "Local" variables), as well as values calculated using the simulator engine.

To get any of these values into Touch Portal for using in our pages, they must first be "requested" from the Simulator. What this means in practical terms is that we have to tell "the system" which variables/data we're interested in seeing. Then, whenever the data we want to see changes in the simulator (for example, the airplane's indicated air speed, or a radio frequency, etc.), that new information is sent (or "pushed") to this plugin (and then to Touch Portal).

This is actually fairly efficient because overall we may be interested in many data points, but only some of those will change often. For example the landing gear position is certainly important, but it will typically only change a couple times during a whole flight. On the other hand something like airplane speed could change quite often and throughout the whole simulator session. The simulator system knows what values have actually changed when, and can send us updates only when that happens.

When we "request" a variable value from the simulator using this plugin, the resulting value is delivered to Touch Portal as a "State." This is actually the only way to get data to Touch Portal at all -- it has to "arrive" as a State value. There is no concept like "go check the value of this variable right now" in TP. So again we must use the "push" concept of data delivery, and the plugin will send State value updates whenever the simulator system tells it they have changed.

In Touch Portal, the States can then be displayed somewhere, or used as an event trigger, or as input to some function. If you have used TP before, you are probably familiar with States. The plugin comes with a few States used for "housekeeping" purposes (for example status of simulator connection), but most of them are created automatically based on Simulator variables that have been requested, and are sorted into the various categories like AutoPilot, Radio & Navigation, etc.

Certainly it is not reasonable (nor actually possible) for this plugin to include every variable "out of the box" as a State. There are almost 3000 Sim Vars alone, never mind the other variable types, many of which will be aircraft model-specific. Each variable/data point can also be formatted in various ways or require different amounts of precision (for example most users probably don't need to know altitude to a thousandth's of a foot, but maybe someone does). Further, every point of data requested creates work and generates network traffic on/between all 4 "involved parties" (the simulator, this plugin, Touch Portal desktop app, and the TP device(s)).

So, the point of this exercise is to customize which data points, variables/States, you may actually need, and how to go about getting them consistently with the least amount of repetition and work.


State Configuration Files

We'll get back to this topic in more detail, but what is important to know overall is that this plugin loads all variable requests/States from simple plain-text configuration files (.INI format). It comes with a set of default States that were "baked into" the initial versions of the plugin, which are themselves loaded from the States.ini file found in the folder's installation directory (in Configuration folder). But the user can also create their own configuration file(s) and use them either in conjunction with the defaults or instead of them.

The point of this is that it becomes fairly easy to customize the set of available variables/states. It also makes it possible to distribute a set of States alongside a TP Page for example, or even to have different setups per airplane or scenario.

The included States.ini file explains the meaning of each parameter in comments at the top. If you're familiar with some of the general concepts involved, that may be all you need to read to create your own configs.

Custom configuration files can be specified in the plugin's Settings, where one can also provide the path to these files (default is in the current users's AppData\Roaming\MSFSTouchPortalPlugin folder).

The WASimUI Editor can be used to edit configuration files using a graphical interface.

Note It is not recommended to edit the default States.ini file included with the plugin. It will work, but this file will get overwritten the next time the plugin is updated.


Creating New States

The plugin provides a number of Actions (in the MSFS - Custom States & Variables category) for creating/editing/deleting/saving/loading custom variable requests. Now it should be said up-front that the user interface available within Touch Portal for Actions is... let's say limited. I've done the best I could with what is available, but it certainly doesn't compare to what I would expect from a user-friendly editor UI/UX (see WASimUI Editor section below for something more like that). Especially since to actually activate anything you need to use the connected device to push a button. That said, it is possible to do all the editing from within TP.

WHEN To Create States

This is a separate heading because it is important to understand. Once a new State is created (by requesting a new variable), it will persist for the duration of the plugin's run time. That is, until the plugin exits for any reason (like a TP restart). All the actions below just need to be activated once (per run time). Or if you want to edit a variable/State you already requested. Otherwise, it is very inefficient to submit "new" requests all the time (eg. as part of some other button's action), and there is no reason to do so.

Generally one would want to create and edit/adjust some custom requests in a "setup session" when creating a new TP page or button, for example, and then once the request(s) is/are finalized they can be saved to a configuration file (as mentioned above and discussed in more detail below) and simply re-loaded next time you need them (or automatically at plugin start).

WHERE To Create States

This is a source of confusion for some. All the actions described below should go on some temporary (or dedicated) button, or set of buttons, which are only going to be used for this particular purpose. Think of it as a separate interface (and set of actions/buttons) just for setting up your variables/states.

In fact to help clear this up some more, I've created and published a special TP page template just for this purpose. It is a template, meaning you need to edit the buttons/actions to actually get what you want.
You can find it over on the Assets page.

Action Details

There are 4 total Actions for specifying variable requests. The differences are based on what kind of variable or data is being requested, and how that information is entered (or selected) by the user. They are also similar in other respects because all data requests have common properties like formatting and sorting options.

I will describe one of the actions in detail and then only document the differences for the other action types. Note that each field described here ultimately corresponds to an entry the the state configuration .INI files, so this information is also relevant if/when editing the files directly.

All these actions appear in the MSFS - Custom States & Variables category.

Request a Named Variable

  • Variable Type - As mentioned in the introduction, MSFS uses many variable types. The most commonly used are the "SimVar" ("A") types otherwise known as simply "Simulator Variables" in the flight simulator documentation. "Local" ('L') type variables are increasingly used in MSFS, but there is usually no reference documentation for what they mean. "Input Event" ('B') types are brand new in MSFS SU13 and still partially experimental.

    These three types, 'A', 'B', and 'L', are also the only type supported by the native SimConnect API. Using any other variable type requires WASimModule WASM extension installed on the sim.
    Also refer to Input Event Type Variables - Considerations below for more details on working with 'B' types.

    Describing each type of variable and how to use them specifically is beyond the scope of these instructions (refer to MSFS SDK docs, HubHop, forums, ask for help, etc). The most commonly used types are "A" and "L".

  • Variable Name - All variables have a name and it must be known before the variable can be requested.
    In the case of Sim Vars, it would be one of the ones listed in the MSFS SDK documentation (link at top). (Note that the Sim Var names never have underscores (_) even though some are shown that way in the documentation index (eg. index shows ADF_ACTIVE_FREQUENCY).)
    Technically all variable types have a unique Name within that type group (eg. there cannot be two "L" type variables named "AGL" but there can be an "L" type "AGL" and a "T" type "AGL" at the same time).
    However, SimVar ("A") types may also have multiple instances of the same variable name which are identified by a numeric "index" value (as per MSFS SDK docs). In these cases the index number is appended after the variable name, separated by a colon (:) character as shown in the example. (Which then actually makes the variable name unique.)
    For example the image above shows requesting the ADF frequency of the 2nd radio, as indicated by the ":2" after the variable name. To get the first radio, put ":1" after the name instead.

  • Unit - Expected Simulation Variable Unit type for this variable. Only "SimVar", "GPS" and "Env[ironment]" type variables require and use a Unit specifier.
    Typically you would select the type shown in the "Units" column of the SimConnect variables reference, but in many cases you may also select a compatible type of unit and it will be converted automatically. For example an altitude could be displayed in feet or meters, or a frequency could be in MHz/KHz/Hz or one of the BCD-encoded formats.

  • Plugin Category - This is the plugin category into which to sort the resulting State. It's just a convenience to break up the long lists into something more manageable.

  • Format - The formatting you would like for this value. If you leave this blank, no formatting will be applied -- the value will be shown as-is from the simulator (this is good for strings, for example, or whole number/boolean/Enum types). For most "real" (floating point) numeric values it is usually useful to at least limit the number of decimal places that will be shown. The most basic formatting instruction is Fn where n is the number of decimal places to show. However in the example above I have specified a fixed format for the frequency so it always shows 3 whole digits and 3 decimal places.
    The formatting capabilities are fairly extensive, and use the conventions described in the .NET Microsoft documentation.

  • Default Value - Default value when no data has been received from Simulator. The corresponding Touch Portal State will be created with this value as default.

  • Update Period - Determines how often the Simulator value is checked/updated.

    • SimFrame simply means "as often as possible." This is usually around the visual frame rate of the sim, but can fluctuate quite a bit.
    • Once will return a value immediately but will not schedule automatic updates (there is also the MSFS Custom States & Variables -> Update a Variable Value action for manual updates).
    • Second and Millisecond let you specify specific intervals at which to check. The actual timing is specified in the next field, Update Interval.
  • Update Interval - The number of Update Periods that should elapse between data updates. Default is 0, which means the data is transmitted every Update Period.

    • For Second or Millisecond Update Period types, here is where you specify the actual timing (how many s/ms to wait between update checks).
    • This is also a good way to limit the number of SimFrame updates if you don't actually need the data at 60Hz or whatever the sim is running at (keep in mind all this data exchange taxes your computer and will affect the resources available to the actual simulation).
  • Delta Epsilon - Only report value change if it is greater than the value of this parameter.

    • This eliminates insignificant fluctuations in value from being reported, and in many cases prevents a lot of unnecessary data updates. For example something like airspeed is constantly changing in insignificant amounts (even before engines are started)... for example by something like +/- 0.00000034 knots. There is usually no good reason to keep sending such small changes between the sim and plugin and then to the TP client. This is especially useful when the values are being used in calculations or to trigger TP events, since again it can prevent a lot of unnecessary processing.

Request a Selected Simulator Variable

This is like the above action but specifically for "Sim Var" type variables, which can be selected from a list.

Note: This listing of Simulator Variables is imported from the MSFS SimConnect SDK online documentation using a custom utility. The data may contain errors or omissions.

  • System - The categories follow the ones in the MSFS Simulation Variables reference docs. Note You may need to toggle the category/type selector between options in order for the listing of variables to properly update.

  • Variable - This should update to show the variables available for the selected System. Variables already being requested are marked with an asterisk (*). "Adding" them again will first remove the previous request and then add the new one. Sim Vars marked with ":N" suffix in the name require an Index value.

  • Index - If the selected Variable requires an index number (they have ":N" after the name), specify it here.

  • Unit - This list should update after selecting a Variable and display all compatible unit types for that particular Variable (for example all "angle" type measures for a direction value, as shown in the example). The default unit for the selected variable is (usually) placed at the top of the list.

All the rest of the fields are as described previously.

Request an Airplane Local Variable

Again very similar to the first action up above, but here, if you're using the WASM integration (WASimModule), you can select a Local Variable from a list of variables currently loaded/used on the Simulator. The list is updated automatically on various sim events (when first connecting, when a new airplane is loaded, or when a flight starts, for example). The list can also be refreshed manually using the MSFS - Plugin -> Connect & Update -> Update Local Variables action.

  • Request Variable - Simply select one of the variables in the list which you would like to request. If the variable you expect isn't shown in the list, this usually means it has not been created yet on the Simulator. Local variables only exist when a simulator object (like an airplane model) creates them, which only happens when that particular object (eg. airplane) is actually loaded into the simulated environment (eg. to fly it).

All the rest of the fields are as described previously.

Request a Calculated Value

OK, last one. So here you really need to be familiar with the "RPN language" at least to some degree. The simplest code will retrieve a variable value, but in most cases that can already be achieved more efficiently by other means (all the actions above). But you can really get creative here and use the simulator engine as a powerful "calculator" to compute all sorts of outputs, including formatted strings.

  • Calculator Code - What to execute. The calculation should return some kind of result (if you don't need a result, there's a separate Action for that). In this example (from HubHop), the calculation returns a Boolean true/false based on the position of the left trailing edge flaps. If you can already understand what that code does, congratulations! (In any case you may find the RPN Tips page helpful.)
  • Result Type - This is the result type to expect from the calculation.
    • Double - A "real" value type with high precision. Use for any value requiring decimal-level precision.
    • Integer - An integral value of up to 64 bits. Use for any value requiring integer-level precision, including Boolean and Enums.
    • String - A string result. Note that any numeric value can also be returned as a string (and for Touch Portal use everything is a string anyway), which by default is formatted by the simulator to a "reasonable" precision, whole integer for whole numbers, and two decimals in most other cases.
    • Formatted - This is a whole separate topic really. The result is a formatted string based on the RPN String Formatting rules. If you can get your head around it, you can pretty much get any result you may need, formatted any way you want.
  • State Name - This is the name for the corresponding Touch Portal State (which will show up in the selected Plugin Category). Unlike with variables, there's no "natural" name for the calculated value, so you may specify one here. The name should be unique at least within the Category it is in.

All the rest of the fields are as described previously.


Adding the State/Variable

OK, now let's say you have one of the above actions set up and assigned to a button.

  • You will need to push that button on the connected TP device (Android/iOS) to actually activate it and complete the request.
  • Once pushed, a new State should appear in the various Touch Portal State selectors, within the category you chose for the new State (see screenshots below).
  • If it does not appear, see Troubleshooting section below.

If you are using my "States Editor" page (linked above), you should see an information or error message right there on the page. Here's an example after adding the "Request a Simulator Variable" example action shown above.

Here's what Touch Portal's States list may look like after adding that variable request.

Note that in some places in TP the categories are not working properly yet. So you end up with all the States in one sub-category named "Dynamic States," but at least they are sorted properly. For example:


Editing and Removing States

To edit an existing variable request, you have to re-submit the whole thing with whatever changes you want. If you change the variable name (or index, for Sim Vars), then it will be considered a new request (and creates a new State). Otherwise any existing State with the same name gets replaced with the new one.

Remove Simulator Variable

For removing an existing variable request there is a dedicated Action: MSFS - Custom States & Variables -> Remove Simulator Variable. This lets you select any single existing variable/State for removal.

Clear Variable Definitions

This action allows removing multiple definitions at once. The set of variables to remove is specified in the first choice selection.

  • All means literally to clear out all variable requests altogether.
  • Custom means to remove all variable requests except those that are included with the plugin by default (loaded from the "States.ini" file).
  • Loaded From Selected File will work if a variable definition was actually loaded from the given file (see below about files). If a loaded request is later edited via the TP actions, for example, it no longer counts as being loaded from a file.
  • Of Selected Type lets you select a variable type, like 'A', 'L', 'B', etc, to remove all requests for that type. This can be especially useful for 'B' and 'L' variables which are usually model-specific anyway.

Saving and Loading States

There are 2 actions available for this in the MSFS - Custom States & Variables category. As you may expect, they save and load variable requests/State definitions to and from files, respectively. Their reason for existence of hopefully fairly obvious -- you can set up all your custom States the way you like it and then easily save them all to a file... then simply load the file again whenever you want those variables/States again. And you can load your custom configurations automatically whenever the plugin starts.

Save Variable Definitions To File

  • You can choose to save either only the custom variables you have added, or all the variables/States (including the ones from the default States.ini configuration). You may choose the latter option if you are not going to use the default file at all, but still want to keep some of those definitions.
  • You will need to type of paste in a file name here, with or without a directory path. You could also use a dynamic variable value as part, or all, of the file name.
    The default file path is the "user configuration" folder, which as mentioned by default is in the current users's AppData\Roaming\MSFSTouchPortalPlugin folder or can be changed in the plugin's Settings.

Load Variable Definitions From File

  • You can type of paste a file name here, with or without a directory path. Or select a file from your file system using the ... button. Or you could also use a dynamic variable value as part, or all, of the file name/path (see example below in the Importing & Using in Pages section).
    The default file path is, again, the "user configuration" folder, which by default is in the current users's AppData\Roaming\MSFSTouchPortalPlugin folder or can be changed in the plugin's Settings.
  • Once this action is activated, the file will be loaded and the variables/States in it will be registered. Same as in the Editing section above, any existing variables/States with the same name will be replaced. Note that you do not need to be connected to the Simulator to load definition files.

Loading Custom Definitions at Startup

Once you have custom configuration file(s) saved, you can have it/them load automatically at startup of the plugin. This can be in addition to, or instead of, the default configuration file. The default configuration is specified by the keyword Default.

In the screenshot above I have specified the default config file as well as a file named CustomStates.ini which is my default plugin settings folder.

  • The ".ini" part is actually implied by default, so I don't need to specify it there (but it's OK to do so, or use any other file extension).
  • You can also enter a full path to a file here if you want to use one outside of the settings folder.
  • Separate multiple entries with a comma. Any number of files can be specified.
  • If any duplicates are found when loading configuration files, the last defined version will be effective. A warning will be logged if any duplicates are encountered (but can be ignored if the duplication is intentional).
  • From the above point you can infer that the order of the files being loaded could be important. For example to have custom requests override any default ones for the same variable, they would have to be loaded after the defaults (as would be the case in the screenshot above).

Input Events ('B') Type Variables - Considerations

Input Events ('B' variables) are defined by aircraft developers, and as such are only loaded with the aircraft and only exist in the system when the current aircraft uses them. Some Input Events are fairly common across a range of aircraft types (eg. single piston), while others can be completely unique to a particular model.

The issue is that we can't request (or set) these variables from the Simulator until they exist. So any requests for these variables will fail until a loaded model is actually using them. Trying to set these event values will also fail, but usually that is more obvious for the user.

The plugin tries to mitigate this problem, somewhat, by automatically trying to re-submit any requests for'B' varsiables when the airplane model changes. So if there are any requests which failed previously, they will be attempted again.

There is also an Action provided which will explicitly try to re-submit any failed 'B' var. requests. It's one of the options in the MSFS - Plugin -> Connect & Update Action). You could trigger this action manually with a button or integrate it into some logic flow.

Also keep in mind you could use the "Load Variables From File" action as part of some event logic flow to load variable requests as needed. There is also an Action provided to clear out existing requests/states, either just your custom ones or all of them (it is also one of the Connect & Update Action options).


Using Custom Definitions with TP Pages - Export / Import

Sometimes it is desirable to use specific variable requests for certain Touch Portal pages, for example when setting up a page (or set of pages) for a specific aircraft or add-on. This is especially true when wanting to share pages with other users but your page relies on custom variable requests. Typically pages are shared by exporting them from Touch Portal (including any required assets like images or files), and the recipient then imports the page including all attached assets.

Exporting Pages

To make it convenient for users of your page(s), the best solution is to include a custom states configuration (.ini) file with your page export. This file should contain only the custom requests your page uses (assume users already have all the defaults that are included with the plugin). There are a couple options on how to distribute these files:

  1. Simply make the configuration file available separately and specify in the instructions that the user should place the .ini file into their plugin configuration folder (AppData\Roaming\MSFSTouchPortalPlugin). To use it, they could load it at plugin startup (in plugin settings) or with an action on the imported page (more on this later).
  2. Include it in the page's exported .tpz file. Touch Portal already has a feature to include required "text" files with exported pages, and we can make use of that. We can even somewhat automate the loading of this file when the page is imported and used (more on this later).
    • The exported .tpz can include any extra files in a /misc subfolder (goes next to icons and pages folders). This is where we put our .ini file.
    • You could just add this folder/file manually to the .tpz file after export (eg. use 7-Zip or rename the .tpz to .zip, add the folder, then rename it back).
    • You could get TP to automatically export the file by referencing it in one of TP's "File I/O" actions which is then included on any button/event/flow of the page being exported. The action doesn't have to do anything useful (eg. "Get line from file to value"), it just needs to reference the states config file. The file itself could be in any directory, but will always be exported into the misc subfolder of the .tpz archive.

When the page is imported the file ends up in the user's TP config folder, in the misc subfolder (next to icons, pages, etc. folders). This location is a little awkward to access (since it depends on the current Windows user name), but the plugin adds a workaround for that. More info on this below in the Importing/Using Pages section.

BTW, it can also be helpful to edit the configuration file manually and give the states unique IDs (the first line of each request definition in the file) and/or names to help clarify to the user where the definitions are coming from (when they're editing their own buttons or modifying yours). Keep in mind the user may be importing other pages with their own custom requests and/or already have their own custom ones set up... plus all the defaults and it can quickly get overwhelming.

Importing & Using In Pages

Essentially we just need the custom states to be loaded at some point before trying to use them. The basic methods are already described above -- Either load the file(s) at plugin startup (using plugin's settings), or somehow via the provided plugin's "Load Variables From File" action.

However we could employ some tricks to help automate this for a user who just imported a new page. There are likely a number of creative ways to accomplish this, but here is one that seems to work fairly well with minimal "code." It requires an "On Event" handler, either embedded in one of the page buttons, or distributed alongside the page (or set of pages) as a global TP Event.

Here is a screenshot of an example event setup, with comments on each step (click to enlarge). This example is set up to handle export option #2 (above) where the states file is exported/imported alongside the page in the TP misc folder.

Here is a complete example button which uses the above event handler and shows the current status of the file (loaded/not loaded). It also loads the file on demand when pressed.


Download: MSFS_Example_LoadCustomStatesFile.tpb


Troubleshooting

The plugin logs errors and warnings to a plain-text file. 7 days worth of logs are kept by default (a new file is started for each day). The log files are located within the plugin's installation folder, which is in Touch Portal's configuration directory:
C:\Users<User_Name>\AppData\Roaming\TouchPortal\plugins\MSFS-TouchPortal-Plugin\logs folder, where <User_Name> is your Windows user name.

If something isn't working as expected, check the log.

Another way to quickly see latest log entries is by using the provided TP States and displaying them in a button area.

  • MSFS - Plugin -> Most recent plugin log messages (MSFSTouchPortalPlugin.Plugin.State.LogMessages) - Shows the last dozen logged messages. Give this one a good size "button" (eg. cell size 4x3 or so).
  • MSFS - System -> Data from most recent Simulator System Event (MSFSTouchPortalPlugin.SimSystem.State.SimSystemEventData) - Shows one line of text from the last significant "simulator event." In case an error or warning is logged, the log entry with the error should show here.

Lastly, you could also monitor the MSFS - System -> Simulator System Event for the Plugin Error event. For example you could have a button light up red when this event happens, so you can know to go check the log.

You can see examples of the last 3 thing I describe on my "States Editor" page (mentioned at the beginning), where the last event and log line are shown on the blue background, and the larger log text block is shown under that.


Editing Configuration Files Manually

Just to come back around to this, the configuration files which hold all this data are plain text and easily editable. They consist of blocks, each defining one variable/State. Within each "block" are parameters describing the various attributes that I've explained above. The names used for the parameters are variables, not the label names shown in the actions above, but they all have the same meaning and expected values. Most of the parameters have reasonable default values, so in many cases there are just a few lines of definition per variable/State.

All this to say that once you get "comfortable" with the system, it may be worth taking a look at the files and find that especially making small changes is much easier than through the TP Actions "interface."

As mentioned, all the parameters and their possible values are documented at the top of included States.ini file which of course also has a bunch of examples as well.

Here's the example I've been using so far of the ADF RADIAL:1 variable request shown in "Request a Simulator Variable" example action, above, but in "configuration file INI format":

[AdfRadial1]
CategoryId = Communication
Name = "ADF RADIAL 1"
VariableType = A
SimVarName = "ADF RADIAL:1"
Unit = "degrees"
DefaultValue = "0"
StringFormat = "F1"
DeltaEpsilon = 0.09

WASimUI Editor - New!

My WASimCommander project includes a user interface (UI) originaly meant for testing, but has proven to be a very useful tool on its own. It allow getting and setting all variable types, triggering key events, and also "Data Request" subscriptions which are idential to the "custom variable requests" I've described above. This is a great way to test first before trying to use variables or events in buttons/pages, and can save a lot of time.

As of v1.2 the UI can also import and export custom variable rquests in the INI file format this plugin uses (as described just above). INI files can be loaded using the "Load" button, and exported using the "Save" button under the Data Requests table (see screenshot on left). The "Save" button has an option to bring up a new window where variable requests can be edited before saving (on the right in the screenshots below).

Hdead over to the project's Releases page and download the latest WASimUI zip file. The UI requires the WASimModule simulator expansion as well, the same one you may already be using for this plugin.