Vermont Energy Control Systems

Rule Programming

This document is a guide to programming the Vesta controller. It is a companion to the sample application document. This document is focused on the process of creating, testing, and fine-tuning the rules that determine Vesta behavior. Here's an example of a rule:

This is an example of a type of rule called a differential rule. This one sets a state variable to indicate that the wood boiler is hot. This determination is based on the difference between two values. The icons at the left allow editing and manipulation and show the status of the rule.

Rule Types

the Vesta controller has several types of rules:

  1. Math Rules, which set a data element based on a mathematical operation
  2. Differential Rules, which act on a difference between two values
  3. Logical Rules, which act on true/false conditions
  4. Timer Rules, which create timers that can be used with other rules
  5. PID Rules, which allow precise control using variable speed or power.

Each rule type will be described in detail in the following sections.

Rule Editing

Rules are based on templates and are constucted using pull-down selections. The rule editing screen looks like this:

Each of the pulldown menus contains only valid choices for the associated field. There is no way to create an invalid rule.

Rule Engine

Rules are evaluated by a periodic task called the rule engine. The rule engine typically runs through the rule set with a frequency of once every minute to as fast as ten times per second. In most applications, once per second is plenty.

A detailed knowledge of Vesta software architecture is NOT necessary in order to program and use the system, but it can be helpful to understand the basic components that make the Vesta controller work. If you want to jump immediately into creating rules you can skip this section.

The Vesta software makes use of shared memory and configuration files. There are several tasks which communicate via a block of shared memory. Each task can also read configuration files from disk as needed. Tasks are completely independent of each other and do not communicate except through shared memory.

For example, there is an I/O task which manages all of the physical inputs and outputs. It reads all of the sensors and discrete inputs and puts their values into shared memory. It reads values for discrete outputs from shared memory and sets the physical outputs accordingly.

In order to do this, it reads data from configuration files to determine what types of sensors are connected and what calibration values should be applied to the raw sensor signals.

This task does not depend on any other task. It doesn't know about rules or datalogging or anything else. You as a programmer cannot communicate directly with this task. Your interaction is entirely through the web interface, which allows you to change the contents of the configuration files.

In the same way, the control task(s) don't have any direct interaction with the physical hardware. They read the rules from configuration files, and read and write values to shared memory.

Configuration Files

All system behavior is determined by configuration files. The configuration files are simple comma separated value (csv) files that can be downloaded into a spreadsheet. In fact, you could configure and program the Vesta system by simply editing the configuration files with a spreadsheet or text editor. You can see the contents of any configuration file by clicking on it on the 'System' tab of the Web Interface.

Control Task

In programming, we are concerned with defining the behavior of the 'control' task. That task reads several configuration files that contain rules. It then implements the logic defined by those rules based on values in shared memory, and sets specified shared memory values as a result.

Shared Memory

Shared memory contains four types of data:

  1. Values for physical inputs and outputs
  2. Variables that are used by the control task
  3. Flags that tell tasks to take specific actions
  4. Command and status data for individual tasks

Any task can read any data that it needs from shared memory. However, only a single task should write data to any specific shared memory location. There are some exceptions, but in general each value is 'owned' by a specific task that is responsible for writing data to it. For instance, the I/O task is responsible for writing sensor data into shared memory.

Figure 2: Home Page showing a variety of Data Elements

While the Vesta controller has a variety of physical inputs and outputs, almost all interaction with the system is through Data Elements. A Data Element has a user-defined name and may represent either a physical input, a physical output, or a variable.

IMPORTANT CONCEPTS: Vesta rules can act only on data elements. There are only two types of data elements:

  1. Physical inputs and outputs. These allow the rules to act on and control the outside world.
  2. Variables. These contain numeric or logical values that can be used as part of any rule.

You can see which physical channels are assigned to specific data elements - just click on the 'Physical I/O' tab.

Creating Data Elements

Data elements representing physical I/O are created using the 'Physical I/O' tab. Data elements representing variables are created on the 'Data Elements' tab.

the Vesta controller is programmed by creating rules that act on Data Elements. Rules cannot be created until the associated data elements exist.

One of the first tasks in setting up an Vesta system is to give each physical I/O channel a data element with a name that describes its function such as 'Wood Boiler Outlet Temp' or 'Second Floor Heat Demand'. This is covered in the user's manual, and is typically part of initial system setup.

Once data elements for physical I/O have been created, the next task is to create data elements for any variables that will be needed.

