Skip to main content

Automated Control Testbed for Integration Verification and Emulation

Project description

ACTIVE

The Automated Control Testbed for Integration, Verification, and Emulation (ACTIVE) is operation management and algorithm testing software designed for building control.

Installation

To install ACTIVE:

pip install Active --index-url https://code.ornl.gov/api/v4/projects/15464/packages/pypi/simple

To install on a machine with no internet connectivity:

pip download Active -d /path/to/my_folder --index-url https://code.ornl.gov/api/v4/projects/15464/packages/pypi/simple
(Move my_folder to the machine)
pip install /path/to/my_folder

Usage

From the command line:

active start config.json

See example.json for an example of a config file.

Environment File Definition

An Environment configuration file is a .json format. It specifies all Components for the Environment as well as options such as source code directories. It follows this format:

{
	"GUI": false,
	"extension directories": [
		...
	],
	"controllers": [
		...
	],
	"data stores": [
		...
	],
	"multiplexers": [
		...
	],
	"emulators": [
		...
	],
	"agents": [
		...
	],
	"tests": [
		...
	]
}

All fields are optional. The specifications for each field are as follows:

{
	"GUI": false
}

The GUI field sets whether or not to stand up the ACTIVE Workbench web-based GUI. If omitted from the file, default is "false".

{
	"extension directories": [
		"/path/to/my/extension"
	]
}

The extension directories block contains a list of strings which are paths to directories containing user code. All code in an extension directory and all sub-directories will be imported, so any side effects from importing will apply to the current ACTIVE instance during start up. See Extensions for a more detailed description of how to create an Extension.

"controllers": [
	{
		"name": "MyControllerName",
		"type": "MyControllerType",
		"parameters": {
			...
		}
	}
],

The controllers block contains a list of definitions for Controller Components. Each Controller contains a unique name. A controller also has a type and parameters. The contents of parameters are determined by the controller's type, while the type must be match either one of the default Controller types (see Controllers for a list) or a custom user defined Controller marked with the @ActiveController("MyControllerType") decorator in one of the directories from the extension directories block above.

"data stores": [
	{
		"name": "MyDataStoreName",
		"type": "MyDataStoreType",
		"parameters": {
			...
		}
	}
],

The data stores block contains a list of definitions for Data Store Components. Each Data Store contains a unique name. A data store also has a type and parameters. The contents of parameters are determined by the data store's type, while the type must be match either one of the default DataStore types (see Data Stores for a list) or a custom user defined DataStore marked with the @ActiveDataStore("MyDataStoreType") decorator in one of the directories from the extension directories block above.

"emulators": [
	{
		"name": "MyEmulatorName",
		"type": "MyEmulatorType",
		"parameters": {
			...
		}
	}
],

The emulators block contains a list of definitions for Emulator Components. Unlike Controller or Data Store Components above, an Emulator will be started by ACTIVE when the Environment is started. Each Emulator contains a unique name. An emulator also has a type and parameters. The contents of parameters are determined by the emulator's type, while the type must be match either one of the default Emulator types (see Emulator for a list) or a custom user defined Emulator marked with the @ActiveEmulator("MyEmulatorType") decorator in one of the directories from the extension directories block above.

"agents": [
	{
		"name": "MyAgentName",
		"type": "MyAgentType",
		"parameters":{
			...
		},
		"strategy": {
			"type": "MyStrategyType",
			"parameters":{
				...
			}
		}
	}
]

The agents block contains a list of definitions for Agent Components. Unlike Controller or Data Store Components above, an Agent will be started by ACTIVE when the Environment is started. Each Agent contains a unique name. An agent also has a type and parameters. The contents of parameters are determined by the agent's type, while the type must be match either one of the default Agent types (see Agent for a list) or a custom user defined Agent marked with the @ActiveAgent("MyAgentType") decorator in one of the directories from the extension directories block above.

