Group – Python Plugins / Python
EMS[LINK]
The Energy Management System in EnergyPlus was a major
breakthrough in provided user-defined capabilities. By
allowing the user to read simulation data, perform custom
calculations, and ultimately manipulate control settings, the
door was opened to any number of new applications, including
evaluation of custom control strategies or custom physical
component models. However, users were limited to writing
scripts in the built-in, custom, EnergyPlus Runtime Language,
and debugging was possible, but difficult.
Users have pushed EMS in many ways well beyond a
traditional Energy “Management” System. At this point, a lot
of EMS scripts are what would be called “plugins” in most
software environments. As of version 9.3 of EnergyPlus, a new
way to write these plugins, in the Python programming language
was made available.
Note: This functionality relies on some aspects of the
EnergyPlus API for making calls into EnergyPlus when these
plugins are running. A majority of the API is described in
section [sec:api-usage], and it is
highly recommended that that section be read first, as this
section will only focus on the differences, and additions. One
point should be made perfectly clear. There are two
Python-related ways of interacting with EnergyPlus. We can
call these “modes”, with each clarified here:
- Library Mode
-
In library mode, an external script (C or Python) is
written which leverages the EnergyPlus API to register
callback functions and initiate a simulation from a function
call.
- Plugin Mode
-
In plugin mode, a (typically) small Python script is
written, then by specifying parameters in an input file, the
client runs EnergyPlus(.exe) in a traditional fashion, and
that EnergyPlus run will call out to the Python script as
needed.
The initial versions of the Plugin and API systems could
not work together, however as of EnergyPlus version 9.6, they
can now be combined! During plugin execution, EnergyPlus
creates a new Python instance internally to allow processing
the user-defined scripts. When EnergyPlus is run in an API
mode, it can actively call back to your client script, as well
as do all the normal things EnergyPlus does. One caveat is
that if you run multiple EnergyPlus runs in parallel threads
in the same process, and they all utilize Python Plugins as
well, you will notice a small slowdown based on how many you
run in parallel. This is due to having to access Python’s
global interpreter lock during the Python portion of the
simulation, and will be investigated to avoid this in a later
version, however it is a small effect unless the number of
runs grows substantially. Also, this problem is only realized
if you are running multiple EnergyPlus threads in the same API
process space.
The API section has information about how to access output
variable data, meters, internal variable data, simulation
parameters, and actuators, so these do not need additional
information here. However, plugin objects have additional ways
to interact with the simulation, and the plugins themselves
need description, which is here.
Python Plugin[LINK]
For EnergyPlus, a Python Plugin is a user-defined Python
class that overrides a premade EnergyPlusPlugin
base class. This base class creates overrideable functions
that, when overridden, determine when the user-defined code
will be called by EnergyPlus. The functions are structured in
this way to allow a single class to defined multiple plugins.
In this way, data can be shared between multiple calling
points on the same class instance by using regular Python
class members.
The EnergyPlusPlugin base class is defined in
a ‘plugin.py’ file inside the ‘pyenergyplus’ folder, which is
located in the root EnergyPlus install directory. When
EnergyPlus starts up, if any plugins are to be run, it starts
up a Python instance and adds the executable directory to the
current Python search path. In this way, a user plugin should
always
from pyenergyplus.plugin import EnergyPlusPlugin.
This will ensure that when EnergyPlus processes this Python
file, it always finds this imported base class. The user will
then create a derived class that inherits this base class, and
write custom functions.
A minimal plugin does not actually have to interact with
EnergyPlus. It is expected that essentially every plugin will
at least read data from sensors or meters, or write data using
actuators, but it is not necessary. Just like when calling
EnergyPlus as a library, when operating in plugin mode, this
data is accessed through the same API methods. To learn how to
interact with the simulation API, see the API usage
section: [sec:api-usage]. Consider
this minimal plugin:
from pyenergyplus.plugin import EnergyPlusPlugin
class DummyPlugin(EnergyPlusPlugin):
def on_end_of_zone_timestep_before_zone_reporting(self, state):
return 0
This skeleton captures the use of a plugin to do nothing,
but still shows some important features.
The base class plugin is properly imported.
A user-defined class is created which inherits the
EnergyPlusPlugin base class.
A method is overridden, which is named appropriately to
describe when EnergyPlus will be calling this function, in
this case, at the end of each zone time step but before
zone-level data is reported.
The custom method returns zero to indicate
success.
NOTE! The functional form of the plugin
methods changed due to an API change between versions 9.3 and
9.4. Any plugin files created using 9.3 will need to add a
second argument to the methods. This same argument will need
to be passed into any EnergyPlus API methods called during the
plugin. Much more information can be found in the API usage
section: [sec:api-usage].
Several notes can be taken from this list. The name of the
function matters, as it determines when the function will be
called. The full list of possible names are:
on_begin_new_environment
on_after_new_environment_warmup_is_complete
on_begin_zone_timestep_before_init_heat_balance
on_begin_zone_timestep_after_init_heat_balance
on_begin_timestep_before_predictor
on_after_predictor_before_hvac_managers
on_after_predictor_after_hvac_managers
on_inside_hvac_system_iteration_loop
on_end_of_zone_timestep_before_zone_reporting
on_end_of_zone_timestep_after_zone_reporting
on_end_of_system_timestep_before_hvac_reporting
on_end_of_system_timestep_after_hvac_reporting
on_end_of_zone_sizing
on_end_of_system_sizing
on_end_of_component_input_read_in
on_user_defined_component_model
on_unitary_system_sizing
The meaning of these names can be found in the
EMSApplicationGuide which comes with the EnergyPlus
install.
It is possible future versions of the program will expose
additional calling points. Note: a single class can override
multiple functions, so that the same class instance is called
at multiple points in a simulation.
Once this plugin is created, it can be placed in a number
of locations on the filesystem, as described in the PythonPlugin:SearchPaths
section 1.2. The
plugin instance, along with any other plugin related objects
are declared in the input file, and then EnergyPlus is
executed. More data is provided in each of the specific object
sections below.
PythonPlugin:SearchPaths[LINK]
Once EnergyPlus initiates a Python process, it will need to
know where to search for user-defined plugin script files A
Python search path is managed that contains a list of possible
folders where Python will search when encountering an import
statement. The folder containing the currently running
EnergyPlus process will be added no matter what, as this
directory contains the plugin and API code, but additional
folders can be specified to meet specific needs. These options
are described in the inputs of the object.
An identifier given to this object. The object is required
to be unique, so this field is only used for reporting
purposes.
Field:
Add Current Working Directory to Search Path[LINK]
Based on different workflows, EnergyPlus may be executed in
directories far away from where the actual binary is stored.
In these cases, it may be useful to put plugin files in the
current working directory, even if the simulation input file
is not located there. Turning this field to Yes will add the
current working directory to the list of search paths.
In a lot of cases, it is expected that the plugin will be
tied closely to a specific input file. In these cases, it may
be useful to keep plugin files right next to the input file,
regardless of the current working directory. Turning this
field to Yes will add the directory where the input file is
located to the list of search paths.
Field:
Add epin Environment Variable to Search Path[LINK]
Some interfaces to EnergyPlus set an environment variable
named "epin" to a path on the system where auxiliary files
will be placed for a simulation run. If this input field is
set to Yes, EnergyPlus will check to see if the "epin"
variable has been set, and if the path exists, the path will
be added to the list of search paths for Python Plugins. This
field is defaulted to Yes, so that input files should work
with tools like EPLaunch directly.
Field: Search Path N[LINK]
There are also some cases, where a user may keep a specific
library of plugin scripts that work with a variety of input
files. In this case, they may want to just point EnergyPlus to
a custom directory away from any specific input file or
working directory. Declaring a path in these fields will add
those paths to the list of search paths. Note: This does not
check the filesystem for path existence.
PythonPlugin:Instance[LINK]
This object captures a single plugin instance for
EnergyPlus. As previously described, a single plugin may be
called at multiple calling points if there are multiple
functions overridden. A single instance is analogous to a
single user-defined class that inherits the EnergyPlusPlugin
base class.
This field represents an identifier for this plugin within
EnergyPlus. In most cases, this field is just used for
reporting, but for user-defined-components, this name is used
as the name of the EMS program manager. Note that if this
instance is used for that application, the plugin must
override the on_user_defined_component_model
function.
Field: Run During Warmup
Days[LINK]
This field specifies whether EnergyPlus should execute this
plugin during warmup days. In most applications, this should
not be enabled, both for runtime savings, and because warmups
are just used to initialize the simulation state.
Field: Python Module
Name[LINK]
This is the name of the Python plugin file name – except –
no file extension. For pluginA.py, just use
pluginA. This file should be found in one of the
folders in the plugin search path, which the user can
customize using the PythonPlugin:SearchPaths
object.
Field: Plugin Class Name[LINK]
This is the name of the user-defined class inside the
plugin file. This class must inherit the EnergyPlusPlugin base
class, or the simulation will issue an error and abort.
Global and
Trend Variable API Methods[LINK]
Plugins have two areas of data storage/bookkeeping that are
not available on the regular EnergyPlus API: Global variables
and Trend variables
- Global Variables
-
Global variables, in this context, reflect variables which
are given space in EnergyPlus, and can be accessed in
read/write fashion by all running plugin instances at any
time. Global variables can then be further used as the basis
for creating custom output variables and trend variables.
Global variables are declared in the input file, then accessed
by name in the plugin script. An example usage is provided
below in the global variable section.
- Trend Variables
-
Trend variables are used to track the history of a
previously declared plugin global variable. By first declaring
a plugin global variable, and then assigning that value in
plugins, this trend mechanism will keep history. The actual
number of history terms is declared in the input file, and the
trend variables are accessed by name in the plugin script.
Example usage is provided below in the trend variable
section.
PythonPlugin:Variables[LINK]
This object defines the “global” variables described
elsewhere in this section. The term global is carried along as
it is the convention used in traditional EMS applications.
There are a few reasons why users may need to use global
variables:
If a variable value is to be read/write between
multiple plugins in different files.
If a client wants to create a custom output variable,
these are based on, and reference, existing global
variables.
If a client wants to create a trend variable, these are
based on, and reference, existing global variables.
To use a global variable, an input object must be defined
in the current input file, which specifies the variable name.
Then, in a plugin, a handle can be looked up for this global
variable using the get_global_handle function,
which accepts the current state and the variable name as
arguments. With the handle, the current value of the global
variable can be looked up using the
get_global_value function, which takes the
current state and the handle for the variable as arguments.
Finally, to update the value of the global variable, the
set_global_value function is used, which takes
the current state, the variable handle and a new value.
Assuming a global variable is defined on input called
“OutdoorTemperature”, an example of this inside a plugin
function follows:
global_var_handle = self.api.exchange.get_global_handle(state, 'OutdoorTemperature')
var_value = self.api.exchange.get_global_value(state, global_var_handle)
self.api.exchange.set_global_value(state, global_var_handle, 3.141)
The inputs required to declare a global variable consist of
the unique PythonPlugin:GlobalVariable object, along with a
series of names to identify each variable.
This field is the name of this variables object, however
since this is required to be a unique object, it does not do
much. It is purely used for reporting of errors.
Field Variable Name N[LINK]
This field is used to declare and identify a plugin
variable inside EnergyPlus. This name is used as the
identifier when accessing this value to read/write in
user-defined plugins.
PythonPlugin:TrendVariable[LINK]
Trend variables allow a predeclared global variable to be
tracked over time steps in the simulation. Once these are
declared, a number of useful worker functions can be employed
to process and read data from the trend. Note that trend
variables are initially declared with values of zero at each
history place, so the first few calls into the simulation
could result in unexpected values of the trend.
To use a trend variable, an input object must be defined
int he current input file, which specifies the attributes of
the trend, including a name and a number of history terms to
keep. Then, in a plugin, a handle can be looked up for this
trend variable using the get_trend_handle
function, which accepts the trend variable name as the only
argument. With the handle, a number of aspects can be
processed/looked up:
The trend value at a specific point in history can be
retrieved using the get_trend_value function,
which accepts the current state, a trend handle and an index
specifying how far back in history to evaluate the
lookup.
The average trend value over a specific range can be
retrieved using the get_trend_average function,
which accepts the current state, a trend handle and a count of
how far back in history to evaluate.
The minimum trend value over a specific range can be
retrieved using the get_trend_min function, which
accepts the current state, a trend handle and a count of how
far back in history to evaluate.
The maximum trend value over a specific range can be
retrieved using the get_trend_max function, which
accepts the current state, a trend handle and a count of how
far back in history to evaluate.
The sum of a trend value over a specific range can be
retrieved using the get_trend_sum function, which
accepts the current state, a trend handle and a count of how
far back in history to evaluate.
The trajectory of a trend (slope of a linear regression
line) over a specific range can be calculated using the
get_trend_direction function, which accepts the
current state, a trend handle and a count of how far back in
history to evaluate.
Assuming a global variable is defined on input called
“CustomTemperature”, and a trend variable is declared called
“TrendVar” with at least 5 history terms saved, an example
usage of this inside a plugin function follows:
# update the variable throughout the simulation
global_var_handle = self.api.exchange.get_global_handle(state, 'CustomTemperature')
self.api.exchange.set_global_value(state, global_var_handle, 3.141)
# get trend values as needed
trend_var_handle = self.api.exchange.get_trend_handle(state, 'TrendVar')
trend_avg = self.api.exchange.get_trend_average(state, trend_var_handle, 5)
trend_min = self.api.exchange.get_trend_min(state, trend_var_handle, 5)
trend_max = self.api.exchange.get_trend_max(state, trend_var_handle, 5)
trend_sum = self.api.exchange.get_trend_sum(state, trend_var_handle, 5)
trend_dir = self.api.exchange.get_trend_direction(state, trend_var_handle, 5)
This field is the name of the trend object, and is used
both for reporting purposes, as well as to identify this trend
inside of plugin code.
Field: Name of
a Python Plugin Variable[LINK]
This field should include the name of a plugin variable
that is declared in the PythonPlugin:Variables
object. A trend variable is simply a wrapper around an
existing variable object, which must be read/written by
plugins, so first declare the variable, then add a trend to it
as needed by referencing the name here.
Field: Number
of Timesteps to be Logged[LINK]
This field specified the number of history terms to keep
for this trend. Trend variables are stored for this number of
zone time steps. If a plugin attempts to access a trend
parameter at greater than this number, an error will
occur.
Packaging Details[LINK]
Implementing these plugins required structural additions to
the package and to the build process. From a user perspective,
the only thing that will be noticed likely is the additional
size of the installer. At the very onset of this project, it
was decided that we would package Python into the installer,
and not require a user to install an external version. This
has been successful, however, at the cost of a larger install
footprint. The EnergyPlus install now includes a Python binary
shared library, any dependent libraries, along with the core
Python standard library of code. This allows users to create
user-defined plugins that access all of the standard Python
library capabilities.
The main question received about this is about installing
non-standard Python packages. While we have not polished up
the instructions on the process, some advice can be given.
However, note that if you break your Python install, either
system or EnergyPlus version, in the process, you could end up
with a very, very, very broken system. So do not do this if
you do not understand the consequences and have a solid
understanding of Python package management. Also, once you
start down this process of using anything non-standard, the
development team will no longer be able to help you debug any
plugin problems.
Some possibilities for using external libraries
include:
If the external package you are wanting is pure Python
code, then you can download and extract it right into a local
directory, add it to the SearchPaths object, and the Python
process set up by EnergyPlus should be able to find
it.
For native code libraries, if you are able to install a
Python version on your system with an identical version to the
one that is packaged up with your install of EnergyPlus, you
may be able to leverage that separate module directory. Use
Pip or whatever package management tool you choose to install
the package. This will install it in that version. Then you
can try to point EnergyPlus to that directory, or copy those
files from one package into the EnergyPlus package.
It is hoped that future versions of this will include a
package management tool with EnergyPlus itself, so that
installing native packages is straightforward.
Group – Python Plugins / Python EMS[LINK]
The Energy Management System in EnergyPlus was a major breakthrough in provided user-defined capabilities. By allowing the user to read simulation data, perform custom calculations, and ultimately manipulate control settings, the door was opened to any number of new applications, including evaluation of custom control strategies or custom physical component models. However, users were limited to writing scripts in the built-in, custom, EnergyPlus Runtime Language, and debugging was possible, but difficult.
Users have pushed EMS in many ways well beyond a traditional Energy “Management” System. At this point, a lot of EMS scripts are what would be called “plugins” in most software environments. As of version 9.3 of EnergyPlus, a new way to write these plugins, in the Python programming language was made available.
Note: This functionality relies on some aspects of the EnergyPlus API for making calls into EnergyPlus when these plugins are running. A majority of the API is described in section [sec:api-usage], and it is highly recommended that that section be read first, as this section will only focus on the differences, and additions. One point should be made perfectly clear. There are two Python-related ways of interacting with EnergyPlus. We can call these “modes”, with each clarified here:
In library mode, an external script (C or Python) is written which leverages the EnergyPlus API to register callback functions and initiate a simulation from a function call.
In plugin mode, a (typically) small Python script is written, then by specifying parameters in an input file, the client runs EnergyPlus(.exe) in a traditional fashion, and that EnergyPlus run will call out to the Python script as needed.
The initial versions of the Plugin and API systems could not work together, however as of EnergyPlus version 9.6, they can now be combined! During plugin execution, EnergyPlus creates a new Python instance internally to allow processing the user-defined scripts. When EnergyPlus is run in an API mode, it can actively call back to your client script, as well as do all the normal things EnergyPlus does. One caveat is that if you run multiple EnergyPlus runs in parallel threads in the same process, and they all utilize Python Plugins as well, you will notice a small slowdown based on how many you run in parallel. This is due to having to access Python’s global interpreter lock during the Python portion of the simulation, and will be investigated to avoid this in a later version, however it is a small effect unless the number of runs grows substantially. Also, this problem is only realized if you are running multiple EnergyPlus threads in the same API process space.
The API section has information about how to access output variable data, meters, internal variable data, simulation parameters, and actuators, so these do not need additional information here. However, plugin objects have additional ways to interact with the simulation, and the plugins themselves need description, which is here.
Python Plugin[LINK]
For EnergyPlus, a Python Plugin is a user-defined Python class that overrides a premade
EnergyPlusPluginbase class. This base class creates overrideable functions that, when overridden, determine when the user-defined code will be called by EnergyPlus. The functions are structured in this way to allow a single class to defined multiple plugins. In this way, data can be shared between multiple calling points on the same class instance by using regular Python class members.The
EnergyPlusPluginbase class is defined in a ‘plugin.py’ file inside the ‘pyenergyplus’ folder, which is located in the root EnergyPlus install directory. When EnergyPlus starts up, if any plugins are to be run, it starts up a Python instance and adds the executable directory to the current Python search path. In this way, a user plugin should alwaysfrom pyenergyplus.plugin import EnergyPlusPlugin. This will ensure that when EnergyPlus processes this Python file, it always finds this imported base class. The user will then create a derived class that inherits this base class, and write custom functions.A minimal plugin does not actually have to interact with EnergyPlus. It is expected that essentially every plugin will at least read data from sensors or meters, or write data using actuators, but it is not necessary. Just like when calling EnergyPlus as a library, when operating in plugin mode, this data is accessed through the same API methods. To learn how to interact with the simulation API, see the API usage section: [sec:api-usage]. Consider this minimal plugin:
This skeleton captures the use of a plugin to do nothing, but still shows some important features.
The base class plugin is properly imported.
A user-defined class is created which inherits the EnergyPlusPlugin base class.
A method is overridden, which is named appropriately to describe when EnergyPlus will be calling this function, in this case, at the end of each zone time step but before zone-level data is reported.
The custom method returns zero to indicate success.
NOTE! The functional form of the plugin methods changed due to an API change between versions 9.3 and 9.4. Any plugin files created using 9.3 will need to add a second argument to the methods. This same argument will need to be passed into any EnergyPlus API methods called during the plugin. Much more information can be found in the API usage section: [sec:api-usage].
Several notes can be taken from this list. The name of the function matters, as it determines when the function will be called. The full list of possible names are:
on_begin_new_environmenton_after_new_environment_warmup_is_completeon_begin_zone_timestep_before_init_heat_balanceon_begin_zone_timestep_after_init_heat_balanceon_begin_timestep_before_predictoron_after_predictor_before_hvac_managerson_after_predictor_after_hvac_managerson_inside_hvac_system_iteration_loopon_end_of_zone_timestep_before_zone_reportingon_end_of_zone_timestep_after_zone_reportingon_end_of_system_timestep_before_hvac_reportingon_end_of_system_timestep_after_hvac_reportingon_end_of_zone_sizingon_end_of_system_sizingon_end_of_component_input_read_inon_user_defined_component_modelon_unitary_system_sizingThe meaning of these names can be found in the EMSApplicationGuide which comes with the EnergyPlus install.
It is possible future versions of the program will expose additional calling points. Note: a single class can override multiple functions, so that the same class instance is called at multiple points in a simulation.
Once this plugin is created, it can be placed in a number of locations on the filesystem, as described in the PythonPlugin:SearchPaths section 1.2. The plugin instance, along with any other plugin related objects are declared in the input file, and then EnergyPlus is executed. More data is provided in each of the specific object sections below.
PythonPlugin:SearchPaths[LINK]
Once EnergyPlus initiates a Python process, it will need to know where to search for user-defined plugin script files A Python search path is managed that contains a list of possible folders where Python will search when encountering an import statement. The folder containing the currently running EnergyPlus process will be added no matter what, as this directory contains the plugin and API code, but additional folders can be specified to meet specific needs. These options are described in the inputs of the object.
Inputs[LINK]
Field: Name[LINK]
An identifier given to this object. The object is required to be unique, so this field is only used for reporting purposes.
Field: Add Current Working Directory to Search Path[LINK]
Based on different workflows, EnergyPlus may be executed in directories far away from where the actual binary is stored. In these cases, it may be useful to put plugin files in the current working directory, even if the simulation input file is not located there. Turning this field to Yes will add the current working directory to the list of search paths.
Field: Add Input File Directory to Search Path[LINK]
In a lot of cases, it is expected that the plugin will be tied closely to a specific input file. In these cases, it may be useful to keep plugin files right next to the input file, regardless of the current working directory. Turning this field to Yes will add the directory where the input file is located to the list of search paths.
Field: Add epin Environment Variable to Search Path[LINK]
Some interfaces to EnergyPlus set an environment variable named "epin" to a path on the system where auxiliary files will be placed for a simulation run. If this input field is set to Yes, EnergyPlus will check to see if the "epin" variable has been set, and if the path exists, the path will be added to the list of search paths for Python Plugins. This field is defaulted to Yes, so that input files should work with tools like EPLaunch directly.
Field: Search Path N[LINK]
There are also some cases, where a user may keep a specific library of plugin scripts that work with a variety of input files. In this case, they may want to just point EnergyPlus to a custom directory away from any specific input file or working directory. Declaring a path in these fields will add those paths to the list of search paths. Note: This does not check the filesystem for path existence.
PythonPlugin:Instance[LINK]
This object captures a single plugin instance for EnergyPlus. As previously described, a single plugin may be called at multiple calling points if there are multiple functions overridden. A single instance is analogous to a single user-defined class that inherits the EnergyPlusPlugin base class.
Inputs[LINK]
Field: Name[LINK]
This field represents an identifier for this plugin within EnergyPlus. In most cases, this field is just used for reporting, but for user-defined-components, this name is used as the name of the EMS program manager. Note that if this instance is used for that application, the plugin must override the
on_user_defined_component_modelfunction.Field: Run During Warmup Days[LINK]
This field specifies whether EnergyPlus should execute this plugin during warmup days. In most applications, this should not be enabled, both for runtime savings, and because warmups are just used to initialize the simulation state.
Field: Python Module Name[LINK]
This is the name of the Python plugin file name – except – no file extension. For
pluginA.py, just usepluginA. This file should be found in one of the folders in the plugin search path, which the user can customize using the PythonPlugin:SearchPaths object.Field: Plugin Class Name[LINK]
This is the name of the user-defined class inside the plugin file. This class must inherit the EnergyPlusPlugin base class, or the simulation will issue an error and abort.
Global and Trend Variable API Methods[LINK]
Plugins have two areas of data storage/bookkeeping that are not available on the regular EnergyPlus API: Global variables and Trend variables
Global variables, in this context, reflect variables which are given space in EnergyPlus, and can be accessed in read/write fashion by all running plugin instances at any time. Global variables can then be further used as the basis for creating custom output variables and trend variables. Global variables are declared in the input file, then accessed by name in the plugin script. An example usage is provided below in the global variable section.
Trend variables are used to track the history of a previously declared plugin global variable. By first declaring a plugin global variable, and then assigning that value in plugins, this trend mechanism will keep history. The actual number of history terms is declared in the input file, and the trend variables are accessed by name in the plugin script. Example usage is provided below in the trend variable section.
PythonPlugin:Variables[LINK]
This object defines the “global” variables described elsewhere in this section. The term global is carried along as it is the convention used in traditional EMS applications. There are a few reasons why users may need to use global variables:
If a variable value is to be read/write between multiple plugins in different files.
If a client wants to create a custom output variable, these are based on, and reference, existing global variables.
If a client wants to create a trend variable, these are based on, and reference, existing global variables.
To use a global variable, an input object must be defined in the current input file, which specifies the variable name. Then, in a plugin, a handle can be looked up for this global variable using the
get_global_handlefunction, which accepts the current state and the variable name as arguments. With the handle, the current value of the global variable can be looked up using theget_global_valuefunction, which takes the current state and the handle for the variable as arguments. Finally, to update the value of the global variable, theset_global_valuefunction is used, which takes the current state, the variable handle and a new value.Assuming a global variable is defined on input called “OutdoorTemperature”, an example of this inside a plugin function follows:
Inputs[LINK]
The inputs required to declare a global variable consist of the unique PythonPlugin:GlobalVariable object, along with a series of names to identify each variable.
Field: Name[LINK]
This field is the name of this variables object, however since this is required to be a unique object, it does not do much. It is purely used for reporting of errors.
Field Variable Name N[LINK]
This field is used to declare and identify a plugin variable inside EnergyPlus. This name is used as the identifier when accessing this value to read/write in user-defined plugins.
PythonPlugin:TrendVariable[LINK]
Trend variables allow a predeclared global variable to be tracked over time steps in the simulation. Once these are declared, a number of useful worker functions can be employed to process and read data from the trend. Note that trend variables are initially declared with values of zero at each history place, so the first few calls into the simulation could result in unexpected values of the trend.
To use a trend variable, an input object must be defined int he current input file, which specifies the attributes of the trend, including a name and a number of history terms to keep. Then, in a plugin, a handle can be looked up for this trend variable using the
get_trend_handlefunction, which accepts the trend variable name as the only argument. With the handle, a number of aspects can be processed/looked up:The trend value at a specific point in history can be retrieved using the
get_trend_valuefunction, which accepts the current state, a trend handle and an index specifying how far back in history to evaluate the lookup.The average trend value over a specific range can be retrieved using the
get_trend_averagefunction, which accepts the current state, a trend handle and a count of how far back in history to evaluate.The minimum trend value over a specific range can be retrieved using the
get_trend_minfunction, which accepts the current state, a trend handle and a count of how far back in history to evaluate.The maximum trend value over a specific range can be retrieved using the
get_trend_maxfunction, which accepts the current state, a trend handle and a count of how far back in history to evaluate.The sum of a trend value over a specific range can be retrieved using the
get_trend_sumfunction, which accepts the current state, a trend handle and a count of how far back in history to evaluate.The trajectory of a trend (slope of a linear regression line) over a specific range can be calculated using the
get_trend_directionfunction, which accepts the current state, a trend handle and a count of how far back in history to evaluate.Assuming a global variable is defined on input called “CustomTemperature”, and a trend variable is declared called “TrendVar” with at least 5 history terms saved, an example usage of this inside a plugin function follows:
Inputs[LINK]
Field: Name[LINK]
This field is the name of the trend object, and is used both for reporting purposes, as well as to identify this trend inside of plugin code.
Field: Name of a Python Plugin Variable[LINK]
This field should include the name of a plugin variable that is declared in the PythonPlugin:Variables object. A trend variable is simply a wrapper around an existing variable object, which must be read/written by plugins, so first declare the variable, then add a trend to it as needed by referencing the name here.
Field: Number of Timesteps to be Logged[LINK]
This field specified the number of history terms to keep for this trend. Trend variables are stored for this number of zone time steps. If a plugin attempts to access a trend parameter at greater than this number, an error will occur.
Packaging Details[LINK]
Implementing these plugins required structural additions to the package and to the build process. From a user perspective, the only thing that will be noticed likely is the additional size of the installer. At the very onset of this project, it was decided that we would package Python into the installer, and not require a user to install an external version. This has been successful, however, at the cost of a larger install footprint. The EnergyPlus install now includes a Python binary shared library, any dependent libraries, along with the core Python standard library of code. This allows users to create user-defined plugins that access all of the standard Python library capabilities.
The main question received about this is about installing non-standard Python packages. While we have not polished up the instructions on the process, some advice can be given. However, note that if you break your Python install, either system or EnergyPlus version, in the process, you could end up with a very, very, very broken system. So do not do this if you do not understand the consequences and have a solid understanding of Python package management. Also, once you start down this process of using anything non-standard, the development team will no longer be able to help you debug any plugin problems.
Some possibilities for using external libraries include:
If the external package you are wanting is pure Python code, then you can download and extract it right into a local directory, add it to the SearchPaths object, and the Python process set up by EnergyPlus should be able to find it.
For native code libraries, if you are able to install a Python version on your system with an identical version to the one that is packaged up with your install of EnergyPlus, you may be able to leverage that separate module directory. Use Pip or whatever package management tool you choose to install the package. This will install it in that version. Then you can try to point EnergyPlus to that directory, or copy those files from one package into the EnergyPlus package.
It is hoped that future versions of this will include a package management tool with EnergyPlus itself, so that installing native packages is straightforward.
Documentation content copyright © 1996-2026 The Board of Trustees of the University of Illinois and the Regents of the University of California through the Ernest Orlando Lawrence Berkeley National Laboratory. All rights reserved. EnergyPlus is a trademark of the US Department of Energy.
This documentation is made available under the EnergyPlus Open Source License v1.0.