All available data elements are displayed on the 'Data Elements' tab of the web interface. This tab allows the name of any data element to be changed. It allows the creation of new variables as well as setting the value for any variable.


There are three types of variables:

  1. Standard variables
  2. State variables
  3. Timer variables

Standard Variables

Standard variables are data elements that contain numeric values. They can get their values from the user interface, or can be set by rules. Values are stored as floating point numbers, but any variable can also be treated as a boolean (true/false) value.

State Variables

State variables are a special class of variable. State variables are treated as boolean values. They are automatically set to 'false' by the system and will remain false unless a rule sets them to true. Any variable with a tilde (~) as the first character in the name will be treated as a state variable.

Note: The 'set to false' behavior only applies to state variables which are 'owned' by the rule engine. See the section on data element ownership for more details.

Timer Variables

A timer variable is any variable that is named as the target of a timer rule. These variables will be decremented automatically by the rule engine. Their value at any time is the number of seconds remaining before they reach zero. See the section on timer rules for more details.

Variables as True / False values

In the Vesta, any non-zero value is considered 'true'. For example, a variable used as a timer will have a numeric value representing the number of seconds remaining. If that value is non-zero, then the timer is 'true'. There are also predefined elements named TRUE and FALSE with values of 1 and 0.

The value of any variable may be set or changed via a rule, it may remain constant for all time, or it may be changed via the web interface.

Variables can be created as needed, and their values may be changed at any time via the web interface. All changes take effect immediately.

Creating Variables

To create a variable, enter the name and numeric value in the corresponding boxes on the Data Elements' tab, and click the 'Create' button.

The view shown above contains the elements set up at initial delivery, These support the 'Front Panel' example that will be discussed in the next section.

The Vesta is delivered with a simple set of rules that use the user-assignable three position switch and LEDs on the controller front cover. This example does not require any external hardware to be connected. Turn on your controller and connect to it to follow the discussion in this section. This configuration and rule set is backed up as 'LedSample' on the Vesta.

Each rule type will be covered in detail in the following sections. This section is intended as a quick introduction to rules.

Figure 3: Front Panel Example

The top portion of the screen shows all of the data elements that are available on the system. Below that, the rules are listed in the order that they will be evaluated.

Comments are in blue and preceded by '//'. In this example, comments break the rules into three sections.

Rules can be rearranged. The icons next to each rule allow the following actions:

  • Delete the rule
  • Move the rule up
  • Move the rule down
  • Insert a new rule above the rule
  • Edit the rule

There's also an indicator next to each rule that shows whether the rule is currently (as of the last refresh) 'active'. In the example above, only one rule is active.

Desired Behavior

For the purposes of this example, we'll make use of the following data elements:

Name Type Description
LED 1 Discrete Output Front Panel LED
LED 2 Discrete Output Front Panel LED
LED 3 Discrete Output Front Panel LED
LED 4 Discrete Output Front Panel LED
User Switch Up Discrete Input True if user switch is up
User Switch Down Discrete Input True if user switch is down
GUI Button Discrete Output Not connected: Set via GUI
~Active Switch State Variable Set to true if any switch is on
Timer 1 Variable Used for illuminating LED 4
Brief Delay Variable Timer interval value

The desired behavior is as follows:

  1. If the user switch is in the 'down' position, illuminate LED 1
  2. If the user switch is in the middle position (neither up nor down) illuminate LED 2
  3. If the user switch is in the 'up' position, illuminate LED 3
  4. When the user switch is moved to the 'up' position, illuminate LED 4 for 10 seconds
  5. When the GUI Button is pressed, illuminate LED 4 for 15 seconds
  6. Keep track of whether any switch is pressed: 'Active Switch' should be true if any switch is pressed: if the user switch is either up or down (not in the center position) or if the GUI Button is pressed

These desired behaviors are of course completely arbitrary and have been developed for the purposes of illustration only. The GUI Button is accessible through the GUI and will be discussed in greater depth in the GUI chapter.

Rules for LED control

The first three rules in the LED control section implement the first three desired behaviors:

The rules are almost an exact restatement of the desired behaviors. Note that all rules are in the general form "Set (some element) to (some value) under (some condition)". Remember that TRUE and FALSE are predefined variables.

The fourth rule implements the fourth desired behavior based on a timer. The timer rules are in the third section and will be discussed there.

Rules for the 'Active Switch' state variable

These three rules serve to set the 'Active Switch' state variable to true if the user switch is up or down, or if the GUI Button is true. Since it's a state variable, it will have a value of false if none of these rules set it to true.