Each Agent also contains another Component, a Strategy, defined under the strategy field. A Strategy contains type and parameters fields just like an Agent, though its type must be defined in an extension class with the @ActiveStrategy("MyStrategyType decorator. ACTIVE currently does not supply any default Strategies.

Not all fields need to be, or can be, set with raw JSON primitives. ACTIVE allows the use of special ACTIVE directives within the environment configuration file for ease of use or for references ACTIVE components. There are two ACTIVE directives:

  • The ACTIVE Component directive: This directive is of the format !ACTIVE:MyComponentName. It provides one of the Controllers, Data Stores, or Emulators as an argument to the constructor of the Component that uses it.
  • The file directive: This directive is of the format !ACTIVE:!FILE-type:/path/to/my/file. It loads a file of format type into the configuration file as a dictionary in place of the reference string. The only type of file currently supported is JSON.

For example, consider the following Environment configuration file:

{
	"extension directories": [
		"/path/to/my/extension"
	]
},
"controllers": [
	{
		"name": "MyControllerName",
		"type": "MyControllerType",
		"parameters": {
		}
	}
],
"agents": [
	{
		"name": "MyAgentName",
		"type": "MyAgentType",
		"parameters":{
		},
		"strategy": {
			"type": "MyStrategyType",
			"parameters":{
				"building_api": "!ACTIVE:MyControllerName",
				"zone_definitions": "!ACTIVE:!FILE-json:/home/data/test_building_2.json"
			}
		}
	}
]

When the MyStrategyType class's __init__(building_api, zone_definitions) constructor is called, building_api will contain a MyControllerType object while zone_definitions will contain a dictionary with the contents of test_building_2.json inside.

Extensions

ACTIVE is designed to run user code without requiring users to modify ACTIVE's source. This is achieved through the creation of Extension package. An extension is any Python package with an ACTIVE decorator used to define one or more Components.

Consider the case of wanting to add your own Strategy to run. You would create a .py file with content like:

from mypackage.genetic_algorithm_strategy_base import GeneticAlgorithmStrategyBase

from active.strategy.decoratorys import ActiveStrategy

@ActiveStrategy("GA")
class GeneticAlgorithmStrategy(GeneticAlgorithmStrategyBase)

Line 1 imports a user written base class named GeneticAlgorithmStrategyBase. This is not strictly neccesary. However, due to the dynamic way in which ACTIVE imports Component classes, static class members will not be available in any Component. This will cause issues with State management in c bindings, such as are used in EnergyPlus via the EnergyPlusController. It is therefore recommended that all custom Components follow this pattern and leave all business logic and data in a superclass as done in this example.

Line 2 imports the decorator.

Line 3 annotates the user's class as an ACTIVE Component. While this Extension is loaded, a Strategy in the Environment configuration file may be given the user defined name ("GA" in this example) as its type and ACTIVE will use this class for it. Extension names override previous names in the order they are specified in the extension directories block. This may be used to override default ACTIVE Components. (eg Giving your own class the annotation @ActiveController("EnergyPlus") will cause all ACTIVE's EnergyPlus Controllers to use your local class instead of the default one.)

Line 4 defines the class which will become the ACTIVE component (and the superclass it uses as discussed previously)

For an example extension, see examples/mypackage:

mystrategy.py is an example of injecting custom extension code into ACTIVE.

logger_controller.py is an example of overridding a default component.

Architecture

ACTIVE conceives of each building operation scenario as a set of Components which manage one independent part of the control logic or communications apiece.

Components

A Component is a logical unit for the operation of building control. Components are intended, to the greatest degree logically possible, to be transparently swappable with other components of the same kind. Two different Data Stores should accept the same inputs when saving a piece of data. This is not always possible. A ThermostatController and a WaterHeaterController should not both have a get_water_temperature() method, but an EcobeeThermostatController and a BACNetThermostatController should both support a get_current_set_point() method or at least throw a NotImplementedError so that the user can appropriately handle a given piece of hardware's inability to perform a certain capability.

