Skip to content

Controls

Tutorial on writing setpoints and schedules for active building control.

Overview

The aedifion Edge Device allows writing setpoints or whole schedules of many setpoints to any writable datapoint on any building automation component in the attached building network. The semantics of writing setpoints and schedules abstracts from the underlying building networks and automation protocols and thereby provides a unified, fine-grained control of the building's automation components. In this article, we cover basic concepts and examples of writing setpoints and schedules for active building control.

Preliminaries

The examples provided in this section partly build on each other. For the sake of brevity, boiler plate code such as imports or variable definitions is only shown once and left out in subsequent examples.

To execute the examples provided in this tutorial, the following is needed:

  • A valid login (username and password) to the aedifion.io platform. If you do not have a login yet, please contact us regarding a demo login. The login used in the example will not work!
  • A project with writable datapoints.
  • Optionally, a working installation of Python or Curl.

Setpoints

Setpoints can be acknowledged or not. In the former case, a reference is returned which can be used to query information about the state of the setpoint write operation. In the latter case, no direct feedback is given about the success or failure of a setpoint write operation and no state is kept for the setpoint write operation.

Once a setpoint is created by the user, the setpoint write operation is immediately started and cannot be delayed, modified, or cancelled afterwards.

Existing setpoints (at the same priority) are overwritten without any warning by a new setpoint. However, if the setpoint write operation is acknowledged, the overwritten value will be returned as part of that operation's state.

If an error occurs on any stage for any reason, the whole setpoint write operation fails. No recovery action is taken, i.e., it is left to the user to ensure that the system is in the desired state.

Once a setpoint is successfully written, it remains active until it is overwritten by another setpoint. In other words, a written setpoint never expires on its own and is never reset automatically.

In summary, setpoints are single one-shot best-effort low-overhead irrevocable write operations. They are fast and easy to use.

.controls Algorithms and Apps

In our product .controls, we provide various standard algorithms. Some of these algorithms can be deployed as .controls apps (the instance of a .controls algorithm) using the HTTP-API. For more details on the .controls infrastructure, see the .controls framework.

API Tutorial

Setpoints and managed through the HTTP API. In this section, we go through the steps of unlocking setpoints for an existing project, configuring selected datapoints for writing, and, finally, writing sample setpoints.

Enabling write access

Setpoints write directly to building automation components and may thus (deliberately) complement, interfere with, or completely override existing control and automation. This is a critical operation and thus disabled per default on all projects. Further, there is a series of safeguards in place that limit and protect access to this feature. We go through these safeguards one by one in the following.

1. Activating setpoints the project

The setpoints feature is by default completely locked for all projects. Trying to post a setpoint results - even with the right roles and permissions (next step) - in an error:

{
  "success": false,
  "error": "Project 1 not found or setpoint writing not enabled for project.",
  "operation": "post"
}

In order to activate setpoints for your project, please contact us personally. We will need to know

  • the project (id) for which you wish to activate writing.
  • the maximum priority that is allowed for writing setpoints and schedules, e.g., for protocols such as BACnet which support different priorities. Writing at higher priorities will not be possible.

2. Configuring roles and permissions

Writing requires write permissions on datapoints. If you do not have sufficient access, you will receive an error message similar to this one:

{
  "success": false,
  "error": "Unauthorized access to endpoint: 39 - POST /v2/datapoint/setpoint"
}

By default, the automatically created admin role of a project has full read/write access on all datapoints. It is, however, strongly advised to set up roles with more restricted write access, e.g., limited to only the necessary datapoints, and not freely assign the admin role to all users just for the sake of simplicity. Please refer to our administration tutorial on how to set up roles and permissions for projects and datapoints exactly as you need them.

3. Configuring datapoints for writing

In addition to the general feature lock (step 1) and the role-based access control (step 2), a third safeguard is in place: lower and upper bounds for writing that are defined individually for each datapoint. Trying to write to a datapoint that has no bounds configured results in this error:

