SimVar Registry

The pkg/registry package is a static, typed metadata store for MSFS SimVar names, accepted unit strings, Go data types, writability, and category information. It gives you a way to validate variable names and units at startup, enumerate all known variables by category or unit, and discover index-aware variables — all without requiring a live SimConnect connection.

The registry contains 104 entries across three categories: "aircraft" (46 vars), "environment" (16 vars), and "simulator" (42 vars). It has no build-tag requirements and no imports from Windows-gated packages, so it compiles and runs on any platform.

Import

import "github.com/mrlm-net/simconnect/pkg/registry"

No //go:build windows tag is needed. The package is safe to import in test utilities, validation tools, or code generators running on Linux or macOS.

SimVarMeta Struct

Every entry in the registry is a SimVarMeta value:

type SimVarMeta struct {
    Name        string   // Canonical SimConnect name, uppercase, no :N suffix
    Units       []string // All accepted unit strings, lowercase canonical form
    DefaultUnit string   // Recommended unit for new data definitions
    Type        string   // Go numeric type: "float64", "float32", "int32",
                         //   "int64", "bool", "string", "enum"
    Category    string   // Domain group: "aircraft", "environment", "simulator"
    Writable    bool     // Whether SimConnect accepts SetDataOnSimObject writes
    Indexed     bool     // Whether the variable accepts a :N suffix
    Description string   // Human-readable summary
}
Field Description
Name Canonical SimConnect variable name in upper case without any :N index suffix. For example: "ENG RPM", not "ENG RPM:1".
Units All unit strings SimConnect accepts for this variable, stored in lowercase. For example: ["feet", "meters"].
DefaultUnit The primary unit recommended for new data definitions. Always one of the values in Units.
Type The Go numeric type appropriate for reading this variable. Valid values: "float64", "float32", "int32", "int64", "bool", "string", "enum".
Category Domain group. Valid values in this release: "aircraft", "environment", "simulator".
Writable true if SimConnect accepts writes via SetDataOnSimObject for this variable.
Indexed true if this variable accepts a :N suffix to address engine, radio, or other per-instance slots (e.g., "ENG RPM:1").
Description Human-readable summary of what the variable represents.

Lookup

Lookup retrieves a single entry by name. The lookup is case-insensitive, and any :N index suffix is stripped before the match.

Signature:

func Lookup(name string) (SimVarMeta, bool)
package main

import (
    "fmt"
    "github.com/mrlm-net/simconnect/pkg/registry"
)

func main() {
    // Exact name
    if meta, ok := registry.Lookup("PLANE ALTITUDE"); ok {
        fmt.Printf("Name:        %s\n", meta.Name)
        fmt.Printf("DefaultUnit: %s\n", meta.DefaultUnit)
        fmt.Printf("Type:        %s\n", meta.Type)
        fmt.Printf("Writable:    %v\n", meta.Writable)
    }

    // Case-insensitive
    if meta, ok := registry.Lookup("plane altitude"); ok {
        fmt.Println("Found:", meta.Name) // PLANE ALTITUDE
    }

    // :N suffix is stripped automatically
    if meta, ok := registry.Lookup("ENG RPM:2"); ok {
        fmt.Println("Found:", meta.Name)    // ENG RPM
        fmt.Println("Indexed:", meta.Indexed) // true
    }

    // Unknown variable
    if _, ok := registry.Lookup("UNKNOWN VAR"); !ok {
        fmt.Println("Variable not found in registry")
    }
}

All

All returns an independent copy of every entry in declaration order. Modifying the returned slice does not affect registry state.

Signature:

func All() []SimVarMeta
package main

import (
    "fmt"
    "github.com/mrlm-net/simconnect/pkg/registry"
)

func main() {
    vars := registry.All()
    fmt.Printf("Total SimVars: %d\n", len(vars))

    for _, meta := range vars {
        fmt.Printf("%-40s  %-12s  %-11s  writable=%-5v  indexed=%v\n",
            meta.Name,
            meta.DefaultUnit,
            meta.Type,
            meta.Writable,
            meta.Indexed,
        )
    }
}

Because All returns a copy, each call allocates a new slice. Call it once and reuse the result if you need to iterate multiple times in a hot path.

Validate

Validate checks whether a given unit string is valid for a named variable. It returns nil on success and a descriptive error on failure. Both the variable name and unit comparisons are case-insensitive. A :N index suffix is stripped from the name before lookup.

Signature:

func Validate(name, unit string) error
package main

import (
    "fmt"
    "github.com/mrlm-net/simconnect/pkg/registry"
)

func main() {
    // Valid combination — returns nil
    err := registry.Validate("PLANE ALTITUDE", "feet")
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("OK")
    }

    // Invalid unit — error lists accepted values
    err = registry.Validate("PLANE ALTITUDE", "knots")
    if err != nil {
        fmt.Println(err)
        // registry: unit "knots" not valid for PLANE ALTITUDE; valid units: feet, meters
    }

    // Unknown variable
    err = registry.Validate("UNKNOWN VAR", "feet")
    if err != nil {
        fmt.Println(err)
        // registry: unknown SimVar: UNKNOWN VAR
    }

    // Validate before registering a data definition
    const varName = "AIRSPEED INDICATED"
    const unit = "knots"
    if err := registry.Validate(varName, unit); err != nil {
        panic("invalid SimVar configuration: " + err.Error())
    }
    // safe to proceed with client.AddToDataDefinition(defID, varName, unit, ...)
}

Validate is most useful as a startup guard. Call it during initialization to catch unit typos before the application reaches the simulator.

ByUnit

ByUnit returns all entries whose Units slice contains the given unit string. The comparison is case-insensitive. Returns nil if no entries match.

Signature:

func ByUnit(unit string) []SimVarMeta
package main

import (
    "fmt"
    "github.com/mrlm-net/simconnect/pkg/registry"
)

func main() {
    // Find all SimVars that accept "degrees" as a unit
    degreeVars := registry.ByUnit("degrees")
    fmt.Printf("SimVars accepting 'degrees': %d\n", len(degreeVars))

    for _, meta := range degreeVars {
        fmt.Printf("  %-45s  default=%-10s  category=%s\n",
            meta.Name,
            meta.DefaultUnit,
            meta.Category,
        )
    }

    // Case-insensitive
    knotsVars := registry.ByUnit("Knots")
    fmt.Printf("\nSimVars accepting 'knots': %d\n", len(knotsVars))
    for _, meta := range knotsVars {
        fmt.Printf("  %s\n", meta.Name)
    }
}

ByCategory

ByCategory returns all entries in a given domain category. The comparison is case-insensitive. Returns nil if no entries match.

Signature:

func ByCategory(category string) []SimVarMeta

Valid categories: "aircraft", "environment", "simulator".

package main

import (
    "fmt"
    "github.com/mrlm-net/simconnect/pkg/registry"
)

func main() {
    // List all aircraft variables
    aircraftVars := registry.ByCategory("aircraft")
    fmt.Printf("Aircraft SimVars: %d\n", len(aircraftVars))

    for _, meta := range aircraftVars {
        fmt.Printf("  %-40s  %-10s  writable=%v\n",
            meta.Name,
            meta.DefaultUnit,
            meta.Writable,
        )
    }

    // Environment variables
    envVars := registry.ByCategory("environment")
    fmt.Printf("\nEnvironment SimVars: %d\n", len(envVars))

    // Simulator variables
    simVars := registry.ByCategory("simulator")
    fmt.Printf("Simulator SimVars: %d\n", len(simVars))
}
Category Count Contents
"aircraft" 46 Position, attitude, speed, altitude, engine, controls, gear, fuel, avionics
"environment" 16 Weather, wind, temperature, pressure, visibility, precipitation
"simulator" 42 Simulation state, camera, time, realism, units, VR, avatar

Indexed Variables

Some SimVars address per-instance data — such as individual engines, radios, or throttle levers — via a :N integer suffix. The registry represents these with Indexed: true on the base name (no suffix).

Indexed variables in this release:

Name Description
ENG RPM Engine RPM for engine N (:1:4)
ENG FUEL FLOW GPH Fuel flow in gallons/hour for engine N
GENERAL ENG THROTTLE LEVER POSITION Throttle lever position for engine N
FUEL SELECTED QUANTITY Quantity in fuel tank N
COM ACTIVE FREQUENCY Active frequency for COM radio N
NAV OBS OBS setting for NAV radio N
CAMERA VIEW TYPE INDEX Camera view type index N

To look up an indexed variable, pass the name with any :N suffix — Lookup strips it automatically:

package main

import (
    "fmt"
    "github.com/mrlm-net/simconnect/pkg/registry"
)

func main() {
    // Look up by base name
    if meta, ok := registry.Lookup("ENG RPM"); ok {
        fmt.Println("Indexed:", meta.Indexed) // true
    }

    // :N suffix is stripped — same result
    if meta, ok := registry.Lookup("ENG RPM:3"); ok {
        fmt.Println("Name:", meta.Name)        // ENG RPM
        fmt.Println("Indexed:", meta.Indexed)  // true
    }

    // Validate a specific engine unit before registering
    for engine := 1; engine <= 4; engine++ {
        varName := fmt.Sprintf("ENG RPM:%d", engine)
        if err := registry.Validate(varName, "rpm"); err != nil {
            fmt.Printf("Engine %d: %v\n", engine, err)
        }
    }
}

When building a data definition for an indexed variable, pass the full :N name to AddToDataDefinition — SimConnect requires the suffix to identify the correct instance. The registry validates the base name and units; SimConnect resolves the index at runtime.

import (
    "fmt"
    "github.com/mrlm-net/simconnect/pkg/registry"
    "github.com/mrlm-net/simconnect/pkg/types"
)

const EngineDefID = 2000

// Validate all four engine slots at startup
for i := 1; i <= 4; i++ {
    name := fmt.Sprintf("ENG RPM:%d", i)
    if err := registry.Validate(name, "rpm"); err != nil {
        panic(err)
    }
    client.AddToDataDefinition(EngineDefID, name, "rpm",
        types.SIMCONNECT_DATATYPE_FLOAT64, 0, 0)
}

Cross-Platform Usage

The pkg/registry package has no build tags and no imports from Windows-gated packages. It compiles and runs correctly on Linux, macOS, and Windows. This makes it useful in contexts where the full SimConnect stack is unavailable:

  • Validation tools — check SimVar configurations in CI pipelines on any OS
  • Code generators — enumerate variables to scaffold struct definitions
  • Test utilities — assert that dataset fields use valid unit strings without requiring a Windows environment
// This import works on all platforms — no //go:build windows needed
import "github.com/mrlm-net/simconnect/pkg/registry"

// Safe to call on Linux/macOS in tests, build tools, or generators
func validateDatasetConfig(vars []struct{ Name, Unit string }) error {
    for _, v := range vars {
        if err := registry.Validate(v.Name, v.Unit); err != nil {
            return err
        }
    }
    return nil
}

All five exported functions (Lookup, All, Validate, ByUnit, ByCategory) are safe for concurrent use. Package state is initialized once in init() and is never mutated after that.

See Also

  • Using Datasets — Pre-built dataset constructors for aircraft, environment, and simulator data
  • Client UsageAddToDataDefinition and RegisterDataset API
  • Manager Usage — Manager-level dataset registration