Agents

An Agent is a backend that runs a Strategy. An Agent is responsible for determining how often and when certain parts of a Strategy are to be run. An Agent may also be required to initialize or interface with some other platform, such as VOLTTRON, in order to run a Strategy within that context.

Agents contain a start() function. This function is responsible for all business logic and is the only part of the Agent that will be invoked by ACTIVE.

All Agents have an additional optional parameter: "main thread". If "main thread" is present and true, the agent will be run to completion on the main ACTIVE thread, in the order it was defined in the environment file, before ACTIVE proceeds to launching any other Agents.

The SimpleAgent runs a Strategy for a given number of episodes, then creates the output files.

Parameter Definition
delay Integer defining the delay, in units of seconds, between each episode is run. Delay is relative to the time the first episode was run, such that if the run time is greater than the delay, the next episode will run immediately
num_episodes Integer defining the number of episodes for which the Strategy is to be run

Sample configuration:

{
	"name": "MachineLearning",
	"type": "simple",
	"parameters":{
		"delay": 0,
		"num_episodes": 1
	},
	"strategy": {
		...
	}
}

The EnergyPlusAPIAgent runs code inside an EnergyPlus simulation. It runs for a given number of episodes. During each episode, the Agent will direct the Strategy to perform any necessary calculations, then launch the EnergyPlus simulation for one episode, then have the Strategy output any files.

Parameter Definition
begin_system_timestep_before_predictor_handler String name for a Callable from the Strategy to register for EnergyPlus as the begin_system_timestep_before_predictor callback
emulator An EnergyPlusAPI type ACTIVE Emulator which will run the simulation
episodes Integer defining the number of episodes for which the Strategy is to be run
inside_system_iteration_loop_handler String name for a Callable from the Strategy to register fo EnergyPlus as the inside_system_iteration_loop callback

Sample configuration:

{
	"name": "MachineLearning",
	"type": "EnergyPlus API",
	"parameters":{
		"begin_system_timestep_before_predictor_handler": "run_rtus",
		"emulator": "!ACTIVE:EnergyPlus",
		"episodes": 2,
		"inside_system_iteration_loop_handler": "run_vavs"
	},
	"strategy": {
		...
	}
}

The IntersectClientAgent runs code inside an INTERSECT client. Functions from the Strategy will be invoked in response to defined events or messages. This Agent will never halt running on its own. Also, if it never receives any of the expected events or messages, it will never invoke any code.

Parameter Definition
intersect_client An IntersectController for the INTERSECT instance to be listened to.
service_mappings A dictionary of four levels. The first level consists of unique INTERSECT service hierarchy definitions, in the format "organization.facility.type.subtype.capability". The second level is "events" and "messages" for that service. The third level are event types or operation sources, with the latter being of the form "capability.function". The last level are the values, strings that correspond this Agent's Strategy's functions. When an event or operation reply from INTERSECT is received

Sample configuration:

{
	"name": "MachineLearning",
	"type": "INTERSECT client",
	"parameters":{
		"intersect_client": "!ACTIVE:INTERSECT",
		"service_mappings": {
		    "oak-ridge-national-laboratory.none.bessd-pilot.soilcosm.digital-twin": {
				"events": {},
				"messages": {
					"SoilCosmDigitalTwin.perform_spinup": "save_model",
					"SoilCosmDigitalTwin.plot": "save_plot",
					"SoilCosmDigitalTwin.update_model": "update_model"
				}
		    },
		    "oak-ridge-national-laboratory.walker-branch.field.none.measurement": {
				"events": {
				    "observation made": "handle_new_observation"
				},
			"messages": {}
		    }
		}
	},
	"strategy": {
	...
	}
}

The VolttronAgent will install the ACTIVEBootstrapAgent (a VOLTTRON Agent, not an ACTIVE Agent) into the instance of VOLTTRON found at the VOLTTRON_HOME environmental variable's location if it does not already exist. It will then run that agent, which will open an instance of ACTIVE inside of Volttron. That instance of ACTIVE will then schedule the Strategy to run.

