Skip to Content
This documentation is provided with the HEAT environment and describes this HEAT instance.

Interface control document

1. Identification

ItemValue
DocumentICD-CMSIMCONNECT-001 rev 1
ProductSimConnect module (SimConnect Module in the module registry)
Product versions covered69d794b
PeerMicrosoft Flight Simulator 2024 or Lockheed Martin Prepar3D v6, through that simulator’s SimConnect server
HostHEAT Capture, HEAT.Capture.ModuleSDK 2.0.5
Data modelSimulationFrame carrying one EntityState for the user aircraft, plus transition events
Date2026-09-02
OwnerVRAI Simulation

2. Scope

This document defines the SimConnect data-definition and subscription contract the module establishes with the simulator, how the two simulator variants are selected and what differs between them, the connection and reconnect lifecycle, and the complete mapping from each registered simulation variable to the field it is published into.

The module is read-only with respect to simulator state. It registers data definitions, subscribes to data and to two system events, and writes nothing back into the simulator. The only file it writes is the remote connection configuration described in section 7.

Section 9 is the normative mapping. Section 10 lists the places in this revision where the value written into a field does not match that field’s defined quantity, scale or unit. Both sections are statements about revision 69d794b, not about the SimConnect API.

3. Interface inventory

IDNameDirectionTransportPeer
IF-CMSIMCONNECT-01Simulation variable subscriptionSimulator to moduleSimConnect client library, local IPC or IPv4MSFS or Prepar3D
IF-CMSIMCONNECT-02System event subscriptionSimulator to moduleSame SimConnect connectionMSFS or Prepar3D
IF-CMSIMCONNECT-03Remote connection configuration fileModule to filesystemSimConnect.cfg beside the module binariesSimConnect client library
IF-CMSIMCONNECT-04Frame publicationModule to hostModule SDK publication pathHEAT Capture

4. Simulator variant selection

There is no runtime simulator detection and no setting that chooses a simulator. The variant is fixed by which of the two packages is installed. Each package ships a different module assembly that supplies its own backend, its own vendor wrapper and its own native client directory.

PropertyMSFS variantPrepar3D variant
Module classMsfsModulePrepar3DModule
Settings idSimConnectMsfsSimConnectPrepar3D
Configuration sectionHEAT.SimConnect.MsfsHEAT.SimConnect.Prepar3D
Settings typeMsfsSettings, no members of its ownPrepar3DSettings, no members of its own
BackendMsfsBackendP3DBackend
Managed wrapperMicrosoft.FlightSimulator.SimConnectLockheedMartin.Prepar3D.SimConnect
Native client directorysimconnect/msfs/SimConnect.dll, resolved relative to the module assemblysimconnect/p3d/SimConnect.dll, resolved relative to the module assembly
Application name sent on openHEAT SimConnect (MSFS)HEAT SimConnect (Prepar3D)
Pump thread nameSimConnect-MSFS-PumpSimConnect-P3D-Pump
Extra data sourcesnoneWeaponsDataSource, DisplayProbeDataSource

Everything else is shared. Both variants register the same ten built-in definition groups, request them at the same periods, and run the same mapper and the same event detector. The only capture differences are the two Prepar3D data sources in sections 9.11 and 9.12.

Both variants are registered as ModuleType.System with ModuleStartupType.SystemStartup, so they connect and hold a connection from HEAT Capture startup, independently of whether a capture session is running.

5. IF-CMSIMCONNECT-01 Simulation variable subscription

5.1 Transport and addressing

ItemValue
Client libraryThe simulator’s own managed SimConnect wrapper over its native SimConnect.dll
Native resolutionThe backend adds its simconnect/<variant>/ directory to the process DLL search path through SetDefaultDllDirectories, AddDllDirectory and SetDllDirectory before the mixed-mode wrapper type is touched
Local addressingConfig index 0, which uses the SimConnect client library’s own default local endpoint. The module supplies no local address, pipe name or port
Remote addressingConfig index 1, resolved from the SimConnect.cfg written by IF-CMSIMCONNECT-03: IPv4, RemoteHost, RemotePort
Simulation objectSIMCONNECT_OBJECT_ID_USER for every request. No AI or multiplayer object is requested
Message pumpOne background thread per connection, waiting on an auto-reset EventWaitHandle with a 500 ms timeout and calling ReceiveMessage when signalled

5.2 Connection lifecycle and reconnect

InitialiseModule creates the client, subscribes to its disconnect and active-state events, makes one synchronous connect attempt, and starts the silence timer. This runs inside the SDK StartupTimeout, 5 seconds by default.

On the simulator’s open acknowledgement the backend raises Opened on the pump thread, and the client then, in this order: registers the ten built-in definition groups, starts the ten data requests, subscribes to the Sim and Pause system events, registers each simulator-specific data source, and logs SimConnect connected to {App} (SimConnect {Major}.{Minor}) with the application name and SimConnect version the simulator reported.

StartCapture resets the event detector and sets the simulation tick counter to zero. It does not touch the connection or the cache. EndCapture does nothing.

Reconnect is driven from two triggers. A failed connect attempt logs SimConnect connection attempt failed - will retry as a warning and starts the reconnect loop. A disconnect, meaning either the simulator’s quit message or an exception on the pump thread, starts the same loop.

The loop waits ReconnectIntervalMs, default 5000 ms, disposes the current backend, and connects again. A failure logs SimConnect reconnect attempt failed at debug level and doubles the delay, capped at 30000 ms. A success logs SimConnect reconnected and ends the loop. The loop is unbounded in attempts and only ends on success, on cancellation, or on module disposal. The backoff is not reset by a later success, because each new loop starts from ReconnectIntervalMs.

Because the backend is recreated on every attempt, the definition groups, data requests, system event subscriptions and data sources are all re-registered on each successful reconnect, and the snapshot cache from before the disconnect is retained rather than cleared.

Disposal cancels the reconnect loop, disposes the silence timer, and disposes the client. Backend disposal cancels the pump, joins the pump thread with a 2 second timeout so the native handle is not freed while a dispatch is in progress, then disposes the wrapper and swallows any exception from it.

5.3 Authentication

None, in either mode. Local mode inherits whatever access control the simulator’s own SimConnect endpoint applies to local clients. Remote mode is a plain IPv4 connection to RemoteHost on RemotePort; the generated configuration carries no credential, and the module presents none.