Timer Rules

There are two timer rules:

  1. Any time the switch is moved to the 'up' position, set Timer 1 for the number of seconds represented by the 'Brief Delay' variable - 10 seconds in this case
  2. Any time the GUI Button becomes true, set Timer 1 for 15 seconds.

Note that one rule uses a variable to determine the timer delay, while the other uses a plain numeric value. When Timer 1 is set, it will immediately begin counting down. As long as it is non-zero, LED 4 will be turned on based on the fourth rule in the LED section above.

Front Panel Uses

Once you're done using the front panel to learn about programming, it still has a few uses:

  1. Testbed for new rules. Rather than testing a new set of rules on actual hardware, create the rules exactly as they will be except have them turn on LEDs rather than actual pumps and valves. If the rules aren't doing exactly what you want, no harm done.
  2. Substitute input for testing. If you have a rule that's triggered by something that's not well suited for testing - an overtemperature switch, for instance - you can test the rule using the front panel switch as the input. Simply update the rule to use the actual input once you're satisfied.
  3. User input and / or status displays. In some cases there may be a need for user input or a desire to provide visual status indication. Simply label the switch and/or LEDs as needed and build rules. Examples might be mode indication or user selection of heat source (Wood / Oil / Auto, for instance).

There are a few topics that concern rules in general rather than any specific rule type.

Rules Set Elements

Important Concept: Every rule has a 'target' element whose value it may set. Different rule types have different behaviors. There are discussed in more detail in the following sections. In summary:

  • Math rules always set their target element every cycle.
  • Every differential rule sets its target element to either TRUE or FALSE every cycle.
  • Logical rules ONLY change their target if the rule evaluates to true. If the rule evaluates to false, they do nothing.
  • Timer rules set their target if the criteria are met. If not, they decrement their target until the target is zero.

Rules can use numeric values or elements as parameters

Important Concept: Some fields in some rules can refer to a data element OR may simply have a numeric value. This provides flexibility: If the parameter is something that you might want to set via another rule or from the user interface, use a variable. If it's a simple value that's unlikely to change, just use the numeric value, For example, consider a rule that determines whether a zone needs heat

Deleting, Moving and Editing Rules

Any rule may be deleted by simply clicking the 'X' button next to the rule. There is no 'undo'.

You can move rules up or down by clicking the arrow buttons next to the rules.

To update a rule, click the pencil icon next to the rule. This will open the rule in a new window (or tab):

You can construct your rule by selecting values from the pulldown menus. In each case, the pulldown will only display choices that are valid for that field. For instance, you can't set the value of an input, so sensors are not shown as choices for the 'target' field.

Note that the pulldown menu choices follow the Vesta color coding standard:

Analog Inputs (sensors)
Analog Outputs
Discrete Inputs
Discrete Outputs

If there's a field that can have either a numeric value or an element reference, there will be a pulldown with a text entry box below it. If the pulldown is set to '--' then the value in the txt box will be used.

Evaluation Sequence

Rules are evaluated in the sequence displayed. Results are not written to shared memory until all rules have been evaluated. This means that if you have two or more rules that set the same element, the last value is the one that will be written back to shared memory.

In the Front Cover example, there is an instance of this situation. When the user switch is moved to the 'up' position, LED 3 lights immediately. However, LED 4 does not light until the next cycle. That's because LED 4 is based on Timer 1, and Timer 1 does not get set until the end of the first cycle.

This sequence behavior can be used to ensure that one event happens before (or after) another.

Default Values for Elements

All elements tied to discrete outputs and state variables are in effect initialized to FALSE at the beginning of each cycle. If no rule sets them to TRUE, they will will evaluate to FALSE and the discrete output will be turned off.

All other elements inherit their previous values. If no rule acts on them, they will retain the same value indefinitely.

Multiple rules for the same Element

It's possible and often desirable to have more than one rule that sets the same element. This is particularly true for discrete output elements. If there are multiple rules that set the same element to TRUE, then it will end up as TRUE if any of the rules is triggered.

The basic behavior is that any element affected by multiple rules ends with the value from the last rule that sets it.

Math rules set an element to the result of a mathematical operation performed on two values, each of which may be an element or a numeric value. The possible mathematical operations are addition, subtraction, multiplication, and division. The template is as follows: Set Element1 to Element/Value (+-*/) Element/Value