Parameter Definition
schedule Dictionary of strings to integers. Keys are function names from Strategy. Values are the number of seconds between one invocation of that function and the next

Sample configuration:

{
	"name": "MachineLearning",
	"type": "volttron",
	"parameters":{
		"schedule": {
			"record": 5,
			"step": 300
		}
	},
	"strategy": {
		...
	}
}

Controllers

A Controller manages all communications with some external program or device for the Strategy. Common Controller operations involve tasks such as retrieving data from a simulation or API or sending control signals to a device. There is no base Controller interface, as separate types of Controller (eg thermostat controllers vs data logger controllers) may have no overlap in functionality.

Clock Controllers

Clock Controllers handle communication with some time source.

The EnergyPlusAPI Clock Controller gets the current time from within a simulation run with EnergyPlus. It requires a local installation of EnergyPlus to function.

Parameter Definition
emulator An EnergyPlusAPI Emulator in which the simulation will be run.

Sample configuration:

{
	"name": "SimulationClock",
	"type": "EnergyPlusAPI Clock",
	"parameters": {
		"emulator": "!ACTIVE:MyEnergyPlustAPIEmulator"
	}
}

The System Clock Controller gets the time from the operating system. It has no parameters.

Sample configuration:

{
	"name": "WallClock",
	"type": "System Clock",
	"parameters": {
	}
}

RTU Controllers

RTU Controller handle communications with a Roof Top Unit (RTU) and its associated Variable Air Volume (VAV) units.

The EnergyPlus API RTU Controller communicates with a virtual RTU inside an EnergyPlus simulation.

Parameter Definition
emulator An EnergyPlusAPI Emulator in which the simulation containing this RTU will be run.
name String unique name for this RTU

Sample configuration:

{
	"name": "RTU 1",
	"type": "EnergyPlus API RTU",
	"parameters": {
		"emulator": "!ACTIVE:MyEnergyPlusAPIEmulator",
		"name": "RTU1"
	}
}

The BACNet RTU Controller communicates with an RTU over the BACNet protocol.

Parameter Definition
address String representation of the device address. In the format of IP and port or the network:device "xx:yy" Bacnet address.
ip String defining own IP and network mask. In the format "xxx.xxx.xxx.xxx/xx"
port Integer port number for connection
vav_addresses Dictionary from String VAV names to dictionaries of parameter names to String BACNet object addresses for that parameter.

Sample configuration:

{
	"name": "RTU1",
	"type": "BACNet RTU",
	"parameters": {
		"address": "127.17.0.101:47801"
		"ip": "127.17.0.100/24", 
		"port": 80,
		"vav_addresses": {
			"102": {
				"supply_airflow_rate": "3000011"
			},
			"103": {
				"supply_airflow_rate": "3000012"
			}
		}
	}
}

The CR1000X RTU Controller communicates with an RTU whose data is being published by a CR1000X data logger.

Parameter Definition
url String base url where the data logger is publishing its data
vav_names List of Strings for each VAV name

Sample configuration:

{
	"name": "RTU1",
	"type": "CR1000X RTU",
	"parameters": {
		"url": "127.17.0.102"
		"vav_names": [
			"102",
			"103"
		]
	}
}

Water Heater Controllers

Water Heater Controllers communicate with a water heater.

There are no default implementations of the interface.

Other Controllers

The BACNetController communicates with a device using the BACNet protocol.

Parameter Definition
ip String defining own IP and network mask. In the format "xxx.xxx.xxx.xxx/xx"
port Integer port number for connection

Sample configuration:

{
	"name": "BACNet1",
	"type": "BACNet",
	"parameters": {
		"ip": "127.17.0.100/24", 
		"port": 80
	}
}

The CR3000 Controller communicates with a CR3000 data logger.