5.4 Wire format

Each definition group is a SimConnect data definition built by adding its variables one at a time, then binding a sequentially laid-out managed struct to the group. Struct packing is 1, character set is ANSI, and the field order in the struct must equal the order the variables were added. Meaning is therefore entirely positional: nothing in the payload identifies which variable a field came from.

GroupStructVariablesRequested period
CoreCoreData31Visual frame
EngineEngineData5Visual frame
FWAFWAData27Visual frame
RWARWAData4Visual frame
LandingGearLandingGearData5Visual frame
AircraftInfoAircraftInfoData2Second
AvionicsAvionicsData17Visual frame
PropulsionControlPropulsionControlData6Visual frame
FuelSystemFuelSystemData22Visual frame
ATCATCData7Second

Simulator-specific sources use request and definition identifiers at or above 100 so they cannot collide with the built-in groups. The Prepar3D weapons group uses 100 and the Prepar3D display probe uses 120.

Requested units are expressed through a fixed neutral enumeration, and each value maps to exactly one SimConnect unit string:

Neutral unitSimConnect unit string
Nonenull, no units string sent
BooleanBool
Numbernumber
Degreesdegrees
Feetfeet
FeetPerMinutefeet per minute
FeetPerSecondfeet per second
FeetPerSecondSquaredfeet per second squared
Knotsknots
Gallonsgallons
Poundspounds
FootPoundsfoot pounds
Percentpercent
PercentOver100percent over 100
Celsiuscelsius
Millibarsmillibars
SlugsPerCubicFootslugs per cubic foot
Machmach
GForceGForce
Metersmeters

Data types are FLOAT64, INT32, STRING32 and STRING256. String variables are registered with the None unit, because SimConnect rejects a non-null units string on a string type.

Every arriving payload is boxed by the backend and stored, under a lock, into a per-group slot in the client’s snapshot cache. Each new payload replaces the previous one for that group; no history is kept.

5.5 Delivery cadence

Delivery is simulator-driven. Eight groups are requested per visual frame, so their arrival rate is the simulator’s render rate. AircraftInfo and ATC are requested once per second. The Prepar3D weapons group is per visual frame and the Prepar3D display probe is once per second.

Publication is not tied to delivery. The module reads the cache at the SDK Interval cadence, 1000 ms by default, so at a 60 Hz render rate roughly 59 of every 60 arrivals of a visual-frame group are overwritten before they are ever read. This is by design for state, but it also means transitions are detected only against the values latched at successive publication cycles, not against every value the simulator delivered.

6. IF-CMSIMCONNECT-02 System event subscription

Two named SimConnect system events are subscribed on every connect: Sim and Pause. Their payload is treated as a boolean, non-zero meaning true.

The module keeps both flags and derives one combined active state, defined as running and not paused. It raises a change only when that combined state flips.

Combined stateConditionModule action
Becomes activeSim non-zero and Pause zeroIf StartOnSimRunning is set and no session is started, logs Simulation is running - starting session and asks the host to start a session
Becomes inactiveSim zero, or Pause non-zeroIf StopOnSimPaused is set and a session is started, logs Simulation paused or stopped - stopping session and asks the host to stop the session

The simulator’s quit message also clears both flags, without raising a combined-state change.

A separate silence timer runs on a 1 second period, independent of these events. When StopOnSilence is set, a session is started, the client is connected, and the time since the last payload of any kind is at least SilenceThreshold, it logs {Time}s of silence detected - stopping session and asks the host to stop the session. The logged value is the seconds component of SilenceThreshold, so a threshold expressed as a whole number of minutes logs as 0s.

7. IF-CMSIMCONNECT-03 Remote connection configuration file

When RemoteHost is empty or null, no file is written and config index 0 is used. When RemoteHost has a value, the module overwrites SimConnect.cfg in the application base directory, beside the module binaries, with exactly this content and then connects with config index 1:

[SimConnect.1] Protocol=IPv4 Address=<RemoteHost> Port=<RemotePort> MaxReceiveSize=4096

The protocol, the section index and the 4096-byte receive size are fixed in code. The file is rewritten on every connect attempt, including every reconnect attempt, and is never deleted.

8. IF-CMSIMCONNECT-04 Frame publication and data model reference

8.1 Entity identity

ItemValue
Entity nameThe TITLE variable last received in the AircraftInfo group, or the literal Unknown Aircraft when no title has been cached
Entity id64-bit FNV-1a hash over the UTF-8 bytes of that same cached title, or 0 when the title is null or empty
Aircraft typeDerived from the CATEGORY variable: Helicopter gives rotary-wing; Airplane, Glider and Amphibian give fixed-wing; every other value, including an empty one, gives unknown

The identity is derived from the cached title, not from the fallback name, so a frame published before the first AircraftInfo payload is named Unknown Aircraft with id 0. The hash is computed from scratch on every publication cycle and is stable across processes and sessions for a given title.

8.2 Frame envelope

Each publication cycle produces one SimulationFrame with one EntityState.

FieldValue
SimulationFrame.simulation_tickA counter incremented once per published frame, reset to zero by StartCapture
SimulationFrame.capture_timeNever set by this module; left at the proto default
SimulationFrame.simulation_time_secondsNever set; left at the proto default
SimulationFrame.entitiesExactly one EntityState
EntityState.timestampNever set; left at the proto default
Event timestampsHost wall clock, UTC Unix milliseconds, taken once per cycle and applied to every event in that frame

The only timestamp a consumer can rely on for state is therefore the SDK’s own envelope value, DataPacket.TimestampUnixMs, taken when the payload is wrapped. See the Module SDK ICD for that envelope.

8.3 Publication preconditions

Nothing is published, and the cycle returns no frame, in either of these cases: the client is null or reports not connected, or the Core group has never delivered a payload. The module does not publish a seeded or zeroed frame.

Once the Core group has delivered once, a frame is published every cycle even if the connection later drops mid-cycle, and every group other than Core is optional. An absent group means its components are omitted, except where section 10 records a group whose absence produces a published value rather than an omission.

Component presence is therefore:

ComponentCondition
WorldPositionComponent, DynamicsComponent, AirDataComponent, CloudDataComponent, GenericAircraftComponentAlways, since Core is a precondition
AircraftEngineComponentEngine cached
AircraftAvionicsComponentAvionics cached
ResourceStoresComponent, FuelSystemComponentFuelSystem cached
AircraftLandingGearComponentLandingGear cached
FWAControlSurfacesComponent, FWAInputComponent, FWADataComponentAircraft type is fixed-wing and FWA cached
RotaryWingDataComponentAircraft type is rotary-wing and RWA cached
ATCDataComponentATC cached
AircraftDisplayStateComponentPrepar3D variant only, and the display probe has delivered once

An unknown aircraft type publishes neither the fixed-wing nor the rotary-wing components, and is not logged.

8.4 Events

Events are edge-triggered against the previous publication cycle’s value. Detector state is recreated by StartCapture, with initial values of not stalling, not overspeeding, on the ground, and engine not running.

EventPayloadTriggerCondition
StateChangedEventstate is stall_warning_onSTALL WARNING false to trueFixed-wing only
StateChangedEventstate is stall_warning_offSTALL WARNING true to falseFixed-wing only
StateChangedEventstate is overspeed_warning_onOVERSPEED WARNING false to trueFixed-wing only
StateChangedEventstate is groundedSIM ON GROUND false to trueAny type
StateChangedEventstate is airborneSIM ON GROUND true to falseAny type
StateChangedEventstate is engine_runningENG COMBUSTION:1 false to trueAny type
StateChangedEventstate is engine_stoppedENG COMBUSTION:1 true to falseAny type

There is deliberately no overspeed_warning_off: the detector is given a null falling-edge label for that transition, so a cleared overspeed warning produces no event.

Because the initial state assumes on the ground with the engine off, a session started with the aircraft already airborne or already running publishes airborne or engine_running on the first cycle even though nothing changed at that instant.

The detector also contains a threshold-event helper that nothing calls, so no ThresholdEvent is ever published by this module. G-force is captured and published as state only.

Prepar3D adds the discrete combat events in section 9.11, drained once per cycle from the weapons source. They carry the same entity id and timestamp as the frame’s other events, not the time the transition was observed on the pump thread.

9. Simulation variable to published field mapping

Conversion factors used below, as defined in the mapper:

ConversionFactor
Feet to metres, and feet per second to metres per second, and feet per second squared to metres per second squared0.3048
Knots to metres per second0.51444
Pounds-force to newtons4.44822
Foot-pounds to newton-metres1.3558179483314004

Every value is narrowed from the transported double to float when written. “Not published” means the variable is registered and cached but no published field is derived from it.

9.1 Core group

Present in every published frame.

Simulation variableRequested unitPublished fieldConversion
PLANE LATITUDEdegreesWorldPositionComponent.latitudenone
PLANE LONGITUDEdegreesWorldPositionComponent.longitudenone
PLANE ALTITUDEfeetWorldPositionComponent.altitude and GenericAircraftComponent.true_altitudefeet to metres
PLANE HEADING DEGREES TRUEdegreesWorldPositionComponent.headingnone
PLANE PITCH DEGREESdegreesWorldPositionComponent.pitch_degnone
PLANE BANK DEGREESdegreesWorldPositionComponent.roll_degnone
VELOCITY WORLD Xfeet per secondDynamicsComponent.velocity.xfeet to metres
VELOCITY WORLD Yfeet per secondDynamicsComponent.velocity.yfeet to metres
VELOCITY WORLD Zfeet per secondDynamicsComponent.velocity.zfeet to metres
ACCELERATION WORLD Xfeet per second squaredDynamicsComponent.acceleration.xfeet to metres
ACCELERATION WORLD Yfeet per second squaredDynamicsComponent.acceleration.yfeet to metres
ACCELERATION WORLD Zfeet per second squaredDynamicsComponent.acceleration.zfeet to metres
GROUND VELOCITYknotsDynamicsComponent.ground_speedknots to metres per second
VELOCITY BODY Zfeet per secondDynamicsComponent.magnitudefeet to metres
SIM ON GROUNDBoolDynamicsComponent.is_groundednon-zero test
AMBIENT TEMPERATUREcelsiusAirDataComponent.ambient_air_temperaturenone
TOTAL AIR TEMPERATUREcelsiusAirDataComponent.total_air_temperaturenone
AMBIENT PRESSUREmillibarsAirDataComponent.air_pressurenone
BAROMETER PRESSUREmillibarsAirDataComponent.sea_level_pressurenone
AMBIENT DENSITYslugs per cubic footAirDataComponent.densitynone
AMBIENT WIND VELOCITYknotsAirDataComponent.wind_velocityknots to metres per second
AMBIENT WIND DIRECTIONdegreesAirDataComponent.surface_wind_directionnone
SPEED OF SOUNDknotsAirDataComponent.speed_of_soundknots to metres per second
AMBIENT VISIBILITYmetersCloudDataComponent.visibilitynone
AMBIENT IN CLOUDBoolCloudDataComponent.in_cloudnon-zero test
PLANE ALT ABOVE GROUNDfeetGenericAircraftComponent.aglfeet to metres
INDICATED ALTITUDEfeetnot published, see SIM-01 in section 10not applicable
KOHLSMAN SETTING MBmillibarsGenericAircraftComponent.barometric_altitude, see SIM-01none
G FORCEGForceGenericAircraftComponent.g_forcenone
MAX G FORCEGForceGenericAircraftComponent.g_force_maxnone
MIN G FORCEGForceGenericAircraftComponent.g_force_minnone

9.2 Engine group

Simulation variableRequested unitPublished fieldConversion
ENG COMBUSTION:1BoolAircraftEngineComponent.engine_state and AircraftEngineComponent.ignition, both from this one variablenon-zero test
GENERAL ENG THROTTLE LEVER POSITION:1percent over 100AircraftEngineComponent.throttlenone
TURB ENG JET THRUST:1poundsAircraftEngineComponent.thrustpounds-force to newtons
TURB ENG THROTTLE LEVER POSITION:1percent over 100AircraftEngineComponent.thrust_percentagenone
GENERAL ENG REVERSE THRUST ACTIVE:1BoolAircraftEngineComponent.reverse_thrust_activenon-zero test

Only engine 1 is registered. A multi-engine aircraft publishes one engine component describing its first engine.

9.3 Fixed-wing group

Published only when the aircraft type resolves to fixed-wing.