Math rules are always active - they set their target element on every cycle. A typical math rule might calculate the difference between two values: Set Boiler Rise to Wood Out minus Wood In

Differential rules set an element based on the difference between two other elements. The target and the value being tested must be elements - the other parameters can be either elements or numeric values. The template is as folllows:

Set Element1 (to TRUE) if Element2 is at least Element/Value greater (or less) than Element/Value with a deadband of Element/Value

NOTE: Differential rules have an implied 'to TRUE' as part of the template. If the conditions in a differential rule are satisfied, the target element will be set to TRUE.

NOTE 2: Differential rules ALWAYS set the value of the target variable. It's set to TRUE if the rule criteria are met, and FALSE if not.

The differential rules have a lot of options and a lot of resulting complexity. There are five parameters involved, and all of them are required.

Example: Solar Circulator

A differential rule might be used to control a solar panel circulator, for instance. In that case, we might want the circulator to be on any time the panel temperature is at least 5 degrees above the storage tank temperature. The rule might look like this:

Set SolarCirc if PanelTemp is at least 5.0 greater than StorageTemp with a deadband of 2.0

In this example, these elements are used:

  1. SolarCirc: A discrete output that turns on the solar panel circulator
  2. PanelTemp: A sensor input that reads the panel outlet temperature
  3. StorageTemp: A sensor input that reads the storage tank temperature

The first element is the target. It is set to TRUE (a numeric value of 1) if the rule is triggered. In most cases, the target element will be a discrete output that controls a pump or a valve. In our example, it's SolarCirc.

The second element is the first of two values to be compared. It will typically be either a sensor value or a variable. In our example it's PanelTemp.

The third element is the differential. In our example it's the numeric value 5.0.

The fourth element is the second value that's part of the comparison. In the example, it's the storage tank temperature. It could also be a variable.

The fifth element is deadband (sometimes called hysteresis). This helps prevent excessive cycling. A more detailed discussion of deadband can be found below.

Example: Thermostat

A fairly common need is to implement a rule that has the same effect as a thermostat. For instance, we might want to open Zone Valve 1 if the top floor temperature is below the top floor setpoint. Here's a differential rule:

Set ZoneValve1 if TopFloorTemp is at least 0.0 less than TopFloorSetpoint with a deadband of 2.0

In this example, these elements are used:

  1. ZoneValve1: A discrete output that opens the top floor zone valve.
  2. TopFloorTemp: A sensor input that reads the top floor temperature
  3. TopFloorSetpoint: A variable that contains the desired temperature for the top floor.

In this case, we don't need a differential term. The numeric value of 0.0 disables the differential calculation. In this case, the rule will be displayed without the differential term.


Deadband is a value that's added (or subtracted) from the temperature difference depending on whether the target element is active or not. It has the effect of preventing short cycling.

If you had a rule that tuned on a circulator whenever a measured temperature was less than 70 degrees, you might have a situation where the temperature was near 70 degrees, but fluctuating between 69.9 and 70. Without deadband, the circulator would cycle on and off with every fluctuation.

With that same rule and a two degree deadband, the system will subtract two degrees from the setpoint whenever the circulator is off. That means that when the temperature hits 70, the circulator turns off. It will stay off until the temperature hits 68 degrees.

In this way, the temperature will cycle between 68 and 70. The value of deadband can be changed to tune system performance.

For rules with a 'less than' term such as our thermostat example, deadband is subtracted from the fourth element (setpoint in this case). For rules with a 'greater than' term, the deadband is added.

Logical rules operate on TRUE/FALSE values. They set an element based on whether some combination of other elements are TRUE or FALSE. The template is as folllows:

Set Element1 to Element/Value if Element2 is / is not true and Element3 is / is not true and Element4 is / is not true

NOTE: Unlike differential rules, logical rules can set the target element to any value, not just TRUE. If the conditions in a logical rule are satisfied, the target element (Element1) will be set to the value of the element or number specified in the second parameter.

NOTE: Also unlike differential rules, a logical rule does not set the value of the target element if conditions of the rule are not satisfied. If the rule is not triggered, then the target element remains unchanged.

In logical rules, the last two elements are optional.

The LED Sample rules that are delivered with the Vesta are described in an earlier section. These provide good examples of logical rules.

Multiple rules and logical OR

Individual logical rules can contain multiple criteria which are combined with a logical AND. Sometime it's desirable to combine criteria with a logical OR. For instance, suppose that you have a set of discrete inputs connected to switches that detect dangerous conditions and you want to turn on an alarm if any of them are true. A single logical rule can't do this. However, you can create a set of rules all with the same target element as follows:

Set Alarm to TRUE if FloorWet is true
Set Alarm to TRUE if OverTemp is true
Set Alarm to TRUE if DoorOpen is true and PrimaryBlower is true

Since logical rules do not set their target element if they're not triggered, multiple logical rules can act on the same target with the result that the target is set if any of the rules are triggered. Remember that discrete outputs and state variables default to FALSE if no rule acts on them. In this case, Alarm is a discrete output so it will end up with a value of false if none of these rules is triggered.

Example: Setback Rule

In the LED example, all of the logical rules set the target element to TRUE. This is the most common situation, and it makes perfect sense if the target element is a discrete output. However, the target could also be a variable or an analog output. In the differential rules section there was an example of a differential rule that provided the same functionality as a thermostat:

Set ZoneValve1 if TopFloorTemp is at least Z0.0 less than TopFloorSetpoint with a deadband of 2.0

If there were a discrete input ( a switch, or timer contacts, or an occupancy sensor) that indicated whether the heated area were occupied, we could add a couple of logical rules to change the TopFloorSetpoint variable:

Set TopFloorSetpoint to Comfortable if Occupied is true
Set TopFloorSetpoint to Cool if Occupied is not true

In this example, these elements are used:

  1. TopFloorSetpoint: A variable that contains the desired temperature for the top floor
  2. Comfortable: A variable with a current value of 72
  3. Cool: A variable with a current value of 65
  4. Occupied: A discrete input that indicates whether the area is occupied

Timer rules set a variable to a value (in seconds) when the specified condition is met. The target variable will automatically count down each cycle. The template is as folllows:

Set Element1 for Element/Value seconds when Element2 (is / becomes) (true / false)

Element1 must be a variable. It is given the value of the second parameter (element or value) when the specified conditions are met. Element1 should not be used as the target of any other rule. Variables that are the target of timer rules are decremented every cycle of the control process until they reach zero.

Becomes vs. Is

In timer rules, the rule can be triggered when a specified variable IS true (or false), or when it BECOMES true (or false). This creates two very different behaviors.


If the rule uses IS as the criteria, then the timer will be reset to the specified value every cycle that the chosen element has the specified value. This is useful if you want to time from the end of a condition. For instance, you might want to keep track of whether the wood boiler could still produce heat. Simply measuring output temperature isn't adequate, since it will fluctuate over time. A reasonable rule might be to consider that the wood boiler is out of fuel if its outlet temperature stays below 160 degrees for 30 minutes. This requires a set of rules, one of which is a timer rule. The first rule we need is a rule to determine whether the wood boiler is hot. We'll create a differential rule:

Set WoodBoilerHot if WoodBoilerOutlet is at least 0.0 more than WoodBoilerMinimum with a deadband of 2.0

This sets a variable (WoodBoilerHot) that tells us whether the wood boiler is hot or not. Now we can set a timer based on the wood boiler outlet being hot:

Set WoodHeatTimer for 1800.0 seconds when WoodBoilerHot is true

As soon as the wood boiler outlet temperature exceeds WoodBoilerMinimum, the first rule sets WoodBoilerHot to true. It will stay true as long as the wood boiler outlet is hot enough, although it may not be true for a few minutes now and then if a slug of cold water is introduced from an inactive zone.

As soon as WoodBoilerHot is true, WoodHeatTimer gets set to 1800 seconds. It will keep getting set to 1800 seconds every cycle as long as WoodBoilerHot remains true. As soon as WoodBoilerHot is no longer true, WoodHeatTimer will start to count down, reaching zero if WoodBoilerHot remains false for 1800 consecutive seconds.


The other behavior for timer rules is BECOMES. In this case, the timer is set when the specified element makes a transition to the specified value. It then counts down, only resetting if the element makes another transition to the specified value. Consider an example where you want to do something different during the time that the boiler is first coming up to temperature. A thermocouple in the flue could detect a rise in flue temperature and trigger a timer:

Set FlueHot if FlueTemperature is at least 0.0 more than 150 with a deadband of 10.0

This tells us that the flue is hot enough to indicate that a fire has been started (or is in progress).

Set FireStartTimer for 600 seconds when FlueHot becomes true

The FireStartTimer will be set as soon as the flue temp climbs above the threshold. It will then count down regardless of whether the temp stays above the threshold or drops below again. The only way it would be reset is if the temp drops below the threshold and then rises again.