Parameter Definition
tables List of Strings for the table names to download. Data from tables earlier in the list takes precedence over data from tables later in the list.
url String url for the server to scrape data from

Sample configuration:

{
	"name": "DataLogger1",
	"type": "CR3000",
	"parameters": {
        "tables": ["my_table5sec", "my_table10min"],
        "url": "127.0.0.1:82"
    }
}

The Delta Solar Inverter Controller communicates with a Delta solar inverter.

Parameter Definition
tables List of Strings for the table names to download. Data from tables earlier in the list takes precedence over data from tables later in the list.
url String url for the server to scrape data from

Sample configuration:

{
	"name": "Inverter1",
	"type": "Delta Solar Inverter",
	"parameters": {
        "password": "password1", 
        "sn": "O1T0000000000", 
        "url": "https://delta-solar.vidagrid.com/api", 
        "username": "myname@company.com"
    }
}

The EnergyPlus Controller sets up and controls EnergyPlus simulations. The EnergyPlusController requires a local installation of EnergyPlus to function.

Parameter Definition
console_out Boolean value determining whether to print the EnergyPlus output to std out

Sample configuration:

{
	"name": "EnergyPlus1",
	"type": "EnergyPlus",
	"parameters": {
		"console_out": false
	}
}

The HTTPController makes HTTP requests to an API. See also the HTTPEmulator for testing locally.

Parameter Definition
url String for the base url all other calls will be subpaths for

Sample configuration:

{
	"name": "API1",
	"type": "HTTP",
	"parameters": {
		"url": "http:/127.0.0.1:80"
	}
}

The INTERSECT Controller communicates with an INTERSECT protocol message bus. It can respond to events or messages or send messages. The ability to respond to messages is only available when provided to an IntersectAgent, with messages to listen to set in the IngersectAgent's "service_mappings".

Parameter Definition
intersect_configuration Dictionary of INTERSECT authentication credentials, as found in an INTERSECT configuration file. See INTERSECT documentation for full details.

Sample configuration:

{
	"name": "INTERSECT",
	"type": "INTERSECT",
	"parameters": {
		"intersect_configuration": {
		    "data_stores": {
		    },
		    "brokers": [
		        {
		            "host": "100.101.102.103",
		            "username": "intersect_username",
		            "password": "intersect_password",
		            "port": 1883,
		            "protocol": "mqtt3.1.1"
		        }
		    ]
		}
	}
}

Data Stores

A Data Store manages all external communication with some method of storing data for the Strategy. Common operations for a Data Store include saving or retrieving data. Data Stores have the functions:

copy(id, input): Copy the object input into the data store, under bucket id. copy_file(id, input): Read the file input and copy its contents into the data store, under bucket id. get_ids(): Get all the top level buckets inside the data store. get_names(id): Get the names of all individual data sets inside bucket id. get_visualization_type(): Get the default visualization type for this data store. Will be one of: DATAFRAME: load() can be counted on to return data in a format which can be converted into a dataframe. Visualization will be a graph with the x axis being a timestamp column and all numerical columns plottable on the y axis. FILES: load() will return the contents of an arbitrary file, which might be csv, an image, text, etc. NONE: This data store does not fit any of the other defined categories. load(id, name, num_items): Load the data inside bucket id. If num_items is specified, retrieve at most that many data sets. If name is specified, only retrieve the one data set of the name. The returned format will be described by get_visualization_type(). load_to_file(id, name, path): Copy the data located under bucket id with name name from the data store to a file located at path. save(id, input): Copy the file input into the data store, under bucket id, then delete the file.

The File System Data Store saves and retrieves data to a local file system. The data id is the folder name, while the data name is the file name within that directory.

Parameter Definition
path String path where data will be saved

Sample configuration:

{
	"name": "LocalStorage",
	"type": "File System",
	"parameters": {
		"path": "/var/simdata/energyplus/data"
	}
}

The PostgreSQL Data Store saves and retrieves data to a PostgreSQL database. id is the table name, while name is a row's key.