Simulation variableRequested unitPublished fieldConversion
AILERON POSITIONpercent over 100FWAControlSurfacesComponent.aileron_positionnone
ELEVATOR POSITIONpercent over 100FWAControlSurfacesComponent.elevator_positionnone
RUDDER POSITIONpercent over 100FWAControlSurfacesComponent.rudder_positionnone
AILERON TRIM PCTpercent over 100FWAControlSurfacesComponent.aileron_trim_percentagenone
ELEVATOR TRIM PCTpercent over 100FWAControlSurfacesComponent.elevator_trim_percentagenone
RUDDER TRIM PCTpercent over 100FWAControlSurfacesComponent.rudder_trim_percentagenone
FLAPS HANDLE INDEXnumberFWAControlSurfacesComponent.flaps_positionnone
FLAPS HANDLE PERCENTpercent over 100FWAControlSurfacesComponent.flaps_position_percentagenone
SPOILERS HANDLE POSITIONpercent over 100FWAControlSurfacesComponent.spoilers_positiontruncating cast to a 32-bit integer, see section 10
G FORCE (FWA copy)GForcenot published; GenericAircraftComponent.g_force is taken from the Core copy insteadnot applicable
YOKE X POSITIONpercent over 100FWAInputComponent.yoke_value.xnone
YOKE Y POSITIONpercent over 100FWAInputComponent.yoke_value.ynone
RUDDER PEDAL POSITIONpercent over 100FWAInputComponent.rudder_valuenone
BRAKE LEFT POSITIONpercent over 100FWAInputComponent.toe_brakes_leftnone
BRAKE RIGHT POSITIONpercent over 100FWAInputComponent.toe_brakes_rightnone
AIRSPEED INDICATEDknotsFWADataComponent.airspeed_calibrated, see section 10knots to metres per second
AIRSPEED MACHmachFWADataComponent.airspeed_machnone
BARBER POLE SPEEDknotsFWADataComponent.airspeed_barber_poleknots to metres per second
STALL WARNINGBoolFWADataComponent.stall_warningnon-zero test
OVERSPEED WARNINGBoolFWADataComponent.overspeed_warningnon-zero test
ATTITUDE INDICATOR PITCH DEGREESdegreesFWADataComponent.altitude_indicator_pitch_degreesnone
ATTITUDE INDICATOR BANK DEGREESdegreesFWADataComponent.altitude_indicator_bank_degreesnone
PLANE HEADING DEGREES GYROdegreesFWADataComponent.plane_gyro_heading_degreesnone
TURN COORDINATOR BALLpercentFWADataComponent.turn_coordinator_ballnone
ANGLE OF ATTACK INDICATORdegreesFWADataComponent.aoa_indicatornone
RADIO HEIGHTfeetFWADataComponent.radio_heightfeet to metres
GEAR WARNINGnumberFWADataComponent.gear_warning_valuenone

FWADataComponent.indicated_altitude and FWADataComponent.kohlsman_setting exist in the schema and are never populated by this module. That is the other half of SIM-01.

FWAInputComponent also carries five fields sourced from other groups:

FieldSourceValue when the source group is not cached
throttle_lever_positionPropulsionControl group, GENERAL ENG THROTTLE LEVER POSITION:10
commanded_throttlePropulsionControl group, TURB ENG THROTTLE LEVER POSITION:10
autothrottle_activeAvionics group, AUTOTHROTTLE ACTIVEtrue, see section 10
afterburner_activePropulsionControl group, TURB ENG AFTERBURNER:1true, see section 10
reverse_thrust_activePropulsionControl group, GENERAL ENG REVERSE THRUST ACTIVE:1true, see section 10

9.4 Rotary-wing group

Published only when the aircraft type resolves to rotary-wing.

Simulation variableRequested unitPublished fieldConversion
ENG TORQUE:1foot poundsRotaryWingDataComponent.main_rotors_torque, as the single element of the listfoot-pounds to newton-metres
TAIL ROTOR BLADE PITCH PCTpercent over 100RotaryWingDataComponent.tail_rotor_torque, see section 10none
ROTOR LATERAL TRIM PCTpercent over 100RotaryWingDataComponent.rotor_lateral_trimnone
ROTOR LONGITUDINAL TRIM PCTpercent over 100RotaryWingDataComponent.rotor_longitudinal_trimnone

engine_torque_limit is not populated.

9.5 Landing gear group

Simulation variableRequested unitPublished fieldConversion
GEAR TOTAL PCT EXTENDEDpercent over 100AircraftLandingGearComponent.extended_percentage, see section 10none
GEAR HANDLE POSITIONBoolAircraftLandingGearComponent.gear_handle_valuenon-zero test
BRAKE PARKING INDICATORBoolAircraftLandingGearComponent.parking_brake_enablednon-zero test
IS GEAR RETRACTABLEBoolAircraftLandingGearComponent.is_gear_retractablenon-zero test
GEAR EMERGENCY HANDLE POSITIONBoolAircraftLandingGearComponent.gear_emergency_handle_positionnon-zero test

No WheelComponent is populated, and allow_steering, parking_brake_available, gear_max_airspeed, hydraulic_pressure, lock_on and is_damaged are not set.

9.6 Aircraft identity group

Simulation variableRequested unitTypeUse
CATEGORYnullSTRING32Aircraft type classification described in 8.1. Not published as a field
TITLEnullSTRING256Entity name and entity id described in 8.1

9.7 Avionics group