PID rules allow the controller to continuously vary the speed or position of a controlled device in order to achieve a target condition. PID is a commonly used control scheme in industrial settings. The theory is beyong the scope of this document, but this is one of many good references available on the web.

Use of PID rules in the Vesta assumes that you have a motor, circulator, fan, blower, or other device that is connected to a VS-1108 Variable Speed Control Unit or some other device that can be controlled directly using the 4-20ma analog outputs on the Vesta.

Line 1 - Rule Setup

PID rules have three lines. The first line sets up the rule itself - what is to be controlled, what the goal is, and when the rule should operate. There are five fields in this line. All are required, and all must refer to Vesta data elements. This rule is from the included Demo application. It varies the current through a light bulb to keep the shade temperature at a target value:

Control Light Bulb to make Shade Temp close to Shade Target based on Room Temp when ~PID Enabled is true

The fields are as follows:

  1. Control Output - 'Light Bulb' in this example. This must refer to a Vesta analog output.
  2. Process Variable - 'Shade Temp' in this example. This is the parameter that you wish to affect and bring as close as possible to a desired target value. It almost certainly needs to be a sensor input, although it could be a variable whose value is calculated from sensor inputs. For example, you could calculate temperature rise through a heat exchanger as the difference between inlet and outlet temperatures. A PID rule could then vary fan or circulator speed to maintain a constant temperature rise.
  3. Target Value - 'Shade Target' in the example. This can be a variable or an analog input. In eiter case, the purpose of the PID rule is to vary the control output to drive the process variable as close as possible to this value.
  4. Bias Input - 'Room Temp' in the example. This is used to predict an initial value for control output. It is discussed in more detail below.
  5. Control Input - '~PID Enabled' in the example. If this data element is true, then the PID rule will be active. If it is not true, then the PID rule will not manage the control output, except that it will set the output to zero when the control input first becomes false.

Line 2 - Tuning Parameters

The second line contains tuning parameters. All are required, and all are directly entered numeric values:

gain = 5.0 damping = 20.0 lmin = 100.0 lmax = 40.0


Gain is the simplest tuning parameter. The technical term is proportional gain, and it's the 'P' in PID. It controls how strongly the PID rule responds to errors - that is, differences between the value of the process variable and the target value. The control output is in percent and has a maximum possible range of 0 to 100. The PID engine will compute an expected value for the control output and then add a correction that is the gain multiplied by the error as defined above.

For example, assume that the expected control output is 50%, but the shade temperature is 5 degrees cooler that the target temperature (an error of 5 degrees). With a gain of 5, that would result in a correction of 25 to be added to the expected output of 50, yielding an output of 75.

Start with a relatively low value for gain. Too high a value will cause large fluctuations as the system over-reacts to small errors.


Proportional gain alone is usually not enough to bring the process variable to the target value. PID controls also contain a factor that looks back to see whether there's been a persistent error over time. It calculates an additional correction based on how long an error has existed and how large that error has been. Mathematically, this technique is called integration, and contributes the 'I' in PID.

In the Vesta PID engine, the damping term controls the effect of the integral factor. A large damping value supresses the effect of the integral factor.

Start with a relatively high value for integral damping - 100 to 1000 or more, especially if there's a large time lag between changes in the control output and resulting changes in the process variable. Once a reasonable value for gain has been established, reduce damping in 50% steps until the system starts to over-react, then go back to the last stable value.

Bias - lmin and lmax

It is helpful to enable the system to make a reasonable estimate of the required control output. In many cases, there's some environmental value that can be used to make an approximate guess. For instance, outdoor temperature might allow an estimate of required radiant floor supply temperature - higher when it's colder outside. In the Vesta PID rule, the bias value is used with lmin and lmax to calculate the estimated control output. The bias value element would be outdoor temperature in the radiant floor example. In our light bulb example it's room temperature, since we expect that room temperature can predict how hot our bulb will need to be to achieve a given shade temperature. If our shade temperature target is 140 degrees and the room temperature is also 140, then the control output would be 0 - no additional heat would be needed. The lmin parameter is the bias value at which the control output would be expected to be at it's minimum.

By the same token, lmax is the bias value at which the system would need maximum control output. We don't really know what that is for our light bulb, but we'll guess that at a room temperature of 0 degrees, it would need 100% output.

Note that it's not critical to have an exact value. As long as the estimate is better than an arbitrary fixed value, it will improve performance.