Parameter Definition
path String path where data will be saved

Sample configuration:

{
	"name": "Database",
	"type": "Postgres",
	"parameters": {
        "database": "mydb",
        "host": "localhost",
        "password": "password1",
        "port": "5432",
        "schema": {
            "table1": {
                "column1": "integer",
                "column2": "decimal"
            }
        },
        "user": "username"
	}
}

The PostgreSQL Data Store saves and retrieves data to a PostgreSQL database. id is the table name, while name is a row's key.

Parameter Definition
database String PostgreSQL internal database name
host String hostname for the server where the database is available
password String password for the database
port String port that the database is available on
schema String Dictionary from table names to dictionaries from column names to PostgreSQL
user String username for the database

Sample configuration:

{
	"name": "Database",
	"type": "Postgres",
	"parameters": {
        "database": "mydb",
        "host": "localhost",
        "password": "password1",
        "port": "5432",
        "schema": {
            "table1": {
                "column1": "integer",
                "column2": "decimal"
            }
        },
        "user": "username"
	}
}

Emulators

An Emulator serves as a local instance of some type of external system, one which would be communicated with via a Controller or Data Store. They are used in scenarios when access to a real system is not available and in testing behavior without using real hardware.

Emulators have start() and stop() functions that are called by ACTIVE to manage their states.

The BACnet Emulator is a virtual BACnet device.

Parameter Definition
address String IP address with network mask defining where the device will be accessible from
port Integer port number to listen on for the device
deviceID Integer unique BACnet protocol ID for the device
device_objects List of BACnet object definitions (see below)

BACnet object definitions:

Parameter Definition
instance Integer for the BACnet object instance number
type String defining the BACnet object type. Supported types are: "analog_input", "analog_output", "analog_value", "binary_input", "binary_output", "binary_value", "character_string", "date_value", "datetime_value", "humidity_input", "humidity_value", "make_state_text", "multistate_input", "multistate_output", "multistate_value", "temperature_input", "temperature_value"
value Value that the object will return when queried.

Sample configuration:

{
	"name": "Device1",
	"type": "BACnet",
	"parameters": {
		"address": "127.17.0.101/24",
		"port": 47808,
		"device_objects": [
			{
				"type": "analog_output",
				"instance": 3000023,
				"value": 89.9
			},
			{
				"type": "analog_input",
				"instance": 3000075,
				"value": 12.3
			},
			{
				"type": "analog_value",
				"instance": 3000079,
				"value": 34.5
			}		
		]
	}
},

The EnergyPlus API Emulator manages an EnergyPlus simulation of a building which it communicates with via the EnergyPlusAPI package.

Parameter Definition
console_output Boolean for whether or not to print EnergyPlus logs to console.
energyplus_location String path to the EnergyPlus install location, the directory where ConvertInputFormat is
floor_config Dictionary from string RTU names to lists of string zone names for zones associated with that RTU. Keys must correspond to entries in rtu_list. Values must appear in zone_list.
idf_file String path to the .idf file to use during the simulation.
num_threads Integer number of threads to use in the simulation
output_dir String path for where EnergyPlus will save its output files
rtu_list List of string names for RTUS in the simulation
variable_schema Dictionary with form described below
weather_file String path to the .epw file for the weather to use in the simulation
zone_list List of string zone names in the simulation

variable_schema is a dictionary of variables from the simulation of the following form:

"F_sched": { 
    "type": "output",
    "name": "Schedule Value",
    "scope": "RTU",
    "key_path": ["RTU", "fan_operation_schedule_name", "fan_schedule_name"],
},

Where "type" is either "output", "internal", or "actuator" and "scope" is either "Environment", "RTU", or "zone". "key_path" is omitted in the case that "scope" is "Environment".

Sample configuration:

{
	"name": "EnergyPlus Simulation",
	"type": "EnergyPlus API",
	"parameters": {
		"console_output": true,
		"energyplus_location": "/usr/local/EnergyPlus-23-1-0/",
		"floor_config": {"RTU1": ["Room 101", "Room 102"]},
		"idf_file": "model.idf",
		"num_threads": 8,
		"output_dir": "active_energyplus_out",
		"rtu_list": ["RTU1"],
		"variable_schema": "!ACTIVE:!FILE-json:EnergyPlusSchema.json",
		"weather_file": "Knoxville_TMY3.epw",
		"zone_list": ["Room 101", "Room 102"]
	}
}

The HTTP Emulator works as a local server to handle HTTP requests. It is intended for use with the HTTP Controller.

Parameter Definition
data Dictionary of paths and responses for the server. See emulator/http_emulator_base.py for a full description
port Integer port for the server to listen on

Sample configuration:

{
	"name": "DataLogger1",
	"type": "HTTP",
	"parameters": {
		"port": 8008,
		"data": {
	        "/path" : [
	            {
	                "content-type": "application/json",
	                "data": {
	                    "my_value": "Content for /path?param1=foo",
	                    "value": "Content for /path?param1=foo"
	                },
	                "query parameters": {
	                    "param1": "foo"
	                }
	            },
	            {
	                "content-type": "application/json",
	                "data": {
	                    "value": "Default content for /path when param1 is not defined or =/= foo"
	                }
	            }
	        ]
	    }            
	}
}

Strategies

A Strategy is a piece of control logic set to be run by an Agent and using Controller and/or Data Stores. For example, a Strategy for controlling a building might be run on an Agent, use Controllers for various devices in the building to obtain information about the building state, perform a machine learning algorithm to make control decisions, use the Controllers to modify the devices, then save the results in a database for a Data Store.

Strategies should have a step() function representing the passing of a full episode/time step of the Strategy's operation.

No default Strategies are currently provided. Users must define Strategies in an Extension.

Testing

Environment files can have one or more tests defined. Tests are composed of a number of steps which are run sequentially. A test will halt the first time any step produces an error. Tests are defined in a list inside the tests section of an environment file.

"tests": [
	[
		# Test 1...
	]
]

In order to run tests, use

active test config.json

Test Definition

Each test is defined by a number of sequential steps inside the environment file.

"tests": [
	[
		{
			// Step 1...
		},
		{
			// Step 2...
		}
	]
]

A step consists of one of the following actions:

A function step invokes a function that was registered through an extension. The process is similar to registering a Component, but the annotation is placed on a function definition instead of a class definition.

from active.testing.decorators import ActiveTestStep

@ActiveTestStep("my test")
def test():

The function should return a list of strings. Each error encountered during the test should be noted by a descriptive string in the list that explains the nature of the problem. An empty list represents a passing test.

The step is defined via

{
	"action": "function",
	"type": "my test",
	"parameters": {
	
	}
}

where type must equal the name registered with @ActiveTestStep("type"). Parameters are given to the function as keyword arguments exactly as they are for Components.

A start step starts an Emulator or Agent.

{
	"action": "start",
	"component": "my emulator"
}

where component must equal the name of an Emulator or Agent.

A stop step stops an Emulator or Agent.

{
	"action": "stop",
	"component": "my emulator"
}

where component must equal the name of an Emulator or Agent.

A wait step simply waits the requested number of seconds before proceeding to the next step.

{
	"action": "wait",
	"seconds": 10
}

Default Test Steps

Controllers have default Test Steps available. They are configurable to run any value getting functions for the Controller, optionally with a range of acceptable values to test for.

The Clock Controller Value Check is the default test for ClockControllers.

Parameter Definition
controller ClockController to be tested
skip List of string parameters (get_foo() functions on controller) to not test.
values Dictionary from string parameters to a dictionary of, optionally, "min" or "max" values for the parameter
{
	"action": "function",
	"type": "Clock Controller Value Check",
	"parameters": {
		"controller": "!ACTIVE:my_clock_controller,
		"skip": [],
		"values": {}
	}
}

