Easy Datarefs¶
To use:
from XPPython3.utils import datarefs
-or-
from XPPython3.utils.datarefs import find_dataref, create_dataref
To make creating and using datarefs easier, XPPython3 includes a module which mimics the way Xlua creates and define datarefs. While originally this was included to make it easier for Aircraft designers to transition from Xlua to python, there is no requirement to use other xlua-related code or restrict use to Aircraft plugins. (This module can be used with or without other python-xlua inspired modules).
There are two functions:
Both functions return a DataRef instance.
- class DataRef¶
Result of
find_dataref()andcreate_dataref(). You should not create an instance of this class yourself.Useful properties of DataRef are:
- property .value¶
Gets or sets the current datatype-specific value of the dataref. This may be a string, an int or float array, an int or float.
For gets, the data is obtained from X-Plane on access. Cache this value if you want to access it multiple times during the same frame.
For sets, the data is immediately updated in X-Plane.:
>>> ref = datarefs.create_dataref('xppython/test/number', 'number') >>> ref.value 0 >>> ref.value = 45.6 >>> ref.value 45.6
Note that for array datatypes, we update only those elements in the slice.:
>>> ref = datarefs.create_dataref('xppython/test/short_array', 'array[5]') >>> ref.value [0, 0, 0, 0, 0] >>> ref.value[2] = 45 >>> ref.value [0, 0, 45, 0, 0] >>> ref.value[2:5] = [1, 2, 3] >>> ref.value [0, 0, 1, 2, 3]
It is an error to not provide enough elements for the slice.:
>>> ref.value[2:5] = [1, 2] RuntimeError: Not enough elements(2) in value to set dataref slice (3)
If you provide too many elements, we’ll truncate the list and accept the result.:
>>> ref.value[2:5] = [4, 3, 2, 1] >>> ref.value [0, 0, 4, 3, 2]
Arrays call also be referenced (set or get) without the
.valueproperty, as long as you use an index or slice.:>>> ref[0:] [0, 0, 4, 3, 2] >>> ref[2:5] = [1, 2, 3] >>> ref.value [0, 0, 1, 2, 3]
Of course setting
refwithout an index or slice simply updates the python variable to become an array/list: Negating the dataref.:>>> ref = [1, 2, 3, 4] >>> ref.value AttributeError: 'list' object has no attribute 'value'
We treat
ref.valuewithout an index or slice similarly, but allow you to specify any number of elements, truncating if you provide too many:>>> ref.value [0, 0, 4, 3, 2] >>> ref.value = [45] >>> ref.value [45, 0, 4, 3, 2] >>> ref.value = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] >>> ref.value [10, 9, 8, 7, 6]
For
stringtypes, we treat slice a little differently, because.valueis a simple python string which does not permit item assignment:>>> ref.value Hello World >>> ref.value[6:] World >>> ref.value[6:] = "Universe" TypeError: 'str' object does not support item assignment >>> ref.value = "Hello Universe" >>> ref.value Hello Universe
Unlike array types, if you provide fewer elements to
.valuethan the dataref size for strings we’ll zero-fill:>>> ref.value = "Hello" >>> ref.value Hello
Note that
stringdatarefs can also be used without.value, if you provide an index or slice:>>> ref[0] H >>> ref[0] = 'h' >>> ref.value hello
In this manner, we will zero-fill only to the width provided by in the slice. This also allows you set string values within a longer dataref such as
sim/cockpit2/tcas/targets/icao_type.:>>> ref = datarefs.find_dataref('sim/cockpit2/tcas/targets/icao_type') >>> ref.value 'C172' >>> ref[0:8] 'C172' >>> ref[8:16] '' >>> ref[8:16] = 'BE35' >>> ref[8:16] 'BE35'
The above example will zero-fill the 8-element slice, and apply the 4-character string only to the first four elements starting at index 8. As before, if you provide more values than are required for the slice, we’ll truncate without error. If you provide too few, we’ll zero-fill.
- property .bytes¶
For non-string datarefs, this is the same as the
valueproperty, which may be an int, float, array of ints or floats. Forstringdatarefs, this returns an array of (python) bytes. For example:>>> ref = datarefs.create_dataref('xppython3/test/string', 'string') >>> ref.value = "Hello World" >>> ref.value Hello World >>> ref.bytes [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 0, 0, 0, ..., 0]
This property is not commonly used.
- property .name¶
The string name of the dataref:
>>> ref.datarefs.create_datarefs('xppython3/test/string', 'string') >>> ref.name 'xppython3/test/string'
- property .types¶
The X-Plane data type, a list containing one or more of the strings ‘int’, ‘float’, ‘double’, ‘float_array’, ‘int_array’, ‘data’. Note that
stringtypes are implemented using X-Planedatadatarefs.
- property .dref¶
Reference to the internal X-Plane XPLMDataRef. This would be the result of
xp.findDataRef()and can be used withxp.getDatai()and related data access functions.
Note
For array types, you can drop ‘.value’ for accessing indexed data: e.g.,
inverter_on[0]is similar toinverter_on.value[0]:inverter_on[0]queries X-Plane for the single valued iteminverter_on.value[0]retrieves from X-Plane the list of values, and then python returns the[0]list element.
Functions¶
- find_dataref(name: str)¶
- Parameters
name (str) – Name of existing dataref to find
- Returns
Use
find_datarefto retrieve and store the accessor which provides the interface to a dataref (either one you created, or an existing dataref):>>> num_batteries = find_dataref("sim/aircraft/electrical/num_batteries") >>> inverter_on = find_dataref("sim/cockpit2/electrical/inverter_on") >>> fuel_pump_on_zero = find_dataref("sim/cockpit/engine/fuel_pump_on[0]") >>> print(fuel_pump_on_zero) DataRef: 'sim/cockpit/engine/fuel_pump_on[0] [int_array]'
There’s no need to determine the datatype as we’ll figure it out. The result of
find_dataref()is a handle, that is, the data has not been retrieved yet.If the dataref is not found, a ValueError exception is raised.
To get the current value, simple access the
.valueattribute (seeDataRefabove for details).>>> if num_batteries.value > 1: ... do_something() ...
If the dataref is an array type, you’ll (probably) want to index it:
>>> if inverter_on.value[0] and inverter_on.value[1]: ... do_something() ... elif inverter_on.value[0]: ... do_something_else() ...
You can find a specific array index, and use it as a single-value dataref:
>>> fuel_pump_on_zero = find_dataref("sim/cockpit/engine/fuel_pump_on[0]") >>> fuel_pump_on_zero.value 1 >>> fuel_pump_on_zero.value = 0
Note, however, if you created the dataref as read-only, you can change its value only if you access it through the non-specific index dataref (e.g.,
ref1below).:>>> ref1 = create_dataref('xppython3/test/array', 'array[16]', callback=False) >>> ref2 = find_dataref('xppython3/test/array[4]') >>> ref1[4] = 47 >>> ref2.value 47 >>> ref2.value = 48 >>> ref1[4] == 47 True
Attempting to set it through the specific-index version (
ref2) will be silently ignored.
- create_dataref(name: str, dataRefType: str = 'number' | 'array' | 'string', callback: None | False | Callable = None)¶
- Parameters
name (str) – Name of dataref to be created
dataRefType (str) – See table for possible values
callback (Callable) –
Noneor function to be called whenever dataref is written to,Falseto make readonly
- Returns
The
dataRefTypeis a string which defaults to “number” if not provided.:'number'creates int/float/double type
'array[x]'creates int_array/float_array of dimension x (x must be a number)
'string':creates data
For
callback:If a function, that function will be called, with no parameters, after the dataref is written to.
If
None(the default), dataref is writable, but no callback: data is simply stored and retrieved.If
False, dataref is read-only to all plugins except the plugin which created it.
For example, to create a numeric dataref which will store a numeric value:
>>> dr_engaged = create_dataref('test/gadget/engaged') >>> print(dr_engaged.value) 0 >>> dr_engaged.value = 42 >>> print(dr_engaged.value) 42
For numeric datarefs, We’ve actually created a dataref within X-Plane which supports integers and floats, so other plugins can use either to access the current value. To the creating plugin (i.e., your plugin) we’ll return an int if you set and int, a float if you set a float. If you set a non-integer float and another plugin accesses it using
xp.getDatai(), we’ll return an integer representation of your float.To create an array of 6 (numeric) elements, provide the dimension:
>>> dr_tank_capacity = create_dataref('test/fuel_tank/capacity', 'array[6]') >>> print(dr_tank_capacity.value) [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] >>> print(dr_tank_capacity[3] = 42 >>> print(dr_tank_capacity.value) [0.0, 0.0, 0.0, 42.0, 0.0, 0.0] >>> print(dr_tank_capacity[3].value) 42 >>> print(dr_tank_capacity.value[3]) 42
Strings are easy, and we automatically create a string of maximum 512 characters:
>>> dr_n_number = create_dataref('test/n_number', 'string') >>> print(dr_n_number.value) '' >>> dr_n_number.value = 'N20113' >>> print(dr_n_number.value) 'N20113'
As with other callbacks within XPPython3, if your dataref callback is a method of PythonInterface, it should also have
selfparameter, which will be available within you callback. For example:class PythonInterface(EasyPython): def __init__(self): super().__init__() self.name = "foobar" def dataref_callback(self): print("someone the dataref created in {self.name}") def onStart(self): datarefs.create_dataref("test/fuel_tank/capacity', 'array[6]', self.dataref_callback)
You will not get any indication within the callback as to what was changed. You could determine this information by storing previous value within the class (e.g.,
self.capacity_previous) and then making the comparison within the callback, as you’ll have access to self.