{
  "success": false,
  "error": "Datapoint 'bacnet100-4120-Real-room-temperature-setpoint-RTs_real' has no bounds for setpoint writing. Cowardly refusing setpoint schedule - please contact support@aedifion.com",
  "operation": "create"
}

Writing bounds can be configured through the PUT /v2/datapoint endpoint which requires the following parameters:

Parameter Datatype Type Required Description Example
project_id integer query yes The numeric id of the project. 1
dataPointID string query yes The alphanumeric id of the datapoint for which to configure writing bounds. bacnet100-4120-Real-room-temperature-setpoint-RTs_real
setpoint_min_value float body (JSON) yes Lower bound for writing to this datapoint. 15
setpoint_max_value float body (JSON) yes Upper bound for writing to this datapoint. 25

Here is an example of configuring writing bounds for a room temperature setpoint. A range of 15° to 25° Celsius seems reasonable in this example:

import requests

api_url = 'https://api.aedifion.io'
auth_john = ("john.doe@aedifion.com", "mys3cr3tp4ssw0rd")
project_id = 1
dataPointID = "bacnet100-4120-Real-room-temperature-setpoint-RTs_real"
datapoint_update = {
    "setpoint_min_value":15,
    "setpoint_max_value":25
}
r = requests.put(f"{api_url}/v2/datapoint",
                 auth=auth_john,
                 json=datapoint_update, 
                 params={"project_id": project_id, "dataPointID": dataPointID})
curl 'https://api3.aedifion.io/v2/datapoint?project_id=1&dataPointID=bacnet100-4120-Real-room-temperature-setpoint-RTs_real'
    -X PUT 
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd 
    -H 'Content-Type: application/json' 
    -d '{
        "setpoint_max_value": 25, 
        "setpoint_min_value": 15
    }'
  1. Point your browser to https://api.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags (Meta, Company, ...) select the Datapoint tag, then the PUT /v2/datapoint endpoint (yellow).
  4. Provide the project_id, dataPointID and the datapoint_details, e.g., "setpoint_max_value": 25 and "setpoint_min_value": 15.
  5. Click "Try it out!".
  6. Inspect the response body and code.

The answer confirms that our request was successful.

{
  "success": true, 
  "operation": "update",
  "resource": {
    "dataPointID": "bacnet100-4120-Real-room-temperature-setpoint-RTs_real",
    "hash_id": "7fSjkcIH",
    "id": 533,
    "project_id": 1,
    "setpoint_max_value": 25,
    "setpoint_min_value": 15
  }
}

Within the configured bounds, writing is now possible while any attempt to write outside these bounds results in an error:

{
  "success": false,
  "error": "Setpoints for datapoint 'bacnet100-4120-Real-room-temperature-setpoint-RTs_real' are restricted to [15.0,25.0]. Cowardly refusing schedule due to value 30.",
  "operation": "create"
}

Writing single setpoints

Setpoints are written through the POST /v2/datapoint/setpoint endpoint. The caller must provide the following parameters:

Parameter Datatype Type Required Description Example
project_id integer query yes The numeric id of the project. 1
dataPointID string query yes The alphanumeric id of the datapoint that should be written to. bacnet100-4120-Real-room-temperature-setpoint-RTs_real
value string query yes A string containing an integer or float value that should be written to the data point or the special string null to clear the value. 16.7
priority integer query no The priority at which to write the setpoint (default = 13). 15
acked boolean query no Whether this setpoint operation is acknowledged or not. False
dryrun boolean query no Whether this is a dry run that only tests but does not actually write the setpoint. False
keep_out_of_service boolean query no Ensures that the values will not get overwritten by the local building automation system when set to true. False

Having enabled write access, we can now write a setpoint. Please carefully choose a datapoint when executing these examples as you are operating on a real building.