If there is no value that can be used to predict the control output, use a relatively stable value (such as room temperature) and set lmin and lmax to be equal amounts above and below the normal value of the bias input. In the light bulb example, 0 and 140 are equally spaced above and below a typical room temperature of 70. That gives a starting point of 50% for control output.

Min and Max Output

In some cases, you may want to set a minimum and/or maximum value for the control output. In most cases, 0 and 100 are appropriate.

Line 3 - Purge Logic

Line 3 is used if there's a need for purge cycles. This is often the case when controlling the draft blower on a wood gasification boiler. When running at low speed, it's necessary to periodically flush the primary chamber by running the blower briefly at high speed. This technique can also be used if low speed allows air bubbles to accumulate, or if there's any other reason to have brief periodic high speed intervals.

Purge values are required. Set them to 0 if purge is not desired.

Min Output = 0.0 Max Output = 100.0 Purge Threshold = 0.0 Purge cycle interval = 0.0 Purge duration = 0.0

Purge Threshold sets the value for control output below which purges are required. A value of 50 means that the system will run purge cycles any time the output is below 50%.

Purge cycle interval is the time in seconds between purges.

Purge duration is the duration in seconds for the purge cycle. The output will be set to 'Max Output' value for this duration each purge cycle.

Comments are technically rules, but they don't perform any action. They can be moved up, moved down, deleted, and edited just like any other rule. Comments can be up to 80 characters in length. They are displayed in C++ style with two leading slashes:

Use comments to break your rules up into logical groups. This will greatly improve readability and make it easier to understand your rules in the future.

the Vesta controller provides a limited set of choices for programming. Sometimes, it may take several rules to accomplish a simple task. However, there are techniques that can reduce the number of rules and make system behavior easier to understand.

Tip #1: Use discrete outputs or state variables to hold true / false information

Very often there will be rules which result in a true / false value which will be used by subsequent rules. For instance, there might be a rule that determines that the outlet of the wood boiler is hot enough to be useful. You could create an ordinary variable named WoodBoilerHot and set it using a differential rule something like this:

Set WoodBoilerHot if WoodBoilerOutlet is at least 0.0 greater than 160 with a deadband of 5.0

This works, and because differential rules have an implied default of FALSE, the WoodBoilerHot variable will be set to false if the condition is not met. The situation is a bit more complex if you're using logical rules, since you'll need an initial rule to set the variable to false:

Set WoodBoilerHot to FALSE if WoodBoilerHot is true
Set WoodBoilerHot to TRUE if WoodBoilerAquastat is true

While both of these rule sets work, the second case would be simpler if a state variable were used: Set ~WoodBoilerHot to TRUE if WoodBoilerAquastat is true

Since the state variable is automatically set to false each cycle, there's no need for the extra rule.

Using a discrete output accomplishes the same thing, with an added benefit: the output can be connected to an LED such as one of the existing LEDs on the controller front panel. In this way, the value is visible. In this example, we could rename LED 1 on the front panel to WoodBoilerHot and put a label on the front panel. The status of the wood boiler would then be visible at a glance.

Tip #2: Think about important system states

Chances are that there are many system states, conditions, or modes that are important in defining or describing system operation. In programming, it helps to create state variables or use discrete outputs (see above) to carry information about those system states.

For instance, one very common and important question is whether there is any heat demand. There may be many rules which depend on the question of whether any zone is calling for heat. For example, there might be a circulator that needs to run if any zone needs heat. With three zones and no system state logic, the rule set might look something like this:

Set PrimaryCirculator to TRUE if ZoneTstat1 is true
Set PrimaryCirculator to TRUE if ZoneTstat2 is true
Set PrimaryCirculator to TRUE if ZoneTstat3 is true

That's not too bad, but the rules do look a bit repetitive. The situation becomes much worse if the circulator is only supposed to run if there is heat available form the wood boiler or heat storage. Assuming an aquastat on the boiler and storage tanks to indicate that here is heat available, the rules now look like this:

Set PrimaryCirculator to TRUE if ZoneTstat1 is true and BoilerAquastat is true
Set PrimaryCirculator to TRUE if ZoneTstat1 is true and StorageAquastat is true
Set PrimaryCirculator to TRUE if ZoneTstat2 is true and BoilerAquastat is true
Set PrimaryCirculator to TRUE if ZoneTstat2 is true and StorageAquastat is true
Set PrimaryCirculator to TRUE if ZoneTstat3 is true and BoilerAquastat is true
Set PrimaryCirculator to TRUE if ZoneTstat3 is true and StorageAquastat is true