Simulation variableRequested unitPublished fieldConversion
AUTOPILOT MASTERBoolAircraftAvionicsComponent.autopilot_masternon-zero test
AUTOPILOT FLIGHT DIRECTOR ACTIVEBoolAircraftAvionicsComponent.flight_director_masternon-zero test
AUTOTHROTTLE ACTIVEBoolAircraftAvionicsComponent.autothrottle_master, and FWAInputComponent.autothrottle_active on fixed-wingnon-zero test
AUTOPILOT HEADING LOCK DIRdegreesAircraftAvionicsComponent.selected_heading_degreesnone
AUTOPILOT ALTITUDE LOCK VARfeetAircraftAvionicsComponent.selected_altitude_metersfeet to metres
AUTOPILOT AIRSPEED HOLD VARknotsAircraftAvionicsComponent.selected_indicated_airspeed_meters_per_secondknots to metres per second
AUTOPILOT MACH HOLD VARmachAircraftAvionicsComponent.selected_machnone
AUTOPILOT VERTICAL HOLD VARfeet per minuteAircraftAvionicsComponent.selected_vertical_speed_meters_per_secondfeet to metres, then divided by 60
AUTOPILOT APPROACH HOLDBoolactive_lateral_mode and active_lateral_mode_label, first prioritysee mode resolution below
AUTOPILOT NAV1 LOCKBoolactive_lateral_mode and active_lateral_mode_label, second prioritysee mode resolution below
AUTOPILOT HEADING LOCKBoolactive_lateral_mode and active_lateral_mode_label, third prioritysee mode resolution below
AUTOPILOT BACKCOURSE HOLDBoolactive_lateral_mode_label onlysee mode resolution below
AUTOPILOT GLIDESLOPE HOLDBoolactive_vertical_mode and active_vertical_mode_label, first prioritysee mode resolution below
AUTOPILOT VERTICAL HOLDBoolactive_vertical_mode and active_vertical_mode_label, second prioritysee mode resolution below
AUTOPILOT ALTITUDE LOCKBoolactive_vertical_mode and active_vertical_mode_label, third prioritysee mode resolution below
AUTOPILOT AIRSPEED HOLDBoolnot publishednot applicable
AUTOPILOT MACH HOLDBoolnot publishednot applicable

Mode resolution is strictly first-match in the priority order shown, so only one lateral and one vertical mode is ever reported even when the simulator has several engaged.

Resolved modeEnum valueLabel
Lateral, approach hold engagedAIRCRAFT_AUTOPILOT_LATERAL_MODE_APPROACHapproach
Lateral, nav1 lock engagedAIRCRAFT_AUTOPILOT_LATERAL_MODE_NAVnav
Lateral, heading lock engagedAIRCRAFT_AUTOPILOT_LATERAL_MODE_HEADING_HOLDheading_hold
Lateral, none engagedAIRCRAFT_AUTOPILOT_LATERAL_MODE_UNSPECIFIEDempty string
Vertical, glideslope hold engagedAIRCRAFT_AUTOPILOT_VERTICAL_MODE_GLIDESLOPEglideslope
Vertical, vertical hold engagedAIRCRAFT_AUTOPILOT_VERTICAL_MODE_VSvertical_speed
Vertical, altitude lock engagedAIRCRAFT_AUTOPILOT_VERTICAL_MODE_ALT_HOLDaltitude_hold
Vertical, none engagedAIRCRAFT_AUTOPILOT_VERTICAL_MODE_UNSPECIFIEDempty string

Backcourse hold is a label-only override: when it is engaged the label becomes backcourse regardless of the other lateral variables, while active_lateral_mode still reports whichever of approach, nav or heading hold matched. A consumer that reads the enum and the label together will see them disagree in that case. There is no backcourse value in the lateral mode enumeration.

9.8 Propulsion control group

Simulation variableRequested unitPublished field
GENERAL ENG THROTTLE LEVER POSITION:1percent over 100FWAInputComponent.throttle_lever_position, fixed-wing only
TURB ENG THROTTLE LEVER POSITION:1percent over 100FWAInputComponent.commanded_throttle, fixed-wing only
GENERAL ENG REVERSE THRUST ACTIVE:1BoolFWAInputComponent.reverse_thrust_active, fixed-wing only
TURB ENG AFTERBURNER:1BoolFWAInputComponent.afterburner_active, fixed-wing only
TURB ENG AFTERBURNER STAGE ACTIVE:1numbernot published; module debug view only
TURB ENG AFTERBURNER PCT ACTIVE:1percent over 100not published; module debug view only

A rotary-wing or unknown-type aircraft publishes nothing at all from this group, because its only published destination is the fixed-wing input component.

9.9 Fuel system group

Nine ResourceStoreEntry rows are published unconditionally whenever the group is cached, whether or not the aircraft has the corresponding tank. A tank the aircraft does not have reports quantity 0, which is indistinguishable from a real empty tank.

Simulation variable pairRequested unitsstore_idstore_labellocationjettisonable
FUEL TANK LEFT MAIN QUANTITY and FUEL TANK LEFT MAIN LEVELgallons, percent over 100left_mainLeft MainSTORE_LOCATION_INTERNALfalse
FUEL TANK RIGHT MAIN QUANTITY and FUEL TANK RIGHT MAIN LEVELgallons, percent over 100right_mainRight MainSTORE_LOCATION_INTERNALfalse
FUEL TANK CENTER QUANTITY and FUEL TANK CENTER LEVELgallons, percent over 100centerCenterSTORE_LOCATION_INTERNALfalse
FUEL TANK LEFT AUX QUANTITY and FUEL TANK LEFT AUX LEVELgallons, percent over 100left_auxLeft AuxSTORE_LOCATION_INTERNALfalse
FUEL TANK RIGHT AUX QUANTITY and FUEL TANK RIGHT AUX LEVELgallons, percent over 100right_auxRight AuxSTORE_LOCATION_INTERNALfalse
FUEL TANK LEFT TIP QUANTITY and FUEL TANK LEFT TIP LEVELgallons, percent over 100left_tipLeft TipSTORE_LOCATION_INTERNALfalse
FUEL TANK RIGHT TIP QUANTITY and FUEL TANK RIGHT TIP LEVELgallons, percent over 100right_tipRight TipSTORE_LOCATION_INTERNALfalse
FUEL TANK EXTERNAL1 QUANTITY and FUEL TANK EXTERNAL1 LEVELgallons, percent over 100external_1External 1STORE_LOCATION_EXTERNALtrue
FUEL TANK EXTERNAL2 QUANTITY and FUEL TANK EXTERNAL2 LEVELgallons, percent over 100external_2External 2STORE_LOCATION_EXTERNALtrue

Within each row, the quantity variable becomes current_quantity unconverted, and the level variable is multiplied by 100 and carried as an extra_data entry keyed fill_level_percent. Every row also sets resource_type to RESOURCE_TYPE_FUEL and unit to RESOURCE_UNIT_GALLONS, and sets max_quantity to 0, resource_type_label to an empty string and unit_label to an empty string.

The remaining variables in the group:

Simulation variableRequested unitPublished field
FUEL DUMP ACTIVEBoolFuelSystemComponent.fuel_dump_active
FUEL CROSS FEEDBoolFuelSystemComponent.crossfeed_enabled
FUEL TOTAL QUANTITYgallonsnot published; module debug view only
FUEL TOTAL QUANTITY WEIGHTpoundsnot published; module debug view only

9.10 ATC identity group

Simulation variableRequested unitTypePublished field
ATC TYPEnullSTRING256ATCDataComponent.atc_type
ATC MODELnullSTRING256ATCDataComponent.atc_model
ATC IDnullSTRING256ATCDataComponent.atc_id
ATC AIRLINEnullSTRING256ATCDataComponent.atc_airline
ATC FLIGHT NUMBERnullSTRING32ATCDataComponent.atc_flight_number
HSI STATION IDENTnullSTRING32ATCDataComponent.hsi_station_ident
TRANSPONDER CODE:1numberINT32ATCDataComponent.transponder_code, formatted as four uppercase hexadecimal digits

The transponder value is registered with the number unit but formatted on the assumption that the simulator returned a binary-coded value, so that each hexadecimal digit is one squawk digit. The module does not validate that assumption, and it does not reject a value whose hexadecimal rendering contains digits 8 or above, which cannot occur in a real octal squawk. A code that needs more than four hexadecimal digits is rendered at its natural width rather than truncated.

9.11 Prepar3D weapons group

Registered and requested per visual frame by the Prepar3D variant only. This group populates no component; it produces only discrete events. Per-station variables are registered for stations 1 to 16 and marshalled as fixed 16-element arrays; the simulator reports zero for stations beyond the aircraft’s actual station count.

Simulation variableRequested unitPublished result
WEAPON SYSTEM STATION OBJECT COUNT:1..16numberA decrease on any station emits FiredEvent
WEAPON SYSTEM STATION OBJECT ID:1..16numberFiredEvent.bullet_entity_id for that station’s release
WEAPON TYPEnull, STRING256Both FiredEvent.weapon_name and FiredEvent.munition_name for a station release, and the suffix of the weapon_selected state
GUN SYSTEM TRIGGER ENGAGEDBoolA false-to-true edge emits FiredEvent with weapon_name gun and munition_name rounds
COUNTERMEASURE SYSTEM STATION OBJECT COUNT:1..16numberA decrease on any station emits CountermeasureEvent with an empty countermeasure_name
FCS TARGETED OBJECT IDnumberA change emits TargetTrackingEvent; see below
WEAPON SYSTEM ARMEDBoolA change emits StateChangedEvent with state master_arm_on or master_arm_off
WEAPON SYSTEM TRIGGER ENGAGEDBoolnot published
STATION COUNTnumbernot published
GUN SYSTEM STATION AMMO COUNT:1..16numbernot published
FCS TARGETED LATITUDEdegreesnot published
FCS TARGETED LONGITUDEdegreesnot published
FCS TARGETED ALTITUDEfeetnot published

On a target change the source emits, in this order, a TargetTrackingEvent with state Released, sensor_or_lock_type fcs and reason changed for the previous target when that was non-zero, then a TargetTrackingEvent with state Locked and sensor_or_lock_type fcs for the new target when that is non-zero. Target ids are read as unsigned 32-bit values before being widened, so a negative identifier from the simulator becomes a large positive entity id.

A weapon-selection change emits StateChangedEvent with state set to weapon_selected: followed by the reported weapon type. A selection clearing to an empty string emits nothing.

Transitions are detected on the pump thread at visual-frame rate and queued, then drained once per publication cycle, so this source does not lose transitions between cycles the way the shared detector does. The queue is unbounded.

The first payload after each connect establishes the baseline and emits nothing.

9.12 Prepar3D display probe group

Registered and requested once per second by the Prepar3D variant only. All eight variables are carried verbatim as AircraftDisplayStateComponent.extra_data entries, and the first four also feed the derived page labels.

Simulation variableRequested unitextra_data key
AVIONICS MASTER SWITCHBoolavionics_master_switch
CIRCUIT GENERAL PANEL ONBoolcircuit_general_panel_on
CIRCUIT AVIONICS ONBoolcircuit_avionics_on
CIRCUIT AUTOPILOT ONBoolcircuit_autopilot_on
PARTIAL PANEL AVIONICSnumberpartial_panel_avionics
PARTIAL PANEL ELECTRICALnumberpartial_panel_electrical
PARTIAL PANEL COMMnumberpartial_panel_comm
PARTIAL PANEL NAVnumberpartial_panel_nav

Two display entries are published, always both and always with these fixed identifiers, and soi_display_id is always an empty string:

display_idroleactive_page resolution, first match wins
primary_flight_displayAIRCRAFT_DISPLAY_ROLE_PFDoff if avionics master, general panel circuit or avionics circuit is zero; electrical_partial if partial-panel electrical is non-zero; avionics_partial if partial-panel avionics is non-zero; otherwise active
multifunction_displayAIRCRAFT_DISPLAY_ROLE_MFDoff if avionics master or avionics circuit is zero; nav_partial if partial-panel nav is non-zero; comm_partial if partial-panel comm is non-zero; avionics_partial if partial-panel avionics is non-zero; otherwise active

active_page is therefore a derived power and degradation label, not a page name. SimConnect exposes generic simulation variables only; the aircraft-local gauge variables that a custom multi-function display uses for its page and sensor-of-interest state are not reachable this way, so no real page identity is available to publish. On registration the source records this as an information-level log line.

The probe also logs its values once on the first payload and again on every change.

9.13 Values published without a source variable

These fields are written on every applicable frame from a constant, not from the simulator. A consumer cannot distinguish them from a measured value.

FieldConstant
AircraftAvionicsComponent.armed_lateral_modeAIRCRAFT_AUTOPILOT_LATERAL_MODE_UNSPECIFIED
AircraftAvionicsComponent.armed_vertical_modeAIRCRAFT_AUTOPILOT_VERTICAL_MODE_UNSPECIFIED
AircraftAvionicsComponent.armed_lateral_mode_labelempty string
AircraftAvionicsComponent.armed_vertical_mode_labelempty string
FuelSystemComponent.fuel_dump_rate0
FuelSystemComponent.fuel_total_flow_rate0
FuelSystemComponent.fuel_transfer_activefalse
FuelSystemComponent.refuel_activefalse
FuelSystemComponent.selected_feed_source_store_idempty string
FuelSystemComponent.active_dump_source_store_idempty string
ResourceStoreEntry.max_quantity0 for every store
AircraftDisplayStateComponent.soi_display_idempty string