project_id = 1
dataPointID = "bacnet100-4120-Real-room-temperature-setpoint-RTs_real"
r = requests.post(f"{api_url}/v2/datapoint/setpoint", 
                  auth=auth_john,
                  params={'project_id': 1, 
                          'dataPointID': dataPointID,
                          'value': 16.7,
                          'priority': 15})
print(r.text)
curl "https://api-dev.aedifion.io/v2/datapoint/setpoint?dataPointID=bacnet100-4120-Real-room-temperature-setpoint-RTs_real&project_id=1&value=16.7&priority=13"
    -X POST 
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags (Meta, Company, ...) select the Datapoint tag, then the POST /v2/datapoint/setpoint endpoint (yellow).
  4. Provide the dataPointID, project_id and the value.
  5. Click "Try it out!".
  6. Inspect the response body and code.

A successful setpoint write operation (from the point of view of the API) returns HTTP 200 (OK) and a JSON containing the details of the setpoint:

{
  "success":true,
  "operation":"create",
  "resource": {
    "acked": false,
    "dataPointID": "bacnet100-4120-Real-room-temperature-setpoint-RTs_real",
    "dryrun": false,    
    "priority": 15,
    "value": 16.7
  }
}

Interpreting the response: For unacknowledged setpoint write operations, a successful response (HTTP 200) only means that the API accepted the request, i.e., the Edge Device is correctly configured and the user is authorized for writing to the building. There may still be errors on the side of the Edge Device that are not reported back to the API. If a real acknowledgement is required, the user should set acked = True or use schedules instead.

We have now set the desired temperature to 16.7 °C and the HVAC system will probably start working hard to follow your control input. Spin up any existing building management system of your choice and check the effect of your actions.

The written setpoint will remain active until it is cleared or overwritten. Since 16.7 °C is pretty cold for an office, we will soon wish to reset this ourselves and let the existing building automation system regain control. To this end, we need to write 'null' to the previously written datapoint and priority. Let's do an acknowledged write this time. And, let's be more careful and do a dryrun first.

r = post(f"{api_url}/v2/datapoint/setpoint", 
         auth=auth_john,
         params={'project_id': 1, 
                 'dataPointID': dataPointID, 
                 'value': 'null', 
                 'priority': 15,
                 'acked': True,
                 'dryrun': True})
print(r.text)

Note that the response now contains a reference for this setpoint write operation.

{
  "success": true,
  "operation": "create",
  "resource": {
    "acked": true,
    "dataPointID": "bacnet100-4120-Real-room-temperature-setpoint-RTs_real",
    "dryrun": true,
    "priority": 15,
    "project_id": 1,
    "reference": "0cce300f-6b9e-447d-ae29-0e7125e2fa36",
    "value": "null"
  }
}

Note that the response contains a reference. This reference can be used to look up the state of the setpoint write operation using the GET /v2/datapoint/setpoint/{reference} endpoint. Querying the previous reference returns the following answer (the log is returned as a JSON-formatted string that we reformatted to a list here for better readability):

{
  "dataPointID": "bacnet100-4120-Real-room-temperature-setpoint-RTs_real",
  "log": [
    {
      "msg": "Setpoint initialized on API.", 
      "status": "initialized", 
      "acked": true, 
      "dryrun": true, 
      "time": "2018-12-28T13:10:33.760509Z"
    }, 
    {
      "msg": "Setpoint request sent to edge device.", 
      "status": "requested", 
      "time": "2018-12-28T13:10:33.774182Z"
    }, 
    {
      "msg": "[DRYRUN] Successfully wrote value 'null' at priority 15 to object instance 3004665 of type 'analogOutput'", 
      "priorityArray": "[16, 'null', 'null', 'null', 'null', 'null', 'null', 'null', 'null', 'null', 'null', 'null', 'null', 'null', 'null', '16.7', '22.5']",
      "status": "written",
      "overwritten_value": "16.7",
      "time": "2018-12-28T13:10:34.146189Z"
    }
  ],
  "old_value": "16.7",
  "priority": 15,
  "project_id": 1,
  "reference": "0cce300f-6b9e-447d-ae29-0e7125e2fa36",
  "status": "written",
  "value": "null"
}