While this achieves the desired results, it's is now starting to feel cumbersome and difficult to understand. It only gets worse as additional rules and conditions are added. A better approach is to use two discrete outputs to carry system state information. The first will be true if there's any demand, and the second will be true if heat is available from storage or the wood boiler. Here's the resulting rule set:

Set ~Demand to TRUE if ZoneTstat1 is true
Set ~Demand to TRUE if ZoneTstat2 is true
Set ~Demand to TRUE if ZoneTstat3 is true

Set ~HeatAvailable to TRUE if BoilerAquastat is true
Set ~HeatAvailable to TRUE if StorageAquastat is true

Set PrimaryCirculator to TRUE if ~Demand is true and ~HeatAvailable is true

As an added bonus, we can get a visual indication of these states if we use a discrete output that's connected to an LED. This example uses state variables, but we could also use LED1 and LED2 on the controller front panel and rename them to 'Demand' and 'HeatAvailable'.

As with any data on a computer, it's prudent to back up the rules and configuration data from the Vesta. All configuration and rule data is stored in text files that can be copied and saved either internally or on another computer. There are three ways to back up data, and two ways to restore from backup.

Fast and Simple


In the Vesta web interface, go to the 'System' tab. To back up all configuration and rule settings, Put a name in the 'Backup' field and click the 'Backup' button. Names must not contain spaces, punctuation, or special characters with the exception of '-' and '_'. A descriptive name is good, perhaps including a date. Backed up configurations appear as choices in the 'Restore' section.

All configurations saved in this way are saved to internal storage in the Vesta controller. This means that if there was a catastrophic failure of the CPU card, the configuration and backups could be lost.


To restore, simply click the 'Restore' button next to the saved configuration that you want to restore. NOTE: it may be necessary to cycle power on the Vesta controller after a Restore operation.

Note that restoring a saved configuration wipes out all current settings.

As delivered, the Vesta controller has three saved configurations:

  1. empty - As described, it's a completely empty configuration with no defined elements and no rules.
  2. full-test - This configuration is used before delivery to test the Vesta controller. All physical inputs and outputs have elements defined, and there are rules that exercise the system. This configuration is not likely to be of any use to end users.
  3. led-sample - This configuration is the 'as-delivered' setup. It has simple rules to illuminate the front panel LEDs based on the position of the user-defined front panel switch.

Web Based Backup

It's possible to individually back up each configuration file to any computer that has access to the Vesta. In the Vesta web interface, go to the 'System' tab. All the configuration files are shown as clickable links. Right-click on each and save as a file on your computer.

Using FTP for Backup and Restore

the Vesta controller is an FTP server, so FTP can be used to copy files to and from the Vesta. You can use any FTP client to do this, but there is a simple command-line FTP client that's included with Windows.

Before starting the backup process, create a directory on your computer for the Vesta files. In this example, there's a directory in 'My Documents' named 'Vesta'.

Bring up a command prompt window. One way is to click 'Start', then choose 'Run...', and in the popup type 'cmd'.

In the command prompt window type the following commands:

cd "My Documents\Vesta
(or the path to whatever directory you choose)

(substitute the address of your Vesta here)

When prompted, enter Vesta for user name. Enter the password for your system, which can be found inside the front cover.

At the ftp prompt, type

cd /usr/local/vesta/data

You can copy individual files from the Vesta controller to your computer by typing

get filename
where filname is the name of the individual file that you want to copy.

You can copy all configuration files by typing

mget *.csv

You can copy files from your computer to the Vesta by typing

put filename

And finally, you can copy all configuration files (assuming that you have them on your computer) by typing

mput *.csv

You can also back up, delete, or replace any configurations that were saved to internal storage. These are simply files in the /var/vesta/backups directory. They are tar files that have been compressed with gzip. If you are familiar with this approach, you can unpack and study the backups anywhere. Otherwise, simply store the files themsleves as desired and copy them back to the Vesta controller if needed.

Other Files

In addition to the basic configuration files, the Vesta application makes use of files stored in several other locations. Some common directories include:

/var/www/private - password protected control panel (real-time GUI) files

/var/www/public - control panel (real-time GUI) files without password protection

/usr/local/vesta/etc - system configuration files

Sample Task

This document is part of the Vesta Control System Software, Copyright Vermont Energy Control Systems LLC.

Vesta contains is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.

Vesta software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with the Vesta system. If not, see