SimConnect exposes no transfer-path, dump-rate or fuel-flow variable in the set this module registers, so the fuel process values above have no available source. The armed autopilot modes have no source either: the module registers only engaged states.

10. Mapping defects in this revision

These are properties of revision 69d794b, not of SimConnect or of the HEAT schema. SIM-01 is the recorded audit finding; the remaining rows are observations from the same reading of this revision and carry no finding id.

RefFieldPublished valueWhy it is wrong
SIM-01GenericAircraftComponent.barometric_altitudeKOHLSMAN SETTING MB in millibarsThe field is an altitude. The module writes the altimeter’s pressure reference setting into it, unconverted, and never reads the INDICATED ALTITUDE variable it registers and caches. FWADataComponent.indicated_altitude and FWADataComponent.kohlsman_setting, the two fields that would carry these values correctly, are both left unset. Published altitude in this revision is materially wrong, and the repository’s own mapper test asserts the wrong value, so any fix must also change that test
noneAircraftLandingGearComponent.extended_percentageGEAR TOTAL PCT EXTENDED as a fraction from 0 to 1The field is defined as a percentage where 0 is up and 100 is fully down. Fully extended gear publishes 1, not 100, so the value is a factor of 100 low
noneFWAControlSurfacesComponent.spoilers_positionSPOILERS HANDLE POSITION, a fraction from 0 to 1, truncated to a 32-bit integerThe field is an integer detent index. Truncation collapses every partial deployment to 0 and only fully deployed spoilers to 1, so intermediate spoiler positions are unobservable
noneRotaryWingDataComponent.tail_rotor_torqueTAIL ROTOR BLADE PITCH PCT as a fractionA blade pitch percentage is not a torque. No unit conversion is applied and none would make it one. The repository’s rotary test asserts this behaviour
noneDynamicsComponent.magnitudeVELOCITY BODY Z converted to metres per secondThe field is the magnitude of the velocity vector. Body-axis longitudinal velocity is signed and excludes the other two axes, so the value is negative in reverse and lower than the true speed in any sideslip or climb
noneAircraftEngineComponent.thrust_percentageTURB ENG THROTTLE LEVER POSITION:1 as a fractionThe field is thrust as a percentage of maximum. A throttle lever position is a command, not a thrust, and the fraction is a factor of 100 low against a percentage field
noneAircraftEngineComponent.ignitionENG COMBUSTION:1Ignition is published as a duplicate of engine_state from the same variable. The module registers no ignition variable, so ignition state is not actually observed
noneFWADataComponent.airspeed_calibratedAIRSPEED INDICATED converted to metres per secondIndicated airspeed is published in the calibrated airspeed field. The two differ by instrument and position error, and the schema has no indicated-airspeed field to move it to
noneAirDataComponent.wind_velocityAMBIENT WIND VELOCITY converted to metres per secondThe field is annotated in knots. The module converts before writing, so the value is roughly half the number a knots-reading consumer expects. surface_wind_speed, which is defined in metres per second, is left unset
noneFWAInputComponent.autothrottle_active, afterburner_active, reverse_thrust_activetrue when the source group has not been cachedEach is computed by comparing a nullable integer against zero. A null, meaning the Avionics or PropulsionControl group has not arrived yet, compares as not equal to zero and therefore publishes true. On a fixed-wing aircraft the first frames after connect can report the autothrottle engaged, the afterburner lit and reverse thrust deployed when none of that is known
noneSimulationFrame.capture_time and EntityState.timestampnever setBoth builders expose the setter and neither is called, so state carries no in-band time. Only events carry a timestamp. Correlating state across modules depends entirely on the SDK envelope timestamp

AircraftAvionicsComponent.active_lateral_mode_label disagreeing with active_lateral_mode under backcourse hold, described in 9.7, is a schema limitation rather than a mapping error: the lateral mode enumeration has no backcourse value.

11. Units and conventions

ConceptConvention
PositionDecimal degrees, positive north and east, from the simulator’s own geodetic position. Narrowed to 32-bit float, which quantises at roughly 0.3 to 1 metre
AltitudeMetres above mean sea level for true altitude, metres above terrain for AGL. Both converted from feet at 0.3048
AttitudeDegrees. Heading is true heading, not magnetic. Pitch and roll are the simulator’s own sign convention, passed through
Linear velocity and accelerationMetres per second and metres per second squared, in the simulator’s world axes, converted from feet
AirspeedMetres per second, converted from knots at 0.51444
MachDimensionless, passed through
TemperatureDegrees Celsius, passed through
PressureMillibars, passed through
Air densitySlugs per cubic foot, passed through unconverted, matching the field’s own annotation
Control positions and trimsFractions from 0 to 1 as delivered by percent over 100, written without rescaling. Fields whose schema expects a percentage therefore read a factor of 100 low
Fuel quantityUS gallons, unconverted, with the unit enumeration set accordingly. Fill level is rescaled to a percentage in extra_data
TorqueNewton-metres for main rotor torque, converted from foot-pounds
ThrustNewtons, converted from pounds-force at 4.44822
BooleansAny non-zero integer is true
Time baseHost wall clock, UTC Unix milliseconds. No simulator clock is read, and no simulation time is published
Frame orderingsimulation_tick increases by one per published frame and restarts at zero on each capture start, so it identifies a frame within a session only

Values are passed through without range validation. The authority for the meaning of each simulation variable is the simulator vendor’s own SimConnect documentation; this module does not define or constrain it.

12. Error behaviour