The status of the operation is now written which means that it was successful and the setpoint is in effect (if this wasn't a dry run). The field old_value contains the value that would be overwritten by this setpoint if this wasn't a dry run, i.e., 16.7° Celsius as was written in the previous unacknowledged setpoint write operation above. Note that additionally the complete priority array (for BACnet datapoints) as it was before this setpoint write operation is returned in the last log message. This lets you determine the last state of the datapoint before your setpoint. In this example, the setpoint at priority 16 will take over and our office would be heated to a comfy 22.5 °C. However, since this was a dry run, the setpoint at priority 15 (16.7 °C) remains active.

Please carefully choose which setpoints to write when you are operating on a real building. To avoid overwriting existing setpoints, use the dryrun feature to determine the current state of the targeted datapoint before writing anything to it.

Having inspected the state of the datapoint and decided that we really want to reset it, we now switch the dryrun flag to False and repeat the above operation. The answer will look almost completely the same as above except that the logs will not indicate a dry run anymore.

Creating .controls apps

.controls apps are created using the POST /v2/controls/app endpoint. The caller must provide the following parameters:

Parameter Datatype Type Required Description Example
project_id integer query yes The numeric id of the project. 1
componentinproject_id integer query yes The unique numeric identifier of the component in project. 12
algorithm string query yes Algorithm of the .controls app. schedule
variation string query no *Variation of the .controls algorithm -
name string query no Name of the .controls app. My fancy .controls app
description string query no Description of the .controls app My .controls app's description

*The variation of a .controls algorithm is a parameter that is defined per .controls algorithm type. It is relevant when a .controls algorithm has different pins mapped to it or there are component-specific requirements of an algorithm.

r = requests.post(f"{api_url}/v2/controls/app", 
                  auth=auth_john,
                  params={'project_id': 1, 
                          'componentinproject_id': 12,
                          'controls_algorithm': 'schedule')
print(r.text)
curl "https://api.cloud.aedifion.eu/v2/controls/app?project_id=1&componentinproject_id=1&algorithm=schedule"
    -X POST 
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags (Meta, Company, ...) select the Datapoint tag, then the POST /v2/controls/app endpoint (green).
  4. Provide the project_id, componentinproject_id, algorithm and the optional parameters as needed.
  5. Click "Try it out!".
  6. Inspect the response body and code.

A successful post .controls app (from the point of view of the API) returns HTTP 200 (OK) and a JSON containing the details of the .controls app:

{
  "operation": "create",
  "resource": {
    "algorithm": "schedule",
    "component_in_project_id": 12,
    "id": "34df4664-2755-4c15-8884-60043ebe58ac",
    "name": "",
    "status": {
      "code": 100,
      "message": "Created"
    }
  },
  "success": true
}

Starting and stopping .controls apps

.controls apps are started and stopped using the POST /v2/controls/app/{controls_app_id}/run endpoint. For the sake of brevity, only endpoint for starting and stopping a single .controls app is described here. To start/stop multiple .controls apps, use the endpoint POST /v2/controls/apps/run. The caller must provide the following parameters:

Parameter Datatype Type Required Description Example
project_id integer query yes The numeric id of the project. 1
controls_app_id string path yes The id of the .controls app. ab5c3de5-7bab-48c3
run boolean query no Desired state of the .controls app (run = true, stop = false). true
r = requests.post(f"{api_url}/v2/controls/app/ab5c3de5-7bab-48c3/run", 
                  auth=auth_john,
                  params={'project_id': 1, 
                          'run': 'true')
print(r.text)
curl "https://api.aedifion.eu/v2/controls/app/34df4664-2755-4c15-8884-60043ebe58ac/run?project_id=3&run=true"
    -X POST 
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags (Meta, Company, ...) select the Datapoint tag, then the POST /v2/controls/app/{controls_app_id}/run endpoint (green).
  4. Provide the project_id, controls_app_id and run parameter.
  5. Click "Try it out!".
  6. Inspect the response body and code.

A successful post .controls app run (from the point of view of the API) returns HTTP 200 (OK) and a JSON containing the details of the .controls app:

{
  "affected": true,
  "controls_app_id": "34df4664-2755-4c15-8884-60043ebe58ac",
  "status": {
    "code": 200,
    "message": "Starting"
  }
}

Deleting .controls apps

.controls deleted using the DELETE /v2/controls/app endpoint and only .controls apps that are not running can be deleted. The caller must provide the following parameters:

Parameter Datatype Type Required Description Example
project_id integer query yes The numeric id of the project. 1
controls_app_id string path yes The id of the .controls app. ab5c3de5-7bab-48c3
r = requests.post(f"{api_url}/v2/controls/app", 
                  auth=auth_john,
                  params={'project_id': 1, 
                          'controls_app_id': 'ab5c3de5-7bab-48c3')
print(r.text)
curl "https://api.aedifion.eu/v2/controls/app?project_id=3&controls_app_id=ab5c3de5-7bab-48c3-9c6d-c8e04d18ef15"
    -X POST 
    -u john.doe@aedifion.com:mys3cr3tp4ssw0rd
  1. Point your browser to https://api.aedifion.io/ui/.
  2. Click "Authorize" on the upper right and provide your login.
  3. From the main tags (Meta, Company, ...) select the Datapoint tag, then the DELETE /v2/controls/app endpoint (red).
  4. Provide the project_id and controls_app_id parameter.
  5. Click "Try it out!".
  6. Inspect the response body and code.

A successful delete .controls app (from the point of view of the API) returns HTTP 200 (OK) and a JSON containing the details of the .controls app:

{
  "operation": "delete",
  "resource": {
    "algorithm": "schedule",
    "component_in_project_id": 12,
    "id": "ab5c3de5-7bab-48c3",
    "name": "",
    "status": {
      "code": 500,
      "message": "Deleting"
    }
  },
  "success": true
}

Get endpoints for .controls apps

The following endpoints can be used to get information relevant to the .controls apps.

  • GET /v2/controls/apps: Fetches .controls apps of a project.
  • GET /v2/controls/app/{controls_app_id}: Fetches information about a single .controls app of a project.
  • GET /v2/controls/app/{controls_app_id}/logs: Fetches detailed information about when a .controls app has been running and what influence it has had.

FAQ

What happens if the Edge Device loses internet connection?
Reset values for the setpoints of all .controls apps are stored on the Edge Device. When the Edge Device loses connection for longer than the alive time-out of a control app, the Edge Device writes the reset values of the .controls app's setpoints. When the connection to the Edge Device is restored, the .controls apps restart if they are set to auto-recovery. Currently, the following default values for setpoint writing parameters are used for all .controls app setpoints:

  • priority: 13
  • reset_value: 'null'
  • keep_out_of_service: 'false'

Please contact support@aedifion.com if you require different configurations of the setpoints for your .controls app.

What happens when the Edge Device crashes?
The reset values of a .controls app are stored in a local database on the harddrive of the Edge Device. The Edge Device is set to automatically reboot when it crashes and will reload and reactivate all running .controls apps (as long as the HD is intact). This process takes no more than one minute. As with everything, crash events and subsequent reloads are logged to the API.

My setpoint or schedule seems to have no effect!
A setpoint operation will have no effect if the data point has already an active value, i.e., a value that is not null, written at a higher priority.

I cannot write at priority higher than 8!
In order to preserve life safety mechanism, the API will generally refuse to write at priorities higher than 8 (= manual operator). Higher priorities can be unlocked on request to support@aedifion.com and require written consent.


Last update: 2023-08-15
Back to top