The RTU Controller Value Check is the default test for RTUControllers.

Parameter Definition
controller RTUController to be tested
skip List of string parameters (get_foo() functions on controller) to not test.
values Dictionary from string parameters to a dictionary of, optionally, "min" or "max" values for the parameter
{
	"action": "function",
	"type": "RTU Controller Value Check",
	"parameters": {
		"controller": "!ACTIVE:my_rtu_controller,
		"skip": [],
		"values": {
	        "cooling_coil_electricity_rate": {
	        	"min": 0,
	        	"max": 100
	        },
	        "cooling_coil_inlet_temperature": {},
	        "fan_electricity_rate": {},
	        "fan_schedule": {},
	        "heating_coil_electricity_rate": {},
	        "heating_coil_outlet_temperature": {},
	        "heating_coil_set_point": {},
	        "outdoor_air_temperature": {},
	        "actuator_temperature": {},
	        "actuator_inlet_mass_flow_rate": {},
	        "cooling_load": {},
	        "cooling_set_point": {},
	        "enthalpy": {},
	        "fan_electricity_rate": {},
	        "floor_area": {},
	        "floor_volume": {},
	        "heating_load": {},
	        "heating_set_point": {},
	        "humidity": {},
	        "inlet_density": {},
	        "inlet_enthalpy": {},
	        "inlet_humidity": {},
	        "inlet_specific_heat": {},
	        "inlet_temperature": {},
	        "relative_humidity": {},
	        "supply_airflow_rate": {},
	        "temperature": {}
		}
	}
}

ACTIVE Workbench

The ACTIVE Workbench is ACTIVE's built in GUI. It serves files from each Data Store in the Environment, according to the get_visualization_type() returned by the Data Store. Each bucket id will be user-selectable and will display each data set name under that bucket to download. DATAFRAME types will be additionally be displayed as a graph. FILES types will be displayed according to type, with .csvs being displayed as tables.

Development

Running in Docker

To build a test container:

build -t active  .
build run -it --rm --name=active active bash
./start-volttron.sh
source /home/volttron/volttron/env/bin/activate
pip3 install /active-0.0.1-py3-none-any.whl
active start config.json

You may ignore the ./start-volttron.sh line if not testing with a VOLTTRON agent.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

active_framework-2.0.9.tar.gz (83.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

active_framework-2.0.9-py3-none-any.whl (100.4 kB view details)

Uploaded Python 3

File details

Details for the file active_framework-2.0.9.tar.gz.

File metadata

  • Download URL: active_framework-2.0.9.tar.gz
  • Upload date:
  • Size: 83.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.26.1 CPython/3.9.25 Linux/5.14.0-570.60.1.el9_6.x86_64

File hashes

Hashes for active_framework-2.0.9.tar.gz
Algorithm Hash digest
SHA256 f5903952b9e3691677afcfc8f0e4c64bf57712e06f47c5bc03b69df51becd334
MD5 a2de02af6a3fca319c4e5b7e27341c0d
BLAKE2b-256 c687c6c58a9a46f168120d4268e73f6748a215e921bc8d78fea620659faa7028

See more details on using hashes here.

File details

Details for the file active_framework-2.0.9-py3-none-any.whl.

File metadata

  • Download URL: active_framework-2.0.9-py3-none-any.whl
  • Upload date:
  • Size: 100.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.26.1 CPython/3.9.25 Linux/5.14.0-570.60.1.el9_6.x86_64

File hashes

Hashes for active_framework-2.0.9-py3-none-any.whl
Algorithm Hash digest
SHA256 b5f68c0fba40bb672f101d454f0e0a6d999be4e3030897463a4972b7726eb55b
MD5 5d4acfbf36b06e9f762bbef49f0b5d1a
BLAKE2b-256 a22164d86ad8311bf5d89fe41245a8963ea18f898035d83cbfca072d1c3e126a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page