ConditionBehaviour
Native SimConnect.dll missing from the variant’s directoryThe backend throws FileNotFoundException naming the expected path before the wrapper loads. It surfaces as a connect failure, so the module retries forever rather than reporting a permanent configuration fault
Simulator not running at initialisationConnect throws, logged as warning SimConnect connection attempt failed - will retry, reconnect loop starts. Initialisation still reports success
Publication cycle while disconnectedNo frame, no log
Publication cycle before the first Core payloadNo frame, no log
Simulator sends its quit messageWarning SimConnect disconnected (sim quit), connection marked down, both system-event flags cleared, reconnect loop starts
Exception on the message pump threadWarning SimConnect MSFS pump error - marking disconnected or SimConnect P3D pump error - marking disconnected, connection marked down, disconnect raised, pump thread exits, reconnect loop starts
SimConnect protocol exception, for example a rejected variable nameDebug SimConnect exception {Code} on send {SendId}. No state change, no retry, nothing published about the affected group
Reconnect attempt failsDebug SimConnect reconnect attempt failed, delay doubles, capped at 30000 ms
Reconnect succeedsInformation SimConnect reconnected
Payload arrives for a data-source request id at or above 100 that no source claimsDebug Unhandled data-source request {RequestId}
Payload arrives for an unrecognised built-in request idError Unhandled data request {RequestId}
CATEGORY is a value the module does not recogniseAircraft type becomes unknown; neither fixed-wing nor rotary-wing components are published, and nothing is logged
Exception during frame constructionReturned as a faulted task. The SDK logs Error in module and the capture loop continues
Backend disposal throws because the simulator has already goneSwallowed

The debug-level handling of protocol exceptions is the significant one. Because definition layout is positional, a rejected variable name silently changes what every following field in that group means, and the only report of it is a debug log line.

13. Configuration affecting the interfaces

SettingDefaultInterface effect
RemoteHostemptyEmpty selects local connection with config index 0 and writes no file. A value writes SimConnect.cfg per section 7 and selects config index 1
RemotePort500Port written into that file. Ignored when RemoteHost is empty
ReconnectIntervalMs5000First delay in the reconnect loop. Doubles per failure, capped at 30000 ms. Does not affect the initial connect attempt
StartOnSimRunningtrueWhether becoming active on IF-CMSIMCONNECT-02 starts a capture session
StopOnSimPausedtrueWhether becoming inactive on IF-CMSIMCONNECT-02 stops the active session
StopOnSilencefalseWhether the silence timer may stop the session
SilenceThreshold30 secondsData-idle duration the silence timer requires. Only consulted when StopOnSilence is set

Nothing in the settings changes which simulation variables are registered, which units are requested, or which periods are used. Those are fixed in code, as is the 500 ms pump wait, the 2 second pump join on disposal, the 1 second silence-timer period, the 30000 ms reconnect cap, the 4096-byte remote receive size, and the 16-station cap in the Prepar3D weapons source.

The generic SDK settings also apply. Interval is the publication cadence and is re-read every cycle; it does not change the simulator’s delivery rate. See Manage capture modules for those, and the Module SDK ICD for the lifecycle and envelope this module runs inside.

14. Compatibility and versioning

There is no protocol version negotiation. The module logs the application name and SimConnect version the simulator reports on open, and then proceeds identically whatever those values are. No version gate, capability check or feature test exists.

Compatibility rests on three assumptions, none of which is verified at runtime:

  • Every registered variable name is accepted by the simulator with the requested unit string. A rejection is only debug-logged, and because layout is positional the group’s remaining fields shift and are misattributed.
  • The vendor wrapper and the native client in the package match the installed simulator. The two packages are not interchangeable and the module cannot detect being paired with the wrong simulator.
  • The managed wrappers are mixed-mode assemblies and cannot load into a collectible assembly load context. A host using a custom module load context must fall back to the non-collectible default context.

Variable coverage is a fixed list. Variables the simulator supports but the module does not register are absent; there is no way to extend the set through configuration.

15. Security considerations

The local interface is the simulator’s own SimConnect endpoint on the same workstation, with no authentication and no encryption. Any local process able to reach that endpoint can subscribe to the same data.

Remote mode increases the exposure: an unauthenticated, unencrypted IPv4 connection whose endpoint the module writes in cleartext into SimConnect.cfg beside its own binaries, rewritten on every connect attempt and never removed. Anyone able to read the module directory learns the remote host and port; anyone able to write it can redirect the module to another host. Treat remote mode as suitable only for a trusted, isolated network segment.

Captured content is aircraft state and, on Prepar3D, weapons employment. The aircraft title, ATC identity and transponder code identify the simulated aircraft rather than the operator, but a session still associates a named user with a training exercise. Restrict access to captured sessions according to the deployment’s own data-handling policy.

16. Conformance

  1. Install the package matching the simulator on that workstation and confirm the native client is present in the variant’s simconnect directory. Confirm on startup that the log records SimConnect connected to with the expected application name and a SimConnect version.
  2. With the simulator loaded into a flight, confirm one entity appears, named with the aircraft title, and that its id is stable across a restart of HEAT Capture with the same aircraft.
  3. Confirm the aircraft type gate: with a fixed-wing aircraft, the three fixed-wing components are present and the rotary-wing component absent; with a helicopter, the reverse. With an aircraft whose category is none of the five recognised values, confirm neither set is published.
  4. Verify SIM-01 directly. Read the simulator’s altimeter setting and its indicated altitude, then confirm the published barometric altitude equals the altimeter setting in millibars and not the indicated altitude in metres. Retain that trace as the before state for any correction.
  5. Verify the scale defects in section 10 on a single frame: extend the gear fully and confirm gear extension publishes 1; deploy spoilers to a partial detent and confirm spoiler position publishes 0.
  6. Confirm the first-frame boolean behaviour: with a fixed-wing aircraft, capture the first frames after a connect and check whether autothrottle, afterburner and reverse thrust are published as engaged before the avionics and propulsion groups have arrived.
  7. Pause the simulation and confirm the session stops when StopOnSimPaused is set, then resume and confirm it starts again when StartOnSimRunning is set.
  8. Close the simulator while capturing. Confirm the sim-quit warning, then restart the simulator and confirm reconnection without restarting HEAT Capture, and that the reconnect log line appears.
  9. On the Prepar3D variant, arm the weapon system, fire from a station, dispense a countermeasure and change the fire-control target. Confirm one event per transition and confirm the countermeasure event carries an empty name.
  10. If remote mode is used, confirm SimConnect.cfg is written beside the module binaries with the expected host and port, and that its presence is acceptable under the deployment’s own handling rules for network configuration.

17. Revision history

RevDateProduct versionChange
12026-09-0269d794bInitial issue.
Opens your browser's print dialog. Choose "Save as PDF" as the destination.